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::PTRUE_C_B:
57 case AArch64::LD1B_2Z_IMM:
58 case AArch64::ST1B_2Z_IMM:
59 case AArch64::STR_ZXI:
60 case AArch64::STR_PXI:
61 case AArch64::LDR_ZXI:
62 case AArch64::LDR_PXI:
63 case AArch64::PTRUE_B:
64 case AArch64::CPY_ZPzI_B:
65 case AArch64::CMPNE_PPzZI_B:
68 case AArch64::SEH_SavePReg:
69 case AArch64::SEH_SaveZReg:
96 if (
AFL.requiresSaveVG(
MF)) {
97 auto &TLI = *
Subtarget.getTargetLowering();
102 switch (
MBBI->getOpcode()) {
106 NewOpc = AArch64::STPXpre;
109 NewOpc = AArch64::STPDpre;
112 NewOpc = AArch64::STPQpre;
114 case AArch64::STRXui:
115 NewOpc = AArch64::STRXpre;
117 case AArch64::STRDui:
118 NewOpc = AArch64::STRDpre;
120 case AArch64::STRQui:
121 NewOpc = AArch64::STRQpre;
124 NewOpc = AArch64::LDPXpost;
127 NewOpc = AArch64::LDPDpost;
130 NewOpc = AArch64::LDPQpost;
132 case AArch64::LDRXui:
133 NewOpc = AArch64::LDRXpost;
135 case AArch64::LDRDui:
136 NewOpc = AArch64::LDRDpost;
138 case AArch64::LDRQui:
139 NewOpc = AArch64::LDRQpost;
143 int64_t MinOffset, MaxOffset;
145 NewOpc, Scale, Width, MinOffset, MaxOffset);
151 if (
MBBI->getOperand(
MBBI->getNumOperands() - 1).getImm() != 0 ||
152 CSStackSizeInc < MinOffset * (int64_t)Scale.
getFixedValue() ||
153 CSStackSizeInc > MaxOffset * (int64_t)Scale.
getFixedValue()) {
167 return std::prev(
MBBI);
172 auto SEH = std::next(
MBBI);
173 if (AArch64InstrInfo::isSEHInstruction(*SEH))
174 SEH->eraseFromParent();
181 unsigned OpndIdx = 0;
182 for (
unsigned OpndEnd =
MBBI->getNumOperands() - 1; OpndIdx < OpndEnd;
184 MIB.
add(
MBBI->getOperand(OpndIdx));
186 assert(
MBBI->getOperand(OpndIdx).getImm() == 0 &&
187 "Unexpected immediate offset in first/last callee-save save/restore "
189 assert(
MBBI->getOperand(OpndIdx - 1).getReg() == AArch64::SP &&
190 "Unexpected base register in callee-save save/restore instruction!");
191 assert(CSStackSizeInc % Scale == 0);
192 MIB.
addImm(CSStackSizeInc / (
int)Scale);
200 AFL.insertSEH(*MIB, *
TII, FrameFlag);
207 return std::prev(
MBB.erase(
MBBI));
212 unsigned LocalStackSize) {
214 unsigned ImmIdx =
MBBI->getNumOperands() - 1;
215 switch (
MBBI->getOpcode()) {
218 case AArch64::SEH_SaveFPLR:
219 case AArch64::SEH_SaveRegP:
220 case AArch64::SEH_SaveReg:
221 case AArch64::SEH_SaveFRegP:
222 case AArch64::SEH_SaveFReg:
223 case AArch64::SEH_SaveAnyRegQP:
224 case AArch64::SEH_SaveAnyRegQPX:
225 ImmOpnd = &
MBBI->getOperand(ImmIdx);
234 if (AArch64InstrInfo::isSEHInstruction(
MI))
237 unsigned Opc =
MI.getOpcode();
241 case AArch64::STRXui:
243 case AArch64::STRDui:
245 case AArch64::LDRXui:
247 case AArch64::LDRDui:
251 case AArch64::STRQui:
253 case AArch64::LDRQui:
260 unsigned OffsetIdx =
MI.getNumExplicitOperands() - 1;
261 assert(
MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP &&
262 "Unexpected base register in callee-save save/restore instruction!");
266 assert(LocalStackSize % Scale == 0);
267 OffsetOpnd.
setImm(OffsetOpnd.
getImm() + LocalStackSize / Scale);
272 assert(
MBBI !=
MI.getParent()->end() &&
"Expecting a valid instruction");
273 assert(AArch64InstrInfo::isSEHInstruction(*
MBBI) &&
274 "Expecting a SEH instruction");
281 if (
AFL.homogeneousPrologEpilog(
MF))
284 if (
AFI->getLocalStackSize() == 0)
295 if (
AFL.needsWinCFI(
MF) &&
AFI->getCalleeSavedStackSize() > 0 &&
296 MF.getFunction().hasOptSize())
301 if (StackBumpBytes >= 512 ||
302 AFL.windowsRequiresStackProbe(
MF, StackBumpBytes))
305 if (
MFI.hasVarSizedObjects())
314 if (
AFL.canUseRedZone(
MF))
319 if (
AFL.getSVEStackSize(
MF))
330 EmitAsyncCFI =
AFI->needsAsyncDwarfUnwindInfo(
MF);
335 collectBlockLiveins();
352void AArch64PrologueEmitter::collectBlockLiveins() {
355 PrologueEndI =
MBB.begin();
356 while (PrologueEndI !=
MBB.end() &&
360 if (PrologueEndI !=
MBB.end()) {
376void AArch64PrologueEmitter::verifyPrologueClobbers()
const {
377 if (PrologueEndI ==
MBB.end())
380 for (MachineInstr &
MI :
381 make_range(
MBB.instr_begin(), PrologueEndI->getIterator())) {
382 for (
auto &
Op :
MI.operands())
383 if (
Op.isReg() &&
Op.isDef())
384 assert(!LiveRegs.contains(
Op.getReg()) &&
385 "live register clobbered by inserted prologue instructions");
390void AArch64PrologueEmitter::determineLocalsStackSize(
391 uint64_t StackSize, uint64_t PrologueSaveSize) {
392 AFI->setLocalStackSize(StackSize - PrologueSaveSize);
399 static const int64_t MAX_BYTES_PER_SCALABLE_BYTE = 16;
400 return Size.getScalable() * MAX_BYTES_PER_SCALABLE_BYTE +
Size.getFixed();
403void AArch64PrologueEmitter::allocateStackSpace(
405 StackOffset AllocSize,
bool EmitCFI, StackOffset InitialOffset,
406 bool FollowupAllocs) {
413 const uint64_t AndMask = ~(MaxAlign - 1);
416 Register TargetReg = RealignmentPadding
417 ?
AFL.findScratchNonCalleeSaveRegister(&
MBB)
424 if (RealignmentPadding) {
445 if (AllocSize.getScalable() == 0 && RealignmentPadding == 0) {
447 assert(ScratchReg != AArch64::NoRegister);
450 .
addImm(AllocSize.getFixed())
451 .
addImm(InitialOffset.getFixed())
452 .
addImm(InitialOffset.getScalable());
457 if (FollowupAllocs) {
473 int64_t ProbeSize =
AFI->getStackProbeSize();
474 if (
upperBound(AllocSize) + RealignmentPadding <= ProbeSize) {
475 Register ScratchReg = RealignmentPadding
476 ?
AFL.findScratchNonCalleeSaveRegister(&
MBB)
478 assert(ScratchReg != AArch64::NoRegister);
483 if (RealignmentPadding) {
489 AFI->setStackRealigned(
true);
491 if (FollowupAllocs ||
upperBound(AllocSize) + RealignmentPadding >
507 assert(TargetReg != AArch64::NoRegister);
512 if (RealignmentPadding) {
525 .buildDefCFARegister(AArch64::SP);
527 if (RealignmentPadding)
528 AFI->setStackRealigned(
true);
538 AFI->setHasRedZone(
false);
544 if (
AFI->shouldSignReturnAddress(
MF)) {
547 if (!
AFL.shouldSignReturnAddressEverywhere(
MF)) {
555 if (
AFI->needsShadowCallStackPrologueEpilogue(
MF)) {
556 emitShadowCallStackPrologue(PrologueBeginI,
DL);
568 if (
HasFP &&
AFI->hasSwiftAsyncContext())
569 emitSwiftAsyncContextFramePointer(PrologueBeginI,
DL);
578 if (std::optional<int> TBPI =
AFI->getTaggedBasePointerIndex())
579 AFI->setTaggedBasePointerOffset(-
MFI.getObjectOffset(*TBPI));
581 AFI->setTaggedBasePointerOffset(
MFI.getStackSize());
591 if (!
AFI->hasStackFrame() && !
AFL.windowsRequiresStackProbe(
MF, NumBytes))
592 return emitEmptyStackFramePrologue(NumBytes, PrologueBeginI,
DL);
594 bool IsWin64 =
Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg());
609 bool FPAfterSVECalleeSaves =
610 Subtarget.isTargetWindows() &&
AFI->getSVECalleeSavedStackSize();
612 if (FPAfterSVECalleeSaves &&
AFI->hasStackHazardSlotIndex())
615 auto PrologueSaveSize =
AFI->getCalleeSavedStackSize() + FixedObject;
617 determineLocalsStackSize(NumBytes, PrologueSaveSize);
620 if (FPAfterSVECalleeSaves) {
629 allocateStackSpace(PrologueBeginI, 0, SaveSize,
false,
StackOffset{},
631 NumBytes -= FixedObject;
638 MBBI,
DL, -
AFI->getCalleeSavedStackSize(), EmitAsyncCFI);
639 NumBytes -=
AFI->getCalleeSavedStackSize();
640 }
else if (CombineSPBump) {
641 assert(!
AFL.getSVEStackSize(
MF) &&
"Cannot combine SP bump with SVE");
649 NumBytes -= PrologueSaveSize;
650 }
else if (PrologueSaveSize != 0) {
652 PrologueBeginI,
DL, -PrologueSaveSize, EmitAsyncCFI);
653 NumBytes -= PrologueSaveSize;
655 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
660 auto &TLI = *
Subtarget.getTargetLowering();
663 while (AfterGPRSavesI != EndI &&
670 AFI->getLocalStackSize());
677 emitFramePointerSetup(AfterGPRSavesI,
DL, FixedObject);
683 emitCalleeSavedGPRLocations(AfterGPRSavesI);
686 const bool NeedsRealignment =
688 const int64_t RealignmentPadding =
689 (NeedsRealignment &&
MFI.getMaxAlign() >
Align(16))
690 ?
MFI.getMaxAlign().value() - 16
693 if (
AFL.windowsRequiresStackProbe(
MF, NumBytes + RealignmentPadding))
694 emitWindowsStackProbe(AfterGPRSavesI,
DL, NumBytes, RealignmentPadding);
697 StackOffset SVECalleeSavesSize = {}, SVELocalsSize = SVEStackSize;
706 if (int64_t CalleeSavedSize =
AFI->getSVECalleeSavedStackSize()) {
707 LLVM_DEBUG(
dbgs() <<
"SVECalleeSavedStackSize = " << CalleeSavedSize
710 SVELocalsSize = SVEStackSize - SVECalleeSavesSize;
714 if (!FPAfterSVECalleeSaves) {
718 AfterSVESavesI !=
MBB.getFirstTerminator())
720 CalleeSavesEnd = AfterSVESavesI;
724 allocateStackSpace(CalleeSavesBegin, 0, SVECalleeSavesSize,
725 EmitAsyncCFI && !
HasFP, CFAOffset,
726 MFI.hasVarSizedObjects() || LocalsSize);
729 CFAOffset += SVECalleeSavesSize;
732 emitCalleeSavedSVELocations(CalleeSavesEnd);
736 assert(!(
AFL.canUseRedZone(
MF) && NeedsRealignment) &&
737 "Cannot use redzone with stack realignment");
738 if (!
AFL.canUseRedZone(
MF)) {
742 allocateStackSpace(CalleeSavesEnd, RealignmentPadding,
744 EmitAsyncCFI && !
HasFP, CFAOffset,
745 MFI.hasVarSizedObjects());
783 MBB.addLiveIn(AArch64::X1);
787 if (
EmitCFI && !EmitAsyncCFI) {
789 emitDefineCFAWithFP(AfterSVESavesI, FixedObject);
798 emitCalleeSavedGPRLocations(AfterSVESavesI);
799 emitCalleeSavedSVELocations(AfterSVESavesI);
803void AArch64PrologueEmitter::emitShadowCallStackPrologue(
814 MBB.addLiveIn(AArch64::X18);
823 static const char CFIInst[] = {
824 dwarf::DW_CFA_val_expression,
827 static_cast<char>(
unsigned(dwarf::DW_OP_breg18)),
828 static_cast<char>(-8) & 0x7f,
831 .buildEscape(StringRef(CFIInst,
sizeof(CFIInst)));
835void AArch64PrologueEmitter::emitSwiftAsyncContextFramePointer(
837 switch (
MF.getTarget().Options.SwiftAsyncFramePointer) {
839 if (
Subtarget.swiftAsyncContextIsDynamicallySet()) {
881void AArch64PrologueEmitter::emitEmptyStackFramePrologue(
884 assert(!
HasFP &&
"unexpected function without stack frame but with FP");
886 "unexpected function without stack frame but with SVE objects");
888 AFI->setLocalStackSize(NumBytes);
898 if (
AFL.canUseRedZone(
MF)) {
899 AFI->setHasRedZone(
true);
900 ++NumRedZoneFunctions;
907 MCSymbol *FrameLabel =
MF.getContext().createTempSymbol();
910 .buildDefCFAOffset(NumBytes, FrameLabel);
921void AArch64PrologueEmitter::emitFramePointerSetup(
923 unsigned FixedObject) {
924 int64_t FPOffset =
AFI->getCalleeSaveBaseToFrameRecordOffset();
926 FPOffset +=
AFI->getLocalStackSize();
928 if (
AFI->hasSwiftAsyncContext()) {
932 const auto &
Attrs =
MF.getFunction().getAttributes();
933 bool HaveInitialContext =
Attrs.hasAttrSomewhere(Attribute::SwiftAsync);
934 if (HaveInitialContext)
935 MBB.addLiveIn(AArch64::X22);
936 Register Reg = HaveInitialContext ? AArch64::X22 : AArch64::XZR;
974 emitDefineCFAWithFP(
MBBI, FixedObject);
978void AArch64PrologueEmitter::emitDefineCFAWithFP(
980 const int OffsetToFirstCalleeSaveFromFP =
981 AFI->getCalleeSaveBaseToFrameRecordOffset() -
982 AFI->getCalleeSavedStackSize();
985 .buildDefCFA(
FramePtr, FixedObject - OffsetToFirstCalleeSaveFromFP);
988void AArch64PrologueEmitter::emitWindowsStackProbe(
990 int64_t RealignmentPadding)
const {
991 if (
AFI->getSVECalleeSavedStackSize())
996 unsigned X15Scratch = AArch64::NoRegister;
998 [
this](
const MachineBasicBlock::RegisterMaskPair &LiveIn) {
999 return RegInfo.isSuperOrSubRegisterEq(AArch64::X15,
1002 X15Scratch =
AFL.findScratchNonCalleeSaveRegister(&
MBB,
true);
1003 assert(X15Scratch != AArch64::NoRegister &&
1004 (X15Scratch < AArch64::X15 || X15Scratch > AArch64::X17));
1006 LiveRegs.removeReg(AArch64::X15);
1015 uint64_t NumWords = (NumBytes + RealignmentPadding) >> 4;
1023 if (NumBytes >= (1 << 28))
1025 "unwinding purposes");
1027 uint32_t LowNumWords = NumWords & 0xFFFF;
1034 if ((NumWords & 0xFFFF0000) != 0) {
1037 .
addImm((NumWords & 0xFFFF0000) >> 16)
1049 const char *ChkStk =
Subtarget.getChkStkName();
1050 switch (
MF.getTarget().getCodeModel()) {
1114 if (RealignmentPadding > 0) {
1115 if (RealignmentPadding >= 4096) {
1118 .
addImm(RealignmentPadding)
1128 .
addImm(RealignmentPadding)
1133 uint64_t AndMask = ~(
MFI.getMaxAlign().value() - 1);
1137 AFI->setStackRealigned(
true);
1143 if (X15Scratch != AArch64::NoRegister) {
1152void AArch64PrologueEmitter::emitCalleeSavedGPRLocations(
1154 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1159 for (
const auto &
Info : CSI) {
1160 unsigned FrameIdx =
Info.getFrameIdx();
1164 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
1165 int64_t
Offset =
MFI.getObjectOffset(FrameIdx) -
AFL.getOffsetOfLocalArea();
1166 CFIBuilder.buildOffset(
Info.getReg(),
Offset);
1170void AArch64PrologueEmitter::emitCalleeSavedSVELocations(
1173 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1179 std::optional<int64_t> IncomingVGOffsetFromDefCFA;
1180 if (
AFL.requiresSaveVG(
MF)) {
1182 reverse(CSI), [](
auto &
Info) {
return Info.getReg() == AArch64::VG; });
1183 IncomingVGOffsetFromDefCFA =
MFI.getObjectOffset(IncomingVG.getFrameIdx()) -
1184 AFL.getOffsetOfLocalArea();
1187 for (
const auto &
Info : CSI) {
1193 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
1194 MCRegister
Reg =
Info.getReg();
1202 CFIBuilder.insertCFIInst(
1208 switch (
MI.getOpcode()) {
1211 case AArch64::CATCHRET:
1212 case AArch64::CLEANUPRET:
1223 SEHEpilogueStartI =
MBB.end();
1228 if (
MBB.end() != EpilogueEndI) {
1229 DL = EpilogueEndI->getDebugLoc();
1243 int64_t ArgumentStackToRestore =
AFL.getArgumentStackToRestore(
MF,
MBB);
1244 bool IsWin64 =
Subtarget.isCallingConvWin64(
MF.getFunction().getCallingConv(),
1245 MF.getFunction().isVarArg());
1248 int64_t AfterCSRPopSize = ArgumentStackToRestore;
1249 auto PrologueSaveSize =
AFI->getCalleeSavedStackSize() + FixedObject;
1254 if (
MF.hasEHFunclets())
1255 AFI->setLocalStackSize(NumBytes - PrologueSaveSize);
1259 auto FirstHomogenousEpilogI =
MBB.getFirstTerminator();
1260 if (FirstHomogenousEpilogI !=
MBB.begin()) {
1261 auto HomogeneousEpilog = std::prev(FirstHomogenousEpilogI);
1262 if (HomogeneousEpilog->getOpcode() == AArch64::HOM_Epilog)
1263 FirstHomogenousEpilogI = HomogeneousEpilog;
1273 assert(AfterCSRPopSize == 0);
1277 bool FPAfterSVECalleeSaves =
1278 Subtarget.isTargetWindows() &&
AFI->getSVECalleeSavedStackSize();
1280 bool CombineSPBump = shouldCombineCSRLocalStackBump(NumBytes);
1282 bool CombineAfterCSRBump =
false;
1283 if (FPAfterSVECalleeSaves) {
1284 AfterCSRPopSize += FixedObject;
1285 }
else if (!CombineSPBump && PrologueSaveSize != 0) {
1287 while (Pop->getOpcode() == TargetOpcode::CFI_INSTRUCTION ||
1288 AArch64InstrInfo::isSEHInstruction(*Pop))
1289 Pop = std::prev(Pop);
1296 if (
OffsetOp.getImm() == 0 && AfterCSRPopSize >= 0) {
1305 AfterCSRPopSize += PrologueSaveSize;
1306 CombineAfterCSRBump =
true;
1315 while (FirstGPRRestoreI != Begin) {
1321 }
else if (CombineSPBump)
1323 AFI->getLocalStackSize());
1333 BuildMI(
MBB, FirstGPRRestoreI, DL,
TII->get(AArch64::SEH_EpilogStart))
1335 SEHEpilogueStartI = FirstGPRRestoreI;
1336 --SEHEpilogueStartI;
1339 if (
HasFP &&
AFI->hasSwiftAsyncContext())
1340 emitSwiftAsyncContextFramePointer(EpilogueEndI, DL);
1345 if (CombineSPBump) {
1346 assert(!SVEStackSize &&
"Cannot combine SP bump with SVE");
1360 NumBytes -= PrologueSaveSize;
1361 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
1365 StackOffset DeallocateBefore = {}, DeallocateAfter = SVEStackSize;
1367 RestoreEnd = FirstGPRRestoreI;
1368 if (int64_t CalleeSavedSize =
AFI->getSVECalleeSavedStackSize()) {
1369 if (FPAfterSVECalleeSaves)
1370 RestoreEnd =
MBB.getFirstTerminator();
1372 RestoreBegin = std::prev(RestoreEnd);
1373 while (RestoreBegin !=
MBB.begin() &&
1382 DeallocateBefore = SVEStackSize - CalleeSavedSizeAsOffset;
1383 DeallocateAfter = CalleeSavedSizeAsOffset;
1387 if (FPAfterSVECalleeSaves) {
1391 if (!
AFI->isStackRealigned() && !
MFI.hasVarSizedObjects()) {
1411 }
else if (SVEStackSize) {
1412 int64_t SVECalleeSavedSize =
AFI->getSVECalleeSavedStackSize();
1417 (
AFI->isStackRealigned() ||
MFI.hasVarSizedObjects()) ? AArch64::FP
1419 if (SVECalleeSavedSize && BaseForSVEDealloc == AArch64::FP) {
1420 Register CalleeSaveBase = AArch64::FP;
1421 if (int64_t CalleeSaveBaseOffset =
1422 AFI->getCalleeSaveBaseToFrameRecordOffset()) {
1427 MF.getRegInfo().createVirtualRegister(&AArch64::GPR64RegClass);
1437 }
else if (BaseForSVEDealloc == AArch64::SP) {
1438 if (SVECalleeSavedSize) {
1442 MBB, RestoreBegin, DL, AArch64::SP, AArch64::SP,
1462 emitCalleeSavedSVERestores(RestoreEnd);
1466 bool RedZone =
AFL.canUseRedZone(
MF);
1469 if (RedZone && AfterCSRPopSize == 0)
1476 bool NoCalleeSaveRestore = PrologueSaveSize == 0;
1477 int64_t StackRestoreBytes = RedZone ? 0 : NumBytes;
1478 if (NoCalleeSaveRestore)
1479 StackRestoreBytes += AfterCSRPopSize;
1482 MBB, FirstGPRRestoreI, DL, AArch64::SP, AArch64::SP,
1489 if (NoCalleeSaveRestore || AfterCSRPopSize == 0)
1499 if (!
IsFunclet && (
MFI.hasVarSizedObjects() ||
AFI->isStackRealigned())) {
1501 MBB, FirstGPRRestoreI, DL, AArch64::SP, AArch64::FP,
1504 }
else if (NumBytes)
1517 if (AfterCSRPopSize) {
1518 assert(AfterCSRPopSize > 0 &&
"attempting to reallocate arg stack that an "
1519 "interrupt may have clobbered");
1522 MBB,
MBB.getFirstTerminator(), DL, AArch64::SP, AArch64::SP,
1529bool AArch64EpilogueEmitter::shouldCombineCSRLocalStackBump(
1541 while (LastI != Begin) {
1543 if (LastI->isTransient())
1548 switch (LastI->getOpcode()) {
1549 case AArch64::STGloop:
1550 case AArch64::STZGloop:
1552 case AArch64::STZGi:
1553 case AArch64::ST2Gi:
1554 case AArch64::STZ2Gi:
1562void AArch64EpilogueEmitter::emitSwiftAsyncContextFramePointer(
1564 switch (
MF.getTarget().Options.SwiftAsyncFramePointer) {
1592void AArch64EpilogueEmitter::emitShadowCallStackEpilogue(
1606 if (
AFI->needsAsyncDwarfUnwindInfo(
MF))
1608 .buildRestore(AArch64::X18);
1611void AArch64EpilogueEmitter::emitCalleeSavedRestores(
1613 const std::vector<CalleeSavedInfo> &CSI =
MFI.getCalleeSavedInfo();
1619 for (
const auto &
Info : CSI) {
1624 MCRegister
Reg =
Info.getReg();
1628 CFIBuilder.buildRestore(
Info.getReg());
1632void AArch64EpilogueEmitter::finalizeEpilogue()
const {
1633 if (
AFI->needsShadowCallStackPrologueEpilogue(
MF)) {
1634 emitShadowCallStackEpilogue(
MBB.getFirstTerminator(), DL);
1638 emitCalleeSavedGPRRestores(
MBB.getFirstTerminator());
1639 if (
AFI->shouldSignReturnAddress(
MF)) {
1642 if (!
AFL.shouldSignReturnAddressEverywhere(
MF)) {
1644 TII->get(AArch64::PAUTH_EPILOGUE))
1651 BuildMI(
MBB,
MBB.getFirstTerminator(), DL,
TII->get(AArch64::SEH_EpilogEnd))
1653 if (!
MF.hasWinCFI())
1654 MF.setHasWinCFI(
true);
1659 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
Analysis containing CSE Info
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
bool isVGInstruction(MachineBasicBlock::iterator MBBI, const TargetLowering &TLI) const
AArch64PrologueEpilogueCommon(MachineFunction &MF, MachineBasicBlock &MBB, const AArch64FrameLowering &AFL)
const AArch64RegisterInfo & RegInfo
const AArch64FrameLowering & AFL
void fixupCalleeSaveRestoreStackOffset(MachineInstr &MI, uint64_t LocalStackSize) const
bool shouldCombineCSRLocalStackBump(uint64_t StackBumpBytes) const
const AArch64Subtarget & Subtarget
bool requiresGetVGCall() const
const TargetInstrInfo * TII
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 the alignment in bytes that this function must be aligned to, which is greater than the defaul...
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
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
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 getScalable(int64_t Scalable)
static StackOffset getFixed(int64_t Fixed)
StringRef - 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 Attrs[]
Key for Kernel::Metadata::mAttrs.
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Define
Register definition.
@ Kill
The last use of a register.
@ Undef
Value of the register doesn't matter.
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.
static bool isSVECalleeSave(MachineBasicBlock::iterator I)
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)
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.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, StackOffset Offset, const TargetInstrInfo *TII, MachineInstr::MIFlag=MachineInstr::NoFlags, bool SetNZCV=false, bool NeedsWinCFI=false, bool *HasWinCFI=nullptr, bool EmitCFAOffset=false, StackOffset InitialOffset={}, unsigned FrameReg=AArch64::SP)
emitFrameOffset - Emit instructions as needed to set DestReg to SrcReg plus Offset.
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.
@ 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.
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 int64_t upperBound(StackOffset Size)
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.
uint64_t value() const
This is a hole in the type system and should not be abused.