OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
7 | 7 |
8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
9 | 9 |
10 #include "lib/error.h" | 10 #include "lib/error.h" |
(...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 | 547 |
548 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 548 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
549 const LocationSummary& locs, | 549 const LocationSummary& locs, |
550 Token::Kind kind, | 550 Token::Kind kind, |
551 BranchInstr* branch, | 551 BranchInstr* branch, |
552 intptr_t deopt_id, | 552 intptr_t deopt_id, |
553 intptr_t try_index) { | 553 intptr_t try_index) { |
554 Register left = locs.in(0).reg(); | 554 Register left = locs.in(0).reg(); |
555 Register right = locs.in(1).reg(); | 555 Register right = locs.in(1).reg(); |
556 const bool left_is_smi = (branch == NULL) ? | 556 const bool left_is_smi = (branch == NULL) ? |
557 false : (branch->left()->ResultCid() == kSmiCid); | 557 false : (branch->computation()->left()->ResultCid() == kSmiCid); |
558 const bool right_is_smi = (branch == NULL) ? | 558 const bool right_is_smi = (branch == NULL) ? |
559 false : (branch->right()->ResultCid() == kSmiCid); | 559 false : (branch->computation()->right()->ResultCid() == kSmiCid); |
| 560 // TODO(fschneider): Move smi smi checks outside this instruction. |
560 if (!left_is_smi || !right_is_smi) { | 561 if (!left_is_smi || !right_is_smi) { |
561 Register temp = locs.temp(0).reg(); | 562 Register temp = locs.temp(0).reg(); |
562 Label* deopt = compiler->AddDeoptStub(deopt_id, | 563 Label* deopt = compiler->AddDeoptStub(deopt_id, |
563 try_index, | 564 try_index, |
564 kDeoptSmiCompareSmi); | 565 kDeoptSmiCompareSmi); |
565 __ movq(temp, left); | 566 __ movq(temp, left); |
566 __ orq(temp, right); | 567 __ orq(temp, right); |
567 __ testq(temp, Immediate(kSmiTagMask)); | 568 __ testq(temp, Immediate(kSmiTagMask)); |
568 __ j(NOT_ZERO, deopt); | 569 __ j(NOT_ZERO, deopt); |
569 } | 570 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 compiler->EmitDoubleCompareBranch( | 623 compiler->EmitDoubleCompareBranch( |
623 true_condition, XMM0, XMM1, branch); | 624 true_condition, XMM0, XMM1, branch); |
624 } else { | 625 } else { |
625 compiler->EmitDoubleCompareBool( | 626 compiler->EmitDoubleCompareBool( |
626 true_condition, XMM0, XMM1, locs.out().reg()); | 627 true_condition, XMM0, XMM1, locs.out().reg()); |
627 } | 628 } |
628 } | 629 } |
629 | 630 |
630 | 631 |
631 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 632 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 633 ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE)); |
632 if (receiver_class_id() == kSmiCid) { | 634 if (receiver_class_id() == kSmiCid) { |
633 // Deoptimizes if both arguments not Smi. | 635 // Deoptimizes if both arguments not Smi. |
634 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. | 636 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. |
635 deopt_id(), try_index()); | 637 deopt_id(), try_index()); |
636 return; | 638 return; |
637 } | 639 } |
638 if (receiver_class_id() == kDoubleCid) { | 640 if (receiver_class_id() == kDoubleCid) { |
639 // Deoptimizes if both arguments are Smi, or if none is Double or Smi. | 641 // Deoptimizes if both arguments are Smi, or if none is Double or Smi. |
640 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. | 642 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. |
641 deopt_id(), try_index()); | 643 deopt_id(), try_index()); |
642 return; | 644 return; |
643 } | 645 } |
644 const bool is_checked_strict_equal = | 646 const bool is_checked_strict_equal = |
645 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); | 647 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
646 if (is_checked_strict_equal) { | 648 if (is_checked_strict_equal) { |
647 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL, | 649 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL, |
648 deopt_id(), try_index()); | 650 deopt_id(), try_index()); |
649 return; | 651 return; |
650 } | 652 } |
651 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 653 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
652 EmitGenericEqualityCompare(compiler, locs(), kind(), NULL, *ic_data(), | 654 EmitGenericEqualityCompare(compiler, locs(), kind(), NULL, *ic_data(), |
653 deopt_id(), token_pos(), try_index()); | 655 deopt_id(), token_pos(), try_index()); |
654 } else { | 656 return; |
655 Register left = locs()->in(0).reg(); | |
656 Register right = locs()->in(1).reg(); | |
657 __ pushq(left); | |
658 __ pushq(right); | |
659 EmitEqualityAsInstanceCall(compiler, | |
660 deopt_id(), | |
661 token_pos(), | |
662 try_index(), | |
663 kind(), | |
664 locs()); | |
665 ASSERT(locs()->out().reg() == RAX); | |
666 } | 657 } |
| 658 Register left = locs()->in(0).reg(); |
| 659 Register right = locs()->in(1).reg(); |
| 660 __ pushq(left); |
| 661 __ pushq(right); |
| 662 EmitEqualityAsInstanceCall(compiler, |
| 663 deopt_id(), |
| 664 token_pos(), |
| 665 try_index(), |
| 666 kind(), |
| 667 locs()); |
| 668 ASSERT(locs()->out().reg() == RAX); |
| 669 } |
| 670 |
| 671 |
| 672 void EqualityCompareComp::EmitBranchCode(FlowGraphCompiler* compiler, |
| 673 BranchInstr* branch) { |
| 674 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 675 if (receiver_class_id() == kSmiCid) { |
| 676 // Deoptimizes if both arguments not Smi. |
| 677 EmitSmiComparisonOp(compiler, *locs(), kind(), branch, |
| 678 deopt_id(), try_index()); |
| 679 return; |
| 680 } |
| 681 if (receiver_class_id() == kDoubleCid) { |
| 682 // Deoptimizes if both arguments are Smi, or if none is Double or Smi. |
| 683 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch, |
| 684 deopt_id(), try_index()); |
| 685 return; |
| 686 } |
| 687 const bool is_checked_strict_equal = |
| 688 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 689 if (is_checked_strict_equal) { |
| 690 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch, |
| 691 deopt_id(), try_index()); |
| 692 return; |
| 693 } |
| 694 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 695 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(), |
| 696 deopt_id(), token_pos(), try_index()); |
| 697 return; |
| 698 } |
| 699 Register left = locs()->in(0).reg(); |
| 700 Register right = locs()->in(1).reg(); |
| 701 __ pushq(left); |
| 702 __ pushq(right); |
| 703 EmitEqualityAsInstanceCall(compiler, |
| 704 deopt_id(), |
| 705 token_pos(), |
| 706 try_index(), |
| 707 Token::kEQ, // kNE reverse occurs at branch. |
| 708 locs()); |
| 709 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; |
| 710 __ CompareObject(RAX, compiler->bool_true()); |
| 711 branch->EmitBranchOnCondition(compiler, branch_condition); |
667 } | 712 } |
668 | 713 |
669 | 714 |
670 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 715 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
671 const intptr_t kNumInputs = 2; | 716 const intptr_t kNumInputs = 2; |
672 if (operands_class_id() == kSmiCid || operands_class_id() == kDoubleCid) { | 717 if (operands_class_id() == kSmiCid || operands_class_id() == kDoubleCid) { |
673 const intptr_t kNumTemps = 1; | 718 const intptr_t kNumTemps = 1; |
674 LocationSummary* summary = | 719 LocationSummary* summary = |
675 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 720 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
676 summary->set_in(0, Location::RequiresRegister()); | 721 summary->set_in(0, Location::RequiresRegister()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 const intptr_t kNumArguments = 2; | 771 const intptr_t kNumArguments = 2; |
727 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()), | 772 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()), |
728 RDI, // Class id register. | 773 RDI, // Class id register. |
729 kNumArguments, | 774 kNumArguments, |
730 Array::Handle(), // No named arguments. | 775 Array::Handle(), // No named arguments. |
731 deopt, // Deoptimize target. | 776 deopt, // Deoptimize target. |
732 deopt_id(), | 777 deopt_id(), |
733 token_pos(), | 778 token_pos(), |
734 try_index(), | 779 try_index(), |
735 locs()); | 780 locs()); |
736 ASSERT(locs()->out().reg() == RAX); | |
737 return; | 781 return; |
738 } | 782 } |
739 const String& function_name = | 783 const String& function_name = |
740 String::ZoneHandle(Symbols::New(Token::Str(kind()))); | 784 String::ZoneHandle(Symbols::New(Token::Str(kind()))); |
741 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 785 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
742 deopt_id(), | 786 deopt_id(), |
743 token_pos(), | 787 token_pos(), |
744 try_index()); | 788 try_index()); |
745 const intptr_t kNumArguments = 2; | 789 const intptr_t kNumArguments = 2; |
746 const intptr_t kNumArgsChecked = 2; // Type-feedback. | 790 const intptr_t kNumArgsChecked = 2; // Type-feedback. |
747 compiler->GenerateInstanceCall(deopt_id(), | 791 compiler->GenerateInstanceCall(deopt_id(), |
748 token_pos(), | 792 token_pos(), |
749 try_index(), | 793 try_index(), |
750 function_name, | 794 function_name, |
751 kNumArguments, | 795 kNumArguments, |
752 Array::ZoneHandle(), // No optional arguments. | 796 Array::ZoneHandle(), // No optional arguments. |
753 kNumArgsChecked, | 797 kNumArgsChecked, |
754 locs()); | 798 locs()); |
755 ASSERT(locs()->out().reg() == RAX); | 799 } |
| 800 |
| 801 |
| 802 void RelationalOpComp::EmitBranchCode(FlowGraphCompiler* compiler, |
| 803 BranchInstr* branch) { |
| 804 if (operands_class_id() == kSmiCid) { |
| 805 EmitSmiComparisonOp(compiler, *locs(), kind(), branch, |
| 806 deopt_id(), try_index()); |
| 807 return; |
| 808 } |
| 809 if (operands_class_id() == kDoubleCid) { |
| 810 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch, |
| 811 deopt_id(), try_index()); |
| 812 return; |
| 813 } |
| 814 EmitNativeCode(compiler); |
| 815 __ CompareObject(RAX, compiler->bool_true()); |
| 816 branch->EmitBranchOnCondition(compiler, EQUAL); |
756 } | 817 } |
757 | 818 |
758 | 819 |
759 LocationSummary* NativeCallComp::MakeLocationSummary() const { | 820 LocationSummary* NativeCallComp::MakeLocationSummary() const { |
760 const intptr_t kNumInputs = 0; | 821 const intptr_t kNumInputs = 0; |
761 const intptr_t kNumTemps = 3; | 822 const intptr_t kNumTemps = 3; |
762 LocationSummary* locs = | 823 LocationSummary* locs = |
763 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 824 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
764 locs->set_temp(0, Location::RegisterLocation(RAX)); | 825 locs->set_temp(0, Location::RegisterLocation(RAX)); |
765 locs->set_temp(1, Location::RegisterLocation(RBX)); | 826 locs->set_temp(1, Location::RegisterLocation(RBX)); |
(...skipping 1368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2134 instance_call()->ArgumentCount(), | 2195 instance_call()->ArgumentCount(), |
2135 instance_call()->argument_names(), | 2196 instance_call()->argument_names(), |
2136 deopt, | 2197 deopt, |
2137 instance_call()->deopt_id(), | 2198 instance_call()->deopt_id(), |
2138 instance_call()->token_pos(), | 2199 instance_call()->token_pos(), |
2139 instance_call()->try_index(), | 2200 instance_call()->try_index(), |
2140 locs()); | 2201 locs()); |
2141 } | 2202 } |
2142 | 2203 |
2143 | 2204 |
2144 // TODO(srdjan): Move to shared. | |
2145 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { | |
2146 if (ic_data.num_args_tested() != 2) return false; | |
2147 if (ic_data.NumberOfChecks() != 1) return false; | |
2148 Function& target = Function::Handle(); | |
2149 GrowableArray<intptr_t> class_ids; | |
2150 ic_data.GetCheckAt(0, &class_ids, &target); | |
2151 return (class_ids[0] == class_id) && (class_ids[1] == class_id); | |
2152 } | |
2153 | |
2154 | |
2155 static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) { | |
2156 if ((kind == Token::kEQ) || (kind == Token::kNE)) { | |
2157 return ic_data.AllTargetsHaveSameOwner(kInstanceCid); | |
2158 } | |
2159 return false; | |
2160 } | |
2161 | |
2162 | |
2163 LocationSummary* BranchInstr::MakeLocationSummary() const { | |
2164 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | |
2165 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) || | |
2166 ICDataWithBothClassIds(*ic_data(), kDoubleCid) || | |
2167 IsCheckedStrictEquals(*ic_data(), kind())) { | |
2168 const intptr_t kNumInputs = 2; | |
2169 const intptr_t kNumTemps = 1; | |
2170 LocationSummary* summary = | |
2171 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
2172 summary->set_in(0, Location::RequiresRegister()); | |
2173 summary->set_in(1, Location::RequiresRegister()); | |
2174 summary->set_temp(0, Location::RequiresRegister()); | |
2175 return summary; | |
2176 } | |
2177 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | |
2178 const intptr_t kNumInputs = 2; | |
2179 const intptr_t kNumTemps = 1; | |
2180 LocationSummary* locs = | |
2181 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | |
2182 locs->set_in(0, Location::RegisterLocation(RAX)); | |
2183 locs->set_in(1, Location::RegisterLocation(RCX)); | |
2184 locs->set_temp(0, Location::RegisterLocation(RDX)); | |
2185 return locs; | |
2186 } | |
2187 // Otherwise polymorphic dispatch. | |
2188 } | |
2189 // Call. | |
2190 const intptr_t kNumInputs = 2; | |
2191 const intptr_t kNumTemps = 0; | |
2192 LocationSummary* locs = | |
2193 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | |
2194 locs->set_in(0, Location::RegisterLocation(RAX)); | |
2195 locs->set_in(1, Location::RegisterLocation(RCX)); | |
2196 return locs; | |
2197 } | |
2198 | |
2199 | |
2200 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2205 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2201 // Relational or equality. | 2206 computation()->EmitBranchCode(compiler, this); |
2202 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | |
2203 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) { | |
2204 EmitSmiComparisonOp(compiler, *locs(), kind(), this, | |
2205 deopt_id(), try_index()); | |
2206 return; | |
2207 } | |
2208 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { | |
2209 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, | |
2210 deopt_id(), try_index()); | |
2211 return; | |
2212 } | |
2213 if (IsCheckedStrictEquals(*ic_data(), kind())) { | |
2214 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this, | |
2215 deopt_id(), try_index()); | |
2216 return; | |
2217 } | |
2218 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. | |
2219 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | |
2220 EmitGenericEqualityCompare(compiler, locs(), kind(), this, *ic_data(), | |
2221 deopt_id(), token_pos(), try_index()); | |
2222 return; | |
2223 } | |
2224 // Otherwise polymorphic dispatch? | |
2225 } | |
2226 Register left = locs()->in(0).reg(); | |
2227 Register right = locs()->in(1).reg(); | |
2228 __ pushq(left); | |
2229 __ pushq(right); | |
2230 if ((kind() == Token::kNE) || (kind() == Token::kEQ)) { | |
2231 EmitEqualityAsInstanceCall(compiler, | |
2232 deopt_id(), | |
2233 token_pos(), | |
2234 try_index(), | |
2235 Token::kEQ, // kNE reverse occurs at branch. | |
2236 locs()); | |
2237 } else { | |
2238 const String& function_name = | |
2239 String::ZoneHandle(Symbols::New(Token::Str(kind()))); | |
2240 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | |
2241 deopt_id(), | |
2242 token_pos(), | |
2243 try_index()); | |
2244 const intptr_t kNumArguments = 2; | |
2245 const intptr_t kNumArgsChecked = 2; // Type-feedback. | |
2246 compiler->GenerateInstanceCall(deopt_id(), | |
2247 token_pos(), | |
2248 try_index(), | |
2249 function_name, | |
2250 kNumArguments, | |
2251 Array::ZoneHandle(), // No optional args. | |
2252 kNumArgsChecked, | |
2253 locs()); | |
2254 } | |
2255 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; | |
2256 __ CompareObject(RAX, compiler->bool_true()); | |
2257 EmitBranchOnCondition(compiler, branch_condition); | |
2258 } | |
2259 | |
2260 | |
2261 LocationSummary* StrictCompareAndBranchInstr::MakeLocationSummary() const { | |
2262 const int kNumInputs = 2; | |
2263 const int kNumTemps = 0; | |
2264 LocationSummary* locs = | |
2265 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
2266 locs->set_in(0, Location::RequiresRegister()); | |
2267 locs->set_in(1, Location::RequiresRegister()); | |
2268 return locs; | |
2269 } | |
2270 | |
2271 | |
2272 void StrictCompareAndBranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
2273 Register left = locs()->in(0).reg(); | |
2274 Register right = locs()->in(1).reg(); | |
2275 __ cmpq(left, right); | |
2276 Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; | |
2277 EmitBranchOnCondition(compiler, cond); | |
2278 } | 2207 } |
2279 | 2208 |
2280 | 2209 |
2281 LocationSummary* CheckClassComp::MakeLocationSummary() const { | 2210 LocationSummary* CheckClassComp::MakeLocationSummary() const { |
2282 const intptr_t kNumInputs = 1; | 2211 const intptr_t kNumInputs = 1; |
2283 const intptr_t kNumTemps = 1; | 2212 const intptr_t kNumTemps = 1; |
2284 LocationSummary* summary = | 2213 LocationSummary* summary = |
2285 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2214 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
2286 summary->set_in(0, Location::RequiresRegister()); | 2215 summary->set_in(0, Location::RequiresRegister()); |
2287 summary->set_temp(0, Location::RequiresRegister()); | 2216 summary->set_temp(0, Location::RequiresRegister()); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2367 } | 2296 } |
2368 __ j(ABOVE_EQUAL, deopt); | 2297 __ j(ABOVE_EQUAL, deopt); |
2369 } | 2298 } |
2370 | 2299 |
2371 | 2300 |
2372 } // namespace dart | 2301 } // namespace dart |
2373 | 2302 |
2374 #undef __ | 2303 #undef __ |
2375 | 2304 |
2376 #endif // defined TARGET_ARCH_X64 | 2305 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |