summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/RemoveUnusedBrs.cpp90
-rw-r--r--test/passes/remove-unused-brs.txt57
-rw-r--r--test/passes/remove-unused-brs.wast56
3 files changed, 183 insertions, 20 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 5b6f0839b..ce839a646 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -607,26 +607,62 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
list[i] = builder.makeDrop(br1->condition);
}
}
- // combine adjacent br_ifs that test the same value into a br_table,
- // when that makes sense
+ // Combine adjacent br_ifs that test the same value into a br_table,
+ // when that makes sense.
tablify(curr);
- // Restructuring of ifs: if we have
- // (block $x
- // (br_if $x (cond))
- // .., no other references to $x
- // )
- // then we can turn that into (if (!cond) ..).
- // Code size wise, we turn the block into an if (no change), and
- // lose the br_if (-2). .. turns into the body of the if in the binary
- // format. We need to flip the condition, which at worst adds 1.
- if (curr->name.is()) {
- auto* br = list[0]->dynCast<Break>();
- // we seek a regular br_if; if the type is unreachable that means it is not
- // actually reached, so ignore
- if (br && br->condition && br->name == curr->name && br->type != unreachable) {
- assert(!br->value); // can't, it would be dropped or last in the block
- if (BranchUtils::BranchSeeker::countNamed(curr, curr->name) == 1) {
- // no other breaks to that name, so we can do this
+ // Pattern-patch ifs, recreating them when it makes sense.
+ restructureIf(curr);
+ }
+ }
+
+ // Restructuring of ifs: if we have
+ // (block $x
+ // (br_if $x (cond))
+ // .., no other references to $x
+ // )
+ // then we can turn that into (if (!cond) ..).
+ // Code size wise, we turn the block into an if (no change), and
+ // lose the br_if (-2). .. turns into the body of the if in the binary
+ // format. We need to flip the condition, which at worst adds 1.
+ // If the block has a return value, we can do something similar, removing
+ // the drop from the br_if and putting the if on the outside,
+ // (block $x
+ // (br_if $x (value) (cond))
+ // .., no other references to $x
+ // ..final element..
+ // )
+ // =>
+ // (if
+ // (cond)
+ // (value) ;; must not have side effects!
+ // (block
+ // .., no other references to $x
+ // ..final element..
+ // )
+ // )
+ // This is beneficial as the block will likely go away in the binary
+ // format (the if arm is an implicit block), and the drop is removed.
+ void restructureIf(Block* curr) {
+ auto& list = curr->list;
+ // We should be called only on potentially-interesting lists.
+ assert(list.size() >= 2);
+ if (curr->name.is()) {
+ Break* br = nullptr;
+ Drop* drop = list[0]->dynCast<Drop>();
+ if (drop) {
+ br = drop->value->dynCast<Break>();
+ } else {
+ br = list[0]->dynCast<Break>();
+ }
+ // Check if the br is conditional and goes to the block. It may or may not have
+ // a value, depending on if it was dropped or not.
+ // If the type is unreachable that means it is not actually reached,
+ // which we can ignore.
+ if (br && br->condition && br->name == curr->name && br->type != unreachable) {
+ if (BranchUtils::BranchSeeker::countNamed(curr, curr->name) == 1) {
+ // no other breaks to that name, so we can do this
+ if (!drop) {
+ assert(!br->value);
Builder builder(*getModule());
replaceCurrent(builder.makeIf(
builder.makeUnary(EqZInt32, br->condition),
@@ -635,7 +671,21 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
curr->name = Name();
ExpressionManipulator::nop(br);
curr->finalize(curr->type);
- return;
+ } else {
+ // If the items we move around have side effects, we can't do this.
+ // TODO: we could use a select, in some cases..?
+ if (!EffectAnalyzer(passOptions, br->value).hasSideEffects() &&
+ !EffectAnalyzer(passOptions, br->condition).hasSideEffects()) {
+ ExpressionManipulator::nop(list[0]);
+ Builder builder(*getModule());
+ replaceCurrent(
+ builder.makeIf(
+ br->condition,
+ br->value,
+ curr
+ )
+ );
+ }
}
}
}
diff --git a/test/passes/remove-unused-brs.txt b/test/passes/remove-unused-brs.txt
index b5bcce9f2..03eb7b716 100644
--- a/test/passes/remove-unused-brs.txt
+++ b/test/passes/remove-unused-brs.txt
@@ -1946,4 +1946,61 @@
)
)
)
+ (func $drop-restructure-if (; 81 ;) (type $3) (param $x i32) (param $y i32) (result i32)
+ (if (result i32)
+ (get_local $y)
+ (get_local $x)
+ (block $label$2 (result i32)
+ (nop)
+ (i32.const 0)
+ )
+ )
+ )
+ (func $drop-restructure-if-final (; 82 ;) (type $3) (param $x i32) (param $y i32) (result i32)
+ (if (result i32)
+ (get_local $y)
+ (get_local $x)
+ (block $label$2 (result i32)
+ (nop)
+ (unreachable)
+ )
+ )
+ )
+ (func $drop-restructure-if-middle (; 83 ;) (type $3) (param $x i32) (param $y i32) (result i32)
+ (if (result i32)
+ (get_local $y)
+ (get_local $x)
+ (block $label$2 (result i32)
+ (nop)
+ (nop)
+ (i32.const 0)
+ )
+ )
+ )
+ (func $drop-restructure-if-bad (; 84 ;) (type $3) (param $x i32) (param $y i32) (result i32)
+ (block $label$2 (result i32)
+ (drop
+ (br_if $label$2
+ (tee_local $y
+ (get_local $x)
+ )
+ (get_local $y)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ (func $drop-restructure-if-bad-2 (; 85 ;) (type $3) (param $x i32) (param $y i32) (result i32)
+ (block $label$2 (result i32)
+ (drop
+ (br_if $label$2
+ (get_local $y)
+ (tee_local $y
+ (get_local $x)
+ )
+ )
+ )
+ (i32.const 0)
+ )
+ )
)
diff --git a/test/passes/remove-unused-brs.wast b/test/passes/remove-unused-brs.wast
index 8325b47ac..7f77fd00c 100644
--- a/test/passes/remove-unused-brs.wast
+++ b/test/passes/remove-unused-brs.wast
@@ -1561,5 +1561,61 @@
)
)
)
+ (func $drop-restructure-if (param $x i32) (param $y i32) (result i32)
+ (block $label$2 (result i32)
+ (drop
+ (br_if $label$2
+ (get_local $x)
+ (get_local $y)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ (func $drop-restructure-if-final (param $x i32) (param $y i32) (result i32)
+ (block $label$2 (result i32)
+ (drop
+ (br_if $label$2
+ (get_local $x)
+ (get_local $y)
+ )
+ )
+ (unreachable)
+ )
+ )
+ (func $drop-restructure-if-middle (param $x i32) (param $y i32) (result i32)
+ (block $label$2 (result i32)
+ (drop
+ (br_if $label$2
+ (get_local $x)
+ (get_local $y)
+ )
+ )
+ (nop) ;; the middle
+ (i32.const 0)
+ )
+ )
+ (func $drop-restructure-if-bad (param $x i32) (param $y i32) (result i32)
+ (block $label$2 (result i32)
+ (drop
+ (br_if $label$2
+ (tee_local $y (get_local $x))
+ (get_local $y)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ (func $drop-restructure-if-bad-2 (param $x i32) (param $y i32) (result i32)
+ (block $label$2 (result i32)
+ (drop
+ (br_if $label$2
+ (get_local $y)
+ (tee_local $y (get_local $x))
+ )
+ )
+ (i32.const 0)
+ )
+ )
)