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 |