summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp34
-rw-r--r--test/passes/optimize-instructions.txt70
-rw-r--r--test/passes/optimize-instructions.wast75
3 files changed, 179 insertions, 0 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index e0c7217a5..1dd05dd0a 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -516,6 +516,12 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
return ret;
}
}
+ // for or, we can potentially combine
+ if (binary->op == OrInt32) {
+ if (auto* ret = combineOr(binary)) {
+ return ret;
+ }
+ }
// relation/comparisons allow for math optimizations
if (binary->isRelational()) {
if (auto* ret = optimizeRelational(binary)) {
@@ -979,6 +985,34 @@ 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>()) {
+ if (left->op != right->op &&
+ ExpressionAnalyzer::equal(left->left, right->left) &&
+ ExpressionAnalyzer::equal(left->right, right->right) &&
+ !EffectAnalyzer(getPassOptions(), left->left).hasSideEffects() &&
+ !EffectAnalyzer(getPassOptions(), left->right).hasSideEffects()) {
+ switch (left->op) {
+ // (x > y) | (x == y) ==> x >= y
+ case EqInt32: {
+ if (right->op == GtSInt32) {
+ left->op = GeSInt32;
+ return left;
+ }
+ break;
+ }
+ default: {}
+ }
+ }
+ }
+ }
+ return nullptr;
+ }
+
// fold constant factors into the offset
void optimizeMemoryAccess(Expression*& ptr, Address& offset) {
// ptr may be a const, but it isn't worth folding that in (we still have a const); in fact,
diff --git a/test/passes/optimize-instructions.txt b/test/passes/optimize-instructions.txt
index 7d82ae8b1..0e8654e48 100644
--- a/test/passes/optimize-instructions.txt
+++ b/test/passes/optimize-instructions.txt
@@ -3223,6 +3223,76 @@
(i32.const 2)
)
)
+ (func $pre-combine-or (; 75 ;) (type $5) (param $x i32) (param $y i32)
+ (drop
+ (i32.ge_s
+ (get_local $x)
+ (get_local $y)
+ )
+ )
+ (drop
+ (i32.ge_s
+ (get_local $x)
+ (get_local $y)
+ )
+ )
+ (drop
+ (i32.or
+ (i32.eq
+ (get_local $x)
+ (i32.const 1)
+ )
+ (i32.gt_s
+ (get_local $x)
+ (get_local $y)
+ )
+ )
+ )
+ (drop
+ (i32.or
+ (i32.eq
+ (get_local $x)
+ (get_local $y)
+ )
+ (i32.gt_s
+ (get_local $x)
+ (i32.const 1)
+ )
+ )
+ )
+ (drop
+ (i32.or
+ (i32.gt_s
+ (call $ne0)
+ (get_local $y)
+ )
+ (i32.eq
+ (call $ne0)
+ (get_local $y)
+ )
+ )
+ )
+ (drop
+ (i32.or
+ (i32.gt_s
+ (get_local $y)
+ (call $ne0)
+ )
+ (i32.eq
+ (call $ne0)
+ (get_local $y)
+ )
+ )
+ )
+ )
+ (func $combine-or (; 76 ;) (type $5) (param $x i32) (param $y i32)
+ (drop
+ (i32.ge_s
+ (get_local $x)
+ (get_local $y)
+ )
+ )
+ )
)
(module
(type $0 (func))
diff --git a/test/passes/optimize-instructions.wast b/test/passes/optimize-instructions.wast
index 234b3913b..be9761a2b 100644
--- a/test/passes/optimize-instructions.wast
+++ b/test/passes/optimize-instructions.wast
@@ -3663,6 +3663,81 @@
(i32.const 2)
)
)
+ (func $pre-combine-or (param $x i32) (param $y i32)
+ (drop (i32.or
+ (i32.gt_s
+ (get_local $x)
+ (get_local $y)
+ )
+ (i32.eq
+ (get_local $y) ;; ordering should not stop us
+ (get_local $x)
+ )
+ ))
+ (drop (i32.or
+ (i32.eq ;; ordering should not stop us
+ (get_local $y)
+ (get_local $x)
+ )
+ (i32.gt_s
+ (get_local $x)
+ (get_local $y)
+ )
+ ))
+ (drop (i32.or
+ (i32.gt_s
+ (get_local $x)
+ (get_local $y)
+ )
+ (i32.eq
+ (get_local $x)
+ (i32.const 1) ;; not equal
+ )
+ ))
+ (drop (i32.or
+ (i32.gt_s
+ (get_local $x)
+ (i32.const 1) ;; not equal
+ )
+ (i32.eq
+ (get_local $x)
+ (get_local $y)
+ )
+ ))
+ (drop (i32.or
+ (i32.gt_s
+ (call $ne0) ;; side effects
+ (get_local $y)
+ )
+ (i32.eq
+ (call $ne0)
+ (get_local $y)
+ )
+ ))
+ (drop (i32.or
+ (i32.gt_s
+ (get_local $y)
+ (call $ne0) ;; side effects
+ )
+ (i32.eq
+ (get_local $y)
+ (call $ne0)
+ )
+ ))
+ )
+ (func $combine-or (param $x i32) (param $y i32)
+ (drop (i32.or
+ (i32.gt_s
+ (get_local $x)
+ (get_local $y)
+ )
+ (i32.eq
+ (get_local $x)
+ (get_local $y)
+ )
+ ))
+ ;; TODO: more stuff here
+ )
)
(module
(import "env" "memory" (memory $0 (shared 256 256)))