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",
301 bool IsTailCallReturn = (
MBB.end() !=
MBBI)
305 int64_t ArgumentPopSize = 0;
306 if (IsTailCallReturn) {
312 ArgumentPopSize = StackAdjust.
getImm();
321 return ArgumentPopSize;
351bool AArch64FrameLowering::homogeneousPrologEpilog(
373 if (Exit && getArgumentStackToRestore(MF, *Exit))
376 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
384 unsigned NumGPRs = 0;
385 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
387 if (
Reg == AArch64::LR) {
388 assert(CSRegs[
I + 1] == AArch64::FP);
389 if (NumGPRs % 2 != 0)
401bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
420 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
421 MI.getOpcode() == AArch64::ADDXri ||
422 MI.getOpcode() == AArch64::ADDSXri)
447 bool IsWin64,
bool IsFunclet)
const {
449 "Tail call reserved stack must be aligned to 16 bytes");
450 if (!IsWin64 || IsFunclet) {
455 Attribute::SwiftAsync))
469 int FrameIndex =
H.CatchObj.FrameIndex;
470 if ((FrameIndex != INT_MAX) &&
471 CatchObjFrameIndices.
insert(FrameIndex)) {
472 FixedObjectSize =
alignTo(FixedObjectSize,
479 FixedObjectSize += 8;
481 return alignTo(FixedObjectSize, 16);
499 const unsigned RedZoneSize =
512 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
516 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
537 RegInfo->hasStackRealignment(MF))
580 const Triple &TT = TM.getTargetTriple();
584 if (TT.isOSDarwin() || TT.isOSWindows())
592 if (TM.Options.FramePointerIsReserved(MF))
622 unsigned Opc =
I->getOpcode();
623 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
624 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
627 int64_t Amount =
I->getOperand(0).getImm();
635 if (CalleePopAmount == 0) {
646 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
657 "non-reserved call frame without var sized objects?");
666 }
else if (CalleePopAmount != 0) {
669 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
681 const auto &
TRI = *Subtarget.getRegisterInfo();
687 CFIBuilder.buildDefCFA(AArch64::SP, 0);
690 if (MFI.shouldSignReturnAddress(MF))
691 MFI.branchProtectionPAuthLR() ? CFIBuilder.buildNegateRAStateWithPC()
692 : CFIBuilder.buildNegateRAState();
695 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
696 CFIBuilder.buildSameValue(AArch64::X18);
699 const std::vector<CalleeSavedInfo> &CSI =
701 for (
const auto &Info : CSI) {
703 if (!
TRI.regNeedsCFI(Reg, Reg))
705 CFIBuilder.buildSameValue(Reg);
712 static const int64_t MAX_BYTES_PER_SCALABLE_BYTE = 16;
713 return Size.getScalable() * MAX_BYTES_PER_SCALABLE_BYTE +
Size.getFixed();
716void AArch64FrameLowering::allocateStackSpace(
718 int64_t RealignmentPadding,
StackOffset AllocSize,
bool NeedsWinCFI,
719 bool *HasWinCFI,
bool EmitCFI,
StackOffset InitialOffset,
720 bool FollowupAllocs)
const {
727 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
729 AArch64FunctionInfo &AFI = *MF.
getInfo<AArch64FunctionInfo>();
733 const uint64_t AndMask = ~(MaxAlign - 1);
736 Register TargetReg = RealignmentPadding
737 ? findScratchNonCalleeSaveRegister(&
MBB)
742 EmitCFI, InitialOffset);
744 if (RealignmentPadding) {
765 if (AllocSize.
getScalable() == 0 && RealignmentPadding == 0) {
766 Register ScratchReg = findScratchNonCalleeSaveRegister(&
MBB);
767 assert(ScratchReg != AArch64::NoRegister);
777 if (FollowupAllocs) {
794 if (
upperBound(AllocSize) + RealignmentPadding <= ProbeSize) {
795 Register ScratchReg = RealignmentPadding
796 ? findScratchNonCalleeSaveRegister(&
MBB)
798 assert(ScratchReg != AArch64::NoRegister);
802 EmitCFI, InitialOffset);
803 if (RealignmentPadding) {
811 if (FollowupAllocs ||
upperBound(AllocSize) + RealignmentPadding >
826 Register TargetReg = findScratchNonCalleeSaveRegister(&
MBB);
827 assert(TargetReg != AArch64::NoRegister);
831 EmitCFI, InitialOffset);
832 if (RealignmentPadding) {
845 .buildDefCFARegister(AArch64::SP);
847 if (RealignmentPadding)
860 case AArch64::W##n: \
861 case AArch64::X##n: \
886 case AArch64::B##n: \
887 case AArch64::H##n: \
888 case AArch64::S##n: \
889 case AArch64::D##n: \
890 case AArch64::Q##n: \
891 return HasSVE ? AArch64::Z##n : AArch64::Q##n
928void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
939 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
942 BitVector GPRsToZero(
TRI.getNumRegs());
943 BitVector FPRsToZero(
TRI.getNumRegs());
946 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
949 GPRsToZero.set(XReg);
953 FPRsToZero.set(XReg);
960 for (MCRegister
Reg : GPRsToZero.set_bits())
964 for (MCRegister
Reg : FPRsToZero.set_bits())
968 for (MCRegister PReg :
969 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
970 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
971 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
973 if (RegsToZero[PReg])
979bool AArch64FrameLowering::windowsRequiresStackProbe(
981 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
982 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
986 StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
995 for (
unsigned i = 0; CSRegs[i]; ++i)
1001 bool HasCall)
const {
1011 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
1013 LivePhysRegs LiveRegs(
TRI);
1016 LiveRegs.addReg(AArch64::X16);
1017 LiveRegs.addReg(AArch64::X17);
1018 LiveRegs.addReg(AArch64::X18);
1023 if (LiveRegs.available(
MRI, AArch64::X9))
1026 for (
unsigned Reg : AArch64::GPR64RegClass) {
1027 if (LiveRegs.available(
MRI,
Reg))
1030 return AArch64::NoRegister;
1057 MBB.isLiveIn(AArch64::NZCV))
1061 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
1067 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
1068 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
1077 F.needsUnwindTableEntry();
1080bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
1088 return SignReturnAddressAll;
1091bool AArch64FrameLowering::shouldCombineCSRLocalStackBump(
1097 if (homogeneousPrologEpilog(MF))
1117 if (StackBumpBytes >= 512 || windowsRequiresStackProbe(MF, StackBumpBytes))
1120 if (MFI.hasVarSizedObjects())
1123 if (
RegInfo->hasStackRealignment(MF))
1140bool AArch64FrameLowering::shouldCombineCSRLocalStackBumpInEpilogue(
1142 if (!shouldCombineCSRLocalStackBump(*
MBB.
getParent(), StackBumpBytes))
1151 while (LastI != Begin) {
1153 if (LastI->isTransient())
1158 switch (LastI->getOpcode()) {
1159 case AArch64::STGloop:
1160 case AArch64::STZGloop:
1162 case AArch64::STZGi:
1163 case AArch64::ST2Gi:
1164 case AArch64::STZ2Gi:
1177 unsigned Opc =
MBBI->getOpcode();
1181 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1182 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1190 case AArch64::STR_ZXI:
1191 case AArch64::LDR_ZXI: {
1192 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1199 case AArch64::STR_PXI:
1200 case AArch64::LDR_PXI: {
1201 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1208 case AArch64::LDPDpost:
1211 case AArch64::STPDpre: {
1212 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1213 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1214 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1221 case AArch64::LDPXpost:
1224 case AArch64::STPXpre: {
1227 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1228 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1232 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1239 case AArch64::LDRDpost:
1242 case AArch64::STRDpre: {
1243 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1244 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1250 case AArch64::LDRXpost:
1253 case AArch64::STRXpre: {
1254 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1261 case AArch64::STPDi:
1262 case AArch64::LDPDi: {
1263 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1264 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1272 case AArch64::STPXi:
1273 case AArch64::LDPXi: {
1276 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1288 case AArch64::STRXui:
1289 case AArch64::LDRXui: {
1297 case AArch64::STRDui:
1298 case AArch64::LDRDui: {
1299 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1306 case AArch64::STPQi:
1307 case AArch64::LDPQi: {
1308 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1309 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1310 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1317 case AArch64::LDPQpost:
1320 case AArch64::STPQpre: {
1321 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1322 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1323 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1331 auto I =
MBB->insertAfter(
MBBI, MIB);
1337 unsigned LocalStackSize) {
1339 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1340 switch (
MBBI->getOpcode()) {
1343 case AArch64::SEH_SaveFPLR:
1344 case AArch64::SEH_SaveRegP:
1345 case AArch64::SEH_SaveReg:
1346 case AArch64::SEH_SaveFRegP:
1347 case AArch64::SEH_SaveFReg:
1348 case AArch64::SEH_SaveAnyRegQP:
1349 case AArch64::SEH_SaveAnyRegQPX:
1350 ImmOpnd = &
MBBI->getOperand(ImmIdx);
1357bool AArch64FrameLowering::requiresGetVGCall(
const MachineFunction &MF)
const {
1358 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
1370 if (ST.isTargetDarwin())
1376 RTLIB::Libcall LC) {
1383 unsigned Opc =
MBBI->getOpcode();
1384 if (
Opc == AArch64::CNTD_XPiI)
1387 if (!requiresGetVGCall(*
MBBI->getMF()))
1390 if (
Opc == AArch64::BL)
1391 return matchLibcall(TLI,
MBBI->getOperand(0), RTLIB::SMEABI_GET_CURRENT_VG);
1393 return Opc == TargetOpcode::COPY;
1397AArch64FrameLowering::convertCalleeSaveRestoreToSPPrePostIncDec(
1400 bool NeedsWinCFI,
bool *HasWinCFI,
bool EmitCFI,
1410 while (isVGInstruction(
MBBI, TLI))
1414 switch (
MBBI->getOpcode()) {
1417 case AArch64::STPXi:
1418 NewOpc = AArch64::STPXpre;
1420 case AArch64::STPDi:
1421 NewOpc = AArch64::STPDpre;
1423 case AArch64::STPQi:
1424 NewOpc = AArch64::STPQpre;
1426 case AArch64::STRXui:
1427 NewOpc = AArch64::STRXpre;
1429 case AArch64::STRDui:
1430 NewOpc = AArch64::STRDpre;
1432 case AArch64::STRQui:
1433 NewOpc = AArch64::STRQpre;
1435 case AArch64::LDPXi:
1436 NewOpc = AArch64::LDPXpost;
1438 case AArch64::LDPDi:
1439 NewOpc = AArch64::LDPDpost;
1441 case AArch64::LDPQi:
1442 NewOpc = AArch64::LDPQpost;
1444 case AArch64::LDRXui:
1445 NewOpc = AArch64::LDRXpost;
1447 case AArch64::LDRDui:
1448 NewOpc = AArch64::LDRDpost;
1450 case AArch64::LDRQui:
1451 NewOpc = AArch64::LDRQpost;
1455 int64_t MinOffset, MaxOffset;
1456 bool Success =
static_cast<const AArch64InstrInfo *
>(
TII)->getMemOpInfo(
1457 NewOpc, Scale, Width, MinOffset, MaxOffset);
1463 if (
MBBI->getOperand(
MBBI->getNumOperands() - 1).getImm() != 0 ||
1464 CSStackSizeInc < MinOffset * (int64_t)Scale.
getFixedValue() ||
1465 CSStackSizeInc > MaxOffset * (int64_t)Scale.
getFixedValue()) {
1471 if (NeedsWinCFI && AArch64InstrInfo::isSEHInstruction(*
MBBI))
1476 false, NeedsWinCFI, HasWinCFI, EmitCFI,
1479 return std::prev(
MBBI);
1484 auto SEH = std::next(
MBBI);
1485 if (AArch64InstrInfo::isSEHInstruction(*SEH))
1486 SEH->eraseFromParent();
1493 unsigned OpndIdx = 0;
1494 for (
unsigned OpndEnd =
MBBI->getNumOperands() - 1; OpndIdx < OpndEnd;
1496 MIB.
add(
MBBI->getOperand(OpndIdx));
1498 assert(
MBBI->getOperand(OpndIdx).getImm() == 0 &&
1499 "Unexpected immediate offset in first/last callee-save save/restore "
1501 assert(
MBBI->getOperand(OpndIdx - 1).getReg() == AArch64::SP &&
1502 "Unexpected base register in callee-save save/restore instruction!");
1503 assert(CSStackSizeInc % Scale == 0);
1504 MIB.
addImm(CSStackSizeInc / (
int)Scale);
1516 CFIInstBuilder(
MBB,
MBBI, FrameFlag)
1517 .buildDefCFAOffset(CFAOffset - CSStackSizeInc);
1522void AArch64FrameLowering::fixupCalleeSaveRestoreStackOffset(
1524 bool *HasWinCFI)
const {
1525 if (AArch64InstrInfo::isSEHInstruction(
MI))
1528 unsigned Opc =
MI.getOpcode();
1531 case AArch64::STPXi:
1532 case AArch64::STRXui:
1533 case AArch64::STPDi:
1534 case AArch64::STRDui:
1535 case AArch64::LDPXi:
1536 case AArch64::LDRXui:
1537 case AArch64::LDPDi:
1538 case AArch64::LDRDui:
1541 case AArch64::STPQi:
1542 case AArch64::STRQui:
1543 case AArch64::LDPQi:
1544 case AArch64::LDRQui:
1551 unsigned OffsetIdx =
MI.getNumExplicitOperands() - 1;
1552 assert(
MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP &&
1553 "Unexpected base register in callee-save save/restore instruction!");
1555 MachineOperand &OffsetOpnd =
MI.getOperand(OffsetIdx);
1557 assert(LocalStackSize % Scale == 0);
1558 OffsetOpnd.
setImm(OffsetOpnd.
getImm() + LocalStackSize / Scale);
1563 assert(
MBBI !=
MI.getParent()->end() &&
"Expecting a valid instruction");
1564 assert(AArch64InstrInfo::isSEHInstruction(*
MBBI) &&
1565 "Expecting a SEH instruction");
1579bool AArch64FrameLowering::isSVECalleeSave(
1581 switch (
I->getOpcode()) {
1584 case AArch64::PTRUE_C_B:
1585 case AArch64::LD1B_2Z_IMM:
1586 case AArch64::ST1B_2Z_IMM:
1587 case AArch64::STR_ZXI:
1588 case AArch64::STR_PXI:
1589 case AArch64::LDR_ZXI:
1590 case AArch64::LDR_PXI:
1591 case AArch64::PTRUE_B:
1592 case AArch64::CPY_ZPzI_B:
1593 case AArch64::CMPNE_PPzZI_B:
1596 case AArch64::SEH_SavePReg:
1597 case AArch64::SEH_SaveZReg:
1619 DL =
MBBI->getDebugLoc();
1626 EmitSignRA(MF.
front());
1628 if (
MBB.isEHFuncletEntry())
1630 if (
MBB.isReturnBlock())
1689 if (MFI.isVariableSizedObjectIndex(FI)) {
1698 bool FPAfterSVECalleeSaves =
1701 if (FPAfterSVECalleeSaves &&
1708 bool IsFixed = MFI.isFixedObjectIndex(FI);
1713 if (!IsFixed && !IsCSR) {
1714 ScalableOffset = -SVEStackSize;
1715 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1730 int64_t ObjectOffset)
const {
1734 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1735 unsigned FixedObject =
1736 getFixedObjectSize(MF, AFI, IsWin64,
false);
1744 int64_t ObjectOffset)
const {
1755 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1756 ? getFPOffset(MF, ObjectOffset).getFixed()
1757 : getStackOffset(MF, ObjectOffset).getFixed();
1762 bool ForSimm)
const {
1764 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1765 bool isFixed = MFI.isFixedObjectIndex(FI);
1772 const MachineFunction &MF, int64_t ObjectOffset,
bool isFixed,
bool isSVE,
1773 Register &FrameReg,
bool PreferFP,
bool ForSimm)
const {
1780 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1781 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1796 PreferFP &= !SVEStackSize;
1804 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1808 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1810 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1815 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1816 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1818 if (FPOffset >= 0) {
1822 }
else if (MFI.hasVarSizedObjects()) {
1826 bool CanUseBP = RegInfo->hasBasePointer(MF);
1827 if (FPOffsetFits && CanUseBP)
1834 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1841 "Funclets should only be present on Win64");
1845 if (FPOffsetFits && PreferFP)
1852 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1853 "In the presence of dynamic stack pointer realignment, "
1854 "non-argument/CSR objects cannot be accessed through the frame pointer");
1856 bool FPAfterSVECalleeSaves =
1866 if (FPAfterSVECalleeSaves) {
1876 RegInfo->hasStackRealignment(MF))) {
1877 FrameReg = RegInfo->getFrameRegister(MF);
1881 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1887 if (FPAfterSVECalleeSaves) {
1894 ScalableOffset = SVECalleeSavedStack;
1896 ScalableOffset = SVECalleeSavedStack - SVEStackSize;
1899 ScalableOffset = SVEStackSize;
1901 ScalableOffset = SVEStackSize - SVECalleeSavedStack;
1904 if (UseFP && !(isFixed || isCSR))
1905 ScalableOffset = -SVEStackSize;
1906 if (!UseFP && (isFixed || isCSR))
1907 ScalableOffset = SVEStackSize;
1911 FrameReg = RegInfo->getFrameRegister(MF);
1916 if (RegInfo->hasBasePointer(MF))
1917 FrameReg = RegInfo->getBaseRegister();
1919 assert(!MFI.hasVarSizedObjects() &&
1920 "Can't use SP when we have var sized objects.");
1921 FrameReg = AArch64::SP;
1949 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1955 bool NeedsWinCFI,
bool IsFirst,
1964 if (Reg2 == AArch64::FP)
1968 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1975 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1976 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR && !IsFirst)
1986 bool UsesWinAAPCS,
bool NeedsWinCFI,
1987 bool NeedsFrameRecord,
bool IsFirst,
1995 if (NeedsFrameRecord)
1996 return Reg2 == AArch64::LR;
2004 unsigned Reg1 = AArch64::NoRegister;
2005 unsigned Reg2 = AArch64::NoRegister;
2008 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
2009 const TargetRegisterClass *RC;
2011 RegPairInfo() =
default;
2013 bool isPaired()
const {
return Reg2 != AArch64::NoRegister; }
2015 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
2021 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
2022 if (SavedRegs.
test(PReg)) {
2023 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
2027 return AArch64::NoRegister;
2037 bool IsLocallyStreaming =
2043 return Subtarget.hasSVE2p1() ||
2044 (Subtarget.hasSME2() &&
2045 (!IsLocallyStreaming && Subtarget.
isStreaming()));
2053 bool NeedsFrameRecord) {
2071 (
Count & 1) == 0) &&
2072 "Odd number of callee-saved regs to spill!");
2074 int StackFillDir = -1;
2076 unsigned FirstReg = 0;
2084 FirstReg =
Count - 1;
2087 int ScalableByteOffset =
2093 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
2095 RPI.Reg1 = CSI[i].getReg();
2097 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
2098 RPI.Type = RegPairInfo::GPR;
2099 RPI.RC = &AArch64::GPR64RegClass;
2100 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
2101 RPI.Type = RegPairInfo::FPR64;
2102 RPI.RC = &AArch64::FPR64RegClass;
2103 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
2104 RPI.Type = RegPairInfo::FPR128;
2105 RPI.RC = &AArch64::FPR128RegClass;
2106 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
2107 RPI.Type = RegPairInfo::ZPR;
2108 RPI.RC = &AArch64::ZPRRegClass;
2109 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
2110 RPI.Type = RegPairInfo::PPR;
2111 RPI.RC = &AArch64::PPRRegClass;
2112 }
else if (RPI.Reg1 == AArch64::VG) {
2113 RPI.Type = RegPairInfo::VG;
2114 RPI.RC = &AArch64::FIXED_REGSRegClass;
2123 ByteOffset += StackFillDir * StackHazardSize;
2126 int Scale =
TRI->getSpillSize(*RPI.RC);
2129 MCRegister NextReg = CSI[i + RegInc].getReg();
2130 bool IsFirst = i == FirstReg;
2132 case RegPairInfo::GPR:
2133 if (AArch64::GPR64RegClass.
contains(NextReg) &&
2135 NeedsWinCFI, NeedsFrameRecord, IsFirst,
2139 case RegPairInfo::FPR64:
2140 if (AArch64::FPR64RegClass.
contains(NextReg) &&
2145 case RegPairInfo::FPR128:
2146 if (AArch64::FPR128RegClass.
contains(NextReg))
2149 case RegPairInfo::PPR:
2151 case RegPairInfo::ZPR:
2153 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
2156 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
2161 case RegPairInfo::VG:
2172 assert((!RPI.isPaired() ||
2173 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
2174 "Out of order callee saved regs!");
2176 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
2177 RPI.Reg1 == AArch64::LR) &&
2178 "FrameRecord must be allocated together with LR");
2181 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
2182 RPI.Reg2 == AArch64::LR) &&
2183 "FrameRecord must be allocated together with LR");
2191 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
2192 RPI.Reg1 + 1 == RPI.Reg2))) &&
2193 "Callee-save registers not saved as adjacent register pair!");
2195 RPI.FrameIdx = CSI[i].getFrameIdx();
2198 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
2202 if (RPI.isScalable() && ScalableByteOffset % Scale != 0) {
2203 ScalableByteOffset =
alignTo(ScalableByteOffset, Scale);
2206 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
2207 assert(OffsetPre % Scale == 0);
2209 if (RPI.isScalable())
2210 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
2212 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
2217 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
2218 (IsWindows && RPI.Reg2 == AArch64::LR)))
2219 ByteOffset += StackFillDir * 8;
2223 if (NeedGapToAlignStack && !NeedsWinCFI && !RPI.isScalable() &&
2224 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
2225 ByteOffset % 16 != 0) {
2226 ByteOffset += 8 * StackFillDir;
2232 NeedGapToAlignStack =
false;
2235 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
2236 assert(OffsetPost % Scale == 0);
2239 int Offset = NeedsWinCFI ? OffsetPre : OffsetPost;
2244 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
2245 (IsWindows && RPI.Reg2 == AArch64::LR)))
2247 RPI.Offset =
Offset / Scale;
2249 assert((!RPI.isPaired() ||
2250 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
2251 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
2252 "Offset out of bounds for LDP/STP immediate");
2254 auto isFrameRecord = [&] {
2256 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
2257 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
2265 return i > 0 && RPI.Reg1 == AArch64::FP &&
2266 CSI[i - 1].getReg() == AArch64::LR;
2271 if (NeedsFrameRecord && isFrameRecord())
2288 std::reverse(RegPairs.
begin(), RegPairs.
end());
2307 MRI.freezeReservedRegs();
2309 if (homogeneousPrologEpilog(MF)) {
2313 for (
auto &RPI : RegPairs) {
2318 if (!
MRI.isReserved(RPI.Reg1))
2319 MBB.addLiveIn(RPI.Reg1);
2320 if (RPI.isPaired() && !
MRI.isReserved(RPI.Reg2))
2321 MBB.addLiveIn(RPI.Reg2);
2325 bool PTrueCreated =
false;
2327 unsigned Reg1 = RPI.Reg1;
2328 unsigned Reg2 = RPI.Reg2;
2341 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2342 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2344 case RegPairInfo::GPR:
2345 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2347 case RegPairInfo::FPR64:
2348 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2350 case RegPairInfo::FPR128:
2351 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2353 case RegPairInfo::ZPR:
2354 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2356 case RegPairInfo::PPR:
2358 Size == 16 ? AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO : AArch64::STR_PXI;
2360 case RegPairInfo::VG:
2361 StrOpc = AArch64::STRXui;
2365 unsigned X0Scratch = AArch64::NoRegister;
2367 if (X0Scratch != AArch64::NoRegister)
2373 if (Reg1 == AArch64::VG) {
2375 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2376 assert(Reg1 != AArch64::NoRegister);
2386 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2387 AArch64::X0, LiveIn.PhysReg);
2395 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2409 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2410 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
2413 assert((!NeedsWinCFI || !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2414 "Windows unwdinding requires a consecutive (FP,LR) pair");
2418 unsigned FrameIdxReg1 = RPI.FrameIdx;
2419 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2420 if (NeedsWinCFI && RPI.isPaired()) {
2425 if (RPI.isPaired() && RPI.isScalable()) {
2431 "Expects SVE2.1 or SME2 target and a predicate register");
2432#ifdef EXPENSIVE_CHECKS
2433 auto IsPPR = [](
const RegPairInfo &c) {
2434 return c.Reg1 == RegPairInfo::PPR;
2436 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2437 auto IsZPR = [](
const RegPairInfo &c) {
2438 return c.Type == RegPairInfo::ZPR;
2440 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2441 assert(!(PPRBegin < ZPRBegin) &&
2442 "Expected callee save predicate to be handled first");
2444 if (!PTrueCreated) {
2445 PTrueCreated =
true;
2450 if (!
MRI.isReserved(Reg1))
2451 MBB.addLiveIn(Reg1);
2452 if (!
MRI.isReserved(Reg2))
2453 MBB.addLiveIn(Reg2);
2454 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2470 if (!
MRI.isReserved(Reg1))
2471 MBB.addLiveIn(Reg1);
2472 if (RPI.isPaired()) {
2473 if (!
MRI.isReserved(Reg2))
2474 MBB.addLiveIn(Reg2);
2493 if (RPI.Type == RegPairInfo::ZPR || RPI.Type == RegPairInfo::PPR) {
2512 DL =
MBBI->getDebugLoc();
2515 if (homogeneousPrologEpilog(MF, &
MBB)) {
2518 for (
auto &RPI : RegPairs) {
2526 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2528 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2529 std::reverse(PPRBegin, PPREnd);
2530 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2532 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2533 std::reverse(ZPRBegin, ZPREnd);
2535 bool PTrueCreated =
false;
2536 for (
const RegPairInfo &RPI : RegPairs) {
2537 unsigned Reg1 = RPI.Reg1;
2538 unsigned Reg2 = RPI.Reg2;
2549 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2550 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2552 case RegPairInfo::GPR:
2553 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2555 case RegPairInfo::FPR64:
2556 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2558 case RegPairInfo::FPR128:
2559 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2561 case RegPairInfo::ZPR:
2562 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2564 case RegPairInfo::PPR:
2565 LdrOpc =
Size == 16 ? AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO
2568 case RegPairInfo::VG:
2573 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2574 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
2580 unsigned FrameIdxReg1 = RPI.FrameIdx;
2581 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2582 if (NeedsWinCFI && RPI.isPaired()) {
2588 if (RPI.isPaired() && RPI.isScalable()) {
2593 "Expects SVE2.1 or SME2 target and a predicate register");
2594#ifdef EXPENSIVE_CHECKS
2595 assert(!(PPRBegin < ZPRBegin) &&
2596 "Expected callee save predicate to be handled first");
2598 if (!PTrueCreated) {
2599 PTrueCreated =
true;
2604 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
2621 if (RPI.isPaired()) {
2648 return std::optional<int>(PSV->getFrameIndex());
2659 return std::nullopt;
2665 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2666 return std::nullopt;
2674void AArch64FrameLowering::determineStackHazardSlot(
2677 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2678 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2692 return AArch64::FPR64RegClass.contains(Reg) ||
2693 AArch64::FPR128RegClass.contains(Reg) ||
2694 AArch64::ZPRRegClass.contains(Reg) ||
2695 AArch64::PPRRegClass.contains(Reg);
2697 bool HasFPRStackObjects =
false;
2700 for (
auto &
MBB : MF) {
2701 for (
auto &
MI :
MBB) {
2703 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
2706 FrameObjects[*FI] |= 2;
2708 FrameObjects[*FI] |= 1;
2712 HasFPRStackObjects =
2713 any_of(FrameObjects, [](
unsigned B) {
return (
B & 3) == 2; });
2716 if (HasFPRCSRs || HasFPRStackObjects) {
2719 << StackHazardSize <<
"\n");
2737 unsigned UnspilledCSGPR = AArch64::NoRegister;
2738 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
2743 unsigned BasePointerReg = RegInfo->hasBasePointer(MF)
2744 ? RegInfo->getBaseRegister()
2747 unsigned ExtraCSSpill = 0;
2748 bool HasUnpairedGPR64 =
false;
2749 bool HasPairZReg =
false;
2750 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2751 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2754 for (
unsigned i = 0; CSRegs[i]; ++i) {
2755 const unsigned Reg = CSRegs[i];
2758 if (Reg == BasePointerReg)
2763 if (UserReservedRegs[Reg]) {
2764 SavedRegs.
reset(Reg);
2768 bool RegUsed = SavedRegs.
test(Reg);
2769 unsigned PairedReg = AArch64::NoRegister;
2770 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2771 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2772 AArch64::FPR128RegClass.
contains(Reg)) {
2775 if (HasUnpairedGPR64)
2776 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2778 PairedReg = CSRegs[i ^ 1];
2785 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2786 PairedReg = AArch64::NoRegister;
2787 HasUnpairedGPR64 =
true;
2789 assert(PairedReg == AArch64::NoRegister ||
2790 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
2791 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
2792 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
2795 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2796 UnspilledCSGPR = Reg;
2797 UnspilledCSGPRPaired = PairedReg;
2805 if (RegInfo->getSpillSize(AArch64::PPRRegClass) == 16 &&
2806 AArch64::PPR_p8to15RegClass.contains(Reg)) {
2807 SavedRegs.
set(AArch64::P4);
2813 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
2814 !SavedRegs.
test(PairedReg)) {
2815 SavedRegs.
set(PairedReg);
2816 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2817 !ReservedRegs[PairedReg])
2818 ExtraCSSpill = PairedReg;
2821 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2822 SavedRegs.
test(CSRegs[i ^ 1]));
2830 if (PnReg != AArch64::NoRegister)
2836 SavedRegs.
set(AArch64::P8);
2841 "Predicate cannot be a reserved register");
2851 SavedRegs.
set(AArch64::X18);
2855 unsigned CSStackSize = 0;
2856 unsigned SVECSStackSize = 0;
2858 for (
unsigned Reg : SavedRegs.
set_bits()) {
2859 auto *RC =
TRI->getMinimalPhysRegClass(Reg);
2860 assert(RC &&
"expected register class!");
2861 auto SpillSize =
TRI->getSpillSize(*RC);
2862 if (AArch64::PPRRegClass.
contains(Reg) ||
2863 AArch64::ZPRRegClass.
contains(Reg))
2864 SVECSStackSize += SpillSize;
2866 CSStackSize += SpillSize;
2872 unsigned NumSavedRegs = SavedRegs.
count();
2881 determineStackHazardSlot(MF, SavedRegs);
2882 if (AFI->hasStackHazardSlotIndex())
2887 SavedRegs.
set(AArch64::LR);
2892 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2893 SavedRegs.
set(AArch64::FP);
2894 SavedRegs.
set(AArch64::LR);
2898 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2899 for (
unsigned Reg : SavedRegs.
set_bits())
2905 int64_t SVEStackSize =
2906 alignTo(SVECSStackSize + estimateSVEStackObjectOffsets(MFI), 16);
2907 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2916 int64_t CalleeStackUsed = 0;
2919 if (FixedOff > CalleeStackUsed)
2920 CalleeStackUsed = FixedOff;
2924 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2925 CalleeStackUsed) > EstimatedStackSizeLimit;
2926 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2927 AFI->setHasStackFrame(
true);
2936 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
2938 <<
" to get a scratch register.\n");
2939 SavedRegs.
set(UnspilledCSGPR);
2940 ExtraCSSpill = UnspilledCSGPR;
2945 if (producePairRegisters(MF)) {
2946 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
2949 SavedRegs.
reset(UnspilledCSGPR);
2950 ExtraCSSpill = AArch64::NoRegister;
2953 SavedRegs.
set(UnspilledCSGPRPaired);
2962 unsigned Size =
TRI->getSpillSize(RC);
2963 Align Alignment =
TRI->getSpillAlign(RC);
2966 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2967 <<
" as the emergency spill slot.\n");
2972 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2976 if (
hasFP(MF) && AFI->hasSwiftAsyncContext())
2981 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2984 AFI->getCalleeSavedStackSize() == AlignedCSStackSize) &&
2985 "Should not invalidate callee saved info");
2989 AFI->setCalleeSavedStackSize(AlignedCSStackSize);
2990 AFI->setCalleeSaveStackHasFreeSpace(AlignedCSStackSize != CSStackSize);
2991 AFI->setSVECalleeSavedStackSize(
alignTo(SVECSStackSize, 16));
2996 std::vector<CalleeSavedInfo> &CSI,
unsigned &MinCSFrameIndex,
2997 unsigned &MaxCSFrameIndex)
const {
3006 std::reverse(CSI.begin(), CSI.end());
3020 if ((
unsigned)FrameIdx < MinCSFrameIndex)
3021 MinCSFrameIndex = FrameIdx;
3022 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
3023 MaxCSFrameIndex = FrameIdx;
3030 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
3031 if (It != CSI.end())
3032 CSI.insert(It, VGInfo);
3034 CSI.push_back(VGInfo);
3038 int HazardSlotIndex = std::numeric_limits<int>::max();
3039 for (
auto &CS : CSI) {
3047 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
3048 "Unexpected register order for hazard slot");
3050 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3053 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
3054 MinCSFrameIndex = HazardSlotIndex;
3055 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
3056 MaxCSFrameIndex = HazardSlotIndex;
3059 unsigned Size = RegInfo->getSpillSize(*RC);
3060 Align Alignment(RegInfo->getSpillAlign(*RC));
3062 CS.setFrameIdx(FrameIdx);
3064 if ((
unsigned)FrameIdx < MinCSFrameIndex)
3065 MinCSFrameIndex = FrameIdx;
3066 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
3067 MaxCSFrameIndex = FrameIdx;
3071 Reg == AArch64::FP) {
3074 if ((
unsigned)FrameIdx < MinCSFrameIndex)
3075 MinCSFrameIndex = FrameIdx;
3076 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
3077 MaxCSFrameIndex = FrameIdx;
3084 HazardSlotIndex == std::numeric_limits<int>::max()) {
3086 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3089 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
3090 MinCSFrameIndex = HazardSlotIndex;
3091 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
3092 MaxCSFrameIndex = HazardSlotIndex;
3116 int &Min,
int &Max) {
3117 Min = std::numeric_limits<int>::max();
3118 Max = std::numeric_limits<int>::min();
3124 for (
auto &CS : CSI) {
3125 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
3126 AArch64::PPRRegClass.contains(CS.getReg())) {
3127 assert((Max == std::numeric_limits<int>::min() ||
3128 Max + 1 == CS.getFrameIdx()) &&
3129 "SVE CalleeSaves are not consecutive");
3131 Min = std::min(Min, CS.getFrameIdx());
3132 Max = std::max(Max, CS.getFrameIdx());
3135 return Min != std::numeric_limits<int>::max();
3144 int &MinCSFrameIndex,
3145 int &MaxCSFrameIndex,
3146 bool AssignOffsets) {
3151 "SVE vectors should never be passed on the stack by value, only by "
3155 auto Assign = [&MFI](
int FI, int64_t
Offset) {
3165 for (
int I = MinCSFrameIndex;
I <= MaxCSFrameIndex; ++
I) {
3181 int StackProtectorFI = -1;
3185 ObjectsToAllocate.
push_back(StackProtectorFI);
3191 if (
I == StackProtectorFI)
3193 if (MaxCSFrameIndex >=
I &&
I >= MinCSFrameIndex)
3202 for (
unsigned FI : ObjectsToAllocate) {
3207 if (Alignment >
Align(16))
3209 "Alignment of scalable vectors > 16 bytes is not yet supported");
3219int64_t AArch64FrameLowering::estimateSVEStackObjectOffsets(
3221 int MinCSFrameIndex, MaxCSFrameIndex;
3225int64_t AArch64FrameLowering::assignSVEStackObjectOffsets(
3236 if (PreferredReg != AArch64::NoRegister && UsedRegs.
available(PreferredReg))
3237 return PreferredReg;
3242 return AArch64::NoRegister;
3274 std::optional<int> *MaybeSpillFI,
3275 Register PreferredReg = AArch64::NoRegister)
3277 *MF.getSubtarget().getInstrInfo())),
3278 TRI(*MF.getSubtarget().getRegisterInfo()) {
3280 if (FreeReg != AArch64::NoRegister)
3282 assert(MaybeSpillFI &&
"Expected emergency spill slot FI information "
3283 "(attempted to spill in prologue/epilogue?)");
3284 if (!MaybeSpillFI->has_value()) {
3287 TRI.getSpillAlign(RC));
3289 FreeReg = SpillCandidate;
3290 SpillFI = MaybeSpillFI->value();
3291 TII.storeRegToStackSlot(MBB, MBBI, FreeReg,
false, *SpillFI, &RC, &TRI,
3304 TII.loadRegFromStackSlot(MBB, MBBI, FreeReg, *SpillFI, &RC, &TRI,
3314 Register FreeReg = AArch64::NoRegister;
3315 std::optional<int> SpillFI;
3360 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
3367 .
add(
MI.getOperand(0))
3373 .
add(
MI.getOperand(1))
3403 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
3407 MF,
MBB,
MI, AArch64::P0, AArch64::PPR_3bRegClass, UsedRegs, SR.
PPR3bRegs,
3413 bool IsNZCVUsed = !UsedRegs.
available(AArch64::NZCV);
3414 std::optional<ScopedScavengeOrSpill> NZCVSaveReg;
3416 NZCVSaveReg.emplace(
3417 MF,
MBB,
MI, AArch64::X0, AArch64::GPR64RegClass, UsedRegs, SR.
GPRRegs,
3423 .
add(
MI.getOperand(1))
3431 .
addImm(AArch64SysReg::NZCV)
3455 .
addImm(AArch64SysReg::NZCV)
3456 .
addReg(NZCVSaveReg->freeRegister())
3472 bool HasPPRSpills =
false;
3476 switch (
MI.getOpcode()) {
3477 case AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO:
3480 LastPTrue =
nullptr;
3482 LastPTrue, SpillSlots);
3483 MI.eraseFromParent();
3485 case AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO:
3487 MI.eraseFromParent();
3490 LastPTrue =
nullptr;
3495 return HasPPRSpills;
3507 if (AFI->
hasStackFrame() &&
TRI.getSpillSize(AArch64::PPRRegClass) == 16) {
3508 auto ComputeScavengeableRegisters = [&](
unsigned RegClassID) {
3509 BitVector Regs =
TRI.getAllocatableSet(MF,
TRI.getRegClass(RegClassID));
3510 assert(Regs.
count() > 0 &&
"Expected scavengeable registers");
3515 SR.
ZPRRegs = ComputeScavengeableRegisters(AArch64::ZPRRegClassID);
3517 SR.
PPR3bRegs = ComputeScavengeableRegisters(AArch64::PPR_3bRegClassID);
3518 SR.
GPRRegs = ComputeScavengeableRegisters(AArch64::GPR64RegClassID);
3530 assert((
Pass == 0 || !HasPPRSpills) &&
"Did not expect PPR spills");
3540 "Upwards growing stack unsupported");
3542 int MinCSFrameIndex, MaxCSFrameIndex;
3543 int64_t SVEStackSize =
3544 assignSVEStackObjectOffsets(MFI, MinCSFrameIndex, MaxCSFrameIndex);
3557 int64_t CurrentOffset =
3561 int FrameIndex =
H.CatchObj.FrameIndex;
3562 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3573 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3574 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3576 "UnwindHelpOffset must be at the start of the fixed object area");
3592 assert(DstReg &&
"There must be a free register after frame setup");
3602struct TagStoreInstr {
3610 MachineFunction *MF;
3611 MachineBasicBlock *
MBB;
3612 MachineRegisterInfo *
MRI;
3621 StackOffset FrameRegOffset;
3625 std::optional<int64_t> FrameRegUpdate;
3627 unsigned FrameRegUpdateFlags;
3637 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3638 :
MBB(
MBB), ZeroData(ZeroData) {
3644 void addInstruction(TagStoreInstr
I) {
3646 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3647 "Non-adjacent tag store instructions.");
3650 void clear() { TagStores.
clear(); }
3655 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3662 const int64_t kMinOffset = -256 * 16;
3663 const int64_t kMaxOffset = 255 * 16;
3666 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3667 if (BaseRegOffsetBytes < kMinOffset ||
3668 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3672 BaseRegOffsetBytes % 16 != 0) {
3673 Register ScratchReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3677 BaseRegOffsetBytes = 0;
3682 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3685 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3687 assert(BaseRegOffsetBytes % 16 == 0);
3691 .
addImm(BaseRegOffsetBytes / 16)
3695 if (BaseRegOffsetBytes == 0)
3697 BaseRegOffsetBytes += InstrSize;
3711 :
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3712 Register SizeReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3716 int64_t LoopSize =
Size;
3719 if (FrameRegUpdate && *FrameRegUpdate)
3720 LoopSize -= LoopSize % 32;
3722 TII->get(ZeroData ? AArch64::STZGloop_wback
3723 : AArch64::STGloop_wback))
3730 LoopI->
setFlags(FrameRegUpdateFlags);
3732 int64_t ExtraBaseRegUpdate =
3733 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3734 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3735 <<
", Size=" <<
Size
3736 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3737 <<
", FrameRegUpdate=" << FrameRegUpdate
3738 <<
", FrameRegOffset.getFixed()="
3739 << FrameRegOffset.
getFixed() <<
"\n");
3740 if (LoopSize <
Size) {
3744 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3745 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3746 "STG immediate out of range");
3748 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3755 }
else if (ExtraBaseRegUpdate) {
3757 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3758 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3761 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3774 int64_t
Size, int64_t *TotalOffset) {
3776 if ((
MI.getOpcode() == AArch64::ADDXri ||
3777 MI.getOpcode() == AArch64::SUBXri) &&
3778 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3780 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3781 if (
MI.getOpcode() == AArch64::SUBXri)
3792 const int64_t kMaxOffset = 4080 - 16;
3794 const int64_t kMinOffset = -4095;
3795 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3796 PostOffset % 16 == 0) {
3807 for (
auto &TS : TSE) {
3811 if (
MI->memoperands_empty()) {
3815 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3821 bool TryMergeSPUpdate) {
3822 if (TagStores.
empty())
3824 TagStoreInstr &FirstTagStore = TagStores[0];
3825 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3826 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3827 DL = TagStores[0].MI->getDebugLoc();
3831 *MF, FirstTagStore.Offset,
false ,
false ,
Reg,
3834 FrameRegUpdate = std::nullopt;
3836 mergeMemRefs(TagStores, CombinedMemRefs);
3839 dbgs() <<
"Replacing adjacent STG instructions:\n";
3840 for (
const auto &Instr : TagStores) {
3849 if (TagStores.
size() < 2)
3851 emitUnrolled(InsertI);
3854 int64_t TotalOffset = 0;
3855 if (TryMergeSPUpdate) {
3861 if (InsertI !=
MBB->
end() &&
3862 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3864 UpdateInstr = &*InsertI++;
3870 if (!UpdateInstr && TagStores.
size() < 2)
3874 FrameRegUpdate = TotalOffset;
3875 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3882 for (
auto &TS : TagStores)
3883 TS.MI->eraseFromParent();
3887 int64_t &
Size,
bool &ZeroData) {
3891 unsigned Opcode =
MI.getOpcode();
3892 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3893 Opcode == AArch64::STZ2Gi);
3895 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3896 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3898 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3901 Size =
MI.getOperand(2).getImm();
3905 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3907 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3912 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3916 16 *
MI.getOperand(2).getImm();
3936 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3942 constexpr int kScanLimit = 10;
3945 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3954 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3955 if (ZeroData != FirstZeroData)
3963 if (!
MI.isTransient())
3972 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3988 LiveRegs.addLiveOuts(*
MBB);
3993 LiveRegs.stepBackward(*
I);
3996 if (LiveRegs.contains(AArch64::NZCV))
4000 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
4005 int64_t CurOffset = Instrs[0].Offset;
4006 for (
auto &Instr : Instrs) {
4007 if (CurOffset >
Instr.Offset)
4014 TagStoreEdit TSE(
MBB, FirstZeroData);
4015 std::optional<int64_t> EndOffset;
4016 for (
auto &Instr : Instrs) {
4017 if (EndOffset && *EndOffset !=
Instr.Offset) {
4019 TSE.emitCode(InsertI, TFI,
false);
4023 TSE.addInstruction(Instr);
4042 II = tryMergeAdjacentSTG(
II,
this, RS);
4049 shouldSignReturnAddressEverywhere(MF))
4058 bool IgnoreSPUpdates)
const {
4060 if (IgnoreSPUpdates) {
4063 FrameReg = AArch64::SP;
4073 FrameReg = AArch64::SP;
4098 bool IsValid =
false;
4100 int ObjectIndex = 0;
4102 int GroupIndex = -1;
4104 bool ObjectFirst =
false;
4107 bool GroupFirst =
false;
4112 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
4116 SmallVector<int, 8> CurrentMembers;
4117 int NextGroupIndex = 0;
4118 std::vector<FrameObject> &Objects;
4121 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
4122 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
4123 void EndCurrentGroup() {
4124 if (CurrentMembers.
size() > 1) {
4129 for (
int Index : CurrentMembers) {
4130 Objects[
Index].GroupIndex = NextGroupIndex;
4136 CurrentMembers.clear();
4140bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
4162 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
4163 A.GroupIndex,
A.ObjectIndex) <
4164 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
4165 B.GroupIndex,
B.ObjectIndex);
4176 std::vector<FrameObject> FrameObjects(MFI.getObjectIndexEnd());
4177 for (
auto &Obj : ObjectsToAllocate) {
4178 FrameObjects[Obj].IsValid =
true;
4179 FrameObjects[Obj].ObjectIndex = Obj;
4184 GroupBuilder GB(FrameObjects);
4185 for (
auto &
MBB : MF) {
4186 for (
auto &
MI :
MBB) {
4187 if (
MI.isDebugInstr())
4192 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
4195 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
4197 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
4202 switch (
MI.getOpcode()) {
4203 case AArch64::STGloop:
4204 case AArch64::STZGloop:
4208 case AArch64::STZGi:
4209 case AArch64::ST2Gi:
4210 case AArch64::STZ2Gi:
4222 if (FI >= 0 && FI < MFI.getObjectIndexEnd() &&
4223 FrameObjects[FI].IsValid)
4231 GB.AddMember(TaggedFI);
4233 GB.EndCurrentGroup();
4236 GB.EndCurrentGroup();
4241 FrameObject::AccessHazard;
4243 for (
auto &Obj : FrameObjects)
4244 if (!Obj.Accesses ||
4245 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
4246 Obj.Accesses = FrameObject::AccessGPR;
4255 FrameObjects[*TBPI].ObjectFirst =
true;
4256 FrameObjects[*TBPI].GroupFirst =
true;
4257 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
4258 if (FirstGroupIndex >= 0)
4259 for (FrameObject &Object : FrameObjects)
4260 if (Object.GroupIndex == FirstGroupIndex)
4261 Object.GroupFirst =
true;
4267 for (
auto &Obj : FrameObjects) {
4271 ObjectsToAllocate[i++] = Obj.ObjectIndex;
4275 dbgs() <<
"Final frame order:\n";
4276 for (
auto &Obj : FrameObjects) {
4279 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
4280 if (Obj.ObjectFirst)
4281 dbgs() <<
", first";
4283 dbgs() <<
", group-first";
4294AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
4305 MF.
insert(MBBInsertPoint, LoopMBB);
4307 MF.
insert(MBBInsertPoint, ExitMBB);
4338 MBB.addSuccessor(LoopMBB);
4342 return ExitMBB->
begin();
4345void AArch64FrameLowering::inlineStackProbeFixed(
4350 const AArch64InstrInfo *
TII =
4352 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
4357 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
4358 int64_t NumBlocks = FrameSize / ProbeSize;
4359 int64_t ResidualSize = FrameSize % ProbeSize;
4361 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
4362 << NumBlocks <<
" blocks of " << ProbeSize
4363 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
4368 for (
int i = 0; i < NumBlocks; ++i) {
4374 EmitAsyncCFI && !HasFP, CFAOffset);
4383 }
else if (NumBlocks != 0) {
4389 EmitAsyncCFI && !HasFP, CFAOffset);
4391 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
4393 if (EmitAsyncCFI && !HasFP) {
4396 .buildDefCFARegister(AArch64::SP);
4400 if (ResidualSize != 0) {
4406 EmitAsyncCFI && !HasFP, CFAOffset);
4423 SmallVector<MachineInstr *, 4> ToReplace;
4424 for (MachineInstr &
MI :
MBB)
4425 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
4426 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
4429 for (MachineInstr *
MI : ToReplace) {
4430 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
4431 Register ScratchReg =
MI->getOperand(0).getReg();
4432 int64_t FrameSize =
MI->getOperand(1).getImm();
4434 MI->getOperand(3).getImm());
4435 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
4438 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
4439 "Stack probe pseudo-instruction expected");
4440 const AArch64InstrInfo *
TII =
4441 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
4442 Register TargetReg =
MI->getOperand(0).getReg();
4443 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
4445 MI->eraseFromParent();
4465 return std::make_tuple(
start(),
Idx) <
4466 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4496 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4497 if (
Offset.getScalable())
4498 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4509void AArch64FrameLowering::emitRemarks(
4512 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4517 const uint64_t HazardSize =
4520 if (HazardSize == 0)
4528 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4530 size_t NumFPLdSt = 0;
4531 size_t NumNonFPLdSt = 0;
4534 for (
const MachineBasicBlock &
MBB : MF) {
4535 for (
const MachineInstr &
MI :
MBB) {
4536 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4538 for (MachineMemOperand *MMO :
MI.memoperands()) {
4545 StackAccesses[ArrIdx].Idx = FrameIdx;
4546 StackAccesses[ArrIdx].Offset =
4555 if (
MI.getOpcode() != AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO &&
4556 MI.getOpcode() != AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO &&
4557 AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg())) {
4565 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4576 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4587 if (StackAccesses.front().isMixed())
4588 MixedObjects.push_back(&StackAccesses.front());
4590 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4592 const auto &
First = *It;
4593 const auto &Second = *(It + 1);
4595 if (Second.isMixed())
4596 MixedObjects.push_back(&Second);
4598 if ((
First.isSME() && Second.isCPU()) ||
4599 (
First.isCPU() && Second.isSME())) {
4600 uint64_t Distance =
static_cast<uint64_t
>(Second.start() -
First.end());
4601 if (Distance < HazardSize)
4606 auto EmitRemark = [&](llvm::StringRef Str) {
4608 auto R = MachineOptimizationRemarkAnalysis(
4609 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4610 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4614 for (
const auto &
P : HazardPairs)
4615 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4617 for (
const auto *Obj : MixedObjects)
4619 formatv(
"{0} accessed by both GP and FP instructions", *Obj).str());
unsigned const MachineRegisterInfo * MRI
static void getLiveRegsForEntryMBB(LivePhysRegs &LiveRegs, const MachineBasicBlock &MBB)
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 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 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 and AArch64EpilogueEmitter classes,...
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")
DXIL Forward Handle Accesses
const HexagonInstrInfo * TII
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 emitEpilogue()
Emit the epilogue.
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.
friend class AArch64EpilogueEmitter
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...
void setSwiftAsyncContextFrameIdx(int FI)
unsigned getTailCallReservedStack() const
unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const
void setCalleeSaveBaseToFrameRecordOffset(int Offset)
bool hasStackProbing() const
unsigned getArgumentStackToRestore() const
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 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.
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 ...
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.
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 & 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.
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)
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