| OLD | NEW |
| 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// | 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| (...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 674 } | 674 } |
| 675 | 675 |
| 676 ForbidTemporaryWithoutReg _(this); | 676 ForbidTemporaryWithoutReg _(this); |
| 677 | 677 |
| 678 // Stack frame mapping. | 678 // Stack frame mapping. |
| 679 Func->genFrame(); | 679 Func->genFrame(); |
| 680 if (Func->hasError()) | 680 if (Func->hasError()) |
| 681 return; | 681 return; |
| 682 Func->dump("After stack frame mapping"); | 682 Func->dump("After stack frame mapping"); |
| 683 | 683 |
| 684 legalizeStackSlots(); | 684 postLowerLegalization(); |
| 685 if (Func->hasError()) | 685 if (Func->hasError()) |
| 686 return; | 686 return; |
| 687 Func->dump("After legalizeStackSlots"); | 687 Func->dump("After postLowerLegalization"); |
| 688 | 688 |
| 689 Func->contractEmptyNodes(); | 689 Func->contractEmptyNodes(); |
| 690 Func->reorderNodes(); | 690 Func->reorderNodes(); |
| 691 | 691 |
| 692 // Branch optimization. This needs to be done just before code emission. In | 692 // Branch optimization. This needs to be done just before code emission. In |
| 693 // particular, no transformations that insert or reorder CfgNodes should be | 693 // particular, no transformations that insert or reorder CfgNodes should be |
| 694 // done after branch optimization. We go ahead and do it before nop insertion | 694 // done after branch optimization. We go ahead and do it before nop insertion |
| 695 // to reduce the amount of work needed for searching for opportunities. | 695 // to reduce the amount of work needed for searching for opportunities. |
| 696 Func->doBranchOpt(); | 696 Func->doBranchOpt(); |
| 697 Func->dump("After branch optimization"); | 697 Func->dump("After branch optimization"); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 739 copyRegAllocFromInfWeightVariable64On32(Func->getVariables()); | 739 copyRegAllocFromInfWeightVariable64On32(Func->getVariables()); |
| 740 Func->dump("After regalloc of infinite-weight variables"); | 740 Func->dump("After regalloc of infinite-weight variables"); |
| 741 | 741 |
| 742 ForbidTemporaryWithoutReg _(this); | 742 ForbidTemporaryWithoutReg _(this); |
| 743 | 743 |
| 744 Func->genFrame(); | 744 Func->genFrame(); |
| 745 if (Func->hasError()) | 745 if (Func->hasError()) |
| 746 return; | 746 return; |
| 747 Func->dump("After stack frame mapping"); | 747 Func->dump("After stack frame mapping"); |
| 748 | 748 |
| 749 legalizeStackSlots(); | 749 postLowerLegalization(); |
| 750 if (Func->hasError()) | 750 if (Func->hasError()) |
| 751 return; | 751 return; |
| 752 Func->dump("After legalizeStackSlots"); | 752 Func->dump("After postLowerLegalization"); |
| 753 | 753 |
| 754 // Nop insertion | 754 // Nop insertion |
| 755 if (Ctx->getFlags().shouldDoNopInsertion()) { | 755 if (Ctx->getFlags().shouldDoNopInsertion()) { |
| 756 Func->doNopInsertion(); | 756 Func->doNopInsertion(); |
| 757 } | 757 } |
| 758 } | 758 } |
| 759 | 759 |
| 760 uint32_t TargetARM32::getStackAlignment() const { | 760 uint32_t TargetARM32::getStackAlignment() const { |
| 761 return ARM32_STACK_ALIGNMENT_BYTES; | 761 return ARM32_STACK_ALIGNMENT_BYTES; |
| 762 } | 762 } |
| (...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1329 _ret(LR, RetValue); | 1329 _ret(LR, RetValue); |
| 1330 _bundle_unlock(); | 1330 _bundle_unlock(); |
| 1331 RI->setDeleted(); | 1331 RI->setDeleted(); |
| 1332 } | 1332 } |
| 1333 | 1333 |
| 1334 bool TargetARM32::isLegalMemOffset(Type Ty, int32_t Offset) const { | 1334 bool TargetARM32::isLegalMemOffset(Type Ty, int32_t Offset) const { |
| 1335 constexpr bool ZeroExt = false; | 1335 constexpr bool ZeroExt = false; |
| 1336 return OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset); | 1336 return OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset); |
| 1337 } | 1337 } |
| 1338 | 1338 |
| 1339 Variable *TargetARM32::newBaseRegister(int32_t Offset, Variable *OrigBaseReg) { | 1339 Variable *TargetARM32::PostLoweringLegalizer::newBaseRegister( |
| 1340 Variable *Base, int32_t Offset, int32_t ScratchRegNum) { |
| 1340 // Legalize will likely need a movw/movt combination, but if the top bits are | 1341 // Legalize will likely need a movw/movt combination, but if the top bits are |
| 1341 // all 0 from negating the offset and subtracting, we could use that instead. | 1342 // all 0 from negating the offset and subtracting, we could use that instead. |
| 1342 bool ShouldSub = (-Offset & 0xFFFF0000) == 0; | 1343 bool ShouldSub = (-Offset & 0xFFFF0000) == 0; |
| 1343 if (ShouldSub) | 1344 if (ShouldSub) |
| 1344 Offset = -Offset; | 1345 Offset = -Offset; |
| 1345 Operand *OffsetVal = legalize(Ctx->getConstantInt32(Offset), | 1346 Operand *OffsetVal = Target->legalize(Target->Ctx->getConstantInt32(Offset), |
| 1346 Legal_Reg | Legal_Flex, getReservedTmpReg()); | 1347 Legal_Reg | Legal_Flex, ScratchRegNum); |
| 1347 Variable *ScratchReg = makeReg(IceType_i32, getReservedTmpReg()); | 1348 Variable *ScratchReg = Target->makeReg(IceType_i32, ScratchRegNum); |
| 1348 if (ShouldSub) | 1349 if (ShouldSub) |
| 1349 _sub(ScratchReg, OrigBaseReg, OffsetVal); | 1350 Target->_sub(ScratchReg, Base, OffsetVal); |
| 1350 else | 1351 else |
| 1351 _add(ScratchReg, OrigBaseReg, OffsetVal); | 1352 Target->_add(ScratchReg, Base, OffsetVal); |
| 1353 |
| 1354 if (ScratchRegNum == Target->getReservedTmpReg()) { |
| 1355 const bool BaseIsStackOrFramePtr = |
| 1356 Base->getRegNum() == static_cast<int32_t>(Target->getFrameOrStackReg()); |
| 1357 // There is currently no code path that would trigger this assertion, so we |
| 1358 // leave this assertion here in case it is ever violated. This is not a |
| 1359 // fatal error (thus the use of assert() and not llvm::report_fatal_error) |
| 1360 // as the program compiled by subzero will still work correctly. |
| 1361 assert(BaseIsStackOrFramePtr); |
| 1362 // Side-effect: updates TempBase to reflect the new Temporary. |
| 1363 if (BaseIsStackOrFramePtr) { |
| 1364 TempBaseReg = ScratchReg; |
| 1365 TempBaseOffset = ShouldSub ? -Offset : Offset; |
| 1366 } else { |
| 1367 TempBaseReg = nullptr; |
| 1368 TempBaseOffset = 0; |
| 1369 } |
| 1370 } |
| 1371 |
| 1352 return ScratchReg; | 1372 return ScratchReg; |
| 1353 } | 1373 } |
| 1354 | 1374 |
| 1355 OperandARM32Mem *TargetARM32::createMemOperand(Type Ty, int32_t Offset, | 1375 OperandARM32Mem *TargetARM32::PostLoweringLegalizer::createMemOperand( |
| 1356 Variable *OrigBaseReg, | 1376 Type Ty, Variable *Base, int32_t Offset, bool AllowOffsets) { |
| 1357 Variable **NewBaseReg, | 1377 assert(!Base->isRematerializable()); |
| 1358 int32_t *NewBaseOffset) { | 1378 if (AllowOffsets && Target->isLegalMemOffset(Ty, Offset)) { |
| 1359 assert(!OrigBaseReg->isRematerializable()); | |
| 1360 if (isLegalMemOffset(Ty, Offset)) { | |
| 1361 return OperandARM32Mem::create( | 1379 return OperandARM32Mem::create( |
| 1362 Func, Ty, OrigBaseReg, | 1380 Target->Func, Ty, Base, |
| 1363 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(Offset)), | 1381 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)), |
| 1364 OperandARM32Mem::Offset); | 1382 OperandARM32Mem::Offset); |
| 1365 } | 1383 } |
| 1366 | 1384 |
| 1367 if (*NewBaseReg == nullptr) { | 1385 if (!AllowOffsets || TempBaseReg == nullptr) { |
| 1368 *NewBaseReg = newBaseRegister(Offset, OrigBaseReg); | 1386 newBaseRegister(Base, Offset, Target->getReservedTmpReg()); |
| 1369 *NewBaseOffset = Offset; | |
| 1370 } | 1387 } |
| 1371 | 1388 |
| 1372 int32_t OffsetDiff = Offset - *NewBaseOffset; | 1389 int32_t OffsetDiff = Offset - TempBaseOffset; |
| 1373 if (!isLegalMemOffset(Ty, OffsetDiff)) { | 1390 assert(AllowOffsets || OffsetDiff == 0); |
| 1374 *NewBaseReg = newBaseRegister(Offset, OrigBaseReg); | 1391 |
| 1375 *NewBaseOffset = Offset; | 1392 if (!Target->isLegalMemOffset(Ty, OffsetDiff)) { |
| 1393 newBaseRegister(Base, Offset, Target->getReservedTmpReg()); |
| 1376 OffsetDiff = 0; | 1394 OffsetDiff = 0; |
| 1377 } | 1395 } |
| 1378 | 1396 |
| 1379 assert(!(*NewBaseReg)->isRematerializable()); | 1397 assert(!TempBaseReg->isRematerializable()); |
| 1380 return OperandARM32Mem::create( | 1398 return OperandARM32Mem::create( |
| 1381 Func, Ty, *NewBaseReg, | 1399 Target->Func, Ty, TempBaseReg, |
| 1382 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetDiff)), | 1400 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(OffsetDiff)), |
| 1383 OperandARM32Mem::Offset); | 1401 OperandARM32Mem::Offset); |
| 1384 } | 1402 } |
| 1385 | 1403 |
| 1386 void TargetARM32::legalizeMov(InstARM32Mov *MovInstr, Variable *OrigBaseReg, | 1404 void TargetARM32::PostLoweringLegalizer::resetTempBaseIfClobberedBy( |
| 1387 Variable **NewBaseReg, int32_t *NewBaseOffset) { | 1405 const Inst *Instr) { |
| 1406 bool ClobbersTempBase = false; |
| 1407 if (TempBaseReg != nullptr) { |
| 1408 Variable *Dest = Instr->getDest(); |
| 1409 if (llvm::isa<InstARM32Call>(Instr)) { |
| 1410 // The following assertion is an invariant, so we remove it from the if |
| 1411 // test. If the invariant is ever broken/invalidated/changed, remember |
| 1412 // to add it back to the if condition. |
| 1413 assert(TempBaseReg->getRegNum() == Target->getReservedTmpReg()); |
| 1414 // The linker may need to clobber IP if the call is too far from PC. Thus, |
| 1415 // we assume IP will be overwritten. |
| 1416 ClobbersTempBase = true; |
| 1417 } else if (Dest != nullptr && |
| 1418 Dest->getRegNum() == TempBaseReg->getRegNum()) { |
| 1419 // Register redefinition. |
| 1420 ClobbersTempBase = true; |
| 1421 } |
| 1422 } |
| 1423 |
| 1424 if (ClobbersTempBase) { |
| 1425 TempBaseReg = nullptr; |
| 1426 TempBaseOffset = 0; |
| 1427 } |
| 1428 } |
| 1429 |
| 1430 void TargetARM32::PostLoweringLegalizer::legalizeMov(InstARM32Mov *MovInstr) { |
| 1388 Variable *Dest = MovInstr->getDest(); | 1431 Variable *Dest = MovInstr->getDest(); |
| 1389 assert(Dest != nullptr); | 1432 assert(Dest != nullptr); |
| 1390 Type DestTy = Dest->getType(); | 1433 Type DestTy = Dest->getType(); |
| 1391 assert(DestTy != IceType_i64); | 1434 assert(DestTy != IceType_i64); |
| 1392 | 1435 |
| 1393 Operand *Src = MovInstr->getSrc(0); | 1436 Operand *Src = MovInstr->getSrc(0); |
| 1394 Type SrcTy = Src->getType(); | 1437 Type SrcTy = Src->getType(); |
| 1395 (void)SrcTy; | 1438 (void)SrcTy; |
| 1396 assert(SrcTy != IceType_i64); | 1439 assert(SrcTy != IceType_i64); |
| 1397 | 1440 |
| 1398 if (MovInstr->isMultiDest() || MovInstr->isMultiSource()) | 1441 if (MovInstr->isMultiDest() || MovInstr->isMultiSource()) |
| 1399 return; | 1442 return; |
| 1400 | 1443 |
| 1401 bool Legalized = false; | 1444 bool Legalized = false; |
| 1402 if (!Dest->hasReg()) { | 1445 if (!Dest->hasReg()) { |
| 1403 auto *SrcR = llvm::cast<Variable>(Src); | 1446 auto *SrcR = llvm::cast<Variable>(Src); |
| 1404 assert(SrcR->hasReg()); | 1447 assert(SrcR->hasReg()); |
| 1405 assert(!SrcR->isRematerializable()); | 1448 assert(!SrcR->isRematerializable()); |
| 1406 const int32_t Offset = Dest->getStackOffset(); | 1449 const int32_t Offset = Dest->getStackOffset(); |
| 1407 // This is a _mov(Mem(), Variable), i.e., a store. | 1450 // This is a _mov(Mem(), Variable), i.e., a store. |
| 1408 _str(SrcR, createMemOperand(DestTy, Offset, OrigBaseReg, NewBaseReg, | 1451 Target->_str(SrcR, createMemOperand(DestTy, StackOrFrameReg, Offset), |
| 1409 NewBaseOffset), | 1452 MovInstr->getPredicate()); |
| 1410 MovInstr->getPredicate()); | |
| 1411 // _str() does not have a Dest, so we add a fake-def(Dest). | 1453 // _str() does not have a Dest, so we add a fake-def(Dest). |
| 1412 Context.insert(InstFakeDef::create(Func, Dest)); | 1454 Target->Context.insert(InstFakeDef::create(Target->Func, Dest)); |
| 1413 Legalized = true; | 1455 Legalized = true; |
| 1414 } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) { | 1456 } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) { |
| 1415 if (Var->isRematerializable()) { | 1457 if (Var->isRematerializable()) { |
| 1416 // Rematerialization arithmetic. | 1458 // This is equivalent to an x86 _lea(RematOffset(%esp/%ebp), Variable). |
| 1459 |
| 1460 // ExtraOffset is only needed for frame-pointer based frames as we have |
| 1461 // to account for spill storage. |
| 1417 const int32_t ExtraOffset = | 1462 const int32_t ExtraOffset = |
| 1418 (static_cast<SizeT>(Var->getRegNum()) == getFrameReg()) | 1463 (static_cast<SizeT>(Var->getRegNum()) == Target->getFrameReg()) |
| 1419 ? getFrameFixedAllocaOffset() | 1464 ? Target->getFrameFixedAllocaOffset() |
| 1420 : 0; | 1465 : 0; |
| 1421 | 1466 |
| 1422 const int32_t Offset = Var->getStackOffset() + ExtraOffset; | 1467 const int32_t Offset = Var->getStackOffset() + ExtraOffset; |
| 1423 Operand *OffsetRF = legalize(Ctx->getConstantInt32(Offset), | 1468 Variable *Base = Target->getPhysicalRegister(Var->getRegNum()); |
| 1424 Legal_Reg | Legal_Flex, Dest->getRegNum()); | 1469 Variable *T = newBaseRegister(Base, Offset, Dest->getRegNum()); |
| 1425 _add(Dest, Var, OffsetRF); | 1470 Target->_mov(Dest, T); |
| 1426 Legalized = true; | 1471 Legalized = true; |
| 1427 } else { | 1472 } else { |
| 1428 if (!Var->hasReg()) { | 1473 if (!Var->hasReg()) { |
| 1474 // This is a _mov(Variable, Mem()), i.e., a load. |
| 1429 const int32_t Offset = Var->getStackOffset(); | 1475 const int32_t Offset = Var->getStackOffset(); |
| 1430 _ldr(Dest, createMemOperand(DestTy, Offset, OrigBaseReg, NewBaseReg, | 1476 Target->_ldr(Dest, createMemOperand(DestTy, StackOrFrameReg, Offset), |
| 1431 NewBaseOffset), | 1477 MovInstr->getPredicate()); |
| 1432 MovInstr->getPredicate()); | |
| 1433 Legalized = true; | 1478 Legalized = true; |
| 1434 } | 1479 } |
| 1435 } | 1480 } |
| 1436 } | 1481 } |
| 1437 | 1482 |
| 1438 if (Legalized) { | 1483 if (Legalized) { |
| 1439 if (MovInstr->isDestRedefined()) { | 1484 if (MovInstr->isDestRedefined()) { |
| 1440 _set_dest_redefined(); | 1485 Target->_set_dest_redefined(); |
| 1441 } | 1486 } |
| 1442 MovInstr->setDeleted(); | 1487 MovInstr->setDeleted(); |
| 1443 } | 1488 } |
| 1444 } | 1489 } |
| 1445 | 1490 |
| 1446 void TargetARM32::legalizeStackSlots() { | 1491 // ARM32 address modes: |
| 1492 // ld/st i[8|16|32]: [reg], [reg +/- imm12], [pc +/- imm12], |
| 1493 // [reg +/- reg << shamt5] |
| 1494 // ld/st f[32|64] : [reg], [reg +/- imm8] , [pc +/- imm8] |
| 1495 // ld/st vectors : [reg] |
| 1496 // |
| 1497 // For now, we don't handle address modes with Relocatables. |
| 1498 namespace { |
| 1499 // MemTraits contains per-type valid address mode information. |
| 1500 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ |
| 1501 static_assert(!(shaddr) || rraddr, "Check ICETYPEARM32_TABLE::" #tag); |
| 1502 ICETYPEARM32_TABLE |
| 1503 #undef X |
| 1504 |
| 1505 static const struct { |
| 1506 int32_t ValidImmMask; |
| 1507 bool CanHaveImm; |
| 1508 bool CanHaveIndex; |
| 1509 bool CanHaveShiftedIndex; |
| 1510 } MemTraits[] = { |
| 1511 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ |
| 1512 { (1 << ubits) - 1, (ubits) > 0, rraddr, shaddr, } \ |
| 1513 , |
| 1514 ICETYPEARM32_TABLE |
| 1515 #undef X |
| 1516 }; |
| 1517 static constexpr SizeT MemTraitsSize = llvm::array_lengthof(MemTraits); |
| 1518 } // end of anonymous namespace |
| 1519 |
| 1520 OperandARM32Mem * |
| 1521 TargetARM32::PostLoweringLegalizer::legalizeMemOperand(OperandARM32Mem *Mem, |
| 1522 bool AllowOffsets) { |
| 1523 assert(!Mem->isRegReg() || !Mem->getIndex()->isRematerializable()); |
| 1524 assert( |
| 1525 Mem->isRegReg() || |
| 1526 Target->isLegalMemOffset(Mem->getType(), Mem->getOffset()->getValue())); |
| 1527 |
| 1528 bool Legalized = false; |
| 1529 Variable *Base = Mem->getBase(); |
| 1530 int32_t Offset = Mem->isRegReg() ? 0 : Mem->getOffset()->getValue(); |
| 1531 if (Base->isRematerializable()) { |
| 1532 const int32_t ExtraOffset = |
| 1533 (static_cast<SizeT>(Base->getRegNum()) == Target->getFrameReg()) |
| 1534 ? Target->getFrameFixedAllocaOffset() |
| 1535 : 0; |
| 1536 Offset += Base->getStackOffset() + ExtraOffset; |
| 1537 Base = Target->getPhysicalRegister(Base->getRegNum()); |
| 1538 assert(!Base->isRematerializable()); |
| 1539 Legalized = true; |
| 1540 } |
| 1541 |
| 1542 if (!Legalized) { |
| 1543 return nullptr; |
| 1544 } |
| 1545 |
| 1546 if (!Mem->isRegReg()) { |
| 1547 return createMemOperand(Mem->getType(), Base, Offset, AllowOffsets); |
| 1548 } |
| 1549 |
| 1550 assert(MemTraits[Mem->getType()].CanHaveIndex); |
| 1551 |
| 1552 if (Offset != 0) { |
| 1553 if (TempBaseReg == nullptr) { |
| 1554 Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg()); |
| 1555 } else { |
| 1556 uint32_t Imm8, Rotate; |
| 1557 const int32_t OffsetDiff = Offset - TempBaseOffset; |
| 1558 if (OffsetDiff == 0) { |
| 1559 Base = TempBaseReg; |
| 1560 } else if (OperandARM32FlexImm::canHoldImm(OffsetDiff, &Rotate, &Imm8)) { |
| 1561 auto *OffsetDiffF = OperandARM32FlexImm::create( |
| 1562 Target->Func, IceType_i32, Imm8, Rotate); |
| 1563 Target->_add(TempBaseReg, TempBaseReg, OffsetDiffF); |
| 1564 TempBaseOffset += OffsetDiff; |
| 1565 Base = TempBaseReg; |
| 1566 } else if (OperandARM32FlexImm::canHoldImm(-OffsetDiff, &Rotate, &Imm8)) { |
| 1567 auto *OffsetDiffF = OperandARM32FlexImm::create( |
| 1568 Target->Func, IceType_i32, Imm8, Rotate); |
| 1569 Target->_sub(TempBaseReg, TempBaseReg, OffsetDiffF); |
| 1570 TempBaseOffset += OffsetDiff; |
| 1571 Base = TempBaseReg; |
| 1572 } else { |
| 1573 Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg()); |
| 1574 } |
| 1575 } |
| 1576 } |
| 1577 |
| 1578 return OperandARM32Mem::create(Target->Func, Mem->getType(), Base, |
| 1579 Mem->getIndex(), Mem->getShiftOp(), |
| 1580 Mem->getShiftAmt(), Mem->getAddrMode()); |
| 1581 } |
| 1582 |
| 1583 void TargetARM32::postLowerLegalization() { |
| 1447 // If a stack variable's frame offset doesn't fit, convert from: | 1584 // If a stack variable's frame offset doesn't fit, convert from: |
| 1448 // ldr X, OFF[SP] | 1585 // ldr X, OFF[SP] |
| 1449 // to: | 1586 // to: |
| 1450 // movw/movt TMP, OFF_PART | 1587 // movw/movt TMP, OFF_PART |
| 1451 // add TMP, TMP, SP | 1588 // add TMP, TMP, SP |
| 1452 // ldr X, OFF_MORE[TMP] | 1589 // ldr X, OFF_MORE[TMP] |
| 1453 // | 1590 // |
| 1454 // This is safe because we have reserved TMP, and add for ARM does not | 1591 // This is safe because we have reserved TMP, and add for ARM does not |
| 1455 // clobber the flags register. | 1592 // clobber the flags register. |
| 1456 Func->dump("Before legalizeStackSlots"); | 1593 Func->dump("Before postLowerLegalization"); |
| 1457 assert(hasComputedFrame()); | 1594 assert(hasComputedFrame()); |
| 1458 Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg()); | |
| 1459 // Do a fairly naive greedy clustering for now. Pick the first stack slot | 1595 // Do a fairly naive greedy clustering for now. Pick the first stack slot |
| 1460 // that's out of bounds and make a new base reg using the architecture's temp | 1596 // that's out of bounds and make a new base reg using the architecture's temp |
| 1461 // register. If that works for the next slot, then great. Otherwise, create a | 1597 // register. If that works for the next slot, then great. Otherwise, create a |
| 1462 // new base register, clobbering the previous base register. Never share a | 1598 // new base register, clobbering the previous base register. Never share a |
| 1463 // base reg across different basic blocks. This isn't ideal if local and | 1599 // base reg across different basic blocks. This isn't ideal if local and |
| 1464 // multi-block variables are far apart and their references are interspersed. | 1600 // multi-block variables are far apart and their references are interspersed. |
| 1465 // It may help to be more coordinated about assign stack slot numbers and may | 1601 // It may help to be more coordinated about assign stack slot numbers and may |
| 1466 // help to assign smaller offsets to higher-weight variables so that they | 1602 // help to assign smaller offsets to higher-weight variables so that they |
| 1467 // don't depend on this legalization. | 1603 // don't depend on this legalization. |
| 1468 for (CfgNode *Node : Func->getNodes()) { | 1604 for (CfgNode *Node : Func->getNodes()) { |
| 1469 Context.init(Node); | 1605 Context.init(Node); |
| 1470 Variable *NewBaseReg = nullptr; | 1606 // One legalizer per basic block, otherwise we would share the Temporary |
| 1471 int32_t NewBaseOffset = 0; | 1607 // Base Register between basic blocks. |
| 1608 PostLoweringLegalizer Legalizer(this); |
| 1472 while (!Context.atEnd()) { | 1609 while (!Context.atEnd()) { |
| 1473 PostIncrLoweringContext PostIncrement(Context); | 1610 PostIncrLoweringContext PostIncrement(Context); |
| 1474 Inst *CurInstr = Context.getCur(); | 1611 Inst *CurInstr = Context.getCur(); |
| 1475 Variable *Dest = CurInstr->getDest(); | |
| 1476 | 1612 |
| 1477 // Check if the previous NewBaseReg is clobbered, and reset if needed. | 1613 // Check if the previous TempBaseReg is clobbered, and reset if needed. |
| 1478 if ((Dest && NewBaseReg && Dest->hasReg() && | 1614 Legalizer.resetTempBaseIfClobberedBy(CurInstr); |
| 1479 Dest->getRegNum() == NewBaseReg->getBaseRegNum()) || | 1615 |
| 1480 llvm::isa<InstFakeKill>(CurInstr)) { | 1616 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { |
| 1481 NewBaseReg = nullptr; | 1617 Legalizer.legalizeMov(MovInstr); |
| 1482 NewBaseOffset = 0; | 1618 } else if (auto *LdrInstr = llvm::dyn_cast<InstARM32Ldr>(CurInstr)) { |
| 1619 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand( |
| 1620 llvm::cast<OperandARM32Mem>(LdrInstr->getSrc(0)))) { |
| 1621 _ldr(CurInstr->getDest(), LegalMem, LdrInstr->getPredicate()); |
| 1622 CurInstr->setDeleted(); |
| 1623 } |
| 1624 } else if (auto *LdrexInstr = llvm::dyn_cast<InstARM32Ldrex>(CurInstr)) { |
| 1625 constexpr bool DisallowOffsetsBecauseLdrex = false; |
| 1626 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand( |
| 1627 llvm::cast<OperandARM32Mem>(LdrexInstr->getSrc(0)), |
| 1628 DisallowOffsetsBecauseLdrex)) { |
| 1629 _ldrex(CurInstr->getDest(), LegalMem, LdrexInstr->getPredicate()); |
| 1630 CurInstr->setDeleted(); |
| 1631 } |
| 1632 } else if (auto *StrInstr = llvm::dyn_cast<InstARM32Str>(CurInstr)) { |
| 1633 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand( |
| 1634 llvm::cast<OperandARM32Mem>(StrInstr->getSrc(1)))) { |
| 1635 _str(llvm::cast<Variable>(CurInstr->getSrc(0)), LegalMem, |
| 1636 StrInstr->getPredicate()); |
| 1637 CurInstr->setDeleted(); |
| 1638 } |
| 1639 } else if (auto *StrexInstr = llvm::dyn_cast<InstARM32Strex>(CurInstr)) { |
| 1640 constexpr bool DisallowOffsetsBecauseStrex = false; |
| 1641 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand( |
| 1642 llvm::cast<OperandARM32Mem>(StrexInstr->getSrc(1)), |
| 1643 DisallowOffsetsBecauseStrex)) { |
| 1644 _strex(CurInstr->getDest(), llvm::cast<Variable>(CurInstr->getSrc(0)), |
| 1645 LegalMem, StrexInstr->getPredicate()); |
| 1646 CurInstr->setDeleted(); |
| 1647 } |
| 1483 } | 1648 } |
| 1484 | 1649 |
| 1485 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { | 1650 // Sanity-check: the Legalizer will either have no Temp, or it will be |
| 1486 legalizeMov(MovInstr, OrigBaseReg, &NewBaseReg, &NewBaseOffset); | 1651 // bound to IP. |
| 1487 } | 1652 Legalizer.assertNoTempOrAssignedToIP(); |
| 1488 } | 1653 } |
| 1489 } | 1654 } |
| 1490 } | 1655 } |
| 1491 | 1656 |
| 1492 Operand *TargetARM32::loOperand(Operand *Operand) { | 1657 Operand *TargetARM32::loOperand(Operand *Operand) { |
| 1493 assert(Operand->getType() == IceType_i64); | 1658 assert(Operand->getType() == IceType_i64); |
| 1494 if (Operand->getType() != IceType_i64) | 1659 if (Operand->getType() != IceType_i64) |
| 1495 return Operand; | 1660 return Operand; |
| 1496 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) | 1661 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) |
| 1497 return Var64On32->getLo(); | 1662 return Var64On32->getLo(); |
| 1498 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) | 1663 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) |
| 1499 return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue())); | 1664 return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue())); |
| 1500 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) { | 1665 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) { |
| 1501 // Conservatively disallow memory operands with side-effects (pre/post | 1666 // Conservatively disallow memory operands with side-effects (pre/post |
| 1502 // increment) in case of duplication. | 1667 // increment) in case of duplication. |
| 1503 assert(Mem->getAddrMode() == OperandARM32Mem::Offset || | 1668 assert(Mem->getAddrMode() == OperandARM32Mem::Offset || |
| 1504 Mem->getAddrMode() == OperandARM32Mem::NegOffset); | 1669 Mem->getAddrMode() == OperandARM32Mem::NegOffset); |
| 1505 Variable *BaseR = legalizeToReg(Mem->getBase()); | |
| 1506 if (Mem->isRegReg()) { | 1670 if (Mem->isRegReg()) { |
| 1507 Variable *IndexR = legalizeToReg(Mem->getIndex()); | 1671 Variable *IndexR = legalizeToReg(Mem->getIndex()); |
| 1508 return OperandARM32Mem::create(Func, IceType_i32, BaseR, IndexR, | 1672 return OperandARM32Mem::create(Func, IceType_i32, Mem->getBase(), IndexR, |
| 1509 Mem->getShiftOp(), Mem->getShiftAmt(), | 1673 Mem->getShiftOp(), Mem->getShiftAmt(), |
| 1510 Mem->getAddrMode()); | 1674 Mem->getAddrMode()); |
| 1511 } else { | 1675 } else { |
| 1512 return OperandARM32Mem::create(Func, IceType_i32, BaseR, Mem->getOffset(), | 1676 return OperandARM32Mem::create(Func, IceType_i32, Mem->getBase(), |
| 1513 Mem->getAddrMode()); | 1677 Mem->getOffset(), Mem->getAddrMode()); |
| 1514 } | 1678 } |
| 1515 } | 1679 } |
| 1516 llvm::report_fatal_error("Unsupported operand type"); | 1680 llvm::report_fatal_error("Unsupported operand type"); |
| 1517 return nullptr; | 1681 return nullptr; |
| 1518 } | 1682 } |
| 1519 | 1683 |
| 1520 Operand *TargetARM32::hiOperand(Operand *Operand) { | 1684 Operand *TargetARM32::hiOperand(Operand *Operand) { |
| 1521 assert(Operand->getType() == IceType_i64); | 1685 assert(Operand->getType() == IceType_i64); |
| 1522 if (Operand->getType() != IceType_i64) | 1686 if (Operand->getType() != IceType_i64) |
| 1523 return Operand; | 1687 return Operand; |
| (...skipping 3260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4784 | 4948 |
| 4785 // Update the computed address parameters once we are sure optimization | 4949 // Update the computed address parameters once we are sure optimization |
| 4786 // is valid. | 4950 // is valid. |
| 4787 *Base = NewBase; | 4951 *Base = NewBase; |
| 4788 *Offset = NewOffset; | 4952 *Offset = NewOffset; |
| 4789 *Reason = BaseInst; | 4953 *Reason = BaseInst; |
| 4790 return true; | 4954 return true; |
| 4791 } | 4955 } |
| 4792 } // end of anonymous namespace | 4956 } // end of anonymous namespace |
| 4793 | 4957 |
| 4794 // ARM32 address modes: | |
| 4795 // ld/st i[8|16|32]: [reg], [reg +/- imm12], [pc +/- imm12], | |
| 4796 // [reg +/- reg << shamt5] | |
| 4797 // ld/st f[32|64] : [reg], [reg +/- imm8] , [pc +/- imm8] | |
| 4798 // ld/st vectors : [reg] | |
| 4799 // | |
| 4800 // For now, we don't handle address modes with Relocatables. | |
| 4801 namespace { | |
| 4802 // MemTraits contains per-type valid address mode information. | |
| 4803 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ | |
| 4804 static_assert(!(shaddr) || rraddr, "Check ICETYPEARM32_TABLE::" #tag); | |
| 4805 ICETYPEARM32_TABLE | |
| 4806 #undef X | |
| 4807 | |
| 4808 static const struct { | |
| 4809 int32_t ValidImmMask; | |
| 4810 bool CanHaveImm; | |
| 4811 bool CanHaveIndex; | |
| 4812 bool CanHaveShiftedIndex; | |
| 4813 } MemTraits[] = { | |
| 4814 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ | |
| 4815 { (1 << ubits) - 1, (ubits) > 0, rraddr, shaddr, } \ | |
| 4816 , | |
| 4817 ICETYPEARM32_TABLE | |
| 4818 #undef X | |
| 4819 }; | |
| 4820 static constexpr SizeT MemTraitsSize = llvm::array_lengthof(MemTraits); | |
| 4821 } // end of anonymous namespace | |
| 4822 | |
| 4823 OperandARM32Mem *TargetARM32::formAddressingMode(Type Ty, Cfg *Func, | 4958 OperandARM32Mem *TargetARM32::formAddressingMode(Type Ty, Cfg *Func, |
| 4824 const Inst *LdSt, | 4959 const Inst *LdSt, |
| 4825 Operand *Base) { | 4960 Operand *Base) { |
| 4826 assert(Base != nullptr); | 4961 assert(Base != nullptr); |
| 4827 int32_t OffsetImm = 0; | 4962 int32_t OffsetImm = 0; |
| 4828 Variable *OffsetReg = nullptr; | 4963 Variable *OffsetReg = nullptr; |
| 4829 int32_t OffsetRegShamt = 0; | 4964 int32_t OffsetRegShamt = 0; |
| 4830 OperandARM32::ShiftKind ShiftKind = OperandARM32::kNoShift; | 4965 OperandARM32::ShiftKind ShiftKind = OperandARM32::kNoShift; |
| 4831 | 4966 |
| 4832 Func->resetCurrentNode(); | 4967 Func->resetCurrentNode(); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4948 OffsetImm = 0; | 5083 OffsetImm = 0; |
| 4949 } | 5084 } |
| 4950 } | 5085 } |
| 4951 | 5086 |
| 4952 assert(BaseVar != nullptr); | 5087 assert(BaseVar != nullptr); |
| 4953 assert(OffsetImm == 0 || OffsetReg == nullptr); | 5088 assert(OffsetImm == 0 || OffsetReg == nullptr); |
| 4954 assert(OffsetReg == nullptr || CanHaveIndex); | 5089 assert(OffsetReg == nullptr || CanHaveIndex); |
| 4955 assert(OffsetImm < 0 ? (ValidImmMask & -OffsetImm) == -OffsetImm | 5090 assert(OffsetImm < 0 ? (ValidImmMask & -OffsetImm) == -OffsetImm |
| 4956 : (ValidImmMask & OffsetImm) == OffsetImm); | 5091 : (ValidImmMask & OffsetImm) == OffsetImm); |
| 4957 | 5092 |
| 4958 Variable *BaseR = makeReg(getPointerType()); | |
| 4959 Context.insert(InstAssign::create(Func, BaseR, BaseVar)); | |
| 4960 if (OffsetReg != nullptr) { | 5093 if (OffsetReg != nullptr) { |
| 4961 Variable *OffsetR = makeReg(getPointerType()); | 5094 Variable *OffsetR = makeReg(getPointerType()); |
| 4962 Context.insert(InstAssign::create(Func, OffsetR, OffsetReg)); | 5095 Context.insert(InstAssign::create(Func, OffsetR, OffsetReg)); |
| 4963 return OperandARM32Mem::create(Func, Ty, BaseR, OffsetR, ShiftKind, | 5096 return OperandARM32Mem::create(Func, Ty, BaseVar, OffsetR, ShiftKind, |
| 4964 OffsetRegShamt); | 5097 OffsetRegShamt); |
| 4965 } | 5098 } |
| 4966 | 5099 |
| 4967 return OperandARM32Mem::create( | 5100 return OperandARM32Mem::create( |
| 4968 Func, Ty, BaseR, | 5101 Func, Ty, BaseVar, |
| 4969 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm))); | 5102 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm))); |
| 4970 } | 5103 } |
| 4971 | 5104 |
| 4972 void TargetARM32::doAddressOptLoad() { | 5105 void TargetARM32::doAddressOptLoad() { |
| 4973 Inst *Instr = Context.getCur(); | 5106 Inst *Instr = Context.getCur(); |
| 4974 assert(llvm::isa<InstLoad>(Instr)); | 5107 assert(llvm::isa<InstLoad>(Instr)); |
| 4975 Variable *Dest = Instr->getDest(); | 5108 Variable *Dest = Instr->getDest(); |
| 4976 Operand *Addr = Instr->getSrc(0); | 5109 Operand *Addr = Instr->getSrc(0); |
| 4977 if (OperandARM32Mem *Mem = | 5110 if (OperandARM32Mem *Mem = |
| 4978 formAddressingMode(Dest->getType(), Func, Instr, Addr)) { | 5111 formAddressingMode(Dest->getType(), Func, Instr, Addr)) { |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5182 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) { | 5315 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) { |
| 5183 // Before doing anything with a Mem operand, we need to ensure that the | 5316 // Before doing anything with a Mem operand, we need to ensure that the |
| 5184 // Base and Index components are in physical registers. | 5317 // Base and Index components are in physical registers. |
| 5185 Variable *Base = Mem->getBase(); | 5318 Variable *Base = Mem->getBase(); |
| 5186 Variable *Index = Mem->getIndex(); | 5319 Variable *Index = Mem->getIndex(); |
| 5187 ConstantInteger32 *Offset = Mem->getOffset(); | 5320 ConstantInteger32 *Offset = Mem->getOffset(); |
| 5188 assert(Index == nullptr || Offset == nullptr); | 5321 assert(Index == nullptr || Offset == nullptr); |
| 5189 Variable *RegBase = nullptr; | 5322 Variable *RegBase = nullptr; |
| 5190 Variable *RegIndex = nullptr; | 5323 Variable *RegIndex = nullptr; |
| 5191 assert(Base); | 5324 assert(Base); |
| 5192 RegBase = legalizeToReg(Base); | 5325 RegBase = llvm::cast<Variable>( |
| 5326 legalize(Base, Legal_Reg | Legal_Rematerializable)); |
| 5193 assert(Ty < MemTraitsSize); | 5327 assert(Ty < MemTraitsSize); |
| 5194 if (Index) { | 5328 if (Index) { |
| 5195 assert(Offset == nullptr); | 5329 assert(Offset == nullptr); |
| 5196 assert(MemTraits[Ty].CanHaveIndex); | 5330 assert(MemTraits[Ty].CanHaveIndex); |
| 5197 RegIndex = legalizeToReg(Index); | 5331 RegIndex = legalizeToReg(Index); |
| 5198 } | 5332 } |
| 5199 if (Offset && Offset->getValue() != 0) { | 5333 if (Offset && Offset->getValue() != 0) { |
| 5200 assert(Index == nullptr); | 5334 assert(Index == nullptr); |
| 5201 static constexpr bool ZeroExt = false; | 5335 static constexpr bool ZeroExt = false; |
| 5202 assert(MemTraits[Ty].CanHaveImm); | 5336 assert(MemTraits[Ty].CanHaveImm); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5317 Variable *BaseReg = makeReg(getPointerType()); | 5451 Variable *BaseReg = makeReg(getPointerType()); |
| 5318 _movw(BaseReg, Offset); | 5452 _movw(BaseReg, Offset); |
| 5319 _movt(BaseReg, Offset); | 5453 _movt(BaseReg, Offset); |
| 5320 From = formMemoryOperand(BaseReg, Ty); | 5454 From = formMemoryOperand(BaseReg, Ty); |
| 5321 return copyToReg(From, RegNum); | 5455 return copyToReg(From, RegNum); |
| 5322 } | 5456 } |
| 5323 } | 5457 } |
| 5324 | 5458 |
| 5325 if (auto *Var = llvm::dyn_cast<Variable>(From)) { | 5459 if (auto *Var = llvm::dyn_cast<Variable>(From)) { |
| 5326 if (Var->isRematerializable()) { | 5460 if (Var->isRematerializable()) { |
| 5461 if (Allowed & Legal_Rematerializable) { |
| 5462 return From; |
| 5463 } |
| 5464 |
| 5327 // TODO(jpp): We don't need to rematerialize Var if legalize() was invoked | 5465 // TODO(jpp): We don't need to rematerialize Var if legalize() was invoked |
| 5328 // for a Variable in a Mem operand. | 5466 // for a Variable in a Mem operand. |
| 5329 Variable *T = makeReg(Var->getType(), RegNum); | 5467 Variable *T = makeReg(Var->getType(), RegNum); |
| 5330 _mov(T, Var); | 5468 _mov(T, Var); |
| 5331 return T; | 5469 return T; |
| 5332 } | 5470 } |
| 5333 // Check if the variable is guaranteed a physical register. This can happen | 5471 // Check if the variable is guaranteed a physical register. This can happen |
| 5334 // either when the variable is pre-colored or when it is assigned infinite | 5472 // either when the variable is pre-colored or when it is assigned infinite |
| 5335 // weight. | 5473 // weight. |
| 5336 bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg()); | 5474 bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg()); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5379 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand); | 5517 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand); |
| 5380 // It may be the case that address mode optimization already creates an | 5518 // It may be the case that address mode optimization already creates an |
| 5381 // OperandARM32Mem, so in that case it wouldn't need another level of | 5519 // OperandARM32Mem, so in that case it wouldn't need another level of |
| 5382 // transformation. | 5520 // transformation. |
| 5383 if (Mem) { | 5521 if (Mem) { |
| 5384 return llvm::cast<OperandARM32Mem>(legalize(Mem)); | 5522 return llvm::cast<OperandARM32Mem>(legalize(Mem)); |
| 5385 } | 5523 } |
| 5386 // If we didn't do address mode optimization, then we only have a | 5524 // If we didn't do address mode optimization, then we only have a |
| 5387 // base/offset to work with. ARM always requires a base register, so | 5525 // base/offset to work with. ARM always requires a base register, so |
| 5388 // just use that to hold the operand. | 5526 // just use that to hold the operand. |
| 5389 Variable *BaseR = legalizeToReg(Operand); | 5527 Variable *Base = llvm::cast<Variable>( |
| 5528 legalize(Operand, Legal_Reg | Legal_Rematerializable)); |
| 5390 return OperandARM32Mem::create( | 5529 return OperandARM32Mem::create( |
| 5391 Func, Ty, BaseR, | 5530 Func, Ty, Base, |
| 5392 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))); | 5531 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))); |
| 5393 } | 5532 } |
| 5394 | 5533 |
| 5395 Variable64On32 *TargetARM32::makeI64RegPair() { | 5534 Variable64On32 *TargetARM32::makeI64RegPair() { |
| 5396 Variable64On32 *Reg = | 5535 Variable64On32 *Reg = |
| 5397 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); | 5536 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
| 5398 Reg->setMustHaveReg(); | 5537 Reg->setMustHaveReg(); |
| 5399 Reg->initHiLo(Func); | 5538 Reg->initHiLo(Func); |
| 5400 Reg->getLo()->setMustNotHaveReg(); | 5539 Reg->getLo()->setMustNotHaveReg(); |
| 5401 Reg->getHi()->setMustNotHaveReg(); | 5540 Reg->getHi()->setMustNotHaveReg(); |
| (...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5958 // Technically R9 is used for TLS with Sandboxing, and we reserve it. | 6097 // Technically R9 is used for TLS with Sandboxing, and we reserve it. |
| 5959 // However, for compatibility with current NaCl LLVM, don't claim that. | 6098 // However, for compatibility with current NaCl LLVM, don't claim that. |
| 5960 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; | 6099 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; |
| 5961 } | 6100 } |
| 5962 | 6101 |
| 5963 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; | 6102 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; |
| 5964 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; | 6103 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; |
| 5965 llvm::SmallBitVector TargetARM32::ScratchRegs; | 6104 llvm::SmallBitVector TargetARM32::ScratchRegs; |
| 5966 | 6105 |
| 5967 } // end of namespace Ice | 6106 } // end of namespace Ice |
| OLD | NEW |