@@ -26,39 +26,10 @@ namespace wasm {
2626
2727namespace LocalGraphInternal {
2828
29- // A relevant action. Supports a get, a set, or an
30- // "other" which can be used for other purposes, to mark
31- // their position in a block
32- struct Action {
33- enum What {
34- Get = 0 ,
35- Set = 1
36- };
37- What what;
38- Index index; // the local index read or written
39- Expression* expr; // the expression itself
40-
41- Action (What what, Index index, Expression* expr) : what(what), index(index), expr(expr) {
42- if (what == Get) assert (expr->is <GetLocal>());
43- if (what == Set) assert (expr->is <SetLocal>());
44- }
45-
46- bool isGet () { return what == Get; }
47- bool isSet () { return what == Set; }
48- };
49-
50- // information about a basic block
29+ // Information about a basic block.
5130struct Info {
52- std::vector<Action > actions; // actions occurring in this block
31+ std::vector<Expression* > actions; // actions occurring in this block: get_locals and set_locals
5332 std::unordered_map<Index, SetLocal*> lastSets; // for each index, the last set_local for it
54-
55- void dump (Function* func) {
56- if (actions.empty ()) return ;
57- std::cout << " actions:\n " ;
58- for (auto & action : actions) {
59- std::cout << " " << (action.isGet () ? " get" : " set" ) << " " << func->getLocalName (action.index ) << " \n " ;
60- }
61- }
6233};
6334
6435// flow helper class. flows the gets to their sets
@@ -85,69 +56,72 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
8556 auto * curr = (*currp)->cast <GetLocal>();
8657 // if in unreachable code, skip
8758 if (!self->currBasicBlock ) return ;
88- self->currBasicBlock ->contents .actions .emplace_back (Action::Get, curr-> index , curr);
59+ self->currBasicBlock ->contents .actions .emplace_back (curr);
8960 self->locations [curr] = currp;
9061 }
9162
9263 static void doVisitSetLocal (Flower* self, Expression** currp) {
9364 auto * curr = (*currp)->cast <SetLocal>();
9465 // if in unreachable code, skip
9566 if (!self->currBasicBlock ) return ;
96- self->currBasicBlock ->contents .actions .emplace_back (Action::Set, curr-> index , curr);
67+ self->currBasicBlock ->contents .actions .emplace_back (curr);
9768 self->currBasicBlock ->contents .lastSets [curr->index ] = curr;
9869 self->locations [curr] = currp;
9970 }
10071
10172 void flow (Function* func) {
10273 // This block struct is optimized for this flow process (Minimal information, iteration index).
10374 struct FlowBlock {
104- // last Traversed Iteration
105- // This value help us to find if this block has been seen while traversing blocks.
75+ // Last Traversed Iteration: This value helps us to find if this block has been seen while traversing blocks.
10676 // 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, ...)
77+ // This speeds up the processing compared to unordered_set or other struct usage. (No need to reset internal values, lookup into container, ...)
10878 size_t lastTraversedIteration;
109- std::vector<Action > actions; // actions occurring in this block
79+ std::vector<Expression* > actions;
11080 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;
81+ // Sor each index, the last set_local for it
82+ // The unordered_map from BasicBlock.Info is converted into a vector
83+ // This speeds up search as there are usually few sets in a block, so just scanning
84+ // them linearly is efficient, avoiding hash computations (while in Info,
85+ // it's convenient to have a map so we can assign them easily, where
86+ // the last one seen overwrites the previous; and, we do that O(1)).
87+ std::vector<std::pair<Index, SetLocal*>> lastSets;
11588 };
11689
11790 auto numLocals = func->getNumLocals ();
11891 std::vector<std::vector<GetLocal*>> allGets;
11992 allGets.resize (numLocals);
12093 std::vector<FlowBlock*> work;
12194
122-
123- // Converts input blocks (basicBlocks) into more efficient blocks to improve memory access.
95+ // Convert input blocks (basicBlocks) into more efficient flow blocks to improve memory access.
12496 std::vector<FlowBlock> flowBlocks;
12597 flowBlocks.resize (basicBlocks.size ());
12698
12799 // Init mapping between basicblocks and flowBlocks
128100 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])) ;
101+ for (Index i = 0 ; i < basicBlocks.size (); ++i) {
102+ basicToFlowMap[ basicBlocks[i].get ()] = &flowBlocks[i];
131103 }
132104
105+ const size_t NULL_ITERATION = -1 ;
106+
133107 FlowBlock* entryFlowBlock = nullptr ;
134- for (size_t i = 0 ; i < flowBlocks.size (); ++i) {
135- auto & optBlock = flowBlocks [i];
136- auto & inBlock = basicBlocks [i];
108+ for (Index i = 0 ; i < flowBlocks.size (); ++i) {
109+ auto & block = basicBlocks [i];
110+ auto & flowBlock = flowBlocks [i];
137111 // 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 );
112+ if (block.get () == entry) entryFlowBlock = &flowBlock;
113+ flowBlock.lastTraversedIteration = NULL_ITERATION;
114+ flowBlock.actions .swap (block->contents .actions );
142115 // 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 ));
116+ auto & in = block->in ;
117+ flowBlock.in .resize (in.size ());
118+ std::transform (in.begin (), in.end (), flowBlock.in .begin (), [&](BasicBlock* block) {
119+ return basicToFlowMap[block];
120+ });
121+ // Convert unordered_map to vector.
122+ flowBlock.lastSets .reserve (block->contents .lastSets .size ());
123+ for (auto set : block->contents .lastSets ) {
124+ flowBlock.lastSets .emplace_back (std::make_pair (set.first , set.second ));
151125 }
152126 }
153127 assert (entryFlowBlock != nullptr );
@@ -157,7 +131,7 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
157131#ifdef LOCAL_GRAPH_DEBUG
158132 std::cout << " basic block " << block.get () << " :\n " ;
159133 for (auto & action : block->contents .actions ) {
160- std::cout << " action: " << action. expr << ' \n ' ;
134+ std::cout << " action: " << * action << ' \n ' ;
161135 }
162136 for (auto * lastSet : block->contents .lastSets ) {
163137 std::cout << " last set " << lastSet << ' \n ' ;
@@ -168,53 +142,56 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
168142 auto & actions = block.actions ;
169143 // move towards the front, handling things as we go
170144 for (int i = int (actions.size ()) - 1 ; i >= 0 ; i--) {
171- auto & action = actions[i];
172- auto index = action.index ;
173- if (action.isGet ()) {
174- allGets[index].push_back (action.expr ->cast <GetLocal>());
145+ auto * action = actions[i];
146+ if (auto * get = action->dynCast <GetLocal>()) {
147+ allGets[get->index ].push_back (get);
175148 } else {
176- // this set is the only set for all those gets
177- auto * set = action. expr ->cast <SetLocal>();
178- auto & gets = allGets[index];
149+ // This set is the only set for all those gets.
150+ auto * set = action->cast <SetLocal>();
151+ auto & gets = allGets[set-> index ];
179152 for (auto * get : gets) {
180153 getSetses[get].insert (set);
181154 }
182155 gets.clear ();
183156 }
184157 }
185- // if anything is left, we must flow it back through other blocks. we
186- // can do that for all gets as a whole, they will get the same results
158+ // If anything is left, we must flow it back through other blocks. we
159+ // can do that for all gets as a whole, they will get the same results.
187160 for (Index index = 0 ; index < numLocals; index++) {
188161 auto & gets = allGets[index];
189162 if (gets.empty ()) continue ;
190163 work.push_back (&block);
191-
192- // note that we may need to revisit the later parts of this initial
193- // block, if we are in a loop, so don't mark it as seen
164+ // Note that we may need to revisit the later parts of this initial
165+ // block, if we are in a loop, so don't mark it as seen.
194166 while (!work.empty ()) {
195167 auto * curr = work.back ();
196168 work.pop_back ();
197- // we have gone through this block; now we must handle flowing to
198- // the inputs
169+ // We have gone through this block; now we must handle flowing to
170+ // the inputs.
199171 if (curr->in .empty ()) {
200172 if (curr == entryFlowBlock) {
201- // these receive a param or zero init value
173+ // These receive a param or zero init value.
202174 for (auto * get : gets) {
203175 getSetses[get].insert (nullptr );
204176 }
205177 }
206178 } else {
207179 for (auto * pred : curr->in ) {
208- if (pred->lastTraversedIteration == currentIteration) continue ;
180+ if (pred->lastTraversedIteration == currentIteration) {
181+ // We've already seen pred in this iteration.
182+ continue ;
183+ }
209184 pred->lastTraversedIteration = currentIteration;
210- auto lastSet = std::find_if (pred->lastSets .begin (), pred->lastSets .end (), [&](std::pair<Index, SetLocal*>& value) { return value.first == index; });
185+ auto lastSet = std::find_if (pred->lastSets .begin (), pred->lastSets .end (), [&](std::pair<Index, SetLocal*>& value) {
186+ return value.first == index;
187+ });
211188 if (lastSet != pred->lastSets .end ()) {
212- // there is a set here, apply it, and stop the flow
189+ // There is a set here, apply it, and stop the flow.
213190 for (auto * get : gets) {
214191 getSetses[get].insert (lastSet->second );
215192 }
216193 } else {
217- // keep on flowing
194+ // Keep on flowing.
218195 work.push_back (pred);
219196 }
220197 }
0 commit comments