diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/stack-ir-non-nullable.wast | 836 |
1 files changed, 836 insertions, 0 deletions
diff --git a/test/lit/passes/stack-ir-non-nullable.wast b/test/lit/passes/stack-ir-non-nullable.wast new file mode 100644 index 000000000..ac34b5107 --- /dev/null +++ b/test/lit/passes/stack-ir-non-nullable.wast @@ -0,0 +1,836 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --generate-stack-ir --optimize-stack-ir --shrink-level=1 \ +;; RUN: -all --print-stack-ir | filecheck %s + +;; Shrink level is set to 1 to enable local2stack in StackIR opts. + +(module + ;; CHECK: (func $if (type $1) (param $param (ref eq)) (result (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: ref.eq + ;; CHECK-NEXT: if + ;; CHECK-NEXT: i32.const 1 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: i32.const 2 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: ) + (func $if (param $param (ref eq)) (result (ref eq)) + (local $temp (ref eq)) + ;; Copy the param into $temp. $temp is then set in both arms of the if, so + ;; it is set before the get at the end of the function, but we still need to + ;; keep this set for validation purposes. Specifically, there is a set of + ;; $temp followed by a get of it in the if condition, which local2stack could + ;; remove in principle, if not for that final get at the function end. + (local.set $temp + (local.get $param) + ) + (if + (ref.eq + (local.get $temp) + (i31.new + (i32.const 0) + ) + ) + (local.set $temp + (i31.new + (i32.const 1) + ) + ) + (local.set $temp + (i31.new + (i32.const 2) + ) + ) + ) + (local.get $temp) + ) + + ;; CHECK: (func $if-no-last-get (type $1) (param $param (ref eq)) (result (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: ref.eq + ;; CHECK-NEXT: if + ;; CHECK-NEXT: i32.const 1 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: i32.const 2 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: ) + (func $if-no-last-get (param $param (ref eq)) (result (ref eq)) + ;; As the original, but now there is no final get, so we can remove the set- + ;; get pair of $temp before the if. + (local $temp (ref eq)) + (local.set $temp + (local.get $param) + ) + (if + (ref.eq + (local.get $temp) + (i31.new + (i32.const 0) + ) + ) + (local.set $temp + (i31.new + (i32.const 1) + ) + ) + (local.set $temp + (i31.new + (i32.const 2) + ) + ) + ) + (local.get $param) ;; this changed from $temp to $param + ) + + ;; CHECK: (func $if-extra-set (type $1) (param $param (ref eq)) (result (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: ref.eq + ;; CHECK-NEXT: if + ;; CHECK-NEXT: i32.const 1 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: i32.const 2 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: ) + (func $if-extra-set (param $param (ref eq)) (result (ref eq)) + ;; As the original, but now there is an extra set before the final get, so + ;; we can optimize - the extra set ensures validation. + (local $temp (ref eq)) + (local.set $temp + (local.get $param) + ) + (if + (ref.eq + (local.get $temp) + (i31.new + (i32.const 0) + ) + ) + (local.set $temp + (i31.new + (i32.const 1) + ) + ) + (local.set $temp + (i31.new + (i32.const 2) + ) + ) + ) + (local.set $temp ;; This set is new. + (local.get $param) + ) + (local.get $temp) + ) + + ;; CHECK: (func $if-wrong-extra-set (type $1) (param $param (ref eq)) (result (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: ref.eq + ;; CHECK-NEXT: if + ;; CHECK-NEXT: i32.const 1 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: i32.const 2 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $param + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: ) + (func $if-wrong-extra-set (param $param (ref eq)) (result (ref eq)) + ;; As the last testcase, but the extra set's index is wrong, so we cannot + ;; optimize. + (local $temp (ref eq)) + (local.set $temp + (local.get $param) + ) + (if + (ref.eq + (local.get $temp) + (i31.new + (i32.const 0) + ) + ) + (local.set $temp + (i31.new + (i32.const 1) + ) + ) + (local.set $temp + (i31.new + (i32.const 2) + ) + ) + ) + (local.set $param ;; This set now writes to $param. + (local.get $param) + ) + (local.get $temp) + ) + + ;; CHECK: (func $if-wrong-extra-get (type $1) (param $param (ref eq)) (result (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: ref.eq + ;; CHECK-NEXT: if + ;; CHECK-NEXT: i32.const 1 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: i32.const 2 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: ) + (func $if-wrong-extra-get (param $param (ref eq)) (result (ref eq)) + ;; As the last testcase, but now it is the get that has the wrong index to + ;; stop us, so we can optimize. + (local $temp (ref eq)) + (local.set $temp + (local.get $param) + ) + (if + (ref.eq + (local.get $temp) + (i31.new + (i32.const 0) + ) + ) + (local.set $temp + (i31.new + (i32.const 1) + ) + ) + (local.set $temp + (i31.new + (i32.const 2) + ) + ) + ) + (local.set $temp + (local.get $param) + ) + (local.get $param) ;; This get does not affect optimizing the pair before the + ;; if, because it is of another local. + ) + + ;; CHECK: (func $if-param (type $2) (param $param (ref eq)) (param $temp (ref eq)) (result (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: ref.eq + ;; CHECK-NEXT: if + ;; CHECK-NEXT: i32.const 1 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: i32.const 2 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: ) + (func $if-param (param $param (ref eq)) (param $temp (ref eq)) (result (ref eq)) + ;; As the original testcase, but now $temp is a param. Validation is no + ;; longer an issue, so we can optimize away the pair. + (local.set $temp + (local.get $param) + ) + (if + (ref.eq + (local.get $temp) + (i31.new + (i32.const 0) + ) + ) + (local.set $temp + (i31.new + (i32.const 1) + ) + ) + (local.set $temp + (i31.new + (i32.const 2) + ) + ) + ) + (local.get $temp) + ) + + ;; CHECK: (func $if-nullable (type $3) (param $param (ref eq)) (result eqref) + ;; CHECK-NEXT: (local $temp eqref) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: ref.eq + ;; CHECK-NEXT: if + ;; CHECK-NEXT: i32.const 1 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: i32.const 2 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: ) + (func $if-nullable (param $param (ref eq)) (result (ref null eq)) + (local $temp (ref null eq)) ;; this changed + ;; As the original testcase, but now $temp is a nullable. Validation is no + ;; longer an issue, so we can optimize away the pair. + (local.set $temp + (local.get $param) + ) + (if + (ref.eq + (local.get $temp) + (i31.new + (i32.const 0) + ) + ) + (local.set $temp + (i31.new + (i32.const 1) + ) + ) + (local.set $temp + (i31.new + (i32.const 2) + ) + ) + ) + (local.get $temp) + ) + + ;; CHECK: (func $if-non-ref (type $4) (param $param i32) (result i32) + ;; CHECK-NEXT: (local $temp i32) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: i32.eqz + ;; CHECK-NEXT: if + ;; CHECK-NEXT: i32.const 1 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: i32.const 2 + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: ) + (func $if-non-ref (param $param i32) (result i32) + (local $temp i32) + ;; As the original testcase, but now $temp is not a ref. Validation is no + ;; longer an issue, so we can optimize away the pair. + (local.set $temp + (local.get $param) + ) + (if + (i32.eqz + (local.get $temp) + (i32.const 0) + ) + (local.set $temp + (i32.const 1) + ) + (local.set $temp + (i32.const 2) + ) + ) + (local.get $temp) + ) + + ;; CHECK: (func $nesting (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: if + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: else + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: ) + (func $nesting (param $param (ref eq)) + (local $temp (ref eq)) + ;; The if arms contain optimization opportunities, even though there are 2 + ;; gets in each one, because this top set helps them all validate. Atm we do + ;; not look backwards, however, so we fail to optimize here. + (local.set $temp + (local.get $param) + ) + (if + (i32.const 0) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + (drop + (local.get $temp) + ) + ) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + (drop + (local.get $temp) + ) + ) + ) + (drop + (local.get $temp) + ) + ) + + ;; CHECK: (func $nesting-left (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: if + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: else + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: end + ;; CHECK-NEXT: ) + (func $nesting-left (param $param (ref eq)) + (local $temp (ref eq)) + ;; As $nesting, but now the left arm has one get, and can be optimized. + (local.set $temp + (local.get $param) + ) + (if + (i32.const 0) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ;; A get was removed here. + ) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + (drop + (local.get $temp) + ) + ) + ) + ) + + ;; CHECK: (func $nesting-right (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: if + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: else + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: end + ;; CHECK-NEXT: ) + (func $nesting-right (param $param (ref eq)) + (local $temp (ref eq)) + ;; As above, but now we can optimize the right arm. + (local.set $temp + (local.get $param) + ) + (if + (i32.const 0) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + (drop + (local.get $temp) + ) + ) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ;; A get was removed here. + ) + ) + ) + + ;; CHECK: (func $nesting-both (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: if + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: else + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: end + ;; CHECK-NEXT: ) + (func $nesting-both (param $param (ref eq)) + (local $temp (ref eq)) + ;; As above, but now we can optimize both arms. + (local.set $temp + (local.get $param) + ) + (if + (i32.const 0) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ;; A get was removed here. + ) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ;; A get was removed here. + ) + ) + ) + + ;; CHECK: (func $nesting-both-less (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: if + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: else + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: end + ;; CHECK-NEXT: ) + (func $nesting-both-less (param $param (ref eq)) + (local $temp (ref eq)) + ;; As above, but without the initial set-get at the top. We can still + ;; optimize both arms. + (if + (i32.const 0) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + ) + ) + + ;; CHECK: (func $nesting-both-after (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: if + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: else + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: ) + (func $nesting-both-after (param $param (ref eq)) + (local $temp (ref eq)) + ;; As above, but now there is a set-get at the end of the function. The get + ;; there should not confuse us; we can still optimize both arms, and after + ;; them as well. + (if + (i32.const 0) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + (block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + ) + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + + ;; CHECK: (func $nesting-irrelevant (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: ) + (func $nesting-irrelevant (param $param (ref eq)) + (local $temp (ref eq)) + ;; The block in the middle here adds a scope, but it does not prevent us from + ;; optimizing. + (local.set $temp + (local.get $param) + ) + (block $block + ) + (drop + (local.get $temp) + ) + ) + + ;; CHECK: (func $nesting-relevant (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: ) + (func $nesting-relevant (param $param (ref eq)) + (local $temp (ref eq)) + ;; As above, but now there is a get in that scope, which is a problem. + (local.set $temp + (local.get $param) + ) + (block $block + (drop + (local.get $temp) + ) + ) + (drop + (local.get $temp) + ) + ) + + ;; CHECK: (func $nesting-after (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: ) + (func $nesting-after (param $param (ref eq)) + (local $temp (ref eq)) + ;; A set-get pair with another after it in a block. We can optimize both. + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + (block $block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + ) + + ;; CHECK: (func $nesting-reverse (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: ) + (func $nesting-reverse (param $param (ref eq)) + (local $temp (ref eq)) + ;; The reverse of the last case, now the block is first. We can optimize + ;; both pairs. + (block $block + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + + ;; CHECK: (func $nesting-covered-but-ended (type $0) (param $param (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: ) + (func $nesting-covered-but-ended (param $param (ref eq)) + (local $temp (ref eq)) + ;; We cannot optimize this first pair, because while we see another set after + ;; us, its scope ends, so our set must help the very final get validate. + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + (block $block + ;; This pair we can almost optimize, but the get after the block reads from + ;; it, so we don't. + (local.set $temp + (local.get $param) + ) + (drop + (local.get $temp) + ) + ) + (drop + (local.get $temp) + ) + ) + + ;; CHECK: (func $two-covers (type $1) (param $param (ref eq)) (result (ref eq)) + ;; CHECK-NEXT: (local $temp (ref eq)) + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: ref.i31 + ;; CHECK-NEXT: ref.eq + ;; CHECK-NEXT: if + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.tee $temp + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: else + ;; CHECK-NEXT: local.get $param + ;; CHECK-NEXT: local.set $temp + ;; CHECK-NEXT: end + ;; CHECK-NEXT: local.get $temp + ;; CHECK-NEXT: ) + (func $two-covers (param $param (ref eq)) (result (ref eq)) + (local $temp (ref eq)) + (local.set $temp + (local.get $param) + ) + (if + (ref.eq + (local.get $temp) + (i31.new + (i32.const 0) + ) + ) + ;; In this if arm we write to $temp twice. That shouldn't confuse us; there's + ;; still a use after the if, and we should not remove the set-get pair before + ;; the if. + (local.set $temp + (local.tee $temp + (local.get $param) + ) + ) + (local.set $temp + (local.get $param) + ) + ) + (local.get $temp) + ) +) |