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 970 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
981 ASSERT(!exception_var().is_captured()); | 981 ASSERT(!exception_var().is_captured()); |
982 ASSERT(!stacktrace_var().is_captured()); | 982 ASSERT(!stacktrace_var().is_captured()); |
983 __ movq(Address(RBP, exception_var().index() * kWordSize), | 983 __ movq(Address(RBP, exception_var().index() * kWordSize), |
984 kExceptionObjectReg); | 984 kExceptionObjectReg); |
985 __ movq(Address(RBP, stacktrace_var().index() * kWordSize), | 985 __ movq(Address(RBP, stacktrace_var().index() * kWordSize), |
986 kStackTraceObjectReg); | 986 kStackTraceObjectReg); |
987 } | 987 } |
988 | 988 |
989 | 989 |
990 LocationSummary* BinaryOpComp::MakeLocationSummary() const { | 990 LocationSummary* BinaryOpComp::MakeLocationSummary() const { |
991 const intptr_t kNumTemps = 1; | |
992 const intptr_t kNumInputs = 2; | 991 const intptr_t kNumInputs = 2; |
993 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 992 if (op_kind() == Token::kTRUNCDIV) { |
994 summary->set_in(0, Location::RequiresRegister()); | 993 const intptr_t kNumTemps = 3; |
995 summary->set_in(1, Location::RequiresRegister()); | 994 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
996 summary->set_out(Location::SameAsFirstInput()); | 995 summary->set_in(0, Location::RegisterLocation(RAX)); |
997 summary->set_temp(0, Location::RequiresRegister()); | 996 summary->set_in(1, Location::RegisterLocation(RCX)); |
998 return summary; | 997 summary->set_out(Location::SameAsFirstInput()); |
| 998 summary->set_temp(0, Location::RegisterLocation(RBX)); |
| 999 // Will be used for for sign extension. |
| 1000 summary->set_temp(1, Location::RegisterLocation(RDX)); |
| 1001 summary->set_temp(2, Location::RequiresRegister()); |
| 1002 return summary; |
| 1003 } else if (op_kind() == Token::kSHR) { |
| 1004 const intptr_t kNumTemps = 1; |
| 1005 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 1006 summary->set_in(0, Location::RequiresRegister()); |
| 1007 summary->set_in(1, Location::RegisterLocation(RCX)); |
| 1008 summary->set_out(Location::SameAsFirstInput()); |
| 1009 summary->set_temp(0, Location::RequiresRegister()); |
| 1010 return summary; |
| 1011 } else if (op_kind() == Token::kSHL) { |
| 1012 const intptr_t kNumTemps = 2; |
| 1013 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 1014 summary->set_in(0, Location::RequiresRegister()); |
| 1015 summary->set_in(1, Location::RequiresRegister()); |
| 1016 summary->set_out(Location::SameAsFirstInput()); |
| 1017 summary->set_temp(0, Location::RequiresRegister()); |
| 1018 summary->set_temp(1, Location::RegisterLocation(RCX)); |
| 1019 return summary; |
| 1020 } else { |
| 1021 const intptr_t kNumTemps = 1; |
| 1022 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 1023 summary->set_in(0, Location::RequiresRegister()); |
| 1024 summary->set_in(1, Location::RequiresRegister()); |
| 1025 summary->set_out(Location::SameAsFirstInput()); |
| 1026 summary->set_temp(0, Location::RequiresRegister()); |
| 1027 return summary; |
| 1028 } |
999 } | 1029 } |
1000 | 1030 |
1001 | 1031 |
1002 // TODO(srdjan): Implement variations. | 1032 // TODO(srdjan): Implement variations. |
1003 static bool TryEmitSmiBinaryOp(FlowGraphCompiler* compiler, | 1033 static bool TryEmitSmiBinaryOp(FlowGraphCompiler* compiler, |
1004 BinaryOpComp* comp) { | 1034 BinaryOpComp* comp) { |
1005 ASSERT((comp->ic_data() != NULL)); | 1035 ASSERT((comp->ic_data() != NULL)); |
1006 const ICData& ic_data = *comp->ic_data(); | 1036 const ICData& ic_data = *comp->ic_data(); |
1007 if (ic_data.IsNull()) return false; | 1037 if (ic_data.IsNull()) return false; |
1008 if (ic_data.num_args_tested() != 2) return false; | 1038 if (ic_data.num_args_tested() != 2) return false; |
1009 if (ic_data.NumberOfChecks() != 1) return false; | 1039 if (ic_data.NumberOfChecks() != 1) return false; |
1010 Function& target = Function::Handle(); | 1040 Function& target = Function::Handle(); |
1011 GrowableArray<const Class*> classes; | 1041 GrowableArray<const Class*> classes; |
1012 ic_data.GetCheckAt(0, &classes, &target); | 1042 ic_data.GetCheckAt(0, &classes, &target); |
1013 const Class& smi_class = | 1043 const Class& smi_class = |
1014 Class::Handle(Isolate::Current()->object_store()->smi_class()); | 1044 Class::Handle(Isolate::Current()->object_store()->smi_class()); |
1015 if ((classes[0]->raw() != smi_class.raw()) || | 1045 if ((classes[0]->raw() != smi_class.raw()) || |
1016 (classes[1]->raw() != smi_class.raw())) { | 1046 (classes[1]->raw() != smi_class.raw())) { |
1017 return false; | 1047 return false; |
1018 } | 1048 } |
1019 // TODO(srdjan): need to allocate a temporary register (now using r10) | 1049 // TODO(srdjan): need to allocate a temporary register (now using r10) |
1020 Register left = comp->locs()->in(0).reg(); | 1050 Register left = comp->locs()->in(0).reg(); |
1021 Register right = comp->locs()->in(1).reg(); | 1051 Register right = comp->locs()->in(1).reg(); |
1022 Register result = comp->locs()->out().reg(); | 1052 Register result = comp->locs()->out().reg(); |
1023 Register temp = comp->locs()->temp(0).reg(); | 1053 Register temp = comp->locs()->temp(0).reg(); |
| 1054 ASSERT(left == result); |
1024 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), | 1055 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), |
1025 comp->instance_call()->token_index(), | 1056 comp->instance_call()->token_index(), |
1026 comp->instance_call()->try_index(), | 1057 comp->instance_call()->try_index(), |
1027 kDeoptSmiBinaryOp, | 1058 kDeoptSmiBinaryOp, |
1028 temp, | 1059 temp, |
1029 right); | 1060 right); |
1030 __ movq(temp, left); | 1061 __ movq(temp, left); |
1031 __ orq(left, right); | 1062 __ orq(left, right); |
1032 __ testq(left, Immediate(kSmiTagMask)); | 1063 __ testq(left, Immediate(kSmiTagMask)); |
1033 __ j(NOT_ZERO, deopt); | 1064 __ j(NOT_ZERO, deopt); |
1034 __ movq(left, temp); | 1065 __ movq(left, temp); |
1035 switch (comp->op_kind()) { | 1066 switch (comp->op_kind()) { |
1036 case Token::kADD: { | 1067 case Token::kADD: { |
1037 __ addq(left, right); | 1068 __ addq(left, right); |
1038 __ j(OVERFLOW, deopt); | 1069 __ j(OVERFLOW, deopt); |
1039 if (result != left) { | |
1040 __ movq(result, left); | |
1041 } | |
1042 break; | 1070 break; |
1043 } | 1071 } |
| 1072 case Token::kSUB: { |
| 1073 __ subq(left, right); |
| 1074 __ j(OVERFLOW, deopt); |
| 1075 break; |
| 1076 } |
| 1077 case Token::kMUL: { |
| 1078 __ SmiUntag(left); |
| 1079 __ imulq(left, right); |
| 1080 __ j(OVERFLOW, deopt); |
| 1081 break; |
| 1082 } |
| 1083 case Token::kBIT_AND: { |
| 1084 // No overflow check. |
| 1085 __ andq(left, right); |
| 1086 break; |
| 1087 } |
| 1088 case Token::kBIT_OR: { |
| 1089 // No overflow check. |
| 1090 __ orq(left, right); |
| 1091 break; |
| 1092 } |
| 1093 case Token::kBIT_XOR: { |
| 1094 // No overflow check. |
| 1095 __ xorq(left, right); |
| 1096 break; |
| 1097 } |
| 1098 case Token::kTRUNCDIV: { |
| 1099 // Handle divide by zero in runtime. |
| 1100 // Deoptimization requires that temp and right are preserved. |
| 1101 __ testq(right, right); |
| 1102 __ j(ZERO, deopt); |
| 1103 ASSERT(left == RAX); |
| 1104 ASSERT((right != RDX) && (right != RAX)); |
| 1105 ASSERT((temp != RDX) && (temp != RAX)); |
| 1106 ASSERT(comp->locs()->temp(1).reg() == RDX); |
| 1107 ASSERT(result == RAX); |
| 1108 Register right_temp = comp->locs()->temp(2).reg(); |
| 1109 __ movq(right_temp, right); |
| 1110 __ SmiUntag(left); |
| 1111 __ SmiUntag(right_temp); |
| 1112 __ cqo(); // Sign extend RAX -> RDX:RAX. |
| 1113 __ idivq(right_temp); // RAX: quotient, RDX: remainder. |
| 1114 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 1115 // case we cannot tag the result. |
| 1116 __ cmpq(result, Immediate(0x4000000000000000)); |
| 1117 __ j(EQUAL, deopt); |
| 1118 __ SmiTag(result); |
| 1119 break; |
| 1120 } |
| 1121 case Token::kDIV: { |
| 1122 // Dispatches to 'Double./'. |
| 1123 // TODO(srdjan): Implement as conversion to double and double division. |
| 1124 return false; |
| 1125 } |
| 1126 case Token::kMOD: { |
| 1127 // TODO(srdjan): Implement. |
| 1128 return false; |
| 1129 } |
| 1130 case Token::kSHR: { |
| 1131 const Immediate kCountLimit = Immediate(0x1F); |
| 1132 __ cmpq(right, Immediate(0)); |
| 1133 __ j(LESS, deopt); |
| 1134 __ SmiUntag(right); |
| 1135 __ cmpq(right, kCountLimit); |
| 1136 Label count_ok; |
| 1137 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 1138 __ movq(right, kCountLimit); |
| 1139 __ Bind(&count_ok); |
| 1140 ASSERT(right == RCX); // Count must be in ECX |
| 1141 __ SmiUntag(left); |
| 1142 __ sarq(left, right); |
| 1143 __ SmiTag(left); |
| 1144 break; |
| 1145 } |
| 1146 case Token::kSHL: { |
| 1147 // Check if count too large for handling it inlined. |
| 1148 __ cmpq(right, |
| 1149 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits)))); |
| 1150 __ j(ABOVE_EQUAL, deopt); |
| 1151 Register right_temp = comp->locs()->temp(1).reg(); |
| 1152 ASSERT(right_temp == RCX); // Count must be in RCX |
| 1153 __ movq(right_temp, right); |
| 1154 __ SmiUntag(right_temp); |
| 1155 // Overflow test (preserve temp and right); |
| 1156 __ shlq(left, right_temp); |
| 1157 __ sarq(left, right_temp); |
| 1158 __ cmpq(left, temp); |
| 1159 __ j(NOT_EQUAL, deopt); // Overflow. |
| 1160 // Shift for result now we know there is no overflow. |
| 1161 __ shlq(left, right_temp); |
| 1162 break; |
| 1163 } |
| 1164 case Token::kOR: |
| 1165 case Token::kAND: { |
| 1166 // Flow graph builder has dissected this operation to guarantee correct |
| 1167 // behavior (short-circuit evaluation). |
| 1168 UNREACHABLE(); |
| 1169 return false; |
| 1170 } |
1044 default: | 1171 default: |
1045 UNREACHABLE(); | 1172 UNREACHABLE(); |
| 1173 return false; |
1046 } | 1174 } |
1047 return true; | 1175 return true; |
1048 } | 1176 } |
1049 | 1177 |
1050 void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1178 void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
1051 if (TryEmitSmiBinaryOp(compiler, this)) { | 1179 if (TryEmitSmiBinaryOp(compiler, this)) { |
1052 // Operation inlined. | 1180 // Operation inlined. |
1053 return; | 1181 return; |
1054 } | 1182 } |
1055 // TODO(srdjan): Remove this code once BinaryOpComp has been implemeneted | 1183 // TODO(srdjan): Remove this code once BinaryOpComp has been implemeneted |
1056 // for all intended operations. | 1184 // for all intended operations. |
1057 Register left = locs()->in(0).reg(); | 1185 Register left = locs()->in(0).reg(); |
1058 Register right = locs()->in(1).reg(); | 1186 Register right = locs()->in(1).reg(); |
1059 __ pushq(left); | 1187 __ pushq(left); |
1060 __ pushq(right); | 1188 __ pushq(right); |
1061 InstanceCallComp* instance_call_comp = instance_call(); | 1189 InstanceCallComp* instance_call_comp = instance_call(); |
1062 instance_call_comp->EmitNativeCode(compiler); | 1190 instance_call_comp->EmitNativeCode(compiler); |
1063 if (locs()->out().reg() != RAX) { | 1191 if (locs()->out().reg() != RAX) { |
1064 __ movq(locs()->out().reg(), RAX); | 1192 __ movq(locs()->out().reg(), RAX); |
1065 } | 1193 } |
1066 } | 1194 } |
1067 | 1195 |
1068 } // namespace dart | 1196 } // namespace dart |
1069 | 1197 |
1070 #undef __ | 1198 #undef __ |
1071 | 1199 |
1072 #endif // defined TARGET_ARCH_X64 | 1200 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |