summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoppin Vincent <vincent.loppin@gmail.com>2018-07-21 02:29:26 +0200
committerAlon Zakai <alonzakai@gmail.com>2018-07-20 17:29:26 -0700
commit7db96b6d0c93e3b92b396169506b5fd4f14a7dd3 (patch)
treea36e05f195adda66e343f6da1e773127f0dbab5c
parent25890f53cba4b9b05341ac146dde755a7fa4fddd (diff)
downloadbinaryen-7db96b6d0c93e3b92b396169506b5fd4f14a7dd3.tar.gz
binaryen-7db96b6d0c93e3b92b396169506b5fd4f14a7dd3.tar.bz2
binaryen-7db96b6d0c93e3b92b396169506b5fd4f14a7dd3.zip
Speedup localgraph (#1610)
* LocalGraph : Replace seen unordered_set by boolean check. * LocalGraph : use unordered_map to store index -> last set_local instead of vector. * LocalGraph : - Use internal counter to avoid invalidation at each cycle. - Move all blocks structs into a contiguous vector of smaller ones.
-rw-r--r--src/ir/LocalGraph.cpp82
1 files changed, 64 insertions, 18 deletions
diff --git a/src/ir/LocalGraph.cpp b/src/ir/LocalGraph.cpp
index 77f5906f0..abbcf889f 100644
--- a/src/ir/LocalGraph.cpp
+++ b/src/ir/LocalGraph.cpp
@@ -50,7 +50,7 @@ struct Action {
// information about a basic block
struct Info {
std::vector<Action> actions; // actions occurring in this block
- std::vector<SetLocal*> lastSets; // for each index, the last set_local for it
+ std::unordered_map<Index, SetLocal*> lastSets; // for each index, the last set_local for it
void dump(Function* func) {
if (actions.empty()) return;
@@ -76,11 +76,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
}
BasicBlock* makeBasicBlock() {
- auto* ret = new BasicBlock();
- auto& lastSets = ret->contents.lastSets;
- lastSets.resize(getFunction()->getNumLocals());
- std::fill(lastSets.begin(), lastSets.end(), nullptr);
- return ret;
+ return new BasicBlock();
}
// cfg traversal work
@@ -103,12 +99,61 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
}
void flow(Function* func) {
+ // This block struct is optimized for this flow process (Minimal information, iteration index).
+ struct FlowBlock {
+ // last Traversed Iteration
+ // This value help us to find if this block has been seen while traversing blocks.
+ // We compare this value to the current iteration index in order to determine if we already process this block in the current iteration.
+ // This speed up the processing compared to unordered_set or other struct usage. (No need to reset internal values, lookup into container, ...)
+ size_t lastTraversedIteration;
+ std::vector<Action> actions; // actions occurring in this block
+ std::vector<FlowBlock*> in;
+ // for each index, the last set_local for it
+ // The unordered_map from BasicBlock is converted ther into a vector
+ // This speed up search as there are almost always fewer than 100 items
+ std::vector<std::pair<Index, SetLocal*>> lastSets;
+ };
+
auto numLocals = func->getNumLocals();
std::vector<std::vector<GetLocal*>> allGets;
allGets.resize(numLocals);
- std::unordered_set<BasicBlock*> seen;
- std::vector<BasicBlock*> work;
- for (auto& block : basicBlocks) {
+ std::vector<FlowBlock*> work;
+
+
+ // Converts input blocks (basicBlocks) into more efficient blocks to improve memory access.
+ std::vector<FlowBlock> flowBlocks;
+ flowBlocks.resize(basicBlocks.size());
+
+ // Init mapping between basicblocks and flowBlocks
+ std::unordered_map<BasicBlock*, FlowBlock*> basicToFlowMap;
+ for (size_t i = 0; i < basicBlocks.size(); ++i) {
+ basicToFlowMap.emplace(std::make_pair(basicBlocks[i].get(), &flowBlocks[i]));
+ }
+
+ FlowBlock* entryFlowBlock = nullptr;
+ for (size_t i = 0; i < flowBlocks.size(); ++i) {
+ auto& optBlock = flowBlocks[i];
+ auto& inBlock = basicBlocks[i];
+ // Get the equivalent block to entry in the flow list
+ if (inBlock.get() == entry) entryFlowBlock = &optBlock;
+ // Initialize iteration index to max size_t to ensure we don't miss a block from wrong value.
+ optBlock.lastTraversedIteration = -1;
+ optBlock.actions.swap(inBlock->contents.actions);
+ // Map in block to flow blocks
+ auto& inBlocks = inBlock->in;
+ optBlock.in.resize(inBlocks.size());
+ std::transform(inBlocks.begin(), inBlocks.end(), optBlock.in.begin(), [&](BasicBlock* block) { return basicToFlowMap[block]; });
+
+ // Convert unordered_map to vector
+ optBlock.lastSets.reserve(inBlock->contents.lastSets.size());
+ for (auto set : inBlock->contents.lastSets) {
+ optBlock.lastSets.emplace_back(std::make_pair(set.first, set.second));
+ }
+ }
+ assert(entryFlowBlock != nullptr);
+
+ size_t currentIteration = 0;
+ for (auto& block : flowBlocks) {
#ifdef LOCAL_GRAPH_DEBUG
std::cout << "basic block " << block.get() << " :\n";
for (auto& action : block->contents.actions) {
@@ -120,7 +165,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
#endif
// go through the block, finding each get and adding it to its index,
// and seeing how sets affect that
- auto& actions = block->contents.actions;
+ auto& actions = block.actions;
// move towards the front, handling things as we go
for (int i = int(actions.size()) - 1; i >= 0; i--) {
auto& action = actions[i];
@@ -142,8 +187,8 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
for (Index index = 0; index < numLocals; index++) {
auto& gets = allGets[index];
if (gets.empty()) continue;
- work.push_back(block.get());
- seen.clear();
+ work.push_back(&block);
+
// note that we may need to revisit the later parts of this initial
// block, if we are in a loop, so don't mark it as seen
while (!work.empty()) {
@@ -152,7 +197,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
// we have gone through this block; now we must handle flowing to
// the inputs
if (curr->in.empty()) {
- if (curr == entry) {
+ if (curr == entryFlowBlock) {
// these receive a param or zero init value
for (auto* get : gets) {
getSetses[get].insert(nullptr);
@@ -160,13 +205,13 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
}
} else {
for (auto* pred : curr->in) {
- if (seen.count(pred)) continue;
- seen.insert(pred);
- auto* lastSet = pred->contents.lastSets[index];
- if (lastSet) {
+ if (pred->lastTraversedIteration == currentIteration) continue;
+ pred->lastTraversedIteration = currentIteration;
+ auto lastSet = std::find_if(pred->lastSets.begin(), pred->lastSets.end(), [&](std::pair<Index, SetLocal*>& value) { return value.first == index; });
+ if (lastSet != pred->lastSets.end()) {
// there is a set here, apply it, and stop the flow
for (auto* get : gets) {
- getSetses[get].insert(lastSet);
+ getSetses[get].insert(lastSet->second);
}
} else {
// keep on flowing
@@ -176,6 +221,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
}
}
gets.clear();
+ currentIteration++;
}
}
}