Index: src/compiler/osr.cc |
diff --git a/src/compiler/osr.cc b/src/compiler/osr.cc |
index b7cd7ec93f919791d32ea0ee48bb15857cd55b52..2ab5d739847f5ac27a9f3e9c39760bd32ce190e9 100644 |
--- a/src/compiler/osr.cc |
+++ b/src/compiler/osr.cc |
@@ -26,6 +26,18 @@ OsrHelper::OsrHelper(CompilationInfo* info) |
info->osr_expr_stack_height()) {} |
+#ifdef DEBUG |
+#define TRACE_COND (FLAG_trace_turbo_graph && FLAG_trace_osr) |
+#else |
+#define TRACE_COND false |
+#endif |
+ |
+#define TRACE(...) \ |
+ do { \ |
+ if (TRACE_COND) PrintF(__VA_ARGS__); \ |
+ } while (false) |
+ |
+ |
// Peel outer loops and rewire the graph so that control reduction can |
// produce a properly formed graph. |
static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common, |
@@ -44,6 +56,9 @@ static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common, |
NodeVector* mapping = |
new (stuff) NodeVector(original_count, sentinel, tmp_zone); |
copies.push_back(mapping); |
+ TRACE("OsrDuplication #%zu, depth %zu, header #%d:%s\n", copies.size(), |
+ loop->depth(), loop_tree->HeaderNode(loop)->id(), |
+ loop_tree->HeaderNode(loop)->op()->mnemonic()); |
// Prepare the mapping for OSR values and the OSR loop entry. |
mapping->at(osr_normal_entry->id()) = dead; |
@@ -54,6 +69,8 @@ static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common, |
outer = outer->parent()) { |
for (Node* node : loop_tree->HeaderNodes(outer)) { |
mapping->at(node->id()) = dead; |
+ TRACE(" ---- #%d:%s -> dead (header)\n", node->id(), |
+ node->op()->mnemonic()); |
} |
} |
@@ -82,71 +99,132 @@ static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common, |
NodeProperties::SetBounds(copy, NodeProperties::GetBounds(orig)); |
} |
mapping->at(orig->id()) = copy; |
+ TRACE(" copy #%d:%s -> #%d\n", orig->id(), orig->op()->mnemonic(), |
+ copy->id()); |
} |
// Fix missing inputs. |
- for (size_t i = 0; i < all.live.size(); i++) { |
- Node* orig = all.live[i]; |
+ for (Node* orig : all.live) { |
Node* copy = mapping->at(orig->id()); |
for (int j = 0; j < copy->InputCount(); j++) { |
- Node* input = copy->InputAt(j); |
- if (input == sentinel) |
+ if (copy->InputAt(j) == sentinel) { |
copy->ReplaceInput(j, mapping->at(orig->InputAt(j)->id())); |
+ } |
} |
} |
- // Construct the transfer from the previous graph copies to the new copy. |
+ // Construct the entry into this loop from previous copies. |
+ |
+ // Gather the live loop header nodes, {loop_header} first. |
Node* loop_header = loop_tree->HeaderNode(loop); |
- NodeVector* previous = |
- copies.size() > 1 ? copies[copies.size() - 2] : nullptr; |
- const int backedges = loop_header->op()->ControlInputCount() - 1; |
- if (backedges == 1) { |
- // Simple case. Map the incoming edges to the loop to the previous copy. |
- for (Node* node : loop_tree->HeaderNodes(loop)) { |
- if (!all.IsLive(node)) continue; // dead phi hanging off loop. |
+ NodeVector header_nodes(tmp_zone); |
+ header_nodes.reserve(loop->HeaderSize()); |
+ header_nodes.push_back(loop_header); // put the loop header first. |
+ for (Node* node : loop_tree->HeaderNodes(loop)) { |
+ if (node != loop_header && all.IsLive(node)) { |
+ header_nodes.push_back(node); |
+ } |
+ } |
+ |
+ // Gather backedges from the previous copies of the inner loops of {loop}. |
+ NodeVectorVector backedges(tmp_zone); |
+ TRACE("Gathering backedges...\n"); |
+ for (int i = 1; i < loop_header->InputCount(); i++) { |
+ if (TRACE_COND) { |
+ Node* control = loop_header->InputAt(i); |
+ size_t incoming_depth = 0; |
+ for (int j = 0; j < control->op()->ControlInputCount(); j++) { |
+ Node* k = NodeProperties::GetControlInput(control, j); |
+ incoming_depth = |
+ std::max(incoming_depth, loop_tree->ContainingLoop(k)->depth()); |
+ } |
+ |
+ TRACE(" edge @%d #%d:%s, incoming depth %zu\n", i, control->id(), |
+ control->op()->mnemonic(), incoming_depth); |
+ } |
+ |
+ for (int pos = static_cast<int>(copies.size()) - 1; pos >= 0; pos--) { |
+ backedges.push_back(NodeVector(tmp_zone)); |
+ backedges.back().reserve(header_nodes.size()); |
+ |
+ NodeVector* previous_map = pos > 0 ? copies[pos - 1] : nullptr; |
+ |
+ for (Node* node : header_nodes) { |
+ Node* input = node->InputAt(i); |
+ if (previous_map) input = previous_map->at(input->id()); |
+ backedges.back().push_back(input); |
+ TRACE(" node #%d:%s(@%d) = #%d:%s\n", node->id(), |
+ node->op()->mnemonic(), i, input->id(), |
+ input->op()->mnemonic()); |
+ } |
+ } |
+ } |
+ |
+ int backedge_count = static_cast<int>(backedges.size()); |
+ if (backedge_count == 1) { |
+ // Simple case of single backedge, therefore a single entry. |
+ int index = 0; |
+ for (Node* node : header_nodes) { |
Node* copy = mapping->at(node->id()); |
- Node* backedge = node->InputAt(1); |
- if (previous) backedge = previous->at(backedge->id()); |
- copy->ReplaceInput(0, backedge); |
+ Node* input = backedges[0][index]; |
+ copy->ReplaceInput(0, input); |
+ TRACE(" header #%d:%s(0) => #%d:%s\n", copy->id(), |
+ copy->op()->mnemonic(), input->id(), input->op()->mnemonic()); |
+ index++; |
} |
} else { |
- // Complex case. Multiple backedges. Introduce a merge for incoming edges. |
- tmp_inputs.clear(); |
- for (int i = 0; i < backedges; i++) { |
- Node* backedge = loop_header->InputAt(i + 1); |
- if (previous) backedge = previous->at(backedge->id()); |
- tmp_inputs.push_back(backedge); |
- } |
- Node* merge = |
- graph->NewNode(common->Merge(backedges), backedges, &tmp_inputs[0]); |
- for (Node* node : loop_tree->HeaderNodes(loop)) { |
- if (!all.IsLive(node)) continue; // dead phi hanging off loop. |
+ // Complex case of multiple backedges from previous copies requires |
+ // merging the backedges to create the entry into the loop header. |
+ Node* merge = nullptr; |
+ int index = 0; |
+ for (Node* node : header_nodes) { |
+ // Gather edge inputs into {tmp_inputs}. |
+ tmp_inputs.clear(); |
+ for (int edge = 0; edge < backedge_count; edge++) { |
+ tmp_inputs.push_back(backedges[edge][index]); |
+ } |
Node* copy = mapping->at(node->id()); |
+ Node* input; |
if (node == loop_header) { |
- // The entry to the loop is the merge. |
+ // Create the merge for the entry into the loop header. |
+ input = merge = graph->NewNode(common->Merge(backedge_count), |
+ backedge_count, &tmp_inputs[0]); |
copy->ReplaceInput(0, merge); |
} else { |
- // Merge inputs to the phi at the loop entry. |
- tmp_inputs.clear(); |
- for (int i = 0; i < backedges; i++) { |
- Node* backedge = node->InputAt(i + 1); |
- if (previous) backedge = previous->at(backedge->id()); |
- tmp_inputs.push_back(backedge); |
- } |
+ // Create a phi that merges values at entry into the loop header. |
+ DCHECK_NOT_NULL(merge); |
+ DCHECK(IrOpcode::IsPhiOpcode(node->opcode())); |
tmp_inputs.push_back(merge); |
- Node* phi = |
- graph->NewNode(common->ResizeMergeOrPhi(node->op(), backedges), |
- backedges + 1, &tmp_inputs[0]); |
+ Node* phi = input = graph->NewNode( |
+ common->ResizeMergeOrPhi(node->op(), backedge_count), |
+ backedge_count + 1, &tmp_inputs[0]); |
copy->ReplaceInput(0, phi); |
} |
+ |
+ // Print the merge. |
+ if (TRACE_COND) { |
+ TRACE(" header #%d:%s(0) => #%d:%s(", copy->id(), |
+ copy->op()->mnemonic(), input->id(), input->op()->mnemonic()); |
+ for (size_t i = 0; i < tmp_inputs.size(); i++) { |
+ if (i > 0) TRACE(", "); |
+ Node* input = tmp_inputs[i]; |
+ TRACE("#%d:%s", input->id(), input->op()->mnemonic()); |
+ } |
+ TRACE(")\n"); |
+ } |
+ |
+ index++; |
} |
} |
} |
// Kill the outer loops in the original graph. |
+ TRACE("Killing outer loop headers...\n"); |
for (LoopTree::Loop* outer = osr_loop->parent(); outer; |
outer = outer->parent()) { |
- loop_tree->HeaderNode(outer)->ReplaceUses(dead); |
+ Node* loop_header = loop_tree->HeaderNode(outer); |
+ loop_header->ReplaceUses(dead); |
+ TRACE(" ---- #%d:%s\n", loop_header->id(), loop_header->op()->mnemonic()); |
} |
// Merge the ends of the graph copies. |