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;
374 if (AFI->hasCalculatedStackSizeSVE())
399bool AArch64FrameLowering::homogeneousPrologEpilog(
425 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
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 if (MFI.branchProtectionPAuthLR()) {
733 CFIBuilder.buildNegateRAStateWithPC();
735 CFIBuilder.buildNegateRAState();
740 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
741 CFIBuilder.buildSameValue(AArch64::X18);
744 const std::vector<CalleeSavedInfo> &CSI =
746 for (
const auto &Info : CSI) {
748 if (!
TRI.regNeedsCFI(Reg, Reg))
750 CFIBuilder.buildSameValue(Reg);
763 case AArch64::W##n: \
764 case AArch64::X##n: \
789 case AArch64::B##n: \
790 case AArch64::H##n: \
791 case AArch64::S##n: \
792 case AArch64::D##n: \
793 case AArch64::Q##n: \
794 return HasSVE ? AArch64::Z##n : AArch64::Q##n
831void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
842 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
845 BitVector GPRsToZero(
TRI.getNumRegs());
846 BitVector FPRsToZero(
TRI.getNumRegs());
849 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
852 GPRsToZero.set(XReg);
856 FPRsToZero.set(XReg);
863 for (MCRegister
Reg : GPRsToZero.set_bits())
867 for (MCRegister
Reg : FPRsToZero.set_bits())
871 for (MCRegister PReg :
872 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
873 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
874 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
876 if (RegsToZero[PReg])
882bool AArch64FrameLowering::windowsRequiresStackProbe(
884 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
885 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
889 StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
898 for (
unsigned i = 0; CSRegs[i]; ++i)
904 bool HasCall)
const {
914 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
916 LivePhysRegs LiveRegs(
TRI);
919 LiveRegs.addReg(AArch64::X16);
920 LiveRegs.addReg(AArch64::X17);
921 LiveRegs.addReg(AArch64::X18);
925 const MachineRegisterInfo &MRI = MF->
getRegInfo();
926 if (LiveRegs.available(MRI, AArch64::X9))
929 for (
unsigned Reg : AArch64::GPR64RegClass) {
930 if (LiveRegs.available(MRI,
Reg))
933 return AArch64::NoRegister;
952 if (!
LiveRegs.available(MRI, AArch64::X16) ||
953 !
LiveRegs.available(MRI, AArch64::X17))
960 MBB.isLiveIn(AArch64::NZCV))
964 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
970 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
971 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
980 F.needsUnwindTableEntry();
983bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
999 unsigned Opc =
MBBI->getOpcode();
1003 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1004 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1012 case AArch64::STR_ZXI:
1013 case AArch64::LDR_ZXI: {
1014 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1021 case AArch64::STR_PXI:
1022 case AArch64::LDR_PXI: {
1023 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1030 case AArch64::LDPDpost:
1033 case AArch64::STPDpre: {
1034 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1035 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1036 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1043 case AArch64::LDPXpost:
1046 case AArch64::STPXpre: {
1049 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1050 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1054 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1055 .
addImm(RegInfo->getSEHRegNum(Reg0))
1056 .
addImm(RegInfo->getSEHRegNum(Reg1))
1061 case AArch64::LDRDpost:
1064 case AArch64::STRDpre: {
1065 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1066 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1072 case AArch64::LDRXpost:
1075 case AArch64::STRXpre: {
1076 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1083 case AArch64::STPDi:
1084 case AArch64::LDPDi: {
1085 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1086 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1094 case AArch64::STPXi:
1095 case AArch64::LDPXi: {
1099 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1100 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1102 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1106 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1113 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1120 case AArch64::STRXui:
1121 case AArch64::LDRXui: {
1122 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1129 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1135 case AArch64::STRDui:
1136 case AArch64::LDRDui: {
1137 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1144 case AArch64::STPQi:
1145 case AArch64::LDPQi: {
1146 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1147 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1148 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1155 case AArch64::LDPQpost:
1158 case AArch64::STPQpre: {
1159 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1160 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1161 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1180 if (ST.isTargetDarwin())
1202 DL =
MBBI->getDebugLoc();
1204 TII->createPauthEpilogueInstr(
MBB,
DL);
1208 EmitSignRA(MF.
front());
1210 if (
MBB.isEHFuncletEntry())
1212 if (
MBB.isReturnBlock())
1268 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1273 if (MFI.isVariableSizedObjectIndex(FI)) {
1283 if (MFI.hasScalableStackID(FI)) {
1284 if (FPAfterSVECalleeSaves &&
1287 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1295 AccessOffset = -PPRStackSize;
1296 return AccessOffset +
1301 bool IsFixed = MFI.isFixedObjectIndex(FI);
1306 if (!IsFixed && !IsCSR) {
1307 ScalableOffset = -SVEStackSize;
1308 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1323 int64_t ObjectOffset)
const {
1327 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1328 unsigned FixedObject =
1329 getFixedObjectSize(MF, AFI, IsWin64,
false);
1337 int64_t ObjectOffset)
const {
1348 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1349 ? getFPOffset(MF, ObjectOffset).getFixed()
1350 : getStackOffset(MF, ObjectOffset).getFixed();
1355 bool ForSimm)
const {
1357 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1358 bool isFixed = MFI.isFixedObjectIndex(FI);
1361 FrameReg, PreferFP, ForSimm);
1367 bool ForSimm)
const {
1373 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1374 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1377 bool isSVE = MFI.isScalableStackID(StackID);
1381 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1392 PreferFP &= !SVEStackSize;
1400 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1404 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1406 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1411 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1412 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1414 if (FPOffset >= 0) {
1418 }
else if (MFI.hasVarSizedObjects()) {
1422 bool CanUseBP = RegInfo->hasBasePointer(MF);
1423 if (FPOffsetFits && CanUseBP)
1430 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1437 "Funclets should only be present on Win64");
1441 if (FPOffsetFits && PreferFP)
1448 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1449 "In the presence of dynamic stack pointer realignment, "
1450 "non-argument/CSR objects cannot be accessed through the frame pointer");
1467 FPOffset -= PPRStackSize;
1469 SPOffset -= PPRStackSize;
1474 if (FPAfterSVECalleeSaves) {
1485 RegInfo->hasStackRealignment(MF))) {
1486 FrameReg = RegInfo->getFrameRegister(MF);
1489 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1496 if (FPAfterSVECalleeSaves) {
1503 SVEAreaOffset = SVECalleeSavedStack;
1505 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1508 SVEAreaOffset = SVEStackSize;
1510 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1513 if (UseFP && !(isFixed || isCSR))
1514 SVEAreaOffset = -SVEStackSize;
1515 if (!UseFP && (isFixed || isCSR))
1516 SVEAreaOffset = SVEStackSize;
1520 FrameReg = RegInfo->getFrameRegister(MF);
1525 if (RegInfo->hasBasePointer(MF))
1526 FrameReg = RegInfo->getBaseRegister();
1528 assert(!MFI.hasVarSizedObjects() &&
1529 "Can't use SP when we have var sized objects.");
1530 FrameReg = AArch64::SP;
1558 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1564 unsigned SpillCount,
unsigned Reg1,
1565 unsigned Reg2,
bool NeedsWinCFI,
1574 if (Reg2 == AArch64::FP)
1584 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1585 return SpillExtendedVolatile
1586 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1587 (SpillCount % 2) == 0)
1592 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1593 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1603 unsigned SpillCount,
unsigned Reg1,
1604 unsigned Reg2,
bool UsesWinAAPCS,
1605 bool NeedsWinCFI,
bool NeedsFrameRecord,
1609 Reg1, Reg2, NeedsWinCFI,
TRI);
1613 if (NeedsFrameRecord)
1614 return Reg2 == AArch64::LR;
1626 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1627 const TargetRegisterClass *RC;
1629 RegPairInfo() =
default;
1631 bool isPaired()
const {
return Reg2.
isValid(); }
1633 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1639 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1640 if (SavedRegs.
test(PReg)) {
1641 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1655 bool IsLocallyStreaming =
1661 return Subtarget.hasSVE2p1() ||
1662 (Subtarget.hasSME2() &&
1663 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1671 bool NeedsFrameRecord) {
1688 (
Count & 1) == 0) &&
1689 "Odd number of callee-saved regs to spill!");
1691 int StackFillDir = -1;
1693 unsigned FirstReg = 0;
1701 FirstReg =
Count - 1;
1713 bool SpillExtendedVolatile =
1715 const auto &
Reg = CSI.getReg();
1716 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1719 int ZPRByteOffset = 0;
1720 int PPRByteOffset = 0;
1725 }
else if (!FPAfterSVECalleeSaves) {
1736 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1737 if (StackFillDir < 0)
1743 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1745 RPI.Reg1 = CSI[i].getReg();
1747 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1748 RPI.Type = RegPairInfo::GPR;
1749 RPI.RC = &AArch64::GPR64RegClass;
1750 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1751 RPI.Type = RegPairInfo::FPR64;
1752 RPI.RC = &AArch64::FPR64RegClass;
1753 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1754 RPI.Type = RegPairInfo::FPR128;
1755 RPI.RC = &AArch64::FPR128RegClass;
1756 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1757 RPI.Type = RegPairInfo::ZPR;
1758 RPI.RC = &AArch64::ZPRRegClass;
1759 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1760 RPI.Type = RegPairInfo::PPR;
1761 RPI.RC = &AArch64::PPRRegClass;
1762 }
else if (RPI.Reg1 == AArch64::VG) {
1763 RPI.Type = RegPairInfo::VG;
1764 RPI.RC = &AArch64::FIXED_REGSRegClass;
1769 int &ScalableByteOffset = RPI.Type == RegPairInfo::PPR && SplitPPRs
1774 if (HasCSHazardPadding &&
1777 ByteOffset += StackFillDir * StackHazardSize;
1781 int Scale =
TRI->getSpillSize(*RPI.RC);
1783 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1784 MCRegister NextReg = CSI[i + RegInc].getReg();
1785 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1787 case RegPairInfo::GPR:
1788 if (AArch64::GPR64RegClass.
contains(NextReg) &&
1790 RPI.Reg1, NextReg, IsWindows,
1791 NeedsWinCFI, NeedsFrameRecord,
TRI))
1794 case RegPairInfo::FPR64:
1795 if (AArch64::FPR64RegClass.
contains(NextReg) &&
1797 RPI.Reg1, NextReg, IsWindows,
1798 NeedsWinCFI, NeedsFrameRecord,
TRI))
1801 case RegPairInfo::FPR128:
1802 if (AArch64::FPR128RegClass.
contains(NextReg))
1805 case RegPairInfo::PPR:
1807 case RegPairInfo::ZPR:
1809 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
1812 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
1817 case RegPairInfo::VG:
1828 assert((!RPI.isPaired() ||
1829 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1830 "Out of order callee saved regs!");
1832 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1833 RPI.Reg1 == AArch64::LR) &&
1834 "FrameRecord must be allocated together with LR");
1837 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1838 RPI.Reg2 == AArch64::LR) &&
1839 "FrameRecord must be allocated together with LR");
1847 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1848 RPI.Reg1 + 1 == RPI.Reg2))) &&
1849 "Callee-save registers not saved as adjacent register pair!");
1851 RPI.FrameIdx = CSI[i].getFrameIdx();
1854 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1858 if (RPI.isScalable() && ScalableByteOffset % Scale != 0)
1859 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1863 if (!RPI.isScalable() && ByteOffset % Scale != 0)
1864 ByteOffset = AlignOffset(ByteOffset, Scale);
1866 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1867 assert(OffsetPre % Scale == 0);
1869 if (RPI.isScalable())
1870 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1872 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1877 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1878 (IsWindows && RPI.Reg2 == AArch64::LR)))
1879 ByteOffset += StackFillDir * 8;
1883 if (NeedGapToAlignStack && !IsWindows && !RPI.isScalable() &&
1884 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1885 ByteOffset % 16 != 0) {
1886 ByteOffset += 8 * StackFillDir;
1892 NeedGapToAlignStack =
false;
1895 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1896 assert(OffsetPost % Scale == 0);
1899 int Offset = IsWindows ? OffsetPre : OffsetPost;
1904 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1905 (IsWindows && RPI.Reg2 == AArch64::LR)))
1907 RPI.Offset =
Offset / Scale;
1909 assert((!RPI.isPaired() ||
1910 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1911 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1912 "Offset out of bounds for LDP/STP immediate");
1914 auto isFrameRecord = [&] {
1916 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1917 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1925 return i > 0 && RPI.Reg1 == AArch64::FP &&
1926 CSI[i - 1].getReg() == AArch64::LR;
1931 if (NeedsFrameRecord && isFrameRecord())
1948 std::reverse(RegPairs.
begin(), RegPairs.
end());
1970 if (homogeneousPrologEpilog(MF)) {
1974 for (
auto &RPI : RegPairs) {
1980 MBB.addLiveIn(RPI.Reg1);
1981 if (RPI.isPaired() && !MRI.
isReserved(RPI.Reg2))
1982 MBB.addLiveIn(RPI.Reg2);
1986 bool PTrueCreated =
false;
2002 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2003 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2005 case RegPairInfo::GPR:
2006 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2008 case RegPairInfo::FPR64:
2009 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2011 case RegPairInfo::FPR128:
2012 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2014 case RegPairInfo::ZPR:
2015 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2017 case RegPairInfo::PPR:
2018 StrOpc = AArch64::STR_PXI;
2020 case RegPairInfo::VG:
2021 StrOpc = AArch64::STRXui;
2027 if (X0Scratch != AArch64::NoRegister)
2033 if (Reg1 == AArch64::VG) {
2035 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2036 assert(Reg1 != AArch64::NoRegister);
2046 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2047 AArch64::X0, LiveIn.PhysReg);
2055 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2057 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2071 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2073 dbgs() <<
", " << RPI.FrameIdx + 1;
2078 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2079 "Windows unwdinding requires a consecutive (FP,LR) pair");
2083 unsigned FrameIdxReg1 = RPI.FrameIdx;
2084 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2090 if (RPI.isPaired() && RPI.isScalable()) {
2096 "Expects SVE2.1 or SME2 target and a predicate register");
2097#ifdef EXPENSIVE_CHECKS
2098 auto IsPPR = [](
const RegPairInfo &c) {
2099 return c.Reg1 == RegPairInfo::PPR;
2101 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2102 auto IsZPR = [](
const RegPairInfo &c) {
2103 return c.Type == RegPairInfo::ZPR;
2105 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2106 assert(!(PPRBegin < ZPRBegin) &&
2107 "Expected callee save predicate to be handled first");
2109 if (!PTrueCreated) {
2110 PTrueCreated =
true;
2116 MBB.addLiveIn(Reg1);
2118 MBB.addLiveIn(Reg2);
2119 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2136 MBB.addLiveIn(Reg1);
2137 if (RPI.isPaired()) {
2139 MBB.addLiveIn(Reg2);
2158 if (RPI.Type == RegPairInfo::ZPR) {
2162 }
else if (RPI.Type == RegPairInfo::PPR) {
2182 DL =
MBBI->getDebugLoc();
2185 if (homogeneousPrologEpilog(MF, &
MBB)) {
2188 for (
auto &RPI : RegPairs) {
2196 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2198 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2199 std::reverse(PPRBegin, PPREnd);
2200 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2202 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2203 std::reverse(ZPRBegin, ZPREnd);
2205 bool PTrueCreated =
false;
2206 for (
const RegPairInfo &RPI : RegPairs) {
2219 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2220 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2222 case RegPairInfo::GPR:
2223 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2225 case RegPairInfo::FPR64:
2226 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2228 case RegPairInfo::FPR128:
2229 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2231 case RegPairInfo::ZPR:
2232 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2234 case RegPairInfo::PPR:
2235 LdrOpc = AArch64::LDR_PXI;
2237 case RegPairInfo::VG:
2244 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2246 dbgs() <<
", " << RPI.FrameIdx + 1;
2253 unsigned FrameIdxReg1 = RPI.FrameIdx;
2254 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2261 if (RPI.isPaired() && RPI.isScalable()) {
2266 "Expects SVE2.1 or SME2 target and a predicate register");
2267#ifdef EXPENSIVE_CHECKS
2268 assert(!(PPRBegin < ZPRBegin) &&
2269 "Expected callee save predicate to be handled first");
2271 if (!PTrueCreated) {
2272 PTrueCreated =
true;
2277 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
2294 if (RPI.isPaired()) {
2321 return std::optional<int>(PSV->getFrameIndex());
2332 return std::nullopt;
2338 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2339 return std::nullopt;
2346 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2352void AArch64FrameLowering::determineStackHazardSlot(
2355 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2356 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2370 return AArch64::FPR64RegClass.contains(Reg) ||
2371 AArch64::FPR128RegClass.contains(Reg) ||
2372 AArch64::ZPRRegClass.contains(Reg);
2375 return AArch64::PPRRegClass.contains(Reg);
2377 bool HasFPRStackObjects =
false;
2378 bool HasPPRStackObjects =
false;
2380 enum SlotType : uint8_t {
2391 for (
auto &
MBB : MF) {
2392 for (
auto &
MI :
MBB) {
2394 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2401 ? SlotType::ZPRorFPR
2407 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2408 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2411 if (SlotTypes[FI] == SlotType::PPR) {
2413 HasPPRStackObjects =
true;
2418 if (HasFPRCSRs || HasFPRStackObjects) {
2421 << StackHazardSize <<
"\n");
2432 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2438 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2439 "non-SVE CC function...\n");
2446 <<
"Calling convention is not supported with SplitSVEObjects\n");
2450 if (!HasPPRCSRs && !HasPPRStackObjects) {
2452 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2456 if (!HasFPRCSRs && !HasFPRStackObjects) {
2459 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2463 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2464 MF.getSubtarget<AArch64Subtarget>();
2466 "Expected SVE to be available for PPRs");
2468 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2472 BitVector FPRZRegs(SavedRegs.
size());
2473 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2474 BitVector::reference RegBit = SavedRegs[
Reg];
2477 unsigned SubRegIdx = 0;
2479 SubRegIdx = AArch64::dsub;
2481 SubRegIdx = AArch64::zsub;
2488 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2491 SavedRegs |= FPRZRegs;
2511 unsigned UnspilledCSGPR = AArch64::NoRegister;
2512 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
2518 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2520 unsigned ExtraCSSpill = 0;
2521 bool HasUnpairedGPR64 =
false;
2522 bool HasPairZReg =
false;
2523 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2524 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2527 for (
unsigned i = 0; CSRegs[i]; ++i) {
2531 if (Reg == BasePointerReg)
2536 if (UserReservedRegs[Reg]) {
2537 SavedRegs.
reset(Reg);
2541 bool RegUsed = SavedRegs.
test(Reg);
2543 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2544 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2545 AArch64::FPR128RegClass.
contains(Reg)) {
2548 if (HasUnpairedGPR64)
2549 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2551 PairedReg = CSRegs[i ^ 1];
2558 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2559 PairedReg = AArch64::NoRegister;
2560 HasUnpairedGPR64 =
true;
2562 assert(PairedReg == AArch64::NoRegister ||
2563 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
2564 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
2565 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
2568 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2569 UnspilledCSGPR = Reg;
2570 UnspilledCSGPRPaired = PairedReg;
2578 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
2579 !SavedRegs.
test(PairedReg)) {
2580 SavedRegs.
set(PairedReg);
2581 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2582 !ReservedRegs[PairedReg])
2583 ExtraCSSpill = PairedReg;
2586 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2587 SavedRegs.
test(CSRegs[i ^ 1]));
2595 if (PnReg.isValid())
2601 SavedRegs.
set(AArch64::P8);
2606 "Predicate cannot be a reserved register");
2616 SavedRegs.
set(AArch64::X18);
2622 determineStackHazardSlot(MF, SavedRegs);
2625 unsigned CSStackSize = 0;
2626 unsigned ZPRCSStackSize = 0;
2627 unsigned PPRCSStackSize = 0;
2629 for (
unsigned Reg : SavedRegs.
set_bits()) {
2631 assert(RC &&
"expected register class!");
2632 auto SpillSize =
TRI->getSpillSize(*RC);
2633 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2634 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2636 ZPRCSStackSize += SpillSize;
2638 PPRCSStackSize += SpillSize;
2640 CSStackSize += SpillSize;
2646 unsigned NumSavedRegs = SavedRegs.
count();
2659 SavedRegs.
set(AArch64::LR);
2664 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2665 SavedRegs.
set(AArch64::FP);
2666 SavedRegs.
set(AArch64::LR);
2670 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2671 for (
unsigned Reg : SavedRegs.
set_bits())
2677 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2679 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2681 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2682 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2691 int64_t CalleeStackUsed = 0;
2694 if (FixedOff > CalleeStackUsed)
2695 CalleeStackUsed = FixedOff;
2699 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2700 CalleeStackUsed) > EstimatedStackSizeLimit;
2701 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2711 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
2713 <<
" to get a scratch register.\n");
2714 SavedRegs.
set(UnspilledCSGPR);
2715 ExtraCSSpill = UnspilledCSGPR;
2720 if (producePairRegisters(MF)) {
2721 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
2724 SavedRegs.
reset(UnspilledCSGPR);
2725 ExtraCSSpill = AArch64::NoRegister;
2728 SavedRegs.
set(UnspilledCSGPRPaired);
2737 unsigned Size =
TRI->getSpillSize(RC);
2738 Align Alignment =
TRI->getSpillAlign(RC);
2740 RS->addScavengingFrameIndex(FI);
2741 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2742 <<
" as the emergency spill slot.\n");
2747 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2756 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2760 "Should not invalidate callee saved info");
2771 std::vector<CalleeSavedInfo> &CSI)
const {
2780 std::reverse(CSI.begin(), CSI.end());
2800 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2801 if (It != CSI.end())
2802 CSI.insert(It, VGInfo);
2804 CSI.push_back(VGInfo);
2808 int HazardSlotIndex = std::numeric_limits<int>::max();
2809 for (
auto &CS : CSI) {
2817 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2818 "Unexpected register order for hazard slot");
2820 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2826 unsigned Size = RegInfo->getSpillSize(*RC);
2827 Align Alignment(RegInfo->getSpillAlign(*RC));
2829 CS.setFrameIdx(FrameIdx);
2834 Reg == AArch64::FP) {
2844 HazardSlotIndex == std::numeric_limits<int>::max()) {
2846 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2873 int &Min,
int &Max) {
2874 Min = std::numeric_limits<int>::max();
2875 Max = std::numeric_limits<int>::min();
2881 for (
auto &CS : CSI) {
2882 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
2883 AArch64::PPRRegClass.contains(CS.getReg())) {
2884 assert((Max == std::numeric_limits<int>::min() ||
2885 Max + 1 == CS.getFrameIdx()) &&
2886 "SVE CalleeSaves are not consecutive");
2887 Min = std::min(Min, CS.getFrameIdx());
2888 Max = std::max(Max, CS.getFrameIdx());
2891 return Min != std::numeric_limits<int>::max();
2904 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
2912 "SVE vectors should never be passed on the stack by value, only by "
2916 auto AllocateObject = [&](
int FI) {
2925 if (Alignment >
Align(16))
2927 "Alignment of scalable vectors > 16 bytes is not yet supported");
2930 StackTop =
alignTo(StackTop, Alignment);
2932 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
2933 "SVE StackTop far too large?!");
2935 int64_t
Offset = -int64_t(StackTop);
2943 int MinCSFrameIndex, MaxCSFrameIndex;
2945 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
2958 int StackProtectorFI = -1;
2962 ObjectsToAllocate.
push_back(StackProtectorFI);
2978 for (
unsigned FI : ObjectsToAllocate)
2993 "Upwards growing stack unsupported");
3008 int64_t CurrentOffset =
3012 int FrameIndex =
H.CatchObj.FrameIndex;
3013 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3024 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3025 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3027 "UnwindHelpOffset must be at the start of the fixed object area");
3030 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3040 RS->enterBasicBlockEnd(
MBB);
3042 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3043 assert(DstReg &&
"There must be a free register after frame setup");
3054struct TagStoreInstr {
3062 MachineFunction *MF;
3063 MachineBasicBlock *
MBB;
3064 MachineRegisterInfo *MRI;
3073 StackOffset FrameRegOffset;
3077 std::optional<int64_t> FrameRegUpdate;
3079 unsigned FrameRegUpdateFlags;
3089 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3090 :
MBB(
MBB), ZeroData(ZeroData) {
3096 void addInstruction(TagStoreInstr
I) {
3098 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3099 "Non-adjacent tag store instructions.");
3102 void clear() { TagStores.
clear(); }
3107 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3114 const int64_t kMinOffset = -256 * 16;
3115 const int64_t kMaxOffset = 255 * 16;
3118 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3119 if (BaseRegOffsetBytes < kMinOffset ||
3120 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3124 BaseRegOffsetBytes % 16 != 0) {
3129 BaseRegOffsetBytes = 0;
3134 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3137 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3139 assert(BaseRegOffsetBytes % 16 == 0);
3143 .
addImm(BaseRegOffsetBytes / 16)
3147 if (BaseRegOffsetBytes == 0)
3149 BaseRegOffsetBytes += InstrSize;
3168 int64_t LoopSize =
Size;
3171 if (FrameRegUpdate && *FrameRegUpdate)
3172 LoopSize -= LoopSize % 32;
3174 TII->get(ZeroData ? AArch64::STZGloop_wback
3175 : AArch64::STGloop_wback))
3182 LoopI->
setFlags(FrameRegUpdateFlags);
3184 int64_t ExtraBaseRegUpdate =
3185 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3186 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3187 <<
", Size=" <<
Size
3188 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3189 <<
", FrameRegUpdate=" << FrameRegUpdate
3190 <<
", FrameRegOffset.getFixed()="
3191 << FrameRegOffset.
getFixed() <<
"\n");
3192 if (LoopSize <
Size) {
3196 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3197 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3198 "STG immediate out of range");
3200 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3207 }
else if (ExtraBaseRegUpdate) {
3209 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3210 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3213 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3226 int64_t
Size, int64_t *TotalOffset) {
3228 if ((
MI.getOpcode() == AArch64::ADDXri ||
3229 MI.getOpcode() == AArch64::SUBXri) &&
3230 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3232 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3233 if (
MI.getOpcode() == AArch64::SUBXri)
3244 const int64_t kMaxOffset = 4080 - 16;
3246 const int64_t kMinOffset = -4095;
3247 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3248 PostOffset % 16 == 0) {
3259 for (
auto &TS : TSE) {
3263 if (
MI->memoperands_empty()) {
3267 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3273 bool TryMergeSPUpdate) {
3274 if (TagStores.
empty())
3276 TagStoreInstr &FirstTagStore = TagStores[0];
3277 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3278 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3279 DL = TagStores[0].MI->getDebugLoc();
3283 *MF, FirstTagStore.Offset,
false ,
3287 FrameRegUpdate = std::nullopt;
3289 mergeMemRefs(TagStores, CombinedMemRefs);
3292 dbgs() <<
"Replacing adjacent STG instructions:\n";
3293 for (
const auto &Instr : TagStores) {
3302 if (TagStores.
size() < 2)
3304 emitUnrolled(InsertI);
3307 int64_t TotalOffset = 0;
3308 if (TryMergeSPUpdate) {
3314 if (InsertI !=
MBB->
end() &&
3315 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3317 UpdateInstr = &*InsertI++;
3323 if (!UpdateInstr && TagStores.
size() < 2)
3327 FrameRegUpdate = TotalOffset;
3328 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3335 for (
auto &TS : TagStores)
3336 TS.MI->eraseFromParent();
3340 int64_t &
Size,
bool &ZeroData) {
3344 unsigned Opcode =
MI.getOpcode();
3345 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3346 Opcode == AArch64::STZ2Gi);
3348 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3349 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3351 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3354 Size =
MI.getOperand(2).getImm();
3358 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3360 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3365 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3369 16 *
MI.getOperand(2).getImm();
3373static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3378 return LiveRegs.available(MRI,
Reg);
3381 size_t NumEmergencySlots = 0;
3383 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3385 return FreeGPRs + NumEmergencySlots;
3404 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3410 constexpr int kScanLimit = 10;
3413 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3422 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3423 if (ZeroData != FirstZeroData)
3431 if (!
MI.isTransient())
3440 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3456 LiveRegs.addLiveOuts(*
MBB);
3461 LiveRegs.stepBackward(*
I);
3464 if (LiveRegs.contains(AArch64::NZCV))
3475 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3476 <<
"due to high register pressure.\n");
3481 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3486 int64_t CurOffset = Instrs[0].Offset;
3487 for (
auto &Instr : Instrs) {
3488 if (CurOffset >
Instr.Offset)
3495 TagStoreEdit TSE(
MBB, FirstZeroData);
3496 std::optional<int64_t> EndOffset;
3497 for (
auto &Instr : Instrs) {
3498 if (EndOffset && *EndOffset !=
Instr.Offset) {
3500 TSE.emitCode(InsertI, TFI,
false);
3504 TSE.addInstruction(Instr);
3523 II = tryMergeAdjacentSTG(
II,
this, RS);
3530 shouldSignReturnAddressEverywhere(MF))
3539 bool IgnoreSPUpdates)
const {
3541 if (IgnoreSPUpdates) {
3544 FrameReg = AArch64::SP;
3554 FrameReg = AArch64::SP;
3579 bool IsValid =
false;
3581 int ObjectIndex = 0;
3583 int GroupIndex = -1;
3585 bool ObjectFirst =
false;
3588 bool GroupFirst =
false;
3593 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3597 SmallVector<int, 8> CurrentMembers;
3598 int NextGroupIndex = 0;
3599 std::vector<FrameObject> &Objects;
3602 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3603 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3604 void EndCurrentGroup() {
3605 if (CurrentMembers.
size() > 1) {
3610 for (
int Index : CurrentMembers) {
3611 Objects[
Index].GroupIndex = NextGroupIndex;
3617 CurrentMembers.clear();
3621bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3643 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3644 A.GroupIndex,
A.ObjectIndex) <
3645 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3646 B.GroupIndex,
B.ObjectIndex);
3655 ObjectsToAllocate.
empty())
3660 for (
auto &Obj : ObjectsToAllocate) {
3661 FrameObjects[Obj].IsValid =
true;
3662 FrameObjects[Obj].ObjectIndex = Obj;
3667 GroupBuilder GB(FrameObjects);
3668 for (
auto &
MBB : MF) {
3669 for (
auto &
MI :
MBB) {
3670 if (
MI.isDebugInstr())
3675 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3678 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3680 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3685 switch (
MI.getOpcode()) {
3686 case AArch64::STGloop:
3687 case AArch64::STZGloop:
3691 case AArch64::STZGi:
3692 case AArch64::ST2Gi:
3693 case AArch64::STZ2Gi:
3706 FrameObjects[FI].IsValid)
3714 GB.AddMember(TaggedFI);
3716 GB.EndCurrentGroup();
3719 GB.EndCurrentGroup();
3724 FrameObject::AccessHazard;
3726 for (
auto &Obj : FrameObjects)
3727 if (!Obj.Accesses ||
3728 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3729 Obj.Accesses = FrameObject::AccessGPR;
3738 FrameObjects[*TBPI].ObjectFirst =
true;
3739 FrameObjects[*TBPI].GroupFirst =
true;
3740 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3741 if (FirstGroupIndex >= 0)
3742 for (FrameObject &Object : FrameObjects)
3743 if (Object.GroupIndex == FirstGroupIndex)
3744 Object.GroupFirst =
true;
3750 for (
auto &Obj : FrameObjects) {
3754 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3758 dbgs() <<
"Final frame order:\n";
3759 for (
auto &Obj : FrameObjects) {
3762 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3763 if (Obj.ObjectFirst)
3764 dbgs() <<
", first";
3766 dbgs() <<
", group-first";
3777AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3788 MF.
insert(MBBInsertPoint, LoopMBB);
3790 MF.
insert(MBBInsertPoint, ExitMBB);
3825 MBB.addSuccessor(LoopMBB);
3829 return ExitMBB->
begin();
3832void AArch64FrameLowering::inlineStackProbeFixed(
3837 const AArch64InstrInfo *
TII =
3839 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
3844 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
3845 int64_t NumBlocks = FrameSize / ProbeSize;
3846 int64_t ResidualSize = FrameSize % ProbeSize;
3848 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
3849 << NumBlocks <<
" blocks of " << ProbeSize
3850 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
3855 for (
int i = 0; i < NumBlocks; ++i) {
3861 EmitAsyncCFI && !HasFP, CFAOffset);
3874 }
else if (NumBlocks != 0) {
3880 EmitAsyncCFI && !HasFP, CFAOffset);
3882 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
3884 if (EmitAsyncCFI && !HasFP) {
3887 .buildDefCFARegister(AArch64::SP);
3891 if (ResidualSize != 0) {
3897 EmitAsyncCFI && !HasFP, CFAOffset);
3918 SmallVector<MachineInstr *, 4> ToReplace;
3919 for (MachineInstr &
MI :
MBB)
3920 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
3921 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
3924 for (MachineInstr *
MI : ToReplace) {
3925 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
3926 Register ScratchReg =
MI->getOperand(0).getReg();
3927 int64_t FrameSize =
MI->getOperand(1).getImm();
3929 MI->getOperand(3).getImm());
3930 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
3933 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
3934 "Stack probe pseudo-instruction expected");
3935 const AArch64InstrInfo *
TII =
3936 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
3937 Register TargetReg =
MI->getOperand(0).getReg();
3938 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
3940 MI->eraseFromParent();
3960 return std::make_tuple(
start(),
Idx) <
3961 std::make_tuple(Rhs.
start(), Rhs.
Idx);
3991 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
3992 if (
Offset.getScalable())
3993 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4004void AArch64FrameLowering::emitRemarks(
4007 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4012 const uint64_t HazardSize =
4015 if (HazardSize == 0)
4023 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4025 size_t NumFPLdSt = 0;
4026 size_t NumNonFPLdSt = 0;
4029 for (
const MachineBasicBlock &
MBB : MF) {
4030 for (
const MachineInstr &
MI :
MBB) {
4031 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4033 for (MachineMemOperand *MMO :
MI.memoperands()) {
4040 StackAccesses[ArrIdx].Idx = FrameIdx;
4041 StackAccesses[ArrIdx].Offset =
4052 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4063 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4074 if (StackAccesses.front().isMixed())
4075 MixedObjects.push_back(&StackAccesses.front());
4077 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4079 const auto &
First = *It;
4080 const auto &Second = *(It + 1);
4082 if (Second.isMixed())
4083 MixedObjects.push_back(&Second);
4085 if ((
First.isSME() && Second.isCPU()) ||
4086 (
First.isCPU() && Second.isSME())) {
4087 uint64_t Distance =
static_cast<uint64_t
>(Second.start() -
First.end());
4088 if (Distance < HazardSize)
4093 auto EmitRemark = [&](llvm::StringRef Str) {
4095 auto R = MachineOptimizationRemarkAnalysis(
4096 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4097 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4101 for (
const auto &
P : HazardPairs)
4102 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4104 for (
const auto *Obj : MixedObjects)
4106 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 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).
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.
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.
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.
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.
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.
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