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;
351 AArch64::PPRRegClass) == 16;
395bool AArch64FrameLowering::homogeneousPrologEpilog(
417 if (Exit && getArgumentStackToRestore(MF, *Exit))
420 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
428 unsigned NumGPRs = 0;
429 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
431 if (
Reg == AArch64::LR) {
432 assert(CSRegs[
I + 1] == AArch64::FP);
433 if (NumGPRs % 2 != 0)
445bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
464 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
465 MI.getOpcode() == AArch64::ADDXri ||
466 MI.getOpcode() == AArch64::ADDSXri)
491 bool IsWin64,
bool IsFunclet)
const {
493 "Tail call reserved stack must be aligned to 16 bytes");
494 if (!IsWin64 || IsFunclet) {
499 Attribute::SwiftAsync))
513 int FrameIndex =
H.CatchObj.FrameIndex;
514 if ((FrameIndex != INT_MAX) &&
515 CatchObjFrameIndices.
insert(FrameIndex)) {
516 FixedObjectSize =
alignTo(FixedObjectSize,
523 FixedObjectSize += 8;
525 return alignTo(FixedObjectSize, 16);
536 const unsigned RedZoneSize =
549 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
553 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
574 RegInfo->hasStackRealignment(MF))
617 const Triple &TT = TM.getTargetTriple();
621 if (TT.isOSDarwin() || TT.isOSWindows())
629 if (TM.Options.FramePointerIsReserved(MF))
659 unsigned Opc =
I->getOpcode();
660 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
661 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
664 int64_t Amount =
I->getOperand(0).getImm();
672 if (CalleePopAmount == 0) {
683 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
694 "non-reserved call frame without var sized objects?");
703 }
else if (CalleePopAmount != 0) {
706 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
718 const auto &
TRI = *Subtarget.getRegisterInfo();
724 CFIBuilder.buildDefCFA(AArch64::SP, 0);
727 if (MFI.shouldSignReturnAddress(MF))
728 MFI.branchProtectionPAuthLR() ? CFIBuilder.buildNegateRAStateWithPC()
729 : CFIBuilder.buildNegateRAState();
732 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
733 CFIBuilder.buildSameValue(AArch64::X18);
736 const std::vector<CalleeSavedInfo> &CSI =
738 for (
const auto &Info : CSI) {
740 if (!
TRI.regNeedsCFI(Reg, Reg))
742 CFIBuilder.buildSameValue(Reg);
755 case AArch64::W##n: \
756 case AArch64::X##n: \
781 case AArch64::B##n: \
782 case AArch64::H##n: \
783 case AArch64::S##n: \
784 case AArch64::D##n: \
785 case AArch64::Q##n: \
786 return HasSVE ? AArch64::Z##n : AArch64::Q##n
823void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
834 const AArch64Subtarget &STI = MF.
getSubtarget<AArch64Subtarget>();
837 BitVector GPRsToZero(
TRI.getNumRegs());
838 BitVector FPRsToZero(
TRI.getNumRegs());
841 if (
TRI.isGeneralPurposeRegister(MF,
Reg)) {
844 GPRsToZero.set(XReg);
848 FPRsToZero.set(XReg);
855 for (MCRegister
Reg : GPRsToZero.set_bits())
859 for (MCRegister
Reg : FPRsToZero.set_bits())
863 for (MCRegister PReg :
864 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
865 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
866 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
868 if (RegsToZero[PReg])
874bool AArch64FrameLowering::windowsRequiresStackProbe(
876 const AArch64Subtarget &Subtarget = MF.
getSubtarget<AArch64Subtarget>();
877 const AArch64FunctionInfo &MFI = *MF.
getInfo<AArch64FunctionInfo>();
881 StackSizeInBytes >= uint64_t(MFI.getStackProbeSize());
890 for (
unsigned i = 0; CSRegs[i]; ++i)
896 bool HasCall)
const {
906 const AArch64Subtarget &Subtarget = MF->
getSubtarget<AArch64Subtarget>();
908 LivePhysRegs LiveRegs(
TRI);
911 LiveRegs.addReg(AArch64::X16);
912 LiveRegs.addReg(AArch64::X17);
913 LiveRegs.addReg(AArch64::X18);
918 if (LiveRegs.available(
MRI, AArch64::X9))
921 for (
unsigned Reg : AArch64::GPR64RegClass) {
922 if (LiveRegs.available(
MRI,
Reg))
925 return AArch64::NoRegister;
952 MBB.isLiveIn(AArch64::NZCV))
956 if (findScratchNonCalleeSaveRegister(TmpMBB) == AArch64::NoRegister)
962 windowsRequiresStackProbe(*MF, std::numeric_limits<uint64_t>::max()))
963 if (findScratchNonCalleeSaveRegister(TmpMBB,
true) == AArch64::NoRegister)
972 F.needsUnwindTableEntry();
975bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
983 return SignReturnAddressAll;
992 unsigned Opc =
MBBI->getOpcode();
996 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
997 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1005 case AArch64::STR_ZXI:
1006 case AArch64::LDR_ZXI: {
1007 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1014 case AArch64::STR_PXI:
1015 case AArch64::LDR_PXI: {
1016 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1023 case AArch64::LDPDpost:
1026 case AArch64::STPDpre: {
1027 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1028 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1029 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1036 case AArch64::LDPXpost:
1039 case AArch64::STPXpre: {
1042 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1043 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1047 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1048 .
addImm(RegInfo->getSEHRegNum(Reg0))
1049 .
addImm(RegInfo->getSEHRegNum(Reg1))
1054 case AArch64::LDRDpost:
1057 case AArch64::STRDpre: {
1058 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1059 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1065 case AArch64::LDRXpost:
1068 case AArch64::STRXpre: {
1069 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1076 case AArch64::STPDi:
1077 case AArch64::LDPDi: {
1078 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1079 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1087 case AArch64::STPXi:
1088 case AArch64::LDPXi: {
1091 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1097 .
addImm(RegInfo->getSEHRegNum(Reg0))
1098 .
addImm(RegInfo->getSEHRegNum(Reg1))
1103 case AArch64::STRXui:
1104 case AArch64::LDRXui: {
1105 int Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1112 case AArch64::STRDui:
1113 case AArch64::LDRDui: {
1114 unsigned Reg = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1121 case AArch64::STPQi:
1122 case AArch64::LDPQi: {
1123 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1124 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1125 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1132 case AArch64::LDPQpost:
1135 case AArch64::STPQpre: {
1136 unsigned Reg0 = RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1137 unsigned Reg1 = RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1138 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1157 if (ST.isTargetDarwin())
1183 DL =
MBBI->getDebugLoc();
1190 EmitSignRA(MF.
front());
1192 if (
MBB.isEHFuncletEntry())
1194 if (
MBB.isReturnBlock())
1250 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1255 if (MFI.isVariableSizedObjectIndex(FI)) {
1264 bool FPAfterSVECalleeSaves =
1266 if (MFI.hasScalableStackID(FI)) {
1267 if (FPAfterSVECalleeSaves &&
1270 "split-sve-objects not supported with FPAfterSVECalleeSaves");
1278 AccessOffset = -PPRStackSize;
1279 return AccessOffset +
1284 bool IsFixed = MFI.isFixedObjectIndex(FI);
1289 if (!IsFixed && !IsCSR) {
1290 ScalableOffset = -SVEStackSize;
1291 }
else if (FPAfterSVECalleeSaves && IsCSR) {
1306 int64_t ObjectOffset)
const {
1310 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
1311 unsigned FixedObject =
1312 getFixedObjectSize(MF, AFI, IsWin64,
false);
1320 int64_t ObjectOffset)
const {
1331 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
1332 ? getFPOffset(MF, ObjectOffset).getFixed()
1333 : getStackOffset(MF, ObjectOffset).getFixed();
1338 bool ForSimm)
const {
1340 int64_t ObjectOffset = MFI.getObjectOffset(FI);
1341 bool isFixed = MFI.isFixedObjectIndex(FI);
1344 FrameReg, PreferFP, ForSimm);
1350 bool ForSimm)
const {
1357 int64_t FPOffset = getFPOffset(MF, ObjectOffset).getFixed();
1358 int64_t
Offset = getStackOffset(MF, ObjectOffset).getFixed();
1361 bool isSVE = MFI.isScalableStackID(StackID);
1365 StackOffset SVEStackSize = ZPRStackSize + PPRStackSize;
1376 PreferFP &= !SVEStackSize;
1384 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
1388 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
1390 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
1395 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
1396 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
1398 if (FPOffset >= 0) {
1402 }
else if (MFI.hasVarSizedObjects()) {
1406 bool CanUseBP = RegInfo->hasBasePointer(MF);
1407 if (FPOffsetFits && CanUseBP)
1414 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
1421 "Funclets should only be present on Win64");
1425 if (FPOffsetFits && PreferFP)
1432 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
1433 "In the presence of dynamic stack pointer realignment, "
1434 "non-argument/CSR objects cannot be accessed through the frame pointer");
1436 bool FPAfterSVECalleeSaves =
1452 FPOffset -= PPRStackSize;
1454 SPOffset -= PPRStackSize;
1459 if (FPAfterSVECalleeSaves) {
1470 RegInfo->hasStackRealignment(MF))) {
1471 FrameReg = RegInfo->getFrameRegister(MF);
1474 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
1481 if (FPAfterSVECalleeSaves) {
1488 SVEAreaOffset = SVECalleeSavedStack;
1490 SVEAreaOffset = SVECalleeSavedStack - SVEStackSize;
1493 SVEAreaOffset = SVEStackSize;
1495 SVEAreaOffset = SVEStackSize - SVECalleeSavedStack;
1498 if (UseFP && !(isFixed || isCSR))
1499 SVEAreaOffset = -SVEStackSize;
1500 if (!UseFP && (isFixed || isCSR))
1501 SVEAreaOffset = SVEStackSize;
1505 FrameReg = RegInfo->getFrameRegister(MF);
1510 if (RegInfo->hasBasePointer(MF))
1511 FrameReg = RegInfo->getBaseRegister();
1513 assert(!MFI.hasVarSizedObjects() &&
1514 "Can't use SP when we have var sized objects.");
1515 FrameReg = AArch64::SP;
1543 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
1549 bool NeedsWinCFI,
bool IsFirst,
1558 if (Reg2 == AArch64::FP)
1562 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
1569 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
1570 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR && !IsFirst)
1580 bool UsesWinAAPCS,
bool NeedsWinCFI,
1581 bool NeedsFrameRecord,
bool IsFirst,
1589 if (NeedsFrameRecord)
1590 return Reg2 == AArch64::LR;
1598 unsigned Reg1 = AArch64::NoRegister;
1599 unsigned Reg2 = AArch64::NoRegister;
1602 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
1603 const TargetRegisterClass *RC;
1605 RegPairInfo() =
default;
1607 bool isPaired()
const {
return Reg2 != AArch64::NoRegister; }
1609 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
1615 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
1616 if (SavedRegs.
test(PReg)) {
1617 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
1621 return AArch64::NoRegister;
1631 bool IsLocallyStreaming =
1637 return Subtarget.hasSVE2p1() ||
1638 (Subtarget.hasSME2() &&
1639 (!IsLocallyStreaming && Subtarget.
isStreaming()));
1647 bool NeedsFrameRecord) {
1665 (
Count & 1) == 0) &&
1666 "Odd number of callee-saved regs to spill!");
1668 int StackFillDir = -1;
1670 unsigned FirstReg = 0;
1678 FirstReg =
Count - 1;
1683 int ZPRByteOffset = 0;
1684 int PPRByteOffset = 0;
1689 }
else if (!FPAfterSVECalleeSaves) {
1701 for (
unsigned i = FirstReg; i <
Count; i += RegInc) {
1703 RPI.Reg1 = CSI[i].getReg();
1705 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
1706 RPI.Type = RegPairInfo::GPR;
1707 RPI.RC = &AArch64::GPR64RegClass;
1708 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
1709 RPI.Type = RegPairInfo::FPR64;
1710 RPI.RC = &AArch64::FPR64RegClass;
1711 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
1712 RPI.Type = RegPairInfo::FPR128;
1713 RPI.RC = &AArch64::FPR128RegClass;
1714 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
1715 RPI.Type = RegPairInfo::ZPR;
1716 RPI.RC = &AArch64::ZPRRegClass;
1717 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
1718 RPI.Type = RegPairInfo::PPR;
1719 RPI.RC = &AArch64::PPRRegClass;
1720 }
else if (RPI.Reg1 == AArch64::VG) {
1721 RPI.Type = RegPairInfo::VG;
1722 RPI.RC = &AArch64::FIXED_REGSRegClass;
1727 int &ScalableByteOffset = RPI.Type == RegPairInfo::PPR && SplitPPRs
1732 if (HasCSHazardPadding &&
1735 ByteOffset += StackFillDir * StackHazardSize;
1738 int Scale =
TRI->getSpillSize(*RPI.RC);
1740 if (
unsigned(i + RegInc) <
Count && !HasCSHazardPadding) {
1741 MCRegister NextReg = CSI[i + RegInc].getReg();
1742 bool IsFirst = i == FirstReg;
1744 case RegPairInfo::GPR:
1745 if (AArch64::GPR64RegClass.
contains(NextReg) &&
1747 NeedsWinCFI, NeedsFrameRecord, IsFirst,
1751 case RegPairInfo::FPR64:
1752 if (AArch64::FPR64RegClass.
contains(NextReg) &&
1757 case RegPairInfo::FPR128:
1758 if (AArch64::FPR128RegClass.
contains(NextReg))
1761 case RegPairInfo::PPR:
1763 case RegPairInfo::ZPR:
1765 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
1768 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
1773 case RegPairInfo::VG:
1784 assert((!RPI.isPaired() ||
1785 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
1786 "Out of order callee saved regs!");
1788 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
1789 RPI.Reg1 == AArch64::LR) &&
1790 "FrameRecord must be allocated together with LR");
1793 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
1794 RPI.Reg2 == AArch64::LR) &&
1795 "FrameRecord must be allocated together with LR");
1803 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
1804 RPI.Reg1 + 1 == RPI.Reg2))) &&
1805 "Callee-save registers not saved as adjacent register pair!");
1807 RPI.FrameIdx = CSI[i].getFrameIdx();
1810 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
1814 if (RPI.isScalable() && ScalableByteOffset % Scale != 0) {
1815 ScalableByteOffset =
alignTo(ScalableByteOffset, Scale);
1818 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1819 assert(OffsetPre % Scale == 0);
1821 if (RPI.isScalable())
1822 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1824 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
1829 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1830 (IsWindows && RPI.Reg2 == AArch64::LR)))
1831 ByteOffset += StackFillDir * 8;
1835 if (NeedGapToAlignStack && !NeedsWinCFI && !RPI.isScalable() &&
1836 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
1837 ByteOffset % 16 != 0) {
1838 ByteOffset += 8 * StackFillDir;
1844 NeedGapToAlignStack =
false;
1847 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
1848 assert(OffsetPost % Scale == 0);
1851 int Offset = NeedsWinCFI ? OffsetPre : OffsetPost;
1856 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
1857 (IsWindows && RPI.Reg2 == AArch64::LR)))
1859 RPI.Offset =
Offset / Scale;
1861 assert((!RPI.isPaired() ||
1862 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
1863 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
1864 "Offset out of bounds for LDP/STP immediate");
1866 auto isFrameRecord = [&] {
1868 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
1869 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
1877 return i > 0 && RPI.Reg1 == AArch64::FP &&
1878 CSI[i - 1].getReg() == AArch64::LR;
1883 if (NeedsFrameRecord && isFrameRecord())
1900 std::reverse(RegPairs.
begin(), RegPairs.
end());
1919 MRI.freezeReservedRegs();
1921 if (homogeneousPrologEpilog(MF)) {
1925 for (
auto &RPI : RegPairs) {
1930 if (!
MRI.isReserved(RPI.Reg1))
1931 MBB.addLiveIn(RPI.Reg1);
1932 if (RPI.isPaired() && !
MRI.isReserved(RPI.Reg2))
1933 MBB.addLiveIn(RPI.Reg2);
1937 bool PTrueCreated =
false;
1939 unsigned Reg1 = RPI.Reg1;
1940 unsigned Reg2 = RPI.Reg2;
1953 unsigned Size =
TRI->getSpillSize(*RPI.RC);
1954 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
1956 case RegPairInfo::GPR:
1957 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
1959 case RegPairInfo::FPR64:
1960 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
1962 case RegPairInfo::FPR128:
1963 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
1965 case RegPairInfo::ZPR:
1966 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
1968 case RegPairInfo::PPR:
1970 Size == 16 ? AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO : AArch64::STR_PXI;
1972 case RegPairInfo::VG:
1973 StrOpc = AArch64::STRXui;
1977 unsigned X0Scratch = AArch64::NoRegister;
1979 if (X0Scratch != AArch64::NoRegister)
1985 if (Reg1 == AArch64::VG) {
1987 Reg1 = findScratchNonCalleeSaveRegister(&
MBB,
true);
1988 assert(Reg1 != AArch64::NoRegister);
1998 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
1999 AArch64::X0, LiveIn.PhysReg);
2007 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
2009 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
2021 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2022 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
2025 assert((!NeedsWinCFI || !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
2026 "Windows unwdinding requires a consecutive (FP,LR) pair");
2030 unsigned FrameIdxReg1 = RPI.FrameIdx;
2031 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2032 if (NeedsWinCFI && RPI.isPaired()) {
2037 if (RPI.isPaired() && RPI.isScalable()) {
2043 "Expects SVE2.1 or SME2 target and a predicate register");
2044#ifdef EXPENSIVE_CHECKS
2045 auto IsPPR = [](
const RegPairInfo &c) {
2046 return c.Reg1 == RegPairInfo::PPR;
2048 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
2049 auto IsZPR = [](
const RegPairInfo &c) {
2050 return c.Type == RegPairInfo::ZPR;
2052 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
2053 assert(!(PPRBegin < ZPRBegin) &&
2054 "Expected callee save predicate to be handled first");
2056 if (!PTrueCreated) {
2057 PTrueCreated =
true;
2062 if (!
MRI.isReserved(Reg1))
2063 MBB.addLiveIn(Reg1);
2064 if (!
MRI.isReserved(Reg2))
2065 MBB.addLiveIn(Reg2);
2066 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
2082 if (!
MRI.isReserved(Reg1))
2083 MBB.addLiveIn(Reg1);
2084 if (RPI.isPaired()) {
2085 if (!
MRI.isReserved(Reg2))
2086 MBB.addLiveIn(Reg2);
2105 if (RPI.Type == RegPairInfo::ZPR) {
2109 }
else if (RPI.Type == RegPairInfo::PPR) {
2128 DL =
MBBI->getDebugLoc();
2131 if (homogeneousPrologEpilog(MF, &
MBB)) {
2134 for (
auto &RPI : RegPairs) {
2142 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
2144 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
2145 std::reverse(PPRBegin, PPREnd);
2146 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
2148 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
2149 std::reverse(ZPRBegin, ZPREnd);
2151 bool PTrueCreated =
false;
2152 for (
const RegPairInfo &RPI : RegPairs) {
2153 unsigned Reg1 = RPI.Reg1;
2154 unsigned Reg2 = RPI.Reg2;
2165 unsigned Size =
TRI->getSpillSize(*RPI.RC);
2166 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
2168 case RegPairInfo::GPR:
2169 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
2171 case RegPairInfo::FPR64:
2172 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
2174 case RegPairInfo::FPR128:
2175 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
2177 case RegPairInfo::ZPR:
2178 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
2180 case RegPairInfo::PPR:
2181 LdrOpc =
Size == 16 ? AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO
2184 case RegPairInfo::VG:
2189 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
2190 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
2196 unsigned FrameIdxReg1 = RPI.FrameIdx;
2197 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
2198 if (NeedsWinCFI && RPI.isPaired()) {
2204 if (RPI.isPaired() && RPI.isScalable()) {
2209 "Expects SVE2.1 or SME2 target and a predicate register");
2210#ifdef EXPENSIVE_CHECKS
2211 assert(!(PPRBegin < ZPRBegin) &&
2212 "Expected callee save predicate to be handled first");
2214 if (!PTrueCreated) {
2215 PTrueCreated =
true;
2220 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
2237 if (RPI.isPaired()) {
2264 return std::optional<int>(PSV->getFrameIndex());
2275 return std::nullopt;
2281 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
2282 return std::nullopt;
2289 return MI.getOpcode() != AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO &&
2290 MI.getOpcode() != AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO &&
2291 AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg());
2297void AArch64FrameLowering::determineStackHazardSlot(
2300 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
2301 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
2315 return AArch64::FPR64RegClass.contains(Reg) ||
2316 AArch64::FPR128RegClass.contains(Reg) ||
2317 AArch64::ZPRRegClass.contains(Reg);
2320 return AArch64::PPRRegClass.contains(Reg);
2322 bool HasFPRStackObjects =
false;
2323 bool HasPPRStackObjects =
false;
2325 enum SlotType : uint8_t {
2336 for (
auto &
MBB : MF) {
2337 for (
auto &
MI :
MBB) {
2339 if (!FI || FI < 0 || FI >
int(SlotTypes.size()))
2346 ? SlotType::ZPRorFPR
2352 for (
int FI = 0; FI < int(SlotTypes.size()); ++FI) {
2353 HasFPRStackObjects |= SlotTypes[FI] == SlotType::ZPRorFPR;
2356 if (SlotTypes[FI] == SlotType::PPR) {
2358 HasPPRStackObjects =
true;
2363 if (HasFPRCSRs || HasFPRStackObjects) {
2366 << StackHazardSize <<
"\n");
2373 if (!HasPPRCSRs && !HasPPRStackObjects) {
2375 dbgs() <<
"Not using SplitSVEObjects as no PPRs are on the stack\n");
2379 if (!HasFPRCSRs && !HasFPRStackObjects) {
2382 <<
"Not using SplitSVEObjects as no FPRs or ZPRs are on the stack\n");
2386 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
2388 LLVM_DEBUG(
dbgs() <<
"SplitSVEObjects is not supported with variable "
2389 "sized objects or realignment\n");
2395 "-aarch64-enable-zpr-predicate-spills");
2403 MF.getFunction().getCallingConv())) {
2405 dbgs() <<
"Calling convention is not supported with SplitSVEObjects");
2409 [[maybe_unused]]
const AArch64Subtarget &Subtarget =
2410 MF.getSubtarget<AArch64Subtarget>();
2412 "Expected SVE to be available for PPRs");
2417 BitVector FPRZRegs(SavedRegs.
size());
2418 for (
size_t Reg = 0,
E = SavedRegs.
size(); HasFPRCSRs &&
Reg <
E; ++
Reg) {
2419 BitVector::reference RegBit = SavedRegs[
Reg];
2422 unsigned SubRegIdx = 0;
2424 SubRegIdx = AArch64::dsub;
2426 SubRegIdx = AArch64::zsub;
2433 TRI->getMatchingSuperReg(
Reg, SubRegIdx, &AArch64::ZPRRegClass);
2436 SavedRegs |= FPRZRegs;
2457 unsigned UnspilledCSGPR = AArch64::NoRegister;
2458 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
2463 unsigned BasePointerReg = RegInfo->hasBasePointer(MF)
2464 ? RegInfo->getBaseRegister()
2467 unsigned ExtraCSSpill = 0;
2468 bool HasUnpairedGPR64 =
false;
2469 bool HasPairZReg =
false;
2470 BitVector UserReservedRegs = RegInfo->getUserReservedRegs(MF);
2471 BitVector ReservedRegs = RegInfo->getReservedRegs(MF);
2474 for (
unsigned i = 0; CSRegs[i]; ++i) {
2475 const unsigned Reg = CSRegs[i];
2478 if (Reg == BasePointerReg)
2483 if (UserReservedRegs[Reg]) {
2484 SavedRegs.
reset(Reg);
2488 bool RegUsed = SavedRegs.
test(Reg);
2489 unsigned PairedReg = AArch64::NoRegister;
2490 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
2491 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
2492 AArch64::FPR128RegClass.
contains(Reg)) {
2495 if (HasUnpairedGPR64)
2496 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
2498 PairedReg = CSRegs[i ^ 1];
2505 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
2506 PairedReg = AArch64::NoRegister;
2507 HasUnpairedGPR64 =
true;
2509 assert(PairedReg == AArch64::NoRegister ||
2510 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
2511 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
2512 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
2515 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
2516 UnspilledCSGPR = Reg;
2517 UnspilledCSGPRPaired = PairedReg;
2525 if (RegInfo->getSpillSize(AArch64::PPRRegClass) == 16 &&
2526 AArch64::PPR_p8to15RegClass.contains(Reg)) {
2527 SavedRegs.
set(AArch64::P4);
2533 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
2534 !SavedRegs.
test(PairedReg)) {
2535 SavedRegs.
set(PairedReg);
2536 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
2537 !ReservedRegs[PairedReg])
2538 ExtraCSSpill = PairedReg;
2541 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
2542 SavedRegs.
test(CSRegs[i ^ 1]));
2550 if (PnReg != AArch64::NoRegister)
2556 SavedRegs.
set(AArch64::P8);
2561 "Predicate cannot be a reserved register");
2571 SavedRegs.
set(AArch64::X18);
2577 determineStackHazardSlot(MF, SavedRegs);
2580 unsigned CSStackSize = 0;
2581 unsigned ZPRCSStackSize = 0;
2582 unsigned PPRCSStackSize = 0;
2584 for (
unsigned Reg : SavedRegs.
set_bits()) {
2585 auto *RC =
TRI->getMinimalPhysRegClass(Reg);
2586 assert(RC &&
"expected register class!");
2587 auto SpillSize =
TRI->getSpillSize(*RC);
2588 bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
2589 bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
2591 ZPRCSStackSize += SpillSize;
2593 PPRCSStackSize += SpillSize;
2595 CSStackSize += SpillSize;
2601 unsigned NumSavedRegs = SavedRegs.
count();
2614 SavedRegs.
set(AArch64::LR);
2619 windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) {
2620 SavedRegs.
set(AArch64::FP);
2621 SavedRegs.
set(AArch64::LR);
2625 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
2626 for (
unsigned Reg : SavedRegs.
set_bits())
2632 auto [ZPRLocalStackSize, PPRLocalStackSize] =
2634 uint64_t SVELocals = ZPRLocalStackSize + PPRLocalStackSize;
2636 alignTo(ZPRCSStackSize + PPRCSStackSize + SVELocals, 16);
2637 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
2646 int64_t CalleeStackUsed = 0;
2649 if (FixedOff > CalleeStackUsed)
2650 CalleeStackUsed = FixedOff;
2654 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
2655 CalleeStackUsed) > EstimatedStackSizeLimit;
2656 if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
2666 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
2668 <<
" to get a scratch register.\n");
2669 SavedRegs.
set(UnspilledCSGPR);
2670 ExtraCSSpill = UnspilledCSGPR;
2675 if (producePairRegisters(MF)) {
2676 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
2679 SavedRegs.
reset(UnspilledCSGPR);
2680 ExtraCSSpill = AArch64::NoRegister;
2683 SavedRegs.
set(UnspilledCSGPRPaired);
2692 unsigned Size =
TRI->getSpillSize(RC);
2693 Align Alignment =
TRI->getSpillAlign(RC);
2696 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
2697 <<
" as the emergency spill slot.\n");
2702 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
2711 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
2715 "Should not invalidate callee saved info");
2726 std::vector<CalleeSavedInfo> &CSI,
unsigned &MinCSFrameIndex,
2727 unsigned &MaxCSFrameIndex)
const {
2736 std::reverse(CSI.begin(), CSI.end());
2750 if ((
unsigned)FrameIdx < MinCSFrameIndex)
2751 MinCSFrameIndex = FrameIdx;
2752 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
2753 MaxCSFrameIndex = FrameIdx;
2760 find_if(CSI, [](
auto &Info) {
return Info.getReg() == AArch64::LR; });
2761 if (It != CSI.end())
2762 CSI.insert(It, VGInfo);
2764 CSI.push_back(VGInfo);
2768 int HazardSlotIndex = std::numeric_limits<int>::max();
2769 for (
auto &CS : CSI) {
2777 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
2778 "Unexpected register order for hazard slot");
2780 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2783 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
2784 MinCSFrameIndex = HazardSlotIndex;
2785 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
2786 MaxCSFrameIndex = HazardSlotIndex;
2789 unsigned Size = RegInfo->getSpillSize(*RC);
2790 Align Alignment(RegInfo->getSpillAlign(*RC));
2792 CS.setFrameIdx(FrameIdx);
2794 if ((
unsigned)FrameIdx < MinCSFrameIndex)
2795 MinCSFrameIndex = FrameIdx;
2796 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
2797 MaxCSFrameIndex = FrameIdx;
2801 Reg == AArch64::FP) {
2804 if ((
unsigned)FrameIdx < MinCSFrameIndex)
2805 MinCSFrameIndex = FrameIdx;
2806 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
2807 MaxCSFrameIndex = FrameIdx;
2814 HazardSlotIndex == std::numeric_limits<int>::max()) {
2816 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
2819 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
2820 MinCSFrameIndex = HazardSlotIndex;
2821 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
2822 MaxCSFrameIndex = HazardSlotIndex;
2846 int &Min,
int &Max) {
2847 Min = std::numeric_limits<int>::max();
2848 Max = std::numeric_limits<int>::min();
2854 for (
auto &CS : CSI) {
2855 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
2856 AArch64::PPRRegClass.contains(CS.getReg())) {
2857 assert((Max == std::numeric_limits<int>::min() ||
2858 Max + 1 == CS.getFrameIdx()) &&
2859 "SVE CalleeSaves are not consecutive");
2860 Min = std::min(Min, CS.getFrameIdx());
2861 Max = std::max(Max, CS.getFrameIdx());
2864 return Min != std::numeric_limits<int>::max();
2877 uint64_t &ZPRStackTop = SVEStack.ZPRStackSize;
2885 "SVE vectors should never be passed on the stack by value, only by "
2889 auto AllocateObject = [&](
int FI) {
2898 if (Alignment >
Align(16))
2900 "Alignment of scalable vectors > 16 bytes is not yet supported");
2903 StackTop =
alignTo(StackTop, Alignment);
2905 assert(StackTop < std::numeric_limits<int64_t>::max() &&
2906 "SVE StackTop far too large?!");
2908 int64_t
Offset = -int64_t(StackTop);
2916 int MinCSFrameIndex, MaxCSFrameIndex;
2918 for (
int FI = MinCSFrameIndex; FI <= MaxCSFrameIndex; ++FI)
2931 int StackProtectorFI = -1;
2935 ObjectsToAllocate.
push_back(StackProtectorFI);
2941 if (MaxCSFrameIndex >= FI && FI >= MinCSFrameIndex)
2952 for (
unsigned FI : ObjectsToAllocate)
2969 if (PreferredReg != AArch64::NoRegister && UsedRegs.
available(PreferredReg))
2970 return PreferredReg;
2975 return AArch64::NoRegister;
3007 std::optional<int> *MaybeSpillFI,
3008 Register PreferredReg = AArch64::NoRegister)
3010 *MF.getSubtarget().getInstrInfo())),
3011 TRI(*MF.getSubtarget().getRegisterInfo()) {
3013 if (FreeReg != AArch64::NoRegister)
3015 assert(MaybeSpillFI &&
"Expected emergency spill slot FI information "
3016 "(attempted to spill in prologue/epilogue?)");
3017 if (!MaybeSpillFI->has_value()) {
3020 TRI.getSpillAlign(RC));
3022 FreeReg = SpillCandidate;
3023 SpillFI = MaybeSpillFI->value();
3024 TII.storeRegToStackSlot(MBB, MBBI, FreeReg,
false, *SpillFI, &RC, &TRI,
3037 TII.loadRegFromStackSlot(MBB, MBBI, FreeReg, *SpillFI, &RC, &TRI,
3047 Register FreeReg = AArch64::NoRegister;
3048 std::optional<int> SpillFI;
3093 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
3100 .
add(
MI.getOperand(0))
3106 .
add(
MI.getOperand(1))
3136 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
3140 MF,
MBB,
MI, AArch64::P0, AArch64::PPR_3bRegClass, UsedRegs, SR.
PPR3bRegs,
3146 bool IsNZCVUsed = !UsedRegs.
available(AArch64::NZCV);
3147 std::optional<ScopedScavengeOrSpill> NZCVSaveReg;
3149 NZCVSaveReg.emplace(
3150 MF,
MBB,
MI, AArch64::X0, AArch64::GPR64RegClass, UsedRegs, SR.
GPRRegs,
3156 .
add(
MI.getOperand(1))
3164 .
addImm(AArch64SysReg::NZCV)
3188 .
addImm(AArch64SysReg::NZCV)
3189 .
addReg(NZCVSaveReg->freeRegister())
3205 bool HasPPRSpills =
false;
3209 switch (
MI.getOpcode()) {
3210 case AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO:
3213 LastPTrue =
nullptr;
3215 LastPTrue, SpillSlots);
3216 MI.eraseFromParent();
3218 case AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO:
3220 MI.eraseFromParent();
3223 LastPTrue =
nullptr;
3228 return HasPPRSpills;
3240 if (AFI->
hasStackFrame() &&
TRI.getSpillSize(AArch64::PPRRegClass) == 16) {
3241 auto ComputeScavengeableRegisters = [&](
unsigned RegClassID) {
3242 BitVector Regs =
TRI.getAllocatableSet(MF,
TRI.getRegClass(RegClassID));
3243 assert(Regs.
count() > 0 &&
"Expected scavengeable registers");
3248 SR.
ZPRRegs = ComputeScavengeableRegisters(AArch64::ZPRRegClassID);
3250 SR.
PPR3bRegs = ComputeScavengeableRegisters(AArch64::PPR_3bRegClassID);
3251 SR.
GPRRegs = ComputeScavengeableRegisters(AArch64::GPR64RegClassID);
3263 assert((
Pass == 0 || !HasPPRSpills) &&
"Did not expect PPR spills");
3273 "Upwards growing stack unsupported");
3285 int64_t CurrentOffset =
3289 int FrameIndex =
H.CatchObj.FrameIndex;
3290 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
3301 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
3302 assert(UnwindHelpOffset == getFixedObjectSize(MF, AFI,
true,
3304 "UnwindHelpOffset must be at the start of the fixed object area");
3320 assert(DstReg &&
"There must be a free register after frame setup");
3330struct TagStoreInstr {
3338 MachineFunction *MF;
3339 MachineBasicBlock *
MBB;
3340 MachineRegisterInfo *
MRI;
3349 StackOffset FrameRegOffset;
3353 std::optional<int64_t> FrameRegUpdate;
3355 unsigned FrameRegUpdateFlags;
3365 TagStoreEdit(MachineBasicBlock *
MBB,
bool ZeroData)
3366 :
MBB(
MBB), ZeroData(ZeroData) {
3372 void addInstruction(TagStoreInstr
I) {
3374 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
3375 "Non-adjacent tag store instructions.");
3378 void clear() { TagStores.
clear(); }
3383 const AArch64FrameLowering *TFI,
bool TryMergeSPUpdate);
3390 const int64_t kMinOffset = -256 * 16;
3391 const int64_t kMaxOffset = 255 * 16;
3394 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
3395 if (BaseRegOffsetBytes < kMinOffset ||
3396 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
3400 BaseRegOffsetBytes % 16 != 0) {
3401 Register ScratchReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3405 BaseRegOffsetBytes = 0;
3410 int64_t InstrSize = (
Size > 16) ? 32 : 16;
3413 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
3415 assert(BaseRegOffsetBytes % 16 == 0);
3419 .
addImm(BaseRegOffsetBytes / 16)
3423 if (BaseRegOffsetBytes == 0)
3425 BaseRegOffsetBytes += InstrSize;
3439 :
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3440 Register SizeReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
3444 int64_t LoopSize =
Size;
3447 if (FrameRegUpdate && *FrameRegUpdate)
3448 LoopSize -= LoopSize % 32;
3450 TII->get(ZeroData ? AArch64::STZGloop_wback
3451 : AArch64::STGloop_wback))
3458 LoopI->
setFlags(FrameRegUpdateFlags);
3460 int64_t ExtraBaseRegUpdate =
3461 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
3462 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
3463 <<
", Size=" <<
Size
3464 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
3465 <<
", FrameRegUpdate=" << FrameRegUpdate
3466 <<
", FrameRegOffset.getFixed()="
3467 << FrameRegOffset.
getFixed() <<
"\n");
3468 if (LoopSize <
Size) {
3472 int64_t STGOffset = ExtraBaseRegUpdate + 16;
3473 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
3474 "STG immediate out of range");
3476 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
3483 }
else if (ExtraBaseRegUpdate) {
3485 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
3486 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
3489 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
3502 int64_t
Size, int64_t *TotalOffset) {
3504 if ((
MI.getOpcode() == AArch64::ADDXri ||
3505 MI.getOpcode() == AArch64::SUBXri) &&
3506 MI.getOperand(0).getReg() ==
Reg &&
MI.getOperand(1).getReg() ==
Reg) {
3508 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
3509 if (
MI.getOpcode() == AArch64::SUBXri)
3520 const int64_t kMaxOffset = 4080 - 16;
3522 const int64_t kMinOffset = -4095;
3523 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
3524 PostOffset % 16 == 0) {
3535 for (
auto &TS : TSE) {
3539 if (
MI->memoperands_empty()) {
3543 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
3549 bool TryMergeSPUpdate) {
3550 if (TagStores.
empty())
3552 TagStoreInstr &FirstTagStore = TagStores[0];
3553 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
3554 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
3555 DL = TagStores[0].MI->getDebugLoc();
3559 *MF, FirstTagStore.Offset,
false ,
3563 FrameRegUpdate = std::nullopt;
3565 mergeMemRefs(TagStores, CombinedMemRefs);
3568 dbgs() <<
"Replacing adjacent STG instructions:\n";
3569 for (
const auto &Instr : TagStores) {
3578 if (TagStores.
size() < 2)
3580 emitUnrolled(InsertI);
3583 int64_t TotalOffset = 0;
3584 if (TryMergeSPUpdate) {
3590 if (InsertI !=
MBB->
end() &&
3591 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
3593 UpdateInstr = &*InsertI++;
3599 if (!UpdateInstr && TagStores.
size() < 2)
3603 FrameRegUpdate = TotalOffset;
3604 FrameRegUpdateFlags = UpdateInstr->
getFlags();
3611 for (
auto &TS : TagStores)
3612 TS.MI->eraseFromParent();
3616 int64_t &
Size,
bool &ZeroData) {
3620 unsigned Opcode =
MI.getOpcode();
3621 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
3622 Opcode == AArch64::STZ2Gi);
3624 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
3625 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
3627 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
3630 Size =
MI.getOperand(2).getImm();
3634 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
3636 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
3641 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
3645 16 *
MI.getOperand(2).getImm();
3665 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
3671 constexpr int kScanLimit = 10;
3674 NextI !=
E &&
Count < kScanLimit; ++NextI) {
3683 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
3684 if (ZeroData != FirstZeroData)
3692 if (!
MI.isTransient())
3701 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
3717 LiveRegs.addLiveOuts(*
MBB);
3722 LiveRegs.stepBackward(*
I);
3725 if (LiveRegs.contains(AArch64::NZCV))
3729 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
3734 int64_t CurOffset = Instrs[0].Offset;
3735 for (
auto &Instr : Instrs) {
3736 if (CurOffset >
Instr.Offset)
3743 TagStoreEdit TSE(
MBB, FirstZeroData);
3744 std::optional<int64_t> EndOffset;
3745 for (
auto &Instr : Instrs) {
3746 if (EndOffset && *EndOffset !=
Instr.Offset) {
3748 TSE.emitCode(InsertI, TFI,
false);
3752 TSE.addInstruction(Instr);
3771 II = tryMergeAdjacentSTG(
II,
this, RS);
3778 shouldSignReturnAddressEverywhere(MF))
3787 bool IgnoreSPUpdates)
const {
3789 if (IgnoreSPUpdates) {
3792 FrameReg = AArch64::SP;
3802 FrameReg = AArch64::SP;
3827 bool IsValid =
false;
3829 int ObjectIndex = 0;
3831 int GroupIndex = -1;
3833 bool ObjectFirst =
false;
3836 bool GroupFirst =
false;
3841 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
3845 SmallVector<int, 8> CurrentMembers;
3846 int NextGroupIndex = 0;
3847 std::vector<FrameObject> &Objects;
3850 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
3851 void AddMember(
int Index) { CurrentMembers.
push_back(Index); }
3852 void EndCurrentGroup() {
3853 if (CurrentMembers.
size() > 1) {
3858 for (
int Index : CurrentMembers) {
3859 Objects[
Index].GroupIndex = NextGroupIndex;
3865 CurrentMembers.clear();
3869bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
3891 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
3892 A.GroupIndex,
A.ObjectIndex) <
3893 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
3894 B.GroupIndex,
B.ObjectIndex);
3903 ObjectsToAllocate.
empty())
3908 for (
auto &Obj : ObjectsToAllocate) {
3909 FrameObjects[Obj].IsValid =
true;
3910 FrameObjects[Obj].ObjectIndex = Obj;
3915 GroupBuilder GB(FrameObjects);
3916 for (
auto &
MBB : MF) {
3917 for (
auto &
MI :
MBB) {
3918 if (
MI.isDebugInstr())
3923 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3926 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
3928 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
3933 switch (
MI.getOpcode()) {
3934 case AArch64::STGloop:
3935 case AArch64::STZGloop:
3939 case AArch64::STZGi:
3940 case AArch64::ST2Gi:
3941 case AArch64::STZ2Gi:
3954 FrameObjects[FI].IsValid)
3962 GB.AddMember(TaggedFI);
3964 GB.EndCurrentGroup();
3967 GB.EndCurrentGroup();
3972 FrameObject::AccessHazard;
3974 for (
auto &Obj : FrameObjects)
3975 if (!Obj.Accesses ||
3976 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
3977 Obj.Accesses = FrameObject::AccessGPR;
3986 FrameObjects[*TBPI].ObjectFirst =
true;
3987 FrameObjects[*TBPI].GroupFirst =
true;
3988 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
3989 if (FirstGroupIndex >= 0)
3990 for (FrameObject &Object : FrameObjects)
3991 if (Object.GroupIndex == FirstGroupIndex)
3992 Object.GroupFirst =
true;
3998 for (
auto &Obj : FrameObjects) {
4002 ObjectsToAllocate[i++] = Obj.ObjectIndex;
4006 dbgs() <<
"Final frame order:\n";
4007 for (
auto &Obj : FrameObjects) {
4010 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
4011 if (Obj.ObjectFirst)
4012 dbgs() <<
", first";
4014 dbgs() <<
", group-first";
4025AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
4036 MF.
insert(MBBInsertPoint, LoopMBB);
4038 MF.
insert(MBBInsertPoint, ExitMBB);
4069 MBB.addSuccessor(LoopMBB);
4073 return ExitMBB->
begin();
4076void AArch64FrameLowering::inlineStackProbeFixed(
4081 const AArch64InstrInfo *
TII =
4083 AArch64FunctionInfo *AFI = MF.
getInfo<AArch64FunctionInfo>();
4088 int64_t ProbeSize = MF.
getInfo<AArch64FunctionInfo>()->getStackProbeSize();
4089 int64_t NumBlocks = FrameSize / ProbeSize;
4090 int64_t ResidualSize = FrameSize % ProbeSize;
4092 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
4093 << NumBlocks <<
" blocks of " << ProbeSize
4094 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
4099 for (
int i = 0; i < NumBlocks; ++i) {
4105 EmitAsyncCFI && !HasFP, CFAOffset);
4114 }
else if (NumBlocks != 0) {
4120 EmitAsyncCFI && !HasFP, CFAOffset);
4122 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
4124 if (EmitAsyncCFI && !HasFP) {
4127 .buildDefCFARegister(AArch64::SP);
4131 if (ResidualSize != 0) {
4137 EmitAsyncCFI && !HasFP, CFAOffset);
4154 SmallVector<MachineInstr *, 4> ToReplace;
4155 for (MachineInstr &
MI :
MBB)
4156 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
4157 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
4160 for (MachineInstr *
MI : ToReplace) {
4161 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
4162 Register ScratchReg =
MI->getOperand(0).getReg();
4163 int64_t FrameSize =
MI->getOperand(1).getImm();
4165 MI->getOperand(3).getImm());
4166 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
4169 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
4170 "Stack probe pseudo-instruction expected");
4171 const AArch64InstrInfo *
TII =
4172 MI->getMF()->getSubtarget<AArch64Subtarget>().getInstrInfo();
4173 Register TargetReg =
MI->getOperand(0).getReg();
4174 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
4176 MI->eraseFromParent();
4196 return std::make_tuple(
start(),
Idx) <
4197 std::make_tuple(Rhs.
start(), Rhs.
Idx);
4227 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
4228 if (
Offset.getScalable())
4229 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
4240void AArch64FrameLowering::emitRemarks(
4243 auto *AFI = MF.
getInfo<AArch64FunctionInfo>();
4248 const uint64_t HazardSize =
4251 if (HazardSize == 0)
4259 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
4261 size_t NumFPLdSt = 0;
4262 size_t NumNonFPLdSt = 0;
4265 for (
const MachineBasicBlock &
MBB : MF) {
4266 for (
const MachineInstr &
MI :
MBB) {
4267 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
4269 for (MachineMemOperand *MMO :
MI.memoperands()) {
4276 StackAccesses[ArrIdx].Idx = FrameIdx;
4277 StackAccesses[ArrIdx].Offset =
4286 if (
MI.getOpcode() != AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO &&
4287 MI.getOpcode() != AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO &&
4288 AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg())) {
4296 StackAccesses[ArrIdx].AccessTypes |= RegTy;
4307 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
4318 if (StackAccesses.front().isMixed())
4319 MixedObjects.push_back(&StackAccesses.front());
4321 for (
auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
4323 const auto &
First = *It;
4324 const auto &Second = *(It + 1);
4326 if (Second.isMixed())
4327 MixedObjects.push_back(&Second);
4329 if ((
First.isSME() && Second.isCPU()) ||
4330 (
First.isCPU() && Second.isSME())) {
4331 uint64_t Distance =
static_cast<uint64_t
>(Second.start() -
First.end());
4332 if (Distance < HazardSize)
4337 auto EmitRemark = [&](llvm::StringRef Str) {
4339 auto R = MachineOptimizationRemarkAnalysis(
4340 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
4341 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
4345 for (
const auto &
P : HazardPairs)
4346 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
4348 for (
const auto *Obj : MixedObjects)
4350 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 > 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 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 arePPRsSpilledAsZPR(const MachineFunction &MF)
Returns true if PPRs are spilled as ZPRs.
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 SVEStackSizes determineSVEStackSizes(MachineFunction &MF, AssignObjectOffsets AssignOffsets)
Process all the SVE stack objects and the SVE stack size and offsets for each object.
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 bool isPPRAccess(const MachineInstr &MI)
static std::optional< int > getMMOFrameID(MachineMemOperand *MMO, const MachineFrameInfo &MFI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declaration of the AArch64PrologueEmitter and AArch64EpilogueEmitter classes,...
static const int kSetTagLoopThreshold
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
This file contains the simple types necessary to represent the attributes associated with functions a...
#define CASE(ATTRNAME, AANAME,...)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
DXIL Forward Handle Accesses
const HexagonInstrInfo * TII
static std::string getTypeString(Type *T)
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
uint64_t IntrinsicInst * II
This file declares the machine register scavenger class.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
This file defines the SmallVector class.
void emitEpilogue()
Emit the epilogue.
StackOffset getSVEStackSize(const MachineFunction &MF) const
Returns the size of the entire SVE stackframe (PPRs + ZPRs).
StackOffset getZPRStackSize(const MachineFunction &MF) const
Returns the size of the entire ZPR stackframe (calleesaves + spills).
void processFunctionBeforeFrameIndicesReplaced(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameIndicesReplaced - This method is called immediately before MO_FrameIndex op...
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override
This method is called during prolog/epilog code insertion to eliminate call frame setup and destroy p...
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override
Check whether or not the given MBB can be used as a prologue for the target.
bool enableStackSlotScavenging(const MachineFunction &MF) const override
Returns true if the stack slot holes in the fixed and callee-save stack area should be used when allo...
bool 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,...
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).
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.
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...
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
bool hasStreamingModeChanges() const
bool shouldSignReturnAddress(const MachineFunction &MF) 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
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
size_type size() const
size - 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...
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...
bool hasScalableStackID(int ObjectIdx) const
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.
unsigned getSpillSize(const TargetRegisterClass &RC) const
Return the size in bytes of the stack slot allocated to hold a spilled copy of a register from class ...
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.
@ 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.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Define
Register definition.
@ 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.
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...
@ LLVM_MARK_AS_BITMASK_ENUM
@ 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...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
void fullyRecomputeLiveIns(ArrayRef< MachineBasicBlock * > MBBs)
Convenience function for recomputing live-in's for a set of MBBs until the computation converges.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
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.
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 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