OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "src/compiler/graph.h" | |
6 #include "src/compiler/loop-analysis.h" | |
7 #include "src/compiler/node.h" | |
8 #include "src/compiler/node-properties-inl.h" | |
9 #include "src/zone.h" | |
10 | |
11 namespace v8 { | |
12 namespace internal { | |
13 namespace compiler { | |
14 | |
15 typedef uint32_t LoopMarks; | |
16 | |
17 | |
18 // TODO(titzer): don't assume entry edges have a particular index. | |
19 // TODO(titzer): use a BitMatrix to generalize this algorithm. | |
20 static const int kMaxLoops = 31; | |
21 static const int kAssumedLoopEntryIndex = 0; // assume loops are entered here. | |
22 static const LoopMarks kVisited = 1; // loop #0 is reserved. | |
23 | |
24 | |
25 // Temporary information for each node during marking. | |
26 struct NodeInfo { | |
27 Node* node; | |
28 NodeInfo* next; // link in chaining loop members | |
29 LoopMarks forward; // accumulated marks in the forward direction | |
30 LoopMarks backward; // accumulated marks in the backward direction | |
31 LoopMarks loop_mark; // loop mark for header nodes; encodes loop_num | |
32 | |
33 bool MarkBackward(LoopMarks bw) { | |
34 LoopMarks prev = backward; | |
35 LoopMarks next = backward | bw; | |
36 backward = next; | |
37 return prev != next; | |
38 } | |
39 | |
40 bool MarkForward(LoopMarks fw) { | |
41 LoopMarks prev = forward; | |
42 LoopMarks next = forward | fw; | |
43 forward = next; | |
44 return prev != next; | |
45 } | |
46 | |
47 bool IsInLoop(int loop_num) { | |
48 DCHECK(loop_num > 0 && loop_num <= 31); | |
49 return forward & backward & (1 << loop_num); | |
50 } | |
51 | |
52 bool IsLoopHeader() { return loop_mark != 0; } | |
53 bool IsInAnyLoop() { return (forward & backward) > kVisited; } | |
54 | |
55 bool IsInHeaderForLoop(int loop_num) { | |
56 DCHECK(loop_num > 0); | |
57 return loop_mark == (kVisited | (1 << loop_num)); | |
58 } | |
59 }; | |
60 | |
61 | |
62 // Temporary loop info needed during traversal and building the loop tree. | |
63 struct LoopInfo { | |
64 Node* header; | |
65 NodeInfo* header_list; | |
66 NodeInfo* body_list; | |
67 LoopTree::Loop* loop; | |
68 }; | |
69 | |
70 | |
71 static const NodeInfo kEmptyNodeInfo = {NULL, NULL, 0, 0, 0}; | |
72 | |
73 | |
74 // Encapsulation of the loop finding algorithm. | |
75 class LoopFinderImpl { | |
76 public: | |
77 LoopFinderImpl(Graph* graph, LoopTree* loop_tree, Zone* zone) | |
78 : end_(graph->end()), | |
79 queue_(zone), | |
80 queued_(graph, 2), | |
81 info_(graph->NodeCount(), kEmptyNodeInfo, zone), | |
82 loops_(zone), | |
83 loop_tree_(loop_tree), | |
84 loops_found_(0) {} | |
85 | |
86 void Run() { | |
87 PropagateBackward(); | |
88 PropagateForward(); | |
89 FinishLoopTree(); | |
90 } | |
91 | |
92 void Print() { | |
93 // Print out the results. | |
94 for (NodeInfo& ni : info_) { | |
95 if (ni.node == NULL) continue; | |
96 for (size_t i = 1; i <= loops_.size(); i++) { | |
97 if (ni.IsInLoop(i)) { | |
98 PrintF("X"); | |
99 } else if (ni.forward & (1 << i)) { | |
100 PrintF("/"); | |
101 } else if (ni.backward & (1 << i)) { | |
102 PrintF("\\"); | |
103 } else { | |
104 PrintF(" "); | |
105 } | |
106 } | |
107 PrintF(" #%d:%s\n", ni.node->id(), ni.node->op()->mnemonic()); | |
108 } | |
109 | |
110 int i = 0; | |
111 for (LoopInfo& li : loops_) { | |
112 PrintF("Loop %d headed at #%d\n", i, li.header->id()); | |
113 i++; | |
114 } | |
115 | |
116 for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { | |
117 PrintLoop(loop); | |
118 } | |
119 } | |
120 | |
121 private: | |
122 Node* end_; | |
123 NodeDeque queue_; | |
124 NodeMarker<bool> queued_; | |
125 ZoneVector<NodeInfo> info_; | |
126 ZoneVector<LoopInfo> loops_; | |
127 LoopTree* loop_tree_; | |
128 int loops_found_; | |
129 | |
130 // Propagate marks backward from loop headers. | |
131 void PropagateBackward() { | |
132 PropagateBackward(end_, kVisited); | |
133 | |
134 while (!queue_.empty()) { | |
135 Node* node = queue_.front(); | |
136 queue_.pop_front(); | |
137 queued_.Set(node, false); | |
138 | |
139 // Setup loop headers first. | |
140 if (node->opcode() == IrOpcode::kLoop) { | |
141 // found the loop node first. | |
142 CreateLoopInfo(node); | |
143 } else if (node->opcode() == IrOpcode::kPhi || | |
144 node->opcode() == IrOpcode::kEffectPhi) { | |
145 // found a phi first. | |
146 Node* merge = node->InputAt(node->InputCount() - 1); | |
147 if (merge->opcode() == IrOpcode::kLoop) CreateLoopInfo(merge); | |
148 } | |
149 | |
150 // Propagate reachability marks backwards from this node. | |
151 NodeInfo& ni = info(node); | |
152 if (ni.IsLoopHeader()) { | |
153 // Handle edges from loop header nodes specially. | |
154 for (int i = 0; i < node->InputCount(); i++) { | |
155 if (i == kAssumedLoopEntryIndex) { | |
156 // Don't propagate the loop mark backwards on the entry edge. | |
157 PropagateBackward(node->InputAt(0), | |
158 kVisited | (ni.backward & ~ni.loop_mark)); | |
159 } else { | |
160 // Only propagate the loop mark on backedges. | |
161 PropagateBackward(node->InputAt(i), ni.loop_mark); | |
162 } | |
163 } | |
164 } else { | |
165 // Propagate all loop marks backwards for a normal node. | |
166 for (Node* const input : node->inputs()) { | |
167 PropagateBackward(input, ni.backward); | |
168 } | |
169 } | |
170 } | |
171 } | |
172 | |
173 // Make a new loop header for the given node. | |
174 void CreateLoopInfo(Node* node) { | |
175 NodeInfo& ni = info(node); | |
176 if (ni.IsLoopHeader()) return; // loop already set up. | |
177 | |
178 loops_found_++; | |
179 size_t loop_num = loops_.size() + 1; | |
180 CHECK(loops_found_ <= kMaxLoops); // TODO(titzer): don't crash. | |
181 // Create a new loop. | |
182 loops_.push_back({node, NULL, NULL, NULL}); | |
183 loop_tree_->NewLoop(); | |
184 LoopMarks loop_mark = kVisited | (1 << loop_num); | |
185 ni.node = node; | |
186 ni.loop_mark = loop_mark; | |
187 | |
188 // Setup loop mark for phis attached to loop header. | |
189 for (Node* use : node->uses()) { | |
190 if (use->opcode() == IrOpcode::kPhi || | |
191 use->opcode() == IrOpcode::kEffectPhi) { | |
192 info(use).loop_mark = loop_mark; | |
193 } | |
194 } | |
195 } | |
196 | |
197 // Propagate marks forward from loops. | |
198 void PropagateForward() { | |
199 for (LoopInfo& li : loops_) { | |
200 queued_.Set(li.header, true); | |
201 queue_.push_back(li.header); | |
202 NodeInfo& ni = info(li.header); | |
203 ni.forward = ni.loop_mark; | |
204 } | |
205 // Propagate forward on paths that were backward reachable from backedges. | |
206 while (!queue_.empty()) { | |
207 Node* node = queue_.front(); | |
208 queue_.pop_front(); | |
209 queued_.Set(node, false); | |
210 NodeInfo& ni = info(node); | |
211 for (Edge edge : node->use_edges()) { | |
212 Node* use = edge.from(); | |
213 NodeInfo& ui = info(use); | |
214 if (IsBackedge(use, ui, edge)) continue; // skip backedges. | |
215 LoopMarks both = ni.forward & ui.backward; | |
216 if (ui.MarkForward(both) && !queued_.Get(use)) { | |
217 queued_.Set(use, true); | |
218 queue_.push_back(use); | |
219 } | |
220 } | |
221 } | |
222 } | |
223 | |
224 bool IsBackedge(Node* use, NodeInfo& ui, Edge& edge) { | |
225 // TODO(titzer): checking for backedges here is ugly. | |
226 if (!ui.IsLoopHeader()) return false; | |
227 if (edge.index() == kAssumedLoopEntryIndex) return false; | |
228 if (use->opcode() == IrOpcode::kPhi || | |
229 use->opcode() == IrOpcode::kEffectPhi) { | |
230 return !NodeProperties::IsControlEdge(edge); | |
231 } | |
232 return true; | |
233 } | |
234 | |
235 NodeInfo& info(Node* node) { | |
236 NodeInfo& i = info_[node->id()]; | |
237 if (i.node == NULL) i.node = node; | |
238 return i; | |
239 } | |
240 | |
241 void PropagateBackward(Node* node, LoopMarks marks) { | |
242 if (info(node).MarkBackward(marks) && !queued_.Get(node)) { | |
243 queue_.push_back(node); | |
244 queued_.Set(node, true); | |
245 } | |
246 } | |
247 | |
248 void FinishLoopTree() { | |
249 // Degenerate cases. | |
250 if (loops_.size() == 0) return; | |
251 if (loops_.size() == 1) return FinishSingleLoop(); | |
252 | |
253 for (size_t i = 1; i <= loops_.size(); i++) ConnectLoopTree(i); | |
254 | |
255 int count = 0; | |
Benedikt Meurer
2014/12/16 06:10:25
s/int/size_t/
titzer
2014/12/16 07:55:09
Done.
| |
256 // Place the node into the innermost nested loop of which it is a member. | |
257 for (NodeInfo& ni : info_) { | |
258 if (ni.node == NULL || !ni.IsInAnyLoop()) continue; | |
259 | |
260 LoopInfo* innermost = NULL; | |
261 size_t index = 0; | |
262 for (size_t i = 1; i <= loops_.size(); i++) { | |
263 if (ni.IsInLoop(i)) { | |
264 LoopInfo* loop = &loops_[i - 1]; | |
265 if (innermost == NULL || | |
266 loop->loop->depth_ > innermost->loop->depth_) { | |
267 innermost = loop; | |
268 index = i; | |
269 } | |
270 } | |
271 } | |
272 if (ni.IsInHeaderForLoop(index)) { | |
273 ni.next = innermost->header_list; | |
274 innermost->header_list = ∋ | |
275 } else { | |
276 ni.next = innermost->body_list; | |
277 innermost->body_list = ∋ | |
278 } | |
279 count++; | |
280 } | |
281 | |
282 // Serialize the node lists for loops into the loop tree. | |
283 loop_tree_->loop_nodes_.reserve(count); | |
284 for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { | |
285 SerializeLoop(loop); | |
286 } | |
287 } | |
288 | |
289 // Handle the simpler case of a single loop (no checks for nesting necessary). | |
290 void FinishSingleLoop() { | |
291 DCHECK(loops_.size() == 1); | |
292 DCHECK(loop_tree_->all_loops_.size() == 1); | |
293 | |
294 // Place nodes into the loop header and body. | |
295 LoopInfo* li = &loops_[0]; | |
296 li->loop = &loop_tree_->all_loops_[0]; | |
297 loop_tree_->SetParent(NULL, li->loop); | |
298 int count = 0; | |
Benedikt Meurer
2014/12/16 06:10:25
s/int/size_t/
titzer
2014/12/16 07:55:09
Done.
| |
299 for (NodeInfo& ni : info_) { | |
300 if (ni.node == NULL || !ni.IsInAnyLoop()) continue; | |
301 DCHECK(ni.IsInLoop(1)); | |
302 if (ni.IsInHeaderForLoop(1)) { | |
303 ni.next = li->header_list; | |
304 li->header_list = ∋ | |
305 } else { | |
306 ni.next = li->body_list; | |
307 li->body_list = ∋ | |
308 } | |
309 count++; | |
310 } | |
311 | |
312 // Serialize the node lists for the loop into the loop tree. | |
313 loop_tree_->loop_nodes_.reserve(count); | |
314 SerializeLoop(li->loop); | |
315 } | |
316 | |
317 // Recursively serialize the list of header nodes and body nodes | |
318 // so that nested loops occupy nested intervals. | |
319 void SerializeLoop(LoopTree::Loop* loop) { | |
320 int loop_num = loop_tree_->LoopNum(loop); | |
321 LoopInfo& li = loops_[loop_num - 1]; | |
322 | |
323 // Serialize the header. | |
324 loop->header_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); | |
325 for (NodeInfo* ni = li.header_list; ni != NULL; ni = ni->next) { | |
326 loop_tree_->loop_nodes_.push_back(ni->node); | |
327 loop_tree_->node_to_loop_num_[ni->node->id()] = | |
328 static_cast<uint8_t>(loop_num); | |
Benedikt Meurer
2014/12/16 06:10:25
Please add a TODO here to ensure that this static_
titzer
2014/12/16 07:55:09
Done.
| |
329 } | |
330 | |
331 // Serialize the body. | |
332 loop->body_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); | |
333 for (NodeInfo* ni = li.body_list; ni != NULL; ni = ni->next) { | |
334 loop_tree_->loop_nodes_.push_back(ni->node); | |
335 loop_tree_->node_to_loop_num_[ni->node->id()] = | |
336 static_cast<uint8_t>(loop_num); | |
Benedikt Meurer
2014/12/16 06:10:25
Please add a TODO here to ensure that this static_
titzer
2014/12/16 07:55:09
Done.
| |
337 } | |
338 | |
339 // Serialize nested loops. | |
340 for (LoopTree::Loop* child : loop->children_) SerializeLoop(child); | |
341 | |
342 loop->body_end_ = static_cast<int>(loop_tree_->loop_nodes_.size()); | |
343 } | |
344 | |
345 // Connect the LoopTree loops to their parents recursively. | |
346 LoopTree::Loop* ConnectLoopTree(size_t loop_num) { | |
347 LoopInfo& li = loops_[loop_num - 1]; | |
348 if (li.loop != NULL) return li.loop; | |
349 | |
350 NodeInfo& ni = info(li.header); | |
351 LoopTree::Loop* parent = NULL; | |
352 for (size_t i = 1; i <= loops_.size(); i++) { | |
353 if (i == loop_num) continue; | |
354 if (ni.IsInLoop(i)) { | |
355 // recursively create potential parent loops first. | |
356 LoopTree::Loop* upper = ConnectLoopTree(i); | |
357 if (parent == NULL || upper->depth_ > parent->depth_) { | |
358 parent = upper; | |
359 } | |
360 } | |
361 } | |
362 li.loop = &loop_tree_->all_loops_[loop_num - 1]; | |
363 loop_tree_->SetParent(parent, li.loop); | |
364 return li.loop; | |
365 } | |
366 | |
367 void PrintLoop(LoopTree::Loop* loop) { | |
368 for (int i = 0; i < loop->depth_; i++) PrintF(" "); | |
369 PrintF("Loop depth = %d ", loop->depth_); | |
370 int i = loop->header_start_; | |
371 while (i < loop->body_start_) { | |
372 PrintF(" H#%d", loop_tree_->loop_nodes_[i++]->id()); | |
373 } | |
374 while (i < loop->body_end_) { | |
375 PrintF(" B#%d", loop_tree_->loop_nodes_[i++]->id()); | |
376 } | |
377 PrintF("\n"); | |
378 for (LoopTree::Loop* child : loop->children_) PrintLoop(child); | |
379 } | |
380 }; | |
381 | |
382 | |
383 LoopTree* LoopFinder::BuildLoopTree(Graph* graph, Zone* zone) { | |
384 LoopTree* loop_tree = | |
385 new (graph->zone()) LoopTree(graph->NodeCount(), graph->zone()); | |
386 LoopFinderImpl finder(graph, loop_tree, zone); | |
387 finder.Run(); | |
388 if (FLAG_trace_turbo_graph) { | |
389 finder.Print(); | |
390 } | |
391 return loop_tree; | |
392 } | |
393 | |
394 } // namespace compiler | |
395 } // namespace internal | |
396 } // namespace v8 | |
OLD | NEW |