diff options
author | Alon Zakai <alonzakai@gmail.com> | 2017-06-28 22:05:05 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-28 22:05:05 -0700 |
commit | e488da5adbef2613c08fe205db5b79b1765a4af3 (patch) | |
tree | e3cab840dcbf7d8d4ccf1f47a742fbfc41e1d5ef /src/ast | |
parent | e2c08d42ab0ffc05d980ae2d34fee0e77b201134 (diff) | |
download | binaryen-e488da5adbef2613c08fe205db5b79b1765a4af3.tar.gz binaryen-e488da5adbef2613c08fe205db5b79b1765a4af3.tar.bz2 binaryen-e488da5adbef2613c08fe205db5b79b1765a4af3.zip |
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).
Diffstat (limited to 'src/ast')
-rw-r--r-- | src/ast/branch-utils.h | 55 | ||||
-rw-r--r-- | src/ast/label-utils.h | 62 |
2 files changed, 117 insertions, 0 deletions
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<Name> getExitingBranches(Expression* ast) { + struct Scanner : public PostWalker<Scanner> { + std::set<Name> 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<Name> getBranchTargets(Expression* ast) { + struct Scanner : public PostWalker<Scanner> { + std::set<Name> 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 diff --git a/src/ast/label-utils.h b/src/ast/label-utils.h new file mode 100644 index 000000000..6ec9ecf5d --- /dev/null +++ b/src/ast/label-utils.h @@ -0,0 +1,62 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_ast_label_h +#define wasm_ast_label_h + +#include "wasm.h" +#include "wasm-traversal.h" + +namespace wasm { + +namespace LabelUtils { + +// Handles branch/loop labels in a function; makes it easy to add new +// ones without duplicates +class LabelManager : public PostWalker<LabelManager> { +public: + LabelManager(Function* func) { + walkFunction(func); + } + + Name getUnique(std::string prefix) { + while (1) { + auto curr = Name(prefix + std::to_string(counter++)); + if (labels.find(curr) == labels.end()) { + labels.insert(curr); + return curr; + } + } + } + + void visitBlock(Block* curr) { + labels.insert(curr->name); + } + void visitLoop(Loop* curr) { + labels.insert(curr->name); + } + +private: + std::set<Name> labels; + size_t counter = 0; +}; + +} // namespace LabelUtils + +} // namespace wasm + +#endif // wasm_ast_label_h + |