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())
962 F.needsUnwindTableEntry();
965bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
981 unsigned Opc =
MBBI->getOpcode();
985 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
986 int Imm =
MBBI->getOperand(ImmIdx).getImm();
994 case AArch64::STR_ZXI:
995 case AArch64::LDR_ZXI: {
996 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1003 case AArch64::STR_PXI:
1004 case AArch64::LDR_PXI: {
1005 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1012 case AArch64::LDPDpost:
1015 case AArch64::STPDpre: {
1016 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1017 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1018 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1025 case AArch64::LDPXpost:
1028 case AArch64::STPXpre: {
1031 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1032 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1036 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1037 .
addImm(RegInfo->getSEHRegNum(Reg0))
1038 .
addImm(RegInfo->getSEHRegNum(Reg1))
1043 case AArch64::LDRDpost:
1046 case AArch64::STRDpre: {
1047 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1048 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1054 case AArch64::LDRXpost:
1057 case AArch64::STRXpre: {
1058 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1065 case AArch64::STPDi:
1066 case AArch64::LDPDi: {
1067 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1068 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1076 case AArch64::STPXi:
1077 case AArch64::LDPXi: {
1081 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1082 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1084 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1088 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1095 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1102 case AArch64::STRXui:
1103 case AArch64::LDRXui: {
1104 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1111 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1117 case AArch64::STRDui:
1118 case AArch64::LDRDui: {
1119 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1126 case AArch64::STPQi:
1127 case AArch64::LDPQi: {
1128 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1129 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1130 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1137 case AArch64::LDPQpost:
1140 case AArch64::STPQpre: {
1141 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1142 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1143 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1162 if (ST.isTargetDarwin())
1184 DL =
MBBI->getDebugLoc();
1186 TII->createPauthEpilogueInstr(
MBB,
DL);
1190 EmitSignRA(MF.
front());
1192 if (
MBB.isEHFuncletEntry())
1194 if (
MBB.isReturnBlock())
1250 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1255 if (MFI.isVariableSizedObjectIndex(FI)) {
1265 if (MFI.hasScalableStackID(FI)) {
1266 if (FPAfterSVECalleeSaves &&
1269 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1277 AccessOffset = -PPRStackSize;
1278 return AccessOffset +
1283 bool IsFixed = MFI.isFixedObjectIndex(FI);
1288 if (!IsFixed && !IsCSR) {
1289 ScalableOffset = -SVEStackSize;
1290 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1305 int64_t ObjectOffset)
const {
1309 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1310 unsigned FixedObject =
1311 getFixedObjectSize(MF, AFI, IsWin64,
false);
1319 int64_t ObjectOffset)
const {
1330 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1331 ? getFPOffset(MF, ObjectOffset).getFixed()
1332 : getStackOffset(MF, ObjectOffset).getFixed();
1337 bool ForSimm)
const {
1339 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1340 bool isFixed = MFI.isFixedObjectIndex(FI);
1343 FrameReg, PreferFP, ForSimm);
1349 bool ForSimm)
const {
1355 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1356 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1364 const int64_t FixedObjectSize =
1365 getFixedObjectSize(MF, AFI, IsWin64,
false);
1369 bool isSVE = MFI.isScalableStackID(StackID);
1373 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1384 PreferFP &= !SVEStackSize;
1392 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1396 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1398 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1403 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1404 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1406 if (FPOffset >= 0) {
1410 }
else if (MFI.hasVarSizedObjects()) {
1414 bool CanUseBP = RegInfo->hasBasePointer(MF);
1415 if (FPOffsetFits && CanUseBP)
1422 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1429 "Funclets should only be present on Win64");
1433 if (FPOffsetFits && PreferFP)
1440 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1441 "In the presence of dynamic stack pointer realignment, "
1442 "non-argument/CSR objects cannot be accessed through the frame pointer");
1459 FPOffset -= PPRStackSize;
1461 SPOffset -= PPRStackSize;
1466 if (FPAfterSVECalleeSaves) {
1477 RegInfo->hasStackRealignment(MF))) {
1478 FrameReg = RegInfo->getFrameRegister(MF);
1481 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1488 if (FPAfterSVECalleeSaves) {
1495 SVEAreaOffset = SVECalleeSavedStack;
1497 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1500 SVEAreaOffset = SVEStackSize;
1502 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1505 if (UseFP && !(isFixed || isCSR))
1506 SVEAreaOffset = -SVEStackSize;
1507 if (!UseFP && (isFixed || isCSR))
1508 SVEAreaOffset = SVEStackSize;
1512 FrameReg = RegInfo->getFrameRegister(MF);
1517 if (RegInfo->hasBasePointer(MF))
1518 FrameReg = RegInfo->getBaseRegister();
1520 assert(!MFI.hasVarSizedObjects() &&
1521 "Can't use SP when we have var sized objects.");
1522 FrameReg = AArch64::SP;
1550 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1556 unsigned SpillCount,
unsigned Reg1,
1557 unsigned Reg2,
bool NeedsWinCFI,
1566 if (Reg2 == AArch64::FP)
1576 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1577 return SpillExtendedVolatile
1578 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1579 (SpillCount % 2) == 0)
1584 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1585 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1595 unsigned SpillCount,
unsigned Reg1,
1596 unsigned Reg2,
bool UsesWinAAPCS,
1597 bool NeedsWinCFI,
bool NeedsFrameRecord,
1601 Reg1, Reg2, NeedsWinCFI,
TRI);
1605 if (NeedsFrameRecord)
1606 return Reg2 == AArch64::LR;
1615 int64_t MinOff, MaxOff;
1616 TypeSize ScaleValue(0U,
false), Width(0U,
false);
1617 if (!
TII->getMemOpInfo(Opcode, ScaleValue, Width, MinOff, MaxOff))
1620 if (
Offset % ScaleValue.getKnownMinValue() != 0)
1623 Offset /= ScaleValue.getKnownMinValue();
1634 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1637 RegPairInfo() =
default;
1639 bool isPaired()
const {
return Reg2.
isValid(); }
1641 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1647 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1648 if (SavedRegs.
test(PReg)) {
1649 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1659 if (Subtarget.
getCLOpts().disable_multivector_spill_fill)
1663 bool IsLocallyStreaming =
1669 return Subtarget.hasSVE2p1() ||
1670 (Subtarget.hasSME2() &&
1671 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1679 bool NeedsFrameRecord) {
1698 (
Count & 1) == 0) &&
1699 "Odd number of callee-saved regs to spill!");
1701 int StackFillDir = -1;
1703 unsigned FirstReg = 0;
1711 FirstReg =
Count - 1;
1723 bool SpillExtendedVolatile =
1725 const auto &
Reg = CSI.getReg();
1726 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1729 int ZPRByteOffset = 0;
1730 int PPRByteOffset = 0;
1735 }
else if (!FPAfterSVECalleeSaves) {
1746 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1747 if (StackFillDir < 0)
1753 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1755 RPI.Reg1 = CSI[i].getReg();
1757 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1758 RPI.Type = RegPairInfo::GPR;
1759 RPI.RC = &AArch64::GPR64RegClass;
1760 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1761 RPI.Type = RegPairInfo::FPR64;
1762 RPI.RC = &AArch64::FPR64RegClass;
1763 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1764 RPI.Type = RegPairInfo::FPR128;
1765 RPI.RC = &AArch64::FPR128RegClass;
1766 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1767 RPI.Type = RegPairInfo::ZPR;
1768 RPI.RC = &AArch64::ZPRRegClass;
1769 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1770 RPI.Type = RegPairInfo::PPR;
1771 RPI.RC = &AArch64::PPRRegClass;
1772 }
else if (RPI.Reg1 == AArch64::VG) {
1773 RPI.Type = RegPairInfo::VG;
1774 RPI.RC = &AArch64::FIXED_REGSRegClass;
1779 int &ScalableByteOffset = RPI.Type == RegPairInfo::PPR && SplitPPRs
1784 if (HasCSHazardPadding &&
1787 ByteOffset += StackFillDir * StackHazardSize;
1791 int Scale =
TRI->getSpillSize(*RPI.RC);
1793 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1794 MCRegister NextReg = CSI[i + RegInc].getReg();
1795 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1796 int Aligned = AlignOffset(ByteOffset, Scale);
1797 int PairOffset = IsWindows ?
Aligned :
Aligned + StackFillDir * 2 * Scale;
1798 bool PairFitsImmRange =
1799 PairOffset / Scale >= -64 && PairOffset / Scale <= 63;
1801 case RegPairInfo::GPR:
1802 if (AArch64::GPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1804 RPI.Reg1, NextReg, IsWindows,
1805 NeedsWinCFI, NeedsFrameRecord,
TRI))
1808 case RegPairInfo::FPR64:
1809 if (AArch64::FPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1811 RPI.Reg1, NextReg, IsWindows,
1812 NeedsWinCFI, NeedsFrameRecord,
TRI))
1815 case RegPairInfo::FPR128:
1816 if (AArch64::FPR128RegClass.
contains(NextReg) && PairFitsImmRange)
1819 case RegPairInfo::PPR:
1821 case RegPairInfo::ZPR:
1831 if (((NextReg - AArch64::Z0) % 2 == 0) && (NextReg + 1 == RPI.Reg1)) {
1832 const int NumRegs = 2;
1833 int Offset = (ScalableByteOffset + StackFillDir * NumRegs * Scale);
1840 case RegPairInfo::VG:
1851 assert((!RPI.isPaired() ||
1852 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1853 "Out of order callee saved regs!");
1855 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1856 RPI.Reg1 == AArch64::LR) &&
1857 "FrameRecord must be allocated together with LR");
1860 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1861 RPI.Reg2 == AArch64::LR) &&
1862 "FrameRecord must be allocated together with LR");
1870 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1871 RPI.Reg1 + 1 == RPI.Reg2))) &&
1872 "Callee-save registers not saved as adjacent register pair!");
1874 RPI.FrameIdx = CSI[i].getFrameIdx();
1877 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1881 if (RPI.isScalable() && ScalableByteOffset % Scale != 0)
1882 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1886 if (!RPI.isScalable() && ByteOffset % Scale != 0)
1887 ByteOffset = AlignOffset(ByteOffset, Scale);
1889 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1890 assert(OffsetPre % Scale == 0);
1892 if (RPI.isScalable())
1893 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1895 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1900 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1901 (IsWindows && RPI.Reg2 == AArch64::LR)))
1902 ByteOffset += StackFillDir * 8;
1906 if (NeedGapToAlignStack && !IsWindows && !RPI.isScalable() &&
1907 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1908 ByteOffset % 16 != 0) {
1909 ByteOffset += 8 * StackFillDir;
1915 NeedGapToAlignStack =
false;
1918 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1919 assert(OffsetPost % Scale == 0);
1922 int Offset = IsWindows ? OffsetPre : OffsetPost;
1927 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1928 (IsWindows && RPI.Reg2 == AArch64::LR)))
1930 RPI.Offset =
Offset / Scale;
1932 assert((!RPI.isPaired() ||
1933 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1934 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1935 "Offset out of bounds for LDP/STP immediate");
1937 auto isFrameRecord = [&] {
1939 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1940 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1948 return i > 0 && RPI.Reg1 == AArch64::FP &&
1949 CSI[i - 1].getReg() == AArch64::LR;
1954 if (NeedsFrameRecord && isFrameRecord())
1971 std::reverse(RegPairs.
begin(), RegPairs.
end());
1993 if (homogeneousPrologEpilog(MF)) {
1997 for (
auto &RPI : RegPairs) {
2003 MBB.addLiveIn(RPI.Reg1);
2004 if (RPI.isPaired() && !MRI.
isReserved(RPI.Reg2))
2005 MBB.addLiveIn(RPI.Reg2);
2009 bool PTrueCreated =
false;
2025 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2026 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2028 case RegPairInfo::GPR:
2029 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2031 case RegPairInfo::FPR64:
2032 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2034 case RegPairInfo::FPR128:
2035 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2037 case RegPairInfo::ZPR:
2038 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2040 case RegPairInfo::PPR:
2041 StrOpc = AArch64::STR_PXI;
2043 case RegPairInfo::VG:
2044 StrOpc = AArch64::STRXui;
2056 if (Reg1 == AArch64::VG) {
2058 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2069 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2070 AArch64::X0, LiveIn.PhysReg);
2078 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2080 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2094 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2096 dbgs() <<
", " << RPI.FrameIdx + 1;
2101 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2102 "Windows unwdinding requires a consecutive (FP,LR) pair");
2103 unsigned FrameIdxReg1 = RPI.FrameIdx;
2104 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2106 if (RPI.isPaired() && RPI.isScalable()) {
2108 "Scalable register groups are not supported by Windows WinCFI");
2114 "Expects SVE2.1 or SME2 target and a predicate register");
2115#ifdef EXPENSIVE_CHECKS
2116 auto IsPPR = [](
const RegPairInfo &c) {
2117 return c.Type == RegPairInfo::PPR;
2119 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2120 auto IsZPR = [](
const RegPairInfo &c) {
2121 return c.Type == RegPairInfo::ZPR;
2123 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2124 assert(!(PPRBegin < ZPRBegin) &&
2125 "Expected callee save predicate to be handled first");
2127 if (!PTrueCreated) {
2128 PTrueCreated =
true;
2134 MBB.addLiveIn(Reg1);
2136 MBB.addLiveIn(Reg2);
2137 assert(RPI.Reg2 + 1 == RPI.Reg1 &&
"Expected reversed ZPR pair");
2138 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg2 - AArch64::Z0));
2160 MBB.addLiveIn(Reg1);
2161 if (RPI.isPaired()) {
2163 MBB.addLiveIn(Reg2);
2182 if (RPI.Type == RegPairInfo::ZPR) {
2186 }
else if (RPI.Type == RegPairInfo::PPR) {
2206 DL =
MBBI->getDebugLoc();
2209 if (homogeneousPrologEpilog(MF, &
MBB)) {
2212 for (
auto &RPI : RegPairs) {
2220 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2222 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2223 std::reverse(PPRBegin, PPREnd);
2224 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2226 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2227 std::reverse(ZPRBegin, ZPREnd);
2229 bool PTrueCreated =
false;
2230 for (
const RegPairInfo &RPI : RegPairs) {
2243 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2244 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2246 case RegPairInfo::GPR:
2247 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2249 case RegPairInfo::FPR64:
2250 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2252 case RegPairInfo::FPR128:
2253 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2255 case RegPairInfo::ZPR:
2256 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2258 case RegPairInfo::PPR:
2259 LdrOpc = AArch64::LDR_PXI;
2261 case RegPairInfo::VG:
2268 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2270 dbgs() <<
", " << RPI.FrameIdx + 1;
2274 unsigned FrameIdxReg1 = RPI.FrameIdx;
2275 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2278 if (RPI.isPaired() && RPI.isScalable()) {
2280 "Scalable register groups are not supported by Windows WinCFI");
2285 "Expects SVE2.1 or SME2 target and a predicate register");
2286#ifdef EXPENSIVE_CHECKS
2287 assert(!(PPRBegin < ZPRBegin) &&
2288 "Expected callee save predicate to be handled first");
2290 if (!PTrueCreated) {
2291 PTrueCreated =
true;
2296 assert(RPI.Reg2 + 1 == RPI.Reg1 &&
"Expected reversed ZPR pair");
2297 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg2 - AArch64::Z0),
2319 if (RPI.isPaired()) {
2346 return std::optional<int>(PSV->getFrameIndex());
2357 return std::nullopt;
2363 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2364 return std::nullopt;
2371 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2377void AArch64FrameLowering::determineStackHazardSlot(
2380 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2381 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2387 const AArch64Options &CLOpts =
2389 if (!CLOpts.stack_hazard_in_non_streaming &&
2390 Attrs.hasNonStreamingInterfaceAndBody())
2398 return AArch64::FPR64RegClass.contains(Reg) ||
2399 AArch64::FPR128RegClass.contains(Reg) ||
2400 AArch64::ZPRRegClass.contains(Reg);
2403 return AArch64::PPRRegClass.contains(Reg);
2405 bool HasFPRStackObjects =
false;
2406 bool HasPPRStackObjects =
false;
2407 if (!HasFPRCSRs || CLOpts.split_sve_objects) {
2408 enum SlotType : uint8_t {
2419 for (
auto &
MBB : MF) {
2420 for (
auto &
MI :
MBB) {
2422 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2429 ? SlotType::ZPRorFPR
2435 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2436 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2439 if (SlotTypes[FI] == SlotType::PPR) {
2441 HasPPRStackObjects =
true;
2446 if (HasFPRCSRs || HasFPRStackObjects) {
2449 << StackHazardSize <<
"\n");
2456 if (CLOpts.split_sve_objects) {
2460 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2466 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2467 "non-SVE CC function...\n");
2474 <<
"Calling convention is not supported with SplitSVEObjects\n");
2478 if (!HasPPRCSRs && !HasPPRStackObjects) {
2480 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2484 if (!HasFPRCSRs && !HasFPRStackObjects) {
2487 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2491 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2492 MF.getSubtarget<AArch64Subtarget>();
2494 "Expected SVE to be available for PPRs");
2496 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2500 BitVector FPRZRegs(SavedRegs.
size());
2501 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2502 BitVector::reference RegBit = SavedRegs[
Reg];
2505 unsigned SubRegIdx = 0;
2507 SubRegIdx = AArch64::dsub;
2509 SubRegIdx = AArch64::zsub;
2516 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2519 SavedRegs |= FPRZRegs;
2546 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2549 bool HasUnpairedGPR64 =
false;
2550 bool HasPairZReg =
false;
2551 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2552 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2555 for (
unsigned i = 0; CSRegs[i]; ++i) {
2559 if (Reg == BasePointerReg)
2564 if (UserReservedRegs[Reg]) {
2565 SavedRegs.
reset(Reg);
2569 bool RegUsed = SavedRegs.
test(Reg);
2571 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2572 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2573 AArch64::FPR128RegClass.
contains(Reg)) {
2576 if (HasUnpairedGPR64)
2577 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2579 PairedReg = CSRegs[i ^ 1];
2586 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2588 HasUnpairedGPR64 =
true;
2591 AArch64::GPR64RegClass.contains(Reg, PairedReg) ||
2592 AArch64::FPR64RegClass.contains(Reg, PairedReg) ||
2593 AArch64::FPR128RegClass.contains(Reg, PairedReg));
2596 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2597 UnspilledCSGPR = Reg;
2598 UnspilledCSGPRPaired = PairedReg;
2606 if (producePairRegisters(MF) && PairedReg.
isValid() &&
2607 !SavedRegs.
test(PairedReg)) {
2608 SavedRegs.
set(PairedReg);
2609 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2610 !ReservedRegs[PairedReg])
2611 ExtraCSSpill = PairedReg;
2614 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2615 SavedRegs.
test(CSRegs[i ^ 1]));
2623 if (PnReg.isValid())
2629 SavedRegs.
set(AArch64::P8);
2634 "Predicate cannot be a reserved register");
2644 SavedRegs.
set(AArch64::X18);
2650 determineStackHazardSlot(MF, SavedRegs);
2653 unsigned CSStackSize = 0;
2654 unsigned ZPRCSStackSize = 0;
2655 unsigned PPRCSStackSize = 0;
2657 for (
unsigned Reg : SavedRegs.
set_bits()) {
2659 assert(RC &&
"expected register class!");
2660 auto SpillSize =
TRI->getSpillSize(*RC);
2661 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2662 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2664 ZPRCSStackSize += SpillSize;
2666 PPRCSStackSize += SpillSize;
2672 return SavedRegs.test(SuperReg);
2675 CSStackSize += SpillSize;
2682 unsigned NumSavedRegs = SavedRegs.
count();
2695 SavedRegs.
set(AArch64::LR);
2700 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2701 SavedRegs.
set(AArch64::FP);
2702 SavedRegs.
set(AArch64::LR);
2706 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2707 for (
unsigned Reg : SavedRegs.
set_bits())
2713 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2715 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2716 uint64_t SVEStackSize =
2717 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2718 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2727 int64_t CalleeStackUsed = 0;
2730 if (FixedOff > CalleeStackUsed)
2731 CalleeStackUsed = FixedOff;
2735 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2736 CalleeStackUsed) > EstimatedStackSizeLimit;
2737 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2747 if (!ExtraCSSpill.
isValid() && UnspilledCSGPR.isValid()) {
2749 <<
" to get a scratch register.\n");
2750 SavedRegs.
set(UnspilledCSGPR);
2751 ExtraCSSpill = UnspilledCSGPR;
2756 if (producePairRegisters(MF)) {
2757 if (!UnspilledCSGPRPaired.
isValid()) {
2760 SavedRegs.
reset(UnspilledCSGPR);
2764 SavedRegs.
set(UnspilledCSGPRPaired);
2770 if (!ExtraCSSpill.
isValid() ||
2774 unsigned Size =
TRI->getSpillSize(RC);
2775 Align Alignment =
TRI->getSpillAlign(RC);
2777 RS->addScavengingFrameIndex(FI);
2778 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2779 <<
" as the emergency spill slot.\n");
2784 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2791 uint64_t AlignedCSStackSize =
alignTo(CSStackSize, 16);
2793 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2797 "Should not invalidate callee saved info");
2808 std::vector<CalleeSavedInfo> &CSI) {
2813 "ZPR callee-save reordering not supported on Windows");
2823 if (AArch64::ZPRRegClass.
contains(CS.getReg())) {
2829 if (ZPRSaves.
size() < 2)
2832 llvm::sort(ZPRSaves, [](
const auto &
A,
const auto &
B) {
2833 return A.getReg() <
B.getReg();
2838 for (
size_t i = 0; i < ZPRSaves.
size();) {
2839 if (i + 1 < ZPRSaves.
size() &&
2840 (ZPRSaves[i].getReg() + 1 == ZPRSaves[i + 1].getReg()) &&
2841 (ZPRSaves[i].getReg() - AArch64::Z0) % 2 == 0) {
2842 Pairs.emplace_back(ZPRSaves[i], ZPRSaves[i + 1]);
2855 const int Scale =
RegInfo->getSpillSize(AArch64::ZPRRegClass);
2856 const int LowestOffset =
2857 (ZPRByteOffset / Scale) -
static_cast<int>(ZPRSaves.
size());
2860 std::optional<CalleeSavedInfo> AlignmentSingle;
2861 if (LowestOffset % 2 != 0) {
2862 if (!Singles.
empty()) {
2865 assert(!Pairs.empty() &&
"Expected a ZPR pair to split");
2866 auto [Even, Odd] = Pairs.pop_back_val();
2867 AlignmentSingle = Odd;
2880 for (
const auto &[Even, Odd] : Pairs) {
2885 if (AlignmentSingle)
2886 ZPRSavesInCSIOrder.
push_back(*AlignmentSingle);
2889 "Reordering should not change the number of ZPR spills");
2890 for (
auto [Position, CS] :
llvm::zip(ZPRPositions, ZPRSavesInCSIOrder))
2896 std::vector<CalleeSavedInfo> &CSI)
const {
2905 std::reverse(CSI.begin(), CSI.end());
2919 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2920 if (It != CSI.end())
2921 CSI.insert(It, VGInfo);
2923 CSI.push_back(VGInfo);
2933 int HazardSlotIndex = std::numeric_limits<int>::max();
2934 for (
auto &CS : CSI) {
2942 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2943 "Unexpected register order for hazard slot");
2945 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2951 unsigned Size = RegInfo->getSpillSize(*RC);
2952 Align Alignment(RegInfo->getSpillAlign(*RC));
2954 CS.setFrameIdx(FrameIdx);
2968 HazardSlotIndex == std::numeric_limits<int>::max()) {
2970 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2997 int &Min,
int &Max) {
2998 Min = std::numeric_limits<int>::max();
2999 Max = std::numeric_limits<int>::min();
3005 for (
auto &CS : CSI) {
3006 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
3007 AArch64::PPRRegClass.contains(CS.getReg())) {
3008 assert((Max == std::numeric_limits<int>::min() ||
3009 Max + 1 == CS.getFrameIdx()) &&
3010 "SVE CalleeSaves are not consecutive");
3011 Min = std::min(Min, CS.getFrameIdx());
3012 Max = std::max(Max, CS.getFrameIdx());
3015 return Min != std::numeric_limits<int>::max();
3028 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
3036 "SVE vectors should never be passed on the stack by value, only by "
3040 auto AllocateObject = [&](
int FI) {
3049 if (Alignment >
Align(16))
3051 "Alignment of scalable vectors > 16 bytes is not yet supported");
3054 StackTop =
alignTo(StackTop, Alignment);
3056 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
3057 "SVE StackTop far too large?!");
3059 int64_t
Offset = -int64_t(StackTop);
3067 int MinCSFrameIndex, MaxCSFrameIndex;
3069 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
3082 int StackProtectorFI = -1;
3086 ObjectsToAllocate.
push_back(StackProtectorFI);
3102 for (
unsigned FI : ObjectsToAllocate)
3117 "Upwards growing stack unsupported");
3132 int64_t CurrentOffset =
3136 int FrameIndex =
H.CatchObj.FrameIndex;
3137 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3148 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3149 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3151 "UnwindHelpOffset must be at the start of the fixed object area");
3154 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3164 RS->enterBasicBlockEnd(
MBB);
3166 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3167 assert(DstReg &&
"There must be a free register after frame setup");
3178struct TagStoreInstr {
3187 MachineBasicBlock *
MBB;
3188 MachineRegisterInfo *MRI;
3197 StackOffset FrameRegOffset;
3201 std::optional<int64_t> FrameRegUpdate;
3203 unsigned FrameRegUpdateFlags;
3213 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3214 :
MBB(
MBB), ZeroData(ZeroData) {
3220 void addInstruction(TagStoreInstr
I) {
3222 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3223 "Non-adjacent tag store instructions.");
3226 void clear() { TagStores.
clear(); }
3231 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3238 const int64_t kMinOffset = -256 * 16;
3239 const int64_t kMaxOffset = 255 * 16;
3242 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3243 if (BaseRegOffsetBytes < kMinOffset ||
3244 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3248 BaseRegOffsetBytes % 16 != 0) {
3253 BaseRegOffsetBytes = 0;
3258 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3261 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3263 assert(BaseRegOffsetBytes % 16 == 0);
3267 .
addImm(BaseRegOffsetBytes / 16)
3271 if (BaseRegOffsetBytes == 0)
3273 BaseRegOffsetBytes += InstrSize;
3292 int64_t LoopSize =
Size;
3295 if (FrameRegUpdate && *FrameRegUpdate)
3296 LoopSize -= LoopSize % 32;
3298 TII->get(ZeroData ? AArch64::STZGloop_wback
3299 : AArch64::STGloop_wback))
3306 LoopI->
setFlags(FrameRegUpdateFlags);
3308 int64_t ExtraBaseRegUpdate =
3309 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3310 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3311 <<
", Size=" <<
Size
3312 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3313 <<
", FrameRegUpdate=" << FrameRegUpdate
3314 <<
", FrameRegOffset.getFixed()="
3315 << FrameRegOffset.
getFixed() <<
"\n");
3316 if (LoopSize <
Size) {
3320 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3321 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3322 "STG immediate out of range");
3324 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3331 }
else if (ExtraBaseRegUpdate) {
3333 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3334 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3337 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3350 int64_t
Size, int64_t *TotalOffset) {
3352 if ((
MI.getOpcode() == AArch64::ADDXri ||
3353 MI.getOpcode() == AArch64::SUBXri) &&
3354 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3356 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3357 if (
MI.getOpcode() == AArch64::SUBXri)
3368 const int64_t kMaxOffset = 4080 - 16;
3370 const int64_t kMinOffset = -4095;
3371 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3372 PostOffset % 16 == 0) {
3383 for (
auto &TS : TSE) {
3387 if (
MI->memoperands_empty()) {
3391 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3397 bool TryMergeSPUpdate) {
3398 if (TagStores.
empty())
3400 TagStoreInstr &FirstTagStore = TagStores[0];
3401 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3402 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3403 DL = TagStores[0].MI->getDebugLoc();
3407 *MF, FirstTagStore.Offset,
false ,
3411 FrameRegUpdate = std::nullopt;
3413 mergeMemRefs(TagStores, CombinedMemRefs);
3416 dbgs() <<
"Replacing adjacent STG instructions:\n";
3417 for (
const auto &Instr : TagStores) {
3426 if (TagStores.
size() < 2)
3428 emitUnrolled(InsertI);
3431 int64_t TotalOffset = 0;
3432 if (TryMergeSPUpdate) {
3438 if (InsertI !=
MBB->
end() &&
3439 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3441 UpdateInstr = &*InsertI++;
3447 if (!UpdateInstr && TagStores.
size() < 2)
3451 FrameRegUpdate = TotalOffset;
3452 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3459 for (
auto &TS : TagStores)
3460 TS.MI->eraseFromParent();
3464 int64_t &
Size,
bool &ZeroData) {
3468 unsigned Opcode =
MI.getOpcode();
3469 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3470 Opcode == AArch64::STZ2Gi);
3472 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3473 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3475 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3478 Size =
MI.getOperand(2).getImm();
3482 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3484 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3489 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3493 16 *
MI.getOperand(2).getImm();
3497static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3502 return LiveRegs.available(MRI,
Reg);
3505 size_t NumEmergencySlots = 0;
3507 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3509 return FreeGPRs + NumEmergencySlots;
3528 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3534 constexpr int kScanLimit = 10;
3537 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3546 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3547 if (ZeroData != FirstZeroData)
3555 if (!
MI.isTransient())
3564 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3580 LiveRegs.addLiveOuts(*
MBB);
3585 LiveRegs.stepBackward(*
I);
3588 if (LiveRegs.contains(AArch64::NZCV))
3599 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3600 <<
"due to high register pressure.\n");
3605 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3610 int64_t CurOffset = Instrs[0].Offset;
3611 for (
auto &Instr : Instrs) {
3612 if (CurOffset >
Instr.Offset)
3619 TagStoreEdit TSE(
MBB, FirstZeroData);
3620 std::optional<int64_t> EndOffset;
3621 for (
auto &Instr : Instrs) {
3622 if (EndOffset && *EndOffset !=
Instr.Offset) {
3624 TSE.emitCode(InsertI, TFI,
false);
3628 TSE.addInstruction(Instr);
3646 .stack_tagging_merge_settag;
3650 II = tryMergeAdjacentSTG(
II,
this, RS);
3657 shouldSignReturnAddressEverywhere(MF))
3666 bool IgnoreSPUpdates)
const {
3668 if (IgnoreSPUpdates) {
3671 FrameReg = AArch64::SP;
3681 FrameReg = AArch64::SP;
3706 bool IsValid =
false;
3708 int ObjectIndex = 0;
3710 int GroupIndex = -1;
3712 bool ObjectFirst =
false;
3715 bool GroupFirst =
false;
3720 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3724 SmallVector<int, 8> CurrentMembers;
3725 int NextGroupIndex = 0;
3726 std::vector<FrameObject> &Objects;
3729 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3730 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3731 void EndCurrentGroup() {
3732 if (CurrentMembers.
size() > 1) {
3737 for (
int Index : CurrentMembers) {
3738 Objects[
Index].GroupIndex = NextGroupIndex;
3744 CurrentMembers.clear();
3748bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3770 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3771 A.GroupIndex,
A.ObjectIndex) <
3772 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3773 B.GroupIndex,
B.ObjectIndex);
3783 ObjectsToAllocate.
empty())
3788 for (
auto &Obj : ObjectsToAllocate) {
3789 FrameObjects[Obj].IsValid =
true;
3790 FrameObjects[Obj].ObjectIndex = Obj;
3795 GroupBuilder GB(FrameObjects);
3796 for (
auto &
MBB : MF) {
3797 for (
auto &
MI :
MBB) {
3798 if (
MI.isDebugInstr())
3803 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3806 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3808 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3813 switch (
MI.getOpcode()) {
3814 case AArch64::STGloop:
3815 case AArch64::STZGloop:
3819 case AArch64::STZGi:
3820 case AArch64::ST2Gi:
3821 case AArch64::STZ2Gi:
3834 FrameObjects[FI].IsValid)
3842 GB.AddMember(TaggedFI);
3844 GB.EndCurrentGroup();
3847 GB.EndCurrentGroup();
3852 FrameObject::AccessHazard;
3854 for (
auto &Obj : FrameObjects)
3855 if (!Obj.Accesses ||
3856 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3857 Obj.Accesses = FrameObject::AccessGPR;
3866 FrameObjects[*TBPI].ObjectFirst =
true;
3867 FrameObjects[*TBPI].GroupFirst =
true;
3868 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3869 if (FirstGroupIndex >= 0)
3870 for (FrameObject &Object : FrameObjects)
3871 if (Object.GroupIndex == FirstGroupIndex)
3872 Object.GroupFirst =
true;
3878 for (
auto &Obj : FrameObjects) {
3882 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3886 dbgs() <<
"Final frame order:\n";
3887 for (
auto &Obj : FrameObjects) {
3890 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3891 if (Obj.ObjectFirst)
3892 dbgs() <<
", first";
3894 dbgs() <<
", group-first";
3905AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3916 MF.
insert(MBBInsertPoint, LoopMBB);
3918 MF.
insert(MBBInsertPoint, ExitMBB);
3953 MBB.addSuccessor(LoopMBB);
3957 return ExitMBB->
begin();
3960void AArch64FrameLowering::inlineStackProbeFixed(
3965 const AArch64InstrInfo *
TII =
3967 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
3972 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
3973 int64_t NumBlocks = FrameSize / ProbeSize;
3974 int64_t ResidualSize = FrameSize % ProbeSize;
3976 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
3977 << NumBlocks <<
" blocks of " << ProbeSize
3978 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
3983 for (
int i = 0; i < NumBlocks; ++i) {
3989 EmitAsyncCFI && !HasFP, CFAOffset);
4002 }
else if (NumBlocks != 0) {
4008 EmitAsyncCFI && !HasFP, CFAOffset);
4010 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
4012 if (EmitAsyncCFI && !HasFP) {
4015 .buildDefCFARegister(AArch64::SP);
4019 if (ResidualSize != 0) {
4025 EmitAsyncCFI && !HasFP, CFAOffset);
4046 SmallVector<MachineInstr *, 4> ToReplace;
4047 for (MachineInstr &
MI :
MBB)
4048 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
4049 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
4052 for (MachineInstr *
MI : ToReplace) {
4053 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
4054 Register ScratchReg =
MI->getOperand(0).getReg();
4055 int64_t FrameSize =
MI->getOperand(1).getImm();
4057 MI->getOperand(3).getImm());
4058 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
4061 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
4062 "Stack probe pseudo-instruction expected");
4063 const AArch64InstrInfo *
TII =
4064 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
4065 Register TargetReg =
MI->getOperand(0).getReg();
4066 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
4068 MI->eraseFromParent();
4088 return std::make_tuple(
start(),
Idx) <
4089 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4119 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4120 if (
Offset.getScalable())
4121 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4132void AArch64FrameLowering::emitRemarks(
4135 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4143 .stack_hazard_remark_size;
4145 if (HazardSize == 0)
4153 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4155 size_t NumFPLdSt = 0;
4156 size_t NumNonFPLdSt = 0;
4159 for (
const MachineBasicBlock &
MBB : MF) {
4160 for (
const MachineInstr &
MI :
MBB) {
4161 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4163 for (MachineMemOperand *MMO :
MI.memoperands()) {
4170 StackAccesses[ArrIdx].Idx = FrameIdx;
4171 StackAccesses[ArrIdx].Offset =
4182 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4193 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4204 if (StackAccesses.front().isMixed())
4205 MixedObjects.push_back(&StackAccesses.front());
4207 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4209 const auto &
First = *It;
4210 const auto &Second = *(It + 1);
4212 if (Second.isMixed())
4213 MixedObjects.push_back(&Second);
4215 if ((
First.isSME() && Second.isCPU()) ||
4216 (
First.isCPU() && Second.isSME())) {
4218 if (Distance < HazardSize)
4223 auto EmitRemark = [&](llvm::StringRef Str) {
4225 auto R = MachineOptimizationRemarkAnalysis(
4226 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4227 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4231 for (
const auto &
P : HazardPairs)
4232 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4234 for (
const auto *Obj : MixedObjects)
4236 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 void orderZPRCalleeSavesForPairs(MachineFunction &MF, const TargetRegisterInfo *RegInfo, std::vector< CalleeSavedInfo > &CSI)
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 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 needsWinCFI(const MachineFunction &MF) const
bool isFPReserved(const MachineFunction &MF) const
Should the Frame Pointer be reserved for the current function?
void processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameFinalized - This method is called immediately before the specified function...
int getSEHFrameIndexOffset(const MachineFunction &MF, int FI) const
unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const
Funclets only need to account for space for the callee saved registers, as the locals are accounted f...
void orderFrameObjects(const MachineFunction &MF, SmallVectorImpl< int > &ObjectsToAllocate) const override
Order the symbols in the local stack frame.
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
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...
bool usesWindowsCFI() const
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.
Function & getFunction()
Return the LLVM function that this machine code represents.
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),...
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
const MCAsmInfo & getMCAsmInfo() const
Return target specific asm information.
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.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
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
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
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 append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
@ 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.
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