diff options
-rw-r--r-- | src/asm2wasm.h | 2 | ||||
-rw-r--r-- | src/ast_utils.h | 20 | ||||
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 6 | ||||
-rw-r--r-- | test/min.asm.js | 8 | ||||
-rw-r--r-- | test/min.fromasm | 8 | ||||
-rw-r--r-- | test/min.fromasm.imprecise | 8 | ||||
-rw-r--r-- | test/min.fromasm.imprecise.no-opts | 10 | ||||
-rw-r--r-- | test/min.fromasm.no-opts | 10 | ||||
-rw-r--r-- | test/passes/remove-unused-brs.txt | 31 | ||||
-rw-r--r-- | test/passes/remove-unused-brs.wast | 34 |
10 files changed, 122 insertions, 15 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index eb5413e20..bce67a582 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -878,7 +878,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) { Name tempRet0; { Expression* curr = wasm.getFunction(getTempRet0)->body; - if (curr->is<Block>()) curr = curr->cast<Block>()->list[0]; + if (curr->is<Block>()) curr = curr->cast<Block>()->list.back(); if (curr->is<Return>()) curr = curr->cast<Return>()->value; auto* get = curr->cast<GetGlobal>(); tempRet0 = get->name; diff --git a/src/ast_utils.h b/src/ast_utils.h index 4664f22ae..ff5d93e02 100644 --- a/src/ast_utils.h +++ b/src/ast_utils.h @@ -51,12 +51,14 @@ struct BreakSeeker : public PostWalker<BreakSeeker, Visitor<BreakSeeker>> { } static bool has(Expression* tree, Name target) { + if (!target.is()) return false; BreakSeeker breakSeeker(target); breakSeeker.walk(tree); return breakSeeker.found > 0; } static Index count(Expression* tree, Name target) { + if (!target.is()) return 0; BreakSeeker breakSeeker(target); breakSeeker.walk(tree); return breakSeeker.found; @@ -425,18 +427,16 @@ struct ExpressionAnalyzer { return !curr->condition && !curr->value; } - // Checks if an expression ends with a simple break, - // and returns a pointer to it if so. - // (It might also have other internal branches.) - static Expression* getEndingSimpleBreak(Expression* curr) { + // Checks if an expression does not flow out in an obvious way. + // We return true if it cannot flow out. If it can flow out, we + // might still return true, as the analysis here is simple and fast. + static bool obviouslyDoesNotFlowOut(Expression* curr) { if (auto* br = curr->dynCast<Break>()) { - if (isSimple(br)) return br; - return nullptr; + if (!br->condition) return true; + } else if (auto* block = curr->dynCast<Block>()) { + if (block->list.size() > 0 && obviouslyDoesNotFlowOut(block->list.back()) && !BreakSeeker::has(block, block->name)) return true; } - if (auto* block = curr->dynCast<Block>()) { - if (block->list.size() > 0) return getEndingSimpleBreak(block->list.back()); - } - return nullptr; + return false; } template<typename T> diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 86a46374f..fa8ab2f6c 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -218,7 +218,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R // let's try to move the code going to the top of the loop into the if-else if (!iff->ifFalse) { // we need the ifTrue to break, so it cannot reach the code we want to move - if (ExpressionAnalyzer::getEndingSimpleBreak(iff->ifTrue)) { + if (ExpressionAnalyzer::obviouslyDoesNotFlowOut(iff->ifTrue)) { iff->ifFalse = builder.stealSlice(block, i + 1, list.size()); return true; } @@ -226,10 +226,10 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R // this is already an if-else. if one side is a dead end, we can append to the other, if // there is no returned value to concern us assert(!isConcreteWasmType(iff->type)); // can't be, since in the middle of a block - if (ExpressionAnalyzer::getEndingSimpleBreak(iff->ifTrue)) { + if (ExpressionAnalyzer::obviouslyDoesNotFlowOut(iff->ifTrue)) { iff->ifFalse = builder.blockifyMerge(iff->ifFalse, builder.stealSlice(block, i + 1, list.size())); return true; - } else if (ExpressionAnalyzer::getEndingSimpleBreak(iff->ifFalse)) { + } else if (ExpressionAnalyzer::obviouslyDoesNotFlowOut(iff->ifFalse)) { iff->ifTrue = builder.blockifyMerge(iff->ifTrue, builder.stealSlice(block, i + 1, list.size())); return true; } diff --git a/test/min.asm.js b/test/min.asm.js index b72002f97..bef48f4c2 100644 --- a/test/min.asm.js +++ b/test/min.asm.js @@ -18,6 +18,8 @@ function (global, env, buffer) { var hF32 = new global.Float32Array(buffer); var hF64 = new global.Float64Array(buffer); + var M = 0; // tempRet + function floats(f) { f = fr(f); var t = fr(0); @@ -40,7 +42,11 @@ function (global, env, buffer) { function ctzzzz() { return ctz32(0x1234) | 0; } + function ub() { + ub(); // emterpreter assertions mode might add some code here + return M | 0; + } - return { floats: floats }; + return { floats: floats, getTempRet0: ub }; } diff --git a/test/min.fromasm b/test/min.fromasm index 54380a4ec..a912c2dad 100644 --- a/test/min.fromasm +++ b/test/min.fromasm @@ -7,6 +7,8 @@ (import "env" "memoryBase" (global $memoryBase i32)) (import "env" "tableBase" (global $tableBase i32)) (export "floats" (func $floats)) + (export "getTempRet0" (func $ub)) + (global $M i32 (i32.const 0)) (func $floats (param $0 f32) (result f32) (local $1 f32) (f32.add @@ -31,4 +33,10 @@ (func $ctzzzz (result i32) (i32.const 2) ) + (func $ub (result i32) + (drop + (call $ub) + ) + (get_global $M) + ) ) diff --git a/test/min.fromasm.imprecise b/test/min.fromasm.imprecise index b07aba04e..a57298eef 100644 --- a/test/min.fromasm.imprecise +++ b/test/min.fromasm.imprecise @@ -6,6 +6,8 @@ (import "env" "memoryBase" (global $memoryBase i32)) (import "env" "tableBase" (global $tableBase i32)) (export "floats" (func $floats)) + (export "getTempRet0" (func $ub)) + (global $M i32 (i32.const 0)) (func $floats (param $0 f32) (result f32) (local $1 f32) (f32.add @@ -30,4 +32,10 @@ (func $ctzzzz (result i32) (i32.const 2) ) + (func $ub (result i32) + (drop + (call $ub) + ) + (get_global $M) + ) ) diff --git a/test/min.fromasm.imprecise.no-opts b/test/min.fromasm.imprecise.no-opts index dd89a9eed..c0fcb1917 100644 --- a/test/min.fromasm.imprecise.no-opts +++ b/test/min.fromasm.imprecise.no-opts @@ -6,6 +6,8 @@ (import "env" "memoryBase" (global $memoryBase i32)) (import "env" "tableBase" (global $tableBase i32)) (export "floats" (func $floats)) + (export "getTempRet0" (func $ub)) + (global $M i32 (i32.const 0)) (func $floats (param $f f32) (result f32) (local $t f32) (return @@ -60,4 +62,12 @@ ) ) ) + (func $ub (result i32) + (drop + (call $ub) + ) + (return + (get_global $M) + ) + ) ) diff --git a/test/min.fromasm.no-opts b/test/min.fromasm.no-opts index dd89a9eed..c0fcb1917 100644 --- a/test/min.fromasm.no-opts +++ b/test/min.fromasm.no-opts @@ -6,6 +6,8 @@ (import "env" "memoryBase" (global $memoryBase i32)) (import "env" "tableBase" (global $tableBase i32)) (export "floats" (func $floats)) + (export "getTempRet0" (func $ub)) + (global $M i32 (i32.const 0)) (func $floats (param $f f32) (result f32) (local $t f32) (return @@ -60,4 +62,12 @@ ) ) ) + (func $ub (result i32) + (drop + (call $ub) + ) + (return + (get_global $M) + ) + ) ) diff --git a/test/passes/remove-unused-brs.txt b/test/passes/remove-unused-brs.txt index 94b214588..2cef4b5ac 100644 --- a/test/passes/remove-unused-brs.txt +++ b/test/passes/remove-unused-brs.txt @@ -4,6 +4,7 @@ (type $1 (func)) (type $2 (func (result i32))) (type $3 (func (param i32 i32) (result i32))) + (type $4 (func (param i32 i32))) (func $b0-yes (type $0) (param $i1 i32) (block $topmost ) @@ -843,4 +844,34 @@ (get_local $y) ) ) + (func $fuzz (type $4) (param $j i32) (param $g i32) + (block $label$break$c + (loop $label$continue$d + (block $label$break$d + (if + (i32.lt_s + (get_local $j) + (i32.const 2147483640) + ) + (block $x + (block $y + (block $z + (br_if $x + (get_local $j) + ) + ) + ) + ) + (block $switch$26 + ) + ) + (i32.store + (i32.const 5724) + (i32.const -254899267) + ) + (br $label$continue$d) + ) + ) + ) + ) ) diff --git a/test/passes/remove-unused-brs.wast b/test/passes/remove-unused-brs.wast index ecbcb6caa..995ab2d3a 100644 --- a/test/passes/remove-unused-brs.wast +++ b/test/passes/remove-unused-brs.wast @@ -760,4 +760,38 @@ ) (i32.add (get_local $x) (get_local $y)) ) + (func $fuzz (param $j i32) (param $g i32) + (block $label$break$c + (loop $label$continue$d + (block $label$break$d + (if + (i32.lt_s + (get_local $j) + (i32.const 2147483640) + ) + (block $x + (block $y + (block $z + (br_if $y + (get_local $j) + ) + (br $x) ;; don't be confused by this + ) + (nop) ;; get me to the store! + ) + ) + (block $switch$26 + (nop) + ) + ) + (i32.store + (i32.const 5724) + (i32.const -254899267) + ) + (br $label$continue$d) + ) + ) + ) + ) ) + |