non-overlapping intervals
diff --git a/src/passes/Outlining.cpp b/src/passes/Outlining.cpp index 68c3d03..b91cbcb 100644 --- a/src/passes/Outlining.cpp +++ b/src/passes/Outlining.cpp
@@ -264,6 +264,77 @@ }; struct Outlining : public Pass { + std::vector<SuffixTree::RepeatedSubstring> + blah(const std::vector<SuffixTree::RepeatedSubstring>& substrings) { + + struct Interval { + unsigned startIdx; + unsigned endIdx; + unsigned idxOfRepeatedSubstring; + unsigned score; + + Interval(unsigned startIdx, + unsigned endIdx, + unsigned idxOfRepeatedSubstring, + unsigned score) + : startIdx(startIdx), endIdx(endIdx), + idxOfRepeatedSubstring(idxOfRepeatedSubstring), score(score) {} + }; + + std::vector<Interval> intervals; + + // Make a construct we can use for finding intervals + for (Index i = 0; i < substrings.size(); i++) { + auto substring = substrings[i]; + for (auto startIdx : substring.StartIndices) { + intervals.emplace_back(startIdx, + startIdx + substring.Length, + i, + substring.Length * + substring.StartIndices.size()); + } + } + + // Sort construct + std::sort(intervals.begin(), intervals.end(), [](Interval a, Interval b) { + return a.startIdx < b.startIdx; + }); + + // Add overlaps with lower scores to doNotInclude set + std::set<uint32_t> doNotInclude; + auto& ref_interval = intervals[0]; + for (Index i = 1; i < intervals.size(); i++) { + auto& interval = intervals[i]; + if (ref_interval.endIdx < interval.startIdx) { + ref_interval = interval; + continue; + } + + // Keep the Interval with the higher score + // Update the ref_interval if its the one we're not keeping + if (interval.score > ref_interval.score) { + doNotInclude.insert(ref_interval.idxOfRepeatedSubstring); + ref_interval = interval; + } else { + doNotInclude.insert(interval.idxOfRepeatedSubstring); + } + } + + std::vector<SuffixTree::RepeatedSubstring> result; + + // Only include non-overlapping substrings + for (Index i = 0; i < substrings.size(); i++) { + if (doNotInclude.find(i) != doNotInclude.end()) { + continue; + } + + auto substring = substrings[i]; + result.push_back(substring); + } + + return result; + } + void run(Module* module) { HashStringifyWalker stringify; // Walk the module and create a "string representation" of the program. @@ -275,6 +346,9 @@ DBG(printHashString(stringify.hashString, stringify.exprs)); // Remove substrings that are substrings of longer repeat substrings. substrings = StringifyProcessor::dedupe(substrings); + ODBG(std::cerr << "\nSubstrings before blah: " << substrings.size()); + substrings = blah(substrings); + ODBG(std::cerr << "\nSubstrings after blah: " << substrings.size()); // Remove substrings with branch and return instructions until an analysis // is performed to see if the intended destination of the branch is included // in the substring to be outlined. @@ -353,6 +427,11 @@ keys.begin(), [](auto pair) { return pair.first; }); for (auto func : keys) { + std::sort(seqByFunc[func].begin(), + seqByFunc[func].end(), + [](OutliningSequence a, OutliningSequence b) { + return a.startIdx < b.startIdx; + }); reconstruct.sequences = std::move(seqByFunc[func]); reconstruct.doWalkFunction(module->getFunction(func)); }
diff --git a/test/gtest/stringify.cpp b/test/gtest/stringify.cpp index c38c29d..0ef3d8c 100644 --- a/test/gtest/stringify.cpp +++ b/test/gtest/stringify.cpp
@@ -288,21 +288,27 @@ SuffixTree::RepeatedSubstring{3u, (std::vector<unsigned>{23, 34})}})); } +// Tests that local.set instructions inside of control flow are filtered +// from being candidates for outlining TEST_F(StringifyTest, FilterLocalSets) { static auto localSetModuleText = R"wasm( (module (func $a (result i32) (local $x i32) - (local.set $x - (i32.const 1) + (block (result i32) + (local.set $x + (i32.const 1) + ) ) (i32.const 0) (i32.const 1) ) (func $b (result i32) (local $x i32) - (local.set $x - (i32.const 1) + (block (result i32) + (local.set $x + (i32.const 1) + ) ) (i32.const 5) (i32.const 0)