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

Side by Side Diff: src/compiler/loop-peeling.cc

Issue 1052753004: [turbofan] Rework handling of loop exits in loop peeling. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 8 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/loop-peeling.h ('k') | test/unittests/compiler/loop-peeling-unittest.cc » ('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 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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/common-operator.h" 5 #include "src/compiler/common-operator.h"
6 #include "src/compiler/graph.h" 6 #include "src/compiler/graph.h"
7 #include "src/compiler/loop-peeling.h" 7 #include "src/compiler/loop-peeling.h"
8 #include "src/compiler/node.h" 8 #include "src/compiler/node.h"
9 #include "src/compiler/node-marker.h" 9 #include "src/compiler/node-marker.h"
10 #include "src/compiler/node-properties.h" 10 #include "src/compiler/node-properties.h"
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 // TODO(turbofan): we use a simple linear search, since the peeled iteration 154 // TODO(turbofan): we use a simple linear search, since the peeled iteration
155 // is really only used in testing. 155 // is really only used in testing.
156 PeeledIterationImpl* impl = static_cast<PeeledIterationImpl*>(this); 156 PeeledIterationImpl* impl = static_cast<PeeledIterationImpl*>(this);
157 for (size_t i = 0; i < impl->node_pairs_.size(); i += 2) { 157 for (size_t i = 0; i < impl->node_pairs_.size(); i += 2) {
158 if (impl->node_pairs_[i] == node) return impl->node_pairs_[i + 1]; 158 if (impl->node_pairs_[i] == node) return impl->node_pairs_[i + 1];
159 } 159 }
160 return node; 160 return node;
161 } 161 }
162 162
163 163
164 static void FindLoopExits(LoopTree* loop_tree, LoopTree::Loop* loop,
165 NodeVector& exits, NodeVector& rets) {
166 // Look for returns and if projections that are outside the loop but whose
167 // control input is inside the loop.
168 for (Node* node : loop_tree->LoopNodes(loop)) {
169 for (Node* use : node->uses()) {
170 if (!loop_tree->Contains(loop, use)) {
171 if (IrOpcode::IsIfProjectionOpcode(use->opcode())) {
172 // This is a branch from inside the loop to outside the loop.
173 exits.push_back(use);
174 } else if (use->opcode() == IrOpcode::kReturn &&
175 loop_tree->Contains(loop,
176 NodeProperties::GetControlInput(use))) {
177 // This is a return from inside the loop.
178 rets.push_back(use);
179 }
180 }
181 }
182 }
183 }
184
185
186 bool LoopPeeler::CanPeel(LoopTree* loop_tree, LoopTree::Loop* loop) {
187 Zone zone;
188 NodeVector exits(&zone);
189 NodeVector rets(&zone);
190 FindLoopExits(loop_tree, loop, exits, rets);
191 return exits.size() <= 1u;
192 }
193
194
164 PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common, 195 PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common,
165 LoopTree* loop_tree, LoopTree::Loop* loop, 196 LoopTree* loop_tree, LoopTree::Loop* loop,
166 Zone* tmp_zone) { 197 Zone* tmp_zone) {
167 PeeledIterationImpl* iter = new (tmp_zone) PeeledIterationImpl(tmp_zone); 198 //============================================================================
168 Peeling peeling(graph, tmp_zone, loop->TotalSize() * 2 + 2, 199 // Find the loop exit region to determine if this loop can be peeled.
169 &iter->node_pairs_); 200 //============================================================================
201 NodeVector exits(tmp_zone);
202 NodeVector rets(tmp_zone);
203 FindLoopExits(loop_tree, loop, exits, rets);
204
205 if (exits.size() != 1) return nullptr; // not peelable currently.
170 206
171 //============================================================================ 207 //============================================================================
172 // Construct the peeled iteration. 208 // Construct the peeled iteration.
173 //============================================================================ 209 //============================================================================
210 PeeledIterationImpl* iter = new (tmp_zone) PeeledIterationImpl(tmp_zone);
211 size_t estimated_peeled_size =
212 5 + (loop->TotalSize() + exits.size() + rets.size()) * 2;
213 Peeling peeling(graph, tmp_zone, estimated_peeled_size, &iter->node_pairs_);
214
174 Node* dead = graph->NewNode(common->Dead()); 215 Node* dead = graph->NewNode(common->Dead());
175 216
176 // Map the loop header nodes to their entry values. 217 // Map the loop header nodes to their entry values.
177 for (Node* node : loop_tree->HeaderNodes(loop)) { 218 for (Node* node : loop_tree->HeaderNodes(loop)) {
178 // TODO(titzer): assuming loop entry at index 0. 219 peeling.Insert(node, node->InputAt(kAssumedLoopEntryIndex));
179 peeling.Insert(node, node->InputAt(0));
180 } 220 }
181 221
182 // Copy all the nodes of loop body for the peeled iteration. 222 // Copy all the nodes of loop body for the peeled iteration.
183 peeling.CopyNodes(graph, tmp_zone, dead, loop_tree->BodyNodes(loop)); 223 peeling.CopyNodes(graph, tmp_zone, dead, loop_tree->BodyNodes(loop));
184 224
185 //============================================================================ 225 //============================================================================
186 // Replace the entry to the loop with the output of the peeled iteration. 226 // Replace the entry to the loop with the output of the peeled iteration.
187 //============================================================================ 227 //============================================================================
188 Node* loop_node = loop_tree->GetLoopControl(loop); 228 Node* loop_node = loop_tree->GetLoopControl(loop);
189 Node* new_entry; 229 Node* new_entry;
(...skipping 30 matching lines...) Expand all
220 // Only one backedge, simply replace the input to loop with output of 260 // Only one backedge, simply replace the input to loop with output of
221 // peeling. 261 // peeling.
222 for (Node* node : loop_tree->HeaderNodes(loop)) { 262 for (Node* node : loop_tree->HeaderNodes(loop)) {
223 node->ReplaceInput(0, peeling.map(node->InputAt(0))); 263 node->ReplaceInput(0, peeling.map(node->InputAt(0)));
224 } 264 }
225 new_entry = peeling.map(loop_node->InputAt(1)); 265 new_entry = peeling.map(loop_node->InputAt(1));
226 } 266 }
227 loop_node->ReplaceInput(0, new_entry); 267 loop_node->ReplaceInput(0, new_entry);
228 268
229 //============================================================================ 269 //============================================================================
230 // Find the loop exit region.
231 //============================================================================
232 NodeVector exits(tmp_zone);
233 Node* end = NULL;
234 for (Node* node : loop_tree->LoopNodes(loop)) {
235 for (Node* use : node->uses()) {
236 if (!loop_tree->Contains(loop, use)) {
237 if (node->opcode() == IrOpcode::kBranch &&
238 (use->opcode() == IrOpcode::kIfTrue ||
239 use->opcode() == IrOpcode::kIfFalse)) {
240 // This is a branch from inside the loop to outside the loop.
241 exits.push_back(use);
242 }
243 }
244 }
245 }
246
247 if (exits.size() == 0) return iter; // no exits => NTL
248
249 if (exits.size() == 1) {
250 // Only one exit, so {end} is that exit.
251 end = exits[0];
252 } else {
253 // {end} should be the common merge from the exits.
254 NodeVector rets(tmp_zone);
255 for (Node* exit : exits) {
256 Node* found = NULL;
257 for (Node* use : exit->uses()) {
258 if (use->opcode() == IrOpcode::kMerge) {
259 found = use;
260 if (end == NULL) {
261 end = found;
262 } else {
263 CHECK_EQ(end, found); // it should be unique!
264 }
265 } else if (use->opcode() == IrOpcode::kReturn) {
266 found = use;
267 rets.push_back(found);
268 }
269 }
270 // There should be a merge or a return for each exit.
271 CHECK(found);
272 }
273 // Return nodes, the end merge, and the phis associated with the end merge
274 // must be duplicated as well.
275 for (Node* node : rets) exits.push_back(node);
276 if (end != NULL) {
277 exits.push_back(end);
278 for (Node* use : end->uses()) {
279 if (NodeProperties::IsPhi(use)) exits.push_back(use);
280 }
281 }
282 }
283
284 //============================================================================
285 // Duplicate the loop exit region and add a merge. 270 // Duplicate the loop exit region and add a merge.
286 //============================================================================ 271 //============================================================================
272
273 // Currently we are limited to peeling loops with a single exit. The exit is
274 // the postdominator of the loop (ignoring returns).
275 Node* postdom = exits[0];
276 for (Node* node : rets) exits.push_back(node);
277 for (Node* use : postdom->uses()) {
278 if (NodeProperties::IsPhi(use)) exits.push_back(use);
279 }
280
287 NodeRange exit_range(&exits[0], &exits[0] + exits.size()); 281 NodeRange exit_range(&exits[0], &exits[0] + exits.size());
288 peeling.CopyNodes(graph, tmp_zone, dead, exit_range); 282 peeling.CopyNodes(graph, tmp_zone, dead, exit_range);
289 283
290 Node* merge = graph->NewNode(common->Merge(2), end, peeling.map(end)); 284 Node* merge = graph->NewNode(common->Merge(2), postdom, peeling.map(postdom));
291 end->ReplaceUses(merge); 285 postdom->ReplaceUses(merge);
292 merge->ReplaceInput(0, end); // HULK SMASH!! 286 merge->ReplaceInput(0, postdom); // input 0 overwritten by above line.
293 287
294 // Find and update all the edges into either the loop or exit region. 288 // Find and update all the edges into either the loop or exit region.
295 for (int i = 0; i < 2; i++) { 289 for (int i = 0; i < 2; i++) {
296 NodeRange range = i == 0 ? loop_tree->LoopNodes(loop) : exit_range; 290 NodeRange range = i == 0 ? loop_tree->LoopNodes(loop) : exit_range;
297 ZoneVector<Edge> value_edges(tmp_zone); 291 ZoneVector<Edge> value_edges(tmp_zone);
298 ZoneVector<Edge> effect_edges(tmp_zone); 292 ZoneVector<Edge> effect_edges(tmp_zone);
299 293
300 for (Node* node : range) { 294 for (Node* node : range) {
301 // Gather value and effect edges from outside the region. 295 // Gather value and effect edges from outside the region.
302 for (Edge edge : node->use_edges()) { 296 for (Edge edge : node->use_edges()) {
(...skipping 27 matching lines...) Expand all
330 } 324 }
331 } 325 }
332 } 326 }
333 327
334 return iter; 328 return iter;
335 } 329 }
336 330
337 } // namespace compiler 331 } // namespace compiler
338 } // namespace internal 332 } // namespace internal
339 } // namespace v8 333 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/loop-peeling.h ('k') | test/unittests/compiler/loop-peeling-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698