diff options
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 51 | ||||
-rw-r--r-- | test/emcc_O2_hello_world.fromasm | 68 | ||||
-rw-r--r-- | test/emcc_O2_hello_world.fromasm.imprecise | 68 | ||||
-rw-r--r-- | test/emcc_hello_world.fromasm | 203 | ||||
-rw-r--r-- | test/emcc_hello_world.fromasm.imprecise | 203 | ||||
-rw-r--r-- | test/memorygrowth.fromasm | 68 | ||||
-rw-r--r-- | test/memorygrowth.fromasm.imprecise | 68 | ||||
-rw-r--r-- | test/passes/remove-unused-brs.txt | 79 | ||||
-rw-r--r-- | test/passes/remove-unused-brs.wast | 36 | ||||
-rw-r--r-- | test/passes/remove-unused-brs_shrink-level=1.txt | 78 | ||||
-rw-r--r-- | test/passes/remove-unused-brs_shrink-level=1.wast | 39 |
11 files changed, 608 insertions, 353 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 diff --git a/test/emcc_O2_hello_world.fromasm b/test/emcc_O2_hello_world.fromasm index 632906543..e4cbfdce5 100644 --- a/test/emcc_O2_hello_world.fromasm +++ b/test/emcc_O2_hello_world.fromasm @@ -8987,48 +8987,46 @@ ) (block (loop $while-in - (block $while-out - (br_if $while-out - (i32.eqz - (i32.and - (get_local $0) - (i32.const 3) - ) - ) - ) - (if - (i32.eqz - (get_local $2) - ) - (return - (get_local $3) - ) - ) - (i32.store8 + (if + (i32.and (get_local $0) - (i32.load8_s - (get_local $1) - ) + (i32.const 3) ) - (set_local $0 - (i32.add + (block + (if + (i32.eqz + (get_local $2) + ) + (return + (get_local $3) + ) + ) + (i32.store8 (get_local $0) - (i32.const 1) + (i32.load8_s + (get_local $1) + ) ) - ) - (set_local $1 - (i32.add - (get_local $1) - (i32.const 1) + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) ) - ) - (set_local $2 - (i32.sub - (get_local $2) - (i32.const 1) + (set_local $1 + (i32.add + (get_local $1) + (i32.const 1) + ) ) + (set_local $2 + (i32.sub + (get_local $2) + (i32.const 1) + ) + ) + (br $while-in) ) - (br $while-in) ) ) (loop $while-in1 diff --git a/test/emcc_O2_hello_world.fromasm.imprecise b/test/emcc_O2_hello_world.fromasm.imprecise index 36a8a7099..684fa5a6b 100644 --- a/test/emcc_O2_hello_world.fromasm.imprecise +++ b/test/emcc_O2_hello_world.fromasm.imprecise @@ -8985,48 +8985,46 @@ ) (block (loop $while-in - (block $while-out - (br_if $while-out - (i32.eqz - (i32.and - (get_local $0) - (i32.const 3) - ) - ) - ) - (if - (i32.eqz - (get_local $2) - ) - (return - (get_local $3) - ) - ) - (i32.store8 + (if + (i32.and (get_local $0) - (i32.load8_s - (get_local $1) - ) + (i32.const 3) ) - (set_local $0 - (i32.add + (block + (if + (i32.eqz + (get_local $2) + ) + (return + (get_local $3) + ) + ) + (i32.store8 (get_local $0) - (i32.const 1) + (i32.load8_s + (get_local $1) + ) ) - ) - (set_local $1 - (i32.add - (get_local $1) - (i32.const 1) + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) ) - ) - (set_local $2 - (i32.sub - (get_local $2) - (i32.const 1) + (set_local $1 + (i32.add + (get_local $1) + (i32.const 1) + ) ) + (set_local $2 + (i32.sub + (get_local $2) + (i32.const 1) + ) + ) + (br $while-in) ) - (br $while-in) ) ) (loop $while-in1 diff --git a/test/emcc_hello_world.fromasm b/test/emcc_hello_world.fromasm index 7443cdaff..904d73289 100644 --- a/test/emcc_hello_world.fromasm +++ b/test/emcc_hello_world.fromasm @@ -2050,8 +2050,8 @@ ) ) (loop $while-in3 - (block $while-out2 - (br_if $while-out2 + (if + (i32.eqz (i32.and (i32.xor (i32.and @@ -2073,24 +2073,27 @@ ) ) ) - (set_local $2 - (i32.add - (get_local $2) - (i32.const 4) + (block + (nop) + (set_local $2 + (i32.add + (get_local $2) + (i32.const 4) + ) ) - ) - (br_if $while-in3 - (i32.gt_u - (tee_local $0 - (i32.add - (get_local $0) - (i32.const -4) + (br_if $while-in3 + (i32.gt_u + (tee_local $0 + (i32.add + (get_local $0) + (i32.const -4) + ) ) + (i32.const 3) ) - (i32.const 3) ) + (br $jumpthreading$inner$0) ) - (br $jumpthreading$inner$0) ) ) (br $jumpthreading$outer$0) @@ -4828,29 +4831,30 @@ ) ) (loop $while-in68 - (block $while-out67 - (br_if $while-out67 - (i32.le_u - (get_local $5) - (get_local $6) - ) + (if + (i32.gt_u + (get_local $5) + (get_local $6) ) - (if - (i32.eqz - (i32.load - (tee_local $10 - (i32.add - (get_local $5) - (i32.const -4) + (block + (nop) + (if + (i32.eqz + (i32.load + (tee_local $10 + (i32.add + (get_local $5) + (i32.const -4) + ) ) ) ) - ) - (block - (set_local $5 - (get_local $10) + (block + (set_local $5 + (get_local $10) + ) + (br $while-in68) ) - (br $while-in68) ) ) ) @@ -7234,49 +7238,48 @@ (i32.const 1) ) (loop $while-in130 - (block $while-out129 - (br_if $while-out129 - (i32.eqz - (tee_local $1 - (i32.load - (i32.add - (get_local $4) - (i32.shl - (get_local $0) - (i32.const 2) - ) - ) + (if + (tee_local $1 + (i32.load + (i32.add + (get_local $4) + (i32.shl + (get_local $0) + (i32.const 2) ) ) ) ) - (call $_pop_arg_336 - (i32.add - (get_local $3) - (i32.shl - (get_local $0) - (i32.const 3) + (block + (nop) + (call $_pop_arg_336 + (i32.add + (get_local $3) + (i32.shl + (get_local $0) + (i32.const 3) + ) ) + (get_local $1) + (get_local $2) ) - (get_local $1) - (get_local $2) - ) - (br_if $while-in130 - (i32.lt_s - (tee_local $0 - (i32.add - (get_local $0) - (i32.const 1) + (br_if $while-in130 + (i32.lt_s + (tee_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) ) + (i32.const 10) ) - (i32.const 10) ) - ) - (block - (set_local $16 - (i32.const 1) + (block + (set_local $16 + (i32.const 1) + ) + (br $label$break$L343) ) - (br $label$break$L343) ) ) ) @@ -15700,48 +15703,46 @@ ) (block (loop $while-in - (block $while-out - (br_if $while-out - (i32.eqz - (i32.and - (get_local $0) - (i32.const 3) - ) - ) - ) - (if - (i32.eqz - (get_local $2) - ) - (return - (get_local $3) - ) - ) - (i32.store8 + (if + (i32.and (get_local $0) - (i32.load8_s - (get_local $1) - ) + (i32.const 3) ) - (set_local $0 - (i32.add + (block + (if + (i32.eqz + (get_local $2) + ) + (return + (get_local $3) + ) + ) + (i32.store8 (get_local $0) - (i32.const 1) + (i32.load8_s + (get_local $1) + ) ) - ) - (set_local $1 - (i32.add - (get_local $1) - (i32.const 1) + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) ) - ) - (set_local $2 - (i32.sub - (get_local $2) - (i32.const 1) + (set_local $1 + (i32.add + (get_local $1) + (i32.const 1) + ) + ) + (set_local $2 + (i32.sub + (get_local $2) + (i32.const 1) + ) ) + (br $while-in) ) - (br $while-in) ) ) (loop $while-in1 diff --git a/test/emcc_hello_world.fromasm.imprecise b/test/emcc_hello_world.fromasm.imprecise index b3ce6e84e..c8df16aa6 100644 --- a/test/emcc_hello_world.fromasm.imprecise +++ b/test/emcc_hello_world.fromasm.imprecise @@ -2043,8 +2043,8 @@ ) ) (loop $while-in3 - (block $while-out2 - (br_if $while-out2 + (if + (i32.eqz (i32.and (i32.xor (i32.and @@ -2066,24 +2066,27 @@ ) ) ) - (set_local $2 - (i32.add - (get_local $2) - (i32.const 4) + (block + (nop) + (set_local $2 + (i32.add + (get_local $2) + (i32.const 4) + ) ) - ) - (br_if $while-in3 - (i32.gt_u - (tee_local $0 - (i32.add - (get_local $0) - (i32.const -4) + (br_if $while-in3 + (i32.gt_u + (tee_local $0 + (i32.add + (get_local $0) + (i32.const -4) + ) ) + (i32.const 3) ) - (i32.const 3) ) + (br $jumpthreading$inner$0) ) - (br $jumpthreading$inner$0) ) ) (br $jumpthreading$outer$0) @@ -4820,29 +4823,30 @@ ) ) (loop $while-in68 - (block $while-out67 - (br_if $while-out67 - (i32.le_u - (get_local $5) - (get_local $6) - ) + (if + (i32.gt_u + (get_local $5) + (get_local $6) ) - (if - (i32.eqz - (i32.load - (tee_local $10 - (i32.add - (get_local $5) - (i32.const -4) + (block + (nop) + (if + (i32.eqz + (i32.load + (tee_local $10 + (i32.add + (get_local $5) + (i32.const -4) + ) ) ) ) - ) - (block - (set_local $5 - (get_local $10) + (block + (set_local $5 + (get_local $10) + ) + (br $while-in68) ) - (br $while-in68) ) ) ) @@ -7220,49 +7224,48 @@ (i32.const 1) ) (loop $while-in130 - (block $while-out129 - (br_if $while-out129 - (i32.eqz - (tee_local $1 - (i32.load - (i32.add - (get_local $4) - (i32.shl - (get_local $0) - (i32.const 2) - ) - ) + (if + (tee_local $1 + (i32.load + (i32.add + (get_local $4) + (i32.shl + (get_local $0) + (i32.const 2) ) ) ) ) - (call $_pop_arg_336 - (i32.add - (get_local $3) - (i32.shl - (get_local $0) - (i32.const 3) + (block + (nop) + (call $_pop_arg_336 + (i32.add + (get_local $3) + (i32.shl + (get_local $0) + (i32.const 3) + ) ) + (get_local $1) + (get_local $2) ) - (get_local $1) - (get_local $2) - ) - (br_if $while-in130 - (i32.lt_s - (tee_local $0 - (i32.add - (get_local $0) - (i32.const 1) + (br_if $while-in130 + (i32.lt_s + (tee_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) ) + (i32.const 10) ) - (i32.const 10) ) - ) - (block - (set_local $16 - (i32.const 1) + (block + (set_local $16 + (i32.const 1) + ) + (br $label$break$L343) ) - (br $label$break$L343) ) ) ) @@ -15686,48 +15689,46 @@ ) (block (loop $while-in - (block $while-out - (br_if $while-out - (i32.eqz - (i32.and - (get_local $0) - (i32.const 3) - ) - ) - ) - (if - (i32.eqz - (get_local $2) - ) - (return - (get_local $3) - ) - ) - (i32.store8 + (if + (i32.and (get_local $0) - (i32.load8_s - (get_local $1) - ) + (i32.const 3) ) - (set_local $0 - (i32.add + (block + (if + (i32.eqz + (get_local $2) + ) + (return + (get_local $3) + ) + ) + (i32.store8 (get_local $0) - (i32.const 1) + (i32.load8_s + (get_local $1) + ) ) - ) - (set_local $1 - (i32.add - (get_local $1) - (i32.const 1) + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) ) - ) - (set_local $2 - (i32.sub - (get_local $2) - (i32.const 1) + (set_local $1 + (i32.add + (get_local $1) + (i32.const 1) + ) + ) + (set_local $2 + (i32.sub + (get_local $2) + (i32.const 1) + ) ) + (br $while-in) ) - (br $while-in) ) ) (loop $while-in1 diff --git a/test/memorygrowth.fromasm b/test/memorygrowth.fromasm index d2c814e8d..48b09d9c3 100644 --- a/test/memorygrowth.fromasm +++ b/test/memorygrowth.fromasm @@ -9052,48 +9052,46 @@ ) (block (loop $while-in - (block $while-out - (br_if $while-out - (i32.eqz - (i32.and - (get_local $0) - (i32.const 3) - ) - ) - ) - (if - (i32.eqz - (get_local $2) - ) - (return - (get_local $3) - ) - ) - (i32.store8 + (if + (i32.and (get_local $0) - (i32.load8_s - (get_local $1) - ) + (i32.const 3) ) - (set_local $0 - (i32.add + (block + (if + (i32.eqz + (get_local $2) + ) + (return + (get_local $3) + ) + ) + (i32.store8 (get_local $0) - (i32.const 1) + (i32.load8_s + (get_local $1) + ) ) - ) - (set_local $1 - (i32.add - (get_local $1) - (i32.const 1) + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) ) - ) - (set_local $2 - (i32.sub - (get_local $2) - (i32.const 1) + (set_local $1 + (i32.add + (get_local $1) + (i32.const 1) + ) ) + (set_local $2 + (i32.sub + (get_local $2) + (i32.const 1) + ) + ) + (br $while-in) ) - (br $while-in) ) ) (loop $while-in1 diff --git a/test/memorygrowth.fromasm.imprecise b/test/memorygrowth.fromasm.imprecise index f9fa51bce..f509f23f2 100644 --- a/test/memorygrowth.fromasm.imprecise +++ b/test/memorygrowth.fromasm.imprecise @@ -9050,48 +9050,46 @@ ) (block (loop $while-in - (block $while-out - (br_if $while-out - (i32.eqz - (i32.and - (get_local $0) - (i32.const 3) - ) - ) - ) - (if - (i32.eqz - (get_local $2) - ) - (return - (get_local $3) - ) - ) - (i32.store8 + (if + (i32.and (get_local $0) - (i32.load8_s - (get_local $1) - ) + (i32.const 3) ) - (set_local $0 - (i32.add + (block + (if + (i32.eqz + (get_local $2) + ) + (return + (get_local $3) + ) + ) + (i32.store8 (get_local $0) - (i32.const 1) + (i32.load8_s + (get_local $1) + ) ) - ) - (set_local $1 - (i32.add - (get_local $1) - (i32.const 1) + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) ) - ) - (set_local $2 - (i32.sub - (get_local $2) - (i32.const 1) + (set_local $1 + (i32.add + (get_local $1) + (i32.const 1) + ) ) + (set_local $2 + (i32.sub + (get_local $2) + (i32.const 1) + ) + ) + (br $while-in) ) - (br $while-in) ) ) (loop $while-in1 diff --git a/test/passes/remove-unused-brs.txt b/test/passes/remove-unused-brs.txt index ab3260a4b..b95ace90d 100644 --- a/test/passes/remove-unused-brs.txt +++ b/test/passes/remove-unused-brs.txt @@ -458,12 +458,15 @@ ) ) (loop $in39 - (block $out40 - (br_if $out40 + (if + (i32.eqz (i32.const 0) ) - (br_if $in39 - (i32.const 1) + (block + (nop) + (br_if $in39 + (i32.const 1) + ) ) ) ) @@ -595,13 +598,16 @@ ) ) (loop $in72 - (block $out73 - (br_if $out73 + (if + (i32.eqz (i32.const 0) ) - (call $loops) - (return) - (br $in72) + (block + (nop) + (call $loops) + (return) + (br $in72) + ) ) ) (loop $in75 @@ -876,4 +882,59 @@ ) ) ) + (func $iffify (type $1) + (if + (i32.eqz + (i32.const 0) + ) + (block + (nop) + (drop + (i32.const 1) + ) + (drop + (i32.const 2) + ) + ) + ) + (block $no + (br_if $no + (i32.const 0) + ) + (drop + (i32.const 1) + ) + (br $no) + (drop + (i32.const 2) + ) + ) + (block $no2 + (br_if $no2 + (i32.const 0) + ) + ) + (block $no3 + (br $no3) + (drop + (i32.const 1) + ) + (drop + (i32.const 2) + ) + ) + (block $no5 + (block $no4 + (br_if $no5 + (i32.const 0) + ) + (drop + (i32.const 1) + ) + (drop + (i32.const 2) + ) + ) + ) + ) ) diff --git a/test/passes/remove-unused-brs.wast b/test/passes/remove-unused-brs.wast index 7a401b893..8b0ad357b 100644 --- a/test/passes/remove-unused-brs.wast +++ b/test/passes/remove-unused-brs.wast @@ -795,5 +795,41 @@ ) ) ) + (func $iffify + (block $yes + (br_if $yes + (i32.const 0) + ) + (drop (i32.const 1)) + (drop (i32.const 2)) + ) + (block $no + (br_if $no + (i32.const 0) + ) + (drop (i32.const 1)) + (br $no) + (drop (i32.const 2)) + ) + (block $no2 + (br_if $no2 + (i32.const 0) + ) + ) + (block $no3 + (br $no3) + (drop (i32.const 1)) + (drop (i32.const 2)) + ) + (block $no5 + (block $no4 + (br_if $no5 + (i32.const 0) + ) + (drop (i32.const 1)) + (drop (i32.const 2)) + ) + ) + ) ) 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 + ) + ) ) |