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

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

Issue 20468002: Allow equality operation on mixed double/smi arguments. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 5 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
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('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/cha.h" 8 #include "vm/cha.h"
9 #include "vm/dart_entry.h" 9 #include "vm/dart_entry.h"
10 #include "vm/flow_graph_builder.h" 10 #include "vm/flow_graph_builder.h"
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 // Returns false if the ICData contains anything other than the 4 combinations 596 // Returns false if the ICData contains anything other than the 4 combinations
597 // of Mint and Smi for the receiver and argument classes. 597 // of Mint and Smi for the receiver and argument classes.
598 static bool HasTwoMintOrSmi(const ICData& ic_data) { 598 static bool HasTwoMintOrSmi(const ICData& ic_data) {
599 GrowableArray<intptr_t> class_ids(2); 599 GrowableArray<intptr_t> class_ids(2);
600 class_ids.Add(kSmiCid); 600 class_ids.Add(kSmiCid);
601 class_ids.Add(kMintCid); 601 class_ids.Add(kMintCid);
602 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); 602 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
603 } 603 }
604 604
605 605
606 // Returns false if the ICData contains anything other than the 4 combinations
607 // of Double and Smi for the receiver and argument classes.
608 static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
609 GrowableArray<intptr_t> class_ids(2);
610 class_ids.Add(kSmiCid);
611 class_ids.Add(kDoubleCid);
612 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
613 }
614
615
606 static bool HasOnlyOneDouble(const ICData& ic_data) { 616 static bool HasOnlyOneDouble(const ICData& ic_data) {
607 return (ic_data.NumberOfChecks() == 1) 617 return (ic_data.NumberOfChecks() == 1)
608 && ic_data.HasReceiverClassId(kDoubleCid); 618 && ic_data.HasReceiverClassId(kDoubleCid);
609 } 619 }
610 620
611 621
612 static bool ShouldSpecializeForDouble(const ICData& ic_data) { 622 static bool ShouldSpecializeForDouble(const ICData& ic_data) {
613 // Unboxed double operation can't handle case of two smis. 623 // Unboxed double operation can't handle case of two smis.
614 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 624 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
615 return false; 625 return false;
(...skipping 2022 matching lines...) Expand 10 before | Expand all | Expand 10 after
2638 new Value(instr->ArgumentAt(1)), 2648 new Value(instr->ArgumentAt(1)),
2639 needs_store_barrier); 2649 needs_store_barrier);
2640 // Discard the environment from the original instruction because the store 2650 // Discard the environment from the original instruction because the store
2641 // can't deoptimize. 2651 // can't deoptimize.
2642 instr->RemoveEnvironment(); 2652 instr->RemoveEnvironment();
2643 ReplaceCall(instr, store); 2653 ReplaceCall(instr, store);
2644 return true; 2654 return true;
2645 } 2655 }
2646 2656
2647 2657
2658 static bool SmiFitsInDouble() { return kSmiBits < 53; }
2659
2660
2661 void FlowGraphOptimizer::HandleComparison(ComparisonInstr* comp,
2662 const ICData& ic_data,
2663 Instruction* current_instruction) {
2664 ASSERT(ic_data.num_args_tested() == 2);
2665 ASSERT(comp->operation_cid() == kIllegalCid);
2666 Instruction* instr = current_iterator()->Current();
2667 if (HasOnlyTwoSmis(ic_data)) {
2668 InsertBefore(instr,
2669 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
2670 instr->env(),
2671 Definition::kEffect);
2672 InsertBefore(instr,
2673 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
2674 instr->env(),
2675 Definition::kEffect);
2676 comp->set_operation_cid(kSmiCid);
2677 } else if (HasTwoMintOrSmi(ic_data) &&
2678 FlowGraphCompiler::SupportsUnboxedMints()) {
2679 comp->set_operation_cid(kMintCid);
2680 } else if (HasTwoDoubleOrSmi(ic_data)) {
2681 // Use double comparison.
2682 if (SmiFitsInDouble()) {
2683 comp->set_operation_cid(kDoubleCid);
2684 } else {
2685 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
2686 // We cannot use double comparison on two Smi-s.
2687 ASSERT(comp->operation_cid() == kIllegalCid);
2688 } else {
2689 InsertBefore(instr,
2690 new CheckEitherNonSmiInstr(comp->left()->Copy(),
2691 comp->right()->Copy(),
2692 comp->deopt_id()),
2693 instr->env(),
2694 Definition::kEffect);
2695 comp->set_operation_cid(kDoubleCid);
2696 }
2697 }
2698 } else {
2699 ASSERT(comp->operation_cid() == kIllegalCid);
2700 }
2701 }
2702
2703
2648 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) { 2704 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) {
2649 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { 2705 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
2650 return; 2706 return;
2651 } 2707 }
2652 const ICData& ic_data = *comp->ic_data(); 2708 HandleComparison(comp, *comp->ic_data(), current_iterator()->Current());
2653 Instruction* instr = current_iterator()->Current();
2654 if (ic_data.NumberOfChecks() == 1) {
2655 ASSERT(ic_data.HasOneTarget());
2656 if (HasOnlyTwoSmis(ic_data)) {
2657 InsertBefore(instr,
2658 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
2659 instr->env(),
2660 Definition::kEffect);
2661 InsertBefore(instr,
2662 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
2663 instr->env(),
2664 Definition::kEffect);
2665 comp->set_operands_class_id(kSmiCid);
2666 } else if (ShouldSpecializeForDouble(ic_data)) {
2667 comp->set_operands_class_id(kDoubleCid);
2668 } else if (HasTwoMintOrSmi(*comp->ic_data()) &&
2669 FlowGraphCompiler::SupportsUnboxedMints()) {
2670 comp->set_operands_class_id(kMintCid);
2671 } else {
2672 ASSERT(comp->operands_class_id() == kIllegalCid);
2673 }
2674 } else if (HasTwoMintOrSmi(*comp->ic_data()) &&
2675 FlowGraphCompiler::SupportsUnboxedMints()) {
2676 comp->set_operands_class_id(kMintCid);
2677 }
2678 } 2709 }
2679 2710
2680 2711
2681 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { 2712 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) {
2682 HandleRelationalOp(instr); 2713 HandleRelationalOp(instr);
2683 } 2714 }
2684 2715
2685 2716
2686 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( 2717 bool FlowGraphOptimizer::CanStrictifyEqualityCompare(
2687 EqualityCompareInstr* compare) { 2718 EqualityCompareInstr* compare) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
2751 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, 2782 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp,
2752 T current_instruction) { 2783 T current_instruction) {
2753 if (StrictifyEqualityCompare(comp, current_instruction)) { 2784 if (StrictifyEqualityCompare(comp, current_instruction)) {
2754 return; 2785 return;
2755 } 2786 }
2756 2787
2757 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { 2788 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
2758 return; 2789 return;
2759 } 2790 }
2760 2791
2761 ASSERT(comp->ic_data()->num_args_tested() == 2); 2792 const ICData& ic_data = *comp->ic_data();
2762 if (comp->ic_data()->NumberOfChecks() == 1) { 2793 HandleComparison(comp, ic_data, current_instruction);
2763 GrowableArray<intptr_t> class_ids;
2764 Function& target = Function::Handle();
2765 comp->ic_data()->GetCheckAt(0, &class_ids, &target);
2766 // TODO(srdjan): allow for mixed mode int/double comparison.
2767 2794
2768 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { 2795 if (comp->operation_cid() != kIllegalCid) {
2769 InsertBefore(current_instruction,
2770 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
2771 current_instruction->env(),
2772 Definition::kEffect);
2773 InsertBefore(current_instruction,
2774 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
2775 current_instruction->env(),
2776 Definition::kEffect);
2777 comp->set_receiver_class_id(kSmiCid);
2778 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) {
2779 comp->set_receiver_class_id(kDoubleCid);
2780 } else if (HasTwoMintOrSmi(*comp->ic_data()) &&
2781 FlowGraphCompiler::SupportsUnboxedMints()) {
2782 comp->set_receiver_class_id(kMintCid);
2783 } else {
2784 ASSERT(comp->receiver_class_id() == kIllegalCid);
2785 }
2786 } else if (HasTwoMintOrSmi(*comp->ic_data()) &&
2787 FlowGraphCompiler::SupportsUnboxedMints()) {
2788 comp->set_receiver_class_id(kMintCid);
2789 }
2790
2791 if (comp->receiver_class_id() != kIllegalCid) {
2792 // Done. 2796 // Done.
2793 return; 2797 return;
2794 } 2798 }
2795 2799
2796 // Check if ICDData contains checks with Smi/Null combinations. In that case 2800 // Check if ICDData contains checks with Smi/Null combinations. In that case
2797 // we can still emit the optimized Smi equality operation but need to add 2801 // we can still emit the optimized Smi equality operation but need to add
2798 // checks for null or Smi. 2802 // checks for null or Smi.
2799 // TODO(srdjan): Add it for Double and Mint. 2803 // TODO(srdjan): Add it for Double and Mint.
2800 GrowableArray<intptr_t> smi_or_null(2); 2804 GrowableArray<intptr_t> smi_or_null(2);
2801 smi_or_null.Add(kSmiCid); 2805 smi_or_null.Add(kSmiCid);
2802 smi_or_null.Add(kNullCid); 2806 smi_or_null.Add(kNullCid);
2803 if (ICDataHasOnlyReceiverArgumentClassIds(*comp->ic_data(), 2807 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data,
2804 smi_or_null, 2808 smi_or_null,
2805 smi_or_null)) { 2809 smi_or_null)) {
2806 const ICData& unary_checks_0 = 2810 const ICData& unary_checks_0 =
2807 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); 2811 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks());
2808 AddCheckClass(comp->left()->definition(), 2812 AddCheckClass(comp->left()->definition(),
2809 unary_checks_0, 2813 unary_checks_0,
2810 comp->deopt_id(), 2814 comp->deopt_id(),
2811 current_instruction->env(), 2815 current_instruction->env(),
2812 current_instruction); 2816 current_instruction);
2813 2817
2814 const ICData& unary_checks_1 = 2818 const ICData& unary_checks_1 =
2815 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); 2819 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1));
2816 AddCheckClass(comp->right()->definition(), 2820 AddCheckClass(comp->right()->definition(),
2817 unary_checks_1, 2821 unary_checks_1,
2818 comp->deopt_id(), 2822 comp->deopt_id(),
2819 current_instruction->env(), 2823 current_instruction->env(),
2820 current_instruction); 2824 current_instruction);
2821 comp->set_receiver_class_id(kSmiCid); 2825 comp->set_operation_cid(kSmiCid);
2822 } 2826 }
2823 } 2827 }
2824 2828
2825 2829
2826 2830
2827 2831
2828 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { 2832 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) {
2829 HandleEqualityCompare(instr, instr); 2833 HandleEqualityCompare(instr, instr);
2830 } 2834 }
2831 2835
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
3131 flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue); 3135 flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue);
3132 RenameDominatedUses(defn, constraint, constraint); 3136 RenameDominatedUses(defn, constraint, constraint);
3133 constraints_.Add(constraint); 3137 constraints_.Add(constraint);
3134 return constraint; 3138 return constraint;
3135 } 3139 }
3136 3140
3137 3141
3138 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { 3142 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) {
3139 BranchInstr* branch = use->instruction()->AsBranch(); 3143 BranchInstr* branch = use->instruction()->AsBranch();
3140 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); 3144 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp();
3141 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { 3145 if ((rel_op != NULL) && (rel_op->operation_cid() == kSmiCid)) {
3142 // Found comparison of two smis. Constrain defn at true and false 3146 // Found comparison of two smis. Constrain defn at true and false
3143 // successors using the other operand as a boundary. 3147 // successors using the other operand as a boundary.
3144 Definition* boundary; 3148 Definition* boundary;
3145 Token::Kind op_kind; 3149 Token::Kind op_kind;
3146 if (use->use_index() == 0) { // Left operand. 3150 if (use->use_index() == 0) { // Left operand.
3147 boundary = rel_op->InputAt(1)->definition(); 3151 boundary = rel_op->InputAt(1)->definition();
3148 op_kind = rel_op->kind(); 3152 op_kind = rel_op->kind();
3149 } else { 3153 } else {
3150 ASSERT(use->use_index() == 1); // Right operand. 3154 ASSERT(use->use_index() == 1); // Right operand.
3151 boundary = rel_op->InputAt(0)->definition(); 3155 boundary = rel_op->InputAt(0)->definition();
(...skipping 2622 matching lines...) Expand 10 before | Expand all | Expand 10 after
5774 5778
5775 5779
5776 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { 5780 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) {
5777 const Object& left = instr->left()->definition()->constant_value(); 5781 const Object& left = instr->left()->definition()->constant_value();
5778 const Object& right = instr->right()->definition()->constant_value(); 5782 const Object& right = instr->right()->definition()->constant_value();
5779 5783
5780 if (instr->left()->definition() == instr->right()->definition()) { 5784 if (instr->left()->definition() == instr->right()->definition()) {
5781 // Fold x == x, and x != x to true/false for numbers and checked strict 5785 // Fold x == x, and x != x to true/false for numbers and checked strict
5782 // comparisons. 5786 // comparisons.
5783 if (instr->IsCheckedStrictEqual() || 5787 if (instr->IsCheckedStrictEqual() ||
5784 RawObject::IsIntegerClassId(instr->receiver_class_id())) { 5788 RawObject::IsIntegerClassId(instr->operation_cid())) {
5785 return SetValue(instr, 5789 return SetValue(instr,
5786 (instr->kind() == Token::kEQ) 5790 (instr->kind() == Token::kEQ)
5787 ? Bool::True() 5791 ? Bool::True()
5788 : Bool::False()); 5792 : Bool::False());
5789 } 5793 }
5790 } 5794 }
5791 5795
5792 if (IsNonConstant(left) || IsNonConstant(right)) { 5796 if (IsNonConstant(left) || IsNonConstant(right)) {
5793 SetValue(instr, non_constant_); 5797 SetValue(instr, non_constant_);
5794 } else if (IsConstant(left) && IsConstant(right)) { 5798 } else if (IsConstant(left) && IsConstant(right)) {
(...skipping 1449 matching lines...) Expand 10 before | Expand all | Expand 10 after
7244 7248
7245 // Insert materializations at environment uses. 7249 // Insert materializations at environment uses.
7246 const Class& cls = Class::Handle(alloc->constructor().Owner()); 7250 const Class& cls = Class::Handle(alloc->constructor().Owner());
7247 for (intptr_t i = 0; i < exits.length(); i++) { 7251 for (intptr_t i = 0; i < exits.length(); i++) {
7248 CreateMaterializationAt(exits[i], alloc, cls, *fields); 7252 CreateMaterializationAt(exits[i], alloc, cls, *fields);
7249 } 7253 }
7250 } 7254 }
7251 7255
7252 7256
7253 } // namespace dart 7257 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698