summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/CodePushing.cpp223
-rw-r--r--test/lit/passes/code-pushing_into_if.wast651
-rw-r--r--test/lit/passes/inlining-optimizing_optimize-level=3.wast148
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: )