summaryrefslogtreecommitdiff
path: root/src/ir
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2019-03-01 10:28:07 -0800
committerGitHub <noreply@github.com>2019-03-01 10:28:07 -0800
commit689fe405a3417fbfd59456035add6f6f53149f35 (patch)
treed6f1dcaf0cbb85eb3ae830f68a46c9a6627d1562 /src/ir
parentf59c3033e678ced61bc8c78e8ac9fbee31ef0210 (diff)
downloadbinaryen-689fe405a3417fbfd59456035add6f6f53149f35.tar.gz
binaryen-689fe405a3417fbfd59456035add6f6f53149f35.tar.bz2
binaryen-689fe405a3417fbfd59456035add6f6f53149f35.zip
Consistently optimize small added constants into load/store offsets (#1924)
See #1919 - we did not do this consistently before. This adds a lowMemoryUnused option to PassOptions. It can be passed on the commandline with --low-memory-unused. If enabled, we run the new optimize-added-constants pass, which does the real work here, replacing older code in post-emscripten. Aside from running at the proper time (unlike the old pass, see #1919), this also has a -propagate mode, which can do stuff like this: y = x + 10 [..] load(y) [..] load(y) => y = x + 10 [..] load(x, offset=10) [..] load(x, offset=10) That is, it can propagate such offsets to the loads/stores. This pattern is common in big interpreter loops, where the pointers are offsets into a big struct of state. The pass does this propagation by using a new feature of LocalGraph, which can verify which locals are in SSA mode. Binaryen IR is not SSA (intentionally, since it's a later IR), but if a local only has a single set for all gets, that means that local is in such a state, and can be optimized. The tricky thing is that all locals are initialized to zero, so there are at minimum two sets. But if we verify that the real set dominates all the gets, then the zero initialization cannot reach them, and we are safe. This PR also makes safe-heap aware of lowMemoryUnused. If so, we check for not just an access of 0, but the range 0-1023. This makes zlib 5% faster, with either the wasm backend or asm2wasm. It also makes it 0.5% smaller. Also helps sqlite (1.5% faster) and lua (1% faster)
Diffstat (limited to 'src/ir')
-rw-r--r--src/ir/LocalGraph.cpp33
-rw-r--r--src/ir/local-graph.h33
2 files changed, 63 insertions, 3 deletions
diff --git a/src/ir/LocalGraph.cpp b/src/ir/LocalGraph.cpp
index 6a99ed44e..1cf883c19 100644
--- a/src/ir/LocalGraph.cpp
+++ b/src/ir/LocalGraph.cpp
@@ -242,5 +242,38 @@ void LocalGraph::computeInfluences() {
}
}
+void LocalGraph::computeSSAIndexes() {
+ std::unordered_map<Index, std::set<SetLocal*>> indexSets;
+ for (auto& pair : getSetses) {
+ auto* get = pair.first;
+ auto& sets = pair.second;
+ for (auto* set : sets) {
+ indexSets[get->index].insert(set);
+ }
+ }
+ for (auto& pair : locations) {
+ auto* curr = pair.first;
+ if (auto* set = curr->dynCast<SetLocal>()) {
+ auto& sets = indexSets[set->index];
+ if (sets.size() == 1 && *sets.begin() != curr) {
+ // While it has just one set, it is not the right one (us),
+ // so mark it invalid.
+ sets.clear();
+ }
+ }
+ }
+ for (auto& pair : indexSets) {
+ auto index = pair.first;
+ auto& sets = pair.second;
+ if (sets.size() == 1) {
+ SSAIndexes.insert(index);
+ }
+ }
+}
+
+bool LocalGraph::isSSA(Index x) {
+ return SSAIndexes.count(x);
+}
+
} // namespace wasm
diff --git a/src/ir/local-graph.h b/src/ir/local-graph.h
index 725be0536..fd6a496c0 100644
--- a/src/ir/local-graph.h
+++ b/src/ir/local-graph.h
@@ -45,13 +45,40 @@ struct LocalGraph {
// value (0 for a var, the received value for a param)
Locations locations; // where each get and set is (for easy replacing)
- // optional computation: compute the influence graphs between sets and gets
- // (useful for algorithms that propagate changes)
+ // Optional: compute the influence graphs between sets and gets
+ // (useful for algorithms that propagate changes).
+
+ void computeInfluences();
std::unordered_map<GetLocal*, std::unordered_set<SetLocal*>> getInfluences; // for each get, the sets whose values are influenced by that get
std::unordered_map<SetLocal*, std::unordered_set<GetLocal*>> setInfluences; // for each set, the gets whose values are influenced by that set
- void computeInfluences();
+ // Optional: Compute the local indexes that are SSA, in the sense of
+ // * a single set for all the gets for that local index
+ // * the set dominates all the gets (logically implied by the former property)
+ // * no other set (aside from the zero-init)
+ // The third property is not exactly standard SSA, but is useful since we are not in
+ // SSA form in our IR. To see why it matters, consider these:
+ //
+ // x = 0 // zero init
+ // [..]
+ // x = 10
+ // y = x + 20
+ // x = 30 // !!!
+ // f(y)
+ //
+ // The !!! line violates that property - it is another set for x, and it may interfere
+ // say with replacing f(y) with f(x + 20). Instead, if we know the only other possible set for x
+ // is the zero init, then things like the !!! line cannot exist, and it is valid to replace
+ // f(y) with f(x + 20).
+ // (This could be simpler, but in wasm the zero init always exists.)
+
+ void computeSSAIndexes();
+
+ bool isSSA(Index x);
+
+private:
+ std::set<Index> SSAIndexes;
};
} // namespace wasm