diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-11-21 08:59:13 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-21 08:59:13 -0800 |
commit | 6cc2bb302d5729c76da42dc0815d6dbba645d952 (patch) | |
tree | 11e60856b2028e73df98eeaea2f0b789c50c8cd1 /src/passes/ReReloop.cpp | |
parent | 44335674936254ef6f8695883e4376a9d5fd1521 (diff) | |
download | binaryen-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.cpp | 13 |
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 |