Skip to content

Commit e488da5

Browse files
authored
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).
1 parent e2c08d4 commit e488da5

21 files changed

Lines changed: 28416 additions & 25205 deletions

src/ast/branch-utils.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define wasm_ast_branch_h
1919

2020
#include "wasm.h"
21+
#include "wasm-traversal.h"
2122

2223
namespace wasm {
2324

@@ -36,6 +37,60 @@ inline bool isBranchTaken(Switch* sw) {
3637
sw->condition->type != unreachable;
3738
}
3839

40+
// returns the set of targets to which we branch that are
41+
// outside of a node
42+
inline std::set<Name> getExitingBranches(Expression* ast) {
43+
struct Scanner : public PostWalker<Scanner> {
44+
std::set<Name> targets;
45+
46+
void visitBreak(Break* curr) {
47+
targets.insert(curr->name);
48+
}
49+
void visitSwitch(Switch* curr) {
50+
for (auto target : targets) {
51+
targets.insert(target);
52+
}
53+
targets.insert(curr->default_);
54+
}
55+
void visitBlock(Block* curr) {
56+
if (curr->name.is()) {
57+
targets.erase(curr->name);
58+
}
59+
}
60+
void visitLoop(Loop* curr) {
61+
if (curr->name.is()) {
62+
targets.erase(curr->name);
63+
}
64+
}
65+
};
66+
Scanner scanner;
67+
scanner.walk(ast);
68+
// anything not erased is a branch out
69+
return scanner.targets;
70+
}
71+
72+
// returns the list of all branch targets in a node
73+
74+
inline std::set<Name> getBranchTargets(Expression* ast) {
75+
struct Scanner : public PostWalker<Scanner> {
76+
std::set<Name> targets;
77+
78+
void visitBlock(Block* curr) {
79+
if (curr->name.is()) {
80+
targets.insert(curr->name);
81+
}
82+
}
83+
void visitLoop(Loop* curr) {
84+
if (curr->name.is()) {
85+
targets.insert(curr->name);
86+
}
87+
}
88+
};
89+
Scanner scanner;
90+
scanner.walk(ast);
91+
return scanner.targets;
92+
}
93+
3994
} // namespace BranchUtils
4095

4196
} // namespace wasm

src/ast/label-utils.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2017 WebAssembly Community Group participants
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef wasm_ast_label_h
18+
#define wasm_ast_label_h
19+
20+
#include "wasm.h"
21+
#include "wasm-traversal.h"
22+
23+
namespace wasm {
24+
25+
namespace LabelUtils {
26+
27+
// Handles branch/loop labels in a function; makes it easy to add new
28+
// ones without duplicates
29+
class LabelManager : public PostWalker<LabelManager> {
30+
public:
31+
LabelManager(Function* func) {
32+
walkFunction(func);
33+
}
34+
35+
Name getUnique(std::string prefix) {
36+
while (1) {
37+
auto curr = Name(prefix + std::to_string(counter++));
38+
if (labels.find(curr) == labels.end()) {
39+
labels.insert(curr);
40+
return curr;
41+
}
42+
}
43+
}
44+
45+
void visitBlock(Block* curr) {
46+
labels.insert(curr->name);
47+
}
48+
void visitLoop(Loop* curr) {
49+
labels.insert(curr->name);
50+
}
51+
52+
private:
53+
std::set<Name> labels;
54+
size_t counter = 0;
55+
};
56+
57+
} // namespace LabelUtils
58+
59+
} // namespace wasm
60+
61+
#endif // wasm_ast_label_h
62+

src/mixed_arena.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ class ArenaVectorBase {
172172
return usedElements;
173173
}
174174

175+
bool empty() const {
176+
return size() == 0;
177+
}
178+
175179
void resize(size_t size) {
176180
if (size > allocatedElements) {
177181
reallocate(size);

src/pass.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -237,29 +237,6 @@ class WalkerPass : public Pass, public WalkerType {
237237
// but registering them here in addition allows them to communicate
238238
// e.g. through PassRunner::getLast
239239

240-
// Handles names in a module, in particular adding names without duplicates
241-
class NameManager : public WalkerPass<PostWalker<NameManager>> {
242-
public:
243-
Name getUnique(std::string prefix);
244-
// TODO: getUniqueInFunction
245-
246-
// visitors
247-
void visitBlock(Block* curr);
248-
void visitLoop(Loop* curr);
249-
void visitBreak(Break* curr);
250-
void visitSwitch(Switch* curr);
251-
void visitCall(Call* curr);
252-
void visitCallImport(CallImport* curr);
253-
void visitFunctionType(FunctionType* curr);
254-
void visitFunction(Function* curr);
255-
void visitImport(Import* curr);
256-
void visitExport(Export* curr);
257-
258-
private:
259-
std::set<Name> names;
260-
size_t counter = 0;
261-
};
262-
263240
// Prints out a module
264241
class Printer : public Pass {
265242
protected:

src/passes/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ SET(passes_SOURCES
22
pass.cpp
33
CoalesceLocals.cpp
44
CodePushing.cpp
5+
CodeFolding.cpp
56
DeadCodeElimination.cpp
67
DuplicateFunctionElimination.cpp
78
ExtractFunction.cpp
@@ -15,7 +16,6 @@ SET(passes_SOURCES
1516
MemoryPacking.cpp
1617
MergeBlocks.cpp
1718
Metrics.cpp
18-
NameManager.cpp
1919
NameList.cpp
2020
OptimizeInstructions.cpp
2121
PickLoadSigns.cpp

0 commit comments

Comments
 (0)