summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast_utils.h20
-rw-r--r--src/passes/RemoveUnusedBrs.cpp6
-rw-r--r--test/passes/remove-unused-brs.txt31
-rw-r--r--test/passes/remove-unused-brs.wast34
4 files changed, 78 insertions, 13 deletions
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/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)
+ )
+ )
+ )
+ )
)
+