From 498210cf0b006ff86e57bd6a68816bda2467266b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 27 Oct 2016 12:28:07 -0700 Subject: recreate simply ifs --- src/passes/RemoveUnusedBrs.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src') diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 328ca275b..63f5d6585 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -422,6 +422,31 @@ struct RemoveUnusedBrs : public WalkerPassname.is() && list.size() >= 2) { + auto* br = list[0]->dynCast(); + 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); + } + } + } } bool selectify; -- cgit v1.2.3 From af021c52634d66db1a3815f553602b9f9464e023 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 27 Oct 2016 14:24:43 -0700 Subject: merge adjacent br_ifs --- src/passes/RemoveUnusedBrs.cpp | 70 +++++++++++++------- test/passes/remove-unused-brs_shrink-level=1.txt | 78 +++++++++++++++++++++++ test/passes/remove-unused-brs_shrink-level=1.wast | 39 ++++++++++++ 3 files changed, 163 insertions(+), 24 deletions(-) (limited to 'src') 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> { + 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 WalkerPassname.is() && list.size() >= 2) { - auto* br = list[0]->dynCast(); - 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(); + if (!br1 || !br1->condition) continue; + auto* br2 = list[i + 1]->dynCast(); + 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(); + 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 diff --git a/test/passes/remove-unused-brs_shrink-level=1.txt b/test/passes/remove-unused-brs_shrink-level=1.txt index 0356cc1da..68015f73f 100644 --- a/test/passes/remove-unused-brs_shrink-level=1.txt +++ b/test/passes/remove-unused-brs_shrink-level=1.txt @@ -16,4 +16,82 @@ ) ) ) + (func $join-br_ifs (type $1) + (block $out + (br_if $out + (i32.or + (i32.const 1) + (i32.const 2) + ) + ) + (nop) + (br_if $out + (i32.const 3) + ) + ) + (block $out2 + (block $out3 + (br_if $out2 + (i32.const 1) + ) + (br_if $out3 + (i32.const 2) + ) + (br_if $out2 + (i32.const 3) + ) + ) + (unreachable) + ) + (block $out4 + (block $out5 + (br_if $out4 + (i32.const 1) + ) + (br_if $out5 + (i32.or + (i32.const 2) + (i32.const 3) + ) + ) + (nop) + ) + (unreachable) + ) + (block $out6 + (block $out7 + (br_if $out6 + (i32.or + (i32.const 1) + (i32.const 2) + ) + ) + (nop) + (br_if $out7 + (i32.const 3) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.or + (call $b14) + (i32.const 0) + ) + ) + (block + (nop) + (nop) + ) + ) + (block $out80 + (br_if $out80 + (i32.const 1) + ) + (br_if $out80 + (call $b14) + ) + ) + ) ) diff --git a/test/passes/remove-unused-brs_shrink-level=1.wast b/test/passes/remove-unused-brs_shrink-level=1.wast index 9698bd899..5a2234de6 100644 --- a/test/passes/remove-unused-brs_shrink-level=1.wast +++ b/test/passes/remove-unused-brs_shrink-level=1.wast @@ -16,5 +16,44 @@ ) ) ) + (func $join-br_ifs + (block $out + (br_if $out (i32.const 1)) + (br_if $out (i32.const 2)) + (br_if $out (i32.const 3)) + ) + (block $out2 + (block $out3 + (br_if $out2 (i32.const 1)) + (br_if $out3 (i32.const 2)) + (br_if $out2 (i32.const 3)) + ) + (unreachable) + ) + (block $out4 + (block $out5 + (br_if $out4 (i32.const 1)) + (br_if $out5 (i32.const 2)) + (br_if $out5 (i32.const 3)) + ) + (unreachable) + ) + (block $out6 + (block $out7 + (br_if $out6 (i32.const 1)) + (br_if $out6 (i32.const 2)) + (br_if $out7 (i32.const 3)) + ) + (unreachable) + ) + (block $out8 + (br_if $out8 (call $b14)) ;; side effect + (br_if $out8 (i32.const 0)) + ) + (block $out8 + (br_if $out8 (i32.const 1)) + (br_if $out8 (call $b14)) ;; side effect + ) + ) ) -- cgit v1.2.3