summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp61
-rw-r--r--test/lit/passes/optimize-instructions.wast117
-rw-r--r--test/passes/asyncify_mod-asyncify-never-unwind_O.txt8
-rw-r--r--test/passes/asyncify_optimize-level=1.txt112
4 files changed, 238 insertions, 60 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 609caf588..b6ebb961a 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -864,6 +864,7 @@ struct OptimizeInstructions
if (auto* ret = optimizeSelect(curr)) {
return replaceCurrent(ret);
}
+ optimizeTernary(curr, curr->condition, curr->ifTrue, curr->ifFalse);
}
void visitGlobalSet(GlobalSet* curr) {
@@ -914,6 +915,7 @@ struct OptimizeInstructions
return replaceCurrent(ret);
}
}
+ optimizeTernary(curr, curr->condition, curr->ifTrue, curr->ifFalse);
}
}
@@ -2779,6 +2781,65 @@ private:
return false;
}
}
+
+ // Optimize an if-else or a select, something with a condition and two
+ // arms with outputs.
+ void optimizeTernary(Expression* curr,
+ Expression* condition,
+ Expression*& ifTrue,
+ Expression*& ifFalse) {
+ if (curr->type == Type::unreachable) {
+ return;
+ }
+
+ using namespace Match;
+ Builder builder(*getModule());
+
+ // If one arm is an operation and the other is an appropriate constant, we
+ // can move the operation outside (where it may be further optimized), e.g.
+ //
+ // (select
+ // (i32.eqz (X))
+ // (i32.const 0|1)
+ // (Y)
+ // )
+ // =>
+ // (i32.eqz
+ // (select
+ // (X)
+ // (i32.const 1|0)
+ // (Y)
+ // )
+ // )
+ {
+ Unary* un;
+ Expression* x;
+ Const* c;
+ auto check = [&](Expression* a, Expression* b) {
+ if (matches(a, unary(&un, EqZInt32, any(&x))) && matches(b, ival(&c))) {
+ auto value = c->value.geti32();
+ return value == 0 || value == 1;
+ }
+ return false;
+ };
+ if (check(ifTrue, ifFalse) || check(ifFalse, ifTrue)) {
+ auto updateArm = [&](Expression* arm) -> Expression* {
+ if (arm == un) {
+ // This is the arm that had the eqz, which we need to remove.
+ return un->value;
+ } else {
+ // This is the arm with the constant, which we need to flip.
+ c->value = Literal(int32_t(1 - c->value.geti32()));
+ return c;
+ }
+ };
+ ifTrue = updateArm(ifTrue);
+ ifFalse = updateArm(ifFalse);
+ un->value = curr;
+ return replaceCurrent(un);
+ }
+ }
+ }
};
Pass* createOptimizeInstructionsPass() { return new OptimizeInstructions; }
diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast
index 5a180e3a5..bb05f17ba 100644
--- a/test/lit/passes/optimize-instructions.wast
+++ b/test/lit/passes/optimize-instructions.wast
@@ -11701,4 +11701,121 @@
(f64.abs (f64.add (local.get $x0) (local.get $x0)))
))
)
+ ;; CHECK: (func $ternary (param $x i32) (param $y i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (if (result i32)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ternary (param $x i32) (param $y i32)
+ (drop
+ (select
+ (i32.const 0)
+ (i32.eqz
+ (local.get $y)
+ )
+ (local.get $x)
+ )
+ )
+ (drop
+ (select
+ (i32.const 1)
+ (i32.eqz
+ (local.get $y)
+ )
+ (local.get $x)
+ )
+ )
+ (drop
+ (select
+ (i32.eqz
+ (local.get $y)
+ )
+ (i32.const 0)
+ (local.get $x)
+ )
+ )
+ (drop
+ (select
+ (i32.eqz
+ (local.get $y)
+ )
+ (i32.const 1)
+ (local.get $x)
+ )
+ )
+ ;; if works too
+ (drop
+ (if (result i32)
+ (local.get $x)
+ (i32.eqz
+ (local.get $y)
+ )
+ (i32.const 1)
+ )
+ )
+ )
+ ;; CHECK: (func $ternary-no (param $x i32) (param $y i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ternary-no (param $x i32) (param $y i32)
+ (drop
+ (select
+ (i32.const 2) ;; only 0 and 1 work
+ (i32.eqz
+ (local.get $y)
+ )
+ (local.get $x)
+ )
+ )
+ )
)
diff --git a/test/passes/asyncify_mod-asyncify-never-unwind_O.txt b/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
index d9308c21c..18f55e79e 100644
--- a/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
+++ b/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
@@ -17,8 +17,8 @@
(export "asyncify_get_state" (func $asyncify_get_state))
(func $calls-import (; has Stack IR ;)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(if (result i32)
(i32.eq
(global.get $__asyncify_state)
@@ -42,9 +42,9 @@
)
(i32.const 0)
)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(call $import)
)
diff --git a/test/passes/asyncify_optimize-level=1.txt b/test/passes/asyncify_optimize-level=1.txt
index 2c8835edf..9909918f2 100644
--- a/test/passes/asyncify_optimize-level=1.txt
+++ b/test/passes/asyncify_optimize-level=1.txt
@@ -19,8 +19,8 @@
(local.set $0
(block $__asyncify_unwind (result i32)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(if (result i32)
(i32.eq
(global.get $__asyncify_state)
@@ -44,9 +44,9 @@
)
(local.get $0)
)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import)
@@ -110,8 +110,8 @@
(local.set $1
(block $__asyncify_unwind (result i32)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(if (result i32)
(i32.eq
(global.get $__asyncify_state)
@@ -135,9 +135,9 @@
)
(local.get $1)
)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(local.set $1
@@ -205,8 +205,8 @@
(local.set $0
(block $__asyncify_unwind (result i32)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(if (result i32)
(i32.eq
(global.get $__asyncify_state)
@@ -230,9 +230,9 @@
)
(local.get $0)
)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(drop
@@ -343,12 +343,12 @@
)
)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $2)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import)
@@ -443,12 +443,12 @@
)
)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $1)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import)
@@ -551,12 +551,12 @@
)
)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $2)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import3
@@ -706,12 +706,12 @@
)
)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $1)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import3
@@ -825,12 +825,12 @@
)
)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $2)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import3
@@ -964,12 +964,12 @@
)
(loop $l
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $1)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import3
@@ -1090,12 +1090,12 @@
)
(loop $l
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $2)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(local.set $1
@@ -1116,12 +1116,12 @@
)
)
(br_if $l
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(global.get $__asyncify_state)
+ (i32.const 1)
+ (local.get $0)
)
- (i32.const 0)
- (local.get $0)
)
)
)
@@ -1194,12 +1194,12 @@
(call $boring)
)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $0)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import)
@@ -1299,12 +1299,12 @@
(call $boring-deep)
)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(local.get $0)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import-deep)
@@ -1374,8 +1374,8 @@
(local.set $0
(block $__asyncify_unwind (result i32)
(if
- (select
- (i32.eqz
+ (i32.eqz
+ (select
(if (result i32)
(i32.eq
(global.get $__asyncify_state)
@@ -1399,9 +1399,9 @@
)
(local.get $0)
)
+ (i32.const 0)
+ (global.get $__asyncify_state)
)
- (i32.const 1)
- (global.get $__asyncify_state)
)
(block
(call $import)