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

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 1700103002: VM: Move representation selection code out of the flow graph optimizer. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: remove some dead code Created 4 years, 10 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 | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/precompiler.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 (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/branch_optimizer.h" 8 #include "vm/branch_optimizer.h"
9 #include "vm/cha.h" 9 #include "vm/cha.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 26 matching lines...) Expand all
37 "Maximum number of polymorphic check, otherwise it is megamorphic."); 37 "Maximum number of polymorphic check, otherwise it is megamorphic.");
38 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, 38 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32,
39 "Maximum number of polymorphic checks in equality operator," 39 "Maximum number of polymorphic checks in equality operator,"
40 " otherwise use megamorphic dispatch."); 40 " otherwise use megamorphic dispatch.");
41 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos"); 41 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos");
42 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); 42 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details.");
43 DEFINE_FLAG(bool, truncating_left_shift, true, 43 DEFINE_FLAG(bool, truncating_left_shift, true,
44 "Optimize left shift to truncate if possible"); 44 "Optimize left shift to truncate if possible");
45 DEFINE_FLAG(bool, use_cha_deopt, true, 45 DEFINE_FLAG(bool, use_cha_deopt, true,
46 "Use class hierarchy analysis even if it can cause deoptimization."); 46 "Use class hierarchy analysis even if it can cause deoptimization.");
47 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32)
48 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass.");
49 #endif
50 47
51 DECLARE_FLAG(bool, precompilation); 48 DECLARE_FLAG(bool, precompilation);
52 DECLARE_FLAG(bool, polymorphic_with_deopt); 49 DECLARE_FLAG(bool, polymorphic_with_deopt);
53 DECLARE_FLAG(bool, trace_cha); 50 DECLARE_FLAG(bool, trace_cha);
54 DECLARE_FLAG(bool, trace_field_guards); 51 DECLARE_FLAG(bool, trace_field_guards);
55 52
56 // Quick access to the current isolate and zone. 53 // Quick access to the current isolate and zone.
57 #define I (isolate()) 54 #define I (isolate())
58 #define Z (zone()) 55 #define Z (zone())
59 56
60 static bool ShouldInlineSimd() { 57 static bool ShouldInlineSimd() {
61 return FlowGraphCompiler::SupportsUnboxedSimd128(); 58 return FlowGraphCompiler::SupportsUnboxedSimd128();
62 } 59 }
63 60
64 61
65 static bool CanUnboxDouble() { 62 static bool CanUnboxDouble() {
66 return FlowGraphCompiler::SupportsUnboxedDoubles(); 63 return FlowGraphCompiler::SupportsUnboxedDoubles();
67 } 64 }
68 65
69 66
70 static bool CanConvertUnboxedMintToDouble() { 67 static bool CanConvertUnboxedMintToDouble() {
71 #if defined(TARGET_ARCH_IA32) 68 return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
72 return true;
73 #else
74 // ARM does not have a short instruction sequence for converting int64 to
75 // double.
76 // TODO(johnmccutchan): Investigate possibility on MIPS once
77 // mints are implemented there.
78 return false;
79 #endif
80 } 69 }
81 70
82 71
83 // Optimize instance calls using ICData. 72 // Optimize instance calls using ICData.
84 void FlowGraphOptimizer::ApplyICData() { 73 void FlowGraphOptimizer::ApplyICData() {
85 VisitBlocks(); 74 VisitBlocks();
86 } 75 }
87 76
88 77
89 void FlowGraphOptimizer::PopulateWithICData() { 78 void FlowGraphOptimizer::PopulateWithICData() {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 Instruction* instr = it.Current(); 120 Instruction* instr = it.Current();
132 if (instr->IsInstanceCall()) { 121 if (instr->IsInstanceCall()) {
133 InstanceCallInstr* call = instr->AsInstanceCall(); 122 InstanceCallInstr* call = instr->AsInstanceCall();
134 if (call->HasICData()) { 123 if (call->HasICData()) {
135 if (TryCreateICData(call)) { 124 if (TryCreateICData(call)) {
136 VisitInstanceCall(call); 125 VisitInstanceCall(call);
137 } 126 }
138 } 127 }
139 } else if (instr->IsPolymorphicInstanceCall()) { 128 } else if (instr->IsPolymorphicInstanceCall()) {
140 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); 129 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall());
141 } else if (instr->IsStrictCompare()) {
142 VisitStrictCompare(instr->AsStrictCompare());
143 } else if (instr->IsBranch()) {
144 ComparisonInstr* compare = instr->AsBranch()->comparison();
145 if (compare->IsStrictCompare()) {
146 VisitStrictCompare(compare->AsStrictCompare());
147 }
148 } 130 }
149 } 131 }
150 current_iterator_ = NULL; 132 current_iterator_ = NULL;
151 } 133 }
152 } 134 }
153 135
154 136
155 // TODO(srdjan): Test/support other number types as well. 137 // TODO(srdjan): Test/support other number types as well.
156 static bool IsNumberCid(intptr_t cid) { 138 static bool IsNumberCid(intptr_t cid) {
157 return (cid == kSmiCid) || (cid == kDoubleCid); 139 return (cid == kSmiCid) || (cid == kDoubleCid);
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 } 578 }
597 } 579 }
598 } 580 }
599 TryMergeTruncDivMod(&div_mod_merge); 581 TryMergeTruncDivMod(&div_mod_merge);
600 TryMergeMathUnary(&sin_cos_merge); 582 TryMergeMathUnary(&sin_cos_merge);
601 current_iterator_ = NULL; 583 current_iterator_ = NULL;
602 } 584 }
603 } 585 }
604 586
605 587
606 bool FlowGraphOptimizer::Canonicalize() {
607 bool changed = false;
608
609 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
610 !block_it.Done();
611 block_it.Advance()) {
612 for (ForwardInstructionIterator it(block_it.Current());
613 !it.Done();
614 it.Advance()) {
615 Instruction* current = it.Current();
616 if (current->HasUnmatchedInputRepresentations()) {
617 // Can't canonicalize this instruction until all conversions for its
618 // inputs are inserted.
619 continue;
620 }
621
622 Instruction* replacement = current->Canonicalize(flow_graph());
623
624 if (replacement != current) {
625 // For non-definitions Canonicalize should return either NULL or
626 // this.
627 ASSERT((replacement == NULL) || current->IsDefinition());
628 flow_graph_->ReplaceCurrentInstruction(&it, current, replacement);
629 changed = true;
630 }
631 }
632 }
633 return changed;
634 }
635
636
637 static bool IsUnboxedInteger(Representation rep) {
638 return (rep == kUnboxedInt32) ||
639 (rep == kUnboxedUint32) ||
640 (rep == kUnboxedMint);
641 }
642
643
644 void FlowGraphOptimizer::InsertConversion(Representation from,
645 Representation to,
646 Value* use,
647 bool is_environment_use) {
648 Instruction* insert_before;
649 Instruction* deopt_target;
650 PhiInstr* phi = use->instruction()->AsPhi();
651 if (phi != NULL) {
652 ASSERT(phi->is_alive());
653 // For phis conversions have to be inserted in the predecessor.
654 insert_before =
655 phi->block()->PredecessorAt(use->use_index())->last_instruction();
656 deopt_target = NULL;
657 } else {
658 deopt_target = insert_before = use->instruction();
659 }
660
661 Definition* converted = NULL;
662 if (IsUnboxedInteger(from) && IsUnboxedInteger(to)) {
663 const intptr_t deopt_id = (to == kUnboxedInt32) && (deopt_target != NULL) ?
664 deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
665 converted = new(Z) UnboxedIntConverterInstr(from,
666 to,
667 use->CopyWithType(),
668 deopt_id);
669 } else if ((from == kUnboxedInt32) && (to == kUnboxedDouble)) {
670 converted = new Int32ToDoubleInstr(use->CopyWithType());
671 } else if ((from == kUnboxedMint) &&
672 (to == kUnboxedDouble) &&
673 CanConvertUnboxedMintToDouble()) {
674 const intptr_t deopt_id = (deopt_target != NULL) ?
675 deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
676 ASSERT(CanUnboxDouble());
677 converted = new MintToDoubleInstr(use->CopyWithType(), deopt_id);
678 } else if ((from == kTagged) && Boxing::Supports(to)) {
679 const intptr_t deopt_id = (deopt_target != NULL) ?
680 deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
681 converted = UnboxInstr::Create(to, use->CopyWithType(), deopt_id);
682 } else if ((to == kTagged) && Boxing::Supports(from)) {
683 converted = BoxInstr::Create(from, use->CopyWithType());
684 } else {
685 // We have failed to find a suitable conversion instruction.
686 // Insert two "dummy" conversion instructions with the correct
687 // "from" and "to" representation. The inserted instructions will
688 // trigger a deoptimization if executed. See #12417 for a discussion.
689 const intptr_t deopt_id = (deopt_target != NULL) ?
690 deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
691 ASSERT(Boxing::Supports(from));
692 ASSERT(Boxing::Supports(to));
693 Definition* boxed = BoxInstr::Create(from, use->CopyWithType());
694 use->BindTo(boxed);
695 InsertBefore(insert_before, boxed, NULL, FlowGraph::kValue);
696 converted = UnboxInstr::Create(to, new(Z) Value(boxed), deopt_id);
697 }
698 ASSERT(converted != NULL);
699 InsertBefore(insert_before, converted, use->instruction()->env(),
700 FlowGraph::kValue);
701 if (is_environment_use) {
702 use->BindToEnvironment(converted);
703 } else {
704 use->BindTo(converted);
705 }
706
707 if ((to == kUnboxedInt32) && (phi != NULL)) {
708 // Int32 phis are unboxed optimistically. Ensure that unboxing
709 // has deoptimization target attached from the goto instruction.
710 flow_graph_->CopyDeoptTarget(converted, insert_before);
711 }
712 }
713
714
715 void FlowGraphOptimizer::ConvertUse(Value* use, Representation from_rep) {
716 const Representation to_rep =
717 use->instruction()->RequiredInputRepresentation(use->use_index());
718 if (from_rep == to_rep || to_rep == kNoRepresentation) {
719 return;
720 }
721 InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/ false);
722 }
723
724
725 void FlowGraphOptimizer::ConvertEnvironmentUse(Value* use,
726 Representation from_rep) {
727 const Representation to_rep = kTagged;
728 if (from_rep == to_rep) {
729 return;
730 }
731 InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/ true);
732 }
733
734
735 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) {
736 const Representation from_rep = def->representation();
737
738 for (Value::Iterator it(def->input_use_list());
739 !it.Done();
740 it.Advance()) {
741 ConvertUse(it.Current(), from_rep);
742 }
743
744 if (flow_graph()->graph_entry()->SuccessorCount() > 1) {
745 for (Value::Iterator it(def->env_use_list());
746 !it.Done();
747 it.Advance()) {
748 Value* use = it.Current();
749 if (use->instruction()->MayThrow() &&
750 use->instruction()->GetBlock()->InsideTryBlock()) {
751 // Environment uses at calls inside try-blocks must be converted to
752 // tagged representation.
753 ConvertEnvironmentUse(it.Current(), from_rep);
754 }
755 }
756 }
757 }
758
759
760 static void UnboxPhi(PhiInstr* phi) {
761 Representation unboxed = phi->representation();
762
763 switch (phi->Type()->ToCid()) {
764 case kDoubleCid:
765 if (CanUnboxDouble()) {
766 unboxed = kUnboxedDouble;
767 }
768 break;
769 case kFloat32x4Cid:
770 if (ShouldInlineSimd()) {
771 unboxed = kUnboxedFloat32x4;
772 }
773 break;
774 case kInt32x4Cid:
775 if (ShouldInlineSimd()) {
776 unboxed = kUnboxedInt32x4;
777 }
778 break;
779 case kFloat64x2Cid:
780 if (ShouldInlineSimd()) {
781 unboxed = kUnboxedFloat64x2;
782 }
783 break;
784 }
785
786 if ((kSmiBits < 32) &&
787 (unboxed == kTagged) &&
788 phi->Type()->IsInt() &&
789 RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt64)) {
790 // On 32-bit platforms conservatively unbox phis that:
791 // - are proven to be of type Int;
792 // - fit into 64bits range;
793 // - have either constants or Box() operations as inputs;
794 // - have at least one Box() operation as an input;
795 // - are used in at least 1 Unbox() operation.
796 bool should_unbox = false;
797 for (intptr_t i = 0; i < phi->InputCount(); i++) {
798 Definition* input = phi->InputAt(i)->definition();
799 if (input->IsBox() &&
800 RangeUtils::Fits(input->range(),
801 RangeBoundary::kRangeBoundaryInt64)) {
802 should_unbox = true;
803 } else if (!input->IsConstant()) {
804 should_unbox = false;
805 break;
806 }
807 }
808
809 if (should_unbox) {
810 // We checked inputs. Check if phi is used in at least one unbox
811 // operation.
812 bool has_unboxed_use = false;
813 for (Value* use = phi->input_use_list();
814 use != NULL;
815 use = use->next_use()) {
816 Instruction* instr = use->instruction();
817 if (instr->IsUnbox()) {
818 has_unboxed_use = true;
819 break;
820 } else if (IsUnboxedInteger(
821 instr->RequiredInputRepresentation(use->use_index()))) {
822 has_unboxed_use = true;
823 break;
824 }
825 }
826
827 if (!has_unboxed_use) {
828 should_unbox = false;
829 }
830 }
831
832 if (should_unbox) {
833 unboxed =
834 RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)
835 ? kUnboxedInt32 : kUnboxedMint;
836 }
837 }
838
839 phi->set_representation(unboxed);
840 }
841
842
843 void FlowGraphOptimizer::SelectRepresentations() {
844 // Conservatively unbox all phis that were proven to be of Double,
845 // Float32x4, or Int32x4 type.
846 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
847 !block_it.Done();
848 block_it.Advance()) {
849 JoinEntryInstr* join_entry = block_it.Current()->AsJoinEntry();
850 if (join_entry != NULL) {
851 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
852 PhiInstr* phi = it.Current();
853 UnboxPhi(phi);
854 }
855 }
856 }
857
858 // Process all instructions and insert conversions where needed.
859 GraphEntryInstr* graph_entry = flow_graph_->graph_entry();
860
861 // Visit incoming parameters and constants.
862 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) {
863 InsertConversionsFor((*graph_entry->initial_definitions())[i]);
864 }
865
866 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
867 !block_it.Done();
868 block_it.Advance()) {
869 BlockEntryInstr* entry = block_it.Current();
870 JoinEntryInstr* join_entry = entry->AsJoinEntry();
871 if (join_entry != NULL) {
872 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
873 PhiInstr* phi = it.Current();
874 ASSERT(phi != NULL);
875 ASSERT(phi->is_alive());
876 InsertConversionsFor(phi);
877 }
878 }
879 CatchBlockEntryInstr* catch_entry = entry->AsCatchBlockEntry();
880 if (catch_entry != NULL) {
881 for (intptr_t i = 0;
882 i < catch_entry->initial_definitions()->length();
883 i++) {
884 InsertConversionsFor((*catch_entry->initial_definitions())[i]);
885 }
886 }
887 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
888 Definition* def = it.Current()->AsDefinition();
889 if (def != NULL) {
890 InsertConversionsFor(def);
891 }
892 }
893 }
894 }
895
896
897 static bool ClassIdIsOneOf(intptr_t class_id, 588 static bool ClassIdIsOneOf(intptr_t class_id,
898 const GrowableArray<intptr_t>& class_ids) { 589 const GrowableArray<intptr_t>& class_ids) {
899 for (intptr_t i = 0; i < class_ids.length(); i++) { 590 for (intptr_t i = 0; i < class_ids.length(); i++) {
900 ASSERT(class_ids[i] != kIllegalCid); 591 ASSERT(class_ids[i] != kIllegalCid);
901 if (class_ids[i] == class_id) { 592 if (class_ids[i] == class_id) {
902 return true; 593 return true;
903 } 594 }
904 } 595 }
905 return false; 596 return false;
906 } 597 }
(...skipping 2807 matching lines...) Expand 10 before | Expand all | Expand 10 after
3714 } 3405 }
3715 3406
3716 // Discard the environment from the original instruction because the store 3407 // Discard the environment from the original instruction because the store
3717 // can't deoptimize. 3408 // can't deoptimize.
3718 instr->RemoveEnvironment(); 3409 instr->RemoveEnvironment();
3719 ReplaceCall(instr, store); 3410 ReplaceCall(instr, store);
3720 return true; 3411 return true;
3721 } 3412 }
3722 3413
3723 3414
3724 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32)
3725 // Smi widening pass is only meaningful on platforms where Smi
3726 // is smaller than 32bit. For now only support it on ARM and ia32.
3727 static bool CanBeWidened(BinarySmiOpInstr* smi_op) {
3728 return BinaryInt32OpInstr::IsSupported(smi_op->op_kind(),
3729 smi_op->left(),
3730 smi_op->right());
3731 }
3732
3733
3734 static bool BenefitsFromWidening(BinarySmiOpInstr* smi_op) {
3735 // TODO(vegorov): when shifts with non-constants shift count are supported
3736 // add them here as we save untagging for the count.
3737 switch (smi_op->op_kind()) {
3738 case Token::kMUL:
3739 case Token::kSHR:
3740 // For kMUL we save untagging of the argument for kSHR
3741 // we save tagging of the result.
3742 return true;
3743
3744 default:
3745 return false;
3746 }
3747 }
3748
3749
3750 void FlowGraphOptimizer::WidenSmiToInt32() {
3751 GrowableArray<BinarySmiOpInstr*> candidates;
3752
3753 // Step 1. Collect all instructions that potentially benefit from widening of
3754 // their operands (or their result) into int32 range.
3755 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
3756 !block_it.Done();
3757 block_it.Advance()) {
3758 for (ForwardInstructionIterator instr_it(block_it.Current());
3759 !instr_it.Done();
3760 instr_it.Advance()) {
3761 BinarySmiOpInstr* smi_op = instr_it.Current()->AsBinarySmiOp();
3762 if ((smi_op != NULL) &&
3763 smi_op->HasSSATemp() &&
3764 BenefitsFromWidening(smi_op) &&
3765 CanBeWidened(smi_op)) {
3766 candidates.Add(smi_op);
3767 }
3768 }
3769 }
3770
3771 if (candidates.is_empty()) {
3772 return;
3773 }
3774
3775 // Step 2. For each block in the graph compute which loop it belongs to.
3776 // We will use this information later during computation of the widening's
3777 // gain: we are going to assume that only conversion occuring inside the
3778 // same loop should be counted against the gain, all other conversions
3779 // can be hoisted and thus cost nothing compared to the loop cost itself.
3780 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
3781 flow_graph()->LoopHeaders();
3782
3783 GrowableArray<intptr_t> loops(flow_graph_->preorder().length());
3784 for (intptr_t i = 0; i < flow_graph_->preorder().length(); i++) {
3785 loops.Add(-1);
3786 }
3787
3788 for (intptr_t loop_id = 0; loop_id < loop_headers.length(); ++loop_id) {
3789 for (BitVector::Iterator loop_it(loop_headers[loop_id]->loop_info());
3790 !loop_it.Done();
3791 loop_it.Advance()) {
3792 loops[loop_it.Current()] = loop_id;
3793 }
3794 }
3795
3796 // Step 3. For each candidate transitively collect all other BinarySmiOpInstr
3797 // and PhiInstr that depend on it and that it depends on and count amount of
3798 // untagging operations that we save in assumption that this whole graph of
3799 // values is using kUnboxedInt32 representation instead of kTagged.
3800 // Convert those graphs that have positive gain to kUnboxedInt32.
3801
3802 // BitVector containing SSA indexes of all processed definitions. Used to skip
3803 // those candidates that belong to dependency graph of another candidate.
3804 BitVector* processed =
3805 new(Z) BitVector(Z, flow_graph_->current_ssa_temp_index());
3806
3807 // Worklist used to collect dependency graph.
3808 DefinitionWorklist worklist(flow_graph_, candidates.length());
3809 for (intptr_t i = 0; i < candidates.length(); i++) {
3810 BinarySmiOpInstr* op = candidates[i];
3811 if (op->WasEliminated() || processed->Contains(op->ssa_temp_index())) {
3812 continue;
3813 }
3814
3815 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3816 THR_Print("analysing candidate: %s\n", op->ToCString());
3817 }
3818 worklist.Clear();
3819 worklist.Add(op);
3820
3821 // Collect dependency graph. Note: more items are added to worklist
3822 // inside this loop.
3823 intptr_t gain = 0;
3824 for (intptr_t j = 0; j < worklist.definitions().length(); j++) {
3825 Definition* defn = worklist.definitions()[j];
3826
3827 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3828 THR_Print("> %s\n", defn->ToCString());
3829 }
3830
3831 if (defn->IsBinarySmiOp() &&
3832 BenefitsFromWidening(defn->AsBinarySmiOp())) {
3833 gain++;
3834 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3835 THR_Print("^ [%" Pd "] (o) %s\n", gain, defn->ToCString());
3836 }
3837 }
3838
3839 const intptr_t defn_loop = loops[defn->GetBlock()->preorder_number()];
3840
3841 // Process all inputs.
3842 for (intptr_t k = 0; k < defn->InputCount(); k++) {
3843 Definition* input = defn->InputAt(k)->definition();
3844 if (input->IsBinarySmiOp() &&
3845 CanBeWidened(input->AsBinarySmiOp())) {
3846 worklist.Add(input);
3847 } else if (input->IsPhi() && (input->Type()->ToCid() == kSmiCid)) {
3848 worklist.Add(input);
3849 } else if (input->IsBinaryMintOp()) {
3850 // Mint operation produces untagged result. We avoid tagging.
3851 gain++;
3852 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3853 THR_Print("^ [%" Pd "] (i) %s\n", gain, input->ToCString());
3854 }
3855 } else if (defn_loop == loops[input->GetBlock()->preorder_number()] &&
3856 (input->Type()->ToCid() == kSmiCid)) {
3857 // Input comes from the same loop, is known to be smi and requires
3858 // untagging.
3859 // TODO(vegorov) this heuristic assumes that values that are not
3860 // known to be smi have to be checked and this check can be
3861 // coalesced with untagging. Start coalescing them.
3862 gain--;
3863 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3864 THR_Print("v [%" Pd "] (i) %s\n", gain, input->ToCString());
3865 }
3866 }
3867 }
3868
3869 // Process all uses.
3870 for (Value* use = defn->input_use_list();
3871 use != NULL;
3872 use = use->next_use()) {
3873 Instruction* instr = use->instruction();
3874 Definition* use_defn = instr->AsDefinition();
3875 if (use_defn == NULL) {
3876 // We assume that tagging before returning or pushing argument costs
3877 // very little compared to the cost of the return/call itself.
3878 if (!instr->IsReturn() && !instr->IsPushArgument()) {
3879 gain--;
3880 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3881 THR_Print("v [%" Pd "] (u) %s\n",
3882 gain,
3883 use->instruction()->ToCString());
3884 }
3885 }
3886 continue;
3887 } else if (use_defn->IsBinarySmiOp() &&
3888 CanBeWidened(use_defn->AsBinarySmiOp())) {
3889 worklist.Add(use_defn);
3890 } else if (use_defn->IsPhi() &&
3891 use_defn->AsPhi()->Type()->ToCid() == kSmiCid) {
3892 worklist.Add(use_defn);
3893 } else if (use_defn->IsBinaryMintOp()) {
3894 // BinaryMintOp requires untagging of its inputs.
3895 // Converting kUnboxedInt32 to kUnboxedMint is essentially zero cost
3896 // sign extension operation.
3897 gain++;
3898 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3899 THR_Print("^ [%" Pd "] (u) %s\n",
3900 gain,
3901 use->instruction()->ToCString());
3902 }
3903 } else if (defn_loop == loops[instr->GetBlock()->preorder_number()]) {
3904 gain--;
3905 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3906 THR_Print("v [%" Pd "] (u) %s\n",
3907 gain,
3908 use->instruction()->ToCString());
3909 }
3910 }
3911 }
3912 }
3913
3914 processed->AddAll(worklist.contains_vector());
3915
3916 if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
3917 THR_Print("~ %s gain %" Pd "\n", op->ToCString(), gain);
3918 }
3919
3920 if (gain > 0) {
3921 // We have positive gain from widening. Convert all BinarySmiOpInstr into
3922 // BinaryInt32OpInstr and set representation of all phis to kUnboxedInt32.
3923 for (intptr_t j = 0; j < worklist.definitions().length(); j++) {
3924 Definition* defn = worklist.definitions()[j];
3925 ASSERT(defn->IsPhi() || defn->IsBinarySmiOp());
3926
3927 if (defn->IsBinarySmiOp()) {
3928 BinarySmiOpInstr* smi_op = defn->AsBinarySmiOp();
3929 BinaryInt32OpInstr* int32_op = new(Z) BinaryInt32OpInstr(
3930 smi_op->op_kind(),
3931 smi_op->left()->CopyWithType(),
3932 smi_op->right()->CopyWithType(),
3933 smi_op->DeoptimizationTarget());
3934
3935 smi_op->ReplaceWith(int32_op, NULL);
3936 } else if (defn->IsPhi()) {
3937 defn->AsPhi()->set_representation(kUnboxedInt32);
3938 ASSERT(defn->Type()->IsInt());
3939 }
3940 }
3941 }
3942 }
3943 }
3944 #else
3945 void FlowGraphOptimizer::WidenSmiToInt32() {
3946 // TODO(vegorov) ideally on 64-bit platforms we would like to narrow smi
3947 // operations to 32-bit where it saves tagging and untagging and allows
3948 // to use shorted (and faster) instructions. But we currently don't
3949 // save enough range information in the ICData to drive this decision.
3950 }
3951 #endif
3952
3953
3954 void FlowGraphOptimizer::EliminateEnvironments() {
3955 // After this pass we can no longer perform LICM and hoist instructions
3956 // that can deoptimize.
3957
3958 flow_graph_->disallow_licm();
3959 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
3960 !block_it.Done();
3961 block_it.Advance()) {
3962 BlockEntryInstr* block = block_it.Current();
3963 block->RemoveEnvironment();
3964 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
3965 Instruction* current = it.Current();
3966 if (!current->CanDeoptimize()) {
3967 // TODO(srdjan): --source-lines needs deopt environments to get at
3968 // the code for this instruction, however, leaving the environment
3969 // changes code.
3970 current->RemoveEnvironment();
3971 }
3972 }
3973 }
3974 }
3975
3976
3977 } // namespace dart 3415 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/precompiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698