summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/RemoveUnusedBrs.cpp43
-rw-r--r--test/lit/passes/asyncify_optimize-level=1.wast497
-rw-r--r--test/lit/passes/remove-unused-brs.wast160
3 files changed, 444 insertions, 256 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 9861695e0..cbad81247 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -80,6 +80,8 @@ static bool canTurnIfIntoBrIf(Expression* ifCondition,
return !EffectAnalyzer(options, wasm, ifCondition).invalidates(value);
}
+const Index TooCostlyToRunUnconditionally = 7;
+
// Check if it is not worth it to run code unconditionally. This
// assumes we are trying to run two expressions where previously
// only one of the two might have executed. We assume here that
@@ -92,9 +94,18 @@ static bool tooCostlyToRunUnconditionally(const PassOptions& passOptions,
return false;
}
// Consider the cost of executing all the code unconditionally.
- const auto TOO_MUCH = 7;
auto total = CostAnalyzer(one).cost + CostAnalyzer(two).cost;
- return total >= TOO_MUCH;
+ return total >= TooCostlyToRunUnconditionally;
+}
+
+// As above, but a single expression that we are considering moving to a place
+// where it executes unconditionally.
+static bool tooCostlyToRunUnconditionally(const PassOptions& passOptions,
+ Expression* curr) {
+ if (passOptions.shrinkLevel) {
+ return false;
+ }
+ return CostAnalyzer(curr).cost >= TooCostlyToRunUnconditionally;
}
struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
@@ -374,6 +385,34 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
anotherCycle = true;
}
}
+
+ // if (condition-A) { if (condition-B) .. }
+ // =>
+ // if (condition-A ? condition-B : 0) { .. }
+ //
+ // This replaces an if, which is 3 bytes, with a select plus a zero, which
+ // is also 3 bytes. The benefit is that the select may be faster, and also
+ // further optimizations may be possible on the select.
+ if (auto* child = curr->ifTrue->dynCast<If>()) {
+ if (child->ifFalse) {
+ return;
+ }
+ // If running the child's condition unconditionally is too expensive,
+ // give up.
+ if (tooCostlyToRunUnconditionally(getPassOptions(), child->condition)) {
+ return;
+ }
+ // Of course we can't do this if the inner if's condition has side
+ // effects, as we would then execute those unconditionally.
+ if (EffectAnalyzer(getPassOptions(), *getModule(), child->condition)
+ .hasSideEffects()) {
+ return;
+ }
+ Builder builder(*getModule());
+ curr->condition = builder.makeSelect(
+ child->condition, curr->condition, builder.makeConst(int32_t(0)));
+ curr->ifTrue = child->ifTrue;
+ }
}
// TODO: if-else can be turned into a br_if as well, if one of the sides is
// a dead end we handle the case of a returned value to a local.set
diff --git a/test/lit/passes/asyncify_optimize-level=1.wast b/test/lit/passes/asyncify_optimize-level=1.wast
index 9406691c4..aa5172f26 100644
--- a/test/lit/passes/asyncify_optimize-level=1.wast
+++ b/test/lit/passes/asyncify_optimize-level=1.wast
@@ -460,54 +460,51 @@
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $__asyncify_unwind (result i32)
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (i32.store
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: (i32.sub
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (if (result i32)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (i32.store
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (call $import)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_if $__asyncify_unwind
;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (call $import)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br_if $__asyncify_unwind
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -540,105 +537,105 @@
;; CHECK: (func $calls-import2-if-else (param $0 i32)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (i32.store
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: (i32.sub
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $__asyncify_unwind (result i32)
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (i32.store
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: (i32.sub
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (if (result i32)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (i32.store
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (local.tee $1
- ;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (i32.store
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (call $import3
+ ;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (call $import3
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br_if $__asyncify_unwind
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_if $__asyncify_unwind
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $2)
@@ -647,17 +644,17 @@
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (call $import3
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br_if $__asyncify_unwind
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (call $import3
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_if $__asyncify_unwind
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -733,57 +730,55 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (local.tee $2
- ;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (local.tee $2
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (return
+ ;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (call $import3
+ ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (call $import3
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br_if $__asyncify_unwind
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_if $__asyncify_unwind
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -827,111 +822,105 @@
;; CHECK: (func $calls-import2-if-else-oneside2 (param $0 i32) (result i32)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (i32.store
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: (i32.sub
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $__asyncify_unwind (result i32)
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (i32.store
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: (i32.sub
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (if (result i32)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (i32.store
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (local.tee $1
- ;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (if (result i32)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (i32.store
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (global.get $__asyncify_data)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (call $import3
+ ;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (call $import3
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br_if $__asyncify_unwind
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_if $__asyncify_unwind
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.eq
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.eq
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (global.get $__asyncify_state)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (return
+ ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
diff --git a/test/lit/passes/remove-unused-brs.wast b/test/lit/passes/remove-unused-brs.wast
index 9ed319cb8..e5b29d2e6 100644
--- a/test/lit/passes/remove-unused-brs.wast
+++ b/test/lit/passes/remove-unused-brs.wast
@@ -335,4 +335,164 @@
)
)
)
+
+ ;; CHECK: (func $if-of-if
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (local.tee $x
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $if-of-if)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $if-of-if
+ (local $x i32)
+ ;; The outer if has side effects in the condition while the inner one does
+ ;; not, which means we can fold them.
+ (if
+ (local.tee $x
+ (i32.const 1)
+ )
+ (if
+ (local.get $x)
+ (call $if-of-if)
+ )
+ )
+ )
+
+ ;; CHECK: (func $if-of-if-but-side-effects
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.tee $x
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.tee $x
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $if-of-if-but-side-effects)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $if-of-if-but-side-effects
+ (local $x i32)
+ ;; The inner if has side effects in the condition, which prevents this
+ ;; optimization.
+ (if
+ (local.tee $x
+ (i32.const 1)
+ )
+ (if
+ (local.tee $x
+ (i32.const 2)
+ )
+ (call $if-of-if-but-side-effects)
+ )
+ )
+ )
+
+ ;; CHECK: (func $if-of-if-but-too-costly
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.tee $x
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $if-of-if-but-too-costly)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $if-of-if-but-too-costly
+ (local $x i32)
+ ;; The inner if's condition has no effects, but it is very costly, so do not
+ ;; run it unconditionally - leave this unoptimized.
+ (if
+ (local.tee $x
+ (i32.const 1)
+ )
+ (if
+ (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz
+ (local.get $x)
+ ))))))))
+ (call $if-of-if-but-too-costly)
+ )
+ )
+ )
+
+ ;; CHECK: (func $if-of-if-but-inner-else
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.tee $x
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (call $if-of-if-but-inner-else)
+ ;; CHECK-NEXT: (call $if-of-if)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $if-of-if-but-inner-else
+ (local $x i32)
+ ;; The inner if has an else. For now, leave this unoptimized.
+ (if
+ (local.tee $x
+ (i32.const 1)
+ )
+ (if
+ (local.get $x)
+ (call $if-of-if-but-inner-else)
+ (call $if-of-if)
+ )
+ )
+ )
+
+ ;; CHECK: (func $if-of-if-but-outer-else
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.tee $x
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (call $if-of-if-but-outer-else)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $if-of-if)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $if-of-if-but-outer-else
+ (local $x i32)
+ ;; The outer if has an else. For now, leave this unoptimized.
+ (if
+ (local.tee $x
+ (i32.const 1)
+ )
+ (if
+ (local.get $x)
+ (call $if-of-if-but-outer-else)
+ )
+ (call $if-of-if)
+ )
+ )
)