@@ -50,7 +50,7 @@ struct Action {
5050// information about a basic block
5151struct Info {
5252 std::vector<Action> actions; // actions occurring in this block
53- std::vector< SetLocal*> lastSets; // for each index, the last set_local for it
53+ std::unordered_map<Index, SetLocal*> lastSets; // for each index, the last set_local for it
5454
5555 void dump (Function* func) {
5656 if (actions.empty ()) return ;
@@ -76,11 +76,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
7676 }
7777
7878 BasicBlock* makeBasicBlock () {
79- auto * ret = new BasicBlock ();
80- auto & lastSets = ret->contents .lastSets ;
81- lastSets.resize (getFunction ()->getNumLocals ());
82- std::fill (lastSets.begin (), lastSets.end (), nullptr );
83- return ret;
79+ return new BasicBlock ();
8480 }
8581
8682 // cfg traversal work
@@ -103,12 +99,61 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
10399 }
104100
105101 void flow (Function* func) {
102+ // This block struct is optimized for this flow process (Minimal information, iteration index).
103+ struct FlowBlock {
104+ // last Traversed Iteration
105+ // This value help us to find if this block has been seen while traversing blocks.
106+ // We compare this value to the current iteration index in order to determine if we already process this block in the current iteration.
107+ // This speed up the processing compared to unordered_set or other struct usage. (No need to reset internal values, lookup into container, ...)
108+ size_t lastTraversedIteration;
109+ std::vector<Action> actions; // actions occurring in this block
110+ std::vector<FlowBlock*> in;
111+ // for each index, the last set_local for it
112+ // The unordered_map from BasicBlock is converted ther into a vector
113+ // This speed up search as there are almost always fewer than 100 items
114+ std::vector<std::pair<Index, SetLocal*>> lastSets;
115+ };
116+
106117 auto numLocals = func->getNumLocals ();
107118 std::vector<std::vector<GetLocal*>> allGets;
108119 allGets.resize (numLocals);
109- std::unordered_set<BasicBlock*> seen;
110- std::vector<BasicBlock*> work;
111- for (auto & block : basicBlocks) {
120+ std::vector<FlowBlock*> work;
121+
122+
123+ // Converts input blocks (basicBlocks) into more efficient blocks to improve memory access.
124+ std::vector<FlowBlock> flowBlocks;
125+ flowBlocks.resize (basicBlocks.size ());
126+
127+ // Init mapping between basicblocks and flowBlocks
128+ std::unordered_map<BasicBlock*, FlowBlock*> basicToFlowMap;
129+ for (size_t i = 0 ; i < basicBlocks.size (); ++i) {
130+ basicToFlowMap.emplace (std::make_pair (basicBlocks[i].get (), &flowBlocks[i]));
131+ }
132+
133+ FlowBlock* entryFlowBlock = nullptr ;
134+ for (size_t i = 0 ; i < flowBlocks.size (); ++i) {
135+ auto & optBlock = flowBlocks[i];
136+ auto & inBlock = basicBlocks[i];
137+ // Get the equivalent block to entry in the flow list
138+ if (inBlock.get () == entry) entryFlowBlock = &optBlock;
139+ // Initialize iteration index to max size_t to ensure we don't miss a block from wrong value.
140+ optBlock.lastTraversedIteration = -1 ;
141+ optBlock.actions .swap (inBlock->contents .actions );
142+ // Map in block to flow blocks
143+ auto & inBlocks = inBlock->in ;
144+ optBlock.in .resize (inBlocks.size ());
145+ std::transform (inBlocks.begin (), inBlocks.end (), optBlock.in .begin (), [&](BasicBlock* block) { return basicToFlowMap[block]; });
146+
147+ // Convert unordered_map to vector
148+ optBlock.lastSets .reserve (inBlock->contents .lastSets .size ());
149+ for (auto set : inBlock->contents .lastSets ) {
150+ optBlock.lastSets .emplace_back (std::make_pair (set.first , set.second ));
151+ }
152+ }
153+ assert (entryFlowBlock != nullptr );
154+
155+ size_t currentIteration = 0 ;
156+ for (auto & block : flowBlocks) {
112157#ifdef LOCAL_GRAPH_DEBUG
113158 std::cout << " basic block " << block.get () << " :\n " ;
114159 for (auto & action : block->contents .actions ) {
@@ -120,7 +165,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
120165#endif
121166 // go through the block, finding each get and adding it to its index,
122167 // and seeing how sets affect that
123- auto & actions = block-> contents .actions ;
168+ auto & actions = block.actions ;
124169 // move towards the front, handling things as we go
125170 for (int i = int (actions.size ()) - 1 ; i >= 0 ; i--) {
126171 auto & action = actions[i];
@@ -142,8 +187,8 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
142187 for (Index index = 0 ; index < numLocals; index++) {
143188 auto & gets = allGets[index];
144189 if (gets.empty ()) continue ;
145- work.push_back (block. get () );
146- seen. clear ();
190+ work.push_back (& block);
191+
147192 // note that we may need to revisit the later parts of this initial
148193 // block, if we are in a loop, so don't mark it as seen
149194 while (!work.empty ()) {
@@ -152,21 +197,21 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
152197 // we have gone through this block; now we must handle flowing to
153198 // the inputs
154199 if (curr->in .empty ()) {
155- if (curr == entry ) {
200+ if (curr == entryFlowBlock ) {
156201 // these receive a param or zero init value
157202 for (auto * get : gets) {
158203 getSetses[get].insert (nullptr );
159204 }
160205 }
161206 } else {
162207 for (auto * pred : curr->in ) {
163- if (seen. count ( pred) ) continue ;
164- seen. insert ( pred) ;
165- auto * lastSet = pred->contents . lastSets [index] ;
166- if (lastSet) {
208+ if (pred-> lastTraversedIteration == currentIteration ) continue ;
209+ pred-> lastTraversedIteration = currentIteration ;
210+ auto lastSet = std::find_if ( pred->lastSets . begin (), pred-> lastSets . end (), [&](std::pair<Index, SetLocal*>& value) { return value. first == index; }) ;
211+ if (lastSet != pred-> lastSets . end () ) {
167212 // there is a set here, apply it, and stop the flow
168213 for (auto * get : gets) {
169- getSetses[get].insert (lastSet);
214+ getSetses[get].insert (lastSet-> second );
170215 }
171216 } else {
172217 // keep on flowing
@@ -176,6 +221,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
176221 }
177222 }
178223 gets.clear ();
224+ currentIteration++;
179225 }
180226 }
181227 }
0 commit comments