diff options
author | Alon Zakai <azakai@google.com> | 2024-04-11 16:41:22 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-11 16:41:22 -0700 |
commit | 111902d98ac2eb1e903af8ec2f2eab8e9bc66cdf (patch) | |
tree | 212b92d622972b0df40c1651305eccdd841a42f8 /test | |
parent | 81f72e8e77e9c67f1ebf178f26edce3b6ebbd9d5 (diff) | |
download | binaryen-111902d98ac2eb1e903af8ec2f2eab8e9bc66cdf.tar.gz binaryen-111902d98ac2eb1e903af8ec2f2eab8e9bc66cdf.tar.bz2 binaryen-111902d98ac2eb1e903af8ec2f2eab8e9bc66cdf.zip |
Fix isGenerative on calls and test via improving OptimizeInstructions::areConsecutiveInputsEqual() (#6481)
"Generative" is what we call something like a struct.new that may be syntactically
identical to another struct.new, but each time a new value is generated. The same
is true for calls, which can do anything, including return a different value for
syntactically identical calls.
This was not a bug because the main user of isGenerative,
areConsecutiveInputsEqual(), was too weak to notice, that is, it gave up sooner,
for other reasons. This PR improves that function to do a much better check,
which makes the fix necessary to prevent regressions.
This is not terribly important for itself, but will help a later PR that will add code
that depends more heavily on areConsecutiveInputsEqual().
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/optimize-instructions-mvp.wast | 331 |
1 files changed, 330 insertions, 1 deletions
diff --git a/test/lit/passes/optimize-instructions-mvp.wast b/test/lit/passes/optimize-instructions-mvp.wast index 1575e8d6b..b618cf200 100644 --- a/test/lit/passes/optimize-instructions-mvp.wast +++ b/test/lit/passes/optimize-instructions-mvp.wast @@ -10,6 +10,9 @@ ;; CHECK: (import "a" "b" (func $get-f64 (result f64))) (import "a" "b" (func $get-f64 (result f64))) + ;; CHECK: (import "a" "c" (func $set-i32 (param i32))) + (import "a" "c" (func $set-i32 (param i32))) + (memory 0) ;; CHECK: (func $and-and (param $i1 i32) (result i32) @@ -14711,7 +14714,9 @@ (local.get $y0) ) )) - ;; this one cannot be optimized as the runtime values may differ + ;; This one cannot be optimized as the runtime values may differ: the calls + ;; are "generative" in that identical syntactic calls may emit different + ;; results. (drop (f64.abs (f64.mul (call $get-f64) @@ -14746,6 +14751,248 @@ (f64.abs (f64.add (local.get $x0) (local.get $x0))) )) ) + + ;; CHECK: (func $optimize-float-points-fallthrough (param $x f64) (param $xb f64) (param $y f32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f32.mul + ;; CHECK-NEXT: (block (result f32) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (result f32) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-float-points-fallthrough (param $x f64) (param $xb f64) (param $y f32) + ;; abs(x * x) ==> x * x , as in the previous function. + ;; + ;; The fallthrough values here are identical, so we can optimize away the + ;; f32.abs despite the effects in both (and even different-looking effects). + (drop (f32.abs + (f32.mul + (block (result f32) + (call $set-i32 + (i32.const 42) + ) + (local.get $y) + ) + (block (result f32) + (call $set-i32 + (i32.const 1337) + ) + (local.get $y) + ) + ) + )) + ) + ;; CHECK: (func $optimize-float-points-fallthrough-b (param $x f64) (param $xb f64) (param $y f32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f64.abs + ;; CHECK-NEXT: (f64.mul + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $get-f64) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $get-f64) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-float-points-fallthrough-b (param $x f64) (param $xb f64) (param $y f32) + ;; But generative effects in the fallthrough values themselves block us. + (drop (f64.abs + (f64.mul + (block (result f64) + (call $set-i32 + (i32.const 42) + ) + (call $get-f64) ;; this changed + ) + (block (result f64) + (call $set-i32 + (i32.const 1337) + ) + (call $get-f64) ;; this changed + ) + ) + )) + ) + ;; CHECK: (func $optimize-float-points-fallthrough-c (param $x f64) (param $xb f64) (param $y f32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f64.abs + ;; CHECK-NEXT: (f64.mul + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (f64.const 12.34) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-float-points-fallthrough-c (param $x f64) (param $xb f64) (param $y f32) + ;; local.tee/get pairs are ok, but atm we don't look at the fallthrough of + ;; the right side (we'd need to consider effects). TODO + (drop (f64.abs + (f64.mul + (block (result f64) + (call $set-i32 + (i32.const 42) + ) + (local.tee $x ;; this changed + (f64.const 12.34) + ) + ) + (block (result f64) + (call $set-i32 + (i32.const 1337) + ) + (local.get $x) ;; this changed + ) + ) + )) + ) + ;; CHECK: (func $optimize-float-points-fallthrough-cb (param $x f64) (param $xb f64) (param $y f32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f64.abs + ;; CHECK-NEXT: (f64.mul + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (f64.const 12.34) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (f64.const 13.37) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-float-points-fallthrough-cb (param $x f64) (param $xb f64) (param $y f32) + ;; A conflicting set in the middle is a problem: here we cannot optimize. + (drop (f64.abs + (f64.mul + (block (result f64) + (call $set-i32 + (i32.const 42) + ) + (local.tee $x + (f64.const 12.34) + ) + ) + (block (result f64) + (local.set $x ;; this changed + (f64.const 13.37) + ) + (local.get $x) + ) + ) + )) + ) + ;; CHECK: (func $optimize-float-points-fallthrough-cc (param $x f64) (param $xb f64) (param $y f32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f64.mul + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (f64.const 12.34) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-float-points-fallthrough-cc (param $x f64) (param $xb f64) (param $y f32) + ;; Removing the local.set and the block on the right lets us optimize using + ;; the tee/get pair. + (drop (f64.abs + (f64.mul + (block (result f64) + (call $set-i32 + (i32.const 42) + ) + (local.tee $x + (f64.const 12.34) + ) + ) + (local.get $x) ;; this moved out + ) + )) + ) + ;; CHECK: (func $optimize-float-points-fallthrough-d (param $x f64) (param $xb f64) (param $y f32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f64.abs + ;; CHECK-NEXT: (f64.mul + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (f64.const 12.34) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (call $set-i32 + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $xb) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-float-points-fallthrough-d (param $x f64) (param $xb f64) (param $y f32) + ;; The wrong local index means we fail again. + (drop (f64.abs + (f64.mul + (block (result f64) + (call $set-i32 + (i32.const 42) + ) + (local.tee $x + (f64.const 12.34) + ) + ) + (block (result f64) + (call $set-i32 + (i32.const 1337) + ) + (local.get $xb) ;; this changed + ) + ) + )) + ) ;; CHECK: (func $ternary (param $x i32) (param $y i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.eqz @@ -15113,6 +15360,88 @@ ) ) ) + ;; CHECK: (func $ternary-identical-arms-tee (param $param i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.get $param) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (call $send-i32 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (call $send-i32 + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.get $param) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.get $param) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $ternary-identical-arms-tee (param $param i32) + (local $x i32) + ;; The select's ifTrue and condition are equal (as a tee/get pair with + ;; only a const in between), but there is a side effect too, that prevents + ;; optimization atm TODO + (drop + (select + (local.tee $x + (local.get $param) + ) + (i32.const 0) + (block (result i32) + (call $send-i32 + (i32.const 42) + ) + (local.get $x) + ) + ) + ) + ;; Side effect on the ifTrue - same outcome, we cannot optimize yet. + (drop + (select + (block (result i32) + (call $send-i32 + (i32.const 1337) + ) + (local.tee $x + (local.get $param) + ) + ) + (i32.const 0) + (local.get $x) + ) + ) + ;; When there are no blocks or things and just a local.tee/get, we can + ;; optimize. + (drop + (select + (local.tee $x + (local.get $param) + ) + (i32.const 0) + (local.get $x) + ) + ) + ) ;; CHECK: (func $ternary-identical-arms-and-type-is-none (param $x i32) (param $y i32) (param $z i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.eqz |