266#define DEBUG_TYPE "frame-info"
269 cl::desc(
"enable use of redzone on AArch64"),
273 "stack-tagging-merge-settag",
283 cl::desc(
"Split allocation of ZPR & PPR objects"),
288 cl::desc(
"Emit homogeneous prologue and epilogue for the size "
289 "optimization (default = off)"));
301 "aarch64-disable-multivector-spill-fill",
310 bool IsTailCallReturn = (
MBB.end() !=
MBBI)
314 int64_t ArgumentPopSize = 0;
315 if (IsTailCallReturn) {
321 ArgumentPopSize = StackAdjust.
getImm();
330 return ArgumentPopSize;
373 if (AFI->hasCalculatedStackSizeSVE())
403bool AArch64FrameLowering::homogeneousPrologEpilog(
429 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
436 unsigned NumGPRs = 0;
437 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
439 if (Reg == AArch64::LR) {
440 assert(CSRegs[
I + 1] == AArch64::FP);
441 if (NumGPRs % 2 != 0)
453bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
472 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
473 MI.getOpcode() == AArch64::ADDXri ||
474 MI.getOpcode() == AArch64::ADDSXri)
499 bool IsWin64,
bool IsFunclet)
const {
501 "Tail call reserved stack must be aligned to 16 bytes");
502 if (!IsWin64 || IsFunclet) {
507 Attribute::SwiftAsync))
521 int FrameIndex =
H.CatchObj.FrameIndex;
522 if ((FrameIndex != INT_MAX) &&
523 CatchObjFrameIndices.
insert(FrameIndex)) {
524 FixedObjectSize =
alignTo(FixedObjectSize,
531 FixedObjectSize += 8;
533 return alignTo(FixedObjectSize, 16);
544 const unsigned RedZoneSize =
557 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
561 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
583 if (Subtarget.getTargetLowering()->useStackGuardMixFP())
592 RegInfo->hasStackRealignment(MF))
639 if (TT.isOSDarwin() || TT.isOSWindows())
677 unsigned Opc =
I->getOpcode();
678 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
679 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
682 int64_t Amount =
I->getOperand(0).getImm();
690 if (CalleePopAmount == 0) {
701 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
712 "non-reserved call frame without var sized objects?");
721 }
else if (CalleePopAmount != 0) {
724 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
736 const auto &
TRI = *Subtarget.getRegisterInfo();
742 CFIBuilder.buildDefCFA(AArch64::SP, 0);
745 if (MFI.shouldSignReturnAddress(MF)) {
746 if (MFI.branchProtectionPAuthLR()) {
747 CFIBuilder.buildNegateRAStateWithPC();
749 CFIBuilder.buildNegateRAState();
754 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
755 CFIBuilder.buildSameValue(AArch64::X18);
758 const std::vector<CalleeSavedInfo> &CSI =
760 for (
const auto &Info : CSI) {
762 if (!
TRI.regNeedsCFI(Reg, Reg))
764 CFIBuilder.buildSameValue(Reg);
777 case AArch64::W##n: \
778 case AArch64::X##n: \
803 case AArch64::B##n: \
804 case AArch64::H##n: \
805 case AArch64::S##n: \
806 case AArch64::D##n: \
807 case AArch64::Q##n: \
808 return HasSVE ? AArch64::Z##n : AArch64::Q##n
845void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
857 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
860 BitVector GPRsToZero(
TRI.getNumRegs());
861 BitVector FPRsToZero(
TRI.getNumRegs());
865 bool HasFPR = STI.hasFPARMv8();
867 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
870 GPRsToZero.set(XReg);
874 FPRsToZero.set(XReg);
881 for (MCRegister
Reg : GPRsToZero.set_bits())
885 for (MCRegister
Reg : FPRsToZero.set_bits())
889 for (MCRegister PReg :
890 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
891 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
892 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
894 if (RegsToZero[PReg])
900bool AArch64FrameLowering::windowsRequiresStackProbe(
902 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
903 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
907 StackSizeInBytes >=
uint64_t(MFI.getStackProbeSize());
916 for (
unsigned i = 0; CSRegs[i]; ++i)
922 bool HasCall)
const {
932 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
934 LivePhysRegs LiveRegs(
TRI);
937 LiveRegs.addReg(AArch64::X16);
938 LiveRegs.addReg(AArch64::X17);
939 LiveRegs.addReg(AArch64::X18);
943 const MachineRegisterInfo &MRI = MF->
getRegInfo();
944 if (LiveRegs.available(MRI, AArch64::X9))
947 for (
unsigned Reg : AArch64::GPR64RegClass) {
948 if (LiveRegs.available(MRI,
Reg))
951 return AArch64::NoRegister;
970 if (!
LiveRegs.available(MRI, AArch64::X16) ||
971 !
LiveRegs.available(MRI, AArch64::X17))
978 MBB.isLiveIn(AArch64::NZCV))
982 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
988 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
989 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
998 F.needsUnwindTableEntry();
1001bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
1017 unsigned Opc =
MBBI->getOpcode();
1021 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1022 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1030 case AArch64::STR_ZXI:
1031 case AArch64::LDR_ZXI: {
1032 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1039 case AArch64::STR_PXI:
1040 case AArch64::LDR_PXI: {
1041 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1048 case AArch64::LDPDpost:
1051 case AArch64::STPDpre: {
1052 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1053 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1054 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1061 case AArch64::LDPXpost:
1064 case AArch64::STPXpre: {
1067 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1068 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1072 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1073 .
addImm(RegInfo->getSEHRegNum(Reg0))
1074 .
addImm(RegInfo->getSEHRegNum(Reg1))
1079 case AArch64::LDRDpost:
1082 case AArch64::STRDpre: {
1083 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1084 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1090 case AArch64::LDRXpost:
1093 case AArch64::STRXpre: {
1094 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1101 case AArch64::STPDi:
1102 case AArch64::LDPDi: {
1103 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1104 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1112 case AArch64::STPXi:
1113 case AArch64::LDPXi: {
1117 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1118 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1120 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1124 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1131 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1138 case AArch64::STRXui:
1139 case AArch64::LDRXui: {
1140 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1147 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1153 case AArch64::STRDui:
1154 case AArch64::LDRDui: {
1155 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1162 case AArch64::STPQi:
1163 case AArch64::LDPQi: {
1164 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1165 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1166 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1173 case AArch64::LDPQpost:
1176 case AArch64::STPQpre: {
1177 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1178 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1179 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1198 if (ST.isTargetDarwin())
1220 DL =
MBBI->getDebugLoc();
1222 TII->createPauthEpilogueInstr(
MBB,
DL);
1226 EmitSignRA(MF.
front());
1228 if (
MBB.isEHFuncletEntry())
1230 if (
MBB.isReturnBlock())
1286 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1291 if (MFI.isVariableSizedObjectIndex(FI)) {
1301 if (MFI.hasScalableStackID(FI)) {
1302 if (FPAfterSVECalleeSaves &&
1305 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1313 AccessOffset = -PPRStackSize;
1314 return AccessOffset +
1319 bool IsFixed = MFI.isFixedObjectIndex(FI);
1324 if (!IsFixed && !IsCSR) {
1325 ScalableOffset = -SVEStackSize;
1326 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1341 int64_t ObjectOffset)
const {
1345 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1346 unsigned FixedObject =
1347 getFixedObjectSize(MF, AFI, IsWin64,
false);
1355 int64_t ObjectOffset)
const {
1366 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1367 ? getFPOffset(MF, ObjectOffset).getFixed()
1368 : getStackOffset(MF, ObjectOffset).getFixed();
1373 bool ForSimm)
const {
1375 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1376 bool isFixed = MFI.isFixedObjectIndex(FI);
1379 FrameReg, PreferFP, ForSimm);
1385 bool ForSimm)
const {
1391 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1392 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1395 bool isSVE = MFI.isScalableStackID(StackID);
1399 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1410 PreferFP &= !SVEStackSize;
1418 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1422 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1424 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1429 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1430 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1432 if (FPOffset >= 0) {
1436 }
else if (MFI.hasVarSizedObjects()) {
1440 bool CanUseBP = RegInfo->hasBasePointer(MF);
1441 if (FPOffsetFits && CanUseBP)
1448 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1455 "Funclets should only be present on Win64");
1459 if (FPOffsetFits && PreferFP)
1466 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1467 "In the presence of dynamic stack pointer realignment, "
1468 "non-argument/CSR objects cannot be accessed through the frame pointer");
1485 FPOffset -= PPRStackSize;
1487 SPOffset -= PPRStackSize;
1492 if (FPAfterSVECalleeSaves) {
1503 RegInfo->hasStackRealignment(MF))) {
1504 FrameReg = RegInfo->getFrameRegister(MF);
1507 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1514 if (FPAfterSVECalleeSaves) {
1521 SVEAreaOffset = SVECalleeSavedStack;
1523 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1526 SVEAreaOffset = SVEStackSize;
1528 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1531 if (UseFP && !(isFixed || isCSR))
1532 SVEAreaOffset = -SVEStackSize;
1533 if (!UseFP && (isFixed || isCSR))
1534 SVEAreaOffset = SVEStackSize;
1538 FrameReg = RegInfo->getFrameRegister(MF);
1543 if (RegInfo->hasBasePointer(MF))
1544 FrameReg = RegInfo->getBaseRegister();
1546 assert(!MFI.hasVarSizedObjects() &&
1547 "Can't use SP when we have var sized objects.");
1548 FrameReg = AArch64::SP;
1576 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1582 unsigned SpillCount,
unsigned Reg1,
1583 unsigned Reg2,
bool NeedsWinCFI,
1592 if (Reg2 == AArch64::FP)
1602 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1603 return SpillExtendedVolatile
1604 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1605 (SpillCount % 2) == 0)
1610 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1611 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1621 unsigned SpillCount,
unsigned Reg1,
1622 unsigned Reg2,
bool UsesWinAAPCS,
1623 bool NeedsWinCFI,
bool NeedsFrameRecord,
1627 Reg1, Reg2, NeedsWinCFI,
TRI);
1631 if (NeedsFrameRecord)
1632 return Reg2 == AArch64::LR;
1644 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1647 RegPairInfo() =
default;
1649 bool isPaired()
const {
return Reg2.
isValid(); }
1651 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1657 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1658 if (SavedRegs.
test(PReg)) {
1659 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1673 bool IsLocallyStreaming =
1679 return Subtarget.hasSVE2p1() ||
1680 (Subtarget.hasSME2() &&
1681 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1689 bool NeedsFrameRecord) {
1706 (
Count & 1) == 0) &&
1707 "Odd number of callee-saved regs to spill!");
1709 int StackFillDir = -1;
1711 unsigned FirstReg = 0;
1719 FirstReg =
Count - 1;
1731 bool SpillExtendedVolatile =
1733 const auto &
Reg = CSI.getReg();
1734 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1737 int ZPRByteOffset = 0;
1738 int PPRByteOffset = 0;
1743 }
else if (!FPAfterSVECalleeSaves) {
1754 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1755 if (StackFillDir < 0)
1761 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1763 RPI.Reg1 = CSI[i].getReg();
1765 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1766 RPI.Type = RegPairInfo::GPR;
1767 RPI.RC = &AArch64::GPR64RegClass;
1768 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1769 RPI.Type = RegPairInfo::FPR64;
1770 RPI.RC = &AArch64::FPR64RegClass;
1771 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1772 RPI.Type = RegPairInfo::FPR128;
1773 RPI.RC = &AArch64::FPR128RegClass;
1774 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1775 RPI.Type = RegPairInfo::ZPR;
1776 RPI.RC = &AArch64::ZPRRegClass;
1777 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1778 RPI.Type = RegPairInfo::PPR;
1779 RPI.RC = &AArch64::PPRRegClass;
1780 }
else if (RPI.Reg1 == AArch64::VG) {
1781 RPI.Type = RegPairInfo::VG;
1782 RPI.RC = &AArch64::FIXED_REGSRegClass;
1787 int &ScalableByteOffset = RPI.Type == RegPairInfo::PPR && SplitPPRs
1792 if (HasCSHazardPadding &&
1795 ByteOffset += StackFillDir * StackHazardSize;
1799 int Scale =
TRI->getSpillSize(*RPI.RC);
1801 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1802 MCRegister NextReg = CSI[i + RegInc].getReg();
1803 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1804 int Aligned = AlignOffset(ByteOffset, Scale);
1805 int PairOffset = IsWindows ?
Aligned :
Aligned + StackFillDir * 2 * Scale;
1806 bool PairFitsImmRange =
1807 PairOffset / Scale >= -64 && PairOffset / Scale <= 63;
1809 case RegPairInfo::GPR:
1810 if (AArch64::GPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1812 RPI.Reg1, NextReg, IsWindows,
1813 NeedsWinCFI, NeedsFrameRecord,
TRI))
1816 case RegPairInfo::FPR64:
1817 if (AArch64::FPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1819 RPI.Reg1, NextReg, IsWindows,
1820 NeedsWinCFI, NeedsFrameRecord,
TRI))
1823 case RegPairInfo::FPR128:
1824 if (AArch64::FPR128RegClass.
contains(NextReg) && PairFitsImmRange)
1827 case RegPairInfo::PPR:
1829 case RegPairInfo::ZPR:
1831 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
1834 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
1839 case RegPairInfo::VG:
1850 assert((!RPI.isPaired() ||
1851 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1852 "Out of order callee saved regs!");
1854 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1855 RPI.Reg1 == AArch64::LR) &&
1856 "FrameRecord must be allocated together with LR");
1859 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1860 RPI.Reg2 == AArch64::LR) &&
1861 "FrameRecord must be allocated together with LR");
1869 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1870 RPI.Reg1 + 1 == RPI.Reg2))) &&
1871 "Callee-save registers not saved as adjacent register pair!");
1873 RPI.FrameIdx = CSI[i].getFrameIdx();
1876 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1880 if (RPI.isScalable() && ScalableByteOffset % Scale != 0)
1881 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1885 if (!RPI.isScalable() && ByteOffset % Scale != 0)
1886 ByteOffset = AlignOffset(ByteOffset, Scale);
1888 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1889 assert(OffsetPre % Scale == 0);
1891 if (RPI.isScalable())
1892 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1894 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1899 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1900 (IsWindows && RPI.Reg2 == AArch64::LR)))
1901 ByteOffset += StackFillDir * 8;
1905 if (NeedGapToAlignStack && !IsWindows && !RPI.isScalable() &&
1906 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1907 ByteOffset % 16 != 0) {
1908 ByteOffset += 8 * StackFillDir;
1914 NeedGapToAlignStack =
false;
1917 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1918 assert(OffsetPost % Scale == 0);
1921 int Offset = IsWindows ? OffsetPre : OffsetPost;
1926 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1927 (IsWindows && RPI.Reg2 == AArch64::LR)))
1929 RPI.Offset =
Offset / Scale;
1931 assert((!RPI.isPaired() ||
1932 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1933 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1934 "Offset out of bounds for LDP/STP immediate");
1936 auto isFrameRecord = [&] {
1938 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1939 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1947 return i > 0 && RPI.Reg1 == AArch64::FP &&
1948 CSI[i - 1].getReg() == AArch64::LR;
1953 if (NeedsFrameRecord && isFrameRecord())
1970 std::reverse(RegPairs.
begin(), RegPairs.
end());
1992 if (homogeneousPrologEpilog(MF)) {
1996 for (
auto &RPI : RegPairs) {
2002 MBB.addLiveIn(RPI.Reg1);
2003 if (RPI.isPaired() && !MRI.
isReserved(RPI.Reg2))
2004 MBB.addLiveIn(RPI.Reg2);
2008 bool PTrueCreated =
false;
2024 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2025 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2027 case RegPairInfo::GPR:
2028 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2030 case RegPairInfo::FPR64:
2031 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2033 case RegPairInfo::FPR128:
2034 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2036 case RegPairInfo::ZPR:
2037 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2039 case RegPairInfo::PPR:
2040 StrOpc = AArch64::STR_PXI;
2042 case RegPairInfo::VG:
2043 StrOpc = AArch64::STRXui;
2049 if (X0Scratch != AArch64::NoRegister)
2055 if (Reg1 == AArch64::VG) {
2057 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2058 assert(Reg1 != AArch64::NoRegister);
2068 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2069 AArch64::X0, LiveIn.PhysReg);
2077 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2079 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2093 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2095 dbgs() <<
", " << RPI.FrameIdx + 1;
2100 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2101 "Windows unwdinding requires a consecutive (FP,LR) pair");
2105 unsigned FrameIdxReg1 = RPI.FrameIdx;
2106 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2112 if (RPI.isPaired() && RPI.isScalable()) {
2118 "Expects SVE2.1 or SME2 target and a predicate register");
2119#ifdef EXPENSIVE_CHECKS
2120 auto IsPPR = [](
const RegPairInfo &c) {
2121 return c.Reg1 == RegPairInfo::PPR;
2123 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2124 auto IsZPR = [](
const RegPairInfo &c) {
2125 return c.Type == RegPairInfo::ZPR;
2127 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2128 assert(!(PPRBegin < ZPRBegin) &&
2129 "Expected callee save predicate to be handled first");
2131 if (!PTrueCreated) {
2132 PTrueCreated =
true;
2138 MBB.addLiveIn(Reg1);
2140 MBB.addLiveIn(Reg2);
2141 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2158 MBB.addLiveIn(Reg1);
2159 if (RPI.isPaired()) {
2161 MBB.addLiveIn(Reg2);
2180 if (RPI.Type == RegPairInfo::ZPR) {
2184 }
else if (RPI.Type == RegPairInfo::PPR) {
2204 DL =
MBBI->getDebugLoc();
2207 if (homogeneousPrologEpilog(MF, &
MBB)) {
2210 for (
auto &RPI : RegPairs) {
2218 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2220 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2221 std::reverse(PPRBegin, PPREnd);
2222 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2224 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2225 std::reverse(ZPRBegin, ZPREnd);
2227 bool PTrueCreated =
false;
2228 for (
const RegPairInfo &RPI : RegPairs) {
2241 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2242 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2244 case RegPairInfo::GPR:
2245 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2247 case RegPairInfo::FPR64:
2248 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2250 case RegPairInfo::FPR128:
2251 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2253 case RegPairInfo::ZPR:
2254 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2256 case RegPairInfo::PPR:
2257 LdrOpc = AArch64::LDR_PXI;
2259 case RegPairInfo::VG:
2266 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2268 dbgs() <<
", " << RPI.FrameIdx + 1;
2275 unsigned FrameIdxReg1 = RPI.FrameIdx;
2276 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2283 if (RPI.isPaired() && RPI.isScalable()) {
2288 "Expects SVE2.1 or SME2 target and a predicate register");
2289#ifdef EXPENSIVE_CHECKS
2290 assert(!(PPRBegin < ZPRBegin) &&
2291 "Expected callee save predicate to be handled first");
2293 if (!PTrueCreated) {
2294 PTrueCreated =
true;
2299 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
2316 if (RPI.isPaired()) {
2343 return std::optional<int>(PSV->getFrameIndex());
2354 return std::nullopt;
2360 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2361 return std::nullopt;
2368 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2374void AArch64FrameLowering::determineStackHazardSlot(
2377 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2378 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2392 return AArch64::FPR64RegClass.contains(Reg) ||
2393 AArch64::FPR128RegClass.contains(Reg) ||
2394 AArch64::ZPRRegClass.contains(Reg);
2397 return AArch64::PPRRegClass.contains(Reg);
2399 bool HasFPRStackObjects =
false;
2400 bool HasPPRStackObjects =
false;
2402 enum SlotType : uint8_t {
2413 for (
auto &
MBB : MF) {
2414 for (
auto &
MI :
MBB) {
2416 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2423 ? SlotType::ZPRorFPR
2429 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2430 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2433 if (SlotTypes[FI] == SlotType::PPR) {
2435 HasPPRStackObjects =
true;
2440 if (HasFPRCSRs || HasFPRStackObjects) {
2443 << StackHazardSize <<
"\n");
2454 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2460 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2461 "non-SVE CC function...\n");
2468 <<
"Calling convention is not supported with SplitSVEObjects\n");
2472 if (!HasPPRCSRs && !HasPPRStackObjects) {
2474 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2478 if (!HasFPRCSRs && !HasFPRStackObjects) {
2481 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2485 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2486 MF.getSubtarget<AArch64Subtarget>();
2488 "Expected SVE to be available for PPRs");
2490 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2494 BitVector FPRZRegs(SavedRegs.
size());
2495 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2496 BitVector::reference RegBit = SavedRegs[
Reg];
2499 unsigned SubRegIdx = 0;
2501 SubRegIdx = AArch64::dsub;
2503 SubRegIdx = AArch64::zsub;
2510 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2513 SavedRegs |= FPRZRegs;
2533 unsigned UnspilledCSGPR = AArch64::NoRegister;
2534 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
2540 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2542 unsigned ExtraCSSpill = 0;
2543 bool HasUnpairedGPR64 =
false;
2544 bool HasPairZReg =
false;
2545 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2546 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2549 for (
unsigned i = 0; CSRegs[i]; ++i) {
2553 if (Reg == BasePointerReg)
2558 if (UserReservedRegs[Reg]) {
2559 SavedRegs.
reset(Reg);
2563 bool RegUsed = SavedRegs.
test(Reg);
2565 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2566 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2567 AArch64::FPR128RegClass.
contains(Reg)) {
2570 if (HasUnpairedGPR64)
2571 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2573 PairedReg = CSRegs[i ^ 1];
2580 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2581 PairedReg = AArch64::NoRegister;
2582 HasUnpairedGPR64 =
true;
2584 assert(PairedReg == AArch64::NoRegister ||
2585 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
2586 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
2587 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
2590 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2591 UnspilledCSGPR = Reg;
2592 UnspilledCSGPRPaired = PairedReg;
2600 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
2601 !SavedRegs.
test(PairedReg)) {
2602 SavedRegs.
set(PairedReg);
2603 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2604 !ReservedRegs[PairedReg])
2605 ExtraCSSpill = PairedReg;
2608 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2609 SavedRegs.
test(CSRegs[i ^ 1]));
2617 if (PnReg.isValid())
2623 SavedRegs.
set(AArch64::P8);
2628 "Predicate cannot be a reserved register");
2638 SavedRegs.
set(AArch64::X18);
2644 determineStackHazardSlot(MF, SavedRegs);
2647 unsigned CSStackSize = 0;
2648 unsigned ZPRCSStackSize = 0;
2649 unsigned PPRCSStackSize = 0;
2651 for (
unsigned Reg : SavedRegs.
set_bits()) {
2653 assert(RC &&
"expected register class!");
2654 auto SpillSize =
TRI->getSpillSize(*RC);
2655 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2656 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2658 ZPRCSStackSize += SpillSize;
2660 PPRCSStackSize += SpillSize;
2666 return SavedRegs.test(SuperReg);
2669 CSStackSize += SpillSize;
2676 unsigned NumSavedRegs = SavedRegs.
count();
2689 SavedRegs.
set(AArch64::LR);
2694 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2695 SavedRegs.
set(AArch64::FP);
2696 SavedRegs.
set(AArch64::LR);
2700 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2701 for (
unsigned Reg : SavedRegs.
set_bits())
2707 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2709 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2710 uint64_t SVEStackSize =
2711 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2712 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2721 int64_t CalleeStackUsed = 0;
2724 if (FixedOff > CalleeStackUsed)
2725 CalleeStackUsed = FixedOff;
2729 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2730 CalleeStackUsed) > EstimatedStackSizeLimit;
2731 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2741 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
2743 <<
" to get a scratch register.\n");
2744 SavedRegs.
set(UnspilledCSGPR);
2745 ExtraCSSpill = UnspilledCSGPR;
2750 if (producePairRegisters(MF)) {
2751 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
2754 SavedRegs.
reset(UnspilledCSGPR);
2755 ExtraCSSpill = AArch64::NoRegister;
2758 SavedRegs.
set(UnspilledCSGPRPaired);
2767 unsigned Size =
TRI->getSpillSize(RC);
2768 Align Alignment =
TRI->getSpillAlign(RC);
2770 RS->addScavengingFrameIndex(FI);
2771 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2772 <<
" as the emergency spill slot.\n");
2777 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2784 uint64_t AlignedCSStackSize =
alignTo(CSStackSize, 16);
2786 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2790 "Should not invalidate callee saved info");
2801 std::vector<CalleeSavedInfo> &CSI)
const {
2810 std::reverse(CSI.begin(), CSI.end());
2824 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2825 if (It != CSI.end())
2826 CSI.insert(It, VGInfo);
2828 CSI.push_back(VGInfo);
2832 int HazardSlotIndex = std::numeric_limits<int>::max();
2833 for (
auto &CS : CSI) {
2841 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2842 "Unexpected register order for hazard slot");
2844 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2850 unsigned Size = RegInfo->getSpillSize(*RC);
2851 Align Alignment(RegInfo->getSpillAlign(*RC));
2853 CS.setFrameIdx(FrameIdx);
2867 HazardSlotIndex == std::numeric_limits<int>::max()) {
2869 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2896 int &Min,
int &Max) {
2897 Min = std::numeric_limits<int>::max();
2898 Max = std::numeric_limits<int>::min();
2904 for (
auto &CS : CSI) {
2905 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
2906 AArch64::PPRRegClass.contains(CS.getReg())) {
2907 assert((Max == std::numeric_limits<int>::min() ||
2908 Max + 1 == CS.getFrameIdx()) &&
2909 "SVE CalleeSaves are not consecutive");
2910 Min = std::min(Min, CS.getFrameIdx());
2911 Max = std::max(Max, CS.getFrameIdx());
2914 return Min != std::numeric_limits<int>::max();
2927 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
2935 "SVE vectors should never be passed on the stack by value, only by "
2939 auto AllocateObject = [&](
int FI) {
2948 if (Alignment >
Align(16))
2950 "Alignment of scalable vectors > 16 bytes is not yet supported");
2953 StackTop =
alignTo(StackTop, Alignment);
2955 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
2956 "SVE StackTop far too large?!");
2958 int64_t
Offset = -int64_t(StackTop);
2966 int MinCSFrameIndex, MaxCSFrameIndex;
2968 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
2981 int StackProtectorFI = -1;
2985 ObjectsToAllocate.
push_back(StackProtectorFI);
3001 for (
unsigned FI : ObjectsToAllocate)
3016 "Upwards growing stack unsupported");
3031 int64_t CurrentOffset =
3035 int FrameIndex =
H.CatchObj.FrameIndex;
3036 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3047 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3048 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3050 "UnwindHelpOffset must be at the start of the fixed object area");
3053 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3063 RS->enterBasicBlockEnd(
MBB);
3065 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3066 assert(DstReg &&
"There must be a free register after frame setup");
3077struct TagStoreInstr {
3086 MachineBasicBlock *
MBB;
3087 MachineRegisterInfo *MRI;
3096 StackOffset FrameRegOffset;
3100 std::optional<int64_t> FrameRegUpdate;
3102 unsigned FrameRegUpdateFlags;
3112 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3113 :
MBB(
MBB), ZeroData(ZeroData) {
3119 void addInstruction(TagStoreInstr
I) {
3121 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3122 "Non-adjacent tag store instructions.");
3125 void clear() { TagStores.
clear(); }
3130 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3137 const int64_t kMinOffset = -256 * 16;
3138 const int64_t kMaxOffset = 255 * 16;
3141 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3142 if (BaseRegOffsetBytes < kMinOffset ||
3143 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3147 BaseRegOffsetBytes % 16 != 0) {
3152 BaseRegOffsetBytes = 0;
3157 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3160 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3162 assert(BaseRegOffsetBytes % 16 == 0);
3166 .
addImm(BaseRegOffsetBytes / 16)
3170 if (BaseRegOffsetBytes == 0)
3172 BaseRegOffsetBytes += InstrSize;
3191 int64_t LoopSize =
Size;
3194 if (FrameRegUpdate && *FrameRegUpdate)
3195 LoopSize -= LoopSize % 32;
3197 TII->get(ZeroData ? AArch64::STZGloop_wback
3198 : AArch64::STGloop_wback))
3205 LoopI->
setFlags(FrameRegUpdateFlags);
3207 int64_t ExtraBaseRegUpdate =
3208 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3209 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3210 <<
", Size=" <<
Size
3211 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3212 <<
", FrameRegUpdate=" << FrameRegUpdate
3213 <<
", FrameRegOffset.getFixed()="
3214 << FrameRegOffset.
getFixed() <<
"\n");
3215 if (LoopSize <
Size) {
3219 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3220 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3221 "STG immediate out of range");
3223 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3230 }
else if (ExtraBaseRegUpdate) {
3232 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3233 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3236 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3249 int64_t
Size, int64_t *TotalOffset) {
3251 if ((
MI.getOpcode() == AArch64::ADDXri ||
3252 MI.getOpcode() == AArch64::SUBXri) &&
3253 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3255 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3256 if (
MI.getOpcode() == AArch64::SUBXri)
3267 const int64_t kMaxOffset = 4080 - 16;
3269 const int64_t kMinOffset = -4095;
3270 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3271 PostOffset % 16 == 0) {
3282 for (
auto &TS : TSE) {
3286 if (
MI->memoperands_empty()) {
3290 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3296 bool TryMergeSPUpdate) {
3297 if (TagStores.
empty())
3299 TagStoreInstr &FirstTagStore = TagStores[0];
3300 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3301 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3302 DL = TagStores[0].MI->getDebugLoc();
3306 *MF, FirstTagStore.Offset,
false ,
3310 FrameRegUpdate = std::nullopt;
3312 mergeMemRefs(TagStores, CombinedMemRefs);
3315 dbgs() <<
"Replacing adjacent STG instructions:\n";
3316 for (
const auto &Instr : TagStores) {
3325 if (TagStores.
size() < 2)
3327 emitUnrolled(InsertI);
3330 int64_t TotalOffset = 0;
3331 if (TryMergeSPUpdate) {
3337 if (InsertI !=
MBB->
end() &&
3338 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3340 UpdateInstr = &*InsertI++;
3346 if (!UpdateInstr && TagStores.
size() < 2)
3350 FrameRegUpdate = TotalOffset;
3351 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3358 for (
auto &TS : TagStores)
3359 TS.MI->eraseFromParent();
3363 int64_t &
Size,
bool &ZeroData) {
3367 unsigned Opcode =
MI.getOpcode();
3368 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3369 Opcode == AArch64::STZ2Gi);
3371 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3372 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3374 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3377 Size =
MI.getOperand(2).getImm();
3381 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3383 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3388 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3392 16 *
MI.getOperand(2).getImm();
3396static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3401 return LiveRegs.available(MRI,
Reg);
3404 size_t NumEmergencySlots = 0;
3406 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3408 return FreeGPRs + NumEmergencySlots;
3427 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3433 constexpr int kScanLimit = 10;
3436 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3445 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3446 if (ZeroData != FirstZeroData)
3454 if (!
MI.isTransient())
3463 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3479 LiveRegs.addLiveOuts(*
MBB);
3484 LiveRegs.stepBackward(*
I);
3487 if (LiveRegs.contains(AArch64::NZCV))
3498 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3499 <<
"due to high register pressure.\n");
3504 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3509 int64_t CurOffset = Instrs[0].Offset;
3510 for (
auto &Instr : Instrs) {
3511 if (CurOffset >
Instr.Offset)
3518 TagStoreEdit TSE(
MBB, FirstZeroData);
3519 std::optional<int64_t> EndOffset;
3520 for (
auto &Instr : Instrs) {
3521 if (EndOffset && *EndOffset !=
Instr.Offset) {
3523 TSE.emitCode(InsertI, TFI,
false);
3527 TSE.addInstruction(Instr);
3546 II = tryMergeAdjacentSTG(
II,
this, RS);
3553 shouldSignReturnAddressEverywhere(MF))
3562 bool IgnoreSPUpdates)
const {
3564 if (IgnoreSPUpdates) {
3567 FrameReg = AArch64::SP;
3577 FrameReg = AArch64::SP;
3602 bool IsValid =
false;
3604 int ObjectIndex = 0;
3606 int GroupIndex = -1;
3608 bool ObjectFirst =
false;
3611 bool GroupFirst =
false;
3616 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3620 SmallVector<int, 8> CurrentMembers;
3621 int NextGroupIndex = 0;
3622 std::vector<FrameObject> &Objects;
3625 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3626 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3627 void EndCurrentGroup() {
3628 if (CurrentMembers.
size() > 1) {
3633 for (
int Index : CurrentMembers) {
3634 Objects[
Index].GroupIndex = NextGroupIndex;
3640 CurrentMembers.clear();
3644bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3666 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3667 A.GroupIndex,
A.ObjectIndex) <
3668 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3669 B.GroupIndex,
B.ObjectIndex);
3678 ObjectsToAllocate.
empty())
3683 for (
auto &Obj : ObjectsToAllocate) {
3684 FrameObjects[Obj].IsValid =
true;
3685 FrameObjects[Obj].ObjectIndex = Obj;
3690 GroupBuilder GB(FrameObjects);
3691 for (
auto &
MBB : MF) {
3692 for (
auto &
MI :
MBB) {
3693 if (
MI.isDebugInstr())
3698 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3701 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3703 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3708 switch (
MI.getOpcode()) {
3709 case AArch64::STGloop:
3710 case AArch64::STZGloop:
3714 case AArch64::STZGi:
3715 case AArch64::ST2Gi:
3716 case AArch64::STZ2Gi:
3729 FrameObjects[FI].IsValid)
3737 GB.AddMember(TaggedFI);
3739 GB.EndCurrentGroup();
3742 GB.EndCurrentGroup();
3747 FrameObject::AccessHazard;
3749 for (
auto &Obj : FrameObjects)
3750 if (!Obj.Accesses ||
3751 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3752 Obj.Accesses = FrameObject::AccessGPR;
3761 FrameObjects[*TBPI].ObjectFirst =
true;
3762 FrameObjects[*TBPI].GroupFirst =
true;
3763 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3764 if (FirstGroupIndex >= 0)
3765 for (FrameObject &Object : FrameObjects)
3766 if (Object.GroupIndex == FirstGroupIndex)
3767 Object.GroupFirst =
true;
3773 for (
auto &Obj : FrameObjects) {
3777 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3781 dbgs() <<
"Final frame order:\n";
3782 for (
auto &Obj : FrameObjects) {
3785 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3786 if (Obj.ObjectFirst)
3787 dbgs() <<
", first";
3789 dbgs() <<
", group-first";
3800AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3811 MF.
insert(MBBInsertPoint, LoopMBB);
3813 MF.
insert(MBBInsertPoint, ExitMBB);
3848 MBB.addSuccessor(LoopMBB);
3852 return ExitMBB->
begin();
3855void AArch64FrameLowering::inlineStackProbeFixed(
3860 const AArch64InstrInfo *
TII =
3862 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
3867 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
3868 int64_t NumBlocks = FrameSize / ProbeSize;
3869 int64_t ResidualSize = FrameSize % ProbeSize;
3871 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
3872 << NumBlocks <<
" blocks of " << ProbeSize
3873 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
3878 for (
int i = 0; i < NumBlocks; ++i) {
3884 EmitAsyncCFI && !HasFP, CFAOffset);
3897 }
else if (NumBlocks != 0) {
3903 EmitAsyncCFI && !HasFP, CFAOffset);
3905 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
3907 if (EmitAsyncCFI && !HasFP) {
3910 .buildDefCFARegister(AArch64::SP);
3914 if (ResidualSize != 0) {
3920 EmitAsyncCFI && !HasFP, CFAOffset);
3941 SmallVector<MachineInstr *, 4> ToReplace;
3942 for (MachineInstr &
MI :
MBB)
3943 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
3944 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
3947 for (MachineInstr *
MI : ToReplace) {
3948 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
3949 Register ScratchReg =
MI->getOperand(0).getReg();
3950 int64_t FrameSize =
MI->getOperand(1).getImm();
3952 MI->getOperand(3).getImm());
3953 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
3956 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
3957 "Stack probe pseudo-instruction expected");
3958 const AArch64InstrInfo *
TII =
3959 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
3960 Register TargetReg =
MI->getOperand(0).getReg();
3961 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
3963 MI->eraseFromParent();
3983 return std::make_tuple(
start(),
Idx) <
3984 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4014 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4015 if (
Offset.getScalable())
4016 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4027void AArch64FrameLowering::emitRemarks(
4030 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4038 if (HazardSize == 0)
4046 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4048 size_t NumFPLdSt = 0;
4049 size_t NumNonFPLdSt = 0;
4052 for (
const MachineBasicBlock &
MBB : MF) {
4053 for (
const MachineInstr &
MI :
MBB) {
4054 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4056 for (MachineMemOperand *MMO :
MI.memoperands()) {
4063 StackAccesses[ArrIdx].Idx = FrameIdx;
4064 StackAccesses[ArrIdx].Offset =
4075 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4086 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4097 if (StackAccesses.front().isMixed())
4098 MixedObjects.push_back(&StackAccesses.front());
4100 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4102 const auto &
First = *It;
4103 const auto &Second = *(It + 1);
4105 if (Second.isMixed())
4106 MixedObjects.push_back(&Second);
4108 if ((
First.isSME() && Second.isCPU()) ||
4109 (
First.isCPU() && Second.isSME())) {
4111 if (Distance < HazardSize)
4116 auto EmitRemark = [&](llvm::StringRef Str) {
4118 auto R = MachineOptimizationRemarkAnalysis(
4119 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4120 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4124 for (
const auto &
P : HazardPairs)
4125 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4127 for (
const auto *Obj : MixedObjects)
4129 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
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 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 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.
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 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.
LLVM_ABI 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
LLVM_ABI 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.
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.
Primary interface to the complete machine description for the target machine.
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
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.
@ Unknown
Not known to have no common set bits.
RegState
Flags to represent properties of register accesses.
@ Define
Register definition.
@ LLVM_MARK_AS_BITMASK_ENUM
constexpr RegState getKillRegState(bool B)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
@ AArch64FrameOffsetCannotUpdate
Offset cannot apply.
constexpr T alignDown(U Value, V Align, W Skew=0)
Returns the largest unsigned integer less than or equal to Value and is Skew mod Align.
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, StackOffset Offset, const TargetInstrInfo *TII, MachineInstr::MIFlag=MachineInstr::NoFlags, bool SetNZCV=false, bool NeedsWinCFI=false, bool *HasWinCFI=nullptr, bool EmitCFAOffset=false, StackOffset InitialOffset={}, unsigned FrameReg=AArch64::SP)
emitFrameOffset - Emit instructions as needed to set DestReg to SrcReg plus Offset.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
constexpr RegState getDefRegState(bool B)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ 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.
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.
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