| 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/common-operator.h" | 5 #include "src/compiler/common-operator.h" |
| 6 #include "src/compiler/control-reducer.h" | 6 #include "src/compiler/control-reducer.h" |
| 7 #include "src/compiler/graph.h" | 7 #include "src/compiler/graph.h" |
| 8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
| 9 #include "src/compiler/node-matchers.h" | 9 #include "src/compiler/node-matchers.h" |
| 10 #include "src/compiler/node-properties-inl.h" | 10 #include "src/compiler/node-properties-inl.h" |
| 11 #include "src/zone-containers.h" | 11 #include "src/zone-containers.h" |
| 12 | 12 |
| 13 namespace v8 { | 13 namespace v8 { |
| 14 namespace internal { | 14 namespace internal { |
| 15 namespace compiler { | 15 namespace compiler { |
| 16 | 16 |
| 17 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; | 17 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; |
| 18 enum Reachability { kFromStart = 8 }; | 18 enum Reachability { kFromStart = 8 }; |
| 19 enum Decision { kFalse, kUnknown, kTrue }; |
| 19 | 20 |
| 20 #define TRACE(x) \ | 21 #define TRACE(x) \ |
| 21 if (FLAG_trace_turbo_reduction) PrintF x | 22 if (FLAG_trace_turbo_reduction) PrintF x |
| 22 | 23 |
| 23 class ControlReducerImpl { | 24 class ControlReducerImpl { |
| 24 public: | 25 public: |
| 25 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, | 26 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, |
| 26 CommonOperatorBuilder* common) | 27 CommonOperatorBuilder* common) |
| 27 : zone_(zone), | 28 : zone_(zone), |
| 28 jsgraph_(jsgraph), | 29 jsgraph_(jsgraph), |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 case IrOpcode::kSelect: | 334 case IrOpcode::kSelect: |
| 334 return ReduceSelect(node); | 335 return ReduceSelect(node); |
| 335 case IrOpcode::kPhi: | 336 case IrOpcode::kPhi: |
| 336 case IrOpcode::kEffectPhi: | 337 case IrOpcode::kEffectPhi: |
| 337 return ReducePhi(node); | 338 return ReducePhi(node); |
| 338 default: | 339 default: |
| 339 return node; | 340 return node; |
| 340 } | 341 } |
| 341 } | 342 } |
| 342 | 343 |
| 343 // Reduce redundant selects. | 344 // Try to statically fold a condition. |
| 344 Node* ReduceSelect(Node* const node) { | 345 Decision DecideCondition(Node* cond) { |
| 345 Node* const cond = node->InputAt(0); | |
| 346 Node* const tvalue = node->InputAt(1); | |
| 347 Node* const fvalue = node->InputAt(2); | |
| 348 if (tvalue == fvalue) return tvalue; | |
| 349 switch (cond->opcode()) { | 346 switch (cond->opcode()) { |
| 350 case IrOpcode::kInt32Constant: | 347 case IrOpcode::kInt32Constant: |
| 351 return Int32Matcher(cond).Is(0) ? fvalue : tvalue; | 348 return Int32Matcher(cond).Is(0) ? kFalse : kTrue; |
| 352 case IrOpcode::kInt64Constant: | 349 case IrOpcode::kInt64Constant: |
| 353 return Int64Matcher(cond).Is(0) ? fvalue : tvalue; | 350 return Int64Matcher(cond).Is(0) ? kFalse : kTrue; |
| 354 case IrOpcode::kNumberConstant: | 351 case IrOpcode::kNumberConstant: |
| 355 return NumberMatcher(cond).Is(0) ? fvalue : tvalue; | 352 return NumberMatcher(cond).Is(0) ? kFalse : kTrue; |
| 356 case IrOpcode::kHeapConstant: { | 353 case IrOpcode::kHeapConstant: { |
| 357 Handle<Object> object = | 354 Handle<Object> object = |
| 358 HeapObjectMatcher<Object>(cond).Value().handle(); | 355 HeapObjectMatcher<Object>(cond).Value().handle(); |
| 359 if (object->IsTrue()) return tvalue; | 356 if (object->IsTrue()) return kTrue; |
| 360 if (object->IsFalse()) return fvalue; | 357 if (object->IsFalse()) return kFalse; |
| 358 // TODO(turbofan): decide more conditions for heap constants. |
| 361 break; | 359 break; |
| 362 } | 360 } |
| 363 default: | 361 default: |
| 364 break; | 362 break; |
| 365 } | 363 } |
| 364 return kUnknown; |
| 365 } |
| 366 |
| 367 // Reduce redundant selects. |
| 368 Node* ReduceSelect(Node* const node) { |
| 369 Node* const tvalue = node->InputAt(1); |
| 370 Node* const fvalue = node->InputAt(2); |
| 371 if (tvalue == fvalue) return tvalue; |
| 372 Decision result = DecideCondition(node->InputAt(0)); |
| 373 if (result == kTrue) return tvalue; |
| 374 if (result == kFalse) return fvalue; |
| 366 return node; | 375 return node; |
| 367 } | 376 } |
| 368 | 377 |
| 369 // Reduce redundant phis. | 378 // Reduce redundant phis. |
| 370 Node* ReducePhi(Node* node) { | 379 Node* ReducePhi(Node* node) { |
| 371 int n = node->InputCount(); | 380 int n = node->InputCount(); |
| 372 if (n <= 1) return dead(); // No non-control inputs. | 381 if (n <= 1) return dead(); // No non-control inputs. |
| 373 if (n == 2) return node->InputAt(0); // Only one non-control input. | 382 if (n == 2) return node->InputAt(0); // Only one non-control input. |
| 374 | 383 |
| 375 Node* replacement = NULL; | 384 Node* replacement = NULL; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 RemoveDeadInputs(node, phi); | 438 RemoveDeadInputs(node, phi); |
| 430 Revisit(phi); | 439 Revisit(phi); |
| 431 } | 440 } |
| 432 // Edit the merge in place, removing dead inputs. | 441 // Edit the merge in place, removing dead inputs. |
| 433 RemoveDeadInputs(node, node); | 442 RemoveDeadInputs(node, node); |
| 434 return node; | 443 return node; |
| 435 } | 444 } |
| 436 | 445 |
| 437 // Reduce branches if they have constant inputs. | 446 // Reduce branches if they have constant inputs. |
| 438 Node* ReduceBranch(Node* node) { | 447 Node* ReduceBranch(Node* node) { |
| 439 Node* cond = node->InputAt(0); | 448 Decision result = DecideCondition(node->InputAt(0)); |
| 440 bool is_true; | 449 if (result == kUnknown) return node; |
| 441 switch (cond->opcode()) { | |
| 442 case IrOpcode::kInt32Constant: | |
| 443 is_true = !Int32Matcher(cond).Is(0); | |
| 444 break; | |
| 445 case IrOpcode::kInt64Constant: | |
| 446 is_true = !Int64Matcher(cond).Is(0); | |
| 447 break; | |
| 448 case IrOpcode::kNumberConstant: | |
| 449 is_true = !NumberMatcher(cond).Is(0); | |
| 450 break; | |
| 451 case IrOpcode::kHeapConstant: { | |
| 452 Handle<Object> object = | |
| 453 HeapObjectMatcher<Object>(cond).Value().handle(); | |
| 454 if (object->IsTrue()) | |
| 455 is_true = true; | |
| 456 else if (object->IsFalse()) | |
| 457 is_true = false; | |
| 458 else | |
| 459 return node; // TODO(turbofan): fold branches on strings, objects. | |
| 460 break; | |
| 461 } | |
| 462 default: | |
| 463 return node; | |
| 464 } | |
| 465 | 450 |
| 466 TRACE(("BranchReduce: #%d:%s = %s\n", node->id(), node->op()->mnemonic(), | 451 TRACE(("BranchReduce: #%d:%s = %s\n", node->id(), node->op()->mnemonic(), |
| 467 is_true ? "true" : "false")); | 452 (result == kTrue) ? "true" : "false")); |
| 468 | 453 |
| 469 // Replace IfTrue and IfFalse projections from this branch. | 454 // Replace IfTrue and IfFalse projections from this branch. |
| 470 Node* control = NodeProperties::GetControlInput(node); | 455 Node* control = NodeProperties::GetControlInput(node); |
| 471 for (UseIter i = node->uses().begin(); i != node->uses().end();) { | 456 for (UseIter i = node->uses().begin(); i != node->uses().end();) { |
| 472 Node* to = *i; | 457 Node* to = *i; |
| 473 if (to->opcode() == IrOpcode::kIfTrue) { | 458 if (to->opcode() == IrOpcode::kIfTrue) { |
| 474 TRACE((" IfTrue: #%d:%s\n", to->id(), to->op()->mnemonic())); | 459 TRACE((" IfTrue: #%d:%s\n", to->id(), to->op()->mnemonic())); |
| 475 i.UpdateToAndIncrement(NULL); | 460 i.UpdateToAndIncrement(NULL); |
| 476 ReplaceNode(to, is_true ? control : dead()); | 461 ReplaceNode(to, (result == kTrue) ? control : dead()); |
| 477 } else if (to->opcode() == IrOpcode::kIfFalse) { | 462 } else if (to->opcode() == IrOpcode::kIfFalse) { |
| 478 TRACE((" IfFalse: #%d:%s\n", to->id(), to->op()->mnemonic())); | 463 TRACE((" IfFalse: #%d:%s\n", to->id(), to->op()->mnemonic())); |
| 479 i.UpdateToAndIncrement(NULL); | 464 i.UpdateToAndIncrement(NULL); |
| 480 ReplaceNode(to, is_true ? dead() : control); | 465 ReplaceNode(to, (result == kTrue) ? dead() : control); |
| 481 } else { | 466 } else { |
| 482 ++i; | 467 ++i; |
| 483 } | 468 } |
| 484 } | 469 } |
| 485 return control; | 470 return control; |
| 486 } | 471 } |
| 487 | 472 |
| 488 // Remove inputs to {node} corresponding to the dead inputs to {merge} | 473 // Remove inputs to {node} corresponding to the dead inputs to {merge} |
| 489 // and compact the remaining inputs, updating the operator. | 474 // and compact the remaining inputs, updating the operator. |
| 490 void RemoveDeadInputs(Node* merge, Node* node) { | 475 void RemoveDeadInputs(Node* merge, Node* node) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 Node* ControlReducer::ReduceBranchForTesting(JSGraph* jsgraph, | 550 Node* ControlReducer::ReduceBranchForTesting(JSGraph* jsgraph, |
| 566 CommonOperatorBuilder* common, | 551 CommonOperatorBuilder* common, |
| 567 Node* node) { | 552 Node* node) { |
| 568 Zone zone(jsgraph->graph()->zone()->isolate()); | 553 Zone zone(jsgraph->graph()->zone()->isolate()); |
| 569 ControlReducerImpl impl(&zone, jsgraph, common); | 554 ControlReducerImpl impl(&zone, jsgraph, common); |
| 570 return impl.ReduceBranch(node); | 555 return impl.ReduceBranch(node); |
| 571 } | 556 } |
| 572 } | 557 } |
| 573 } | 558 } |
| 574 } // namespace v8::internal::compiler | 559 } // namespace v8::internal::compiler |
| OLD | NEW |