Chromium Code Reviews| 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 732 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 ASSERT(!stacktrace_var().is_captured()); | 743 ASSERT(!stacktrace_var().is_captured()); |
| 744 __ movq(Address(RBP, exception_var().index() * kWordSize), | 744 __ movq(Address(RBP, exception_var().index() * kWordSize), |
| 745 kExceptionObjectReg); | 745 kExceptionObjectReg); |
| 746 __ movq(Address(RBP, stacktrace_var().index() * kWordSize), | 746 __ movq(Address(RBP, stacktrace_var().index() * kWordSize), |
| 747 kStackTraceObjectReg); | 747 kStackTraceObjectReg); |
| 748 } | 748 } |
| 749 | 749 |
| 750 | 750 |
| 751 LocationSummary* BinaryOpComp::MakeLocationSummary() const { | 751 LocationSummary* BinaryOpComp::MakeLocationSummary() const { |
| 752 const intptr_t kNumInputs = 2; | 752 const intptr_t kNumInputs = 2; |
| 753 | |
| 754 if (operands_type() == kDoubleOperands) { | |
| 755 const intptr_t kNumTemps = 1; | |
| 756 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | |
| 757 summary->set_in(0, Location::RequiresRegister()); | |
| 758 summary->set_in(1, Location::RequiresRegister()); | |
| 759 summary->set_out(Location::RegisterLocation(RAX)); | |
| 760 summary->set_temp(0, Location::RequiresRegister()); | |
| 761 return summary; | |
| 762 } | |
| 763 | |
| 764 ASSERT(operands_type() == kSmiOperands); | |
| 765 | |
| 753 if (op_kind() == Token::kTRUNCDIV) { | 766 if (op_kind() == Token::kTRUNCDIV) { |
| 754 const intptr_t kNumTemps = 3; | 767 const intptr_t kNumTemps = 3; |
| 755 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 768 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 756 summary->set_in(0, Location::RegisterLocation(RAX)); | 769 summary->set_in(0, Location::RegisterLocation(RAX)); |
| 757 summary->set_in(1, Location::RegisterLocation(RCX)); | 770 summary->set_in(1, Location::RegisterLocation(RCX)); |
| 758 summary->set_out(Location::SameAsFirstInput()); | 771 summary->set_out(Location::SameAsFirstInput()); |
| 759 summary->set_temp(0, Location::RegisterLocation(RBX)); | 772 summary->set_temp(0, Location::RegisterLocation(RBX)); |
| 760 // Will be used for for sign extension. | 773 // Will be used for for sign extension. |
| 761 summary->set_temp(1, Location::RegisterLocation(RDX)); | 774 summary->set_temp(1, Location::RegisterLocation(RDX)); |
| 762 summary->set_temp(2, Location::RequiresRegister()); | 775 summary->set_temp(2, Location::RequiresRegister()); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 784 summary->set_in(0, Location::RequiresRegister()); | 797 summary->set_in(0, Location::RequiresRegister()); |
| 785 summary->set_in(1, Location::RequiresRegister()); | 798 summary->set_in(1, Location::RequiresRegister()); |
| 786 summary->set_out(Location::SameAsFirstInput()); | 799 summary->set_out(Location::SameAsFirstInput()); |
| 787 summary->set_temp(0, Location::RequiresRegister()); | 800 summary->set_temp(0, Location::RequiresRegister()); |
| 788 return summary; | 801 return summary; |
| 789 } | 802 } |
| 790 } | 803 } |
| 791 | 804 |
| 792 | 805 |
| 793 // TODO(srdjan): Implement variations. | 806 // TODO(srdjan): Implement variations. |
| 794 static bool TryEmitSmiBinaryOp(FlowGraphCompiler* compiler, | 807 static void EmitSmiBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) { |
| 795 BinaryOpComp* comp) { | |
| 796 ASSERT((comp->ic_data() != NULL)); | |
| 797 const ICData& ic_data = *comp->ic_data(); | |
| 798 if (ic_data.IsNull()) return false; | |
| 799 if (ic_data.num_args_tested() != 2) return false; | |
| 800 if (ic_data.NumberOfChecks() != 1) return false; | |
| 801 Function& target = Function::Handle(); | |
| 802 GrowableArray<const Class*> classes; | |
| 803 ic_data.GetCheckAt(0, &classes, &target); | |
| 804 const Class& smi_class = | |
| 805 Class::Handle(Isolate::Current()->object_store()->smi_class()); | |
| 806 if ((classes[0]->raw() != smi_class.raw()) || | |
| 807 (classes[1]->raw() != smi_class.raw())) { | |
| 808 return false; | |
| 809 } | |
| 810 // TODO(srdjan): need to allocate a temporary register (now using r10) | 808 // TODO(srdjan): need to allocate a temporary register (now using r10) |
| 811 Register left = comp->locs()->in(0).reg(); | 809 Register left = comp->locs()->in(0).reg(); |
| 812 Register right = comp->locs()->in(1).reg(); | 810 Register right = comp->locs()->in(1).reg(); |
| 813 Register result = comp->locs()->out().reg(); | 811 Register result = comp->locs()->out().reg(); |
| 814 Register temp = comp->locs()->temp(0).reg(); | 812 Register temp = comp->locs()->temp(0).reg(); |
| 815 ASSERT(left == result); | 813 ASSERT(left == result); |
| 816 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), | 814 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), |
| 817 comp->instance_call()->token_index(), | 815 comp->instance_call()->token_index(), |
| 818 comp->instance_call()->try_index(), | 816 comp->instance_call()->try_index(), |
| 819 kDeoptSmiBinaryOp, | 817 kDeoptSmiBinaryOp, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 875 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 873 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 876 // case we cannot tag the result. | 874 // case we cannot tag the result. |
| 877 __ cmpq(result, Immediate(0x4000000000000000)); | 875 __ cmpq(result, Immediate(0x4000000000000000)); |
| 878 __ j(EQUAL, deopt); | 876 __ j(EQUAL, deopt); |
| 879 __ SmiTag(result); | 877 __ SmiTag(result); |
| 880 break; | 878 break; |
| 881 } | 879 } |
| 882 case Token::kDIV: { | 880 case Token::kDIV: { |
| 883 // Dispatches to 'Double./'. | 881 // Dispatches to 'Double./'. |
| 884 // TODO(srdjan): Implement as conversion to double and double division. | 882 // TODO(srdjan): Implement as conversion to double and double division. |
| 885 return false; | 883 UNREACHABLE(); |
| 884 return; | |
|
Mads Ager (google)
2012/06/08 09:15:53
Why 'return' here and 'break' below?
Vyacheslav Egorov (Google)
2012/06/08 11:11:13
Done.
| |
| 886 } | 885 } |
| 887 case Token::kMOD: { | 886 case Token::kMOD: { |
| 888 // TODO(srdjan): Implement. | 887 // TODO(srdjan): Implement. |
| 889 return false; | 888 UNREACHABLE(); |
| 889 return; | |
| 890 } | 890 } |
| 891 case Token::kSHR: { | 891 case Token::kSHR: { |
| 892 const Immediate kCountLimit = Immediate(0x1F); | 892 const Immediate kCountLimit = Immediate(0x1F); |
| 893 __ cmpq(right, Immediate(0)); | 893 __ cmpq(right, Immediate(0)); |
| 894 __ j(LESS, deopt); | 894 __ j(LESS, deopt); |
| 895 __ SmiUntag(right); | 895 __ SmiUntag(right); |
| 896 __ cmpq(right, kCountLimit); | 896 __ cmpq(right, kCountLimit); |
| 897 Label count_ok; | 897 Label count_ok; |
| 898 __ j(LESS, &count_ok, Assembler::kNearJump); | 898 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 899 __ movq(right, kCountLimit); | 899 __ movq(right, kCountLimit); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 920 __ j(NOT_EQUAL, deopt); // Overflow. | 920 __ j(NOT_EQUAL, deopt); // Overflow. |
| 921 // Shift for result now we know there is no overflow. | 921 // Shift for result now we know there is no overflow. |
| 922 __ shlq(left, right_temp); | 922 __ shlq(left, right_temp); |
| 923 break; | 923 break; |
| 924 } | 924 } |
| 925 case Token::kOR: | 925 case Token::kOR: |
| 926 case Token::kAND: { | 926 case Token::kAND: { |
| 927 // Flow graph builder has dissected this operation to guarantee correct | 927 // Flow graph builder has dissected this operation to guarantee correct |
| 928 // behavior (short-circuit evaluation). | 928 // behavior (short-circuit evaluation). |
| 929 UNREACHABLE(); | 929 UNREACHABLE(); |
| 930 return false; | 930 break; |
| 931 } | 931 } |
| 932 default: | 932 default: |
| 933 UNREACHABLE(); | 933 UNREACHABLE(); |
| 934 return false; | 934 break; |
| 935 } | 935 } |
| 936 return; | |
|
Mads Ager (google)
2012/06/08 09:15:53
Why the explicit return?
Vyacheslav Egorov (Google)
2012/06/08 11:11:13
Done.
| |
| 937 } | |
| 938 | |
| 939 | |
| 940 static void LoadDoubleOrSmi(FlowGraphCompiler* compiler, | |
|
srdjan
2012/06/08 05:18:22
LoadDoubleOrSmiToXMM?
srdjan
2012/06/08 05:18:22
WHy not move it into FlowGraphCompiler and elimina
Vyacheslav Egorov (Google)
2012/06/08 11:11:13
Done.
Vyacheslav Egorov (Google)
2012/06/08 11:11:13
Done.
| |
| 941 XmmRegister result, | |
| 942 Register reg, | |
| 943 Register temp, | |
| 944 Label* not_double_or_smi) { | |
| 945 Label is_smi, done; | |
| 946 __ testq(reg, Immediate(kSmiTagMask)); | |
| 947 __ j(ZERO, &is_smi); | |
| 948 __ CompareClassId(reg, kDouble); | |
| 949 __ j(NOT_EQUAL, not_double_or_smi); | |
| 950 __ movsd(result, FieldAddress(reg, Double::value_offset())); | |
| 951 __ jmp(&done); | |
| 952 __ Bind(&is_smi); | |
| 953 __ movq(temp, reg); | |
| 954 __ SmiUntag(temp); | |
| 955 __ cvtsi2sd(result, temp); | |
| 956 __ Bind(&done); | |
| 957 } | |
| 958 | |
| 959 | |
| 960 | |
| 961 static bool EmitDoubleBinaryOp(FlowGraphCompiler* compiler, | |
| 962 BinaryOpComp* comp) { | |
| 963 Register left = comp->locs()->in(0).reg(); | |
| 964 Register right = comp->locs()->in(1).reg(); | |
| 965 Register temp = comp->locs()->temp(0).reg(); | |
| 966 Register result = comp->locs()->out().reg(); | |
| 967 | |
| 968 | |
| 969 const Class& double_class = | |
| 970 Class::ZoneHandle(Isolate::Current()->object_store()->double_class()); | |
| 971 const Code& stub = | |
| 972 Code::Handle(StubCode::GetAllocationStubForClass(double_class)); | |
| 973 const ExternalLabel label(double_class.ToCString(), stub.EntryPoint()); | |
| 974 __ pushq(left); | |
| 975 __ pushq(right); | |
| 976 compiler->GenerateCall(comp->instance_call()->token_index(), | |
| 977 comp->instance_call()->try_index(), | |
| 978 &label, | |
| 979 PcDescriptors::kOther); | |
| 980 // Newly allocated object is now in result register (RAX). | |
| 981 ASSERT(result == RAX); | |
| 982 __ popq(right); | |
| 983 __ popq(left); | |
| 984 | |
| 985 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), | |
| 986 comp->instance_call()->token_index(), | |
| 987 comp->instance_call()->try_index(), | |
| 988 kDeoptDoubleBinaryOp, | |
| 989 left, | |
| 990 right); | |
| 991 | |
| 992 LoadDoubleOrSmi(compiler, XMM0, left, temp, deopt); | |
| 993 LoadDoubleOrSmi(compiler, XMM1, right, temp, deopt); | |
| 994 | |
| 995 switch (comp->op_kind()) { | |
| 996 case Token::kADD: __ addsd(XMM0, XMM1); break; | |
| 997 case Token::kSUB: __ subsd(XMM0, XMM1); break; | |
| 998 case Token::kMUL: __ mulsd(XMM0, XMM1); break; | |
| 999 case Token::kDIV: __ divsd(XMM0, XMM1); break; | |
| 1000 default: UNREACHABLE(); | |
| 1001 } | |
| 1002 | |
| 1003 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); | |
| 936 return true; | 1004 return true; |
| 937 } | 1005 } |
| 938 | 1006 |
| 1007 | |
| 939 void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1008 void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 940 if (TryEmitSmiBinaryOp(compiler, this)) { | 1009 switch (operands_type()) { |
| 941 // Operation inlined. | 1010 case kSmiOperands: |
| 942 return; | 1011 EmitSmiBinaryOp(compiler, this); |
| 943 } | 1012 break; |
| 944 // TODO(srdjan): Remove this code once BinaryOpComp has been implemeneted | 1013 |
| 945 // for all intended operations. | 1014 case kDoubleOperands: |
| 946 Register left = locs()->in(0).reg(); | 1015 EmitDoubleBinaryOp(compiler, this); |
| 947 Register right = locs()->in(1).reg(); | 1016 break; |
| 948 __ pushq(left); | 1017 |
| 949 __ pushq(right); | 1018 default: |
| 950 InstanceCallComp* instance_call_comp = instance_call(); | 1019 UNREACHABLE(); |
| 951 instance_call_comp->EmitNativeCode(compiler); | |
| 952 if (locs()->out().reg() != RAX) { | |
| 953 __ movq(locs()->out().reg(), RAX); | |
| 954 } | 1020 } |
| 955 } | 1021 } |
| 956 | 1022 |
| 957 | 1023 |
| 958 LocationSummary* UnarySmiOpComp::MakeLocationSummary() const { | 1024 LocationSummary* UnarySmiOpComp::MakeLocationSummary() const { |
| 959 const intptr_t kNumInputs = 1; | 1025 const intptr_t kNumInputs = 1; |
| 960 const intptr_t kNumTemps = 0; | 1026 const intptr_t kNumTemps = 0; |
| 961 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 1027 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 962 summary->set_in(0, Location::RequiresRegister()); | 1028 summary->set_in(0, Location::RequiresRegister()); |
| 963 summary->set_out(Location::SameAsFirstInput()); | 1029 summary->set_out(Location::SameAsFirstInput()); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1063 } else { | 1129 } else { |
| 1064 UNREACHABLE(); | 1130 UNREACHABLE(); |
| 1065 } | 1131 } |
| 1066 } | 1132 } |
| 1067 | 1133 |
| 1068 } // namespace dart | 1134 } // namespace dart |
| 1069 | 1135 |
| 1070 #undef __ | 1136 #undef __ |
| 1071 | 1137 |
| 1072 #endif // defined TARGET_ARCH_X64 | 1138 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |