Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: src/compiler/osr.cc

Issue 1004993004: [turbofan] Fix bug in OSR deconstruction. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/opcodes.h ('k') | src/runtime/runtime.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 do { \
37 if (TRACE_COND) 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
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
OLDNEW
« no previous file with comments | « src/compiler/opcodes.h ('k') | src/runtime/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698