diff options
Diffstat (limited to 'src/ir')
-rw-r--r-- | src/ir/LocalGraph.cpp | 26 | ||||
-rw-r--r-- | src/ir/local-graph.h | 47 | ||||
-rw-r--r-- | src/ir/possible-contents.cpp | 9 |
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) { |