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",
296STATISTIC(NumRedZoneFunctions,
"Number of functions using red zone");
312 int64_t ArgumentPopSize = 0;
313 if (IsTailCallReturn) {
319 ArgumentPopSize = StackAdjust.
getImm();
328 return ArgumentPopSize;
335 bool HasCall =
false);
346 if (AFI->hasCalculatedStackSizeSVE())
361bool AArch64FrameLowering::homogeneousPrologEpilog(
387 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
394 unsigned NumGPRs = 0;
395 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
397 if (Reg == AArch64::LR) {
398 assert(CSRegs[
I + 1] == AArch64::FP);
399 if (NumGPRs % 2 != 0)
403 if (AArch64::GPR64RegClass.
contains(Reg))
411bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
430 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
431 MI.getOpcode() == AArch64::ADDXri ||
432 MI.getOpcode() == AArch64::ADDSXri)
460 "Tail call reserved stack must be aligned to 16 bytes");
461 if (!IsWin64 || IsFunclet) {
466 Attribute::SwiftAsync))
480 int FrameIndex =
H.CatchObj.FrameIndex;
481 if ((FrameIndex != INT_MAX) &&
482 CatchObjFrameIndices.
insert(FrameIndex)) {
483 FixedObjectSize =
alignTo(FixedObjectSize,
490 FixedObjectSize += 8;
492 return alignTo(FixedObjectSize, 16);
509 const unsigned RedZoneSize =
522 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
526 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
590 const Triple &TT = TM.getTargetTriple();
594 if (TT.isOSDarwin() || TT.isOSWindows())
602 if (TM.Options.FramePointerIsReserved(MF))
632 unsigned Opc =
I->getOpcode();
633 bool IsDestroy =
Opc ==
TII->getCallFrameDestroyOpcode();
634 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
637 int64_t Amount =
I->getOperand(0).getImm();
645 if (CalleePopAmount == 0) {
656 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
667 "non-reserved call frame without var sized objects?");
676 }
else if (CalleePopAmount != 0) {
679 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
686void AArch64FrameLowering::emitCalleeSavedGPRLocations(
696 for (
const auto &Info : CSI) {
697 unsigned FrameIdx =
Info.getFrameIdx();
701 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
703 CFIBuilder.buildOffset(
Info.getReg(),
Offset);
707void AArch64FrameLowering::emitCalleeSavedSVELocations(
722 std::optional<int64_t> IncomingVGOffsetFromDefCFA;
725 reverse(CSI), [](
auto &Info) {
return Info.getReg() == AArch64::VG; });
726 IncomingVGOffsetFromDefCFA =
730 for (
const auto &Info : CSI) {
736 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
745 CFIBuilder.insertCFIInst(
755 const auto &
TRI = *Subtarget.getRegisterInfo();
761 CFIBuilder.buildDefCFA(AArch64::SP, 0);
764 if (MFI.shouldSignReturnAddress(MF))
765 MFI.branchProtectionPAuthLR() ? CFIBuilder.buildNegateRAStateWithPC()
766 : CFIBuilder.buildNegateRAState();
769 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
770 CFIBuilder.buildSameValue(AArch64::X18);
773 const std::vector<CalleeSavedInfo> &CSI =
775 for (
const auto &
Info : CSI) {
777 if (!
TRI.regNeedsCFI(Reg, Reg))
779 CFIBuilder.buildSameValue(Reg);
797 for (
const auto &
Info : CSI) {
811void AArch64FrameLowering::emitCalleeSavedGPRRestores(
816void AArch64FrameLowering::emitCalleeSavedSVERestores(
824 static const int64_t MAX_BYTES_PER_SCALABLE_BYTE = 16;
825 return Size.getScalable() * MAX_BYTES_PER_SCALABLE_BYTE +
Size.getFixed();
828void AArch64FrameLowering::allocateStackSpace(
830 int64_t RealignmentPadding,
StackOffset AllocSize,
bool NeedsWinCFI,
831 bool *HasWinCFI,
bool EmitCFI,
StackOffset InitialOffset,
832 bool FollowupAllocs)
const {
845 const uint64_t AndMask = ~(MaxAlign - 1);
848 Register TargetReg = RealignmentPadding
854 EmitCFI, InitialOffset);
856 if (RealignmentPadding) {
877 if (AllocSize.
getScalable() == 0 && RealignmentPadding == 0) {
879 assert(ScratchReg != AArch64::NoRegister);
889 if (FollowupAllocs) {
906 if (
upperBound(AllocSize) + RealignmentPadding <= ProbeSize) {
907 Register ScratchReg = RealignmentPadding
910 assert(ScratchReg != AArch64::NoRegister);
914 EmitCFI, InitialOffset);
915 if (RealignmentPadding) {
923 if (FollowupAllocs ||
upperBound(AllocSize) + RealignmentPadding >
939 assert(TargetReg != AArch64::NoRegister);
943 EmitCFI, InitialOffset);
944 if (RealignmentPadding) {
959 if (RealignmentPadding)
972 case AArch64::W##n: \
973 case AArch64::X##n: \
998 case AArch64::B##n: \
999 case AArch64::H##n: \
1000 case AArch64::S##n: \
1001 case AArch64::D##n: \
1002 case AArch64::Q##n: \
1003 return HasSVE ? AArch64::Z##n : AArch64::Q##n
1040void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
1048 DL =
MBBI->getDebugLoc();
1058 if (
TRI.isGeneralPurposeRegister(MF, Reg)) {
1061 GPRsToZero.set(XReg);
1065 FPRsToZero.set(XReg);
1081 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
1082 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
1083 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
1085 if (RegsToZero[PReg])
1098 StackSizeInBytes >=
uint64_t(MFI.getStackProbeSize());
1104 LiveRegs.addLiveIns(
MBB);
1107 for (
unsigned i = 0; CSRegs[i]; ++i)
1108 LiveRegs.addReg(CSRegs[i]);
1138 LiveRegs.addReg(AArch64::X16);
1139 LiveRegs.addReg(AArch64::X17);
1140 LiveRegs.addReg(AArch64::X18);
1145 if (LiveRegs.available(
MRI, AArch64::X9))
1148 for (
unsigned Reg : AArch64::GPR64RegClass) {
1149 if (LiveRegs.available(
MRI, Reg))
1152 return AArch64::NoRegister;
1171 if (!LiveRegs.available(
MRI, AArch64::X16) ||
1172 !LiveRegs.available(
MRI, AArch64::X17))
1199 F.needsUnwindTableEntry();
1209 return SignReturnAddressAll;
1212bool AArch64FrameLowering::shouldCombineCSRLocalStackBump(
1218 if (homogeneousPrologEpilog(MF))
1241 if (MFI.hasVarSizedObjects())
1244 if (
RegInfo->hasStackRealignment(MF))
1261bool AArch64FrameLowering::shouldCombineCSRLocalStackBumpInEpilogue(
1263 if (!shouldCombineCSRLocalStackBump(*
MBB.
getParent(), StackBumpBytes))
1272 while (LastI != Begin) {
1274 if (LastI->isTransient())
1279 switch (LastI->getOpcode()) {
1280 case AArch64::STGloop:
1281 case AArch64::STZGloop:
1283 case AArch64::STZGi:
1284 case AArch64::ST2Gi:
1285 case AArch64::STZ2Gi:
1298 unsigned Opc =
MBBI->getOpcode();
1302 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1303 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1311 case AArch64::STR_ZXI:
1312 case AArch64::LDR_ZXI: {
1313 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1320 case AArch64::STR_PXI:
1321 case AArch64::LDR_PXI: {
1322 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1329 case AArch64::LDPDpost:
1332 case AArch64::STPDpre: {
1333 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1334 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1335 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1342 case AArch64::LDPXpost:
1345 case AArch64::STPXpre: {
1348 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1349 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1353 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1360 case AArch64::LDRDpost:
1363 case AArch64::STRDpre: {
1364 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1365 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1371 case AArch64::LDRXpost:
1374 case AArch64::STRXpre: {
1375 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1382 case AArch64::STPDi:
1383 case AArch64::LDPDi: {
1384 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1385 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1393 case AArch64::STPXi:
1394 case AArch64::LDPXi: {
1397 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1409 case AArch64::STRXui:
1410 case AArch64::LDRXui: {
1411 int Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1418 case AArch64::STRDui:
1419 case AArch64::LDRDui: {
1420 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1427 case AArch64::STPQi:
1428 case AArch64::LDPQi: {
1429 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1430 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1431 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1438 case AArch64::LDPQpost:
1441 case AArch64::STPQpre: {
1442 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1443 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1444 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1458 unsigned LocalStackSize) {
1460 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1461 switch (
MBBI->getOpcode()) {
1464 case AArch64::SEH_SaveFPLR:
1465 case AArch64::SEH_SaveRegP:
1466 case AArch64::SEH_SaveReg:
1467 case AArch64::SEH_SaveFRegP:
1468 case AArch64::SEH_SaveFReg:
1469 case AArch64::SEH_SaveAnyRegQP:
1470 case AArch64::SEH_SaveAnyRegQPX:
1471 ImmOpnd = &
MBBI->getOperand(ImmIdx);
1491 if (ST.isTargetDarwin())
1497 RTLIB::Libcall LC) {
1504 unsigned Opc =
MBBI->getOpcode();
1505 if (
Opc == AArch64::CNTD_XPiI)
1511 if (
Opc == AArch64::BL)
1512 return matchLibcall(TLI,
MBBI->getOperand(0), RTLIB::SMEABI_GET_CURRENT_VG);
1514 return Opc == TargetOpcode::COPY;
1523 bool NeedsWinCFI,
bool *HasWinCFI,
bool EmitCFI,
1525 int CFAOffset = 0) {
1538 switch (
MBBI->getOpcode()) {
1541 case AArch64::STPXi:
1542 NewOpc = AArch64::STPXpre;
1544 case AArch64::STPDi:
1545 NewOpc = AArch64::STPDpre;
1547 case AArch64::STPQi:
1548 NewOpc = AArch64::STPQpre;
1550 case AArch64::STRXui:
1551 NewOpc = AArch64::STRXpre;
1553 case AArch64::STRDui:
1554 NewOpc = AArch64::STRDpre;
1556 case AArch64::STRQui:
1557 NewOpc = AArch64::STRQpre;
1559 case AArch64::LDPXi:
1560 NewOpc = AArch64::LDPXpost;
1562 case AArch64::LDPDi:
1563 NewOpc = AArch64::LDPDpost;
1565 case AArch64::LDPQi:
1566 NewOpc = AArch64::LDPQpost;
1568 case AArch64::LDRXui:
1569 NewOpc = AArch64::LDRXpost;
1571 case AArch64::LDRDui:
1572 NewOpc = AArch64::LDRDpost;
1574 case AArch64::LDRQui:
1575 NewOpc = AArch64::LDRQpost;
1579 int64_t MinOffset, MaxOffset;
1581 NewOpc, Scale, Width, MinOffset, MaxOffset);
1587 if (
MBBI->getOperand(
MBBI->getNumOperands() - 1).getImm() != 0 ||
1588 CSStackSizeInc < MinOffset * (int64_t)Scale.
getFixedValue() ||
1589 CSStackSizeInc > MaxOffset * (int64_t)Scale.
getFixedValue()) {
1600 false, NeedsWinCFI, HasWinCFI, EmitCFI,
1603 return std::prev(
MBBI);
1608 auto SEH = std::next(
MBBI);
1610 SEH->eraseFromParent();
1617 unsigned OpndIdx = 0;
1618 for (
unsigned OpndEnd =
MBBI->getNumOperands() - 1; OpndIdx < OpndEnd;
1620 MIB.
add(
MBBI->getOperand(OpndIdx));
1622 assert(
MBBI->getOperand(OpndIdx).getImm() == 0 &&
1623 "Unexpected immediate offset in first/last callee-save save/restore "
1625 assert(
MBBI->getOperand(OpndIdx - 1).getReg() == AArch64::SP &&
1626 "Unexpected base register in callee-save save/restore instruction!");
1627 assert(CSStackSizeInc % Scale == 0);
1628 MIB.
addImm(CSStackSizeInc / (
int)Scale);
1655 unsigned Opc =
MI.getOpcode();
1658 case AArch64::STPXi:
1659 case AArch64::STRXui:
1660 case AArch64::STPDi:
1661 case AArch64::STRDui:
1662 case AArch64::LDPXi:
1663 case AArch64::LDRXui:
1664 case AArch64::LDPDi:
1665 case AArch64::LDRDui:
1668 case AArch64::STPQi:
1669 case AArch64::STRQui:
1670 case AArch64::LDPQi:
1671 case AArch64::LDRQui:
1678 unsigned OffsetIdx =
MI.getNumExplicitOperands() - 1;
1679 assert(
MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP &&
1680 "Unexpected base register in callee-save save/restore instruction!");
1684 assert(LocalStackSize % Scale == 0);
1685 OffsetOpnd.
setImm(OffsetOpnd.
getImm() + LocalStackSize / Scale);
1690 assert(
MBBI !=
MI.getParent()->end() &&
"Expecting a valid instruction");
1692 "Expecting a SEH instruction");
1707 switch (
I->getOpcode()) {
1710 case AArch64::PTRUE_C_B:
1711 case AArch64::LD1B_2Z_IMM:
1712 case AArch64::ST1B_2Z_IMM:
1713 case AArch64::STR_ZXI:
1714 case AArch64::STR_PXI:
1715 case AArch64::LDR_ZXI:
1716 case AArch64::LDR_PXI:
1717 case AArch64::PTRUE_B:
1718 case AArch64::CPY_ZPzI_B:
1719 case AArch64::CMPNE_PPzZI_B:
1722 case AArch64::SEH_SavePReg:
1723 case AArch64::SEH_SaveZReg:
1733 bool NeedsUnwindInfo) {
1749 if (NeedsUnwindInfo) {
1752 static const char CFIInst[] = {
1753 dwarf::DW_CFA_val_expression,
1756 static_cast<char>(
unsigned(dwarf::DW_OP_breg18)),
1757 static_cast<char>(-8) & 0x7f,
1789 unsigned FixedObject) {
1794 const int OffsetToFirstCalleeSaveFromFP =
1809 LiveRegs.addLiveOuts(
MBB);
1812 LiveRegs.stepBackward(
MI);
1833 DL =
MBBI->getDebugLoc();
1840 EmitSignRA(MF.
front());
1861 bool HasFP =
hasFP(MF);
1863 bool HasWinCFI =
false;
1872 while (NonFrameStart !=
End &&
1877 if (NonFrameStart !=
MBB.
end()) {
1880 LiveRegs.removeReg(AArch64::SP);
1881 LiveRegs.removeReg(AArch64::X19);
1882 LiveRegs.removeReg(AArch64::FP);
1883 LiveRegs.removeReg(AArch64::LR);
1889 LiveRegs.removeReg(AArch64::X0);
1893 if (NonFrameStart ==
MBB.
end())
1898 for (auto &Op : MI.operands())
1899 if (Op.isReg() && Op.isDef())
1900 assert(!LiveRegs.contains(Op.getReg()) &&
1901 "live register clobbered by inserted prologue instructions");
1918 if (MFnI.shouldSignReturnAddress(MF)) {
1926 HasWinCFI |= NeedsWinCFI;
1929 if (MFnI.needsShadowCallStackPrologueEpilogue(MF)) {
1931 MFnI.needsDwarfUnwindInfo(MF));
1932 HasWinCFI |= NeedsWinCFI;
1935 if (EmitCFI && MFnI.isMTETagged()) {
2013 assert(!HasFP &&
"unexpected function without stack frame but with FP");
2015 "unexpected function without stack frame but with SVE objects");
2019 if (NeedsWinCFI && HasWinCFI) {
2029 ++NumRedZoneFunctions;
2067 bool FPAfterSVECalleeSaves =
2076 bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes);
2077 bool HomPrologEpilog = homogeneousPrologEpilog(MF);
2078 if (FPAfterSVECalleeSaves) {
2087 allocateStackSpace(
MBB,
MBBI, 0, SaveSize, NeedsWinCFI, &HasWinCFI,
2090 NumBytes -= FixedObject;
2097 &HasWinCFI, EmitAsyncCFI);
2099 }
else if (CombineSPBump) {
2100 assert(!SVEStackSize &&
"Cannot combine SP bump with SVE");
2106 }
else if (HomPrologEpilog) {
2108 NumBytes -= PrologueSaveSize;
2109 }
else if (PrologueSaveSize != 0) {
2111 MBB,
MBBI,
DL,
TII, -PrologueSaveSize, NeedsWinCFI, &HasWinCFI,
2113 NumBytes -= PrologueSaveSize;
2115 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
2123 if (CombineSPBump &&
2127 NeedsWinCFI, &HasWinCFI);
2132 if (!IsFunclet && HasFP) {
2144 bool HaveInitialContext = Attrs.hasAttrSomewhere(Attribute::SwiftAsync);
2145 if (HaveInitialContext)
2147 Register Reg = HaveInitialContext ? AArch64::X22 : AArch64::XZR;
2163 if (HomPrologEpilog) {
2176 if (NeedsWinCFI && HasWinCFI) {
2181 NeedsWinCFI =
false;
2192 emitCalleeSavedGPRLocations(
MBB,
MBBI);
2195 const bool NeedsRealignment =
2196 NumBytes && !IsFunclet && RegInfo->hasStackRealignment(MF);
2197 const int64_t RealignmentPadding =
2205 "SVE callee saves not yet supported with stack probing");
2209 unsigned X15Scratch = AArch64::NoRegister;
2214 AArch64::X15, LiveIn.PhysReg);
2217 assert(X15Scratch != AArch64::NoRegister &&
2218 (X15Scratch < AArch64::X15 || X15Scratch > AArch64::X17));
2220 LiveRegs.removeReg(AArch64::X15);
2229 uint64_t NumWords = (NumBytes + RealignmentPadding) >> 4;
2237 if (NumBytes >= (1 << 28))
2239 "unwinding purposes");
2241 uint32_t LowNumWords = NumWords & 0xFFFF;
2248 if ((NumWords & 0xFFFF0000) != 0) {
2251 .
addImm((NumWords & 0xFFFF0000) >> 16)
2322 if (RealignmentPadding > 0) {
2323 if (RealignmentPadding >= 4096) {
2326 .
addImm(RealignmentPadding)
2336 .
addImm(RealignmentPadding)
2351 if (X15Scratch != AArch64::NoRegister) {
2360 StackOffset SVECalleeSavesSize = {}, SVELocalsSize = SVEStackSize;
2369 LLVM_DEBUG(
dbgs() <<
"SVECalleeSavedStackSize = " << CalleeSavedSize
2372 SVELocalsSize = SVEStackSize - SVECalleeSavesSize;
2376 if (!FPAfterSVECalleeSaves) {
2381 CalleeSavesEnd =
MBBI;
2385 allocateStackSpace(
MBB, CalleeSavesBegin, 0, SVECalleeSavesSize,
false,
2386 nullptr, EmitAsyncCFI && !HasFP, CFAOffset,
2390 CFAOffset += SVECalleeSavesSize;
2393 emitCalleeSavedSVELocations(
MBB, CalleeSavesEnd);
2398 "Cannot use redzone with stack realignment");
2403 allocateStackSpace(
MBB, CalleeSavesEnd, RealignmentPadding,
2405 NeedsWinCFI, &HasWinCFI, EmitAsyncCFI && !HasFP,
2417 if (!IsFunclet && RegInfo->hasBasePointer(MF)) {
2429 if (NeedsWinCFI && HasWinCFI) {
2437 if (IsFunclet &&
F.hasPersonalityFn()) {
2447 if (EmitCFI && !EmitAsyncCFI) {
2458 emitCalleeSavedGPRLocations(
MBB,
MBBI);
2459 emitCalleeSavedSVELocations(
MBB,
MBBI);
2464 switch (
MI.getOpcode()) {
2467 case AArch64::CATCHRET:
2468 case AArch64::CLEANUPRET:
2483 bool HasWinCFI =
false;
2484 bool IsFunclet =
false;
2487 DL =
MBBI->getDebugLoc();
2495 emitShadowCallStackEpilogue(*TII, MF, MBB, MBB.getFirstTerminator(), DL,
2497 HasWinCFI |= NeedsWinCFI;
2504 if (!shouldSignReturnAddressEverywhere(MF)) {
2505 BuildMI(MBB, MBB.getFirstTerminator(), DL,
2506 TII->get(AArch64::PAUTH_EPILOGUE))
2507 .setMIFlag(MachineInstr::FrameDestroy);
2510 HasWinCFI |= NeedsWinCFI;
2514 TII->get(AArch64::SEH_EpilogEnd))
2526 int64_t NumBytes = IsFunclet ? getWinEHFuncletFrameSize(MF)
2527 : MFI.getStackSize();
2541 int64_t AfterCSRPopSize = ArgumentStackToRestore;
2549 if (homogeneousPrologEpilog(MF, &
MBB)) {
2553 auto HomogeneousEpilog = std::prev(LastPopI);
2554 if (HomogeneousEpilog->getOpcode() == AArch64::HOM_Epilog)
2555 LastPopI = HomogeneousEpilog;
2565 assert(AfterCSRPopSize == 0);
2569 bool FPAfterSVECalleeSaves =
2572 bool CombineSPBump = shouldCombineCSRLocalStackBumpInEpilogue(
MBB, NumBytes);
2574 bool CombineAfterCSRBump =
false;
2575 if (FPAfterSVECalleeSaves) {
2576 AfterCSRPopSize += FixedObject;
2577 }
else if (!CombineSPBump && PrologueSaveSize != 0) {
2579 while (Pop->getOpcode() == TargetOpcode::CFI_INSTRUCTION ||
2581 Pop = std::prev(Pop);
2588 if (
OffsetOp.getImm() == 0 && AfterCSRPopSize >= 0) {
2590 MBB, Pop,
DL,
TII, PrologueSaveSize, NeedsWinCFI, &HasWinCFI, EmitCFI,
2597 AfterCSRPopSize += PrologueSaveSize;
2598 CombineAfterCSRBump =
true;
2607 while (LastPopI != Begin) {
2613 }
else if (CombineSPBump)
2615 NeedsWinCFI, &HasWinCFI);
2627 EpilogStartI = LastPopI;
2663 if (CombineSPBump) {
2664 assert(!SVEStackSize &&
"Cannot combine SP bump with SVE");
2667 if (EmitCFI && hasFP(MF))
2678 NumBytes -= PrologueSaveSize;
2679 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
2683 StackOffset DeallocateBefore = {}, DeallocateAfter = SVEStackSize;
2686 if (FPAfterSVECalleeSaves)
2689 RestoreBegin = std::prev(RestoreEnd);
2690 while (RestoreBegin !=
MBB.
begin() &&
2699 DeallocateBefore = SVEStackSize - CalleeSavedSizeAsOffset;
2700 DeallocateAfter = CalleeSavedSizeAsOffset;
2704 if (FPAfterSVECalleeSaves) {
2711 NeedsWinCFI, &HasWinCFI);
2727 NeedsWinCFI, &HasWinCFI);
2728 }
else if (SVEStackSize) {
2736 if (SVECalleeSavedSize && BaseForSVEDealloc == AArch64::FP) {
2737 Register CalleeSaveBase = AArch64::FP;
2738 if (int64_t CalleeSaveBaseOffset =
2744 &AArch64::GPR64RegClass);
2754 }
else if (BaseForSVEDealloc == AArch64::SP) {
2755 if (SVECalleeSavedSize) {
2759 MBB, RestoreBegin,
DL, AArch64::SP, AArch64::SP,
2761 false, NeedsWinCFI, &HasWinCFI, EmitCFI && !hasFP(MF),
2768 NeedsWinCFI, &HasWinCFI, EmitCFI && !hasFP(MF),
2774 NeedsWinCFI, &HasWinCFI, EmitCFI && !hasFP(MF),
2779 emitCalleeSavedSVERestores(
MBB, RestoreEnd);
2783 bool RedZone = canUseRedZone(MF);
2786 if (RedZone && AfterCSRPopSize == 0)
2793 bool NoCalleeSaveRestore = PrologueSaveSize == 0;
2794 int64_t StackRestoreBytes = RedZone ? 0 : NumBytes;
2795 if (NoCalleeSaveRestore)
2796 StackRestoreBytes += AfterCSRPopSize;
2799 MBB, LastPopI,
DL, AArch64::SP, AArch64::SP,
2806 if (NoCalleeSaveRestore || AfterCSRPopSize == 0) {
2819 MBB, LastPopI,
DL, AArch64::SP, AArch64::FP,
2822 }
else if (NumBytes)
2828 if (EmitCFI && hasFP(MF))
2835 if (AfterCSRPopSize) {
2836 assert(AfterCSRPopSize > 0 &&
"attempting to reallocate arg stack that an "
2837 "interrupt may have clobbered");
2842 false, NeedsWinCFI, &HasWinCFI, EmitCFI,
2889 if (MFI.isVariableSizedObjectIndex(FI)) {
2898 bool FPAfterSVECalleeSaves =
2901 if (FPAfterSVECalleeSaves &&
2908 bool IsFixed = MFI.isFixedObjectIndex(FI);
2913 if (!IsFixed && !IsCSR) {
2914 ScalableOffset = -SVEStackSize;
2915 }
else if (FPAfterSVECalleeSaves && IsCSR) {
2930 int64_t ObjectOffset) {
2934 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
2935 unsigned FixedObject =
2944 int64_t ObjectOffset) {
2955 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
2962 bool ForSimm)
const {
2965 bool isFixed = MFI.isFixedObjectIndex(FI);
2972 const MachineFunction &MF, int64_t ObjectOffset,
bool isFixed,
bool isSVE,
2973 Register &FrameReg,
bool PreferFP,
bool ForSimm)
const {
2996 PreferFP &= !SVEStackSize;
3004 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
3008 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
3010 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
3015 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
3016 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
3018 if (FPOffset >= 0) {
3022 }
else if (MFI.hasVarSizedObjects()) {
3026 bool CanUseBP = RegInfo->hasBasePointer(MF);
3027 if (FPOffsetFits && CanUseBP)
3034 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
3041 "Funclets should only be present on Win64");
3045 if (FPOffsetFits && PreferFP)
3052 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
3053 "In the presence of dynamic stack pointer realignment, "
3054 "non-argument/CSR objects cannot be accessed through the frame pointer");
3056 bool FPAfterSVECalleeSaves =
3066 if (FPAfterSVECalleeSaves) {
3076 RegInfo->hasStackRealignment(MF))) {
3077 FrameReg = RegInfo->getFrameRegister(MF);
3081 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
3087 if (FPAfterSVECalleeSaves) {
3094 ScalableOffset = SVECalleeSavedStack;
3096 ScalableOffset = SVECalleeSavedStack - SVEStackSize;
3099 ScalableOffset = SVEStackSize;
3101 ScalableOffset = SVEStackSize - SVECalleeSavedStack;
3104 if (UseFP && !(isFixed || isCSR))
3105 ScalableOffset = -SVEStackSize;
3106 if (!UseFP && (isFixed || isCSR))
3107 ScalableOffset = SVEStackSize;
3111 FrameReg = RegInfo->getFrameRegister(MF);
3116 if (RegInfo->hasBasePointer(MF))
3117 FrameReg = RegInfo->getBaseRegister();
3119 assert(!MFI.hasVarSizedObjects() &&
3120 "Can't use SP when we have var sized objects.");
3121 FrameReg = AArch64::SP;
3148 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
3154 bool NeedsWinCFI,
bool IsFirst,
3163 if (Reg2 == AArch64::FP)
3167 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
3174 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
3175 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR && !IsFirst)
3185 bool UsesWinAAPCS,
bool NeedsWinCFI,
3186 bool NeedsFrameRecord,
bool IsFirst,
3194 if (NeedsFrameRecord)
3195 return Reg2 == AArch64::LR;
3203 unsigned Reg1 = AArch64::NoRegister;
3204 unsigned Reg2 = AArch64::NoRegister;
3207 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
3210 RegPairInfo() =
default;
3212 bool isPaired()
const {
return Reg2 != AArch64::NoRegister; }
3214 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
3220 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
3221 if (SavedRegs.
test(PReg)) {
3222 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
3226 return AArch64::NoRegister;
3236 bool IsLocallyStreaming =
3242 return Subtarget.hasSVE2p1() ||
3243 (Subtarget.hasSME2() &&
3244 (!IsLocallyStreaming && Subtarget.
isStreaming()));
3250 bool NeedsFrameRecord) {
3261 unsigned Count = CSI.
size();
3268 "Odd number of callee-saved regs to spill!");
3270 int StackFillDir = -1;
3272 unsigned FirstReg = 0;
3280 FirstReg = Count - 1;
3283 int ScalableByteOffset =
3289 for (
unsigned i = FirstReg; i < Count; i += RegInc) {
3291 RPI.Reg1 = CSI[i].getReg();
3293 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
3294 RPI.Type = RegPairInfo::GPR;
3295 RPI.RC = &AArch64::GPR64RegClass;
3296 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
3297 RPI.Type = RegPairInfo::FPR64;
3298 RPI.RC = &AArch64::FPR64RegClass;
3299 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
3300 RPI.Type = RegPairInfo::FPR128;
3301 RPI.RC = &AArch64::FPR128RegClass;
3302 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
3303 RPI.Type = RegPairInfo::ZPR;
3304 RPI.RC = &AArch64::ZPRRegClass;
3305 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
3306 RPI.Type = RegPairInfo::PPR;
3307 RPI.RC = &AArch64::PPRRegClass;
3308 }
else if (RPI.Reg1 == AArch64::VG) {
3309 RPI.Type = RegPairInfo::VG;
3310 RPI.RC = &AArch64::FIXED_REGSRegClass;
3319 ByteOffset += StackFillDir * StackHazardSize;
3322 int Scale =
TRI->getSpillSize(*RPI.RC);
3325 MCRegister NextReg = CSI[i + RegInc].getReg();
3326 bool IsFirst = i == FirstReg;
3328 case RegPairInfo::GPR:
3329 if (AArch64::GPR64RegClass.
contains(NextReg) &&
3331 NeedsWinCFI, NeedsFrameRecord, IsFirst,
3335 case RegPairInfo::FPR64:
3336 if (AArch64::FPR64RegClass.
contains(NextReg) &&
3341 case RegPairInfo::FPR128:
3342 if (AArch64::FPR128RegClass.
contains(NextReg))
3345 case RegPairInfo::PPR:
3347 case RegPairInfo::ZPR:
3349 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
3352 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
3357 case RegPairInfo::VG:
3368 assert((!RPI.isPaired() ||
3369 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
3370 "Out of order callee saved regs!");
3372 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
3373 RPI.Reg1 == AArch64::LR) &&
3374 "FrameRecord must be allocated together with LR");
3377 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
3378 RPI.Reg2 == AArch64::LR) &&
3379 "FrameRecord must be allocated together with LR");
3387 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
3388 RPI.Reg1 + 1 == RPI.Reg2))) &&
3389 "Callee-save registers not saved as adjacent register pair!");
3391 RPI.FrameIdx = CSI[i].getFrameIdx();
3394 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
3398 if (RPI.isScalable() && ScalableByteOffset % Scale != 0) {
3399 ScalableByteOffset =
alignTo(ScalableByteOffset, Scale);
3402 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
3403 assert(OffsetPre % Scale == 0);
3405 if (RPI.isScalable())
3406 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
3408 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
3413 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
3414 (IsWindows && RPI.Reg2 == AArch64::LR)))
3415 ByteOffset += StackFillDir * 8;
3419 if (NeedGapToAlignStack && !NeedsWinCFI && !RPI.isScalable() &&
3420 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
3421 ByteOffset % 16 != 0) {
3422 ByteOffset += 8 * StackFillDir;
3428 NeedGapToAlignStack =
false;
3431 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
3432 assert(OffsetPost % Scale == 0);
3435 int Offset = NeedsWinCFI ? OffsetPre : OffsetPost;
3440 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
3441 (IsWindows && RPI.Reg2 == AArch64::LR)))
3443 RPI.Offset =
Offset / Scale;
3445 assert((!RPI.isPaired() ||
3446 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
3447 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
3448 "Offset out of bounds for LDP/STP immediate");
3450 auto isFrameRecord = [&] {
3452 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
3453 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
3461 return i > 0 && RPI.Reg1 == AArch64::FP &&
3462 CSI[i - 1].getReg() == AArch64::LR;
3467 if (NeedsFrameRecord && isFrameRecord())
3484 std::reverse(RegPairs.
begin(), RegPairs.
end());
3503 MRI.freezeReservedRegs();
3505 if (homogeneousPrologEpilog(MF)) {
3509 for (
auto &RPI : RegPairs) {
3514 if (!
MRI.isReserved(RPI.Reg1))
3516 if (RPI.isPaired() && !
MRI.isReserved(RPI.Reg2))
3521 bool PTrueCreated =
false;
3523 unsigned Reg1 = RPI.Reg1;
3524 unsigned Reg2 = RPI.Reg2;
3537 unsigned Size =
TRI->getSpillSize(*RPI.RC);
3538 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
3540 case RegPairInfo::GPR:
3541 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
3543 case RegPairInfo::FPR64:
3544 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
3546 case RegPairInfo::FPR128:
3547 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
3549 case RegPairInfo::ZPR:
3550 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
3552 case RegPairInfo::PPR:
3554 Size == 16 ? AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO : AArch64::STR_PXI;
3556 case RegPairInfo::VG:
3557 StrOpc = AArch64::STRXui;
3561 unsigned X0Scratch = AArch64::NoRegister;
3563 if (X0Scratch != AArch64::NoRegister)
3569 if (Reg1 == AArch64::VG) {
3572 assert(Reg1 != AArch64::NoRegister);
3582 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
3583 AArch64::X0, LiveIn.PhysReg);
3591 RTLIB::Libcall LC = RTLIB::SMEABI_GET_CURRENT_VG;
3593 TRI->getCallPreservedMask(MF, TLI.getLibcallCallingConv(LC));
3605 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
3606 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
3609 assert((!NeedsWinCFI || !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
3610 "Windows unwdinding requires a consecutive (FP,LR) pair");
3614 unsigned FrameIdxReg1 = RPI.FrameIdx;
3615 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
3616 if (NeedsWinCFI && RPI.isPaired()) {
3621 if (RPI.isPaired() && RPI.isScalable()) {
3627 "Expects SVE2.1 or SME2 target and a predicate register");
3628#ifdef EXPENSIVE_CHECKS
3629 auto IsPPR = [](
const RegPairInfo &c) {
3630 return c.Reg1 == RegPairInfo::PPR;
3632 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
3633 auto IsZPR = [](
const RegPairInfo &c) {
3634 return c.Type == RegPairInfo::ZPR;
3636 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
3637 assert(!(PPRBegin < ZPRBegin) &&
3638 "Expected callee save predicate to be handled first");
3640 if (!PTrueCreated) {
3641 PTrueCreated =
true;
3646 if (!
MRI.isReserved(Reg1))
3648 if (!
MRI.isReserved(Reg2))
3650 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
3666 if (!
MRI.isReserved(Reg1))
3668 if (RPI.isPaired()) {
3669 if (!
MRI.isReserved(Reg2))
3689 if (RPI.Type == RegPairInfo::ZPR || RPI.Type == RegPairInfo::PPR) {
3708 DL =
MBBI->getDebugLoc();
3711 if (homogeneousPrologEpilog(MF, &
MBB)) {
3714 for (
auto &RPI : RegPairs) {
3722 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
3724 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
3725 std::reverse(PPRBegin, PPREnd);
3726 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
3728 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
3729 std::reverse(ZPRBegin, ZPREnd);
3731 bool PTrueCreated =
false;
3732 for (
const RegPairInfo &RPI : RegPairs) {
3733 unsigned Reg1 = RPI.Reg1;
3734 unsigned Reg2 = RPI.Reg2;
3745 unsigned Size =
TRI->getSpillSize(*RPI.RC);
3746 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
3748 case RegPairInfo::GPR:
3749 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
3751 case RegPairInfo::FPR64:
3752 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
3754 case RegPairInfo::FPR128:
3755 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
3757 case RegPairInfo::ZPR:
3758 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
3760 case RegPairInfo::PPR:
3761 LdrOpc =
Size == 16 ? AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO
3764 case RegPairInfo::VG:
3769 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
3770 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
3776 unsigned FrameIdxReg1 = RPI.FrameIdx;
3777 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
3778 if (NeedsWinCFI && RPI.isPaired()) {
3784 if (RPI.isPaired() && RPI.isScalable()) {
3789 "Expects SVE2.1 or SME2 target and a predicate register");
3790#ifdef EXPENSIVE_CHECKS
3791 assert(!(PPRBegin < ZPRBegin) &&
3792 "Expected callee save predicate to be handled first");
3794 if (!PTrueCreated) {
3795 PTrueCreated =
true;
3800 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
3817 if (RPI.isPaired()) {
3842 dyn_cast_or_null<FixedStackPseudoSourceValue>(MMO->
getPseudoValue());
3844 return std::optional<int>(PSV->getFrameIndex());
3855 return std::nullopt;
3861 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
3862 return std::nullopt;
3870void AArch64FrameLowering::determineStackHazardSlot(
3874 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
3887 bool HasFPRCSRs =
any_of(SavedRegs.
set_bits(), [](
unsigned Reg) {
3888 return AArch64::FPR64RegClass.contains(Reg) ||
3889 AArch64::FPR128RegClass.contains(Reg) ||
3890 AArch64::ZPRRegClass.contains(Reg) ||
3891 AArch64::PPRRegClass.contains(Reg);
3893 bool HasFPRStackObjects =
false;
3896 for (
auto &
MBB : MF) {
3897 for (
auto &
MI :
MBB) {
3899 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3902 FrameObjects[*FI] |= 2;
3904 FrameObjects[*FI] |= 1;
3908 HasFPRStackObjects =
3909 any_of(FrameObjects, [](
unsigned B) {
return (
B & 3) == 2; });
3912 if (HasFPRCSRs || HasFPRStackObjects) {
3915 << StackHazardSize <<
"\n");
3933 unsigned UnspilledCSGPR = AArch64::NoRegister;
3934 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
3943 unsigned ExtraCSSpill = 0;
3944 bool HasUnpairedGPR64 =
false;
3945 bool HasPairZReg =
false;
3950 for (
unsigned i = 0; CSRegs[i]; ++i) {
3951 const unsigned Reg = CSRegs[i];
3954 if (Reg == BasePointerReg)
3959 if (UserReservedRegs[Reg]) {
3960 SavedRegs.
reset(Reg);
3964 bool RegUsed = SavedRegs.
test(Reg);
3965 unsigned PairedReg = AArch64::NoRegister;
3966 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
3967 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
3968 AArch64::FPR128RegClass.contains(Reg)) {
3971 if (HasUnpairedGPR64)
3972 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
3974 PairedReg = CSRegs[i ^ 1];
3981 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
3982 PairedReg = AArch64::NoRegister;
3983 HasUnpairedGPR64 =
true;
3985 assert(PairedReg == AArch64::NoRegister ||
3986 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
3987 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
3988 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
3991 if (AArch64::GPR64RegClass.
contains(Reg) && !ReservedRegs[Reg]) {
3992 UnspilledCSGPR = Reg;
3993 UnspilledCSGPRPaired = PairedReg;
4001 if (RegInfo->getSpillSize(AArch64::PPRRegClass) == 16 &&
4002 AArch64::PPR_p8to15RegClass.contains(Reg)) {
4003 SavedRegs.
set(AArch64::P4);
4009 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
4010 !SavedRegs.
test(PairedReg)) {
4011 SavedRegs.
set(PairedReg);
4012 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
4013 !ReservedRegs[PairedReg])
4014 ExtraCSSpill = PairedReg;
4017 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
4018 SavedRegs.
test(CSRegs[i ^ 1]));
4026 if (PnReg != AArch64::NoRegister)
4032 SavedRegs.
set(AArch64::P8);
4037 "Predicate cannot be a reserved register");
4047 SavedRegs.
set(AArch64::X18);
4051 unsigned CSStackSize = 0;
4052 unsigned SVECSStackSize = 0;
4054 for (
unsigned Reg : SavedRegs.
set_bits()) {
4055 auto *RC =
TRI->getMinimalPhysRegClass(Reg);
4056 assert(RC &&
"expected register class!");
4057 auto SpillSize =
TRI->getSpillSize(*RC);
4058 if (AArch64::PPRRegClass.
contains(Reg) ||
4059 AArch64::ZPRRegClass.
contains(Reg))
4060 SVECSStackSize += SpillSize;
4062 CSStackSize += SpillSize;
4068 unsigned NumSavedRegs = SavedRegs.
count();
4077 determineStackHazardSlot(MF, SavedRegs);
4078 if (AFI->hasStackHazardSlotIndex())
4083 SavedRegs.
set(AArch64::LR);
4089 SavedRegs.
set(AArch64::FP);
4090 SavedRegs.
set(AArch64::LR);
4094 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
4095 for (
unsigned Reg : SavedRegs.
set_bits())
4101 int64_t SVEStackSize =
4102 alignTo(SVECSStackSize + estimateSVEStackObjectOffsets(MFI), 16);
4103 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
4112 int64_t CalleeStackUsed = 0;
4115 if (FixedOff > CalleeStackUsed)
4116 CalleeStackUsed = FixedOff;
4120 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
4121 CalleeStackUsed) > EstimatedStackSizeLimit;
4123 AFI->setHasStackFrame(
true);
4132 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
4134 <<
" to get a scratch register.\n");
4135 SavedRegs.
set(UnspilledCSGPR);
4136 ExtraCSSpill = UnspilledCSGPR;
4141 if (producePairRegisters(MF)) {
4142 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
4145 SavedRegs.
reset(UnspilledCSGPR);
4146 ExtraCSSpill = AArch64::NoRegister;
4149 SavedRegs.
set(UnspilledCSGPRPaired);
4158 unsigned Size =
TRI->getSpillSize(RC);
4159 Align Alignment =
TRI->getSpillAlign(RC);
4162 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
4163 <<
" as the emergency spill slot.\n");
4168 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
4172 if (
hasFP(MF) && AFI->hasSwiftAsyncContext())
4177 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
4180 AFI->getCalleeSavedStackSize() == AlignedCSStackSize) &&
4181 "Should not invalidate callee saved info");
4185 AFI->setCalleeSavedStackSize(AlignedCSStackSize);
4186 AFI->setCalleeSaveStackHasFreeSpace(AlignedCSStackSize != CSStackSize);
4187 AFI->setSVECalleeSavedStackSize(
alignTo(SVECSStackSize, 16));
4192 std::vector<CalleeSavedInfo> &CSI,
unsigned &MinCSFrameIndex,
4193 unsigned &MaxCSFrameIndex)
const {
4202 std::reverse(CSI.begin(), CSI.end());
4216 if ((
unsigned)FrameIdx < MinCSFrameIndex)
4217 MinCSFrameIndex = FrameIdx;
4218 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
4219 MaxCSFrameIndex = FrameIdx;
4226 find_if(CSI, [](
auto &
Info) {
return Info.getReg() == AArch64::LR; });
4227 if (It != CSI.end())
4228 CSI.insert(It, VGInfo);
4230 CSI.push_back(VGInfo);
4234 int HazardSlotIndex = std::numeric_limits<int>::max();
4235 for (
auto &CS : CSI) {
4243 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
4244 "Unexpected register order for hazard slot");
4246 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
4249 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
4250 MinCSFrameIndex = HazardSlotIndex;
4251 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
4252 MaxCSFrameIndex = HazardSlotIndex;
4258 CS.setFrameIdx(FrameIdx);
4260 if ((
unsigned)FrameIdx < MinCSFrameIndex)
4261 MinCSFrameIndex = FrameIdx;
4262 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
4263 MaxCSFrameIndex = FrameIdx;
4267 Reg == AArch64::FP) {
4270 if ((
unsigned)FrameIdx < MinCSFrameIndex)
4271 MinCSFrameIndex = FrameIdx;
4272 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
4273 MaxCSFrameIndex = FrameIdx;
4280 HazardSlotIndex == std::numeric_limits<int>::max()) {
4282 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
4285 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
4286 MinCSFrameIndex = HazardSlotIndex;
4287 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
4288 MaxCSFrameIndex = HazardSlotIndex;
4312 int &Min,
int &Max) {
4313 Min = std::numeric_limits<int>::max();
4314 Max = std::numeric_limits<int>::min();
4320 for (
auto &CS : CSI) {
4321 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
4322 AArch64::PPRRegClass.contains(CS.getReg())) {
4323 assert((Max == std::numeric_limits<int>::min() ||
4324 Max + 1 == CS.getFrameIdx()) &&
4325 "SVE CalleeSaves are not consecutive");
4327 Min = std::min(Min, CS.getFrameIdx());
4328 Max = std::max(Max, CS.getFrameIdx());
4331 return Min != std::numeric_limits<int>::max();
4340 int &MinCSFrameIndex,
4341 int &MaxCSFrameIndex,
4342 bool AssignOffsets) {
4347 "SVE vectors should never be passed on the stack by value, only by "
4351 auto Assign = [&MFI](
int FI, int64_t
Offset) {
4361 for (
int I = MinCSFrameIndex;
I <= MaxCSFrameIndex; ++
I) {
4377 int StackProtectorFI = -1;
4381 ObjectsToAllocate.
push_back(StackProtectorFI);
4387 if (
I == StackProtectorFI)
4389 if (MaxCSFrameIndex >=
I &&
I >= MinCSFrameIndex)
4398 for (
unsigned FI : ObjectsToAllocate) {
4403 if (Alignment >
Align(16))
4405 "Alignment of scalable vectors > 16 bytes is not yet supported");
4415int64_t AArch64FrameLowering::estimateSVEStackObjectOffsets(
4417 int MinCSFrameIndex, MaxCSFrameIndex;
4421int64_t AArch64FrameLowering::assignSVEStackObjectOffsets(
4432 if (PreferredReg != AArch64::NoRegister && UsedRegs.
available(PreferredReg))
4433 return PreferredReg;
4438 return AArch64::NoRegister;
4470 std::optional<int> *MaybeSpillFI,
4471 Register PreferredReg = AArch64::NoRegister)
4473 *MF.getSubtarget().getInstrInfo())),
4474 TRI(*MF.getSubtarget().getRegisterInfo()) {
4476 if (FreeReg != AArch64::NoRegister)
4478 assert(MaybeSpillFI &&
"Expected emergency spill slot FI information "
4479 "(attempted to spill in prologue/epilogue?)");
4480 if (!MaybeSpillFI->has_value()) {
4483 TRI.getSpillAlign(RC));
4485 FreeReg = SpillCandidate;
4486 SpillFI = MaybeSpillFI->value();
4510 Register FreeReg = AArch64::NoRegister;
4511 std::optional<int> SpillFI;
4556 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
4563 .
add(
MI.getOperand(0))
4569 .
add(
MI.getOperand(1))
4599 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
4603 MF,
MBB,
MI, AArch64::P0, AArch64::PPR_3bRegClass, UsedRegs, SR.
PPR3bRegs,
4609 bool IsNZCVUsed = !UsedRegs.
available(AArch64::NZCV);
4610 std::optional<ScopedScavengeOrSpill> NZCVSaveReg;
4612 NZCVSaveReg.emplace(
4613 MF,
MBB,
MI, AArch64::X0, AArch64::GPR64RegClass, UsedRegs, SR.
GPRRegs,
4619 .
add(
MI.getOperand(1))
4627 .
addImm(AArch64SysReg::NZCV)
4651 .
addImm(AArch64SysReg::NZCV)
4652 .
addReg(NZCVSaveReg->freeRegister())
4668 bool HasPPRSpills =
false;
4672 switch (
MI.getOpcode()) {
4673 case AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO:
4676 LastPTrue =
nullptr;
4678 LastPTrue, SpillSlots);
4679 MI.eraseFromParent();
4681 case AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO:
4683 MI.eraseFromParent();
4686 LastPTrue =
nullptr;
4691 return HasPPRSpills;
4703 if (AFI->
hasStackFrame() &&
TRI.getSpillSize(AArch64::PPRRegClass) == 16) {
4704 auto ComputeScavengeableRegisters = [&](
unsigned RegClassID) {
4705 BitVector Regs =
TRI.getAllocatableSet(MF,
TRI.getRegClass(RegClassID));
4706 assert(Regs.
count() > 0 &&
"Expected scavengeable registers");
4711 SR.
ZPRRegs = ComputeScavengeableRegisters(AArch64::ZPRRegClassID);
4713 SR.PPR3bRegs = ComputeScavengeableRegisters(AArch64::PPR_3bRegClassID);
4714 SR.GPRRegs = ComputeScavengeableRegisters(AArch64::GPR64RegClassID);
4726 assert((
Pass == 0 || !HasPPRSpills) &&
"Did not expect PPR spills");
4736 "Upwards growing stack unsupported");
4738 int MinCSFrameIndex, MaxCSFrameIndex;
4739 int64_t SVEStackSize =
4740 assignSVEStackObjectOffsets(MFI, MinCSFrameIndex, MaxCSFrameIndex);
4753 int64_t CurrentOffset =
4757 int FrameIndex =
H.CatchObj.FrameIndex;
4758 if ((FrameIndex != INT_MAX) && MFI.
getObjectOffset(FrameIndex) == 0) {
4769 int64_t UnwindHelpOffset =
alignTo(CurrentOffset + 8,
Align(16));
4772 "UnwindHelpOffset must be at the start of the fixed object area");
4788 assert(DstReg &&
"There must be a free register after frame setup");
4798struct TagStoreInstr {
4821 std::optional<int64_t> FrameRegUpdate;
4823 unsigned FrameRegUpdateFlags;
4834 :
MBB(
MBB), ZeroData(ZeroData) {
4840 void addInstruction(TagStoreInstr
I) {
4842 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
4843 "Non-adjacent tag store instructions.");
4846 void clear() { TagStores.
clear(); }
4858 const int64_t kMinOffset = -256 * 16;
4859 const int64_t kMaxOffset = 255 * 16;
4862 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
4863 if (BaseRegOffsetBytes < kMinOffset ||
4864 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
4868 BaseRegOffsetBytes % 16 != 0) {
4869 Register ScratchReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4873 BaseRegOffsetBytes = 0;
4878 int64_t InstrSize = (
Size > 16) ? 32 : 16;
4881 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
4882 : (ZeroData ? AArch64::STZ2Gi : AArch64::ST2Gi);
4883 assert(BaseRegOffsetBytes % 16 == 0);
4887 .
addImm(BaseRegOffsetBytes / 16)
4891 if (BaseRegOffsetBytes == 0)
4893 BaseRegOffsetBytes += InstrSize;
4907 :
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4908 Register SizeReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4912 int64_t LoopSize =
Size;
4915 if (FrameRegUpdate && *FrameRegUpdate)
4916 LoopSize -= LoopSize % 32;
4918 TII->get(ZeroData ? AArch64::STZGloop_wback
4919 : AArch64::STGloop_wback))
4926 LoopI->
setFlags(FrameRegUpdateFlags);
4928 int64_t ExtraBaseRegUpdate =
4929 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
4930 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
4931 <<
", Size=" <<
Size
4932 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
4933 <<
", FrameRegUpdate=" << FrameRegUpdate
4934 <<
", FrameRegOffset.getFixed()="
4935 << FrameRegOffset.
getFixed() <<
"\n");
4936 if (LoopSize <
Size) {
4940 int64_t STGOffset = ExtraBaseRegUpdate + 16;
4941 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
4942 "STG immediate out of range");
4944 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
4951 }
else if (ExtraBaseRegUpdate) {
4953 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
4954 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
4957 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
4970 int64_t
Size, int64_t *TotalOffset) {
4972 if ((
MI.getOpcode() == AArch64::ADDXri ||
4973 MI.getOpcode() == AArch64::SUBXri) &&
4974 MI.getOperand(0).getReg() == Reg &&
MI.getOperand(1).getReg() == Reg) {
4976 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
4977 if (
MI.getOpcode() == AArch64::SUBXri)
4988 const int64_t kMaxOffset = 4080 - 16;
4990 const int64_t kMinOffset = -4095;
4991 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
4992 PostOffset % 16 == 0) {
5003 for (
auto &TS : TSE) {
5007 if (
MI->memoperands_empty()) {
5011 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
5017 bool TryMergeSPUpdate) {
5018 if (TagStores.
empty())
5020 TagStoreInstr &FirstTagStore = TagStores[0];
5021 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
5022 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
5023 DL = TagStores[0].MI->getDebugLoc();
5027 *MF, FirstTagStore.Offset,
false ,
false , Reg,
5030 FrameRegUpdate = std::nullopt;
5032 mergeMemRefs(TagStores, CombinedMemRefs);
5035 dbgs() <<
"Replacing adjacent STG instructions:\n";
5036 for (
const auto &Instr : TagStores) {
5045 if (TagStores.
size() < 2)
5047 emitUnrolled(InsertI);
5050 int64_t TotalOffset = 0;
5051 if (TryMergeSPUpdate) {
5057 if (InsertI !=
MBB->
end() &&
5058 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
5060 UpdateInstr = &*InsertI++;
5066 if (!UpdateInstr && TagStores.
size() < 2)
5070 FrameRegUpdate = TotalOffset;
5071 FrameRegUpdateFlags = UpdateInstr->
getFlags();
5078 for (
auto &TS : TagStores)
5079 TS.MI->eraseFromParent();
5083 int64_t &
Size,
bool &ZeroData) {
5087 unsigned Opcode =
MI.getOpcode();
5088 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
5089 Opcode == AArch64::STZ2Gi);
5091 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
5092 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
5094 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
5097 Size =
MI.getOperand(2).getImm();
5101 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
5103 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
5108 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
5112 16 *
MI.getOperand(2).getImm();
5132 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
5138 constexpr int kScanLimit = 10;
5141 NextI != E && Count < kScanLimit; ++NextI) {
5150 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
5151 if (ZeroData != FirstZeroData)
5159 if (!
MI.isTransient())
5168 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
5184 LiveRegs.addLiveOuts(*
MBB);
5189 LiveRegs.stepBackward(*
I);
5192 if (LiveRegs.contains(AArch64::NZCV))
5196 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
5201 int64_t CurOffset = Instrs[0].Offset;
5202 for (
auto &Instr : Instrs) {
5203 if (CurOffset >
Instr.Offset)
5210 TagStoreEdit TSE(
MBB, FirstZeroData);
5211 std::optional<int64_t> EndOffset;
5212 for (
auto &Instr : Instrs) {
5213 if (EndOffset && *EndOffset !=
Instr.Offset) {
5215 TSE.emitCode(InsertI, TFI,
false);
5219 TSE.addInstruction(Instr);
5238 II = tryMergeAdjacentSTG(
II,
this, RS);
5254 bool IgnoreSPUpdates)
const {
5256 if (IgnoreSPUpdates) {
5259 FrameReg = AArch64::SP;
5269 FrameReg = AArch64::SP;
5294 bool IsValid =
false;
5296 int ObjectIndex = 0;
5298 int GroupIndex = -1;
5300 bool ObjectFirst =
false;
5303 bool GroupFirst =
false;
5308 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
5313 int NextGroupIndex = 0;
5314 std::vector<FrameObject> &Objects;
5317 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
5319 void EndCurrentGroup() {
5320 if (CurrentMembers.
size() > 1) {
5325 for (
int Index : CurrentMembers) {
5326 Objects[
Index].GroupIndex = NextGroupIndex;
5332 CurrentMembers.clear();
5336bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
5358 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
5359 A.GroupIndex,
A.ObjectIndex) <
5360 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
5361 B.GroupIndex,
B.ObjectIndex);
5372 std::vector<FrameObject> FrameObjects(MFI.getObjectIndexEnd());
5373 for (
auto &Obj : ObjectsToAllocate) {
5374 FrameObjects[Obj].IsValid =
true;
5375 FrameObjects[Obj].ObjectIndex = Obj;
5380 GroupBuilder GB(FrameObjects);
5381 for (
auto &
MBB : MF) {
5382 for (
auto &
MI :
MBB) {
5383 if (
MI.isDebugInstr())
5388 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
5391 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
5393 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
5398 switch (
MI.getOpcode()) {
5399 case AArch64::STGloop:
5400 case AArch64::STZGloop:
5404 case AArch64::STZGi:
5405 case AArch64::ST2Gi:
5406 case AArch64::STZ2Gi:
5418 if (FI >= 0 && FI < MFI.getObjectIndexEnd() &&
5419 FrameObjects[FI].IsValid)
5427 GB.AddMember(TaggedFI);
5429 GB.EndCurrentGroup();
5432 GB.EndCurrentGroup();
5437 FrameObject::AccessHazard;
5439 for (
auto &Obj : FrameObjects)
5440 if (!Obj.Accesses ||
5441 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
5442 Obj.Accesses = FrameObject::AccessGPR;
5451 FrameObjects[*TBPI].ObjectFirst =
true;
5452 FrameObjects[*TBPI].GroupFirst =
true;
5453 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
5454 if (FirstGroupIndex >= 0)
5455 for (FrameObject &Object : FrameObjects)
5456 if (Object.GroupIndex == FirstGroupIndex)
5457 Object.GroupFirst =
true;
5463 for (
auto &Obj : FrameObjects) {
5467 ObjectsToAllocate[i++] = Obj.ObjectIndex;
5471 dbgs() <<
"Final frame order:\n";
5472 for (
auto &Obj : FrameObjects) {
5475 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
5476 if (Obj.ObjectFirst)
5477 dbgs() <<
", first";
5479 dbgs() <<
", group-first";
5490AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
5501 MF.
insert(MBBInsertPoint, LoopMBB);
5503 MF.
insert(MBBInsertPoint, ExitMBB);
5538 return ExitMBB->
begin();
5541void AArch64FrameLowering::inlineStackProbeFixed(
5554 int64_t NumBlocks = FrameSize / ProbeSize;
5555 int64_t ResidualSize = FrameSize % ProbeSize;
5557 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
5558 << NumBlocks <<
" blocks of " << ProbeSize
5559 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
5564 for (
int i = 0; i < NumBlocks; ++i) {
5570 EmitAsyncCFI && !HasFP, CFAOffset);
5579 }
else if (NumBlocks != 0) {
5585 EmitAsyncCFI && !HasFP, CFAOffset);
5587 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
5589 if (EmitAsyncCFI && !HasFP) {
5596 if (ResidualSize != 0) {
5602 EmitAsyncCFI && !HasFP, CFAOffset);
5621 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
5622 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
5626 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
5627 Register ScratchReg =
MI->getOperand(0).getReg();
5628 int64_t FrameSize =
MI->getOperand(1).getImm();
5630 MI->getOperand(3).getImm());
5631 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
5634 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
5635 "Stack probe pseudo-instruction expected");
5638 Register TargetReg =
MI->getOperand(0).getReg();
5639 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
5641 MI->eraseFromParent();
5661 return std::make_tuple(start(),
Idx) <
5662 std::make_tuple(Rhs.
start(), Rhs.
Idx);
5667 return AccessTypes & (AccessType::GPR | AccessType::PPR);
5669 bool isSME()
const {
return AccessTypes & AccessType::FPR; }
5670 bool isMixed()
const {
return isCPU() && isSME(); }
5676 switch (AccessTypes) {
5677 case AccessType::FPR:
5679 case AccessType::PPR:
5681 case AccessType::GPR:
5683 case AccessType::NotAccessed:
5692 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
5693 if (
Offset.getScalable())
5694 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
5705void AArch64FrameLowering::emitRemarks(
5716 if (HazardSize == 0)
5724 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
5726 size_t NumFPLdSt = 0;
5727 size_t NumNonFPLdSt = 0;
5732 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
5741 StackAccesses[ArrIdx].Idx = FrameIdx;
5742 StackAccesses[ArrIdx].Offset =
5751 if (
MI.getOpcode() != AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO &&
5752 MI.getOpcode() != AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO &&
5753 AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg())) {
5761 StackAccesses[ArrIdx].AccessTypes |= RegTy;
5772 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
5783 if (StackAccesses.front().isMixed())
5784 MixedObjects.
push_back(&StackAccesses.front());
5786 for (
auto It = StackAccesses.begin(),
End = std::prev(StackAccesses.end());
5788 const auto &
First = *It;
5789 const auto &Second = *(It + 1);
5791 if (Second.isMixed())
5792 MixedObjects.push_back(&Second);
5794 if ((
First.isSME() && Second.isCPU()) ||
5795 (
First.isCPU() && Second.isSME())) {
5797 if (Distance < HazardSize)
5805 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
5806 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
5810 for (
const auto &
P : HazardPairs)
5811 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
5813 for (
const auto *Obj : MixedObjects)
5815 formatv(
"{0} accessed by both GP and FP instructions", *Obj).str());
unsigned const MachineRegisterInfo * MRI
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
static int64_t getArgumentStackToRestore(MachineFunction &MF, MachineBasicBlock &MBB)
Returns how much of the incoming argument stack area (in bytes) we should clean up in an epilogue.
static void getLiveRegsForEntryMBB(LivePhysRegs &LiveRegs, const MachineBasicBlock &MBB)
static void emitCalleeSavedRestores(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool SVE)
static void computeCalleeSaveRegisterPairs(MachineFunction &MF, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI, SmallVectorImpl< RegPairInfo > &RegPairs, bool NeedsFrameRecord)
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 Register findScratchNonCalleeSaveRegister(MachineBasicBlock *MBB, bool HasCall=false)
static const unsigned DefaultSafeSPDisplacement
This is the biggest offset to the stack pointer we can encode in aarch64 instructions (without using ...
static bool needsWinCFI(const MachineFunction &MF)
static bool isInPrologueOrEpilogue(const MachineInstr &MI)
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 requiresGetVGCall(MachineFunction &MF)
bool isVGInstruction(MachineBasicBlock::iterator MBBI, const TargetLowering &TLI)
bool enableMultiVectorSpillFill(const AArch64Subtarget &Subtarget, MachineFunction &MF)
static std::optional< int > getLdStFrameID(const MachineInstr &MI, const MachineFrameInfo &MFI)
static bool produceCompactUnwindFrame(MachineFunction &MF)
static cl::opt< bool > StackHazardInNonStreaming("aarch64-stack-hazard-in-non-streaming", cl::init(false), cl::Hidden)
static bool matchLibcall(const TargetLowering &TLI, const MachineOperand &MO, RTLIB::Libcall LC)
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 void fixupCalleeSaveRestoreStackOffset(MachineInstr &MI, uint64_t LocalStackSize, bool NeedsWinCFI, bool *HasWinCFI)
static bool requiresSaveVG(const MachineFunction &MF)
static bool invalidateWindowsRegisterPairing(unsigned Reg1, unsigned Reg2, bool NeedsWinCFI, bool IsFirst, const TargetRegisterInfo *TRI)
static bool windowsRequiresStackProbe(const MachineFunction &MF, uint64_t StackSizeInBytes)
static MachineBasicBlock::iterator convertCalleeSaveRestoreToSPPrePostIncDec(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, const TargetInstrInfo *TII, int CSStackSizeInc, bool NeedsWinCFI, bool *HasWinCFI, bool EmitCFI, MachineInstr::MIFlag FrameFlag=MachineInstr::FrameSetup, int CFAOffset=0)
static void fixupSEHOpcode(MachineBasicBlock::iterator MBBI, unsigned LocalStackSize)
static StackOffset getSVEStackSize(const MachineFunction &MF)
Returns the size of the entire SVE stackframe (calleesaves + spills).
static cl::opt< bool > DisableMultiVectorSpillFill("aarch64-disable-multivector-spill-fill", cl::desc("Disable use of LD/ST pairs for SME2 or SVE2p1"), cl::init(false), cl::Hidden)
static cl::opt< bool > EnableRedZone("aarch64-redzone", cl::desc("enable use of redzone on AArch64"), cl::init(false), cl::Hidden)
static MachineBasicBlock::iterator InsertSEH(MachineBasicBlock::iterator MBBI, const TargetInstrInfo &TII, MachineInstr::MIFlag Flag)
static void getLivePhysRegsUpTo(MachineInstr &MI, const TargetRegisterInfo &TRI, LivePhysRegs &LiveRegs)
Collect live registers from the end of MI's parent up to (including) MI in LiveRegs.
static bool isLikelyToHaveSVEStack(const MachineFunction &MF)
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 IsSVECalleeSave(MachineBasicBlock::iterator I)
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 void emitDefineCFAWithFP(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned FixedObject)
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 StackOffset getFPOffset(const MachineFunction &MF, int64_t ObjectOffset)
static bool isTargetWindows(const MachineFunction &MF)
static bool shouldSignReturnAddressEverywhere(const MachineFunction &MF)
static StackOffset getStackOffset(const MachineFunction &MF, int64_t ObjectOffset)
static void emitShadowCallStackEpilogue(const TargetInstrInfo &TII, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, bool NeedsWinCFI)
static int64_t upperBound(StackOffset Size)
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 bool isFuncletReturnInstr(const MachineInstr &MI)
static unsigned getStackHazardSize(const MachineFunction &MF)
static void emitShadowCallStackPrologue(const TargetInstrInfo &TII, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, bool NeedsWinCFI, bool NeedsUnwindInfo)
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)
static unsigned getFixedObjectSize(const MachineFunction &MF, const AArch64FunctionInfo *AFI, bool IsWin64, bool IsFunclet)
Returns the size of the fixed object area (allocated next to sp on entry) On Win64 this may include a...
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Analysis containing CSE Info
DXIL Forward Handle Accesses
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static const HTTPClientCleanup Cleanup
const HexagonInstrInfo * TII
std::pair< Instruction::BinaryOps, Value * > OffsetOp
Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
static std::string getTypeString(Type *T)
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Register const TargetRegisterInfo * TRI
uint64_t IntrinsicInst * II
static const MCPhysReg FPR[]
FPR - The set of FP registers that should be allocated for arguments on Darwin and AIX.
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.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static const unsigned FramePtr
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.
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.
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 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 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...
void emitPacRetPlusLeafHardening(MachineFunction &MF) const
Harden the entire function with pac-ret.
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
bool needsShadowCallStackPrologueEpilogue(MachineFunction &MF) const
void setSwiftAsyncContextFrameIdx(int FI)
unsigned getTailCallReservedStack() const
unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const
void setCalleeSaveBaseToFrameRecordOffset(int Offset)
bool hasStackProbing() const
unsigned getArgumentStackToRestore() const
void setLocalStackSize(uint64_t Size)
int getCalleeSaveBaseToFrameRecordOffset() const
bool hasStreamingModeChanges() const
bool shouldSignReturnAddress(const MachineFunction &MF) const
void setPredicateRegForFillSpill(unsigned Reg)
int getStackHazardSlotIndex() const
int64_t getStackProbeSize() const
uint64_t getStackSizeSVE() const
void setHasRedZone(bool s)
bool hasStackFrame() const
std::optional< int > getTaggedBasePointerIndex() const
SMEAttrs getSMEFnAttrs() const
uint64_t getLocalStackSize() const
void setStackRealigned(bool s)
bool needsDwarfUnwindInfo(const MachineFunction &MF) const
unsigned getVarArgsGPRSize() const
void setStackSizeSVE(uint64_t S)
bool isStackRealigned() const
bool hasSwiftAsyncContext() const
bool hasStackHazardSlotIndex() const
void setTaggedBasePointerOffset(unsigned Offset)
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 isSEHInstruction(const MachineInstr &MI)
Return true if the instructions is a SEH instruction used for unwinding on Windows.
static bool isFpOrNEON(Register Reg)
Returns whether the physical register is FP or NEON.
BitVector getReservedRegs(const MachineFunction &MF) const override
BitVector getUserReservedRegs(const MachineFunction &MF) const
bool hasBasePointer(const MachineFunction &MF) const
bool cannotEliminateFrame(const MachineFunction &MF) const
unsigned getBaseRegister() const
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
bool isTargetILP32() const
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
const Triple & getTargetTriple() const
const char * getChkStkName() 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 isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
bool swiftAsyncContextIsDynamicallySet() const
Return whether FrameLowering should always set the "extended frame present" bit in FP,...
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this functions.
unsigned getRedZoneSize(const Function &F) const
bool supportSwiftError() const override
Return true if the target supports swifterror attribute.
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.
LLVM_ABI bool hasAttrSomewhere(Attribute::AttrKind Kind, unsigned *Index=nullptr) const
Return true if the specified attribute is set for at least one parameter or for the return value.
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.
void buildEscape(StringRef Bytes, StringRef Comment="") const
void buildDefCFAOffset(int64_t Offset, MCSymbol *Label=nullptr) const
void buildRestore(MCRegister Reg) const
void buildDefCFARegister(MCRegister Reg) const
void insertCFIInst(const MCCFIInstruction &CFIInst) const
void buildDefCFA(MCRegister Reg, int64_t Offset) const
The CalleeSavedInfo class tracks the information need to locate where a callee saved register is in t...
bool hasOptSize() const
Optimize this function for size (-Os) or minimum size (-Oz).
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.
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL, Register DestReg, Register SrcReg, bool KillSrc, bool RenamableDest=false, bool RenamableSrc=false) const override
Emit instructions to copy a pair of physical registers.
void storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg, bool isKill, int FrameIndex, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, Register VReg, MachineInstr::MIFlag Flags=MachineInstr::NoFlags) const override
Store the specified register of the given register class to the specified stack frame index.
void loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register DestReg, int FrameIndex, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, Register VReg, MachineInstr::MIFlag Flags=MachineInstr::NoFlags) const override
Load the specified register of the given register class from the specified stack frame index.
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
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Wrapper class representing physical registers. Should be passed by value.
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
instr_iterator instr_begin()
iterator_range< livein_iterator > liveins() const
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
bool isEHFuncletEntry() const
Returns true if this is the entry block of an EH funclet.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
bool isReturnBlock() const
Convenience function that returns true if the block ends in a return instruction.
MachineInstr & instr_back()
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
LLVM_ABI DebugLoc findDebugLoc(instr_iterator MBBI)
Find the next valid DebugLoc starting at MBBI, skipping any debug instructions.
LLVM_ABI iterator getLastNonDebugInstr(bool SkipPseudoOp=true)
Returns an iterator to the last non-debug instruction in the basic block, or end().
instr_iterator instr_end()
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
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 '...
LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
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 ...
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
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...
Align getMaxAlign() const
Return the alignment in bytes that this function must be aligned to, which is greater than the defaul...
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.
void setHasWinCFI(bool v)
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.
MCContext & getContext() const
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
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)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
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 & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
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.
void setImm(int64_t immVal)
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
static MachineOperand CreateImm(int64_t Val)
const char * getSymbolName() const
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)
StringRef - Represent a constant reference to a string, i.e.
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.
const char * getLibcallName(RTLIB::Libcall Call) const
Get the libcall routine name for the specified libcall.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
Primary interface to the complete machine description for the target machine.
CodeModel::Model getCodeModel() const
Returns the code model.
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
SwiftAsyncFramePointerMode SwiftAsyncFramePointer
Control when and how the Swift async frame pointer bit should be set.
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...
const TargetRegisterClass * getMinimalPhysRegClass(MCRegister Reg, MVT VT=MVT::Other) const
Returns the Register Class of a physical register of the given type, picking the most sub register cl...
Align getSpillAlign(const TargetRegisterClass &RC) const
Return the minimum required alignment in bytes for a spill slot for a register of this class.
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.
virtual const TargetLowering * getTargetLowering() const
Triple - Helper class for working with autoconf configuration names.
LLVM_ABI StringRef getArchName() const
Get the architecture (first) component of the triple.
static constexpr TypeSize getFixed(ScalarTy ExactSize)
The instances of the Type class are immutable: once they are created, they are never changed.
constexpr ScalarTy getFixedValue() const
self_iterator getIterator()
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.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
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...
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
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 Attrs[]
Key for Kernel::Metadata::mAttrs.
@ 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.
@ Kill
The last use of a register.
@ Undef
Value of the register doesn't matter.
Reg
All possible values of the reg field in the ModR/M byte.
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)
MCCFIInstruction createDefCFA(const TargetRegisterInfo &TRI, unsigned FrameReg, unsigned Reg, const StackOffset &Offset, bool LastAdjustmentWasScalable=true)
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)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
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.
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)
@ Always
Always set the bit.
@ Never
Never set the bit.
@ DeploymentBased
Determine whether to set the bit statically or dynamically based on the deployment target.
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)
LLVM_ABI EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
@ Success
The lock was released successfully.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
unsigned getDefRegState(bool B)
MCCFIInstruction createCFAOffset(const TargetRegisterInfo &MRI, unsigned Reg, const StackOffset &OffsetFromDefCFA, std::optional< int64_t > IncomingVGOffsetFromDefCFA)
unsigned getKillRegState(bool B)
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)
bool isAsynchronousEHPersonality(EHPersonality Pers)
Returns true if this personality function catches asynchronous exceptions.
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.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
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