summaryrefslogtreecommitdiff
path: root/src/ir
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir')
-rw-r--r--src/ir/LocalGraph.cpp26
-rw-r--r--src/ir/local-graph.h47
-rw-r--r--src/ir/possible-contents.cpp9
3 files changed, 49 insertions, 33 deletions
diff --git a/src/ir/LocalGraph.cpp b/src/ir/LocalGraph.cpp
index beef635b1..e1876f6d2 100644
--- a/src/ir/LocalGraph.cpp
+++ b/src/ir/LocalGraph.cpp
@@ -40,14 +40,14 @@ struct Info {
// flow helper class. flows the gets to their sets
struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
- LocalGraph::GetSetses& getSetses;
+ LocalGraph::GetSetsMap& getSetsMap;
LocalGraph::Locations& locations;
- Flower(LocalGraph::GetSetses& getSetses,
+ Flower(LocalGraph::GetSetsMap& getSetsMap,
LocalGraph::Locations& locations,
Function* func,
Module* module)
- : getSetses(getSetses), locations(locations) {
+ : getSetsMap(getSetsMap), locations(locations) {
setFunction(func);
setModule(module);
// create the CFG by walking the IR
@@ -183,7 +183,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
auto* set = action->cast<LocalSet>();
auto& gets = allGets[set->index];
for (auto* get : gets) {
- getSetses[get].insert(set);
+ getSetsMap[get].insert(set);
}
gets.clear();
}
@@ -206,7 +206,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
// confusing when debugging, but it does not have any downside for
// optimization (since unreachable code should be removed anyhow).
for (auto* get : gets) {
- getSetses[get].insert(nullptr);
+ getSetsMap[get].insert(nullptr);
}
continue;
}
@@ -222,7 +222,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
if (curr == entryFlowBlock) {
// These receive a param or zero init value.
for (auto* get : gets) {
- getSetses[get].insert(nullptr);
+ getSetsMap[get].insert(nullptr);
}
}
} else {
@@ -241,7 +241,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
if (lastSet != pred->lastSets.end()) {
// There is a set here, apply it, and stop the flow.
for (auto* get : gets) {
- getSetses[get].insert(lastSet->second);
+ getSetsMap[get].insert(lastSet->second);
}
} else {
// Keep on flowing.
@@ -261,11 +261,11 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
// LocalGraph implementation
LocalGraph::LocalGraph(Function* func, Module* module) : func(func) {
- LocalGraphInternal::Flower flower(getSetses, locations, func, module);
+ LocalGraphInternal::Flower flower(getSetsMap, locations, func, module);
#ifdef LOCAL_GRAPH_DEBUG
std::cout << "LocalGraph::dump\n";
- for (auto& [get, sets] : getSetses) {
+ for (auto& [get, sets] : getSetsMap) {
std::cout << "GET\n" << get << " is influenced by\n";
for (auto* set : sets) {
std::cout << set << '\n';
@@ -276,8 +276,8 @@ LocalGraph::LocalGraph(Function* func, Module* module) : func(func) {
}
bool LocalGraph::equivalent(LocalGet* a, LocalGet* b) {
- auto& aSets = getSetses[a];
- auto& bSets = getSetses[b];
+ auto& aSets = getSetsMap[a];
+ auto& bSets = getSetsMap[b];
// The simple case of one set dominating two gets easily proves that they must
// have the same value. (Note that we can infer dominance from the fact that
// there is a single set: if the set did not dominate one of the gets then
@@ -315,7 +315,7 @@ bool LocalGraph::equivalent(LocalGet* a, LocalGet* b) {
void LocalGraph::computeSetInfluences() {
for (auto& [curr, _] : locations) {
if (auto* get = curr->dynCast<LocalGet>()) {
- for (auto* set : getSetses[get]) {
+ for (auto* set : getSetsMap[get]) {
setInfluences[set].insert(get);
}
}
@@ -335,7 +335,7 @@ void LocalGraph::computeGetInfluences() {
void LocalGraph::computeSSAIndexes() {
std::unordered_map<Index, std::set<LocalSet*>> indexSets;
- for (auto& [get, sets] : getSetses) {
+ for (auto& [get, sets] : getSetsMap) {
for (auto* set : sets) {
indexSets[get->index].insert(set);
}
diff --git a/src/ir/local-graph.h b/src/ir/local-graph.h
index fd9306d5c..1a674de86 100644
--- a/src/ir/local-graph.h
+++ b/src/ir/local-graph.h
@@ -39,37 +39,42 @@ namespace wasm {
// code will be removed anyhow).
//
struct LocalGraph {
- // main API
-
- // The constructor computes getSetses, the sets affecting each get.
- //
// If a module is passed in, it is used to find which features are needed in
// the computation (for example, if exception handling is disabled, then we
// can generate a simpler CFG, as calls cannot throw).
LocalGraph(Function* func, Module* module = nullptr);
- // The local.sets relevant for an index or a get. The most common case is to
- // have a single set; after that, to be a phi of 2 items, so we use a small
- // set of size 2 to avoid allocations there.
+ // Get the sets relevant for a local.get.
+ //
+ // A nullptr set means there is no local.set for that value, which means it is
+ // the initial value from the function entry: 0 for a var, the received value
+ // for a param.
+ //
+ // Often there is a single set, or a phi or two items, so we use a small set.
using Sets = SmallSet<LocalSet*, 2>;
+ const Sets& getSets(LocalGet* get) const {
+ // When we return an empty result, use a canonical constant empty set to
+ // avoid allocation.
+ static const Sets empty;
+ auto iter = getSetsMap.find(get);
+ if (iter == getSetsMap.end()) {
+ return empty;
+ }
+ return iter->second;
+ }
- using GetSetses = std::unordered_map<LocalGet*, Sets>;
-
+ // Where each get and set is. We compute this while doing the main computation
+ // and make it accessible for users, for easy replacing of things without
+ // extra work.
using Locations = std::map<Expression*, Expression**>;
-
- // externally useful information
- GetSetses getSetses; // the sets affecting each get. a nullptr set means the
- // initial value (0 for a var, the received value for a
- // param)
- Locations locations; // where each get and set is (for easy replacing)
+ Locations locations;
// Checks if two gets are equivalent, that is, definitely have the same
// value.
bool equivalent(LocalGet* a, LocalGet* b);
- // Optional: 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 computeSetInfluences();
void computeGetInfluences();
@@ -109,9 +114,15 @@ struct LocalGraph {
bool isSSA(Index x);
+ // Defined publicly as other utilities need similar data layouts.
+ using GetSetsMap = std::unordered_map<LocalGet*, Sets>;
+
private:
Function* func;
std::set<Index> SSAIndexes;
+
+ // A map of each get to the sets relevant to it.
+ GetSetsMap getSetsMap;
};
} // namespace wasm
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index e5e6cf659..aa6564653 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -1245,7 +1245,12 @@ struct InfoCollector
// the type must be the same for all gets of that local.)
LocalGraph localGraph(func, getModule());
- for (auto& [get, setsForGet] : localGraph.getSetses) {
+ for (auto& [curr, _] : localGraph.locations) {
+ auto* get = curr->dynCast<LocalGet>();
+ if (!get) {
+ continue;
+ }
+
auto index = get->index;
auto type = func->getLocalType(index);
if (!isRelevant(type)) {
@@ -1253,7 +1258,7 @@ struct InfoCollector
}
// Each get reads from its relevant sets.
- for (auto* set : setsForGet) {
+ for (auto* set : localGraph.getSets(get)) {
for (Index i = 0; i < type.size(); i++) {
Location source;
if (set) {