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,
858 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
861 BitVector GPRsToZero(
TRI.getNumRegs());
862 BitVector FPRsToZero(
TRI.getNumRegs());
866 bool HasFPR = STI.hasFPARMv8();
868 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
871 GPRsToZero.set(XReg);
875 FPRsToZero.set(XReg);
882 for (MCRegister
Reg : GPRsToZero.set_bits())
886 for (MCRegister
Reg : FPRsToZero.set_bits())
890 for (MCRegister PReg :
891 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
892 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
893 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
895 if (RegsToZero[PReg])
901bool AArch64FrameLowering::windowsRequiresStackProbe(
903 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
904 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
908 StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
917 for (
unsigned i = 0; CSRegs[i]; ++i)
923 bool HasCall)
const {
933 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
935 LivePhysRegs LiveRegs(
TRI);
938 LiveRegs.addReg(AArch64::X16);
939 LiveRegs.addReg(AArch64::X17);
940 LiveRegs.addReg(AArch64::X18);
944 const MachineRegisterInfo &MRI = MF->
getRegInfo();
945 if (LiveRegs.available(MRI, AArch64::X9))
948 for (
unsigned Reg : AArch64::GPR64RegClass) {
949 if (LiveRegs.available(MRI,
Reg))
952 return AArch64::NoRegister;
971 if (!
LiveRegs.available(MRI, AArch64::X16) ||
972 !
LiveRegs.available(MRI, AArch64::X17))
979 MBB.isLiveIn(AArch64::NZCV))
983 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
989 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
990 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
999 F.needsUnwindTableEntry();
1002bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
1018 unsigned Opc =
MBBI->getOpcode();
1022 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1023 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1031 case AArch64::STR_ZXI:
1032 case AArch64::LDR_ZXI: {
1033 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1040 case AArch64::STR_PXI:
1041 case AArch64::LDR_PXI: {
1042 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1049 case AArch64::LDPDpost:
1052 case AArch64::STPDpre: {
1053 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1054 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1055 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1062 case AArch64::LDPXpost:
1065 case AArch64::STPXpre: {
1068 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1069 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1073 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1074 .
addImm(RegInfo->getSEHRegNum(Reg0))
1075 .
addImm(RegInfo->getSEHRegNum(Reg1))
1080 case AArch64::LDRDpost:
1083 case AArch64::STRDpre: {
1084 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1085 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1091 case AArch64::LDRXpost:
1094 case AArch64::STRXpre: {
1095 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1102 case AArch64::STPDi:
1103 case AArch64::LDPDi: {
1104 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1105 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1113 case AArch64::STPXi:
1114 case AArch64::LDPXi: {
1118 int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1119 int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1121 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1125 else if (SEHReg0 >= 19 && SEHReg1 >= 19)
1132 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegIP))
1139 case AArch64::STRXui:
1140 case AArch64::LDRXui: {
1141 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1148 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegI))
1154 case AArch64::STRDui:
1155 case AArch64::LDRDui: {
1156 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1163 case AArch64::STPQi:
1164 case AArch64::LDPQi: {
1165 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1166 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1167 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1174 case AArch64::LDPQpost:
1177 case AArch64::STPQpre: {
1178 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1179 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1180 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1199 if (ST.isTargetDarwin())
1221 DL =
MBBI->getDebugLoc();
1223 TII->createPauthEpilogueInstr(
MBB,
DL);
1227 EmitSignRA(MF.
front());
1229 if (
MBB.isEHFuncletEntry())
1231 if (
MBB.isReturnBlock())
1287 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1292 if (MFI.isVariableSizedObjectIndex(FI)) {
1302 if (MFI.hasScalableStackID(FI)) {
1303 if (FPAfterSVECalleeSaves &&
1306 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1314 AccessOffset = -PPRStackSize;
1315 return AccessOffset +
1320 bool IsFixed = MFI.isFixedObjectIndex(FI);
1325 if (!IsFixed && !IsCSR) {
1326 ScalableOffset = -SVEStackSize;
1327 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1342 int64_t ObjectOffset)
const {
1346 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1347 unsigned FixedObject =
1348 getFixedObjectSize(MF, AFI, IsWin64,
false);
1356 int64_t ObjectOffset)
const {
1367 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1368 ? getFPOffset(MF, ObjectOffset).getFixed()
1369 : getStackOffset(MF, ObjectOffset).getFixed();
1374 bool ForSimm)
const {
1376 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1377 bool isFixed = MFI.isFixedObjectIndex(FI);
1380 FrameReg, PreferFP, ForSimm);
1386 bool ForSimm)
const {
1392 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1393 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1396 bool isSVE = MFI.isScalableStackID(StackID);
1400 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1411 PreferFP &= !SVEStackSize;
1419 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1423 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1425 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1430 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1431 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1433 if (FPOffset >= 0) {
1437 }
else if (MFI.hasVarSizedObjects()) {
1441 bool CanUseBP = RegInfo->hasBasePointer(MF);
1442 if (FPOffsetFits && CanUseBP)
1449 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1456 "Funclets should only be present on Win64");
1460 if (FPOffsetFits && PreferFP)
1467 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1468 "In the presence of dynamic stack pointer realignment, "
1469 "non-argument/CSR objects cannot be accessed through the frame pointer");
1486 FPOffset -= PPRStackSize;
1488 SPOffset -= PPRStackSize;
1493 if (FPAfterSVECalleeSaves) {
1504 RegInfo->hasStackRealignment(MF))) {
1505 FrameReg = RegInfo->getFrameRegister(MF);
1508 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1515 if (FPAfterSVECalleeSaves) {
1522 SVEAreaOffset = SVECalleeSavedStack;
1524 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1527 SVEAreaOffset = SVEStackSize;
1529 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1532 if (UseFP && !(isFixed || isCSR))
1533 SVEAreaOffset = -SVEStackSize;
1534 if (!UseFP && (isFixed || isCSR))
1535 SVEAreaOffset = SVEStackSize;
1539 FrameReg = RegInfo->getFrameRegister(MF);
1544 if (RegInfo->hasBasePointer(MF))
1545 FrameReg = RegInfo->getBaseRegister();
1547 assert(!MFI.hasVarSizedObjects() &&
1548 "Can't use SP when we have var sized objects.");
1549 FrameReg = AArch64::SP;
1577 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1583 unsigned SpillCount,
unsigned Reg1,
1584 unsigned Reg2,
bool NeedsWinCFI,
1593 if (Reg2 == AArch64::FP)
1603 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1604 return SpillExtendedVolatile
1605 ? !((Reg1 == AArch64::FP && Reg2 == AArch64::LR) ||
1606 (SpillCount % 2) == 0)
1611 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1612 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR)
1622 unsigned SpillCount,
unsigned Reg1,
1623 unsigned Reg2,
bool UsesWinAAPCS,
1624 bool NeedsWinCFI,
bool NeedsFrameRecord,
1628 Reg1, Reg2, NeedsWinCFI,
TRI);
1632 if (NeedsFrameRecord)
1633 return Reg2 == AArch64::LR;
1645 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1648 RegPairInfo() =
default;
1650 bool isPaired()
const {
return Reg2.
isValid(); }
1652 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1658 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1659 if (SavedRegs.
test(PReg)) {
1660 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1674 bool IsLocallyStreaming =
1680 return Subtarget.hasSVE2p1() ||
1681 (Subtarget.hasSME2() &&
1682 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1690 bool NeedsFrameRecord) {
1707 (
Count & 1) == 0) &&
1708 "Odd number of callee-saved regs to spill!");
1710 int StackFillDir = -1;
1712 unsigned FirstReg = 0;
1720 FirstReg =
Count - 1;
1732 bool SpillExtendedVolatile =
1734 const auto &
Reg = CSI.getReg();
1735 return Reg >= AArch64::X0 &&
Reg <= AArch64::X18;
1738 int ZPRByteOffset = 0;
1739 int PPRByteOffset = 0;
1744 }
else if (!FPAfterSVECalleeSaves) {
1755 auto AlignOffset = [StackFillDir](
int Offset,
int Align) {
1756 if (StackFillDir < 0)
1762 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1764 RPI.Reg1 = CSI[i].getReg();
1766 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1767 RPI.Type = RegPairInfo::GPR;
1768 RPI.RC = &AArch64::GPR64RegClass;
1769 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1770 RPI.Type = RegPairInfo::FPR64;
1771 RPI.RC = &AArch64::FPR64RegClass;
1772 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1773 RPI.Type = RegPairInfo::FPR128;
1774 RPI.RC = &AArch64::FPR128RegClass;
1775 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1776 RPI.Type = RegPairInfo::ZPR;
1777 RPI.RC = &AArch64::ZPRRegClass;
1778 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1779 RPI.Type = RegPairInfo::PPR;
1780 RPI.RC = &AArch64::PPRRegClass;
1781 }
else if (RPI.Reg1 == AArch64::VG) {
1782 RPI.Type = RegPairInfo::VG;
1783 RPI.RC = &AArch64::FIXED_REGSRegClass;
1788 int &ScalableByteOffset = RPI.Type == RegPairInfo::PPR && SplitPPRs
1793 if (HasCSHazardPadding &&
1796 ByteOffset += StackFillDir * StackHazardSize;
1800 int Scale =
TRI->getSpillSize(*RPI.RC);
1802 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1803 MCRegister NextReg = CSI[i + RegInc].getReg();
1804 unsigned SpillCount = NeedsWinCFI ? FirstReg - i : i;
1805 int Aligned = AlignOffset(ByteOffset, Scale);
1806 int PairOffset = IsWindows ?
Aligned :
Aligned + StackFillDir * 2 * Scale;
1807 bool PairFitsImmRange =
1808 PairOffset / Scale >= -64 && PairOffset / Scale <= 63;
1810 case RegPairInfo::GPR:
1811 if (AArch64::GPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1813 RPI.Reg1, NextReg, IsWindows,
1814 NeedsWinCFI, NeedsFrameRecord,
TRI))
1817 case RegPairInfo::FPR64:
1818 if (AArch64::FPR64RegClass.
contains(NextReg) && PairFitsImmRange &&
1820 RPI.Reg1, NextReg, IsWindows,
1821 NeedsWinCFI, NeedsFrameRecord,
TRI))
1824 case RegPairInfo::FPR128:
1825 if (AArch64::FPR128RegClass.
contains(NextReg) && PairFitsImmRange)
1828 case RegPairInfo::PPR:
1830 case RegPairInfo::ZPR:
1832 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
1835 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
1840 case RegPairInfo::VG:
1851 assert((!RPI.isPaired() ||
1852 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1853 "Out of order callee saved regs!");
1855 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1856 RPI.Reg1 == AArch64::LR) &&
1857 "FrameRecord must be allocated together with LR");
1860 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1861 RPI.Reg2 == AArch64::LR) &&
1862 "FrameRecord must be allocated together with LR");
1870 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1871 RPI.Reg1 + 1 == RPI.Reg2))) &&
1872 "Callee-save registers not saved as adjacent register pair!");
1874 RPI.FrameIdx = CSI[i].getFrameIdx();
1877 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1881 if (RPI.isScalable() && ScalableByteOffset % Scale != 0)
1882 ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
1886 if (!RPI.isScalable() && ByteOffset % Scale != 0)
1887 ByteOffset = AlignOffset(ByteOffset, Scale);
1889 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1890 assert(OffsetPre % Scale == 0);
1892 if (RPI.isScalable())
1893 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1895 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1900 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1901 (IsWindows && RPI.Reg2 == AArch64::LR)))
1902 ByteOffset += StackFillDir * 8;
1906 if (NeedGapToAlignStack && !IsWindows && !RPI.isScalable() &&
1907 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1908 ByteOffset % 16 != 0) {
1909 ByteOffset += 8 * StackFillDir;
1915 NeedGapToAlignStack =
false;
1918 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1919 assert(OffsetPost % Scale == 0);
1922 int Offset = IsWindows ? OffsetPre : OffsetPost;
1927 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1928 (IsWindows && RPI.Reg2 == AArch64::LR)))
1930 RPI.Offset =
Offset / Scale;
1932 assert((!RPI.isPaired() ||
1933 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1934 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1935 "Offset out of bounds for LDP/STP immediate");
1937 auto isFrameRecord = [&] {
1939 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1940 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1948 return i > 0 && RPI.Reg1 == AArch64::FP &&
1949 CSI[i - 1].getReg() == AArch64::LR;
1954 if (NeedsFrameRecord && isFrameRecord())
1971 std::reverse(RegPairs.
begin(), RegPairs.
end());
1993 if (homogeneousPrologEpilog(MF)) {
1997 for (
auto &RPI : RegPairs) {
2003 MBB.addLiveIn(RPI.Reg1);
2004 if (RPI.isPaired() && !MRI.
isReserved(RPI.Reg2))
2005 MBB.addLiveIn(RPI.Reg2);
2009 bool PTrueCreated =
false;
2025 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2026 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2028 case RegPairInfo::GPR:
2029 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
2031 case RegPairInfo::FPR64:
2032 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
2034 case RegPairInfo::FPR128:
2035 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
2037 case RegPairInfo::ZPR:
2038 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
2040 case RegPairInfo::PPR:
2041 StrOpc = AArch64::STR_PXI;
2043 case RegPairInfo::VG:
2044 StrOpc = AArch64::STRXui;
2050 if (X0Scratch != AArch64::NoRegister)
2056 if (Reg1 == AArch64::VG) {
2058 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
2059 assert(Reg1 != AArch64::NoRegister);
2069 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
2070 AArch64::X0, LiveIn.PhysReg);
2078 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2080 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2094 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2096 dbgs() <<
", " << RPI.FrameIdx + 1;
2101 !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2102 "Windows unwdinding requires a consecutive (FP,LR) pair");
2106 unsigned FrameIdxReg1 = RPI.FrameIdx;
2107 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2113 if (RPI.isPaired() && RPI.isScalable()) {
2119 "Expects SVE2.1 or SME2 target and a predicate register");
2120#ifdef EXPENSIVE_CHECKS
2121 auto IsPPR = [](
const RegPairInfo &c) {
2122 return c.Reg1 == RegPairInfo::PPR;
2124 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2125 auto IsZPR = [](
const RegPairInfo &c) {
2126 return c.Type == RegPairInfo::ZPR;
2128 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2129 assert(!(PPRBegin < ZPRBegin) &&
2130 "Expected callee save predicate to be handled first");
2132 if (!PTrueCreated) {
2133 PTrueCreated =
true;
2139 MBB.addLiveIn(Reg1);
2141 MBB.addLiveIn(Reg2);
2142 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2159 MBB.addLiveIn(Reg1);
2160 if (RPI.isPaired()) {
2162 MBB.addLiveIn(Reg2);
2181 if (RPI.Type == RegPairInfo::ZPR) {
2185 }
else if (RPI.Type == RegPairInfo::PPR) {
2205 DL =
MBBI->getDebugLoc();
2208 if (homogeneousPrologEpilog(MF, &
MBB)) {
2211 for (
auto &RPI : RegPairs) {
2219 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2221 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2222 std::reverse(PPRBegin, PPREnd);
2223 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2225 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2226 std::reverse(ZPRBegin, ZPREnd);
2228 bool PTrueCreated =
false;
2229 for (
const RegPairInfo &RPI : RegPairs) {
2242 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2243 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2245 case RegPairInfo::GPR:
2246 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2248 case RegPairInfo::FPR64:
2249 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2251 case RegPairInfo::FPR128:
2252 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2254 case RegPairInfo::ZPR:
2255 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2257 case RegPairInfo::PPR:
2258 LdrOpc = AArch64::LDR_PXI;
2260 case RegPairInfo::VG:
2267 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2269 dbgs() <<
", " << RPI.FrameIdx + 1;
2276 unsigned FrameIdxReg1 = RPI.FrameIdx;
2277 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2284 if (RPI.isPaired() && RPI.isScalable()) {
2289 "Expects SVE2.1 or SME2 target and a predicate register");
2290#ifdef EXPENSIVE_CHECKS
2291 assert(!(PPRBegin < ZPRBegin) &&
2292 "Expected callee save predicate to be handled first");
2294 if (!PTrueCreated) {
2295 PTrueCreated =
true;
2300 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
2317 if (RPI.isPaired()) {
2344 return std::optional<int>(PSV->getFrameIndex());
2355 return std::nullopt;
2361 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2362 return std::nullopt;
2369 return AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2375void AArch64FrameLowering::determineStackHazardSlot(
2378 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2379 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2393 return AArch64::FPR64RegClass.contains(Reg) ||
2394 AArch64::FPR128RegClass.contains(Reg) ||
2395 AArch64::ZPRRegClass.contains(Reg);
2398 return AArch64::PPRRegClass.contains(Reg);
2400 bool HasFPRStackObjects =
false;
2401 bool HasPPRStackObjects =
false;
2403 enum SlotType : uint8_t {
2414 for (
auto &
MBB : MF) {
2415 for (
auto &
MI :
MBB) {
2417 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2424 ? SlotType::ZPRorFPR
2430 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2431 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2434 if (SlotTypes[FI] == SlotType::PPR) {
2436 HasPPRStackObjects =
true;
2441 if (HasFPRCSRs || HasFPRStackObjects) {
2444 << StackHazardSize <<
"\n");
2455 LLVM_DEBUG(
dbgs() <<
"Using SplitSVEObjects for SVE CC function\n");
2461 LLVM_DEBUG(
dbgs() <<
"Determining if SplitSVEObjects should be used in "
2462 "non-SVE CC function...\n");
2469 <<
"Calling convention is not supported with SplitSVEObjects\n");
2473 if (!HasPPRCSRs && !HasPPRStackObjects) {
2475 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2479 if (!HasFPRCSRs && !HasFPRStackObjects) {
2482 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2486 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2487 MF.getSubtarget<AArch64Subtarget>();
2489 "Expected SVE to be available for PPRs");
2491 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2495 BitVector FPRZRegs(SavedRegs.
size());
2496 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2497 BitVector::reference RegBit = SavedRegs[
Reg];
2500 unsigned SubRegIdx = 0;
2502 SubRegIdx = AArch64::dsub;
2504 SubRegIdx = AArch64::zsub;
2511 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2514 SavedRegs |= FPRZRegs;
2534 unsigned UnspilledCSGPR = AArch64::NoRegister;
2535 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
2541 RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() :
MCRegister();
2543 unsigned ExtraCSSpill = 0;
2544 bool HasUnpairedGPR64 =
false;
2545 bool HasPairZReg =
false;
2546 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2547 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2550 for (
unsigned i = 0; CSRegs[i]; ++i) {
2554 if (Reg == BasePointerReg)
2559 if (UserReservedRegs[Reg]) {
2560 SavedRegs.
reset(Reg);
2564 bool RegUsed = SavedRegs.
test(Reg);
2566 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2567 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2568 AArch64::FPR128RegClass.
contains(Reg)) {
2571 if (HasUnpairedGPR64)
2572 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2574 PairedReg = CSRegs[i ^ 1];
2581 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2582 PairedReg = AArch64::NoRegister;
2583 HasUnpairedGPR64 =
true;
2585 assert(PairedReg == AArch64::NoRegister ||
2586 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
2587 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
2588 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
2591 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2592 UnspilledCSGPR = Reg;
2593 UnspilledCSGPRPaired = PairedReg;
2601 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
2602 !SavedRegs.
test(PairedReg)) {
2603 SavedRegs.
set(PairedReg);
2604 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2605 !ReservedRegs[PairedReg])
2606 ExtraCSSpill = PairedReg;
2609 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2610 SavedRegs.
test(CSRegs[i ^ 1]));
2618 if (PnReg.isValid())
2624 SavedRegs.
set(AArch64::P8);
2629 "Predicate cannot be a reserved register");
2639 SavedRegs.
set(AArch64::X18);
2645 determineStackHazardSlot(MF, SavedRegs);
2648 unsigned CSStackSize = 0;
2649 unsigned ZPRCSStackSize = 0;
2650 unsigned PPRCSStackSize = 0;
2652 for (
unsigned Reg : SavedRegs.
set_bits()) {
2654 assert(RC &&
"expected register class!");
2655 auto SpillSize =
TRI->getSpillSize(*RC);
2656 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2657 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2659 ZPRCSStackSize += SpillSize;
2661 PPRCSStackSize += SpillSize;
2667 return SavedRegs.test(SuperReg);
2670 CSStackSize += SpillSize;
2677 unsigned NumSavedRegs = SavedRegs.
count();
2690 SavedRegs.
set(AArch64::LR);
2695 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2696 SavedRegs.
set(AArch64::FP);
2697 SavedRegs.
set(AArch64::LR);
2701 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2702 for (
unsigned Reg : SavedRegs.
set_bits())
2708 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2710 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2712 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2713 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2722 int64_t CalleeStackUsed = 0;
2725 if (FixedOff > CalleeStackUsed)
2726 CalleeStackUsed = FixedOff;
2730 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2731 CalleeStackUsed) > EstimatedStackSizeLimit;
2732 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2742 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
2744 <<
" to get a scratch register.\n");
2745 SavedRegs.
set(UnspilledCSGPR);
2746 ExtraCSSpill = UnspilledCSGPR;
2751 if (producePairRegisters(MF)) {
2752 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
2755 SavedRegs.
reset(UnspilledCSGPR);
2756 ExtraCSSpill = AArch64::NoRegister;
2759 SavedRegs.
set(UnspilledCSGPRPaired);
2768 unsigned Size =
TRI->getSpillSize(RC);
2769 Align Alignment =
TRI->getSpillAlign(RC);
2771 RS->addScavengingFrameIndex(FI);
2772 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2773 <<
" as the emergency spill slot.\n");
2778 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2787 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2791 "Should not invalidate callee saved info");
2802 std::vector<CalleeSavedInfo> &CSI)
const {
2811 std::reverse(CSI.begin(), CSI.end());
2831 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2832 if (It != CSI.end())
2833 CSI.insert(It, VGInfo);
2835 CSI.push_back(VGInfo);
2839 int HazardSlotIndex = std::numeric_limits<int>::max();
2840 for (
auto &
CS : CSI) {
2848 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2849 "Unexpected register order for hazard slot");
2851 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2857 unsigned Size = RegInfo->getSpillSize(*RC);
2858 Align Alignment(RegInfo->getSpillAlign(*RC));
2860 CS.setFrameIdx(FrameIdx);
2865 Reg == AArch64::FP) {
2875 HazardSlotIndex == std::numeric_limits<int>::max()) {
2877 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2904 int &Min,
int &Max) {
2905 Min = std::numeric_limits<int>::max();
2906 Max = std::numeric_limits<int>::min();
2912 for (
auto &
CS : CSI) {
2913 if (AArch64::ZPRRegClass.
contains(
CS.getReg()) ||
2914 AArch64::PPRRegClass.contains(
CS.getReg())) {
2915 assert((Max == std::numeric_limits<int>::min() ||
2916 Max + 1 ==
CS.getFrameIdx()) &&
2917 "SVE CalleeSaves are not consecutive");
2918 Min = std::min(Min,
CS.getFrameIdx());
2919 Max = std::max(Max,
CS.getFrameIdx());
2922 return Min != std::numeric_limits<int>::max();
2935 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
2943 "SVE vectors should never be passed on the stack by value, only by "
2947 auto AllocateObject = [&](
int FI) {
2956 if (Alignment >
Align(16))
2958 "Alignment of scalable vectors > 16 bytes is not yet supported");
2961 StackTop =
alignTo(StackTop, Alignment);
2963 assert(StackTop < (
uint64_t)std::numeric_limits<int64_t>::max() &&
2964 "SVE StackTop far too large?!");
2966 int64_t
Offset = -int64_t(StackTop);
2974 int MinCSFrameIndex, MaxCSFrameIndex;
2976 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
2989 int StackProtectorFI = -1;
2993 ObjectsToAllocate.
push_back(StackProtectorFI);
3009 for (
unsigned FI : ObjectsToAllocate)
3024 "Upwards growing stack unsupported");
3039 int64_t CurrentOffset =
3043 int FrameIndex =
H.CatchObj.FrameIndex;
3044 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3055 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3056 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3058 "UnwindHelpOffset must be at the start of the fixed object area");
3061 EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
3071 RS->enterBasicBlockEnd(
MBB);
3073 Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
3074 assert(DstReg &&
"There must be a free register after frame setup");
3085struct TagStoreInstr {
3093 MachineFunction *MF;
3094 MachineBasicBlock *
MBB;
3095 MachineRegisterInfo *MRI;
3104 StackOffset FrameRegOffset;
3108 std::optional<int64_t> FrameRegUpdate;
3110 unsigned FrameRegUpdateFlags;
3120 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3121 :
MBB(
MBB), ZeroData(ZeroData) {
3127 void addInstruction(TagStoreInstr
I) {
3129 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3130 "Non-adjacent tag store instructions.");
3133 void clear() { TagStores.
clear(); }
3138 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3145 const int64_t kMinOffset = -256 * 16;
3146 const int64_t kMaxOffset = 255 * 16;
3149 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3150 if (BaseRegOffsetBytes < kMinOffset ||
3151 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3155 BaseRegOffsetBytes % 16 != 0) {
3160 BaseRegOffsetBytes = 0;
3165 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3168 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3170 assert(BaseRegOffsetBytes % 16 == 0);
3174 .
addImm(BaseRegOffsetBytes / 16)
3178 if (BaseRegOffsetBytes == 0)
3180 BaseRegOffsetBytes += InstrSize;
3199 int64_t LoopSize =
Size;
3202 if (FrameRegUpdate && *FrameRegUpdate)
3203 LoopSize -= LoopSize % 32;
3205 TII->get(ZeroData ? AArch64::STZGloop_wback
3206 : AArch64::STGloop_wback))
3213 LoopI->
setFlags(FrameRegUpdateFlags);
3215 int64_t ExtraBaseRegUpdate =
3216 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3217 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3218 <<
", Size=" <<
Size
3219 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3220 <<
", FrameRegUpdate=" << FrameRegUpdate
3221 <<
", FrameRegOffset.getFixed()="
3222 << FrameRegOffset.
getFixed() <<
"\n");
3223 if (LoopSize <
Size) {
3227 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3228 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3229 "STG immediate out of range");
3231 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3238 }
else if (ExtraBaseRegUpdate) {
3240 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3241 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3244 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3257 int64_t
Size, int64_t *TotalOffset) {
3259 if ((
MI.getOpcode() == AArch64::ADDXri ||
3260 MI.getOpcode() == AArch64::SUBXri) &&
3261 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3263 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3264 if (
MI.getOpcode() == AArch64::SUBXri)
3275 const int64_t kMaxOffset = 4080 - 16;
3277 const int64_t kMinOffset = -4095;
3278 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3279 PostOffset % 16 == 0) {
3290 for (
auto &TS : TSE) {
3294 if (
MI->memoperands_empty()) {
3298 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3304 bool TryMergeSPUpdate) {
3305 if (TagStores.
empty())
3307 TagStoreInstr &FirstTagStore = TagStores[0];
3308 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3309 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3310 DL = TagStores[0].MI->getDebugLoc();
3314 *MF, FirstTagStore.Offset,
false ,
3318 FrameRegUpdate = std::nullopt;
3320 mergeMemRefs(TagStores, CombinedMemRefs);
3323 dbgs() <<
"Replacing adjacent STG instructions:\n";
3324 for (
const auto &Instr : TagStores) {
3333 if (TagStores.
size() < 2)
3335 emitUnrolled(InsertI);
3338 int64_t TotalOffset = 0;
3339 if (TryMergeSPUpdate) {
3345 if (InsertI !=
MBB->
end() &&
3346 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3348 UpdateInstr = &*InsertI++;
3354 if (!UpdateInstr && TagStores.
size() < 2)
3358 FrameRegUpdate = TotalOffset;
3359 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3366 for (
auto &TS : TagStores)
3367 TS.MI->eraseFromParent();
3371 int64_t &
Size,
bool &ZeroData) {
3375 unsigned Opcode =
MI.getOpcode();
3376 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3377 Opcode == AArch64::STZ2Gi);
3379 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3380 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3382 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3385 Size =
MI.getOperand(2).getImm();
3389 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3391 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3396 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3400 16 *
MI.getOperand(2).getImm();
3404static size_t countAvailableScavengerSlots(
LivePhysRegs &LiveRegs,
3409 return LiveRegs.available(MRI,
Reg);
3412 size_t NumEmergencySlots = 0;
3414 NumEmergencySlots =
RS->getNumScavengingFrameIndices();
3416 return FreeGPRs + NumEmergencySlots;
3435 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3441 constexpr int kScanLimit = 10;
3444 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3453 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3454 if (ZeroData != FirstZeroData)
3462 if (!
MI.isTransient())
3471 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3487 LiveRegs.addLiveOuts(*
MBB);
3492 LiveRegs.stepBackward(*
I);
3495 if (LiveRegs.contains(AArch64::NZCV))
3506 dbgs() <<
"Failed to merge MTE stack tagging instructions into loop "
3507 <<
"due to high register pressure.\n");
3512 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3517 int64_t CurOffset = Instrs[0].Offset;
3518 for (
auto &Instr : Instrs) {
3519 if (CurOffset >
Instr.Offset)
3526 TagStoreEdit TSE(
MBB, FirstZeroData);
3527 std::optional<int64_t> EndOffset;
3528 for (
auto &Instr : Instrs) {
3529 if (EndOffset && *EndOffset !=
Instr.Offset) {
3531 TSE.emitCode(InsertI, TFI,
false);
3535 TSE.addInstruction(Instr);
3554 II = tryMergeAdjacentSTG(
II,
this, RS);
3561 shouldSignReturnAddressEverywhere(MF))
3570 bool IgnoreSPUpdates)
const {
3572 if (IgnoreSPUpdates) {
3575 FrameReg = AArch64::SP;
3585 FrameReg = AArch64::SP;
3610 bool IsValid =
false;
3612 int ObjectIndex = 0;
3614 int GroupIndex = -1;
3616 bool ObjectFirst =
false;
3619 bool GroupFirst =
false;
3624 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3628 SmallVector<int, 8> CurrentMembers;
3629 int NextGroupIndex = 0;
3630 std::vector<FrameObject> &Objects;
3633 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3634 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3635 void EndCurrentGroup() {
3636 if (CurrentMembers.
size() > 1) {
3641 for (
int Index : CurrentMembers) {
3642 Objects[
Index].GroupIndex = NextGroupIndex;
3648 CurrentMembers.clear();
3652bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3674 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3675 A.GroupIndex,
A.ObjectIndex) <
3676 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3677 B.GroupIndex,
B.ObjectIndex);
3686 ObjectsToAllocate.
empty())
3691 for (
auto &Obj : ObjectsToAllocate) {
3692 FrameObjects[Obj].IsValid =
true;
3693 FrameObjects[Obj].ObjectIndex = Obj;
3698 GroupBuilder GB(FrameObjects);
3699 for (
auto &
MBB : MF) {
3700 for (
auto &
MI :
MBB) {
3701 if (
MI.isDebugInstr())
3706 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3709 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3711 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3716 switch (
MI.getOpcode()) {
3717 case AArch64::STGloop:
3718 case AArch64::STZGloop:
3722 case AArch64::STZGi:
3723 case AArch64::ST2Gi:
3724 case AArch64::STZ2Gi:
3737 FrameObjects[FI].IsValid)
3745 GB.AddMember(TaggedFI);
3747 GB.EndCurrentGroup();
3750 GB.EndCurrentGroup();
3755 FrameObject::AccessHazard;
3757 for (
auto &Obj : FrameObjects)
3758 if (!Obj.Accesses ||
3759 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3760 Obj.Accesses = FrameObject::AccessGPR;
3769 FrameObjects[*TBPI].ObjectFirst =
true;
3770 FrameObjects[*TBPI].GroupFirst =
true;
3771 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3772 if (FirstGroupIndex >= 0)
3773 for (FrameObject &Object : FrameObjects)
3774 if (Object.GroupIndex == FirstGroupIndex)
3775 Object.GroupFirst =
true;
3781 for (
auto &Obj : FrameObjects) {
3785 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3789 dbgs() <<
"Final frame order:\n";
3790 for (
auto &Obj : FrameObjects) {
3793 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3794 if (Obj.ObjectFirst)
3795 dbgs() <<
", first";
3797 dbgs() <<
", group-first";
3808AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3819 MF.
insert(MBBInsertPoint, LoopMBB);
3821 MF.
insert(MBBInsertPoint, ExitMBB);
3856 MBB.addSuccessor(LoopMBB);
3860 return ExitMBB->
begin();
3863void AArch64FrameLowering::inlineStackProbeFixed(
3868 const AArch64InstrInfo *
TII =
3870 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
3875 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
3876 int64_t NumBlocks = FrameSize / ProbeSize;
3877 int64_t ResidualSize = FrameSize % ProbeSize;
3879 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
3880 << NumBlocks <<
" blocks of " << ProbeSize
3881 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
3886 for (
int i = 0; i < NumBlocks; ++i) {
3892 EmitAsyncCFI && !HasFP, CFAOffset);
3905 }
else if (NumBlocks != 0) {
3911 EmitAsyncCFI && !HasFP, CFAOffset);
3913 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
3915 if (EmitAsyncCFI && !HasFP) {
3918 .buildDefCFARegister(AArch64::SP);
3922 if (ResidualSize != 0) {
3928 EmitAsyncCFI && !HasFP, CFAOffset);
3949 SmallVector<MachineInstr *, 4> ToReplace;
3950 for (MachineInstr &
MI :
MBB)
3951 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
3952 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
3955 for (MachineInstr *
MI : ToReplace) {
3956 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
3957 Register ScratchReg =
MI->getOperand(0).getReg();
3958 int64_t FrameSize =
MI->getOperand(1).getImm();
3960 MI->getOperand(3).getImm());
3961 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
3964 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
3965 "Stack probe pseudo-instruction expected");
3966 const AArch64InstrInfo *
TII =
3967 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
3968 Register TargetReg =
MI->getOperand(0).getReg();
3969 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
3971 MI->eraseFromParent();
3991 return std::make_tuple(
start(),
Idx) <
3992 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4022 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4023 if (
Offset.getScalable())
4024 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4035void AArch64FrameLowering::emitRemarks(
4038 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4043 const uint64_t HazardSize =
4046 if (HazardSize == 0)
4054 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4056 size_t NumFPLdSt = 0;
4057 size_t NumNonFPLdSt = 0;
4060 for (
const MachineBasicBlock &
MBB : MF) {
4061 for (
const MachineInstr &
MI :
MBB) {
4062 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4064 for (MachineMemOperand *MMO :
MI.memoperands()) {
4071 StackAccesses[ArrIdx].Idx = FrameIdx;
4072 StackAccesses[ArrIdx].Offset =
4083 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4094 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4105 if (StackAccesses.front().isMixed())
4106 MixedObjects.push_back(&StackAccesses.front());
4108 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4110 const auto &
First = *It;
4111 const auto &Second = *(It + 1);
4113 if (Second.isMixed())
4114 MixedObjects.push_back(&Second);
4116 if ((
First.isSME() && Second.isCPU()) ||
4117 (
First.isCPU() && Second.isSME())) {
4118 uint64_t Distance =
static_cast<uint64_t
>(Second.start() -
First.end());
4119 if (Distance < HazardSize)
4124 auto EmitRemark = [&](llvm::StringRef Str) {
4126 auto R = MachineOptimizationRemarkAnalysis(
4127 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4128 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4132 for (
const auto &
P : HazardPairs)
4133 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4135 for (
const auto *Obj : MixedObjects)
4137 formatv(
"{0} accessed by both GP and FP instructions", *Obj).str());
static void getLiveRegsForEntryMBB(LivePhysRegs &LiveRegs, const MachineBasicBlock &MBB)
static const unsigned DefaultSafeSPDisplacement
This is the biggest offset to the stack pointer we can encode in aarch64 instructions (without using ...
static RegState getPrologueDeath(MachineFunction &MF, unsigned Reg)
static bool produceCompactUnwindFrame(const AArch64FrameLowering &, MachineFunction &MF)
static cl::opt< bool > StackTaggingMergeSetTag("stack-tagging-merge-settag", cl::desc("merge settag instruction in function epilog"), cl::init(true), cl::Hidden)
bool enableMultiVectorSpillFill(const AArch64Subtarget &Subtarget, MachineFunction &MF)
static std::optional< int > getLdStFrameID(const MachineInstr &MI, const MachineFrameInfo &MFI)
static cl::opt< bool > SplitSVEObjects("aarch64-split-sve-objects", cl::desc("Split allocation of ZPR & PPR objects"), cl::init(true), cl::Hidden)
static cl::opt< bool > StackHazardInNonStreaming("aarch64-stack-hazard-in-non-streaming", cl::init(false), cl::Hidden)
void computeCalleeSaveRegisterPairs(const AArch64FrameLowering &AFL, MachineFunction &MF, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI, SmallVectorImpl< RegPairInfo > &RegPairs, bool NeedsFrameRecord)
static cl::opt< bool > OrderFrameObjects("aarch64-order-frame-objects", cl::desc("sort stack allocations"), cl::init(true), cl::Hidden)
static cl::opt< bool > DisableMultiVectorSpillFill("aarch64-disable-multivector-spill-fill", cl::desc("Disable use of LD/ST pairs for SME2 or SVE2p1"), cl::init(false), cl::Hidden)
static cl::opt< bool > EnableRedZone("aarch64-redzone", cl::desc("enable use of redzone on AArch64"), cl::init(false), cl::Hidden)
static bool invalidateRegisterPairing(bool SpillExtendedVolatile, unsigned SpillCount, unsigned Reg1, unsigned Reg2, bool UsesWinAAPCS, bool NeedsWinCFI, bool NeedsFrameRecord, const TargetRegisterInfo *TRI)
Returns true if Reg1 and Reg2 cannot be paired using a ldp/stp instruction.
cl::opt< bool > EnableHomogeneousPrologEpilog("homogeneous-prolog-epilog", cl::Hidden, cl::desc("Emit homogeneous prologue and epilogue for the size " "optimization (default = off)"))
static bool isLikelyToHaveSVEStack(const AArch64FrameLowering &AFL, const MachineFunction &MF)
static bool invalidateWindowsRegisterPairing(bool SpillExtendedVolatile, unsigned SpillCount, unsigned Reg1, unsigned Reg2, bool NeedsWinCFI, const TargetRegisterInfo *TRI)
static SVEStackSizes determineSVEStackSizes(MachineFunction &MF, AssignObjectOffsets AssignOffsets)
Process all the SVE stack objects and the SVE stack size and offsets for each object.
static bool isTargetWindows(const MachineFunction &MF)
static unsigned estimateRSStackSizeLimit(MachineFunction &MF)
Look at each instruction that references stack frames and return the stack size limit beyond which so...
static bool getSVECalleeSaveSlotRange(const MachineFrameInfo &MFI, int &Min, int &Max)
returns true if there are any SVE callee saves.
static cl::opt< unsigned > StackHazardRemarkSize("aarch64-stack-hazard-remark-size", cl::init(0), cl::Hidden)
static MCRegister getRegisterOrZero(MCRegister Reg, bool HasSVE)
static unsigned getStackHazardSize(const MachineFunction &MF)
MCRegister findFreePredicateReg(BitVector &SavedRegs)
static bool isPPRAccess(const MachineInstr &MI)
static std::optional< int > getMMOFrameID(MachineMemOperand *MMO, const MachineFrameInfo &MFI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declaration of the AArch64PrologueEmitter and AArch64EpilogueEmitter classes,...
static const int kSetTagLoopThreshold
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
This file contains the simple types necessary to represent the attributes associated with functions a...
#define CASE(ATTRNAME, AANAME,...)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
DXIL Forward Handle Accesses
const HexagonInstrInfo * TII
static std::string getTypeString(Type *T)
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
uint64_t IntrinsicInst * II
This file declares the machine register scavenger class.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
This file defines the SmallVector class.
void emitEpilogue()
Emit the epilogue.
StackOffset getSVEStackSize(const MachineFunction &MF) const
Returns the size of the entire SVE stackframe (PPRs + ZPRs).
StackOffset getZPRStackSize(const MachineFunction &MF) const
Returns the size of the entire ZPR stackframe (calleesaves + spills).
void processFunctionBeforeFrameIndicesReplaced(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameIndicesReplaced - This method is called immediately before MO_FrameIndex op...
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override
This method is called during prolog/epilog code insertion to eliminate call frame setup and destroy p...
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override
Check whether or not the given MBB can be used as a prologue for the target.
bool enableStackSlotScavenging(const MachineFunction &MF) const override
Returns true if the stack slot holes in the fixed and callee-save stack area should be used when allo...
bool assignCalleeSavedSpillSlots(MachineFunction &MF, const TargetRegisterInfo *TRI, std::vector< CalleeSavedInfo > &CSI) const override
assignCalleeSavedSpillSlots - Allows target to override spill slot assignment logic.
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
spillCalleeSavedRegisters - Issues instruction(s) to spill all callee saved registers and returns tru...
bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MutableArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee saved registers and returns...
bool enableFullCFIFixup(const MachineFunction &MF) const override
enableFullCFIFixup - Returns true if we may need to fix the unwind information such that it is accura...
StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI) const override
getFrameIndexReferenceFromSP - This method returns the offset from the stack pointer to the slot of t...
bool enableCFIFixup(const MachineFunction &MF) const override
Returns true if we may need to fix the unwind information for the function.
StackOffset getNonLocalFrameIndexReference(const MachineFunction &MF, int FI) const override
getNonLocalFrameIndexReference - This method returns the offset used to reference a frame index locat...
TargetStackID::Value getStackIDForScalableVectors() const override
Returns the StackID that scalable vectors should be associated with.
friend class AArch64PrologueEmitter
bool hasFPImpl(const MachineFunction &MF) const override
hasFPImpl - Return true if the specified function should have a dedicated frame pointer register.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override
emitProlog/emitEpilog - These methods insert prolog and epilog code into the function.
friend class AArch64EpilogueEmitter
void resetCFIToInitialState(MachineBasicBlock &MBB) const override
Emit CFI instructions that recreate the state of the unwind information upon function entry.
bool hasReservedCallFrame(const MachineFunction &MF) const override
hasReservedCallFrame - Under normal circumstances, when a frame pointer is not required,...
bool hasSVECalleeSavesAboveFrameRecord(const MachineFunction &MF) const
StackOffset resolveFrameOffsetReference(const MachineFunction &MF, int64_t ObjectOffset, bool isFixed, TargetStackID::Value StackID, Register &FrameReg, bool PreferFP, bool ForSimm) const
bool canUseRedZone(const MachineFunction &MF) const
Can this function use the red zone for local allocations.
bool needsWinCFI(const MachineFunction &MF) const
bool isFPReserved(const MachineFunction &MF) const
Should the Frame Pointer be reserved for the current function?
void processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameFinalized - This method is called immediately before the specified function...
int getSEHFrameIndexOffset(const MachineFunction &MF, int FI) const
unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const
Funclets only need to account for space for the callee saved registers, as the locals are accounted f...
void orderFrameObjects(const MachineFunction &MF, SmallVectorImpl< int > &ObjectsToAllocate) const override
Order the symbols in the local stack frame.
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
StackOffset getPPRStackSize(const MachineFunction &MF) const
Returns the size of the entire PPR stackframe (calleesaves + spills + hazard padding).
int64_t getArgumentStackToRestore(MachineFunction &MF, MachineBasicBlock &MBB) const
Returns how much of the incoming argument stack area (in bytes) we should clean up in an epilogue.
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const override
getFrameIndexReference - Provide a base+offset reference to an FI slot for debug info.
StackOffset getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI, Register &FrameReg, bool IgnoreSPUpdates) const override
For Win64 AArch64 EH, the offset to the Unwind object is from the SP before the update.
StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg, bool PreferFP, bool ForSimm) const
unsigned getWinEHParentFrameOffset(const MachineFunction &MF) const override
The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve the parent's frame pointer...
bool requiresSaveVG(const MachineFunction &MF) const
void emitPacRetPlusLeafHardening(MachineFunction &MF) const
Harden the entire function with pac-ret.
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
unsigned getPPRCalleeSavedStackSize() const
void setHasStackFrame(bool s)
void setSwiftAsyncContextFrameIdx(int FI)
unsigned getTailCallReservedStack() const
unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const
void setCalleeSaveBaseToFrameRecordOffset(int Offset)
bool hasStackProbing() const
unsigned getArgumentStackToRestore() const
void setCalleeSaveStackHasFreeSpace(bool s)
int getCalleeSaveBaseToFrameRecordOffset() const
SignReturnAddress getSignReturnAddressCondition() const
bool hasStreamingModeChanges() const
void setPredicateRegForFillSpill(unsigned Reg)
int getStackHazardSlotIndex() const
void setCalleeSavedStackSize(unsigned Size)
void setSplitSVEObjects(bool s)
bool hasStackFrame() const
void setStackSizeSVE(uint64_t ZPR, uint64_t PPR)
std::optional< int > getTaggedBasePointerIndex() const
SMEAttrs getSMEFnAttrs() const
uint64_t getLocalStackSize() const
bool needsDwarfUnwindInfo(const MachineFunction &MF) const
unsigned getVarArgsGPRSize() const
uint64_t getStackSizePPR() const
bool hasSwiftAsyncContext() const
bool hasStackHazardSlotIndex() const
void setStackHazardSlotIndex(int Index)
unsigned getZPRCalleeSavedStackSize() const
void setStackHazardCSRSlotIndex(int Index)
unsigned getPredicateRegForFillSpill() const
void setSVECalleeSavedStackSize(unsigned ZPR, unsigned PPR)
bool hasCalculatedStackSizeSVE() const
uint64_t getStackSizeZPR() const
bool hasSVEStackSize() const
bool isStackHazardIncludedInCalleeSaveArea() const
unsigned getSVECalleeSavedStackSize() const
bool hasSplitSVEObjects() const
bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const
bool hasCalleeSaveStackFreeSpace() const
static bool isTailCallReturnInst(const MachineInstr &MI)
Returns true if MI is one of the TCRETURN* instructions.
static bool isFpOrNEON(Register Reg)
Returns whether the physical register is FP or NEON.
void emitPrologue()
Emit the prologue.
bool isTargetWindows() const
const AArch64RegisterInfo * getRegisterInfo() const override
bool isNeonAvailable() const
Returns true if the target has NEON and the function at runtime is known to have NEON enabled (e....
const AArch64InstrInfo * getInstrInfo() const override
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
bool isSVEorStreamingSVEAvailable() const
Returns true if the target has access to either the full range of SVE instructions,...
bool isStreaming() const
Returns true if the function has a streaming body.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this functions.
unsigned getRedZoneSize(const Function &F) const
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
bool empty() const
Check if the array is empty.
bool test(unsigned Idx) const
Returns true if bit Idx is set.
BitVector & reset()
Reset all bits in the bitvector.
size_type count() const
Returns the number of bits which are set.
BitVector & set()
Set all bits in the bitvector.
iterator_range< const_set_bits_iterator > set_bits() const
size_type size() const
Returns the number of bits in this bitvector.
Helper class for creating CFI instructions and inserting them into MIR.
The CalleeSavedInfo class tracks the information need to locate where a callee saved register is in t...
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
AttributeList getAttributes() const
Return the attribute list for this Function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
A set of physical registers with utility functions to track liveness when walking backward/forward th...
bool usesWindowsCFI() const
Wrapper class representing physical registers. Should be passed by value.
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
MachineInstr & instr_back()
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
reverse_iterator rbegin()
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
LLVM_ABI int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
const AllocaInst * getObjectAllocation(int ObjectIdx) const
Return the underlying Alloca of the specified stack object if it exists.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
bool hasCalls() const
Return true if the current function has any function calls.
bool isFrameAddressTaken() const
This method may be called any time after instruction selection is complete to determine if there is a...
void setObjectOffset(int ObjectIdx, int64_t SPOffset)
Set the stack frame offset of the specified object.
bool isCalleeSavedObjectIndex(int ObjectIdx) const
uint64_t getMaxCallFrameSize() const
Return the maximum size of a call frame that must be allocated for an outgoing function call.
bool hasPatchPoint() const
This method may be called any time after instruction selection is complete to determine if there is a...
bool hasScalableStackID(int ObjectIdx) const
int getStackProtectorIndex() const
Return the index for the stack protector object.
LLVM_ABI uint64_t estimateStackSize(const MachineFunction &MF) const
Estimate and return the size of the stack frame.
void setStackID(int ObjectIdx, uint8_t ID)
bool isCalleeSavedInfoValid() const
Has the callee saved info been calculated yet?
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
bool isMaxCallFrameSizeComputed() const
bool hasStackMap() const
This method may be called any time after instruction selection is complete to determine if there is a...
LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment, TargetStackID::Value StackID=TargetStackID::Default)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
const std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const
Returns a reference to call saved info vector for the current function.
unsigned getNumObjects() const
Return the number of objects.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
bool hasStackProtectorIndex() const
bool hasStackObjects() const
Return true if there are any stack objects in this function.
uint8_t getStackID(int ObjectIdx) const
unsigned getNumFixedObjects() const
Return the number of fixed objects.
void setIsCalleeSavedObjectIndex(int ObjectIdx, bool IsCalleeSaved)
int64_t getObjectOffset(int ObjectIdx) const
Return the assigned stack offset of the specified object from the incoming stack pointer.
int getObjectIndexBegin() const
Return the minimum frame object index.
void setObjectAlignment(int ObjectIdx, Align Alignment)
setObjectAlignment - Change the alignment of the specified stack object.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
const WinEHFuncInfo * getWinEHFuncInfo() const
getWinEHFuncInfo - Return information about how the current function uses Windows exception handling.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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