266#define DEBUG_TYPE "frame-info"
273 bool IsTailCallReturn = (
MBB.end() !=
MBBI)
277 int64_t ArgumentPopSize = 0;
278 if (IsTailCallReturn) {
284 ArgumentPopSize = StackAdjust.
getImm();
293 return ArgumentPopSize;
336 if (AFI->hasCalculatedStackSizeSVE())
366bool AArch64FrameLowering::homogeneousPrologEpilog(
370 const AArch64Options &CLOpts =
372 if (!CLOpts.homogeneous_prolog_epilog)
394 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
401 unsigned NumGPRs = 0;
402 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
404 if (Reg == AArch64::LR) {
405 assert(CSRegs[
I + 1] == AArch64::FP);
406 if (NumGPRs % 2 != 0)
418bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
437 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
438 MI.getOpcode() == AArch64::ADDXri ||
439 MI.getOpcode() == AArch64::ADDSXri)
464 bool IsWin64,
bool IsFunclet)
const {
466 "Tail call reserved stack must be aligned to 16 bytes");
467 if (!IsWin64 || IsFunclet) {
472 Attribute::SwiftAsync))
486 int FrameIndex =
H.CatchObj.FrameIndex;
487 if ((FrameIndex != INT_MAX) &&
488 CatchObjFrameIndices.
insert(FrameIndex)) {
489 FixedObjectSize =
alignTo(FixedObjectSize,
496 FixedObjectSize += 8;
498 return alignTo(FixedObjectSize, 16);
509 const unsigned RedZoneSize =
522 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
526 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
548 if (Subtarget.getTargetLowering()->useStackGuardMixFP())
557 RegInfo->hasStackRealignment(MF))
603 if (TT.isOSDarwin() || TT.isOSWindows())
641 unsigned Opc =
I->getOpcode();
642 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
643 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
646 int64_t Amount =
I->getOperand(0).getImm();
654 if (CalleePopAmount == 0) {
665 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
676 "non-reserved call frame without var sized objects?");
685 }
else if (CalleePopAmount != 0) {
688 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
700 const auto &
TRI = *Subtarget.getRegisterInfo();
706 CFIBuilder.buildDefCFA(AArch64::SP, 0);
709 if (MFI.shouldSignReturnAddress(MF)) {
710 if (MFI.branchProtectionPAuthLR()) {
711 CFIBuilder.buildNegateRAStateWithPC();
713 CFIBuilder.buildNegateRAState();
718 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
719 CFIBuilder.buildSameValue(AArch64::X18);
722 const std::vector<CalleeSavedInfo> &CSI =
724 for (
const auto &Info : CSI) {
726 if (!
TRI.regNeedsCFI(Reg, Reg))
728 CFIBuilder.buildSameValue(Reg);
741 case AArch64::W##n: \
742 case AArch64::X##n: \
767 case AArch64::B##n: \
768 case AArch64::H##n: \
769 case AArch64::S##n: \
770 case AArch64::D##n: \
771 case AArch64::Q##n: \
772 return HasSVE ? AArch64::Z##n : AArch64::Q##n
809void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
821 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
824 BitVector GPRsToZero(
TRI.getNumRegs());
825 BitVector FPRsToZero(
TRI.getNumRegs());
829 bool HasFPR = STI.hasFPARMv8();
831 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
834 GPRsToZero.set(XReg);
838 FPRsToZero.set(XReg);
845 for (MCRegister
Reg : GPRsToZero.set_bits())
849 for (MCRegister
Reg : FPRsToZero.set_bits())
853 for (MCRegister PReg :
854 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
855 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
856 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
858 if (RegsToZero[PReg])
864bool AArch64FrameLowering::windowsRequiresStackProbe(
866 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
867 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
871 StackSizeInBytes >=
uint64_t(MFI.getStackProbeSize());
880 for (
unsigned i = 0; CSRegs[i]; ++i)
886 bool HasCall)
const {
896 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
898 LivePhysRegs LiveRegs(
TRI);
901 LiveRegs.addReg(AArch64::X16);
902 LiveRegs.addReg(AArch64::X17);
903 LiveRegs.addReg(AArch64::X18);
907 const MachineRegisterInfo &MRI = MF->
getRegInfo();
908 if (LiveRegs.available(MRI, AArch64::X9))
911 for (
unsigned Reg : AArch64::GPR64RegClass) {
912 if (LiveRegs.available(MRI,
Reg))
934 if (!
LiveRegs.available(MRI, AArch64::X16) ||
935 !
LiveRegs.available(MRI, AArch64::X17))
942 MBB.isLiveIn(AArch64::NZCV))
946 if (!findScratchNonCalleeSaveRegister(TmpMBB).
isValid())
952 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
953 if (!findScratchNonCalleeSaveRegister(TmpMBB,
true).
isValid())
959bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
975 unsigned Opc =
MBBI->getOpcode();
979 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
980 int Imm =
MBBI->getOperand(ImmIdx).getImm();
988 case AArch64::STR_ZXI:
989 case AArch64::LDR_ZXI: {
990 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
997 case AArch64::STR_PXI:
998 case AArch64::LDR_PXI: {
999 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1006 case AArch64::LDPDpost:
1009 case AArch64::STPDpre: {
1010 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1011 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1012 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1019 case AArch64::LDPXpost:
1022 case AArch64::STPXpre: {
1025 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1026 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1030 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1031 .
addImm(RegInfo->getSEHRegNum(Reg0))
1032 .
addImm(RegInfo->getSEHRegNum(Reg1))
1037 case AArch64::LDRDpost:
1040 case AArch64::STRDpre: {
1041 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1042 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1048 case AArch64::LDRXpost:
1051 case AArch64::STRXpre: {
1052 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1059 case AArch64::STPDi:
1060 case AArch64::LDPDi: {
1061 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1062 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1070 case AArch64::STPXi:
1071 case AArch64::LDPXi: {
1075 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1076 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1078 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1082 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1089 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1096 case AArch64::STRXui:
1097 case AArch64::LDRXui: {
1098 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1105 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1111 case AArch64::STRDui:
1112 case AArch64::LDRDui: {
1113 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1120 case AArch64::STPQi:
1121 case AArch64::LDPQi: {
1122 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1123 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1124 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1131 case AArch64::LDPQpost:
1134 case AArch64::STPQpre: {
1135 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1136 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1137 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1156 if (ST.isTargetDarwin())
1178 DL =
MBBI->getDebugLoc();
1180 TII->createPauthEpilogueInstr(
MBB,
DL);
1184 EmitSignRA(MF.
front());
1186 if (
MBB.isEHFuncletEntry())
1188 if (
MBB.isReturnBlock())
1244 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1249 if (MFI.isVariableSizedObjectIndex(FI)) {
1259 if (MFI.hasScalableStackID(FI)) {
1260 if (FPAfterSVECalleeSaves &&
1263 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1271 AccessOffset = -PPRStackSize;
1272 return AccessOffset +
1277 bool IsFixed = MFI.isFixedObjectIndex(FI);
1282 if (!IsFixed && !IsCSR) {
1283 ScalableOffset = -SVEStackSize;
1284 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1299 int64_t ObjectOffset)
const {
1303 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1304 unsigned FixedObject =
1305 getFixedObjectSize(MF, AFI, IsWin64,
false);
1313 int64_t ObjectOffset)
const {
1324 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1325 ? getFPOffset(MF, ObjectOffset).getFixed()
1326 : getStackOffset(MF, ObjectOffset).getFixed();
1331 bool ForSimm)
const {
1333 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1334 bool isFixed = MFI.isFixedObjectIndex(FI);
1337 FrameReg, PreferFP, ForSimm);
1343 bool ForSimm)
const {
1349 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1350 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1358 const int64_t FixedObjectSize =
1359 getFixedObjectSize(MF, AFI, IsWin64,
false);
1363 bool isSVE = MFI.isScalableStackID(StackID);
1367 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1378 PreferFP &= !SVEStackSize;
1386 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1390 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1392 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1397 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1398 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1400 if (FPOffset >= 0) {
1404 }
else if (MFI.hasVarSizedObjects()) {
1408 bool CanUseBP = RegInfo->hasBasePointer(MF);
1409 if (FPOffsetFits && CanUseBP)
1416 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1423 "Funclets should only be present on Win64");
1427 if (FPOffsetFits && PreferFP)
1434 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1435 "In the presence of dynamic stack pointer realignment, "
1436 "non-argument/CSR objects cannot be accessed through the frame pointer");
1453 FPOffset -= PPRStackSize;
1455 SPOffset -= PPRStackSize;
1460 if (FPAfterSVECalleeSaves) {
1471 RegInfo->hasStackRealignment(MF))) {
1472 FrameReg = RegInfo->getFrameRegister(MF);
1475 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1482 if (FPAfterSVECalleeSaves) {
1489 SVEAreaOffset = SVECalleeSavedStack;
1491 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1494 SVEAreaOffset = SVEStackSize;
1496 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1499 if (UseFP && !(isFixed || isCSR))
1500 SVEAreaOffset = -SVEStackSize;
1501 if (!UseFP && (isFixed || isCSR))
1502 SVEAreaOffset = SVEStackSize;
1506 FrameReg = RegInfo->getFrameRegister(MF);
1511 if (RegInfo->hasBasePointer(MF))
1512 FrameReg = RegInfo->getBaseRegister();
1514 assert(!MFI.hasVarSizedObjects() &&
1515 "Can't use SP when we have var sized objects.");
1516 FrameReg = AArch64::SP;
1544 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1550 unsigned SpillCount,
unsigned Reg1,
1551 unsigned Reg2,
bool NeedsWinCFI,
1560 if (Reg2 == AArch64::FP)
1570 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1571 return SpillExtendedVolatile
1572 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1573 (SpillCount % 2) == 0)
1578 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1579 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1589 unsigned SpillCount,
unsigned Reg1,
1590 unsigned Reg2,
bool UsesWinAAPCS,
1591 bool NeedsWinCFI,
bool NeedsFrameRecord,
1595 Reg1, Reg2, NeedsWinCFI,
TRI);
1599 if (NeedsFrameRecord)
1600 return Reg2 == AArch64::LR;
1609 int64_t MinOff, MaxOff;
1610 TypeSize ScaleValue(0U,
false), Width(0U,
false);
1611 if (!
TII->getMemOpInfo(Opcode, ScaleValue, Width, MinOff, MaxOff))
1614 if (
Offset % ScaleValue.getKnownMinValue() != 0)
1617 Offset /= ScaleValue.getKnownMinValue();
1628 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1631 RegPairInfo() =
default;
1633 bool isPaired()
const {
return Reg2.
isValid(); }
1635 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1641 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1642 if (SavedRegs.
test(PReg)) {
1643 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1653 if (Subtarget.
getCLOpts().disable_multivector_spill_fill)
1657 bool IsLocallyStreaming =
1663 return Subtarget.hasSVE2p1() ||
1664 (Subtarget.hasSME2() &&
1665 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1673 bool NeedsFrameRecord) {
1693 (
Count & 1) == 0) &&
1694 "Odd number of callee-saved regs to spill!");
1696 int StackFillDir = -1;
1698 unsigned FirstReg = 0;
1706 FirstReg =
Count - 1;
1718 bool SpillExtendedVolatile =
1720 const auto &
Reg = CSI.getReg();
1721 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1724 int ZPRByteOffset = 0;
1725 int PPRByteOffset = 0;
1730 }
else if (!FPAfterSVECalleeSaves) {
1741 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1742 if (StackFillDir < 0)
1748 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1750 RPI.Reg1 = CSI[i].getReg();
1752 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1753 RPI.Type = RegPairInfo::GPR;
1754 RPI.RC = &AArch64::GPR64RegClass;
1755 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1756 RPI.Type = RegPairInfo::FPR64;
1757 RPI.RC = &AArch64::FPR64RegClass;
1758 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1759 RPI.Type = RegPairInfo::FPR128;
1760 RPI.RC = &AArch64::FPR128RegClass;
1761 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1762 RPI.Type = RegPairInfo::ZPR;
1763 RPI.RC = &AArch64::ZPRRegClass;
1764 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1765 RPI.Type = RegPairInfo::PPR;
1766 RPI.RC = &AArch64::PPRRegClass;
1767 }
else if (RPI.Reg1 == AArch64::VG) {
1768 RPI.Type = RegPairInfo::VG;
1769 RPI.RC = &AArch64::FIXED_REGSRegClass;
1774 int &ScalableByteOffset = RPI.Type == RegPairInfo::PPR && SplitPPRs
1779 if (HasCSHazardPadding &&
1782 ByteOffset += StackFillDir * StackHazardSize;
1785 int Scale =
TRI->getSpillSize(*RPI.RC);
1787 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1788 MCRegister NextReg = CSI[i + RegInc].getReg();
1789 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1790 int Aligned = AlignOffset(ByteOffset, Scale);
1791 int PairOffset = IsWindows ?
Aligned :
Aligned + StackFillDir * 2 * Scale;
1792 bool PairFitsImmRange =
1793 PairOffset / Scale >= -64 && PairOffset / Scale <= 63;
1795 case RegPairInfo::GPR:
1796 if (AArch64::GPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1798 RPI.Reg1, NextReg, IsWindows,
1799 NeedsWinCFI, NeedsFrameRecord,
TRI))
1802 case RegPairInfo::FPR64:
1803 if (AArch64::FPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1805 RPI.Reg1, NextReg, IsWindows,
1806 NeedsWinCFI, NeedsFrameRecord,
TRI))
1809 case RegPairInfo::FPR128:
1810 if (AArch64::FPR128RegClass.
contains(NextReg) && PairFitsImmRange)
1813 case RegPairInfo::PPR:
1815 case RegPairInfo::ZPR:
1825 if (((NextReg - AArch64::Z0) % 2 == 0) && (NextReg + 1 == RPI.Reg1)) {
1826 const int NumRegs = 2;
1827 int Offset = (ScalableByteOffset + StackFillDir * NumRegs * Scale);
1834 case RegPairInfo::VG:
1845 assert((!RPI.isPaired() ||
1846 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1847 "Out of order callee saved regs!");
1849 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1850 RPI.Reg1 == AArch64::LR) &&
1851 "FrameRecord must be allocated together with LR");
1854 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1855 RPI.Reg2 == AArch64::LR) &&
1856 "FrameRecord must be allocated together with LR");
1864 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1865 RPI.Reg1 + 1 == RPI.Reg2))) &&
1866 "Callee-save registers not saved as adjacent register pair!");
1868 RPI.FrameIdx = CSI[i].getFrameIdx();
1871 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1875 if (RPI.isScalable() && ScalableByteOffset % Scale != 0)
1876 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1880 if (!RPI.isScalable() && ByteOffset % Scale != 0)
1881 ByteOffset = AlignOffset(ByteOffset, Scale);
1883 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1884 assert(OffsetPre % Scale == 0);
1886 if (RPI.isScalable())
1887 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1889 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1894 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1895 (IsWindows && RPI.Reg2 == AArch64::LR)))
1896 ByteOffset += StackFillDir * 8;
1900 if (NeedGapToAlignStack && !IsWindows && !RPI.isScalable() &&
1901 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1902 ByteOffset % 16 != 0) {
1903 ByteOffset += 8 * StackFillDir;
1909 NeedGapToAlignStack =
false;
1912 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1913 assert(OffsetPost % Scale == 0);
1916 int Offset = IsWindows ? OffsetPre : OffsetPost;
1921 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1922 (IsWindows && RPI.Reg2 == AArch64::LR)))
1924 RPI.Offset =
Offset / Scale;
1926 assert((!RPI.isPaired() ||
1927 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1928 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1929 "Offset out of bounds for LDP/STP immediate");
1931 auto isFrameRecord = [&] {
1933 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1934 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1942 return i > 0 && RPI.Reg1 == AArch64::FP &&
1943 CSI[i - 1].getReg() == AArch64::LR;
1948 if (NeedsFrameRecord && isFrameRecord())
1965 std::reverse(RegPairs.
begin(), RegPairs.
end());
1987 if (homogeneousPrologEpilog(MF)) {
1991 for (
auto &RPI : RegPairs) {
1997 MBB.addLiveIn(RPI.Reg1);
1998 if (RPI.isPaired() && !MRI.
isReserved(RPI.Reg2))
1999 MBB.addLiveIn(RPI.Reg2);
2003 bool PTrueCreated =
false;
2019 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2020 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2022 case RegPairInfo::GPR:
2023 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2025 case RegPairInfo::FPR64:
2026 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2028 case RegPairInfo::FPR128:
2029 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2031 case RegPairInfo::ZPR:
2032 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2034 case RegPairInfo::PPR:
2035 StrOpc = AArch64::STR_PXI;
2037 case RegPairInfo::VG:
2038 StrOpc = AArch64::STRXui;
2050 if (Reg1 == AArch64::VG) {
2052 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2063 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2064 AArch64::X0, LiveIn.PhysReg);
2072 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2074 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2088 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2090 dbgs() <<
", " << RPI.FrameIdx + 1;
2095 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2096 "Windows unwdinding requires a consecutive (FP,LR) pair");
2097 unsigned FrameIdxReg1 = RPI.FrameIdx;
2098 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2100 if (RPI.isPaired() && RPI.isScalable()) {
2102 "Scalable register groups are not supported by Windows WinCFI");
2108 "Expects SVE2.1 or SME2 target and a predicate register");
2109#ifdef EXPENSIVE_CHECKS
2110 auto IsPPR = [](
const RegPairInfo &c) {
2111 return c.Type == RegPairInfo::PPR;
2113 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2114 auto IsZPR = [](
const RegPairInfo &c) {
2115 return c.Type == RegPairInfo::ZPR;
2117 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2118 assert(!(PPRBegin < ZPRBegin) &&
2119 "Expected callee save predicate to be handled first");
2121 if (!PTrueCreated) {
2122 PTrueCreated =
true;
2128 MBB.addLiveIn(Reg1);
2130 MBB.addLiveIn(Reg2);
2131 assert(RPI.Reg2 + 1 == RPI.Reg1 &&
"Expected reversed ZPR pair");
2132 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg2 - AArch64::Z0));
2154 MBB.addLiveIn(Reg1);
2155 if (RPI.isPaired()) {
2157 MBB.addLiveIn(Reg2);
2176 if (RPI.Type == RegPairInfo::ZPR) {
2180 }
else if (RPI.Type == RegPairInfo::PPR) {
2200 DL =
MBBI->getDebugLoc();
2203 if (homogeneousPrologEpilog(MF, &
MBB)) {
2206 for (
auto &RPI : RegPairs) {
2214 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2216 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2217 std::reverse(PPRBegin, PPREnd);
2218 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2220 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2221 std::reverse(ZPRBegin, ZPREnd);
2223 bool PTrueCreated =
false;
2224 for (
const RegPairInfo &RPI : RegPairs) {
2237 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2238 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2240 case RegPairInfo::GPR:
2241 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2243 case RegPairInfo::FPR64:
2244 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2246 case RegPairInfo::FPR128:
2247 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2249 case RegPairInfo::ZPR:
2250 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2252 case RegPairInfo::PPR:
2253 LdrOpc = AArch64::LDR_PXI;
2255 case RegPairInfo::VG:
2262 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2264 dbgs() <<
", " << RPI.FrameIdx + 1;
2268 unsigned FrameIdxReg1 = RPI.FrameIdx;
2269 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2272 if (RPI.isPaired() && RPI.isScalable()) {
2274 "Scalable register groups are not supported by Windows WinCFI");
2279 "Expects SVE2.1 or SME2 target and a predicate register");
2280#ifdef EXPENSIVE_CHECKS
2281 assert(!(PPRBegin < ZPRBegin) &&
2282 "Expected callee save predicate to be handled first");
2284 if (!PTrueCreated) {
2285 PTrueCreated =
true;
2290 assert(RPI.Reg2 + 1 == RPI.Reg1 &&
"Expected reversed ZPR pair");
2291 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg2 - AArch64::Z0),
2313 if (RPI.isPaired()) {
2340 return std::optional<int>(PSV->getFrameIndex());
2351 return std::nullopt;
2357 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2358 return std::nullopt;
2365 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2371void AArch64FrameLowering::determineStackHazardSlot(
2374 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2375 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2381 const AArch64Options &CLOpts =
2383 if (!CLOpts.stack_hazard_in_non_streaming &&
2384 Attrs.hasNonStreamingInterfaceAndBody())
2392 return AArch64::FPR64RegClass.contains(Reg) ||
2393 AArch64::FPR128RegClass.contains(Reg) ||
2394 AArch64::ZPRRegClass.contains(Reg);
2397 return AArch64::PPRRegClass.contains(Reg);
2399 bool HasFPRStackObjects =
false;
2400 bool HasPPRStackObjects =
false;
2401 if (!HasFPRCSRs || CLOpts.split_sve_objects) {
2402 enum SlotType : uint8_t {
2413 for (
auto &
MBB : MF) {
2414 for (
auto &
MI :
MBB) {
2416 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2423 ? SlotType::ZPRorFPR
2429 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2430 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2433 if (SlotTypes[FI] == SlotType::PPR) {
2435 HasPPRStackObjects =
true;
2440 if (HasFPRCSRs || HasFPRStackObjects) {
2443 << StackHazardSize <<
"\n");
2450 if (CLOpts.split_sve_objects) {
2454 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2460 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2461 "non-SVE CC function...\n");
2468 <<
"Calling convention is not supported with SplitSVEObjects\n");
2472 if (!HasPPRCSRs && !HasPPRStackObjects) {
2474 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2478 if (!HasFPRCSRs && !HasFPRStackObjects) {
2481 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2485 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2486 MF.getSubtarget<AArch64Subtarget>();
2488 "Expected SVE to be available for PPRs");
2490 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2494 BitVector FPRZRegs(SavedRegs.
size());
2495 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2496 BitVector::reference RegBit = SavedRegs[
Reg];
2499 unsigned SubRegIdx = 0;
2501 SubRegIdx = AArch64::dsub;
2503 SubRegIdx = AArch64::zsub;
2510 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2513 SavedRegs |= FPRZRegs;
2540 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2543 bool HasUnpairedGPR64 =
false;
2544 bool HasPairZReg =
false;
2545 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2546 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2549 for (
unsigned i = 0; CSRegs[i]; ++i) {
2553 if (Reg == BasePointerReg)
2558 if (UserReservedRegs[Reg]) {
2559 SavedRegs.
reset(Reg);
2563 bool RegUsed = SavedRegs.
test(Reg);
2565 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2566 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2567 AArch64::FPR128RegClass.
contains(Reg)) {
2570 if (HasUnpairedGPR64)
2571 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2573 PairedReg = CSRegs[i ^ 1];
2580 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2582 HasUnpairedGPR64 =
true;
2585 AArch64::GPR64RegClass.contains(Reg, PairedReg) ||
2586 AArch64::FPR64RegClass.contains(Reg, PairedReg) ||
2587 AArch64::FPR128RegClass.contains(Reg, PairedReg));
2590 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2591 UnspilledCSGPR = Reg;
2592 UnspilledCSGPRPaired = PairedReg;
2600 if (producePairRegisters(MF) && PairedReg.
isValid() &&
2601 !SavedRegs.
test(PairedReg)) {
2602 SavedRegs.
set(PairedReg);
2603 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2604 !ReservedRegs[PairedReg])
2605 ExtraCSSpill = PairedReg;
2608 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2609 SavedRegs.
test(CSRegs[i ^ 1]));
2617 if (PnReg.isValid())
2623 SavedRegs.
set(AArch64::P8);
2628 "Predicate cannot be a reserved register");
2638 SavedRegs.
set(AArch64::X18);
2644 determineStackHazardSlot(MF, SavedRegs);
2647 unsigned CSStackSize = 0;
2648 unsigned ZPRCSStackSize = 0;
2649 unsigned PPRCSStackSize = 0;
2651 for (
unsigned Reg : SavedRegs.
set_bits()) {
2653 assert(RC &&
"expected register class!");
2654 auto SpillSize =
TRI->getSpillSize(*RC);
2655 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2656 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2658 ZPRCSStackSize += SpillSize;
2660 PPRCSStackSize += SpillSize;
2666 return SavedRegs.test(SuperReg);
2669 CSStackSize += SpillSize;
2676 unsigned NumSavedRegs = SavedRegs.
count();
2689 SavedRegs.
set(AArch64::LR);
2694 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2695 SavedRegs.
set(AArch64::FP);
2696 SavedRegs.
set(AArch64::LR);
2700 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2701 for (
unsigned Reg : SavedRegs.
set_bits())
2707 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2709 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2710 uint64_t SVEStackSize =
2711 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2712 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2721 int64_t CalleeStackUsed = 0;
2724 if (FixedOff > CalleeStackUsed)
2725 CalleeStackUsed = FixedOff;
2729 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2730 CalleeStackUsed) > EstimatedStackSizeLimit;
2731 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2741 if (!ExtraCSSpill.
isValid() && UnspilledCSGPR.isValid()) {
2743 <<
" to get a scratch register.\n");
2744 SavedRegs.
set(UnspilledCSGPR);
2745 ExtraCSSpill = UnspilledCSGPR;
2750 if (producePairRegisters(MF)) {
2751 if (!UnspilledCSGPRPaired.
isValid()) {
2754 SavedRegs.
reset(UnspilledCSGPR);
2758 SavedRegs.
set(UnspilledCSGPRPaired);
2764 if (!ExtraCSSpill.
isValid() ||
2768 unsigned Size =
TRI->getSpillSize(RC);
2769 Align Alignment =
TRI->getSpillAlign(RC);
2771 RS->addScavengingFrameIndex(FI);
2772 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2773 <<
" as the emergency spill slot.\n");
2778 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2785 uint64_t AlignedCSStackSize =
alignTo(CSStackSize, 16);
2787 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2791 "Should not invalidate callee saved info");
2808 std::vector<CalleeSavedInfo> &CSI) {
2810 "ZPR callee-save reordering not supported on Windows");
2817 return AArch64::ZPRRegClass.contains(CS.getReg());
2821 ZPRSaves = ZPRSaves.
drop_until(IsZPR).take_while(IsZPR);
2823 if (ZPRSaves.
size() < 2)
2830 const int Scale =
RegInfo->getSpillSize(AArch64::ZPRRegClass);
2831 const int LowestOffset =
2832 (ZPRByteOffset / Scale) -
static_cast<int>(ZPRSaves.
size());
2834 int NumToAlign =
alignTo(LowestOffset, 4) - LowestOffset;
2835 if (NumToAlign >
int(ZPRSaves.
size()))
2839 [](
const auto &
A,
const auto &
B) {
return A.getReg() <
B.getReg(); });
2845 int ZPRsNeededForAlignment = NumToAlign;
2846 for (
size_t i = 0; i < ZPRSaves.
size();) {
2847 int ZPRsRemaining = int(ZPRSaves.
size()) - i;
2848 if (i + 3 < ZPRSaves.
size() &&
2849 (ZPRSaves[i].getReg() - AArch64::Z0) % 4 == 0 &&
2850 ZPRSaves[i].getReg() + 3 == ZPRSaves[i + 3].getReg() &&
2851 ZPRsRemaining - 4 >= ZPRsNeededForAlignment) {
2853 {ZPRSaves[i], ZPRSaves[i + 1], ZPRSaves[i + 2], ZPRSaves[i + 3]});
2860 bool MustSplitPairForSingle =
2861 ZPRsNeededForAlignment == 1 && Singles.empty() && ZPRsRemaining == 2;
2863 if (i + 1 < ZPRSaves.
size() &&
2864 (ZPRSaves[i].getReg() - AArch64::Z0) % 2 == 0 &&
2865 ZPRSaves[i].getReg() + 1 == ZPRSaves[i + 1].getReg() &&
2866 !MustSplitPairForSingle) {
2867 Pairs.
push_back({ZPRSaves[i], ZPRSaves[i + 1]});
2870 if (ZPRsNeededForAlignment != 1 || !Singles.empty())
2871 ZPRsNeededForAlignment -= 2;
2877 Singles.push_back(ZPRSaves[i++]);
2878 ZPRsNeededForAlignment--;
2884 int NumUnassigned = ZPRSaves.
size();
2890 ZPRSaves[--NumUnassigned] = CS;
2894 if (NumToAlign & 0b01)
2895 Emit(Singles.pop_back_val());
2896 if (NumToAlign & 0b10) {
2900 Emit({Singles.pop_back_val(), Singles.pop_back_val()});
2903 for (
const auto &Quad : Quads)
2906 for (
const auto &Pair : Pairs)
2909 for (
const auto &
Single : Singles)
2915 std::vector<CalleeSavedInfo> &CSI)
const {
2924 std::reverse(CSI.begin(), CSI.end());
2938 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2939 if (It != CSI.end())
2940 CSI.insert(It, VGInfo);
2942 CSI.push_back(VGInfo);
2952 int HazardSlotIndex = std::numeric_limits<int>::max();
2953 for (
auto &CS : CSI) {
2961 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2962 "Unexpected register order for hazard slot");
2964 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2970 unsigned Size = RegInfo->getSpillSize(*RC);
2971 Align Alignment(RegInfo->getSpillAlign(*RC));
2973 CS.setFrameIdx(FrameIdx);
2987 HazardSlotIndex == std::numeric_limits<int>::max()) {
2989 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
3016 int &Min,
int &Max) {
3017 Min = std::numeric_limits<int>::max();
3018 Max = std::numeric_limits<int>::min();
3024 for (
auto &CS : CSI) {
3025 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
3026 AArch64::PPRRegClass.contains(CS.getReg())) {
3027 assert((Max == std::numeric_limits<int>::min() ||
3028 Max + 1 == CS.getFrameIdx()) &&
3029 "SVE CalleeSaves are not consecutive");
3030 Min = std::min(Min, CS.getFrameIdx());
3031 Max = std::max(Max, CS.getFrameIdx());
3034 return Min != std::numeric_limits<int>::max();
3047 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
3055 "SVE vectors should never be passed on the stack by value, only by "
3059 auto AllocateObject = [&](
int FI) {
3068 if (Alignment >
Align(16))
3070 "Alignment of scalable vectors > 16 bytes is not yet supported");
3073 StackTop =
alignTo(StackTop, Alignment);
3075 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
3076 "SVE StackTop far too large?!");
3078 int64_t
Offset = -int64_t(StackTop);
3086 int MinCSFrameIndex, MaxCSFrameIndex;
3088 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
3101 int StackProtectorFI = -1;
3105 ObjectsToAllocate.
push_back(StackProtectorFI);
3121 for (
unsigned FI : ObjectsToAllocate)
3136 "Upwards growing stack unsupported");
3151 int64_t CurrentOffset =
3155 int FrameIndex =
H.CatchObj.FrameIndex;
3156 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3167 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3168 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3170 "UnwindHelpOffset must be at the start of the fixed object area");
3173 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3183 RS->enterBasicBlockEnd(
MBB);
3185 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3186 assert(DstReg &&
"There must be a free register after frame setup");
3197struct TagStoreInstr {
3206 MachineBasicBlock *
MBB;
3207 MachineRegisterInfo *MRI;
3216 StackOffset FrameRegOffset;
3220 std::optional<int64_t> FrameRegUpdate;
3222 unsigned FrameRegUpdateFlags;
3232 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3233 :
MBB(
MBB), ZeroData(ZeroData) {
3239 void addInstruction(TagStoreInstr
I) {
3241 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3242 "Non-adjacent tag store instructions.");
3245 void clear() { TagStores.
clear(); }
3250 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3257 const int64_t kMinOffset = -256 * 16;
3258 const int64_t kMaxOffset = 255 * 16;
3261 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3262 if (BaseRegOffsetBytes < kMinOffset ||
3263 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3267 BaseRegOffsetBytes % 16 != 0) {
3272 BaseRegOffsetBytes = 0;
3277 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3280 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3282 assert(BaseRegOffsetBytes % 16 == 0);
3286 .
addImm(BaseRegOffsetBytes / 16)
3290 if (BaseRegOffsetBytes == 0)
3292 BaseRegOffsetBytes += InstrSize;
3311 int64_t LoopSize =
Size;
3314 if (FrameRegUpdate && *FrameRegUpdate)
3315 LoopSize -= LoopSize % 32;
3317 TII->get(ZeroData ? AArch64::STZGloop_wback
3318 : AArch64::STGloop_wback))
3325 LoopI->
setFlags(FrameRegUpdateFlags);
3327 int64_t ExtraBaseRegUpdate =
3328 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3329 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3330 <<
", Size=" <<
Size
3331 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3332 <<
", FrameRegUpdate=" << FrameRegUpdate
3333 <<
", FrameRegOffset.getFixed()="
3334 << FrameRegOffset.
getFixed() <<
"\n");
3335 if (LoopSize <
Size) {
3339 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3340 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3341 "STG immediate out of range");
3343 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3350 }
else if (ExtraBaseRegUpdate) {
3352 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3353 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3356 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3369 int64_t
Size, int64_t *TotalOffset) {
3371 if ((
MI.getOpcode() == AArch64::ADDXri ||
3372 MI.getOpcode() == AArch64::SUBXri) &&
3373 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3375 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3376 if (
MI.getOpcode() == AArch64::SUBXri)
3387 const int64_t kMaxOffset = 4080 - 16;
3389 const int64_t kMinOffset = -4095;
3390 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3391 PostOffset % 16 == 0) {
3402 for (
auto &TS : TSE) {
3406 if (
MI->memoperands_empty()) {
3410 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3416 bool TryMergeSPUpdate) {
3417 if (TagStores.
empty())
3419 TagStoreInstr &FirstTagStore = TagStores[0];
3420 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3421 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3422 DL = TagStores[0].MI->getDebugLoc();
3426 *MF, FirstTagStore.Offset,
false ,
3430 FrameRegUpdate = std::nullopt;
3432 mergeMemRefs(TagStores, CombinedMemRefs);
3435 dbgs() <<
"Replacing adjacent STG instructions:\n";
3436 for (
const auto &Instr : TagStores) {
3445 if (TagStores.
size() < 2)
3447 emitUnrolled(InsertI);
3450 int64_t TotalOffset = 0;
3451 if (TryMergeSPUpdate) {
3457 if (InsertI !=
MBB->
end() &&
3458 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3460 UpdateInstr = &*InsertI++;
3466 if (!UpdateInstr && TagStores.
size() < 2)
3470 FrameRegUpdate = TotalOffset;
3471 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3478 for (
auto &TS : TagStores)
3479 TS.MI->eraseFromParent();
3483 int64_t &
Size,
bool &ZeroData) {
3487 unsigned Opcode =
MI.getOpcode();
3488 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3489 Opcode == AArch64::STZ2Gi);
3491 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3492 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3494 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3497 Size =
MI.getOperand(2).getImm();
3501 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3503 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3508 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3512 16 *
MI.getOperand(2).getImm();
3516static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3521 return LiveRegs.available(MRI,
Reg);
3524 size_t NumEmergencySlots = 0;
3526 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3528 return FreeGPRs + NumEmergencySlots;
3547 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3553 constexpr int kScanLimit = 10;
3556 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3565 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3566 if (ZeroData != FirstZeroData)
3574 if (!
MI.isTransient())
3583 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3599 LiveRegs.addLiveOuts(*
MBB);
3604 LiveRegs.stepBackward(*
I);
3607 if (LiveRegs.contains(AArch64::NZCV))
3618 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3619 <<
"due to high register pressure.\n");
3624 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3629 int64_t CurOffset = Instrs[0].Offset;
3630 for (
auto &Instr : Instrs) {
3631 if (CurOffset >
Instr.Offset)
3638 TagStoreEdit TSE(
MBB, FirstZeroData);
3639 std::optional<int64_t> EndOffset;
3640 for (
auto &Instr : Instrs) {
3641 if (EndOffset && *EndOffset !=
Instr.Offset) {
3643 TSE.emitCode(InsertI, TFI,
false);
3647 TSE.addInstruction(Instr);
3665 .stack_tagging_merge_settag;
3669 II = tryMergeAdjacentSTG(
II,
this, RS);
3676 shouldSignReturnAddressEverywhere(MF))
3685 bool IgnoreSPUpdates)
const {
3687 if (IgnoreSPUpdates) {
3690 FrameReg = AArch64::SP;
3700 FrameReg = AArch64::SP;
3725 bool IsValid =
false;
3727 int ObjectIndex = 0;
3729 int GroupIndex = -1;
3731 bool ObjectFirst =
false;
3734 bool GroupFirst =
false;
3739 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3743 SmallVector<int, 8> CurrentMembers;
3744 int NextGroupIndex = 0;
3745 std::vector<FrameObject> &Objects;
3748 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3749 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3750 void EndCurrentGroup() {
3751 if (CurrentMembers.
size() > 1) {
3756 for (
int Index : CurrentMembers) {
3757 Objects[
Index].GroupIndex = NextGroupIndex;
3763 CurrentMembers.clear();
3767bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3789 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3790 A.GroupIndex,
A.ObjectIndex) <
3791 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3792 B.GroupIndex,
B.ObjectIndex);
3802 ObjectsToAllocate.
empty())
3807 for (
auto &Obj : ObjectsToAllocate) {
3808 FrameObjects[Obj].IsValid =
true;
3809 FrameObjects[Obj].ObjectIndex = Obj;
3814 GroupBuilder GB(FrameObjects);
3815 for (
auto &
MBB : MF) {
3816 for (
auto &
MI :
MBB) {
3817 if (
MI.isDebugInstr())
3822 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3825 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3827 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3832 switch (
MI.getOpcode()) {
3833 case AArch64::STGloop:
3834 case AArch64::STZGloop:
3838 case AArch64::STZGi:
3839 case AArch64::ST2Gi:
3840 case AArch64::STZ2Gi:
3853 FrameObjects[FI].IsValid)
3861 GB.AddMember(TaggedFI);
3863 GB.EndCurrentGroup();
3866 GB.EndCurrentGroup();
3871 FrameObject::AccessHazard;
3873 for (
auto &Obj : FrameObjects)
3874 if (!Obj.Accesses ||
3875 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3876 Obj.Accesses = FrameObject::AccessGPR;
3885 FrameObjects[*TBPI].ObjectFirst =
true;
3886 FrameObjects[*TBPI].GroupFirst =
true;
3887 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3888 if (FirstGroupIndex >= 0)
3889 for (FrameObject &Object : FrameObjects)
3890 if (Object.GroupIndex == FirstGroupIndex)
3891 Object.GroupFirst =
true;
3897 for (
auto &Obj : FrameObjects) {
3901 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3905 dbgs() <<
"Final frame order:\n";
3906 for (
auto &Obj : FrameObjects) {
3909 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3910 if (Obj.ObjectFirst)
3911 dbgs() <<
", first";
3913 dbgs() <<
", group-first";
3924AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3935 MF.
insert(MBBInsertPoint, LoopMBB);
3937 MF.
insert(MBBInsertPoint, ExitMBB);
3972 MBB.addSuccessor(LoopMBB);
3976 return ExitMBB->
begin();
3979void AArch64FrameLowering::inlineStackProbeFixed(
3984 const AArch64InstrInfo *
TII =
3986 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
3991 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
3992 int64_t NumBlocks = FrameSize / ProbeSize;
3993 int64_t ResidualSize = FrameSize % ProbeSize;
3995 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
3996 << NumBlocks <<
" blocks of " << ProbeSize
3997 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
4002 for (
int i = 0; i < NumBlocks; ++i) {
4008 EmitAsyncCFI && !HasFP, CFAOffset);
4021 }
else if (NumBlocks != 0) {
4027 EmitAsyncCFI && !HasFP, CFAOffset);
4029 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
4031 if (EmitAsyncCFI && !HasFP) {
4034 .buildDefCFARegister(AArch64::SP);
4038 if (ResidualSize != 0) {
4044 EmitAsyncCFI && !HasFP, CFAOffset);
4065 SmallVector<MachineInstr *, 4> ToReplace;
4066 for (MachineInstr &
MI :
MBB)
4067 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
4068 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
4071 for (MachineInstr *
MI : ToReplace) {
4072 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
4073 Register ScratchReg =
MI->getOperand(0).getReg();
4074 int64_t FrameSize =
MI->getOperand(1).getImm();
4076 MI->getOperand(3).getImm());
4077 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
4080 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
4081 "Stack probe pseudo-instruction expected");
4082 const AArch64InstrInfo *
TII =
4083 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
4084 Register TargetReg =
MI->getOperand(0).getReg();
4085 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
4087 MI->eraseFromParent();
4107 return std::make_tuple(
start(),
Idx) <
4108 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4138 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4139 if (
Offset.getScalable())
4140 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4151void AArch64FrameLowering::emitRemarks(
4154 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4162 .stack_hazard_remark_size;
4164 if (HazardSize == 0)
4172 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4174 size_t NumFPLdSt = 0;
4175 size_t NumNonFPLdSt = 0;
4178 for (
const MachineBasicBlock &
MBB : MF) {
4179 for (
const MachineInstr &
MI :
MBB) {
4180 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4182 for (MachineMemOperand *MMO :
MI.memoperands()) {
4189 StackAccesses[ArrIdx].Idx = FrameIdx;
4190 StackAccesses[ArrIdx].Offset =
4201 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4212 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4223 if (StackAccesses.front().isMixed())
4224 MixedObjects.push_back(&StackAccesses.front());
4226 for (
auto It = StackAccesses.begin(),
End = std::prev(StackAccesses.end());
4228 const auto &
First = *It;
4229 const auto &Second = *(It + 1);
4231 if (Second.isMixed())
4232 MixedObjects.push_back(&Second);
4234 if ((
First.isSME() && Second.isCPU()) ||
4235 (
First.isCPU() && Second.isSME())) {
4237 if (Distance < HazardSize)
4242 auto EmitRemark = [&](llvm::StringRef Str) {
4244 auto R = MachineOptimizationRemarkAnalysis(
4245 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4246 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4250 for (
const auto &
P : HazardPairs)
4251 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4253 for (
const auto *Obj : MixedObjects)
4255 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)
void computeCalleeSaveRegisterPairs(const AArch64FrameLowering &AFL, MachineFunction &MF, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI, SmallVectorImpl< RegPairInfo > &RegPairs, bool NeedsFrameRecord)
static void orderZPRCalleeSavesForGroups(MachineFunction &MF, const TargetRegisterInfo *RegInfo, std::vector< CalleeSavedInfo > &CSI)
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
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
This file contains the simple types necessary to represent the attributes associated with functions a...
#define CASE(ATTRNAME, AANAME,...)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
DXIL Forward Handle Accesses
const HexagonInstrInfo * TII
Module.h This file contains the declarations for the Module class.
static std::string getTypeString(Type *T)
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
uint64_t IntrinsicInst * II
This file declares the machine register scavenger class.
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
This file defines the SmallVector class.
void emitEpilogue()
Emit the epilogue.
StackOffset getSVEStackSize(const MachineFunction &MF) const
Returns the size of the entire SVE stackframe (PPRs + ZPRs).
StackOffset getZPRStackSize(const MachineFunction &MF) const
Returns the size of the entire ZPR stackframe (calleesaves + spills).
void processFunctionBeforeFrameIndicesReplaced(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameIndicesReplaced - This method is called immediately before MO_FrameIndex op...
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override
This method is called during prolog/epilog code insertion to eliminate call frame setup and destroy p...
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override
Check whether or not the given MBB can be used as a prologue for the target.
bool enableStackSlotScavenging(const MachineFunction &MF) const override
Returns true if the stack slot holes in the fixed and callee-save stack area should be used when allo...
bool assignCalleeSavedSpillSlots(MachineFunction &MF, const TargetRegisterInfo *TRI, std::vector< CalleeSavedInfo > &CSI) const override
assignCalleeSavedSpillSlots - Allows target to override spill slot assignment logic.
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
spillCalleeSavedRegisters - Issues instruction(s) to spill all callee saved registers and returns tru...
bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MutableArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee saved registers and returns...
bool enableFullCFIFixup(const MachineFunction &MF) const override
enableFullCFIFixup - Returns true if we may need to fix the unwind information such that it is accura...
StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI) const override
getFrameIndexReferenceFromSP - This method returns the offset from the stack pointer to the slot of t...
bool enableCFIFixup(const MachineFunction &MF) const override
Returns true if we may need to fix the unwind information for the function.
StackOffset getNonLocalFrameIndexReference(const MachineFunction &MF, int FI) const override
getNonLocalFrameIndexReference - This method returns the offset used to reference a frame index locat...
TargetStackID::Value getStackIDForScalableVectors() const override
Returns the StackID that scalable vectors should be associated with.
friend class AArch64PrologueEmitter
bool hasFPImpl(const MachineFunction &MF) const override
hasFPImpl - Return true if the specified function should have a dedicated frame pointer register.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override
emitProlog/emitEpilog - These methods insert prolog and epilog code into the function.
friend class AArch64EpilogueEmitter
void resetCFIToInitialState(MachineBasicBlock &MBB) const override
Emit CFI instructions that recreate the state of the unwind information upon function entry.
bool hasReservedCallFrame(const MachineFunction &MF) const override
hasReservedCallFrame - Under normal circumstances, when a frame pointer is not required,...
bool hasSVECalleeSavesAboveFrameRecord(const MachineFunction &MF) const
StackOffset resolveFrameOffsetReference(const MachineFunction &MF, int64_t ObjectOffset, bool isFixed, TargetStackID::Value StackID, Register &FrameReg, bool PreferFP, bool ForSimm) const
bool canUseRedZone(const MachineFunction &MF) const
Can this function use the red zone for local allocations.
bool isFPReserved(const MachineFunction &MF) const
Should the Frame Pointer be reserved for the current function?
void processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameFinalized - This method is called immediately before the specified function...
int getSEHFrameIndexOffset(const MachineFunction &MF, int FI) const
unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const
Funclets only need to account for space for the callee saved registers, as the locals are accounted f...
void orderFrameObjects(const MachineFunction &MF, SmallVectorImpl< int > &ObjectsToAllocate) const override
Order the symbols in the local stack frame.
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
StackOffset getPPRStackSize(const MachineFunction &MF) const
Returns the size of the entire PPR stackframe (calleesaves + spills + hazard padding).
int64_t getArgumentStackToRestore(MachineFunction &MF, MachineBasicBlock &MBB) const
Returns how much of the incoming argument stack area (in bytes) we should clean up in an epilogue.
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const override
getFrameIndexReference - Provide a base+offset reference to an FI slot for debug info.
StackOffset getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI, Register &FrameReg, bool IgnoreSPUpdates) const override
For Win64 AArch64 EH, the offset to the Unwind object is from the SP before the update.
StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg, bool PreferFP, bool ForSimm) const
unsigned getWinEHParentFrameOffset(const MachineFunction &MF) const override
The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve the parent's frame pointer...
bool requiresSaveVG(const MachineFunction &MF) const
void emitPacRetPlusLeafHardening(MachineFunction &MF) const
Harden the entire function with pac-ret.
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
unsigned getPPRCalleeSavedStackSize() const
void setHasStackFrame(bool s)
void setSwiftAsyncContextFrameIdx(int FI)
unsigned getTailCallReservedStack() const
unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const
void setCalleeSaveBaseToFrameRecordOffset(int Offset)
bool hasStackProbing() const
unsigned getArgumentStackToRestore() const
void setCalleeSaveStackHasFreeSpace(bool s)
int getCalleeSaveBaseToFrameRecordOffset() const
SignReturnAddress getSignReturnAddressCondition() const
bool hasStreamingModeChanges() const
void setPredicateRegForFillSpill(unsigned Reg)
int getStackHazardSlotIndex() const
void setCalleeSavedStackSize(unsigned Size)
void setSplitSVEObjects(bool s)
bool hasStackFrame() const
void setStackSizeSVE(uint64_t ZPR, uint64_t PPR)
std::optional< int > getTaggedBasePointerIndex() const
SMEAttrs getSMEFnAttrs() const
uint64_t getLocalStackSize() const
bool needsDwarfUnwindInfo(const MachineFunction &MF) const
unsigned getVarArgsGPRSize() const
uint64_t getStackSizePPR() const
bool hasSwiftAsyncContext() const
bool hasStackHazardSlotIndex() const
void setStackHazardSlotIndex(int Index)
unsigned getZPRCalleeSavedStackSize() const
void setStackHazardCSRSlotIndex(int Index)
unsigned getPredicateRegForFillSpill() const
void setSVECalleeSavedStackSize(unsigned ZPR, unsigned PPR)
bool hasCalculatedStackSizeSVE() const
uint64_t getStackSizeZPR() const
bool hasSVEStackSize() const
bool isStackHazardIncludedInCalleeSaveArea() const
unsigned getSVECalleeSavedStackSize() const
bool hasSplitSVEObjects() const
bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const
bool hasCalleeSaveStackFreeSpace() const
static bool isTailCallReturnInst(const MachineInstr &MI)
Returns true if MI is one of the TCRETURN* instructions.
static bool isFpOrNEON(Register Reg)
Returns whether the physical register is FP or NEON.
void emitPrologue()
Emit the prologue.
bool isTargetWindows() const
const AArch64RegisterInfo * getRegisterInfo() const override
bool isNeonAvailable() const
Returns true if the target has NEON and the function at runtime is known to have NEON enabled (e....
const AArch64InstrInfo * getInstrInfo() const override
const 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 isStreaming() const
Returns true if the function has a streaming body.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this functions.
unsigned getRedZoneSize(const Function &F) const
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
bool empty() const
Check if the array is empty.
bool test(unsigned Idx) const
Returns true if bit Idx is set.
BitVector & reset()
Reset all bits in the bitvector.
size_type count() const
Returns the number of bits which are set.
BitVector & set()
Set all bits in the bitvector.
iterator_range< const_set_bits_iterator > set_bits() const
size_type size() const
Returns the number of bits in this bitvector.
Helper class for creating CFI instructions and inserting them into MIR.
The CalleeSavedInfo class tracks the information need to locate where a callee saved register is in t...
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
AttributeList getAttributes() const
Return the attribute list for this Function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Module * getParent()
Get the module that this global value is contained inside of...
A set of physical registers with utility functions to track liveness when walking backward/forward th...
Wrapper class representing physical registers. Should be passed by value.
constexpr bool isValid() const
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
MachineInstr & instr_back()
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
reverse_iterator rbegin()
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
LLVM_ABI int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
const AllocaInst * getObjectAllocation(int ObjectIdx) const
Return the underlying Alloca of the specified stack object if it exists.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
bool hasCalls() const
Return true if the current function has any function calls.
bool isFrameAddressTaken() const
This method may be called any time after instruction selection is complete to determine if there is a...
void setObjectOffset(int ObjectIdx, int64_t SPOffset)
Set the stack frame offset of the specified object.
bool isCalleeSavedObjectIndex(int ObjectIdx) const
uint64_t getMaxCallFrameSize() const
Return the maximum size of a call frame that must be allocated for an outgoing function call.
bool hasPatchPoint() const
This method may be called any time after instruction selection is complete to determine if there is a...
bool hasScalableStackID(int ObjectIdx) const
int getStackProtectorIndex() const
Return the index for the stack protector object.
LLVM_ABI uint64_t estimateStackSize(const MachineFunction &MF) const
Estimate and return the size of the stack frame.
void setStackID(int ObjectIdx, uint8_t ID)
bool isCalleeSavedInfoValid() const
Has the callee saved info been calculated yet?
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
bool isMaxCallFrameSizeComputed() const
bool hasStackMap() const
This method may be called any time after instruction selection is complete to determine if there is a...
LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment, TargetStackID::Value StackID=TargetStackID::Default)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
const std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const
Returns a reference to call saved info vector for the current function.
unsigned getNumObjects() const
Return the number of objects.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
bool hasStackProtectorIndex() const
bool hasStackObjects() const
Return true if there are any stack objects in this function.
uint8_t getStackID(int ObjectIdx) const
unsigned getNumFixedObjects() const
Return the number of fixed objects.
void setIsCalleeSavedObjectIndex(int ObjectIdx, bool IsCalleeSaved)
int64_t getObjectOffset(int ObjectIdx) const
Return the assigned stack offset of the specified object from the incoming stack pointer.
int getObjectIndexBegin() const
Return the minimum frame object index.
void setObjectAlignment(int ObjectIdx, Align Alignment)
setObjectAlignment - Change the alignment of the specified stack object.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
const WinEHFuncInfo * getWinEHFuncInfo() const
getWinEHFuncInfo - Return information about how the current function uses Windows exception handling.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
bool framePointerIsReserved() const
Returns true if the frame pointer must always either point to a new frame record or be un-modified in...
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
bool needsWinCFI() const
True if this function uses SEH unwind opcodes and needs an unwind table entry.
Function & getFunction()
Return the LLVM function that this machine code represents.
bool usesWindowsUnwindInfo() const
True if this function describes its unwind information with Windows SEH unwind opcodes (....
BasicBlockListType::iterator iterator
bool disableFramePointerElim() const
Returns true if frame pointer elimination should be disabled for this function.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineBasicBlock & front() const
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
bool hasEHFunclets() const
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
void setFlags(unsigned flags)
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
const PseudoSourceValue * getPseudoValue() const
@ MOVolatile
The memory access is volatile.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
const Value * getValue() const
Return the base address of the memory access.
MachineOperand class - Representation of each machine instruction operand.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI void freezeReservedRegs()
freezeReservedRegs - Called by the register allocator to freeze the set of reserved registers before ...
bool isReserved(MCRegister PhysReg) const
isReserved - Returns true when PhysReg is a reserved register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI bool isLiveIn(Register Reg) const
LLVM_ABI const MCPhysReg * getCalleeSavedRegs() const
Returns list of callee saved registers.
LLVM_ABI bool isPhysRegUsed(MCRegister PhysReg, bool SkipRegMaskTest=false) const
Return true if the specified register is modified or read in this function.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
MutableArrayRef< T > drop_until(PredicateT Pred) const
Return a copy of *this with the first N elements not satisfying the given predicate removed.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
SMEAttrs is a utility class to parse the SME ACLE attributes on functions.
bool hasStreamingInterface() const
bool hasNonStreamingInterfaceAndBody() const
bool hasStreamingBody() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
A SetVector that performs no allocations if smaller than a certain size.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StackOffset holds a fixed and a scalable offset in bytes.
int64_t getFixed() const
Returns the fixed component of the stack.
int64_t getScalable() const
Returns the scalable component of the stack.
static StackOffset get(int64_t Fixed, int64_t Scalable)
static StackOffset getScalable(int64_t Scalable)
static StackOffset getFixed(int64_t Fixed)
bool hasFP(const MachineFunction &MF) const
hasFP - Return true if the specified function should have a dedicated frame pointer register.
virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS=nullptr) const
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
int getOffsetOfLocalArea() const
getOffsetOfLocalArea - This method returns the offset of the local area from the stack pointer on ent...
Align getStackAlign() const
getStackAlignment - This method returns the number of bytes to which the stack pointer must be aligne...
StackDirection getStackGrowthDirection() const
getStackGrowthDirection - Return the direction the stack grows
virtual bool enableCFIFixup(const MachineFunction &MF) const
Returns true if we may need to fix the unwind information for the function.
const Triple & getTargetTriple() const
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
bool hasStackRealignment(const MachineFunction &MF) const
True if stack realignment is required and still possible.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
Triple - Helper class for working with autoconf configuration names.
bool isOSBinFormatMachO() const
Tests whether the environment is MachO.
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, unsigned Imm)
getArithExtendImm - Encode the extend type and shift amount for an arithmetic instruction: imm: 3-bit...
const 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 stable_sort(R &&Range)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
int isAArch64FrameOffsetLegal(const MachineInstr &MI, StackOffset &Offset, bool *OutUseUnscaledOp=nullptr, unsigned *OutUnscaledOp=nullptr, int64_t *EmittableOffset=nullptr)
Check if the Offset is a valid frame offset for MI.
@ 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.
@ 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....
@ 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.
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