262#define DEBUG_TYPE "frame-info"
265 cl::desc(
"enable use of redzone on AArch64"),
269 "stack-tagging-merge-settag",
279 cl::desc(
"Emit homogeneous prologue and epilogue for the size "
280 "optimization (default = off)"));
292 "aarch64-disable-multivector-spill-fill",
306 bool IsTailCallReturn = (
MBB.end() !=
MBBI)
310 int64_t ArgumentPopSize = 0;
311 if (IsTailCallReturn) {
317 ArgumentPopSize = StackAdjust.
getImm();
326 return ArgumentPopSize;
341 if (AFI->hasCalculatedStackSizeSVE())
356bool AArch64FrameLowering::homogeneousPrologEpilog(
381 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
382 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
389 unsigned NumGPRs = 0;
390 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
392 if (
Reg == AArch64::LR) {
393 assert(CSRegs[
I + 1] == AArch64::FP);
394 if (NumGPRs % 2 != 0)
406bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
425 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
426 MI.getOpcode() == AArch64::ADDXri ||
427 MI.getOpcode() == AArch64::ADDSXri)
452 bool IsWin64,
bool IsFunclet)
const {
454 "Tail call reserved stack must be aligned to 16 bytes");
455 if (!IsWin64 || IsFunclet) {
460 Attribute::SwiftAsync))
474 int FrameIndex =
H.CatchObj.FrameIndex;
475 if ((FrameIndex != INT_MAX) &&
476 CatchObjFrameIndices.
insert(FrameIndex)) {
477 FixedObjectSize =
alignTo(FixedObjectSize,
484 FixedObjectSize += 8;
486 return alignTo(FixedObjectSize, 16);
504 const unsigned RedZoneSize =
517 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
521 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
542 RegInfo->hasStackRealignment(MF))
585 const Triple &TT = TM.getTargetTriple();
589 if (TT.isOSDarwin() || TT.isOSWindows())
597 if (TM.Options.FramePointerIsReserved(MF))
627 unsigned Opc =
I->getOpcode();
628 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
629 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
632 int64_t Amount =
I->getOperand(0).getImm();
640 if (CalleePopAmount == 0) {
651 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
662 "non-reserved call frame without var sized objects?");
671 }
else if (CalleePopAmount != 0) {
674 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
686 const auto &
TRI = *Subtarget.getRegisterInfo();
692 CFIBuilder.buildDefCFA(AArch64::SP, 0);
695 if (MFI.shouldSignReturnAddress(MF))
696 MFI.branchProtectionPAuthLR() ? CFIBuilder.buildNegateRAStateWithPC()
697 : CFIBuilder.buildNegateRAState();
700 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
701 CFIBuilder.buildSameValue(AArch64::X18);
704 const std::vector<CalleeSavedInfo> &CSI =
706 for (
const auto &Info : CSI) {
708 if (!
TRI.regNeedsCFI(Reg, Reg))
710 CFIBuilder.buildSameValue(Reg);
728 for (
const auto &
Info : CSI) {
742void AArch64FrameLowering::emitCalleeSavedGPRRestores(
747void AArch64FrameLowering::emitCalleeSavedSVERestores(
755 static const int64_t MAX_BYTES_PER_SCALABLE_BYTE = 16;
756 return Size.getScalable() * MAX_BYTES_PER_SCALABLE_BYTE +
Size.getFixed();
759void AArch64FrameLowering::allocateStackSpace(
761 int64_t RealignmentPadding,
StackOffset AllocSize,
bool NeedsWinCFI,
762 bool *HasWinCFI,
bool EmitCFI,
StackOffset InitialOffset,
763 bool FollowupAllocs)
const {
770 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
772 AArch64FunctionInfo &AFI = *MF.
getInfo<AArch64FunctionInfo>();
776 const uint64_t AndMask = ~(MaxAlign - 1);
779 Register TargetReg = RealignmentPadding
780 ? findScratchNonCalleeSaveRegister(&
MBB)
785 EmitCFI, InitialOffset);
787 if (RealignmentPadding) {
808 if (AllocSize.
getScalable() == 0 && RealignmentPadding == 0) {
809 Register ScratchReg = findScratchNonCalleeSaveRegister(&
MBB);
810 assert(ScratchReg != AArch64::NoRegister);
820 if (FollowupAllocs) {
837 if (
upperBound(AllocSize) + RealignmentPadding <= ProbeSize) {
838 Register ScratchReg = RealignmentPadding
839 ? findScratchNonCalleeSaveRegister(&
MBB)
841 assert(ScratchReg != AArch64::NoRegister);
845 EmitCFI, InitialOffset);
846 if (RealignmentPadding) {
854 if (FollowupAllocs ||
upperBound(AllocSize) + RealignmentPadding >
869 Register TargetReg = findScratchNonCalleeSaveRegister(&
MBB);
870 assert(TargetReg != AArch64::NoRegister);
874 EmitCFI, InitialOffset);
875 if (RealignmentPadding) {
888 .buildDefCFARegister(AArch64::SP);
890 if (RealignmentPadding)
903 case AArch64::W##n: \
904 case AArch64::X##n: \
929 case AArch64::B##n: \
930 case AArch64::H##n: \
931 case AArch64::S##n: \
932 case AArch64::D##n: \
933 case AArch64::Q##n: \
934 return HasSVE ? AArch64::Z##n : AArch64::Q##n
971void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
982 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
985 BitVector GPRsToZero(
TRI.getNumRegs());
986 BitVector FPRsToZero(
TRI.getNumRegs());
989 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
992 GPRsToZero.set(XReg);
996 FPRsToZero.set(XReg);
1003 for (MCRegister
Reg : GPRsToZero.set_bits())
1007 for (MCRegister
Reg : FPRsToZero.set_bits())
1011 for (MCRegister PReg :
1012 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
1013 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
1014 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
1016 if (RegsToZero[PReg])
1022bool AArch64FrameLowering::windowsRequiresStackProbe(
1024 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
1025 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
1029 StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
1035 LiveRegs.addLiveIns(
MBB);
1038 for (
unsigned i = 0; CSRegs[i]; ++i)
1039 LiveRegs.addReg(CSRegs[i]);
1044 bool HasCall)
const {
1054 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
1056 LivePhysRegs LiveRegs(
TRI);
1059 LiveRegs.addReg(AArch64::X16);
1060 LiveRegs.addReg(AArch64::X17);
1061 LiveRegs.addReg(AArch64::X18);
1066 if (LiveRegs.available(
MRI, AArch64::X9))
1069 for (
unsigned Reg : AArch64::GPR64RegClass) {
1070 if (LiveRegs.available(
MRI,
Reg))
1073 return AArch64::NoRegister;
1092 if (!LiveRegs.available(
MRI, AArch64::X16) ||
1093 !LiveRegs.available(
MRI, AArch64::X17))
1100 MBB.isLiveIn(AArch64::NZCV))
1104 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
1110 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
1111 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
1120 F.needsUnwindTableEntry();
1123bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
1131 return SignReturnAddressAll;
1134bool AArch64FrameLowering::shouldCombineCSRLocalStackBump(
1140 if (homogeneousPrologEpilog(MF))
1160 if (StackBumpBytes >= 512 || windowsRequiresStackProbe(MF, StackBumpBytes))
1163 if (MFI.hasVarSizedObjects())
1166 if (
RegInfo->hasStackRealignment(MF))
1183bool AArch64FrameLowering::shouldCombineCSRLocalStackBumpInEpilogue(
1185 if (!shouldCombineCSRLocalStackBump(*
MBB.
getParent(), StackBumpBytes))
1194 while (LastI != Begin) {
1196 if (LastI->isTransient())
1201 switch (LastI->getOpcode()) {
1202 case AArch64::STGloop:
1203 case AArch64::STZGloop:
1205 case AArch64::STZGi:
1206 case AArch64::ST2Gi:
1207 case AArch64::STZ2Gi:
1220 unsigned Opc =
MBBI->getOpcode();
1224 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1225 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1233 case AArch64::STR_ZXI:
1234 case AArch64::LDR_ZXI: {
1235 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1242 case AArch64::STR_PXI:
1243 case AArch64::LDR_PXI: {
1244 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1251 case AArch64::LDPDpost:
1254 case AArch64::STPDpre: {
1255 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1256 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1257 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1264 case AArch64::LDPXpost:
1267 case AArch64::STPXpre: {
1270 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1271 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1275 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1282 case AArch64::LDRDpost:
1285 case AArch64::STRDpre: {
1286 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1287 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1293 case AArch64::LDRXpost:
1296 case AArch64::STRXpre: {
1297 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1304 case AArch64::STPDi:
1305 case AArch64::LDPDi: {
1306 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1307 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1315 case AArch64::STPXi:
1316 case AArch64::LDPXi: {
1319 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1331 case AArch64::STRXui:
1332 case AArch64::LDRXui: {
1340 case AArch64::STRDui:
1341 case AArch64::LDRDui: {
1342 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1349 case AArch64::STPQi:
1350 case AArch64::LDPQi: {
1351 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1352 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1353 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1360 case AArch64::LDPQpost:
1363 case AArch64::STPQpre: {
1364 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1365 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1366 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1374 auto I =
MBB->insertAfter(
MBBI, MIB);
1380 unsigned LocalStackSize) {
1382 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1383 switch (
MBBI->getOpcode()) {
1386 case AArch64::SEH_SaveFPLR:
1387 case AArch64::SEH_SaveRegP:
1388 case AArch64::SEH_SaveReg:
1389 case AArch64::SEH_SaveFRegP:
1390 case AArch64::SEH_SaveFReg:
1391 case AArch64::SEH_SaveAnyRegQP:
1392 case AArch64::SEH_SaveAnyRegQPX:
1393 ImmOpnd = &
MBBI->getOperand(ImmIdx);
1400bool AArch64FrameLowering::requiresGetVGCall(
const MachineFunction &MF)
const {
1401 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
1413 if (ST.isTargetDarwin())
1419 RTLIB::Libcall LC) {
1426 unsigned Opc =
MBBI->getOpcode();
1427 if (
Opc == AArch64::CNTD_XPiI)
1430 if (!requiresGetVGCall(*
MBBI->getMF()))
1433 if (
Opc == AArch64::BL)
1434 return matchLibcall(TLI,
MBBI->getOperand(0), RTLIB::SMEABI_GET_CURRENT_VG);
1436 return Opc == TargetOpcode::COPY;
1440AArch64FrameLowering::convertCalleeSaveRestoreToSPPrePostIncDec(
1443 bool NeedsWinCFI,
bool *HasWinCFI,
bool EmitCFI,
1453 while (isVGInstruction(
MBBI, TLI))
1457 switch (
MBBI->getOpcode()) {
1460 case AArch64::STPXi:
1461 NewOpc = AArch64::STPXpre;
1463 case AArch64::STPDi:
1464 NewOpc = AArch64::STPDpre;
1466 case AArch64::STPQi:
1467 NewOpc = AArch64::STPQpre;
1469 case AArch64::STRXui:
1470 NewOpc = AArch64::STRXpre;
1472 case AArch64::STRDui:
1473 NewOpc = AArch64::STRDpre;
1475 case AArch64::STRQui:
1476 NewOpc = AArch64::STRQpre;
1478 case AArch64::LDPXi:
1479 NewOpc = AArch64::LDPXpost;
1481 case AArch64::LDPDi:
1482 NewOpc = AArch64::LDPDpost;
1484 case AArch64::LDPQi:
1485 NewOpc = AArch64::LDPQpost;
1487 case AArch64::LDRXui:
1488 NewOpc = AArch64::LDRXpost;
1490 case AArch64::LDRDui:
1491 NewOpc = AArch64::LDRDpost;
1493 case AArch64::LDRQui:
1494 NewOpc = AArch64::LDRQpost;
1498 int64_t MinOffset, MaxOffset;
1499 bool Success =
static_cast<const AArch64InstrInfo *
>(
TII)->getMemOpInfo(
1500 NewOpc, Scale, Width, MinOffset, MaxOffset);
1506 if (
MBBI->getOperand(
MBBI->getNumOperands() - 1).getImm() != 0 ||
1507 CSStackSizeInc < MinOffset * (int64_t)Scale.
getFixedValue() ||
1508 CSStackSizeInc > MaxOffset * (int64_t)Scale.
getFixedValue()) {
1514 if (NeedsWinCFI && AArch64InstrInfo::isSEHInstruction(*
MBBI))
1519 false, NeedsWinCFI, HasWinCFI, EmitCFI,
1522 return std::prev(
MBBI);
1527 auto SEH = std::next(
MBBI);
1528 if (AArch64InstrInfo::isSEHInstruction(*SEH))
1529 SEH->eraseFromParent();
1536 unsigned OpndIdx = 0;
1537 for (
unsigned OpndEnd =
MBBI->getNumOperands() - 1; OpndIdx < OpndEnd;
1539 MIB.
add(
MBBI->getOperand(OpndIdx));
1541 assert(
MBBI->getOperand(OpndIdx).getImm() == 0 &&
1542 "Unexpected immediate offset in first/last callee-save save/restore "
1544 assert(
MBBI->getOperand(OpndIdx - 1).getReg() == AArch64::SP &&
1545 "Unexpected base register in callee-save save/restore instruction!");
1546 assert(CSStackSizeInc % Scale == 0);
1547 MIB.
addImm(CSStackSizeInc / (
int)Scale);
1559 CFIInstBuilder(
MBB,
MBBI, FrameFlag)
1560 .buildDefCFAOffset(CFAOffset - CSStackSizeInc);
1565void AArch64FrameLowering::fixupCalleeSaveRestoreStackOffset(
1567 bool *HasWinCFI)
const {
1568 if (AArch64InstrInfo::isSEHInstruction(
MI))
1571 unsigned Opc =
MI.getOpcode();
1574 case AArch64::STPXi:
1575 case AArch64::STRXui:
1576 case AArch64::STPDi:
1577 case AArch64::STRDui:
1578 case AArch64::LDPXi:
1579 case AArch64::LDRXui:
1580 case AArch64::LDPDi:
1581 case AArch64::LDRDui:
1584 case AArch64::STPQi:
1585 case AArch64::STRQui:
1586 case AArch64::LDPQi:
1587 case AArch64::LDRQui:
1594 unsigned OffsetIdx =
MI.getNumExplicitOperands() - 1;
1595 assert(
MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP &&
1596 "Unexpected base register in callee-save save/restore instruction!");
1598 MachineOperand &OffsetOpnd =
MI.getOperand(OffsetIdx);
1600 assert(LocalStackSize % Scale == 0);
1601 OffsetOpnd.
setImm(OffsetOpnd.
getImm() + LocalStackSize / Scale);
1606 assert(
MBBI !=
MI.getParent()->end() &&
"Expecting a valid instruction");
1607 assert(AArch64InstrInfo::isSEHInstruction(*
MBBI) &&
1608 "Expecting a SEH instruction");
1622bool AArch64FrameLowering::isSVECalleeSave(
1624 switch (
I->getOpcode()) {
1627 case AArch64::PTRUE_C_B:
1628 case AArch64::LD1B_2Z_IMM:
1629 case AArch64::ST1B_2Z_IMM:
1630 case AArch64::STR_ZXI:
1631 case AArch64::STR_PXI:
1632 case AArch64::LDR_ZXI:
1633 case AArch64::LDR_PXI:
1634 case AArch64::PTRUE_B:
1635 case AArch64::CPY_ZPzI_B:
1636 case AArch64::CMPNE_PPzZI_B:
1639 case AArch64::SEH_SavePReg:
1640 case AArch64::SEH_SaveZReg:
1684 DL =
MBBI->getDebugLoc();
1691 EmitSignRA(MF.
front());
1693 if (
MBB.isEHFuncletEntry())
1695 if (
MBB.isReturnBlock())
1707 switch (
MI.getOpcode()) {
1710 case AArch64::CATCHRET:
1711 case AArch64::CLEANUPRET:
1726 bool HasWinCFI =
false;
1727 bool IsFunclet =
false;
1730 DL =
MBBI->getDebugLoc();
1740 HasWinCFI |= NeedsWinCFI;
1743 emitCalleeSavedGPRRestores(
MBB,
MBB.getFirstTerminator());
1747 if (!shouldSignReturnAddressEverywhere(MF)) {
1749 TII->get(AArch64::PAUTH_EPILOGUE))
1753 HasWinCFI |= NeedsWinCFI;
1757 TII->get(AArch64::SEH_EpilogEnd))
1765 MBB.erase(EpilogStartI);
1782 unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
1784 int64_t AfterCSRPopSize = ArgumentStackToRestore;
1792 if (homogeneousPrologEpilog(MF, &
MBB)) {
1794 auto FirstHomogenousEpilogI =
MBB.getFirstTerminator();
1795 if (FirstHomogenousEpilogI !=
MBB.begin()) {
1796 auto HomogeneousEpilog = std::prev(FirstHomogenousEpilogI);
1797 if (HomogeneousEpilog->getOpcode() == AArch64::HOM_Epilog)
1798 FirstHomogenousEpilogI = HomogeneousEpilog;
1808 assert(AfterCSRPopSize == 0);
1812 bool FPAfterSVECalleeSaves =
1815 bool CombineSPBump = shouldCombineCSRLocalStackBumpInEpilogue(
MBB, NumBytes);
1817 bool CombineAfterCSRBump =
false;
1818 if (FPAfterSVECalleeSaves) {
1819 AfterCSRPopSize += FixedObject;
1820 }
else if (!CombineSPBump && PrologueSaveSize != 0) {
1822 while (Pop->getOpcode() == TargetOpcode::CFI_INSTRUCTION ||
1823 AArch64InstrInfo::isSEHInstruction(*Pop))
1824 Pop = std::prev(Pop);
1831 if (
OffsetOp.getImm() == 0 && AfterCSRPopSize >= 0) {
1832 convertCalleeSaveRestoreToSPPrePostIncDec(
1833 MBB, Pop,
DL,
TII, PrologueSaveSize, NeedsWinCFI, &HasWinCFI, EmitCFI,
1840 AfterCSRPopSize += PrologueSaveSize;
1841 CombineAfterCSRBump =
true;
1850 while (FirstGPRRestoreI != Begin) {
1853 (!FPAfterSVECalleeSaves && isSVECalleeSave(FirstGPRRestoreI))) {
1856 }
else if (CombineSPBump)
1857 fixupCalleeSaveRestoreStackOffset(
1868 BuildMI(
MBB, FirstGPRRestoreI,
DL,
TII->get(AArch64::SEH_EpilogStart))
1870 EpilogStartI = FirstGPRRestoreI;
1906 if (CombineSPBump) {
1907 assert(!SVEStackSize &&
"Cannot combine SP bump with SVE");
1910 if (EmitCFI &&
hasFP(MF))
1921 NumBytes -= PrologueSaveSize;
1922 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
1926 StackOffset DeallocateBefore = {}, DeallocateAfter = SVEStackSize;
1928 RestoreEnd = FirstGPRRestoreI;
1930 if (FPAfterSVECalleeSaves)
1931 RestoreEnd =
MBB.getFirstTerminator();
1933 RestoreBegin = std::prev(RestoreEnd);
1934 while (RestoreBegin !=
MBB.begin() &&
1935 isSVECalleeSave(std::prev(RestoreBegin)))
1938 assert(isSVECalleeSave(RestoreBegin) &&
1939 isSVECalleeSave(std::prev(RestoreEnd)) &&
"Unexpected instruction");
1943 DeallocateBefore = SVEStackSize - CalleeSavedSizeAsOffset;
1944 DeallocateAfter = CalleeSavedSizeAsOffset;
1948 if (FPAfterSVECalleeSaves) {
1955 NeedsWinCFI, &HasWinCFI);
1971 NeedsWinCFI, &HasWinCFI);
1972 }
else if (SVEStackSize) {
1980 if (SVECalleeSavedSize && BaseForSVEDealloc == AArch64::FP) {
1981 Register CalleeSaveBase = AArch64::FP;
1982 if (int64_t CalleeSaveBaseOffset =
1987 CalleeSaveBase =
MBB.getParent()->getRegInfo().createVirtualRegister(
1988 &AArch64::GPR64RegClass);
1998 }
else if (BaseForSVEDealloc == AArch64::SP) {
1999 if (SVECalleeSavedSize) {
2003 MBB, RestoreBegin,
DL, AArch64::SP, AArch64::SP,
2005 false, NeedsWinCFI, &HasWinCFI, EmitCFI && !
hasFP(MF),
2012 NeedsWinCFI, &HasWinCFI, EmitCFI && !
hasFP(MF),
2018 NeedsWinCFI, &HasWinCFI, EmitCFI && !
hasFP(MF),
2023 emitCalleeSavedSVERestores(
MBB, RestoreEnd);
2030 if (RedZone && AfterCSRPopSize == 0)
2037 bool NoCalleeSaveRestore = PrologueSaveSize == 0;
2038 int64_t StackRestoreBytes = RedZone ? 0 : NumBytes;
2039 if (NoCalleeSaveRestore)
2040 StackRestoreBytes += AfterCSRPopSize;
2043 MBB, FirstGPRRestoreI,
DL, AArch64::SP, AArch64::SP,
2050 if (NoCalleeSaveRestore || AfterCSRPopSize == 0) {
2063 MBB, FirstGPRRestoreI,
DL, AArch64::SP, AArch64::FP,
2066 }
else if (NumBytes)
2072 if (EmitCFI &&
hasFP(MF))
2079 if (AfterCSRPopSize) {
2080 assert(AfterCSRPopSize > 0 &&
"attempting to reallocate arg stack that an "
2081 "interrupt may have clobbered");
2084 MBB,
MBB.getFirstTerminator(),
DL, AArch64::SP, AArch64::SP,
2086 false, NeedsWinCFI, &HasWinCFI, EmitCFI,
2133 if (MFI.isVariableSizedObjectIndex(FI)) {
2142 bool FPAfterSVECalleeSaves =
2145 if (FPAfterSVECalleeSaves &&
2152 bool IsFixed = MFI.isFixedObjectIndex(FI);
2157 if (!IsFixed && !IsCSR) {
2158 ScalableOffset = -SVEStackSize;
2159 }
else if (FPAfterSVECalleeSaves && IsCSR) {
2174 int64_t ObjectOffset)
const {
2178 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
2179 unsigned FixedObject =
2180 getFixedObjectSize(MF, AFI, IsWin64,
false);
2188 int64_t ObjectOffset)
const {
2199 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
2200 ? getFPOffset(MF, ObjectOffset).getFixed()
2201 : getStackOffset(MF, ObjectOffset).getFixed();
2206 bool ForSimm)
const {
2208 int64_t ObjectOffset = MFI.getObjectOffset(FI);
2209 bool isFixed = MFI.isFixedObjectIndex(FI);
2216 const MachineFunction &MF, int64_t ObjectOffset,
bool isFixed,
bool isSVE,
2217 Register &FrameReg,
bool PreferFP,
bool ForSimm)
const {
2224 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
2225 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
2240 PreferFP &= !SVEStackSize;
2248 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
2252 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
2254 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
2259 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
2260 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
2262 if (FPOffset >= 0) {
2266 }
else if (MFI.hasVarSizedObjects()) {
2270 bool CanUseBP = RegInfo->hasBasePointer(MF);
2271 if (FPOffsetFits && CanUseBP)
2278 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
2285 "Funclets should only be present on Win64");
2289 if (FPOffsetFits && PreferFP)
2296 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
2297 "In the presence of dynamic stack pointer realignment, "
2298 "non-argument/CSR objects cannot be accessed through the frame pointer");
2300 bool FPAfterSVECalleeSaves =
2310 if (FPAfterSVECalleeSaves) {
2320 RegInfo->hasStackRealignment(MF))) {
2321 FrameReg = RegInfo->getFrameRegister(MF);
2325 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
2331 if (FPAfterSVECalleeSaves) {
2338 ScalableOffset = SVECalleeSavedStack;
2340 ScalableOffset = SVECalleeSavedStack - SVEStackSize;
2343 ScalableOffset = SVEStackSize;
2345 ScalableOffset = SVEStackSize - SVECalleeSavedStack;
2348 if (UseFP && !(isFixed || isCSR))
2349 ScalableOffset = -SVEStackSize;
2350 if (!UseFP && (isFixed || isCSR))
2351 ScalableOffset = SVEStackSize;
2355 FrameReg = RegInfo->getFrameRegister(MF);
2360 if (RegInfo->hasBasePointer(MF))
2361 FrameReg = RegInfo->getBaseRegister();
2363 assert(!MFI.hasVarSizedObjects() &&
2364 "Can't use SP when we have var sized objects.");
2365 FrameReg = AArch64::SP;
2393 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
2399 bool NeedsWinCFI,
bool IsFirst,
2408 if (Reg2 == AArch64::FP)
2412 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
2419 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
2420 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR && !IsFirst)
2430 bool UsesWinAAPCS,
bool NeedsWinCFI,
2431 bool NeedsFrameRecord,
bool IsFirst,
2439 if (NeedsFrameRecord)
2440 return Reg2 == AArch64::LR;
2448 unsigned Reg1 = AArch64::NoRegister;
2449 unsigned Reg2 = AArch64::NoRegister;
2452 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
2453 const TargetRegisterClass *RC;
2455 RegPairInfo() =
default;
2457 bool isPaired()
const {
return Reg2 != AArch64::NoRegister; }
2459 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
2465 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
2466 if (SavedRegs.
test(PReg)) {
2467 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
2471 return AArch64::NoRegister;
2481 bool IsLocallyStreaming =
2487 return Subtarget.hasSVE2p1() ||
2488 (Subtarget.hasSME2() &&
2489 (!IsLocallyStreaming && Subtarget.
isStreaming()));
2497 bool NeedsFrameRecord) {
2515 (
Count & 1) == 0) &&
2516 "Odd number of callee-saved regs to spill!");
2518 int StackFillDir = -1;
2520 unsigned FirstReg = 0;
2528 FirstReg =
Count - 1;
2531 int ScalableByteOffset =
2537 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
2539 RPI.Reg1 = CSI[i].getReg();
2541 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
2542 RPI.Type = RegPairInfo::GPR;
2543 RPI.RC = &AArch64::GPR64RegClass;
2544 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
2545 RPI.Type = RegPairInfo::FPR64;
2546 RPI.RC = &AArch64::FPR64RegClass;
2547 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
2548 RPI.Type = RegPairInfo::FPR128;
2549 RPI.RC = &AArch64::FPR128RegClass;
2550 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
2551 RPI.Type = RegPairInfo::ZPR;
2552 RPI.RC = &AArch64::ZPRRegClass;
2553 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
2554 RPI.Type = RegPairInfo::PPR;
2555 RPI.RC = &AArch64::PPRRegClass;
2556 }
else if (RPI.Reg1 == AArch64::VG) {
2557 RPI.Type = RegPairInfo::VG;
2558 RPI.RC = &AArch64::FIXED_REGSRegClass;
2567 ByteOffset += StackFillDir * StackHazardSize;
2570 int Scale =
TRI->getSpillSize(*RPI.RC);
2573 MCRegister NextReg = CSI[i + RegInc].getReg();
2574 bool IsFirst = i == FirstReg;
2576 case RegPairInfo::GPR:
2577 if (AArch64::GPR64RegClass.
contains(NextReg) &&
2579 NeedsWinCFI, NeedsFrameRecord, IsFirst,
2583 case RegPairInfo::FPR64:
2584 if (AArch64::FPR64RegClass.
contains(NextReg) &&
2589 case RegPairInfo::FPR128:
2590 if (AArch64::FPR128RegClass.
contains(NextReg))
2593 case RegPairInfo::PPR:
2595 case RegPairInfo::ZPR:
2597 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
2600 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
2605 case RegPairInfo::VG:
2616 assert((!RPI.isPaired() ||
2617 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
2618 "Out of order callee saved regs!");
2620 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
2621 RPI.Reg1 == AArch64::LR) &&
2622 "FrameRecord must be allocated together with LR");
2625 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
2626 RPI.Reg2 == AArch64::LR) &&
2627 "FrameRecord must be allocated together with LR");
2635 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
2636 RPI.Reg1 + 1 == RPI.Reg2))) &&
2637 "Callee-save registers not saved as adjacent register pair!");
2639 RPI.FrameIdx = CSI[i].getFrameIdx();
2642 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
2646 if (RPI.isScalable() && ScalableByteOffset % Scale != 0) {
2647 ScalableByteOffset =
alignTo(ScalableByteOffset, Scale);
2650 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
2651 assert(OffsetPre % Scale == 0);
2653 if (RPI.isScalable())
2654 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
2656 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
2661 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
2662 (IsWindows && RPI.Reg2 == AArch64::LR)))
2663 ByteOffset += StackFillDir * 8;
2667 if (NeedGapToAlignStack && !NeedsWinCFI && !RPI.isScalable() &&
2668 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
2669 ByteOffset % 16 != 0) {
2670 ByteOffset += 8 * StackFillDir;
2676 NeedGapToAlignStack =
false;
2679 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
2680 assert(OffsetPost % Scale == 0);
2683 int Offset = NeedsWinCFI ? OffsetPre : OffsetPost;
2688 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
2689 (IsWindows && RPI.Reg2 == AArch64::LR)))
2691 RPI.Offset =
Offset / Scale;
2693 assert((!RPI.isPaired() ||
2694 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
2695 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
2696 "Offset out of bounds for LDP/STP immediate");
2698 auto isFrameRecord = [&] {
2700 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
2701 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
2709 return i > 0 && RPI.Reg1 == AArch64::FP &&
2710 CSI[i - 1].getReg() == AArch64::LR;
2715 if (NeedsFrameRecord && isFrameRecord())
2732 std::reverse(RegPairs.
begin(), RegPairs.
end());
2751 MRI.freezeReservedRegs();
2753 if (homogeneousPrologEpilog(MF)) {
2757 for (
auto &RPI : RegPairs) {
2762 if (!
MRI.isReserved(RPI.Reg1))
2763 MBB.addLiveIn(RPI.Reg1);
2764 if (RPI.isPaired() && !
MRI.isReserved(RPI.Reg2))
2765 MBB.addLiveIn(RPI.Reg2);
2769 bool PTrueCreated =
false;
2771 unsigned Reg1 = RPI.Reg1;
2772 unsigned Reg2 = RPI.Reg2;
2785 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2786 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2788 case RegPairInfo::GPR:
2789 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2791 case RegPairInfo::FPR64:
2792 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2794 case RegPairInfo::FPR128:
2795 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2797 case RegPairInfo::ZPR:
2798 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2800 case RegPairInfo::PPR:
2802 Size == 16 ? AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO : AArch64::STR_PXI;
2804 case RegPairInfo::VG:
2805 StrOpc = AArch64::STRXui;
2809 unsigned X0Scratch = AArch64::NoRegister;
2811 if (X0Scratch != AArch64::NoRegister)
2817 if (Reg1 == AArch64::VG) {
2819 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2820 assert(Reg1 != AArch64::NoRegister);
2830 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2831 AArch64::X0, LiveIn.PhysReg);
2839 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2853 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2854 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
2857 assert((!NeedsWinCFI || !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2858 "Windows unwdinding requires a consecutive (FP,LR) pair");
2862 unsigned FrameIdxReg1 = RPI.FrameIdx;
2863 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2864 if (NeedsWinCFI && RPI.isPaired()) {
2869 if (RPI.isPaired() && RPI.isScalable()) {
2875 "Expects SVE2.1 or SME2 target and a predicate register");
2876#ifdef EXPENSIVE_CHECKS
2877 auto IsPPR = [](
const RegPairInfo &c) {
2878 return c.Reg1 == RegPairInfo::PPR;
2880 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2881 auto IsZPR = [](
const RegPairInfo &c) {
2882 return c.Type == RegPairInfo::ZPR;
2884 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2885 assert(!(PPRBegin < ZPRBegin) &&
2886 "Expected callee save predicate to be handled first");
2888 if (!PTrueCreated) {
2889 PTrueCreated =
true;
2894 if (!
MRI.isReserved(Reg1))
2895 MBB.addLiveIn(Reg1);
2896 if (!
MRI.isReserved(Reg2))
2897 MBB.addLiveIn(Reg2);
2898 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2914 if (!
MRI.isReserved(Reg1))
2915 MBB.addLiveIn(Reg1);
2916 if (RPI.isPaired()) {
2917 if (!
MRI.isReserved(Reg2))
2918 MBB.addLiveIn(Reg2);
2937 if (RPI.Type == RegPairInfo::ZPR || RPI.Type == RegPairInfo::PPR) {
2956 DL =
MBBI->getDebugLoc();
2959 if (homogeneousPrologEpilog(MF, &
MBB)) {
2962 for (
auto &RPI : RegPairs) {
2970 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2972 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2973 std::reverse(PPRBegin, PPREnd);
2974 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2976 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2977 std::reverse(ZPRBegin, ZPREnd);
2979 bool PTrueCreated =
false;
2980 for (
const RegPairInfo &RPI : RegPairs) {
2981 unsigned Reg1 = RPI.Reg1;
2982 unsigned Reg2 = RPI.Reg2;
2993 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2994 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2996 case RegPairInfo::GPR:
2997 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2999 case RegPairInfo::FPR64:
3000 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
3002 case RegPairInfo::FPR128:
3003 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
3005 case RegPairInfo::ZPR:
3006 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
3008 case RegPairInfo::PPR:
3009 LdrOpc =
Size == 16 ? AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO
3012 case RegPairInfo::VG:
3017 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
3018 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
3024 unsigned FrameIdxReg1 = RPI.FrameIdx;
3025 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
3026 if (NeedsWinCFI && RPI.isPaired()) {
3032 if (RPI.isPaired() && RPI.isScalable()) {
3037 "Expects SVE2.1 or SME2 target and a predicate register");
3038#ifdef EXPENSIVE_CHECKS
3039 assert(!(PPRBegin < ZPRBegin) &&
3040 "Expected callee save predicate to be handled first");
3042 if (!PTrueCreated) {
3043 PTrueCreated =
true;
3048 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
3065 if (RPI.isPaired()) {
3092 return std::optional<int>(PSV->getFrameIndex());
3103 return std::nullopt;
3109 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
3110 return std::nullopt;
3118void AArch64FrameLowering::determineStackHazardSlot(
3121 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
3122 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
3136 return AArch64::FPR64RegClass.contains(Reg) ||
3137 AArch64::FPR128RegClass.contains(Reg) ||
3138 AArch64::ZPRRegClass.contains(Reg) ||
3139 AArch64::PPRRegClass.contains(Reg);
3141 bool HasFPRStackObjects =
false;
3144 for (
auto &
MBB : MF) {
3145 for (
auto &
MI :
MBB) {
3147 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3150 FrameObjects[*FI] |= 2;
3152 FrameObjects[*FI] |= 1;
3156 HasFPRStackObjects =
3157 any_of(FrameObjects, [](
unsigned B) {
return (
B & 3) == 2; });
3160 if (HasFPRCSRs || HasFPRStackObjects) {
3163 << StackHazardSize <<
"\n");
3181 unsigned UnspilledCSGPR = AArch64::NoRegister;
3182 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
3187 unsigned BasePointerReg = RegInfo->hasBasePointer(MF)
3188 ? RegInfo->getBaseRegister()
3191 unsigned ExtraCSSpill = 0;
3192 bool HasUnpairedGPR64 =
false;
3193 bool HasPairZReg =
false;
3194 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
3195 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
3198 for (
unsigned i = 0; CSRegs[i]; ++i) {
3199 const unsigned Reg = CSRegs[i];
3202 if (Reg == BasePointerReg)
3207 if (UserReservedRegs[Reg]) {
3208 SavedRegs.
reset(Reg);
3212 bool RegUsed = SavedRegs.
test(Reg);
3213 unsigned PairedReg = AArch64::NoRegister;
3214 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
3215 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
3216 AArch64::FPR128RegClass.
contains(Reg)) {
3219 if (HasUnpairedGPR64)
3220 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
3222 PairedReg = CSRegs[i ^ 1];
3229 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
3230 PairedReg = AArch64::NoRegister;
3231 HasUnpairedGPR64 =
true;
3233 assert(PairedReg == AArch64::NoRegister ||
3234 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
3235 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
3236 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
3239 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
3240 UnspilledCSGPR = Reg;
3241 UnspilledCSGPRPaired = PairedReg;
3249 if (RegInfo->getSpillSize(AArch64::PPRRegClass) == 16 &&
3250 AArch64::PPR_p8to15RegClass.contains(Reg)) {
3251 SavedRegs.
set(AArch64::P4);
3257 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
3258 !SavedRegs.
test(PairedReg)) {
3259 SavedRegs.
set(PairedReg);
3260 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
3261 !ReservedRegs[PairedReg])
3262 ExtraCSSpill = PairedReg;
3265 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
3266 SavedRegs.
test(CSRegs[i ^ 1]));
3274 if (PnReg != AArch64::NoRegister)
3280 SavedRegs.
set(AArch64::P8);
3285 "Predicate cannot be a reserved register");
3295 SavedRegs.
set(AArch64::X18);
3299 unsigned CSStackSize = 0;
3300 unsigned SVECSStackSize = 0;
3302 for (
unsigned Reg : SavedRegs.
set_bits()) {
3303 auto *RC =
TRI->getMinimalPhysRegClass(Reg);
3304 assert(RC &&
"expected register class!");
3305 auto SpillSize =
TRI->getSpillSize(*RC);
3306 if (AArch64::PPRRegClass.
contains(Reg) ||
3307 AArch64::ZPRRegClass.
contains(Reg))
3308 SVECSStackSize += SpillSize;
3310 CSStackSize += SpillSize;
3316 unsigned NumSavedRegs = SavedRegs.
count();
3325 determineStackHazardSlot(MF, SavedRegs);
3326 if (AFI->hasStackHazardSlotIndex())
3331 SavedRegs.
set(AArch64::LR);
3336 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
3337 SavedRegs.
set(AArch64::FP);
3338 SavedRegs.
set(AArch64::LR);
3342 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
3343 for (
unsigned Reg : SavedRegs.
set_bits())
3349 int64_t SVEStackSize =
3350 alignTo(SVECSStackSize + estimateSVEStackObjectOffsets(MFI), 16);
3351 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
3360 int64_t CalleeStackUsed = 0;
3363 if (FixedOff > CalleeStackUsed)
3364 CalleeStackUsed = FixedOff;
3368 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
3369 CalleeStackUsed) > EstimatedStackSizeLimit;
3370 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
3371 AFI->setHasStackFrame(
true);
3380 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
3382 <<
" to get a scratch register.\n");
3383 SavedRegs.
set(UnspilledCSGPR);
3384 ExtraCSSpill = UnspilledCSGPR;
3389 if (producePairRegisters(MF)) {
3390 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
3393 SavedRegs.
reset(UnspilledCSGPR);
3394 ExtraCSSpill = AArch64::NoRegister;
3397 SavedRegs.
set(UnspilledCSGPRPaired);
3406 unsigned Size =
TRI->getSpillSize(RC);
3407 Align Alignment =
TRI->getSpillAlign(RC);
3410 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
3411 <<
" as the emergency spill slot.\n");
3416 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
3420 if (
hasFP(MF) && AFI->hasSwiftAsyncContext())
3425 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
3428 AFI->getCalleeSavedStackSize() == AlignedCSStackSize) &&
3429 "Should not invalidate callee saved info");
3433 AFI->setCalleeSavedStackSize(AlignedCSStackSize);
3434 AFI->setCalleeSaveStackHasFreeSpace(AlignedCSStackSize != CSStackSize);
3435 AFI->setSVECalleeSavedStackSize(
alignTo(SVECSStackSize, 16));
3440 std::vector<CalleeSavedInfo> &CSI,
unsigned &MinCSFrameIndex,
3441 unsigned &MaxCSFrameIndex)
const {
3450 std::reverse(CSI.begin(), CSI.end());
3464 if ((
unsigned)FrameIdx < MinCSFrameIndex)
3465 MinCSFrameIndex = FrameIdx;
3466 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
3467 MaxCSFrameIndex = FrameIdx;
3474 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
3475 if (It != CSI.end())
3476 CSI.insert(It, VGInfo);
3478 CSI.push_back(VGInfo);
3482 int HazardSlotIndex = std::numeric_limits<int>::max();
3483 for (
auto &CS : CSI) {
3491 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
3492 "Unexpected register order for hazard slot");
3494 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3497 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
3498 MinCSFrameIndex = HazardSlotIndex;
3499 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
3500 MaxCSFrameIndex = HazardSlotIndex;
3503 unsigned Size = RegInfo->getSpillSize(*RC);
3504 Align Alignment(RegInfo->getSpillAlign(*RC));
3506 CS.setFrameIdx(FrameIdx);
3508 if ((
unsigned)FrameIdx < MinCSFrameIndex)
3509 MinCSFrameIndex = FrameIdx;
3510 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
3511 MaxCSFrameIndex = FrameIdx;
3515 Reg == AArch64::FP) {
3518 if ((
unsigned)FrameIdx < MinCSFrameIndex)
3519 MinCSFrameIndex = FrameIdx;
3520 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
3521 MaxCSFrameIndex = FrameIdx;
3528 HazardSlotIndex == std::numeric_limits<int>::max()) {
3530 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3533 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
3534 MinCSFrameIndex = HazardSlotIndex;
3535 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
3536 MaxCSFrameIndex = HazardSlotIndex;
3560 int &Min,
int &Max) {
3561 Min = std::numeric_limits<int>::max();
3562 Max = std::numeric_limits<int>::min();
3568 for (
auto &CS : CSI) {
3569 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
3570 AArch64::PPRRegClass.contains(CS.getReg())) {
3571 assert((Max == std::numeric_limits<int>::min() ||
3572 Max + 1 == CS.getFrameIdx()) &&
3573 "SVE CalleeSaves are not consecutive");
3575 Min = std::min(Min, CS.getFrameIdx());
3576 Max = std::max(Max, CS.getFrameIdx());
3579 return Min != std::numeric_limits<int>::max();
3588 int &MinCSFrameIndex,
3589 int &MaxCSFrameIndex,
3590 bool AssignOffsets) {
3595 "SVE vectors should never be passed on the stack by value, only by "
3599 auto Assign = [&MFI](
int FI, int64_t
Offset) {
3609 for (
int I = MinCSFrameIndex;
I <= MaxCSFrameIndex; ++
I) {
3625 int StackProtectorFI = -1;
3629 ObjectsToAllocate.
push_back(StackProtectorFI);
3635 if (
I == StackProtectorFI)
3637 if (MaxCSFrameIndex >=
I &&
I >= MinCSFrameIndex)
3646 for (
unsigned FI : ObjectsToAllocate) {
3651 if (Alignment >
Align(16))
3653 "Alignment of scalable vectors > 16 bytes is not yet supported");
3663int64_t AArch64FrameLowering::estimateSVEStackObjectOffsets(
3665 int MinCSFrameIndex, MaxCSFrameIndex;
3669int64_t AArch64FrameLowering::assignSVEStackObjectOffsets(
3680 if (PreferredReg != AArch64::NoRegister && UsedRegs.
available(PreferredReg))
3681 return PreferredReg;
3686 return AArch64::NoRegister;
3718 std::optional<int> *MaybeSpillFI,
3719 Register PreferredReg = AArch64::NoRegister)
3721 *MF.getSubtarget().getInstrInfo())),
3722 TRI(*MF.getSubtarget().getRegisterInfo()) {
3724 if (FreeReg != AArch64::NoRegister)
3726 assert(MaybeSpillFI &&
"Expected emergency spill slot FI information "
3727 "(attempted to spill in prologue/epilogue?)");
3728 if (!MaybeSpillFI->has_value()) {
3731 TRI.getSpillAlign(RC));
3733 FreeReg = SpillCandidate;
3734 SpillFI = MaybeSpillFI->value();
3735 TII.storeRegToStackSlot(MBB, MBBI, FreeReg,
false, *SpillFI, &RC, &TRI,
3748 TII.loadRegFromStackSlot(MBB, MBBI, FreeReg, *SpillFI, &RC, &TRI,
3758 Register FreeReg = AArch64::NoRegister;
3759 std::optional<int> SpillFI;
3804 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
3811 .
add(
MI.getOperand(0))
3817 .
add(
MI.getOperand(1))
3847 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
3851 MF,
MBB,
MI, AArch64::P0, AArch64::PPR_3bRegClass, UsedRegs, SR.
PPR3bRegs,
3857 bool IsNZCVUsed = !UsedRegs.
available(AArch64::NZCV);
3858 std::optional<ScopedScavengeOrSpill> NZCVSaveReg;
3860 NZCVSaveReg.emplace(
3861 MF,
MBB,
MI, AArch64::X0, AArch64::GPR64RegClass, UsedRegs, SR.
GPRRegs,
3867 .
add(
MI.getOperand(1))
3875 .
addImm(AArch64SysReg::NZCV)
3899 .
addImm(AArch64SysReg::NZCV)
3900 .
addReg(NZCVSaveReg->freeRegister())
3916 bool HasPPRSpills =
false;
3920 switch (
MI.getOpcode()) {
3921 case AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO:
3924 LastPTrue =
nullptr;
3926 LastPTrue, SpillSlots);
3927 MI.eraseFromParent();
3929 case AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO:
3931 MI.eraseFromParent();
3934 LastPTrue =
nullptr;
3939 return HasPPRSpills;
3951 if (AFI->
hasStackFrame() &&
TRI.getSpillSize(AArch64::PPRRegClass) == 16) {
3952 auto ComputeScavengeableRegisters = [&](
unsigned RegClassID) {
3953 BitVector Regs =
TRI.getAllocatableSet(MF,
TRI.getRegClass(RegClassID));
3954 assert(Regs.
count() > 0 &&
"Expected scavengeable registers");
3959 SR.
ZPRRegs = ComputeScavengeableRegisters(AArch64::ZPRRegClassID);
3961 SR.
PPR3bRegs = ComputeScavengeableRegisters(AArch64::PPR_3bRegClassID);
3962 SR.
GPRRegs = ComputeScavengeableRegisters(AArch64::GPR64RegClassID);
3974 assert((
Pass == 0 || !HasPPRSpills) &&
"Did not expect PPR spills");
3984 "Upwards growing stack unsupported");
3986 int MinCSFrameIndex, MaxCSFrameIndex;
3987 int64_t SVEStackSize =
3988 assignSVEStackObjectOffsets(MFI, MinCSFrameIndex, MaxCSFrameIndex);
4001 int64_t CurrentOffset =
4005 int FrameIndex =
H.CatchObj.FrameIndex;
4006 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
4017 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
4018 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
4020 "UnwindHelpOffset must be at the start of the fixed object area");
4036 assert(DstReg &&
"There must be a free register after frame setup");
4046struct TagStoreInstr {
4054 MachineFunction *MF;
4055 MachineBasicBlock *
MBB;
4056 MachineRegisterInfo *
MRI;
4065 StackOffset FrameRegOffset;
4069 std::optional<int64_t> FrameRegUpdate;
4071 unsigned FrameRegUpdateFlags;
4081 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
4082 :
MBB(
MBB), ZeroData(ZeroData) {
4088 void addInstruction(TagStoreInstr
I) {
4090 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
4091 "Non-adjacent tag store instructions.");
4094 void clear() { TagStores.
clear(); }
4099 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
4106 const int64_t kMinOffset = -256 * 16;
4107 const int64_t kMaxOffset = 255 * 16;
4110 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
4111 if (BaseRegOffsetBytes < kMinOffset ||
4112 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
4116 BaseRegOffsetBytes % 16 != 0) {
4117 Register ScratchReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4121 BaseRegOffsetBytes = 0;
4126 int64_t InstrSize = (
Size > 16) ? 32 : 16;
4129 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
4131 assert(BaseRegOffsetBytes % 16 == 0);
4135 .
addImm(BaseRegOffsetBytes / 16)
4139 if (BaseRegOffsetBytes == 0)
4141 BaseRegOffsetBytes += InstrSize;
4155 :
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4156 Register SizeReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4160 int64_t LoopSize =
Size;
4163 if (FrameRegUpdate && *FrameRegUpdate)
4164 LoopSize -= LoopSize % 32;
4166 TII->get(ZeroData ? AArch64::STZGloop_wback
4167 : AArch64::STGloop_wback))
4174 LoopI->
setFlags(FrameRegUpdateFlags);
4176 int64_t ExtraBaseRegUpdate =
4177 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
4178 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
4179 <<
", Size=" <<
Size
4180 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
4181 <<
", FrameRegUpdate=" << FrameRegUpdate
4182 <<
", FrameRegOffset.getFixed()="
4183 << FrameRegOffset.
getFixed() <<
"\n");
4184 if (LoopSize <
Size) {
4188 int64_t STGOffset = ExtraBaseRegUpdate + 16;
4189 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
4190 "STG immediate out of range");
4192 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
4199 }
else if (ExtraBaseRegUpdate) {
4201 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
4202 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
4205 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
4218 int64_t
Size, int64_t *TotalOffset) {
4220 if ((
MI.getOpcode() == AArch64::ADDXri ||
4221 MI.getOpcode() == AArch64::SUBXri) &&
4222 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
4224 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
4225 if (
MI.getOpcode() == AArch64::SUBXri)
4236 const int64_t kMaxOffset = 4080 - 16;
4238 const int64_t kMinOffset = -4095;
4239 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
4240 PostOffset % 16 == 0) {
4251 for (
auto &TS : TSE) {
4255 if (
MI->memoperands_empty()) {
4259 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
4265 bool TryMergeSPUpdate) {
4266 if (TagStores.
empty())
4268 TagStoreInstr &FirstTagStore = TagStores[0];
4269 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
4270 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
4271 DL = TagStores[0].MI->getDebugLoc();
4275 *MF, FirstTagStore.Offset,
false ,
false ,
Reg,
4278 FrameRegUpdate = std::nullopt;
4280 mergeMemRefs(TagStores, CombinedMemRefs);
4283 dbgs() <<
"Replacing adjacent STG instructions:\n";
4284 for (
const auto &Instr : TagStores) {
4293 if (TagStores.
size() < 2)
4295 emitUnrolled(InsertI);
4298 int64_t TotalOffset = 0;
4299 if (TryMergeSPUpdate) {
4305 if (InsertI !=
MBB->
end() &&
4306 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
4308 UpdateInstr = &*InsertI++;
4314 if (!UpdateInstr && TagStores.
size() < 2)
4318 FrameRegUpdate = TotalOffset;
4319 FrameRegUpdateFlags = UpdateInstr->
getFlags();
4326 for (
auto &TS : TagStores)
4327 TS.MI->eraseFromParent();
4331 int64_t &
Size,
bool &ZeroData) {
4335 unsigned Opcode =
MI.getOpcode();
4336 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
4337 Opcode == AArch64::STZ2Gi);
4339 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
4340 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
4342 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
4345 Size =
MI.getOperand(2).getImm();
4349 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
4351 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
4356 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
4360 16 *
MI.getOperand(2).getImm();
4380 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
4386 constexpr int kScanLimit = 10;
4389 NextI !=
E &&
Count < kScanLimit; ++NextI) {
4398 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
4399 if (ZeroData != FirstZeroData)
4407 if (!
MI.isTransient())
4416 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
4432 LiveRegs.addLiveOuts(*
MBB);
4437 LiveRegs.stepBackward(*
I);
4440 if (LiveRegs.contains(AArch64::NZCV))
4444 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
4449 int64_t CurOffset = Instrs[0].Offset;
4450 for (
auto &Instr : Instrs) {
4451 if (CurOffset >
Instr.Offset)
4458 TagStoreEdit TSE(
MBB, FirstZeroData);
4459 std::optional<int64_t> EndOffset;
4460 for (
auto &Instr : Instrs) {
4461 if (EndOffset && *EndOffset !=
Instr.Offset) {
4463 TSE.emitCode(InsertI, TFI,
false);
4467 TSE.addInstruction(Instr);
4486 II = tryMergeAdjacentSTG(
II,
this, RS);
4493 shouldSignReturnAddressEverywhere(MF))
4502 bool IgnoreSPUpdates)
const {
4504 if (IgnoreSPUpdates) {
4507 FrameReg = AArch64::SP;
4517 FrameReg = AArch64::SP;
4542 bool IsValid =
false;
4544 int ObjectIndex = 0;
4546 int GroupIndex = -1;
4548 bool ObjectFirst =
false;
4551 bool GroupFirst =
false;
4556 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
4560 SmallVector<int, 8> CurrentMembers;
4561 int NextGroupIndex = 0;
4562 std::vector<FrameObject> &Objects;
4565 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
4566 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
4567 void EndCurrentGroup() {
4568 if (CurrentMembers.
size() > 1) {
4573 for (
int Index : CurrentMembers) {
4574 Objects[
Index].GroupIndex = NextGroupIndex;
4580 CurrentMembers.clear();
4584bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
4606 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
4607 A.GroupIndex,
A.ObjectIndex) <
4608 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
4609 B.GroupIndex,
B.ObjectIndex);
4620 std::vector<FrameObject> FrameObjects(MFI.getObjectIndexEnd());
4621 for (
auto &Obj : ObjectsToAllocate) {
4622 FrameObjects[Obj].IsValid =
true;
4623 FrameObjects[Obj].ObjectIndex = Obj;
4628 GroupBuilder GB(FrameObjects);
4629 for (
auto &
MBB : MF) {
4630 for (
auto &
MI :
MBB) {
4631 if (
MI.isDebugInstr())
4636 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
4639 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
4641 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
4646 switch (
MI.getOpcode()) {
4647 case AArch64::STGloop:
4648 case AArch64::STZGloop:
4652 case AArch64::STZGi:
4653 case AArch64::ST2Gi:
4654 case AArch64::STZ2Gi:
4666 if (FI >= 0 && FI < MFI.getObjectIndexEnd() &&
4667 FrameObjects[FI].IsValid)
4675 GB.AddMember(TaggedFI);
4677 GB.EndCurrentGroup();
4680 GB.EndCurrentGroup();
4685 FrameObject::AccessHazard;
4687 for (
auto &Obj : FrameObjects)
4688 if (!Obj.Accesses ||
4689 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
4690 Obj.Accesses = FrameObject::AccessGPR;
4699 FrameObjects[*TBPI].ObjectFirst =
true;
4700 FrameObjects[*TBPI].GroupFirst =
true;
4701 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
4702 if (FirstGroupIndex >= 0)
4703 for (FrameObject &Object : FrameObjects)
4704 if (Object.GroupIndex == FirstGroupIndex)
4705 Object.GroupFirst =
true;
4711 for (
auto &Obj : FrameObjects) {
4715 ObjectsToAllocate[i++] = Obj.ObjectIndex;
4719 dbgs() <<
"Final frame order:\n";
4720 for (
auto &Obj : FrameObjects) {
4723 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
4724 if (Obj.ObjectFirst)
4725 dbgs() <<
", first";
4727 dbgs() <<
", group-first";
4738AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
4749 MF.
insert(MBBInsertPoint, LoopMBB);
4751 MF.
insert(MBBInsertPoint, ExitMBB);
4782 MBB.addSuccessor(LoopMBB);
4786 return ExitMBB->
begin();
4789void AArch64FrameLowering::inlineStackProbeFixed(
4794 const AArch64InstrInfo *
TII =
4796 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
4801 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
4802 int64_t NumBlocks = FrameSize / ProbeSize;
4803 int64_t ResidualSize = FrameSize % ProbeSize;
4805 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
4806 << NumBlocks <<
" blocks of " << ProbeSize
4807 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
4812 for (
int i = 0; i < NumBlocks; ++i) {
4818 EmitAsyncCFI && !HasFP, CFAOffset);
4827 }
else if (NumBlocks != 0) {
4833 EmitAsyncCFI && !HasFP, CFAOffset);
4835 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
4837 if (EmitAsyncCFI && !HasFP) {
4840 .buildDefCFARegister(AArch64::SP);
4844 if (ResidualSize != 0) {
4850 EmitAsyncCFI && !HasFP, CFAOffset);
4867 SmallVector<MachineInstr *, 4> ToReplace;
4868 for (MachineInstr &
MI :
MBB)
4869 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
4870 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
4873 for (MachineInstr *
MI : ToReplace) {
4874 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
4875 Register ScratchReg =
MI->getOperand(0).getReg();
4876 int64_t FrameSize =
MI->getOperand(1).getImm();
4878 MI->getOperand(3).getImm());
4879 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
4882 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
4883 "Stack probe pseudo-instruction expected");
4884 const AArch64InstrInfo *
TII =
4885 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
4886 Register TargetReg =
MI->getOperand(0).getReg();
4887 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
4889 MI->eraseFromParent();
4909 return std::make_tuple(
start(),
Idx) <
4910 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4940 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4941 if (
Offset.getScalable())
4942 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4953void AArch64FrameLowering::emitRemarks(
4956 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4961 const uint64_t HazardSize =
4964 if (HazardSize == 0)
4972 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4974 size_t NumFPLdSt = 0;
4975 size_t NumNonFPLdSt = 0;
4978 for (
const MachineBasicBlock &
MBB : MF) {
4979 for (
const MachineInstr &
MI :
MBB) {
4980 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4982 for (MachineMemOperand *MMO :
MI.memoperands()) {
4989 StackAccesses[ArrIdx].Idx = FrameIdx;
4990 StackAccesses[ArrIdx].Offset =
4999 if (
MI.getOpcode() != AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO &&
5000 MI.getOpcode() != AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO &&
5001 AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg())) {
5009 StackAccesses[ArrIdx].AccessTypes |= RegTy;
5020 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
5031 if (StackAccesses.front().isMixed())
5032 MixedObjects.push_back(&StackAccesses.front());
5034 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
5036 const auto &
First = *It;
5037 const auto &Second = *(It + 1);
5039 if (Second.isMixed())
5040 MixedObjects.push_back(&Second);
5042 if ((
First.isSME() && Second.isCPU()) ||
5043 (
First.isCPU() && Second.isSME())) {
5044 uint64_t Distance =
static_cast<uint64_t
>(Second.start() -
First.end());
5045 if (Distance < HazardSize)
5050 auto EmitRemark = [&](llvm::StringRef Str) {
5052 auto R = MachineOptimizationRemarkAnalysis(
5053 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
5054 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
5058 for (
const auto &
P : HazardPairs)
5059 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
5061 for (
const auto *Obj : MixedObjects)
5063 formatv(
"{0} accessed by both GP and FP instructions", *Obj).str());
unsigned const MachineRegisterInfo * MRI
static int64_t getArgumentStackToRestore(MachineFunction &MF, MachineBasicBlock &MBB)
Returns how much of the incoming argument stack area (in bytes) we should clean up in an epilogue.
static void getLiveRegsForEntryMBB(LivePhysRegs &LiveRegs, const MachineBasicBlock &MBB)
static void emitCalleeSavedRestores(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool SVE)
static Register tryScavengeRegister(LiveRegUnits const &UsedRegs, BitVector const &ScavengeableRegs, Register PreferredReg)
Attempts to scavenge a register from ScavengeableRegs given the used registers in UsedRegs.
static const unsigned DefaultSafeSPDisplacement
This is the biggest offset to the stack pointer we can encode in aarch64 instructions (without using ...
static bool isInPrologueOrEpilogue(const MachineInstr &MI)
static bool produceCompactUnwindFrame(const AArch64FrameLowering &, MachineFunction &MF)
static bool expandFillPPRFromZPRSlotPseudo(MachineBasicBlock &MBB, MachineInstr &MI, const TargetRegisterInfo &TRI, LiveRegUnits const &UsedRegs, ScavengeableRegs const &SR, MachineInstr *&LastPTrue, EmergencyStackSlots &SpillSlots)
Expands:
static cl::opt< bool > StackTaggingMergeSetTag("stack-tagging-merge-settag", cl::desc("merge settag instruction in function epilog"), cl::init(true), cl::Hidden)
bool enableMultiVectorSpillFill(const AArch64Subtarget &Subtarget, MachineFunction &MF)
static std::optional< int > getLdStFrameID(const MachineInstr &MI, const MachineFrameInfo &MFI)
static cl::opt< bool > StackHazardInNonStreaming("aarch64-stack-hazard-in-non-streaming", cl::init(false), cl::Hidden)
static bool matchLibcall(const TargetLowering &TLI, const MachineOperand &MO, RTLIB::Libcall LC)
void computeCalleeSaveRegisterPairs(const AArch64FrameLowering &AFL, MachineFunction &MF, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI, SmallVectorImpl< RegPairInfo > &RegPairs, bool NeedsFrameRecord)
static int64_t determineSVEStackObjectOffsets(MachineFrameInfo &MFI, int &MinCSFrameIndex, int &MaxCSFrameIndex, bool AssignOffsets)
static cl::opt< bool > OrderFrameObjects("aarch64-order-frame-objects", cl::desc("sort stack allocations"), cl::init(true), cl::Hidden)
static bool invalidateWindowsRegisterPairing(unsigned Reg1, unsigned Reg2, bool NeedsWinCFI, bool IsFirst, const TargetRegisterInfo *TRI)
static void fixupSEHOpcode(MachineBasicBlock::iterator MBBI, unsigned LocalStackSize)
static cl::opt< bool > DisableMultiVectorSpillFill("aarch64-disable-multivector-spill-fill", cl::desc("Disable use of LD/ST pairs for SME2 or SVE2p1"), cl::init(false), cl::Hidden)
static cl::opt< bool > EnableRedZone("aarch64-redzone", cl::desc("enable use of redzone on AArch64"), cl::init(false), cl::Hidden)
static MachineBasicBlock::iterator InsertSEH(MachineBasicBlock::iterator MBBI, const TargetInstrInfo &TII, MachineInstr::MIFlag Flag)
cl::opt< bool > EnableHomogeneousPrologEpilog("homogeneous-prolog-epilog", cl::Hidden, cl::desc("Emit homogeneous prologue and epilogue for the size " "optimization (default = off)"))
static bool expandSMEPPRToZPRSpillPseudos(MachineBasicBlock &MBB, const TargetRegisterInfo &TRI, ScavengeableRegs const &SR, EmergencyStackSlots &SpillSlots)
Expands all FILL_PPR_FROM_ZPR_SLOT_PSEUDO and SPILL_PPR_TO_ZPR_SLOT_PSEUDO operations within the Mach...
static bool isLikelyToHaveSVEStack(const AArch64FrameLowering &AFL, const MachineFunction &MF)
static bool invalidateRegisterPairing(unsigned Reg1, unsigned Reg2, bool UsesWinAAPCS, bool NeedsWinCFI, bool NeedsFrameRecord, bool IsFirst, const TargetRegisterInfo *TRI)
Returns true if Reg1 and Reg2 cannot be paired using a ldp/stp instruction.
unsigned findFreePredicateReg(BitVector &SavedRegs)
static unsigned getPrologueDeath(MachineFunction &MF, unsigned Reg)
static void expandSpillPPRToZPRSlotPseudo(MachineBasicBlock &MBB, MachineInstr &MI, const TargetRegisterInfo &TRI, LiveRegUnits const &UsedRegs, ScavengeableRegs const &SR, EmergencyStackSlots &SpillSlots)
Expands:
static bool isTargetWindows(const MachineFunction &MF)
static void emitShadowCallStackEpilogue(const TargetInstrInfo &TII, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, bool NeedsWinCFI)
static int64_t upperBound(StackOffset Size)
static unsigned estimateRSStackSizeLimit(MachineFunction &MF)
Look at each instruction that references stack frames and return the stack size limit beyond which so...
static bool getSVECalleeSaveSlotRange(const MachineFrameInfo &MFI, int &Min, int &Max)
returns true if there are any SVE callee saves.
static cl::opt< unsigned > StackHazardRemarkSize("aarch64-stack-hazard-remark-size", cl::init(0), cl::Hidden)
static MCRegister getRegisterOrZero(MCRegister Reg, bool HasSVE)
static bool isFuncletReturnInstr(const MachineInstr &MI)
static unsigned getStackHazardSize(const MachineFunction &MF)
static void propagateFrameFlags(MachineInstr &SourceMI, ArrayRef< MachineInstr * > MachineInstrs)
Propagates frame-setup/destroy flags from SourceMI to all instructions in MachineInstrs.
static std::optional< int > getMMOFrameID(MachineMemOperand *MMO, const MachineFrameInfo &MFI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declaration of the AArch64PrologueEmitter class, which is is used to emit the ...
static const int kSetTagLoopThreshold
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
This file contains the simple types necessary to represent the attributes associated with functions a...
#define CASE(ATTRNAME, AANAME,...)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Analysis containing CSE Info
DXIL Forward Handle Accesses
const HexagonInstrInfo * TII
std::pair< Instruction::BinaryOps, Value * > OffsetOp
Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
static std::string getTypeString(Type *T)
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
uint64_t IntrinsicInst * II
This file declares the machine register scavenger class.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
This file defines the SmallVector class.
void processFunctionBeforeFrameIndicesReplaced(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameIndicesReplaced - This method is called immediately before MO_FrameIndex op...
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override
This method is called during prolog/epilog code insertion to eliminate call frame setup and destroy p...
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override
Check whether or not the given MBB can be used as a prologue for the target.
bool enableStackSlotScavenging(const MachineFunction &MF) const override
Returns true if the stack slot holes in the fixed and callee-save stack area should be used when allo...
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
spillCalleeSavedRegisters - Issues instruction(s) to spill all callee saved registers and returns tru...
bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MutableArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee saved registers and returns...
bool enableFullCFIFixup(const MachineFunction &MF) const override
enableFullCFIFixup - Returns true if we may need to fix the unwind information such that it is accura...
StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI) const override
getFrameIndexReferenceFromSP - This method returns the offset from the stack pointer to the slot of t...
bool enableCFIFixup(const MachineFunction &MF) const override
Returns true if we may need to fix the unwind information for the function.
StackOffset getNonLocalFrameIndexReference(const MachineFunction &MF, int FI) const override
getNonLocalFrameIndexReference - This method returns the offset used to reference a frame index locat...
TargetStackID::Value getStackIDForScalableVectors() const override
Returns the StackID that scalable vectors should be associated with.
friend class AArch64PrologueEmitter
bool hasFPImpl(const MachineFunction &MF) const override
hasFPImpl - Return true if the specified function should have a dedicated frame pointer register.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override
emitProlog/emitEpilog - These methods insert prolog and epilog code into the function.
void resetCFIToInitialState(MachineBasicBlock &MBB) const override
Emit CFI instructions that recreate the state of the unwind information upon function entry.
bool hasReservedCallFrame(const MachineFunction &MF) const override
hasReservedCallFrame - Under normal circumstances, when a frame pointer is not required,...
bool canUseRedZone(const MachineFunction &MF) const
Can this function use the red zone for local allocations.
bool needsWinCFI(const MachineFunction &MF) const
bool isFPReserved(const MachineFunction &MF) const
Should the Frame Pointer be reserved for the current function?
void processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameFinalized - This method is called immediately before the specified function...
int getSEHFrameIndexOffset(const MachineFunction &MF, int FI) const
unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const
Funclets only need to account for space for the callee saved registers, as the locals are accounted f...
void orderFrameObjects(const MachineFunction &MF, SmallVectorImpl< int > &ObjectsToAllocate) const override
Order the symbols in the local stack frame.
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
StackOffset getSVEStackSize(const MachineFunction &MF) const
Returns the size of the entire SVE stackframe (calleesaves + spills).
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const override
getFrameIndexReference - Provide a base+offset reference to an FI slot for debug info.
StackOffset resolveFrameOffsetReference(const MachineFunction &MF, int64_t ObjectOffset, bool isFixed, bool isSVE, Register &FrameReg, bool PreferFP, bool ForSimm) const
bool assignCalleeSavedSpillSlots(MachineFunction &MF, const TargetRegisterInfo *TRI, std::vector< CalleeSavedInfo > &CSI, unsigned &MinCSFrameIndex, unsigned &MaxCSFrameIndex) const override
assignCalleeSavedSpillSlots - Allows target to override spill slot assignment logic.
StackOffset getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI, Register &FrameReg, bool IgnoreSPUpdates) const override
For Win64 AArch64 EH, the offset to the Unwind object is from the SP before the update.
StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg, bool PreferFP, bool ForSimm) const
unsigned getWinEHParentFrameOffset(const MachineFunction &MF) const override
The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve the parent's frame pointer...
bool requiresSaveVG(const MachineFunction &MF) const
void emitPacRetPlusLeafHardening(MachineFunction &MF) const
Harden the entire function with pac-ret.
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
bool needsShadowCallStackPrologueEpilogue(MachineFunction &MF) const
void setSwiftAsyncContextFrameIdx(int FI)
unsigned getTailCallReservedStack() const
unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const
void setCalleeSaveBaseToFrameRecordOffset(int Offset)
bool hasStackProbing() const
unsigned getArgumentStackToRestore() const
void setLocalStackSize(uint64_t Size)
int getCalleeSaveBaseToFrameRecordOffset() const
bool hasStreamingModeChanges() const
bool shouldSignReturnAddress(const MachineFunction &MF) const
void setPredicateRegForFillSpill(unsigned Reg)
int getStackHazardSlotIndex() const
int64_t getStackProbeSize() const
uint64_t getStackSizeSVE() const
bool hasStackFrame() const
std::optional< int > getTaggedBasePointerIndex() const
SMEAttrs getSMEFnAttrs() const
uint64_t getLocalStackSize() const
void setStackRealigned(bool s)
bool needsDwarfUnwindInfo(const MachineFunction &MF) const
unsigned getVarArgsGPRSize() const
void setStackSizeSVE(uint64_t S)
bool isStackRealigned() const
bool hasSwiftAsyncContext() const
bool hasStackHazardSlotIndex() const
void setStackHazardSlotIndex(int Index)
void setStackHazardCSRSlotIndex(int Index)
unsigned getPredicateRegForFillSpill() const
bool hasCalculatedStackSizeSVE() const
unsigned getSVECalleeSavedStackSize() const
bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const
void setMinMaxSVECSFrameIndex(int Min, int Max)
bool hasCalleeSaveStackFreeSpace() const
static bool isTailCallReturnInst(const MachineInstr &MI)
Returns true if MI is one of the TCRETURN* instructions.
static bool isFpOrNEON(Register Reg)
Returns whether the physical register is FP or NEON.
void emitPrologue()
Emit the prologue.
bool isTargetWindows() const
const AArch64RegisterInfo * getRegisterInfo() const override
bool isNeonAvailable() const
Returns true if the target has NEON and the function at runtime is known to have NEON enabled (e....
const AArch64InstrInfo * getInstrInfo() const override
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
bool isSVEorStreamingSVEAvailable() const
Returns true if the target has access to either the full range of SVE instructions,...
bool isStreaming() const
Returns true if the function has a streaming body.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this functions.
unsigned getRedZoneSize(const Function &F) const
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
bool test(unsigned Idx) const
size_type count() const
count - Returns the number of bits which are set.
iterator_range< const_set_bits_iterator > set_bits() const
Helper class for creating CFI instructions and inserting them into MIR.
void buildRestore(MCRegister Reg) const
void buildDefCFA(MCRegister Reg, int64_t Offset) const
The CalleeSavedInfo class tracks the information need to locate where a callee saved register is in t...
bool hasOptSize() const
Optimize this function for size (-Os) or minimum size (-Oz).
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
AttributeList getAttributes() const
Return the attribute list for this Function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
A set of physical registers with utility functions to track liveness when walking backward/forward th...
A set of register units used to track register liveness.
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
LLVM_ABI void stepBackward(const MachineInstr &MI)
Updates liveness when stepping backwards over the instruction MI.
LLVM_ABI void addLiveOuts(const MachineBasicBlock &MBB)
Adds registers living out of block MBB.
bool usesWindowsCFI() const
Wrapper class representing physical registers. Should be passed by value.
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
MachineInstr & instr_back()
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
reverse_iterator rbegin()
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
LLVM_ABI int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
const AllocaInst * getObjectAllocation(int ObjectIdx) const
Return the underlying Alloca of the specified stack object if it exists.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
bool hasCalls() const
Return true if the current function has any function calls.
bool isFrameAddressTaken() const
This method may be called any time after instruction selection is complete to determine if there is a...
Align getMaxAlign() const
Return the alignment in bytes that this function must be aligned to, which is greater than the defaul...
void setObjectOffset(int ObjectIdx, int64_t SPOffset)
Set the stack frame offset of the specified object.
uint64_t getMaxCallFrameSize() const
Return the maximum size of a call frame that must be allocated for an outgoing function call.
bool hasPatchPoint() const
This method may be called any time after instruction selection is complete to determine if there is a...
int getStackProtectorIndex() const
Return the index for the stack protector object.
LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
LLVM_ABI uint64_t estimateStackSize(const MachineFunction &MF) const
Estimate and return the size of the stack frame.
void setStackID(int ObjectIdx, uint8_t ID)
bool isCalleeSavedInfoValid() const
Has the callee saved info been calculated yet?
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
bool isMaxCallFrameSizeComputed() const
bool hasStackMap() const
This method may be called any time after instruction selection is complete to determine if there is a...
const std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const
Returns a reference to call saved info vector for the current function.
unsigned getNumObjects() const
Return the number of objects.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
bool hasStackProtectorIndex() const
bool hasStackObjects() const
Return true if there are any stack objects in this function.
uint8_t getStackID(int ObjectIdx) const
unsigned getNumFixedObjects() const
Return the number of fixed objects.
int64_t getObjectOffset(int ObjectIdx) const
Return the assigned stack offset of the specified object from the incoming stack pointer.
int getObjectIndexBegin() const
Return the minimum frame object index.
void setObjectAlignment(int ObjectIdx, Align Alignment)
setObjectAlignment - Change the alignment of the specified stack object.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
const WinEHFuncInfo * getWinEHFuncInfo() const
getWinEHFuncInfo - Return information about how the current function uses Windows exception handling.
void setHasWinCFI(bool v)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineBasicBlock & front() const
bool hasEHFunclets() const
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
void setFlags(unsigned flags)
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI void moveBefore(MachineInstr *MovePos)
Move the instruction before MovePos.
A description of a memory reference used in the backend.
const PseudoSourceValue * getPseudoValue() const
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
const Value * getValue() const
Return the base address of the memory access.
MachineOperand class - Representation of each machine instruction operand.
void setImm(int64_t immVal)
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI bool isLiveIn(Register Reg) const
LLVM_ABI const MCPhysReg * getCalleeSavedRegs() const
Returns list of callee saved registers.
LLVM_ABI bool isPhysRegUsed(MCRegister PhysReg, bool SkipRegMaskTest=false) const
Return true if the specified register is modified or read in this function.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Pass interface - Implemented by all 'passes'.
void enterBasicBlockEnd(MachineBasicBlock &MBB)
Start tracking liveness from the end of basic block MBB.
Register FindUnusedReg(const TargetRegisterClass *RC) const
Find an unused register of the specified register class.
void backward()
Update internal register state and move MBB iterator backwards.
void addScavengingFrameIndex(int FI)
Add a scavenging frame index.
Wrapper class representing virtual and physical registers.
SMEAttrs is a utility class to parse the SME ACLE attributes on functions.
bool hasStreamingInterface() const
bool hasNonStreamingInterfaceAndBody() const
bool hasStreamingBody() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
A SetVector that performs no allocations if smaller than a certain size.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StackOffset holds a fixed and a scalable offset in bytes.
int64_t getFixed() const
Returns the fixed component of the stack.
int64_t getScalable() const
Returns the scalable component of the stack.
static StackOffset get(int64_t Fixed, int64_t Scalable)
static StackOffset getScalable(int64_t Scalable)
static StackOffset getFixed(int64_t Fixed)
StringRef - Represent a constant reference to a string, i.e.
bool hasFP(const MachineFunction &MF) const
hasFP - Return true if the specified function should have a dedicated frame pointer register.
virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS=nullptr) const
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
int getOffsetOfLocalArea() const
getOffsetOfLocalArea - This method returns the offset of the local area from the stack pointer on ent...
Align getStackAlign() const
getStackAlignment - This method returns the number of bytes to which the stack pointer must be aligne...
StackDirection getStackGrowthDirection() const
getStackGrowthDirection - Return the direction the stack grows
virtual bool enableCFIFixup(const MachineFunction &MF) const
Returns true if we may need to fix the unwind information for the function.
TargetInstrInfo - Interface to description of machine instruction set.
CallingConv::ID getLibcallCallingConv(RTLIB::Libcall Call) const
Get the CallingConv that should be used for the specified libcall.
const char * getLibcallName(RTLIB::Libcall Call) const
Get the libcall routine name for the specified libcall.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
Primary interface to the complete machine description for the target machine.
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
SwiftAsyncFramePointerMode SwiftAsyncFramePointer
Control when and how the Swift async frame pointer bit should be set.
LLVM_ABI bool DisableFramePointerElim(const MachineFunction &MF) const
DisableFramePointerElim - This returns true if frame pointer elimination optimization should be disab...
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
bool hasStackRealignment(const MachineFunction &MF) const
True if stack realignment is required and still possible.
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
Triple - Helper class for working with autoconf configuration names.
static constexpr TypeSize getFixed(ScalarTy ExactSize)
constexpr ScalarTy getFixedValue() const
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, unsigned Imm)
getArithExtendImm - Encode the extend type and shift amount for an arithmetic instruction: imm: 3-bit...
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
const unsigned StackProbeMaxLoopUnroll
Maximum number of iterations to unroll for a constant size probing loop.
const unsigned StackProbeMaxUnprobedStack
Maximum allowed number of unprobed bytes above SP at an ABI boundary.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ AArch64_SVE_VectorCall
Used between AArch64 SVE functions.
@ PreserveMost
Used for runtime calls that preserves most registers.
@ CXX_FAST_TLS
Used for access functions.
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
@ PreserveAll
Used for runtime calls that preserves (almost) all registers.
@ PreserveNone
Used for runtime calls that preserves none general registers.
@ Win64
The C convention as implemented on Windows/x86-64 and AArch64.
@ SwiftTail
This follows the Swift calling convention in how arguments are passed but guarantees tail calls will ...
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Define
Register definition.
@ Kill
The last use of a register.
initializer< Ty > init(const Ty &Val)
NodeAddr< InstrNode * > Instr
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
int isAArch64FrameOffsetLegal(const MachineInstr &MI, StackOffset &Offset, bool *OutUseUnscaledOp=nullptr, unsigned *OutUnscaledOp=nullptr, int64_t *EmittableOffset=nullptr)
Check if the Offset is a valid frame offset for MI.
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
@ AArch64FrameOffsetCannotUpdate
Offset cannot apply.
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
@ Always
Always set the bit.
@ Never
Never set the bit.
@ DeploymentBased
Determine whether to set the bit statically or dynamically based on the deployment target.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, StackOffset Offset, const TargetInstrInfo *TII, MachineInstr::MIFlag=MachineInstr::NoFlags, bool SetNZCV=false, bool NeedsWinCFI=false, bool *HasWinCFI=nullptr, bool EmitCFAOffset=false, StackOffset InitialOffset={}, unsigned FrameReg=AArch64::SP)
emitFrameOffset - Emit instructions as needed to set DestReg to SrcReg plus Offset.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
FunctionAddr VTableAddr Count
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Success
The lock was released successfully.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
unsigned getDefRegState(bool B)
unsigned getKillRegState(bool B)
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
void fullyRecomputeLiveIns(ArrayRef< MachineBasicBlock * > MBBs)
Convenience function for recomputing live-in's for a set of MBBs until the computation converges.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Emergency stack slots for expanding SPILL_PPR_TO_ZPR_SLOT_PSEUDO and FILL_PPR_FROM_ZPR_SLOT_PSEUDO.
std::optional< int > PPRSpillFI
std::optional< int > GPRSpillFI
std::optional< int > ZPRSpillFI
Registers available for scavenging (ZPR, PPR3b, GPR).
RAII helper class for scavenging or spilling a register.
Register operator*() const
ScopedScavengeOrSpill(ScopedScavengeOrSpill &&)=delete
ScopedScavengeOrSpill(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SpillCandidate, const TargetRegisterClass &RC, LiveRegUnits const &UsedRegs, BitVector const &AllocatableRegs, std::optional< int > *MaybeSpillFI, Register PreferredReg=AArch64::NoRegister)
Register freeRegister() const
Returns the free register (found from scavenging or spilling a register).
ScopedScavengeOrSpill(const ScopedScavengeOrSpill &)=delete
bool operator<(const StackAccess &Rhs) const
void print(raw_ostream &OS) const
std::string getTypeString() const
This struct is a compact representation of a valid (non-zero power of two) alignment.
uint64_t value() const
This is a hole in the type system and should not be abused.
Pair of physical register and lane mask.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
SmallVector< WinEHTryBlockMapEntry, 4 > TryBlockMap
SmallVector< WinEHHandlerType, 1 > HandlerArray