diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 14 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions.wast | 34 | ||||
-rw-r--r-- | test/passes/inlining-optimizing_optimize-level=3.txt | 10 |
3 files changed, 52 insertions, 6 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 7e6b00212..be89257a1 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1698,6 +1698,20 @@ private: Bits::getMaxBits(left, this) == 1) { return builder.makeUnary(Abstract::getUnary(type, EqZ), left); } + // bool(x) ^ 1 ==> !bool(x) + if (matches(curr, binary(Xor, any(&left), ival(1))) && + Bits::getMaxBits(left, this) == 1) { + auto* result = builder.makeUnary(Abstract::getUnary(type, EqZ), left); + if (left->type == Type::i64) { + // Xor's result is also an i64 in this case, but EqZ returns i32, so we + // must expand it so that we keep returning the same value as before. + // This means we replace a xor and a const with a xor and an extend, + // which is still smaller (the const is 2 bytes, the extend just 1), and + // also the extend may be removed by further work. + result = builder.makeUnary(ExtendUInt32, result); + } + return result; + } // bool(x) | 1 ==> 1 if (matches(curr, binary(Or, pure(&left), ival(1))) && Bits::getMaxBits(left, this) == 1) { diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast index 52381efc4..5a180e3a5 100644 --- a/test/lit/passes/optimize-instructions.wast +++ b/test/lit/passes/optimize-instructions.wast @@ -8337,6 +8337,24 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.extend_i32_u + ;; CHECK-NEXT: (i64.eqz + ;; CHECK-NEXT: (i64.and + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (i64.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.wrap_i64 ;; CHECK-NEXT: (i64.shr_u ;; CHECK-NEXT: (local.get $y) @@ -8481,6 +8499,22 @@ ) (i32.const 1) )) + ;; i32(bool(expr)) ^ 1 -> !bool(expr) + (drop (i32.xor + (i32.and + (local.get $x) + (i32.const 1) + ) + (i32.const 1) + )) + ;; i64(bool(expr)) ^ 1 -> extend(!bool(expr)) + (drop (i64.xor + (i64.and + (local.get $y) + (i64.const 1) + ) + (i64.const 1) + )) ;; i64(bool(expr)) != 0 -> i32(bool(expr)) (drop (i64.ne (i64.shr_u diff --git a/test/passes/inlining-optimizing_optimize-level=3.txt b/test/passes/inlining-optimizing_optimize-level=3.txt index b3ad7e801..a46fb8028 100644 --- a/test/passes/inlining-optimizing_optimize-level=3.txt +++ b/test/passes/inlining-optimizing_optimize-level=3.txt @@ -5057,9 +5057,8 @@ (i32.gt_s (local.tee $5 (i32.add - (i32.xor + (i32.eqz (local.get $31) - (i32.const 1) ) (local.get $19) ) @@ -6618,16 +6617,15 @@ (local.get $6) (local.tee $5 (i32.add + (i32.eqz + (local.get $12) + ) (i32.sub (local.get $37) (local.tee $7 (local.get $5) ) ) - (i32.xor - (local.get $12) - (i32.const 1) - ) ) ) (i32.lt_s |