diff options
-rw-r--r-- | src/cfg/Relooper.cpp | 7 | ||||
-rw-r--r-- | src/passes/ReReloop.cpp | 3 | ||||
-rw-r--r-- | test/example/c-api-kitchen-sink.c | 3 | ||||
-rw-r--r-- | test/passes/rereloop.txt | 47 | ||||
-rw-r--r-- | test/passes/rereloop.wast | 21 |
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) + ) + ) ) |