diff options
author | Alon Zakai <azakai@google.com> | 2022-09-01 10:34:19 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-01 10:34:19 -0700 |
commit | f058bb53b3d8977f800894d305b7f537b9aff3d5 (patch) | |
tree | 2da33a1d13c9d8c0b63c8fdbfb2f00993d0740e4 /test/lit/passes/optimize-instructions.wast | |
parent | 7c5f6c2aca80d70cf05fc83739f87ff23c75a1e3 (diff) | |
download | binaryen-f058bb53b3d8977f800894d305b7f537b9aff3d5.tar.gz binaryen-f058bb53b3d8977f800894d305b7f537b9aff3d5.tar.bz2 binaryen-f058bb53b3d8977f800894d305b7f537b9aff3d5.zip |
OptimizeInstructions: Select => and/or in more cases (#4154)
x ? 0 : y ==> z & y where z = !x
x ? y : 1 ==> z | y where z = !x
Only do this when we have z = !x, that is, we can invert x without adding
an actual eqz (which would add work).
To do this, canonicalize selects to prefer to flip the arms, when
possible, if it would move a constant to a location that the existing
optimizations already turn into an and/or. That is,
x >= 5 ? 0 : y != 42
would be canonicalized into
x < 5 ? y != 42 : 0
and existing opts turn that into
(x < 5) & (y != 42)
The canonicalization does not always help this optimization, as we need
the values to be boolean to do this, but canonicalizing is still nice to get
more regular code which might compress slightly better.
Diffstat (limited to 'test/lit/passes/optimize-instructions.wast')
-rw-r--r-- | test/lit/passes/optimize-instructions.wast | 125 |
1 files changed, 117 insertions, 8 deletions
diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast index 3c9cfb2be..71d4e7fe3 100644 --- a/test/lit/passes/optimize-instructions.wast +++ b/test/lit/passes/optimize-instructions.wast @@ -893,9 +893,35 @@ ) ) ) + ;; CHECK: (func $select-or-negation (param $x i32) (param $y i32) (result i32) + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (i32.eq + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.ge_u + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $select-or-negation (param $x i32) (param $y i32) (result i32) + (select + ;; We can turn this select into an and by negating the condition. + (i32.const 0) + (i32.eq + (local.get $y) + (i32.const 1337) + ) + (i32.lt_u + (local.get $x) + (i32.const 20) + ) + ) + ) ;; CHECK: (func $select-or-no-const (param $x i32) (param $y i32) (result i32) ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: (i32.eq ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: (i32.const 1337) @@ -908,8 +934,8 @@ ;; CHECK-NEXT: ) (func $select-or-no-const (param $x i32) (param $y i32) (result i32) (select - ;; The wrong const (should be 1). - (i32.const 0) + ;; The wrong const (should be 0 or 1). + (i32.const 2) (i32.eq (local.get $y) (i32.const 1337) @@ -945,14 +971,97 @@ ) ) ) - ;; CHECK: (func $select-and-no-const (param $x i32) (param $y i32) (result i32) + ;; CHECK: (func $select-and-negation (param $x i32) (param $y i32) (result i32) + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (i32.eq + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.ne + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $select-and-negation (param $x i32) (param $y i32) (result i32) + (select + (i32.eq + (local.get $y) + (i32.const 1337) + ) + ;; With a 1 here, we negate the condition. + (i32.const 1) + (i32.eq + (local.get $x) + (i32.const 42) + ) + ) + ) + ;; CHECK: (func $select-and-negation-impossible (param $x i32) (param $y i32) (result i32) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.eq + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.shr_u + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 31) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $select-and-negation-impossible (param $x i32) (param $y i32) (result i32) + (select + (i32.eq + (local.get $y) + (i32.const 1337) + ) + ;; With a 1 here, we must negate the condition, but the condition here + ;; cannot be negated in a simple way, so skip. + (i32.const 1) + (i32.shr_u + (local.get $x) + (i32.const 31) + ) + ) + ) + ;; CHECK: (func $select-and-negation-impossible-float (param $x f64) (param $y i32) (result i32) ;; CHECK-NEXT: (select ;; CHECK-NEXT: (i32.eq ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (f64.le + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $select-and-negation-impossible-float (param $x f64) (param $y i32) (result i32) + (select + (i32.eq + (local.get $y) + (i32.const 1337) + ) + ;; With a 1 here, we must negate the condition, but the condition here + ;; cannot be negated due to it operating on floats (where NaNs cause + ;; difficulties), so we skip. + (i32.const 1) + (f64.le + (local.get $x) + (f64.const 3.14159) + ) + ) + ) + ;; CHECK: (func $select-and-no-const (param $x i32) (param $y i32) (result i32) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: (i32.eq + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.ne ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) @@ -964,8 +1073,8 @@ (local.get $y) (i32.const 1337) ) - ;; The wrong constant (should be 0). - (i32.const 1) + ;; The wrong constant (should be 0 or 1). + (i32.const 2) (i32.eq (local.get $x) (i32.const 42) @@ -11271,9 +11380,9 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i64.const 0) ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: (i64.ne + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: (i64.eq ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: (i64.const 1) ;; CHECK-NEXT: ) |