summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp11
-rw-r--r--src/binaryen-c.h5
-rw-r--r--src/ir/block-utils.h6
-rw-r--r--src/ir/effects.h93
-rw-r--r--src/ir/local-utils.h18
-rw-r--r--src/js/binaryen.js-post.js5
-rw-r--r--src/passes/CodeFolding.cpp4
-rw-r--r--src/passes/CodePushing.cpp24
-rw-r--r--src/passes/DeadArgumentElimination.cpp3
-rw-r--r--src/passes/LocalCSE.cpp18
-rw-r--r--src/passes/LoopInvariantCodeMotion.cpp9
-rw-r--r--src/passes/MergeBlocks.cpp27
-rw-r--r--src/passes/OptimizeAddedConstants.cpp3
-rw-r--r--src/passes/OptimizeInstructions.cpp62
-rw-r--r--src/passes/RemoveUnusedBrs.cpp39
-rw-r--r--src/passes/SimplifyGlobals.cpp2
-rw-r--r--src/passes/SimplifyLocals.cpp25
-rw-r--r--src/passes/Vacuum.cpp35
-rw-r--r--src/wasm2js.h14
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()) {