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

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

Issue 504143003: Support Int32 representation for selected binary operations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 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 | Annotate | Revision Log
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/cha.h" 8 #include "vm/cha.h"
9 #include "vm/cpu.h" 9 #include "vm/cpu.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 24 matching lines...) Expand all
35 " otherwise use megamorphic dispatch."); 35 " otherwise use megamorphic dispatch.");
36 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); 36 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis.");
37 DEFINE_FLAG(bool, trace_constant_propagation, false, 37 DEFINE_FLAG(bool, trace_constant_propagation, false,
38 "Print constant propagation and useless code elimination."); 38 "Print constant propagation and useless code elimination.");
39 DEFINE_FLAG(bool, trace_load_optimization, false, 39 DEFINE_FLAG(bool, trace_load_optimization, false,
40 "Print live sets for load optimization pass."); 40 "Print live sets for load optimization pass.");
41 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); 41 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details.");
42 DEFINE_FLAG(bool, truncating_left_shift, true, 42 DEFINE_FLAG(bool, truncating_left_shift, true,
43 "Optimize left shift to truncate if possible"); 43 "Optimize left shift to truncate if possible");
44 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); 44 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis.");
45 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32)
46 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass.");
47 #endif
45 DECLARE_FLAG(bool, enable_type_checks); 48 DECLARE_FLAG(bool, enable_type_checks);
46 DECLARE_FLAG(bool, source_lines); 49 DECLARE_FLAG(bool, source_lines);
47 DECLARE_FLAG(bool, trace_type_check_elimination); 50 DECLARE_FLAG(bool, trace_type_check_elimination);
48 DECLARE_FLAG(bool, warn_on_javascript_compatibility); 51 DECLARE_FLAG(bool, warn_on_javascript_compatibility);
49 52
50 // Quick access to the locally defined isolate() method. 53 // Quick access to the locally defined isolate() method.
51 #define I (isolate()) 54 #define I (isolate())
52 55
53 static bool ShouldInlineSimd() { 56 static bool ShouldInlineSimd() {
54 return FlowGraphCompiler::SupportsUnboxedSimd128(); 57 return FlowGraphCompiler::SupportsUnboxedSimd128();
(...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 ASSERT((replacement == NULL) || current->IsDefinition()); 577 ASSERT((replacement == NULL) || current->IsDefinition());
575 ReplaceCurrentInstruction(&it, current, replacement, flow_graph_); 578 ReplaceCurrentInstruction(&it, current, replacement, flow_graph_);
576 changed = true; 579 changed = true;
577 } 580 }
578 } 581 }
579 } 582 }
580 return changed; 583 return changed;
581 } 584 }
582 585
583 586
587 static bool IsUnboxedInteger(Representation rep) {
588 return (rep == kUnboxedInt32) ||
589 (rep == kUnboxedUint32) ||
590 (rep == kUnboxedMint);
591 }
592
593
584 void FlowGraphOptimizer::InsertConversion(Representation from, 594 void FlowGraphOptimizer::InsertConversion(Representation from,
585 Representation to, 595 Representation to,
586 Value* use, 596 Value* use,
587 bool is_environment_use) { 597 bool is_environment_use) {
588 Instruction* insert_before; 598 Instruction* insert_before;
589 Instruction* deopt_target; 599 Instruction* deopt_target;
590 PhiInstr* phi = use->instruction()->AsPhi(); 600 PhiInstr* phi = use->instruction()->AsPhi();
591 if (phi != NULL) { 601 if (phi != NULL) {
Florian Schneider 2014/08/27 09:36:51 Can you simplify the computation of deopt_target a
Vyacheslav Egorov (Google) 2014/08/27 11:45:37 Done.
592 ASSERT(phi->is_alive()); 602 ASSERT(phi->is_alive());
593 // For phis conversions have to be inserted in the predecessor. 603 // For phis conversions have to be inserted in the predecessor.
594 insert_before = 604 insert_before =
595 phi->block()->PredecessorAt(use->use_index())->last_instruction(); 605 phi->block()->PredecessorAt(use->use_index())->last_instruction();
596 deopt_target = NULL; 606 deopt_target = NULL;
597 } else { 607 } else {
598 deopt_target = insert_before = use->instruction(); 608 deopt_target = insert_before = use->instruction();
599 } 609 }
600 610
611 bool force_inherit_deopt_target = false;
612
601 Definition* converted = NULL; 613 Definition* converted = NULL;
602 if ((from == kTagged) && (to == kUnboxedMint)) { 614 if ((from == kTagged) && (to == kUnboxedMint)) {
603 ASSERT((deopt_target != NULL) || 615 ASSERT((deopt_target != NULL) ||
604 (use->Type()->ToCid() == kUnboxedMint)); 616 (use->Type()->ToCid() == kUnboxedMint));
605 const intptr_t deopt_id = (deopt_target != NULL) ? 617 const intptr_t deopt_id = (deopt_target != NULL) ?
606 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; 618 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
607 converted = new(I) UnboxIntegerInstr(use->CopyWithType(), deopt_id); 619 converted = new(I) UnboxIntegerInstr(use->CopyWithType(), deopt_id);
608 } else if ((from == kUnboxedMint) && (to == kTagged)) { 620 } else if ((from == kUnboxedMint) && (to == kTagged)) {
609 converted = new(I) BoxIntegerInstr(use->CopyWithType()); 621 converted = new(I) BoxIntegerInstr(use->CopyWithType());
610 } else if ((from == kUnboxedMint) && (to == kUnboxedUint32)) { 622 } else if (IsUnboxedInteger(from) && IsUnboxedInteger(to)) {
611 converted = new(I) UnboxedIntConverterInstr(from, to, use->CopyWithType()); 623 const intptr_t deopt_id = (to == kUnboxedInt32) && (deopt_target != NULL) ?
612 } else if ((from == kUnboxedUint32) && (to == kUnboxedMint)) { 624 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
613 converted = new(I) UnboxedIntConverterInstr(from, to, use->CopyWithType()); 625 force_inherit_deopt_target = (to == kUnboxedInt32) && (phi != NULL);
626 converted = new(I) UnboxedIntConverterInstr(from,
627 to,
628 use->CopyWithType(),
629 deopt_id);
630 } else if ((from == kUnboxedInt32) && (to == kUnboxedDouble)) {
631 converted = new Int32ToDoubleInstr(use->CopyWithType());
632 } else if ((from == kTagged) && (to == kUnboxedInt32)) {
633 const intptr_t deopt_id = (deopt_target != NULL) ?
634 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
635 force_inherit_deopt_target = (phi != NULL);
636 converted = new UnboxInt32Instr(use->CopyWithType(), deopt_id);
637 } else if ((from == kUnboxedInt32) && (to == kTagged)) {
638 converted = new BoxInt32Instr(use->CopyWithType());
614 } else if ((from == kTagged) && (to == kUnboxedUint32)) { 639 } else if ((from == kTagged) && (to == kUnboxedUint32)) {
615 const intptr_t deopt_id = (deopt_target != NULL) ? 640 const intptr_t deopt_id = (deopt_target != NULL) ?
616 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; 641 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
617 converted = new UnboxUint32Instr(use->CopyWithType(), deopt_id); 642 converted = new UnboxUint32Instr(use->CopyWithType(), deopt_id);
618 } else if (from == kUnboxedMint && to == kUnboxedDouble) { 643 } else if (from == kUnboxedMint && to == kUnboxedDouble) {
619 ASSERT(CanUnboxDouble()); 644 ASSERT(CanUnboxDouble());
620 // Convert by boxing/unboxing. 645 // Convert by boxing/unboxing.
621 // TODO(fschneider): Implement direct unboxed mint-to-double conversion. 646 // TODO(fschneider): Implement direct unboxed mint-to-double conversion.
622 BoxIntegerInstr* boxed = 647 BoxIntegerInstr* boxed =
623 new(I) BoxIntegerInstr(use->CopyWithType()); 648 new(I) BoxIntegerInstr(use->CopyWithType());
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
684 if (from == kUnboxedDouble) { 709 if (from == kUnboxedDouble) {
685 boxed = new(I) BoxDoubleInstr(use->CopyWithType()); 710 boxed = new(I) BoxDoubleInstr(use->CopyWithType());
686 } else if (from == kUnboxedInt32x4) { 711 } else if (from == kUnboxedInt32x4) {
687 boxed = new(I) BoxInt32x4Instr(use->CopyWithType()); 712 boxed = new(I) BoxInt32x4Instr(use->CopyWithType());
688 } else if (from == kUnboxedFloat32x4) { 713 } else if (from == kUnboxedFloat32x4) {
689 boxed = new(I) BoxFloat32x4Instr(use->CopyWithType()); 714 boxed = new(I) BoxFloat32x4Instr(use->CopyWithType());
690 } else if (from == kUnboxedMint) { 715 } else if (from == kUnboxedMint) {
691 boxed = new(I) BoxIntegerInstr(use->CopyWithType()); 716 boxed = new(I) BoxIntegerInstr(use->CopyWithType());
692 } else if (from == kUnboxedFloat64x2) { 717 } else if (from == kUnboxedFloat64x2) {
693 boxed = new(I) BoxFloat64x2Instr(use->CopyWithType()); 718 boxed = new(I) BoxFloat64x2Instr(use->CopyWithType());
719 } else if (from == kUnboxedInt32) {
720 boxed = new(I) BoxInt32Instr(use->CopyWithType());
721 } else if (from == kUnboxedUint32) {
722 boxed = new(I) BoxUint32Instr(use->CopyWithType());
694 } else { 723 } else {
695 UNIMPLEMENTED(); 724 UNIMPLEMENTED();
696 } 725 }
697 use->BindTo(boxed); 726 use->BindTo(boxed);
698 InsertBefore(insert_before, boxed, NULL, FlowGraph::kValue); 727 InsertBefore(insert_before, boxed, NULL, FlowGraph::kValue);
699 Value* to_value = new(I) Value(boxed); 728 Value* to_value = new(I) Value(boxed);
700 if (to == kUnboxedDouble) { 729 if (to == kUnboxedDouble) {
701 converted = new(I) UnboxDoubleInstr(to_value, deopt_id); 730 converted = new(I) UnboxDoubleInstr(to_value, deopt_id);
702 } else if (to == kUnboxedInt32x4) { 731 } else if (to == kUnboxedInt32x4) {
703 converted = new(I) UnboxInt32x4Instr(to_value, deopt_id); 732 converted = new(I) UnboxInt32x4Instr(to_value, deopt_id);
704 } else if (to == kUnboxedFloat32x4) { 733 } else if (to == kUnboxedFloat32x4) {
705 converted = new(I) UnboxFloat32x4Instr(to_value, deopt_id); 734 converted = new(I) UnboxFloat32x4Instr(to_value, deopt_id);
706 } else if (to == kUnboxedMint) { 735 } else if (to == kUnboxedMint) {
707 converted = new(I) UnboxIntegerInstr(to_value, deopt_id); 736 converted = new(I) UnboxIntegerInstr(to_value, deopt_id);
708 } else if (to == kUnboxedFloat64x2) { 737 } else if (to == kUnboxedFloat64x2) {
709 converted = new(I) UnboxFloat64x2Instr(to_value, deopt_id); 738 converted = new(I) UnboxFloat64x2Instr(to_value, deopt_id);
739 } else if (to == kUnboxedInt32) {
740 boxed = new(I) UnboxInt32Instr(use->CopyWithType(), deopt_id);
741 } else if (to == kUnboxedUint32) {
742 boxed = new(I) UnboxUint32Instr(use->CopyWithType(), deopt_id);
710 } else { 743 } else {
711 UNIMPLEMENTED(); 744 UNIMPLEMENTED();
712 } 745 }
713 } 746 }
714 ASSERT(converted != NULL); 747 ASSERT(converted != NULL);
715 InsertBefore(insert_before, converted, use->instruction()->env(), 748 InsertBefore(insert_before, converted, use->instruction()->env(),
716 FlowGraph::kValue); 749 FlowGraph::kValue);
717 if (is_environment_use) { 750 if (is_environment_use) {
718 use->BindToEnvironment(converted); 751 use->BindToEnvironment(converted);
719 } else { 752 } else {
720 use->BindTo(converted); 753 use->BindTo(converted);
721 } 754 }
755
756 if (force_inherit_deopt_target) {
757 flow_graph_->CopyDeoptTarget(converted, insert_before);
758 }
722 } 759 }
723 760
724 761
725 void FlowGraphOptimizer::ConvertUse(Value* use, Representation from_rep) { 762 void FlowGraphOptimizer::ConvertUse(Value* use, Representation from_rep) {
726 const Representation to_rep = 763 const Representation to_rep =
727 use->instruction()->RequiredInputRepresentation(use->use_index()); 764 use->instruction()->RequiredInputRepresentation(use->use_index());
728 if (from_rep == to_rep || to_rep == kNoRepresentation) { 765 if (from_rep == to_rep || to_rep == kNoRepresentation) {
729 return; 766 return;
730 } 767 }
731 InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/ false); 768 InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/ false);
(...skipping 26 matching lines...) Expand all
758 if (use->instruction()->MayThrow() && 795 if (use->instruction()->MayThrow() &&
759 use->instruction()->GetBlock()->InsideTryBlock()) { 796 use->instruction()->GetBlock()->InsideTryBlock()) {
760 // Environment uses at calls inside try-blocks must be converted to 797 // Environment uses at calls inside try-blocks must be converted to
761 // tagged representation. 798 // tagged representation.
762 ConvertEnvironmentUse(it.Current(), from_rep); 799 ConvertEnvironmentUse(it.Current(), from_rep);
763 } 800 }
764 } 801 }
765 } 802 }
766 803
767 804
768 // Returns true if phi's representation was changed. 805 static void UnboxPhi(PhiInstr* phi) {
769 static bool UnboxPhi(PhiInstr* phi) { 806 Representation unboxed = phi->representation();
770 Representation current = phi->representation();
771 Representation unboxed = current;
772 807
773 switch (phi->Type()->ToCid()) { 808 switch (phi->Type()->ToCid()) {
774 case kDoubleCid: 809 case kDoubleCid:
775 if (CanUnboxDouble()) { 810 if (CanUnboxDouble()) {
776 unboxed = kUnboxedDouble; 811 unboxed = kUnboxedDouble;
777 } 812 }
778 break; 813 break;
779 case kFloat32x4Cid: 814 case kFloat32x4Cid:
780 if (ShouldInlineSimd()) { 815 if (ShouldInlineSimd()) {
781 unboxed = kUnboxedFloat32x4; 816 unboxed = kUnboxedFloat32x4;
782 } 817 }
783 break; 818 break;
784 case kInt32x4Cid: 819 case kInt32x4Cid:
785 if (ShouldInlineSimd()) { 820 if (ShouldInlineSimd()) {
786 unboxed = kUnboxedInt32x4; 821 unboxed = kUnboxedInt32x4;
787 } 822 }
788 break; 823 break;
789 case kFloat64x2Cid: 824 case kFloat64x2Cid:
790 if (ShouldInlineSimd()) { 825 if (ShouldInlineSimd()) {
791 unboxed = kUnboxedFloat64x2; 826 unboxed = kUnboxedFloat64x2;
792 } 827 }
793 break; 828 break;
794 } 829 }
795 830
796 if (unboxed != current) { 831 phi->set_representation(unboxed);
797 phi->set_representation(unboxed);
798 return true;
799 }
800
801 return false;
802 } 832 }
803 833
804 834
805 void FlowGraphOptimizer::SelectRepresentations() { 835 void FlowGraphOptimizer::SelectRepresentations() {
806 // Conservatively unbox all phis that were proven to be of Double, 836 // Conservatively unbox all phis that were proven to be of Double,
807 // Float32x4, or Int32x4 type. 837 // Float32x4, or Int32x4 type.
808 for (intptr_t i = 0; i < block_order_.length(); ++i) { 838 for (intptr_t i = 0; i < block_order_.length(); ++i) {
809 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); 839 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry();
810 if (join_entry != NULL) { 840 if (join_entry != NULL) {
811 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { 841 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
(...skipping 3774 matching lines...) Expand 10 before | Expand all | Expand 10 after
4586 } 4616 }
4587 4617
4588 // Discard the environment from the original instruction because the store 4618 // Discard the environment from the original instruction because the store
4589 // can't deoptimize. 4619 // can't deoptimize.
4590 instr->RemoveEnvironment(); 4620 instr->RemoveEnvironment();
4591 ReplaceCall(instr, store); 4621 ReplaceCall(instr, store);
4592 return true; 4622 return true;
4593 } 4623 }
4594 4624
4595 4625
4626 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32)
4627 // Smi widening pass is only meaningful on platforms where Smi
4628 // is smaller than 32bit. For now only support it on ARM and ia32.
4629
4630 class DefinitionWorklist {
4631 public:
4632 DefinitionWorklist(FlowGraph* flow_graph,
4633 intptr_t initial_capacity)
4634 : defs_(initial_capacity),
4635 contains_(new BitVector(flow_graph->current_ssa_temp_index())) {
4636 }
4637
4638 void Add(Definition* defn) {
4639 if (!Contains(defn)) {
4640 defs_.Add(defn);
4641 contains_->Add(defn->ssa_temp_index());
4642 }
4643 }
4644
4645 bool Contains(Definition* defn) const {
4646 return (defn->ssa_temp_index() >= 0) &&
4647 contains_->Contains(defn->ssa_temp_index());
4648 }
4649
4650 const GrowableArray<Definition*>& definitions() const { return defs_; }
4651 BitVector* contains() const { return contains_; }
4652
4653 void Clear() {
4654 defs_.TruncateTo(0);
4655 contains_->Clear();
4656 }
4657
4658 private:
4659 GrowableArray<Definition*> defs_;
4660 BitVector* contains_;
4661 };
4662
4663
4664 static bool CanBeWidened(BinarySmiOpInstr* smi_op) {
4665 return BinaryInt32OpInstr::IsSupported(smi_op->op_kind(),
4666 smi_op->left(),
4667 smi_op->right());
4668 }
4669
4670
4671 static bool BenefitsFromWidening(BinarySmiOpInstr* smi_op) {
4672 switch (smi_op->op_kind()) {
4673 case Token::kMUL:
4674 case Token::kSHR:
4675 // For kMUL we save untagging of the argument for kSHR
4676 // we save tagging of the result.
4677 return true;
Florian Schneider 2014/08/27 09:36:51 For left and right shift we can save untagging of
Vyacheslav Egorov (Google) 2014/08/27 11:45:37 Done.
4678 default:
4679 return false;
4680 }
4681 }
4682
4683
4684 void FlowGraphOptimizer::WidenSmiToInt32() {
4685 GrowableArray<BinarySmiOpInstr*> candidates;
4686
4687 // Step 1. Collect all instructions that potentially benefit from widening of
4688 // their operands (or their result) into int32 range.
4689 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
4690 !block_it.Done();
4691 block_it.Advance()) {
4692 for (ForwardInstructionIterator instr_it(block_it.Current());
4693 !instr_it.Done();
4694 instr_it.Advance()) {
4695 BinarySmiOpInstr* smi_op = instr_it.Current()->AsBinarySmiOp();
4696 if (smi_op != NULL &&
4697 BenefitsFromWidening(smi_op) &&
4698 CanBeWidened(smi_op)) {
4699 candidates.Add(smi_op);
4700 }
4701 }
4702 }
4703
4704 if (candidates.length() == 0) {
4705 return;
4706 }
4707
4708 // Step 2. For each block in the graph compute which loop it belongs to.
4709 // We will use this information later during computation of the widening's
4710 // gain: we are going to assume that only conversion occuring inside the
4711 // same loop should be counted against the gain, all other conversions
4712 // can be hoisted and thus cost nothing compared to the loop cost itself.
4713 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
4714 flow_graph()->loop_headers();
4715
4716 GrowableArray<intptr_t> loops(flow_graph_->preorder().length());
4717 for (intptr_t i = 0; i < flow_graph_->preorder().length(); i++) {
4718 loops.Add(-1);
4719 }
4720
4721 for (intptr_t loop_id = 0; loop_id < loop_headers.length(); ++loop_id) {
4722 for (BitVector::Iterator loop_it(loop_headers[loop_id]->loop_info());
4723 !loop_it.Done();
4724 loop_it.Advance()) {
4725 loops[loop_it.Current()] = loop_id;
4726 }
4727 }
4728
4729 // Step 3. For each candidate transitively collect all other BinarySmiOpInstr
4730 // and PhiInstr that depend on it and that it depends on and count amount of
4731 // untagging opertaions that we save in assumption that this whole graph of
4732 // values is using kUnboxedInt32 representaion instead of kTagged.
Florian Schneider 2014/08/27 09:36:51 s/representaion/representation/
Vyacheslav Egorov (Google) 2014/08/27 11:45:37 Done.
4733 // Convert those graphs that have positive gain to kUnboxedInt32.
4734
4735 // BitVector containing SSA indexes of all processed definitions. Used to skip
4736 // those candidates that belong to dependency graph of another candidate.
4737 BitVector* processed = new BitVector(flow_graph_->current_ssa_temp_index());
4738
4739 // Worklist used to collect dependency graph.
4740 DefinitionWorklist worklist(flow_graph_, candidates.length());
4741 for (intptr_t i = 0; i < candidates.length(); i++) {
4742 BinarySmiOpInstr* op = candidates[i];
4743 if (op->WasEliminated() || processed->Contains(op->ssa_temp_index())) {
4744 continue;
4745 }
4746
4747 if (FLAG_trace_smi_widening) {
4748 OS::Print("analysing candidate: %s\n", op->ToCString());
4749 }
4750 worklist.Clear();
4751 worklist.Add(op);
4752
4753 // Collect dependency graph. Note: more items are added to worklist
4754 // inside this loop.
4755 intptr_t gain = 0;
4756 for (intptr_t j = 0; j < worklist.definitions().length(); j++) {
4757 Definition* defn = worklist.definitions()[j];
4758
4759 if (FLAG_trace_smi_widening) {
4760 OS::Print("> %s\n", defn->ToCString());
4761 }
4762
4763 if (defn->IsBinarySmiOp() &&
4764 BenefitsFromWidening(defn->AsBinarySmiOp())) {
4765 gain++;
4766 if (FLAG_trace_smi_widening) {
4767 OS::Print("^ [%d] (o) %s\n", gain, defn->ToCString());
4768 }
4769 }
4770
4771 const intptr_t defn_loop = loops[defn->GetBlock()->preorder_number()];
4772
4773 // Process all inputs.
4774 for (intptr_t k = 0; k < defn->InputCount(); k++) {
4775 Definition* input = defn->InputAt(k)->definition();
4776 if (input->IsBinarySmiOp() &&
4777 CanBeWidened(input->AsBinarySmiOp())) {
4778 worklist.Add(input);
4779 } else if (input->IsPhi() && input->Type()->ToCid() == kSmiCid) {
4780 worklist.Add(input);
4781 } else if (input->IsBinaryMintOp()) {
4782 // Mint operation produces untagged result. We avoid tagging.
4783 gain++;
4784 if (FLAG_trace_smi_widening) {
4785 OS::Print("^ [%d] (i) %s\n", gain, input->ToCString());
4786 }
4787 } else if (defn_loop == loops[input->GetBlock()->preorder_number()] &&
4788 (input->Type()->ToCid() == kSmiCid)) {
4789 // Input comes from the same loop, is known to be smi and requires
4790 // untagging.
4791 // TODO(vegorov) this heuristic assumes that values that are not
4792 // known to be smi have to be checked and this check can be
4793 // coalesced with untagging. Start coalescing them.
4794 gain--;
4795 if (FLAG_trace_smi_widening) {
4796 OS::Print("v [%d] (i) %s\n", gain, input->ToCString());
4797 }
4798 }
4799 }
4800
4801 // Process all uses.
4802 for (Value* use = defn->input_use_list();
4803 use != NULL;
4804 use = use->next_use()) {
4805 Instruction* instr = use->instruction();
4806 Definition* use_defn = instr->AsDefinition();
4807 if (use_defn == NULL) {
4808 // We assume that tagging before returning or pushing argument costs
4809 // very little compared to the cost of the return/call itself.
4810 if (!instr->IsReturn() && !instr->IsPushArgument()) {
4811 gain--;
4812 if (FLAG_trace_smi_widening) {
4813 OS::Print("v [%d] (u) %s\n",
4814 gain, use->instruction()->ToCString());
4815 }
4816 }
4817 continue;
4818 } else if (use_defn->IsBinarySmiOp() &&
4819 CanBeWidened(use_defn->AsBinarySmiOp())) {
4820 worklist.Add(use_defn);
4821 } else if (use_defn->IsPhi() &&
4822 use_defn->AsPhi()->Type()->ToCid() == kSmiCid) {
4823 worklist.Add(use_defn);
4824 } else if (use_defn->IsBinaryMintOp()) {
4825 // BinaryMintOp requires untagging of its inputs.
4826 // Converting kUnboxedInt32 to kUnboxedMint is essentially zero cost
4827 // sign extension operation.
4828 gain++;
4829 if (FLAG_trace_smi_widening) {
4830 OS::Print("^ [%d] (u) %s\n", gain, use->instruction()->ToCString());
4831 }
4832 } else if (defn_loop == loops[instr->GetBlock()->preorder_number()]) {
4833 gain--;
4834 if (FLAG_trace_smi_widening) {
4835 OS::Print("v [%d] (u) %s\n", gain, use->instruction()->ToCString());
4836 }
4837 }
4838 }
4839 }
4840
4841 processed->AddAll(worklist.contains());
4842
4843 if (FLAG_trace_smi_widening) {
4844 OS::Print("~ %s gain %d\n", op->ToCString(), gain);
4845 }
4846
4847 if (gain > 0) {
4848 // We have positive gain from widening. Convert all BinarySmiOpInstr into
4849 // BinaryInt32OpInstr and set representation of all phis to kUnboxedInt32.
4850 for (intptr_t j = 0; j < worklist.definitions().length(); j++) {
4851 Definition* defn = worklist.definitions()[j];
4852 ASSERT(defn->IsPhi() || defn->IsBinarySmiOp());
4853
4854 if (defn->IsBinarySmiOp()) {
4855 BinarySmiOpInstr* smi_op = defn->AsBinarySmiOp();
4856 BinaryInt32OpInstr* int32_op = new(I) BinaryInt32OpInstr(
4857 smi_op->op_kind(),
4858 smi_op->left()->CopyWithType(),
4859 smi_op->right()->CopyWithType(),
4860 smi_op->DeoptimizationTarget());
4861
4862 smi_op->ReplaceWith(int32_op, NULL);
4863 } else if (defn->IsPhi()) {
4864 defn->AsPhi()->set_representation(kUnboxedInt32);
4865 }
4866 }
4867 }
4868 }
4869 }
4870 #else
4871 void FlowGraphOptimizer::WidenSmiToInt32() {
4872 // TODO(vegorov) ideally on 64-bit platforms we would like to narrow smi
4873 // operations to 32-bit where it saves tagging and untagging and allows
4874 // to use shorted (and faster) instructions. But we currently don't
4875 // save enough range information in the ICData to drive this decision.
4876 }
4877 #endif
4878
4596 void FlowGraphOptimizer::InferIntRanges() { 4879 void FlowGraphOptimizer::InferIntRanges() {
4597 RangeAnalysis range_analysis(flow_graph_); 4880 RangeAnalysis range_analysis(flow_graph_);
4598 range_analysis.Analyze(); 4881 range_analysis.Analyze();
4599 } 4882 }
4600 4883
4601 4884
4602 void TryCatchAnalyzer::Optimize(FlowGraph* flow_graph) { 4885 void TryCatchAnalyzer::Optimize(FlowGraph* flow_graph) {
4603 // For every catch-block: Iterate over all call instructions inside the 4886 // For every catch-block: Iterate over all call instructions inside the
4604 // corresponding try-block and figure out for each environment value if it 4887 // corresponding try-block and figure out for each environment value if it
4605 // is the same constant at all calls. If yes, replace the initial definition 4888 // is the same constant at all calls. If yes, replace the initial definition
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
4693 // speculatively hoisting checks. 4976 // speculatively hoisting checks.
4694 if (FLAG_trace_optimization) { 4977 if (FLAG_trace_optimization) {
4695 OS::Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n", 4978 OS::Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n",
4696 current->DebugName(), 4979 current->DebugName(),
4697 current->GetDeoptId(), 4980 current->GetDeoptId(),
4698 current->GetBlock()->block_id(), 4981 current->GetBlock()->block_id(),
4699 pre_header->block_id()); 4982 pre_header->block_id());
4700 } 4983 }
4701 // Move the instruction out of the loop. 4984 // Move the instruction out of the loop.
4702 current->RemoveEnvironment(); 4985 current->RemoveEnvironment();
4703 it->RemoveCurrentFromGraph(); 4986 if (it != NULL) {
4987 it->RemoveCurrentFromGraph();
4988 } else {
4989 current->RemoveFromGraph();
4990 }
4704 GotoInstr* last = pre_header->last_instruction()->AsGoto(); 4991 GotoInstr* last = pre_header->last_instruction()->AsGoto();
4705 // Using kind kEffect will not assign a fresh ssa temporary index. 4992 // Using kind kEffect will not assign a fresh ssa temporary index.
4706 flow_graph()->InsertBefore(last, current, last->env(), FlowGraph::kEffect); 4993 flow_graph()->InsertBefore(last, current, last->env(), FlowGraph::kEffect);
4707 current->deopt_id_ = last->GetDeoptId(); 4994 current->deopt_id_ = last->GetDeoptId();
4708 } 4995 }
4709 4996
4710 4997
4711 void LICM::TryHoistCheckSmiThroughPhi(ForwardInstructionIterator* it, 4998 void LICM::TrySpecializeSmiPhi(PhiInstr* phi,
4712 BlockEntryInstr* header, 4999 BlockEntryInstr* header,
4713 BlockEntryInstr* pre_header, 5000 BlockEntryInstr* pre_header) {
4714 CheckSmiInstr* current) { 5001 if (phi->Type()->ToCid() == kSmiCid) {
4715 PhiInstr* phi = current->value()->definition()->AsPhi();
4716 if (!header->loop_info()->Contains(phi->block()->preorder_number())) {
4717 return; 5002 return;
4718 } 5003 }
4719 5004
4720 if (phi->Type()->ToCid() == kSmiCid) {
4721 it->RemoveCurrentFromGraph();
4722 return;
4723 }
4724
4725 // Check if there is only a single kDynamicCid input to the phi that 5005 // Check if there is only a single kDynamicCid input to the phi that
4726 // comes from the pre-header. 5006 // comes from the pre-header.
4727 const intptr_t kNotFound = -1; 5007 const intptr_t kNotFound = -1;
4728 intptr_t non_smi_input = kNotFound; 5008 intptr_t non_smi_input = kNotFound;
4729 for (intptr_t i = 0; i < phi->InputCount(); ++i) { 5009 for (intptr_t i = 0; i < phi->InputCount(); ++i) {
4730 Value* input = phi->InputAt(i); 5010 Value* input = phi->InputAt(i);
4731 if (input->Type()->ToCid() != kSmiCid) { 5011 if (input->Type()->ToCid() != kSmiCid) {
4732 if ((non_smi_input != kNotFound) || 5012 if ((non_smi_input != kNotFound) ||
4733 (input->Type()->ToCid() != kDynamicCid)) { 5013 (input->Type()->ToCid() != kDynamicCid)) {
4734 // There are multiple kDynamicCid inputs or there is an input that is 5014 // There are multiple kDynamicCid inputs or there is an input that is
4735 // known to be non-smi. 5015 // known to be non-smi.
4736 return; 5016 return;
4737 } else { 5017 } else {
4738 non_smi_input = i; 5018 non_smi_input = i;
4739 } 5019 }
4740 } 5020 }
4741 } 5021 }
4742 5022
4743 if ((non_smi_input == kNotFound) || 5023 if ((non_smi_input == kNotFound) ||
4744 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) { 5024 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) {
4745 return; 5025 return;
4746 } 5026 }
4747 5027
5028 CheckSmiInstr* check = NULL;
5029 for (Value* use = phi->input_use_list();
5030 (use != NULL) && (check == NULL);
5031 use = use->next_use()) {
5032 check = use->instruction()->AsCheckSmi();
5033 }
5034
5035 if (check == NULL) {
5036 return;
5037 }
5038
4748 // Host CheckSmi instruction and make this phi smi one. 5039 // Host CheckSmi instruction and make this phi smi one.
4749 Hoist(it, pre_header, current); 5040 Hoist(NULL, pre_header, check);
4750 5041
4751 // Replace value we are checking with phi's input. 5042 // Replace value we are checking with phi's input.
4752 current->value()->BindTo(phi->InputAt(non_smi_input)->definition()); 5043 check->value()->BindTo(phi->InputAt(non_smi_input)->definition());
4753 5044
4754 phi->UpdateType(CompileType::FromCid(kSmiCid)); 5045 phi->UpdateType(CompileType::FromCid(kSmiCid));
4755 } 5046 }
4756 5047
4757 5048
4758 // Load instructions handled by load elimination. 5049 // Load instructions handled by load elimination.
4759 static bool IsLoadEliminationCandidate(Instruction* instr) { 5050 static bool IsLoadEliminationCandidate(Instruction* instr) {
4760 return instr->IsLoadField() 5051 return instr->IsLoadField()
4761 || instr->IsLoadIndexed() 5052 || instr->IsLoadIndexed()
4762 || instr->IsLoadStaticField() 5053 || instr->IsLoadStaticField()
4763 || instr->IsCurrentContext(); 5054 || instr->IsCurrentContext();
4764 } 5055 }
4765 5056
4766 5057
4767 static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets, 5058 static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets,
4768 intptr_t loop_header_index, 5059 intptr_t loop_header_index,
4769 Instruction* instr) { 5060 Instruction* instr) {
4770 return IsLoadEliminationCandidate(instr) && 5061 return IsLoadEliminationCandidate(instr) &&
4771 (sets != NULL) && 5062 (sets != NULL) &&
4772 instr->HasPlaceId() && 5063 instr->HasPlaceId() &&
4773 ((*sets)[loop_header_index] != NULL) && 5064 ((*sets)[loop_header_index] != NULL) &&
4774 (*sets)[loop_header_index]->Contains(instr->place_id()); 5065 (*sets)[loop_header_index]->Contains(instr->place_id());
4775 } 5066 }
4776 5067
4777 5068
5069 void LICM::OptimisticallySpecializeSmiPhis() {
5070 if (!flow_graph()->parsed_function().function().
5071 allows_hoisting_check_class()) {
5072 // Do not hoist any.
5073 return;
5074 }
5075
5076 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
5077 flow_graph()->loop_headers();
5078
5079 for (intptr_t i = 0; i < loop_headers.length(); ++i) {
5080 JoinEntryInstr* header = loop_headers[i]->AsJoinEntry();
5081 // Skip loop that don't have a pre-header block.
5082 BlockEntryInstr* pre_header = FindPreHeader(header);
5083 if (pre_header == NULL) continue;
5084
5085 for (PhiIterator it(header); !it.Done(); it.Advance()) {
5086 TrySpecializeSmiPhi(it.Current(), header, pre_header);
5087 }
5088 }
5089 }
5090
5091
4778 void LICM::Optimize() { 5092 void LICM::Optimize() {
4779 if (!flow_graph()->parsed_function().function(). 5093 if (!flow_graph()->parsed_function().function().
4780 allows_hoisting_check_class()) { 5094 allows_hoisting_check_class()) {
4781 // Do not hoist any. 5095 // Do not hoist any.
4782 return; 5096 return;
4783 } 5097 }
4784 5098
4785 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = 5099 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
4786 flow_graph()->loop_headers(); 5100 flow_graph()->loop_headers();
4787 5101
(...skipping 26 matching lines...) Expand all
4814 inputs_loop_invariant = false; 5128 inputs_loop_invariant = false;
4815 break; 5129 break;
4816 } 5130 }
4817 } 5131 }
4818 if (inputs_loop_invariant && 5132 if (inputs_loop_invariant &&
4819 !current->IsAssertAssignable() && 5133 !current->IsAssertAssignable() &&
4820 !current->IsAssertBoolean()) { 5134 !current->IsAssertBoolean()) {
4821 // TODO(fschneider): Enable hoisting of Assert-instructions 5135 // TODO(fschneider): Enable hoisting of Assert-instructions
4822 // if it safe to do. 5136 // if it safe to do.
4823 Hoist(&it, pre_header, current); 5137 Hoist(&it, pre_header, current);
4824 } else if (current->IsCheckSmi() &&
4825 current->InputAt(0)->definition()->IsPhi()) {
4826 TryHoistCheckSmiThroughPhi(
4827 &it, header, pre_header, current->AsCheckSmi());
4828 } 5138 }
4829 } 5139 }
4830 } 5140 }
4831 } 5141 }
4832 } 5142 }
4833 } 5143 }
4834 5144
4835 5145
4836 // Place describes an abstract location (e.g. field) that IR can load 5146 // Place describes an abstract location (e.g. field) that IR can load
4837 // from or store to. 5147 // from or store to.
(...skipping 3092 matching lines...) Expand 10 before | Expand all | Expand 10 after
7930 ASSERT(!result.IsNull()); 8240 ASSERT(!result.IsNull());
7931 SetValue(defn, result); 8241 SetValue(defn, result);
7932 } 8242 }
7933 8243
7934 8244
7935 void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) { 8245 void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) {
7936 HandleBinaryOp(instr, instr->op_kind(), *instr->left(), *instr->right()); 8246 HandleBinaryOp(instr, instr->op_kind(), *instr->left(), *instr->right());
7937 } 8247 }
7938 8248
7939 8249
8250 void ConstantPropagator::VisitBinaryInt32Op(BinaryInt32OpInstr* instr) {
8251 HandleBinaryOp(instr, instr->op_kind(), *instr->left(), *instr->right());
8252 }
8253
8254
7940 void ConstantPropagator::VisitBoxInteger(BoxIntegerInstr* instr) { 8255 void ConstantPropagator::VisitBoxInteger(BoxIntegerInstr* instr) {
7941 // TODO(kmillikin): Handle box operation. 8256 // TODO(kmillikin): Handle box operation.
7942 SetValue(instr, non_constant_); 8257 SetValue(instr, non_constant_);
7943 } 8258 }
7944 8259
7945 8260
7946 void ConstantPropagator::VisitUnboxInteger(UnboxIntegerInstr* instr) { 8261 void ConstantPropagator::VisitUnboxInteger(UnboxIntegerInstr* instr) {
7947 // TODO(kmillikin): Handle unbox operation. 8262 // TODO(kmillikin): Handle unbox operation.
7948 SetValue(instr, non_constant_); 8263 SetValue(instr, non_constant_);
7949 } 8264 }
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
7991 const Object& value = instr->value()->definition()->constant_value(); 8306 const Object& value = instr->value()->definition()->constant_value();
7992 if (IsConstant(value) && value.IsInteger()) { 8307 if (IsConstant(value) && value.IsInteger()) {
7993 SetValue(instr, Double::Handle(I, 8308 SetValue(instr, Double::Handle(I,
7994 Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld))); 8309 Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
7995 } else if (IsNonConstant(value)) { 8310 } else if (IsNonConstant(value)) {
7996 SetValue(instr, non_constant_); 8311 SetValue(instr, non_constant_);
7997 } 8312 }
7998 } 8313 }
7999 8314
8000 8315
8316 void ConstantPropagator::VisitInt32ToDouble(Int32ToDoubleInstr* instr) {
8317 const Object& value = instr->value()->definition()->constant_value();
8318 if (IsConstant(value) && value.IsInteger()) {
8319 SetValue(instr, Double::Handle(I,
8320 Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
8321 } else if (IsNonConstant(value)) {
8322 SetValue(instr, non_constant_);
8323 }
8324 }
8325
8326
8001 void ConstantPropagator::VisitDoubleToInteger(DoubleToIntegerInstr* instr) { 8327 void ConstantPropagator::VisitDoubleToInteger(DoubleToIntegerInstr* instr) {
8002 // TODO(kmillikin): Handle conversion. 8328 // TODO(kmillikin): Handle conversion.
8003 SetValue(instr, non_constant_); 8329 SetValue(instr, non_constant_);
8004 } 8330 }
8005 8331
8006 8332
8007 void ConstantPropagator::VisitDoubleToSmi(DoubleToSmiInstr* instr) { 8333 void ConstantPropagator::VisitDoubleToSmi(DoubleToSmiInstr* instr) {
8008 // TODO(kmillikin): Handle conversion. 8334 // TODO(kmillikin): Handle conversion.
8009 SetValue(instr, non_constant_); 8335 SetValue(instr, non_constant_);
8010 } 8336 }
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after
8375 SetValue(instr, non_constant_); 8701 SetValue(instr, non_constant_);
8376 } 8702 }
8377 8703
8378 8704
8379 void ConstantPropagator::VisitUnboxUint32(UnboxUint32Instr* instr) { 8705 void ConstantPropagator::VisitUnboxUint32(UnboxUint32Instr* instr) {
8380 // TODO(kmillikin): Handle unbox operation. 8706 // TODO(kmillikin): Handle unbox operation.
8381 SetValue(instr, non_constant_); 8707 SetValue(instr, non_constant_);
8382 } 8708 }
8383 8709
8384 8710
8711 void ConstantPropagator::VisitBoxInt32(BoxInt32Instr* instr) {
8712 // TODO(kmillikin): Handle box operation.
8713 SetValue(instr, non_constant_);
8714 }
8715
8716
8717 void ConstantPropagator::VisitUnboxInt32(UnboxInt32Instr* instr) {
8718 // TODO(kmillikin): Handle unbox operation.
8719 SetValue(instr, non_constant_);
8720 }
8721
8722
8385 void ConstantPropagator::VisitUnboxedIntConverter( 8723 void ConstantPropagator::VisitUnboxedIntConverter(
8386 UnboxedIntConverterInstr* instr) { 8724 UnboxedIntConverterInstr* instr) {
8387 SetValue(instr, non_constant_); 8725 SetValue(instr, non_constant_);
8388 } 8726 }
8389 8727
8390 8728
8391 void ConstantPropagator::VisitBinaryUint32Op(BinaryUint32OpInstr* instr) { 8729 void ConstantPropagator::VisitBinaryUint32Op(BinaryUint32OpInstr* instr) {
8392 HandleBinaryOp(instr, instr->op_kind(), *instr->left(), *instr->right()); 8730 HandleBinaryOp(instr, instr->op_kind(), *instr->left(), *instr->right());
8393 TruncateInteger(instr, static_cast<int64_t>(0xFFFFFFFF)); 8731 TruncateInteger(instr, static_cast<int64_t>(0xFFFFFFFF));
8394 } 8732 }
(...skipping 1220 matching lines...) Expand 10 before | Expand all | Expand 10 after
9615 9953
9616 // Insert materializations at environment uses. 9954 // Insert materializations at environment uses.
9617 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { 9955 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) {
9618 CreateMaterializationAt( 9956 CreateMaterializationAt(
9619 exits_collector_.exits()[i], alloc, alloc->cls(), *slots); 9957 exits_collector_.exits()[i], alloc, alloc->cls(), *slots);
9620 } 9958 }
9621 } 9959 }
9622 9960
9623 9961
9624 } // namespace dart 9962 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698