| OLD | NEW |
| 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/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intrinsifier.h" | 8 #include "vm/intrinsifier.h" |
| 9 | 9 |
| 10 #include "vm/assembler.h" | 10 #include "vm/assembler.h" |
| (...skipping 815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 } | 826 } |
| 827 | 827 |
| 828 | 828 |
| 829 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { | 829 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { |
| 830 return Integer_bitOrFromInteger(assembler); | 830 return Integer_bitOrFromInteger(assembler); |
| 831 } | 831 } |
| 832 | 832 |
| 833 | 833 |
| 834 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { | 834 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
| 835 Label fall_through; | 835 Label fall_through; |
| 836 __ Untested("Intrinsifier::Integer_bitXorFromInteger"); | |
| 837 | 836 |
| 838 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis | 837 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis |
| 839 __ eor(R0, R0, ShifterOperand(R1)); | 838 __ eor(R0, R0, ShifterOperand(R1)); |
| 840 | 839 |
| 841 __ Ret(); | 840 __ Ret(); |
| 842 __ Bind(&fall_through); | 841 __ Bind(&fall_through); |
| 843 return false; | 842 return false; |
| 844 } | 843 } |
| 845 | 844 |
| 846 | 845 |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown | 1118 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown |
| 1120 // type. Return true or false object in the register R0. Any NaN argument | 1119 // type. Return true or false object in the register R0. Any NaN argument |
| 1121 // returns false. Any non-double arg1 causes control flow to fall through to the | 1120 // returns false. Any non-double arg1 causes control flow to fall through to the |
| 1122 // slow case (compiled method body). | 1121 // slow case (compiled method body). |
| 1123 static bool CompareDoubles(Assembler* assembler, Condition true_condition) { | 1122 static bool CompareDoubles(Assembler* assembler, Condition true_condition) { |
| 1124 Label fall_through, is_smi, double_op; | 1123 Label fall_through, is_smi, double_op; |
| 1125 | 1124 |
| 1126 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1125 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1127 // Both arguments are double, right operand is in R0. | 1126 // Both arguments are double, right operand is in R0. |
| 1128 | 1127 |
| 1129 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag); | 1128 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); |
| 1130 __ vldrd(D1, Address(R0)); | |
| 1131 __ Bind(&double_op); | 1129 __ Bind(&double_op); |
| 1132 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. | 1130 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. |
| 1133 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag); | 1131 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1134 __ vldrd(D0, Address(R0)); | |
| 1135 | 1132 |
| 1136 __ vcmpd(D0, D1); | 1133 __ vcmpd(D0, D1); |
| 1137 __ vmstat(); | 1134 __ vmstat(); |
| 1138 __ LoadObject(R0, Bool::False()); | 1135 __ LoadObject(R0, Bool::False()); |
| 1139 // Return false if D0 or D1 was NaN before checking true condition. | 1136 // Return false if D0 or D1 was NaN before checking true condition. |
| 1140 __ bx(LR, VS); | 1137 __ bx(LR, VS); |
| 1141 __ LoadObject(R0, Bool::True(), true_condition); | 1138 __ LoadObject(R0, Bool::True(), true_condition); |
| 1142 __ Ret(); | 1139 __ Ret(); |
| 1143 | 1140 |
| 1144 __ Bind(&is_smi); // Convert R0 to a double. | 1141 __ Bind(&is_smi); // Convert R0 to a double. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1176 } | 1173 } |
| 1177 | 1174 |
| 1178 | 1175 |
| 1179 // Expects left argument to be double (receiver). Right argument is unknown. | 1176 // Expects left argument to be double (receiver). Right argument is unknown. |
| 1180 // Both arguments are on stack. | 1177 // Both arguments are on stack. |
| 1181 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { | 1178 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { |
| 1182 Label fall_through; | 1179 Label fall_through; |
| 1183 | 1180 |
| 1184 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); | 1181 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); |
| 1185 // Both arguments are double, right operand is in R0. | 1182 // Both arguments are double, right operand is in R0. |
| 1186 // Can't use FieldAddress here. R0 is heap-object-tagged, so the offset will | 1183 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); |
| 1187 // not be 4-byte aligned. | |
| 1188 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag); | |
| 1189 __ vldrd(D1, Address(R0)); | |
| 1190 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. | 1184 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. |
| 1191 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag); | 1185 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1192 __ vldrd(D0, Address(R0)); | |
| 1193 switch (kind) { | 1186 switch (kind) { |
| 1194 case Token::kADD: __ vaddd(D0, D0, D1); break; | 1187 case Token::kADD: __ vaddd(D0, D0, D1); break; |
| 1195 case Token::kSUB: __ vsubd(D0, D0, D1); break; | 1188 case Token::kSUB: __ vsubd(D0, D0, D1); break; |
| 1196 case Token::kMUL: __ vmuld(D0, D0, D1); break; | 1189 case Token::kMUL: __ vmuld(D0, D0, D1); break; |
| 1197 case Token::kDIV: __ vdivd(D0, D0, D1); break; | 1190 case Token::kDIV: __ vdivd(D0, D0, D1); break; |
| 1198 default: UNREACHABLE(); | 1191 default: UNREACHABLE(); |
| 1199 } | 1192 } |
| 1200 const Class& double_class = Class::Handle( | 1193 const Class& double_class = Class::Handle( |
| 1201 Isolate::Current()->object_store()->double_class()); | 1194 Isolate::Current()->object_store()->double_class()); |
| 1202 __ TryAllocate(double_class, &fall_through, R0); // Result register. | 1195 __ TryAllocate(double_class, &fall_through, R0); // Result register. |
| 1203 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag); | 1196 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1204 __ vstrd(D0, Address(R1)); | |
| 1205 __ Ret(); | 1197 __ Ret(); |
| 1206 __ Bind(&fall_through); | 1198 __ Bind(&fall_through); |
| 1207 return false; | 1199 return false; |
| 1208 } | 1200 } |
| 1209 | 1201 |
| 1210 | 1202 |
| 1211 bool Intrinsifier::Double_add(Assembler* assembler) { | 1203 bool Intrinsifier::Double_add(Assembler* assembler) { |
| 1212 return DoubleArithmeticOperations(assembler, Token::kADD); | 1204 return DoubleArithmeticOperations(assembler, Token::kADD); |
| 1213 } | 1205 } |
| 1214 | 1206 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1258 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1250 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1259 __ tst(R0, ShifterOperand(kSmiTagMask)); | 1251 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 1260 __ b(&fall_through, NE); | 1252 __ b(&fall_through, NE); |
| 1261 // Is Smi. | 1253 // Is Smi. |
| 1262 __ SmiUntag(R0); | 1254 __ SmiUntag(R0); |
| 1263 __ vmovsr(S0, R0); | 1255 __ vmovsr(S0, R0); |
| 1264 __ vcvtdi(D0, S0); | 1256 __ vcvtdi(D0, S0); |
| 1265 const Class& double_class = Class::Handle( | 1257 const Class& double_class = Class::Handle( |
| 1266 Isolate::Current()->object_store()->double_class()); | 1258 Isolate::Current()->object_store()->double_class()); |
| 1267 __ TryAllocate(double_class, &fall_through, R0); // Result register. | 1259 __ TryAllocate(double_class, &fall_through, R0); // Result register. |
| 1268 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag); | 1260 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1269 __ vstrd(D0, Address(R1)); | |
| 1270 __ Ret(); | 1261 __ Ret(); |
| 1271 __ Bind(&fall_through); | 1262 __ Bind(&fall_through); |
| 1272 return false; | 1263 return false; |
| 1273 } | 1264 } |
| 1274 | 1265 |
| 1275 | 1266 |
| 1276 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { | 1267 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { |
| 1277 Label is_true; | 1268 Label is_true; |
| 1278 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1269 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1279 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag); | 1270 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1280 __ vldrd(D0, Address(R0)); | |
| 1281 __ vcmpd(D0, D0); | 1271 __ vcmpd(D0, D0); |
| 1282 __ vmstat(); | 1272 __ vmstat(); |
| 1283 __ LoadObject(R0, Bool::False(), VC); | 1273 __ LoadObject(R0, Bool::False(), VC); |
| 1284 __ LoadObject(R0, Bool::True(), VS); | 1274 __ LoadObject(R0, Bool::True(), VS); |
| 1285 __ Ret(); | 1275 __ Ret(); |
| 1286 return true; | 1276 return true; |
| 1287 } | 1277 } |
| 1288 | 1278 |
| 1289 | 1279 |
| 1290 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { | 1280 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { |
| 1291 Label is_false, is_true, is_zero; | 1281 Label is_false, is_true, is_zero; |
| 1292 __ Untested("Intrinsifier::Double_getIsNegative"); | |
| 1293 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1282 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1294 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag); | 1283 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1295 __ vldrd(D0, Address(R0)); | |
| 1296 __ LoadDImmediate(D1, 0.0, R1); | 1284 __ LoadDImmediate(D1, 0.0, R1); |
| 1297 __ vcmpd(D0, D1); | 1285 __ vcmpd(D0, D1); |
| 1298 __ vmstat(); | 1286 __ vmstat(); |
| 1299 __ b(&is_false, VS); // NaN -> false. | 1287 __ b(&is_false, VS); // NaN -> false. |
| 1300 __ b(&is_zero, EQ); // Check for negative zero. | 1288 __ b(&is_zero, EQ); // Check for negative zero. |
| 1301 __ b(&is_false, CS); // >= 0 -> false. | 1289 __ b(&is_false, CS); // >= 0 -> false. |
| 1302 | 1290 |
| 1303 __ Bind(&is_true); | 1291 __ Bind(&is_true); |
| 1304 __ LoadObject(R0, Bool::True()); | 1292 __ LoadObject(R0, Bool::True()); |
| 1305 __ Ret(); | 1293 __ Ret(); |
| 1306 | 1294 |
| 1307 __ Bind(&is_false); | 1295 __ Bind(&is_false); |
| 1308 __ LoadObject(R0, Bool::False()); | 1296 __ LoadObject(R0, Bool::False()); |
| 1309 __ Ret(); | 1297 __ Ret(); |
| 1310 | 1298 |
| 1311 __ Bind(&is_zero); | 1299 __ Bind(&is_zero); |
| 1312 // Check for negative zero by looking at the sign bit. | 1300 // Check for negative zero by looking at the sign bit. |
| 1313 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1. | 1301 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1. |
| 1314 __ mov(R1, ShifterOperand(R1, LSR, 31)); | 1302 __ mov(R1, ShifterOperand(R1, LSR, 31)); |
| 1315 __ tst(R1, ShifterOperand(1)); | 1303 __ tst(R1, ShifterOperand(1)); |
| 1316 __ b(&is_true, NE); // Sign bit set. | 1304 __ b(&is_true, NE); // Sign bit set. |
| 1317 __ b(&is_false); | 1305 __ b(&is_false); |
| 1318 return true; | 1306 return true; |
| 1319 } | 1307 } |
| 1320 | 1308 |
| 1321 | 1309 |
| 1322 bool Intrinsifier::Double_toInt(Assembler* assembler) { | 1310 bool Intrinsifier::Double_toInt(Assembler* assembler) { |
| 1323 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1311 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1324 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag); | 1312 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1325 __ vldrd(D0, Address(R0)); | |
| 1326 __ vcvtid(S0, D0); | 1313 __ vcvtid(S0, D0); |
| 1327 __ vmovrs(R0, S0); | 1314 __ vmovrs(R0, S0); |
| 1328 // Overflow is signaled with minint. | 1315 // Overflow is signaled with minint. |
| 1329 Label fall_through; | 1316 Label fall_through; |
| 1330 // Check for overflow and that it fits into Smi. | 1317 // Check for overflow and that it fits into Smi. |
| 1331 __ CompareImmediate(R0, 0xC0000000); | 1318 __ CompareImmediate(R0, 0xC0000000); |
| 1332 __ b(&fall_through, MI); | 1319 __ b(&fall_through, MI); |
| 1333 __ SmiTag(R0); | 1320 __ SmiTag(R0); |
| 1334 __ Ret(); | 1321 __ Ret(); |
| 1335 __ Bind(&fall_through); | 1322 __ Bind(&fall_through); |
| 1336 return false; | 1323 return false; |
| 1337 } | 1324 } |
| 1338 | 1325 |
| 1339 | 1326 |
| 1340 bool Intrinsifier::Math_sqrt(Assembler* assembler) { | 1327 bool Intrinsifier::Math_sqrt(Assembler* assembler) { |
| 1341 Label fall_through, is_smi, double_op; | 1328 Label fall_through, is_smi, double_op; |
| 1342 __ Untested("Intrinsifier::Math_sqrt"); | |
| 1343 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1329 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1344 // Argument is double and is in R0. | 1330 // Argument is double and is in R0. |
| 1345 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag); | 1331 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); |
| 1346 __ vldrd(D1, Address(R0)); | |
| 1347 __ Bind(&double_op); | 1332 __ Bind(&double_op); |
| 1348 __ vsqrtd(D0, D1); | 1333 __ vsqrtd(D0, D1); |
| 1349 const Class& double_class = Class::Handle( | 1334 const Class& double_class = Class::Handle( |
| 1350 Isolate::Current()->object_store()->double_class()); | 1335 Isolate::Current()->object_store()->double_class()); |
| 1351 __ TryAllocate(double_class, &fall_through, R0); // Result register. | 1336 __ TryAllocate(double_class, &fall_through, R0); // Result register. |
| 1352 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag); | 1337 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1353 __ vstrd(D0, Address(R1)); | |
| 1354 __ Ret(); | 1338 __ Ret(); |
| 1355 __ Bind(&is_smi); | 1339 __ Bind(&is_smi); |
| 1356 __ SmiUntag(R0); | 1340 __ SmiUntag(R0); |
| 1357 __ vmovsr(S0, R0); | 1341 __ vmovsr(S0, R0); |
| 1358 __ vcvtdi(D1, S0); | 1342 __ vcvtdi(D1, S0); |
| 1359 __ b(&double_op); | 1343 __ b(&double_op); |
| 1360 __ Bind(&fall_through); | 1344 __ Bind(&fall_through); |
| 1361 return false; | 1345 return false; |
| 1362 } | 1346 } |
| 1363 | 1347 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1387 const Field& random_A_field = Field::ZoneHandle( | 1371 const Field& random_A_field = Field::ZoneHandle( |
| 1388 random_class.LookupStaticField(Symbols::_A())); | 1372 random_class.LookupStaticField(Symbols::_A())); |
| 1389 ASSERT(!random_A_field.IsNull()); | 1373 ASSERT(!random_A_field.IsNull()); |
| 1390 ASSERT(random_A_field.is_const()); | 1374 ASSERT(random_A_field.is_const()); |
| 1391 const Instance& a_value = Instance::Handle(random_A_field.value()); | 1375 const Instance& a_value = Instance::Handle(random_A_field.value()); |
| 1392 const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value(); | 1376 const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value(); |
| 1393 // 'a_int_value' is a mask. | 1377 // 'a_int_value' is a mask. |
| 1394 ASSERT(Utils::IsUint(32, a_int_value)); | 1378 ASSERT(Utils::IsUint(32, a_int_value)); |
| 1395 int32_t a_int32_value = static_cast<int32_t>(a_int_value); | 1379 int32_t a_int32_value = static_cast<int32_t>(a_int_value); |
| 1396 | 1380 |
| 1397 __ Untested("Random_nextState"); | |
| 1398 | |
| 1399 __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver. | 1381 __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver. |
| 1400 __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'. | 1382 __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'. |
| 1401 // Addresses of _state[0] and _state[1]. | 1383 // Addresses of _state[0] and _state[1]. |
| 1402 | 1384 |
| 1403 const int64_t disp_0 = | 1385 const int64_t disp_0 = |
| 1404 FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid); | 1386 FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid); |
| 1405 | 1387 |
| 1406 const int64_t disp_1 = | 1388 const int64_t disp_1 = |
| 1407 FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid) + | 1389 FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid) + |
| 1408 FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid); | 1390 FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1697 __ Bind(&ok); | 1679 __ Bind(&ok); |
| 1698 __ Ret(); | 1680 __ Ret(); |
| 1699 | 1681 |
| 1700 __ Bind(&fall_through); | 1682 __ Bind(&fall_through); |
| 1701 return false; | 1683 return false; |
| 1702 } | 1684 } |
| 1703 | 1685 |
| 1704 } // namespace dart | 1686 } // namespace dart |
| 1705 | 1687 |
| 1706 #endif // defined TARGET_ARCH_ARM | 1688 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |