summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cfg/Relooper.cpp7
-rw-r--r--src/passes/ReReloop.cpp3
-rw-r--r--test/example/c-api-kitchen-sink.c3
-rw-r--r--test/passes/rereloop.txt47
-rw-r--r--test/passes/rereloop.wast21
5 files changed, 76 insertions, 5 deletions
diff --git a/src/cfg/Relooper.cpp b/src/cfg/Relooper.cpp
index 9fcc9c8be..b326d761d 100644
--- a/src/cfg/Relooper.cpp
+++ b/src/cfg/Relooper.cpp
@@ -328,7 +328,12 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
NextOuter->list.push_back(Outer);
Outer->name = CurrName; // breaking on Outer leads to the content in NextOuter
NextOuter->list.push_back(CurrContent);
- NextOuter->list.push_back(Builder.makeBreak(SwitchLeave));
+ // if this is not a dead end, also need to break to the outside
+ // this is both an optimization, and avoids incorrectness as adding
+ // a brak in unreachable code can make a place look reachable that isn't
+ if (CurrContent->type != wasm::unreachable) {
+ NextOuter->list.push_back(Builder.makeBreak(SwitchLeave));
+ }
// prepare for more nesting
Outer = NextOuter;
} else {
diff --git a/src/passes/ReReloop.cpp b/src/passes/ReReloop.cpp
index 6bdc0eb06..db2ec5698 100644
--- a/src/passes/ReReloop.cpp
+++ b/src/passes/ReReloop.cpp
@@ -28,6 +28,7 @@
#include "wasm-traversal.h"
#include "pass.h"
#include "cfg/Relooper.h"
+#include "ast_utils.h"
namespace wasm {
@@ -314,6 +315,8 @@ struct ReReloop : public Pass {
CFG::RelooperBuilder builder(*module, temp);
function->body = relooper.Render(builder);
}
+ // TODO: should this be in the relooper itself?
+ ReFinalize().walk(function->body);
}
};
diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c
index 5935e9993..b2218993c 100644
--- a/test/example/c-api-kitchen-sink.c
+++ b/test/example/c-api-kitchen-sink.c
@@ -427,6 +427,9 @@ void test_relooper() {
RelooperRef relooper = RelooperCreate();
BinaryenExpressionRef temp = makeInt32(module, -99);
RelooperBlockRef block0 = RelooperAddBlockWithSwitch(relooper, makeCallCheck(module, 0), temp);
+ // TODO: this example is not very good, the blocks should end in a |return| as otherwise they
+ // fall through to each other. A relooper block should end in something that stops control
+ // flow, if it doesn't have branches going out
RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module, 1));
RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module, 2));
RelooperBlockRef block3 = RelooperAddBlock(relooper, makeCallCheck(module, 3));
diff --git a/test/passes/rereloop.txt b/test/passes/rereloop.txt
index c15934c0b..17a084395 100644
--- a/test/passes/rereloop.txt
+++ b/test/passes/rereloop.txt
@@ -541,7 +541,6 @@
(block
(br $block$3$break)
)
- (br $switch$1$leave)
)
(block
(block
@@ -552,7 +551,6 @@
)
)
)
- (br $switch$1$leave)
)
)
(block
@@ -572,7 +570,6 @@
(block
(br $block$6$break)
)
- (br $switch$3$leave)
)
(block
(block
@@ -586,7 +583,6 @@
)
)
)
- (br $switch$3$leave)
)
)
(block
@@ -704,4 +700,47 @@
)
)
)
+ (func $switcher-to-nowhere (type $2) (param $0 i32) (result i32)
+ (local $1 i32)
+ (block
+ )
+ (block $switch$1$leave
+ (block $switch$1$default
+ (block $switch$1$case$3
+ (block $switch$1$case$4
+ (br_table $switch$1$case$4 $switch$1$case$3 $switch$1$default
+ (get_local $0)
+ )
+ )
+ (block
+ (block
+ (block
+ (return
+ (i32.const 1)
+ )
+ )
+ )
+ )
+ )
+ (block
+ (block
+ (block
+ (return
+ (i32.const 2)
+ )
+ )
+ )
+ )
+ )
+ (block
+ (block
+ (block
+ (return
+ (i32.const 3)
+ )
+ )
+ )
+ )
+ )
+ )
)
diff --git a/test/passes/rereloop.wast b/test/passes/rereloop.wast
index 38c74ff56..0680c97fe 100644
--- a/test/passes/rereloop.wast
+++ b/test/passes/rereloop.wast
@@ -175,5 +175,26 @@
(i32.const 3)
)
)
+
+ (func $switcher-to-nowhere (param $0 i32) (result i32)
+ (block $switch
+ (block $switch-case0
+ (block $switch-case
+ (br_table $switch-case $switch-case0 $switch
+ (get_local $0)
+ )
+ )
+ (return
+ (i32.const 1)
+ )
+ )
+ (return
+ (i32.const 2)
+ )
+ )
+ (return
+ (i32.const 3)
+ )
+ )
)