OLD | NEW |
---|---|
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler.h" | 5 #include "src/compiler.h" |
6 #include "src/compiler/all-nodes.h" | 6 #include "src/compiler/all-nodes.h" |
7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
8 #include "src/compiler/control-reducer.h" | 8 #include "src/compiler/control-reducer.h" |
9 #include "src/compiler/frame.h" | 9 #include "src/compiler/frame.h" |
10 #include "src/compiler/graph.h" | 10 #include "src/compiler/graph.h" |
11 #include "src/compiler/graph-visualizer.h" | 11 #include "src/compiler/graph-visualizer.h" |
12 #include "src/compiler/js-graph.h" | 12 #include "src/compiler/js-graph.h" |
13 #include "src/compiler/loop-analysis.h" | 13 #include "src/compiler/loop-analysis.h" |
14 #include "src/compiler/node.h" | 14 #include "src/compiler/node.h" |
15 #include "src/compiler/node-marker.h" | 15 #include "src/compiler/node-marker.h" |
16 #include "src/compiler/osr.h" | 16 #include "src/compiler/osr.h" |
17 #include "src/scopes.h" | 17 #include "src/scopes.h" |
18 | 18 |
19 namespace v8 { | 19 namespace v8 { |
20 namespace internal { | 20 namespace internal { |
21 namespace compiler { | 21 namespace compiler { |
22 | 22 |
23 OsrHelper::OsrHelper(CompilationInfo* info) | 23 OsrHelper::OsrHelper(CompilationInfo* info) |
24 : parameter_count_(info->scope()->num_parameters()), | 24 : parameter_count_(info->scope()->num_parameters()), |
25 stack_slot_count_(info->scope()->num_stack_slots() + | 25 stack_slot_count_(info->scope()->num_stack_slots() + |
26 info->osr_expr_stack_height()) {} | 26 info->osr_expr_stack_height()) {} |
27 | 27 |
28 | 28 |
29 #ifdef DEBUG | |
30 #define TRACE_COND (FLAG_trace_turbo_graph && FLAG_trace_osr) | |
31 #else | |
32 #define TRACE_COND false | |
33 #endif | |
34 | |
35 #define TRACE(...) \ | |
36 if (TRACE_COND) do { \ | |
Michael Starzinger
2015/03/17 16:30:04
nit: Shouldn't the if-statement go into the do-whi
titzer
2015/03/17 16:41:29
Done.
| |
37 PrintF(__VA_ARGS__); \ | |
38 } while (false) | |
39 | |
40 | |
29 // Peel outer loops and rewire the graph so that control reduction can | 41 // Peel outer loops and rewire the graph so that control reduction can |
30 // produce a properly formed graph. | 42 // produce a properly formed graph. |
31 static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common, | 43 static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common, |
32 Zone* tmp_zone, Node* dead, | 44 Zone* tmp_zone, Node* dead, |
33 LoopTree* loop_tree, LoopTree::Loop* osr_loop, | 45 LoopTree* loop_tree, LoopTree::Loop* osr_loop, |
34 Node* osr_normal_entry, Node* osr_loop_entry) { | 46 Node* osr_normal_entry, Node* osr_loop_entry) { |
35 const int original_count = graph->NodeCount(); | 47 const int original_count = graph->NodeCount(); |
36 AllNodes all(tmp_zone, graph); | 48 AllNodes all(tmp_zone, graph); |
37 NodeVector tmp_inputs(tmp_zone); | 49 NodeVector tmp_inputs(tmp_zone); |
38 Node* sentinel = graph->NewNode(dead->op()); | 50 Node* sentinel = graph->NewNode(dead->op()); |
39 | 51 |
40 // Make a copy of the graph for each outer loop. | 52 // Make a copy of the graph for each outer loop. |
41 ZoneVector<NodeVector*> copies(tmp_zone); | 53 ZoneVector<NodeVector*> copies(tmp_zone); |
42 for (LoopTree::Loop* loop = osr_loop->parent(); loop; loop = loop->parent()) { | 54 for (LoopTree::Loop* loop = osr_loop->parent(); loop; loop = loop->parent()) { |
43 void* stuff = tmp_zone->New(sizeof(NodeVector)); | 55 void* stuff = tmp_zone->New(sizeof(NodeVector)); |
44 NodeVector* mapping = | 56 NodeVector* mapping = |
45 new (stuff) NodeVector(original_count, sentinel, tmp_zone); | 57 new (stuff) NodeVector(original_count, sentinel, tmp_zone); |
46 copies.push_back(mapping); | 58 copies.push_back(mapping); |
59 TRACE("OsrDuplication #%zu, depth %zu, header #%d:%s\n", copies.size(), | |
60 loop->depth(), loop_tree->HeaderNode(loop)->id(), | |
61 loop_tree->HeaderNode(loop)->op()->mnemonic()); | |
47 | 62 |
48 // Prepare the mapping for OSR values and the OSR loop entry. | 63 // Prepare the mapping for OSR values and the OSR loop entry. |
49 mapping->at(osr_normal_entry->id()) = dead; | 64 mapping->at(osr_normal_entry->id()) = dead; |
50 mapping->at(osr_loop_entry->id()) = dead; | 65 mapping->at(osr_loop_entry->id()) = dead; |
51 | 66 |
52 // The outer loops are dead in this copy. | 67 // The outer loops are dead in this copy. |
53 for (LoopTree::Loop* outer = loop->parent(); outer; | 68 for (LoopTree::Loop* outer = loop->parent(); outer; |
54 outer = outer->parent()) { | 69 outer = outer->parent()) { |
55 for (Node* node : loop_tree->HeaderNodes(outer)) { | 70 for (Node* node : loop_tree->HeaderNodes(outer)) { |
56 mapping->at(node->id()) = dead; | 71 mapping->at(node->id()) = dead; |
72 TRACE(" ---- #%d:%s -> dead (header)\n", node->id(), | |
73 node->op()->mnemonic()); | |
57 } | 74 } |
58 } | 75 } |
59 | 76 |
60 // Copy all nodes. | 77 // Copy all nodes. |
61 for (size_t i = 0; i < all.live.size(); i++) { | 78 for (size_t i = 0; i < all.live.size(); i++) { |
62 Node* orig = all.live[i]; | 79 Node* orig = all.live[i]; |
63 Node* copy = mapping->at(orig->id()); | 80 Node* copy = mapping->at(orig->id()); |
64 if (copy != sentinel) { | 81 if (copy != sentinel) { |
65 // Mapping already exists. | 82 // Mapping already exists. |
66 continue; | 83 continue; |
67 } | 84 } |
68 if (orig->InputCount() == 0 || orig->opcode() == IrOpcode::kParameter || | 85 if (orig->InputCount() == 0 || orig->opcode() == IrOpcode::kParameter || |
69 orig->opcode() == IrOpcode::kOsrValue) { | 86 orig->opcode() == IrOpcode::kOsrValue) { |
70 // No need to copy leaf nodes or parameters. | 87 // No need to copy leaf nodes or parameters. |
71 mapping->at(orig->id()) = orig; | 88 mapping->at(orig->id()) = orig; |
72 continue; | 89 continue; |
73 } | 90 } |
74 | 91 |
75 // Copy the node. | 92 // Copy the node. |
76 tmp_inputs.clear(); | 93 tmp_inputs.clear(); |
77 for (Node* input : orig->inputs()) { | 94 for (Node* input : orig->inputs()) { |
78 tmp_inputs.push_back(mapping->at(input->id())); | 95 tmp_inputs.push_back(mapping->at(input->id())); |
79 } | 96 } |
80 copy = graph->NewNode(orig->op(), orig->InputCount(), &tmp_inputs[0]); | 97 copy = graph->NewNode(orig->op(), orig->InputCount(), &tmp_inputs[0]); |
81 if (NodeProperties::IsTyped(orig)) { | 98 if (NodeProperties::IsTyped(orig)) { |
82 NodeProperties::SetBounds(copy, NodeProperties::GetBounds(orig)); | 99 NodeProperties::SetBounds(copy, NodeProperties::GetBounds(orig)); |
83 } | 100 } |
84 mapping->at(orig->id()) = copy; | 101 mapping->at(orig->id()) = copy; |
102 TRACE(" copy #%d:%s -> #%d\n", orig->id(), orig->op()->mnemonic(), | |
103 copy->id()); | |
85 } | 104 } |
86 | 105 |
87 // Fix missing inputs. | 106 // Fix missing inputs. |
88 for (size_t i = 0; i < all.live.size(); i++) { | 107 for (Node* orig : all.live) { |
89 Node* orig = all.live[i]; | |
90 Node* copy = mapping->at(orig->id()); | 108 Node* copy = mapping->at(orig->id()); |
91 for (int j = 0; j < copy->InputCount(); j++) { | 109 for (int j = 0; j < copy->InputCount(); j++) { |
92 Node* input = copy->InputAt(j); | 110 if (copy->InputAt(j) == sentinel) { |
93 if (input == sentinel) | |
94 copy->ReplaceInput(j, mapping->at(orig->InputAt(j)->id())); | 111 copy->ReplaceInput(j, mapping->at(orig->InputAt(j)->id())); |
112 } | |
95 } | 113 } |
96 } | 114 } |
97 | 115 |
98 // Construct the transfer from the previous graph copies to the new copy. | 116 // Construct the entry into this loop from previous copies. |
117 | |
118 // Gather the live loop header nodes, {loop_header} first. | |
99 Node* loop_header = loop_tree->HeaderNode(loop); | 119 Node* loop_header = loop_tree->HeaderNode(loop); |
100 NodeVector* previous = | 120 NodeVector header_nodes(tmp_zone); |
101 copies.size() > 1 ? copies[copies.size() - 2] : nullptr; | 121 header_nodes.reserve(loop->HeaderSize()); |
102 const int backedges = loop_header->op()->ControlInputCount() - 1; | 122 header_nodes.push_back(loop_header); // put the loop header first. |
103 if (backedges == 1) { | 123 for (Node* node : loop_tree->HeaderNodes(loop)) { |
104 // Simple case. Map the incoming edges to the loop to the previous copy. | 124 if (node != loop_header && all.IsLive(node)) { |
105 for (Node* node : loop_tree->HeaderNodes(loop)) { | 125 header_nodes.push_back(node); |
106 if (!all.IsLive(node)) continue; // dead phi hanging off loop. | 126 } |
127 } | |
128 | |
129 // Gather backedges from the previous copies of the inner loops of {loop}. | |
130 NodeVectorVector backedges(tmp_zone); | |
131 TRACE("Gathering backedges...\n"); | |
132 for (int i = 1; i < loop_header->InputCount(); i++) { | |
133 if (TRACE_COND) { | |
134 Node* control = loop_header->InputAt(i); | |
135 size_t incoming_depth = 0; | |
136 for (int j = 0; j < control->op()->ControlInputCount(); j++) { | |
137 Node* k = NodeProperties::GetControlInput(control, j); | |
138 incoming_depth = | |
139 std::max(incoming_depth, loop_tree->ContainingLoop(k)->depth()); | |
140 } | |
141 | |
142 TRACE(" edge @%d #%d:%s, incoming depth %zu\n", i, control->id(), | |
143 control->op()->mnemonic(), incoming_depth); | |
144 } | |
145 | |
146 for (int pos = static_cast<int>(copies.size()) - 1; pos >= 0; pos--) { | |
147 backedges.push_back(NodeVector(tmp_zone)); | |
148 backedges.back().reserve(header_nodes.size()); | |
149 | |
150 NodeVector* previous_map = pos > 0 ? copies[pos - 1] : nullptr; | |
151 | |
152 for (Node* node : header_nodes) { | |
153 Node* input = node->InputAt(i); | |
154 if (previous_map) input = previous_map->at(input->id()); | |
155 backedges.back().push_back(input); | |
156 TRACE(" node #%d:%s(@%d) = #%d:%s\n", node->id(), | |
157 node->op()->mnemonic(), i, input->id(), | |
158 input->op()->mnemonic()); | |
159 } | |
160 } | |
161 } | |
162 | |
163 int backedge_count = static_cast<int>(backedges.size()); | |
164 if (backedge_count == 1) { | |
165 // Simple case of single backedge, therefore a single entry. | |
166 int index = 0; | |
167 for (Node* node : header_nodes) { | |
107 Node* copy = mapping->at(node->id()); | 168 Node* copy = mapping->at(node->id()); |
108 Node* backedge = node->InputAt(1); | 169 Node* input = backedges[0][index]; |
109 if (previous) backedge = previous->at(backedge->id()); | 170 copy->ReplaceInput(0, input); |
110 copy->ReplaceInput(0, backedge); | 171 TRACE(" header #%d:%s(0) => #%d:%s\n", copy->id(), |
172 copy->op()->mnemonic(), input->id(), input->op()->mnemonic()); | |
173 index++; | |
111 } | 174 } |
112 } else { | 175 } else { |
113 // Complex case. Multiple backedges. Introduce a merge for incoming edges. | 176 // Complex case of multiple backedges from previous copies requires |
114 tmp_inputs.clear(); | 177 // merging the backedges to create the entry into the loop header. |
115 for (int i = 0; i < backedges; i++) { | 178 Node* merge = nullptr; |
116 Node* backedge = loop_header->InputAt(i + 1); | 179 int index = 0; |
117 if (previous) backedge = previous->at(backedge->id()); | 180 for (Node* node : header_nodes) { |
118 tmp_inputs.push_back(backedge); | 181 // Gather edge inputs into {tmp_inputs}. |
119 } | 182 tmp_inputs.clear(); |
120 Node* merge = | 183 for (int edge = 0; edge < backedge_count; edge++) { |
121 graph->NewNode(common->Merge(backedges), backedges, &tmp_inputs[0]); | 184 tmp_inputs.push_back(backedges[edge][index]); |
122 for (Node* node : loop_tree->HeaderNodes(loop)) { | 185 } |
123 if (!all.IsLive(node)) continue; // dead phi hanging off loop. | |
124 Node* copy = mapping->at(node->id()); | 186 Node* copy = mapping->at(node->id()); |
187 Node* input; | |
125 if (node == loop_header) { | 188 if (node == loop_header) { |
126 // The entry to the loop is the merge. | 189 // Create the merge for the entry into the loop header. |
190 input = merge = graph->NewNode(common->Merge(backedge_count), | |
191 backedge_count, &tmp_inputs[0]); | |
127 copy->ReplaceInput(0, merge); | 192 copy->ReplaceInput(0, merge); |
128 } else { | 193 } else { |
129 // Merge inputs to the phi at the loop entry. | 194 // Create a phi that merges values at entry into the loop header. |
130 tmp_inputs.clear(); | 195 DCHECK_NOT_NULL(merge); |
131 for (int i = 0; i < backedges; i++) { | 196 DCHECK(IrOpcode::IsPhiOpcode(node->opcode())); |
132 Node* backedge = node->InputAt(i + 1); | |
133 if (previous) backedge = previous->at(backedge->id()); | |
134 tmp_inputs.push_back(backedge); | |
135 } | |
136 tmp_inputs.push_back(merge); | 197 tmp_inputs.push_back(merge); |
137 Node* phi = | 198 Node* phi = input = graph->NewNode( |
138 graph->NewNode(common->ResizeMergeOrPhi(node->op(), backedges), | 199 common->ResizeMergeOrPhi(node->op(), backedge_count), |
139 backedges + 1, &tmp_inputs[0]); | 200 backedge_count + 1, &tmp_inputs[0]); |
140 copy->ReplaceInput(0, phi); | 201 copy->ReplaceInput(0, phi); |
141 } | 202 } |
203 | |
204 // Print the merge. | |
205 if (TRACE_COND) { | |
206 TRACE(" header #%d:%s(0) => #%d:%s(", copy->id(), | |
207 copy->op()->mnemonic(), input->id(), input->op()->mnemonic()); | |
208 for (size_t i = 0; i < tmp_inputs.size(); i++) { | |
209 if (i > 0) TRACE(", "); | |
210 Node* input = tmp_inputs[i]; | |
211 TRACE("#%d:%s", input->id(), input->op()->mnemonic()); | |
212 } | |
213 TRACE(")\n"); | |
214 } | |
215 | |
216 index++; | |
142 } | 217 } |
143 } | 218 } |
144 } | 219 } |
145 | 220 |
146 // Kill the outer loops in the original graph. | 221 // Kill the outer loops in the original graph. |
222 TRACE("Killing outer loop headers...\n"); | |
147 for (LoopTree::Loop* outer = osr_loop->parent(); outer; | 223 for (LoopTree::Loop* outer = osr_loop->parent(); outer; |
148 outer = outer->parent()) { | 224 outer = outer->parent()) { |
149 loop_tree->HeaderNode(outer)->ReplaceUses(dead); | 225 Node* loop_header = loop_tree->HeaderNode(outer); |
226 loop_header->ReplaceUses(dead); | |
227 TRACE(" ---- #%d:%s\n", loop_header->id(), loop_header->op()->mnemonic()); | |
150 } | 228 } |
151 | 229 |
152 // Merge the ends of the graph copies. | 230 // Merge the ends of the graph copies. |
153 Node* end = graph->end(); | 231 Node* end = graph->end(); |
154 tmp_inputs.clear(); | 232 tmp_inputs.clear(); |
155 for (int i = -1; i < static_cast<int>(copies.size()); i++) { | 233 for (int i = -1; i < static_cast<int>(copies.size()); i++) { |
156 Node* input = end->InputAt(0); | 234 Node* input = end->InputAt(0); |
157 if (i >= 0) input = copies[i]->at(input->id()); | 235 if (i >= 0) input = copies[i]->at(input->id()); |
158 if (input->opcode() == IrOpcode::kMerge) { | 236 if (input->opcode() == IrOpcode::kMerge) { |
159 for (Node* node : input->inputs()) tmp_inputs.push_back(node); | 237 for (Node* node : input->inputs()) tmp_inputs.push_back(node); |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 // the first spill slots. | 355 // the first spill slots. |
278 frame->ReserveSpillSlots(UnoptimizedFrameSlots()); | 356 frame->ReserveSpillSlots(UnoptimizedFrameSlots()); |
279 // The frame needs to be adjusted by the number of unoptimized frame slots. | 357 // The frame needs to be adjusted by the number of unoptimized frame slots. |
280 frame->SetOsrStackSlotCount(static_cast<int>(UnoptimizedFrameSlots())); | 358 frame->SetOsrStackSlotCount(static_cast<int>(UnoptimizedFrameSlots())); |
281 } | 359 } |
282 | 360 |
283 | 361 |
284 } // namespace compiler | 362 } // namespace compiler |
285 } // namespace internal | 363 } // namespace internal |
286 } // namespace v8 | 364 } // namespace v8 |
OLD | NEW |