266#define DEBUG_TYPE "frame-info"
273 bool IsTailCallReturn = (
MBB.end() !=
MBBI)
277 int64_t ArgumentPopSize = 0;
278 if (IsTailCallReturn) {
284 ArgumentPopSize = StackAdjust.
getImm();
293 return ArgumentPopSize;
336 if (AFI->hasCalculatedStackSizeSVE())
365bool AArch64FrameLowering::homogeneousPrologEpilog(
369 const AArch64Options &CLOpts =
371 if (!CLOpts.homogeneous_prolog_epilog)
393 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
400 unsigned NumGPRs = 0;
401 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
403 if (Reg == AArch64::LR) {
404 assert(CSRegs[
I + 1] == AArch64::FP);
405 if (NumGPRs % 2 != 0)
417bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
436 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
437 MI.getOpcode() == AArch64::ADDXri ||
438 MI.getOpcode() == AArch64::ADDSXri)
463 bool IsWin64,
bool IsFunclet)
const {
465 "Tail call reserved stack must be aligned to 16 bytes");
466 if (!IsWin64 || IsFunclet) {
471 Attribute::SwiftAsync))
485 int FrameIndex =
H.CatchObj.FrameIndex;
486 if ((FrameIndex != INT_MAX) &&
487 CatchObjFrameIndices.
insert(FrameIndex)) {
488 FixedObjectSize =
alignTo(FixedObjectSize,
495 FixedObjectSize += 8;
497 return alignTo(FixedObjectSize, 16);
508 const unsigned RedZoneSize =
521 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
525 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
547 if (Subtarget.getTargetLowering()->useStackGuardMixFP())
556 RegInfo->hasStackRealignment(MF))
602 if (TT.isOSDarwin() || TT.isOSWindowsOrUEFI())
640 unsigned Opc =
I->getOpcode();
641 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
642 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
645 int64_t Amount =
I->getOperand(0).getImm();
653 if (CalleePopAmount == 0) {
664 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
675 "non-reserved call frame without var sized objects?");
684 }
else if (CalleePopAmount != 0) {
687 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
699 const auto &
TRI = *Subtarget.getRegisterInfo();
705 CFIBuilder.buildDefCFA(AArch64::SP, 0);
708 if (MFI.shouldSignReturnAddress(MF)) {
709 if (MFI.branchProtectionPAuthLR()) {
710 CFIBuilder.buildNegateRAStateWithPC();
712 CFIBuilder.buildNegateRAState();
717 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
718 CFIBuilder.buildSameValue(AArch64::X18);
721 const std::vector<CalleeSavedInfo> &CSI =
723 for (
const auto &Info : CSI) {
725 if (!
TRI.regNeedsCFI(Reg, Reg))
727 CFIBuilder.buildSameValue(Reg);
740 case AArch64::W##n: \
741 case AArch64::X##n: \
766 case AArch64::B##n: \
767 case AArch64::H##n: \
768 case AArch64::S##n: \
769 case AArch64::D##n: \
770 case AArch64::Q##n: \
771 return HasSVE ? AArch64::Z##n : AArch64::Q##n
808void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
820 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
823 BitVector GPRsToZero(
TRI.getNumRegs());
824 BitVector FPRsToZero(
TRI.getNumRegs());
828 bool HasFPR = STI.hasFPARMv8();
830 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
833 GPRsToZero.set(XReg);
837 FPRsToZero.set(XReg);
844 for (MCRegister
Reg : GPRsToZero.set_bits())
848 for (MCRegister
Reg : FPRsToZero.set_bits())
852 for (MCRegister PReg :
853 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
854 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
855 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
857 if (RegsToZero[PReg])
863bool AArch64FrameLowering::windowsRequiresStackProbe(
865 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
866 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
870 StackSizeInBytes >=
uint64_t(MFI.getStackProbeSize());
879 for (
unsigned i = 0; CSRegs[i]; ++i)
885 bool HasCall)
const {
895 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
897 LivePhysRegs LiveRegs(
TRI);
900 LiveRegs.addReg(AArch64::X16);
901 LiveRegs.addReg(AArch64::X17);
902 LiveRegs.addReg(AArch64::X18);
906 const MachineRegisterInfo &MRI = MF->
getRegInfo();
907 if (LiveRegs.available(MRI, AArch64::X9))
910 for (
unsigned Reg : AArch64::GPR64RegClass) {
911 if (LiveRegs.available(MRI,
Reg))
933 if (!
LiveRegs.available(MRI, AArch64::X16) ||
934 !
LiveRegs.available(MRI, AArch64::X17))
941 MBB.isLiveIn(AArch64::NZCV))
945 if (!findScratchNonCalleeSaveRegister(TmpMBB).
isValid())
951 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
952 if (!findScratchNonCalleeSaveRegister(TmpMBB,
true).
isValid())
958bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
974 unsigned Opc =
MBBI->getOpcode();
978 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
979 int Imm =
MBBI->getOperand(ImmIdx).getImm();
987 case AArch64::STR_ZXI:
988 case AArch64::LDR_ZXI: {
989 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
996 case AArch64::STR_PXI:
997 case AArch64::LDR_PXI: {
998 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1005 case AArch64::LDPDpost:
1008 case AArch64::STPDpre: {
1009 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1010 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1011 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1018 case AArch64::LDPXpost:
1021 case AArch64::STPXpre: {
1024 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1025 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1029 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1030 .
addImm(RegInfo->getSEHRegNum(Reg0))
1031 .
addImm(RegInfo->getSEHRegNum(Reg1))
1036 case AArch64::LDRDpost:
1039 case AArch64::STRDpre: {
1040 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1041 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1047 case AArch64::LDRXpost:
1050 case AArch64::STRXpre: {
1051 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1058 case AArch64::STPDi:
1059 case AArch64::LDPDi: {
1060 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1061 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1069 case AArch64::STPXi:
1070 case AArch64::LDPXi: {
1074 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1075 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1077 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1081 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1088 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1095 case AArch64::STRXui:
1096 case AArch64::LDRXui: {
1097 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1104 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1110 case AArch64::STRDui:
1111 case AArch64::LDRDui: {
1112 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1119 case AArch64::STPQi:
1120 case AArch64::LDPQi: {
1121 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1122 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1123 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1130 case AArch64::LDPQpost:
1133 case AArch64::STPQpre: {
1134 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1135 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1136 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1155 if (ST.isTargetDarwin())
1177 DL =
MBBI->getDebugLoc();
1179 TII->createPauthEpilogueInstr(
MBB,
DL);
1183 EmitSignRA(MF.
front());
1185 if (
MBB.isEHFuncletEntry())
1187 if (
MBB.isReturnBlock())
1243 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1248 if (MFI.isVariableSizedObjectIndex(FI)) {
1258 if (MFI.hasScalableStackID(FI)) {
1259 if (FPAfterSVECalleeSaves &&
1262 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1270 AccessOffset = -PPRStackSize;
1271 return AccessOffset +
1276 bool IsFixed = MFI.isFixedObjectIndex(FI);
1281 if (!IsFixed && !IsCSR) {
1282 ScalableOffset = -SVEStackSize;
1283 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1298 int64_t ObjectOffset)
const {
1302 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1303 unsigned FixedObject =
1304 getFixedObjectSize(MF, AFI, IsWin64,
false);
1312 int64_t ObjectOffset)
const {
1323 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1324 ? getFPOffset(MF, ObjectOffset).getFixed()
1325 : getStackOffset(MF, ObjectOffset).getFixed();
1330 bool ForSimm)
const {
1332 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1333 bool isFixed = MFI.isFixedObjectIndex(FI);
1336 FrameReg, PreferFP, ForSimm);
1342 bool ForSimm)
const {
1348 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1349 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1357 const int64_t FixedObjectSize =
1358 getFixedObjectSize(MF, AFI, IsWin64,
false);
1362 bool isSVE = MFI.isScalableStackID(StackID);
1366 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1377 PreferFP &= !SVEStackSize;
1385 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1389 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1391 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1396 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1397 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1399 if (FPOffset >= 0) {
1403 }
else if (MFI.hasVarSizedObjects()) {
1407 bool CanUseBP = RegInfo->hasBasePointer(MF);
1408 if (FPOffsetFits && CanUseBP)
1415 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1422 "Funclets should only be present on Win64");
1426 if (FPOffsetFits && PreferFP)
1433 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1434 "In the presence of dynamic stack pointer realignment, "
1435 "non-argument/CSR objects cannot be accessed through the frame pointer");
1452 FPOffset -= PPRStackSize;
1454 SPOffset -= PPRStackSize;
1459 if (FPAfterSVECalleeSaves) {
1470 RegInfo->hasStackRealignment(MF))) {
1471 FrameReg = RegInfo->getFrameRegister(MF);
1474 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1481 if (FPAfterSVECalleeSaves) {
1488 SVEAreaOffset = SVECalleeSavedStack;
1490 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1493 SVEAreaOffset = SVEStackSize;
1495 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1498 if (UseFP && !(isFixed || isCSR))
1499 SVEAreaOffset = -SVEStackSize;
1500 if (!UseFP && (isFixed || isCSR))
1501 SVEAreaOffset = SVEStackSize;
1505 FrameReg = RegInfo->getFrameRegister(MF);
1510 if (RegInfo->hasBasePointer(MF))
1511 FrameReg = RegInfo->getBaseRegister();
1513 assert(!MFI.hasVarSizedObjects() &&
1514 "Can't use SP when we have var sized objects.");
1515 FrameReg = AArch64::SP;
1543 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1549 unsigned SpillCount,
unsigned Reg1,
1550 unsigned Reg2,
bool NeedsWinCFI,
1559 if (Reg2 == AArch64::FP)
1569 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1570 return SpillExtendedVolatile
1571 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1572 (SpillCount % 2) == 0)
1577 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1578 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1588 unsigned SpillCount,
unsigned Reg1,
1589 unsigned Reg2,
bool UsesWinAAPCS,
1590 bool NeedsWinCFI,
bool NeedsFrameRecord,
1594 Reg1, Reg2, NeedsWinCFI,
TRI);
1598 if (NeedsFrameRecord)
1599 return Reg2 == AArch64::LR;
1608 int64_t MinOff, MaxOff;
1609 TypeSize ScaleValue(0U,
false), Width(0U,
false);
1610 if (!
TII->getMemOpInfo(Opcode, ScaleValue, Width, MinOff, MaxOff))
1613 if (
Offset % ScaleValue.getKnownMinValue() != 0)
1616 Offset /= ScaleValue.getKnownMinValue();
1622struct RegGroupInfo {
1627 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1630 RegGroupInfo() =
default;
1632 bool isPaired()
const {
return getNumRegs() == 2; }
1634 bool isQuad()
const {
return getNumRegs() == 4; }
1636 bool isGrouped()
const {
return isPaired() || isQuad(); }
1638 unsigned getNumRegs()
const {
1644 unsigned NumRegs = (Reg1 - Reg2) + 1;
1645 assert(NumRegs == 2 || NumRegs == 4);
1649 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1653 return {Reg1, Reg2};
1655 assert(Reg1 - 3 == Reg2 &&
"Quad not contiguous");
1656 return {Reg1, Reg1 - 1, Reg1 - 2, Reg1 - 3};
1661 auto getFrameIndexes()
const {
1662 return seq(FrameIdx, FrameIdx +
int(getNumRegs()));
1665 Register getAsMultiVectorRegister()
const {
1666 assert(
Type == ZPR && isGrouped() &&
"Expected ZPR register group");
1667 return (isQuad() ? AArch64::Z0_Z1_Z2_Z3 : AArch64::Z0_Z1) +
1668 (Reg2 - AArch64::Z0);
1671 void dump(
const TargetRegisterInfo *
TRI)
const {
1675 dbgs() <<
") -> fi#(";
1677 [&](
int FrameIdx) {
dbgs() << FrameIdx; });
1685 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1686 if (SavedRegs.
test(PReg)) {
1687 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1697 if (Subtarget.
getCLOpts().disable_multivector_spill_fill)
1701 bool IsLocallyStreaming =
1707 return Subtarget.hasSVE2p1() ||
1708 (Subtarget.hasSME2() &&
1709 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1717 bool NeedsFrameRecord) {
1737 (
Count & 1) == 0) &&
1738 "Odd number of callee-saved regs to spill!");
1740 int StackFillDir = -1;
1742 unsigned FirstReg = 0;
1750 FirstReg =
Count - 1;
1762 bool SpillExtendedVolatile =
1764 const auto &
Reg = CSI.getReg();
1765 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1768 int ZPRByteOffset = 0;
1769 int PPRByteOffset = 0;
1774 }
else if (!FPAfterSVECalleeSaves) {
1785 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1786 if (StackFillDir < 0)
1792 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1794 RGI.Reg1 = CSI[i].getReg();
1796 if (AArch64::GPR64RegClass.
contains(RGI.Reg1)) {
1797 RGI.Type = RegGroupInfo::GPR;
1798 RGI.RC = &AArch64::GPR64RegClass;
1799 }
else if (AArch64::FPR64RegClass.
contains(RGI.Reg1)) {
1800 RGI.Type = RegGroupInfo::FPR64;
1801 RGI.RC = &AArch64::FPR64RegClass;
1802 }
else if (AArch64::FPR128RegClass.
contains(RGI.Reg1)) {
1803 RGI.Type = RegGroupInfo::FPR128;
1804 RGI.RC = &AArch64::FPR128RegClass;
1805 }
else if (AArch64::ZPRRegClass.
contains(RGI.Reg1)) {
1806 RGI.Type = RegGroupInfo::ZPR;
1807 RGI.RC = &AArch64::ZPRRegClass;
1808 }
else if (AArch64::PPRRegClass.
contains(RGI.Reg1)) {
1809 RGI.Type = RegGroupInfo::PPR;
1810 RGI.RC = &AArch64::PPRRegClass;
1811 }
else if (RGI.Reg1 == AArch64::VG) {
1812 RGI.Type = RegGroupInfo::VG;
1813 RGI.RC = &AArch64::FIXED_REGSRegClass;
1818 int &ScalableByteOffset = RGI.Type == RegGroupInfo::PPR && SplitPPRs
1823 if (HasCSHazardPadding &&
1826 ByteOffset += StackFillDir * StackHazardSize;
1829 int Scale =
TRI->getSpillSize(*RGI.RC);
1831 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1832 MCRegister NextReg = CSI[i + RegInc].getReg();
1833 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1834 int Aligned = AlignOffset(ByteOffset, Scale);
1835 int PairOffset = IsWindows ?
Aligned :
Aligned + StackFillDir * 2 * Scale;
1836 bool PairFitsImmRange =
1837 PairOffset / Scale >= -64 && PairOffset / Scale <= 63;
1839 case RegGroupInfo::GPR:
1840 if (AArch64::GPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1842 RGI.Reg1, NextReg, IsWindows,
1843 NeedsWinCFI, NeedsFrameRecord,
TRI))
1846 case RegGroupInfo::FPR64:
1847 if (AArch64::FPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1849 RGI.Reg1, NextReg, IsWindows,
1850 NeedsWinCFI, NeedsFrameRecord,
TRI))
1853 case RegGroupInfo::FPR128:
1854 if (AArch64::FPR128RegClass.
contains(NextReg) && PairFitsImmRange)
1857 case RegGroupInfo::PPR:
1859 case RegGroupInfo::ZPR: {
1871 auto GetZPRTupleLowestReg =
1872 [&](
unsigned NumRegs) -> std::optional<Register> {
1874 if (RGI.Reg1 % NumRegs != NumRegs - 1)
1875 return std::nullopt;
1878 if (i + RegInc * NumRegs >
Count)
1879 return std::nullopt;
1881 for (
unsigned Idx = 1; Idx < NumRegs; ++Idx) {
1883 Register ExpectedReg = RGI.Reg1 - Idx;
1884 if (
Reg != ExpectedReg)
1885 return std::nullopt;
1888 return RGI.Reg1 - NumRegs + 1;
1891 for (
unsigned TupleSize : {4, 2}) {
1892 if (
auto LowReg = GetZPRTupleLowestReg(TupleSize)) {
1895 TupleSize == 4 ? AArch64::LD1B_4Z_IMM : AArch64::LD1B_2Z_IMM;
1897 (ScalableByteOffset + StackFillDir * TupleSize * Scale);
1907 case RegGroupInfo::VG:
1918 [[maybe_unused]]
bool RegsOrdered =
1919 all_of(
seq(RGI.getNumRegs() - 1), [&](
int RegOffset) {
1920 return CSI[i + RegInc * RegOffset].getFrameIdx() + RegInc ==
1921 CSI[i + RegInc * RegOffset + RegInc].getFrameIdx();
1923 assert(RegsOrdered &&
"Out of order callee saved regs!");
1925 assert((!RGI.isQuad() || RGI.Type == RegGroupInfo::ZPR) &&
1926 "Currently only ZPR's support four-register spills");
1928 assert((!RGI.isPaired() || !NeedsFrameRecord || RGI.Reg2 != AArch64::FP ||
1929 RGI.Reg1 == AArch64::LR) &&
1930 "FrameRecord must be allocated together with LR");
1933 assert((!RGI.isPaired() || !NeedsFrameRecord || RGI.Reg1 != AArch64::FP ||
1934 RGI.Reg2 == AArch64::LR) &&
1935 "FrameRecord must be allocated together with LR");
1943 ((RGI.Reg1 == AArch64::LR && RGI.Reg2 == AArch64::FP) ||
1944 RGI.Reg1 + 1 == RGI.Reg2))) &&
1945 "Callee-save registers not saved as adjacent register pair!");
1947 RGI.FrameIdx = CSI[i].getFrameIdx();
1950 RGI.FrameIdx = CSI[i + RegInc * (RGI.getNumRegs() - 1)].getFrameIdx();
1954 if (RGI.isScalable() && ScalableByteOffset % Scale != 0)
1955 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1959 if (!RGI.isScalable() && ByteOffset % Scale != 0)
1960 ByteOffset = AlignOffset(ByteOffset, Scale);
1962 int OffsetPre = RGI.isScalable() ? ScalableByteOffset : ByteOffset;
1963 assert(OffsetPre % Scale == 0);
1965 if (RGI.isScalable())
1966 ScalableByteOffset += StackFillDir * RGI.getNumRegs() * Scale;
1968 ByteOffset += StackFillDir * RGI.getNumRegs() * Scale;
1973 ((!IsWindows && RGI.Reg2 == AArch64::FP) ||
1974 (IsWindows && RGI.Reg2 == AArch64::LR)))
1975 ByteOffset += StackFillDir * 8;
1979 if (NeedGapToAlignStack && !IsWindows && !RGI.isScalable() &&
1980 RGI.Type != RegGroupInfo::FPR128 && !RGI.isPaired() &&
1981 ByteOffset % 16 != 0) {
1982 ByteOffset += 8 * StackFillDir;
1988 NeedGapToAlignStack =
false;
1991 int OffsetPost = RGI.isScalable() ? ScalableByteOffset : ByteOffset;
1992 assert(OffsetPost % Scale == 0);
1995 int Offset = IsWindows ? OffsetPre : OffsetPost;
2000 ((!IsWindows && RGI.Reg2 == AArch64::FP) ||
2001 (IsWindows && RGI.Reg2 == AArch64::LR)))
2005 (!RGI.isGrouped() || RGI.Type != RegGroupInfo::ZPR ||
2007 TII, (RGI.isQuad() ? AArch64::LD1B_4Z_IMM : AArch64::LD1B_2Z_IMM),
2009 "Offset invalid for LD1B/ST1B pair/quad variant immediate");
2011 RGI.Offset =
Offset / Scale;
2012 assert((!RGI.isGrouped() || RGI.Type == RegGroupInfo::ZPR ||
2013 (!RGI.isScalable() && RGI.Offset >= -64 && RGI.Offset <= 63) ||
2014 (RGI.isScalable() && RGI.Offset >= -256 && RGI.Offset <= 255)) &&
2015 "Offset out of bounds for LDP/STP immediate");
2017 auto isFrameRecord = [&] {
2019 return IsWindows ? RGI.Reg1 == AArch64::FP && RGI.Reg2 == AArch64::LR
2020 : RGI.Reg1 == AArch64::LR && RGI.Reg2 == AArch64::FP;
2028 return i > 0 && RGI.Reg1 == AArch64::FP &&
2029 CSI[i - 1].getReg() == AArch64::LR;
2034 if (NeedsFrameRecord && isFrameRecord())
2038 i += RegInc * (RGI.getNumRegs() - 1);
2050 std::reverse(RegGroups.
begin(), RegGroups.
end());
2072 if (homogeneousPrologEpilog(MF)) {
2076 for (
auto &RGI : RegGroups) {
2082 MBB.addLiveIn(RGI.Reg1);
2083 if (RGI.isPaired() && !MRI.
isReserved(RGI.Reg2))
2084 MBB.addLiveIn(RGI.Reg2);
2088 bool PTrueCreated =
false;
2104 unsigned Size =
TRI->getSpillSize(*RGI.RC);
2105 Align Alignment =
TRI->getSpillAlign(*RGI.RC);
2107 case RegGroupInfo::GPR:
2108 StrOpc = RGI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2110 case RegGroupInfo::FPR64:
2111 StrOpc = RGI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2113 case RegGroupInfo::FPR128:
2114 StrOpc = RGI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2116 case RegGroupInfo::ZPR:
2117 StrOpc = RGI.isQuad()
2118 ? AArch64::ST1B_4Z_IMM
2119 : (RGI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI);
2121 case RegGroupInfo::PPR:
2122 StrOpc = AArch64::STR_PXI;
2124 case RegGroupInfo::VG:
2125 StrOpc = AArch64::STRXui;
2137 if (Reg1 == AArch64::VG) {
2139 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2150 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2151 AArch64::X0, LiveIn.PhysReg);
2159 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2161 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2175 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2176 "Windows unwdinding requires a consecutive (FP,LR) pair");
2181 if (!PTrueCreated && RGI.isGrouped() && RGI.isScalable()) {
2185 "Expects SVE2.1 or SME2 target and a predicate register");
2186 PTrueCreated =
true;
2197 if (RGI.isGrouped() && RGI.isScalable()) {
2199 "Scalable register groups are not supported by Windows CFI yet");
2200#ifdef EXPENSIVE_CHECKS
2201 auto IsPPR = [](
const RegGroupInfo &c) {
2202 return c.Type == RegGroupInfo::PPR;
2204 auto PPRBegin = std::find_if(RegGroups.
begin(), RegGroups.
end(), IsPPR);
2205 auto IsZPR = [](
const RegGroupInfo &c) {
2206 return c.Type == RegGroupInfo::ZPR;
2208 auto ZPRBegin = std::find_if(RegGroups.
begin(), RegGroups.
end(), IsZPR);
2209 assert(!(PPRBegin < ZPRBegin) &&
2210 "Expected callee save predicate to be handled first");
2213 assert(RGI.Reg2 < RGI.Reg1 &&
"Expected reversed ZPR group");
2214 MIB.
addReg(RGI.getAsMultiVectorRegister());
2228 if (RGI.isPaired()) {
2247 if (RGI.Type == RegGroupInfo::ZPR)
2249 else if (RGI.Type == RegGroupInfo::PPR)
2267 DL =
MBBI->getDebugLoc();
2270 if (homogeneousPrologEpilog(MF, &
MBB)) {
2273 for (
auto &RGI : RegGroups) {
2281 auto IsPPR = [](
const RegGroupInfo &c) {
2282 return c.Type == RegGroupInfo::PPR;
2285 auto PPREnd = std::find_if_not(PPRBegin, RegGroups.
end(), IsPPR);
2286 std::reverse(PPRBegin, PPREnd);
2287 auto IsZPR = [](
const RegGroupInfo &c) {
2288 return c.Type == RegGroupInfo::ZPR;
2291 auto ZPREnd = std::find_if_not(ZPRBegin, RegGroups.
end(), IsZPR);
2292 std::reverse(ZPRBegin, ZPREnd);
2294 bool PTrueCreated =
false;
2295 for (
const RegGroupInfo &RGI : RegGroups) {
2308 unsigned Size =
TRI->getSpillSize(*RGI.RC);
2309 Align Alignment =
TRI->getSpillAlign(*RGI.RC);
2311 case RegGroupInfo::GPR:
2312 LdrOpc = RGI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2314 case RegGroupInfo::FPR64:
2315 LdrOpc = RGI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2317 case RegGroupInfo::FPR128:
2318 LdrOpc = RGI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2320 case RegGroupInfo::ZPR:
2321 LdrOpc = RGI.isQuad()
2322 ? AArch64::LD1B_4Z_IMM
2323 : (RGI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI);
2325 case RegGroupInfo::PPR:
2326 LdrOpc = AArch64::LDR_PXI;
2328 case RegGroupInfo::VG:
2338 if (!PTrueCreated && RGI.isGrouped() && RGI.isScalable()) {
2342 "Expects SVE2.1 or SME2 target and a predicate register");
2343 PTrueCreated =
true;
2349 if (RGI.isGrouped() && RGI.isScalable()) {
2351 "Scalable register groups are not supported by Windows CFI yet");
2352#ifdef EXPENSIVE_CHECKS
2353 assert(!(PPRBegin < ZPRBegin) &&
2354 "Expected callee save predicate to be handled first");
2356 assert(RGI.Reg2 < RGI.Reg1 &&
"Expected reversed ZPR group");
2396 return std::optional<int>(PSV->getFrameIndex());
2407 return std::nullopt;
2413 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2414 return std::nullopt;
2421 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2427void AArch64FrameLowering::determineStackHazardSlot(
2430 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2431 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2437 const AArch64Options &CLOpts =
2439 if (!CLOpts.stack_hazard_in_non_streaming &&
2440 Attrs.hasNonStreamingInterfaceAndBody())
2448 return AArch64::FPR64RegClass.contains(Reg) ||
2449 AArch64::FPR128RegClass.contains(Reg) ||
2450 AArch64::ZPRRegClass.contains(Reg);
2453 return AArch64::PPRRegClass.contains(Reg);
2455 bool HasFPRStackObjects =
false;
2456 bool HasPPRStackObjects =
false;
2457 if (!HasFPRCSRs || CLOpts.split_sve_objects) {
2458 enum SlotType : uint8_t {
2469 for (
auto &
MBB : MF) {
2470 for (
auto &
MI :
MBB) {
2472 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2479 ? SlotType::ZPRorFPR
2485 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2486 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2489 if (SlotTypes[FI] == SlotType::PPR) {
2491 HasPPRStackObjects =
true;
2496 if (HasFPRCSRs || HasFPRStackObjects) {
2499 << StackHazardSize <<
"\n");
2506 if (CLOpts.split_sve_objects) {
2510 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2516 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2517 "non-SVE CC function...\n");
2524 <<
"Calling convention is not supported with SplitSVEObjects\n");
2528 if (!HasPPRCSRs && !HasPPRStackObjects) {
2530 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2534 if (!HasFPRCSRs && !HasFPRStackObjects) {
2537 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2541 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2542 MF.getSubtarget<AArch64Subtarget>();
2544 "Expected SVE to be available for PPRs");
2546 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2550 BitVector FPRZRegs(SavedRegs.
size());
2551 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2552 BitVector::reference RegBit = SavedRegs[
Reg];
2555 unsigned SubRegIdx = 0;
2557 SubRegIdx = AArch64::dsub;
2559 SubRegIdx = AArch64::zsub;
2566 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2569 SavedRegs |= FPRZRegs;
2596 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2599 bool HasUnpairedGPR64 =
false;
2600 bool HasPairZReg =
false;
2601 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2602 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2605 for (
unsigned i = 0; CSRegs[i]; ++i) {
2609 if (Reg == BasePointerReg)
2614 if (UserReservedRegs[Reg]) {
2615 SavedRegs.
reset(Reg);
2619 bool RegUsed = SavedRegs.
test(Reg);
2621 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2622 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2623 AArch64::FPR128RegClass.
contains(Reg)) {
2626 if (HasUnpairedGPR64)
2627 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2629 PairedReg = CSRegs[i ^ 1];
2636 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2638 HasUnpairedGPR64 =
true;
2641 AArch64::GPR64RegClass.contains(Reg, PairedReg) ||
2642 AArch64::FPR64RegClass.contains(Reg, PairedReg) ||
2643 AArch64::FPR128RegClass.contains(Reg, PairedReg));
2646 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2647 UnspilledCSGPR = Reg;
2648 UnspilledCSGPRPaired = PairedReg;
2656 if (producePairRegisters(MF) && PairedReg.
isValid() &&
2657 !SavedRegs.
test(PairedReg)) {
2658 SavedRegs.
set(PairedReg);
2659 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2660 !ReservedRegs[PairedReg])
2661 ExtraCSSpill = PairedReg;
2664 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2665 SavedRegs.
test(CSRegs[i ^ 1]));
2673 if (PnReg.isValid())
2679 SavedRegs.
set(AArch64::P8);
2684 "Predicate cannot be a reserved register");
2694 SavedRegs.
set(AArch64::X18);
2700 determineStackHazardSlot(MF, SavedRegs);
2703 unsigned CSStackSize = 0;
2704 unsigned ZPRCSStackSize = 0;
2705 unsigned PPRCSStackSize = 0;
2707 for (
unsigned Reg : SavedRegs.
set_bits()) {
2709 assert(RC &&
"expected register class!");
2710 auto SpillSize =
TRI->getSpillSize(*RC);
2711 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2712 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2714 ZPRCSStackSize += SpillSize;
2716 PPRCSStackSize += SpillSize;
2722 return SavedRegs.test(SuperReg);
2725 CSStackSize += SpillSize;
2732 unsigned NumSavedRegs = SavedRegs.
count();
2745 SavedRegs.
set(AArch64::LR);
2750 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2751 SavedRegs.
set(AArch64::FP);
2752 SavedRegs.
set(AArch64::LR);
2756 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2757 for (
unsigned Reg : SavedRegs.
set_bits())
2763 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2765 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2766 uint64_t SVEStackSize =
2767 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2768 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2777 int64_t CalleeStackUsed = 0;
2780 if (FixedOff > CalleeStackUsed)
2781 CalleeStackUsed = FixedOff;
2785 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2786 CalleeStackUsed) > EstimatedStackSizeLimit;
2787 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2797 if (!ExtraCSSpill.
isValid() && UnspilledCSGPR.isValid()) {
2799 <<
" to get a scratch register.\n");
2800 SavedRegs.
set(UnspilledCSGPR);
2801 ExtraCSSpill = UnspilledCSGPR;
2806 if (producePairRegisters(MF)) {
2807 if (!UnspilledCSGPRPaired.
isValid()) {
2810 SavedRegs.
reset(UnspilledCSGPR);
2814 SavedRegs.
set(UnspilledCSGPRPaired);
2820 if (!ExtraCSSpill.
isValid() ||
2824 unsigned Size =
TRI->getSpillSize(RC);
2825 Align Alignment =
TRI->getSpillAlign(RC);
2827 RS->addScavengingFrameIndex(FI);
2828 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2829 <<
" as the emergency spill slot.\n");
2834 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2841 uint64_t AlignedCSStackSize =
alignTo(CSStackSize, 16);
2843 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2847 "Should not invalidate callee saved info");
2864 std::vector<CalleeSavedInfo> &CSI) {
2866 "ZPR callee-save reordering not supported on Windows");
2873 return AArch64::ZPRRegClass.contains(CS.getReg());
2877 ZPRSaves = ZPRSaves.
drop_until(IsZPR).take_while(IsZPR);
2879 if (ZPRSaves.
size() < 2)
2886 const int Scale =
RegInfo->getSpillSize(AArch64::ZPRRegClass);
2887 const int LowestOffset =
2888 (ZPRByteOffset / Scale) -
static_cast<int>(ZPRSaves.
size());
2890 int NumToAlign =
alignTo(LowestOffset, 4) - LowestOffset;
2891 if (NumToAlign >
int(ZPRSaves.
size()))
2895 [](
const auto &
A,
const auto &
B) {
return A.getReg() <
B.getReg(); });
2901 int ZPRsNeededForAlignment = NumToAlign;
2902 for (
size_t i = 0; i < ZPRSaves.
size();) {
2903 int ZPRsRemaining = int(ZPRSaves.
size()) - i;
2904 if (i + 3 < ZPRSaves.
size() &&
2905 (ZPRSaves[i].getReg() - AArch64::Z0) % 4 == 0 &&
2906 ZPRSaves[i].getReg() + 3 == ZPRSaves[i + 3].getReg() &&
2907 ZPRsRemaining - 4 >= ZPRsNeededForAlignment) {
2909 {ZPRSaves[i], ZPRSaves[i + 1], ZPRSaves[i + 2], ZPRSaves[i + 3]});
2916 bool MustSplitPairForSingle =
2917 ZPRsNeededForAlignment == 1 && Singles.empty() && ZPRsRemaining == 2;
2919 if (i + 1 < ZPRSaves.
size() &&
2920 (ZPRSaves[i].getReg() - AArch64::Z0) % 2 == 0 &&
2921 ZPRSaves[i].getReg() + 1 == ZPRSaves[i + 1].getReg() &&
2922 !MustSplitPairForSingle) {
2923 Pairs.
push_back({ZPRSaves[i], ZPRSaves[i + 1]});
2926 if (ZPRsNeededForAlignment != 1 || !Singles.empty())
2927 ZPRsNeededForAlignment -= 2;
2933 Singles.push_back(ZPRSaves[i++]);
2934 ZPRsNeededForAlignment--;
2940 int NumUnassigned = ZPRSaves.
size();
2946 ZPRSaves[--NumUnassigned] = CS;
2950 if (NumToAlign & 0b01)
2951 Emit(Singles.pop_back_val());
2952 if (NumToAlign & 0b10) {
2956 Emit({Singles.pop_back_val(), Singles.pop_back_val()});
2959 for (
const auto &Quad : Quads)
2962 for (
const auto &Pair : Pairs)
2965 for (
const auto &
Single : Singles)
2971 std::vector<CalleeSavedInfo> &CSI)
const {
2980 std::reverse(CSI.begin(), CSI.end());
2994 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2995 if (It != CSI.end())
2996 CSI.insert(It, VGInfo);
2998 CSI.push_back(VGInfo);
3008 int HazardSlotIndex = std::numeric_limits<int>::max();
3009 for (
auto &CS : CSI) {
3017 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
3018 "Unexpected register order for hazard slot");
3020 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3026 unsigned Size = RegInfo->getSpillSize(*RC);
3027 Align Alignment(RegInfo->getSpillAlign(*RC));
3029 CS.setFrameIdx(FrameIdx);
3043 HazardSlotIndex == std::numeric_limits<int>::max()) {
3045 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3072 int &Min,
int &Max) {
3073 Min = std::numeric_limits<int>::max();
3074 Max = std::numeric_limits<int>::min();
3080 for (
auto &CS : CSI) {
3081 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
3082 AArch64::PPRRegClass.contains(CS.getReg())) {
3083 assert((Max == std::numeric_limits<int>::min() ||
3084 Max + 1 == CS.getFrameIdx()) &&
3085 "SVE CalleeSaves are not consecutive");
3086 Min = std::min(Min, CS.getFrameIdx());
3087 Max = std::max(Max, CS.getFrameIdx());
3090 return Min != std::numeric_limits<int>::max();
3103 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
3111 "SVE vectors should never be passed on the stack by value, only by "
3115 auto AllocateObject = [&](
int FI) {
3124 if (Alignment >
Align(16))
3126 "Alignment of scalable vectors > 16 bytes is not yet supported");
3129 StackTop =
alignTo(StackTop, Alignment);
3131 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
3132 "SVE StackTop far too large?!");
3134 int64_t
Offset = -int64_t(StackTop);
3142 int MinCSFrameIndex, MaxCSFrameIndex;
3144 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
3157 int StackProtectorFI = -1;
3161 ObjectsToAllocate.
push_back(StackProtectorFI);
3177 for (
unsigned FI : ObjectsToAllocate)
3192 "Upwards growing stack unsupported");
3207 int64_t CurrentOffset =
3211 int FrameIndex =
H.CatchObj.FrameIndex;
3212 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3223 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3224 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3226 "UnwindHelpOffset must be at the start of the fixed object area");
3229 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3239 RS->enterBasicBlockEnd(
MBB);
3241 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3242 assert(DstReg &&
"There must be a free register after frame setup");
3253struct TagStoreInstr {
3262 MachineBasicBlock *
MBB;
3263 MachineRegisterInfo *MRI;
3272 StackOffset FrameRegOffset;
3276 std::optional<int64_t> FrameRegUpdate;
3278 unsigned FrameRegUpdateFlags;
3288 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3289 :
MBB(
MBB), ZeroData(ZeroData) {
3295 void addInstruction(TagStoreInstr
I) {
3297 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3298 "Non-adjacent tag store instructions.");
3301 void clear() { TagStores.
clear(); }
3306 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3313 const int64_t kMinOffset = -256 * 16;
3314 const int64_t kMaxOffset = 255 * 16;
3317 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3318 if (BaseRegOffsetBytes < kMinOffset ||
3319 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3323 BaseRegOffsetBytes % 16 != 0) {
3328 BaseRegOffsetBytes = 0;
3333 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3336 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3338 assert(BaseRegOffsetBytes % 16 == 0);
3342 .
addImm(BaseRegOffsetBytes / 16)
3346 if (BaseRegOffsetBytes == 0)
3348 BaseRegOffsetBytes += InstrSize;
3367 int64_t LoopSize =
Size;
3370 if (FrameRegUpdate && *FrameRegUpdate)
3371 LoopSize -= LoopSize % 32;
3373 TII->get(ZeroData ? AArch64::STZGloop_wback
3374 : AArch64::STGloop_wback))
3381 LoopI->
setFlags(FrameRegUpdateFlags);
3383 int64_t ExtraBaseRegUpdate =
3384 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3385 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3386 <<
", Size=" <<
Size
3387 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3388 <<
", FrameRegUpdate=" << FrameRegUpdate
3389 <<
", FrameRegOffset.getFixed()="
3390 << FrameRegOffset.
getFixed() <<
"\n");
3391 if (LoopSize <
Size) {
3395 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3396 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3397 "STG immediate out of range");
3399 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3406 }
else if (ExtraBaseRegUpdate) {
3408 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3409 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3412 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3425 int64_t
Size, int64_t *TotalOffset) {
3427 if ((
MI.getOpcode() == AArch64::ADDXri ||
3428 MI.getOpcode() == AArch64::SUBXri) &&
3429 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3431 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3432 if (
MI.getOpcode() == AArch64::SUBXri)
3443 const int64_t kMaxOffset = 4080 - 16;
3445 const int64_t kMinOffset = -4095;
3446 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3447 PostOffset % 16 == 0) {
3458 for (
auto &TS : TSE) {
3462 if (
MI->memoperands_empty()) {
3466 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3472 bool TryMergeSPUpdate) {
3473 if (TagStores.
empty())
3475 TagStoreInstr &FirstTagStore = TagStores[0];
3476 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3477 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3478 DL = TagStores[0].MI->getDebugLoc();
3482 *MF, FirstTagStore.Offset,
false ,
3486 FrameRegUpdate = std::nullopt;
3488 mergeMemRefs(TagStores, CombinedMemRefs);
3491 dbgs() <<
"Replacing adjacent STG instructions:\n";
3492 for (
const auto &Instr : TagStores) {
3501 if (TagStores.
size() < 2)
3503 emitUnrolled(InsertI);
3506 int64_t TotalOffset = 0;
3507 if (TryMergeSPUpdate) {
3513 if (InsertI !=
MBB->
end() &&
3514 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3516 UpdateInstr = &*InsertI++;
3522 if (!UpdateInstr && TagStores.
size() < 2)
3526 FrameRegUpdate = TotalOffset;
3527 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3534 for (
auto &TS : TagStores)
3535 TS.MI->eraseFromParent();
3539 int64_t &
Size,
bool &ZeroData) {
3543 unsigned Opcode =
MI.getOpcode();
3544 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3545 Opcode == AArch64::STZ2Gi);
3547 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3548 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3550 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3553 Size =
MI.getOperand(2).getImm();
3557 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3559 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3564 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3568 16 *
MI.getOperand(2).getImm();
3572static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3577 return LiveRegs.available(MRI,
Reg);
3580 size_t NumEmergencySlots = 0;
3582 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3584 return FreeGPRs + NumEmergencySlots;
3603 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3609 constexpr int kScanLimit = 10;
3612 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3621 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3622 if (ZeroData != FirstZeroData)
3630 if (!
MI.isTransient())
3639 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3655 LiveRegs.addLiveOuts(*
MBB);
3660 LiveRegs.stepBackward(*
I);
3663 if (LiveRegs.contains(AArch64::NZCV))
3674 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3675 <<
"due to high register pressure.\n");
3680 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3685 int64_t CurOffset = Instrs[0].Offset;
3686 for (
auto &Instr : Instrs) {
3687 if (CurOffset >
Instr.Offset)
3694 TagStoreEdit TSE(
MBB, FirstZeroData);
3695 std::optional<int64_t> EndOffset;
3696 for (
auto &Instr : Instrs) {
3697 if (EndOffset && *EndOffset !=
Instr.Offset) {
3699 TSE.emitCode(InsertI, TFI,
false);
3703 TSE.addInstruction(Instr);
3721 .stack_tagging_merge_settag;
3725 II = tryMergeAdjacentSTG(
II,
this, RS);
3732 shouldSignReturnAddressEverywhere(MF))
3741 bool IgnoreSPUpdates)
const {
3743 if (IgnoreSPUpdates) {
3746 FrameReg = AArch64::SP;
3756 FrameReg = AArch64::SP;
3781 bool IsValid =
false;
3783 int ObjectIndex = 0;
3785 int GroupIndex = -1;
3787 bool ObjectFirst =
false;
3790 bool GroupFirst =
false;
3795 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3799 SmallVector<int, 8> CurrentMembers;
3800 int NextGroupIndex = 0;
3801 std::vector<FrameObject> &Objects;
3804 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3805 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3806 void EndCurrentGroup() {
3807 if (CurrentMembers.
size() > 1) {
3812 for (
int Index : CurrentMembers) {
3813 Objects[
Index].GroupIndex = NextGroupIndex;
3819 CurrentMembers.clear();
3823bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3845 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3846 A.GroupIndex,
A.ObjectIndex) <
3847 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3848 B.GroupIndex,
B.ObjectIndex);
3858 ObjectsToAllocate.
empty())
3863 for (
auto &Obj : ObjectsToAllocate) {
3864 FrameObjects[Obj].IsValid =
true;
3865 FrameObjects[Obj].ObjectIndex = Obj;
3870 GroupBuilder GB(FrameObjects);
3871 for (
auto &
MBB : MF) {
3872 for (
auto &
MI :
MBB) {
3873 if (
MI.isDebugInstr())
3878 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3881 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3883 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3888 switch (
MI.getOpcode()) {
3889 case AArch64::STGloop:
3890 case AArch64::STZGloop:
3894 case AArch64::STZGi:
3895 case AArch64::ST2Gi:
3896 case AArch64::STZ2Gi:
3909 FrameObjects[FI].IsValid)
3917 GB.AddMember(TaggedFI);
3919 GB.EndCurrentGroup();
3922 GB.EndCurrentGroup();
3927 FrameObject::AccessHazard;
3929 for (
auto &Obj : FrameObjects)
3930 if (!Obj.Accesses ||
3931 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3932 Obj.Accesses = FrameObject::AccessGPR;
3941 FrameObjects[*TBPI].ObjectFirst =
true;
3942 FrameObjects[*TBPI].GroupFirst =
true;
3943 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3944 if (FirstGroupIndex >= 0)
3945 for (FrameObject &Object : FrameObjects)
3946 if (Object.GroupIndex == FirstGroupIndex)
3947 Object.GroupFirst =
true;
3953 for (
auto &Obj : FrameObjects) {
3957 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3961 dbgs() <<
"Final frame order:\n";
3962 for (
auto &Obj : FrameObjects) {
3965 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3966 if (Obj.ObjectFirst)
3967 dbgs() <<
", first";
3969 dbgs() <<
", group-first";
3980AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3991 MF.
insert(MBBInsertPoint, LoopMBB);
3993 MF.
insert(MBBInsertPoint, ExitMBB);
4028 MBB.addSuccessor(LoopMBB);
4032 return ExitMBB->
begin();
4035void AArch64FrameLowering::inlineStackProbeFixed(
4040 const AArch64InstrInfo *
TII =
4042 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
4047 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
4048 int64_t NumBlocks = FrameSize / ProbeSize;
4049 int64_t ResidualSize = FrameSize % ProbeSize;
4051 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
4052 << NumBlocks <<
" blocks of " << ProbeSize
4053 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
4058 for (
int i = 0; i < NumBlocks; ++i) {
4064 EmitAsyncCFI && !HasFP, CFAOffset);
4077 }
else if (NumBlocks != 0) {
4083 EmitAsyncCFI && !HasFP, CFAOffset);
4085 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
4087 if (EmitAsyncCFI && !HasFP) {
4090 .buildDefCFARegister(AArch64::SP);
4094 if (ResidualSize != 0) {
4100 EmitAsyncCFI && !HasFP, CFAOffset);
4121 SmallVector<MachineInstr *, 4> ToReplace;
4122 for (MachineInstr &
MI :
MBB)
4123 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
4124 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
4127 for (MachineInstr *
MI : ToReplace) {
4128 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
4129 Register ScratchReg =
MI->getOperand(0).getReg();
4130 int64_t FrameSize =
MI->getOperand(1).getImm();
4132 MI->getOperand(3).getImm());
4133 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
4136 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
4137 "Stack probe pseudo-instruction expected");
4138 const AArch64InstrInfo *
TII =
4139 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
4140 Register TargetReg =
MI->getOperand(0).getReg();
4141 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
4143 MI->eraseFromParent();
4163 return std::make_tuple(
start(),
Idx) <
4164 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4194 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4195 if (
Offset.getScalable())
4196 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4207void AArch64FrameLowering::emitRemarks(
4210 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4218 .stack_hazard_remark_size;
4220 if (HazardSize == 0)
4228 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4230 size_t NumFPLdSt = 0;
4231 size_t NumNonFPLdSt = 0;
4234 for (
const MachineBasicBlock &
MBB : MF) {
4235 for (
const MachineInstr &
MI :
MBB) {
4236 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4238 for (MachineMemOperand *MMO :
MI.memoperands()) {
4245 StackAccesses[ArrIdx].Idx = FrameIdx;
4246 StackAccesses[ArrIdx].Offset =
4257 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4268 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4279 if (StackAccesses.front().isMixed())
4280 MixedObjects.push_back(&StackAccesses.front());
4282 for (
auto It = StackAccesses.begin(),
End = std::prev(StackAccesses.end());
4284 const auto &
First = *It;
4285 const auto &Second = *(It + 1);
4287 if (Second.isMixed())
4288 MixedObjects.push_back(&Second);
4290 if ((
First.isSME() && Second.isCPU()) ||
4291 (
First.isCPU() && Second.isSME())) {
4293 if (Distance < HazardSize)
4298 auto EmitRemark = [&](llvm::StringRef Str) {
4300 auto R = MachineOptimizationRemarkAnalysis(
4301 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4302 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4306 for (
const auto &
P : HazardPairs)
4307 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4309 for (
const auto *Obj : MixedObjects)
4311 formatv(
"{0} accessed by both GP and FP instructions", *Obj).str());
static void getLiveRegsForEntryMBB(LivePhysRegs &LiveRegs, const MachineBasicBlock &MBB)
static const unsigned DefaultSafeSPDisplacement
This is the biggest offset to the stack pointer we can encode in aarch64 instructions (without using ...
static RegState getPrologueDeath(MachineFunction &MF, unsigned Reg)
static bool produceCompactUnwindFrame(const AArch64FrameLowering &, MachineFunction &MF)
bool enableMultiVectorSpillFill(const AArch64Subtarget &Subtarget, MachineFunction &MF)
static std::optional< int > getLdStFrameID(const MachineInstr &MI, const MachineFrameInfo &MFI)
static void orderZPRCalleeSavesForGroups(MachineFunction &MF, const TargetRegisterInfo *RegInfo, std::vector< CalleeSavedInfo > &CSI)
void computeCalleeSaveRegisterGroups(const AArch64FrameLowering &AFL, MachineFunction &MF, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI, SmallVectorImpl< RegGroupInfo > &RegGroups, bool NeedsFrameRecord)
static bool invalidateRegisterPairing(bool SpillExtendedVolatile, unsigned SpillCount, unsigned Reg1, unsigned Reg2, bool UsesWinAAPCS, bool NeedsWinCFI, bool NeedsFrameRecord, const TargetRegisterInfo *TRI)
Returns true if Reg1 and Reg2 cannot be paired using a ldp/stp instruction.
static bool isLikelyToHaveSVEStack(const AArch64FrameLowering &AFL, const MachineFunction &MF)
static bool invalidateWindowsRegisterPairing(bool SpillExtendedVolatile, unsigned SpillCount, unsigned Reg1, unsigned Reg2, bool NeedsWinCFI, const TargetRegisterInfo *TRI)
static SVEStackSizes determineSVEStackSizes(MachineFunction &MF, AssignObjectOffsets AssignOffsets)
Process all the SVE stack objects and the SVE stack size and offsets for each object.
static bool isTargetWindows(const MachineFunction &MF)
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 MCRegister getRegisterOrZero(MCRegister Reg, bool HasSVE)
static unsigned getStackHazardSize(const MachineFunction &MF)
static bool isValidMemOpOffset(const AArch64InstrInfo *TII, unsigned Opcode, int Offset)
MCRegister findFreePredicateReg(BitVector &SavedRegs)
static bool isPPRAccess(const MachineInstr &MI)
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
AMDGPU Reserve WWM Registers
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
Module.h This file contains the declarations for the Module class.
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 isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
This file defines the SmallVector class.
void emitEpilogue()
Emit the epilogue.
StackOffset getSVEStackSize(const MachineFunction &MF) const
Returns the size of the entire SVE stackframe (PPRs + ZPRs).
StackOffset getZPRStackSize(const MachineFunction &MF) const
Returns the size of the entire ZPR stackframe (calleesaves + spills).
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 assignCalleeSavedSpillSlots(MachineFunction &MF, const TargetRegisterInfo *TRI, std::vector< CalleeSavedInfo > &CSI) const override
assignCalleeSavedSpillSlots - Allows target to override spill slot assignment logic.
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 hasSVECalleeSavesAboveFrameRecord(const MachineFunction &MF) const
StackOffset resolveFrameOffsetReference(const MachineFunction &MF, int64_t ObjectOffset, bool isFixed, TargetStackID::Value StackID, Register &FrameReg, bool PreferFP, bool ForSimm) const
bool canUseRedZone(const MachineFunction &MF) const
Can this function use the red zone for local allocations.
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
StackOffset getPPRStackSize(const MachineFunction &MF) const
Returns the size of the entire PPR stackframe (calleesaves + spills + hazard padding).
int64_t getArgumentStackToRestore(MachineFunction &MF, MachineBasicBlock &MBB) const
Returns how much of the incoming argument stack area (in bytes) we should clean up in an epilogue.
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
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 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...
unsigned getPPRCalleeSavedStackSize() const
void setHasStackFrame(bool s)
void setSwiftAsyncContextFrameIdx(int FI)
unsigned getTailCallReservedStack() const
unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const
void setCalleeSaveBaseToFrameRecordOffset(int Offset)
bool hasStackProbing() const
unsigned getArgumentStackToRestore() const
void setCalleeSaveStackHasFreeSpace(bool s)
int getCalleeSaveBaseToFrameRecordOffset() const
SignReturnAddress getSignReturnAddressCondition() const
bool hasStreamingModeChanges() const
void setPredicateRegForFillSpill(unsigned Reg)
int getStackHazardSlotIndex() const
void setCalleeSavedStackSize(unsigned Size)
void setSplitSVEObjects(bool s)
bool hasStackFrame() const
void setStackSizeSVE(uint64_t ZPR, uint64_t PPR)
std::optional< int > getTaggedBasePointerIndex() const
SMEAttrs getSMEFnAttrs() const
uint64_t getLocalStackSize() const
bool needsDwarfUnwindInfo(const MachineFunction &MF) const
unsigned getVarArgsGPRSize() const
uint64_t getStackSizePPR() const
bool hasSwiftAsyncContext() const
bool hasStackHazardSlotIndex() const
void setStackHazardSlotIndex(int Index)
unsigned getZPRCalleeSavedStackSize() const
void setStackHazardCSRSlotIndex(int Index)
unsigned getPredicateRegForFillSpill() const
void setSVECalleeSavedStackSize(unsigned ZPR, unsigned PPR)
bool hasCalculatedStackSizeSVE() const
uint64_t getStackSizeZPR() const
bool hasSVEStackSize() const
bool isStackHazardIncludedInCalleeSaveArea() const
unsigned getSVECalleeSavedStackSize() const
bool hasSplitSVEObjects() const
bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const
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.
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 AArch64Options & getCLOpts() const
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 isTargetWindowsOrUEFI() const
UEFI follows the Windows ARM64 ABI and produces PE/COFF images, so most of the Windows specific ABI h...
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
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
bool empty() const
Check if the array is empty.
bool test(unsigned Idx) const
Returns true if bit Idx is set.
BitVector & reset()
Reset all bits in the bitvector.
size_type count() const
Returns the number of bits which are set.
BitVector & set()
Set all bits in the bitvector.
iterator_range< const_set_bits_iterator > set_bits() const
size_type size() const
Returns the number of bits in this bitvector.
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 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.
Module * getParent()
Get the module that this global value is contained inside of...
A set of physical registers with utility functions to track liveness when walking backward/forward th...
Wrapper class representing physical registers. Should be passed by value.
constexpr bool isValid() const
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.
reverse_iterator rbegin()
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
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...
void setObjectOffset(int ObjectIdx, int64_t SPOffset)
Set the stack frame offset of the specified object.
bool isCalleeSavedObjectIndex(int ObjectIdx) const
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...
bool hasScalableStackID(int ObjectIdx) const
int getStackProtectorIndex() const
Return the index for the stack protector object.
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...
LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment, TargetStackID::Value StackID=TargetStackID::Default)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
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.
void setIsCalleeSavedObjectIndex(int ObjectIdx, bool IsCalleeSaved)
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.
bool framePointerIsReserved() const
Returns true if the frame pointer must always either point to a new frame record or be un-modified in...
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
bool needsWinCFI() const
True if this function uses SEH unwind opcodes and needs an unwind table entry.
Function & getFunction()
Return the LLVM function that this machine code represents.
bool usesWindowsUnwindInfo() const
True if this function describes its unwind information with Windows SEH unwind opcodes (....
BasicBlockListType::iterator iterator
bool disableFramePointerElim() const
Returns true if frame pointer elimination should be disabled for this function.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineBasicBlock & front() const
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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 & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
void setFlags(unsigned flags)
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
const PseudoSourceValue * getPseudoValue() const
@ MOVolatile
The memory access is volatile.
@ 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.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI void freezeReservedRegs()
freezeReservedRegs - Called by the register allocator to freeze the set of reserved registers before ...
bool isReserved(MCRegister PhysReg) const
isReserved - Returns true when PhysReg is a reserved register.
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.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
MutableArrayRef< T > drop_until(PredicateT Pred) const
Return a copy of *this with the first N elements not satisfying the given predicate removed.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
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)
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.
const Triple & getTargetTriple() const
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.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
Triple - Helper class for working with autoconf configuration names.
bool isOSBinFormatMachO() const
Tests whether the environment is MachO.
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...
const AArch64MCOptions & getCLOpts(const MCTargetOptions &Options)
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.
@ Fast
Attempts to make calls as fast as possible (e.g.
@ 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 ...
@ C
The default llvm calling convention, compatible with C.
@ ScalablePredicateVector
NodeAddr< InstrNode * > Instr
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
void stable_sort(R &&Range)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
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.
@ Unknown
Not known to have no common set bits.
RegState
Flags to represent properties of register accesses.
@ Define
Register definition.
@ LLVM_MARK_AS_BITMASK_ENUM
constexpr RegState getKillRegState(bool B)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
void interleaveComma(const Container &c, StreamT &os, UnaryFunctor each_fn)
@ AArch64FrameOffsetCannotUpdate
Offset cannot apply.
constexpr T alignDown(U Value, V Align, W Skew=0)
Returns the largest unsigned integer less than or equal to Value and is Skew mod Align.
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)
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
constexpr RegState getDefRegState(bool B)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
auto reverse_conditionally(ContainerTy &&C, bool ShouldReverse)
Return a range that conditionally reverses C.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
@ End
Run the machine verifier once, at the end of the pipeline.
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.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
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.
constexpr 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 getUnknownStack(MachineFunction &MF)
Stack memory without other information.
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