262#define DEBUG_TYPE "frame-info"
265 cl::desc(
"enable use of redzone on AArch64"),
269 "stack-tagging-merge-settag",
279 cl::desc(
"Emit homogeneous prologue and epilogue for the size "
280 "optimization (default = off)"));
292 "aarch64-disable-multivector-spill-fill",
301 bool IsTailCallReturn = (
MBB.end() !=
MBBI)
305 int64_t ArgumentPopSize = 0;
306 if (IsTailCallReturn) {
312 ArgumentPopSize = StackAdjust.
getImm();
321 return ArgumentPopSize;
351bool AArch64FrameLowering::homogeneousPrologEpilog(
373 if (Exit && getArgumentStackToRestore(MF, *Exit))
376 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
384 unsigned NumGPRs = 0;
385 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
387 if (
Reg == AArch64::LR) {
388 assert(CSRegs[
I + 1] == AArch64::FP);
389 if (NumGPRs % 2 != 0)
401bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
420 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
421 MI.getOpcode() == AArch64::ADDXri ||
422 MI.getOpcode() == AArch64::ADDSXri)
447 bool IsWin64,
bool IsFunclet)
const {
449 "Tail call reserved stack must be aligned to 16 bytes");
450 if (!IsWin64 || IsFunclet) {
455 Attribute::SwiftAsync))
469 int FrameIndex =
H.CatchObj.FrameIndex;
470 if ((FrameIndex != INT_MAX) &&
471 CatchObjFrameIndices.
insert(FrameIndex)) {
472 FixedObjectSize =
alignTo(FixedObjectSize,
479 FixedObjectSize += 8;
481 return alignTo(FixedObjectSize, 16);
499 const unsigned RedZoneSize =
512 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
516 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
537 RegInfo->hasStackRealignment(MF))
580 const Triple &TT = TM.getTargetTriple();
584 if (TT.isOSDarwin() || TT.isOSWindows())
592 if (TM.Options.FramePointerIsReserved(MF))
622 unsigned Opc =
I->getOpcode();
623 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
624 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
627 int64_t Amount =
I->getOperand(0).getImm();
635 if (CalleePopAmount == 0) {
646 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
657 "non-reserved call frame without var sized objects?");
666 }
else if (CalleePopAmount != 0) {
669 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
681 const auto &
TRI = *Subtarget.getRegisterInfo();
687 CFIBuilder.buildDefCFA(AArch64::SP, 0);
690 if (MFI.shouldSignReturnAddress(MF))
691 MFI.branchProtectionPAuthLR() ? CFIBuilder.buildNegateRAStateWithPC()
692 : CFIBuilder.buildNegateRAState();
695 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
696 CFIBuilder.buildSameValue(AArch64::X18);
699 const std::vector<CalleeSavedInfo> &CSI =
701 for (
const auto &Info : CSI) {
703 if (!
TRI.regNeedsCFI(Reg, Reg))
705 CFIBuilder.buildSameValue(Reg);
718 case AArch64::W##n: \
719 case AArch64::X##n: \
744 case AArch64::B##n: \
745 case AArch64::H##n: \
746 case AArch64::S##n: \
747 case AArch64::D##n: \
748 case AArch64::Q##n: \
749 return HasSVE ? AArch64::Z##n : AArch64::Q##n
786void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
797 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
800 BitVector GPRsToZero(
TRI.getNumRegs());
801 BitVector FPRsToZero(
TRI.getNumRegs());
804 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
807 GPRsToZero.set(XReg);
811 FPRsToZero.set(XReg);
818 for (MCRegister
Reg : GPRsToZero.set_bits())
822 for (MCRegister
Reg : FPRsToZero.set_bits())
826 for (MCRegister PReg :
827 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
828 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
829 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
831 if (RegsToZero[PReg])
837bool AArch64FrameLowering::windowsRequiresStackProbe(
839 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
840 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
844 StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
853 for (
unsigned i = 0; CSRegs[i]; ++i)
859 bool HasCall)
const {
869 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
871 LivePhysRegs LiveRegs(
TRI);
874 LiveRegs.addReg(AArch64::X16);
875 LiveRegs.addReg(AArch64::X17);
876 LiveRegs.addReg(AArch64::X18);
881 if (LiveRegs.available(
MRI, AArch64::X9))
884 for (
unsigned Reg : AArch64::GPR64RegClass) {
885 if (LiveRegs.available(
MRI,
Reg))
888 return AArch64::NoRegister;
915 MBB.isLiveIn(AArch64::NZCV))
919 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
925 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
926 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
935 F.needsUnwindTableEntry();
938bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
946 return SignReturnAddressAll;
955 unsigned Opc =
MBBI->getOpcode();
959 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
960 int Imm =
MBBI->getOperand(ImmIdx).getImm();
968 case AArch64::STR_ZXI:
969 case AArch64::LDR_ZXI: {
970 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
977 case AArch64::STR_PXI:
978 case AArch64::LDR_PXI: {
979 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
986 case AArch64::LDPDpost:
989 case AArch64::STPDpre: {
990 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
991 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
992 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
999 case AArch64::LDPXpost:
1002 case AArch64::STPXpre: {
1005 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1006 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1010 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1011 .
addImm(RegInfo->getSEHRegNum(Reg0))
1012 .
addImm(RegInfo->getSEHRegNum(Reg1))
1017 case AArch64::LDRDpost:
1020 case AArch64::STRDpre: {
1021 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1022 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1028 case AArch64::LDRXpost:
1031 case AArch64::STRXpre: {
1032 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1039 case AArch64::STPDi:
1040 case AArch64::LDPDi: {
1041 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1042 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1050 case AArch64::STPXi:
1051 case AArch64::LDPXi: {
1054 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1060 .
addImm(RegInfo->getSEHRegNum(Reg0))
1061 .
addImm(RegInfo->getSEHRegNum(Reg1))
1066 case AArch64::STRXui:
1067 case AArch64::LDRXui: {
1068 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1075 case AArch64::STRDui:
1076 case AArch64::LDRDui: {
1077 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1084 case AArch64::STPQi:
1085 case AArch64::LDPQi: {
1086 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1087 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1088 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1095 case AArch64::LDPQpost:
1098 case AArch64::STPQpre: {
1099 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1100 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1101 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1120 if (ST.isTargetDarwin())
1150 DL =
MBBI->getDebugLoc();
1157 EmitSignRA(MF.
front());
1159 if (
MBB.isEHFuncletEntry())
1161 if (
MBB.isReturnBlock())
1220 if (MFI.isVariableSizedObjectIndex(FI)) {
1229 bool FPAfterSVECalleeSaves =
1232 if (FPAfterSVECalleeSaves &&
1239 bool IsFixed = MFI.isFixedObjectIndex(FI);
1244 if (!IsFixed && !IsCSR) {
1245 ScalableOffset = -SVEStackSize;
1246 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1261 int64_t ObjectOffset)
const {
1265 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1266 unsigned FixedObject =
1267 getFixedObjectSize(MF, AFI, IsWin64,
false);
1275 int64_t ObjectOffset)
const {
1286 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1287 ? getFPOffset(MF, ObjectOffset).getFixed()
1288 : getStackOffset(MF, ObjectOffset).getFixed();
1293 bool ForSimm)
const {
1295 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1296 bool isFixed = MFI.isFixedObjectIndex(FI);
1303 const MachineFunction &MF, int64_t ObjectOffset,
bool isFixed,
bool isSVE,
1304 Register &FrameReg,
bool PreferFP,
bool ForSimm)
const {
1311 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1312 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1327 PreferFP &= !SVEStackSize;
1335 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1339 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1341 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1346 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1347 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1349 if (FPOffset >= 0) {
1353 }
else if (MFI.hasVarSizedObjects()) {
1357 bool CanUseBP = RegInfo->hasBasePointer(MF);
1358 if (FPOffsetFits && CanUseBP)
1365 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1372 "Funclets should only be present on Win64");
1376 if (FPOffsetFits && PreferFP)
1383 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1384 "In the presence of dynamic stack pointer realignment, "
1385 "non-argument/CSR objects cannot be accessed through the frame pointer");
1387 bool FPAfterSVECalleeSaves =
1397 if (FPAfterSVECalleeSaves) {
1407 RegInfo->hasStackRealignment(MF))) {
1408 FrameReg = RegInfo->getFrameRegister(MF);
1412 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1418 if (FPAfterSVECalleeSaves) {
1425 ScalableOffset = SVECalleeSavedStack;
1427 ScalableOffset = SVECalleeSavedStack - SVEStackSize;
1430 ScalableOffset = SVEStackSize;
1432 ScalableOffset = SVEStackSize - SVECalleeSavedStack;
1435 if (UseFP && !(isFixed || isCSR))
1436 ScalableOffset = -SVEStackSize;
1437 if (!UseFP && (isFixed || isCSR))
1438 ScalableOffset = SVEStackSize;
1442 FrameReg = RegInfo->getFrameRegister(MF);
1447 if (RegInfo->hasBasePointer(MF))
1448 FrameReg = RegInfo->getBaseRegister();
1450 assert(!MFI.hasVarSizedObjects() &&
1451 "Can't use SP when we have var sized objects.");
1452 FrameReg = AArch64::SP;
1480 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1486 bool NeedsWinCFI,
bool IsFirst,
1495 if (Reg2 == AArch64::FP)
1499 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1506 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1507 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR && !IsFirst)
1517 bool UsesWinAAPCS,
bool NeedsWinCFI,
1518 bool NeedsFrameRecord,
bool IsFirst,
1526 if (NeedsFrameRecord)
1527 return Reg2 == AArch64::LR;
1535 unsigned Reg1 = AArch64::NoRegister;
1536 unsigned Reg2 = AArch64::NoRegister;
1539 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1540 const TargetRegisterClass *RC;
1542 RegPairInfo() =
default;
1544 bool isPaired()
const {
return Reg2 != AArch64::NoRegister; }
1546 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1552 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1553 if (SavedRegs.
test(PReg)) {
1554 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1558 return AArch64::NoRegister;
1568 bool IsLocallyStreaming =
1574 return Subtarget.hasSVE2p1() ||
1575 (Subtarget.hasSME2() &&
1576 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1584 bool NeedsFrameRecord) {
1602 (
Count & 1) == 0) &&
1603 "Odd number of callee-saved regs to spill!");
1605 int StackFillDir = -1;
1607 unsigned FirstReg = 0;
1615 FirstReg =
Count - 1;
1618 int ScalableByteOffset =
1624 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1626 RPI.Reg1 = CSI[i].getReg();
1628 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1629 RPI.Type = RegPairInfo::GPR;
1630 RPI.RC = &AArch64::GPR64RegClass;
1631 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1632 RPI.Type = RegPairInfo::FPR64;
1633 RPI.RC = &AArch64::FPR64RegClass;
1634 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1635 RPI.Type = RegPairInfo::FPR128;
1636 RPI.RC = &AArch64::FPR128RegClass;
1637 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1638 RPI.Type = RegPairInfo::ZPR;
1639 RPI.RC = &AArch64::ZPRRegClass;
1640 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1641 RPI.Type = RegPairInfo::PPR;
1642 RPI.RC = &AArch64::PPRRegClass;
1643 }
else if (RPI.Reg1 == AArch64::VG) {
1644 RPI.Type = RegPairInfo::VG;
1645 RPI.RC = &AArch64::FIXED_REGSRegClass;
1654 ByteOffset += StackFillDir * StackHazardSize;
1657 int Scale =
TRI->getSpillSize(*RPI.RC);
1660 MCRegister NextReg = CSI[i + RegInc].getReg();
1661 bool IsFirst = i == FirstReg;
1663 case RegPairInfo::GPR:
1664 if (AArch64::GPR64RegClass.
contains(NextReg) &&
1666 NeedsWinCFI, NeedsFrameRecord, IsFirst,
1670 case RegPairInfo::FPR64:
1671 if (AArch64::FPR64RegClass.
contains(NextReg) &&
1676 case RegPairInfo::FPR128:
1677 if (AArch64::FPR128RegClass.
contains(NextReg))
1680 case RegPairInfo::PPR:
1682 case RegPairInfo::ZPR:
1684 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
1687 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
1692 case RegPairInfo::VG:
1703 assert((!RPI.isPaired() ||
1704 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1705 "Out of order callee saved regs!");
1707 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1708 RPI.Reg1 == AArch64::LR) &&
1709 "FrameRecord must be allocated together with LR");
1712 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1713 RPI.Reg2 == AArch64::LR) &&
1714 "FrameRecord must be allocated together with LR");
1722 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1723 RPI.Reg1 + 1 == RPI.Reg2))) &&
1724 "Callee-save registers not saved as adjacent register pair!");
1726 RPI.FrameIdx = CSI[i].getFrameIdx();
1729 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1733 if (RPI.isScalable() && ScalableByteOffset % Scale != 0) {
1734 ScalableByteOffset =
alignTo(ScalableByteOffset, Scale);
1737 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1738 assert(OffsetPre % Scale == 0);
1740 if (RPI.isScalable())
1741 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1743 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1748 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1749 (IsWindows && RPI.Reg2 == AArch64::LR)))
1750 ByteOffset += StackFillDir * 8;
1754 if (NeedGapToAlignStack && !NeedsWinCFI && !RPI.isScalable() &&
1755 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1756 ByteOffset % 16 != 0) {
1757 ByteOffset += 8 * StackFillDir;
1763 NeedGapToAlignStack =
false;
1766 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1767 assert(OffsetPost % Scale == 0);
1770 int Offset = NeedsWinCFI ? OffsetPre : OffsetPost;
1775 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1776 (IsWindows && RPI.Reg2 == AArch64::LR)))
1778 RPI.Offset =
Offset / Scale;
1780 assert((!RPI.isPaired() ||
1781 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1782 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1783 "Offset out of bounds for LDP/STP immediate");
1785 auto isFrameRecord = [&] {
1787 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1788 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1796 return i > 0 && RPI.Reg1 == AArch64::FP &&
1797 CSI[i - 1].getReg() == AArch64::LR;
1802 if (NeedsFrameRecord && isFrameRecord())
1819 std::reverse(RegPairs.
begin(), RegPairs.
end());
1838 MRI.freezeReservedRegs();
1840 if (homogeneousPrologEpilog(MF)) {
1844 for (
auto &RPI : RegPairs) {
1849 if (!
MRI.isReserved(RPI.Reg1))
1850 MBB.addLiveIn(RPI.Reg1);
1851 if (RPI.isPaired() && !
MRI.isReserved(RPI.Reg2))
1852 MBB.addLiveIn(RPI.Reg2);
1856 bool PTrueCreated =
false;
1858 unsigned Reg1 = RPI.Reg1;
1859 unsigned Reg2 = RPI.Reg2;
1872 unsigned Size =
TRI->getSpillSize(*RPI.RC);
1873 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
1875 case RegPairInfo::GPR:
1876 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
1878 case RegPairInfo::FPR64:
1879 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
1881 case RegPairInfo::FPR128:
1882 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
1884 case RegPairInfo::ZPR:
1885 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
1887 case RegPairInfo::PPR:
1889 Size == 16 ? AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO : AArch64::STR_PXI;
1891 case RegPairInfo::VG:
1892 StrOpc = AArch64::STRXui;
1896 unsigned X0Scratch = AArch64::NoRegister;
1898 if (X0Scratch != AArch64::NoRegister)
1904 if (Reg1 == AArch64::VG) {
1906 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
1907 assert(Reg1 != AArch64::NoRegister);
1917 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
1918 AArch64::X0, LiveIn.PhysReg);
1926 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
1928 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
1940 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
1941 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
1944 assert((!NeedsWinCFI || !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
1945 "Windows unwdinding requires a consecutive (FP,LR) pair");
1949 unsigned FrameIdxReg1 = RPI.FrameIdx;
1950 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
1951 if (NeedsWinCFI && RPI.isPaired()) {
1956 if (RPI.isPaired() && RPI.isScalable()) {
1962 "Expects SVE2.1 or SME2 target and a predicate register");
1963#ifdef EXPENSIVE_CHECKS
1964 auto IsPPR = [](
const RegPairInfo &c) {
1965 return c.Reg1 == RegPairInfo::PPR;
1967 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
1968 auto IsZPR = [](
const RegPairInfo &c) {
1969 return c.Type == RegPairInfo::ZPR;
1971 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
1972 assert(!(PPRBegin < ZPRBegin) &&
1973 "Expected callee save predicate to be handled first");
1975 if (!PTrueCreated) {
1976 PTrueCreated =
true;
1981 if (!
MRI.isReserved(Reg1))
1982 MBB.addLiveIn(Reg1);
1983 if (!
MRI.isReserved(Reg2))
1984 MBB.addLiveIn(Reg2);
1985 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2001 if (!
MRI.isReserved(Reg1))
2002 MBB.addLiveIn(Reg1);
2003 if (RPI.isPaired()) {
2004 if (!
MRI.isReserved(Reg2))
2005 MBB.addLiveIn(Reg2);
2024 if (RPI.Type == RegPairInfo::ZPR || RPI.Type == RegPairInfo::PPR) {
2043 DL =
MBBI->getDebugLoc();
2046 if (homogeneousPrologEpilog(MF, &
MBB)) {
2049 for (
auto &RPI : RegPairs) {
2057 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2059 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2060 std::reverse(PPRBegin, PPREnd);
2061 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2063 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2064 std::reverse(ZPRBegin, ZPREnd);
2066 bool PTrueCreated =
false;
2067 for (
const RegPairInfo &RPI : RegPairs) {
2068 unsigned Reg1 = RPI.Reg1;
2069 unsigned Reg2 = RPI.Reg2;
2080 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2081 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2083 case RegPairInfo::GPR:
2084 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2086 case RegPairInfo::FPR64:
2087 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2089 case RegPairInfo::FPR128:
2090 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2092 case RegPairInfo::ZPR:
2093 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2095 case RegPairInfo::PPR:
2096 LdrOpc =
Size == 16 ? AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO
2099 case RegPairInfo::VG:
2104 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2105 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
2111 unsigned FrameIdxReg1 = RPI.FrameIdx;
2112 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2113 if (NeedsWinCFI && RPI.isPaired()) {
2119 if (RPI.isPaired() && RPI.isScalable()) {
2124 "Expects SVE2.1 or SME2 target and a predicate register");
2125#ifdef EXPENSIVE_CHECKS
2126 assert(!(PPRBegin < ZPRBegin) &&
2127 "Expected callee save predicate to be handled first");
2129 if (!PTrueCreated) {
2130 PTrueCreated =
true;
2135 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
2152 if (RPI.isPaired()) {
2179 return std::optional<int>(PSV->getFrameIndex());
2190 return std::nullopt;
2196 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2197 return std::nullopt;
2205void AArch64FrameLowering::determineStackHazardSlot(
2208 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2209 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2223 return AArch64::FPR64RegClass.contains(Reg) ||
2224 AArch64::FPR128RegClass.contains(Reg) ||
2225 AArch64::ZPRRegClass.contains(Reg) ||
2226 AArch64::PPRRegClass.contains(Reg);
2228 bool HasFPRStackObjects =
false;
2231 for (
auto &
MBB : MF) {
2232 for (
auto &
MI :
MBB) {
2234 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
2237 FrameObjects[*FI] |= 2;
2239 FrameObjects[*FI] |= 1;
2243 HasFPRStackObjects =
2244 any_of(FrameObjects, [](
unsigned B) {
return (
B & 3) == 2; });
2247 if (HasFPRCSRs || HasFPRStackObjects) {
2250 << StackHazardSize <<
"\n");
2268 unsigned UnspilledCSGPR = AArch64::NoRegister;
2269 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
2274 unsigned BasePointerReg = RegInfo->hasBasePointer(MF)
2275 ? RegInfo->getBaseRegister()
2278 unsigned ExtraCSSpill = 0;
2279 bool HasUnpairedGPR64 =
false;
2280 bool HasPairZReg =
false;
2281 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2282 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2285 for (
unsigned i = 0; CSRegs[i]; ++i) {
2286 const unsigned Reg = CSRegs[i];
2289 if (Reg == BasePointerReg)
2294 if (UserReservedRegs[Reg]) {
2295 SavedRegs.
reset(Reg);
2299 bool RegUsed = SavedRegs.
test(Reg);
2300 unsigned PairedReg = AArch64::NoRegister;
2301 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2302 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2303 AArch64::FPR128RegClass.
contains(Reg)) {
2306 if (HasUnpairedGPR64)
2307 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2309 PairedReg = CSRegs[i ^ 1];
2316 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2317 PairedReg = AArch64::NoRegister;
2318 HasUnpairedGPR64 =
true;
2320 assert(PairedReg == AArch64::NoRegister ||
2321 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
2322 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
2323 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
2326 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2327 UnspilledCSGPR = Reg;
2328 UnspilledCSGPRPaired = PairedReg;
2336 if (RegInfo->getSpillSize(AArch64::PPRRegClass) == 16 &&
2337 AArch64::PPR_p8to15RegClass.contains(Reg)) {
2338 SavedRegs.
set(AArch64::P4);
2344 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
2345 !SavedRegs.
test(PairedReg)) {
2346 SavedRegs.
set(PairedReg);
2347 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2348 !ReservedRegs[PairedReg])
2349 ExtraCSSpill = PairedReg;
2352 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2353 SavedRegs.
test(CSRegs[i ^ 1]));
2361 if (PnReg != AArch64::NoRegister)
2367 SavedRegs.
set(AArch64::P8);
2372 "Predicate cannot be a reserved register");
2382 SavedRegs.
set(AArch64::X18);
2386 unsigned CSStackSize = 0;
2387 unsigned SVECSStackSize = 0;
2389 for (
unsigned Reg : SavedRegs.
set_bits()) {
2390 auto *RC =
TRI->getMinimalPhysRegClass(Reg);
2391 assert(RC &&
"expected register class!");
2392 auto SpillSize =
TRI->getSpillSize(*RC);
2393 if (AArch64::PPRRegClass.
contains(Reg) ||
2394 AArch64::ZPRRegClass.
contains(Reg))
2395 SVECSStackSize += SpillSize;
2397 CSStackSize += SpillSize;
2403 unsigned NumSavedRegs = SavedRegs.
count();
2412 determineStackHazardSlot(MF, SavedRegs);
2413 if (AFI->hasStackHazardSlotIndex())
2418 SavedRegs.
set(AArch64::LR);
2423 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2424 SavedRegs.
set(AArch64::FP);
2425 SavedRegs.
set(AArch64::LR);
2429 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2430 for (
unsigned Reg : SavedRegs.
set_bits())
2436 int64_t SVEStackSize =
2437 alignTo(SVECSStackSize + estimateSVEStackObjectOffsets(MFI), 16);
2438 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2447 int64_t CalleeStackUsed = 0;
2450 if (FixedOff > CalleeStackUsed)
2451 CalleeStackUsed = FixedOff;
2455 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2456 CalleeStackUsed) > EstimatedStackSizeLimit;
2457 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2458 AFI->setHasStackFrame(
true);
2467 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
2469 <<
" to get a scratch register.\n");
2470 SavedRegs.
set(UnspilledCSGPR);
2471 ExtraCSSpill = UnspilledCSGPR;
2476 if (producePairRegisters(MF)) {
2477 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
2480 SavedRegs.
reset(UnspilledCSGPR);
2481 ExtraCSSpill = AArch64::NoRegister;
2484 SavedRegs.
set(UnspilledCSGPRPaired);
2493 unsigned Size =
TRI->getSpillSize(RC);
2494 Align Alignment =
TRI->getSpillAlign(RC);
2497 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2498 <<
" as the emergency spill slot.\n");
2503 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2507 if (
hasFP(MF) && AFI->hasSwiftAsyncContext())
2512 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2515 AFI->getCalleeSavedStackSize() == AlignedCSStackSize) &&
2516 "Should not invalidate callee saved info");
2520 AFI->setCalleeSavedStackSize(AlignedCSStackSize);
2521 AFI->setCalleeSaveStackHasFreeSpace(AlignedCSStackSize != CSStackSize);
2522 AFI->setSVECalleeSavedStackSize(
alignTo(SVECSStackSize, 16));
2527 std::vector<CalleeSavedInfo> &CSI,
unsigned &MinCSFrameIndex,
2528 unsigned &MaxCSFrameIndex)
const {
2537 std::reverse(CSI.begin(), CSI.end());
2551 if ((
unsigned)FrameIdx < MinCSFrameIndex)
2552 MinCSFrameIndex = FrameIdx;
2553 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
2554 MaxCSFrameIndex = FrameIdx;
2561 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2562 if (It != CSI.end())
2563 CSI.insert(It, VGInfo);
2565 CSI.push_back(VGInfo);
2569 int HazardSlotIndex = std::numeric_limits<int>::max();
2570 for (
auto &CS : CSI) {
2578 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2579 "Unexpected register order for hazard slot");
2581 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2584 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
2585 MinCSFrameIndex = HazardSlotIndex;
2586 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
2587 MaxCSFrameIndex = HazardSlotIndex;
2590 unsigned Size = RegInfo->getSpillSize(*RC);
2591 Align Alignment(RegInfo->getSpillAlign(*RC));
2593 CS.setFrameIdx(FrameIdx);
2595 if ((
unsigned)FrameIdx < MinCSFrameIndex)
2596 MinCSFrameIndex = FrameIdx;
2597 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
2598 MaxCSFrameIndex = FrameIdx;
2602 Reg == AArch64::FP) {
2605 if ((
unsigned)FrameIdx < MinCSFrameIndex)
2606 MinCSFrameIndex = FrameIdx;
2607 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
2608 MaxCSFrameIndex = FrameIdx;
2615 HazardSlotIndex == std::numeric_limits<int>::max()) {
2617 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2620 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
2621 MinCSFrameIndex = HazardSlotIndex;
2622 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
2623 MaxCSFrameIndex = HazardSlotIndex;
2647 int &Min,
int &Max) {
2648 Min = std::numeric_limits<int>::max();
2649 Max = std::numeric_limits<int>::min();
2655 for (
auto &CS : CSI) {
2656 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
2657 AArch64::PPRRegClass.contains(CS.getReg())) {
2658 assert((Max == std::numeric_limits<int>::min() ||
2659 Max + 1 == CS.getFrameIdx()) &&
2660 "SVE CalleeSaves are not consecutive");
2662 Min = std::min(Min, CS.getFrameIdx());
2663 Max = std::max(Max, CS.getFrameIdx());
2666 return Min != std::numeric_limits<int>::max();
2675 int &MinCSFrameIndex,
2676 int &MaxCSFrameIndex,
2677 bool AssignOffsets) {
2682 "SVE vectors should never be passed on the stack by value, only by "
2686 auto Assign = [&MFI](
int FI, int64_t
Offset) {
2696 for (
int I = MinCSFrameIndex;
I <= MaxCSFrameIndex; ++
I) {
2712 int StackProtectorFI = -1;
2716 ObjectsToAllocate.
push_back(StackProtectorFI);
2722 if (
I == StackProtectorFI)
2724 if (MaxCSFrameIndex >=
I &&
I >= MinCSFrameIndex)
2733 for (
unsigned FI : ObjectsToAllocate) {
2738 if (Alignment >
Align(16))
2740 "Alignment of scalable vectors > 16 bytes is not yet supported");
2750int64_t AArch64FrameLowering::estimateSVEStackObjectOffsets(
2752 int MinCSFrameIndex, MaxCSFrameIndex;
2756int64_t AArch64FrameLowering::assignSVEStackObjectOffsets(
2767 if (PreferredReg != AArch64::NoRegister && UsedRegs.
available(PreferredReg))
2768 return PreferredReg;
2773 return AArch64::NoRegister;
2805 std::optional<int> *MaybeSpillFI,
2806 Register PreferredReg = AArch64::NoRegister)
2808 *MF.getSubtarget().getInstrInfo())),
2809 TRI(*MF.getSubtarget().getRegisterInfo()) {
2811 if (FreeReg != AArch64::NoRegister)
2813 assert(MaybeSpillFI &&
"Expected emergency spill slot FI information "
2814 "(attempted to spill in prologue/epilogue?)");
2815 if (!MaybeSpillFI->has_value()) {
2818 TRI.getSpillAlign(RC));
2820 FreeReg = SpillCandidate;
2821 SpillFI = MaybeSpillFI->value();
2822 TII.storeRegToStackSlot(MBB, MBBI, FreeReg,
false, *SpillFI, &RC, &TRI,
2835 TII.loadRegFromStackSlot(MBB, MBBI, FreeReg, *SpillFI, &RC, &TRI,
2845 Register FreeReg = AArch64::NoRegister;
2846 std::optional<int> SpillFI;
2891 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
2898 .
add(
MI.getOperand(0))
2904 .
add(
MI.getOperand(1))
2934 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
2938 MF,
MBB,
MI, AArch64::P0, AArch64::PPR_3bRegClass, UsedRegs, SR.
PPR3bRegs,
2944 bool IsNZCVUsed = !UsedRegs.
available(AArch64::NZCV);
2945 std::optional<ScopedScavengeOrSpill> NZCVSaveReg;
2947 NZCVSaveReg.emplace(
2948 MF,
MBB,
MI, AArch64::X0, AArch64::GPR64RegClass, UsedRegs, SR.
GPRRegs,
2954 .
add(
MI.getOperand(1))
2962 .
addImm(AArch64SysReg::NZCV)
2986 .
addImm(AArch64SysReg::NZCV)
2987 .
addReg(NZCVSaveReg->freeRegister())
3003 bool HasPPRSpills =
false;
3007 switch (
MI.getOpcode()) {
3008 case AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO:
3011 LastPTrue =
nullptr;
3013 LastPTrue, SpillSlots);
3014 MI.eraseFromParent();
3016 case AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO:
3018 MI.eraseFromParent();
3021 LastPTrue =
nullptr;
3026 return HasPPRSpills;
3038 if (AFI->
hasStackFrame() &&
TRI.getSpillSize(AArch64::PPRRegClass) == 16) {
3039 auto ComputeScavengeableRegisters = [&](
unsigned RegClassID) {
3040 BitVector Regs =
TRI.getAllocatableSet(MF,
TRI.getRegClass(RegClassID));
3041 assert(Regs.
count() > 0 &&
"Expected scavengeable registers");
3046 SR.
ZPRRegs = ComputeScavengeableRegisters(AArch64::ZPRRegClassID);
3048 SR.
PPR3bRegs = ComputeScavengeableRegisters(AArch64::PPR_3bRegClassID);
3049 SR.
GPRRegs = ComputeScavengeableRegisters(AArch64::GPR64RegClassID);
3061 assert((
Pass == 0 || !HasPPRSpills) &&
"Did not expect PPR spills");
3071 "Upwards growing stack unsupported");
3073 int MinCSFrameIndex, MaxCSFrameIndex;
3074 int64_t SVEStackSize =
3075 assignSVEStackObjectOffsets(MFI, MinCSFrameIndex, MaxCSFrameIndex);
3088 int64_t CurrentOffset =
3092 int FrameIndex =
H.CatchObj.FrameIndex;
3093 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3104 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3105 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3107 "UnwindHelpOffset must be at the start of the fixed object area");
3123 assert(DstReg &&
"There must be a free register after frame setup");
3133struct TagStoreInstr {
3141 MachineFunction *MF;
3142 MachineBasicBlock *
MBB;
3143 MachineRegisterInfo *
MRI;
3152 StackOffset FrameRegOffset;
3156 std::optional<int64_t> FrameRegUpdate;
3158 unsigned FrameRegUpdateFlags;
3168 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3169 :
MBB(
MBB), ZeroData(ZeroData) {
3175 void addInstruction(TagStoreInstr
I) {
3177 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3178 "Non-adjacent tag store instructions.");
3181 void clear() { TagStores.
clear(); }
3186 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3193 const int64_t kMinOffset = -256 * 16;
3194 const int64_t kMaxOffset = 255 * 16;
3197 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3198 if (BaseRegOffsetBytes < kMinOffset ||
3199 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3203 BaseRegOffsetBytes % 16 != 0) {
3204 Register ScratchReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3208 BaseRegOffsetBytes = 0;
3213 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3216 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3218 assert(BaseRegOffsetBytes % 16 == 0);
3222 .
addImm(BaseRegOffsetBytes / 16)
3226 if (BaseRegOffsetBytes == 0)
3228 BaseRegOffsetBytes += InstrSize;
3242 :
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3243 Register SizeReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3247 int64_t LoopSize =
Size;
3250 if (FrameRegUpdate && *FrameRegUpdate)
3251 LoopSize -= LoopSize % 32;
3253 TII->get(ZeroData ? AArch64::STZGloop_wback
3254 : AArch64::STGloop_wback))
3261 LoopI->
setFlags(FrameRegUpdateFlags);
3263 int64_t ExtraBaseRegUpdate =
3264 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3265 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3266 <<
", Size=" <<
Size
3267 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3268 <<
", FrameRegUpdate=" << FrameRegUpdate
3269 <<
", FrameRegOffset.getFixed()="
3270 << FrameRegOffset.
getFixed() <<
"\n");
3271 if (LoopSize <
Size) {
3275 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3276 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3277 "STG immediate out of range");
3279 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3286 }
else if (ExtraBaseRegUpdate) {
3288 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3289 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3292 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3305 int64_t
Size, int64_t *TotalOffset) {
3307 if ((
MI.getOpcode() == AArch64::ADDXri ||
3308 MI.getOpcode() == AArch64::SUBXri) &&
3309 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3311 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3312 if (
MI.getOpcode() == AArch64::SUBXri)
3323 const int64_t kMaxOffset = 4080 - 16;
3325 const int64_t kMinOffset = -4095;
3326 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3327 PostOffset % 16 == 0) {
3338 for (
auto &TS : TSE) {
3342 if (
MI->memoperands_empty()) {
3346 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3352 bool TryMergeSPUpdate) {
3353 if (TagStores.
empty())
3355 TagStoreInstr &FirstTagStore = TagStores[0];
3356 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3357 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3358 DL = TagStores[0].MI->getDebugLoc();
3362 *MF, FirstTagStore.Offset,
false ,
false ,
Reg,
3365 FrameRegUpdate = std::nullopt;
3367 mergeMemRefs(TagStores, CombinedMemRefs);
3370 dbgs() <<
"Replacing adjacent STG instructions:\n";
3371 for (
const auto &Instr : TagStores) {
3380 if (TagStores.
size() < 2)
3382 emitUnrolled(InsertI);
3385 int64_t TotalOffset = 0;
3386 if (TryMergeSPUpdate) {
3392 if (InsertI !=
MBB->
end() &&
3393 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3395 UpdateInstr = &*InsertI++;
3401 if (!UpdateInstr && TagStores.
size() < 2)
3405 FrameRegUpdate = TotalOffset;
3406 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3413 for (
auto &TS : TagStores)
3414 TS.MI->eraseFromParent();
3418 int64_t &
Size,
bool &ZeroData) {
3422 unsigned Opcode =
MI.getOpcode();
3423 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3424 Opcode == AArch64::STZ2Gi);
3426 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3427 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3429 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3432 Size =
MI.getOperand(2).getImm();
3436 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3438 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3443 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3447 16 *
MI.getOperand(2).getImm();
3467 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3473 constexpr int kScanLimit = 10;
3476 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3485 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3486 if (ZeroData != FirstZeroData)
3494 if (!
MI.isTransient())
3503 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3519 LiveRegs.addLiveOuts(*
MBB);
3524 LiveRegs.stepBackward(*
I);
3527 if (LiveRegs.contains(AArch64::NZCV))
3531 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3536 int64_t CurOffset = Instrs[0].Offset;
3537 for (
auto &Instr : Instrs) {
3538 if (CurOffset >
Instr.Offset)
3545 TagStoreEdit TSE(
MBB, FirstZeroData);
3546 std::optional<int64_t> EndOffset;
3547 for (
auto &Instr : Instrs) {
3548 if (EndOffset && *EndOffset !=
Instr.Offset) {
3550 TSE.emitCode(InsertI, TFI,
false);
3554 TSE.addInstruction(Instr);
3573 II = tryMergeAdjacentSTG(
II,
this, RS);
3580 shouldSignReturnAddressEverywhere(MF))
3589 bool IgnoreSPUpdates)
const {
3591 if (IgnoreSPUpdates) {
3594 FrameReg = AArch64::SP;
3604 FrameReg = AArch64::SP;
3629 bool IsValid =
false;
3631 int ObjectIndex = 0;
3633 int GroupIndex = -1;
3635 bool ObjectFirst =
false;
3638 bool GroupFirst =
false;
3643 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3647 SmallVector<int, 8> CurrentMembers;
3648 int NextGroupIndex = 0;
3649 std::vector<FrameObject> &Objects;
3652 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3653 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3654 void EndCurrentGroup() {
3655 if (CurrentMembers.
size() > 1) {
3660 for (
int Index : CurrentMembers) {
3661 Objects[
Index].GroupIndex = NextGroupIndex;
3667 CurrentMembers.clear();
3671bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3693 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3694 A.GroupIndex,
A.ObjectIndex) <
3695 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3696 B.GroupIndex,
B.ObjectIndex);
3707 std::vector<FrameObject> FrameObjects(MFI.getObjectIndexEnd());
3708 for (
auto &Obj : ObjectsToAllocate) {
3709 FrameObjects[Obj].IsValid =
true;
3710 FrameObjects[Obj].ObjectIndex = Obj;
3715 GroupBuilder GB(FrameObjects);
3716 for (
auto &
MBB : MF) {
3717 for (
auto &
MI :
MBB) {
3718 if (
MI.isDebugInstr())
3723 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3726 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3728 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3733 switch (
MI.getOpcode()) {
3734 case AArch64::STGloop:
3735 case AArch64::STZGloop:
3739 case AArch64::STZGi:
3740 case AArch64::ST2Gi:
3741 case AArch64::STZ2Gi:
3753 if (FI >= 0 && FI < MFI.getObjectIndexEnd() &&
3754 FrameObjects[FI].IsValid)
3762 GB.AddMember(TaggedFI);
3764 GB.EndCurrentGroup();
3767 GB.EndCurrentGroup();
3772 FrameObject::AccessHazard;
3774 for (
auto &Obj : FrameObjects)
3775 if (!Obj.Accesses ||
3776 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3777 Obj.Accesses = FrameObject::AccessGPR;
3786 FrameObjects[*TBPI].ObjectFirst =
true;
3787 FrameObjects[*TBPI].GroupFirst =
true;
3788 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3789 if (FirstGroupIndex >= 0)
3790 for (FrameObject &Object : FrameObjects)
3791 if (Object.GroupIndex == FirstGroupIndex)
3792 Object.GroupFirst =
true;
3798 for (
auto &Obj : FrameObjects) {
3802 ObjectsToAllocate[i++] = Obj.ObjectIndex;
3806 dbgs() <<
"Final frame order:\n";
3807 for (
auto &Obj : FrameObjects) {
3810 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
3811 if (Obj.ObjectFirst)
3812 dbgs() <<
", first";
3814 dbgs() <<
", group-first";
3825AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
3836 MF.
insert(MBBInsertPoint, LoopMBB);
3838 MF.
insert(MBBInsertPoint, ExitMBB);
3869 MBB.addSuccessor(LoopMBB);
3873 return ExitMBB->
begin();
3876void AArch64FrameLowering::inlineStackProbeFixed(
3881 const AArch64InstrInfo *
TII =
3883 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
3888 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
3889 int64_t NumBlocks = FrameSize / ProbeSize;
3890 int64_t ResidualSize = FrameSize % ProbeSize;
3892 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
3893 << NumBlocks <<
" blocks of " << ProbeSize
3894 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
3899 for (
int i = 0; i < NumBlocks; ++i) {
3905 EmitAsyncCFI && !HasFP, CFAOffset);
3914 }
else if (NumBlocks != 0) {
3920 EmitAsyncCFI && !HasFP, CFAOffset);
3922 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
3924 if (EmitAsyncCFI && !HasFP) {
3927 .buildDefCFARegister(AArch64::SP);
3931 if (ResidualSize != 0) {
3937 EmitAsyncCFI && !HasFP, CFAOffset);
3954 SmallVector<MachineInstr *, 4> ToReplace;
3955 for (MachineInstr &
MI :
MBB)
3956 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
3957 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
3960 for (MachineInstr *
MI : ToReplace) {
3961 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
3962 Register ScratchReg =
MI->getOperand(0).getReg();
3963 int64_t FrameSize =
MI->getOperand(1).getImm();
3965 MI->getOperand(3).getImm());
3966 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
3969 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
3970 "Stack probe pseudo-instruction expected");
3971 const AArch64InstrInfo *
TII =
3972 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
3973 Register TargetReg =
MI->getOperand(0).getReg();
3974 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
3976 MI->eraseFromParent();
3996 return std::make_tuple(
start(),
Idx) <
3997 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4027 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4028 if (
Offset.getScalable())
4029 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4040void AArch64FrameLowering::emitRemarks(
4043 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4048 const uint64_t HazardSize =
4051 if (HazardSize == 0)
4059 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4061 size_t NumFPLdSt = 0;
4062 size_t NumNonFPLdSt = 0;
4065 for (
const MachineBasicBlock &
MBB : MF) {
4066 for (
const MachineInstr &
MI :
MBB) {
4067 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4069 for (MachineMemOperand *MMO :
MI.memoperands()) {
4076 StackAccesses[ArrIdx].Idx = FrameIdx;
4077 StackAccesses[ArrIdx].Offset =
4086 if (
MI.getOpcode() != AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO &&
4087 MI.getOpcode() != AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO &&
4088 AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg())) {
4096 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4107 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4118 if (StackAccesses.front().isMixed())
4119 MixedObjects.push_back(&StackAccesses.front());
4121 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4123 const auto &
First = *It;
4124 const auto &Second = *(It + 1);
4126 if (Second.isMixed())
4127 MixedObjects.push_back(&Second);
4129 if ((
First.isSME() && Second.isCPU()) ||
4130 (
First.isCPU() && Second.isSME())) {
4131 uint64_t Distance =
static_cast<uint64_t
>(Second.start() -
First.end());
4132 if (Distance < HazardSize)
4137 auto EmitRemark = [&](llvm::StringRef Str) {
4139 auto R = MachineOptimizationRemarkAnalysis(
4140 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4141 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4145 for (
const auto &
P : HazardPairs)
4146 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4148 for (
const auto *Obj : MixedObjects)
4150 formatv(
"{0} accessed by both GP and FP instructions", *Obj).str());
unsigned const MachineRegisterInfo * MRI
static void getLiveRegsForEntryMBB(LivePhysRegs &LiveRegs, const MachineBasicBlock &MBB)
static Register tryScavengeRegister(LiveRegUnits const &UsedRegs, BitVector const &ScavengeableRegs, Register PreferredReg)
Attempts to scavenge a register from ScavengeableRegs given the used registers in UsedRegs.
static const unsigned DefaultSafeSPDisplacement
This is the biggest offset to the stack pointer we can encode in aarch64 instructions (without using ...
static bool isInPrologueOrEpilogue(const MachineInstr &MI)
static bool produceCompactUnwindFrame(const AArch64FrameLowering &, MachineFunction &MF)
static bool expandFillPPRFromZPRSlotPseudo(MachineBasicBlock &MBB, MachineInstr &MI, const TargetRegisterInfo &TRI, LiveRegUnits const &UsedRegs, ScavengeableRegs const &SR, MachineInstr *&LastPTrue, EmergencyStackSlots &SpillSlots)
Expands:
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 > 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 int64_t determineSVEStackObjectOffsets(MachineFrameInfo &MFI, int &MinCSFrameIndex, int &MaxCSFrameIndex, bool AssignOffsets)
static cl::opt< bool > OrderFrameObjects("aarch64-order-frame-objects", cl::desc("sort stack allocations"), cl::init(true), cl::Hidden)
static bool invalidateWindowsRegisterPairing(unsigned Reg1, unsigned Reg2, bool NeedsWinCFI, bool IsFirst, const TargetRegisterInfo *TRI)
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)
cl::opt< bool > EnableHomogeneousPrologEpilog("homogeneous-prolog-epilog", cl::Hidden, cl::desc("Emit homogeneous prologue and epilogue for the size " "optimization (default = off)"))
static bool expandSMEPPRToZPRSpillPseudos(MachineBasicBlock &MBB, const TargetRegisterInfo &TRI, ScavengeableRegs const &SR, EmergencyStackSlots &SpillSlots)
Expands all FILL_PPR_FROM_ZPR_SLOT_PSEUDO and SPILL_PPR_TO_ZPR_SLOT_PSEUDO operations within the Mach...
static bool isLikelyToHaveSVEStack(const AArch64FrameLowering &AFL, const MachineFunction &MF)
static bool invalidateRegisterPairing(unsigned Reg1, unsigned Reg2, bool UsesWinAAPCS, bool NeedsWinCFI, bool NeedsFrameRecord, bool IsFirst, const TargetRegisterInfo *TRI)
Returns true if Reg1 and Reg2 cannot be paired using a ldp/stp instruction.
unsigned findFreePredicateReg(BitVector &SavedRegs)
static unsigned getPrologueDeath(MachineFunction &MF, unsigned Reg)
static void expandSpillPPRToZPRSlotPseudo(MachineBasicBlock &MBB, MachineInstr &MI, const TargetRegisterInfo &TRI, LiveRegUnits const &UsedRegs, ScavengeableRegs const &SR, EmergencyStackSlots &SpillSlots)
Expands:
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)
static void propagateFrameFlags(MachineInstr &SourceMI, ArrayRef< MachineInstr * > MachineInstrs)
Propagates frame-setup/destroy flags from SourceMI to all instructions in MachineInstrs.
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.
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 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 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
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
StackOffset getSVEStackSize(const MachineFunction &MF) const
Returns the size of the entire SVE stackframe (calleesaves + spills).
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 resolveFrameOffsetReference(const MachineFunction &MF, int64_t ObjectOffset, bool isFixed, bool isSVE, Register &FrameReg, bool PreferFP, bool ForSimm) const
bool assignCalleeSavedSpillSlots(MachineFunction &MF, const TargetRegisterInfo *TRI, std::vector< CalleeSavedInfo > &CSI, unsigned &MinCSFrameIndex, unsigned &MaxCSFrameIndex) const override
assignCalleeSavedSpillSlots - Allows target to override spill slot assignment logic.
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...
void setSwiftAsyncContextFrameIdx(int FI)
unsigned getTailCallReservedStack() const
unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const
void setCalleeSaveBaseToFrameRecordOffset(int Offset)
bool hasStackProbing() const
unsigned getArgumentStackToRestore() const
int getCalleeSaveBaseToFrameRecordOffset() const
bool hasStreamingModeChanges() const
bool shouldSignReturnAddress(const MachineFunction &MF) const
void setPredicateRegForFillSpill(unsigned Reg)
int getStackHazardSlotIndex() const
uint64_t getStackSizeSVE() const
bool hasStackFrame() const
std::optional< int > getTaggedBasePointerIndex() const
SMEAttrs getSMEFnAttrs() const
uint64_t getLocalStackSize() const
bool needsDwarfUnwindInfo(const MachineFunction &MF) const
unsigned getVarArgsGPRSize() const
void setStackSizeSVE(uint64_t S)
bool hasSwiftAsyncContext() const
bool hasStackHazardSlotIndex() const
void setStackHazardSlotIndex(int Index)
void setStackHazardCSRSlotIndex(int Index)
unsigned getPredicateRegForFillSpill() const
bool hasCalculatedStackSizeSVE() const
unsigned getSVECalleeSavedStackSize() const
bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const
void setMinMaxSVECSFrameIndex(int Min, int Max)
bool hasCalleeSaveStackFreeSpace() const
static bool isTailCallReturnInst(const MachineInstr &MI)
Returns true if MI is one of the TCRETURN* instructions.
static bool isFpOrNEON(Register Reg)
Returns whether the physical register is FP or NEON.
void emitPrologue()
Emit the prologue.
bool isTargetWindows() const
const AArch64RegisterInfo * getRegisterInfo() const override
bool isNeonAvailable() const
Returns true if the target has NEON and the function at runtime is known to have NEON enabled (e....
const AArch64InstrInfo * getInstrInfo() const override
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
bool isSVEorStreamingSVEAvailable() const
Returns true if the target has access to either the full range of SVE instructions,...
bool isStreaming() const
Returns true if the function has a streaming body.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this functions.
unsigned getRedZoneSize(const Function &F) const
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
bool test(unsigned Idx) const
size_type count() const
count - Returns the number of bits which are set.
iterator_range< const_set_bits_iterator > set_bits() const
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...
A set of register units used to track register liveness.
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
LLVM_ABI void stepBackward(const MachineInstr &MI)
Updates liveness when stepping backwards over the instruction MI.
LLVM_ABI void addLiveOuts(const MachineBasicBlock &MBB)
Adds registers living out of block MBB.
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.
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...
int getStackProtectorIndex() const
Return the index for the stack protector object.
LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
LLVM_ABI uint64_t estimateStackSize(const MachineFunction &MF) const
Estimate and return the size of the stack frame.
void setStackID(int ObjectIdx, uint8_t ID)
bool isCalleeSavedInfoValid() const
Has the callee saved info been calculated yet?
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
bool isMaxCallFrameSizeComputed() const
bool hasStackMap() const
This method may be called any time after instruction selection is complete to determine if there is a...
const std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const
Returns a reference to call saved info vector for the current function.
unsigned getNumObjects() const
Return the number of objects.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
bool hasStackProtectorIndex() const
bool hasStackObjects() const
Return true if there are any stack objects in this function.
uint8_t getStackID(int ObjectIdx) const
unsigned getNumFixedObjects() const
Return the number of fixed objects.
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 & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
void setFlags(unsigned flags)
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI void moveBefore(MachineInstr *MovePos)
Move the instruction before MovePos.
A description of a memory reference used in the backend.
const PseudoSourceValue * getPseudoValue() const
@ 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.
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI bool isLiveIn(Register Reg) const
LLVM_ABI const MCPhysReg * getCalleeSavedRegs() const
Returns list of callee saved registers.
LLVM_ABI bool isPhysRegUsed(MCRegister PhysReg, bool SkipRegMaskTest=false) const
Return true if the specified register is modified or read in this function.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Pass interface - Implemented by all 'passes'.
void enterBasicBlockEnd(MachineBasicBlock &MBB)
Start tracking liveness from the end of basic block MBB.
Register FindUnusedReg(const TargetRegisterClass *RC) const
Find an unused register of the specified register class.
void backward()
Update internal register state and move MBB iterator backwards.
void addScavengingFrameIndex(int FI)
Add a scavenging frame index.
Wrapper class representing virtual and physical registers.
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.
TargetInstrInfo - Interface to description of machine instruction set.
Primary interface to the complete machine description for the target machine.
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
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.
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
Triple - Helper class for working with autoconf configuration names.
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, unsigned Imm)
getArithExtendImm - Encode the extend type and shift amount for an arithmetic instruction: imm: 3-bit...
const unsigned StackProbeMaxLoopUnroll
Maximum number of iterations to unroll for a constant size probing loop.
const unsigned StackProbeMaxUnprobedStack
Maximum allowed number of unprobed bytes above SP at an ABI boundary.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ AArch64_SVE_VectorCall
Used between AArch64 SVE functions.
@ PreserveMost
Used for runtime calls that preserves most registers.
@ CXX_FAST_TLS
Used for access functions.
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
@ PreserveAll
Used for runtime calls that preserves (almost) all registers.
@ 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 ...
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Define
Register definition.
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.
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
@ AArch64FrameOffsetCannotUpdate
Offset cannot apply.
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)
FunctionAddr VTableAddr Count
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.
unsigned getDefRegState(bool B)
unsigned getKillRegState(bool B)
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
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...
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
void fullyRecomputeLiveIns(ArrayRef< MachineBasicBlock * > MBBs)
Convenience function for recomputing live-in's for a set of MBBs until the computation converges.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Emergency stack slots for expanding SPILL_PPR_TO_ZPR_SLOT_PSEUDO and FILL_PPR_FROM_ZPR_SLOT_PSEUDO.
std::optional< int > PPRSpillFI
std::optional< int > GPRSpillFI
std::optional< int > ZPRSpillFI
Registers available for scavenging (ZPR, PPR3b, GPR).
RAII helper class for scavenging or spilling a register.
Register operator*() const
ScopedScavengeOrSpill(ScopedScavengeOrSpill &&)=delete
ScopedScavengeOrSpill(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SpillCandidate, const TargetRegisterClass &RC, LiveRegUnits const &UsedRegs, BitVector const &AllocatableRegs, std::optional< int > *MaybeSpillFI, Register PreferredReg=AArch64::NoRegister)
Register freeRegister() const
Returns the free register (found from scavenging or spilling a register).
ScopedScavengeOrSpill(const ScopedScavengeOrSpill &)=delete
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.
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 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