19#define DEBUG_TYPE "frame-info"
21STATISTIC(NumRedZoneFunctions,
"Number of functions using red zone");
32 return AFI->hasStreamingModeChanges() &&
38 unsigned Opc =
MBBI->getOpcode();
39 if (
Opc == AArch64::CNTD_XPiI)
45 if (
Opc == AArch64::BL)
48 return Opc == TargetOpcode::COPY;
53 switch (
I->getOpcode()) {
56 case AArch64::LD1B_2Z_IMM:
57 case AArch64::ST1B_2Z_IMM:
58 case AArch64::LD1B_4Z_IMM:
59 case AArch64::ST1B_4Z_IMM:
60 case AArch64::STR_ZXI:
61 case AArch64::LDR_ZXI:
62 case AArch64::PTRUE_C_B:
65 case AArch64::SEH_SaveZReg:
72 switch (
I->getOpcode()) {
75 case AArch64::STR_PXI:
76 case AArch64::LDR_PXI:
79 case AArch64::SEH_SavePReg:
101 if (
AFL.hasSVECalleeSavesAboveFrameRecord(
MF)) {
102 if (AFI->hasStackHazardSlotIndex())
103 reportFatalUsageError(
"SME hazard padding is not supported on Windows");
104 SVELayout = SVEStackLayout::CalleeSavesAboveFrameRecord;
105 }
else if (
AFI->hasSplitSVEObjects()) {
106 SVELayout = SVEStackLayout::Split;
119 if (
AFL.requiresSaveVG(
MF)) {
120 auto &TLI = *
Subtarget.getTargetLowering();
125 switch (
MBBI->getOpcode()) {
129 NewOpc = AArch64::STPXpre;
132 NewOpc = AArch64::STPDpre;
135 NewOpc = AArch64::STPQpre;
137 case AArch64::STRXui:
138 NewOpc = AArch64::STRXpre;
140 case AArch64::STRDui:
141 NewOpc = AArch64::STRDpre;
143 case AArch64::STRQui:
144 NewOpc = AArch64::STRQpre;
147 NewOpc = AArch64::LDPXpost;
150 NewOpc = AArch64::LDPDpost;
153 NewOpc = AArch64::LDPQpost;
155 case AArch64::LDRXui:
156 NewOpc = AArch64::LDRXpost;
158 case AArch64::LDRDui:
159 NewOpc = AArch64::LDRDpost;
161 case AArch64::LDRQui:
162 NewOpc = AArch64::LDRQpost;
166 int64_t MinOffset, MaxOffset;
167 bool Success =
TII->getMemOpInfo(NewOpc, Scale, Width, MinOffset, MaxOffset);
176 if (
MBBI->getOperand(
MBBI->getNumOperands() - 1).getImm() != 0 ||
177 CSStackSizeInc < MinOffset * (int64_t)Scale.
getFixedValue() ||
178 CSStackSizeInc > MaxOffset * (int64_t)Scale.
getFixedValue() ||
180 (NewOpc == AArch64::LDPXpost || NewOpc == AArch64::STPXpre) &&
181 RegInfo.getEncodingValue(
MBBI->getOperand(0).getReg()) + 1 !=
182 RegInfo.getEncodingValue(
MBBI->getOperand(1).getReg()))) {
196 return std::prev(
MBBI);
201 auto SEH = std::next(
MBBI);
202 if (AArch64InstrInfo::isSEHInstruction(*SEH))
203 SEH->eraseFromParent();
210 unsigned OpndIdx = 0;
211 for (
unsigned OpndEnd =
MBBI->getNumOperands() - 1; OpndIdx < OpndEnd;
213 MIB.
add(
MBBI->getOperand(OpndIdx));
215 assert(
MBBI->getOperand(OpndIdx).getImm() == 0 &&
216 "Unexpected immediate offset in first/last callee-save save/restore "
218 assert(
MBBI->getOperand(OpndIdx - 1).getReg() == AArch64::SP &&
219 "Unexpected base register in callee-save save/restore instruction!");
220 assert(CSStackSizeInc % Scale == 0);
221 MIB.
addImm(CSStackSizeInc / (
int)Scale);
229 AFL.insertSEH(*MIB, *
TII, FrameFlag);
236 return std::prev(
MBB.erase(
MBBI));
241 unsigned LocalStackSize) {
243 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
244 switch (
MBBI->getOpcode()) {
247 case AArch64::SEH_SaveFPLR:
248 case AArch64::SEH_SaveRegP:
249 case AArch64::SEH_SaveReg:
250 case AArch64::SEH_SaveFRegP:
251 case AArch64::SEH_SaveFReg:
252 case AArch64::SEH_SaveAnyRegI:
253 case AArch64::SEH_SaveAnyRegIP:
254 case AArch64::SEH_SaveAnyRegQP:
255 case AArch64::SEH_SaveAnyRegQPX:
256 ImmOpnd = &
MBBI->getOperand(ImmIdx);
265 if (AArch64InstrInfo::isSEHInstruction(
MI))
268 unsigned Opc =
MI.getOpcode();
272 case AArch64::STRXui:
274 case AArch64::STRDui:
276 case AArch64::LDRXui:
278 case AArch64::LDRDui:
282 case AArch64::STRQui:
284 case AArch64::LDRQui:
291 unsigned OffsetIdx =
MI.getNumExplicitOperands() - 1;
292 assert(
MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP &&
293 "Unexpected base register in callee-save save/restore instruction!");
297 assert(LocalStackSize % Scale == 0);
298 OffsetOpnd.
setImm(OffsetOpnd.
getImm() + LocalStackSize / Scale);
303 assert(
MBBI !=
MI.getParent()->end() &&
"Expecting a valid instruction");
304 assert(AArch64InstrInfo::isSEHInstruction(*
MBBI) &&
305 "Expecting a SEH instruction");
312 if (
AFL.homogeneousPrologEpilog(
MF))
315 if (
AFI->getLocalStackSize() == 0)
331 if (
MF.needsWinCFI() &&
AFI->getCalleeSavedStackSize() > 0 &&
332 MF.getFunction().hasOptSize())
337 if (StackBumpBytes >= 512 ||
338 AFL.windowsRequiresStackProbe(
MF, StackBumpBytes))
341 if (
MFI.hasVarSizedObjects())
350 if (
AFL.canUseRedZone(
MF))
355 if (
AFI->hasSVEStackSize())
369 return {{PPRCalleeSavesSize, PPRLocalsSize},
370 {ZPRCalleeSavesSize, ZPRLocalsSize}};
373 {ZPRCalleeSavesSize, PPRLocalsSize + ZPRLocalsSize}};
382 BeforePPRs =
SVE.PPR.CalleeSavesSize;
384 if (
SVE.ZPR.CalleeSavesSize)
385 AfterPPRs +=
SVE.PPR.LocalsSize +
SVE.ZPR.CalleeSavesSize;
387 AfterZPRs +=
SVE.PPR.LocalsSize;
389 return {BeforePPRs, AfterPPRs, AfterZPRs};
405 IsEpilogue ?
MBB.begin() :
MBB.getFirstTerminator();
406 auto AdjustI = [&](
auto MBBI) {
return IsEpilogue ? std::prev(
MBBI) :
MBBI; };
408 if (PPRCalleeSavesSize) {
409 PPRsI = AdjustI(PPRsI);
412 IsEpilogue ? (--PPRsI) : (++PPRsI);
415 if (ZPRCalleeSavesSize) {
416 ZPRsI = AdjustI(ZPRsI);
419 IsEpilogue ? (--ZPRsI) : (++ZPRsI);
422 return {{PPRsI,
MBBI}, {ZPRsI, PPRsI}};
423 return {{
MBBI, PPRsI}, {PPRsI, ZPRsI}};
431 EmitAsyncCFI =
AFI->needsAsyncDwarfUnwindInfo(
MF);
436 collectBlockLiveins();
453void AArch64PrologueEmitter::collectBlockLiveins() {
456 PrologueEndI =
MBB.begin();
457 while (PrologueEndI !=
MBB.end() &&
461 if (PrologueEndI !=
MBB.end()) {
477void AArch64PrologueEmitter::verifyPrologueClobbers()
const {
478 if (PrologueEndI ==
MBB.end())
481 for (MachineInstr &
MI :
482 make_range(
MBB.instr_begin(), PrologueEndI->getIterator())) {
483 for (
auto &
Op :
MI.operands())
484 if (
Op.isReg() &&
Op.isDef())
485 assert(!LiveRegs.contains(
Op.getReg()) &&
486 "live register clobbered by inserted prologue instructions");
491void AArch64PrologueEmitter::determineLocalsStackSize(
493 AFI->setLocalStackSize(StackSize - PrologueSaveSize);
500 static const int64_t MAX_BYTES_PER_SCALABLE_BYTE = 16;
501 return Size.getScalable() * MAX_BYTES_PER_SCALABLE_BYTE +
Size.getFixed();
504void AArch64PrologueEmitter::allocateStackSpace(
506 StackOffset AllocSize,
bool EmitCFI, StackOffset InitialOffset,
507 bool FollowupAllocs) {
514 const uint64_t AndMask = ~(MaxAlign - 1);
517 Register TargetReg = RealignmentPadding
518 ?
AFL.findScratchNonCalleeSaveRegister(&
MBB)
525 if (RealignmentPadding) {
546 if (AllocSize.getScalable() == 0 && RealignmentPadding == 0) {
548 assert(ScratchReg.isValid());
551 .
addImm(AllocSize.getFixed())
552 .
addImm(InitialOffset.getFixed())
553 .
addImm(InitialOffset.getScalable());
558 if (FollowupAllocs) {
578 int64_t ProbeSize =
AFI->getStackProbeSize();
579 if (
upperBound(AllocSize) + RealignmentPadding <= ProbeSize) {
580 Register ScratchReg = RealignmentPadding
581 ?
AFL.findScratchNonCalleeSaveRegister(&
MBB)
583 assert(ScratchReg.isValid());
588 if (RealignmentPadding) {
594 AFI->setStackRealigned(
true);
596 if (FollowupAllocs ||
upperBound(AllocSize) + RealignmentPadding >
616 assert(TargetReg.isValid());
621 if (RealignmentPadding) {
634 .buildDefCFARegister(AArch64::SP);
636 if (RealignmentPadding)
637 AFI->setStackRealigned(
true);
647 AFI->setHasRedZone(
false);
657 if (
AFI->getArgumentStackToRestore())
660 if (
AFI->shouldSignReturnAddress(
MF)) {
663 if (!
AFL.shouldSignReturnAddressEverywhere(
MF)) {
671 if (
AFI->needsShadowCallStackPrologueEpilogue(
MF)) {
672 emitShadowCallStackPrologue(PrologueBeginI,
DL);
684 if (
HasFP &&
AFI->hasSwiftAsyncContext())
685 emitSwiftAsyncContextFramePointer(PrologueBeginI,
DL);
694 if (std::optional<int> TBPI =
AFI->getTaggedBasePointerIndex())
695 AFI->setTaggedBasePointerOffset(-
MFI.getObjectOffset(*TBPI));
697 AFI->setTaggedBasePointerOffset(
MFI.getStackSize());
707 if (!
AFI->hasStackFrame() && !
AFL.windowsRequiresStackProbe(
MF, NumBytes))
708 return emitEmptyStackFramePrologue(NumBytes, PrologueBeginI,
DL);
710 bool IsWin64 =
Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg());
713 auto PrologueSaveSize =
AFI->getCalleeSavedStackSize() + FixedObject;
715 determineLocalsStackSize(NumBytes, PrologueSaveSize);
723 "unexpected SVE allocs after PPRs with CalleeSavesAboveFrameRecord");
730 allocateStackSpace(PrologueBeginI, 0, SaveSize,
false,
StackOffset{},
732 NumBytes -= FixedObject;
739 MBBI,
DL, -
AFI->getCalleeSavedStackSize(), EmitAsyncCFI);
740 NumBytes -=
AFI->getCalleeSavedStackSize();
741 }
else if (CombineSPBump) {
742 assert(!
AFL.getSVEStackSize(
MF) &&
"Cannot combine SP bump with SVE");
750 NumBytes -= PrologueSaveSize;
751 }
else if (PrologueSaveSize != 0) {
753 PrologueBeginI,
DL, -PrologueSaveSize, EmitAsyncCFI);
754 NumBytes -= PrologueSaveSize;
756 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
761 auto &TLI = *
Subtarget.getTargetLowering();
764 while (AfterGPRSavesI != EndI &&
771 AFI->getLocalStackSize());
778 emitFramePointerSetup(AfterGPRSavesI,
DL, FixedObject);
784 emitCalleeSavedGPRLocations(AfterGPRSavesI);
787 const bool NeedsRealignment =
789 const int64_t RealignmentPadding =
790 (NeedsRealignment &&
MFI.getMaxAlign() >
Align(16))
791 ?
MFI.getMaxAlign().value() - 16
794 if (
AFL.windowsRequiresStackProbe(
MF, NumBytes + RealignmentPadding))
795 emitWindowsStackProbe(AfterGPRSavesI,
DL, NumBytes, RealignmentPadding);
805 auto [PPRRange, ZPRRange] =
807 ZPR.CalleeSavesSize,
false);
808 AfterSVESavesI = ZPRRange.End;
810 emitCalleeSavedSVELocations(AfterSVESavesI);
812 allocateStackSpace(PPRRange.Begin, 0, SVEAllocs.
BeforePPRs,
813 EmitAsyncCFI && !
HasFP, CFAOffset,
817 assert(PPRRange.End == ZPRRange.Begin &&
818 "Expected ZPR callee saves after PPR locals");
819 allocateStackSpace(PPRRange.End, 0, SVEAllocs.
AfterPPRs,
820 EmitAsyncCFI && !
HasFP, CFAOffset,
833 assert(!(
AFL.canUseRedZone(
MF) && NeedsRealignment) &&
834 "Cannot use redzone with stack realignment");
835 if (!
AFL.canUseRedZone(
MF)) {
839 allocateStackSpace(AfterSVESavesI, RealignmentPadding, SVEAllocs.
AfterZPRs,
840 EmitAsyncCFI && !
HasFP, CFAOffset,
841 MFI.hasVarSizedObjects());
880 MBB.addLiveIn(AArch64::X1);
884 if (
EmitCFI && !EmitAsyncCFI) {
886 emitDefineCFAWithFP(AfterSVESavesI, FixedObject);
889 AFL.getSVEStackSize(
MF) +
896 emitCalleeSavedGPRLocations(AfterSVESavesI);
897 emitCalleeSavedSVELocations(AfterSVESavesI);
901void AArch64PrologueEmitter::emitShadowCallStackPrologue(
912 MBB.addLiveIn(AArch64::X18);
921 static const char CFIInst[] = {
922 dwarf::DW_CFA_val_expression,
925 static_cast<char>(
unsigned(dwarf::DW_OP_breg18)),
926 static_cast<char>(-8) & 0x7f,
929 .buildEscape(StringRef(CFIInst,
sizeof(CFIInst)));
933void AArch64PrologueEmitter::emitSwiftAsyncContextFramePointer(
935 switch (
MF.getTarget().Options.SwiftAsyncFramePointer) {
937 if (
Subtarget.swiftAsyncContextIsDynamicallySet()) {
979void AArch64PrologueEmitter::emitEmptyStackFramePrologue(
982 assert(!
HasFP &&
"unexpected function without stack frame but with FP");
984 "unexpected function without stack frame but with SVE objects");
986 AFI->setLocalStackSize(NumBytes);
996 if (
AFL.canUseRedZone(
MF)) {
997 AFI->setHasRedZone(
true);
998 ++NumRedZoneFunctions;
1005 MCSymbol *FrameLabel =
MF.getContext().createTempSymbol();
1008 .buildDefCFAOffset(NumBytes, FrameLabel);
1019void AArch64PrologueEmitter::emitFramePointerSetup(
1021 unsigned FixedObject) {
1022 int64_t FPOffset =
AFI->getCalleeSaveBaseToFrameRecordOffset();
1024 FPOffset +=
AFI->getLocalStackSize();
1026 if (
AFI->hasSwiftAsyncContext()) {
1030 const auto &
Attrs =
MF.getFunction().getAttributes();
1031 bool HaveInitialContext =
Attrs.hasAttrSomewhere(Attribute::SwiftAsync);
1032 if (HaveInitialContext)
1033 MBB.addLiveIn(AArch64::X22);
1034 Register Reg = HaveInitialContext ? AArch64::X22 : AArch64::XZR;
1072 emitDefineCFAWithFP(
MBBI, FixedObject);
1076void AArch64PrologueEmitter::emitDefineCFAWithFP(
1078 const int OffsetToFirstCalleeSaveFromFP =
1079 AFI->getCalleeSaveBaseToFrameRecordOffset() -
1080 AFI->getCalleeSavedStackSize();
1083 .buildDefCFA(
FramePtr, FixedObject - OffsetToFirstCalleeSaveFromFP);
1086void AArch64PrologueEmitter::emitWindowsStackProbe(
1088 int64_t RealignmentPadding)
const {
1089 if (
AFI->getSVECalleeSavedStackSize())
1096 [
this](
const MachineBasicBlock::RegisterMaskPair &LiveIn) {
1097 return RegInfo.isSuperOrSubRegisterEq(AArch64::X15,
1100 X15Scratch =
AFL.findScratchNonCalleeSaveRegister(&
MBB,
true);
1101 assert(X15Scratch.isValid() &&
1102 (X15Scratch < AArch64::X15 || X15Scratch > AArch64::X17));
1104 LiveRegs.removeReg(AArch64::X15);
1113 uint64_t NumWords = (NumBytes + RealignmentPadding) >> 4;
1121 if (NumBytes >= (1 << 28))
1123 "unwinding purposes");
1125 uint32_t LowNumWords = NumWords & 0xFFFF;
1132 if ((NumWords & 0xFFFF0000) != 0) {
1135 .
addImm((NumWords & 0xFFFF0000) >> 16)
1147 const AArch64TargetLowering *TLI =
Subtarget.getTargetLowering();
1148 RTLIB::LibcallImpl ChkStkLibcall = TLI->getLibcallImpl(RTLIB::STACK_PROBE);
1149 if (ChkStkLibcall == RTLIB::Unsupported)
1152 const char *ChkStk = TLI->getLibcallImplName(ChkStkLibcall).data();
1153 switch (
MF.getTarget().getCodeModel()) {
1217 if (RealignmentPadding > 0) {
1218 if (RealignmentPadding >= 4096) {
1221 .
addImm(RealignmentPadding)
1231 .
addImm(RealignmentPadding)
1236 uint64_t AndMask = ~(
MFI.getMaxAlign().value() - 1);
1240 AFI->setStackRealigned(
true);
1246 if (X15Scratch.isValid()) {
1255void AArch64PrologueEmitter::emitCalleeSavedGPRLocations(
1257 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1262 for (
const auto &Info : CSI) {
1263 unsigned FrameIdx =
Info.getFrameIdx();
1264 if (
MFI.hasScalableStackID(FrameIdx))
1267 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
1268 int64_t
Offset =
MFI.getObjectOffset(FrameIdx) -
AFL.getOffsetOfLocalArea();
1269 CFIBuilder.buildOffset(
Info.getReg(),
Offset);
1273void AArch64PrologueEmitter::emitCalleeSavedSVELocations(
1276 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1282 std::optional<int64_t> IncomingVGOffsetFromDefCFA;
1283 if (
AFL.requiresSaveVG(
MF)) {
1285 reverse(CSI), [](
auto &Info) {
return Info.getReg() == AArch64::VG; });
1286 IncomingVGOffsetFromDefCFA =
MFI.getObjectOffset(IncomingVG.getFrameIdx()) -
1287 AFL.getOffsetOfLocalArea();
1290 StackOffset PPRStackSize =
AFL.getPPRStackSize(
MF);
1291 for (
const auto &Info : CSI) {
1292 int FI =
Info.getFrameIdx();
1293 if (!
MFI.hasScalableStackID(FI))
1298 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
1299 MCRegister
Reg =
Info.getReg();
1313 CFIBuilder.insertCFIInst(
1319 switch (
MI.getOpcode()) {
1322 case AArch64::CATCHRET:
1323 case AArch64::CLEANUPRET:
1334 SEHEpilogueStartI =
MBB.end();
1341 "expected negative offset (with optional fixed portion)");
1343 if (int64_t FixedOffset =
Offset.getFixed()) {
1359 if (
MBB.end() != EpilogueEndI) {
1360 DL = EpilogueEndI->getDebugLoc();
1374 int64_t ArgumentStackToRestore =
AFL.getArgumentStackToRestore(
MF,
MBB);
1375 bool IsWin64 =
Subtarget.isCallingConvWin64(
MF.getFunction().getCallingConv(),
1376 MF.getFunction().isVarArg());
1379 int64_t AfterCSRPopSize = ArgumentStackToRestore;
1380 auto PrologueSaveSize =
AFI->getCalleeSavedStackSize() + FixedObject;
1385 if (
MF.hasEHFunclets())
1386 AFI->setLocalStackSize(NumBytes - PrologueSaveSize);
1390 auto FirstHomogenousEpilogI =
MBB.getFirstTerminator();
1391 if (FirstHomogenousEpilogI !=
MBB.begin()) {
1392 auto HomogeneousEpilog = std::prev(FirstHomogenousEpilogI);
1393 if (HomogeneousEpilog->getOpcode() == AArch64::HOM_Epilog)
1394 FirstHomogenousEpilogI = HomogeneousEpilog;
1404 assert(AfterCSRPopSize == 0);
1408 bool CombineSPBump = shouldCombineCSRLocalStackBump(NumBytes);
1410 unsigned ProloguePopSize = PrologueSaveSize;
1416 ProloguePopSize -= FixedObject;
1417 AfterCSRPopSize += FixedObject;
1421 if (!CombineSPBump && ProloguePopSize != 0) {
1423 while (Pop->getOpcode() == TargetOpcode::CFI_INSTRUCTION ||
1424 AArch64InstrInfo::isSEHInstruction(*Pop) ||
1427 Pop = std::prev(Pop);
1434 if (
OffsetOp.getImm() == 0 && AfterCSRPopSize >= 0) {
1440 if (AArch64InstrInfo::isSEHInstruction(*AfterLastPop))
1454 AfterCSRPopSize += ProloguePopSize;
1463 while (FirstGPRRestoreI != Begin) {
1470 }
else if (CombineSPBump)
1472 AFI->getLocalStackSize());
1482 BuildMI(
MBB, FirstGPRRestoreI, DL,
TII->get(AArch64::SEH_EpilogStart))
1484 SEHEpilogueStartI = FirstGPRRestoreI;
1485 --SEHEpilogueStartI;
1495 ?
MBB.getFirstTerminator()
1497 PPR.CalleeSavesSize, ZPR.CalleeSavesSize,
true);
1499 if (
HasFP &&
AFI->hasSwiftAsyncContext())
1500 emitSwiftAsyncContextFramePointer(EpilogueEndI, DL);
1503 if (CombineSPBump) {
1504 assert(!
AFI->hasSVEStackSize() &&
"Cannot combine SP bump with SVE");
1518 NumBytes -= PrologueSaveSize;
1519 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
1521 StackOffset SVECalleeSavesSize = ZPR.CalleeSavesSize + PPR.CalleeSavesSize;
1527 "unexpected SVE allocs after PPRs with CalleeSavesAboveFrameRecord");
1531 if (!
AFI->isStackRealigned() && !
MFI.hasVarSizedObjects()) {
1541 }
else if (
AFI->hasSVEStackSize()) {
1546 (
AFI->isStackRealigned() ||
MFI.hasVarSizedObjects()) ? AArch64::FP
1548 if (SVECalleeSavesSize && BaseForSVEDealloc == AArch64::FP) {
1552 -SVECalleeSavesSize - PPR.LocalsSize -
1556 moveSPBelowFP(ZPRRange.Begin, FPOffsetZPR);
1564 assert(!FPOffsetPPR.
getFixed() &&
"expected only scalable offset");
1568 }
else if (BaseForSVEDealloc == AArch64::SP) {
1577 NumBytes -= NonSVELocals.getFixed();
1585 assert(PPRRange.Begin == ZPRRange.End &&
1586 "Expected PPR restores after ZPR");
1599 emitCalleeSavedSVERestores(
1604 bool RedZone =
AFL.canUseRedZone(
MF);
1607 if (RedZone && AfterCSRPopSize == 0)
1614 bool NoCalleeSaveRestore = PrologueSaveSize == 0;
1615 int64_t StackRestoreBytes = RedZone ? 0 : NumBytes;
1616 if (NoCalleeSaveRestore)
1617 StackRestoreBytes += AfterCSRPopSize;
1620 MBB, FirstGPRRestoreI, DL, AArch64::SP, AArch64::SP,
1627 if (NoCalleeSaveRestore || AfterCSRPopSize == 0)
1637 if (!
IsFunclet && (
MFI.hasVarSizedObjects() ||
AFI->isStackRealigned())) {
1639 MBB, FirstGPRRestoreI, DL, AArch64::SP, AArch64::FP,
1642 }
else if (NumBytes)
1655 if (AfterCSRPopSize) {
1656 assert(AfterCSRPopSize > 0 &&
"attempting to reallocate arg stack that an "
1657 "interrupt may have clobbered");
1660 MBB,
MBB.getFirstTerminator(), DL, AArch64::SP, AArch64::SP,
1667bool AArch64EpilogueEmitter::shouldCombineCSRLocalStackBump(
1679 while (LastI != Begin) {
1681 if (LastI->isTransient())
1686 switch (LastI->getOpcode()) {
1687 case AArch64::STGloop:
1688 case AArch64::STZGloop:
1690 case AArch64::STZGi:
1691 case AArch64::ST2Gi:
1692 case AArch64::STZ2Gi:
1700void AArch64EpilogueEmitter::emitSwiftAsyncContextFramePointer(
1702 switch (
MF.getTarget().Options.SwiftAsyncFramePointer) {
1730void AArch64EpilogueEmitter::emitShadowCallStackEpilogue(
1744 if (
AFI->needsAsyncDwarfUnwindInfo(
MF))
1746 .buildRestore(AArch64::X18);
1749void AArch64EpilogueEmitter::emitCalleeSavedRestores(
1751 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1757 for (
const auto &Info : CSI) {
1758 if (
SVE !=
MFI.hasScalableStackID(
Info.getFrameIdx()))
1761 MCRegister
Reg =
Info.getReg();
1765 CFIBuilder.buildRestore(
Info.getReg());
1769void AArch64EpilogueEmitter::finalizeEpilogue()
const {
1770 if (
AFI->needsShadowCallStackPrologueEpilogue(
MF)) {
1771 emitShadowCallStackEpilogue(
MBB.getFirstTerminator(), DL);
1775 emitCalleeSavedGPRRestores(
MBB.getFirstTerminator());
1776 if (
AFI->shouldSignReturnAddress(
MF)) {
1779 if (!
AFL.shouldSignReturnAddressEverywhere(
MF))
1780 TII->createPauthEpilogueInstr(
MBB, DL);
1785 BuildMI(
MBB,
MBB.getFirstTerminator(), DL,
TII->get(AArch64::SEH_EpilogEnd))
1787 if (!
MF.hasWinCFI())
1788 MF.setHasWinCFI(
true);
1793 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...
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.
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.
MachineBasicBlock::iterator End
struct llvm::SVEPartitions::@327166152017175235362202041204223104077330276266 ZPR
struct llvm::SVEPartitions::@327166152017175235362202041204223104077330276266 PPR
MachineBasicBlock::iterator Begin
StackOffset totalSize() const