257#define DEBUG_TYPE "frame-info"
260 cl::desc(
"enable use of redzone on AArch64"),
264 "stack-tagging-merge-settag",
274 cl::desc(
"Emit homogeneous prologue and epilogue for the size "
275 "optimization (default = off)"));
287 "aarch64-disable-multivector-spill-fill",
291STATISTIC(NumRedZoneFunctions,
"Number of functions using red zone");
307 int64_t ArgumentPopSize = 0;
308 if (IsTailCallReturn) {
314 ArgumentPopSize = StackAdjust.
getImm();
323 return ArgumentPopSize;
334bool AArch64FrameLowering::homogeneousPrologEpilog(
359 if (AFI->hasSwiftAsyncContext() || AFI->hasStreamingModeChanges())
366 unsigned NumGPRs = 0;
367 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
369 if (Reg == AArch64::LR) {
370 assert(CSRegs[
I + 1] == AArch64::FP);
371 if (NumGPRs % 2 != 0)
375 if (AArch64::GPR64RegClass.
contains(Reg))
383bool AArch64FrameLowering::producePairRegisters(
MachineFunction &MF)
const {
402 if (
MI.isDebugInstr() ||
MI.isPseudo() ||
403 MI.getOpcode() == AArch64::ADDXri ||
404 MI.getOpcode() == AArch64::ADDSXri)
431 if (!IsWin64 || IsFunclet) {
436 Attribute::SwiftAsync))
441 const unsigned UnwindHelpObject = (MF.
hasEHFunclets() ? 8 : 0);
443 alignTo(VarArgsArea + UnwindHelpObject, 16);
460 const unsigned RedZoneSize =
473 bool LowerQRegCopyThroughMem = Subtarget.hasFPARMv8() &&
477 return !(MFI.
hasCalls() ||
hasFP(MF) || NumBytes > RedZoneSize ||
538 unsigned Opc =
I->getOpcode();
539 bool IsDestroy = Opc ==
TII->getCallFrameDestroyOpcode();
540 uint64_t CalleePopAmount = IsDestroy ?
I->getOperand(1).getImm() : 0;
543 int64_t Amount =
I->getOperand(0).getImm();
551 if (CalleePopAmount == 0) {
562 assert(Amount > -0xffffff && Amount < 0xffffff &&
"call frame too large");
573 "non-reserved call frame without var sized objects?");
582 }
else if (CalleePopAmount != 0) {
585 assert(CalleePopAmount < 0xffffff &&
"call frame too large");
592void AArch64FrameLowering::emitCalleeSavedGPRLocations(
598 bool LocallyStreaming =
599 Attrs.hasStreamingBody() && !Attrs.hasStreamingInterface();
610 for (
const auto &Info : CSI) {
611 unsigned FrameIdx =
Info.getFrameIdx();
615 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
616 int64_t DwarfReg =
TRI.getDwarfRegNum(
Info.getReg(),
true);
623 (!LocallyStreaming &&
624 DwarfReg ==
TRI.getDwarfRegNum(AArch64::VG,
true)))
635void AArch64FrameLowering::emitCalleeSavedSVELocations(
651 for (
const auto &Info : CSI) {
657 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
692 const MCInstrDesc &CFIDesc =
TII.get(TargetOpcode::CFI_INSTRUCTION);
698 nullptr,
TRI.getDwarfRegNum(AArch64::SP,
true), 0));
702 if (MFI.shouldSignReturnAddress(MF)) {
703 auto CFIInst = MFI.branchProtectionPAuthLR()
711 if (MFI.needsShadowCallStackPrologueEpilogue(MF))
713 TRI.getDwarfRegNum(AArch64::X18,
true));
716 const std::vector<CalleeSavedInfo> &CSI =
718 for (
const auto &
Info : CSI) {
719 unsigned Reg =
Info.getReg();
720 if (!
TRI.regNeedsCFI(Reg, Reg))
723 TRI.getDwarfRegNum(Reg,
true));
742 for (
const auto &
Info : CSI) {
747 unsigned Reg =
Info.getReg();
752 if (!
Info.isRestored())
756 nullptr,
TRI.getDwarfRegNum(
Info.getReg(),
true)));
763void AArch64FrameLowering::emitCalleeSavedGPRRestores(
768void AArch64FrameLowering::emitCalleeSavedSVERestores(
776 static const int64_t MAX_BYTES_PER_SCALABLE_BYTE = 16;
777 return Size.getScalable() * MAX_BYTES_PER_SCALABLE_BYTE +
Size.getFixed();
780void AArch64FrameLowering::allocateStackSpace(
782 int64_t RealignmentPadding,
StackOffset AllocSize,
bool NeedsWinCFI,
783 bool *HasWinCFI,
bool EmitCFI,
StackOffset InitialOffset,
784 bool FollowupAllocs)
const {
797 const uint64_t AndMask = ~(MaxAlign - 1);
800 Register TargetReg = RealignmentPadding
806 EmitCFI, InitialOffset);
808 if (RealignmentPadding) {
829 if (AllocSize.
getScalable() == 0 && RealignmentPadding == 0) {
831 assert(ScratchReg != AArch64::NoRegister);
841 if (FollowupAllocs) {
858 if (
upperBound(AllocSize) + RealignmentPadding <= ProbeSize) {
859 Register ScratchReg = RealignmentPadding
862 assert(ScratchReg != AArch64::NoRegister);
866 EmitCFI, InitialOffset);
867 if (RealignmentPadding) {
875 if (FollowupAllocs ||
upperBound(AllocSize) + RealignmentPadding >
891 assert(TargetReg != AArch64::NoRegister);
895 EmitCFI, InitialOffset);
896 if (RealignmentPadding) {
916 if (RealignmentPadding)
929 case AArch64::W##n: \
930 case AArch64::X##n: \
955 case AArch64::B##n: \
956 case AArch64::H##n: \
957 case AArch64::S##n: \
958 case AArch64::D##n: \
959 case AArch64::Q##n: \
960 return HasSVE ? AArch64::Z##n : AArch64::Q##n
997void AArch64FrameLowering::emitZeroCallUsedRegs(
BitVector RegsToZero,
1005 DL =
MBBI->getDebugLoc();
1015 if (
TRI.isGeneralPurposeRegister(MF, Reg)) {
1018 GPRsToZero.set(XReg);
1022 FPRsToZero.set(XReg);
1038 {AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, AArch64::P4,
1039 AArch64::P5, AArch64::P6, AArch64::P7, AArch64::P8, AArch64::P9,
1040 AArch64::P10, AArch64::P11, AArch64::P12, AArch64::P13, AArch64::P14,
1042 if (RegsToZero[PReg])
1054 for (
unsigned i = 0; CSRegs[i]; ++i)
1055 LiveRegs.
addReg(CSRegs[i]);
1089 for (
unsigned Reg : AArch64::GPR64RegClass) {
1093 return AArch64::NoRegister;
1139 StackSizeInBytes >=
uint64_t(MFI.getStackProbeSize());
1145 F.needsUnwindTableEntry();
1148bool AArch64FrameLowering::shouldCombineCSRLocalStackBump(
1154 if (homogeneousPrologEpilog(MF))
1177 if (MFI.hasVarSizedObjects())
1180 if (
RegInfo->hasStackRealignment(MF))
1197bool AArch64FrameLowering::shouldCombineCSRLocalStackBumpInEpilogue(
1199 if (!shouldCombineCSRLocalStackBump(*
MBB.
getParent(), StackBumpBytes))
1208 while (LastI != Begin) {
1210 if (LastI->isTransient())
1215 switch (LastI->getOpcode()) {
1216 case AArch64::STGloop:
1217 case AArch64::STZGloop:
1219 case AArch64::STZGi:
1220 case AArch64::ST2Gi:
1221 case AArch64::STZ2Gi:
1234 unsigned Opc =
MBBI->getOpcode();
1238 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1239 int Imm =
MBBI->getOperand(ImmIdx).getImm();
1247 case AArch64::LDPDpost:
1250 case AArch64::STPDpre: {
1251 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1252 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1253 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFRegP_X))
1260 case AArch64::LDPXpost:
1263 case AArch64::STPXpre: {
1266 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1267 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFPLR_X))
1271 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveRegP_X))
1278 case AArch64::LDRDpost:
1281 case AArch64::STRDpre: {
1282 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1283 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveFReg_X))
1289 case AArch64::LDRXpost:
1292 case AArch64::STRXpre: {
1293 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1300 case AArch64::STPDi:
1301 case AArch64::LDPDi: {
1302 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1303 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1311 case AArch64::STPXi:
1312 case AArch64::LDPXi: {
1315 if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
1327 case AArch64::STRXui:
1328 case AArch64::LDRXui: {
1329 int Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1336 case AArch64::STRDui:
1337 case AArch64::LDRDui: {
1338 unsigned Reg =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1345 case AArch64::STPQi:
1346 case AArch64::LDPQi: {
1347 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(0).getReg());
1348 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1349 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQP))
1356 case AArch64::LDPQpost:
1359 case AArch64::STPQpre: {
1360 unsigned Reg0 =
RegInfo->getSEHRegNum(
MBBI->getOperand(1).getReg());
1361 unsigned Reg1 =
RegInfo->getSEHRegNum(
MBBI->getOperand(2).getReg());
1362 MIB =
BuildMI(MF,
DL,
TII.get(AArch64::SEH_SaveAnyRegQPX))
1376 unsigned LocalStackSize) {
1378 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
1379 switch (
MBBI->getOpcode()) {
1382 case AArch64::SEH_SaveFPLR:
1383 case AArch64::SEH_SaveRegP:
1384 case AArch64::SEH_SaveReg:
1385 case AArch64::SEH_SaveFRegP:
1386 case AArch64::SEH_SaveFReg:
1387 case AArch64::SEH_SaveAnyRegQP:
1388 case AArch64::SEH_SaveAnyRegQPX:
1389 ImmOpnd = &
MBBI->getOperand(ImmIdx);
1409 if (ST.isTargetDarwin())
1415 unsigned Opc =
MBBI->getOpcode();
1416 if (Opc == AArch64::CNTD_XPiI || Opc == AArch64::RDSVLI_XI ||
1417 Opc == AArch64::UBFMXri)
1421 if (Opc == AArch64::ORRXrr)
1424 if (Opc == AArch64::BL) {
1425 auto Op1 =
MBBI->getOperand(0);
1426 return Op1.isSymbol() &&
1427 (
StringRef(Op1.getSymbolName()) ==
"__arm_get_current_vg");
1440 bool NeedsWinCFI,
bool *HasWinCFI,
bool EmitCFI,
1442 int CFAOffset = 0) {
1454 switch (
MBBI->getOpcode()) {
1457 case AArch64::STPXi:
1458 NewOpc = AArch64::STPXpre;
1460 case AArch64::STPDi:
1461 NewOpc = AArch64::STPDpre;
1463 case AArch64::STPQi:
1464 NewOpc = AArch64::STPQpre;
1466 case AArch64::STRXui:
1467 NewOpc = AArch64::STRXpre;
1469 case AArch64::STRDui:
1470 NewOpc = AArch64::STRDpre;
1472 case AArch64::STRQui:
1473 NewOpc = AArch64::STRQpre;
1475 case AArch64::LDPXi:
1476 NewOpc = AArch64::LDPXpost;
1478 case AArch64::LDPDi:
1479 NewOpc = AArch64::LDPDpost;
1481 case AArch64::LDPQi:
1482 NewOpc = AArch64::LDPQpost;
1484 case AArch64::LDRXui:
1485 NewOpc = AArch64::LDRXpost;
1487 case AArch64::LDRDui:
1488 NewOpc = AArch64::LDRDpost;
1490 case AArch64::LDRQui:
1491 NewOpc = AArch64::LDRQpost;
1495 int64_t MinOffset, MaxOffset;
1497 NewOpc, Scale, Width, MinOffset, MaxOffset);
1503 if (
MBBI->getOperand(
MBBI->getNumOperands() - 1).getImm() != 0 ||
1504 CSStackSizeInc < MinOffset * (int64_t)Scale.
getFixedValue() ||
1505 CSStackSizeInc > MaxOffset * (int64_t)Scale.
getFixedValue()) {
1516 false, NeedsWinCFI, HasWinCFI, EmitCFI,
1519 return std::prev(
MBBI);
1524 auto SEH = std::next(
MBBI);
1526 SEH->eraseFromParent();
1533 unsigned OpndIdx = 0;
1534 for (
unsigned OpndEnd =
MBBI->getNumOperands() - 1; OpndIdx < OpndEnd;
1536 MIB.
add(
MBBI->getOperand(OpndIdx));
1538 assert(
MBBI->getOperand(OpndIdx).getImm() == 0 &&
1539 "Unexpected immediate offset in first/last callee-save save/restore "
1541 assert(
MBBI->getOperand(OpndIdx - 1).getReg() == AArch64::SP &&
1542 "Unexpected base register in callee-save save/restore instruction!");
1543 assert(CSStackSizeInc % Scale == 0);
1544 MIB.
addImm(CSStackSizeInc / (
int)Scale);
1575 unsigned Opc =
MI.getOpcode();
1578 case AArch64::STPXi:
1579 case AArch64::STRXui:
1580 case AArch64::STPDi:
1581 case AArch64::STRDui:
1582 case AArch64::LDPXi:
1583 case AArch64::LDRXui:
1584 case AArch64::LDPDi:
1585 case AArch64::LDRDui:
1588 case AArch64::STPQi:
1589 case AArch64::STRQui:
1590 case AArch64::LDPQi:
1591 case AArch64::LDRQui:
1598 unsigned OffsetIdx =
MI.getNumExplicitOperands() - 1;
1599 assert(
MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP &&
1600 "Unexpected base register in callee-save save/restore instruction!");
1604 assert(LocalStackSize % Scale == 0);
1605 OffsetOpnd.
setImm(OffsetOpnd.
getImm() + LocalStackSize / Scale);
1610 assert(
MBBI !=
MI.getParent()->end() &&
"Expecting a valid instruction");
1612 "Expecting a SEH instruction");
1627 switch (
I->getOpcode()) {
1630 case AArch64::PTRUE_C_B:
1631 case AArch64::LD1B_2Z_IMM:
1632 case AArch64::ST1B_2Z_IMM:
1633 case AArch64::STR_ZXI:
1634 case AArch64::STR_PXI:
1635 case AArch64::LDR_ZXI:
1636 case AArch64::LDR_PXI:
1637 case AArch64::PTRUE_B:
1638 case AArch64::CPY_ZPzI_B:
1639 case AArch64::CMPNE_PPzZI_B:
1650 bool NeedsUnwindInfo) {
1666 if (NeedsUnwindInfo) {
1669 static const char CFIInst[] = {
1670 dwarf::DW_CFA_val_expression,
1673 static_cast<char>(
unsigned(dwarf::DW_OP_breg18)),
1674 static_cast<char>(-8) & 0x7f,
1677 nullptr,
StringRef(CFIInst,
sizeof(CFIInst))));
1715 const int OffsetToFirstCalleeSaveFromFP =
1719 unsigned Reg =
TRI->getDwarfRegNum(
FramePtr,
true);
1721 nullptr, Reg, FixedObject - OffsetToFirstCalleeSaveFromFP));
1753 bool HasFP =
hasFP(MF);
1755 bool HasWinCFI =
false;
1764 while (NonFrameStart !=
End &&
1769 if (NonFrameStart !=
MBB.
end()) {
1785 if (NonFrameStart ==
MBB.
end())
1790 for (auto &Op : MI.operands())
1791 if (Op.isReg() && Op.isDef())
1792 assert(!LiveRegs.contains(Op.getReg()) &&
1793 "live register clobbered by inserted prologue instructions");
1810 if (MFnI.needsShadowCallStackPrologueEpilogue(MF))
1812 MFnI.needsDwarfUnwindInfo(MF));
1814 if (MFnI.shouldSignReturnAddress(MF)) {
1821 if (EmitCFI && MFnI.isMTETagged()) {
1899 assert(!HasFP &&
"unexpected function without stack frame but with FP");
1901 "unexpected function without stack frame but with SVE objects");
1910 ++NumRedZoneFunctions;
1942 bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes);
1943 bool HomPrologEpilog = homogeneousPrologEpilog(MF);
1944 if (CombineSPBump) {
1945 assert(!SVEStackSize &&
"Cannot combine SP bump with SVE");
1951 }
else if (HomPrologEpilog) {
1953 NumBytes -= PrologueSaveSize;
1954 }
else if (PrologueSaveSize != 0) {
1956 MBB,
MBBI,
DL,
TII, -PrologueSaveSize, NeedsWinCFI, &HasWinCFI,
1958 NumBytes -= PrologueSaveSize;
1960 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
1967 if (CombineSPBump &&
1971 NeedsWinCFI, &HasWinCFI);
1976 if (!IsFunclet && HasFP) {
1988 bool HaveInitialContext = Attrs.hasAttrSomewhere(Attribute::SwiftAsync);
1989 if (HaveInitialContext)
1991 Register Reg = HaveInitialContext ? AArch64::X22 : AArch64::XZR;
2007 if (HomPrologEpilog) {
2020 if (NeedsWinCFI && HasWinCFI) {
2025 NeedsWinCFI =
false;
2036 emitCalleeSavedGPRLocations(
MBB,
MBBI);
2039 const bool NeedsRealignment =
2040 NumBytes && !IsFunclet && RegInfo->hasStackRealignment(MF);
2041 const int64_t RealignmentPadding =
2047 uint64_t NumWords = (NumBytes + RealignmentPadding) >> 4;
2055 if (NumBytes >= (1 << 28))
2057 "unwinding purposes");
2059 uint32_t LowNumWords = NumWords & 0xFFFF;
2066 if ((NumWords & 0xFFFF0000) != 0) {
2069 .
addImm((NumWords & 0xFFFF0000) >> 16)
2140 if (RealignmentPadding > 0) {
2141 if (RealignmentPadding >= 4096) {
2144 .
addImm(RealignmentPadding)
2154 .
addImm(RealignmentPadding)
2171 StackOffset SVECalleeSavesSize = {}, SVELocalsSize = SVEStackSize;
2177 LLVM_DEBUG(
dbgs() <<
"SVECalleeSavedStackSize = " << CalleeSavedSize
2180 CalleeSavesBegin =
MBBI;
2184 CalleeSavesEnd =
MBBI;
2187 SVELocalsSize = SVEStackSize - SVECalleeSavesSize;
2194 allocateStackSpace(
MBB, CalleeSavesBegin, 0, SVECalleeSavesSize,
false,
2195 nullptr, EmitAsyncCFI && !HasFP, CFAOffset,
2197 CFAOffset += SVECalleeSavesSize;
2200 emitCalleeSavedSVELocations(
MBB, CalleeSavesEnd);
2205 "Cannot use redzone with stack realignment");
2210 allocateStackSpace(
MBB, CalleeSavesEnd, RealignmentPadding,
2212 NeedsWinCFI, &HasWinCFI, EmitAsyncCFI && !HasFP,
2224 if (!IsFunclet && RegInfo->hasBasePointer(MF)) {
2236 if (NeedsWinCFI && HasWinCFI) {
2244 if (IsFunclet &&
F.hasPersonalityFn()) {
2254 if (EmitCFI && !EmitAsyncCFI) {
2261 *RegInfo, AArch64::SP, AArch64::SP, TotalSize,
2267 emitCalleeSavedGPRLocations(
MBB,
MBBI);
2268 emitCalleeSavedSVELocations(
MBB,
MBBI);
2273 switch (
MI.getOpcode()) {
2276 case AArch64::CATCHRET:
2277 case AArch64::CLEANUPRET:
2292 bool HasWinCFI =
false;
2293 bool IsFunclet =
false;
2296 DL =
MBBI->getDebugLoc();
2304 BuildMI(MBB, MBB.getFirstTerminator(), DL,
2305 TII->get(AArch64::PAUTH_EPILOGUE))
2306 .setMIFlag(MachineInstr::FrameDestroy);
2316 TII->get(AArch64::SEH_EpilogEnd))
2343 int64_t AfterCSRPopSize = ArgumentStackToRestore;
2351 if (homogeneousPrologEpilog(MF, &
MBB)) {
2355 auto HomogeneousEpilog = std::prev(LastPopI);
2356 if (HomogeneousEpilog->getOpcode() == AArch64::HOM_Epilog)
2357 LastPopI = HomogeneousEpilog;
2367 assert(AfterCSRPopSize == 0);
2370 bool CombineSPBump = shouldCombineCSRLocalStackBumpInEpilogue(
MBB, NumBytes);
2372 bool CombineAfterCSRBump =
false;
2373 if (!CombineSPBump && PrologueSaveSize != 0) {
2375 while (Pop->getOpcode() == TargetOpcode::CFI_INSTRUCTION ||
2377 Pop = std::prev(Pop);
2380 const MachineOperand &OffsetOp = Pop->getOperand(Pop->getNumOperands() - 1);
2384 if (OffsetOp.
getImm() == 0 && AfterCSRPopSize >= 0) {
2386 MBB, Pop,
DL,
TII, PrologueSaveSize, NeedsWinCFI, &HasWinCFI, EmitCFI,
2393 AfterCSRPopSize += PrologueSaveSize;
2394 CombineAfterCSRBump =
true;
2403 while (LastPopI != Begin) {
2409 }
else if (CombineSPBump)
2411 NeedsWinCFI, &HasWinCFI);
2423 EpilogStartI = LastPopI;
2459 if (CombineSPBump) {
2460 assert(!SVEStackSize &&
"Cannot combine SP bump with SVE");
2463 if (EmitCFI &&
hasFP(MF)) {
2465 unsigned Reg = RegInfo.getDwarfRegNum(AArch64::SP,
true);
2480 NumBytes -= PrologueSaveSize;
2481 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
2485 StackOffset DeallocateBefore = {}, DeallocateAfter = SVEStackSize;
2488 RestoreBegin = std::prev(RestoreEnd);
2489 while (RestoreBegin !=
MBB.
begin() &&
2498 DeallocateBefore = SVEStackSize - CalleeSavedSizeAsOffset;
2499 DeallocateAfter = CalleeSavedSizeAsOffset;
2521 MBB, RestoreBegin,
DL, AArch64::SP, AArch64::SP,
2523 false,
false,
nullptr, EmitCFI && !
hasFP(MF),
2530 false,
nullptr, EmitCFI && !
hasFP(MF),
2536 false,
nullptr, EmitCFI && !
hasFP(MF),
2541 emitCalleeSavedSVERestores(
MBB, RestoreEnd);
2548 if (RedZone && AfterCSRPopSize == 0)
2555 bool NoCalleeSaveRestore = PrologueSaveSize == 0;
2556 int64_t StackRestoreBytes = RedZone ? 0 : NumBytes;
2557 if (NoCalleeSaveRestore)
2558 StackRestoreBytes += AfterCSRPopSize;
2561 MBB, LastPopI,
DL, AArch64::SP, AArch64::SP,
2568 if (NoCalleeSaveRestore || AfterCSRPopSize == 0) {
2581 MBB, LastPopI,
DL, AArch64::SP, AArch64::FP,
2584 }
else if (NumBytes)
2590 if (EmitCFI &&
hasFP(MF)) {
2592 unsigned Reg = RegInfo.getDwarfRegNum(AArch64::SP,
true);
2603 if (AfterCSRPopSize) {
2604 assert(AfterCSRPopSize > 0 &&
"attempting to reallocate arg stack that an "
2605 "interrupt may have clobbered");
2610 false, NeedsWinCFI, &HasWinCFI, EmitCFI,
2657 if (MFI.isVariableSizedObjectIndex(FI)) {
2671 bool IsFixed = MFI.isFixedObjectIndex(FI);
2676 if (!IsFixed && !IsCSR)
2677 ScalableOffset = -SVEStackSize;
2689 int64_t ObjectOffset) {
2693 bool IsWin64 = Subtarget.isCallingConvWin64(
F.getCallingConv(),
F.isVarArg());
2694 unsigned FixedObject =
2703 int64_t ObjectOffset) {
2714 return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
2721 bool ForSimm)
const {
2724 bool isFixed = MFI.isFixedObjectIndex(FI);
2731 const MachineFunction &MF, int64_t ObjectOffset,
bool isFixed,
bool isSVE,
2732 Register &FrameReg,
bool PreferFP,
bool ForSimm)
const {
2755 PreferFP &= !SVEStackSize;
2763 }
else if (isCSR && RegInfo->hasStackRealignment(MF)) {
2767 assert(
hasFP(MF) &&
"Re-aligned stack must have frame pointer");
2769 }
else if (
hasFP(MF) && !RegInfo->hasStackRealignment(MF)) {
2774 bool FPOffsetFits = !ForSimm || FPOffset >= -256;
2775 PreferFP |=
Offset > -FPOffset && !SVEStackSize;
2777 if (FPOffset >= 0) {
2781 }
else if (MFI.hasVarSizedObjects()) {
2785 bool CanUseBP = RegInfo->hasBasePointer(MF);
2786 if (FPOffsetFits && CanUseBP)
2793 }
else if (MF.
hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
2800 "Funclets should only be present on Win64");
2804 if (FPOffsetFits && PreferFP)
2811 ((isFixed || isCSR) || !RegInfo->hasStackRealignment(MF) || !UseFP) &&
2812 "In the presence of dynamic stack pointer realignment, "
2813 "non-argument/CSR objects cannot be accessed through the frame pointer");
2825 RegInfo->hasStackRealignment(MF))) {
2826 FrameReg = RegInfo->getFrameRegister(MF);
2830 FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister()
2836 if (UseFP && !(isFixed || isCSR))
2837 ScalableOffset = -SVEStackSize;
2838 if (!UseFP && (isFixed || isCSR))
2839 ScalableOffset = SVEStackSize;
2842 FrameReg = RegInfo->getFrameRegister(MF);
2847 if (RegInfo->hasBasePointer(MF))
2848 FrameReg = RegInfo->getBaseRegister();
2850 assert(!MFI.hasVarSizedObjects() &&
2851 "Can't use SP when we have var sized objects.");
2852 FrameReg = AArch64::SP;
2879 Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
2885 bool NeedsWinCFI,
bool IsFirst,
2894 if (Reg2 == AArch64::FP)
2898 if (
TRI->getEncodingValue(Reg2) ==
TRI->getEncodingValue(Reg1) + 1)
2905 if (Reg1 >= AArch64::X19 && Reg1 <= AArch64::X27 &&
2906 (Reg1 - AArch64::X19) % 2 == 0 && Reg2 == AArch64::LR && !IsFirst)
2916 bool UsesWinAAPCS,
bool NeedsWinCFI,
2917 bool NeedsFrameRecord,
bool IsFirst,
2925 if (NeedsFrameRecord)
2926 return Reg2 == AArch64::LR;
2934 unsigned Reg1 = AArch64::NoRegister;
2935 unsigned Reg2 = AArch64::NoRegister;
2938 enum RegType { GPR, FPR64, FPR128, PPR, ZPR, VG }
Type;
2941 RegPairInfo() =
default;
2943 bool isPaired()
const {
return Reg2 != AArch64::NoRegister; }
2945 bool isScalable()
const {
return Type == PPR ||
Type == ZPR; }
2951 for (
unsigned PReg = AArch64::P8; PReg <= AArch64::P15; ++PReg) {
2952 if (SavedRegs.
test(PReg)) {
2953 unsigned PNReg = PReg - AArch64::P0 + AArch64::PN0;
2957 return AArch64::NoRegister;
2967 bool IsLocallyStreaming =
2973 return Subtarget.hasSVE2p1() ||
2974 (Subtarget.hasSME2() &&
2975 (!IsLocallyStreaming && Subtarget.
isStreaming()));
2981 bool NeedsFrameRecord) {
2992 unsigned Count = CSI.
size();
2999 "Odd number of callee-saved regs to spill!");
3001 int StackFillDir = -1;
3003 unsigned FirstReg = 0;
3011 FirstReg = Count - 1;
3018 for (
unsigned i = FirstReg; i < Count; i += RegInc) {
3020 RPI.Reg1 = CSI[i].getReg();
3022 if (AArch64::GPR64RegClass.
contains(RPI.Reg1)) {
3023 RPI.Type = RegPairInfo::GPR;
3024 RPI.RC = &AArch64::GPR64RegClass;
3025 }
else if (AArch64::FPR64RegClass.
contains(RPI.Reg1)) {
3026 RPI.Type = RegPairInfo::FPR64;
3027 RPI.RC = &AArch64::FPR64RegClass;
3028 }
else if (AArch64::FPR128RegClass.
contains(RPI.Reg1)) {
3029 RPI.Type = RegPairInfo::FPR128;
3030 RPI.RC = &AArch64::FPR128RegClass;
3031 }
else if (AArch64::ZPRRegClass.
contains(RPI.Reg1)) {
3032 RPI.Type = RegPairInfo::ZPR;
3033 RPI.RC = &AArch64::ZPRRegClass;
3034 }
else if (AArch64::PPRRegClass.
contains(RPI.Reg1)) {
3035 RPI.Type = RegPairInfo::PPR;
3036 RPI.RC = &AArch64::PPRRegClass;
3037 }
else if (RPI.Reg1 == AArch64::VG) {
3038 RPI.Type = RegPairInfo::VG;
3039 RPI.RC = &AArch64::FIXED_REGSRegClass;
3048 ByteOffset += StackFillDir * StackHazardSize;
3051 int Scale =
TRI->getSpillSize(*RPI.RC);
3054 Register NextReg = CSI[i + RegInc].getReg();
3055 bool IsFirst = i == FirstReg;
3057 case RegPairInfo::GPR:
3058 if (AArch64::GPR64RegClass.
contains(NextReg) &&
3060 NeedsWinCFI, NeedsFrameRecord, IsFirst,
3064 case RegPairInfo::FPR64:
3065 if (AArch64::FPR64RegClass.
contains(NextReg) &&
3070 case RegPairInfo::FPR128:
3071 if (AArch64::FPR128RegClass.
contains(NextReg))
3074 case RegPairInfo::PPR:
3076 case RegPairInfo::ZPR:
3078 ((RPI.Reg1 - AArch64::Z0) & 1) == 0 && (NextReg == RPI.Reg1 + 1)) {
3081 int Offset = (ScalableByteOffset + StackFillDir * 2 * Scale) / Scale;
3086 case RegPairInfo::VG:
3097 assert((!RPI.isPaired() ||
3098 (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) &&
3099 "Out of order callee saved regs!");
3101 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP ||
3102 RPI.Reg1 == AArch64::LR) &&
3103 "FrameRecord must be allocated together with LR");
3106 assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
3107 RPI.Reg2 == AArch64::LR) &&
3108 "FrameRecord must be allocated together with LR");
3116 ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
3117 RPI.Reg1 + 1 == RPI.Reg2))) &&
3118 "Callee-save registers not saved as adjacent register pair!");
3120 RPI.FrameIdx = CSI[i].getFrameIdx();
3123 RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
3125 int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
3126 assert(OffsetPre % Scale == 0);
3128 if (RPI.isScalable())
3129 ScalableByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
3131 ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale);
3136 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
3137 (IsWindows && RPI.Reg2 == AArch64::LR)))
3138 ByteOffset += StackFillDir * 8;
3142 if (NeedGapToAlignStack && !NeedsWinCFI && !RPI.isScalable() &&
3143 RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired() &&
3144 ByteOffset % 16 != 0) {
3145 ByteOffset += 8 * StackFillDir;
3151 NeedGapToAlignStack =
false;
3154 int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
3155 assert(OffsetPost % Scale == 0);
3158 int Offset = NeedsWinCFI ? OffsetPre : OffsetPost;
3163 ((!IsWindows && RPI.Reg2 == AArch64::FP) ||
3164 (IsWindows && RPI.Reg2 == AArch64::LR)))
3166 RPI.Offset =
Offset / Scale;
3168 assert((!RPI.isPaired() ||
3169 (!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) ||
3170 (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) &&
3171 "Offset out of bounds for LDP/STP immediate");
3173 auto isFrameRecord = [&] {
3175 return IsWindows ? RPI.Reg1 == AArch64::FP && RPI.Reg2 == AArch64::LR
3176 : RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP;
3184 return i > 0 && RPI.Reg1 == AArch64::FP &&
3185 CSI[i - 1].getReg() == AArch64::LR;
3190 if (NeedsFrameRecord && isFrameRecord())
3207 std::reverse(RegPairs.
begin(), RegPairs.
end());
3226 MRI.freezeReservedRegs();
3228 if (homogeneousPrologEpilog(MF)) {
3232 for (
auto &RPI : RegPairs) {
3237 if (!
MRI.isReserved(RPI.Reg1))
3239 if (RPI.isPaired() && !
MRI.isReserved(RPI.Reg2))
3244 bool PTrueCreated =
false;
3246 unsigned Reg1 = RPI.Reg1;
3247 unsigned Reg2 = RPI.Reg2;
3260 unsigned Size =
TRI->getSpillSize(*RPI.RC);
3261 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
3263 case RegPairInfo::GPR:
3264 StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui;
3266 case RegPairInfo::FPR64:
3267 StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui;
3269 case RegPairInfo::FPR128:
3270 StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui;
3272 case RegPairInfo::ZPR:
3273 StrOpc = RPI.isPaired() ? AArch64::ST1B_2Z_IMM : AArch64::STR_ZXI;
3275 case RegPairInfo::PPR:
3277 Size == 16 ? AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO : AArch64::STR_PXI;
3279 case RegPairInfo::VG:
3280 StrOpc = AArch64::STRXui;
3284 unsigned X0Scratch = AArch64::NoRegister;
3285 if (Reg1 == AArch64::VG) {
3288 assert(Reg1 != AArch64::NoRegister);
3291 if (Attrs.hasStreamingBody() && !Attrs.hasStreamingInterface() &&
3316 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
3317 AArch64::X0, LiveIn.PhysReg);
3321 if (X0Scratch != AArch64::NoRegister)
3328 const uint32_t *RegMask =
TRI->getCallPreservedMask(
3343 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
3344 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
3347 assert((!NeedsWinCFI || !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) &&
3348 "Windows unwdinding requires a consecutive (FP,LR) pair");
3352 unsigned FrameIdxReg1 = RPI.FrameIdx;
3353 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
3354 if (NeedsWinCFI && RPI.isPaired()) {
3359 if (RPI.isPaired() && RPI.isScalable()) {
3365 "Expects SVE2.1 or SME2 target and a predicate register");
3366#ifdef EXPENSIVE_CHECKS
3367 auto IsPPR = [](
const RegPairInfo &c) {
3368 return c.Reg1 == RegPairInfo::PPR;
3370 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
3371 auto IsZPR = [](
const RegPairInfo &c) {
3372 return c.Type == RegPairInfo::ZPR;
3374 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
3375 assert(!(PPRBegin < ZPRBegin) &&
3376 "Expected callee save predicate to be handled first");
3378 if (!PTrueCreated) {
3379 PTrueCreated =
true;
3384 if (!
MRI.isReserved(Reg1))
3386 if (!
MRI.isReserved(Reg2))
3388 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0));
3404 if (!
MRI.isReserved(Reg1))
3406 if (RPI.isPaired()) {
3407 if (!
MRI.isReserved(Reg2))
3427 if (RPI.Type == RegPairInfo::ZPR || RPI.Type == RegPairInfo::PPR) {
3433 if (X0Scratch != AArch64::NoRegister)
3453 DL =
MBBI->getDebugLoc();
3456 if (homogeneousPrologEpilog(MF, &
MBB)) {
3459 for (
auto &RPI : RegPairs) {
3467 auto IsPPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::PPR; };
3468 auto PPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsPPR);
3469 auto PPREnd = std::find_if_not(PPRBegin, RegPairs.
end(), IsPPR);
3470 std::reverse(PPRBegin, PPREnd);
3471 auto IsZPR = [](
const RegPairInfo &c) {
return c.Type == RegPairInfo::ZPR; };
3472 auto ZPRBegin = std::find_if(RegPairs.
begin(), RegPairs.
end(), IsZPR);
3473 auto ZPREnd = std::find_if_not(ZPRBegin, RegPairs.
end(), IsZPR);
3474 std::reverse(ZPRBegin, ZPREnd);
3476 bool PTrueCreated =
false;
3477 for (
const RegPairInfo &RPI : RegPairs) {
3478 unsigned Reg1 = RPI.Reg1;
3479 unsigned Reg2 = RPI.Reg2;
3490 unsigned Size =
TRI->getSpillSize(*RPI.RC);
3491 Align Alignment =
TRI->getSpillAlign(*RPI.RC);
3493 case RegPairInfo::GPR:
3494 LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui;
3496 case RegPairInfo::FPR64:
3497 LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui;
3499 case RegPairInfo::FPR128:
3500 LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui;
3502 case RegPairInfo::ZPR:
3503 LdrOpc = RPI.isPaired() ? AArch64::LD1B_2Z_IMM : AArch64::LDR_ZXI;
3505 case RegPairInfo::PPR:
3506 LdrOpc =
Size == 16 ? AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO
3509 case RegPairInfo::VG:
3514 dbgs() <<
") -> fi#(" << RPI.FrameIdx;
3515 if (RPI.isPaired())
dbgs() <<
", " << RPI.FrameIdx + 1;
3521 unsigned FrameIdxReg1 = RPI.FrameIdx;
3522 unsigned FrameIdxReg2 = RPI.FrameIdx + 1;
3523 if (NeedsWinCFI && RPI.isPaired()) {
3529 if (RPI.isPaired() && RPI.isScalable()) {
3534 "Expects SVE2.1 or SME2 target and a predicate register");
3535#ifdef EXPENSIVE_CHECKS
3536 assert(!(PPRBegin < ZPRBegin) &&
3537 "Expected callee save predicate to be handled first");
3539 if (!PTrueCreated) {
3540 PTrueCreated =
true;
3545 MIB.
addReg( AArch64::Z0_Z1 + (RPI.Reg1 - AArch64::Z0),
3562 if (RPI.isPaired()) {
3587 dyn_cast_or_null<FixedStackPseudoSourceValue>(MMO->
getPseudoValue());
3589 return std::optional<int>(PSV->getFrameIndex());
3600 return std::nullopt;
3606 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
3607 return std::nullopt;
3615void AArch64FrameLowering::determineStackHazardSlot(
3618 if (StackHazardSize == 0 || StackHazardSize % 16 != 0 ||
3631 bool HasFPRCSRs =
any_of(SavedRegs.
set_bits(), [](
unsigned Reg) {
3632 return AArch64::FPR64RegClass.contains(Reg) ||
3633 AArch64::FPR128RegClass.contains(Reg) ||
3634 AArch64::ZPRRegClass.contains(Reg) ||
3635 AArch64::PPRRegClass.contains(Reg);
3637 bool HasFPRStackObjects =
false;
3640 for (
auto &
MBB : MF) {
3641 for (
auto &
MI :
MBB) {
3643 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
3646 FrameObjects[*FI] |= 2;
3648 FrameObjects[*FI] |= 1;
3652 HasFPRStackObjects =
3653 any_of(FrameObjects, [](
unsigned B) {
return (
B & 3) == 2; });
3656 if (HasFPRCSRs || HasFPRStackObjects) {
3659 << StackHazardSize <<
"\n");
3677 unsigned UnspilledCSGPR = AArch64::NoRegister;
3678 unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
3687 unsigned ExtraCSSpill = 0;
3688 bool HasUnpairedGPR64 =
false;
3689 bool HasPairZReg =
false;
3691 for (
unsigned i = 0; CSRegs[i]; ++i) {
3692 const unsigned Reg = CSRegs[i];
3695 if (Reg == BasePointerReg)
3698 bool RegUsed = SavedRegs.
test(Reg);
3699 unsigned PairedReg = AArch64::NoRegister;
3700 const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
3701 if (RegIsGPR64 || AArch64::FPR64RegClass.
contains(Reg) ||
3702 AArch64::FPR128RegClass.contains(Reg)) {
3705 if (HasUnpairedGPR64)
3706 PairedReg = CSRegs[i % 2 == 0 ? i - 1 : i + 1];
3708 PairedReg = CSRegs[i ^ 1];
3715 if (RegIsGPR64 && !AArch64::GPR64RegClass.
contains(PairedReg)) {
3716 PairedReg = AArch64::NoRegister;
3717 HasUnpairedGPR64 =
true;
3719 assert(PairedReg == AArch64::NoRegister ||
3720 AArch64::GPR64RegClass.
contains(Reg, PairedReg) ||
3721 AArch64::FPR64RegClass.
contains(Reg, PairedReg) ||
3722 AArch64::FPR128RegClass.
contains(Reg, PairedReg));
3725 if (AArch64::GPR64RegClass.
contains(Reg) &&
3727 UnspilledCSGPR = Reg;
3728 UnspilledCSGPRPaired = PairedReg;
3736 if (RegInfo->getSpillSize(AArch64::PPRRegClass) == 16 &&
3737 AArch64::PPR_p8to15RegClass.contains(Reg)) {
3738 SavedRegs.
set(AArch64::P4);
3744 if (producePairRegisters(MF) && PairedReg != AArch64::NoRegister &&
3745 !SavedRegs.
test(PairedReg)) {
3746 SavedRegs.
set(PairedReg);
3747 if (AArch64::GPR64RegClass.
contains(PairedReg) &&
3749 ExtraCSSpill = PairedReg;
3752 HasPairZReg |= (AArch64::ZPRRegClass.contains(Reg, CSRegs[i ^ 1]) &&
3753 SavedRegs.
test(CSRegs[i ^ 1]));
3761 if (PnReg != AArch64::NoRegister)
3767 SavedRegs.
set(AArch64::P8);
3772 "Predicate cannot be a reserved register");
3782 SavedRegs.
set(AArch64::X18);
3786 unsigned CSStackSize = 0;
3787 unsigned SVECSStackSize = 0;
3789 for (
unsigned Reg : SavedRegs.
set_bits()) {
3790 auto *RC =
TRI->getMinimalPhysRegClass(Reg);
3791 assert(RC &&
"expected register class!");
3792 auto SpillSize =
TRI->getSpillSize(*RC);
3793 if (AArch64::PPRRegClass.
contains(Reg) ||
3794 AArch64::ZPRRegClass.
contains(Reg))
3795 SVECSStackSize += SpillSize;
3797 CSStackSize += SpillSize;
3807 if (Attrs.hasStreamingBody() && !Attrs.hasStreamingInterface())
3815 determineStackHazardSlot(MF, SavedRegs);
3816 if (AFI->hasStackHazardSlotIndex())
3820 unsigned NumSavedRegs = SavedRegs.
count();
3826 SavedRegs.
set(AArch64::FP);
3827 SavedRegs.
set(AArch64::LR);
3831 dbgs() <<
"*** determineCalleeSaves\nSaved CSRs:";
3832 for (
unsigned Reg : SavedRegs.
set_bits())
3838 int64_t SVEStackSize =
3839 alignTo(SVECSStackSize + estimateSVEStackObjectOffsets(MFI), 16);
3840 bool CanEliminateFrame = (SavedRegs.
count() == 0) && !SVEStackSize;
3849 int64_t CalleeStackUsed = 0;
3852 if (FixedOff > CalleeStackUsed)
3853 CalleeStackUsed = FixedOff;
3857 bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize +
3858 CalleeStackUsed) > EstimatedStackSizeLimit;
3860 AFI->setHasStackFrame(
true);
3869 if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) {
3871 <<
" to get a scratch register.\n");
3872 SavedRegs.
set(UnspilledCSGPR);
3873 ExtraCSSpill = UnspilledCSGPR;
3878 if (producePairRegisters(MF)) {
3879 if (UnspilledCSGPRPaired == AArch64::NoRegister) {
3882 SavedRegs.
reset(UnspilledCSGPR);
3883 ExtraCSSpill = AArch64::NoRegister;
3886 SavedRegs.
set(UnspilledCSGPRPaired);
3895 unsigned Size =
TRI->getSpillSize(RC);
3896 Align Alignment =
TRI->getSpillAlign(RC);
3899 LLVM_DEBUG(
dbgs() <<
"No available CS registers, allocated fi#" << FI
3900 <<
" as the emergency spill slot.\n");
3905 CSStackSize += 8 * (SavedRegs.
count() - NumSavedRegs);
3909 if (
hasFP(MF) && AFI->hasSwiftAsyncContext())
3914 << EstimatedStackSize + AlignedCSStackSize <<
" bytes.\n");
3917 AFI->getCalleeSavedStackSize() == AlignedCSStackSize) &&
3918 "Should not invalidate callee saved info");
3922 AFI->setCalleeSavedStackSize(AlignedCSStackSize);
3923 AFI->setCalleeSaveStackHasFreeSpace(AlignedCSStackSize != CSStackSize);
3924 AFI->setSVECalleeSavedStackSize(
alignTo(SVECSStackSize, 16));
3929 std::vector<CalleeSavedInfo> &CSI,
unsigned &MinCSFrameIndex,
3930 unsigned &MaxCSFrameIndex)
const {
3939 std::reverse(CSI.begin(), CSI.end());
3953 if ((
unsigned)FrameIdx < MinCSFrameIndex)
3954 MinCSFrameIndex = FrameIdx;
3955 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
3956 MaxCSFrameIndex = FrameIdx;
3961 std::vector<CalleeSavedInfo> VGSaves;
3965 VGInfo.setRestored(
false);
3966 VGSaves.push_back(VGInfo);
3970 if (Attrs.hasStreamingBody() && !Attrs.hasStreamingInterface())
3971 VGSaves.push_back(VGInfo);
3973 bool InsertBeforeLR =
false;
3975 for (
unsigned I = 0;
I < CSI.size();
I++)
3976 if (CSI[
I].
getReg() == AArch64::LR) {
3977 InsertBeforeLR =
true;
3978 CSI.insert(CSI.begin() +
I, VGSaves.begin(), VGSaves.end());
3982 if (!InsertBeforeLR)
3983 CSI.insert(CSI.end(), VGSaves.begin(), VGSaves.end());
3987 int HazardSlotIndex = std::numeric_limits<int>::max();
3988 for (
auto &CS : CSI) {
3996 assert(HazardSlotIndex == std::numeric_limits<int>::max() &&
3997 "Unexpected register order for hazard slot");
3999 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
4002 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
4003 MinCSFrameIndex = HazardSlotIndex;
4004 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
4005 MaxCSFrameIndex = HazardSlotIndex;
4011 CS.setFrameIdx(FrameIdx);
4013 if ((
unsigned)FrameIdx < MinCSFrameIndex)
4014 MinCSFrameIndex = FrameIdx;
4015 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
4016 MaxCSFrameIndex = FrameIdx;
4020 Reg == AArch64::FP) {
4023 if ((
unsigned)FrameIdx < MinCSFrameIndex)
4024 MinCSFrameIndex = FrameIdx;
4025 if ((
unsigned)FrameIdx > MaxCSFrameIndex)
4026 MaxCSFrameIndex = FrameIdx;
4033 HazardSlotIndex == std::numeric_limits<int>::max()) {
4035 LLVM_DEBUG(
dbgs() <<
"Created CSR Hazard at slot " << HazardSlotIndex
4038 if ((
unsigned)HazardSlotIndex < MinCSFrameIndex)
4039 MinCSFrameIndex = HazardSlotIndex;
4040 if ((
unsigned)HazardSlotIndex > MaxCSFrameIndex)
4041 MaxCSFrameIndex = HazardSlotIndex;
4065 int &Min,
int &Max) {
4066 Min = std::numeric_limits<int>::max();
4067 Max = std::numeric_limits<int>::min();
4073 for (
auto &CS : CSI) {
4074 if (AArch64::ZPRRegClass.
contains(CS.getReg()) ||
4075 AArch64::PPRRegClass.contains(CS.getReg())) {
4076 assert((Max == std::numeric_limits<int>::min() ||
4077 Max + 1 == CS.getFrameIdx()) &&
4078 "SVE CalleeSaves are not consecutive");
4080 Min = std::min(Min, CS.getFrameIdx());
4081 Max = std::max(Max, CS.getFrameIdx());
4084 return Min != std::numeric_limits<int>::max();
4093 int &MinCSFrameIndex,
4094 int &MaxCSFrameIndex,
4095 bool AssignOffsets) {
4100 "SVE vectors should never be passed on the stack by value, only by "
4104 auto Assign = [&MFI](
int FI, int64_t
Offset) {
4114 for (
int I = MinCSFrameIndex;
I <= MaxCSFrameIndex; ++
I) {
4130 int StackProtectorFI = -1;
4134 ObjectsToAllocate.
push_back(StackProtectorFI);
4140 if (
I == StackProtectorFI)
4142 if (MaxCSFrameIndex >=
I &&
I >= MinCSFrameIndex)
4151 for (
unsigned FI : ObjectsToAllocate) {
4156 if (Alignment >
Align(16))
4158 "Alignment of scalable vectors > 16 bytes is not yet supported");
4168int64_t AArch64FrameLowering::estimateSVEStackObjectOffsets(
4170 int MinCSFrameIndex, MaxCSFrameIndex;
4174int64_t AArch64FrameLowering::assignSVEStackObjectOffsets(
4185 if (PreferredReg != AArch64::NoRegister && UsedRegs.
available(PreferredReg))
4186 return PreferredReg;
4191 return AArch64::NoRegister;
4223 std::optional<int> *MaybeSpillFI,
4224 Register PreferredReg = AArch64::NoRegister)
4226 *MF.getSubtarget().getInstrInfo())),
4227 TRI(*MF.getSubtarget().getRegisterInfo()) {
4229 if (FreeReg != AArch64::NoRegister)
4231 assert(MaybeSpillFI &&
"Expected emergency spill slot FI information "
4232 "(attempted to spill in prologue/epilogue?)");
4233 if (!MaybeSpillFI->has_value()) {
4236 TRI.getSpillAlign(RC));
4238 FreeReg = SpillCandidate;
4239 SpillFI = MaybeSpillFI->value();
4263 Register FreeReg = AArch64::NoRegister;
4264 std::optional<int> SpillFI;
4309 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
4316 .
add(
MI.getOperand(0))
4322 .
add(
MI.getOperand(1))
4352 MF,
MBB,
MI, AArch64::Z0, AArch64::ZPRRegClass, UsedRegs, SR.
ZPRRegs,
4356 MF,
MBB,
MI, AArch64::P0, AArch64::PPR_3bRegClass, UsedRegs, SR.
PPR3bRegs,
4362 bool IsNZCVUsed = !UsedRegs.
available(AArch64::NZCV);
4363 std::optional<ScopedScavengeOrSpill> NZCVSaveReg;
4365 NZCVSaveReg.emplace(
4366 MF,
MBB,
MI, AArch64::X0, AArch64::GPR64RegClass, UsedRegs, SR.
GPRRegs,
4372 .
add(
MI.getOperand(1))
4380 .
addImm(AArch64SysReg::NZCV)
4404 .
addImm(AArch64SysReg::NZCV)
4405 .
addReg(NZCVSaveReg->freeRegister())
4421 bool HasPPRSpills =
false;
4425 switch (
MI.getOpcode()) {
4426 case AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO:
4429 LastPTrue =
nullptr;
4431 LastPTrue, SpillSlots);
4432 MI.eraseFromParent();
4434 case AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO:
4436 MI.eraseFromParent();
4439 LastPTrue =
nullptr;
4444 return HasPPRSpills;
4456 if (AFI->
hasStackFrame() &&
TRI.getSpillSize(AArch64::PPRRegClass) == 16) {
4457 auto ComputeScavengeableRegisters = [&](
unsigned RegClassID) {
4458 BitVector Regs =
TRI.getAllocatableSet(MF,
TRI.getRegClass(RegClassID));
4459 assert(Regs.
count() > 0 &&
"Expected scavengeable registers");
4464 SR.
ZPRRegs = ComputeScavengeableRegisters(AArch64::ZPRRegClassID);
4466 SR.PPR3bRegs = ComputeScavengeableRegisters(AArch64::PPR_3bRegClassID);
4467 SR.GPRRegs = ComputeScavengeableRegisters(AArch64::GPR64RegClassID);
4479 assert((
Pass == 0 || !HasPPRSpills) &&
"Did not expect PPR spills");
4489 "Upwards growing stack unsupported");
4491 int MinCSFrameIndex, MaxCSFrameIndex;
4492 int64_t SVEStackSize =
4493 assignSVEStackObjectOffsets(MFI, MinCSFrameIndex, MaxCSFrameIndex);
4512 int64_t FixedObject =
4525 assert(DstReg &&
"There must be a free register after frame setup");
4534struct TagStoreInstr {
4557 std::optional<int64_t> FrameRegUpdate;
4559 unsigned FrameRegUpdateFlags;
4570 :
MBB(
MBB), ZeroData(ZeroData) {
4576 void addInstruction(TagStoreInstr
I) {
4578 TagStores.
back().Offset + TagStores.
back().Size ==
I.Offset) &&
4579 "Non-adjacent tag store instructions.");
4582 void clear() { TagStores.
clear(); }
4594 const int64_t kMinOffset = -256 * 16;
4595 const int64_t kMaxOffset = 255 * 16;
4598 int64_t BaseRegOffsetBytes = FrameRegOffset.
getFixed();
4599 if (BaseRegOffsetBytes < kMinOffset ||
4600 BaseRegOffsetBytes + (
Size -
Size % 32) > kMaxOffset ||
4604 BaseRegOffsetBytes % 16 != 0) {
4605 Register ScratchReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4608 BaseReg = ScratchReg;
4609 BaseRegOffsetBytes = 0;
4614 int64_t InstrSize = (
Size > 16) ? 32 : 16;
4617 ? (ZeroData ? AArch64::STZGi : AArch64::STGi)
4618 : (ZeroData ? AArch64::STZ2Gi : AArch64::ST2Gi);
4619 assert(BaseRegOffsetBytes % 16 == 0);
4623 .
addImm(BaseRegOffsetBytes / 16)
4627 if (BaseRegOffsetBytes == 0)
4629 BaseRegOffsetBytes += InstrSize;
4643 :
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4644 Register SizeReg =
MRI->createVirtualRegister(&AArch64::GPR64RegClass);
4648 int64_t LoopSize =
Size;
4651 if (FrameRegUpdate && *FrameRegUpdate)
4652 LoopSize -= LoopSize % 32;
4654 TII->get(ZeroData ? AArch64::STZGloop_wback
4655 : AArch64::STGloop_wback))
4662 LoopI->
setFlags(FrameRegUpdateFlags);
4664 int64_t ExtraBaseRegUpdate =
4665 FrameRegUpdate ? (*FrameRegUpdate - FrameRegOffset.
getFixed() -
Size) : 0;
4666 LLVM_DEBUG(
dbgs() <<
"TagStoreEdit::emitLoop: LoopSize=" << LoopSize
4667 <<
", Size=" <<
Size
4668 <<
", ExtraBaseRegUpdate=" << ExtraBaseRegUpdate
4669 <<
", FrameRegUpdate=" << FrameRegUpdate
4670 <<
", FrameRegOffset.getFixed()="
4671 << FrameRegOffset.
getFixed() <<
"\n");
4672 if (LoopSize <
Size) {
4676 int64_t STGOffset = ExtraBaseRegUpdate + 16;
4677 assert(STGOffset % 16 == 0 && STGOffset >= -4096 && STGOffset <= 4080 &&
4678 "STG immediate out of range");
4680 TII->get(ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex))
4687 }
else if (ExtraBaseRegUpdate) {
4689 int64_t AddSubOffset = std::abs(ExtraBaseRegUpdate);
4690 assert(AddSubOffset <= 4095 &&
"ADD/SUB immediate out of range");
4693 TII->get(ExtraBaseRegUpdate > 0 ? AArch64::ADDXri : AArch64::SUBXri))
4706 int64_t
Size, int64_t *TotalOffset) {
4708 if ((
MI.getOpcode() == AArch64::ADDXri ||
4709 MI.getOpcode() == AArch64::SUBXri) &&
4710 MI.getOperand(0).getReg() == Reg &&
MI.getOperand(1).getReg() == Reg) {
4712 int64_t
Offset =
MI.getOperand(2).getImm() << Shift;
4713 if (
MI.getOpcode() == AArch64::SUBXri)
4724 const int64_t kMaxOffset = 4080 - 16;
4726 const int64_t kMinOffset = -4095;
4727 if (PostOffset <= kMaxOffset && PostOffset >= kMinOffset &&
4728 PostOffset % 16 == 0) {
4739 for (
auto &TS : TSE) {
4743 if (
MI->memoperands_empty()) {
4747 MemRefs.
append(
MI->memoperands_begin(),
MI->memoperands_end());
4753 bool TryMergeSPUpdate) {
4754 if (TagStores.
empty())
4756 TagStoreInstr &FirstTagStore = TagStores[0];
4757 TagStoreInstr &LastTagStore = TagStores[TagStores.
size() - 1];
4758 Size = LastTagStore.Offset - FirstTagStore.Offset + LastTagStore.Size;
4759 DL = TagStores[0].MI->getDebugLoc();
4763 *MF, FirstTagStore.Offset,
false ,
false , Reg,
4766 FrameRegUpdate = std::nullopt;
4768 mergeMemRefs(TagStores, CombinedMemRefs);
4771 dbgs() <<
"Replacing adjacent STG instructions:\n";
4772 for (
const auto &Instr : TagStores) {
4781 if (TagStores.
size() < 2)
4783 emitUnrolled(InsertI);
4786 int64_t TotalOffset = 0;
4787 if (TryMergeSPUpdate) {
4793 if (InsertI !=
MBB->
end() &&
4794 canMergeRegUpdate(InsertI, FrameReg, FrameRegOffset.
getFixed() +
Size,
4796 UpdateInstr = &*InsertI++;
4802 if (!UpdateInstr && TagStores.
size() < 2)
4806 FrameRegUpdate = TotalOffset;
4807 FrameRegUpdateFlags = UpdateInstr->
getFlags();
4814 for (
auto &TS : TagStores)
4815 TS.MI->eraseFromParent();
4819 int64_t &
Size,
bool &ZeroData) {
4823 unsigned Opcode =
MI.getOpcode();
4824 ZeroData = (Opcode == AArch64::STZGloop || Opcode == AArch64::STZGi ||
4825 Opcode == AArch64::STZ2Gi);
4827 if (Opcode == AArch64::STGloop || Opcode == AArch64::STZGloop) {
4828 if (!
MI.getOperand(0).isDead() || !
MI.getOperand(1).isDead())
4830 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isFI())
4833 Size =
MI.getOperand(2).getImm();
4837 if (Opcode == AArch64::STGi || Opcode == AArch64::STZGi)
4839 else if (Opcode == AArch64::ST2Gi || Opcode == AArch64::STZ2Gi)
4844 if (
MI.getOperand(0).getReg() != AArch64::SP || !
MI.getOperand(1).isFI())
4848 16 *
MI.getOperand(2).getImm();
4868 if (!isMergeableStackTaggingInstruction(
MI,
Offset,
Size, FirstZeroData))
4874 constexpr int kScanLimit = 10;
4877 NextI != E && Count < kScanLimit; ++NextI) {
4886 if (isMergeableStackTaggingInstruction(
MI,
Offset,
Size, ZeroData)) {
4887 if (ZeroData != FirstZeroData)
4895 if (!
MI.isTransient())
4904 if (
MI.mayLoadOrStore() ||
MI.hasUnmodeledSideEffects() ||
MI.isCall())
4920 LiveRegs.addLiveOuts(*
MBB);
4925 LiveRegs.stepBackward(*
I);
4928 if (LiveRegs.contains(AArch64::NZCV))
4932 [](
const TagStoreInstr &
Left,
const TagStoreInstr &
Right) {
4937 int64_t CurOffset = Instrs[0].Offset;
4938 for (
auto &Instr : Instrs) {
4939 if (CurOffset >
Instr.Offset)
4946 TagStoreEdit TSE(
MBB, FirstZeroData);
4947 std::optional<int64_t> EndOffset;
4948 for (
auto &Instr : Instrs) {
4949 if (EndOffset && *EndOffset !=
Instr.Offset) {
4951 TSE.emitCode(InsertI, TFI,
false);
4955 TSE.addInstruction(Instr);
4975 if (
MI.getOpcode() != AArch64::VGSavePseudo &&
4976 MI.getOpcode() != AArch64::VGRestorePseudo)
4980 bool LocallyStreaming =
4987 int64_t VGFrameIdx =
4989 assert(VGFrameIdx != std::numeric_limits<int>::max() &&
4990 "Expected FrameIdx for VG");
4993 if (
MI.getOpcode() == AArch64::VGSavePseudo) {
4998 nullptr,
TRI->getDwarfRegNum(AArch64::VG,
true),
Offset));
5001 nullptr,
TRI->getDwarfRegNum(AArch64::VG,
true)));
5004 TII->get(TargetOpcode::CFI_INSTRUCTION))
5007 MI.eraseFromParent();
5018 II = tryMergeAdjacentSTG(
II,
this, RS);
5027 bool IgnoreSPUpdates)
const {
5029 if (IgnoreSPUpdates) {
5032 FrameReg = AArch64::SP;
5042 FrameReg = AArch64::SP;
5067 bool IsValid =
false;
5069 int ObjectIndex = 0;
5071 int GroupIndex = -1;
5073 bool ObjectFirst =
false;
5076 bool GroupFirst =
false;
5080 unsigned Accesses = 0;
5081 enum { AccessFPR = 1, AccessHazard = 2, AccessGPR = 4 };
5086 int NextGroupIndex = 0;
5087 std::vector<FrameObject> &Objects;
5090 GroupBuilder(std::vector<FrameObject> &Objects) : Objects(Objects) {}
5092 void EndCurrentGroup() {
5093 if (CurrentMembers.
size() > 1) {
5098 for (
int Index : CurrentMembers) {
5099 Objects[
Index].GroupIndex = NextGroupIndex;
5105 CurrentMembers.clear();
5109bool FrameObjectCompare(
const FrameObject &
A,
const FrameObject &
B) {
5131 return std::make_tuple(!
A.IsValid,
A.Accesses,
A.ObjectFirst,
A.GroupFirst,
5132 A.GroupIndex,
A.ObjectIndex) <
5133 std::make_tuple(!
B.IsValid,
B.Accesses,
B.ObjectFirst,
B.GroupFirst,
5134 B.GroupIndex,
B.ObjectIndex);
5145 std::vector<FrameObject> FrameObjects(MFI.getObjectIndexEnd());
5146 for (
auto &Obj : ObjectsToAllocate) {
5147 FrameObjects[Obj].IsValid =
true;
5148 FrameObjects[Obj].ObjectIndex = Obj;
5153 GroupBuilder GB(FrameObjects);
5154 for (
auto &
MBB : MF) {
5155 for (
auto &
MI :
MBB) {
5156 if (
MI.isDebugInstr())
5161 if (FI && *FI >= 0 && *FI < (
int)FrameObjects.size()) {
5164 FrameObjects[*FI].Accesses |= FrameObject::AccessFPR;
5166 FrameObjects[*FI].Accesses |= FrameObject::AccessGPR;
5171 switch (
MI.getOpcode()) {
5172 case AArch64::STGloop:
5173 case AArch64::STZGloop:
5177 case AArch64::STZGi:
5178 case AArch64::ST2Gi:
5179 case AArch64::STZ2Gi:
5191 if (FI >= 0 && FI < MFI.getObjectIndexEnd() &&
5192 FrameObjects[FI].IsValid)
5200 GB.AddMember(TaggedFI);
5202 GB.EndCurrentGroup();
5205 GB.EndCurrentGroup();
5210 FrameObject::AccessHazard;
5212 for (
auto &Obj : FrameObjects)
5213 if (!Obj.Accesses ||
5214 Obj.Accesses == (FrameObject::AccessGPR | FrameObject::AccessFPR))
5215 Obj.Accesses = FrameObject::AccessGPR;
5224 FrameObjects[*TBPI].ObjectFirst =
true;
5225 FrameObjects[*TBPI].GroupFirst =
true;
5226 int FirstGroupIndex = FrameObjects[*TBPI].GroupIndex;
5227 if (FirstGroupIndex >= 0)
5228 for (FrameObject &Object : FrameObjects)
5229 if (Object.GroupIndex == FirstGroupIndex)
5230 Object.GroupFirst =
true;
5236 for (
auto &Obj : FrameObjects) {
5240 ObjectsToAllocate[i++] = Obj.ObjectIndex;
5244 dbgs() <<
"Final frame order:\n";
5245 for (
auto &Obj : FrameObjects) {
5248 dbgs() <<
" " << Obj.ObjectIndex <<
": group " << Obj.GroupIndex;
5249 if (Obj.ObjectFirst)
5250 dbgs() <<
", first";
5252 dbgs() <<
", group-first";
5263AArch64FrameLowering::inlineStackProbeLoopExactMultiple(
5274 MF.
insert(MBBInsertPoint, LoopMBB);
5276 MF.
insert(MBBInsertPoint, ExitMBB);
5311 return ExitMBB->
begin();
5314void AArch64FrameLowering::inlineStackProbeFixed(
5327 int64_t NumBlocks = FrameSize / ProbeSize;
5328 int64_t ResidualSize = FrameSize % ProbeSize;
5330 LLVM_DEBUG(
dbgs() <<
"Stack probing: total " << FrameSize <<
" bytes, "
5331 << NumBlocks <<
" blocks of " << ProbeSize
5332 <<
" bytes, plus " << ResidualSize <<
" bytes\n");
5337 for (
int i = 0; i < NumBlocks; ++i) {
5343 EmitAsyncCFI && !HasFP, CFAOffset);
5352 }
else if (NumBlocks != 0) {
5358 EmitAsyncCFI && !HasFP, CFAOffset);
5360 MBBI = inlineStackProbeLoopExactMultiple(
MBBI, ProbeSize, ScratchReg);
5362 if (EmitAsyncCFI && !HasFP) {
5366 unsigned Reg =
RegInfo.getDwarfRegNum(AArch64::SP,
true);
5375 if (ResidualSize != 0) {
5381 EmitAsyncCFI && !HasFP, CFAOffset);
5400 if (
MI.getOpcode() == AArch64::PROBED_STACKALLOC ||
5401 MI.getOpcode() == AArch64::PROBED_STACKALLOC_VAR)
5405 if (
MI->getOpcode() == AArch64::PROBED_STACKALLOC) {
5406 Register ScratchReg =
MI->getOperand(0).getReg();
5407 int64_t FrameSize =
MI->getOperand(1).getImm();
5409 MI->getOperand(3).getImm());
5410 inlineStackProbeFixed(
MI->getIterator(), ScratchReg, FrameSize,
5413 assert(
MI->getOpcode() == AArch64::PROBED_STACKALLOC_VAR &&
5414 "Stack probe pseudo-instruction expected");
5417 Register TargetReg =
MI->getOperand(0).getReg();
5418 (void)
TII->probedStackAlloc(
MI->getIterator(), TargetReg,
true);
5420 MI->eraseFromParent();
5440 return std::make_tuple(start(),
Idx) <
5441 std::make_tuple(Rhs.
start(), Rhs.
Idx);
5446 return AccessTypes & (AccessType::GPR | AccessType::PPR);
5448 bool isSME()
const {
return AccessTypes & AccessType::FPR; }
5449 bool isMixed()
const {
return isCPU() && isSME(); }
5455 switch (AccessTypes) {
5456 case AccessType::FPR:
5458 case AccessType::PPR:
5460 case AccessType::GPR:
5462 case AccessType::NotAccessed:
5471 << (
Offset.getFixed() < 0 ?
"" :
"+") <<
Offset.getFixed();
5472 if (
Offset.getScalable())
5473 OS << (
Offset.getScalable() < 0 ?
"" :
"+") <<
Offset.getScalable()
5484void AArch64FrameLowering::emitRemarks(
5488 if (
Attrs.hasNonStreamingInterfaceAndBody())
5495 if (HazardSize == 0)
5503 std::vector<StackAccess> StackAccesses(MFI.
getNumObjects());
5505 size_t NumFPLdSt = 0;
5506 size_t NumNonFPLdSt = 0;
5511 if (!
MI.mayLoadOrStore() ||
MI.getNumMemOperands() < 1)
5520 StackAccesses[ArrIdx].Idx = FrameIdx;
5521 StackAccesses[ArrIdx].Offset =
5530 if (
MI.getOpcode() != AArch64::SPILL_PPR_TO_ZPR_SLOT_PSEUDO &&
5531 MI.getOpcode() != AArch64::FILL_PPR_FROM_ZPR_SLOT_PSEUDO &&
5532 AArch64::PPRRegClass.contains(
MI.getOperand(0).getReg())) {
5540 StackAccesses[ArrIdx].AccessTypes |= RegTy;
5551 if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
5560 StackAccesses.end());
5565 if (StackAccesses.front().isMixed())
5566 MixedObjects.
push_back(&StackAccesses.front());
5568 for (
auto It = StackAccesses.begin(),
End = std::prev(StackAccesses.end());
5570 const auto &
First = *It;
5571 const auto &Second = *(It + 1);
5573 if (Second.isMixed())
5576 if ((
First.isSME() && Second.isCPU()) ||
5577 (
First.isCPU() && Second.isSME())) {
5579 if (Distance < HazardSize)
5587 "sme",
"StackHazard", MF.getFunction().getSubprogram(), &MF.front());
5588 return R <<
formatv(
"stack hazard in '{0}': ", MF.getName()).str() << Str;
5592 for (
const auto &
P : HazardPairs)
5593 EmitRemark(
formatv(
"{0} is too close to {1}", *
P.first, *
P.second).str());
5595 for (
const auto *Obj : MixedObjects)
5597 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 emitShadowCallStackEpilogue(const TargetInstrInfo &TII, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL)
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 const unsigned DefaultSafeSPDisplacement
This is the biggest offset to the stack pointer we can encode in aarch64 instructions (without using ...
static void emitDefineCFAWithFP(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned FixedObject)
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 void insertCFISameValue(const MCInstrDesc &Desc, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertPt, unsigned DwarfReg)
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 enableMultiVectorSpillFill(const AArch64Subtarget &Subtarget, MachineFunction &MF)
bool isVGInstruction(MachineBasicBlock::iterator MBBI)
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 int64_t determineSVEStackObjectOffsets(MachineFrameInfo &MFI, int &MinCSFrameIndex, int &MaxCSFrameIndex, bool AssignOffsets)
static cl::opt< bool > OrderFrameObjects("aarch64-order-frame-objects", cl::desc("sort stack allocations"), cl::init(true), cl::Hidden)
static bool windowsRequiresStackProbe(MachineFunction &MF, uint64_t StackSizeInBytes)
static void fixupCalleeSaveRestoreStackOffset(MachineInstr &MI, uint64_t LocalStackSize, bool NeedsWinCFI, bool *HasWinCFI)
static bool invalidateWindowsRegisterPairing(unsigned Reg1, unsigned Reg2, bool NeedsWinCFI, bool IsFirst, const TargetRegisterInfo *TRI)
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 Register findScratchNonCalleeSaveRegister(MachineBasicBlock *MBB)
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.
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...
MachineBasicBlock::iterator emitVGSaveRestore(MachineBasicBlock::iterator II, const AArch64FrameLowering *TFI)
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 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 StackOffset getStackOffset(const MachineFunction &MF, int64_t ObjectOffset)
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 bool requiresSaveVG(MachineFunction &MF)
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...
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
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
static std::string getTypeString(Type *T)
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
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.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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.
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...
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)
void setVGIdx(unsigned Idx)
int getCalleeSaveBaseToFrameRecordOffset() const
bool hasStreamingModeChanges() const
bool shouldSignReturnAddress(const MachineFunction &MF) const
void setPredicateRegForFillSpill(unsigned Reg)
int getStackHazardSlotIndex() const
void setStreamingVGIdx(unsigned FrameIdx)
int64_t getStackProbeSize() const
uint64_t getStackSizeSVE() const
void setHasRedZone(bool s)
bool hasStackFrame() const
std::optional< int > getTaggedBasePointerIndex() 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 setStackHazardCSRSlotIndex(int Index)
unsigned getPredicateRegForFillSpill() const
unsigned getSVECalleeSavedStackSize() const
bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const
int64_t getStreamingVGIdx() 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 instruciton used for unwinding on Windows.
static bool isFpOrNEON(Register Reg)
Returns whether the physical register is FP or NEON.
bool isReservedReg(const MachineFunction &MF, MCRegister Reg) 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.
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
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 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 copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, bool KillSrc, bool RenamableDest=false, bool RenamableSrc=false) const override
Emit instructions to copy a pair of physical registers.
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...
bool available(const MachineRegisterInfo &MRI, MCPhysReg Reg) const
Returns true if register Reg and no aliasing register is in the set.
void stepBackward(const MachineInstr &MI)
Simulates liveness when stepping backwards over an instruction(bundle).
void removeReg(MCPhysReg Reg)
Removes a physical register, all its sub-registers, and all its super-registers from the set.
void addLiveIns(const MachineBasicBlock &MBB)
Adds all live-in registers of basic block MBB.
void addLiveOuts(const MachineBasicBlock &MBB)
Adds all live-out registers of basic block MBB.
void addReg(MCPhysReg Reg)
Adds a physical register and all its sub-registers to the set.
A set of register units used to track register liveness.
bool available(MCPhysReg Reg) const
Returns true if no part of physical register Reg is live.
void stepBackward(const MachineInstr &MI)
Updates liveness when stepping backwards over the instruction MI.
void addLiveOuts(const MachineBasicBlock &MBB)
Adds registers living out of block MBB.
bool usesWindowsCFI() const
static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register, SMLoc Loc={})
.cfi_def_cfa_register modifies a rule for computing CFA.
static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register, SMLoc Loc={})
.cfi_restore says that the rule for Register is now the same as it was at the beginning of the functi...
static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})
.cfi_def_cfa defines a rule for computing CFA as: take address from Register and add Offset to it.
static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})
.cfi_offset Previous value of Register is saved at offset Offset from CFA.
static MCCFIInstruction createNegateRAStateWithPC(MCSymbol *L, SMLoc Loc={})
.cfi_negate_ra_state_with_pc AArch64 negate RA state with PC.
static MCCFIInstruction createNegateRAState(MCSymbol *L, SMLoc Loc={})
.cfi_negate_ra_state AArch64 negate RA state.
static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset, SMLoc Loc={})
.cfi_def_cfa_offset modifies a rule for computing CFA.
static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals, SMLoc Loc={}, StringRef Comment="")
.cfi_escape Allows the user to add arbitrary bytes to the unwind info.
static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register, SMLoc Loc={})
.cfi_same_value Current value of Register is the same as in the previous frame.
MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Describe properties that are true of each instruction in the target description file.
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 ...
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.
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
MachineInstr & instr_back()
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
DebugLoc findDebugLoc(instr_iterator MBBI)
Find the next valid DebugLoc starting at MBBI, skipping any debug instructions.
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.
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 '...
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.
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.
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.
int CreateSpillStackObject(uint64_t Size, Align Alignment)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
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.
unsigned addFrameInst(const MCCFIInstruction &Inst)
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 & addCFIIndex(unsigned CFIIndex) 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.
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.
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)
static MachineOperand CreateImm(int64_t Val)
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,...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
bool isLiveIn(Register Reg) const
const MCPhysReg * getCalleeSavedRegs() const
Returns list of callee saved registers.
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 hasStreamingBody() const
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.
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.
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 TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
virtual const TargetInstrInfo * getInstrInfo() const
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).
@ AArch64_SME_ABI_Support_Routines_PreserveMost_From_X1
Preserve X1-X15, X19-X29, SP, Z0-Z31, P0-P15.
@ 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
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)
MCCFIInstruction createCFAOffset(const TargetRegisterInfo &MRI, unsigned Reg, const StackOffset &OffsetFromDefCFA)
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.
const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=6)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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.
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.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
auto remove_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::remove_if which take ranges instead of having to pass begin/end explicitly.
unsigned getDefRegState(bool B)
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.
void fullyRecomputeLiveIns(ArrayRef< MachineBasicBlock * > MBBs)
Convenience function for recomputing live-in's for a set of MBBs until the computation converges.
Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Emergency stack slots for expanding SPILL_PPR_TO_ZPR_SLOT_PSEUDO and FILL_PPR_FROM_ZPR_SLOT_PSEUDO.
std::optional< int > PPRSpillFI
std::optional< int > GPRSpillFI
std::optional< int > ZPRSpillFI
Registers available for scavenging (ZPR, PPR3b, GPR).
RAII helper class for scavenging or spilling a register.
Register operator*() const
ScopedScavengeOrSpill(ScopedScavengeOrSpill &&)=delete
ScopedScavengeOrSpill(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SpillCandidate, const TargetRegisterClass &RC, LiveRegUnits const &UsedRegs, BitVector const &AllocatableRegs, std::optional< int > *MaybeSpillFI, Register PreferredReg=AArch64::NoRegister)
Register freeRegister() const
Returns the free register (found from scavenging or spilling a register).
ScopedScavengeOrSpill(const ScopedScavengeOrSpill &)=delete
bool operator<(const StackAccess &Rhs) const
void print(raw_ostream &OS) const
std::string getTypeString() const
This struct is a compact representation of a valid (non-zero power of two) alignment.
uint64_t value() const
This is a hole in the type system and should not be abused.
Description of the encoding of one expression Op.
Pair of physical register and lane mask.
static MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.