| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |