From e488da5adbef2613c08fe205db5b79b1765a4af3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 28 Jun 2017 22:05:05 -0700 Subject: Code folding (#1076) Adds a pass that folds code, i.e. merges it when possible. See details in comment in the pass implementation cpp. This is enabled by default in -Os and -Oz. Seems risky to enable anywhere else, as it does add branches - likely predictable ones so maybe no slowdown, but still some risk. Code size numbers: wasm-backend: 196331 + binaryen -Os (before): 182598 + binaryen -Os (with folding): 181943 asm2wasm -Os (before): 172463 asm2wasm -Os (with folding): 168774 So this reduces wasm-backend output by an additional 0.5% than it could before. Mainly this is because the wasm backend already has code folding, whereas on asm2wasm output, where we didn't have folding before, this saves over 2%. The 0.5% improvement on the wasm backend's output might be because this can fold more types of code than LLVM can (it can fold nested control flow, in particular). --- src/ast/branch-utils.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'src/ast/branch-utils.h') diff --git a/src/ast/branch-utils.h b/src/ast/branch-utils.h index a54b8151f..bdf52d36a 100644 --- a/src/ast/branch-utils.h +++ b/src/ast/branch-utils.h @@ -18,6 +18,7 @@ #define wasm_ast_branch_h #include "wasm.h" +#include "wasm-traversal.h" namespace wasm { @@ -36,6 +37,60 @@ inline bool isBranchTaken(Switch* sw) { sw->condition->type != unreachable; } +// returns the set of targets to which we branch that are +// outside of a node +inline std::set getExitingBranches(Expression* ast) { + struct Scanner : public PostWalker { + std::set targets; + + void visitBreak(Break* curr) { + targets.insert(curr->name); + } + void visitSwitch(Switch* curr) { + for (auto target : targets) { + targets.insert(target); + } + targets.insert(curr->default_); + } + void visitBlock(Block* curr) { + if (curr->name.is()) { + targets.erase(curr->name); + } + } + void visitLoop(Loop* curr) { + if (curr->name.is()) { + targets.erase(curr->name); + } + } + }; + Scanner scanner; + scanner.walk(ast); + // anything not erased is a branch out + return scanner.targets; +} + +// returns the list of all branch targets in a node + +inline std::set getBranchTargets(Expression* ast) { + struct Scanner : public PostWalker { + std::set targets; + + void visitBlock(Block* curr) { + if (curr->name.is()) { + targets.insert(curr->name); + } + } + void visitLoop(Loop* curr) { + if (curr->name.is()) { + targets.insert(curr->name); + } + } + }; + Scanner scanner; + scanner.walk(ast); + return scanner.targets; +} + } // namespace BranchUtils } // namespace wasm -- cgit v1.2.3