267#define DEBUG_TYPE "frame-info"
270 cl::desc(
"enable use of redzone on AArch64"),
274 "stack-tagging-merge-settag",
284 cl::desc(
"Split allocation of ZPR & PPR objects"),
289 cl::desc(
"Emit homogeneous prologue and epilogue for the size "
290 "optimization (default = off)"));
302 "aarch64-disable-multivector-spill-fill",
311 bool IsTailCallReturn = (
MBB.end() !=
MBBI)
315 int64_t ArgumentPopSize = 0;
316 if (IsTailCallReturn) {
322 ArgumentPopSize = StackAdjust.
getImm();
331 return ArgumentPopSize;
399bool AArch64FrameLowering::homogeneousPrologEpilog(
432 unsigned NumGPRs = 0;
433 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
435 if (Reg == AArch64::LR) {
436 assert(CSRegs[
I + 1] == AArch64::FP);
437 if (NumGPRs % 2 != 0)
449bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
468 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
469 MI.getOpcode() == AArch64::ADDXri ||
470 MI.getOpcode() == AArch64::ADDSXri)
495 bool IsWin64,
bool IsFunclet)
const {
497 "Tail call reserved stack must be aligned to 16 bytes");
498 if (!IsWin64 || IsFunclet) {
503 Attribute::SwiftAsync))
517 int FrameIndex =
H.CatchObj.FrameIndex;
518 if ((FrameIndex != INT_MAX) &&
519 CatchObjFrameIndices.
insert(FrameIndex)) {
520 FixedObjectSize =
alignTo(FixedObjectSize,
527 FixedObjectSize += 8;
529 return alignTo(FixedObjectSize, 16);
540 const unsigned RedZoneSize =
553 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
557 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
578 RegInfo->hasStackRealignment(MF))
625 if (TT.isOSDarwin() || TT.isOSWindows())
663 unsigned Opc =
I->getOpcode();
664 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
665 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
668 int64_t Amount =
I->getOperand(0).getImm();
676 if (CalleePopAmount == 0) {
687 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
698 "non-reserved call frame without var sized objects?");
707 }
else if (CalleePopAmount != 0) {
710 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
722 const auto &
TRI = *Subtarget.getRegisterInfo();
728 CFIBuilder.buildDefCFA(AArch64::SP, 0);
731 if (MFI.shouldSignReturnAddress(MF))
732 MFI.branchProtectionPAuthLR() ? CFIBuilder.buildNegateRAStateWithPC()
733 : CFIBuilder.buildNegateRAState();
736 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
737 CFIBuilder.buildSameValue(AArch64::X18);
740 const std::vector<CalleeSavedInfo> &CSI =
742 for (
const auto &Info : CSI) {
744 if (!
TRI.regNeedsCFI(Reg, Reg))
746 CFIBuilder.buildSameValue(Reg);
759 case AArch64::W##n: \
760 case AArch64::X##n: \
785 case AArch64::B##n: \
786 case AArch64::H##n: \
787 case AArch64::S##n: \
788 case AArch64::D##n: \
789 case AArch64::Q##n: \
790 return HasSVE ? AArch64::Z##n : AArch64::Q##n
827void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
838 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
841 BitVector GPRsToZero(
TRI.getNumRegs());
842 BitVector FPRsToZero(
TRI.getNumRegs());
845 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
848 GPRsToZero.set(XReg);
852 FPRsToZero.set(XReg);
859 for (MCRegister
Reg : GPRsToZero.set_bits())
863 for (MCRegister
Reg : FPRsToZero.set_bits())
867 for (MCRegister PReg :
868 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
869 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
870 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
872 if (RegsToZero[PReg])
878bool AArch64FrameLowering::windowsRequiresStackProbe(
880 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
881 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
885 StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
894 for (
unsigned i = 0; CSRegs[i]; ++i)
900 bool HasCall)
const {
910 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
912 LivePhysRegs LiveRegs(
TRI);
915 LiveRegs.addReg(AArch64::X16);
916 LiveRegs.addReg(AArch64::X17);
917 LiveRegs.addReg(AArch64::X18);
921 const MachineRegisterInfo &MRI = MF->
getRegInfo();
922 if (LiveRegs.available(MRI, AArch64::X9))
925 for (
unsigned Reg : AArch64::GPR64RegClass) {
926 if (LiveRegs.available(MRI,
Reg))
929 return AArch64::NoRegister;
948 if (!
LiveRegs.available(MRI, AArch64::X16) ||
949 !
LiveRegs.available(MRI, AArch64::X17))
956 MBB.isLiveIn(AArch64::NZCV))
960 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
966 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
967 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
976 F.needsUnwindTableEntry();
979bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
995 unsigned Opc =
MBBI->getOpcode();
999 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1000 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1008 case AArch64::STR_ZXI:
1009 case AArch64::LDR_ZXI: {
1010 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1017 case AArch64::STR_PXI:
1018 case AArch64::LDR_PXI: {
1019 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1026 case AArch64::LDPDpost:
1029 case AArch64::STPDpre: {
1030 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1031 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1032 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1039 case AArch64::LDPXpost:
1042 case AArch64::STPXpre: {
1045 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1046 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1050 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1051 .
addImm(RegInfo->getSEHRegNum(Reg0))
1052 .
addImm(RegInfo->getSEHRegNum(Reg1))
1057 case AArch64::LDRDpost:
1060 case AArch64::STRDpre: {
1061 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1062 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1068 case AArch64::LDRXpost:
1071 case AArch64::STRXpre: {
1072 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1079 case AArch64::STPDi:
1080 case AArch64::LDPDi: {
1081 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1082 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1090 case AArch64::STPXi:
1091 case AArch64::LDPXi: {
1095 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1096 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1098 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1102 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1109 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1116 case AArch64::STRXui:
1117 case AArch64::LDRXui: {
1118 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1125 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1131 case AArch64::STRDui:
1132 case AArch64::LDRDui: {
1133 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1140 case AArch64::STPQi:
1141 case AArch64::LDPQi: {
1142 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1143 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1144 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1151 case AArch64::LDPQpost:
1154 case AArch64::STPQpre: {
1155 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1156 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1157 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1176 if (ST.isTargetDarwin())
1198 DL =
MBBI->getDebugLoc();
1200 TII->createPauthEpilogueInstr(
MBB,
DL);
1204 EmitSignRA(MF.
front());
1206 if (
MBB.isEHFuncletEntry())
1208 if (
MBB.isReturnBlock())
1264 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1269 if (MFI.isVariableSizedObjectIndex(FI)) {
1279 if (MFI.hasScalableStackID(FI)) {
1280 if (FPAfterSVECalleeSaves &&
1283 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1291 AccessOffset = -PPRStackSize;
1292 return AccessOffset +
1297 bool IsFixed = MFI.isFixedObjectIndex(FI);
1302 if (!IsFixed && !IsCSR) {
1303 ScalableOffset = -SVEStackSize;
1304 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1319 int64_t ObjectOffset)
const {
1323 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1324 unsigned FixedObject =
1325 getFixedObjectSize(MF, AFI, IsWin64,
false);
1333 int64_t ObjectOffset)
const {
1344 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1345 ? getFPOffset(MF, ObjectOffset).getFixed()
1346 : getStackOffset(MF, ObjectOffset).getFixed();
1351 bool ForSimm)
const {
1353 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1354 bool isFixed = MFI.isFixedObjectIndex(FI);
1357 FrameReg, PreferFP, ForSimm);
1363 bool ForSimm)
const {
1369 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1370 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1373 bool isSVE = MFI.isScalableStackID(StackID);
1377 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1388 PreferFP &= !SVEStackSize;
1396 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1400 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1402 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1407 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1408 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1410 if (FPOffset >= 0) {
1414 }
else if (MFI.hasVarSizedObjects()) {
1418 bool CanUseBP = RegInfo->hasBasePointer(MF);
1419 if (FPOffsetFits && CanUseBP)
1426 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1433 "Funclets should only be present on Win64");
1437 if (FPOffsetFits && PreferFP)
1444 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1445 "In the presence of dynamic stack pointer realignment, "
1446 "non-argument/CSR objects cannot be accessed through the frame pointer");
1463 FPOffset -= PPRStackSize;
1465 SPOffset -= PPRStackSize;
1470 if (FPAfterSVECalleeSaves) {
1481 RegInfo->hasStackRealignment(MF))) {
1482 FrameReg = RegInfo->getFrameRegister(MF);
1485 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1492 if (FPAfterSVECalleeSaves) {
1499 SVEAreaOffset = SVECalleeSavedStack;
1501 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1504 SVEAreaOffset = SVEStackSize;
1506 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1509 if (UseFP && !(isFixed || isCSR))
1510 SVEAreaOffset = -SVEStackSize;
1511 if (!UseFP && (isFixed || isCSR))
1512 SVEAreaOffset = SVEStackSize;
1516 FrameReg = RegInfo->getFrameRegister(MF);
1521 if (RegInfo->hasBasePointer(MF))
1522 FrameReg = RegInfo->getBaseRegister();
1524 assert(!MFI.hasVarSizedObjects() &&
1525 "Can't use SP when we have var sized objects.");
1526 FrameReg = AArch64::SP;
1554 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1560 unsigned SpillCount,
unsigned Reg1,
1561 unsigned Reg2,
bool NeedsWinCFI,
1570 if (Reg2 == AArch64::FP)
1580 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1581 return SpillExtendedVolatile
1582 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1583 (SpillCount % 2) == 0)
1588 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1589 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1599 unsigned SpillCount,
unsigned Reg1,
1600 unsigned Reg2,
bool UsesWinAAPCS,
1601 bool NeedsWinCFI,
bool NeedsFrameRecord,
1605 Reg1, Reg2, NeedsWinCFI,
TRI);
1609 if (NeedsFrameRecord)
1610 return Reg2 == AArch64::LR;
1622 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1623 const TargetRegisterClass *RC;
1625 RegPairInfo() =
default;
1627 bool isPaired()
const {
return Reg2.
isValid(); }
1629 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1635 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1636 if (SavedRegs.
test(PReg)) {
1637 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1651 bool IsLocallyStreaming =
1657 return Subtarget.hasSVE2p1() ||
1658 (Subtarget.hasSME2() &&
1659 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1667 bool NeedsFrameRecord) {
1684 (
Count & 1) == 0) &&
1685 "Odd number of callee-saved regs to spill!");
1687 int StackFillDir = -1;
1689 unsigned FirstReg = 0;
1697 FirstReg =
Count - 1;
1709 bool SpillExtendedVolatile =
1711 const auto &
Reg = CSI.getReg();
1712 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1715 int ZPRByteOffset = 0;
1716 int PPRByteOffset = 0;
1721 }
else if (!FPAfterSVECalleeSaves) {
1732 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1733 if (StackFillDir < 0)
1739 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1741 RPI.Reg1 = CSI[i].getReg();
1743 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1744 RPI.Type = RegPairInfo::GPR;
1745 RPI.RC = &AArch64::GPR64RegClass;
1746 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1747 RPI.Type = RegPairInfo::FPR64;
1748 RPI.RC = &AArch64::FPR64RegClass;
1749 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1750 RPI.Type = RegPairInfo::FPR128;
1751 RPI.RC = &AArch64::FPR128RegClass;
1752 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1753 RPI.Type = RegPairInfo::ZPR;
1754 RPI.RC = &AArch64::ZPRRegClass;
1755 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1756 RPI.Type = RegPairInfo::PPR;
1757 RPI.RC = &AArch64::PPRRegClass;
1758 }
else if (RPI.Reg1 == AArch64::VG) {
1759 RPI.Type = RegPairInfo::VG;
1760 RPI.RC = &AArch64::FIXED_REGSRegClass;
1765 int &ScalableByteOffset = RPI.Type == RegPairInfo::PPR && SplitPPRs
1770 if (HasCSHazardPadding &&
1773 ByteOffset += StackFillDir * StackHazardSize;
1777 int Scale =
TRI->getSpillSize(*RPI.RC);
1779 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1780 MCRegister NextReg = CSI[i + RegInc].getReg();
1781 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1783 case RegPairInfo::GPR:
1784 if (AArch64::GPR64RegClass.
contains(NextReg) &&
1786 RPI.Reg1, NextReg, IsWindows,
1787 NeedsWinCFI, NeedsFrameRecord,
TRI))
1790 case RegPairInfo::FPR64:
1791 if (AArch64::FPR64RegClass.
contains(NextReg) &&
1793 RPI.Reg1, NextReg, IsWindows,
1794 NeedsWinCFI, NeedsFrameRecord,
TRI))
1797 case RegPairInfo::FPR128:
1798 if (AArch64::FPR128RegClass.
contains(NextReg))
1801 case RegPairInfo::PPR:
1803 case RegPairInfo::ZPR:
1805 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
1808 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
1813 case RegPairInfo::VG:
1824 assert((!RPI.isPaired() ||
1825 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1826 "Out of order callee saved regs!");
1828 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1829 RPI.Reg1 == AArch64::LR) &&
1830 "FrameRecord must be allocated together with LR");
1833 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1834 RPI.Reg2 == AArch64::LR) &&
1835 "FrameRecord must be allocated together with LR");
1843 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1844 RPI.Reg1 + 1 == RPI.Reg2))) &&
1845 "Callee-save registers not saved as adjacent register pair!");
1847 RPI.FrameIdx = CSI[i].getFrameIdx();
1850 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1854 if (RPI.isScalable() && ScalableByteOffset % Scale != 0)
1855 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1859 if (!RPI.isScalable() && ByteOffset % Scale != 0)
1860 ByteOffset = AlignOffset(ByteOffset, Scale);
1862 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1863 assert(OffsetPre % Scale == 0);
1865 if (RPI.isScalable())
1866 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1868 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1873 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1874 (IsWindows && RPI.Reg2 == AArch64::LR)))
1875 ByteOffset += StackFillDir * 8;
1879 if (NeedGapToAlignStack && !IsWindows && !RPI.isScalable() &&
1880 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1881 ByteOffset % 16 != 0) {
1882 ByteOffset += 8 * StackFillDir;
1888 NeedGapToAlignStack =
false;
1891 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1892 assert(OffsetPost % Scale == 0);
1895 int Offset = IsWindows ? OffsetPre : OffsetPost;
1900 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1901 (IsWindows && RPI.Reg2 == AArch64::LR)))
1903 RPI.Offset =
Offset / Scale;
1905 assert((!RPI.isPaired() ||
1906 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1907 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1908 "Offset out of bounds for LDP/STP immediate");
1910 auto isFrameRecord = [&] {
1912 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1913 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1921 return i > 0 && RPI.Reg1 == AArch64::FP &&
1922 CSI[i - 1].getReg() == AArch64::LR;
1927 if (NeedsFrameRecord && isFrameRecord())
1944 std::reverse(RegPairs.
begin(), RegPairs.
end());
1966 if (homogeneousPrologEpilog(MF)) {
1970 for (
auto &RPI : RegPairs) {
1976 MBB.addLiveIn(RPI.Reg1);
1977 if (RPI.isPaired() && !MRI.
isReserved(RPI.Reg2))
1978 MBB.addLiveIn(RPI.Reg2);
1982 bool PTrueCreated =
false;
1998 unsigned Size =
TRI->getSpillSize(*RPI.RC);
1999 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2001 case RegPairInfo::GPR:
2002 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2004 case RegPairInfo::FPR64:
2005 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2007 case RegPairInfo::FPR128:
2008 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2010 case RegPairInfo::ZPR:
2011 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2013 case RegPairInfo::PPR:
2014 StrOpc = AArch64::STR_PXI;
2016 case RegPairInfo::VG:
2017 StrOpc = AArch64::STRXui;
2023 if (X0Scratch != AArch64::NoRegister)
2029 if (Reg1 == AArch64::VG) {
2031 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2032 assert(Reg1 != AArch64::NoRegister);
2042 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2043 AArch64::X0, LiveIn.PhysReg);
2051 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2053 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2067 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2069 dbgs() <<
", " << RPI.FrameIdx + 1;
2074 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2075 "Windows unwdinding requires a consecutive (FP,LR) pair");
2079 unsigned FrameIdxReg1 = RPI.FrameIdx;
2080 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2086 if (RPI.isPaired() && RPI.isScalable()) {
2092 "Expects SVE2.1 or SME2 target and a predicate register");
2093#ifdef EXPENSIVE_CHECKS
2094 auto IsPPR = [](
const RegPairInfo &c) {
2095 return c.Reg1 == RegPairInfo::PPR;
2097 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2098 auto IsZPR = [](
const RegPairInfo &c) {
2099 return c.Type == RegPairInfo::ZPR;
2101 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2102 assert(!(PPRBegin < ZPRBegin) &&
2103 "Expected callee save predicate to be handled first");
2105 if (!PTrueCreated) {
2106 PTrueCreated =
true;
2112 MBB.addLiveIn(Reg1);
2114 MBB.addLiveIn(Reg2);
2115 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2132 MBB.addLiveIn(Reg1);
2133 if (RPI.isPaired()) {
2135 MBB.addLiveIn(Reg2);
2154 if (RPI.Type == RegPairInfo::ZPR) {
2158 }
else if (RPI.Type == RegPairInfo::PPR) {
2178 DL =
MBBI->getDebugLoc();
2181 if (homogeneousPrologEpilog(MF, &
MBB)) {
2184 for (
auto &RPI : RegPairs) {
2192 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2194 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2195 std::reverse(PPRBegin, PPREnd);
2196 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2198 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2199 std::reverse(ZPRBegin, ZPREnd);
2201 bool PTrueCreated =
false;
2202 for (
const RegPairInfo &RPI : RegPairs) {
2215 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2216 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2218 case RegPairInfo::GPR:
2219 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2221 case RegPairInfo::FPR64:
2222 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2224 case RegPairInfo::FPR128:
2225 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2227 case RegPairInfo::ZPR:
2228 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2230 case RegPairInfo::PPR:
2231 LdrOpc = AArch64::LDR_PXI;
2233 case RegPairInfo::VG:
2240 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2242 dbgs() <<
", " << RPI.FrameIdx + 1;
2249 unsigned FrameIdxReg1 = RPI.FrameIdx;
2250 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2257 if (RPI.isPaired() && RPI.isScalable()) {
2262 "Expects SVE2.1 or SME2 target and a predicate register");
2263#ifdef EXPENSIVE_CHECKS
2264 assert(!(PPRBegin < ZPRBegin) &&
2265 "Expected callee save predicate to be handled first");
2267 if (!PTrueCreated) {
2268 PTrueCreated =
true;
2273 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
2290 if (RPI.isPaired()) {
2317 return std::optional<int>(PSV->getFrameIndex());
2328 return std::nullopt;
2334 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2335 return std::nullopt;
2342 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2348void AArch64FrameLowering::determineStackHazardSlot(
2351 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2352 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2366 return AArch64::FPR64RegClass.contains(Reg) ||
2367 AArch64::FPR128RegClass.contains(Reg) ||
2368 AArch64::ZPRRegClass.contains(Reg);
2371 return AArch64::PPRRegClass.contains(Reg);
2373 bool HasFPRStackObjects =
false;
2374 bool HasPPRStackObjects =
false;
2376 enum SlotType : uint8_t {
2387 for (
auto &
MBB : MF) {
2388 for (
auto &
MI :
MBB) {
2390 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2397 ? SlotType::ZPRorFPR
2403 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2404 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2407 if (SlotTypes[FI] == SlotType::PPR) {
2409 HasPPRStackObjects =
true;
2414 if (HasFPRCSRs || HasFPRStackObjects) {
2417 << StackHazardSize <<
"\n");
2428 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2434 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2435 "non-SVE CC function...\n");
2442 <<
"Calling convention is not supported with SplitSVEObjects\n");
2446 if (!HasPPRCSRs && !HasPPRStackObjects) {
2448 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2452 if (!HasFPRCSRs && !HasFPRStackObjects) {
2455 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2459 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2460 MF.getSubtarget<AArch64Subtarget>();
2462 "Expected SVE to be available for PPRs");
2464 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2468 BitVector FPRZRegs(SavedRegs.
size());
2469 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2470 BitVector::reference RegBit = SavedRegs[
Reg];
2473 unsigned SubRegIdx = 0;
2475 SubRegIdx = AArch64::dsub;
2477 SubRegIdx = AArch64::zsub;
2484 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2487 SavedRegs |= FPRZRegs;
2507 unsigned UnspilledCSGPR = AArch64::NoRegister;
2508 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
2514 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2516 unsigned ExtraCSSpill = 0;
2517 bool HasUnpairedGPR64 =
false;
2518 bool HasPairZReg =
false;
2519 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2520 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2523 for (
unsigned i = 0; CSRegs[i]; ++i) {
2527 if (Reg == BasePointerReg)
2532 if (UserReservedRegs[Reg]) {
2533 SavedRegs.
reset(Reg);
2537 bool RegUsed = SavedRegs.
test(Reg);
2539 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2540 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2541 AArch64::FPR128RegClass.
contains(Reg)) {
2544 if (HasUnpairedGPR64)
2545 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2547 PairedReg = CSRegs[i ^ 1];
2554 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2555 PairedReg = AArch64::NoRegister;
2556 HasUnpairedGPR64 =
true;
2558 assert(PairedReg == AArch64::NoRegister ||
2559 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
2560 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
2561 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
2564 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2565 UnspilledCSGPR = Reg;
2566 UnspilledCSGPRPaired = PairedReg;
2574 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
2575 !SavedRegs.
test(PairedReg)) {
2576 SavedRegs.
set(PairedReg);
2577 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2578 !ReservedRegs[PairedReg])
2579 ExtraCSSpill = PairedReg;
2582 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2583 SavedRegs.
test(CSRegs[i ^ 1]));
2591 if (PnReg.isValid())
2597 SavedRegs.
set(AArch64::P8);
2602 "Predicate cannot be a reserved register");
2612 SavedRegs.
set(AArch64::X18);
2618 determineStackHazardSlot(MF, SavedRegs);
2621 unsigned CSStackSize = 0;
2622 unsigned ZPRCSStackSize = 0;
2623 unsigned PPRCSStackSize = 0;
2625 for (
unsigned Reg : SavedRegs.
set_bits()) {
2627 assert(RC &&
"expected register class!");
2628 auto SpillSize =
TRI->getSpillSize(*RC);
2629 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2630 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2632 ZPRCSStackSize += SpillSize;
2634 PPRCSStackSize += SpillSize;
2636 CSStackSize += SpillSize;
2642 unsigned NumSavedRegs = SavedRegs.
count();
2655 SavedRegs.
set(AArch64::LR);
2660 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2661 SavedRegs.
set(AArch64::FP);
2662 SavedRegs.
set(AArch64::LR);
2666 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2667 for (
unsigned Reg : SavedRegs.
set_bits())
2673 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2675 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2677 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2678 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2687 int64_t CalleeStackUsed = 0;
2690 if (FixedOff > CalleeStackUsed)
2691 CalleeStackUsed = FixedOff;
2695 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2696 CalleeStackUsed) > EstimatedStackSizeLimit;
2697 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2707 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
2709 <<
" to get a scratch register.\n");
2710 SavedRegs.
set(UnspilledCSGPR);
2711 ExtraCSSpill = UnspilledCSGPR;
2716 if (producePairRegisters(MF)) {
2717 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
2720 SavedRegs.
reset(UnspilledCSGPR);
2721 ExtraCSSpill = AArch64::NoRegister;
2724 SavedRegs.
set(UnspilledCSGPRPaired);
2733 unsigned Size =
TRI->getSpillSize(RC);
2734 Align Alignment =
TRI->getSpillAlign(RC);
2736 RS->addScavengingFrameIndex(FI);
2737 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2738 <<
" as the emergency spill slot.\n");
2743 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2752 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2756 "Should not invalidate callee saved info");
2767 std::vector<CalleeSavedInfo> &CSI)
const {
2776 std::reverse(CSI.begin(), CSI.end());
2796 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2797 if (It != CSI.end())
2798 CSI.insert(It, VGInfo);
2800 CSI.push_back(VGInfo);
2804 int HazardSlotIndex = std::numeric_limits<int>::max();
2805 for (
auto &CS : CSI) {
2813 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2814 "Unexpected register order for hazard slot");
2816 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2822 unsigned Size = RegInfo->getSpillSize(*RC);
2823 Align Alignment(RegInfo->getSpillAlign(*RC));
2825 CS.setFrameIdx(FrameIdx);
2830 Reg == AArch64::FP) {
2840 HazardSlotIndex == std::numeric_limits<int>::max()) {
2842 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2869 int &Min,
int &Max) {
2870 Min = std::numeric_limits<int>::max();
2871 Max = std::numeric_limits<int>::min();
2877 for (
auto &CS : CSI) {
2878 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
2879 AArch64::PPRRegClass.contains(CS.getReg())) {
2880 assert((Max == std::numeric_limits<int>::min() ||
2881 Max + 1 == CS.getFrameIdx()) &&
2882 "SVE CalleeSaves are not consecutive");
2883 Min = std::min(Min, CS.getFrameIdx());
2884 Max = std::max(Max, CS.getFrameIdx());
2887 return Min != std::numeric_limits<int>::max();
2900 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
2908 "SVE vectors should never be passed on the stack by value, only by "
2912 auto AllocateObject = [&](
int FI) {
2921 if (Alignment >
Align(16))
2923 "Alignment of scalable vectors > 16 bytes is not yet supported");
2926 StackTop =
alignTo(StackTop, Alignment);
2928 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
2929 "SVE StackTop far too large?!");
2931 int64_t
Offset = -int64_t(StackTop);
2939 int MinCSFrameIndex, MaxCSFrameIndex;
2941 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
2954 int StackProtectorFI = -1;
2958 ObjectsToAllocate.
push_back(StackProtectorFI);
2974 for (
unsigned FI : ObjectsToAllocate)
2989 "Upwards growing stack unsupported");
3004 int64_t CurrentOffset =
3008 int FrameIndex =
H.CatchObj.FrameIndex;
3009 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3020 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3021 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3023 "UnwindHelpOffset must be at the start of the fixed object area");
3026 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3036 RS->enterBasicBlockEnd(
MBB);
3038 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3039 assert(DstReg &&
"There must be a free register after frame setup");
3050struct TagStoreInstr {
3058 MachineFunction *MF;
3059 MachineBasicBlock *
MBB;
3060 MachineRegisterInfo *MRI;
3069 StackOffset FrameRegOffset;
3073 std::optional<int64_t> FrameRegUpdate;
3075 unsigned FrameRegUpdateFlags;
3085 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3086 :
MBB(
MBB), ZeroData(ZeroData) {
3092 void addInstruction(TagStoreInstr
I) {
3094 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3095 "Non-adjacent tag store instructions.");
3098 void clear() { TagStores.
clear(); }
3103 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3110 const int64_t kMinOffset = -256 * 16;
3111 const int64_t kMaxOffset = 255 * 16;
3114 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3115 if (BaseRegOffsetBytes < kMinOffset ||
3116 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3120 BaseRegOffsetBytes % 16 != 0) {
3125 BaseRegOffsetBytes = 0;
3130 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3133 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3135 assert(BaseRegOffsetBytes % 16 == 0);
3139 .
addImm(BaseRegOffsetBytes / 16)
3143 if (BaseRegOffsetBytes == 0)
3145 BaseRegOffsetBytes += InstrSize;
3164 int64_t LoopSize =
Size;
3167 if (FrameRegUpdate && *FrameRegUpdate)
3168 LoopSize -= LoopSize % 32;
3170 TII->get(ZeroData ? AArch64::STZGloop_wback
3171 : AArch64::STGloop_wback))
3178 LoopI->
setFlags(FrameRegUpdateFlags);
3180 int64_t ExtraBaseRegUpdate =
3181 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3182 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3183 <<
", Size=" <<
Size
3184 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3185 <<
", FrameRegUpdate=" << FrameRegUpdate
3186 <<
", FrameRegOffset.getFixed()="
3187 << FrameRegOffset.
getFixed() <<
"\n");
3188 if (LoopSize <
Size) {
3192 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3193 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3194 "STG immediate out of range");
3196 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3203 }
else if (ExtraBaseRegUpdate) {
3205 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3206 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3209 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3222 int64_t
Size, int64_t *TotalOffset) {
3224 if ((
MI.getOpcode() == AArch64::ADDXri ||
3225 MI.getOpcode() == AArch64::SUBXri) &&
3226 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3228 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3229 if (
MI.getOpcode() == AArch64::SUBXri)
3240 const int64_t kMaxOffset = 4080 - 16;
3242 const int64_t kMinOffset = -4095;
3243 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3244 PostOffset % 16 == 0) {
3255 for (
auto &TS : TSE) {
3259 if (
MI->memoperands_empty()) {
3263 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3269 bool TryMergeSPUpdate) {
3270 if (TagStores.
empty())
3272 TagStoreInstr &FirstTagStore = TagStores[0];
3273 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3274 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3275 DL = TagStores[0].MI->getDebugLoc();
3279 *MF, FirstTagStore.Offset,
false ,
3283 FrameRegUpdate = std::nullopt;
3285 mergeMemRefs(TagStores, CombinedMemRefs);
3288 dbgs() <<
"Replacing adjacent STG instructions:\n";
3289 for (
const auto &Instr : TagStores) {
3298 if (TagStores.
size() < 2)
3300 emitUnrolled(InsertI);
3303 int64_t TotalOffset = 0;
3304 if (TryMergeSPUpdate) {
3310 if (InsertI !=
MBB->
end() &&
3311 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3313 UpdateInstr = &*InsertI++;
3319 if (!UpdateInstr && TagStores.
size() < 2)
3323 FrameRegUpdate = TotalOffset;
3324 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3331 for (
auto &TS : TagStores)
3332 TS.MI->eraseFromParent();
3336 int64_t &
Size,
bool &ZeroData) {
3340 unsigned Opcode =
MI.getOpcode();
3341 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3342 Opcode == AArch64::STZ2Gi);
3344 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3345 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3347 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3350 Size =
MI.getOperand(2).getImm();
3354 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3356 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3361 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3365 16 *
MI.getOperand(2).getImm();
3369static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3374 return LiveRegs.available(MRI,
Reg);
3377 size_t NumEmergencySlots = 0;
3379 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3381 return FreeGPRs + NumEmergencySlots;
3400 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3406 constexpr int kScanLimit = 10;
3409 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3418 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3419 if (ZeroData != FirstZeroData)
3427 if (!
MI.isTransient())
3436 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3452 LiveRegs.addLiveOuts(*
MBB);
3457 LiveRegs.stepBackward(*
I);
3460 if (LiveRegs.contains(AArch64::NZCV))
3471 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3472 <<
"due to high register pressure.\n");
3477 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3482 int64_t CurOffset = Instrs[0].Offset;
3483 for (
auto &Instr : Instrs) {
3484 if (CurOffset >
Instr.Offset)
3491 TagStoreEdit TSE(
MBB, FirstZeroData);
3492 std::optional<int64_t> EndOffset;
3493 for (
auto &Instr : Instrs) {
3494 if (EndOffset && *EndOffset !=
Instr.Offset) {
3496 TSE.emitCode(InsertI, TFI,
false);
3500 TSE.addInstruction(Instr);
3519 II = tryMergeAdjacentSTG(
II,
this, RS);
3526 shouldSignReturnAddressEverywhere(MF))
3535 bool IgnoreSPUpdates)
const {
3537 if (IgnoreSPUpdates) {
3540 FrameReg = AArch64::SP;
3550 FrameReg = AArch64::SP;
3575 bool IsValid =
false;
3577 int ObjectIndex = 0;
3579 int GroupIndex = -1;
3581 bool ObjectFirst =
false;
3584 bool GroupFirst =
false;
3589 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3593 SmallVector<int, 8> CurrentMembers;
3594 int NextGroupIndex = 0;
3595 std::vector<FrameObject> &Objects;
3598 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3599 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3600 void EndCurrentGroup() {
3601 if (CurrentMembers.
size() > 1) {
3606 for (
int Index : CurrentMembers) {
3607 Objects[
Index].GroupIndex = NextGroupIndex;
3613 CurrentMembers.clear();
3617bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3639 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3640 A.GroupIndex,
A.ObjectIndex) <
3641 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3642 B.GroupIndex,
B.ObjectIndex);
3651 ObjectsToAllocate.
empty())
3656 for (
auto &Obj : ObjectsToAllocate) {
3657 FrameObjects[Obj].IsValid =
true;
3658 FrameObjects[Obj].ObjectIndex = Obj;
3663 GroupBuilder GB(FrameObjects);
3664 for (
auto &
MBB : MF) {
3665 for (
auto &
MI :
MBB) {
3666 if (
MI.isDebugInstr())
3671 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3674 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3676 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3681 switch (
MI.getOpcode()) {
3682 case AArch64::STGloop:
3683 case AArch64::STZGloop:
3687 case AArch64::STZGi:
3688 case AArch64::ST2Gi:
3689 case AArch64::STZ2Gi:
3702 FrameObjects[FI].IsValid)
3710 GB.AddMember(TaggedFI);
3712 GB.EndCurrentGroup();
3715 GB.EndCurrentGroup();
3720 FrameObject::AccessHazard;
3722 for (
auto &Obj : FrameObjects)
3723 if (!Obj.Accesses ||
3724 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3725 Obj.Accesses = FrameObject::AccessGPR;
3734 FrameObjects[*TBPI].ObjectFirst =
true;
3735 FrameObjects[*TBPI].GroupFirst =
true;
3736 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3737 if (FirstGroupIndex >= 0)
3738 for (FrameObject &Object : FrameObjects)
3739 if (Object.GroupIndex == FirstGroupIndex)
3740 Object.GroupFirst =
true;
3746 for (
auto &Obj : FrameObjects) {
3750 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3754 dbgs() <<
"Final frame order:\n";
3755 for (
auto &Obj : FrameObjects) {
3758 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3759 if (Obj.ObjectFirst)
3760 dbgs() <<
", first";
3762 dbgs() <<
", group-first";
3773AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3784 MF.
insert(MBBInsertPoint, LoopMBB);
3786 MF.
insert(MBBInsertPoint, ExitMBB);
3821 MBB.addSuccessor(LoopMBB);
3825 return ExitMBB->
begin();
3828void AArch64FrameLowering::inlineStackProbeFixed(
3833 const AArch64InstrInfo *
TII =
3835 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
3840 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
3841 int64_t NumBlocks = FrameSize / ProbeSize;
3842 int64_t ResidualSize = FrameSize % ProbeSize;
3844 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
3845 << NumBlocks <<
" blocks of " << ProbeSize
3846 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
3851 for (
int i = 0; i < NumBlocks; ++i) {
3857 EmitAsyncCFI && !HasFP, CFAOffset);
3870 }
else if (NumBlocks != 0) {
3876 EmitAsyncCFI && !HasFP, CFAOffset);
3878 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
3880 if (EmitAsyncCFI && !HasFP) {
3883 .buildDefCFARegister(AArch64::SP);
3887 if (ResidualSize != 0) {
3893 EmitAsyncCFI && !HasFP, CFAOffset);
3914 SmallVector<MachineInstr *, 4> ToReplace;
3915 for (MachineInstr &
MI :
MBB)
3916 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
3917 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
3920 for (MachineInstr *
MI : ToReplace) {
3921 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
3922 Register ScratchReg =
MI->getOperand(0).getReg();
3923 int64_t FrameSize =
MI->getOperand(1).getImm();
3925 MI->getOperand(3).getImm());
3926 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
3929 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
3930 "Stack probe pseudo-instruction expected");
3931 const AArch64InstrInfo *
TII =
3932 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
3933 Register TargetReg =
MI->getOperand(0).getReg();
3934 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
3936 MI->eraseFromParent();
3956 return std::make_tuple(
start(),
Idx) <
3957 std::make_tuple(Rhs.
start(), Rhs.
Idx);
3987 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
3988 if (
Offset.getScalable())
3989 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4000void AArch64FrameLowering::emitRemarks(
4003 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4008 const uint64_t HazardSize =
4011 if (HazardSize == 0)
4019 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4021 size_t NumFPLdSt = 0;
4022 size_t NumNonFPLdSt = 0;
4025 for (
const MachineBasicBlock &
MBB : MF) {
4026 for (
const MachineInstr &
MI :
MBB) {
4027 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4029 for (MachineMemOperand *MMO :
MI.memoperands()) {
4036 StackAccesses[ArrIdx].Idx = FrameIdx;
4037 StackAccesses[ArrIdx].Offset =
4048 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4059 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4070 if (StackAccesses.front().isMixed())
4071 MixedObjects.push_back(&StackAccesses.front());
4073 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4075 const auto &
First = *It;
4076 const auto &Second = *(It + 1);
4078 if (Second.isMixed())
4079 MixedObjects.push_back(&Second);
4081 if ((
First.isSME() && Second.isCPU()) ||
4082 (
First.isCPU() && Second.isSME())) {
4083 uint64_t Distance =
static_cast<uint64_t
>(Second.start() -
First.end());
4084 if (Distance < HazardSize)
4089 auto EmitRemark = [&](llvm::StringRef Str) {
4091 auto R = MachineOptimizationRemarkAnalysis(
4092 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4093 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4097 for (
const auto &
P : HazardPairs)
4098 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4100 for (
const auto *Obj : MixedObjects)
4102 formatv(
"{0} accessed by both GP and FP instructions", *Obj).str());
static void getLiveRegsForEntryMBB(LivePhysRegs &LiveRegs, const MachineBasicBlock &MBB)
static const unsigned DefaultSafeSPDisplacement
This is the biggest offset to the stack pointer we can encode in aarch64 instructions (without using ...
static RegState getPrologueDeath(MachineFunction &MF, unsigned Reg)
static bool produceCompactUnwindFrame(const AArch64FrameLowering &, MachineFunction &MF)
static cl::opt< bool > StackTaggingMergeSetTag("stack-tagging-merge-settag", cl::desc("merge settag instruction in function epilog"), cl::init(true), cl::Hidden)
bool enableMultiVectorSpillFill(const AArch64Subtarget &Subtarget, MachineFunction &MF)
static std::optional< int > getLdStFrameID(const MachineInstr &MI, const MachineFrameInfo &MFI)
static cl::opt< bool > SplitSVEObjects("aarch64-split-sve-objects", cl::desc("Split allocation of ZPR & PPR objects"), cl::init(true), cl::Hidden)
static cl::opt< bool > StackHazardInNonStreaming("aarch64-stack-hazard-in-non-streaming", cl::init(false), cl::Hidden)
void computeCalleeSaveRegisterPairs(const AArch64FrameLowering &AFL, MachineFunction &MF, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI, SmallVectorImpl< RegPairInfo > &RegPairs, bool NeedsFrameRecord)
static cl::opt< bool > OrderFrameObjects("aarch64-order-frame-objects", cl::desc("sort stack allocations"), cl::init(true), cl::Hidden)
static cl::opt< bool > DisableMultiVectorSpillFill("aarch64-disable-multivector-spill-fill", cl::desc("Disable use of LD/ST pairs for SME2 or SVE2p1"), cl::init(false), cl::Hidden)
static cl::opt< bool > EnableRedZone("aarch64-redzone", cl::desc("enable use of redzone on AArch64"), cl::init(false), cl::Hidden)
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.
cl::opt< bool > EnableHomogeneousPrologEpilog("homogeneous-prolog-epilog", cl::Hidden, cl::desc("Emit homogeneous prologue and epilogue for the size " "optimization (default = off)"))
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 cl::opt< unsigned > StackHazardRemarkSize("aarch64-stack-hazard-remark-size", cl::init(0), cl::Hidden)
static MCRegister getRegisterOrZero(MCRegister Reg, bool HasSVE)
static unsigned getStackHazardSize(const MachineFunction &MF)
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
static int getArgumentStackToRestore(MachineFunction &MF, MachineBasicBlock &MBB)
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
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 contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
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).
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 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
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
bool test(unsigned Idx) const
size_type count() const
count - Returns the number of bits which are set.
iterator_range< const_set_bits_iterator > set_bits() const
size_type size() const
size - 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.
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.
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 int CreateSpillStackObject(uint64_t Size, Align Alignment)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
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...
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.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineBasicBlock & front() const
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.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
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.
Primary interface to the complete machine description for the target machine.
const Triple & getTargetTriple() const
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
LLVM_ABI bool FramePointerIsReserved(const MachineFunction &MF) const
FramePointerIsReserved - This returns true if the frame pointer must always either point to a new fra...
LLVM_ABI bool DisableFramePointerElim(const MachineFunction &MF) const
DisableFramePointerElim - This returns true if frame pointer elimination optimization should be disab...
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.
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
initializer< Ty > init(const Ty &Val)
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.
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.
FunctionAddr VTableAddr Count
constexpr RegState getDefRegState(bool B)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ 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...
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.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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.
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