diff options
Diffstat (limited to 'src/ir/drop.h')
-rw-r--r-- | src/ir/drop.h | 83 |
1 files changed, 79 insertions, 4 deletions
diff --git a/src/ir/drop.h b/src/ir/drop.h index 9ed5276ff..a13b83332 100644 --- a/src/ir/drop.h +++ b/src/ir/drop.h @@ -17,6 +17,7 @@ #ifndef wasm_ir_drop_h #define wasm_ir_drop_h +#include "ir/branch-utils.h" #include "ir/effects.h" #include "ir/iteration.h" #include "wasm-builder.h" @@ -32,10 +33,10 @@ namespace wasm { // // The caller must also pass in a last item to append to the output (which is // typically what the original expression is replaced with). -Expression* getDroppedChildrenAndAppend(Expression* curr, - Module& wasm, - const PassOptions& options, - Expression* last) { +inline Expression* getDroppedChildrenAndAppend(Expression* curr, + Module& wasm, + const PassOptions& options, + Expression* last) { Builder builder(wasm); std::vector<Expression*> contents; for (auto* child : ChildIterator(curr)) { @@ -57,6 +58,80 @@ Expression* getDroppedChildrenAndAppend(Expression* curr, return builder.makeBlock(contents); } +// As the above, but only operates on children that execute unconditionally. +// That is the case in almost all expressions, except for those with +// conditional execution, like if, which unconditionally executes the condition +// but then conditionally executes one of the two arms. The above function +// simply returns all children in order, so it does this to if: +// +// (if +// (condition) +// (arm-A) +// (arm-B) +// ) +// => +// (drop +// (condition) +// ) +// (drop +// (arm-A) +// ) +// (drop +// (arm-B) +// ) +// (appended last item) +// +// This is dangerous as it executes what were conditional children in an +// unconditional way. To avoid that issue, this function will only operate on +// unconditional children, and keep conditional ones as they were. That means +// it will not split up and drop the children of an if, for example. All we do +// in that case is drop the entire if and append the last item: +// +// (drop +// (if +// (condition) +// (arm-A) +// (arm-B) +// ) +// ) +// (appended last item) +// +// Also this function preserves other unremovable expressions like trys and +// pops. +inline Expression* +getDroppedUnconditionalChildrenAndAppend(Expression* curr, + Module& wasm, + const PassOptions& options, + Expression* last) { + // We check for shallow effects here, since we may be able to remove |curr| + // itself but keep its children around - we don't want effects in the children + // to stop us from improving the code. Note that there are cases where the + // combined curr+children has fewer effects than curr itself, such as if curr + // is a block and the child branches to it, but in such cases we cannot remove + // curr anyhow (those cases are ruled out below), so looking at non-shallow + // effects would never help us (and would be slower to run). + ShallowEffectAnalyzer effects(options, wasm, curr); + // Ignore a trap, as the unreachable replacement would trap too. + if (last->type == Type::unreachable) { + effects.trap = false; + } + + // We cannot remove + // 1. Expressions with unremovable side effects + // 2. if: 'if's contains conditional expressions + // 3. try: Removing a try could leave a pop without a proper parent + // 4. pop: Pops are struturally necessary in catch bodies + // 5. Branch targets: We will need the target for the branches to it to + // validate. + if (effects.hasUnremovableSideEffects() || curr->is<If>() || + curr->is<Try>() || curr->is<Pop>() || + BranchUtils::getDefinedName(curr).is()) { + Builder builder(wasm); + return builder.makeSequence(builder.makeDrop(curr), last); + } + return getDroppedChildrenAndAppend(curr, wasm, options, last); +} + } // namespace wasm #endif // wasm_ir_drop_h |