Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/flow_graph_builder.h" | 7 #include "vm/flow_graph_builder.h" |
| 8 #include "vm/il_printer.h" | 8 #include "vm/il_printer.h" |
| 9 #include "vm/object_store.h" | 9 #include "vm/object_store.h" |
| 10 #include "vm/parser.h" | 10 #include "vm/parser.h" |
| (...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 | 589 |
| 590 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 590 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 591 instr->computation()->Accept(this, instr); | 591 instr->computation()->Accept(this, instr); |
| 592 } | 592 } |
| 593 | 593 |
| 594 | 594 |
| 595 void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp, | 595 void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp, |
| 596 BindInstr* instr) { | 596 BindInstr* instr) { |
| 597 if (FLAG_eliminate_type_checks && | 597 if (FLAG_eliminate_type_checks && |
| 598 !comp->is_eliminated() && | 598 !comp->is_eliminated() && |
| 599 !comp->dst_type().IsMalformed() && | |
| 600 comp->value()->CompileTypeIsMoreSpecificThan(comp->dst_type())) { | 599 comp->value()->CompileTypeIsMoreSpecificThan(comp->dst_type())) { |
| 600 // TODO(regis): Remove is_eliminated_ field and support. | |
| 601 comp->eliminate(); | 601 comp->eliminate(); |
| 602 if (is_ssa_) { | |
| 603 UseVal* use = comp->value()->AsUse(); | |
| 604 // TODO(regis): Handle constant input value (not a definition). | |
|
srdjan
2012/08/15 17:49:56
s/not a definition/cannot access definition/
regis
2012/08/15 22:49:18
Done.
| |
| 605 if (use != NULL) { | |
| 606 Definition* result = use->definition(); | |
| 607 ASSERT(result != NULL); | |
| 608 // Replace uses and remove the current instructions via the iterator. | |
| 609 instr->ReplaceUsesWith(result); | |
| 610 ASSERT(current_iterator()->Current()->AsBind() == instr); | |
| 611 current_iterator()->RemoveCurrentFromGraph(); | |
| 612 if (FLAG_trace_optimization) { | |
| 613 OS::Print("Replacing v%d with v%d\n", | |
| 614 instr->ssa_temp_index(), | |
| 615 result->ssa_temp_index()); | |
|
srdjan
2012/08/15 17:49:56
You are not really replacing, but removing. Please
regis
2012/08/15 22:49:18
I have removed the instruction, but replaced its u
| |
| 616 } | |
| 617 } | |
| 618 } | |
| 602 if (FLAG_trace_type_check_elimination) { | 619 if (FLAG_trace_type_check_elimination) { |
| 603 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | 620 FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
| 604 comp->token_pos(), | 621 comp->token_pos(), |
| 605 comp->value(), | 622 comp->value(), |
| 606 comp->dst_type(), | 623 comp->dst_type(), |
| 607 comp->dst_name(), | 624 comp->dst_name(), |
| 608 comp->is_eliminated()); | 625 comp->is_eliminated()); |
| 609 } | 626 } |
| 610 } | 627 } |
| 611 } | 628 } |
| 612 | 629 |
| 613 | 630 |
| 614 void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanComp* comp, | 631 void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanComp* comp, |
| 615 BindInstr* instr) { | 632 BindInstr* instr) { |
| 633 // TODO(regis): Propagate NullType as well and revise the comment and code | |
| 634 // below to also eliminate the test for non-null and non-constant value. | |
| 635 | |
| 636 // We can only eliminate an 'assert boolean' test when the checked value is | |
| 637 // a constant time constant. Indeed, a variable of the proper compile time | |
| 638 // type (bool) may still hold null at run time and therefore fail the test. | |
| 616 if (FLAG_eliminate_type_checks && | 639 if (FLAG_eliminate_type_checks && |
| 617 !comp->is_eliminated() && | 640 !comp->is_eliminated() && |
| 641 comp->value()->IsConstant() && | |
| 642 !comp->value()->IsConstantNull() && | |
| 618 comp->value()->CompileTypeIsMoreSpecificThan( | 643 comp->value()->CompileTypeIsMoreSpecificThan( |
| 619 Type::Handle(Type::BoolInterface()))) { | 644 Type::Handle(Type::BoolInterface()))) { |
| 645 // TODO(regis): Remove is_eliminated_ field and support. | |
|
srdjan
2012/08/15 17:49:56
I do not think this is correct. Let's discuss offl
srdjan
2012/08/15 19:55:56
My mistake. You are doing it only for constant inp
regis
2012/08/15 22:49:18
Yes, we only do this for constants, but this will
| |
| 620 comp->eliminate(); | 646 comp->eliminate(); |
| 647 if (is_ssa_) { | |
| 648 UseVal* use = comp->value()->AsUse(); | |
| 649 // TODO(regis): Handle constant input value (not a definition). | |
| 650 if (use != NULL) { | |
| 651 Definition* result = use->definition(); | |
| 652 ASSERT(result != NULL); | |
| 653 // Replace uses and remove the current instructions via the iterator. | |
| 654 instr->ReplaceUsesWith(result); | |
| 655 ASSERT(current_iterator()->Current()->AsBind() == instr); | |
| 656 current_iterator()->RemoveCurrentFromGraph(); | |
| 657 if (FLAG_trace_optimization) { | |
| 658 OS::Print("Replacing v%d with v%d\n", | |
| 659 instr->ssa_temp_index(), | |
| 660 result->ssa_temp_index()); | |
| 661 } | |
| 662 } | |
| 663 } | |
| 621 if (FLAG_trace_type_check_elimination) { | 664 if (FLAG_trace_type_check_elimination) { |
| 622 const String& name = String::Handle(Symbols::New("boolean expression")); | 665 const String& name = String::Handle(Symbols::New("boolean expression")); |
| 623 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | 666 FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
| 624 comp->token_pos(), | 667 comp->token_pos(), |
| 625 comp->value(), | 668 comp->value(), |
| 626 Type::Handle(Type::BoolInterface()), | 669 Type::Handle(Type::BoolInterface()), |
| 627 name, | 670 name, |
| 628 comp->is_eliminated()); | 671 comp->is_eliminated()); |
| 629 } | 672 } |
| 630 } | 673 } |
| 631 } | 674 } |
| 632 | 675 |
| 633 | 676 |
| 677 void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfComp* comp, | |
| 678 BindInstr* instr) { | |
| 679 // TODO(regis): Propagate NullType as well and revise the comment and code | |
| 680 // below to also eliminate the test for non-null and non-constant value. | |
| 681 | |
| 682 // We can only eliminate an 'instance of' test when the checked value is | |
| 683 // a constant time constant. Indeed, a variable of the proper compile time | |
| 684 // type may still hold null at run time and therefore fail the test. | |
| 685 // We do not bother checking for Object destination type, since the graph | |
| 686 // builder did already. | |
| 687 if (FLAG_eliminate_type_checks && | |
| 688 comp->value()->IsConstant() && | |
| 689 !comp->value()->IsConstantNull() && | |
| 690 comp->value()->CompileTypeIsMoreSpecificThan(comp->type())) { | |
|
srdjan
2012/08/15 17:49:56
ditto
| |
| 691 if (is_ssa_) { | |
| 692 UseVal* use = comp->value()->AsUse(); | |
| 693 // TODO(regis): Handle constant input value (not a definition). | |
| 694 if (use != NULL) { | |
| 695 Definition* result = use->definition(); | |
| 696 ASSERT(result != NULL); | |
| 697 // Replace uses and remove the current instructions via the iterator. | |
| 698 instr->ReplaceUsesWith(result); | |
| 699 ASSERT(current_iterator()->Current()->AsBind() == instr); | |
| 700 current_iterator()->RemoveCurrentFromGraph(); | |
| 701 if (FLAG_trace_optimization) { | |
| 702 OS::Print("Replacing v%d with v%d\n", | |
| 703 instr->ssa_temp_index(), | |
| 704 result->ssa_temp_index()); | |
| 705 } | |
| 706 } | |
| 707 } | |
| 708 if (FLAG_trace_type_check_elimination) { | |
| 709 const String& name = String::Handle(Symbols::New("InstanceOf")); | |
| 710 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | |
| 711 comp->token_pos(), | |
| 712 comp->value(), | |
| 713 comp->type(), | |
| 714 name, | |
| 715 /* eliminated = */ true); | |
| 716 } | |
| 717 } | |
| 718 } | |
| 719 | |
| 720 | |
| 634 void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) { | 721 void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) { |
| 635 if (graph_entry->start_env() == NULL) { | 722 if (graph_entry->start_env() == NULL) { |
| 636 return; | 723 return; |
| 637 } | 724 } |
| 638 // Visit incoming parameters. | 725 // Visit incoming parameters. |
| 639 for (intptr_t i = 0; i < graph_entry->start_env()->values().length(); i++) { | 726 for (intptr_t i = 0; i < graph_entry->start_env()->values().length(); i++) { |
| 640 Value* val = graph_entry->start_env()->values()[i]; | 727 Value* val = graph_entry->start_env()->values()[i]; |
| 641 if (val->IsUse()) { | 728 if (val->IsUse()) { |
| 642 ParameterInstr* param = val->AsUse()->definition()->AsParameter(); | 729 ParameterInstr* param = val->AsUse()->definition()->AsParameter(); |
| 643 if (param != NULL) { | 730 if (param != NULL) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 659 } | 746 } |
| 660 } | 747 } |
| 661 } | 748 } |
| 662 | 749 |
| 663 | 750 |
| 664 void FlowGraphTypePropagator::VisitBind(BindInstr* bind) { | 751 void FlowGraphTypePropagator::VisitBind(BindInstr* bind) { |
| 665 // No need to propagate the input types of the bound computation, as long as | 752 // No need to propagate the input types of the bound computation, as long as |
| 666 // PhiInstr's are handled as part of JoinEntryInstr. | 753 // PhiInstr's are handled as part of JoinEntryInstr. |
| 667 // Visit computation and possibly eliminate type check. | 754 // Visit computation and possibly eliminate type check. |
| 668 bind->computation()->Accept(this, bind); | 755 bind->computation()->Accept(this, bind); |
| 669 // Cache propagated computation type. | 756 // The current bind may have been removed from the graph. |
| 670 AbstractType& type = AbstractType::Handle(bind->computation()->CompileType()); | 757 if (current_iterator()->Current()->AsBind() == bind) { |
| 671 bool changed = bind->SetPropagatedType(type); | 758 // Current bind was not removed. |
| 672 if (changed) { | 759 // Cache propagated computation type. |
| 673 still_changing_ = true; | 760 AbstractType& computation_type = |
| 761 AbstractType::Handle(bind->computation()->CompileType()); | |
| 762 bool changed = bind->SetPropagatedType(computation_type); | |
| 763 if (changed) { | |
| 764 still_changing_ = true; | |
| 765 } | |
| 674 } | 766 } |
| 675 } | 767 } |
| 676 | 768 |
| 677 | 769 |
| 678 void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) { | 770 void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) { |
| 679 // We could set the propagated type of the phi to the least upper bound of its | 771 // We could set the propagated type of the phi to the least upper bound of its |
| 680 // input propagated types. However, keeping all propagated types allows us to | 772 // input propagated types. However, keeping all propagated types allows us to |
| 681 // optimize method dispatch. | 773 // optimize method dispatch. |
| 682 // TODO(regis): Support a set of propagated types. For now, we compute the | 774 // TODO(regis): Support a set of propagated types. For now, we compute the |
| 683 // least specific of the input propagated types. | 775 // least specific of the input propagated types. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 730 LocationSummary* locs = it.Current()->locs(); | 822 LocationSummary* locs = it.Current()->locs(); |
| 731 if ((locs != NULL) && locs->can_call()) { | 823 if ((locs != NULL) && locs->can_call()) { |
| 732 is_leaf_ = false; | 824 is_leaf_ = false; |
| 733 return; | 825 return; |
| 734 } | 826 } |
| 735 } | 827 } |
| 736 } | 828 } |
| 737 } | 829 } |
| 738 | 830 |
| 739 } // namespace dart | 831 } // namespace dart |
| OLD | NEW |