diff options
-rw-r--r-- | src/passes/Precompute.cpp | 43 | ||||
-rw-r--r-- | test/passes/precompute-propagate_all-features.txt | 7 | ||||
-rw-r--r-- | test/passes/precompute-propagate_all-features.wast | 7 |
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) ) |