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;
304 if (LastI !=
MBB.end() && (LastI->getOpcode() == AArch64::CATCHRET ||
305 LastI->getOpcode() == AArch64::CLEANUPRET))
351 if (AFI->hasCalculatedStackSizeSVE())
380bool AArch64FrameLowering::homogeneousPrologEpilog(
384 const AArch64Options &CLOpts =
386 if (!CLOpts.homogeneous_prolog_epilog)
408 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
415 unsigned NumGPRs = 0;
416 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
418 if (Reg == AArch64::LR) {
419 assert(CSRegs[
I + 1] == AArch64::FP);
420 if (NumGPRs % 2 != 0)
432bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
451 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
452 MI.getOpcode() == AArch64::ADDXri ||
453 MI.getOpcode() == AArch64::ADDSXri)
478 bool IsWin64,
bool IsFunclet)
const {
480 "Tail call reserved stack must be aligned to 16 bytes");
483 }
else if (IsFunclet) {
497 SmallSetVector<int, 8> CatchObjFrameIndices;
498 for (
const WinEHTryBlockMapEntry &TBME : EHInfo.
TryBlockMap) {
501 if ((FrameIndex != INT_MAX) &&
502 CatchObjFrameIndices.
insert(FrameIndex)) {
503 FixedObjectSize =
alignTo(FixedObjectSize,
510 FixedObjectSize += 8;
512 return alignTo(FixedObjectSize, 16);
523 const unsigned RedZoneSize =
536 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
540 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
568 if (Subtarget.getTargetLowering()->useStackGuardMixFP())
577 RegInfo->hasStackRealignment(MF))
623 if (TT.isOSDarwin() || TT.isOSWindowsOrUEFI())
661 unsigned Opc =
I->getOpcode();
662 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
663 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
666 int64_t Amount =
I->getOperand(0).getImm();
674 if (CalleePopAmount == 0) {
685 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
696 "non-reserved call frame without var sized objects?");
705 }
else if (CalleePopAmount != 0) {
708 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
720 const auto &
TRI = *Subtarget.getRegisterInfo();
726 CFIBuilder.buildDefCFA(AArch64::SP, 0);
729 if (MFI.shouldSignReturnAddress(MF)) {
730 if (MFI.branchProtectionPAuthLR()) {
731 CFIBuilder.buildNegateRAStateWithPC();
733 CFIBuilder.buildNegateRAState();
738 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
739 CFIBuilder.buildSameValue(AArch64::X18);
742 const std::vector<CalleeSavedInfo> &CSI =
744 for (
const auto &Info : CSI) {
746 if (!
TRI.regNeedsCFI(Reg, Reg))
748 CFIBuilder.buildSameValue(Reg);
761 case AArch64::W##n: \
762 case AArch64::X##n: \
787 case AArch64::B##n: \
788 case AArch64::H##n: \
789 case AArch64::S##n: \
790 case AArch64::D##n: \
791 case AArch64::Q##n: \
792 return HasSVE ? AArch64::Z##n : AArch64::Q##n
829void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
841 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
844 BitVector GPRsToZero(
TRI.getNumRegs());
845 BitVector FPRsToZero(
TRI.getNumRegs());
849 bool HasFPR = STI.hasFPARMv8();
851 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
854 GPRsToZero.set(XReg);
858 FPRsToZero.set(XReg);
865 for (MCRegister
Reg : GPRsToZero.set_bits())
869 for (MCRegister
Reg : FPRsToZero.set_bits())
873 for (MCRegister PReg :
874 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
875 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
876 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
878 if (RegsToZero[PReg])
884bool AArch64FrameLowering::windowsRequiresStackProbe(
886 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
887 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
891 StackSizeInBytes >=
uint64_t(MFI.getStackProbeSize());
900 for (
unsigned i = 0; CSRegs[i]; ++i)
906 bool HasCall)
const {
916 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
918 LivePhysRegs LiveRegs(
TRI);
921 LiveRegs.addReg(AArch64::X16);
922 LiveRegs.addReg(AArch64::X17);
923 LiveRegs.addReg(AArch64::X18);
928 if (LiveRegs.available(
MRI, AArch64::X9))
931 for (
unsigned Reg : AArch64::GPR64RegClass) {
932 if (LiveRegs.available(
MRI,
Reg))
962 MBB.isLiveIn(AArch64::NZCV))
966 if (!findScratchNonCalleeSaveRegister(TmpMBB).
isValid())
972 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
973 if (!findScratchNonCalleeSaveRegister(TmpMBB,
true).
isValid())
979bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
995 unsigned Opc =
MBBI->getOpcode();
999 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1000 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1008 case AArch64::STR_ZXI:
1009 case AArch64::LDR_ZXI: {
1010 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1017 case AArch64::STR_PXI:
1018 case AArch64::LDR_PXI: {
1019 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1026 case AArch64::LDPDpost:
1029 case AArch64::STPDpre: {
1030 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1031 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1032 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1039 case AArch64::LDPXpost:
1042 case AArch64::STPXpre: {
1045 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1046 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1050 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1051 .
addImm(RegInfo->getSEHRegNum(Reg0))
1052 .
addImm(RegInfo->getSEHRegNum(Reg1))
1057 case AArch64::LDRDpost:
1060 case AArch64::STRDpre: {
1061 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1062 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1068 case AArch64::LDRXpost:
1071 case AArch64::STRXpre: {
1072 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1079 case AArch64::STPDi:
1080 case AArch64::LDPDi: {
1081 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1082 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1090 case AArch64::STPXi:
1091 case AArch64::LDPXi: {
1095 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1096 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1098 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1102 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1109 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1116 case AArch64::STRXui:
1117 case AArch64::LDRXui: {
1118 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1125 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1131 case AArch64::STRDui:
1132 case AArch64::LDRDui: {
1133 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1140 case AArch64::STPQi:
1141 case AArch64::LDPQi: {
1142 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1143 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1144 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1151 case AArch64::LDPQpost:
1154 case AArch64::STPQpre: {
1155 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1156 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1157 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1176 if (ST.isTargetDarwin())
1198 DL =
MBBI->getDebugLoc();
1200 TII->createPauthEpilogueInstr(
MBB,
DL);
1204 EmitSignRA(MF.
front());
1206 if (
MBB.isEHFuncletEntry())
1208 if (
MBB.isReturnBlock())
1264 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1269 if (MFI.isVariableSizedObjectIndex(FI)) {
1279 if (MFI.hasScalableStackID(FI)) {
1280 if (FPAfterSVECalleeSaves &&
1283 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1291 AccessOffset = -PPRStackSize;
1292 return AccessOffset +
1297 bool IsFixed = MFI.isFixedObjectIndex(FI);
1302 if (!IsFixed && !IsCSR) {
1303 ScalableOffset = -SVEStackSize;
1304 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1319 int64_t ObjectOffset)
const {
1323 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1324 unsigned FixedObject =
1325 getFixedObjectSize(MF, AFI, IsWin64,
false);
1333 int64_t ObjectOffset)
const {
1344 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1345 ? getFPOffset(MF, ObjectOffset).getFixed()
1346 : getStackOffset(MF, ObjectOffset).getFixed();
1351 bool ForSimm)
const {
1353 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1354 bool isFixed = MFI.isFixedObjectIndex(FI);
1357 FrameReg, PreferFP, ForSimm);
1363 bool ForSimm)
const {
1369 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1370 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1378 const int64_t FixedObjectSize =
1379 getFixedObjectSize(MF, AFI, IsWin64,
false);
1383 bool isSVE = MFI.isScalableStackID(StackID);
1387 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1398 PreferFP &= !SVEStackSize;
1406 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1410 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1412 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1417 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1418 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1420 if (FPOffset >= 0) {
1424 }
else if (MFI.hasVarSizedObjects()) {
1428 bool CanUseBP = RegInfo->hasBasePointer(MF);
1429 if (FPOffsetFits && CanUseBP)
1436 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1443 "Funclets should only be present on Win64");
1447 if (FPOffsetFits && PreferFP)
1454 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1455 "In the presence of dynamic stack pointer realignment, "
1456 "non-argument/CSR objects cannot be accessed through the frame pointer");
1473 FPOffset -= PPRStackSize;
1475 SPOffset -= PPRStackSize;
1480 if (FPAfterSVECalleeSaves) {
1491 RegInfo->hasStackRealignment(MF))) {
1492 FrameReg = RegInfo->getFrameRegister(MF);
1495 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1502 if (FPAfterSVECalleeSaves) {
1509 SVEAreaOffset = SVECalleeSavedStack;
1511 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1514 SVEAreaOffset = SVEStackSize;
1516 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1519 if (UseFP && !(isFixed || isCSR))
1520 SVEAreaOffset = -SVEStackSize;
1521 if (!UseFP && (isFixed || isCSR))
1522 SVEAreaOffset = SVEStackSize;
1526 FrameReg = RegInfo->getFrameRegister(MF);
1531 if (RegInfo->hasBasePointer(MF))
1532 FrameReg = RegInfo->getBaseRegister();
1534 assert(!MFI.hasVarSizedObjects() &&
1535 "Can't use SP when we have var sized objects.");
1536 FrameReg = AArch64::SP;
1564 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1570 unsigned SpillCount,
unsigned Reg1,
1571 unsigned Reg2,
bool NeedsWinCFI,
1580 if (Reg2 == AArch64::FP)
1590 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1591 return SpillExtendedVolatile
1592 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1593 (SpillCount % 2) == 0)
1598 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1599 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1609 unsigned SpillCount,
unsigned Reg1,
1610 unsigned Reg2,
bool UsesWinAAPCS,
1611 bool NeedsWinCFI,
bool NeedsFrameRecord,
1615 Reg1, Reg2, NeedsWinCFI,
TRI);
1619 if (NeedsFrameRecord)
1620 return Reg2 == AArch64::LR;
1629 int64_t MinOff, MaxOff;
1630 TypeSize ScaleValue(0U,
false), Width(0U,
false);
1631 if (!
TII->getMemOpInfo(Opcode, ScaleValue, Width, MinOff, MaxOff))
1634 if (
Offset % ScaleValue.getKnownMinValue() != 0)
1637 Offset /= ScaleValue.getKnownMinValue();
1643struct RegGroupInfo {
1648 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1651 RegGroupInfo() =
default;
1653 bool isPaired()
const {
return getNumRegs() == 2; }
1655 bool isQuad()
const {
return getNumRegs() == 4; }
1657 bool isGrouped()
const {
return isPaired() || isQuad(); }
1659 unsigned getNumRegs()
const {
1665 unsigned NumRegs = (Reg1 - Reg2) + 1;
1666 assert(NumRegs == 2 || NumRegs == 4);
1670 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1674 return {Reg1, Reg2};
1676 assert(Reg1 - 3 == Reg2 &&
"Quad not contiguous");
1677 return {Reg1, Reg1 - 1, Reg1 - 2, Reg1 - 3};
1682 auto getFrameIndexes()
const {
1683 return seq(FrameIdx, FrameIdx +
int(getNumRegs()));
1686 Register getAsMultiVectorRegister()
const {
1687 assert(
Type == ZPR && isGrouped() &&
"Expected ZPR register group");
1688 return (isQuad() ? AArch64::Z0_Z1_Z2_Z3 : AArch64::Z0_Z1) +
1689 (Reg2 - AArch64::Z0);
1692 void dump(
const TargetRegisterInfo *
TRI)
const {
1696 dbgs() <<
") -> fi#(";
1698 [&](
int FrameIdx) {
dbgs() << FrameIdx; });
1706 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1707 if (SavedRegs.
test(PReg)) {
1708 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1718 if (Subtarget.
getCLOpts().disable_multivector_spill_fill)
1722 bool IsLocallyStreaming =
1728 return Subtarget.hasSVE2p1() ||
1729 (Subtarget.hasSME2() &&
1730 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1738 bool NeedsFrameRecord) {
1758 (
Count & 1) == 0) &&
1759 "Odd number of callee-saved regs to spill!");
1761 int StackFillDir = -1;
1763 unsigned FirstReg = 0;
1771 FirstReg =
Count - 1;
1783 bool SpillExtendedVolatile =
1785 const auto &
Reg = CSI.getReg();
1786 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1789 int ZPRByteOffset = 0;
1790 int PPRByteOffset = 0;
1795 }
else if (!FPAfterSVECalleeSaves) {
1806 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1807 if (StackFillDir < 0)
1813 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1815 RGI.Reg1 = CSI[i].getReg();
1817 if (AArch64::GPR64RegClass.
contains(RGI.Reg1)) {
1818 RGI.Type = RegGroupInfo::GPR;
1819 RGI.RC = &AArch64::GPR64RegClass;
1820 }
else if (AArch64::FPR64RegClass.
contains(RGI.Reg1)) {
1821 RGI.Type = RegGroupInfo::FPR64;
1822 RGI.RC = &AArch64::FPR64RegClass;
1823 }
else if (AArch64::FPR128RegClass.
contains(RGI.Reg1)) {
1824 RGI.Type = RegGroupInfo::FPR128;
1825 RGI.RC = &AArch64::FPR128RegClass;
1826 }
else if (AArch64::ZPRRegClass.
contains(RGI.Reg1)) {
1827 RGI.Type = RegGroupInfo::ZPR;
1828 RGI.RC = &AArch64::ZPRRegClass;
1829 }
else if (AArch64::PPRRegClass.
contains(RGI.Reg1)) {
1830 RGI.Type = RegGroupInfo::PPR;
1831 RGI.RC = &AArch64::PPRRegClass;
1832 }
else if (RGI.Reg1 == AArch64::VG) {
1833 RGI.Type = RegGroupInfo::VG;
1834 RGI.RC = &AArch64::FIXED_REGSRegClass;
1839 int &ScalableByteOffset = RGI.Type == RegGroupInfo::PPR && SplitPPRs
1844 if (HasCSHazardPadding &&
1847 ByteOffset += StackFillDir * StackHazardSize;
1850 int Scale =
TRI->getSpillSize(*RGI.RC);
1852 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1853 MCRegister NextReg = CSI[i + RegInc].getReg();
1854 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1855 int Aligned = AlignOffset(ByteOffset, Scale);
1856 int PairOffset = IsWindows ?
Aligned :
Aligned + StackFillDir * 2 * Scale;
1857 bool PairFitsImmRange =
1858 PairOffset / Scale >= -64 && PairOffset / Scale <= 63;
1860 case RegGroupInfo::GPR:
1861 if (AArch64::GPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1863 RGI.Reg1, NextReg, IsWindows,
1864 NeedsWinCFI, NeedsFrameRecord,
TRI))
1867 case RegGroupInfo::FPR64:
1868 if (AArch64::FPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1870 RGI.Reg1, NextReg, IsWindows,
1871 NeedsWinCFI, NeedsFrameRecord,
TRI))
1874 case RegGroupInfo::FPR128:
1875 if (AArch64::FPR128RegClass.
contains(NextReg) && PairFitsImmRange)
1878 case RegGroupInfo::PPR:
1880 case RegGroupInfo::ZPR: {
1892 auto GetZPRTupleLowestReg =
1893 [&](
unsigned NumRegs) -> std::optional<Register> {
1895 if (RGI.Reg1 % NumRegs != NumRegs - 1)
1896 return std::nullopt;
1899 if (i + RegInc * NumRegs >
Count)
1900 return std::nullopt;
1902 for (
unsigned Idx = 1; Idx < NumRegs; ++Idx) {
1904 Register ExpectedReg = RGI.Reg1 - Idx;
1905 if (
Reg != ExpectedReg)
1906 return std::nullopt;
1909 return RGI.Reg1 - NumRegs + 1;
1912 for (
unsigned TupleSize : {4, 2}) {
1913 if (
auto LowReg = GetZPRTupleLowestReg(TupleSize)) {
1916 TupleSize == 4 ? AArch64::LD1B_4Z_IMM : AArch64::LD1B_2Z_IMM;
1918 (ScalableByteOffset + StackFillDir * TupleSize * Scale);
1928 case RegGroupInfo::VG:
1939 [[maybe_unused]]
bool RegsOrdered =
1940 all_of(
seq(RGI.getNumRegs() - 1), [&](
int RegOffset) {
1941 return CSI[i + RegInc * RegOffset].getFrameIdx() + RegInc ==
1942 CSI[i + RegInc * RegOffset + RegInc].getFrameIdx();
1944 assert(RegsOrdered &&
"Out of order callee saved regs!");
1946 assert((!RGI.isQuad() || RGI.Type == RegGroupInfo::ZPR) &&
1947 "Currently only ZPR's support four-register spills");
1949 assert((!RGI.isPaired() || !NeedsFrameRecord || RGI.Reg2 != AArch64::FP ||
1950 RGI.Reg1 == AArch64::LR) &&
1951 "FrameRecord must be allocated together with LR");
1954 assert((!RGI.isPaired() || !NeedsFrameRecord || RGI.Reg1 != AArch64::FP ||
1955 RGI.Reg2 == AArch64::LR) &&
1956 "FrameRecord must be allocated together with LR");
1964 ((RGI.Reg1 == AArch64::LR && RGI.Reg2 == AArch64::FP) ||
1965 RGI.Reg1 + 1 == RGI.Reg2))) &&
1966 "Callee-save registers not saved as adjacent register pair!");
1968 RGI.FrameIdx = CSI[i].getFrameIdx();
1971 RGI.FrameIdx = CSI[i + RegInc * (RGI.getNumRegs() - 1)].getFrameIdx();
1975 if (RGI.isScalable() && ScalableByteOffset % Scale != 0)
1976 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1980 if (!RGI.isScalable() && ByteOffset % Scale != 0)
1981 ByteOffset = AlignOffset(ByteOffset, Scale);
1983 int OffsetPre = RGI.isScalable() ? ScalableByteOffset : ByteOffset;
1984 assert(OffsetPre % Scale == 0);
1986 if (RGI.isScalable())
1987 ScalableByteOffset += StackFillDir * RGI.getNumRegs() * Scale;
1989 ByteOffset += StackFillDir * RGI.getNumRegs() * Scale;
1994 ((!IsWindows && RGI.Reg2 == AArch64::FP) ||
1995 (IsWindows && RGI.Reg2 == AArch64::LR)))
1996 ByteOffset += StackFillDir * 8;
2000 if (NeedGapToAlignStack && !IsWindows && !RGI.isScalable() &&
2001 RGI.Type != RegGroupInfo::FPR128 && !RGI.isPaired() &&
2002 ByteOffset % 16 != 0) {
2003 ByteOffset += 8 * StackFillDir;
2009 NeedGapToAlignStack =
false;
2012 int OffsetPost = RGI.isScalable() ? ScalableByteOffset : ByteOffset;
2013 assert(OffsetPost % Scale == 0);
2016 int Offset = IsWindows ? OffsetPre : OffsetPost;
2021 ((!IsWindows && RGI.Reg2 == AArch64::FP) ||
2022 (IsWindows && RGI.Reg2 == AArch64::LR)))
2026 (!RGI.isGrouped() || RGI.Type != RegGroupInfo::ZPR ||
2028 TII, (RGI.isQuad() ? AArch64::LD1B_4Z_IMM : AArch64::LD1B_2Z_IMM),
2030 "Offset invalid for LD1B/ST1B pair/quad variant immediate");
2032 RGI.Offset =
Offset / Scale;
2033 assert((!RGI.isGrouped() || RGI.Type == RegGroupInfo::ZPR ||
2034 (!RGI.isScalable() && RGI.Offset >= -64 && RGI.Offset <= 63) ||
2035 (RGI.isScalable() && RGI.Offset >= -256 && RGI.Offset <= 255)) &&
2036 "Offset out of bounds for LDP/STP immediate");
2038 auto isFrameRecord = [&] {
2040 return IsWindows ? RGI.Reg1 == AArch64::FP && RGI.Reg2 == AArch64::LR
2041 : RGI.Reg1 == AArch64::LR && RGI.Reg2 == AArch64::FP;
2049 return i > 0 && RGI.Reg1 == AArch64::FP &&
2050 CSI[i - 1].getReg() == AArch64::LR;
2055 if (NeedsFrameRecord && isFrameRecord())
2059 i += RegInc * (RGI.getNumRegs() - 1);
2071 std::reverse(RegGroups.
begin(), RegGroups.
end());
2091 MRI.freezeReservedRegs();
2093 if (homogeneousPrologEpilog(MF)) {
2097 for (
auto &RGI : RegGroups) {
2102 if (!
MRI.isReserved(RGI.Reg1))
2103 MBB.addLiveIn(RGI.Reg1);
2104 if (RGI.isPaired() && !
MRI.isReserved(RGI.Reg2))
2105 MBB.addLiveIn(RGI.Reg2);
2109 bool PTrueCreated =
false;
2125 unsigned Size =
TRI->getSpillSize(*RGI.RC);
2126 Align Alignment =
TRI->getSpillAlign(*RGI.RC);
2128 case RegGroupInfo::GPR:
2129 StrOpc = RGI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2131 case RegGroupInfo::FPR64:
2132 StrOpc = RGI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2134 case RegGroupInfo::FPR128:
2135 StrOpc = RGI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2137 case RegGroupInfo::ZPR:
2138 StrOpc = RGI.isQuad()
2139 ? AArch64::ST1B_4Z_IMM
2140 : (RGI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI);
2142 case RegGroupInfo::PPR:
2143 StrOpc = AArch64::STR_PXI;
2145 case RegGroupInfo::VG:
2146 StrOpc = AArch64::STRXui;
2158 if (Reg1 == AArch64::VG) {
2160 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2171 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2172 AArch64::X0, LiveIn.PhysReg);
2180 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2182 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2196 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2197 "Windows unwdinding requires a consecutive (FP,LR) pair");
2202 if (!PTrueCreated && RGI.isGrouped() && RGI.isScalable()) {
2206 "Expects SVE2.1 or SME2 target and a predicate register");
2207 PTrueCreated =
true;
2214 if (!
MRI.isReserved(Reg))
2218 if (RGI.isGrouped() && RGI.isScalable()) {
2220 "Scalable register groups are not supported by Windows CFI yet");
2221#ifdef EXPENSIVE_CHECKS
2222 auto IsPPR = [](
const RegGroupInfo &c) {
2223 return c.Type == RegGroupInfo::PPR;
2225 auto PPRBegin = std::find_if(RegGroups.
begin(), RegGroups.
end(), IsPPR);
2226 auto IsZPR = [](
const RegGroupInfo &c) {
2227 return c.Type == RegGroupInfo::ZPR;
2229 auto ZPRBegin = std::find_if(RegGroups.
begin(), RegGroups.
end(), IsZPR);
2230 assert(!(PPRBegin < ZPRBegin) &&
2231 "Expected callee save predicate to be handled first");
2234 assert(RGI.Reg2 < RGI.Reg1 &&
"Expected reversed ZPR group");
2235 MIB.
addReg(RGI.getAsMultiVectorRegister());
2249 if (RGI.isPaired()) {
2268 if (RGI.Type == RegGroupInfo::ZPR)
2270 else if (RGI.Type == RegGroupInfo::PPR)
2288 DL =
MBBI->getDebugLoc();
2291 if (homogeneousPrologEpilog(MF, &
MBB)) {
2294 for (
auto &RGI : RegGroups) {
2302 auto IsPPR = [](
const RegGroupInfo &c) {
2303 return c.Type == RegGroupInfo::PPR;
2306 auto PPREnd = std::find_if_not(PPRBegin, RegGroups.
end(), IsPPR);
2307 std::reverse(PPRBegin, PPREnd);
2308 auto IsZPR = [](
const RegGroupInfo &c) {
2309 return c.Type == RegGroupInfo::ZPR;
2312 auto ZPREnd = std::find_if_not(ZPRBegin, RegGroups.
end(), IsZPR);
2313 std::reverse(ZPRBegin, ZPREnd);
2320 bool PTrueCreated =
false;
2321 for (
const RegGroupInfo &RGI : RegGroups) {
2334 unsigned Size =
TRI->getSpillSize(*RGI.RC);
2335 Align Alignment =
TRI->getSpillAlign(*RGI.RC);
2337 case RegGroupInfo::GPR:
2338 LdrOpc = RGI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2340 case RegGroupInfo::FPR64:
2341 LdrOpc = RGI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2343 case RegGroupInfo::FPR128:
2344 LdrOpc = RGI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2346 case RegGroupInfo::ZPR:
2347 LdrOpc = RGI.isQuad()
2348 ? AArch64::LD1B_4Z_IMM
2349 : (RGI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI);
2351 case RegGroupInfo::PPR:
2352 LdrOpc = AArch64::LDR_PXI;
2354 case RegGroupInfo::VG:
2364 if (!PTrueCreated && RGI.isGrouped() && RGI.isScalable()) {
2368 "Expects SVE2.1 or SME2 target and a predicate register");
2369 PTrueCreated =
true;
2374 if (KeepLR && RGI.Type == RegGroupInfo::GPR &&
2375 (Reg1 == AArch64::LR || Reg2 == AArch64::LR)) {
2379 if (!RGI.isPaired())
2381 assert(Reg2 == AArch64::LR &&
"Expected LR to be the second of the pair");
2397 if (RGI.isGrouped() && RGI.isScalable()) {
2399 "Scalable register groups are not supported by Windows CFI yet");
2400#ifdef EXPENSIVE_CHECKS
2401 assert(!(PPRBegin < ZPRBegin) &&
2402 "Expected callee save predicate to be handled first");
2404 assert(RGI.Reg2 < RGI.Reg1 &&
"Expected reversed ZPR group");
2444 return std::optional<int>(PSV->getFrameIndex());
2455 return std::nullopt;
2461 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2462 return std::nullopt;
2469 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2475void AArch64FrameLowering::determineStackHazardSlot(
2478 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2479 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2485 const AArch64Options &CLOpts =
2487 if (!CLOpts.stack_hazard_in_non_streaming &&
2488 Attrs.hasNonStreamingInterfaceAndBody())
2496 return AArch64::FPR64RegClass.contains(Reg) ||
2497 AArch64::FPR128RegClass.contains(Reg) ||
2498 AArch64::ZPRRegClass.contains(Reg);
2501 return AArch64::PPRRegClass.contains(Reg);
2503 bool HasFPRStackObjects =
false;
2504 bool HasPPRStackObjects =
false;
2505 if (!HasFPRCSRs || CLOpts.split_sve_objects) {
2506 enum SlotType : uint8_t {
2517 for (
auto &
MBB : MF) {
2518 for (
auto &
MI :
MBB) {
2520 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2527 ? SlotType::ZPRorFPR
2533 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2534 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2537 if (SlotTypes[FI] == SlotType::PPR) {
2539 HasPPRStackObjects =
true;
2544 if (HasFPRCSRs || HasFPRStackObjects) {
2547 << StackHazardSize <<
"\n");
2554 if (CLOpts.split_sve_objects) {
2558 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2564 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2565 "non-SVE CC function...\n");
2572 <<
"Calling convention is not supported with SplitSVEObjects\n");
2576 if (!HasPPRCSRs && !HasPPRStackObjects) {
2578 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2582 if (!HasFPRCSRs && !HasFPRStackObjects) {
2585 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2589 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2590 MF.getSubtarget<AArch64Subtarget>();
2592 "Expected SVE to be available for PPRs");
2594 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2598 BitVector FPRZRegs(SavedRegs.
size());
2599 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2600 BitVector::reference RegBit = SavedRegs[
Reg];
2603 unsigned SubRegIdx = 0;
2605 SubRegIdx = AArch64::dsub;
2607 SubRegIdx = AArch64::zsub;
2614 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2617 SavedRegs |= FPRZRegs;
2647 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2650 bool HasUnpairedGPR64 =
false;
2651 bool HasPairZReg =
false;
2652 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2653 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2656 for (
unsigned i = 0; CSRegs[i]; ++i) {
2660 if (Reg == BasePointerReg)
2665 if (UserReservedRegs[Reg]) {
2666 SavedRegs.
reset(Reg);
2670 bool RegUsed = SavedRegs.
test(Reg);
2672 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2673 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2674 AArch64::FPR128RegClass.
contains(Reg)) {
2677 if (HasUnpairedGPR64)
2678 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2680 PairedReg = CSRegs[i ^ 1];
2687 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2689 HasUnpairedGPR64 =
true;
2692 AArch64::GPR64RegClass.contains(Reg, PairedReg) ||
2693 AArch64::FPR64RegClass.contains(Reg, PairedReg) ||
2694 AArch64::FPR128RegClass.contains(Reg, PairedReg));
2697 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2698 UnspilledCSGPR = Reg;
2699 UnspilledCSGPRPaired = PairedReg;
2707 if (producePairRegisters(MF) && PairedReg.
isValid() &&
2708 !SavedRegs.
test(PairedReg)) {
2709 SavedRegs.
set(PairedReg);
2710 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2711 !ReservedRegs[PairedReg])
2712 ExtraCSSpill = PairedReg;
2715 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2716 SavedRegs.
test(CSRegs[i ^ 1]));
2724 if (PnReg.isValid())
2730 SavedRegs.
set(AArch64::P8);
2735 "Predicate cannot be a reserved register");
2745 SavedRegs.
set(AArch64::X18);
2751 determineStackHazardSlot(MF, SavedRegs);
2754 unsigned CSStackSize = 0;
2755 unsigned ZPRCSStackSize = 0;
2756 unsigned PPRCSStackSize = 0;
2758 for (
unsigned Reg : SavedRegs.
set_bits()) {
2760 assert(RC &&
"expected register class!");
2761 auto SpillSize =
TRI->getSpillSize(*RC);
2762 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2763 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2765 ZPRCSStackSize += SpillSize;
2767 PPRCSStackSize += SpillSize;
2773 return SavedRegs.test(SuperReg);
2776 CSStackSize += SpillSize;
2783 unsigned NumSavedRegs = SavedRegs.
count();
2796 SavedRegs.
set(AArch64::LR);
2801 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2802 SavedRegs.
set(AArch64::FP);
2803 SavedRegs.
set(AArch64::LR);
2807 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2808 for (
unsigned Reg : SavedRegs.
set_bits())
2814 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2816 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2817 uint64_t SVEStackSize =
2818 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2819 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2828 int64_t CalleeStackUsed = 0;
2831 if (FixedOff > CalleeStackUsed)
2832 CalleeStackUsed = FixedOff;
2836 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2837 CalleeStackUsed) > EstimatedStackSizeLimit;
2838 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2850 <<
" to get a scratch register.\n");
2851 SavedRegs.
set(UnspilledCSGPR);
2852 ExtraCSSpill = UnspilledCSGPR;
2857 if (producePairRegisters(MF)) {
2858 if (!UnspilledCSGPRPaired.
isValid()) {
2861 SavedRegs.
reset(UnspilledCSGPR);
2865 SavedRegs.
set(UnspilledCSGPRPaired);
2871 if (!ExtraCSSpill.
isValid() ||
2875 unsigned Size =
TRI->getSpillSize(RC);
2876 Align Alignment =
TRI->getSpillAlign(RC);
2878 RS->addScavengingFrameIndex(FI);
2879 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2880 <<
" as the emergency spill slot.\n");
2885 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2892 uint64_t AlignedCSStackSize =
alignTo(CSStackSize, 16);
2894 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2898 "Should not invalidate callee saved info");
2915 std::vector<CalleeSavedInfo> &CSI) {
2917 "ZPR callee-save reordering not supported on Windows");
2924 return AArch64::ZPRRegClass.contains(CS.getReg());
2928 ZPRSaves = ZPRSaves.
drop_until(IsZPR).take_while(IsZPR);
2930 if (ZPRSaves.
size() < 2)
2937 const int Scale =
RegInfo->getSpillSize(AArch64::ZPRRegClass);
2938 const int LowestOffset =
2939 (ZPRByteOffset / Scale) -
static_cast<int>(ZPRSaves.
size());
2941 int NumToAlign =
alignTo(LowestOffset, 4) - LowestOffset;
2942 if (NumToAlign >
int(ZPRSaves.
size()))
2946 [](
const auto &
A,
const auto &
B) {
return A.getReg() <
B.getReg(); });
2952 int ZPRsNeededForAlignment = NumToAlign;
2953 for (
size_t i = 0; i < ZPRSaves.
size();) {
2954 int ZPRsRemaining = int(ZPRSaves.
size()) - i;
2955 if (i + 3 < ZPRSaves.
size() &&
2956 (ZPRSaves[i].getReg() - AArch64::Z0) % 4 == 0 &&
2957 ZPRSaves[i].getReg() + 3 == ZPRSaves[i + 3].getReg() &&
2958 ZPRsRemaining - 4 >= ZPRsNeededForAlignment) {
2960 {ZPRSaves[i], ZPRSaves[i + 1], ZPRSaves[i + 2], ZPRSaves[i + 3]});
2967 bool MustSplitPairForSingle =
2968 ZPRsNeededForAlignment == 1 && Singles.empty() && ZPRsRemaining == 2;
2970 if (i + 1 < ZPRSaves.
size() &&
2971 (ZPRSaves[i].getReg() - AArch64::Z0) % 2 == 0 &&
2972 ZPRSaves[i].getReg() + 1 == ZPRSaves[i + 1].getReg() &&
2973 !MustSplitPairForSingle) {
2974 Pairs.
push_back({ZPRSaves[i], ZPRSaves[i + 1]});
2977 if (ZPRsNeededForAlignment != 1 || !Singles.empty())
2978 ZPRsNeededForAlignment -= 2;
2984 Singles.push_back(ZPRSaves[i++]);
2985 ZPRsNeededForAlignment--;
2991 int NumUnassigned = ZPRSaves.
size();
2997 ZPRSaves[--NumUnassigned] = CS;
3001 if (NumToAlign & 0b01)
3002 Emit(Singles.pop_back_val());
3003 if (NumToAlign & 0b10) {
3007 Emit({Singles.pop_back_val(), Singles.pop_back_val()});
3010 for (
const auto &Quad : Quads)
3013 for (
const auto &Pair : Pairs)
3016 for (
const auto &
Single : Singles)
3022 std::vector<CalleeSavedInfo> &CSI)
const {
3031 std::reverse(CSI.begin(), CSI.end());
3045 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
3046 if (It != CSI.end())
3047 CSI.insert(It, VGInfo);
3049 CSI.push_back(VGInfo);
3059 int HazardSlotIndex = std::numeric_limits<int>::max();
3060 for (
auto &CS : CSI) {
3068 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
3069 "Unexpected register order for hazard slot");
3071 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3077 unsigned Size = RegInfo->getSpillSize(*RC);
3078 Align Alignment(RegInfo->getSpillAlign(*RC));
3080 CS.setFrameIdx(FrameIdx);
3094 HazardSlotIndex == std::numeric_limits<int>::max()) {
3096 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3123 int &Min,
int &Max) {
3124 Min = std::numeric_limits<int>::max();
3125 Max = std::numeric_limits<int>::min();
3131 for (
auto &CS : CSI) {
3132 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
3133 AArch64::PPRRegClass.contains(CS.getReg())) {
3134 assert((Max == std::numeric_limits<int>::min() ||
3135 Max + 1 == CS.getFrameIdx()) &&
3136 "SVE CalleeSaves are not consecutive");
3137 Min = std::min(Min, CS.getFrameIdx());
3138 Max = std::max(Max, CS.getFrameIdx());
3141 return Min != std::numeric_limits<int>::max();
3154 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
3162 "SVE vectors should never be passed on the stack by value, only by "
3166 auto AllocateObject = [&](
int FI) {
3175 if (Alignment >
Align(16))
3177 "Alignment of scalable vectors > 16 bytes is not yet supported");
3180 StackTop =
alignTo(StackTop, Alignment);
3182 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
3183 "SVE StackTop far too large?!");
3185 int64_t
Offset = -int64_t(StackTop);
3193 int MinCSFrameIndex, MaxCSFrameIndex;
3195 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
3208 int StackProtectorFI = -1;
3212 ObjectsToAllocate.
push_back(StackProtectorFI);
3228 for (
unsigned FI : ObjectsToAllocate)
3243 "Upwards growing stack unsupported");
3258 int64_t CurrentOffset =
3262 int FrameIndex =
H.CatchObj.FrameIndex;
3263 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3274 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3275 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3277 "UnwindHelpOffset must be at the start of the fixed object area");
3280 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3290 RS->enterBasicBlockEnd(
MBB);
3292 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3293 assert(DstReg &&
"There must be a free register after frame setup");
3304struct TagStoreInstr {
3313 MachineBasicBlock *
MBB;
3314 MachineRegisterInfo *
MRI;
3323 StackOffset FrameRegOffset;
3327 std::optional<int64_t> FrameRegUpdate;
3329 unsigned FrameRegUpdateFlags;
3339 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3340 :
MBB(
MBB), ZeroData(ZeroData) {
3346 void addInstruction(TagStoreInstr
I) {
3348 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3349 "Non-adjacent tag store instructions.");
3352 void clear() { TagStores.
clear(); }
3357 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3364 const int64_t kMinOffset = -256 * 16;
3365 const int64_t kMaxOffset = 255 * 16;
3368 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3369 if (BaseRegOffsetBytes < kMinOffset ||
3370 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3374 BaseRegOffsetBytes % 16 != 0) {
3379 BaseRegOffsetBytes = 0;
3384 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3387 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3389 assert(BaseRegOffsetBytes % 16 == 0);
3393 .
addImm(BaseRegOffsetBytes / 16)
3397 if (BaseRegOffsetBytes == 0)
3399 BaseRegOffsetBytes += InstrSize;
3418 int64_t LoopSize =
Size;
3421 if (FrameRegUpdate && *FrameRegUpdate)
3422 LoopSize -= LoopSize % 32;
3424 TII->get(ZeroData ? AArch64::STZGloop_wback
3425 : AArch64::STGloop_wback))
3432 LoopI->
setFlags(FrameRegUpdateFlags);
3434 int64_t ExtraBaseRegUpdate =
3435 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3436 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3437 <<
", Size=" <<
Size
3438 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3439 <<
", FrameRegUpdate=" << FrameRegUpdate
3440 <<
", FrameRegOffset.getFixed()="
3441 << FrameRegOffset.
getFixed() <<
"\n");
3442 if (LoopSize <
Size) {
3446 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3447 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3448 "STG immediate out of range");
3450 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3457 }
else if (ExtraBaseRegUpdate) {
3459 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3460 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3463 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3476 int64_t
Size, int64_t *TotalOffset) {
3478 if ((
MI.getOpcode() == AArch64::ADDXri ||
3479 MI.getOpcode() == AArch64::SUBXri) &&
3480 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3482 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3483 if (
MI.getOpcode() == AArch64::SUBXri)
3494 const int64_t kMaxOffset = 4080 - 16;
3496 const int64_t kMinOffset = -4095;
3497 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3498 PostOffset % 16 == 0) {
3509 for (
auto &TS : TSE) {
3513 if (
MI->memoperands_empty()) {
3517 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3523 bool TryMergeSPUpdate) {
3524 if (TagStores.
empty())
3526 TagStoreInstr &FirstTagStore = TagStores[0];
3527 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3528 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3529 DL = TagStores[0].MI->getDebugLoc();
3533 *MF, FirstTagStore.Offset,
false ,
3537 FrameRegUpdate = std::nullopt;
3539 mergeMemRefs(TagStores, CombinedMemRefs);
3542 dbgs() <<
"Replacing adjacent STG instructions:\n";
3543 for (
const auto &Instr : TagStores) {
3552 if (TagStores.
size() < 2)
3554 emitUnrolled(InsertI);
3557 int64_t TotalOffset = 0;
3558 if (TryMergeSPUpdate) {
3564 if (InsertI !=
MBB->
end() &&
3565 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3567 UpdateInstr = &*InsertI++;
3573 if (!UpdateInstr && TagStores.
size() < 2)
3577 FrameRegUpdate = TotalOffset;
3578 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3585 for (
auto &TS : TagStores)
3586 TS.MI->eraseFromParent();
3590 int64_t &
Size,
bool &ZeroData) {
3594 unsigned Opcode =
MI.getOpcode();
3595 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3596 Opcode == AArch64::STZ2Gi);
3598 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3599 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3601 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3604 Size =
MI.getOperand(2).getImm();
3608 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3610 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3615 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3619 16 *
MI.getOperand(2).getImm();
3623static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3628 return LiveRegs.available(
MRI,
Reg);
3631 size_t NumEmergencySlots = 0;
3633 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3635 return FreeGPRs + NumEmergencySlots;
3654 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3660 constexpr int kScanLimit = 10;
3663 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3672 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3673 if (ZeroData != FirstZeroData)
3681 if (!
MI.isTransient())
3690 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3706 LiveRegs.addLiveOuts(*
MBB);
3711 LiveRegs.stepBackward(*
I);
3714 if (LiveRegs.contains(AArch64::NZCV))
3725 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3726 <<
"due to high register pressure.\n");
3731 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3736 int64_t CurOffset = Instrs[0].Offset;
3737 for (
auto &Instr : Instrs) {
3738 if (CurOffset >
Instr.Offset)
3745 TagStoreEdit TSE(
MBB, FirstZeroData);
3746 std::optional<int64_t> EndOffset;
3747 for (
auto &Instr : Instrs) {
3748 if (EndOffset && *EndOffset !=
Instr.Offset) {
3750 TSE.emitCode(InsertI, TFI,
false);
3754 TSE.addInstruction(Instr);
3772 .stack_tagging_merge_settag;
3776 II = tryMergeAdjacentSTG(
II,
this, RS);
3783 shouldSignReturnAddressEverywhere(MF))
3792 bool IgnoreSPUpdates)
const {
3794 if (IgnoreSPUpdates) {
3797 FrameReg = AArch64::SP;
3807 FrameReg = AArch64::SP;
3832 bool IsValid =
false;
3834 int ObjectIndex = 0;
3836 int GroupIndex = -1;
3838 bool ObjectFirst =
false;
3841 bool GroupFirst =
false;
3846 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3850 SmallVector<int, 8> CurrentMembers;
3851 int NextGroupIndex = 0;
3852 std::vector<FrameObject> &Objects;
3855 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3856 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3857 void EndCurrentGroup() {
3858 if (CurrentMembers.
size() > 1) {
3863 for (
int Index : CurrentMembers) {
3864 Objects[
Index].GroupIndex = NextGroupIndex;
3870 CurrentMembers.clear();
3874bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3896 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3897 A.GroupIndex,
A.ObjectIndex) <
3898 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3899 B.GroupIndex,
B.ObjectIndex);
3909 ObjectsToAllocate.
empty())
3914 for (
auto &Obj : ObjectsToAllocate) {
3915 FrameObjects[Obj].IsValid =
true;
3916 FrameObjects[Obj].ObjectIndex = Obj;
3921 GroupBuilder GB(FrameObjects);
3922 for (
auto &
MBB : MF) {
3923 for (
auto &
MI :
MBB) {
3924 if (
MI.isDebugInstr())
3929 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3932 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3934 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3939 switch (
MI.getOpcode()) {
3940 case AArch64::STGloop:
3941 case AArch64::STZGloop:
3945 case AArch64::STZGi:
3946 case AArch64::ST2Gi:
3947 case AArch64::STZ2Gi:
3960 FrameObjects[FI].IsValid)
3968 GB.AddMember(TaggedFI);
3970 GB.EndCurrentGroup();
3973 GB.EndCurrentGroup();
3978 FrameObject::AccessHazard;
3980 for (
auto &Obj : FrameObjects)
3981 if (!Obj.Accesses ||
3982 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3983 Obj.Accesses = FrameObject::AccessGPR;
3992 FrameObjects[*TBPI].ObjectFirst =
true;
3993 FrameObjects[*TBPI].GroupFirst =
true;
3994 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3995 if (FirstGroupIndex >= 0)
3996 for (FrameObject &Object : FrameObjects)
3997 if (Object.GroupIndex == FirstGroupIndex)
3998 Object.GroupFirst =
true;
4004 for (
auto &Obj : FrameObjects) {
4008 ObjectsToAllocate[i++] = Obj.ObjectIndex;
4012 dbgs() <<
"Final frame order:\n";
4013 for (
auto &Obj : FrameObjects) {
4016 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
4017 if (Obj.ObjectFirst)
4018 dbgs() <<
", first";
4020 dbgs() <<
", group-first";
4031AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
4042 MF.
insert(MBBInsertPoint, LoopMBB);
4044 MF.
insert(MBBInsertPoint, ExitMBB);
4079 MBB.addSuccessor(LoopMBB);
4083 return ExitMBB->
begin();
4086void AArch64FrameLowering::inlineStackProbeFixed(
4091 const AArch64InstrInfo *
TII =
4093 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
4098 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
4099 int64_t NumBlocks = FrameSize / ProbeSize;
4100 int64_t ResidualSize = FrameSize % ProbeSize;
4102 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
4103 << NumBlocks <<
" blocks of " << ProbeSize
4104 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
4109 for (
int i = 0; i < NumBlocks; ++i) {
4115 EmitAsyncCFI && !HasFP, CFAOffset);
4128 }
else if (NumBlocks != 0) {
4134 EmitAsyncCFI && !HasFP, CFAOffset);
4136 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
4138 if (EmitAsyncCFI && !HasFP) {
4141 .buildDefCFARegister(AArch64::SP);
4145 if (ResidualSize != 0) {
4151 EmitAsyncCFI && !HasFP, CFAOffset);
4172 SmallVector<MachineInstr *, 4> ToReplace;
4173 for (MachineInstr &
MI :
MBB)
4174 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
4175 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
4178 for (MachineInstr *
MI : ToReplace) {
4179 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
4180 Register ScratchReg =
MI->getOperand(0).getReg();
4181 int64_t FrameSize =
MI->getOperand(1).getImm();
4183 MI->getOperand(3).getImm());
4184 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
4187 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
4188 "Stack probe pseudo-instruction expected");
4189 const AArch64InstrInfo *
TII =
4190 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
4191 Register TargetReg =
MI->getOperand(0).getReg();
4192 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
4194 MI->eraseFromParent();
4214 return std::make_tuple(
start(),
Idx) <
4215 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4245 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4246 if (
Offset.getScalable())
4247 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4258void AArch64FrameLowering::emitRemarks(
4261 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4269 .stack_hazard_remark_size;
4271 if (HazardSize == 0)
4279 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4281 size_t NumFPLdSt = 0;
4282 size_t NumNonFPLdSt = 0;
4285 for (
const MachineBasicBlock &
MBB : MF) {
4286 for (
const MachineInstr &
MI :
MBB) {
4287 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4289 for (MachineMemOperand *MMO :
MI.memoperands()) {
4296 StackAccesses[ArrIdx].Idx = FrameIdx;
4297 StackAccesses[ArrIdx].Offset =
4308 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4319 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4330 if (StackAccesses.front().isMixed())
4331 MixedObjects.push_back(&StackAccesses.front());
4333 for (
auto It = StackAccesses.begin(),
End = std::prev(StackAccesses.end());
4335 const auto &
First = *It;
4336 const auto &Second = *(It + 1);
4338 if (Second.isMixed())
4339 MixedObjects.push_back(&Second);
4341 if ((
First.isSME() && Second.isCPU()) ||
4342 (
First.isCPU() && Second.isSME())) {
4344 if (Distance < HazardSize)
4349 auto EmitRemark = [&](llvm::StringRef Str) {
4351 auto R = MachineOptimizationRemarkAnalysis(
4352 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4353 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4357 for (
const auto &
P : HazardPairs)
4358 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4360 for (
const auto *Obj : MixedObjects)
4362 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
MachineRegisterInfo & MRI
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.
bool authenticatesReturnAddressEarly(MachineFunction &MF, MachineBasicBlock &MBB) const
Whether the return address is authenticated before the epilogue starts, in the return block MBB,...
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)
bool hasWinCallToCalleePopFunction() const
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
static bool shouldSignReturnAddress(SignReturnAddress Condition, bool IsLRSpilled)
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 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.
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