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)) {
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_SaveAnyRegQ:
256 case AArch64::SEH_SaveAnyRegQX:
257 case AArch64::SEH_SaveAnyRegQP:
258 case AArch64::SEH_SaveAnyRegQPX:
259 ImmOpnd = &
MBBI->getOperand(ImmIdx);
268 if (AArch64InstrInfo::isSEHInstruction(
MI))
271 unsigned Opc =
MI.getOpcode();
275 case AArch64::STRXui:
277 case AArch64::STRDui:
279 case AArch64::LDRXui:
281 case AArch64::LDRDui:
285 case AArch64::STRQui:
287 case AArch64::LDRQui:
294 unsigned OffsetIdx =
MI.getNumExplicitOperands() - 1;
295 assert(
MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP &&
296 "Unexpected base register in callee-save save/restore instruction!");
300 assert(LocalStackSize % Scale == 0);
301 OffsetOpnd.
setImm(OffsetOpnd.
getImm() + LocalStackSize / Scale);
306 assert(
MBBI !=
MI.getParent()->end() &&
"Expecting a valid instruction");
307 assert(AArch64InstrInfo::isSEHInstruction(*
MBBI) &&
308 "Expecting a SEH instruction");
315 if (
AFL.homogeneousPrologEpilog(
MF))
318 if (
AFI->getLocalStackSize() == 0)
334 if (
MF.needsWinCFI() &&
AFI->getCalleeSavedStackSize() > 0 &&
335 MF.getFunction().hasOptSize())
340 if (StackBumpBytes >= 512 ||
341 AFL.windowsRequiresStackProbe(
MF, StackBumpBytes))
344 if (
MFI.hasVarSizedObjects())
353 if (
AFL.canUseRedZone(
MF))
358 if (
AFI->hasSVEStackSize())
372 return {{PPRCalleeSavesSize, PPRLocalsSize},
373 {ZPRCalleeSavesSize, ZPRLocalsSize}};
376 {ZPRCalleeSavesSize, PPRLocalsSize + ZPRLocalsSize}};
385 BeforePPRs =
SVE.PPR.CalleeSavesSize;
387 if (
SVE.ZPR.CalleeSavesSize)
388 AfterPPRs +=
SVE.PPR.LocalsSize +
SVE.ZPR.CalleeSavesSize;
390 AfterZPRs +=
SVE.PPR.LocalsSize;
392 return {BeforePPRs, AfterPPRs, AfterZPRs};
408 IsEpilogue ?
MBB.begin() :
MBB.getFirstTerminator();
409 auto AdjustI = [&](
auto MBBI) {
return IsEpilogue ? std::prev(
MBBI) :
MBBI; };
411 if (PPRCalleeSavesSize) {
412 PPRsI = AdjustI(PPRsI);
415 IsEpilogue ? (--PPRsI) : (++PPRsI);
418 if (ZPRCalleeSavesSize) {
419 ZPRsI = AdjustI(ZPRsI);
422 IsEpilogue ? (--ZPRsI) : (++ZPRsI);
425 return {{PPRsI,
MBBI}, {ZPRsI, PPRsI}};
426 return {{
MBBI, PPRsI}, {PPRsI, ZPRsI}};
434 EmitAsyncCFI =
AFI->needsAsyncDwarfUnwindInfo(
MF);
439 collectBlockLiveins();
456void AArch64PrologueEmitter::collectBlockLiveins() {
459 PrologueEndI =
MBB.begin();
460 while (PrologueEndI !=
MBB.end() &&
464 if (PrologueEndI !=
MBB.end()) {
480void AArch64PrologueEmitter::verifyPrologueClobbers()
const {
481 if (PrologueEndI ==
MBB.end())
484 for (MachineInstr &
MI :
485 make_range(
MBB.instr_begin(), PrologueEndI->getIterator())) {
486 for (
auto &
Op :
MI.operands())
487 if (
Op.isReg() &&
Op.isDef())
488 assert(!LiveRegs.contains(
Op.getReg()) &&
489 "live register clobbered by inserted prologue instructions");
494void AArch64PrologueEmitter::determineLocalsStackSize(
496 AFI->setLocalStackSize(StackSize - PrologueSaveSize);
503 static const int64_t MAX_BYTES_PER_SCALABLE_BYTE = 16;
504 return Size.getScalable() * MAX_BYTES_PER_SCALABLE_BYTE +
Size.getFixed();
507void AArch64PrologueEmitter::allocateStackSpace(
509 StackOffset AllocSize,
bool EmitCFI, StackOffset InitialOffset,
510 bool FollowupAllocs) {
517 const uint64_t AndMask = ~(MaxAlign - 1);
519 if (!
Subtarget.getTargetLowering()->hasInlineStackProbe(
MF)) {
520 Register TargetReg = RealignmentPadding
521 ?
AFL.findScratchNonCalleeSaveRegister(&
MBB)
528 if (RealignmentPadding) {
549 if (AllocSize.getScalable() == 0 && RealignmentPadding == 0) {
551 assert(ScratchReg.isValid());
554 .
addImm(AllocSize.getFixed())
555 .
addImm(InitialOffset.getFixed())
556 .
addImm(InitialOffset.getScalable());
561 if (FollowupAllocs) {
581 int64_t ProbeSize =
AFI->getStackProbeSize();
582 if (
upperBound(AllocSize) + RealignmentPadding <= ProbeSize) {
583 Register ScratchReg = RealignmentPadding
584 ?
AFL.findScratchNonCalleeSaveRegister(&
MBB)
586 assert(ScratchReg.isValid());
591 if (RealignmentPadding) {
597 AFI->setStackRealigned(
true);
599 if (FollowupAllocs ||
upperBound(AllocSize) + RealignmentPadding >
619 assert(TargetReg.isValid());
624 if (RealignmentPadding) {
637 .buildDefCFARegister(AArch64::SP);
639 if (RealignmentPadding)
640 AFI->setStackRealigned(
true);
650 AFI->setHasRedZone(
false);
660 if (int64_t ArgBytes =
AFI->getArgumentStackToRestore()) {
676 if (
AFI->shouldSignReturnAddress(
MF)) {
679 if (!
AFL.shouldSignReturnAddressEverywhere(
MF)) {
687 if (
AFI->needsShadowCallStackPrologueEpilogue(
MF)) {
688 emitShadowCallStackPrologue(PrologueBeginI,
DL);
700 if (
HasFP &&
AFI->hasSwiftAsyncContext())
701 emitSwiftAsyncContextFramePointer(PrologueBeginI,
DL);
710 if (std::optional<int> TBPI =
AFI->getTaggedBasePointerIndex())
711 AFI->setTaggedBasePointerOffset(-
MFI.getObjectOffset(*TBPI));
713 AFI->setTaggedBasePointerOffset(
MFI.getStackSize());
723 if (!
AFI->hasStackFrame() && !
AFL.windowsRequiresStackProbe(
MF, NumBytes))
724 return emitEmptyStackFramePrologue(NumBytes, PrologueBeginI,
DL);
726 bool IsWin64 =
Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg());
729 auto PrologueSaveSize =
AFI->getCalleeSavedStackSize() + FixedObject;
731 determineLocalsStackSize(NumBytes, PrologueSaveSize);
739 "unexpected SVE allocs after PPRs with CalleeSavesAboveFrameRecord");
746 allocateStackSpace(PrologueBeginI, 0, SaveSize,
false,
StackOffset{},
748 NumBytes -= FixedObject;
755 MBBI,
DL, -
AFI->getCalleeSavedStackSize(), EmitAsyncCFI);
756 NumBytes -=
AFI->getCalleeSavedStackSize();
757 }
else if (CombineSPBump) {
758 assert(!
AFL.getSVEStackSize(
MF) &&
"Cannot combine SP bump with SVE");
766 NumBytes -= PrologueSaveSize;
767 }
else if (PrologueSaveSize != 0) {
769 PrologueBeginI,
DL, -PrologueSaveSize, EmitAsyncCFI);
770 NumBytes -= PrologueSaveSize;
772 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
780 while (AfterGPRSavesI != EndI &&
787 AFI->getLocalStackSize());
794 emitFramePointerSetup(AfterGPRSavesI,
DL, FixedObject);
800 emitCalleeSavedGPRLocations(AfterGPRSavesI);
803 const bool NeedsRealignment =
805 const int64_t RealignmentPadding =
806 (NeedsRealignment &&
MFI.getMaxAlign() >
Align(16))
807 ?
MFI.getMaxAlign().value() - 16
810 if (
AFL.windowsRequiresStackProbe(
MF, NumBytes + RealignmentPadding))
811 emitWindowsStackProbe(AfterGPRSavesI,
DL, NumBytes, RealignmentPadding);
821 auto [PPRRange, ZPRRange] =
823 ZPR.CalleeSavesSize,
false);
824 AfterSVESavesI = ZPRRange.End;
826 emitCalleeSavedSVELocations(AfterSVESavesI);
828 allocateStackSpace(PPRRange.Begin, 0, SVEAllocs.
BeforePPRs,
829 EmitAsyncCFI && !
HasFP, CFAOffset,
833 assert(PPRRange.End == ZPRRange.Begin &&
834 "Expected ZPR callee saves after PPR locals");
835 allocateStackSpace(PPRRange.End, 0, SVEAllocs.
AfterPPRs,
836 EmitAsyncCFI && !
HasFP, CFAOffset,
849 assert(!(
AFL.canUseRedZone(
MF) && NeedsRealignment) &&
850 "Cannot use redzone with stack realignment");
851 if (!
AFL.canUseRedZone(
MF)) {
855 allocateStackSpace(AfterSVESavesI, RealignmentPadding, SVEAllocs.
AfterZPRs,
856 EmitAsyncCFI && !
HasFP, CFAOffset,
857 MFI.hasVarSizedObjects());
896 MBB.addLiveIn(AArch64::X1);
900 if (
EmitCFI && !EmitAsyncCFI) {
902 emitDefineCFAWithFP(AfterSVESavesI, FixedObject);
905 AFL.getSVEStackSize(
MF) +
912 emitCalleeSavedGPRLocations(AfterSVESavesI);
913 emitCalleeSavedSVELocations(AfterSVESavesI);
917void AArch64PrologueEmitter::emitShadowCallStackPrologue(
928 MBB.addLiveIn(AArch64::X18);
937 static const char CFIInst[] = {
938 dwarf::DW_CFA_val_expression,
941 static_cast<char>(
unsigned(dwarf::DW_OP_breg18)),
942 static_cast<char>(-8) & 0x7f,
945 .buildEscape(StringRef(CFIInst,
sizeof(CFIInst)));
949void AArch64PrologueEmitter::emitSwiftAsyncContextFramePointer(
951 switch (
MF.getTarget().Options.SwiftAsyncFramePointer) {
953 if (
Subtarget.swiftAsyncContextIsDynamicallySet()) {
995void AArch64PrologueEmitter::emitEmptyStackFramePrologue(
998 assert(!
HasFP &&
"unexpected function without stack frame but with FP");
1000 "unexpected function without stack frame but with SVE objects");
1002 AFI->setLocalStackSize(NumBytes);
1012 if (
AFL.canUseRedZone(
MF)) {
1013 AFI->setHasRedZone(
true);
1014 ++NumRedZoneFunctions;
1021 MCSymbol *FrameLabel =
MF.getContext().createTempSymbol();
1024 .buildDefCFAOffset(NumBytes, FrameLabel);
1035void AArch64PrologueEmitter::emitFramePointerSetup(
1037 unsigned FixedObject) {
1038 int64_t FPOffset =
AFI->getCalleeSaveBaseToFrameRecordOffset();
1040 FPOffset +=
AFI->getLocalStackSize();
1042 if (
AFI->hasSwiftAsyncContext()) {
1046 const auto &
Attrs =
MF.getFunction().getAttributes();
1047 bool HaveInitialContext =
Attrs.hasAttrSomewhere(Attribute::SwiftAsync);
1048 if (HaveInitialContext)
1049 MBB.addLiveIn(AArch64::X22);
1050 Register Reg = HaveInitialContext ? AArch64::X22 : AArch64::XZR;
1088 emitDefineCFAWithFP(
MBBI, FixedObject);
1092void AArch64PrologueEmitter::emitDefineCFAWithFP(
1094 const int OffsetToFirstCalleeSaveFromFP =
1095 AFI->getCalleeSaveBaseToFrameRecordOffset() -
1096 AFI->getCalleeSavedStackSize();
1099 .buildDefCFA(
FramePtr, FixedObject - OffsetToFirstCalleeSaveFromFP);
1102void AArch64PrologueEmitter::emitWindowsStackProbe(
1104 int64_t RealignmentPadding)
const {
1105 if (
AFI->getSVECalleeSavedStackSize())
1112 [
this](
const MachineBasicBlock::RegisterMaskPair &LiveIn) {
1113 return RegInfo.isSuperOrSubRegisterEq(AArch64::X15,
1116 X15Scratch =
AFL.findScratchNonCalleeSaveRegister(&
MBB,
true);
1117 assert(X15Scratch.isValid() &&
1118 (X15Scratch < AArch64::X15 || X15Scratch > AArch64::X17));
1120 LiveRegs.removeReg(AArch64::X15);
1129 uint64_t NumWords = (NumBytes + RealignmentPadding) >> 4;
1137 if (NumBytes >= (1 << 28))
1139 "unwinding purposes");
1141 uint32_t LowNumWords = NumWords & 0xFFFF;
1148 if ((NumWords & 0xFFFF0000) != 0) {
1151 .
addImm((NumWords & 0xFFFF0000) >> 16)
1163 const AArch64TargetLowering *
TLI =
Subtarget.getTargetLowering();
1164 RTLIB::LibcallImpl ChkStkLibcall =
TLI->getLibcallImpl(RTLIB::STACK_PROBE);
1165 if (ChkStkLibcall == RTLIB::Unsupported)
1168 const char *ChkStk =
TLI->getLibcallImplName(ChkStkLibcall).data();
1169 switch (
MF.getTarget().getCodeModel()) {
1233 if (RealignmentPadding > 0) {
1234 if (RealignmentPadding >= 4096) {
1237 .
addImm(RealignmentPadding)
1247 .
addImm(RealignmentPadding)
1252 uint64_t AndMask = ~(
MFI.getMaxAlign().value() - 1);
1256 AFI->setStackRealigned(
true);
1262 if (X15Scratch.isValid()) {
1271void AArch64PrologueEmitter::emitCalleeSavedGPRLocations(
1273 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1278 for (
const auto &Info : CSI) {
1279 unsigned FrameIdx =
Info.getFrameIdx();
1280 if (
MFI.hasScalableStackID(FrameIdx))
1283 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
1284 int64_t
Offset =
MFI.getObjectOffset(FrameIdx) -
AFL.getOffsetOfLocalArea();
1285 CFIBuilder.buildOffset(
Info.getReg(),
Offset);
1289void AArch64PrologueEmitter::emitCalleeSavedSVELocations(
1292 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1298 std::optional<int64_t> IncomingVGOffsetFromDefCFA;
1299 if (
AFL.requiresSaveVG(
MF)) {
1301 reverse(CSI), [](
auto &Info) {
return Info.getReg() == AArch64::VG; });
1302 IncomingVGOffsetFromDefCFA =
MFI.getObjectOffset(IncomingVG.getFrameIdx()) -
1303 AFL.getOffsetOfLocalArea();
1306 StackOffset PPRStackSize =
AFL.getPPRStackSize(
MF);
1307 for (
const auto &Info : CSI) {
1308 int FI =
Info.getFrameIdx();
1309 if (!
MFI.hasScalableStackID(FI))
1314 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
1315 MCRegister
Reg =
Info.getReg();
1329 CFIBuilder.insertCFIInst(
1335 switch (
MI.getOpcode()) {
1338 case AArch64::CATCHRET:
1339 case AArch64::CLEANUPRET:
1350 SEHEpilogueStartI =
MBB.end();
1357 "expected negative offset (with optional fixed portion)");
1359 if (int64_t FixedOffset =
Offset.getFixed()) {
1375 if (
MBB.end() != EpilogueEndI) {
1376 DL = EpilogueEndI->getDebugLoc();
1390 int64_t ArgumentStackToRestore =
AFL.getArgumentStackToRestore(
MF,
MBB);
1391 bool IsWin64 =
Subtarget.isCallingConvWin64(
MF.getFunction().getCallingConv(),
1392 MF.getFunction().isVarArg());
1395 const bool AuthenticateReturnAddressEarly =
1398 int64_t AfterCSRPopSize = ArgumentStackToRestore;
1399 auto PrologueSaveSize =
AFI->getCalleeSavedStackSize() + FixedObject;
1404 if (
MF.hasEHFunclets())
1405 AFI->setLocalStackSize(NumBytes - PrologueSaveSize);
1409 auto FirstHomogenousEpilogI =
MBB.getFirstTerminator();
1410 if (FirstHomogenousEpilogI !=
MBB.begin()) {
1411 auto HomogeneousEpilog = std::prev(FirstHomogenousEpilogI);
1412 if (HomogeneousEpilog->getOpcode() == AArch64::HOM_Epilog)
1413 FirstHomogenousEpilogI = HomogeneousEpilog;
1423 assert(AfterCSRPopSize == 0);
1427 bool CombineSPBump = shouldCombineCSRLocalStackBump(NumBytes);
1429 unsigned ProloguePopSize = PrologueSaveSize;
1435 ProloguePopSize -= FixedObject;
1436 AfterCSRPopSize += FixedObject;
1442 if (!CombineSPBump && ProloguePopSize != 0 &&
1443 AuthenticateReturnAddressEarly) {
1444 AfterCSRPopSize += ProloguePopSize;
1445 }
else if (!CombineSPBump && ProloguePopSize != 0) {
1447 while (Pop->getOpcode() == TargetOpcode::CFI_INSTRUCTION ||
1448 AArch64InstrInfo::isSEHInstruction(*Pop) ||
1451 Pop = std::prev(Pop);
1458 if (
OffsetOp.getImm() == 0 && AfterCSRPopSize >= 0) {
1464 if (AArch64InstrInfo::isSEHInstruction(*AfterLastPop))
1478 AfterCSRPopSize += ProloguePopSize;
1487 while (FirstGPRRestoreI != Begin) {
1494 }
else if (CombineSPBump)
1496 AFI->getLocalStackSize());
1502 if (AuthenticateReturnAddressEarly)
1503 emitEarlyReturnAddressAuthentication(FirstGPRRestoreI,
MFI.getStackSize(),
1513 BuildMI(
MBB, FirstGPRRestoreI, DL,
TII->get(AArch64::SEH_EpilogStart))
1515 SEHEpilogueStartI = FirstGPRRestoreI;
1516 --SEHEpilogueStartI;
1526 ?
MBB.getFirstTerminator()
1528 PPR.CalleeSavesSize, ZPR.CalleeSavesSize,
true);
1530 if (
HasFP &&
AFI->hasSwiftAsyncContext())
1531 emitSwiftAsyncContextFramePointer(EpilogueEndI, DL);
1534 if (CombineSPBump) {
1535 assert(!
AFI->hasSVEStackSize() &&
"Cannot combine SP bump with SVE");
1549 NumBytes -= PrologueSaveSize;
1550 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
1552 StackOffset SVECalleeSavesSize = ZPR.CalleeSavesSize + PPR.CalleeSavesSize;
1558 "unexpected SVE allocs after PPRs with CalleeSavesAboveFrameRecord");
1562 if (!
AFI->isStackRealigned() && !
MFI.hasVarSizedObjects()) {
1572 }
else if (
AFI->hasSVEStackSize()) {
1577 (
AFI->isStackRealigned() ||
MFI.hasVarSizedObjects()) ? AArch64::FP
1579 if (SVECalleeSavesSize && BaseForSVEDealloc == AArch64::FP) {
1583 -SVECalleeSavesSize - PPR.LocalsSize -
1587 moveSPBelowFP(ZPRRange.Begin, FPOffsetZPR);
1595 assert(!FPOffsetPPR.
getFixed() &&
"expected only scalable offset");
1599 }
else if (BaseForSVEDealloc == AArch64::SP) {
1608 NumBytes -= NonSVELocals.getFixed();
1616 assert(PPRRange.Begin == ZPRRange.End &&
1617 "Expected PPR restores after ZPR");
1630 emitCalleeSavedSVERestores(
1635 bool RedZone =
AFL.canUseRedZone(
MF);
1638 if (RedZone && AfterCSRPopSize == 0)
1645 bool NoCalleeSaveRestore = PrologueSaveSize == 0;
1646 int64_t StackRestoreBytes = RedZone ? 0 : NumBytes;
1647 if (NoCalleeSaveRestore)
1648 StackRestoreBytes += AfterCSRPopSize;
1651 MBB, FirstGPRRestoreI, DL, AArch64::SP, AArch64::SP,
1658 if (NoCalleeSaveRestore || AfterCSRPopSize == 0)
1668 if (!
IsFunclet && (
MFI.hasVarSizedObjects() ||
AFI->isStackRealigned())) {
1670 MBB, FirstGPRRestoreI, DL, AArch64::SP, AArch64::FP,
1673 }
else if (NumBytes)
1686 if (AfterCSRPopSize) {
1687 assert(AfterCSRPopSize > 0 &&
"attempting to reallocate arg stack that an "
1688 "interrupt may have clobbered");
1691 MBB,
MBB.getFirstTerminator(), DL, AArch64::SP, AArch64::SP,
1698bool AArch64EpilogueEmitter::shouldCombineCSRLocalStackBump(
1710 while (LastI != Begin) {
1712 if (LastI->isTransient())
1717 switch (LastI->getOpcode()) {
1718 case AArch64::STGloop:
1719 case AArch64::STZGloop:
1721 case AArch64::STZGi:
1722 case AArch64::ST2Gi:
1723 case AArch64::STZ2Gi:
1731void AArch64EpilogueEmitter::emitSwiftAsyncContextFramePointer(
1733 switch (
MF.getTarget().Options.SwiftAsyncFramePointer) {
1761void AArch64EpilogueEmitter::emitShadowCallStackEpilogue(
1775 if (
AFI->needsAsyncDwarfUnwindInfo(
MF))
1777 .buildRestore(AArch64::X18);
1780void AArch64EpilogueEmitter::emitEarlyReturnAddressAuthentication(
1782 int64_t PrologueSaveSize) {
1796 if (
AFI->hasSVEStackSize())
1798 "argument size in a function with SVE stack objects "
1799 "that signs its return address on Windows");
1802 std::optional<int> LRFrameIdx;
1803 for (
const CalleeSavedInfo &CSI :
MFI.getCalleeSavedInfo())
1804 if (CSI.getReg() == AArch64::LR)
1805 LRFrameIdx = CSI.getFrameIdx();
1812 bool UseFP =
MFI.hasVarSizedObjects() ||
AFI->isStackRealigned();
1815 int64_t Adjustment =
1816 UseFP ? PrologueSaveSize -
AFI->getCalleeSaveBaseToFrameRecordOffset()
1819 MBB,
MBBI, DL, AArch64::X16, UseFP ? AArch64::FP : AArch64::SP,
1829 MachineInstrBuilder MIB =
1832 MIB.addReg(AArch64::FP).addImm(1);
1834 MIB.addFrameIndex(*LRFrameIdx).addImm(0);
1835 MIB.addMemOperand(
MF.getMachineMemOperand(
1853 Builder->findRegisterUseOperand(AArch64::LR, &
RegInfo)->setIsUndef();
1856 if (
AFI->branchProtectionPAuthLR())
1861 if (
MI.getOpcode() == AArch64::PAUTH_EPILOGUE)
1862 MI.eraseFromParent();
1863 AuthenticatedReturnAddressEarly =
true;
1866void AArch64EpilogueEmitter::emitCalleeSavedRestores(
1868 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1874 for (
const auto &Info : CSI) {
1875 if (
SVE !=
MFI.hasScalableStackID(
Info.getFrameIdx()))
1878 MCRegister
Reg =
Info.getReg();
1882 CFIBuilder.buildRestore(
Info.getReg());
1886bool AArch64EpilogueEmitter::hasEpilogueUnwindOps()
const {
1891 if (
AFI->shouldSignReturnAddress(
MF))
1893 return std::any_of(std::next(SEHEpilogueStartI),
MBB.end(),
1894 [](
const MachineInstr &
MI) {
1895 return AArch64InstrInfo::isSEHInstruction(MI) &&
1896 MI.getOpcode() != AArch64::SEH_EpilogEnd;
1900void AArch64EpilogueEmitter::finalizeEpilogue()
const {
1906 if (
AFI->needsShadowCallStackPrologueEpilogue(
MF)) {
1907 emitShadowCallStackEpilogue(
MBB.getFirstTerminator(), DL);
1911 emitCalleeSavedGPRRestores(
MBB.getFirstTerminator());
1912 if (
AFI->shouldSignReturnAddress(
MF)) {
1915 if (!
AFL.shouldSignReturnAddressEverywhere(
MF) &&
1916 !AuthenticatedReturnAddressEarly)
1917 TII->createPauthEpilogueInstr(
MBB, DL);
1929 int64_t TailCalleePopBytes =
AFI->getArgumentStackToRestore() -
1930 AFL.getArgumentStackToRestore(
MF,
MBB);
1931 if (TailCalleePopBytes > 0) {
1935 TII->get(AArch64::SEH_StackAlloc))
1936 .
addImm(TailCalleePopBytes)
1942 BuildMI(
MBB,
MBB.getFirstTerminator(), DL,
TII->get(AArch64::SEH_EpilogEnd))
1944 if (!
MF.hasWinCFI())
1945 MF.setHasWinCFI(
true);
1950 MBB.erase(SEHEpilogueStartI);
const AArch64Subtarget & Subtarget
const TargetLowering & TLI
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
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.
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