| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/simulator.h" | 9 #include "vm/simulator.h" |
| 10 #include "vm/runtime_entry.h" | 10 #include "vm/runtime_entry.h" |
| 11 #include "vm/stub_code.h" | 11 #include "vm/stub_code.h" |
| 12 | 12 |
| 13 namespace dart { | 13 namespace dart { |
| 14 | 14 |
| 15 // TODO(regis): Enable this flag after PrintStopMessage stub is implemented. | 15 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); |
| 16 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); | |
| 17 | 16 |
| 18 | 17 |
| 19 bool CPUFeatures::integer_division_supported_ = false; | 18 bool CPUFeatures::integer_division_supported_ = false; |
| 20 #if defined(DEBUG) | 19 #if defined(DEBUG) |
| 21 bool CPUFeatures::initialized_ = false; | 20 bool CPUFeatures::initialized_ = false; |
| 22 #endif | 21 #endif |
| 23 | 22 |
| 24 | 23 |
| 25 bool CPUFeatures::integer_division_supported() { | 24 bool CPUFeatures::integer_division_supported() { |
| 26 DEBUG_ASSERT(initialized_); | 25 DEBUG_ASSERT(initialized_); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 kLdExRnShift = 16, | 106 kLdExRnShift = 16, |
| 108 kLdExRtShift = 12, | 107 kLdExRtShift = 12, |
| 109 kStrExRnShift = 16, | 108 kStrExRnShift = 16, |
| 110 kStrExRdShift = 12, | 109 kStrExRdShift = 12, |
| 111 kStrExRtShift = 0, | 110 kStrExRtShift = 0, |
| 112 }; | 111 }; |
| 113 | 112 |
| 114 | 113 |
| 115 uint32_t Address::encoding3() const { | 114 uint32_t Address::encoding3() const { |
| 116 ASSERT(kind_ == Immediate); | 115 ASSERT(kind_ == Immediate); |
| 117 const uint32_t offset_mask = (1 << 12) - 1; | 116 uint32_t offset = encoding_ & kOffset12Mask; |
| 118 uint32_t offset = encoding_ & offset_mask; | |
| 119 ASSERT(offset < 256); | 117 ASSERT(offset < 256); |
| 120 return (encoding_ & ~offset_mask) | ((offset & 0xf0) << 4) | (offset & 0xf); | 118 return (encoding_ & ~kOffset12Mask) | ((offset & 0xf0) << 4) | (offset & 0xf); |
| 121 } | 119 } |
| 122 | 120 |
| 123 | 121 |
| 124 uint32_t Address::vencoding() const { | 122 uint32_t Address::vencoding() const { |
| 125 ASSERT(kind_ == Immediate); | 123 ASSERT(kind_ == Immediate); |
| 126 const uint32_t offset_mask = (1 << 12) - 1; | 124 uint32_t offset = encoding_ & kOffset12Mask; |
| 127 uint32_t offset = encoding_ & offset_mask; | |
| 128 ASSERT(offset < (1 << 10)); // In the range 0 to +1020. | 125 ASSERT(offset < (1 << 10)); // In the range 0 to +1020. |
| 129 ASSERT(Utils::IsAligned(offset, 4)); // Multiple of 4. | 126 ASSERT(Utils::IsAligned(offset, 4)); // Multiple of 4. |
| 130 int mode = encoding_ & ((8|4|1) << 21); | 127 int mode = encoding_ & ((8|4|1) << 21); |
| 131 ASSERT((mode == Offset) || (mode == NegOffset)); | 128 ASSERT((mode == Offset) || (mode == NegOffset)); |
| 132 uint32_t vencoding = (encoding_ & (0xf << kRnShift)) | (offset >> 2); | 129 uint32_t vencoding = (encoding_ & (0xf << kRnShift)) | (offset >> 2); |
| 133 if (mode == Offset) { | 130 if (mode == Offset) { |
| 134 vencoding |= 1 << 23; | 131 vencoding |= 1 << 23; |
| 135 } | 132 } |
| 136 return vencoding; | 133 return vencoding; |
| 137 } | 134 } |
| (...skipping 1104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1242 if (object.IsNull() || | 1239 if (object.IsNull() || |
| 1243 object.IsSmi() || | 1240 object.IsSmi() || |
| 1244 (object.raw() == Bool::True().raw()) || | 1241 (object.raw() == Bool::True().raw()) || |
| 1245 (object.raw() == Bool::False().raw())) { | 1242 (object.raw() == Bool::False().raw())) { |
| 1246 // This object is never relocated; do not use object pool. | 1243 // This object is never relocated; do not use object pool. |
| 1247 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw())); | 1244 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw())); |
| 1248 return; | 1245 return; |
| 1249 } | 1246 } |
| 1250 const int32_t offset = | 1247 const int32_t offset = |
| 1251 Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; | 1248 Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; |
| 1252 if (Address::CanHoldLoadOffset(kLoadWord, offset)) { | 1249 int32_t offset_mask; |
| 1250 if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) { |
| 1253 ldr(rd, Address(PP, offset)); | 1251 ldr(rd, Address(PP, offset)); |
| 1254 } else { | 1252 } else { |
| 1255 int32_t offset12_hi = offset & ~kOffset12Mask; // signed | 1253 int32_t offset_hi = offset & ~offset_mask; // signed |
| 1256 uint32_t offset12_lo = offset & kOffset12Mask; // unsigned | 1254 uint32_t offset_lo = offset & offset_mask; // unsigned |
| 1257 AddImmediate(rd, PP, offset12_hi); | 1255 AddImmediate(rd, PP, offset_hi); |
| 1258 ldr(rd, Address(rd, offset12_lo)); | 1256 ldr(rd, Address(rd, offset_lo)); |
| 1259 } | 1257 } |
| 1260 } | 1258 } |
| 1261 | 1259 |
| 1262 | 1260 |
| 1263 void Assembler::Bind(Label* label) { | 1261 void Assembler::Bind(Label* label) { |
| 1264 ASSERT(!label->IsBound()); | 1262 ASSERT(!label->IsBound()); |
| 1265 int bound_pc = buffer_.Size(); | 1263 int bound_pc = buffer_.Size(); |
| 1266 while (label->IsLinked()) { | 1264 while (label->IsLinked()) { |
| 1267 int32_t position = label->Position(); | 1265 int32_t position = label->Position(); |
| 1268 int32_t next = buffer_.Load<int32_t>(position); | 1266 int32_t next = buffer_.Load<int32_t>(position); |
| 1269 int32_t encoded = Assembler::EncodeBranchOffset(bound_pc - position, next); | 1267 int32_t encoded = Assembler::EncodeBranchOffset(bound_pc - position, next); |
| 1270 buffer_.Store<int32_t>(position, encoded); | 1268 buffer_.Store<int32_t>(position, encoded); |
| 1271 label->position_ = Assembler::DecodeBranchOffset(next); | 1269 label->position_ = Assembler::DecodeBranchOffset(next); |
| 1272 } | 1270 } |
| 1273 label->BindTo(bound_pc); | 1271 label->BindTo(bound_pc); |
| 1274 } | 1272 } |
| 1275 | 1273 |
| 1276 | 1274 |
| 1277 bool Address::CanHoldLoadOffset(LoadOperandType type, int offset) { | 1275 bool Address::CanHoldLoadOffset(LoadOperandType type, |
| 1276 int32_t offset, |
| 1277 int32_t* offset_mask) { |
| 1278 switch (type) { | 1278 switch (type) { |
| 1279 case kLoadSignedByte: | 1279 case kLoadSignedByte: |
| 1280 case kLoadSignedHalfword: | 1280 case kLoadSignedHalfword: |
| 1281 case kLoadUnsignedHalfword: | 1281 case kLoadUnsignedHalfword: |
| 1282 case kLoadWordPair: | 1282 case kLoadWordPair: { |
| 1283 *offset_mask = 0xff; |
| 1283 return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3. | 1284 return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3. |
| 1285 } |
| 1284 case kLoadUnsignedByte: | 1286 case kLoadUnsignedByte: |
| 1285 case kLoadWord: | 1287 case kLoadWord: { |
| 1288 *offset_mask = 0xfff; |
| 1286 return Utils::IsAbsoluteUint(12, offset); // Addressing mode 2. | 1289 return Utils::IsAbsoluteUint(12, offset); // Addressing mode 2. |
| 1290 } |
| 1287 case kLoadSWord: | 1291 case kLoadSWord: |
| 1288 case kLoadDWord: | 1292 case kLoadDWord: { |
| 1293 *offset_mask = 0x3ff; |
| 1289 return Utils::IsAbsoluteUint(10, offset); // VFP addressing mode. | 1294 return Utils::IsAbsoluteUint(10, offset); // VFP addressing mode. |
| 1290 default: | 1295 } |
| 1296 default: { |
| 1291 UNREACHABLE(); | 1297 UNREACHABLE(); |
| 1292 return false; | 1298 return false; |
| 1299 } |
| 1293 } | 1300 } |
| 1294 } | 1301 } |
| 1295 | 1302 |
| 1296 | 1303 |
| 1297 bool Address::CanHoldStoreOffset(StoreOperandType type, int offset) { | 1304 bool Address::CanHoldStoreOffset(StoreOperandType type, |
| 1305 int32_t offset, |
| 1306 int32_t* offset_mask) { |
| 1298 switch (type) { | 1307 switch (type) { |
| 1299 case kStoreHalfword: | 1308 case kStoreHalfword: |
| 1300 case kStoreWordPair: | 1309 case kStoreWordPair: { |
| 1310 *offset_mask = 0xff; |
| 1301 return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3. | 1311 return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3. |
| 1312 } |
| 1302 case kStoreByte: | 1313 case kStoreByte: |
| 1303 case kStoreWord: | 1314 case kStoreWord: { |
| 1315 *offset_mask = 0xfff; |
| 1304 return Utils::IsAbsoluteUint(12, offset); // Addressing mode 2. | 1316 return Utils::IsAbsoluteUint(12, offset); // Addressing mode 2. |
| 1317 } |
| 1305 case kStoreSWord: | 1318 case kStoreSWord: |
| 1306 case kStoreDWord: | 1319 case kStoreDWord: { |
| 1320 *offset_mask = 0x3ff; |
| 1307 return Utils::IsAbsoluteUint(10, offset); // VFP addressing mode. | 1321 return Utils::IsAbsoluteUint(10, offset); // VFP addressing mode. |
| 1308 default: | 1322 } |
| 1323 default: { |
| 1309 UNREACHABLE(); | 1324 UNREACHABLE(); |
| 1310 return false; | 1325 return false; |
| 1326 } |
| 1311 } | 1327 } |
| 1312 } | 1328 } |
| 1313 | 1329 |
| 1314 | 1330 |
| 1315 void Assembler::Push(Register rd, Condition cond) { | 1331 void Assembler::Push(Register rd, Condition cond) { |
| 1316 str(rd, Address(SP, -kWordSize, Address::PreIndex), cond); | 1332 str(rd, Address(SP, -kWordSize, Address::PreIndex), cond); |
| 1317 } | 1333 } |
| 1318 | 1334 |
| 1319 | 1335 |
| 1320 void Assembler::Pop(Register rd, Condition cond) { | 1336 void Assembler::Pop(Register rd, Condition cond) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1386 } | 1402 } |
| 1387 | 1403 |
| 1388 | 1404 |
| 1389 void Assembler::BranchLinkPatchable(const ExternalLabel* label) { | 1405 void Assembler::BranchLinkPatchable(const ExternalLabel* label) { |
| 1390 // Make sure that class CallPattern is able to patch the label referred | 1406 // Make sure that class CallPattern is able to patch the label referred |
| 1391 // to by this code sequence. | 1407 // to by this code sequence. |
| 1392 // For added code robustness, use 'blx lr' in a patchable sequence and | 1408 // For added code robustness, use 'blx lr' in a patchable sequence and |
| 1393 // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). | 1409 // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). |
| 1394 const int32_t offset = | 1410 const int32_t offset = |
| 1395 Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag; | 1411 Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag; |
| 1396 if (Address::CanHoldLoadOffset(kLoadWord, offset)) { | 1412 int32_t offset_mask; |
| 1413 if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) { |
| 1397 ldr(LR, Address(PP, offset)); | 1414 ldr(LR, Address(PP, offset)); |
| 1398 } else { | 1415 } else { |
| 1399 int32_t offset12_hi = offset & ~kOffset12Mask; // signed | 1416 int32_t offset_hi = offset & ~offset_mask; // signed |
| 1400 uint32_t offset12_lo = offset & kOffset12Mask; // unsigned | 1417 uint32_t offset_lo = offset & offset_mask; // unsigned |
| 1401 // Inline a simplified version of AddImmediate(LR, CP, offset12_hi). | 1418 // Inline a simplified version of AddImmediate(LR, CP, offset_hi). |
| 1402 ShifterOperand shifter_op; | 1419 ShifterOperand shifter_op; |
| 1403 if (ShifterOperand::CanHold(offset12_hi, &shifter_op)) { | 1420 if (ShifterOperand::CanHold(offset_hi, &shifter_op)) { |
| 1404 add(LR, PP, shifter_op); | 1421 add(LR, PP, shifter_op); |
| 1405 } else { | 1422 } else { |
| 1406 movw(LR, Utils::Low16Bits(offset12_hi)); | 1423 movw(LR, Utils::Low16Bits(offset_hi)); |
| 1407 const uint16_t value_high = Utils::High16Bits(offset12_hi); | 1424 const uint16_t value_high = Utils::High16Bits(offset_hi); |
| 1408 if (value_high != 0) { | 1425 if (value_high != 0) { |
| 1409 movt(LR, value_high); | 1426 movt(LR, value_high); |
| 1410 } | 1427 } |
| 1411 add(LR, PP, ShifterOperand(LR)); | 1428 add(LR, PP, ShifterOperand(LR)); |
| 1412 } | 1429 } |
| 1413 ldr(LR, Address(LR, offset12_lo)); | 1430 ldr(LR, Address(LR, offset_lo)); |
| 1414 } | 1431 } |
| 1415 blx(LR); // Use blx instruction so that the return branch prediction works. | 1432 blx(LR); // Use blx instruction so that the return branch prediction works. |
| 1416 } | 1433 } |
| 1417 | 1434 |
| 1418 | 1435 |
| 1419 void Assembler::BranchLinkStore(const ExternalLabel* label, Address ad) { | 1436 void Assembler::BranchLinkStore(const ExternalLabel* label, Address ad) { |
| 1420 // TODO(regis): Revisit this code sequence. | 1437 // TODO(regis): Revisit this code sequence. |
| 1421 LoadImmediate(IP, label->address()); // Target address is never patched. | 1438 LoadImmediate(IP, label->address()); // Target address is never patched. |
| 1422 str(PC, ad); | 1439 str(PC, ad); |
| 1423 blx(IP); // Use blx instruction so that the return branch prediction works. | 1440 blx(IP); // Use blx instruction so that the return branch prediction works. |
| 1424 } | 1441 } |
| 1425 | 1442 |
| 1426 | 1443 |
| 1427 void Assembler::BranchLinkOffset(Register base, int offset) { | 1444 void Assembler::BranchLinkOffset(Register base, int offset) { |
| 1428 ASSERT(base != PC); | 1445 ASSERT(base != PC); |
| 1429 ASSERT(base != IP); | 1446 ASSERT(base != IP); |
| 1430 if (Address::CanHoldLoadOffset(kLoadWord, offset)) { | 1447 int32_t offset_mask; |
| 1448 if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) { |
| 1431 ldr(IP, Address(base, offset)); | 1449 ldr(IP, Address(base, offset)); |
| 1432 } else { | 1450 } else { |
| 1433 int offset_hi = offset & ~kOffset12Mask; | 1451 int offset_hi = offset & ~offset_mask; |
| 1434 int offset_lo = offset & kOffset12Mask; | 1452 int offset_lo = offset & offset_mask; |
| 1435 ShifterOperand offset_hi_op; | 1453 ShifterOperand offset_hi_op; |
| 1436 if (ShifterOperand::CanHold(offset_hi, &offset_hi_op)) { | 1454 if (ShifterOperand::CanHold(offset_hi, &offset_hi_op)) { |
| 1437 add(IP, base, offset_hi_op); | 1455 add(IP, base, offset_hi_op); |
| 1438 ldr(IP, Address(IP, offset_lo)); | 1456 ldr(IP, Address(IP, offset_lo)); |
| 1439 } else { | 1457 } else { |
| 1440 LoadImmediate(IP, offset_hi); | 1458 LoadImmediate(IP, offset_hi); |
| 1441 add(IP, IP, ShifterOperand(base)); | 1459 add(IP, IP, ShifterOperand(base)); |
| 1442 ldr(IP, Address(IP, offset_lo)); | 1460 ldr(IP, Address(IP, offset_lo)); |
| 1443 } | 1461 } |
| 1444 } | 1462 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1486 vmovdrr(dd, IP, scratch, cond); | 1504 vmovdrr(dd, IP, scratch, cond); |
| 1487 } | 1505 } |
| 1488 } | 1506 } |
| 1489 | 1507 |
| 1490 | 1508 |
| 1491 void Assembler::LoadFromOffset(LoadOperandType type, | 1509 void Assembler::LoadFromOffset(LoadOperandType type, |
| 1492 Register reg, | 1510 Register reg, |
| 1493 Register base, | 1511 Register base, |
| 1494 int32_t offset, | 1512 int32_t offset, |
| 1495 Condition cond) { | 1513 Condition cond) { |
| 1496 if (!Address::CanHoldLoadOffset(type, offset)) { | 1514 int32_t offset_mask; |
| 1515 if (!Address::CanHoldLoadOffset(type, offset, &offset_mask)) { |
| 1497 ASSERT(base != IP); | 1516 ASSERT(base != IP); |
| 1498 LoadImmediate(IP, offset, cond); | 1517 AddImmediate(IP, base, offset & ~offset_mask, cond); |
| 1499 add(IP, IP, ShifterOperand(base), cond); | |
| 1500 base = IP; | 1518 base = IP; |
| 1501 offset = 0; | 1519 offset = offset & offset_mask; |
| 1502 } | 1520 } |
| 1503 ASSERT(Address::CanHoldLoadOffset(type, offset)); | |
| 1504 switch (type) { | 1521 switch (type) { |
| 1505 case kLoadSignedByte: | 1522 case kLoadSignedByte: |
| 1506 ldrsb(reg, Address(base, offset), cond); | 1523 ldrsb(reg, Address(base, offset), cond); |
| 1507 break; | 1524 break; |
| 1508 case kLoadUnsignedByte: | 1525 case kLoadUnsignedByte: |
| 1509 ldrb(reg, Address(base, offset), cond); | 1526 ldrb(reg, Address(base, offset), cond); |
| 1510 break; | 1527 break; |
| 1511 case kLoadSignedHalfword: | 1528 case kLoadSignedHalfword: |
| 1512 ldrsh(reg, Address(base, offset), cond); | 1529 ldrsh(reg, Address(base, offset), cond); |
| 1513 break; | 1530 break; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1524 UNREACHABLE(); | 1541 UNREACHABLE(); |
| 1525 } | 1542 } |
| 1526 } | 1543 } |
| 1527 | 1544 |
| 1528 | 1545 |
| 1529 void Assembler::StoreToOffset(StoreOperandType type, | 1546 void Assembler::StoreToOffset(StoreOperandType type, |
| 1530 Register reg, | 1547 Register reg, |
| 1531 Register base, | 1548 Register base, |
| 1532 int32_t offset, | 1549 int32_t offset, |
| 1533 Condition cond) { | 1550 Condition cond) { |
| 1534 if (!Address::CanHoldStoreOffset(type, offset)) { | 1551 int32_t offset_mask; |
| 1552 if (!Address::CanHoldStoreOffset(type, offset, &offset_mask)) { |
| 1535 ASSERT(reg != IP); | 1553 ASSERT(reg != IP); |
| 1536 ASSERT(base != IP); | 1554 ASSERT(base != IP); |
| 1537 LoadImmediate(IP, offset, cond); | 1555 AddImmediate(IP, base, offset & ~offset_mask, cond); |
| 1538 add(IP, IP, ShifterOperand(base), cond); | |
| 1539 base = IP; | 1556 base = IP; |
| 1540 offset = 0; | 1557 offset = offset & offset_mask; |
| 1541 } | 1558 } |
| 1542 ASSERT(Address::CanHoldStoreOffset(type, offset)); | |
| 1543 switch (type) { | 1559 switch (type) { |
| 1544 case kStoreByte: | 1560 case kStoreByte: |
| 1545 strb(reg, Address(base, offset), cond); | 1561 strb(reg, Address(base, offset), cond); |
| 1546 break; | 1562 break; |
| 1547 case kStoreHalfword: | 1563 case kStoreHalfword: |
| 1548 strh(reg, Address(base, offset), cond); | 1564 strh(reg, Address(base, offset), cond); |
| 1549 break; | 1565 break; |
| 1550 case kStoreWord: | 1566 case kStoreWord: |
| 1551 str(reg, Address(base, offset), cond); | 1567 str(reg, Address(base, offset), cond); |
| 1552 break; | 1568 break; |
| 1553 case kStoreWordPair: | 1569 case kStoreWordPair: |
| 1554 strd(reg, Address(base, offset), cond); | 1570 strd(reg, Address(base, offset), cond); |
| 1555 break; | 1571 break; |
| 1556 default: | 1572 default: |
| 1557 UNREACHABLE(); | 1573 UNREACHABLE(); |
| 1558 } | 1574 } |
| 1559 } | 1575 } |
| 1560 | 1576 |
| 1561 | 1577 |
| 1562 void Assembler::LoadSFromOffset(SRegister reg, | 1578 void Assembler::LoadSFromOffset(SRegister reg, |
| 1563 Register base, | 1579 Register base, |
| 1564 int32_t offset, | 1580 int32_t offset, |
| 1565 Condition cond) { | 1581 Condition cond) { |
| 1566 if (!Address::CanHoldLoadOffset(kLoadSWord, offset)) { | 1582 int32_t offset_mask; |
| 1583 if (!Address::CanHoldLoadOffset(kLoadSWord, offset, &offset_mask)) { |
| 1567 ASSERT(base != IP); | 1584 ASSERT(base != IP); |
| 1568 LoadImmediate(IP, offset, cond); | 1585 AddImmediate(IP, base, offset & ~offset_mask, cond); |
| 1569 add(IP, IP, ShifterOperand(base), cond); | |
| 1570 base = IP; | 1586 base = IP; |
| 1571 offset = 0; | 1587 offset = offset & offset_mask; |
| 1572 } | 1588 } |
| 1573 ASSERT(Address::CanHoldLoadOffset(kLoadSWord, offset)); | |
| 1574 vldrs(reg, Address(base, offset), cond); | 1589 vldrs(reg, Address(base, offset), cond); |
| 1575 } | 1590 } |
| 1576 | 1591 |
| 1577 | 1592 |
| 1578 void Assembler::StoreSToOffset(SRegister reg, | 1593 void Assembler::StoreSToOffset(SRegister reg, |
| 1579 Register base, | 1594 Register base, |
| 1580 int32_t offset, | 1595 int32_t offset, |
| 1581 Condition cond) { | 1596 Condition cond) { |
| 1582 if (!Address::CanHoldStoreOffset(kStoreSWord, offset)) { | 1597 int32_t offset_mask; |
| 1598 if (!Address::CanHoldStoreOffset(kStoreSWord, offset, &offset_mask)) { |
| 1583 ASSERT(base != IP); | 1599 ASSERT(base != IP); |
| 1584 LoadImmediate(IP, offset, cond); | 1600 AddImmediate(IP, base, offset & ~offset_mask, cond); |
| 1585 add(IP, IP, ShifterOperand(base), cond); | |
| 1586 base = IP; | 1601 base = IP; |
| 1587 offset = 0; | 1602 offset = offset & offset_mask; |
| 1588 } | 1603 } |
| 1589 ASSERT(Address::CanHoldStoreOffset(kStoreSWord, offset)); | |
| 1590 vstrs(reg, Address(base, offset), cond); | 1604 vstrs(reg, Address(base, offset), cond); |
| 1591 } | 1605 } |
| 1592 | 1606 |
| 1593 | 1607 |
| 1594 void Assembler::LoadDFromOffset(DRegister reg, | 1608 void Assembler::LoadDFromOffset(DRegister reg, |
| 1595 Register base, | 1609 Register base, |
| 1596 int32_t offset, | 1610 int32_t offset, |
| 1597 Condition cond) { | 1611 Condition cond) { |
| 1598 if (!Address::CanHoldLoadOffset(kLoadDWord, offset)) { | 1612 int32_t offset_mask; |
| 1613 if (!Address::CanHoldLoadOffset(kLoadDWord, offset, &offset_mask)) { |
| 1599 ASSERT(base != IP); | 1614 ASSERT(base != IP); |
| 1600 LoadImmediate(IP, offset, cond); | 1615 AddImmediate(IP, base, offset & ~offset_mask, cond); |
| 1601 add(IP, IP, ShifterOperand(base), cond); | |
| 1602 base = IP; | 1616 base = IP; |
| 1603 offset = 0; | 1617 offset = offset & offset_mask; |
| 1604 } | 1618 } |
| 1605 ASSERT(Address::CanHoldLoadOffset(kLoadDWord, offset)); | |
| 1606 vldrd(reg, Address(base, offset), cond); | 1619 vldrd(reg, Address(base, offset), cond); |
| 1607 } | 1620 } |
| 1608 | 1621 |
| 1609 | 1622 |
| 1610 void Assembler::StoreDToOffset(DRegister reg, | 1623 void Assembler::StoreDToOffset(DRegister reg, |
| 1611 Register base, | 1624 Register base, |
| 1612 int32_t offset, | 1625 int32_t offset, |
| 1613 Condition cond) { | 1626 Condition cond) { |
| 1614 if (!Address::CanHoldStoreOffset(kStoreDWord, offset)) { | 1627 int32_t offset_mask; |
| 1628 if (!Address::CanHoldStoreOffset(kStoreDWord, offset, &offset_mask)) { |
| 1615 ASSERT(base != IP); | 1629 ASSERT(base != IP); |
| 1616 LoadImmediate(IP, offset, cond); | 1630 AddImmediate(IP, base, offset & ~offset_mask, cond); |
| 1617 add(IP, IP, ShifterOperand(base), cond); | |
| 1618 base = IP; | 1631 base = IP; |
| 1619 offset = 0; | 1632 offset = offset & offset_mask; |
| 1620 } | 1633 } |
| 1621 ASSERT(Address::CanHoldStoreOffset(kStoreDWord, offset)); | |
| 1622 vstrd(reg, Address(base, offset), cond); | 1634 vstrd(reg, Address(base, offset), cond); |
| 1623 } | 1635 } |
| 1624 | 1636 |
| 1625 | 1637 |
| 1626 void Assembler::AddImmediate(Register rd, int32_t value, Condition cond) { | 1638 void Assembler::AddImmediate(Register rd, int32_t value, Condition cond) { |
| 1627 AddImmediate(rd, rd, value, cond); | 1639 AddImmediate(rd, rd, value, cond); |
| 1628 } | 1640 } |
| 1629 | 1641 |
| 1630 | 1642 |
| 1631 void Assembler::AddImmediate(Register rd, Register rn, int32_t value, | 1643 void Assembler::AddImmediate(Register rd, Register rn, int32_t value, |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1777 bic(SP, SP, ShifterOperand(OS::ActivationFrameAlignment() - 1)); | 1789 bic(SP, SP, ShifterOperand(OS::ActivationFrameAlignment() - 1)); |
| 1778 } | 1790 } |
| 1779 } | 1791 } |
| 1780 | 1792 |
| 1781 | 1793 |
| 1782 void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) { | 1794 void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) { |
| 1783 // Preserve volatile CPU registers. | 1795 // Preserve volatile CPU registers. |
| 1784 EnterFrame(kDartVolatileCpuRegs | (1 << FP), 0); | 1796 EnterFrame(kDartVolatileCpuRegs | (1 << FP), 0); |
| 1785 | 1797 |
| 1786 // Preserve all volatile FPU registers. | 1798 // Preserve all volatile FPU registers. |
| 1787 // TODO(regis): Use vstmd instruction once supported. | 1799 vstmd(DB_W, SP, kDartFirstVolatileFpuReg, kDartLastVolatileFpuReg); |
| 1788 // vstmd(DB_W, SP, kDartFirstVolatileFpuReg, kDartLastVolatileFpuReg); | |
| 1789 | 1800 |
| 1790 ReserveAlignedFrameSpace(frame_space); | 1801 ReserveAlignedFrameSpace(frame_space); |
| 1791 } | 1802 } |
| 1792 | 1803 |
| 1793 | 1804 |
| 1794 void Assembler::LeaveCallRuntimeFrame() { | 1805 void Assembler::LeaveCallRuntimeFrame() { |
| 1795 // SP might have been modified to reserve space for arguments | 1806 // SP might have been modified to reserve space for arguments |
| 1796 // and ensure proper alignment of the stack frame. | 1807 // and ensure proper alignment of the stack frame. |
| 1797 // We need to restore it before restoring registers. | 1808 // We need to restore it before restoring registers. |
| 1798 const intptr_t kPushedRegistersSize = | 1809 const intptr_t kPushedRegistersSize = |
| 1799 kDartVolatileCpuRegCount * kWordSize; | 1810 kDartVolatileCpuRegCount * kWordSize + |
| 1800 // TODO(regis): + kDartVolatileFpuRegCount * 2 * kWordSize; | 1811 kDartVolatileFpuRegCount * 2 * kWordSize; |
| 1801 AddImmediate(SP, FP, -kPushedRegistersSize); | 1812 AddImmediate(SP, FP, -kPushedRegistersSize); |
| 1802 | 1813 |
| 1803 // Restore all volatile FPU registers. | 1814 // Restore all volatile FPU registers. |
| 1804 // TODO(regis): Use vldmd instruction once supported. | 1815 vldmd(IA_W, SP, kDartFirstVolatileFpuReg, kDartLastVolatileFpuReg); |
| 1805 // vldmd(IA_W, SP, kDartFirstVolatileFpuReg, kDartLastVolatileFpuReg); | |
| 1806 | 1816 |
| 1807 // Restore volatile CPU registers. | 1817 // Restore volatile CPU registers. |
| 1808 LeaveFrame(kDartVolatileCpuRegs | (1 << FP)); | 1818 LeaveFrame(kDartVolatileCpuRegs | (1 << FP)); |
| 1809 } | 1819 } |
| 1810 | 1820 |
| 1811 | 1821 |
| 1812 void Assembler::CallRuntime(const RuntimeEntry& entry) { | 1822 void Assembler::CallRuntime(const RuntimeEntry& entry) { |
| 1813 entry.Call(this); | 1823 entry.Call(this); |
| 1814 } | 1824 } |
| 1815 | 1825 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1936 // Do not reuse an existing entry, since each reference may be patched | 1946 // Do not reuse an existing entry, since each reference may be patched |
| 1937 // independently. | 1947 // independently. |
| 1938 object_pool_.Add(smi); | 1948 object_pool_.Add(smi); |
| 1939 return object_pool_.Length() - 1; | 1949 return object_pool_.Length() - 1; |
| 1940 } | 1950 } |
| 1941 | 1951 |
| 1942 } // namespace dart | 1952 } // namespace dart |
| 1943 | 1953 |
| 1944 #endif // defined TARGET_ARCH_ARM | 1954 #endif // defined TARGET_ARCH_ARM |
| 1945 | 1955 |
| OLD | NEW |