summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/RemoveUnusedBrs.cpp51
1 files changed, 49 insertions, 2 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 328ca275b..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,10 +424,55 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R
continue;
}
}
+ 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