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 "lib/error.h" | 8 #include "lib/error.h" |
9 #include "vm/flow_graph_compiler.h" | 9 #include "vm/flow_graph_compiler.h" |
10 #include "vm/locations.h" | 10 #include "vm/locations.h" |
(...skipping 872 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
883 return NULL; | 883 return NULL; |
884 } | 884 } |
885 | 885 |
886 | 886 |
887 void CatchEntryComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 887 void CatchEntryComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
888 UNIMPLEMENTED(); | 888 UNIMPLEMENTED(); |
889 } | 889 } |
890 | 890 |
891 | 891 |
892 LocationSummary* BinaryOpComp::MakeLocationSummary() const { | 892 LocationSummary* BinaryOpComp::MakeLocationSummary() const { |
893 const intptr_t kNumTemps = 1; | |
894 const intptr_t kNumInputs = 2; | 893 const intptr_t kNumInputs = 2; |
895 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 894 if (op_kind() == Token::kTRUNCDIV) { |
896 summary->set_in(0, Location::RequiresRegister()); | 895 const intptr_t kNumTemps = 3; |
897 summary->set_in(1, Location::RequiresRegister()); | 896 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
898 summary->set_out(Location::SameAsFirstInput()); | 897 summary->set_in(0, Location::RegisterLocation(RAX)); |
899 summary->set_temp(0, Location::RequiresRegister()); | 898 summary->set_in(1, Location::RegisterLocation(RCX)); |
900 return summary; | 899 summary->set_out(Location::SameAsFirstInput()); |
900 summary->set_temp(0, Location::RegisterLocation(RBX)); | |
901 // Will be used for for sign extension. | |
902 summary->set_temp(1, Location::RegisterLocation(RDX)); | |
903 summary->set_temp(2, Location::RequiresRegister()); | |
904 return summary; | |
905 } else if (op_kind() == Token::kSHR) { | |
906 const intptr_t kNumTemps = 1; | |
907 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | |
908 summary->set_in(0, Location::RequiresRegister()); | |
909 summary->set_in(1, Location::RegisterLocation(RCX)); | |
910 summary->set_out(Location::SameAsFirstInput()); | |
911 summary->set_temp(0, Location::RequiresRegister()); | |
912 return summary; | |
913 } else if (op_kind() == Token::kSHL) { | |
914 const intptr_t kNumTemps = 2; | |
915 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | |
916 summary->set_in(0, Location::RequiresRegister()); | |
917 summary->set_in(1, Location::RequiresRegister()); | |
918 summary->set_out(Location::SameAsFirstInput()); | |
919 summary->set_temp(0, Location::RequiresRegister()); | |
920 summary->set_temp(1, Location::RegisterLocation(RCX)); | |
921 return summary; | |
922 } else { | |
923 const intptr_t kNumTemps = 1; | |
924 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | |
925 summary->set_in(0, Location::RequiresRegister()); | |
926 summary->set_in(1, Location::RequiresRegister()); | |
927 summary->set_out(Location::SameAsFirstInput()); | |
928 summary->set_temp(0, Location::RequiresRegister()); | |
929 return summary; | |
930 } | |
901 } | 931 } |
902 | 932 |
903 | 933 |
904 // TODO(srdjan): Implement variations. | 934 // TODO(srdjan): Implement variations. |
905 static bool TryEmitSmiBinaryOp(FlowGraphCompiler* compiler, | 935 static bool TryEmitSmiBinaryOp(FlowGraphCompiler* compiler, |
906 BinaryOpComp* comp) { | 936 BinaryOpComp* comp) { |
907 ASSERT((comp->ic_data() != NULL)); | 937 ASSERT((comp->ic_data() != NULL)); |
908 const ICData& ic_data = *comp->ic_data(); | 938 const ICData& ic_data = *comp->ic_data(); |
909 if (ic_data.IsNull()) return false; | 939 if (ic_data.IsNull()) return false; |
910 if (ic_data.num_args_tested() != 2) return false; | 940 if (ic_data.num_args_tested() != 2) return false; |
911 if (ic_data.NumberOfChecks() != 1) return false; | 941 if (ic_data.NumberOfChecks() != 1) return false; |
912 Function& target = Function::Handle(); | 942 Function& target = Function::Handle(); |
913 GrowableArray<const Class*> classes; | 943 GrowableArray<const Class*> classes; |
914 ic_data.GetCheckAt(0, &classes, &target); | 944 ic_data.GetCheckAt(0, &classes, &target); |
915 const Class& smi_class = | 945 const Class& smi_class = |
916 Class::Handle(Isolate::Current()->object_store()->smi_class()); | 946 Class::Handle(Isolate::Current()->object_store()->smi_class()); |
917 if ((classes[0]->raw() != smi_class.raw()) || | 947 if ((classes[0]->raw() != smi_class.raw()) || |
918 (classes[1]->raw() != smi_class.raw())) { | 948 (classes[1]->raw() != smi_class.raw())) { |
919 return false; | 949 return false; |
920 } | 950 } |
921 // TODO(srdjan): need to allocate a temporary register (now using r10) | 951 // TODO(srdjan): need to allocate a temporary register (now using r10) |
922 Register left = comp->locs()->in(0).reg(); | 952 Register left = comp->locs()->in(0).reg(); |
923 Register right = comp->locs()->in(1).reg(); | 953 Register right = comp->locs()->in(1).reg(); |
924 Register result = comp->locs()->out().reg(); | 954 Register result = comp->locs()->out().reg(); |
925 Register temp = comp->locs()->temp(0).reg(); | 955 Register temp = comp->locs()->temp(0).reg(); |
956 ASSERT(left == result); | |
926 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), | 957 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), |
927 comp->instance_call()->token_index(), | 958 comp->instance_call()->token_index(), |
928 comp->instance_call()->try_index(), | 959 comp->instance_call()->try_index(), |
929 kDeoptSmiBinaryOp, | 960 kDeoptSmiBinaryOp, |
930 temp, | 961 temp, |
931 right); | 962 right); |
932 __ movq(temp, left); | 963 __ movq(temp, left); |
933 __ orq(left, right); | 964 __ orq(left, right); |
934 __ testq(left, Immediate(kSmiTagMask)); | 965 __ testq(left, Immediate(kSmiTagMask)); |
935 __ j(NOT_ZERO, deopt); | 966 __ j(NOT_ZERO, deopt); |
936 __ movq(left, temp); | 967 __ movq(left, temp); |
937 switch (comp->op_kind()) { | 968 switch (comp->op_kind()) { |
938 case Token::kADD: { | 969 case Token::kADD: { |
939 __ addq(left, right); | 970 __ addq(left, right); |
940 __ j(OVERFLOW, deopt); | 971 __ j(OVERFLOW, deopt); |
941 if (result != left) { | |
942 __ movq(result, left); | |
943 } | |
944 break; | 972 break; |
945 } | 973 } |
974 case Token::kSUB: { | |
975 __ subq(left, right); | |
976 __ j(OVERFLOW, deopt); | |
977 break; | |
978 } | |
979 case Token::kMUL: { | |
980 __ SmiUntag(left); | |
981 __ imulq(left, right); | |
982 __ j(OVERFLOW, deopt); | |
983 break; | |
984 } | |
985 case Token::kBIT_AND: { | |
986 // No overflow check. | |
987 __ andq(left, right); | |
988 break; | |
989 } | |
990 case Token::kBIT_OR: { | |
Florian Schneider
2012/05/30 14:21:12
Maybe also add the same comment as in the BIT_AND
srdjan
2012/05/30 17:03:13
Added it.
| |
991 __ orq(left, right); | |
992 break; | |
993 } | |
994 case Token::kBIT_XOR: { | |
995 // No overflow check. | |
996 __ xorq(left, right); | |
997 break; | |
998 } | |
999 case Token::kTRUNCDIV: { | |
1000 // Handle divide by zero in runtime. | |
1001 // Deoptimization requires that temp and right are preserved. | |
1002 __ testq(right, right); | |
1003 __ j(ZERO, deopt); | |
1004 ASSERT(left == RAX); | |
1005 ASSERT((right != RDX) && (right != RAX)); | |
1006 ASSERT((temp != RDX) && (temp != RAX)); | |
1007 ASSERT(comp->locs()->temp(1).reg() == RDX); | |
1008 ASSERT(result == RAX); | |
1009 Register right_temp = comp->locs()->temp(2).reg(); | |
1010 __ movq(right_temp, right); | |
1011 __ SmiUntag(left); | |
1012 __ SmiUntag(right_temp); | |
1013 __ cqo(); // Sign extend RAX -> RDX:RAX. | |
1014 __ idivq(right_temp); // RAX: quotient, RDX: remainder. | |
1015 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | |
1016 // case we cannot tag the result. | |
1017 __ cmpq(result, Immediate(0x4000000000000000)); | |
1018 __ j(EQUAL, deopt); | |
1019 __ SmiTag(result); | |
1020 break; | |
1021 } | |
1022 case Token::kDIV: { | |
1023 // Dispatches to 'Double./'. | |
1024 // TODO(srdjan): Implement as conversion to double and double division. | |
1025 return false; | |
1026 } | |
1027 case Token::kMOD: { | |
1028 // TODO(srdjan): Implement. | |
1029 return false; | |
1030 } | |
1031 case Token::kSHR: { | |
1032 const Immediate kCountLimit = Immediate(0x1F); | |
1033 __ cmpq(right, Immediate(0)); | |
1034 __ j(LESS, deopt); | |
1035 __ SmiUntag(right); | |
1036 __ cmpq(right, kCountLimit); | |
1037 Label count_ok; | |
1038 __ j(LESS, &count_ok, Assembler::kNearJump); | |
1039 __ movq(right, kCountLimit); | |
1040 __ Bind(&count_ok); | |
1041 ASSERT(right == RCX); // Count must be in ECX | |
1042 __ SmiUntag(left); | |
1043 __ sarq(left, right); | |
1044 __ SmiTag(left); | |
1045 break; | |
1046 } | |
1047 case Token::kSHL: { | |
1048 // Check if count too large for handling it inlined. | |
1049 __ cmpq(right, | |
1050 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits)))); | |
1051 __ j(ABOVE_EQUAL, deopt); | |
1052 Register right_temp = comp->locs()->temp(1).reg(); | |
1053 ASSERT(right_temp == RCX); // Count must be in RCX | |
1054 __ movq(right_temp, right); | |
1055 __ SmiUntag(right_temp); | |
1056 // Overflow test (preserve temp and right); | |
1057 __ shlq(left, right_temp); | |
1058 __ sarq(left, right_temp); | |
1059 __ cmpq(left, temp); | |
1060 __ j(NOT_EQUAL, deopt); // Overflow. | |
1061 // Shift for result now we know there is no overflow. | |
1062 __ shlq(left, right_temp); | |
1063 break; | |
1064 } | |
1065 case Token::kOR: | |
1066 case Token::kAND: { | |
1067 // Flow graph builder has dissected this operation to guarantee correct | |
1068 // behavior (short-circuit evaluation). | |
1069 UNREACHABLE(); | |
1070 } | |
946 default: | 1071 default: |
947 UNREACHABLE(); | 1072 // Not implemented. |
1073 return false; | |
948 } | 1074 } |
949 return true; | 1075 return true; |
950 } | 1076 } |
951 | 1077 |
952 void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1078 void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
953 if (TryEmitSmiBinaryOp(compiler, this)) { | 1079 if (TryEmitSmiBinaryOp(compiler, this)) { |
954 // Operation inlined. | 1080 // Operation inlined. |
955 return; | 1081 return; |
956 } | 1082 } |
957 // TODO(srdjan): Remove this code once BinaryOpComp has been implemeneted | 1083 // TODO(srdjan): Remove this code once BinaryOpComp has been implemeneted |
958 // for all intended operations. | 1084 // for all intended operations. |
959 Register left = locs()->in(0).reg(); | 1085 Register left = locs()->in(0).reg(); |
960 Register right = locs()->in(1).reg(); | 1086 Register right = locs()->in(1).reg(); |
961 __ pushq(left); | 1087 __ pushq(left); |
962 __ pushq(right); | 1088 __ pushq(right); |
963 InstanceCallComp* instance_call_comp = instance_call(); | 1089 InstanceCallComp* instance_call_comp = instance_call(); |
964 instance_call_comp->EmitNativeCode(compiler); | 1090 instance_call_comp->EmitNativeCode(compiler); |
965 if (locs()->out().reg() != RAX) { | 1091 if (locs()->out().reg() != RAX) { |
966 __ movq(locs()->out().reg(), RAX); | 1092 __ movq(locs()->out().reg(), RAX); |
967 } | 1093 } |
968 } | 1094 } |
969 | 1095 |
970 } // namespace dart | 1096 } // namespace dart |
971 | 1097 |
972 #undef __ | 1098 #undef __ |
973 | 1099 |
974 #endif // defined TARGET_ARCH_X64 | 1100 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |