diff options
author | Alon Zakai <azakai@google.com> | 2022-11-01 10:08:04 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-01 17:08:04 +0000 |
commit | 288a12645d060d8f2ec97b13b5795cd53a8a7811 (patch) | |
tree | 7f4ea84aaee76796978938525e52a56325edad6b | |
parent | 5e0ab66800de5d376429fcd281bd4cd1e41d8ed5 (diff) | |
download | binaryen-288a12645d060d8f2ec97b13b5795cd53a8a7811.tar.gz binaryen-288a12645d060d8f2ec97b13b5795cd53a8a7811.tar.bz2 binaryen-288a12645d060d8f2ec97b13b5795cd53a8a7811.zip |
CodePushing: Push into If arms (#5191)
Previously the pass only pushed past an if or a br_if. This does the same but into an
if arm. On Wasm GC for example this can perform allocation sinking:
function foo() {
x = new A();
if (..) {
use(x);
}
}
=>
function foo() {
if (..) {
x = new A(); // this moved
use(x);
}
}
The allocation won't happen if we never enter the if. This helps wasm MVP too,
and in fact some existing tests benefit.
-rw-r--r-- | src/passes/CodePushing.cpp | 223 | ||||
-rw-r--r-- | test/lit/passes/code-pushing_into_if.wast | 651 | ||||
-rw-r--r-- | test/lit/passes/inlining-optimizing_optimize-level=3.wast | 148 |
3 files changed, 923 insertions, 99 deletions
diff --git a/src/passes/CodePushing.cpp b/src/passes/CodePushing.cpp index 4adbb3423..1ab037b12 100644 --- a/src/passes/CodePushing.cpp +++ b/src/passes/CodePushing.cpp @@ -20,6 +20,7 @@ // #include <ir/effects.h> +#include <ir/manipulation.h> #include <pass.h> #include <wasm-builder.h> #include <wasm.h> @@ -95,21 +96,27 @@ public: // 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. - // we never need to push past a final element, as we couldn't be used after - // it. - Index relevant = list.size() - 1; const Index nothing = -1; Index i = 0; Index firstPushable = nothing; - while (i < relevant) { + while (i < list.size()) { if (firstPushable == nothing && isPushable(list[i])) { firstPushable = i; i++; continue; } if (firstPushable != nothing && isPushPoint(list[i])) { - // optimize this segment, and proceed from where it tells us - i = optimizeSegment(firstPushable, i); + // Optimize this segment, and proceed from where it tells us. First + // optimize things into the if, if possible, which does not move the + // push point. Then move things past the push point (which has the + // relative effect of moving the push point backwards as other things + // move forward). + optimizeIntoIf(firstPushable, i); + // We never need to push past a final element, as we couldn't be used + // after it. + if (i < list.size() - 1) { + i = optimizeSegment(firstPushable, i); + } firstPushable = nothing; continue; } @@ -196,16 +203,7 @@ private: while (1) { auto* pushable = isPushable(list[i]); 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, module, pushable)) - .first; - } - auto& effects = iter->second; + const auto& effects = getPushableEffects(pushable); if (cumulativeEffects.invalidates(effects)) { // we can't push this, so further pushables must pass it cumulativeEffects.mergeIn(effects); @@ -213,14 +211,14 @@ private: // we can push this, great! toPush.push_back(pushable); } - if (i == firstPushable) { - // no point in looking further - break; - } } else { // something that can't be pushed, so it might block further pushing cumulativeEffects.walk(list[i]); } + if (i == firstPushable) { + // no point in looking further + break; + } assert(i > 0); i--; } @@ -252,6 +250,184 @@ private: return pushPoint - total + 1; } + // Similar to optimizeSegment, but for the case where the push point is an if, + // and we try to push into the if's arms, doing things like this: + // + // x = op(); + // if (..) { + // .. + // } + // => + // if (..) { + // x = op(); // this moved + // .. + // } + // + // This does not move the push point, so it does not have a return value, + // unlike optimizeSegment. + void optimizeIntoIf(Index firstPushable, Index pushPoint) { + assert(firstPushable != Index(-1) && pushPoint != Index(-1) && + firstPushable < pushPoint); + + auto* iff = list[pushPoint]->dynCast<If>(); + if (!iff) { + return; + } + + // Everything that matters if you want to be pushed past the pushPoint. This + // begins with the if condition's effects, as we must always push past + // those. Later, we will add to this when we need to. + EffectAnalyzer cumulativeEffects(passOptions, module, iff->condition); + + // See optimizeSegment for why we can ignore control flow transfers here. + cumulativeEffects.ignoreControlFlowTransfers(); + + // Find the effects of the arms, which will affect what can be pushed. + EffectAnalyzer ifTrueEffects(passOptions, module, iff->ifTrue); + EffectAnalyzer ifFalseEffects(passOptions, module); + if (iff->ifFalse) { + ifFalseEffects.walk(iff->ifFalse); + } + + // We need to know which locals are used after the if, as that can determine + // if we can push or not. + EffectAnalyzer postIfEffects(passOptions, module); + for (Index i = pushPoint + 1; i < list.size(); i++) { + postIfEffects.walk(list[pushPoint]); + } + + // Start at the instruction right before the push point, and go back from + // there: + // + // x = op(); + // y = op(); + // if (..) { + // .. + // } + // + // Here we will try to push y first, and then x. Note that if we push y + // then we can immediately try to push x after it, as it will remain in + // order with x if we do. If we do *not* push y we can still try to push x + // but we must move it past y, which means we need to check for interference + // between them (which we do by adding y's effects to cumulativeEffects). + // + // Decrement at the top of the loop for simplicity, so start with i at one + // past the first thing we can push (which is right before the push point). + Index i = pushPoint; + while (1) { + if (i == firstPushable) { + // We just finished processing the first thing that could be pushed; + // stop. + break; + } + assert(i > 0); + i--; + auto* pushable = isPushable(list[i]); + if (!pushable) { + // Something that is staying where it is, so anything we push later must + // move past it. Note the effects and continue. + cumulativeEffects.walk(list[i]); + continue; + } + + auto index = pushable->index; + + const auto& effects = getPushableEffects(pushable); + + if (cumulativeEffects.invalidates(effects)) { + // This can't be moved forward. Add it to the things that are not + // moving. + cumulativeEffects.walk(list[i]); + continue; + } + + // We only try to push into an arm if the local is used there. If the + // local is not used in either arm then we'll want to push it past the + // entire if, which is what optimizeSegment handles. + // + // We can push into the if-true arm if the local cannot be used if we go + // through the other arm: + // + // x = op(); + // if (..) { + // // we would like to move "x = op()" to here + // .. + // } else { + // use(x); + // } + // use(x); + // + // Either of those use(x)s would stop us from moving to if-true arm. + // + // One specific case we handle is if there is a use after the if but the + // arm we don't push into is unreachable. In that case we only get to the + // later code after going through the reachable arm, which is ok to push + // into: + // + // x = op(); + // if (..) { + // // We'll push "x = op()" to here. + // use(x); + // } else { + // return; + // } + // use(x); + auto maybePushInto = [&](Expression*& arm, + const Expression* otherArm, + EffectAnalyzer& armEffects, + const EffectAnalyzer& otherArmEffects) { + if (!arm || !armEffects.localsRead.count(index) || + otherArmEffects.localsRead.count(index)) { + // No arm, or this arm has no read of the index, or the other arm + // reads the index. + return false; + } + if (postIfEffects.localsRead.count(index) && + (!otherArm || otherArm->type != Type::unreachable)) { + // The local is read later, which is bad, and there is no unreachable + // in the other arm which as mentioned above is the only thing that + // could have made it work out for us. + return false; + } + + // We can do it! Push into one of the if's arms, and put a nop where it + // used to be. + Builder builder(module); + auto* block = builder.blockify(arm); + arm = block; + // TODO: this is quadratic in the number of pushed things + ExpressionManipulator::spliceIntoBlock(block, 0, pushable); + list[i] = builder.makeNop(); + + // The code we pushed adds to the effects in that arm. + armEffects.walk(pushable); + + // TODO: After pushing we could recurse and run both this function and + // optimizeSegment in that location. For now, leave that to later + // cycles of the optimizer, as this case seems rairly rare. + return true; + }; + + if (!maybePushInto( + iff->ifTrue, iff->ifFalse, ifTrueEffects, ifFalseEffects) && + !maybePushInto( + iff->ifFalse, iff->ifTrue, ifFalseEffects, ifTrueEffects)) { + // We didn't push this anywhere, so further pushables must pass it. + cumulativeEffects.mergeIn(effects); + } + } + } + + const EffectAnalyzer& getPushableEffects(LocalSet* pushable) { + auto iter = pushableEffects.find(pushable); + if (iter == pushableEffects.end()) { + iter = + pushableEffects.try_emplace(pushable, passOptions, module, pushable) + .first; + } + return iter->second; + } + // Pushables may need to be scanned more than once, so cache their effects. std::unordered_map<LocalSet*, EffectAnalyzer> pushableEffects; }; @@ -286,10 +462,9 @@ struct CodePushing : public WalkerPass<PostWalker<CodePushing>> { void visitLocalGet(LocalGet* curr) { numGetsSoFar[curr->index]++; } void visitBlock(Block* curr) { - // Pushing code only makes sense if we are size 3 or above: we need - // one element to push, an element to push it past, and an element to use - // what we pushed. - if (curr->list.size() < 3) { + // Pushing code only makes sense if we are size 2 or above: we need one + // element to push and an element to push it into, at minimum. + if (curr->list.size() < 2) { return; } // At this point in the postorder traversal we have gone through all our diff --git a/test/lit/passes/code-pushing_into_if.wast b/test/lit/passes/code-pushing_into_if.wast new file mode 100644 index 000000000..e856f446c --- /dev/null +++ b/test/lit/passes/code-pushing_into_if.wast @@ -0,0 +1,651 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --code-pushing -S -o - | filecheck %s + +(module + ;; CHECK: (func $if-nop (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-nop (param $p i32) + (local $x i32) + ;; The set local is not used in any if arm; do nothing. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (nop) + ) + ) + + ;; CHECK: (func $if-nop-nop (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-nop-nop (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (nop) + (nop) ;; add a nop here compared to the last testcase (no output change) + ) + ) + + ;; CHECK: (func $if-use (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use (param $p i32) + (local $x i32) + ;; The set local is used in one arm and nowhere else; push it there. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-use-nop (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-nop (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + (nop) ;; add a nop here compared to the last testcase (no output change) + ) + ) + + ;; CHECK: (func $if-else-use (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-else-use (param $p i32) + (local $x i32) + ;; The set local is used in one arm and nowhere else; push it there. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (nop) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $unpushed-interference (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $unpushed-interference (param $p i32) + (local $x i32) + (local $y i32) + (local.set $x (i32.const 1)) + ;; This set is not pushed (as it is not used in the if) and it will then + ;; prevent the previous set of $x from being pushed, since we can't push a + ;; set of $x past a get of it. + (local.set $y (local.get $x)) + (if + (local.get $p) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-use-use (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-use (param $p i32) + (local $x i32) + ;; The set local is used in both arms, so we can't do anything. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-use-after (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-after (param $p i32) + (local $x i32) + ;; The use after the if prevents optimization. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $if-use-after-nop (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-after-nop (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + (nop) ;; add a nop here compared to the last testcase (no output change) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $if-else-use-after (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-else-use-after (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (nop) + (drop (local.get $x)) ;; now the use in the if is in the else arm + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $if-use-after-unreachable (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-after-unreachable (param $p i32) + (local $x i32) + ;; A use after the if is ok as the other arm is unreachable. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + (return) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $if-use-after-unreachable-else (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-after-unreachable-else (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (return) ;; as above, but with arms flipped + (drop (local.get $x)) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $optimize-many (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local $z i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $z + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $z) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-many (param $p i32) + (local $x i32) + (local $y i32) + (local $z i32) + ;; Multiple things we can push, to various arms. + (local.set $x (i32.const 1)) + (local.set $y (i32.const 2)) + (local.set $z (i32.const 3)) + (if + (local.get $p) + (block + (drop (local.get $x)) + (drop (local.get $z)) + ) + (drop (local.get $y)) + ) + ) + + ;; CHECK: (func $past-other (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-other (param $p i32) + (local $x i32) + (local $t i32) + ;; We can push this past the drop after it. + (local.set $x (local.get $t)) + (drop (i32.const 2)) + (if + (local.get $p) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $past-other-no (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $t + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-other-no (param $p i32) + (local $x i32) + (local $t i32) + ;; We cannot push this due to the tee, which interferes with us. + (local.set $x (local.get $t)) + (drop (local.tee $t (i32.const 2))) + (if + (local.get $p) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $past-condition-no (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.tee $t + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-condition-no (param $p i32) + (local $x i32) + (local $t i32) + ;; We cannot push this due to the tee in the if condition. + (local.set $x (local.get $t)) + (if + (local.tee $t (local.get $p)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $past-condition-no-2 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-condition-no-2 + (local $x i32) + (local $t i32) + ;; We cannot push this due to the read of $x in the if condition. + (local.set $x (local.get $t)) + (if + (local.get $x) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $past-condition-no-3 (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-condition-no-3 (param $p i32) + (local $x i32) + (local $t i32) + ;; We cannot push this due to the write of $x in the if condition. + (local.set $x (local.get $t)) + (if + (local.tee $x (local.get $p)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-condition-return (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-condition-return (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (block (result i32) + (return) ;; This return does not prevent us from optimizing; if it + ;; happens then we don't need the local.set to execute + ;; anyhow. + (local.get $p) + ) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-condition-break-used (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block $out + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (br $out) + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-condition-break-used (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + ;; As above, but the return is replaced with a break. The break goes to a + ;; location with a use of the local, which prevents optimization. + (block $out + (if + (block (result i32) + (br $out) + (local.get $p) + ) + (drop (local.get $x)) + ) + (return) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $one-push-prevents-another (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $one-push-prevents-another (param $p i32) + (local $x i32) + (local $y i32) + ;; We will push $y into one arm, and as a result both arms will have a get + ;; of $x, which prevents pushing $x. + (local.set $x (i32.const 1)) + (local.set $y (local.get $x)) + (if + (local.get $p) + (drop (local.get $x)) + (drop (local.get $y)) + ) + ) + + ;; CHECK: (func $one-push-prevents-another-flipped (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $one-push-prevents-another-flipped (param $p i32) + (local $x i32) + (local $y i32) + ;; As above but with if arms flipped. The result should be similar, with + ;; only $y pushed. + (local.set $x (i32.const 1)) + (local.set $y (local.get $x)) + (if + (local.get $p) + (drop (local.get $y)) + (drop (local.get $x)) + ) + ) +) diff --git a/test/lit/passes/inlining-optimizing_optimize-level=3.wast b/test/lit/passes/inlining-optimizing_optimize-level=3.wast index 4fa8e1936..a33f3bf2e 100644 --- a/test/lit/passes/inlining-optimizing_optimize-level=3.wast +++ b/test/lit/passes/inlining-optimizing_optimize-level=3.wast @@ -4218,16 +4218,16 @@ ;; CHECK-NEXT: (block $label$break$L1 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.ge_s - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (i32.gt_s ;; CHECK-NEXT: (local.get $10) ;; CHECK-NEXT: (i32.sub ;; CHECK-NEXT: (i32.const 2147483647) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) @@ -4239,7 +4239,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $10) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -4617,7 +4617,7 @@ ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L1) @@ -4757,7 +4757,7 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L1) @@ -4943,7 +4943,7 @@ ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L1) @@ -5010,7 +5010,7 @@ ;; CHECK-NEXT: (i32.const 57) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L1) @@ -5067,13 +5067,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (i32.ge_s ;; CHECK-NEXT: (local.get $19) ;; CHECK-NEXT: (i32.const 0) @@ -5090,9 +5090,9 @@ ;; CHECK-NEXT: (i32.const 19) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L1) @@ -5101,7 +5101,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (if - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (i32.store ;; CHECK-NEXT: (i32.add @@ -5144,7 +5144,7 @@ ;; CHECK-NEXT: (local.get $29) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L1) @@ -5273,7 +5273,7 @@ ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (local.get $10) @@ -5287,7 +5287,7 @@ ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (local.get $10) @@ -5303,14 +5303,14 @@ ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.store offset=4 ;; CHECK-NEXT: (local.get $5) ;; CHECK-NEXT: (i32.shr_s ;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (i32.lt_s - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 31) @@ -5330,7 +5330,7 @@ ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (local.get $10) @@ -5344,7 +5344,7 @@ ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (local.get $10) @@ -5358,7 +5358,7 @@ ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (local.get $10) @@ -5374,14 +5374,14 @@ ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.store offset=4 ;; CHECK-NEXT: (local.get $5) ;; CHECK-NEXT: (i32.shr_s ;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (i32.lt_s - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 31) @@ -5928,7 +5928,7 @@ ;; CHECK-NEXT: (i32.const 9) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $30) - ;; CHECK-NEXT: (local.tee $17 + ;; CHECK-NEXT: (local.tee $18 ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $15) ;; CHECK-NEXT: (i32.const 32) @@ -6134,7 +6134,7 @@ ;; CHECK-NEXT: (i32.const 4075) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $14 @@ -6453,7 +6453,7 @@ ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (loop $while-in62 - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (select ;; CHECK-NEXT: (i32.const 29) ;; CHECK-NEXT: (local.get $11) @@ -6487,7 +6487,7 @@ ;; CHECK-NEXT: (local.get $11) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.tee $12 @@ -6580,7 +6580,7 @@ ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $21) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -6638,7 +6638,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (loop $while-in70 (result i32) - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (select ;; CHECK-NEXT: (i32.const 9) ;; CHECK-NEXT: (local.tee $7 @@ -6663,7 +6663,7 @@ ;; CHECK-NEXT: (i32.sub ;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) @@ -6671,7 +6671,7 @@ ;; CHECK-NEXT: (local.set $34 ;; CHECK-NEXT: (i32.shr_u ;; CHECK-NEXT: (i32.const 1000000000) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $11 @@ -6691,7 +6691,7 @@ ;; CHECK-NEXT: (local.get $7) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -6792,7 +6792,7 @@ ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $21) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -6988,22 +6988,24 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $8 - ;; CHECK-NEXT: (i32.load - ;; CHECK-NEXT: (local.tee $6 - ;; CHECK-NEXT: (i32.sub - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (local.get $20) - ;; CHECK-NEXT: (i32.shl - ;; CHECK-NEXT: (local.get $8) - ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (local.tee $18 + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (local.tee $6 + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (local.get $20) + ;; CHECK-NEXT: (i32.shl + ;; CHECK-NEXT: (local.get $8) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 4092) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 4092) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $8 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (local.get $12) ;; CHECK-NEXT: (i32.rem_u @@ -7026,7 +7028,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.eqz - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -7035,7 +7037,7 @@ ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (local.get $12) ;; CHECK-NEXT: (i32.div_u - ;; CHECK-NEXT: (local.get $8) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: (local.get $12) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) @@ -7044,7 +7046,7 @@ ;; CHECK-NEXT: (local.set $14 ;; CHECK-NEXT: (if (result f64) ;; CHECK-NEXT: (i32.lt_u - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: (local.tee $45 ;; CHECK-NEXT: (i32.div_s ;; CHECK-NEXT: (local.get $12) @@ -7059,7 +7061,7 @@ ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $26) ;; CHECK-NEXT: (i32.eq - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: (local.get $45) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -7103,8 +7105,8 @@ ;; CHECK-NEXT: (local.get $6) ;; CHECK-NEXT: (local.tee $8 ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: (local.get $8) - ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -7363,7 +7365,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_if $do-once91 ;; CHECK-NEXT: (local.get $19) - ;; CHECK-NEXT: (local.tee $17 + ;; CHECK-NEXT: (local.tee $18 ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $9) ;; CHECK-NEXT: (i32.const 8) @@ -7466,7 +7468,7 @@ ;; CHECK-NEXT: (i32.const 102) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (select @@ -7493,7 +7495,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (select @@ -7525,7 +7527,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $9) ;; CHECK-NEXT: (i32.const 8) @@ -7547,7 +7549,7 @@ ;; CHECK-NEXT: (local.tee $19 ;; CHECK-NEXT: (i32.or ;; CHECK-NEXT: (local.get $5) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) @@ -7954,9 +7956,9 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (i32.eqz - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $6 @@ -8021,7 +8023,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br_if $do-once115 ;; CHECK-NEXT: (i32.and - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: (i32.le_s ;; CHECK-NEXT: (local.get $7) ;; CHECK-NEXT: (i32.const 0) @@ -8305,12 +8307,6 @@ ;; CHECK-NEXT: (local.get $23) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $11 - ;; CHECK-NEXT: (i32.and - ;; CHECK-NEXT: (local.get $15) - ;; CHECK-NEXT: (i32.const 32) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.or ;; CHECK-NEXT: (local.tee $5 @@ -8325,6 +8321,12 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $11 + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $15) + ;; CHECK-NEXT: (i32.const 32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $8 ;; CHECK-NEXT: (local.get $23) ;; CHECK-NEXT: ) @@ -8609,7 +8611,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $17 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (local.tee $15 ;; CHECK-NEXT: (select @@ -8632,7 +8634,7 @@ ;; CHECK-NEXT: (local.get $5) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $8 @@ -8648,7 +8650,7 @@ ;; CHECK-NEXT: (local.get $6) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $15) - ;; CHECK-NEXT: (local.get $17) + ;; CHECK-NEXT: (local.get $18) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -8719,7 +8721,7 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L1) @@ -8991,7 +8993,7 @@ ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (block (result i32) @@ -9034,7 +9036,7 @@ ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L343) @@ -9058,7 +9060,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $18 + ;; CHECK-NEXT: (local.set $17 ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $label$break$L343) @@ -9088,7 +9090,7 @@ ;; CHECK-NEXT: (global.set $STACKTOP ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $18) + ;; CHECK-NEXT: (local.get $17) ;; CHECK-NEXT: ) (func $_printf_core (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32) (local $5 i32) @@ -14809,7 +14811,6 @@ ) ) ;; CHECK: (func $_fmt_u (param $0 i32) (param $1 i32) (param $2 i32) (result i32) - ;; CHECK-NEXT: (local $3 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (loop $while-in @@ -14838,9 +14839,6 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $3 - ;; CHECK-NEXT: (global.get $tempRet0) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.gt_u ;; CHECK-NEXT: (local.get $1) @@ -14848,7 +14846,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: (global.get $tempRet0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $while-in) ;; CHECK-NEXT: ) |