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::STRQui:
1141 case AArch64::LDRQui: {
1142 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1143 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQ))
1149 case AArch64::STPQi:
1150 case AArch64::LDPQi: {
1151 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1152 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1153 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1160 case AArch64::LDRQpost:
1163 case AArch64::STRQpre: {
1164 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1165 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQX))
1171 case AArch64::LDPQpost:
1174 case AArch64::STPQpre: {
1175 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1176 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1177 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1196 if (ST.isTargetDarwin())
1218 DL =
MBBI->getDebugLoc();
1220 TII->createPauthEpilogueInstr(
MBB,
DL);
1224 EmitSignRA(MF.
front());
1226 if (
MBB.isEHFuncletEntry())
1228 if (
MBB.isReturnBlock())
1284 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1289 if (MFI.isVariableSizedObjectIndex(FI)) {
1299 if (MFI.hasScalableStackID(FI)) {
1300 if (FPAfterSVECalleeSaves &&
1303 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1311 AccessOffset = -PPRStackSize;
1312 return AccessOffset +
1317 bool IsFixed = MFI.isFixedObjectIndex(FI);
1322 if (!IsFixed && !IsCSR) {
1323 ScalableOffset = -SVEStackSize;
1324 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1339 int64_t ObjectOffset)
const {
1343 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1344 unsigned FixedObject =
1345 getFixedObjectSize(MF, AFI, IsWin64,
false);
1353 int64_t ObjectOffset)
const {
1364 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1365 ? getFPOffset(MF, ObjectOffset).getFixed()
1366 : getStackOffset(MF, ObjectOffset).getFixed();
1371 bool ForSimm)
const {
1373 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1374 bool isFixed = MFI.isFixedObjectIndex(FI);
1377 FrameReg, PreferFP, ForSimm);
1383 bool ForSimm)
const {
1389 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1390 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1398 const int64_t FixedObjectSize =
1399 getFixedObjectSize(MF, AFI, IsWin64,
false);
1403 bool isSVE = MFI.isScalableStackID(StackID);
1407 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1418 PreferFP &= !SVEStackSize;
1426 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1430 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1432 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1437 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1438 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1440 if (FPOffset >= 0) {
1444 }
else if (MFI.hasVarSizedObjects()) {
1448 bool CanUseBP = RegInfo->hasBasePointer(MF);
1449 if (FPOffsetFits && CanUseBP)
1456 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1463 "Funclets should only be present on Win64");
1467 if (FPOffsetFits && PreferFP)
1474 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1475 "In the presence of dynamic stack pointer realignment, "
1476 "non-argument/CSR objects cannot be accessed through the frame pointer");
1493 FPOffset -= PPRStackSize;
1495 SPOffset -= PPRStackSize;
1500 if (FPAfterSVECalleeSaves) {
1511 RegInfo->hasStackRealignment(MF))) {
1512 FrameReg = RegInfo->getFrameRegister(MF);
1515 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1522 if (FPAfterSVECalleeSaves) {
1529 SVEAreaOffset = SVECalleeSavedStack;
1531 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1534 SVEAreaOffset = SVEStackSize;
1536 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1539 if (UseFP && !(isFixed || isCSR))
1540 SVEAreaOffset = -SVEStackSize;
1541 if (!UseFP && (isFixed || isCSR))
1542 SVEAreaOffset = SVEStackSize;
1546 FrameReg = RegInfo->getFrameRegister(MF);
1551 if (RegInfo->hasBasePointer(MF))
1552 FrameReg = RegInfo->getBaseRegister();
1554 assert(!MFI.hasVarSizedObjects() &&
1555 "Can't use SP when we have var sized objects.");
1556 FrameReg = AArch64::SP;
1584 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1590 int PairOffset,
unsigned Reg1,
1591 unsigned Reg2,
bool NeedsWinCFI,
1600 if (Reg2 == AArch64::FP)
1610 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1611 return SpillExtendedVolatile
1612 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1613 (PairOffset % 16) == 0)
1618 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1619 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1629 int PairOffset,
unsigned Reg1,
1630 unsigned Reg2,
bool UsesWinAAPCS,
1631 bool NeedsWinCFI,
bool NeedsFrameRecord,
1635 Reg1, Reg2, NeedsWinCFI,
TRI);
1639 if (NeedsFrameRecord)
1640 return Reg2 == AArch64::LR;
1649 int64_t MinOff, MaxOff;
1650 TypeSize ScaleValue(0U,
false), Width(0U,
false);
1651 if (!
TII->getMemOpInfo(Opcode, ScaleValue, Width, MinOff, MaxOff))
1654 if (
Offset % ScaleValue.getKnownMinValue() != 0)
1657 Offset /= ScaleValue.getKnownMinValue();
1663struct RegGroupInfo {
1668 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1671 RegGroupInfo() =
default;
1673 bool isPaired()
const {
return getNumRegs() == 2; }
1675 bool isQuad()
const {
return getNumRegs() == 4; }
1677 bool isGrouped()
const {
return isPaired() || isQuad(); }
1679 unsigned getNumRegs()
const {
1685 unsigned NumRegs = (Reg1 - Reg2) + 1;
1686 assert(NumRegs == 2 || NumRegs == 4);
1690 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1694 return {Reg1, Reg2};
1696 assert(Reg1 - 3 == Reg2 &&
"Quad not contiguous");
1697 return {Reg1, Reg1 - 1, Reg1 - 2, Reg1 - 3};
1702 auto getFrameIndexes()
const {
1703 return seq(FrameIdx, FrameIdx +
int(getNumRegs()));
1706 Register getAsMultiVectorRegister()
const {
1707 assert(
Type == ZPR && isGrouped() &&
"Expected ZPR register group");
1708 return (isQuad() ? AArch64::Z0_Z1_Z2_Z3 : AArch64::Z0_Z1) +
1709 (Reg2 - AArch64::Z0);
1712 void dump(
const TargetRegisterInfo *
TRI)
const {
1716 dbgs() <<
") -> fi#(";
1718 [&](
int FrameIdx) {
dbgs() << FrameIdx; });
1726 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1727 if (SavedRegs.
test(PReg)) {
1728 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1738 if (Subtarget.
getCLOpts().disable_multivector_spill_fill)
1742 bool IsLocallyStreaming =
1748 return Subtarget.hasSVE2p1() ||
1749 (Subtarget.hasSME2() &&
1750 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1758 bool NeedsFrameRecord) {
1778 (
Count & 1) == 0) &&
1779 "Odd number of callee-saved regs to spill!");
1781 int StackFillDir = -1;
1783 unsigned FirstReg = 0;
1791 FirstReg =
Count - 1;
1803 bool SpillExtendedVolatile =
1805 const auto &
Reg = CSI.getReg();
1806 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1809 int ZPRByteOffset = 0;
1810 int PPRByteOffset = 0;
1815 }
else if (!FPAfterSVECalleeSaves) {
1826 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1827 if (StackFillDir < 0)
1833 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1835 RGI.Reg1 = CSI[i].getReg();
1837 if (AArch64::GPR64RegClass.
contains(RGI.Reg1)) {
1838 RGI.Type = RegGroupInfo::GPR;
1839 RGI.RC = &AArch64::GPR64RegClass;
1840 }
else if (AArch64::FPR64RegClass.
contains(RGI.Reg1)) {
1841 RGI.Type = RegGroupInfo::FPR64;
1842 RGI.RC = &AArch64::FPR64RegClass;
1843 }
else if (AArch64::FPR128RegClass.
contains(RGI.Reg1)) {
1844 RGI.Type = RegGroupInfo::FPR128;
1845 RGI.RC = &AArch64::FPR128RegClass;
1846 }
else if (AArch64::ZPRRegClass.
contains(RGI.Reg1)) {
1847 RGI.Type = RegGroupInfo::ZPR;
1848 RGI.RC = &AArch64::ZPRRegClass;
1849 }
else if (AArch64::PPRRegClass.
contains(RGI.Reg1)) {
1850 RGI.Type = RegGroupInfo::PPR;
1851 RGI.RC = &AArch64::PPRRegClass;
1852 }
else if (RGI.Reg1 == AArch64::VG) {
1853 RGI.Type = RegGroupInfo::VG;
1854 RGI.RC = &AArch64::FIXED_REGSRegClass;
1859 int &ScalableByteOffset = RGI.Type == RegGroupInfo::PPR && SplitPPRs
1864 if (HasCSHazardPadding &&
1867 ByteOffset += StackFillDir * StackHazardSize;
1870 int Scale =
TRI->getSpillSize(*RGI.RC);
1872 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1873 MCRegister NextReg = CSI[i + RegInc].getReg();
1874 int Aligned = AlignOffset(ByteOffset, Scale);
1875 int PairOffset = IsWindows ?
Aligned :
Aligned + StackFillDir * 2 * Scale;
1876 bool PairFitsImmRange =
1877 PairOffset / Scale >= -64 && PairOffset / Scale <= 63;
1879 case RegGroupInfo::GPR:
1880 case RegGroupInfo::FPR64:
1881 case RegGroupInfo::FPR128: {
1883 RGI.Type == RegGroupInfo::GPR ? AArch64::GPR64RegClass
1884 : RGI.Type == RegGroupInfo::FPR64 ? AArch64::FPR64RegClass
1885 : AArch64::FPR128RegClass;
1887 if (SpillRC.
contains(NextReg) && PairFitsImmRange &&
1889 RGI.Reg1, NextReg, IsWindows,
1890 NeedsWinCFI, NeedsFrameRecord,
TRI))
1894 case RegGroupInfo::PPR:
1896 case RegGroupInfo::ZPR: {
1908 auto GetZPRTupleLowestReg =
1909 [&](
unsigned NumRegs) -> std::optional<Register> {
1911 if (RGI.Reg1 % NumRegs != NumRegs - 1)
1912 return std::nullopt;
1915 if (i + RegInc * NumRegs >
Count)
1916 return std::nullopt;
1918 for (
unsigned Idx = 1; Idx < NumRegs; ++Idx) {
1920 Register ExpectedReg = RGI.Reg1 - Idx;
1921 if (
Reg != ExpectedReg)
1922 return std::nullopt;
1925 return RGI.Reg1 - NumRegs + 1;
1928 for (
unsigned TupleSize : {4, 2}) {
1929 if (
auto LowReg = GetZPRTupleLowestReg(TupleSize)) {
1932 TupleSize == 4 ? AArch64::LD1B_4Z_IMM : AArch64::LD1B_2Z_IMM;
1934 (ScalableByteOffset + StackFillDir * TupleSize * Scale);
1944 case RegGroupInfo::VG:
1955 [[maybe_unused]]
bool RegsOrdered =
1956 all_of(
seq(RGI.getNumRegs() - 1), [&](
int RegOffset) {
1957 return CSI[i + RegInc * RegOffset].getFrameIdx() + RegInc ==
1958 CSI[i + RegInc * RegOffset + RegInc].getFrameIdx();
1960 assert(RegsOrdered &&
"Out of order callee saved regs!");
1962 assert((!RGI.isQuad() || RGI.Type == RegGroupInfo::ZPR) &&
1963 "Currently only ZPR's support four-register spills");
1965 assert((!RGI.isPaired() || !NeedsFrameRecord || RGI.Reg2 != AArch64::FP ||
1966 RGI.Reg1 == AArch64::LR) &&
1967 "FrameRecord must be allocated together with LR");
1970 assert((!RGI.isPaired() || !NeedsFrameRecord || RGI.Reg1 != AArch64::FP ||
1971 RGI.Reg2 == AArch64::LR) &&
1972 "FrameRecord must be allocated together with LR");
1980 ((RGI.Reg1 == AArch64::LR && RGI.Reg2 == AArch64::FP) ||
1981 RGI.Reg1 + 1 == RGI.Reg2))) &&
1982 "Callee-save registers not saved as adjacent register pair!");
1984 RGI.FrameIdx = CSI[i].getFrameIdx();
1987 RGI.FrameIdx = CSI[i + RegInc * (RGI.getNumRegs() - 1)].getFrameIdx();
1991 if (RGI.isScalable() && ScalableByteOffset % Scale != 0)
1992 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1996 if (!RGI.isScalable() && ByteOffset % Scale != 0)
1997 ByteOffset = AlignOffset(ByteOffset, Scale);
1999 int OffsetPre = RGI.isScalable() ? ScalableByteOffset : ByteOffset;
2000 assert(OffsetPre % Scale == 0);
2002 if (RGI.isScalable())
2003 ScalableByteOffset += StackFillDir * RGI.getNumRegs() * Scale;
2005 ByteOffset += StackFillDir * RGI.getNumRegs() * Scale;
2010 ((!IsWindows && RGI.Reg2 == AArch64::FP) ||
2011 (IsWindows && RGI.Reg2 == AArch64::LR)))
2012 ByteOffset += StackFillDir * 8;
2016 if (NeedGapToAlignStack && !IsWindows && !RGI.isScalable() &&
2017 RGI.Type != RegGroupInfo::FPR128 && !RGI.isPaired() &&
2018 ByteOffset % 16 != 0) {
2019 ByteOffset += 8 * StackFillDir;
2025 NeedGapToAlignStack =
false;
2028 int OffsetPost = RGI.isScalable() ? ScalableByteOffset : ByteOffset;
2029 assert(OffsetPost % Scale == 0);
2032 int Offset = IsWindows ? OffsetPre : OffsetPost;
2037 ((!IsWindows && RGI.Reg2 == AArch64::FP) ||
2038 (IsWindows && RGI.Reg2 == AArch64::LR)))
2042 (!RGI.isGrouped() || RGI.Type != RegGroupInfo::ZPR ||
2044 TII, (RGI.isQuad() ? AArch64::LD1B_4Z_IMM : AArch64::LD1B_2Z_IMM),
2046 "Offset invalid for LD1B/ST1B pair/quad variant immediate");
2048 RGI.Offset =
Offset / Scale;
2049 assert((!RGI.isGrouped() || RGI.Type == RegGroupInfo::ZPR ||
2050 (!RGI.isScalable() && RGI.Offset >= -64 && RGI.Offset <= 63) ||
2051 (RGI.isScalable() && RGI.Offset >= -256 && RGI.Offset <= 255)) &&
2052 "Offset out of bounds for LDP/STP immediate");
2054 auto isFrameRecord = [&] {
2056 return IsWindows ? RGI.Reg1 == AArch64::FP && RGI.Reg2 == AArch64::LR
2057 : RGI.Reg1 == AArch64::LR && RGI.Reg2 == AArch64::FP;
2065 return i > 0 && RGI.Reg1 == AArch64::FP &&
2066 CSI[i - 1].getReg() == AArch64::LR;
2071 if (NeedsFrameRecord && isFrameRecord())
2075 i += RegInc * (RGI.getNumRegs() - 1);
2087 std::reverse(RegGroups.
begin(), RegGroups.
end());
2107 MRI.freezeReservedRegs();
2109 if (homogeneousPrologEpilog(MF)) {
2113 for (
auto &RGI : RegGroups) {
2118 if (!
MRI.isReserved(RGI.Reg1))
2119 MBB.addLiveIn(RGI.Reg1);
2120 if (RGI.isPaired() && !
MRI.isReserved(RGI.Reg2))
2121 MBB.addLiveIn(RGI.Reg2);
2125 bool PTrueCreated =
false;
2141 unsigned Size =
TRI->getSpillSize(*RGI.RC);
2142 Align Alignment =
TRI->getSpillAlign(*RGI.RC);
2144 case RegGroupInfo::GPR:
2145 StrOpc = RGI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2147 case RegGroupInfo::FPR64:
2148 StrOpc = RGI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2150 case RegGroupInfo::FPR128:
2151 StrOpc = RGI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2153 case RegGroupInfo::ZPR:
2154 StrOpc = RGI.isQuad()
2155 ? AArch64::ST1B_4Z_IMM
2156 : (RGI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI);
2158 case RegGroupInfo::PPR:
2159 StrOpc = AArch64::STR_PXI;
2161 case RegGroupInfo::VG:
2162 StrOpc = AArch64::STRXui;
2174 if (Reg1 == AArch64::VG) {
2176 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2187 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2188 AArch64::X0, LiveIn.PhysReg);
2196 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2198 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2212 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2213 "Windows unwdinding requires a consecutive (FP,LR) pair");
2218 if (!PTrueCreated && RGI.isGrouped() && RGI.isScalable()) {
2222 "Expects SVE2.1 or SME2 target and a predicate register");
2223 PTrueCreated =
true;
2230 if (!
MRI.isReserved(Reg))
2234 if (RGI.isGrouped() && RGI.isScalable()) {
2236 "Scalable register groups are not supported by Windows CFI yet");
2237#ifdef EXPENSIVE_CHECKS
2238 auto IsPPR = [](
const RegGroupInfo &c) {
2239 return c.Type == RegGroupInfo::PPR;
2241 auto PPRBegin = std::find_if(RegGroups.
begin(), RegGroups.
end(), IsPPR);
2242 auto IsZPR = [](
const RegGroupInfo &c) {
2243 return c.Type == RegGroupInfo::ZPR;
2245 auto ZPRBegin = std::find_if(RegGroups.
begin(), RegGroups.
end(), IsZPR);
2246 assert(!(PPRBegin < ZPRBegin) &&
2247 "Expected callee save predicate to be handled first");
2250 assert(RGI.Reg2 < RGI.Reg1 &&
"Expected reversed ZPR group");
2251 MIB.
addReg(RGI.getAsMultiVectorRegister());
2265 if (RGI.isPaired()) {
2284 if (RGI.Type == RegGroupInfo::ZPR)
2286 else if (RGI.Type == RegGroupInfo::PPR)
2304 DL =
MBBI->getDebugLoc();
2307 if (homogeneousPrologEpilog(MF, &
MBB)) {
2310 for (
auto &RGI : RegGroups) {
2318 auto IsPPR = [](
const RegGroupInfo &c) {
2319 return c.Type == RegGroupInfo::PPR;
2322 auto PPREnd = std::find_if_not(PPRBegin, RegGroups.
end(), IsPPR);
2323 std::reverse(PPRBegin, PPREnd);
2324 auto IsZPR = [](
const RegGroupInfo &c) {
2325 return c.Type == RegGroupInfo::ZPR;
2328 auto ZPREnd = std::find_if_not(ZPRBegin, RegGroups.
end(), IsZPR);
2329 std::reverse(ZPRBegin, ZPREnd);
2336 bool PTrueCreated =
false;
2337 for (
const RegGroupInfo &RGI : RegGroups) {
2350 unsigned Size =
TRI->getSpillSize(*RGI.RC);
2351 Align Alignment =
TRI->getSpillAlign(*RGI.RC);
2353 case RegGroupInfo::GPR:
2354 LdrOpc = RGI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2356 case RegGroupInfo::FPR64:
2357 LdrOpc = RGI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2359 case RegGroupInfo::FPR128:
2360 LdrOpc = RGI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2362 case RegGroupInfo::ZPR:
2363 LdrOpc = RGI.isQuad()
2364 ? AArch64::LD1B_4Z_IMM
2365 : (RGI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI);
2367 case RegGroupInfo::PPR:
2368 LdrOpc = AArch64::LDR_PXI;
2370 case RegGroupInfo::VG:
2380 if (!PTrueCreated && RGI.isGrouped() && RGI.isScalable()) {
2384 "Expects SVE2.1 or SME2 target and a predicate register");
2385 PTrueCreated =
true;
2390 if (KeepLR && RGI.Type == RegGroupInfo::GPR &&
2391 (Reg1 == AArch64::LR || Reg2 == AArch64::LR)) {
2395 if (!RGI.isPaired())
2397 assert(Reg2 == AArch64::LR &&
"Expected LR to be the second of the pair");
2413 if (RGI.isGrouped() && RGI.isScalable()) {
2415 "Scalable register groups are not supported by Windows CFI yet");
2416#ifdef EXPENSIVE_CHECKS
2417 assert(!(PPRBegin < ZPRBegin) &&
2418 "Expected callee save predicate to be handled first");
2420 assert(RGI.Reg2 < RGI.Reg1 &&
"Expected reversed ZPR group");
2460 return std::optional<int>(PSV->getFrameIndex());
2471 return std::nullopt;
2477 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2478 return std::nullopt;
2485 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2491void AArch64FrameLowering::determineStackHazardSlot(
2494 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2495 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2501 const AArch64Options &CLOpts =
2503 if (!CLOpts.stack_hazard_in_non_streaming &&
2504 Attrs.hasNonStreamingInterfaceAndBody())
2512 return AArch64::FPR64RegClass.contains(Reg) ||
2513 AArch64::FPR128RegClass.contains(Reg) ||
2514 AArch64::ZPRRegClass.contains(Reg);
2517 return AArch64::PPRRegClass.contains(Reg);
2519 bool HasFPRStackObjects =
false;
2520 bool HasPPRStackObjects =
false;
2521 if (!HasFPRCSRs || CLOpts.split_sve_objects) {
2522 enum SlotType : uint8_t {
2533 for (
auto &
MBB : MF) {
2534 for (
auto &
MI :
MBB) {
2536 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2543 ? SlotType::ZPRorFPR
2549 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2550 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2553 if (SlotTypes[FI] == SlotType::PPR) {
2555 HasPPRStackObjects =
true;
2560 if (HasFPRCSRs || HasFPRStackObjects) {
2563 << StackHazardSize <<
"\n");
2570 if (CLOpts.split_sve_objects) {
2574 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2580 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2581 "non-SVE CC function...\n");
2588 <<
"Calling convention is not supported with SplitSVEObjects\n");
2592 if (!HasPPRCSRs && !HasPPRStackObjects) {
2594 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2598 if (!HasFPRCSRs && !HasFPRStackObjects) {
2601 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2605 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2606 MF.getSubtarget<AArch64Subtarget>();
2608 "Expected SVE to be available for PPRs");
2610 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2614 BitVector FPRZRegs(SavedRegs.
size());
2615 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2616 BitVector::reference RegBit = SavedRegs[
Reg];
2619 unsigned SubRegIdx = 0;
2621 SubRegIdx = AArch64::dsub;
2623 SubRegIdx = AArch64::zsub;
2630 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2633 SavedRegs |= FPRZRegs;
2663 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2666 bool HasUnpairedGPR64 =
false;
2667 bool HasPairZReg =
false;
2668 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2669 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2672 for (
unsigned i = 0; CSRegs[i]; ++i) {
2676 if (Reg == BasePointerReg)
2681 if (UserReservedRegs[Reg]) {
2682 SavedRegs.
reset(Reg);
2686 bool RegUsed = SavedRegs.
test(Reg);
2688 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2689 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2690 AArch64::FPR128RegClass.
contains(Reg)) {
2693 if (HasUnpairedGPR64)
2694 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2696 PairedReg = CSRegs[i ^ 1];
2703 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2705 HasUnpairedGPR64 =
true;
2708 AArch64::GPR64RegClass.contains(Reg, PairedReg) ||
2709 AArch64::FPR64RegClass.contains(Reg, PairedReg) ||
2710 AArch64::FPR128RegClass.contains(Reg, PairedReg));
2713 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2714 UnspilledCSGPR = Reg;
2715 UnspilledCSGPRPaired = PairedReg;
2723 if (producePairRegisters(MF) && PairedReg.
isValid() &&
2724 !SavedRegs.
test(PairedReg)) {
2725 SavedRegs.
set(PairedReg);
2726 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2727 !ReservedRegs[PairedReg])
2728 ExtraCSSpill = PairedReg;
2731 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2732 SavedRegs.
test(CSRegs[i ^ 1]));
2740 if (PnReg.isValid())
2746 SavedRegs.
set(AArch64::P8);
2751 "Predicate cannot be a reserved register");
2761 SavedRegs.
set(AArch64::X18);
2767 determineStackHazardSlot(MF, SavedRegs);
2770 unsigned CSStackSize = 0;
2771 unsigned ZPRCSStackSize = 0;
2772 unsigned PPRCSStackSize = 0;
2774 for (
unsigned Reg : SavedRegs.
set_bits()) {
2776 assert(RC &&
"expected register class!");
2777 auto SpillSize =
TRI->getSpillSize(*RC);
2778 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2779 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2781 ZPRCSStackSize += SpillSize;
2783 PPRCSStackSize += SpillSize;
2789 return SavedRegs.test(SuperReg);
2792 CSStackSize += SpillSize;
2799 unsigned NumSavedRegs = SavedRegs.
count();
2812 SavedRegs.
set(AArch64::LR);
2817 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2818 SavedRegs.
set(AArch64::FP);
2819 SavedRegs.
set(AArch64::LR);
2823 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2824 for (
unsigned Reg : SavedRegs.
set_bits())
2830 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2832 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2833 uint64_t SVEStackSize =
2834 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2835 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2844 int64_t CalleeStackUsed = 0;
2847 if (FixedOff > CalleeStackUsed)
2848 CalleeStackUsed = FixedOff;
2852 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2853 CalleeStackUsed) > EstimatedStackSizeLimit;
2854 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2866 <<
" to get a scratch register.\n");
2867 SavedRegs.
set(UnspilledCSGPR);
2868 ExtraCSSpill = UnspilledCSGPR;
2873 if (producePairRegisters(MF)) {
2874 if (!UnspilledCSGPRPaired.
isValid()) {
2877 SavedRegs.
reset(UnspilledCSGPR);
2881 SavedRegs.
set(UnspilledCSGPRPaired);
2887 if (!ExtraCSSpill.
isValid() ||
2891 unsigned Size =
TRI->getSpillSize(RC);
2892 Align Alignment =
TRI->getSpillAlign(RC);
2894 RS->addScavengingFrameIndex(FI);
2895 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2896 <<
" as the emergency spill slot.\n");
2901 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2908 uint64_t AlignedCSStackSize =
alignTo(CSStackSize, 16);
2910 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2914 "Should not invalidate callee saved info");
2931 std::vector<CalleeSavedInfo> &CSI) {
2933 "ZPR callee-save reordering not supported on Windows");
2940 return AArch64::ZPRRegClass.contains(CS.getReg());
2944 ZPRSaves = ZPRSaves.
drop_until(IsZPR).take_while(IsZPR);
2946 if (ZPRSaves.
size() < 2)
2953 const int Scale =
RegInfo->getSpillSize(AArch64::ZPRRegClass);
2954 const int LowestOffset =
2955 (ZPRByteOffset / Scale) -
static_cast<int>(ZPRSaves.
size());
2957 int NumToAlign =
alignTo(LowestOffset, 4) - LowestOffset;
2958 if (NumToAlign >
int(ZPRSaves.
size()))
2962 [](
const auto &
A,
const auto &
B) {
return A.getReg() <
B.getReg(); });
2968 int ZPRsNeededForAlignment = NumToAlign;
2969 for (
size_t i = 0; i < ZPRSaves.
size();) {
2970 int ZPRsRemaining = int(ZPRSaves.
size()) - i;
2971 if (i + 3 < ZPRSaves.
size() &&
2972 (ZPRSaves[i].getReg() - AArch64::Z0) % 4 == 0 &&
2973 ZPRSaves[i].getReg() + 3 == ZPRSaves[i + 3].getReg() &&
2974 ZPRsRemaining - 4 >= ZPRsNeededForAlignment) {
2976 {ZPRSaves[i], ZPRSaves[i + 1], ZPRSaves[i + 2], ZPRSaves[i + 3]});
2983 bool MustSplitPairForSingle =
2984 ZPRsNeededForAlignment == 1 && Singles.empty() && ZPRsRemaining == 2;
2986 if (i + 1 < ZPRSaves.
size() &&
2987 (ZPRSaves[i].getReg() - AArch64::Z0) % 2 == 0 &&
2988 ZPRSaves[i].getReg() + 1 == ZPRSaves[i + 1].getReg() &&
2989 !MustSplitPairForSingle) {
2990 Pairs.
push_back({ZPRSaves[i], ZPRSaves[i + 1]});
2993 if (ZPRsNeededForAlignment != 1 || !Singles.empty())
2994 ZPRsNeededForAlignment -= 2;
3000 Singles.push_back(ZPRSaves[i++]);
3001 ZPRsNeededForAlignment--;
3007 int NumUnassigned = ZPRSaves.
size();
3013 ZPRSaves[--NumUnassigned] = CS;
3017 if (NumToAlign & 0b01)
3018 Emit(Singles.pop_back_val());
3019 if (NumToAlign & 0b10) {
3023 Emit({Singles.pop_back_val(), Singles.pop_back_val()});
3026 for (
const auto &Quad : Quads)
3029 for (
const auto &Pair : Pairs)
3032 for (
const auto &
Single : Singles)
3038 std::vector<CalleeSavedInfo> &CSI)
const {
3047 std::reverse(CSI.begin(), CSI.end());
3061 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
3062 if (It != CSI.end())
3063 CSI.insert(It, VGInfo);
3065 CSI.push_back(VGInfo);
3075 int HazardSlotIndex = std::numeric_limits<int>::max();
3076 for (
auto &CS : CSI) {
3084 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
3085 "Unexpected register order for hazard slot");
3087 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3093 unsigned Size = RegInfo->getSpillSize(*RC);
3094 Align Alignment(RegInfo->getSpillAlign(*RC));
3096 CS.setFrameIdx(FrameIdx);
3110 HazardSlotIndex == std::numeric_limits<int>::max()) {
3112 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3139 int &Min,
int &Max) {
3140 Min = std::numeric_limits<int>::max();
3141 Max = std::numeric_limits<int>::min();
3147 for (
auto &CS : CSI) {
3148 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
3149 AArch64::PPRRegClass.contains(CS.getReg())) {
3150 assert((Max == std::numeric_limits<int>::min() ||
3151 Max + 1 == CS.getFrameIdx()) &&
3152 "SVE CalleeSaves are not consecutive");
3153 Min = std::min(Min, CS.getFrameIdx());
3154 Max = std::max(Max, CS.getFrameIdx());
3157 return Min != std::numeric_limits<int>::max();
3170 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
3178 "SVE vectors should never be passed on the stack by value, only by "
3182 auto AllocateObject = [&](
int FI) {
3191 if (Alignment >
Align(16))
3193 "Alignment of scalable vectors > 16 bytes is not yet supported");
3196 StackTop =
alignTo(StackTop, Alignment);
3198 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
3199 "SVE StackTop far too large?!");
3201 int64_t
Offset = -int64_t(StackTop);
3209 int MinCSFrameIndex, MaxCSFrameIndex;
3211 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
3224 int StackProtectorFI = -1;
3228 ObjectsToAllocate.
push_back(StackProtectorFI);
3244 for (
unsigned FI : ObjectsToAllocate)
3259 "Upwards growing stack unsupported");
3274 int64_t CurrentOffset =
3278 int FrameIndex =
H.CatchObj.FrameIndex;
3279 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3290 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3291 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3293 "UnwindHelpOffset must be at the start of the fixed object area");
3296 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3306 RS->enterBasicBlockEnd(
MBB);
3308 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3309 assert(DstReg &&
"There must be a free register after frame setup");
3320struct TagStoreInstr {
3329 MachineBasicBlock *
MBB;
3330 MachineRegisterInfo *
MRI;
3339 StackOffset FrameRegOffset;
3343 std::optional<int64_t> FrameRegUpdate;
3345 unsigned FrameRegUpdateFlags;
3355 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3356 :
MBB(
MBB), ZeroData(ZeroData) {
3362 void addInstruction(TagStoreInstr
I) {
3364 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3365 "Non-adjacent tag store instructions.");
3368 void clear() { TagStores.
clear(); }
3373 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3380 const int64_t kMinOffset = -256 * 16;
3381 const int64_t kMaxOffset = 255 * 16;
3384 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3385 if (BaseRegOffsetBytes < kMinOffset ||
3386 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3390 BaseRegOffsetBytes % 16 != 0) {
3395 BaseRegOffsetBytes = 0;
3400 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3403 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3405 assert(BaseRegOffsetBytes % 16 == 0);
3409 .
addImm(BaseRegOffsetBytes / 16)
3413 if (BaseRegOffsetBytes == 0)
3415 BaseRegOffsetBytes += InstrSize;
3434 int64_t LoopSize =
Size;
3437 if (FrameRegUpdate && *FrameRegUpdate)
3438 LoopSize -= LoopSize % 32;
3440 TII->get(ZeroData ? AArch64::STZGloop_wback
3441 : AArch64::STGloop_wback))
3448 LoopI->
setFlags(FrameRegUpdateFlags);
3450 int64_t ExtraBaseRegUpdate =
3451 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3452 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3453 <<
", Size=" <<
Size
3454 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3455 <<
", FrameRegUpdate=" << FrameRegUpdate
3456 <<
", FrameRegOffset.getFixed()="
3457 << FrameRegOffset.
getFixed() <<
"\n");
3458 if (LoopSize <
Size) {
3462 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3463 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3464 "STG immediate out of range");
3466 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3473 }
else if (ExtraBaseRegUpdate) {
3475 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3476 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3479 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3492 int64_t
Size, int64_t *TotalOffset) {
3494 if ((
MI.getOpcode() == AArch64::ADDXri ||
3495 MI.getOpcode() == AArch64::SUBXri) &&
3496 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3498 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3499 if (
MI.getOpcode() == AArch64::SUBXri)
3510 const int64_t kMaxOffset = 4080 - 16;
3512 const int64_t kMinOffset = -4095;
3513 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3514 PostOffset % 16 == 0) {
3525 for (
auto &TS : TSE) {
3529 if (
MI->memoperands_empty()) {
3533 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3539 bool TryMergeSPUpdate) {
3540 if (TagStores.
empty())
3542 TagStoreInstr &FirstTagStore = TagStores[0];
3543 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3544 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3545 DL = TagStores[0].MI->getDebugLoc();
3549 *MF, FirstTagStore.Offset,
false ,
3553 FrameRegUpdate = std::nullopt;
3555 mergeMemRefs(TagStores, CombinedMemRefs);
3558 dbgs() <<
"Replacing adjacent STG instructions:\n";
3559 for (
const auto &Instr : TagStores) {
3568 if (TagStores.
size() < 2)
3570 emitUnrolled(InsertI);
3573 int64_t TotalOffset = 0;
3574 if (TryMergeSPUpdate) {
3580 if (InsertI !=
MBB->
end() &&
3581 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3583 UpdateInstr = &*InsertI++;
3589 if (!UpdateInstr && TagStores.
size() < 2)
3593 FrameRegUpdate = TotalOffset;
3594 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3601 for (
auto &TS : TagStores)
3602 TS.MI->eraseFromParent();
3606 int64_t &
Size,
bool &ZeroData) {
3610 unsigned Opcode =
MI.getOpcode();
3611 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3612 Opcode == AArch64::STZ2Gi);
3614 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3615 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3617 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3620 Size =
MI.getOperand(2).getImm();
3624 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3626 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3631 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3635 16 *
MI.getOperand(2).getImm();
3639static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3644 return LiveRegs.available(
MRI,
Reg);
3647 size_t NumEmergencySlots = 0;
3649 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3651 return FreeGPRs + NumEmergencySlots;
3670 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3676 constexpr int kScanLimit = 10;
3679 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3688 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3689 if (ZeroData != FirstZeroData)
3697 if (!
MI.isTransient())
3706 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3722 LiveRegs.addLiveOuts(*
MBB);
3727 LiveRegs.stepBackward(*
I);
3730 if (LiveRegs.contains(AArch64::NZCV))
3741 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3742 <<
"due to high register pressure.\n");
3747 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3752 int64_t CurOffset = Instrs[0].Offset;
3753 for (
auto &Instr : Instrs) {
3754 if (CurOffset >
Instr.Offset)
3761 TagStoreEdit TSE(
MBB, FirstZeroData);
3762 std::optional<int64_t> EndOffset;
3763 for (
auto &Instr : Instrs) {
3764 if (EndOffset && *EndOffset !=
Instr.Offset) {
3766 TSE.emitCode(InsertI, TFI,
false);
3770 TSE.addInstruction(Instr);
3788 .stack_tagging_merge_settag;
3792 II = tryMergeAdjacentSTG(
II,
this, RS);
3799 shouldSignReturnAddressEverywhere(MF))
3808 bool IgnoreSPUpdates)
const {
3810 if (IgnoreSPUpdates) {
3813 FrameReg = AArch64::SP;
3823 FrameReg = AArch64::SP;
3848 bool IsValid =
false;
3850 int ObjectIndex = 0;
3852 int GroupIndex = -1;
3854 bool ObjectFirst =
false;
3857 bool GroupFirst =
false;
3862 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3866 SmallVector<int, 8> CurrentMembers;
3867 int NextGroupIndex = 0;
3868 std::vector<FrameObject> &Objects;
3871 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3872 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3873 void EndCurrentGroup() {
3874 if (CurrentMembers.
size() > 1) {
3879 for (
int Index : CurrentMembers) {
3880 Objects[
Index].GroupIndex = NextGroupIndex;
3886 CurrentMembers.clear();
3890bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3912 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3913 A.GroupIndex,
A.ObjectIndex) <
3914 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3915 B.GroupIndex,
B.ObjectIndex);
3925 ObjectsToAllocate.
empty())
3930 for (
auto &Obj : ObjectsToAllocate) {
3931 FrameObjects[Obj].IsValid =
true;
3932 FrameObjects[Obj].ObjectIndex = Obj;
3937 GroupBuilder GB(FrameObjects);
3938 for (
auto &
MBB : MF) {
3939 for (
auto &
MI :
MBB) {
3940 if (
MI.isDebugInstr())
3945 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3948 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3950 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3955 switch (
MI.getOpcode()) {
3956 case AArch64::STGloop:
3957 case AArch64::STZGloop:
3961 case AArch64::STZGi:
3962 case AArch64::ST2Gi:
3963 case AArch64::STZ2Gi:
3976 FrameObjects[FI].IsValid)
3984 GB.AddMember(TaggedFI);
3986 GB.EndCurrentGroup();
3989 GB.EndCurrentGroup();
3994 FrameObject::AccessHazard;
3996 for (
auto &Obj : FrameObjects)
3997 if (!Obj.Accesses ||
3998 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3999 Obj.Accesses = FrameObject::AccessGPR;
4008 FrameObjects[*TBPI].ObjectFirst =
true;
4009 FrameObjects[*TBPI].GroupFirst =
true;
4010 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
4011 if (FirstGroupIndex >= 0)
4012 for (FrameObject &Object : FrameObjects)
4013 if (Object.GroupIndex == FirstGroupIndex)
4014 Object.GroupFirst =
true;
4020 for (
auto &Obj : FrameObjects) {
4024 ObjectsToAllocate[i++] = Obj.ObjectIndex;
4028 dbgs() <<
"Final frame order:\n";
4029 for (
auto &Obj : FrameObjects) {
4032 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
4033 if (Obj.ObjectFirst)
4034 dbgs() <<
", first";
4036 dbgs() <<
", group-first";
4047AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
4058 MF.
insert(MBBInsertPoint, LoopMBB);
4060 MF.
insert(MBBInsertPoint, ExitMBB);
4095 MBB.addSuccessor(LoopMBB);
4099 return ExitMBB->
begin();
4102void AArch64FrameLowering::inlineStackProbeFixed(
4107 const AArch64InstrInfo *
TII =
4109 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
4114 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
4115 int64_t NumBlocks = FrameSize / ProbeSize;
4116 int64_t ResidualSize = FrameSize % ProbeSize;
4118 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
4119 << NumBlocks <<
" blocks of " << ProbeSize
4120 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
4125 for (
int i = 0; i < NumBlocks; ++i) {
4131 EmitAsyncCFI && !HasFP, CFAOffset);
4144 }
else if (NumBlocks != 0) {
4150 EmitAsyncCFI && !HasFP, CFAOffset);
4152 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
4154 if (EmitAsyncCFI && !HasFP) {
4157 .buildDefCFARegister(AArch64::SP);
4161 if (ResidualSize != 0) {
4167 EmitAsyncCFI && !HasFP, CFAOffset);
4188 SmallVector<MachineInstr *, 4> ToReplace;
4189 for (MachineInstr &
MI :
MBB)
4190 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
4191 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
4194 for (MachineInstr *
MI : ToReplace) {
4195 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
4196 Register ScratchReg =
MI->getOperand(0).getReg();
4197 int64_t FrameSize =
MI->getOperand(1).getImm();
4199 MI->getOperand(3).getImm());
4200 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
4203 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
4204 "Stack probe pseudo-instruction expected");
4205 const AArch64InstrInfo *
TII =
4206 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
4207 Register TargetReg =
MI->getOperand(0).getReg();
4208 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
4210 MI->eraseFromParent();
4230 return std::make_tuple(
start(),
Idx) <
4231 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4261 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4262 if (
Offset.getScalable())
4263 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4274void AArch64FrameLowering::emitRemarks(
4277 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4285 .stack_hazard_remark_size;
4287 if (HazardSize == 0)
4295 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4297 size_t NumFPLdSt = 0;
4298 size_t NumNonFPLdSt = 0;
4301 for (
const MachineBasicBlock &
MBB : MF) {
4302 for (
const MachineInstr &
MI :
MBB) {
4303 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4305 for (MachineMemOperand *MMO :
MI.memoperands()) {
4312 StackAccesses[ArrIdx].Idx = FrameIdx;
4313 StackAccesses[ArrIdx].Offset =
4324 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4335 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4346 if (StackAccesses.front().isMixed())
4347 MixedObjects.push_back(&StackAccesses.front());
4349 for (
auto It = StackAccesses.begin(),
End = std::prev(StackAccesses.end());
4351 const auto &
First = *It;
4352 const auto &Second = *(It + 1);
4354 if (Second.isMixed())
4355 MixedObjects.push_back(&Second);
4357 if ((
First.isSME() && Second.isCPU()) ||
4358 (
First.isCPU() && Second.isSME())) {
4360 if (Distance < HazardSize)
4365 auto EmitRemark = [&](llvm::StringRef Str) {
4367 auto R = MachineOptimizationRemarkAnalysis(
4368 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4369 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4373 for (
const auto &
P : HazardPairs)
4374 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4376 for (
const auto *Obj : MixedObjects)
4378 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)
static bool invalidateWindowsRegisterPairing(bool SpillExtendedVolatile, int PairOffset, unsigned Reg1, unsigned Reg2, bool NeedsWinCFI, const TargetRegisterInfo *TRI)
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, int PairOffset, 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 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...
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
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