diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-04-26 15:22:46 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-26 15:22:46 -0700 |
commit | 52d14d008a6a836c2cdbfe68852d274840e5de14 (patch) | |
tree | 684b2bef11816892107096fb92a6110dc2f776ab /src | |
parent | 353be4a0537de508f45ee72624d1af65bd5597dd (diff) | |
download | binaryen-52d14d008a6a836c2cdbfe68852d274840e5de14.tar.gz binaryen-52d14d008a6a836c2cdbfe68852d274840e5de14.tar.bz2 binaryen-52d14d008a6a836c2cdbfe68852d274840e5de14.zip |
code-folding improvements (#1512)
Noticed by Souper.
* We only folded identical code in an if-else when both arms were blocks, so we were missing the case of one arm being just a singleton expression. This PR will wraps that in a block so the rest of the optimization can work on it, if it sees it is going to be folded out. Turns out this is common for phis.
* We only ran code-folding in -Os, because I assumed it was just good for code size, but as it may remove phis in the wasm VM later, seems like we should run it when not optimizing for size as well.
Together, these two shrink lua -O3 by almost 1%.
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/CodeFolding.cpp | 25 | ||||
-rw-r--r-- | src/passes/pass.cpp | 2 |
2 files changed, 23 insertions, 4 deletions
diff --git a/src/passes/CodeFolding.cpp b/src/passes/CodeFolding.cpp index c2ad07595..b639c7681 100644 --- a/src/passes/CodeFolding.cpp +++ b/src/passes/CodeFolding.cpp @@ -15,7 +15,8 @@ */ // -// Folds duplicate code together, saving space. +// Folds duplicate code together, saving space (and possibly phis in +// the wasm VM, which can save time). // // We fold tails of code where they merge and moving the code // to the merge point is helpful. There are two cases here: (1) expressions, @@ -198,8 +199,6 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> { void visitIf(If* curr) { if (!curr->ifFalse) return; // if both sides are identical, this is easy to fold - // (except if the condition is unreachable and we return a value, then we can't just replace - // outselves with a drop if (ExpressionAnalyzer::equal(curr->ifTrue, curr->ifFalse)) { Builder builder(*getModule()); // remove if (4 bytes), remove one arm, add drop (1), add block (3), @@ -216,6 +215,26 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> { // if both are blocks, look for a tail we can merge auto* left = curr->ifTrue->dynCast<Block>(); auto* right = curr->ifFalse->dynCast<Block>(); + // If one is a block and the other isn't, and the non-block is a tail + // of the other, we can fold that - for our convenience, we just add + // a block and run the rest of the optimization mormally. + auto maybeAddBlock = [this](Block* block, Expression*& other) -> Block* { + // if other is a suffix of the block, wrap it in a block + if (block->list.empty() || + !ExpressionAnalyzer::equal(other, block->list.back())) { + return nullptr; + } + // do it, assign to the out param `other`, and return the block + Builder builder(*getModule()); + auto* ret = builder.makeBlock(other); + other = ret; + return ret; + }; + if (left && !right) { + right = maybeAddBlock(left, curr->ifFalse); + } else if (!left && right) { + left = maybeAddBlock(right, curr->ifTrue); + } // we need nameless blocks, as if there is a name, someone might branch // to the end, skipping the code we want to merge if (left && right && diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 38a21fae8..0ec5864e0 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -154,7 +154,7 @@ void PassRunner::addDefaultFunctionOptimizationPasses() { add("simplify-locals"); add("vacuum"); // previous pass creates garbage add("reorder-locals"); - if (options.shrinkLevel >= 1) { + if (options.optimizeLevel >= 3 || options.shrinkLevel >= 1) { add("code-folding"); } add("merge-blocks"); // makes remove-unused-brs more effective |