diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 11 | ||||
-rw-r--r-- | src/binaryen-c.h | 5 | ||||
-rw-r--r-- | src/ir/block-utils.h | 6 | ||||
-rw-r--r-- | src/ir/effects.h | 93 | ||||
-rw-r--r-- | src/ir/local-utils.h | 18 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 5 | ||||
-rw-r--r-- | src/passes/CodeFolding.cpp | 4 | ||||
-rw-r--r-- | src/passes/CodePushing.cpp | 24 | ||||
-rw-r--r-- | src/passes/DeadArgumentElimination.cpp | 3 | ||||
-rw-r--r-- | src/passes/LocalCSE.cpp | 18 | ||||
-rw-r--r-- | src/passes/LoopInvariantCodeMotion.cpp | 9 | ||||
-rw-r--r-- | src/passes/MergeBlocks.cpp | 27 | ||||
-rw-r--r-- | src/passes/OptimizeAddedConstants.cpp | 3 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 62 | ||||
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 39 | ||||
-rw-r--r-- | src/passes/SimplifyGlobals.cpp | 2 | ||||
-rw-r--r-- | src/passes/SimplifyLocals.cpp | 25 | ||||
-rw-r--r-- | src/passes/Vacuum.cpp | 35 | ||||
-rw-r--r-- | src/wasm2js.h | 14 |
19 files changed, 271 insertions, 132 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 3d311f5bd..1362e0960 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -4508,17 +4508,22 @@ BinaryenSideEffects BinaryenSideEffectIsAtomic(void) { return static_cast<BinaryenSideEffects>( EffectAnalyzer::SideEffects::IsAtomic); } +BinaryenSideEffects BinaryenSideEffectThrows(void) { + return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::Throws); +} BinaryenSideEffects BinaryenSideEffectAny(void) { return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::Any); } BinaryenSideEffects -BinaryenExpressionGetSideEffects(BinaryenExpressionRef expr) { +BinaryenExpressionGetSideEffects(BinaryenExpressionRef expr, + BinaryenFeatures features) { if (tracing) { std::cout << " BinaryenExpressionGetSideEffects(expressions[" - << expressions[expr] << "]);\n"; + << expressions[expr] << "], " << features << ");\n"; } - return EffectAnalyzer(globalPassOptions, (Expression*)expr).getSideEffects(); + return EffectAnalyzer(globalPassOptions, features, (Expression*)expr) + .getSideEffects(); } // diff --git a/src/binaryen-c.h b/src/binaryen-c.h index d4ea9ccfa..0a9a70f4d 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -1497,10 +1497,11 @@ BINARYEN_API BinaryenSideEffects BinaryenSideEffectReadsMemory(void); BINARYEN_API BinaryenSideEffects BinaryenSideEffectWritesMemory(void); BINARYEN_API BinaryenSideEffects BinaryenSideEffectImplicitTrap(void); BINARYEN_API BinaryenSideEffects BinaryenSideEffectIsAtomic(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectThrows(void); BINARYEN_API BinaryenSideEffects BinaryenSideEffectAny(void); -BINARYEN_API BinaryenSideEffects -BinaryenExpressionGetSideEffects(BinaryenExpressionRef expr); +BINARYEN_API BinaryenSideEffects BinaryenExpressionGetSideEffects( + BinaryenExpressionRef expr, BinaryenFeatures features); // // ========== CFG / Relooper ========== diff --git a/src/ir/block-utils.h b/src/ir/block-utils.h index d3a4e0a64..f8224186f 100644 --- a/src/ir/block-utils.h +++ b/src/ir/block-utils.h @@ -37,8 +37,10 @@ simplifyToContents(Block* block, T* parent, bool allowTypeChange = false) { !BranchUtils::BranchSeeker::has(list[0], block->name)) { // just one element. try to replace the block auto* singleton = list[0]; - auto sideEffects = - EffectAnalyzer(parent->getPassOptions(), singleton).hasSideEffects(); + auto sideEffects = EffectAnalyzer(parent->getPassOptions(), + parent->getModule()->features, + singleton) + .hasSideEffects(); if (!sideEffects && !singleton->type.isConcrete()) { // no side effects, and singleton is not returning a value, so we can // throw away the block and its contents, basically diff --git a/src/ir/effects.h b/src/ir/effects.h index 0d1e2c2b1..9c1ed18f2 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -27,9 +27,11 @@ namespace wasm { struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<EffectAnalyzer>> { - EffectAnalyzer(const PassOptions& passOptions, Expression* ast = nullptr) { - ignoreImplicitTraps = passOptions.ignoreImplicitTraps; - debugInfo = passOptions.debugInfo; + EffectAnalyzer(const PassOptions& passOptions, + FeatureSet features, + Expression* ast = nullptr) + : ignoreImplicitTraps(passOptions.ignoreImplicitTraps), + debugInfo(passOptions.debugInfo), features(features) { if (ast) { analyze(ast); } @@ -37,6 +39,7 @@ struct EffectAnalyzer bool ignoreImplicitTraps; bool debugInfo; + FeatureSet features; void analyze(Expression* ast) { breakNames.clear(); @@ -45,6 +48,7 @@ struct EffectAnalyzer if (breakNames.size() > 0) { branches = true; } + assert(tryDepth == 0); } // Core effect tracking @@ -66,6 +70,36 @@ struct EffectAnalyzer // An atomic load/store/RMW/Cmpxchg or an operator that has a defined ordering // wrt atomics (e.g. memory.grow) bool isAtomic = false; + bool throws = false; + // The nested depth of try. If an instruction that may throw is inside an + // inner try, we don't mark it as 'throws', because it will be caught by an + // inner catch. + size_t tryDepth = 0; + + static void scan(EffectAnalyzer* self, Expression** currp) { + Expression* curr = *currp; + // We need to decrement try depth before catch starts, so handle it + // separately + if (curr->is<Try>()) { + self->pushTask(doVisitTry, currp); + self->pushTask(scan, &curr->cast<Try>()->catchBody); + self->pushTask(doStartCatch, currp); + self->pushTask(scan, &curr->cast<Try>()->body); + self->pushTask(doStartTry, currp); + return; + } + PostWalker<EffectAnalyzer, OverriddenVisitor<EffectAnalyzer>>::scan(self, + currp); + } + + static void doStartTry(EffectAnalyzer* self, Expression** currp) { + self->tryDepth++; + } + + static void doStartCatch(EffectAnalyzer* self, Expression** currp) { + assert(self->tryDepth > 0 && "try depth cannot be negative"); + self->tryDepth--; + } // Helper functions to check for various effect types @@ -76,17 +110,20 @@ struct EffectAnalyzer return globalsRead.size() + globalsWritten.size() > 0; } bool accessesMemory() const { return calls || readsMemory || writesMemory; } + bool transfersControlFlow() const { return branches || throws; } bool hasGlobalSideEffects() const { - return calls || globalsWritten.size() > 0 || writesMemory || isAtomic; + return calls || globalsWritten.size() > 0 || writesMemory || isAtomic || + throws; } bool hasSideEffects() const { return hasGlobalSideEffects() || localsWritten.size() > 0 || branches || implicitTrap; } bool hasAnything() const { - return branches || calls || accessesLocal() || readsMemory || - writesMemory || accessesGlobal() || implicitTrap || isAtomic; + return calls || accessesLocal() || readsMemory || writesMemory || + accessesGlobal() || implicitTrap || isAtomic || + transfersControlFlow(); } bool noticesGlobalSideEffects() { @@ -99,8 +136,8 @@ struct EffectAnalyzer // checks if these effects would invalidate another set (e.g., if we write, we // invalidate someone that reads, they can't be moved past us) bool invalidates(const EffectAnalyzer& other) { - if ((branches && other.hasSideEffects()) || - (other.branches && hasSideEffects()) || + if ((transfersControlFlow() && other.hasSideEffects()) || + (other.transfersControlFlow() && hasSideEffects()) || ((writesMemory || calls) && other.accessesMemory()) || (accessesMemory() && (other.writesMemory || other.calls))) { return true; @@ -137,7 +174,8 @@ struct EffectAnalyzer } } // we are ok to reorder implicit traps, but not conditionalize them - if ((implicitTrap && other.branches) || (other.implicitTrap && branches)) { + if ((implicitTrap && other.transfersControlFlow()) || + (other.implicitTrap && transfersControlFlow())) { return true; } // we can't reorder an implicit trap in a way that alters global state @@ -155,6 +193,7 @@ struct EffectAnalyzer writesMemory = writesMemory || other.writesMemory; implicitTrap = implicitTrap || other.implicitTrap; isAtomic = isAtomic || other.isAtomic; + throws = throws || other.throws; for (auto i : other.localsRead) { localsRead.insert(i); } @@ -223,6 +262,10 @@ struct EffectAnalyzer void visitCall(Call* curr) { calls = true; + // When EH is enabled, any call can throw. + if (features.hasExceptionHandling() && tryDepth == 0) { + throws = true; + } if (curr->isReturn) { branches = true; } @@ -235,6 +278,9 @@ struct EffectAnalyzer } void visitCallIndirect(CallIndirect* curr) { calls = true; + if (features.hasExceptionHandling() && tryDepth == 0) { + throws = true; + } if (curr->isReturn) { branches = true; } @@ -391,9 +437,16 @@ struct EffectAnalyzer void visitRefIsNull(RefIsNull* curr) {} void visitRefFunc(RefFunc* curr) {} void visitTry(Try* curr) {} - // We safely model throws as branches - void visitThrow(Throw* curr) { branches = true; } - void visitRethrow(Rethrow* curr) { branches = true; } + void visitThrow(Throw* curr) { + if (tryDepth == 0) { + throws = true; + } + } + void visitRethrow(Rethrow* curr) { + if (tryDepth == 0) { + throws = true; + } + } void visitBrOnExn(BrOnExn* curr) { breakNames.insert(curr->name); } void visitNop(Nop* curr) {} void visitUnreachable(Unreachable* curr) { branches = true; } @@ -402,10 +455,12 @@ struct EffectAnalyzer // Helpers - static bool - canReorder(const PassOptions& passOptions, Expression* a, Expression* b) { - EffectAnalyzer aEffects(passOptions, a); - EffectAnalyzer bEffects(passOptions, b); + static bool canReorder(const PassOptions& passOptions, + FeatureSet features, + Expression* a, + Expression* b) { + EffectAnalyzer aEffects(passOptions, features, a); + EffectAnalyzer bEffects(passOptions, features, b); return !aEffects.invalidates(bEffects); } @@ -423,7 +478,8 @@ struct EffectAnalyzer WritesMemory = 1 << 7, ImplicitTrap = 1 << 8, IsAtomic = 1 << 9, - Any = (1 << 10) - 1 + Throws = 1 << 10, + Any = (1 << 11) - 1 }; uint32_t getSideEffects() const { uint32_t effects = 0; @@ -457,6 +513,9 @@ struct EffectAnalyzer if (isAtomic) { effects |= SideEffects::IsAtomic; } + if (throws) { + effects |= SideEffects::Throws; + } return effects; } }; diff --git a/src/ir/local-utils.h b/src/ir/local-utils.h index c2a99b5af..0eba31889 100644 --- a/src/ir/local-utils.h +++ b/src/ir/local-utils.h @@ -45,18 +45,23 @@ struct UnneededSetRemover : public PostWalker<UnneededSetRemover> { PassOptions& passOptions; LocalGetCounter* localGetCounter = nullptr; + FeatureSet features; - UnneededSetRemover(Function* func, PassOptions& passOptions) - : passOptions(passOptions) { + UnneededSetRemover(Function* func, + PassOptions& passOptions, + FeatureSet features) + : passOptions(passOptions), features(features) { LocalGetCounter counter(func); - UnneededSetRemover inner(counter, func, passOptions); + UnneededSetRemover inner(counter, func, passOptions, features); removed = inner.removed; } UnneededSetRemover(LocalGetCounter& localGetCounter, Function* func, - PassOptions& passOptions) - : passOptions(passOptions), localGetCounter(&localGetCounter) { + PassOptions& passOptions, + FeatureSet features) + : passOptions(passOptions), localGetCounter(&localGetCounter), + features(features) { walk(func->body); } @@ -91,7 +96,8 @@ struct UnneededSetRemover : public PostWalker<UnneededSetRemover> { auto* value = set->value; if (set->isTee()) { replaceCurrent(value); - } else if (EffectAnalyzer(passOptions, set->value).hasSideEffects()) { + } else if (EffectAnalyzer(passOptions, features, set->value) + .hasSideEffects()) { Drop* drop = ExpressionManipulator::convert<LocalSet, Drop>(set); drop->value = value; drop->finalize(); diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 5857c21c9..fd2832bf2 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -471,6 +471,7 @@ function initializeConstants() { 'WritesMemory', 'ImplicitTrap', 'IsAtomic', + 'Throws', 'Any' ].forEach(function(name) { Module['SideEffects'][name] = Module['_BinaryenSideEffect' + name](); @@ -2759,8 +2760,8 @@ Module['getExpressionInfo'] = function(expr) { }; // Gets the side effects of the specified expression -Module['getSideEffects'] = function(expr) { - return Module['_BinaryenExpressionGetSideEffects'](expr); +Module['getSideEffects'] = function(expr, features) { + return Module['_BinaryenExpressionGetSideEffects'](expr, features); }; Module['createType'] = function(types) { diff --git a/src/passes/CodeFolding.cpp b/src/passes/CodeFolding.cpp index 9b6e1143d..e4d24e33d 100644 --- a/src/passes/CodeFolding.cpp +++ b/src/passes/CodeFolding.cpp @@ -569,7 +569,9 @@ private: // TODO: this should not be a problem in // *non*-terminating tails, but // double-verify that - if (EffectAnalyzer(getPassOptions(), newItem) + if (EffectAnalyzer(getPassOptions(), + getModule()->features, + newItem) .hasExternalBreakTargets()) { return true; } diff --git a/src/passes/CodePushing.cpp b/src/passes/CodePushing.cpp index 4eb69b92e..6907f4fdc 100644 --- a/src/passes/CodePushing.cpp +++ b/src/passes/CodePushing.cpp @@ -82,14 +82,16 @@ class Pusher { LocalAnalyzer& analyzer; std::vector<Index>& numGetsSoFar; PassOptions& passOptions; + FeatureSet features; public: Pusher(Block* block, LocalAnalyzer& analyzer, std::vector<Index>& numGetsSoFar, - PassOptions& passOptions) + PassOptions& passOptions, + FeatureSet features) : list(block->list), analyzer(analyzer), numGetsSoFar(numGetsSoFar), - passOptions(passOptions) { + passOptions(passOptions), features(features) { // Find an optimization segment: from the first pushable thing, to the first // point past which we want to push. We then push in that range before // continuing forward. @@ -126,7 +128,7 @@ private: // but also have no side effects, as it may not execute if pushed. if (analyzer.isSFA(index) && numGetsSoFar[index] == analyzer.getNumGets(index) && - !EffectAnalyzer(passOptions, set->value).hasSideEffects()) { + !EffectAnalyzer(passOptions, features, set->value).hasSideEffects()) { return set; } return nullptr; @@ -157,7 +159,7 @@ private: assert(firstPushable != Index(-1) && pushPoint != Index(-1) && firstPushable < pushPoint); // everything that matters if you want to be pushed past the pushPoint - EffectAnalyzer cumulativeEffects(passOptions); + EffectAnalyzer cumulativeEffects(passOptions, features); cumulativeEffects.analyze(list[pushPoint]); // it is ok to ignore the branching here, that is the crucial point of this // opt @@ -169,11 +171,12 @@ private: if (pushable) { auto iter = pushableEffects.find(pushable); if (iter == pushableEffects.end()) { - iter = pushableEffects - .emplace(std::piecewise_construct, - std::forward_as_tuple(pushable), - std::forward_as_tuple(passOptions, pushable)) - .first; + iter = + pushableEffects + .emplace(std::piecewise_construct, + std::forward_as_tuple(pushable), + std::forward_as_tuple(passOptions, features, pushable)) + .first; } auto& effects = iter->second; if (cumulativeEffects.invalidates(effects)) { @@ -263,7 +266,8 @@ struct CodePushing : public WalkerPass<PostWalker<CodePushing>> { // don't hit a non-control-flow ordering invalidation issue, since if this // isn't a loop, it's fine (we're not used outside), and if it is, we hit // the assign before any use (as we can't push it past a use). - Pusher pusher(curr, analyzer, numGetsSoFar, getPassOptions()); + Pusher pusher( + curr, analyzer, numGetsSoFar, getPassOptions(), getModule()->features); } }; diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 43ebc6721..a20ff1fb8 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -341,7 +341,8 @@ struct DAE : public Pass { bool canRemove = std::none_of(calls.begin(), calls.end(), [&](Call* call) { auto* operand = call->operands[i]; - return EffectAnalyzer(runner->options, operand).hasSideEffects(); + return EffectAnalyzer(runner->options, module->features, operand) + .hasSideEffects(); }); if (canRemove) { // Wonderful, nothing stands in our way! Do it. diff --git a/src/passes/LocalCSE.cpp b/src/passes/LocalCSE.cpp index b49c92310..f7c1cda26 100644 --- a/src/passes/LocalCSE.cpp +++ b/src/passes/LocalCSE.cpp @@ -60,8 +60,11 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> { Index index; // the local we are assigned to, local.get that to reuse us EffectAnalyzer effects; - UsableInfo(Expression* value, Index index, PassOptions& passOptions) - : value(value), index(index), effects(passOptions, value) {} + UsableInfo(Expression* value, + Index index, + PassOptions& passOptions, + FeatureSet features) + : value(value), index(index), effects(passOptions, features, value) {} }; // a list of usables in a linear execution trace @@ -136,7 +139,7 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> { // pre operations Expression* curr = *currp; - EffectAnalyzer effects(self->getPassOptions()); + EffectAnalyzer effects(self->getPassOptions(), self->getModule()->features); if (effects.checkPre(curr)) { self->checkInvalidations(effects); } @@ -152,7 +155,7 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> { // post operations - EffectAnalyzer effects(self->getPassOptions()); + EffectAnalyzer effects(self->getPassOptions(), self->getModule()->features); if (effects.checkPost(curr)) { self->checkInvalidations(effects, curr); } @@ -194,7 +197,9 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> { } else { // not in table, add this, maybe we can help others later usables.emplace(std::make_pair( - hashed, UsableInfo(value, set->index, getPassOptions()))); + hashed, + UsableInfo( + value, set->index, getPassOptions(), getModule()->features))); } } } else if (auto* get = curr->dynCast<LocalGet>()) { @@ -215,7 +220,8 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> { if (!value->type.isConcrete()) { return false; // don't bother with unreachable etc. } - if (EffectAnalyzer(getPassOptions(), value).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), getModule()->features, value) + .hasSideEffects()) { return false; // we can't combine things with side effects } auto& options = getPassRunner()->options; diff --git a/src/passes/LoopInvariantCodeMotion.cpp b/src/passes/LoopInvariantCodeMotion.cpp index a95f4c8eb..26e2a0844 100644 --- a/src/passes/LoopInvariantCodeMotion.cpp +++ b/src/passes/LoopInvariantCodeMotion.cpp @@ -60,13 +60,14 @@ struct LoopInvariantCodeMotion // Accumulate effects of things we can't move out - things // we move out later must cross them, so we must verify it // is ok to do so. - EffectAnalyzer effectsSoFar(getPassOptions()); + FeatureSet features = getModule()->features; + EffectAnalyzer effectsSoFar(getPassOptions(), features); // The loop's total effects also matter. For example, a store // in the loop means we can't move a load outside. // FIXME: we look at the loop "tail" area too, after the last // possible branch back, which can cause false positives // for bad effect interactions. - EffectAnalyzer loopEffects(getPassOptions(), loop); + EffectAnalyzer loopEffects(getPassOptions(), features, loop); // Note all the sets in each loop, and how many per index. Currently // EffectAnalyzer can't do that, and we need it to know if we // can move a set out of the loop (if there is another set @@ -107,8 +108,8 @@ struct LoopInvariantCodeMotion // a branch to it anyhow, so we would stop before that point anyhow. } // If this may branch, we are done. - EffectAnalyzer effects(getPassOptions(), curr); - if (effects.branches) { + EffectAnalyzer effects(getPassOptions(), features, curr); + if (effects.transfersControlFlow()) { break; } if (interestingToMove(curr)) { diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp index 276c50d9e..ab368429f 100644 --- a/src/passes/MergeBlocks.cpp +++ b/src/passes/MergeBlocks.cpp @@ -101,7 +101,8 @@ struct ProblemFinder : public ControlFlowWalker<ProblemFinder> { brIfs++; } // if the value has side effects, we can't remove it - if (EffectAnalyzer(passOptions, curr->value).hasSideEffects()) { + if (EffectAnalyzer(passOptions, getModule()->features, curr->value) + .hasSideEffects()) { foundProblem = true; } } @@ -224,6 +225,7 @@ optimizeBlock(Block* curr, Module* module, PassOptions& passOptions) { Expression* expression = childBlock; // check if it's ok to remove the value from all breaks to us ProblemFinder finder(passOptions); + finder.setModule(module); finder.origin = childBlock->name; finder.walk(expression); if (finder.found()) { @@ -418,17 +420,18 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> { if (!child) { return outer; } + FeatureSet features = getModule()->features; if ((dependency1 && *dependency1) || (dependency2 && *dependency2)) { // there are dependencies, things we must be reordered through. make sure // no problems there - EffectAnalyzer childEffects(getPassOptions(), child); + EffectAnalyzer childEffects(getPassOptions(), features, child); if (dependency1 && *dependency1 && - EffectAnalyzer(getPassOptions(), *dependency1) + EffectAnalyzer(getPassOptions(), features, *dependency1) .invalidates(childEffects)) { return outer; } if (dependency2 && *dependency2 && - EffectAnalyzer(getPassOptions(), *dependency2) + EffectAnalyzer(getPassOptions(), features, *dependency2) .invalidates(childEffects)) { return outer; } @@ -495,16 +498,17 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> { Expression*& third) { // TODO: for now, just stop when we see any side effect. instead, we could // check effects carefully for reordering + FeatureSet features = getModule()->features; Block* outer = nullptr; - if (EffectAnalyzer(getPassOptions(), first).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), features, first).hasSideEffects()) { return; } outer = optimize(curr, first, outer); - if (EffectAnalyzer(getPassOptions(), second).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), features, second).hasSideEffects()) { return; } outer = optimize(curr, second, outer); - if (EffectAnalyzer(getPassOptions(), third).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), features, third).hasSideEffects()) { return; } optimize(curr, third, outer); @@ -529,7 +533,8 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> { template<typename T> void handleCall(T* curr) { Block* outer = nullptr; for (Index i = 0; i < curr->operands.size(); i++) { - if (EffectAnalyzer(getPassOptions(), curr->operands[i]) + if (EffectAnalyzer( + getPassOptions(), getModule()->features, curr->operands[i]) .hasSideEffects()) { return; } @@ -541,15 +546,17 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> { void visitCall(Call* curr) { handleCall(curr); } void visitCallIndirect(CallIndirect* curr) { + FeatureSet features = getModule()->features; Block* outer = nullptr; for (Index i = 0; i < curr->operands.size(); i++) { - if (EffectAnalyzer(getPassOptions(), curr->operands[i]) + if (EffectAnalyzer(getPassOptions(), features, curr->operands[i]) .hasSideEffects()) { return; } outer = optimize(curr, curr->operands[i], outer); } - if (EffectAnalyzer(getPassOptions(), curr->target).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), features, curr->target) + .hasSideEffects()) { return; } optimize(curr, curr->target, outer); diff --git a/src/passes/OptimizeAddedConstants.cpp b/src/passes/OptimizeAddedConstants.cpp index f0c1ec2d9..e5cbf108a 100644 --- a/src/passes/OptimizeAddedConstants.cpp +++ b/src/passes/OptimizeAddedConstants.cpp @@ -360,7 +360,8 @@ private: void cleanUpAfterPropagation() { // Remove sets that no longer have uses. This allows further propagation by // letting us see the accurate amount of uses of each set. - UnneededSetRemover remover(getFunction(), getPassOptions()); + UnneededSetRemover remover( + getFunction(), getPassOptions(), getModule()->features); } std::map<LocalSet*, Index> helperIndexes; diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index ef7c17000..90abed825 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -330,6 +330,7 @@ struct OptimizeInstructions // Optimizations that don't yet fit in the pattern DSL, but could be // eventually maybe Expression* handOptimize(Expression* curr) { + FeatureSet features = getModule()->features; // if this contains dead code, don't bother trying to optimize it, the type // might change (if might not be unreachable if just one arm is, for // example). this optimization pass focuses on actually executing code. the @@ -472,7 +473,7 @@ struct OptimizeInstructions if (auto* subZero = sub->left->dynCast<Const>()) { if (subZero->value.geti32() == 0) { if (EffectAnalyzer::canReorder( - getPassOptions(), sub->right, binary->right)) { + getPassOptions(), features, sub->right, binary->right)) { sub->left = binary->right; return sub; } @@ -630,7 +631,8 @@ struct OptimizeInstructions } // finally, try more expensive operations on the binary in // the case that they have no side effects - if (!EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) { + if (!EffectAnalyzer(getPassOptions(), features, binary->left) + .hasSideEffects()) { if (ExpressionAnalyzer::equal(binary->left, binary->right)) { return optimizeBinaryWithEqualEffectlessChildren(binary); } @@ -750,7 +752,8 @@ struct OptimizeInstructions // if we can replace the if with one arm, and no side effects in the // condition, do that auto needCondition = - EffectAnalyzer(getPassOptions(), iff->condition).hasSideEffects(); + EffectAnalyzer(getPassOptions(), features, iff->condition) + .hasSideEffects(); auto isSubType = Type::isSubType(iff->ifTrue->type, iff->type); if (isSubType && !needCondition) { return iff->ifTrue; @@ -781,8 +784,8 @@ struct OptimizeInstructions auto* condition = select->condition->dynCast<Unary>(); if (condition && condition->op == EqZInt32) { // flip select to remove eqz, if we can reorder - EffectAnalyzer ifTrue(getPassOptions(), select->ifTrue); - EffectAnalyzer ifFalse(getPassOptions(), select->ifFalse); + EffectAnalyzer ifTrue(getPassOptions(), features, select->ifTrue); + EffectAnalyzer ifFalse(getPassOptions(), features, select->ifFalse); if (!ifTrue.invalidates(ifFalse)) { select->condition = condition->value; std::swap(select->ifTrue, select->ifFalse); @@ -792,7 +795,7 @@ struct OptimizeInstructions // constant condition, we can just pick the right side (barring side // effects) if (c->value.getInteger()) { - if (!EffectAnalyzer(getPassOptions(), select->ifFalse) + if (!EffectAnalyzer(getPassOptions(), features, select->ifFalse) .hasSideEffects()) { return select->ifTrue; } else { @@ -800,7 +803,7 @@ struct OptimizeInstructions // local, which is bad } } else { - if (!EffectAnalyzer(getPassOptions(), select->ifTrue) + if (!EffectAnalyzer(getPassOptions(), features, select->ifTrue) .hasSideEffects()) { return select->ifFalse; } else { @@ -812,7 +815,7 @@ struct OptimizeInstructions } if (ExpressionAnalyzer::equal(select->ifTrue, select->ifFalse)) { // sides are identical, fold - EffectAnalyzer value(getPassOptions(), select->ifTrue); + EffectAnalyzer value(getPassOptions(), features, select->ifTrue); if (value.hasSideEffects()) { // at best we don't need the condition, but need to execute the value // twice. a block is larger than a select by 2 bytes, and @@ -820,7 +823,8 @@ struct OptimizeInstructions // so it's not clear this is worth it, TODO } else { // value has no side effects - EffectAnalyzer condition(getPassOptions(), select->condition); + EffectAnalyzer condition( + getPassOptions(), features, select->condition); if (!condition.hasSideEffects()) { return select->ifTrue; } else { @@ -887,14 +891,15 @@ private: // write more concise pattern matching code elsewhere. void canonicalize(Binary* binary) { assert(Properties::isSymmetric(binary)); + FeatureSet features = getModule()->features; auto swap = [&]() { assert(EffectAnalyzer::canReorder( - getPassOptions(), binary->left, binary->right)); + getPassOptions(), features, binary->left, binary->right)); std::swap(binary->left, binary->right); }; auto maybeSwap = [&]() { if (EffectAnalyzer::canReorder( - getPassOptions(), binary->left, binary->right)) { + getPassOptions(), features, binary->left, binary->right)) { swap(); } }; @@ -1064,6 +1069,7 @@ private: ZeroRemover(PassOptions& passOptions) : passOptions(passOptions) {} void visitBinary(Binary* curr) { + FeatureSet features = getModule()->features; auto* left = curr->left->dynCast<Const>(); auto* right = curr->right->dynCast<Const>(); if (curr->op == AddInt32) { @@ -1086,7 +1092,8 @@ private: // shift has side effects if (((left && left->value.geti32() == 0) || (right && Bits::getEffectiveShifts(right) == 0)) && - !EffectAnalyzer(passOptions, curr->right).hasSideEffects()) { + !EffectAnalyzer(passOptions, features, curr->right) + .hasSideEffects()) { replaceCurrent(curr->left); return; } @@ -1094,12 +1101,14 @@ private: // multiplying by zero is a zero, unless the other side has side // effects if (left && left->value.geti32() == 0 && - !EffectAnalyzer(passOptions, curr->right).hasSideEffects()) { + !EffectAnalyzer(passOptions, features, curr->right) + .hasSideEffects()) { replaceCurrent(left); return; } if (right && right->value.geti32() == 0 && - !EffectAnalyzer(passOptions, curr->left).hasSideEffects()) { + !EffectAnalyzer(passOptions, features, curr->left) + .hasSideEffects()) { replaceCurrent(right); return; } @@ -1107,7 +1116,9 @@ private: } }; Expression* walked = binary; - ZeroRemover(getPassOptions()).walk(walked); + ZeroRemover remover(getPassOptions()); + remover.setModule(getModule()); + remover.walk(walked); if (constant == 0) { return walked; // nothing more to do } @@ -1142,8 +1153,9 @@ private: if (!Properties::emitsBoolean(left) || !Properties::emitsBoolean(right)) { return nullptr; } - auto leftEffects = EffectAnalyzer(getPassOptions(), left); - auto rightEffects = EffectAnalyzer(getPassOptions(), right); + FeatureSet features = getModule()->features; + auto leftEffects = EffectAnalyzer(getPassOptions(), features, left); + auto rightEffects = EffectAnalyzer(getPassOptions(), features, right); auto leftHasSideEffects = leftEffects.hasSideEffects(); auto rightHasSideEffects = rightEffects.hasSideEffects(); if (leftHasSideEffects && rightHasSideEffects) { @@ -1189,13 +1201,16 @@ private: // (x > y) | (x == y) ==> x >= y Expression* combineOr(Binary* binary) { assert(binary->op == OrInt32); + FeatureSet features = getModule()->features; if (auto* left = binary->left->dynCast<Binary>()) { if (auto* right = binary->right->dynCast<Binary>()) { if (left->op != right->op && ExpressionAnalyzer::equal(left->left, right->left) && ExpressionAnalyzer::equal(left->right, right->right) && - !EffectAnalyzer(getPassOptions(), left->left).hasSideEffects() && - !EffectAnalyzer(getPassOptions(), left->right).hasSideEffects()) { + !EffectAnalyzer(getPassOptions(), features, left->left) + .hasSideEffects() && + !EffectAnalyzer(getPassOptions(), features, left->right) + .hasSideEffects()) { switch (left->op) { // (x > y) | (x == y) ==> x >= y case EqInt32: { @@ -1296,6 +1311,7 @@ private: // is a constant // TODO: templatize on type? Expression* optimizeWithConstantOnRight(Binary* binary) { + FeatureSet features = getModule()->features; auto type = binary->right->type; auto* right = binary->right->cast<Const>(); if (type.isInteger()) { @@ -1309,7 +1325,7 @@ private: return binary->left; } else if ((binary->op == Abstract::getBinary(type, Abstract::Mul) || binary->op == Abstract::getBinary(type, Abstract::And)) && - !EffectAnalyzer(getPassOptions(), binary->left) + !EffectAnalyzer(getPassOptions(), features, binary->left) .hasSideEffects()) { return binary->right; } else if (binary->op == EqInt64) { @@ -1323,7 +1339,7 @@ private: if (binary->op == Abstract::getBinary(type, Abstract::And)) { return binary->left; } else if (binary->op == Abstract::getBinary(type, Abstract::Or) && - !EffectAnalyzer(getPassOptions(), binary->left) + !EffectAnalyzer(getPassOptions(), features, binary->left) .hasSideEffects()) { return binary->right; } @@ -1381,7 +1397,9 @@ private: if ((binary->op == Abstract::getBinary(type, Abstract::Shl) || binary->op == Abstract::getBinary(type, Abstract::ShrU) || binary->op == Abstract::getBinary(type, Abstract::ShrS)) && - !EffectAnalyzer(getPassOptions(), binary->right).hasSideEffects()) { + !EffectAnalyzer( + getPassOptions(), getModule()->features, binary->right) + .hasSideEffects()) { return binary->left; } } diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 786fcaf67..2d944d212 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -35,7 +35,8 @@ namespace wasm { // not have side effects (as they would run unconditionally) static bool canTurnIfIntoBrIf(Expression* ifCondition, Expression* brValue, - PassOptions& options) { + PassOptions& options, + FeatureSet features) { // if the if isn't even reached, this is all dead code anyhow if (ifCondition->type == Type::unreachable) { return false; @@ -43,11 +44,11 @@ static bool canTurnIfIntoBrIf(Expression* ifCondition, if (!brValue) { return true; } - EffectAnalyzer value(options, brValue); + EffectAnalyzer value(options, features, brValue); if (value.hasSideEffects()) { return false; } - return !EffectAnalyzer(options, ifCondition).invalidates(value); + return !EffectAnalyzer(options, features, ifCondition).invalidates(value); } // Check if it is not worth it to run code unconditionally. This @@ -302,11 +303,13 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { } void visitIf(If* curr) { + FeatureSet features = getModule()->features; if (!curr->ifFalse) { // if without an else. try to reduce // if (condition) br => br_if (condition) if (Break* br = curr->ifTrue->dynCast<Break>()) { - if (canTurnIfIntoBrIf(curr->condition, br->value, getPassOptions())) { + if (canTurnIfIntoBrIf( + curr->condition, br->value, getPassOptions(), features)) { if (!br->condition) { br->condition = curr->condition; } else { @@ -327,7 +330,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { } // Of course we can't do this if the br's condition has side // effects, as we would then execute those unconditionally. - if (EffectAnalyzer(getPassOptions(), br->condition) + if (EffectAnalyzer(getPassOptions(), features, br->condition) .hasSideEffects()) { return; } @@ -521,7 +524,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { return false; } // if there is control flow, we must stop looking - if (EffectAnalyzer(getPassOptions(), curr).branches) { + if (EffectAnalyzer(getPassOptions(), getModule()->features, curr) + .transfersControlFlow()) { return false; } if (i == 0) { @@ -744,6 +748,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { // the if is dead // * note that we do this at the end, because un-conditionalizing can // interfere with optimizeLoop()ing. + FeatureSet features = getModule()->features; auto& list = curr->list; for (Index i = 0; i < list.size(); i++) { auto* iff = list[i]->dynCast<If>(); @@ -755,7 +760,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { auto* ifTrueBreak = iff->ifTrue->dynCast<Break>(); if (ifTrueBreak && !ifTrueBreak->condition && canTurnIfIntoBrIf( - iff->condition, ifTrueBreak->value, passOptions)) { + iff->condition, ifTrueBreak->value, passOptions, features)) { // we are an if-else where the ifTrue is a break without a // condition, so we can do this ifTrueBreak->condition = iff->condition; @@ -768,7 +773,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { auto* ifFalseBreak = iff->ifFalse->dynCast<Break>(); if (ifFalseBreak && !ifFalseBreak->condition && canTurnIfIntoBrIf( - iff->condition, ifFalseBreak->value, passOptions)) { + iff->condition, ifFalseBreak->value, passOptions, features)) { ifFalseBreak->condition = Builder(*getModule()).makeUnary(EqZInt32, iff->condition); ifFalseBreak->finalize(); @@ -797,7 +802,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { if (shrink && br2->type != Type::unreachable) { // Join adjacent br_ifs to the same target, making one br_if // with a "selectified" condition that executes both. - if (!EffectAnalyzer(passOptions, br2->condition) + if (!EffectAnalyzer(passOptions, features, br2->condition) .hasSideEffects()) { // it's ok to execute them both, do it Builder builder(*getModule()); @@ -888,8 +893,10 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { // If the items we move around have side effects, we can't do // this. // TODO: we could use a select, in some cases..? - if (!EffectAnalyzer(passOptions, br->value).hasSideEffects() && - !EffectAnalyzer(passOptions, br->condition) + FeatureSet features = getModule()->features; + if (!EffectAnalyzer(passOptions, features, br->value) + .hasSideEffects() && + !EffectAnalyzer(passOptions, features, br->condition) .hasSideEffects()) { ExpressionManipulator::nop(list[0]); Builder builder(*getModule()); @@ -923,11 +930,12 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { return nullptr; } // Check if side effects allow this. - EffectAnalyzer condition(passOptions, iff->condition); + FeatureSet features = getModule()->features; + EffectAnalyzer condition(passOptions, features, iff->condition); if (!condition.hasSideEffects()) { - EffectAnalyzer ifTrue(passOptions, iff->ifTrue); + EffectAnalyzer ifTrue(passOptions, features, iff->ifTrue); if (!ifTrue.hasSideEffects()) { - EffectAnalyzer ifFalse(passOptions, iff->ifFalse); + EffectAnalyzer ifFalse(passOptions, features, iff->ifFalse); if (!ifFalse.hasSideEffects()) { return Builder(*getModule()) .makeSelect(iff->condition, iff->ifTrue, iff->ifFalse); @@ -1184,7 +1192,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { } // if the condition has side effects, we can't replace many // appearances of it with a single one - if (EffectAnalyzer(passOptions, conditionValue).hasSideEffects()) { + if (EffectAnalyzer(passOptions, getModule()->features, conditionValue) + .hasSideEffects()) { start++; continue; } diff --git a/src/passes/SimplifyGlobals.cpp b/src/passes/SimplifyGlobals.cpp index b18f726ed..aa211b86b 100644 --- a/src/passes/SimplifyGlobals.cpp +++ b/src/passes/SimplifyGlobals.cpp @@ -133,7 +133,7 @@ struct ConstantGlobalApplier return; } // Otherwise, invalidate if we need to. - EffectAnalyzer effects(getPassOptions()); + EffectAnalyzer effects(getPassOptions(), getModule()->features); effects.visit(curr); assert(effects.globalsWritten.empty()); // handled above if (effects.calls) { diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp index f7558aa83..23ab1bc92 100644 --- a/src/passes/SimplifyLocals.cpp +++ b/src/passes/SimplifyLocals.cpp @@ -78,8 +78,10 @@ struct SimplifyLocals Expression** item; EffectAnalyzer effects; - SinkableInfo(Expression** item, PassOptions& passOptions) - : item(item), effects(passOptions, *item) {} + SinkableInfo(Expression** item, + PassOptions& passOptions, + FeatureSet features) + : item(item), effects(passOptions, features, *item) {} }; // a list of sinkables in a linear execution trace @@ -298,7 +300,7 @@ struct SimplifyLocals Expression** currp) { Expression* curr = *currp; - EffectAnalyzer effects(self->getPassOptions()); + EffectAnalyzer effects(self->getPassOptions(), self->getModule()->features); if (effects.checkPre(curr)) { self->checkInvalidations(effects); } @@ -384,7 +386,8 @@ struct SimplifyLocals } } - EffectAnalyzer effects(self->getPassOptions()); + FeatureSet features = self->getModule()->features; + EffectAnalyzer effects(self->getPassOptions(), features); if (effects.checkPost(original)) { self->checkInvalidations(effects); } @@ -392,8 +395,8 @@ struct SimplifyLocals if (set && self->canSink(set)) { Index index = set->index; assert(self->sinkables.count(index) == 0); - self->sinkables.emplace( - std::make_pair(index, SinkableInfo(currp, self->getPassOptions()))); + self->sinkables.emplace(std::make_pair( + index, SinkableInfo(currp, self->getPassOptions(), features))); } if (!allowNesting) { @@ -504,6 +507,7 @@ struct SimplifyLocals // ) // ) // so we must check for that. + FeatureSet features = this->getModule()->features; for (size_t j = 0; j < breaks.size(); j++) { // move break local.set's value to the break auto* breakLocalSetPointer = breaks[j].sinkables.at(sharedIndex).item; @@ -520,8 +524,9 @@ struct SimplifyLocals // itself, there is any risk Nop nop; *breakLocalSetPointer = &nop; - EffectAnalyzer condition(this->getPassOptions(), br->condition); - EffectAnalyzer value(this->getPassOptions(), set); + EffectAnalyzer condition( + this->getPassOptions(), features, br->condition); + EffectAnalyzer value(this->getPassOptions(), features, set); *breakLocalSetPointer = set; if (condition.invalidates(value)) { // indeed, we can't do this, stop @@ -994,7 +999,9 @@ struct SimplifyLocals // We may have already had a local with no uses, or we may have just // gotten there thanks to the EquivalentOptimizer. If there are such // locals, remove all their sets. - UnneededSetRemover setRemover(getCounter, func, this->getPassOptions()); + UnneededSetRemover setRemover( + getCounter, func, this->getPassOptions(), this->getModule()->features); + setRemover.setModule(this->getModule()); return eqOpter.anotherCycle || setRemover.removed; } diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index a222b0159..f0bdd7722 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -54,6 +54,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { // * The result may be used or unused. // * The type may or may not matter (a drop can drop anything, for example). Expression* optimize(Expression* curr, bool resultUsed, bool typeMatters) { + FeatureSet features = getModule()->features; auto type = curr->type; // An unreachable node must not be changed. if (type == Type::unreachable) { @@ -97,8 +98,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { // side effects (the load itself may trap, if we are not ignoring such // things) auto* load = curr->cast<Load>(); - if (!resultUsed && - !EffectAnalyzer(getPassOptions(), curr).hasSideEffects()) { + if (!resultUsed && !EffectAnalyzer(getPassOptions(), features, curr) + .hasSideEffects()) { if (!typeMatters || load->ptr->type == type) { return load->ptr; } @@ -124,12 +125,12 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { // side effects, as well as the node itself, as some unaries and // binaries have implicit traps if (auto* unary = curr->dynCast<Unary>()) { - EffectAnalyzer tester(getPassOptions()); + EffectAnalyzer tester(getPassOptions(), features); tester.visitUnary(unary); if (tester.hasSideEffects()) { return curr; } - if (EffectAnalyzer(getPassOptions(), unary->value) + if (EffectAnalyzer(getPassOptions(), features, unary->value) .hasSideEffects()) { curr = unary->value; continue; @@ -137,14 +138,14 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { return nullptr; } } else if (auto* binary = curr->dynCast<Binary>()) { - EffectAnalyzer tester(getPassOptions()); + EffectAnalyzer tester(getPassOptions(), features); tester.visitBinary(binary); if (tester.hasSideEffects()) { return curr; } - if (EffectAnalyzer(getPassOptions(), binary->left) + if (EffectAnalyzer(getPassOptions(), features, binary->left) .hasSideEffects()) { - if (EffectAnalyzer(getPassOptions(), binary->right) + if (EffectAnalyzer(getPassOptions(), features, binary->right) .hasSideEffects()) { return curr; // leave them } else { @@ -152,7 +153,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { continue; } } else { - if (EffectAnalyzer(getPassOptions(), binary->right) + if (EffectAnalyzer(getPassOptions(), features, binary->right) .hasSideEffects()) { curr = binary->right; continue; @@ -164,13 +165,14 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { // TODO: if two have side effects, we could replace the select with // say an add? auto* select = curr->cast<Select>(); - if (EffectAnalyzer(getPassOptions(), select->ifTrue) + if (EffectAnalyzer(getPassOptions(), features, select->ifTrue) .hasSideEffects()) { - if (EffectAnalyzer(getPassOptions(), select->ifFalse) + if (EffectAnalyzer(getPassOptions(), features, select->ifFalse) .hasSideEffects()) { return curr; // leave them } else { - if (EffectAnalyzer(getPassOptions(), select->condition) + if (EffectAnalyzer( + getPassOptions(), features, select->condition) .hasSideEffects()) { return curr; // leave them } else { @@ -179,9 +181,10 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { } } } else { - if (EffectAnalyzer(getPassOptions(), select->ifFalse) + if (EffectAnalyzer(getPassOptions(), features, select->ifFalse) .hasSideEffects()) { - if (EffectAnalyzer(getPassOptions(), select->condition) + if (EffectAnalyzer( + getPassOptions(), features, select->condition) .hasSideEffects()) { return curr; // leave them } else { @@ -189,7 +192,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { continue; } } else { - if (EffectAnalyzer(getPassOptions(), select->condition) + if (EffectAnalyzer( + getPassOptions(), features, select->condition) .hasSideEffects()) { curr = select->condition; continue; @@ -419,7 +423,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { ExpressionManipulator::nop(curr->body); } if (curr->sig.results == Type::none && - !EffectAnalyzer(getPassOptions(), curr->body).hasSideEffects()) { + !EffectAnalyzer(getPassOptions(), getModule()->features, curr->body) + .hasSideEffects()) { ExpressionManipulator::nop(curr->body); } } diff --git a/src/wasm2js.h b/src/wasm2js.h index 55759c959..802765b1a 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -1128,11 +1128,12 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, // If the target has effects that interact with the operands, we must // reorder it to the start. bool mustReorder = false; - EffectAnalyzer targetEffects(parent->options, curr->target); + EffectAnalyzer targetEffects( + parent->options, module->features, curr->target); if (targetEffects.hasAnything()) { for (auto* operand : curr->operands) { if (targetEffects.invalidates( - EffectAnalyzer(parent->options, operand))) { + EffectAnalyzer(parent->options, module->features, operand))) { mustReorder = true; break; } @@ -1720,9 +1721,12 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, // reorder it to the start. We must also use locals if the values have // side effects, as a JS conditional does not visit both sides. bool useLocals = false; - EffectAnalyzer conditionEffects(parent->options, curr->condition); - EffectAnalyzer ifTrueEffects(parent->options, curr->ifTrue); - EffectAnalyzer ifFalseEffects(parent->options, curr->ifFalse); + EffectAnalyzer conditionEffects( + parent->options, module->features, curr->condition); + EffectAnalyzer ifTrueEffects( + parent->options, module->features, curr->ifTrue); + EffectAnalyzer ifFalseEffects( + parent->options, module->features, curr->ifFalse); if (conditionEffects.invalidates(ifTrueEffects) || conditionEffects.invalidates(ifFalseEffects) || ifTrueEffects.hasSideEffects() || ifFalseEffects.hasSideEffects()) { |