summaryrefslogtreecommitdiff
path: root/src/passes/ReReloop.cpp
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-11-21 08:59:13 -0800
committerGitHub <noreply@github.com>2018-11-21 08:59:13 -0800
commit6cc2bb302d5729c76da42dc0815d6dbba645d952 (patch)
tree11e60856b2028e73df98eeaea2f0b789c50c8cd1 /src/passes/ReReloop.cpp
parent44335674936254ef6f8695883e4376a9d5fd1521 (diff)
downloadbinaryen-6cc2bb302d5729c76da42dc0815d6dbba645d952.tar.gz
binaryen-6cc2bb302d5729c76da42dc0815d6dbba645d952.tar.bz2
binaryen-6cc2bb302d5729c76da42dc0815d6dbba645d952.zip
Relooper CFG optimizations (#1759)
Previously the relooper would do some optimizations when deciding when to use an if vs a switch, how to group blocks, etc. This PR adds an additional pre-optimization phase with some basic but useful simplify-cfg style passes, * Skip empty blocks when they have just one exit. * Merge exiting branches when they are equivalent. * Canonicalize block contents to make such comparisons more useful. * Turn a trivial one-target switch into a simple branch. This can help in noticeable ways when running the rereloop pass, e.g. on LLVM wasm backend output. Also: * Binaryen C API changes to the relooper, which now gets a Module for its constructor. It needs it for the optimizations, as it may construct new nodes. * Many relooper-fuzzer improvements. * Clean up HashType usage.
Diffstat (limited to 'src/passes/ReReloop.cpp')
-rw-r--r--src/passes/ReReloop.cpp13
1 files changed, 7 insertions, 6 deletions
diff --git a/src/passes/ReReloop.cpp b/src/passes/ReReloop.cpp
index d96b95715..aae0ea262 100644
--- a/src/passes/ReReloop.cpp
+++ b/src/passes/ReReloop.cpp
@@ -41,7 +41,7 @@ struct ReReloop final : public Pass {
Pass* create() override { return new ReReloop; }
- CFG::Relooper relooper;
+ std::unique_ptr<CFG::Relooper> relooper;
std::unique_ptr<Builder> builder;
// block handling
@@ -50,7 +50,7 @@ struct ReReloop final : public Pass {
CFG::Block* makeCFGBlock() {
auto* ret = new CFG::Block(builder->makeBlock());
- relooper.AddBlock(ret);
+ relooper->AddBlock(ret);
return ret;
}
@@ -301,6 +301,7 @@ struct ReReloop final : public Pass {
// first, traverse the function body. note how we don't need to traverse
// into expressions, as we know they contain no control flow
builder = make_unique<Builder>(*module);
+ relooper = make_unique<CFG::Relooper>(module);
auto* entry = startCFGBlock();
stack.push_back(TaskPtr(new TriageTask(*this, function->body)));
// main loop
@@ -314,7 +315,7 @@ struct ReReloop final : public Pass {
// blocks that do not have any exits are dead ends in the relooper. we need
// to make sure that are in fact dead ends, and do not flow control anywhere.
// add a return as needed
- for (auto* cfgBlock : relooper.Blocks) {
+ for (auto* cfgBlock : relooper->Blocks) {
auto* block = cfgBlock->Code->cast<Block>();
if (cfgBlock->BranchesOut.empty() && block->type != unreachable) {
block->list.push_back(
@@ -326,7 +327,7 @@ struct ReReloop final : public Pass {
}
#ifdef RERELOOP_DEBUG
std::cout << "rerelooping " << function->name << '\n';
- for (auto* block : relooper.Blocks) {
+ for (auto* block : relooper->Blocks) {
std::cout << block << " block:\n" << block->Code << '\n';
for (auto& pair : block->BranchesOut) {
auto* target = pair.first;
@@ -339,12 +340,12 @@ struct ReReloop final : public Pass {
}
#endif
// run the relooper to recreate control flow
- relooper.Calculate(entry);
+ relooper->Calculate(entry);
// render
{
auto temp = builder->addVar(function, i32);
CFG::RelooperBuilder builder(*module, temp);
- function->body = relooper.Render(builder);
+ function->body = relooper->Render(builder);
// if the function has a result, and the relooper emitted
// something that seems like it flows out without a value
// (but that path is never reached; it just has a br to it