20#define DEBUG_TYPE "frame-info"
22STATISTIC(NumRedZoneFunctions,
"Number of functions using red zone");
33 return AFI->hasStreamingModeChanges() &&
39 unsigned Opc =
MBBI->getOpcode();
40 if (
Opc == AArch64::CNTD_XPiI)
46 if (
Opc == AArch64::BL)
49 return Opc == TargetOpcode::COPY;
54 switch (
I->getOpcode()) {
57 case AArch64::LD1B_2Z_IMM:
58 case AArch64::ST1B_2Z_IMM:
59 case AArch64::LD1B_4Z_IMM:
60 case AArch64::ST1B_4Z_IMM:
61 case AArch64::STR_ZXI:
62 case AArch64::LDR_ZXI:
63 case AArch64::PTRUE_C_B:
66 case AArch64::SEH_SaveZReg:
73 switch (
I->getOpcode()) {
76 case AArch64::STR_PXI:
77 case AArch64::LDR_PXI:
80 case AArch64::SEH_SavePReg:
102 if (
AFL.hasSVECalleeSavesAboveFrameRecord(
MF)) {
103 if (AFI->hasStackHazardSlotIndex())
104 reportFatalUsageError(
"SME hazard padding is not supported on Windows");
105 SVELayout = SVEStackLayout::CalleeSavesAboveFrameRecord;
106 }
else if (
AFI->hasSplitSVEObjects()) {
107 SVELayout = SVEStackLayout::Split;
120 if (
AFL.requiresSaveVG(
MF)) {
121 auto &TLI = *
Subtarget.getTargetLowering();
126 switch (
MBBI->getOpcode()) {
130 NewOpc = AArch64::STPXpre;
133 NewOpc = AArch64::STPDpre;
136 NewOpc = AArch64::STPQpre;
138 case AArch64::STRXui:
139 NewOpc = AArch64::STRXpre;
141 case AArch64::STRDui:
142 NewOpc = AArch64::STRDpre;
144 case AArch64::STRQui:
145 NewOpc = AArch64::STRQpre;
148 NewOpc = AArch64::LDPXpost;
151 NewOpc = AArch64::LDPDpost;
154 NewOpc = AArch64::LDPQpost;
156 case AArch64::LDRXui:
157 NewOpc = AArch64::LDRXpost;
159 case AArch64::LDRDui:
160 NewOpc = AArch64::LDRDpost;
162 case AArch64::LDRQui:
163 NewOpc = AArch64::LDRQpost;
167 int64_t MinOffset, MaxOffset;
168 bool Success =
TII->getMemOpInfo(NewOpc, Scale, Width, MinOffset, MaxOffset);
177 if (
MBBI->getOperand(
MBBI->getNumOperands() - 1).getImm() != 0 ||
178 CSStackSizeInc < MinOffset * (int64_t)Scale.
getFixedValue() ||
179 CSStackSizeInc > MaxOffset * (int64_t)Scale.
getFixedValue() ||
181 (NewOpc == AArch64::LDPXpost || NewOpc == AArch64::STPXpre) &&
182 RegInfo.getEncodingValue(
MBBI->getOperand(0).getReg()) + 1 !=
183 RegInfo.getEncodingValue(
MBBI->getOperand(1).getReg()))) {
197 return std::prev(
MBBI);
202 auto SEH = std::next(
MBBI);
203 if (AArch64InstrInfo::isSEHInstruction(*SEH))
204 SEH->eraseFromParent();
211 unsigned OpndIdx = 0;
212 for (
unsigned OpndEnd =
MBBI->getNumOperands() - 1; OpndIdx < OpndEnd;
214 MIB.
add(
MBBI->getOperand(OpndIdx));
216 assert(
MBBI->getOperand(OpndIdx).getImm() == 0 &&
217 "Unexpected immediate offset in first/last callee-save save/restore "
219 assert(
MBBI->getOperand(OpndIdx - 1).getReg() == AArch64::SP &&
220 "Unexpected base register in callee-save save/restore instruction!");
221 assert(CSStackSizeInc % Scale == 0);
222 MIB.
addImm(CSStackSizeInc / (
int)Scale);
230 AFL.insertSEH(*MIB, *
TII, FrameFlag);
237 return std::prev(
MBB.erase(
MBBI));
242 unsigned LocalStackSize) {
244 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
245 switch (
MBBI->getOpcode()) {
248 case AArch64::SEH_SaveFPLR:
249 case AArch64::SEH_SaveRegP:
250 case AArch64::SEH_SaveReg:
251 case AArch64::SEH_SaveFRegP:
252 case AArch64::SEH_SaveFReg:
253 case AArch64::SEH_SaveAnyRegI:
254 case AArch64::SEH_SaveAnyRegIP:
255 case AArch64::SEH_SaveAnyRegQP:
256 case AArch64::SEH_SaveAnyRegQPX:
257 ImmOpnd = &
MBBI->getOperand(ImmIdx);
266 if (AArch64InstrInfo::isSEHInstruction(
MI))
269 unsigned Opc =
MI.getOpcode();
273 case AArch64::STRXui:
275 case AArch64::STRDui:
277 case AArch64::LDRXui:
279 case AArch64::LDRDui:
283 case AArch64::STRQui:
285 case AArch64::LDRQui:
292 unsigned OffsetIdx =
MI.getNumExplicitOperands() - 1;
293 assert(
MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP &&
294 "Unexpected base register in callee-save save/restore instruction!");
298 assert(LocalStackSize % Scale == 0);
299 OffsetOpnd.
setImm(OffsetOpnd.
getImm() + LocalStackSize / Scale);
304 assert(
MBBI !=
MI.getParent()->end() &&
"Expecting a valid instruction");
305 assert(AArch64InstrInfo::isSEHInstruction(*
MBBI) &&
306 "Expecting a SEH instruction");
313 if (
AFL.homogeneousPrologEpilog(
MF))
316 if (
AFI->getLocalStackSize() == 0)
332 if (
MF.needsWinCFI() &&
AFI->getCalleeSavedStackSize() > 0 &&
333 MF.getFunction().hasOptSize())
338 if (StackBumpBytes >= 512 ||
339 AFL.windowsRequiresStackProbe(
MF, StackBumpBytes))
342 if (
MFI.hasVarSizedObjects())
351 if (
AFL.canUseRedZone(
MF))
356 if (
AFI->hasSVEStackSize())
370 return {{PPRCalleeSavesSize, PPRLocalsSize},
371 {ZPRCalleeSavesSize, ZPRLocalsSize}};
374 {ZPRCalleeSavesSize, PPRLocalsSize + ZPRLocalsSize}};
383 BeforePPRs =
SVE.PPR.CalleeSavesSize;
385 if (
SVE.ZPR.CalleeSavesSize)
386 AfterPPRs +=
SVE.PPR.LocalsSize +
SVE.ZPR.CalleeSavesSize;
388 AfterZPRs +=
SVE.PPR.LocalsSize;
390 return {BeforePPRs, AfterPPRs, AfterZPRs};
406 IsEpilogue ?
MBB.begin() :
MBB.getFirstTerminator();
407 auto AdjustI = [&](
auto MBBI) {
return IsEpilogue ? std::prev(
MBBI) :
MBBI; };
409 if (PPRCalleeSavesSize) {
410 PPRsI = AdjustI(PPRsI);
413 IsEpilogue ? (--PPRsI) : (++PPRsI);
416 if (ZPRCalleeSavesSize) {
417 ZPRsI = AdjustI(ZPRsI);
420 IsEpilogue ? (--ZPRsI) : (++ZPRsI);
423 return {{PPRsI,
MBBI}, {ZPRsI, PPRsI}};
424 return {{
MBBI, PPRsI}, {PPRsI, ZPRsI}};
432 EmitAsyncCFI =
AFI->needsAsyncDwarfUnwindInfo(
MF);
437 collectBlockLiveins();
454void AArch64PrologueEmitter::collectBlockLiveins() {
457 PrologueEndI =
MBB.begin();
458 while (PrologueEndI !=
MBB.end() &&
462 if (PrologueEndI !=
MBB.end()) {
478void AArch64PrologueEmitter::verifyPrologueClobbers()
const {
479 if (PrologueEndI ==
MBB.end())
482 for (MachineInstr &
MI :
483 make_range(
MBB.instr_begin(), PrologueEndI->getIterator())) {
484 for (
auto &
Op :
MI.operands())
485 if (
Op.isReg() &&
Op.isDef())
486 assert(!LiveRegs.contains(
Op.getReg()) &&
487 "live register clobbered by inserted prologue instructions");
492void AArch64PrologueEmitter::determineLocalsStackSize(
494 AFI->setLocalStackSize(StackSize - PrologueSaveSize);
501 static const int64_t MAX_BYTES_PER_SCALABLE_BYTE = 16;
502 return Size.getScalable() * MAX_BYTES_PER_SCALABLE_BYTE +
Size.getFixed();
505void AArch64PrologueEmitter::allocateStackSpace(
507 StackOffset AllocSize,
bool EmitCFI, StackOffset InitialOffset,
508 bool FollowupAllocs) {
515 const uint64_t AndMask = ~(MaxAlign - 1);
518 Register TargetReg = RealignmentPadding
519 ?
AFL.findScratchNonCalleeSaveRegister(&
MBB)
526 if (RealignmentPadding) {
547 if (AllocSize.getScalable() == 0 && RealignmentPadding == 0) {
549 assert(ScratchReg.isValid());
552 .
addImm(AllocSize.getFixed())
553 .
addImm(InitialOffset.getFixed())
554 .
addImm(InitialOffset.getScalable());
559 if (FollowupAllocs) {
579 int64_t ProbeSize =
AFI->getStackProbeSize();
580 if (
upperBound(AllocSize) + RealignmentPadding <= ProbeSize) {
581 Register ScratchReg = RealignmentPadding
582 ?
AFL.findScratchNonCalleeSaveRegister(&
MBB)
584 assert(ScratchReg.isValid());
589 if (RealignmentPadding) {
595 AFI->setStackRealigned(
true);
597 if (FollowupAllocs ||
upperBound(AllocSize) + RealignmentPadding >
617 assert(TargetReg.isValid());
622 if (RealignmentPadding) {
635 .buildDefCFARegister(AArch64::SP);
637 if (RealignmentPadding)
638 AFI->setStackRealigned(
true);
648 AFI->setHasRedZone(
false);
658 if (int64_t ArgBytes =
AFI->getArgumentStackToRestore()) {
674 if (
AFI->shouldSignReturnAddress(
MF)) {
677 if (!
AFL.shouldSignReturnAddressEverywhere(
MF)) {
685 if (
AFI->needsShadowCallStackPrologueEpilogue(
MF)) {
686 emitShadowCallStackPrologue(PrologueBeginI,
DL);
698 if (
HasFP &&
AFI->hasSwiftAsyncContext())
699 emitSwiftAsyncContextFramePointer(PrologueBeginI,
DL);
708 if (std::optional<int> TBPI =
AFI->getTaggedBasePointerIndex())
709 AFI->setTaggedBasePointerOffset(-
MFI.getObjectOffset(*TBPI));
711 AFI->setTaggedBasePointerOffset(
MFI.getStackSize());
721 if (!
AFI->hasStackFrame() && !
AFL.windowsRequiresStackProbe(
MF, NumBytes))
722 return emitEmptyStackFramePrologue(NumBytes, PrologueBeginI,
DL);
724 bool IsWin64 =
Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg());
727 auto PrologueSaveSize =
AFI->getCalleeSavedStackSize() + FixedObject;
729 determineLocalsStackSize(NumBytes, PrologueSaveSize);
737 "unexpected SVE allocs after PPRs with CalleeSavesAboveFrameRecord");
744 allocateStackSpace(PrologueBeginI, 0, SaveSize,
false,
StackOffset{},
746 NumBytes -= FixedObject;
753 MBBI,
DL, -
AFI->getCalleeSavedStackSize(), EmitAsyncCFI);
754 NumBytes -=
AFI->getCalleeSavedStackSize();
755 }
else if (CombineSPBump) {
756 assert(!
AFL.getSVEStackSize(
MF) &&
"Cannot combine SP bump with SVE");
764 NumBytes -= PrologueSaveSize;
765 }
else if (PrologueSaveSize != 0) {
767 PrologueBeginI,
DL, -PrologueSaveSize, EmitAsyncCFI);
768 NumBytes -= PrologueSaveSize;
770 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
775 auto &TLI = *
Subtarget.getTargetLowering();
778 while (AfterGPRSavesI != EndI &&
785 AFI->getLocalStackSize());
792 emitFramePointerSetup(AfterGPRSavesI,
DL, FixedObject);
798 emitCalleeSavedGPRLocations(AfterGPRSavesI);
801 const bool NeedsRealignment =
803 const int64_t RealignmentPadding =
804 (NeedsRealignment &&
MFI.getMaxAlign() >
Align(16))
805 ?
MFI.getMaxAlign().value() - 16
808 if (
AFL.windowsRequiresStackProbe(
MF, NumBytes + RealignmentPadding))
809 emitWindowsStackProbe(AfterGPRSavesI,
DL, NumBytes, RealignmentPadding);
819 auto [PPRRange, ZPRRange] =
821 ZPR.CalleeSavesSize,
false);
822 AfterSVESavesI = ZPRRange.End;
824 emitCalleeSavedSVELocations(AfterSVESavesI);
826 allocateStackSpace(PPRRange.Begin, 0, SVEAllocs.
BeforePPRs,
827 EmitAsyncCFI && !
HasFP, CFAOffset,
831 assert(PPRRange.End == ZPRRange.Begin &&
832 "Expected ZPR callee saves after PPR locals");
833 allocateStackSpace(PPRRange.End, 0, SVEAllocs.
AfterPPRs,
834 EmitAsyncCFI && !
HasFP, CFAOffset,
847 assert(!(
AFL.canUseRedZone(
MF) && NeedsRealignment) &&
848 "Cannot use redzone with stack realignment");
849 if (!
AFL.canUseRedZone(
MF)) {
853 allocateStackSpace(AfterSVESavesI, RealignmentPadding, SVEAllocs.
AfterZPRs,
854 EmitAsyncCFI && !
HasFP, CFAOffset,
855 MFI.hasVarSizedObjects());
894 MBB.addLiveIn(AArch64::X1);
898 if (
EmitCFI && !EmitAsyncCFI) {
900 emitDefineCFAWithFP(AfterSVESavesI, FixedObject);
903 AFL.getSVEStackSize(
MF) +
910 emitCalleeSavedGPRLocations(AfterSVESavesI);
911 emitCalleeSavedSVELocations(AfterSVESavesI);
915void AArch64PrologueEmitter::emitShadowCallStackPrologue(
926 MBB.addLiveIn(AArch64::X18);
935 static const char CFIInst[] = {
936 dwarf::DW_CFA_val_expression,
939 static_cast<char>(
unsigned(dwarf::DW_OP_breg18)),
940 static_cast<char>(-8) & 0x7f,
943 .buildEscape(StringRef(CFIInst,
sizeof(CFIInst)));
947void AArch64PrologueEmitter::emitSwiftAsyncContextFramePointer(
949 switch (
MF.getTarget().Options.SwiftAsyncFramePointer) {
951 if (
Subtarget.swiftAsyncContextIsDynamicallySet()) {
993void AArch64PrologueEmitter::emitEmptyStackFramePrologue(
996 assert(!
HasFP &&
"unexpected function without stack frame but with FP");
998 "unexpected function without stack frame but with SVE objects");
1000 AFI->setLocalStackSize(NumBytes);
1010 if (
AFL.canUseRedZone(
MF)) {
1011 AFI->setHasRedZone(
true);
1012 ++NumRedZoneFunctions;
1019 MCSymbol *FrameLabel =
MF.getContext().createTempSymbol();
1022 .buildDefCFAOffset(NumBytes, FrameLabel);
1033void AArch64PrologueEmitter::emitFramePointerSetup(
1035 unsigned FixedObject) {
1036 int64_t FPOffset =
AFI->getCalleeSaveBaseToFrameRecordOffset();
1038 FPOffset +=
AFI->getLocalStackSize();
1040 if (
AFI->hasSwiftAsyncContext()) {
1044 const auto &
Attrs =
MF.getFunction().getAttributes();
1045 bool HaveInitialContext =
Attrs.hasAttrSomewhere(Attribute::SwiftAsync);
1046 if (HaveInitialContext)
1047 MBB.addLiveIn(AArch64::X22);
1048 Register Reg = HaveInitialContext ? AArch64::X22 : AArch64::XZR;
1086 emitDefineCFAWithFP(
MBBI, FixedObject);
1090void AArch64PrologueEmitter::emitDefineCFAWithFP(
1092 const int OffsetToFirstCalleeSaveFromFP =
1093 AFI->getCalleeSaveBaseToFrameRecordOffset() -
1094 AFI->getCalleeSavedStackSize();
1097 .buildDefCFA(
FramePtr, FixedObject - OffsetToFirstCalleeSaveFromFP);
1100void AArch64PrologueEmitter::emitWindowsStackProbe(
1102 int64_t RealignmentPadding)
const {
1103 if (
AFI->getSVECalleeSavedStackSize())
1110 [
this](
const MachineBasicBlock::RegisterMaskPair &LiveIn) {
1111 return RegInfo.isSuperOrSubRegisterEq(AArch64::X15,
1114 X15Scratch =
AFL.findScratchNonCalleeSaveRegister(&
MBB,
true);
1115 assert(X15Scratch.isValid() &&
1116 (X15Scratch < AArch64::X15 || X15Scratch > AArch64::X17));
1118 LiveRegs.removeReg(AArch64::X15);
1127 uint64_t NumWords = (NumBytes + RealignmentPadding) >> 4;
1135 if (NumBytes >= (1 << 28))
1137 "unwinding purposes");
1139 uint32_t LowNumWords = NumWords & 0xFFFF;
1146 if ((NumWords & 0xFFFF0000) != 0) {
1149 .
addImm((NumWords & 0xFFFF0000) >> 16)
1161 const AArch64TargetLowering *TLI =
Subtarget.getTargetLowering();
1162 RTLIB::LibcallImpl ChkStkLibcall = TLI->getLibcallImpl(RTLIB::STACK_PROBE);
1163 if (ChkStkLibcall == RTLIB::Unsupported)
1166 const char *ChkStk = TLI->getLibcallImplName(ChkStkLibcall).data();
1167 switch (
MF.getTarget().getCodeModel()) {
1231 if (RealignmentPadding > 0) {
1232 if (RealignmentPadding >= 4096) {
1235 .
addImm(RealignmentPadding)
1245 .
addImm(RealignmentPadding)
1250 uint64_t AndMask = ~(
MFI.getMaxAlign().value() - 1);
1254 AFI->setStackRealigned(
true);
1260 if (X15Scratch.isValid()) {
1269void AArch64PrologueEmitter::emitCalleeSavedGPRLocations(
1271 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1276 for (
const auto &Info : CSI) {
1277 unsigned FrameIdx =
Info.getFrameIdx();
1278 if (
MFI.hasScalableStackID(FrameIdx))
1281 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
1282 int64_t
Offset =
MFI.getObjectOffset(FrameIdx) -
AFL.getOffsetOfLocalArea();
1283 CFIBuilder.buildOffset(
Info.getReg(),
Offset);
1287void AArch64PrologueEmitter::emitCalleeSavedSVELocations(
1290 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1296 std::optional<int64_t> IncomingVGOffsetFromDefCFA;
1297 if (
AFL.requiresSaveVG(
MF)) {
1299 reverse(CSI), [](
auto &Info) {
return Info.getReg() == AArch64::VG; });
1300 IncomingVGOffsetFromDefCFA =
MFI.getObjectOffset(IncomingVG.getFrameIdx()) -
1301 AFL.getOffsetOfLocalArea();
1304 StackOffset PPRStackSize =
AFL.getPPRStackSize(
MF);
1305 for (
const auto &Info : CSI) {
1306 int FI =
Info.getFrameIdx();
1307 if (!
MFI.hasScalableStackID(FI))
1312 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
1313 MCRegister
Reg =
Info.getReg();
1327 CFIBuilder.insertCFIInst(
1333 switch (
MI.getOpcode()) {
1336 case AArch64::CATCHRET:
1337 case AArch64::CLEANUPRET:
1348 SEHEpilogueStartI =
MBB.end();
1355 "expected negative offset (with optional fixed portion)");
1357 if (int64_t FixedOffset =
Offset.getFixed()) {
1373 if (
MBB.end() != EpilogueEndI) {
1374 DL = EpilogueEndI->getDebugLoc();
1388 int64_t ArgumentStackToRestore =
AFL.getArgumentStackToRestore(
MF,
MBB);
1389 bool IsWin64 =
Subtarget.isCallingConvWin64(
MF.getFunction().getCallingConv(),
1390 MF.getFunction().isVarArg());
1393 const bool AuthenticateReturnAddressEarly =
1396 int64_t AfterCSRPopSize = ArgumentStackToRestore;
1397 auto PrologueSaveSize =
AFI->getCalleeSavedStackSize() + FixedObject;
1402 if (
MF.hasEHFunclets())
1403 AFI->setLocalStackSize(NumBytes - PrologueSaveSize);
1407 auto FirstHomogenousEpilogI =
MBB.getFirstTerminator();
1408 if (FirstHomogenousEpilogI !=
MBB.begin()) {
1409 auto HomogeneousEpilog = std::prev(FirstHomogenousEpilogI);
1410 if (HomogeneousEpilog->getOpcode() == AArch64::HOM_Epilog)
1411 FirstHomogenousEpilogI = HomogeneousEpilog;
1421 assert(AfterCSRPopSize == 0);
1425 bool CombineSPBump = shouldCombineCSRLocalStackBump(NumBytes);
1427 unsigned ProloguePopSize = PrologueSaveSize;
1433 ProloguePopSize -= FixedObject;
1434 AfterCSRPopSize += FixedObject;
1440 if (!CombineSPBump && ProloguePopSize != 0 &&
1441 AuthenticateReturnAddressEarly) {
1442 AfterCSRPopSize += ProloguePopSize;
1443 }
else if (!CombineSPBump && ProloguePopSize != 0) {
1445 while (Pop->getOpcode() == TargetOpcode::CFI_INSTRUCTION ||
1446 AArch64InstrInfo::isSEHInstruction(*Pop) ||
1449 Pop = std::prev(Pop);
1456 if (
OffsetOp.getImm() == 0 && AfterCSRPopSize >= 0) {
1462 if (AArch64InstrInfo::isSEHInstruction(*AfterLastPop))
1476 AfterCSRPopSize += ProloguePopSize;
1485 while (FirstGPRRestoreI != Begin) {
1492 }
else if (CombineSPBump)
1494 AFI->getLocalStackSize());
1500 if (AuthenticateReturnAddressEarly)
1501 emitEarlyReturnAddressAuthentication(FirstGPRRestoreI,
MFI.getStackSize(),
1511 BuildMI(
MBB, FirstGPRRestoreI, DL,
TII->get(AArch64::SEH_EpilogStart))
1513 SEHEpilogueStartI = FirstGPRRestoreI;
1514 --SEHEpilogueStartI;
1524 ?
MBB.getFirstTerminator()
1526 PPR.CalleeSavesSize, ZPR.CalleeSavesSize,
true);
1528 if (
HasFP &&
AFI->hasSwiftAsyncContext())
1529 emitSwiftAsyncContextFramePointer(EpilogueEndI, DL);
1532 if (CombineSPBump) {
1533 assert(!
AFI->hasSVEStackSize() &&
"Cannot combine SP bump with SVE");
1547 NumBytes -= PrologueSaveSize;
1548 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
1550 StackOffset SVECalleeSavesSize = ZPR.CalleeSavesSize + PPR.CalleeSavesSize;
1556 "unexpected SVE allocs after PPRs with CalleeSavesAboveFrameRecord");
1560 if (!
AFI->isStackRealigned() && !
MFI.hasVarSizedObjects()) {
1570 }
else if (
AFI->hasSVEStackSize()) {
1575 (
AFI->isStackRealigned() ||
MFI.hasVarSizedObjects()) ? AArch64::FP
1577 if (SVECalleeSavesSize && BaseForSVEDealloc == AArch64::FP) {
1581 -SVECalleeSavesSize - PPR.LocalsSize -
1585 moveSPBelowFP(ZPRRange.Begin, FPOffsetZPR);
1593 assert(!FPOffsetPPR.
getFixed() &&
"expected only scalable offset");
1597 }
else if (BaseForSVEDealloc == AArch64::SP) {
1606 NumBytes -= NonSVELocals.getFixed();
1614 assert(PPRRange.Begin == ZPRRange.End &&
1615 "Expected PPR restores after ZPR");
1628 emitCalleeSavedSVERestores(
1633 bool RedZone =
AFL.canUseRedZone(
MF);
1636 if (RedZone && AfterCSRPopSize == 0)
1643 bool NoCalleeSaveRestore = PrologueSaveSize == 0;
1644 int64_t StackRestoreBytes = RedZone ? 0 : NumBytes;
1645 if (NoCalleeSaveRestore)
1646 StackRestoreBytes += AfterCSRPopSize;
1649 MBB, FirstGPRRestoreI, DL, AArch64::SP, AArch64::SP,
1656 if (NoCalleeSaveRestore || AfterCSRPopSize == 0)
1666 if (!
IsFunclet && (
MFI.hasVarSizedObjects() ||
AFI->isStackRealigned())) {
1668 MBB, FirstGPRRestoreI, DL, AArch64::SP, AArch64::FP,
1671 }
else if (NumBytes)
1684 if (AfterCSRPopSize) {
1685 assert(AfterCSRPopSize > 0 &&
"attempting to reallocate arg stack that an "
1686 "interrupt may have clobbered");
1689 MBB,
MBB.getFirstTerminator(), DL, AArch64::SP, AArch64::SP,
1696bool AArch64EpilogueEmitter::shouldCombineCSRLocalStackBump(
1708 while (LastI != Begin) {
1710 if (LastI->isTransient())
1715 switch (LastI->getOpcode()) {
1716 case AArch64::STGloop:
1717 case AArch64::STZGloop:
1719 case AArch64::STZGi:
1720 case AArch64::ST2Gi:
1721 case AArch64::STZ2Gi:
1729void AArch64EpilogueEmitter::emitSwiftAsyncContextFramePointer(
1731 switch (
MF.getTarget().Options.SwiftAsyncFramePointer) {
1759void AArch64EpilogueEmitter::emitShadowCallStackEpilogue(
1773 if (
AFI->needsAsyncDwarfUnwindInfo(
MF))
1775 .buildRestore(AArch64::X18);
1778void AArch64EpilogueEmitter::emitEarlyReturnAddressAuthentication(
1780 int64_t PrologueSaveSize) {
1794 if (
AFI->hasSVEStackSize())
1796 "argument size in a function with SVE stack objects "
1797 "that signs its return address on Windows");
1800 std::optional<int> LRFrameIdx;
1801 for (
const CalleeSavedInfo &CSI :
MFI.getCalleeSavedInfo())
1802 if (CSI.getReg() == AArch64::LR)
1803 LRFrameIdx = CSI.getFrameIdx();
1810 bool UseFP =
MFI.hasVarSizedObjects() ||
AFI->isStackRealigned();
1813 int64_t Adjustment =
1814 UseFP ? PrologueSaveSize -
AFI->getCalleeSaveBaseToFrameRecordOffset()
1817 MBB,
MBBI, DL, AArch64::X16, UseFP ? AArch64::FP : AArch64::SP,
1827 MachineInstrBuilder MIB =
1830 MIB.addReg(AArch64::FP).addImm(1);
1832 MIB.addFrameIndex(*LRFrameIdx).addImm(0);
1833 MIB.addMemOperand(
MF.getMachineMemOperand(
1851 Builder->findRegisterUseOperand(AArch64::LR, &
RegInfo)->setIsUndef();
1854 if (
AFI->branchProtectionPAuthLR())
1859 if (
MI.getOpcode() == AArch64::PAUTH_EPILOGUE)
1860 MI.eraseFromParent();
1861 AuthenticatedReturnAddressEarly =
true;
1864void AArch64EpilogueEmitter::emitCalleeSavedRestores(
1866 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1872 for (
const auto &Info : CSI) {
1873 if (
SVE !=
MFI.hasScalableStackID(
Info.getFrameIdx()))
1876 MCRegister
Reg =
Info.getReg();
1880 CFIBuilder.buildRestore(
Info.getReg());
1884bool AArch64EpilogueEmitter::hasEpilogueUnwindOps()
const {
1889 if (
AFI->shouldSignReturnAddress(
MF))
1891 return std::any_of(std::next(SEHEpilogueStartI),
MBB.end(),
1892 [](
const MachineInstr &
MI) {
1893 return AArch64InstrInfo::isSEHInstruction(MI) &&
1894 MI.getOpcode() != AArch64::SEH_EpilogEnd;
1898void AArch64EpilogueEmitter::finalizeEpilogue()
const {
1904 if (
AFI->needsShadowCallStackPrologueEpilogue(
MF)) {
1905 emitShadowCallStackEpilogue(
MBB.getFirstTerminator(), DL);
1909 emitCalleeSavedGPRRestores(
MBB.getFirstTerminator());
1910 if (
AFI->shouldSignReturnAddress(
MF)) {
1913 if (!
AFL.shouldSignReturnAddressEverywhere(
MF) &&
1914 !AuthenticatedReturnAddressEarly)
1915 TII->createPauthEpilogueInstr(
MBB, DL);
1927 int64_t TailCalleePopBytes =
AFI->getArgumentStackToRestore() -
1928 AFL.getArgumentStackToRestore(
MF,
MBB);
1929 if (TailCalleePopBytes > 0) {
1933 TII->get(AArch64::SEH_StackAlloc))
1934 .
addImm(TailCalleePopBytes)
1940 BuildMI(
MBB,
MBB.getFirstTerminator(), DL,
TII->get(AArch64::SEH_EpilogEnd))
1942 if (!
MF.hasWinCFI())
1943 MF.setHasWinCFI(
true);
1948 MBB.erase(SEHEpilogueStartI);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declaration of the AArch64PrologueEmitter and AArch64EpilogueEmitter classes,...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
This file contains constants used for implementing Dwarf debug support.
const HexagonInstrInfo * TII
std::pair< Instruction::BinaryOps, Value * > OffsetOp
Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static Function * getFunction(FunctionType *Ty, const Twine &Name, Module *M)
static const unsigned FramePtr
void emitEpilogue()
Emit the epilogue.
AArch64EpilogueEmitter(MachineFunction &MF, MachineBasicBlock &MBB, const AArch64FrameLowering &AFL)
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
void setStackRealigned(bool s)
void emitPrologue()
Emit the prologue.
AArch64PrologueEmitter(MachineFunction &MF, MachineBasicBlock &MBB, const AArch64FrameLowering &AFL)
const MachineFrameInfo & MFI
AArch64FunctionInfo * AFI
MachineBasicBlock::iterator convertCalleeSaveRestoreToSPPrePostIncDec(MachineBasicBlock::iterator MBBI, const DebugLoc &DL, int CSStackSizeInc, bool EmitCFI, MachineInstr::MIFlag FrameFlag=MachineInstr::FrameSetup, int CFAOffset=0) const
SVEFrameSizes getSVEStackFrameSizes() const
bool isVGInstruction(MachineBasicBlock::iterator MBBI, const TargetLowering &TLI) const
AArch64PrologueEpilogueCommon(MachineFunction &MF, MachineBasicBlock &MBB, const AArch64FrameLowering &AFL)
const AArch64RegisterInfo & RegInfo
const AArch64FrameLowering & AFL
@ CalleeSavesAboveFrameRecord
void fixupCalleeSaveRestoreStackOffset(MachineInstr &MI, uint64_t LocalStackSize) const
bool shouldCombineCSRLocalStackBump(uint64_t StackBumpBytes) const
const AArch64Subtarget & Subtarget
SVEStackAllocations getSVEStackAllocations(SVEFrameSizes const &)
const AArch64InstrInfo * TII
bool requiresGetVGCall() const
const AArch64TargetLowering * getTargetLowering() const override
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this functions.
Helper class for creating CFI instructions and inserting them into MIR.
void buildDefCFAOffset(int64_t Offset, MCSymbol *Label=nullptr) const
void insertCFIInst(const MCCFIInstruction &CFIInst) const
void buildDefCFA(MCRegister Reg, int64_t Offset) const
A set of physical registers with utility functions to track liveness when walking backward/forward th...
MachineInstrBundleIterator< MachineInstr > iterator
Align getMaxAlign() const
Return alignment of this function's frame.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
@ MOVolatile
The memory access is volatile.
@ MOLoad
The memory access reads data.
MachineOperand class - Representation of each machine instruction operand.
void setImm(int64_t immVal)
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
static MachineOperand CreateImm(int64_t Val)
const char * getSymbolName() const
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Wrapper class representing virtual and physical registers.
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 getFixed(int64_t Fixed)
Represent a constant reference to a string, i.e.
const char * getLibcallName(RTLIB::Libcall Call) const
Get the libcall routine name for the specified libcall.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
static constexpr TypeSize getFixed(ScalarTy ExactSize)
constexpr ScalarTy getFixedValue() const
#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...
constexpr bool authenticatesLRViaX17(bool BranchProtectionPAuthLR, bool HasPAuth)
Controls whether, for PAUTH_EPILOGUE_ENTRY_SP, we use the hint-space AUTI[AB]1716 instruction to auth...
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 StackProbeMaxUnprobedStack
Maximum allowed number of unprobed bytes above SP at an ABI boundary.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
This is an optimization pass for GlobalISel generic memory operations.
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.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Kill
The last use of a register.
@ Undef
Value of the register doesn't matter.
@ Define
Register definition.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
static bool matchLibcall(const TargetLowering &TLI, const MachineOperand &MO, RTLIB::Libcall LC)
static bool isPartOfSVECalleeSaves(MachineBasicBlock::iterator I)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
static bool isFuncletReturnInstr(const MachineInstr &MI)
auto reverse(ContainerTy &&C)
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.
@ 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.
void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, StackOffset Offset, const TargetInstrInfo *TII, MachineInstr::MIFlag=MachineInstr::NoFlags, bool SetNZCV=false, bool NeedsWinCFI=false, bool *HasWinCFI=nullptr, bool EmitCFAOffset=false, StackOffset InitialOffset={}, unsigned FrameReg=AArch64::SP)
emitFrameOffset - Emit instructions as needed to set DestReg to SrcReg plus Offset.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
static bool isPartOfPPRCalleeSaves(MachineBasicBlock::iterator I)
@ Success
The lock was released successfully.
static void fixupSEHOpcode(MachineBasicBlock::iterator MBBI, unsigned LocalStackSize)
MCCFIInstruction createCFAOffset(const TargetRegisterInfo &MRI, unsigned Reg, const StackOffset &OffsetFromDefCFA, std::optional< int64_t > IncomingVGOffsetFromDefCFA)
DWARFExpression::Operation Op
bool isAsynchronousEHPersonality(EHPersonality Pers)
Returns true if this personality function catches asynchronous exceptions.
static SVEPartitions partitionSVECS(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, StackOffset PPRCalleeSavesSize, StackOffset ZPRCalleeSavesSize, bool IsEpilogue)
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
static bool isPartOfZPRCalleeSaves(MachineBasicBlock::iterator I)
static int64_t upperBound(StackOffset Size)
@ End
Run the machine verifier once, at the end of the pipeline.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
This struct is a compact representation of a valid (non-zero power of two) alignment.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
static LLVM_ABI MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
MachineBasicBlock::iterator End
struct llvm::SVEPartitions::@327166152017175235362202041204223104077330276266 ZPR
struct llvm::SVEPartitions::@327166152017175235362202041204223104077330276266 PPR
MachineBasicBlock::iterator Begin
StackOffset totalSize() const