summaryrefslogtreecommitdiff
path: root/src/passes/RemoveUnusedBrs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/RemoveUnusedBrs.cpp')
-rw-r--r--src/passes/RemoveUnusedBrs.cpp70
1 files changed, 46 insertions, 24 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 63f5d6585..69a7c4ff1 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -393,6 +393,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R
// perform some final optimizations
struct FinalOptimizer : public PostWalker<FinalOptimizer, Visitor<FinalOptimizer>> {
+ bool selectify;
+
void visitBlock(Block* curr) {
// if a block has an if br else br, we can un-conditionalize the latter, allowing
// the if to become a br_if.
@@ -422,35 +424,55 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R
continue;
}
}
- // 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() && list.size() >= 2) {
- auto* br = list[0]->dynCast<Break>();
- if (br && br->condition && br->name == curr->name) {
- assert(!br->value); // can't, it would be dropped or last in the block
- if (BreakSeeker::count(curr, curr->name) == 1) {
- // no other breaks to that name, so we can do this
- Builder builder(*getModule());
- replaceCurrent(builder.makeIf(
- builder.makeUnary(EqZInt32, br->condition),
- curr
- ));
- curr->name = Name();
- ExpressionManipulator::nop(br);
+ if (list.size() >= 2) {
+ if (selectify) {
+ // Join adjacent br_ifs to the same target, making one br_if with
+ // a "selectified" condition that executes both.
+ for (Index i = 0; i < list.size() - 1; i++) {
+ auto* br1 = list[i]->dynCast<Break>();
+ if (!br1 || !br1->condition) continue;
+ auto* br2 = list[i + 1]->dynCast<Break>();
+ if (!br2 || !br2->condition) continue;
+ if (br1->name == br2->name) {
+ assert(!br1->value && !br2->value);
+ if (!EffectAnalyzer(br2->condition).hasSideEffects()) {
+ // it's ok to execute them both, do it
+ Builder builder(*getModule());
+ br1->condition = builder.makeBinary(OrInt32, br1->condition, br2->condition);
+ ExpressionManipulator::nop(br2);
+ }
+ }
+ }
+ }
+ // 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>();
+ if (br && br->condition && br->name == curr->name) {
+ assert(!br->value); // can't, it would be dropped or last in the block
+ if (BreakSeeker::count(curr, curr->name) == 1) {
+ // no other breaks to that name, so we can do this
+ Builder builder(*getModule());
+ replaceCurrent(builder.makeIf(
+ builder.makeUnary(EqZInt32, br->condition),
+ curr
+ ));
+ curr->name = Name();
+ ExpressionManipulator::nop(br);
+ return;
+ }
}
}
}
}
- bool selectify;
-
void visitIf(If* curr) {
// we may have simplified ifs enough to turn them into selects
// this is helpful for code size, but can be a tradeoff with performance as we run both code paths