summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/Precompute.cpp43
-rw-r--r--test/passes/precompute-propagate_all-features.txt7
-rw-r--r--test/passes/precompute-propagate_all-features.wast7
3 files changed, 36 insertions, 21 deletions
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp
index 980fb17bd..4209ffbe2 100644
--- a/src/passes/Precompute.cpp
+++ b/src/passes/Precompute.cpp
@@ -114,24 +114,27 @@ struct Precompute
GetValues getValues;
- bool worked;
-
void doWalkFunction(Function* func) {
- // if propagating, we may need multiple rounds: each propagation can
- // lead to the main walk removing code, which might open up more
- // propagation opportunities
- do {
- getValues.clear();
- // with extra effort, we can utilize the get-set graph to precompute
- // things that use locals that are known to be constant. otherwise,
- // we just look at what is immediately before us
- if (propagate) {
- optimizeLocals(func);
- }
- // do the main walk over everything
- worked = false;
+ // Walk the function and precompute things.
+ super::doWalkFunction(func);
+ if (!propagate) {
+ return;
+ }
+ // When propagating, we can utilize the graph of local operations to
+ // precompute the values from a local.set to a local.get. This populates
+ // getValues which is then used by a subsequent walk that applies those
+ // values.
+ bool propagated = propagateLocals(func);
+ if (propagated) {
+ // We found constants to propagate and entered them in getValues. Do
+ // another walk to apply them and perhaps other optimizations that are
+ // unlocked.
super::doWalkFunction(func);
- } while (propagate && worked);
+ }
+ // Note that in principle even more cycles could find further work here, in
+ // very rare cases. To avoid constructing a LocalGraph again just for that
+ // unlikely chance, we leave such things for later runs of this pass and for
+ // --converge.
}
template<typename T> void reuseConstantNode(T* curr, Flow flow) {
@@ -223,7 +226,6 @@ struct Precompute
// this was precomputed
if (flow.values.isConcrete()) {
replaceCurrent(flow.getConstExpression(*getModule()));
- worked = true;
} else {
ExpressionManipulator::nop(curr);
}
@@ -273,7 +275,8 @@ private:
}
// Propagates values around. Returns whether we propagated.
- void optimizeLocals(Function* func) {
+ bool propagateLocals(Function* func) {
+ bool propagated = false;
// using the graph of get-set interactions, do a constant-propagation type
// operation: note which sets are assigned locals, then see if that lets us
// compute other sets as locals (since some of the gets they read may be
@@ -390,9 +393,11 @@ private:
for (auto* set : localGraph.getInfluences[get]) {
work.push(set);
}
+ propagated = true;
}
}
}
+ return propagated;
}
bool canEmitConstantFor(const Literals& values) {
@@ -421,7 +426,7 @@ private:
}
// All other reference types cannot be precomputed. Even an immutable GC
// reference is not currently something this pass can handle, as it will
- // evaluate and reevaluate code multiple times in e.g. optimizeLocals, see
+ // evaluate and reevaluate code multiple times in e.g. propagateLocals, see
// the comment above.
if (type.isRef()) {
return false;
diff --git a/test/passes/precompute-propagate_all-features.txt b/test/passes/precompute-propagate_all-features.txt
index 09f2bc42d..6001d54ba 100644
--- a/test/passes/precompute-propagate_all-features.txt
+++ b/test/passes/precompute-propagate_all-features.txt
@@ -240,7 +240,12 @@
(func $multipass (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
(nop)
- (nop)
+ (if
+ (local.get $3)
+ (local.set $2
+ (i32.const 0)
+ )
+ )
(local.get $2)
)
(func $through-fallthrough (param $x i32) (param $y i32) (result i32)
diff --git a/test/passes/precompute-propagate_all-features.wast b/test/passes/precompute-propagate_all-features.wast
index bad12eac8..59a06a860 100644
--- a/test/passes/precompute-propagate_all-features.wast
+++ b/test/passes/precompute-propagate_all-features.wast
@@ -141,7 +141,12 @@
(func $multipass (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
(if
- (local.get $3)
+ (local.get $3) ;; this will be precomputed to 0. after that, the if will be
+ ;; precomputed to not exist at all. removing the set in the
+ ;; if body then allows us to optimize the value of $3 in the
+ ;; if lower down, but we do not do an additional cycle of
+ ;; this pass automatically as such things are fairly rare,
+ ;; so that opportunity remains unoptimized in this test.
(local.set $3 ;; this set is completely removed, allowing later opts
(i32.const 24)
)