summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp29
-rw-r--r--test/lit/passes/inlining-optimizing_optimize-level=3.wast9
-rw-r--r--test/lit/passes/optimize-instructions.wast32
3 files changed, 59 insertions, 11 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index c0ba2dc02..aa3de46e8 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -2513,11 +2513,15 @@ private:
}
// We can combine `or` operations, e.g.
- // (x > y) | (x == y) ==> x >= y
- Expression* combineOr(Binary* binary) {
- assert(binary->op == OrInt32);
- if (auto* left = binary->left->dynCast<Binary>()) {
- if (auto* right = binary->right->dynCast<Binary>()) {
+ // (x > y) | (x == y) ==> x >= y
+ // (x != 0) | (y != 0) ==> (x | y) != 0
+ Expression* combineOr(Binary* curr) {
+ using namespace Abstract;
+ using namespace Match;
+
+ assert(curr->op == OrInt32);
+ if (auto* left = curr->left->dynCast<Binary>()) {
+ if (auto* right = curr->right->dynCast<Binary>()) {
if (left->op != right->op &&
ExpressionAnalyzer::equal(left->left, right->left) &&
ExpressionAnalyzer::equal(left->right, right->right) &&
@@ -2538,6 +2542,21 @@ private:
}
}
}
+ {
+ // (i32(x) != 0) | (i32(y) != 0) ==> i32(x | y) != 0
+ // (i64(x) != 0) | (i64(y) != 0) ==> i64(x | y) != 0
+ Expression *x, *y;
+ if (matches(curr,
+ binary(OrInt32,
+ binary(Ne, any(&x), ival(0)),
+ binary(Ne, any(&y), ival(0)))) &&
+ x->type == y->type) {
+ auto* inner = curr->left->cast<Binary>();
+ inner->left = Builder(*getModule())
+ .makeBinary(Abstract::getBinary(x->type, Or), x, y);
+ return inner;
+ }
+ }
return nullptr;
}
diff --git a/test/lit/passes/inlining-optimizing_optimize-level=3.wast b/test/lit/passes/inlining-optimizing_optimize-level=3.wast
index 980075d14..632ec16ec 100644
--- a/test/lit/passes/inlining-optimizing_optimize-level=3.wast
+++ b/test/lit/passes/inlining-optimizing_optimize-level=3.wast
@@ -8849,19 +8849,16 @@
;; CHECK-NEXT: (i32.or
;; CHECK-NEXT: (local.get $6)
;; CHECK-NEXT: (local.tee $12
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (i32.ne
+ ;; CHECK-NEXT: (i32.ne
+ ;; CHECK-NEXT: (i32.or
;; CHECK-NEXT: (i32.load
;; CHECK-NEXT: (local.get $13)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (i32.load offset=4
;; CHECK-NEXT: (local.get $13)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast
index 3504ef857..574671076 100644
--- a/test/lit/passes/optimize-instructions.wast
+++ b/test/lit/passes/optimize-instructions.wast
@@ -11002,6 +11002,38 @@
(i64.eq (local.get $b) (i64.const 0))
))
)
+ ;; CHECK: (func $optimize-combined-by-or-noequal-to-zero (param $x i32) (param $y i32) (param $a i64) (param $b i64)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.ne
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.ne
+ ;; CHECK-NEXT: (i64.or
+ ;; CHECK-NEXT: (local.get $a)
+ ;; CHECK-NEXT: (local.get $b)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $optimize-combined-by-or-noequal-to-zero (param $x i32) (param $y i32) (param $a i64) (param $b i64)
+ ;; (i32(x) != 0) | (i32(y) != 0) ==> i32(x | y) != 0
+ (drop (i32.or
+ (i32.ne (local.get $x) (i32.const 0))
+ (i32.ne (local.get $y) (i32.const 0))
+ ))
+ ;; (i64(x) != 0) | (i64(y) != 0) ==> i64(x | y) != 0
+ (drop (i32.or
+ (i64.ne (local.get $a) (i64.const 0))
+ (i64.ne (local.get $b) (i64.const 0))
+ ))
+ )
;; CHECK: (func $optimize-relationals (param $x i32) (param $y i32) (param $X i64) (param $Y i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eq