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())
404bool AArch64FrameLowering::homogeneousPrologEpilog(
430 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
437 unsigned NumGPRs = 0;
438 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
440 if (Reg == AArch64::LR) {
441 assert(CSRegs[
I + 1] == AArch64::FP);
442 if (NumGPRs % 2 != 0)
454bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
473 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
474 MI.getOpcode() == AArch64::ADDXri ||
475 MI.getOpcode() == AArch64::ADDSXri)
500 bool IsWin64,
bool IsFunclet)
const {
502 "Tail call reserved stack must be aligned to 16 bytes");
503 if (!IsWin64 || IsFunclet) {
508 Attribute::SwiftAsync))
522 int FrameIndex =
H.CatchObj.FrameIndex;
523 if ((FrameIndex != INT_MAX) &&
524 CatchObjFrameIndices.
insert(FrameIndex)) {
525 FixedObjectSize =
alignTo(FixedObjectSize,
532 FixedObjectSize += 8;
534 return alignTo(FixedObjectSize, 16);
545 const unsigned RedZoneSize =
558 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
562 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
584 if (Subtarget.getTargetLowering()->useStackGuardMixFP())
593 RegInfo->hasStackRealignment(MF))
640 if (TT.isOSDarwin() || TT.isOSWindows())
678 unsigned Opc =
I->getOpcode();
679 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
680 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
683 int64_t Amount =
I->getOperand(0).getImm();
691 if (CalleePopAmount == 0) {
702 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
713 "non-reserved call frame without var sized objects?");
722 }
else if (CalleePopAmount != 0) {
725 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
737 const auto &
TRI = *Subtarget.getRegisterInfo();
743 CFIBuilder.buildDefCFA(AArch64::SP, 0);
746 if (MFI.shouldSignReturnAddress(MF)) {
747 if (MFI.branchProtectionPAuthLR()) {
748 CFIBuilder.buildNegateRAStateWithPC();
750 CFIBuilder.buildNegateRAState();
755 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
756 CFIBuilder.buildSameValue(AArch64::X18);
759 const std::vector<CalleeSavedInfo> &CSI =
761 for (
const auto &Info : CSI) {
763 if (!
TRI.regNeedsCFI(Reg, Reg))
765 CFIBuilder.buildSameValue(Reg);
778 case AArch64::W##n: \
779 case AArch64::X##n: \
804 case AArch64::B##n: \
805 case AArch64::H##n: \
806 case AArch64::S##n: \
807 case AArch64::D##n: \
808 case AArch64::Q##n: \
809 return HasSVE ? AArch64::Z##n : AArch64::Q##n
846void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
857 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
860 BitVector GPRsToZero(
TRI.getNumRegs());
861 BitVector FPRsToZero(
TRI.getNumRegs());
864 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
867 GPRsToZero.set(XReg);
871 FPRsToZero.set(XReg);
878 for (MCRegister
Reg : GPRsToZero.set_bits())
882 for (MCRegister
Reg : FPRsToZero.set_bits())
886 for (MCRegister PReg :
887 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
888 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
889 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
891 if (RegsToZero[PReg])
897bool AArch64FrameLowering::windowsRequiresStackProbe(
899 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
900 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
904 StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
913 for (
unsigned i = 0; CSRegs[i]; ++i)
919 bool HasCall)
const {
929 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
931 LivePhysRegs LiveRegs(
TRI);
934 LiveRegs.addReg(AArch64::X16);
935 LiveRegs.addReg(AArch64::X17);
936 LiveRegs.addReg(AArch64::X18);
940 const MachineRegisterInfo &MRI = MF->
getRegInfo();
941 if (LiveRegs.available(MRI, AArch64::X9))
944 for (
unsigned Reg : AArch64::GPR64RegClass) {
945 if (LiveRegs.available(MRI,
Reg))
948 return AArch64::NoRegister;
967 if (!
LiveRegs.available(MRI, AArch64::X16) ||
968 !
LiveRegs.available(MRI, AArch64::X17))
975 MBB.isLiveIn(AArch64::NZCV))
979 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
985 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
986 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
995 F.needsUnwindTableEntry();
998bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
1014 unsigned Opc =
MBBI->getOpcode();
1018 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1019 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1027 case AArch64::STR_ZXI:
1028 case AArch64::LDR_ZXI: {
1029 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1036 case AArch64::STR_PXI:
1037 case AArch64::LDR_PXI: {
1038 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1045 case AArch64::LDPDpost:
1048 case AArch64::STPDpre: {
1049 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1050 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1051 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1058 case AArch64::LDPXpost:
1061 case AArch64::STPXpre: {
1064 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1065 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1069 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1070 .
addImm(RegInfo->getSEHRegNum(Reg0))
1071 .
addImm(RegInfo->getSEHRegNum(Reg1))
1076 case AArch64::LDRDpost:
1079 case AArch64::STRDpre: {
1080 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1081 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1087 case AArch64::LDRXpost:
1090 case AArch64::STRXpre: {
1091 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1098 case AArch64::STPDi:
1099 case AArch64::LDPDi: {
1100 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1101 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1109 case AArch64::STPXi:
1110 case AArch64::LDPXi: {
1114 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1115 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1117 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1121 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1128 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1135 case AArch64::STRXui:
1136 case AArch64::LDRXui: {
1137 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1144 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1150 case AArch64::STRDui:
1151 case AArch64::LDRDui: {
1152 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1159 case AArch64::STPQi:
1160 case AArch64::LDPQi: {
1161 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1162 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1163 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1170 case AArch64::LDPQpost:
1173 case AArch64::STPQpre: {
1174 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1175 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1176 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1195 if (ST.isTargetDarwin())
1217 DL =
MBBI->getDebugLoc();
1219 TII->createPauthEpilogueInstr(
MBB,
DL);
1223 EmitSignRA(MF.
front());
1225 if (
MBB.isEHFuncletEntry())
1227 if (
MBB.isReturnBlock())
1283 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1288 if (MFI.isVariableSizedObjectIndex(FI)) {
1298 if (MFI.hasScalableStackID(FI)) {
1299 if (FPAfterSVECalleeSaves &&
1302 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1310 AccessOffset = -PPRStackSize;
1311 return AccessOffset +
1316 bool IsFixed = MFI.isFixedObjectIndex(FI);
1321 if (!IsFixed && !IsCSR) {
1322 ScalableOffset = -SVEStackSize;
1323 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1338 int64_t ObjectOffset)
const {
1342 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1343 unsigned FixedObject =
1344 getFixedObjectSize(MF, AFI, IsWin64,
false);
1352 int64_t ObjectOffset)
const {
1363 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1364 ? getFPOffset(MF, ObjectOffset).getFixed()
1365 : getStackOffset(MF, ObjectOffset).getFixed();
1370 bool ForSimm)
const {
1372 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1373 bool isFixed = MFI.isFixedObjectIndex(FI);
1376 FrameReg, PreferFP, ForSimm);
1382 bool ForSimm)
const {
1388 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1389 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1392 bool isSVE = MFI.isScalableStackID(StackID);
1396 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1407 PreferFP &= !SVEStackSize;
1415 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1419 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1421 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1426 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1427 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1429 if (FPOffset >= 0) {
1433 }
else if (MFI.hasVarSizedObjects()) {
1437 bool CanUseBP = RegInfo->hasBasePointer(MF);
1438 if (FPOffsetFits && CanUseBP)
1445 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1452 "Funclets should only be present on Win64");
1456 if (FPOffsetFits && PreferFP)
1463 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1464 "In the presence of dynamic stack pointer realignment, "
1465 "non-argument/CSR objects cannot be accessed through the frame pointer");
1482 FPOffset -= PPRStackSize;
1484 SPOffset -= PPRStackSize;
1489 if (FPAfterSVECalleeSaves) {
1500 RegInfo->hasStackRealignment(MF))) {
1501 FrameReg = RegInfo->getFrameRegister(MF);
1504 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1511 if (FPAfterSVECalleeSaves) {
1518 SVEAreaOffset = SVECalleeSavedStack;
1520 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1523 SVEAreaOffset = SVEStackSize;
1525 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1528 if (UseFP && !(isFixed || isCSR))
1529 SVEAreaOffset = -SVEStackSize;
1530 if (!UseFP && (isFixed || isCSR))
1531 SVEAreaOffset = SVEStackSize;
1535 FrameReg = RegInfo->getFrameRegister(MF);
1540 if (RegInfo->hasBasePointer(MF))
1541 FrameReg = RegInfo->getBaseRegister();
1543 assert(!MFI.hasVarSizedObjects() &&
1544 "Can't use SP when we have var sized objects.");
1545 FrameReg = AArch64::SP;
1573 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1579 unsigned SpillCount,
unsigned Reg1,
1580 unsigned Reg2,
bool NeedsWinCFI,
1589 if (Reg2 == AArch64::FP)
1599 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1600 return SpillExtendedVolatile
1601 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1602 (SpillCount % 2) == 0)
1607 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1608 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1618 unsigned SpillCount,
unsigned Reg1,
1619 unsigned Reg2,
bool UsesWinAAPCS,
1620 bool NeedsWinCFI,
bool NeedsFrameRecord,
1624 Reg1, Reg2, NeedsWinCFI,
TRI);
1628 if (NeedsFrameRecord)
1629 return Reg2 == AArch64::LR;
1641 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1644 RegPairInfo() =
default;
1646 bool isPaired()
const {
return Reg2.
isValid(); }
1648 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1654 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1655 if (SavedRegs.
test(PReg)) {
1656 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1670 bool IsLocallyStreaming =
1676 return Subtarget.hasSVE2p1() ||
1677 (Subtarget.hasSME2() &&
1678 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1686 bool NeedsFrameRecord) {
1703 (
Count & 1) == 0) &&
1704 "Odd number of callee-saved regs to spill!");
1706 int StackFillDir = -1;
1708 unsigned FirstReg = 0;
1716 FirstReg =
Count - 1;
1728 bool SpillExtendedVolatile =
1730 const auto &
Reg = CSI.getReg();
1731 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1734 int ZPRByteOffset = 0;
1735 int PPRByteOffset = 0;
1740 }
else if (!FPAfterSVECalleeSaves) {
1751 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1752 if (StackFillDir < 0)
1758 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1760 RPI.Reg1 = CSI[i].getReg();
1762 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1763 RPI.Type = RegPairInfo::GPR;
1764 RPI.RC = &AArch64::GPR64RegClass;
1765 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1766 RPI.Type = RegPairInfo::FPR64;
1767 RPI.RC = &AArch64::FPR64RegClass;
1768 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1769 RPI.Type = RegPairInfo::FPR128;
1770 RPI.RC = &AArch64::FPR128RegClass;
1771 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1772 RPI.Type = RegPairInfo::ZPR;
1773 RPI.RC = &AArch64::ZPRRegClass;
1774 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1775 RPI.Type = RegPairInfo::PPR;
1776 RPI.RC = &AArch64::PPRRegClass;
1777 }
else if (RPI.Reg1 == AArch64::VG) {
1778 RPI.Type = RegPairInfo::VG;
1779 RPI.RC = &AArch64::FIXED_REGSRegClass;
1784 int &ScalableByteOffset = RPI.Type == RegPairInfo::PPR && SplitPPRs
1789 if (HasCSHazardPadding &&
1792 ByteOffset += StackFillDir * StackHazardSize;
1796 int Scale =
TRI->getSpillSize(*RPI.RC);
1798 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1799 MCRegister NextReg = CSI[i + RegInc].getReg();
1800 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1801 int Aligned = AlignOffset(ByteOffset, Scale);
1802 int PairOffset = IsWindows ?
Aligned :
Aligned + StackFillDir * 2 * Scale;
1803 bool PairFitsImmRange =
1804 PairOffset / Scale >= -64 && PairOffset / Scale <= 63;
1806 case RegPairInfo::GPR:
1807 if (AArch64::GPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1809 RPI.Reg1, NextReg, IsWindows,
1810 NeedsWinCFI, NeedsFrameRecord,
TRI))
1813 case RegPairInfo::FPR64:
1814 if (AArch64::FPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1816 RPI.Reg1, NextReg, IsWindows,
1817 NeedsWinCFI, NeedsFrameRecord,
TRI))
1820 case RegPairInfo::FPR128:
1821 if (AArch64::FPR128RegClass.
contains(NextReg) && PairFitsImmRange)
1824 case RegPairInfo::PPR:
1826 case RegPairInfo::ZPR:
1828 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
1831 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
1836 case RegPairInfo::VG:
1847 assert((!RPI.isPaired() ||
1848 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1849 "Out of order callee saved regs!");
1851 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1852 RPI.Reg1 == AArch64::LR) &&
1853 "FrameRecord must be allocated together with LR");
1856 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1857 RPI.Reg2 == AArch64::LR) &&
1858 "FrameRecord must be allocated together with LR");
1866 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1867 RPI.Reg1 + 1 == RPI.Reg2))) &&
1868 "Callee-save registers not saved as adjacent register pair!");
1870 RPI.FrameIdx = CSI[i].getFrameIdx();
1873 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1877 if (RPI.isScalable() && ScalableByteOffset % Scale != 0)
1878 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1882 if (!RPI.isScalable() && ByteOffset % Scale != 0)
1883 ByteOffset = AlignOffset(ByteOffset, Scale);
1885 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1886 assert(OffsetPre % Scale == 0);
1888 if (RPI.isScalable())
1889 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1891 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1896 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1897 (IsWindows && RPI.Reg2 == AArch64::LR)))
1898 ByteOffset += StackFillDir * 8;
1902 if (NeedGapToAlignStack && !IsWindows && !RPI.isScalable() &&
1903 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1904 ByteOffset % 16 != 0) {
1905 ByteOffset += 8 * StackFillDir;
1911 NeedGapToAlignStack =
false;
1914 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1915 assert(OffsetPost % Scale == 0);
1918 int Offset = IsWindows ? OffsetPre : OffsetPost;
1923 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1924 (IsWindows && RPI.Reg2 == AArch64::LR)))
1926 RPI.Offset =
Offset / Scale;
1928 assert((!RPI.isPaired() ||
1929 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1930 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1931 "Offset out of bounds for LDP/STP immediate");
1933 auto isFrameRecord = [&] {
1935 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1936 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1944 return i > 0 && RPI.Reg1 == AArch64::FP &&
1945 CSI[i - 1].getReg() == AArch64::LR;
1950 if (NeedsFrameRecord && isFrameRecord())
1967 std::reverse(RegPairs.
begin(), RegPairs.
end());
1989 if (homogeneousPrologEpilog(MF)) {
1993 for (
auto &RPI : RegPairs) {
1999 MBB.addLiveIn(RPI.Reg1);
2000 if (RPI.isPaired() && !MRI.
isReserved(RPI.Reg2))
2001 MBB.addLiveIn(RPI.Reg2);
2005 bool PTrueCreated =
false;
2021 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2022 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2024 case RegPairInfo::GPR:
2025 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2027 case RegPairInfo::FPR64:
2028 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2030 case RegPairInfo::FPR128:
2031 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2033 case RegPairInfo::ZPR:
2034 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2036 case RegPairInfo::PPR:
2037 StrOpc = AArch64::STR_PXI;
2039 case RegPairInfo::VG:
2040 StrOpc = AArch64::STRXui;
2046 if (X0Scratch != AArch64::NoRegister)
2052 if (Reg1 == AArch64::VG) {
2054 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2055 assert(Reg1 != AArch64::NoRegister);
2065 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2066 AArch64::X0, LiveIn.PhysReg);
2074 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2076 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2090 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2092 dbgs() <<
", " << RPI.FrameIdx + 1;
2097 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2098 "Windows unwdinding requires a consecutive (FP,LR) pair");
2102 unsigned FrameIdxReg1 = RPI.FrameIdx;
2103 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2109 if (RPI.isPaired() && RPI.isScalable()) {
2115 "Expects SVE2.1 or SME2 target and a predicate register");
2116#ifdef EXPENSIVE_CHECKS
2117 auto IsPPR = [](
const RegPairInfo &c) {
2118 return c.Reg1 == RegPairInfo::PPR;
2120 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2121 auto IsZPR = [](
const RegPairInfo &c) {
2122 return c.Type == RegPairInfo::ZPR;
2124 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2125 assert(!(PPRBegin < ZPRBegin) &&
2126 "Expected callee save predicate to be handled first");
2128 if (!PTrueCreated) {
2129 PTrueCreated =
true;
2135 MBB.addLiveIn(Reg1);
2137 MBB.addLiveIn(Reg2);
2138 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2155 MBB.addLiveIn(Reg1);
2156 if (RPI.isPaired()) {
2158 MBB.addLiveIn(Reg2);
2177 if (RPI.Type == RegPairInfo::ZPR) {
2181 }
else if (RPI.Type == RegPairInfo::PPR) {
2201 DL =
MBBI->getDebugLoc();
2204 if (homogeneousPrologEpilog(MF, &
MBB)) {
2207 for (
auto &RPI : RegPairs) {
2215 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2217 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2218 std::reverse(PPRBegin, PPREnd);
2219 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2221 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2222 std::reverse(ZPRBegin, ZPREnd);
2224 bool PTrueCreated =
false;
2225 for (
const RegPairInfo &RPI : RegPairs) {
2238 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2239 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2241 case RegPairInfo::GPR:
2242 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2244 case RegPairInfo::FPR64:
2245 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2247 case RegPairInfo::FPR128:
2248 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2250 case RegPairInfo::ZPR:
2251 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2253 case RegPairInfo::PPR:
2254 LdrOpc = AArch64::LDR_PXI;
2256 case RegPairInfo::VG:
2263 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2265 dbgs() <<
", " << RPI.FrameIdx + 1;
2272 unsigned FrameIdxReg1 = RPI.FrameIdx;
2273 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2280 if (RPI.isPaired() && RPI.isScalable()) {
2285 "Expects SVE2.1 or SME2 target and a predicate register");
2286#ifdef EXPENSIVE_CHECKS
2287 assert(!(PPRBegin < ZPRBegin) &&
2288 "Expected callee save predicate to be handled first");
2290 if (!PTrueCreated) {
2291 PTrueCreated =
true;
2296 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
2313 if (RPI.isPaired()) {
2340 return std::optional<int>(PSV->getFrameIndex());
2351 return std::nullopt;
2357 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2358 return std::nullopt;
2365 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2371void AArch64FrameLowering::determineStackHazardSlot(
2374 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2375 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2389 return AArch64::FPR64RegClass.contains(Reg) ||
2390 AArch64::FPR128RegClass.contains(Reg) ||
2391 AArch64::ZPRRegClass.contains(Reg);
2394 return AArch64::PPRRegClass.contains(Reg);
2396 bool HasFPRStackObjects =
false;
2397 bool HasPPRStackObjects =
false;
2399 enum SlotType : uint8_t {
2410 for (
auto &
MBB : MF) {
2411 for (
auto &
MI :
MBB) {
2413 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2420 ? SlotType::ZPRorFPR
2426 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2427 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2430 if (SlotTypes[FI] == SlotType::PPR) {
2432 HasPPRStackObjects =
true;
2437 if (HasFPRCSRs || HasFPRStackObjects) {
2440 << StackHazardSize <<
"\n");
2451 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2457 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2458 "non-SVE CC function...\n");
2465 <<
"Calling convention is not supported with SplitSVEObjects\n");
2469 if (!HasPPRCSRs && !HasPPRStackObjects) {
2471 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2475 if (!HasFPRCSRs && !HasFPRStackObjects) {
2478 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2482 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2483 MF.getSubtarget<AArch64Subtarget>();
2485 "Expected SVE to be available for PPRs");
2487 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2491 BitVector FPRZRegs(SavedRegs.
size());
2492 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2493 BitVector::reference RegBit = SavedRegs[
Reg];
2496 unsigned SubRegIdx = 0;
2498 SubRegIdx = AArch64::dsub;
2500 SubRegIdx = AArch64::zsub;
2507 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2510 SavedRegs |= FPRZRegs;
2530 unsigned UnspilledCSGPR = AArch64::NoRegister;
2531 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
2537 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2539 unsigned ExtraCSSpill = 0;
2540 bool HasUnpairedGPR64 =
false;
2541 bool HasPairZReg =
false;
2542 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2543 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2546 for (
unsigned i = 0; CSRegs[i]; ++i) {
2550 if (Reg == BasePointerReg)
2555 if (UserReservedRegs[Reg]) {
2556 SavedRegs.
reset(Reg);
2560 bool RegUsed = SavedRegs.
test(Reg);
2562 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2563 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2564 AArch64::FPR128RegClass.
contains(Reg)) {
2567 if (HasUnpairedGPR64)
2568 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2570 PairedReg = CSRegs[i ^ 1];
2577 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2578 PairedReg = AArch64::NoRegister;
2579 HasUnpairedGPR64 =
true;
2581 assert(PairedReg == AArch64::NoRegister ||
2582 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
2583 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
2584 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
2587 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2588 UnspilledCSGPR = Reg;
2589 UnspilledCSGPRPaired = PairedReg;
2597 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
2598 !SavedRegs.
test(PairedReg)) {
2599 SavedRegs.
set(PairedReg);
2600 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2601 !ReservedRegs[PairedReg])
2602 ExtraCSSpill = PairedReg;
2605 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2606 SavedRegs.
test(CSRegs[i ^ 1]));
2614 if (PnReg.isValid())
2620 SavedRegs.
set(AArch64::P8);
2625 "Predicate cannot be a reserved register");
2635 SavedRegs.
set(AArch64::X18);
2641 determineStackHazardSlot(MF, SavedRegs);
2644 unsigned CSStackSize = 0;
2645 unsigned ZPRCSStackSize = 0;
2646 unsigned PPRCSStackSize = 0;
2648 for (
unsigned Reg : SavedRegs.
set_bits()) {
2650 assert(RC &&
"expected register class!");
2651 auto SpillSize =
TRI->getSpillSize(*RC);
2652 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2653 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2655 ZPRCSStackSize += SpillSize;
2657 PPRCSStackSize += SpillSize;
2663 return SavedRegs.test(SuperReg);
2666 CSStackSize += SpillSize;
2673 unsigned NumSavedRegs = SavedRegs.
count();
2686 SavedRegs.
set(AArch64::LR);
2691 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2692 SavedRegs.
set(AArch64::FP);
2693 SavedRegs.
set(AArch64::LR);
2697 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2698 for (
unsigned Reg : SavedRegs.
set_bits())
2704 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2706 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2708 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2709 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2718 int64_t CalleeStackUsed = 0;
2721 if (FixedOff > CalleeStackUsed)
2722 CalleeStackUsed = FixedOff;
2726 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2727 CalleeStackUsed) > EstimatedStackSizeLimit;
2728 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2738 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
2740 <<
" to get a scratch register.\n");
2741 SavedRegs.
set(UnspilledCSGPR);
2742 ExtraCSSpill = UnspilledCSGPR;
2747 if (producePairRegisters(MF)) {
2748 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
2751 SavedRegs.
reset(UnspilledCSGPR);
2752 ExtraCSSpill = AArch64::NoRegister;
2755 SavedRegs.
set(UnspilledCSGPRPaired);
2764 unsigned Size =
TRI->getSpillSize(RC);
2765 Align Alignment =
TRI->getSpillAlign(RC);
2767 RS->addScavengingFrameIndex(FI);
2768 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2769 <<
" as the emergency spill slot.\n");
2774 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2783 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2787 "Should not invalidate callee saved info");
2798 std::vector<CalleeSavedInfo> &CSI)
const {
2807 std::reverse(CSI.begin(), CSI.end());
2827 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2828 if (It != CSI.end())
2829 CSI.insert(It, VGInfo);
2831 CSI.push_back(VGInfo);
2835 int HazardSlotIndex = std::numeric_limits<int>::max();
2836 for (
auto &CS : CSI) {
2844 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2845 "Unexpected register order for hazard slot");
2847 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2853 unsigned Size = RegInfo->getSpillSize(*RC);
2854 Align Alignment(RegInfo->getSpillAlign(*RC));
2856 CS.setFrameIdx(FrameIdx);
2861 Reg == AArch64::FP) {
2871 HazardSlotIndex == std::numeric_limits<int>::max()) {
2873 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2900 int &Min,
int &Max) {
2901 Min = std::numeric_limits<int>::max();
2902 Max = std::numeric_limits<int>::min();
2908 for (
auto &CS : CSI) {
2909 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
2910 AArch64::PPRRegClass.contains(CS.getReg())) {
2911 assert((Max == std::numeric_limits<int>::min() ||
2912 Max + 1 == CS.getFrameIdx()) &&
2913 "SVE CalleeSaves are not consecutive");
2914 Min = std::min(Min, CS.getFrameIdx());
2915 Max = std::max(Max, CS.getFrameIdx());
2918 return Min != std::numeric_limits<int>::max();
2931 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
2939 "SVE vectors should never be passed on the stack by value, only by "
2943 auto AllocateObject = [&](
int FI) {
2952 if (Alignment >
Align(16))
2954 "Alignment of scalable vectors > 16 bytes is not yet supported");
2957 StackTop =
alignTo(StackTop, Alignment);
2959 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
2960 "SVE StackTop far too large?!");
2962 int64_t
Offset = -int64_t(StackTop);
2970 int MinCSFrameIndex, MaxCSFrameIndex;
2972 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
2985 int StackProtectorFI = -1;
2989 ObjectsToAllocate.
push_back(StackProtectorFI);
3005 for (
unsigned FI : ObjectsToAllocate)
3020 "Upwards growing stack unsupported");
3035 int64_t CurrentOffset =
3039 int FrameIndex =
H.CatchObj.FrameIndex;
3040 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3051 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3052 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3054 "UnwindHelpOffset must be at the start of the fixed object area");
3057 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3067 RS->enterBasicBlockEnd(
MBB);
3069 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3070 assert(DstReg &&
"There must be a free register after frame setup");
3081struct TagStoreInstr {
3089 MachineFunction *MF;
3090 MachineBasicBlock *
MBB;
3091 MachineRegisterInfo *MRI;
3100 StackOffset FrameRegOffset;
3104 std::optional<int64_t> FrameRegUpdate;
3106 unsigned FrameRegUpdateFlags;
3116 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3117 :
MBB(
MBB), ZeroData(ZeroData) {
3123 void addInstruction(TagStoreInstr
I) {
3125 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3126 "Non-adjacent tag store instructions.");
3129 void clear() { TagStores.
clear(); }
3134 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3141 const int64_t kMinOffset = -256 * 16;
3142 const int64_t kMaxOffset = 255 * 16;
3145 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3146 if (BaseRegOffsetBytes < kMinOffset ||
3147 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3151 BaseRegOffsetBytes % 16 != 0) {
3156 BaseRegOffsetBytes = 0;
3161 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3164 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3166 assert(BaseRegOffsetBytes % 16 == 0);
3170 .
addImm(BaseRegOffsetBytes / 16)
3174 if (BaseRegOffsetBytes == 0)
3176 BaseRegOffsetBytes += InstrSize;
3195 int64_t LoopSize =
Size;
3198 if (FrameRegUpdate && *FrameRegUpdate)
3199 LoopSize -= LoopSize % 32;
3201 TII->get(ZeroData ? AArch64::STZGloop_wback
3202 : AArch64::STGloop_wback))
3209 LoopI->
setFlags(FrameRegUpdateFlags);
3211 int64_t ExtraBaseRegUpdate =
3212 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3213 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3214 <<
", Size=" <<
Size
3215 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3216 <<
", FrameRegUpdate=" << FrameRegUpdate
3217 <<
", FrameRegOffset.getFixed()="
3218 << FrameRegOffset.
getFixed() <<
"\n");
3219 if (LoopSize <
Size) {
3223 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3224 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3225 "STG immediate out of range");
3227 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3234 }
else if (ExtraBaseRegUpdate) {
3236 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3237 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3240 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3253 int64_t
Size, int64_t *TotalOffset) {
3255 if ((
MI.getOpcode() == AArch64::ADDXri ||
3256 MI.getOpcode() == AArch64::SUBXri) &&
3257 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3259 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3260 if (
MI.getOpcode() == AArch64::SUBXri)
3271 const int64_t kMaxOffset = 4080 - 16;
3273 const int64_t kMinOffset = -4095;
3274 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3275 PostOffset % 16 == 0) {
3286 for (
auto &TS : TSE) {
3290 if (
MI->memoperands_empty()) {
3294 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3300 bool TryMergeSPUpdate) {
3301 if (TagStores.
empty())
3303 TagStoreInstr &FirstTagStore = TagStores[0];
3304 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3305 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3306 DL = TagStores[0].MI->getDebugLoc();
3310 *MF, FirstTagStore.Offset,
false ,
3314 FrameRegUpdate = std::nullopt;
3316 mergeMemRefs(TagStores, CombinedMemRefs);
3319 dbgs() <<
"Replacing adjacent STG instructions:\n";
3320 for (
const auto &Instr : TagStores) {
3329 if (TagStores.
size() < 2)
3331 emitUnrolled(InsertI);
3334 int64_t TotalOffset = 0;
3335 if (TryMergeSPUpdate) {
3341 if (InsertI !=
MBB->
end() &&
3342 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3344 UpdateInstr = &*InsertI++;
3350 if (!UpdateInstr && TagStores.
size() < 2)
3354 FrameRegUpdate = TotalOffset;
3355 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3362 for (
auto &TS : TagStores)
3363 TS.MI->eraseFromParent();
3367 int64_t &
Size,
bool &ZeroData) {
3371 unsigned Opcode =
MI.getOpcode();
3372 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3373 Opcode == AArch64::STZ2Gi);
3375 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3376 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3378 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3381 Size =
MI.getOperand(2).getImm();
3385 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3387 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3392 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3396 16 *
MI.getOperand(2).getImm();
3400static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3405 return LiveRegs.available(MRI,
Reg);
3408 size_t NumEmergencySlots = 0;
3410 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3412 return FreeGPRs + NumEmergencySlots;
3431 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3437 constexpr int kScanLimit = 10;
3440 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3449 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3450 if (ZeroData != FirstZeroData)
3458 if (!
MI.isTransient())
3467 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3483 LiveRegs.addLiveOuts(*
MBB);
3488 LiveRegs.stepBackward(*
I);
3491 if (LiveRegs.contains(AArch64::NZCV))
3502 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3503 <<
"due to high register pressure.\n");
3508 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3513 int64_t CurOffset = Instrs[0].Offset;
3514 for (
auto &Instr : Instrs) {
3515 if (CurOffset >
Instr.Offset)
3522 TagStoreEdit TSE(
MBB, FirstZeroData);
3523 std::optional<int64_t> EndOffset;
3524 for (
auto &Instr : Instrs) {
3525 if (EndOffset && *EndOffset !=
Instr.Offset) {
3527 TSE.emitCode(InsertI, TFI,
false);
3531 TSE.addInstruction(Instr);
3550 II = tryMergeAdjacentSTG(
II,
this, RS);
3557 shouldSignReturnAddressEverywhere(MF))
3566 bool IgnoreSPUpdates)
const {
3568 if (IgnoreSPUpdates) {
3571 FrameReg = AArch64::SP;
3581 FrameReg = AArch64::SP;
3606 bool IsValid =
false;
3608 int ObjectIndex = 0;
3610 int GroupIndex = -1;
3612 bool ObjectFirst =
false;
3615 bool GroupFirst =
false;
3620 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3624 SmallVector<int, 8> CurrentMembers;
3625 int NextGroupIndex = 0;
3626 std::vector<FrameObject> &Objects;
3629 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3630 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3631 void EndCurrentGroup() {
3632 if (CurrentMembers.
size() > 1) {
3637 for (
int Index : CurrentMembers) {
3638 Objects[
Index].GroupIndex = NextGroupIndex;
3644 CurrentMembers.clear();
3648bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3670 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3671 A.GroupIndex,
A.ObjectIndex) <
3672 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3673 B.GroupIndex,
B.ObjectIndex);
3682 ObjectsToAllocate.
empty())
3687 for (
auto &Obj : ObjectsToAllocate) {
3688 FrameObjects[Obj].IsValid =
true;
3689 FrameObjects[Obj].ObjectIndex = Obj;
3694 GroupBuilder GB(FrameObjects);
3695 for (
auto &
MBB : MF) {
3696 for (
auto &
MI :
MBB) {
3697 if (
MI.isDebugInstr())
3702 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3705 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3707 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3712 switch (
MI.getOpcode()) {
3713 case AArch64::STGloop:
3714 case AArch64::STZGloop:
3718 case AArch64::STZGi:
3719 case AArch64::ST2Gi:
3720 case AArch64::STZ2Gi:
3733 FrameObjects[FI].IsValid)
3741 GB.AddMember(TaggedFI);
3743 GB.EndCurrentGroup();
3746 GB.EndCurrentGroup();
3751 FrameObject::AccessHazard;
3753 for (
auto &Obj : FrameObjects)
3754 if (!Obj.Accesses ||
3755 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3756 Obj.Accesses = FrameObject::AccessGPR;
3765 FrameObjects[*TBPI].ObjectFirst =
true;
3766 FrameObjects[*TBPI].GroupFirst =
true;
3767 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3768 if (FirstGroupIndex >= 0)
3769 for (FrameObject &Object : FrameObjects)
3770 if (Object.GroupIndex == FirstGroupIndex)
3771 Object.GroupFirst =
true;
3777 for (
auto &Obj : FrameObjects) {
3781 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3785 dbgs() <<
"Final frame order:\n";
3786 for (
auto &Obj : FrameObjects) {
3789 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3790 if (Obj.ObjectFirst)
3791 dbgs() <<
", first";
3793 dbgs() <<
", group-first";
3804AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3815 MF.
insert(MBBInsertPoint, LoopMBB);
3817 MF.
insert(MBBInsertPoint, ExitMBB);
3852 MBB.addSuccessor(LoopMBB);
3856 return ExitMBB->
begin();
3859void AArch64FrameLowering::inlineStackProbeFixed(
3864 const AArch64InstrInfo *
TII =
3866 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
3871 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
3872 int64_t NumBlocks = FrameSize / ProbeSize;
3873 int64_t ResidualSize = FrameSize % ProbeSize;
3875 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
3876 << NumBlocks <<
" blocks of " << ProbeSize
3877 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
3882 for (
int i = 0; i < NumBlocks; ++i) {
3888 EmitAsyncCFI && !HasFP, CFAOffset);
3901 }
else if (NumBlocks != 0) {
3907 EmitAsyncCFI && !HasFP, CFAOffset);
3909 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
3911 if (EmitAsyncCFI && !HasFP) {
3914 .buildDefCFARegister(AArch64::SP);
3918 if (ResidualSize != 0) {
3924 EmitAsyncCFI && !HasFP, CFAOffset);
3945 SmallVector<MachineInstr *, 4> ToReplace;
3946 for (MachineInstr &
MI :
MBB)
3947 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
3948 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
3951 for (MachineInstr *
MI : ToReplace) {
3952 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
3953 Register ScratchReg =
MI->getOperand(0).getReg();
3954 int64_t FrameSize =
MI->getOperand(1).getImm();
3956 MI->getOperand(3).getImm());
3957 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
3960 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
3961 "Stack probe pseudo-instruction expected");
3962 const AArch64InstrInfo *
TII =
3963 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
3964 Register TargetReg =
MI->getOperand(0).getReg();
3965 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
3967 MI->eraseFromParent();
3987 return std::make_tuple(
start(),
Idx) <
3988 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4018 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4019 if (
Offset.getScalable())
4020 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4031void AArch64FrameLowering::emitRemarks(
4034 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4039 const uint64_t HazardSize =
4042 if (HazardSize == 0)
4050 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4052 size_t NumFPLdSt = 0;
4053 size_t NumNonFPLdSt = 0;
4056 for (
const MachineBasicBlock &
MBB : MF) {
4057 for (
const MachineInstr &
MI :
MBB) {
4058 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4060 for (MachineMemOperand *MMO :
MI.memoperands()) {
4067 StackAccesses[ArrIdx].Idx = FrameIdx;
4068 StackAccesses[ArrIdx].Offset =
4079 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4090 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4101 if (StackAccesses.front().isMixed())
4102 MixedObjects.push_back(&StackAccesses.front());
4104 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4106 const auto &
First = *It;
4107 const auto &Second = *(It + 1);
4109 if (Second.isMixed())
4110 MixedObjects.push_back(&Second);
4112 if ((
First.isSME() && Second.isCPU()) ||
4113 (
First.isCPU() && Second.isSME())) {
4114 uint64_t Distance =
static_cast<uint64_t
>(Second.start() -
First.end());
4115 if (Distance < HazardSize)
4120 auto EmitRemark = [&](llvm::StringRef Str) {
4122 auto R = MachineOptimizationRemarkAnalysis(
4123 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4124 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4128 for (
const auto &
P : HazardPairs)
4129 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4131 for (
const auto *Obj : MixedObjects)
4133 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.
@ 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