summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast_utils.h17
-rw-r--r--src/passes/SimplifyLocals.cpp27
-rw-r--r--test/passes/simplify-locals.txt12
-rw-r--r--test/passes/simplify-locals.wast8
4 files changed, 56 insertions, 8 deletions
diff --git a/src/ast_utils.h b/src/ast_utils.h
index bf42d10e1..5ab427178 100644
--- a/src/ast_utils.h
+++ b/src/ast_utils.h
@@ -53,6 +53,7 @@ struct EffectAnalyzer : public WasmWalker<EffectAnalyzer> {
bool accessesLocal() { return readsLocal || writesLocal; }
bool accessesMemory() { return calls || readsMemory || writesMemory; }
bool hasSideEffects() { return calls || writesLocal || writesMemory; }
+ bool hasAnything() { return branches || calls || readsLocal || writesLocal || readsMemory || writesMemory; }
// 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(EffectAnalyzer& other) {
@@ -61,7 +62,23 @@ struct EffectAnalyzer : public WasmWalker<EffectAnalyzer> {
|| (accessesMemory() && (other.writesMemory || other.calls)) || (accessesLocal() && other.writesLocal);
}
+ // the checks above happen after the node's children were processed, in the order of execution
+ // we must also check for control flow that happens before the children, i.e., loops
+ bool checkPre(Expression* curr) {
+ if (curr->is<Loop>()) {
+ branches = true;
+ return true;
+ }
+ return false;
+ }
+
+ bool checkPost(Expression* curr) {
+ visit(curr);
+ return hasAnything();
+ }
+
void visitBlock(Block *curr) { branches = true; }
+ void visitLoop(Loop *curr) { branches = true; }
void visitIf(If *curr) { branches = true; }
void visitBreak(Break *curr) { branches = true; }
void visitSwitch(Switch *curr) { branches = true; }
diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp
index a0f843bbd..cd6cb2ca7 100644
--- a/src/passes/SimplifyLocals.cpp
+++ b/src/passes/SimplifyLocals.cpp
@@ -78,14 +78,7 @@ struct SimplifyLocals : public WalkerPass<FastExecutionWalker<SimplifyLocals>> {
}
}
- void walk(Expression*& curr) override {
- if (!curr) return;
-
- FastExecutionWalker::walk(curr);
-
- // invalidations TODO: this is O(n^2) in sinkables
- EffectAnalyzer effects;
- effects.visit(curr);
+ void checkInvalidations(EffectAnalyzer& effects) {
std::vector<Name> invalidated;
for (auto& sinkable : sinkables) {
if (effects.invalidates(sinkable.second.effects)) {
@@ -96,6 +89,24 @@ struct SimplifyLocals : public WalkerPass<FastExecutionWalker<SimplifyLocals>> {
sinkables.erase(name);
}
}
+
+ void walk(Expression*& curr) override {
+ if (!curr) return;
+
+ EffectAnalyzer effects;
+
+ if (effects.checkPre(curr)) {
+ checkInvalidations(effects);
+ }
+
+ FastExecutionWalker::walk(curr);
+
+ // TODO: this is O(n^2) in sinkables
+
+ if (effects.checkPost(curr)) {
+ checkInvalidations(effects);
+ }
+ }
};
static RegisterPass<SimplifyLocals> registerPass("simplify-locals", "miscellaneous locals-related optimizations");
diff --git a/test/passes/simplify-locals.txt b/test/passes/simplify-locals.txt
index 88c00dbe9..880639f79 100644
--- a/test/passes/simplify-locals.txt
+++ b/test/passes/simplify-locals.txt
@@ -240,5 +240,17 @@
)
(get_local $a)
)
+ (block $loopey
+ (set_local $a
+ (i32.const 1337)
+ )
+ (loop $loop-out4 $loop-in5
+ (get_local $a)
+ (set_local $a
+ (i32.const 9876)
+ )
+ )
+ (get_local $a)
+ )
)
)
diff --git a/test/passes/simplify-locals.wast b/test/passes/simplify-locals.wast
index 5b1db2d12..db17c5533 100644
--- a/test/passes/simplify-locals.wast
+++ b/test/passes/simplify-locals.wast
@@ -136,6 +136,14 @@
)
(get_local $a)
)
+ (block $loopey
+ (set_local $a (i32.const 1337))
+ (loop
+ (get_local $a)
+ (set_local $a (i32.const 9876))
+ )
+ (get_local $a)
+ )
)
)