diff options
author | Alon Zakai <azakai@google.com> | 2022-10-07 10:31:05 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-07 10:31:05 -0700 |
commit | ada164df40f9b590f546dfecdddecc3894e345ae (patch) | |
tree | 8362af7aa04a83c700bdb1ca51b1311ca8a03ebf /src/ir/possible-contents.cpp | |
parent | d5aa6e7c070a7a14a6eb23edbe6343f6ee638e92 (diff) | |
download | binaryen-ada164df40f9b590f546dfecdddecc3894e345ae.tar.gz binaryen-ada164df40f9b590f546dfecdddecc3894e345ae.tar.bz2 binaryen-ada164df40f9b590f546dfecdddecc3894e345ae.zip |
GUFA: Use SSA-style information (#5121)
Previously we treated each local index as a location, and every local.set to
that index could be read by every local.get. With this we connect only
relevant sets to gets.
Practically speaking, this removes LocalLocation which is what was just
described, and instead there is ParamLocation for incoming parameter
values. And local.get/set use normal ExpressionLocations to connect a
set to a get.
I was worried this would be slow, since computing LocalGraph takes time,
but it actually more than makes up for itself on J2Wasm and we are faster
actually rocket I guess since we do less updating after local.sets.
This makes a noticeable change on the J2Wasm binary, and perhaps will
help with benchmarks.
Diffstat (limited to 'src/ir/possible-contents.cpp')
-rw-r--r-- | src/ir/possible-contents.cpp | 82 |
1 files changed, 45 insertions, 37 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 9ad43f090..6d75d65ca 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -19,6 +19,7 @@ #include "ir/branch-utils.h" #include "ir/eh-utils.h" +#include "ir/local-graph.h" #include "ir/module-utils.h" #include "ir/possible-contents.h" #include "wasm.h" @@ -217,7 +218,8 @@ template<typename T> void disallowDuplicates(const T& targets) { // A link indicates a flow of content from one location to another. For // example, if we do a local.get and return that value from a function, then -// we have a link from a LocalLocation to a ResultLocation. +// we have a link from the ExpressionLocation of that local.get to a +// ResultLocation. template<typename T> struct Link { T from; T to; @@ -438,7 +440,7 @@ struct InfoCollector auto* func = getModule()->getFunction(curr->func); for (Index i = 0; i < func->getParams().size(); i++) { info.links.push_back( - {SignatureParamLocation{func->type, i}, LocalLocation{func, i, 0}}); + {SignatureParamLocation{func->type, i}, ParamLocation{func, i}}); } for (Index i = 0; i < func->getResults().size(); i++) { info.links.push_back( @@ -494,28 +496,19 @@ struct InfoCollector receiveChildValue(curr->value, curr); } - // Locals read and write to their index. - // TODO: we could use a LocalGraph for SSA-like precision - void visitLocalGet(LocalGet* curr) { - if (isRelevant(curr->type)) { - for (Index i = 0; i < curr->type.size(); i++) { - info.links.push_back({LocalLocation{getFunction(), curr->index, i}, - ExpressionLocation{curr, i}}); - } - } - } void visitLocalSet(LocalSet* curr) { if (!isRelevant(curr->value->type)) { return; } - for (Index i = 0; i < curr->value->type.size(); i++) { - info.links.push_back({ExpressionLocation{curr->value, i}, - LocalLocation{getFunction(), curr->index, i}}); - } - // Tees also flow out the value (receiveChildValue will see if this is a tee + // Tees flow out the value (receiveChildValue will see if this is a tee // based on the type, automatically). receiveChildValue(curr->value, curr); + + // We handle connecting local.gets to local.sets below, in visitFunction. + } + void visitLocalGet(LocalGet* curr) { + // We handle connecting local.gets to local.sets below, in visitFunction. } // Globals read and write from their location. @@ -582,7 +575,7 @@ struct InfoCollector curr, [&](Index i) { assert(i <= target->getParams().size()); - return LocalLocation{target, i, 0}; + return ParamLocation{target, i}; }, [&](Index i) { assert(i <= target->getResults().size()); @@ -931,26 +924,41 @@ struct InfoCollector void visitReturn(Return* curr) { addResult(curr->value); } - void visitFunction(Function* curr) { - // Vars have an initial value. - for (Index i = 0; i < curr->getNumLocals(); i++) { - if (curr->isVar(i)) { - Index j = 0; - for (auto t : curr->getLocalType(i)) { - if (t.isDefaultable()) { - info.links.push_back( - {getNullLocation(t), LocalLocation{curr, i, j}}); - } - j++; - } - } - } - + void visitFunction(Function* func) { // Functions with a result can flow a value out from their body. - addResult(curr->body); + addResult(func->body); // See visitPop(). assert(handledPops == totalPops); + + // Handle local.get/sets: each set must write to the proper gets. + LocalGraph localGraph(func); + + for (auto& [get, setsForGet] : localGraph.getSetses) { + auto index = get->index; + auto type = func->getLocalType(index); + if (!isRelevant(type)) { + continue; + } + + // Each get reads from its relevant sets. + for (auto* set : setsForGet) { + for (Index i = 0; i < type.size(); i++) { + Location source; + if (set) { + // This is a normal local.set. + source = ExpressionLocation{set->value, i}; + } else if (getFunction()->isParam(index)) { + // This is a parameter. + source = ParamLocation{getFunction(), index}; + } else { + // This is the default value from the function entry, a null. + source = getNullLocation(type[i]); + } + info.links.push_back({source, ExpressionLocation{get, i}}); + } + } + } } // Helpers @@ -1284,7 +1292,7 @@ Flower::Flower(Module& wasm) : wasm(wasm) { auto calledFromOutside = [&](Name funcName) { auto* func = wasm.getFunction(funcName); for (Index i = 0; i < func->getParams().size(); i++) { - roots[LocalLocation{func, i, 0}] = PossibleContents::many(); + roots[ParamLocation{func, i}] = PossibleContents::many(); } }; @@ -1793,8 +1801,8 @@ void Flower::dump(Location location) { std::cout << " : " << loc->index << '\n'; } else if (auto* loc = std::get_if<TagLocation>(&location)) { std::cout << " tagloc " << loc->tag << '\n'; - } else if (auto* loc = std::get_if<LocalLocation>(&location)) { - std::cout << " localloc " << loc->func->name << " : " << loc->index + } else if (auto* loc = std::get_if<ParamLocation>(&location)) { + std::cout << " paramloc " << loc->func->name << " : " << loc->index << " tupleIndex " << loc->tupleIndex << '\n'; } else if (auto* loc = std::get_if<ResultLocation>(&location)) { std::cout << " resultloc " << loc->func->name << " : " << loc->index |