5 #include "src/compiler/loop-analysis.h" 7 #include "src/compiler/graph.h" 8 #include "src/compiler/node-marker.h" 9 #include "src/compiler/node-properties.h" 10 #include "src/compiler/node.h" 11 #include "src/zone/zone.h" 17 #define OFFSET(x) ((x)&0x1F) 18 #define BIT(x) (1u << OFFSET(x)) 19 #define INDEX(x) ((x) >> 5) 59 info_(graph->NodeCount(), {
nullptr,
nullptr}, zone),
61 loop_num_(graph->NodeCount(), -1, zone),
62 loop_tree_(loop_tree),
77 if (ni.node ==
nullptr)
continue;
78 for (
int i = 1;
i <= loops_found_;
i++) {
79 int index = ni.node->id() * width_ + INDEX(
i);
80 bool marked_forward = forward_[index] & BIT(
i);
81 bool marked_backward = backward_[index] & BIT(
i);
82 if (marked_forward && marked_backward) {
84 }
else if (marked_forward) {
86 }
else if (marked_backward) {
92 PrintF(
" #%d:%s\n", ni.node->id(), ni.node->op()->mnemonic());
97 PrintF(
"Loop %d headed at #%d\n",
i, li.header->id());
121 return static_cast<int>(loop_tree_->node_to_loop_num_.size());
125 bool PropagateBackwardMarks(
Node* from,
Node* to,
int loop_filter) {
126 if (from == to)
return false;
127 uint32_t* fp = &backward_[from->id() * width_];
128 uint32_t* tp = &backward_[to->id() * width_];
130 for (
int i = 0;
i < width_;
i++) {
131 uint32_t mask =
i == INDEX(loop_filter) ? ~BIT(loop_filter) : 0xFFFFFFFF;
135 if (!change && (prev != next)) change =
true;
141 bool SetBackwardMark(
Node* to,
int loop_num) {
142 uint32_t* tp = &backward_[to->id() * width_ + INDEX(loop_num)];
144 uint32_t next = prev | BIT(loop_num);
150 bool SetForwardMark(
Node* to,
int loop_num) {
151 uint32_t* tp = &forward_[to->id() * width_ + INDEX(loop_num)];
153 uint32_t next = prev | BIT(loop_num);
159 bool PropagateForwardMarks(
Node* from,
Node* to) {
160 if (from == to)
return false;
162 int findex = from->id() * width_;
163 int tindex = to->id() * width_;
164 for (
int i = 0;
i < width_;
i++) {
165 uint32_t marks = backward_[tindex +
i] & forward_[findex +
i];
168 forward_[tindex +
i] = next;
169 if (!change && (prev != next)) change =
true;
174 bool IsInLoop(
Node* node,
int loop_num) {
175 int offset = node->id() * width_ + INDEX(loop_num);
176 return backward_[offset] & forward_[offset] & BIT(loop_num);
180 void PropagateBackward() {
181 ResizeBackwardMarks();
182 SetBackwardMark(end_, 0);
185 while (!queue_.empty()) {
186 Node* node = queue_.front();
189 queued_.Set(node,
false);
193 if (node->opcode() == IrOpcode::kLoop) {
195 loop_num = CreateLoopInfo(node);
196 }
else if (NodeProperties::IsPhi(node)) {
198 Node* merge = node->InputAt(node->InputCount() - 1);
199 if (merge->opcode() == IrOpcode::kLoop) {
200 loop_num = CreateLoopInfo(merge);
202 }
else if (node->opcode() == IrOpcode::kLoopExit) {
205 CreateLoopInfo(node->InputAt(1));
206 }
else if (node->opcode() == IrOpcode::kLoopExitValue ||
207 node->opcode() == IrOpcode::kLoopExitEffect) {
208 Node* loop_exit = NodeProperties::GetControlInput(node);
211 CreateLoopInfo(loop_exit->InputAt(1));
215 for (
int i = 0;
i < node->InputCount();
i++) {
216 Node* input = node->InputAt(
i);
217 if (IsBackedge(node,
i)) {
219 if (SetBackwardMark(input, loop_num)) Queue(input);
222 if (PropagateBackwardMarks(node, input, loop_num)) Queue(input);
229 int CreateLoopInfo(
Node* node) {
230 DCHECK_EQ(IrOpcode::kLoop, node->opcode());
231 int loop_num = LoopNum(node);
232 if (loop_num > 0)
return loop_num;
234 loop_num = ++loops_found_;
235 if (INDEX(loop_num) >= width_) ResizeBackwardMarks();
238 loops_.push_back({node,
nullptr,
nullptr,
nullptr,
nullptr});
239 loop_tree_->NewLoop();
240 SetLoopMarkForLoopHeader(node, loop_num);
244 void SetLoopMark(
Node* node,
int loop_num) {
246 SetBackwardMark(node, loop_num);
247 loop_tree_->node_to_loop_num_[node->id()] = loop_num;
250 void SetLoopMarkForLoopHeader(
Node* node,
int loop_num) {
251 DCHECK_EQ(IrOpcode::kLoop, node->opcode());
252 SetLoopMark(node, loop_num);
253 for (
Node* use : node->uses()) {
254 if (NodeProperties::IsPhi(use)) {
255 SetLoopMark(use, loop_num);
259 if (node->InputCount() <= 1)
continue;
261 if (use->opcode() == IrOpcode::kLoopExit) {
262 SetLoopMark(use, loop_num);
263 for (
Node* exit_use : use->uses()) {
264 if (exit_use->opcode() == IrOpcode::kLoopExitValue ||
265 exit_use->opcode() == IrOpcode::kLoopExitEffect) {
266 SetLoopMark(exit_use, loop_num);
273 void ResizeBackwardMarks() {
274 int new_width = width_ + 1;
275 int max = num_nodes();
277 memset(new_backward, 0, new_width * max *
sizeof(
uint32_t));
279 for (
int i = 0;
i < max;
i++) {
280 uint32_t* np = &new_backward[
i * new_width];
282 for (
int j = 0; j < width_; j++) np[j] = op[j];
286 backward_ = new_backward;
289 void ResizeForwardMarks() {
290 int max = num_nodes();
291 forward_ = zone_->NewArray<
uint32_t>(width_ * max);
292 memset(forward_, 0, width_ * max *
sizeof(
uint32_t));
296 void PropagateForward() {
297 ResizeForwardMarks();
299 SetForwardMark(li.header, LoopNum(li.header));
303 while (!queue_.empty()) {
304 Node* node = queue_.front();
306 queued_.Set(node,
false);
307 for (
Edge edge : node->use_edges()) {
308 Node* use = edge.from();
309 if (!IsBackedge(use, edge.index())) {
310 if (PropagateForwardMarks(node, use)) Queue(use);
316 bool IsLoopHeaderNode(
Node* node) {
317 return node->opcode() == IrOpcode::kLoop || NodeProperties::IsPhi(node);
320 bool IsLoopExitNode(
Node* node) {
321 return node->opcode() == IrOpcode::kLoopExit ||
322 node->opcode() == IrOpcode::kLoopExitValue ||
323 node->opcode() == IrOpcode::kLoopExitEffect;
326 bool IsBackedge(
Node* use,
int index) {
327 if (LoopNum(use) <= 0)
return false;
328 if (NodeProperties::IsPhi(use)) {
329 return index != NodeProperties::FirstControlIndex(use) &&
330 index != kAssumedLoopEntryIndex;
331 }
else if (use->opcode() == IrOpcode::kLoop) {
332 return index != kAssumedLoopEntryIndex;
334 DCHECK(IsLoopExitNode(use));
338 int LoopNum(
Node* node) {
return loop_tree_->node_to_loop_num_[node->id()]; }
342 if (
i.node ==
nullptr)
i.node = node;
346 void Queue(
Node* node) {
347 if (!queued_.Get(node)) {
348 queue_.push_back(node);
349 queued_.Set(node,
true);
354 if (LoopNum(node_info->node) == loop_num) {
355 if (IsLoopHeaderNode(node_info->node)) {
356 node_info->next = loop->header_list;
357 loop->header_list = node_info;
359 DCHECK(IsLoopExitNode(node_info->node));
360 node_info->next = loop->exit_list;
361 loop->exit_list = node_info;
364 node_info->next = loop->body_list;
365 loop->body_list = node_info;
369 void FinishLoopTree() {
370 DCHECK(loops_found_ == static_cast<int>(loops_.size()));
371 DCHECK(loops_found_ == static_cast<int>(loop_tree_->all_loops_.size()));
374 if (loops_found_ == 0)
return;
375 if (loops_found_ == 1)
return FinishSingleLoop();
377 for (
int i = 1;
i <= loops_found_;
i++) ConnectLoopTree(
i);
382 if (ni.node ==
nullptr)
continue;
385 int innermost_index = 0;
386 int pos = ni.node->id() * width_;
388 for (
int i = 0;
i < width_;
i++) {
389 uint32_t marks = backward_[pos +
i] & forward_[pos +
i];
391 for (
int j = 0; j < 32; j++) {
392 if (marks & (1u << j)) {
393 int loop_num =
i * 32 + j;
394 if (loop_num == 0)
continue;
396 if (innermost ==
nullptr ||
397 loop->loop->depth_ > innermost->loop->depth_) {
399 innermost_index = loop_num;
404 if (innermost ==
nullptr)
continue;
407 CHECK(ni.node->opcode() != IrOpcode::kReturn);
409 AddNodeToLoop(&ni, innermost, innermost_index);
414 loop_tree_->loop_nodes_.reserve(count);
421 void FinishSingleLoop() {
424 li->loop = &loop_tree_->all_loops_[0];
425 loop_tree_->SetParent(
nullptr, li->loop);
428 if (ni.node ==
nullptr || !IsInLoop(ni.node, 1))
continue;
431 CHECK(ni.node->opcode() != IrOpcode::kReturn);
433 AddNodeToLoop(&ni, li, 1);
438 loop_tree_->loop_nodes_.reserve(count);
439 SerializeLoop(li->loop);
445 int loop_num = loop_tree_->LoopNum(loop);
449 loop->header_start_ =
static_cast<int>(loop_tree_->loop_nodes_.size());
450 for (
NodeInfo* ni = li.header_list; ni !=
nullptr; ni = ni->next) {
451 loop_tree_->loop_nodes_.push_back(ni->node);
452 loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num;
456 loop->body_start_ =
static_cast<int>(loop_tree_->loop_nodes_.size());
457 for (
NodeInfo* ni = li.body_list; ni !=
nullptr; ni = ni->next) {
458 loop_tree_->loop_nodes_.push_back(ni->node);
459 loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num;
463 for (
LoopTree::Loop* child : loop->children_) SerializeLoop(child);
466 loop->exits_start_ =
static_cast<int>(loop_tree_->loop_nodes_.size());
467 for (
NodeInfo* ni = li.exit_list; ni !=
nullptr; ni = ni->next) {
468 loop_tree_->loop_nodes_.push_back(ni->node);
469 loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num;
472 loop->exits_end_ =
static_cast<int>(loop_tree_->loop_nodes_.size());
478 if (li.loop !=
nullptr)
return li.loop;
482 for (
int i = 1;
i <= loops_found_;
i++) {
483 if (
i == loop_num)
continue;
484 if (IsInLoop(ni.node,
i)) {
487 if (parent ==
nullptr || upper->depth_ > parent->depth_) {
492 li.loop = &loop_tree_->all_loops_[loop_num - 1];
493 loop_tree_->SetParent(parent, li.loop);
498 for (
int i = 0;
i < loop->depth_;
i++) PrintF(
" ");
499 PrintF(
"Loop depth = %d ", loop->depth_);
500 int i = loop->header_start_;
501 while (i < loop->body_start_) {
502 PrintF(
" H#%d", loop_tree_->loop_nodes_[
i++]->id());
504 while (i < loop->exits_start_) {
505 PrintF(
" B#%d", loop_tree_->loop_nodes_[
i++]->id());
507 while (i < loop->exits_end_) {
508 PrintF(
" E#%d", loop_tree_->loop_nodes_[
i++]->id());
518 new (graph->zone())
LoopTree(graph->NodeCount(), graph->zone());
521 if (FLAG_trace_turbo_loop) {
528 Node* LoopTree::HeaderNode(Loop* loop) {
529 Node* first = *HeaderNodes(loop).begin();
530 if (first->opcode() == IrOpcode::kLoop)
return first;
531 DCHECK(IrOpcode::IsPhiOpcode(first->opcode()));
532 Node* header = NodeProperties::GetControlInput(first);
533 DCHECK_EQ(IrOpcode::kLoop, header->opcode());