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

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, 4 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 | « no previous file | 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
2648 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) { 2661 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) {
2649 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { 2662 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
2650 return; 2663 return;
2651 } 2664 }
2652 const ICData& ic_data = *comp->ic_data(); 2665 const ICData& ic_data = *comp->ic_data();
Cutch 2013/07/25 21:03:36 To match HandleEqualityCompare why don't you add:
srdjan 2013/07/25 22:17:02 Factored out code. Done.
2653 Instruction* instr = current_iterator()->Current(); 2666 Instruction* instr = current_iterator()->Current();
2654 if (ic_data.NumberOfChecks() == 1) { 2667 if (HasOnlyTwoSmis(ic_data)) {
2655 ASSERT(ic_data.HasOneTarget()); 2668 InsertBefore(instr,
2656 if (HasOnlyTwoSmis(ic_data)) { 2669 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
2657 InsertBefore(instr, 2670 instr->env(),
2658 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), 2671 Definition::kEffect);
2659 instr->env(), 2672 InsertBefore(instr,
2660 Definition::kEffect); 2673 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
2661 InsertBefore(instr, 2674 instr->env(),
2662 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), 2675 Definition::kEffect);
2663 instr->env(), 2676 comp->set_operation_cid(kSmiCid);
2664 Definition::kEffect); 2677 } else if (HasTwoMintOrSmi(ic_data) &&
2665 comp->set_operands_class_id(kSmiCid); 2678 FlowGraphCompiler::SupportsUnboxedMints()) {
2666 } else if (ShouldSpecializeForDouble(ic_data)) { 2679 comp->set_operation_cid(kMintCid);
2667 comp->set_operands_class_id(kDoubleCid); 2680 } else if (HasTwoDoubleOrSmi(ic_data)) {
2668 } else if (HasTwoMintOrSmi(*comp->ic_data()) && 2681 // Use double comparison.
2669 FlowGraphCompiler::SupportsUnboxedMints()) { 2682 if (SmiFitsInDouble()) {
2670 comp->set_operands_class_id(kMintCid); 2683 comp->set_operation_cid(kDoubleCid);
2671 } else { 2684 } else {
2672 ASSERT(comp->operands_class_id() == kIllegalCid); 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 }
2673 } 2697 }
2674 } else if (HasTwoMintOrSmi(*comp->ic_data()) && 2698 } else {
2675 FlowGraphCompiler::SupportsUnboxedMints()) { 2699 ASSERT(comp->operation_cid() == kIllegalCid);
2676 comp->set_operands_class_id(kMintCid);
2677 } 2700 }
2678 } 2701 }
2679 2702
2680 2703
2681 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { 2704 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) {
2682 HandleRelationalOp(instr); 2705 HandleRelationalOp(instr);
2683 } 2706 }
2684 2707
2685 2708
2686 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( 2709 bool FlowGraphOptimizer::CanStrictifyEqualityCompare(
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
2751 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, 2774 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp,
2752 T current_instruction) { 2775 T current_instruction) {
2753 if (StrictifyEqualityCompare(comp, current_instruction)) { 2776 if (StrictifyEqualityCompare(comp, current_instruction)) {
2754 return; 2777 return;
2755 } 2778 }
2756 2779
2757 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { 2780 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
2758 return; 2781 return;
2759 } 2782 }
2760 2783
2761 ASSERT(comp->ic_data()->num_args_tested() == 2); 2784 const ICData& ic_data = *comp->ic_data();
2762 if (comp->ic_data()->NumberOfChecks() == 1) { 2785 ASSERT(ic_data.num_args_tested() == 2);
Cutch 2013/07/25 21:03:36 Can this duplicate code in HandleEqualityCompare a
srdjan 2013/07/25 22:17:02 Done.
2763 GrowableArray<intptr_t> class_ids; 2786 ASSERT(comp->operation_cid() == kIllegalCid);
2764 Function& target = Function::Handle(); 2787 if (HasOnlyTwoSmis(ic_data)) {
2765 comp->ic_data()->GetCheckAt(0, &class_ids, &target); 2788 InsertBefore(current_instruction,
2766 // TODO(srdjan): allow for mixed mode int/double comparison. 2789 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
2767 2790 current_instruction->env(),
2768 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { 2791 Definition::kEffect);
2769 InsertBefore(current_instruction, 2792 InsertBefore(current_instruction,
2770 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), 2793 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
2771 current_instruction->env(), 2794 current_instruction->env(),
2772 Definition::kEffect); 2795 Definition::kEffect);
2773 InsertBefore(current_instruction, 2796 comp->set_operation_cid(kSmiCid);
2774 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), 2797 } else if (HasTwoMintOrSmi(ic_data) &&
2775 current_instruction->env(), 2798 FlowGraphCompiler::SupportsUnboxedMints()) {
2776 Definition::kEffect); 2799 comp->set_operation_cid(kMintCid);
2777 comp->set_receiver_class_id(kSmiCid); 2800 } else if (HasTwoDoubleOrSmi(ic_data)) {
2778 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { 2801 // Use double comparison.
2779 comp->set_receiver_class_id(kDoubleCid); 2802 if (SmiFitsInDouble()) {
2780 } else if (HasTwoMintOrSmi(*comp->ic_data()) && 2803 comp->set_operation_cid(kDoubleCid);
2781 FlowGraphCompiler::SupportsUnboxedMints()) {
2782 comp->set_receiver_class_id(kMintCid);
2783 } else { 2804 } else {
2784 ASSERT(comp->receiver_class_id() == kIllegalCid); 2805 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
2806 // We cannot use double comparison on two Smi-s.
2807 ASSERT(comp->operation_cid() == kIllegalCid);
2808 } else {
2809 InsertBefore(current_instruction,
2810 new CheckEitherNonSmiInstr(comp->left()->Copy(),
2811 comp->right()->Copy(),
2812 comp->deopt_id()),
2813 current_instruction->env(),
2814 Definition::kEffect);
2815 comp->set_operation_cid(kDoubleCid);
2816 }
2785 } 2817 }
2786 } else if (HasTwoMintOrSmi(*comp->ic_data()) && 2818 } else {
2787 FlowGraphCompiler::SupportsUnboxedMints()) { 2819 ASSERT(comp->operation_cid() == kIllegalCid);
2788 comp->set_receiver_class_id(kMintCid);
2789 } 2820 }
2790 2821
2791 if (comp->receiver_class_id() != kIllegalCid) { 2822 if (comp->operation_cid() != kIllegalCid) {
2792 // Done. 2823 // Done.
2793 return; 2824 return;
2794 } 2825 }
2795 2826
2796 // Check if ICDData contains checks with Smi/Null combinations. In that case 2827 // 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 2828 // we can still emit the optimized Smi equality operation but need to add
2798 // checks for null or Smi. 2829 // checks for null or Smi.
2799 // TODO(srdjan): Add it for Double and Mint. 2830 // TODO(srdjan): Add it for Double and Mint.
2800 GrowableArray<intptr_t> smi_or_null(2); 2831 GrowableArray<intptr_t> smi_or_null(2);
2801 smi_or_null.Add(kSmiCid); 2832 smi_or_null.Add(kSmiCid);
2802 smi_or_null.Add(kNullCid); 2833 smi_or_null.Add(kNullCid);
2803 if (ICDataHasOnlyReceiverArgumentClassIds(*comp->ic_data(), 2834 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data,
2804 smi_or_null, 2835 smi_or_null,
2805 smi_or_null)) { 2836 smi_or_null)) {
2806 const ICData& unary_checks_0 = 2837 const ICData& unary_checks_0 =
2807 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); 2838 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks());
2808 AddCheckClass(comp->left()->definition(), 2839 AddCheckClass(comp->left()->definition(),
2809 unary_checks_0, 2840 unary_checks_0,
2810 comp->deopt_id(), 2841 comp->deopt_id(),
2811 current_instruction->env(), 2842 current_instruction->env(),
2812 current_instruction); 2843 current_instruction);
2813 2844
2814 const ICData& unary_checks_1 = 2845 const ICData& unary_checks_1 =
2815 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); 2846 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1));
2816 AddCheckClass(comp->right()->definition(), 2847 AddCheckClass(comp->right()->definition(),
2817 unary_checks_1, 2848 unary_checks_1,
2818 comp->deopt_id(), 2849 comp->deopt_id(),
2819 current_instruction->env(), 2850 current_instruction->env(),
2820 current_instruction); 2851 current_instruction);
2821 comp->set_receiver_class_id(kSmiCid); 2852 comp->set_operation_cid(kSmiCid);
2822 } 2853 }
2823 } 2854 }
2824 2855
2825 2856
2826 2857
2827 2858
2828 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { 2859 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) {
2829 HandleEqualityCompare(instr, instr); 2860 HandleEqualityCompare(instr, instr);
2830 } 2861 }
2831 2862
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
3131 flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue); 3162 flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue);
3132 RenameDominatedUses(defn, constraint, constraint); 3163 RenameDominatedUses(defn, constraint, constraint);
3133 constraints_.Add(constraint); 3164 constraints_.Add(constraint);
3134 return constraint; 3165 return constraint;
3135 } 3166 }
3136 3167
3137 3168
3138 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { 3169 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) {
3139 BranchInstr* branch = use->instruction()->AsBranch(); 3170 BranchInstr* branch = use->instruction()->AsBranch();
3140 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); 3171 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp();
3141 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { 3172 if ((rel_op != NULL) && (rel_op->operation_cid() == kSmiCid)) {
3142 // Found comparison of two smis. Constrain defn at true and false 3173 // Found comparison of two smis. Constrain defn at true and false
3143 // successors using the other operand as a boundary. 3174 // successors using the other operand as a boundary.
3144 Definition* boundary; 3175 Definition* boundary;
3145 Token::Kind op_kind; 3176 Token::Kind op_kind;
3146 if (use->use_index() == 0) { // Left operand. 3177 if (use->use_index() == 0) { // Left operand.
3147 boundary = rel_op->InputAt(1)->definition(); 3178 boundary = rel_op->InputAt(1)->definition();
3148 op_kind = rel_op->kind(); 3179 op_kind = rel_op->kind();
3149 } else { 3180 } else {
3150 ASSERT(use->use_index() == 1); // Right operand. 3181 ASSERT(use->use_index() == 1); // Right operand.
3151 boundary = rel_op->InputAt(0)->definition(); 3182 boundary = rel_op->InputAt(0)->definition();
(...skipping 2622 matching lines...) Expand 10 before | Expand all | Expand 10 after
5774 5805
5775 5806
5776 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { 5807 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) {
5777 const Object& left = instr->left()->definition()->constant_value(); 5808 const Object& left = instr->left()->definition()->constant_value();
5778 const Object& right = instr->right()->definition()->constant_value(); 5809 const Object& right = instr->right()->definition()->constant_value();
5779 5810
5780 if (instr->left()->definition() == instr->right()->definition()) { 5811 if (instr->left()->definition() == instr->right()->definition()) {
5781 // Fold x == x, and x != x to true/false for numbers and checked strict 5812 // Fold x == x, and x != x to true/false for numbers and checked strict
5782 // comparisons. 5813 // comparisons.
5783 if (instr->IsCheckedStrictEqual() || 5814 if (instr->IsCheckedStrictEqual() ||
5784 RawObject::IsIntegerClassId(instr->receiver_class_id())) { 5815 RawObject::IsIntegerClassId(instr->operation_cid())) {
5785 return SetValue(instr, 5816 return SetValue(instr,
5786 (instr->kind() == Token::kEQ) 5817 (instr->kind() == Token::kEQ)
5787 ? Bool::True() 5818 ? Bool::True()
5788 : Bool::False()); 5819 : Bool::False());
5789 } 5820 }
5790 } 5821 }
5791 5822
5792 if (IsNonConstant(left) || IsNonConstant(right)) { 5823 if (IsNonConstant(left) || IsNonConstant(right)) {
5793 SetValue(instr, non_constant_); 5824 SetValue(instr, non_constant_);
5794 } else if (IsConstant(left) && IsConstant(right)) { 5825 } else if (IsConstant(left) && IsConstant(right)) {
(...skipping 1449 matching lines...) Expand 10 before | Expand all | Expand 10 after
7244 7275
7245 // Insert materializations at environment uses. 7276 // Insert materializations at environment uses.
7246 const Class& cls = Class::Handle(alloc->constructor().Owner()); 7277 const Class& cls = Class::Handle(alloc->constructor().Owner());
7247 for (intptr_t i = 0; i < exits.length(); i++) { 7278 for (intptr_t i = 0; i < exits.length(); i++) {
7248 CreateMaterializationAt(exits[i], alloc, cls, *fields); 7279 CreateMaterializationAt(exits[i], alloc, cls, *fields);
7249 } 7280 }
7250 } 7281 }
7251 7282
7252 7283
7253 } // namespace dart 7284 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698