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_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);
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!?");
777 auto &TLI = *
Subtarget.getTargetLowering();
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);
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