Index: src/compiler/loop-analysis.cc |
diff --git a/src/compiler/loop-analysis.cc b/src/compiler/loop-analysis.cc |
index d52c7c7742df51f2a679f2a2897332b895bcaf1a..bc3f94deaa50912163bb12089b42b439dfc42b4c 100644 |
--- a/src/compiler/loop-analysis.cc |
+++ b/src/compiler/loop-analysis.cc |
@@ -29,6 +29,7 @@ struct NodeInfo { |
struct LoopInfo { |
Node* header; |
NodeInfo* header_list; |
+ NodeInfo* exit_list; |
NodeInfo* body_list; |
LoopTree::Loop* loop; |
}; |
@@ -81,9 +82,9 @@ class LoopFinderImpl { |
if (marked_forward && marked_backward) { |
PrintF("X"); |
} else if (marked_forward) { |
- PrintF("/"); |
+ PrintF(">"); |
} else if (marked_backward) { |
- PrintF("\\"); |
+ PrintF("<"); |
} else { |
PrintF(" "); |
} |
@@ -198,12 +199,22 @@ class LoopFinderImpl { |
if (merge->opcode() == IrOpcode::kLoop) { |
loop_num = CreateLoopInfo(merge); |
} |
+ } else if (node->opcode() == IrOpcode::kLoopExit) { |
+ // Intentionally ignore return value. Loop exit node marks |
+ // are propagated normally. |
+ CreateLoopInfo(node->InputAt(1)); |
+ } else if (node->opcode() == IrOpcode::kLoopExitValue || |
+ node->opcode() == IrOpcode::kLoopExitEffect) { |
+ Node* loop_exit = NodeProperties::GetControlInput(node); |
+ // Intentionally ignore return value. Loop exit node marks |
+ // are propagated normally. |
+ CreateLoopInfo(loop_exit->InputAt(1)); |
} |
// Propagate marks backwards from this node. |
for (int i = 0; i < node->InputCount(); i++) { |
Node* input = node->InputAt(i); |
- if (loop_num > 0 && i != kAssumedLoopEntryIndex) { |
+ if (IsBackedge(node, i)) { |
// Only propagate the loop mark on backedges. |
if (SetBackwardMark(input, loop_num)) Queue(input); |
} else { |
@@ -216,6 +227,7 @@ class LoopFinderImpl { |
// Make a new loop if necessary for the given node. |
int CreateLoopInfo(Node* node) { |
+ DCHECK_EQ(IrOpcode::kLoop, node->opcode()); |
int loop_num = LoopNum(node); |
if (loop_num > 0) return loop_num; |
@@ -223,21 +235,39 @@ class LoopFinderImpl { |
if (INDEX(loop_num) >= width_) ResizeBackwardMarks(); |
// Create a new loop. |
- loops_.push_back({node, nullptr, nullptr, nullptr}); |
+ loops_.push_back({node, nullptr, nullptr, nullptr, nullptr}); |
loop_tree_->NewLoop(); |
+ SetLoopMarkForLoopHeader(node, loop_num); |
+ return loop_num; |
+ } |
+ |
+ void SetLoopMark(Node* node, int loop_num) { |
+ info(node); // create the NodeInfo |
SetBackwardMark(node, loop_num); |
loop_tree_->node_to_loop_num_[node->id()] = loop_num; |
+ } |
- // Setup loop mark for phis attached to loop header. |
+ void SetLoopMarkForLoopHeader(Node* node, int loop_num) { |
+ DCHECK_EQ(IrOpcode::kLoop, node->opcode()); |
+ SetLoopMark(node, loop_num); |
for (Node* use : node->uses()) { |
if (NodeProperties::IsPhi(use)) { |
- info(use); // create the NodeInfo |
- SetBackwardMark(use, loop_num); |
- loop_tree_->node_to_loop_num_[use->id()] = loop_num; |
+ SetLoopMark(use, loop_num); |
} |
- } |
- return loop_num; |
+ // Do not keep the loop alive if it does not have any backedges. |
+ if (node->InputCount() <= 1) continue; |
+ |
+ if (use->opcode() == IrOpcode::kLoopExit) { |
+ SetLoopMark(use, loop_num); |
+ for (Node* exit_use : use->uses()) { |
+ if (exit_use->opcode() == IrOpcode::kLoopExitValue || |
+ exit_use->opcode() == IrOpcode::kLoopExitEffect) { |
+ SetLoopMark(exit_use, loop_num); |
+ } |
+ } |
+ } |
+ } |
} |
void ResizeBackwardMarks() { |
@@ -276,20 +306,33 @@ class LoopFinderImpl { |
queued_.Set(node, false); |
for (Edge edge : node->use_edges()) { |
Node* use = edge.from(); |
- if (!IsBackedge(use, edge)) { |
+ if (!IsBackedge(use, edge.index())) { |
if (PropagateForwardMarks(node, use)) Queue(use); |
} |
} |
} |
} |
- bool IsBackedge(Node* use, Edge& edge) { |
+ bool IsLoopHeaderNode(Node* node) { |
+ return node->opcode() == IrOpcode::kLoop || NodeProperties::IsPhi(node); |
+ } |
+ |
+ bool IsLoopExitNode(Node* node) { |
+ return node->opcode() == IrOpcode::kLoopExit || |
+ node->opcode() == IrOpcode::kLoopExitValue || |
+ node->opcode() == IrOpcode::kLoopExitEffect; |
+ } |
+ |
+ bool IsBackedge(Node* use, int index) { |
if (LoopNum(use) <= 0) return false; |
- if (edge.index() == kAssumedLoopEntryIndex) return false; |
if (NodeProperties::IsPhi(use)) { |
- return !NodeProperties::IsControlEdge(edge); |
+ return index != NodeProperties::FirstControlIndex(use) && |
+ index != kAssumedLoopEntryIndex; |
+ } else if (use->opcode() == IrOpcode::kLoop) { |
+ return index != kAssumedLoopEntryIndex; |
} |
- return true; |
+ DCHECK(IsLoopExitNode(use)); |
+ return false; |
} |
int LoopNum(Node* node) { return loop_tree_->node_to_loop_num_[node->id()]; } |
@@ -307,6 +350,22 @@ class LoopFinderImpl { |
} |
} |
+ void AddNodeToLoop(NodeInfo* node_info, LoopInfo* loop, int loop_num) { |
+ if (LoopNum(node_info->node) == loop_num) { |
+ if (IsLoopHeaderNode(node_info->node)) { |
+ node_info->next = loop->header_list; |
+ loop->header_list = node_info; |
+ } else { |
+ DCHECK(IsLoopExitNode(node_info->node)); |
+ node_info->next = loop->exit_list; |
+ loop->exit_list = node_info; |
+ } |
+ } else { |
+ node_info->next = loop->body_list; |
+ loop->body_list = node_info; |
+ } |
+ } |
+ |
void FinishLoopTree() { |
DCHECK(loops_found_ == static_cast<int>(loops_.size())); |
DCHECK(loops_found_ == static_cast<int>(loop_tree_->all_loops_.size())); |
@@ -342,13 +401,7 @@ class LoopFinderImpl { |
} |
} |
if (innermost == nullptr) continue; |
- if (LoopNum(ni.node) == innermost_index) { |
- ni.next = innermost->header_list; |
- innermost->header_list = ∋ |
- } else { |
- ni.next = innermost->body_list; |
- innermost->body_list = ∋ |
- } |
+ AddNodeToLoop(&ni, innermost, innermost_index); |
count++; |
} |
@@ -368,13 +421,7 @@ class LoopFinderImpl { |
size_t count = 0; |
for (NodeInfo& ni : info_) { |
if (ni.node == nullptr || !IsInLoop(ni.node, 1)) continue; |
- if (LoopNum(ni.node) == 1) { |
- ni.next = li->header_list; |
- li->header_list = ∋ |
- } else { |
- ni.next = li->body_list; |
- li->body_list = ∋ |
- } |
+ AddNodeToLoop(&ni, li, 1); |
count++; |
} |
@@ -406,7 +453,14 @@ class LoopFinderImpl { |
// Serialize nested loops. |
for (LoopTree::Loop* child : loop->children_) SerializeLoop(child); |
- loop->body_end_ = static_cast<int>(loop_tree_->loop_nodes_.size()); |
+ // Serialize the exits. |
+ loop->exits_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); |
+ for (NodeInfo* ni = li.exit_list; ni != nullptr; ni = ni->next) { |
+ loop_tree_->loop_nodes_.push_back(ni->node); |
+ loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num; |
+ } |
+ |
+ loop->exits_end_ = static_cast<int>(loop_tree_->loop_nodes_.size()); |
} |
// Connect the LoopTree loops to their parents recursively. |
@@ -438,9 +492,12 @@ class LoopFinderImpl { |
while (i < loop->body_start_) { |
PrintF(" H#%d", loop_tree_->loop_nodes_[i++]->id()); |
} |
- while (i < loop->body_end_) { |
+ while (i < loop->exits_start_) { |
PrintF(" B#%d", loop_tree_->loop_nodes_[i++]->id()); |
} |
+ while (i < loop->exits_end_) { |
+ PrintF(" E#%d", loop_tree_->loop_nodes_[i++]->id()); |
+ } |
PrintF("\n"); |
for (LoopTree::Loop* child : loop->children_) PrintLoop(child); |
} |