19#define DEBUG_TYPE "frame-info"
21STATISTIC(NumRedZoneFunctions,
"Number of functions using red zone");
28 : MF(MF), MBB(MBB), F(MF.
getFunction()), MFI(MF.getFrameInfo()),
30 RegInfo(*Subtarget.getRegisterInfo()) {
31 TII = Subtarget.getInstrInfo();
35 EmitAsyncCFI = AFI->needsAsyncDwarfUnwindInfo(MF);
36 HasFP = AFL.hasFP(MF);
37 NeedsWinCFI = AFL.needsWinCFI(MF);
38 IsFunclet = MBB.isEHFuncletEntry();
39 HomPrologEpilog = AFL.homogeneousPrologEpilog(MF);
42 collectBlockLiveins();
53 LiveRegs.addLiveOuts(
MBB);
56 LiveRegs.stepBackward(
MI);
59void AArch64PrologueEmitter::collectBlockLiveins() {
62 PrologueEndI =
MBB.begin();
63 while (PrologueEndI !=
MBB.end() &&
67 if (PrologueEndI !=
MBB.end()) {
70 LiveRegs.removeReg(AArch64::SP);
71 LiveRegs.removeReg(AArch64::X19);
72 LiveRegs.removeReg(AArch64::FP);
73 LiveRegs.removeReg(AArch64::LR);
78 if (AFL.requiresGetVGCall(MF))
79 LiveRegs.removeReg(AArch64::X0);
83void AArch64PrologueEmitter::verifyPrologueClobbers()
const {
84 if (PrologueEndI == MBB.end())
87 for (MachineInstr &
MI :
88 make_range(MBB.instr_begin(), PrologueEndI->getIterator())) {
89 for (
auto &
Op :
MI.operands())
90 if (
Op.isReg() &&
Op.isDef())
91 assert(!LiveRegs.contains(
Op.getReg()) &&
92 "live register clobbered by inserted prologue instructions");
97void AArch64PrologueEmitter::determineLocalsStackSize(
98 uint64_t StackSize, uint64_t PrologueSaveSize) {
99 AFI->setLocalStackSize(StackSize - PrologueSaveSize);
100 CombineSPBump = AFL.shouldCombineCSRLocalStackBump(MF, StackSize);
110 AFI->setHasRedZone(
false);
116 if (AFI->shouldSignReturnAddress(MF)) {
119 if (!AFL.shouldSignReturnAddressEverywhere(MF)) {
120 BuildMI(MBB, PrologueBeginI,
DL, TII->get(AArch64::PAUTH_PROLOGUE))
124 HasWinCFI |= NeedsWinCFI;
127 if (AFI->needsShadowCallStackPrologueEpilogue(MF)) {
128 emitShadowCallStackPrologue(PrologueBeginI,
DL);
129 HasWinCFI |= NeedsWinCFI;
132 if (EmitCFI && AFI->isMTETagged())
133 BuildMI(MBB, PrologueBeginI,
DL, TII->get(AArch64::EMITMTETAGGED))
140 if (HasFP && AFI->hasSwiftAsyncContext())
141 emitSwiftAsyncContextFramePointer(PrologueBeginI,
DL);
150 if (std::optional<int> TBPI = AFI->getTaggedBasePointerIndex())
151 AFI->setTaggedBasePointerOffset(-MFI.getObjectOffset(*TBPI));
153 AFI->setTaggedBasePointerOffset(MFI.getStackSize());
162 IsFunclet ? AFL.getWinEHFuncletFrameSize(MF) : MFI.getStackSize();
163 if (!AFI->hasStackFrame() && !AFL.windowsRequiresStackProbe(MF, NumBytes))
164 return emitEmptyStackFramePrologue(NumBytes, PrologueBeginI,
DL);
166 bool IsWin64 = Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg());
167 unsigned FixedObject = AFL.getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
181 bool FPAfterSVECalleeSaves =
182 Subtarget.isTargetWindows() && AFI->getSVECalleeSavedStackSize();
184 if (FPAfterSVECalleeSaves && AFI->hasStackHazardSlotIndex())
187 auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
189 determineLocalsStackSize(NumBytes, PrologueSaveSize);
192 if (FPAfterSVECalleeSaves) {
201 AFL.allocateStackSpace(MBB, PrologueBeginI, 0, SaveSize, NeedsWinCFI,
205 NumBytes -= FixedObject;
209 while (
MBBI != EndI && AFL.isSVECalleeSave(
MBBI))
211 FirstGPRSaveI = AFL.convertCalleeSaveRestoreToSPPrePostIncDec(
212 MBB,
MBBI,
DL, TII, -AFI->getCalleeSavedStackSize(), NeedsWinCFI,
213 &HasWinCFI, EmitAsyncCFI);
214 NumBytes -= AFI->getCalleeSavedStackSize();
215 }
else if (CombineSPBump) {
216 assert(!AFL.getSVEStackSize(MF) &&
"Cannot combine SP bump with SVE");
222 }
else if (HomPrologEpilog) {
224 NumBytes -= PrologueSaveSize;
225 }
else if (PrologueSaveSize != 0) {
226 FirstGPRSaveI = AFL.convertCalleeSaveRestoreToSPPrePostIncDec(
227 MBB, PrologueBeginI,
DL, TII, -PrologueSaveSize, NeedsWinCFI,
228 &HasWinCFI, EmitAsyncCFI);
229 NumBytes -= PrologueSaveSize;
231 assert(NumBytes >= 0 &&
"Negative stack allocation size!?");
236 auto &TLI = *MF.getSubtarget().getTargetLowering();
239 while (AfterGPRSavesI != EndI &&
241 !AFL.isSVECalleeSave(AfterGPRSavesI)) {
244 (!AFL.requiresSaveVG(MF) || !AFL.isVGInstruction(AfterGPRSavesI, TLI)))
245 AFL.fixupCalleeSaveRestoreStackOffset(
246 *AfterGPRSavesI, AFI->getLocalStackSize(), NeedsWinCFI, &HasWinCFI);
252 if (!IsFunclet && HasFP)
253 emitFramePointerSetup(AfterGPRSavesI,
DL, FixedObject);
259 emitCalleeSavedGPRLocations(AfterGPRSavesI);
262 const bool NeedsRealignment =
263 NumBytes && !IsFunclet && RegInfo.hasStackRealignment(MF);
264 const int64_t RealignmentPadding =
265 (NeedsRealignment && MFI.getMaxAlign() >
Align(16))
266 ? MFI.getMaxAlign().value() - 16
269 if (AFL.windowsRequiresStackProbe(MF, NumBytes + RealignmentPadding))
270 emitWindowsStackProbe(AfterGPRSavesI,
DL, NumBytes, RealignmentPadding);
272 StackOffset SVEStackSize = AFL.getSVEStackSize(MF);
273 StackOffset SVECalleeSavesSize = {}, SVELocalsSize = SVEStackSize;
282 if (int64_t CalleeSavedSize = AFI->getSVECalleeSavedStackSize()) {
283 LLVM_DEBUG(
dbgs() <<
"SVECalleeSavedStackSize = " << CalleeSavedSize
286 SVELocalsSize = SVEStackSize - SVECalleeSavesSize;
290 if (!FPAfterSVECalleeSaves) {
292 assert(AFL.isSVECalleeSave(CalleeSavesBegin) &&
"Unexpected instruction");
293 while (AFL.isSVECalleeSave(AfterSVESavesI) &&
294 AfterSVESavesI != MBB.getFirstTerminator())
296 CalleeSavesEnd = AfterSVESavesI;
300 AFL.allocateStackSpace(MBB, CalleeSavesBegin, 0, SVECalleeSavesSize,
301 false,
nullptr, EmitAsyncCFI && !HasFP, CFAOffset,
302 MFI.hasVarSizedObjects() || LocalsSize);
305 CFAOffset += SVECalleeSavesSize;
308 emitCalleeSavedSVELocations(CalleeSavesEnd);
312 assert(!(AFL.canUseRedZone(MF) && NeedsRealignment) &&
313 "Cannot use redzone with stack realignment");
314 if (!AFL.canUseRedZone(MF)) {
318 AFL.allocateStackSpace(MBB, CalleeSavesEnd, RealignmentPadding,
320 NeedsWinCFI, &HasWinCFI, EmitAsyncCFI && !HasFP,
321 CFAOffset, MFI.hasVarSizedObjects());
332 if (!IsFunclet && RegInfo.hasBasePointer(MF)) {
333 TII->copyPhysReg(MBB, AfterSVESavesI,
DL, RegInfo.getBaseRegister(),
337 BuildMI(MBB, AfterSVESavesI,
DL, TII->get(AArch64::SEH_Nop))
344 if (NeedsWinCFI && HasWinCFI) {
345 BuildMI(MBB, AfterSVESavesI,
DL, TII->get(AArch64::SEH_PrologEnd))
352 if (IsFunclet && F.hasPersonalityFn()) {
355 BuildMI(MBB, AfterSVESavesI,
DL, TII->get(TargetOpcode::COPY),
359 MBB.addLiveIn(AArch64::X1);
363 if (EmitCFI && !EmitAsyncCFI) {
365 emitDefineCFAWithFP(AfterSVESavesI, FixedObject);
374 emitCalleeSavedGPRLocations(AfterSVESavesI);
375 emitCalleeSavedSVELocations(AfterSVESavesI);
379void AArch64PrologueEmitter::emitShadowCallStackPrologue(
390 MBB.addLiveIn(AArch64::X18);
399 static const char CFIInst[] = {
400 dwarf::DW_CFA_val_expression,
403 static_cast<char>(
unsigned(dwarf::DW_OP_breg18)),
404 static_cast<char>(-8) & 0x7f,
407 .buildEscape(StringRef(CFIInst,
sizeof(CFIInst)));
411void AArch64PrologueEmitter::emitSwiftAsyncContextFramePointer(
413 switch (MF.getTarget().Options.SwiftAsyncFramePointer) {
415 if (Subtarget.swiftAsyncContextIsDynamicallySet()) {
418 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::LOADgot), AArch64::X16)
426 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::ORRXrs), AArch64::FP)
429 .
addImm(Subtarget.isTargetILP32() ? 32 : 0);
441 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::ORRXri), AArch64::FP)
457void AArch64PrologueEmitter::emitEmptyStackFramePrologue(
460 assert(!HasFP &&
"unexpected function without stack frame but with FP");
461 assert(!AFL.getSVEStackSize(MF) &&
462 "unexpected function without stack frame but with SVE objects");
464 AFI->setLocalStackSize(NumBytes);
466 if (NeedsWinCFI && HasWinCFI) {
474 if (AFL.canUseRedZone(MF)) {
475 AFI->setHasRedZone(
true);
476 ++NumRedZoneFunctions;
483 MCSymbol *FrameLabel = MF.getContext().createTempSymbol();
486 .buildDefCFAOffset(NumBytes, FrameLabel);
497void AArch64PrologueEmitter::emitFramePointerSetup(
499 unsigned FixedObject) {
500 int64_t FPOffset = AFI->getCalleeSaveBaseToFrameRecordOffset();
502 FPOffset += AFI->getLocalStackSize();
504 if (AFI->hasSwiftAsyncContext()) {
508 const auto &
Attrs = MF.getFunction().getAttributes();
509 bool HaveInitialContext =
Attrs.hasAttrSomewhere(Attribute::SwiftAsync);
510 if (HaveInitialContext)
511 MBB.addLiveIn(AArch64::X22);
512 Register Reg = HaveInitialContext ? AArch64::X22 : AArch64::XZR;
513 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::StoreSwiftAsyncContext))
521 assert(Subtarget.getTargetTriple().getArchName() !=
"arm64e");
528 if (HomPrologEpilog) {
541 if (NeedsWinCFI && HasWinCFI) {
550 emitDefineCFAWithFP(
MBBI, FixedObject);
554void AArch64PrologueEmitter::emitDefineCFAWithFP(
556 const AArch64RegisterInfo *
TRI = Subtarget.getRegisterInfo();
557 const int OffsetToFirstCalleeSaveFromFP =
558 AFI->getCalleeSaveBaseToFrameRecordOffset() -
559 AFI->getCalleeSavedStackSize();
562 .buildDefCFA(
FramePtr, FixedObject - OffsetToFirstCalleeSaveFromFP);
565void AArch64PrologueEmitter::emitWindowsStackProbe(
567 int64_t RealignmentPadding)
const {
568 if (AFI->getSVECalleeSavedStackSize())
573 unsigned X15Scratch = AArch64::NoRegister;
574 const AArch64Subtarget &STI = MF.getSubtarget<AArch64Subtarget>();
576 [&STI](
const MachineBasicBlock::RegisterMaskPair &LiveIn) {
577 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
578 AArch64::X15, LiveIn.PhysReg);
580 X15Scratch = AFL.findScratchNonCalleeSaveRegister(&MBB,
true);
581 assert(X15Scratch != AArch64::NoRegister &&
582 (X15Scratch < AArch64::X15 || X15Scratch > AArch64::X17));
584 LiveRegs.removeReg(AArch64::X15);
586 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::ORRXrr), X15Scratch)
593 uint64_t NumWords = (NumBytes + RealignmentPadding) >> 4;
601 if (NumBytes >= (1 << 28))
603 "unwinding purposes");
605 uint32_t LowNumWords = NumWords & 0xFFFF;
606 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::MOVZXi), AArch64::X15)
612 if ((NumWords & 0xFFFF0000) != 0) {
613 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::MOVKXi), AArch64::X15)
615 .
addImm((NumWords & 0xFFFF0000) >> 16)
622 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::MOVi64imm), AArch64::X15)
627 const char *ChkStk = Subtarget.getChkStkName();
628 switch (MF.getTarget().getCodeModel()) {
679 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::SUBXrx64), AArch64::SP)
692 if (RealignmentPadding > 0) {
693 if (RealignmentPadding >= 4096) {
696 .
addImm(RealignmentPadding)
698 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::ADDXrx64), AArch64::X15)
704 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::ADDXri), AArch64::X15)
706 .
addImm(RealignmentPadding)
711 uint64_t AndMask = ~(MFI.getMaxAlign().value() - 1);
712 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::ANDXri), AArch64::SP)
715 AFI->setStackRealigned(
true);
721 if (X15Scratch != AArch64::NoRegister) {
722 BuildMI(MBB,
MBBI,
DL, TII->get(AArch64::ORRXrr), AArch64::X15)
730void AArch64PrologueEmitter::emitCalleeSavedGPRLocations(
732 MachineFunction &MF = *MBB.getParent();
733 MachineFrameInfo &MFI = MF.getFrameInfo();
735 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
740 for (
const auto &
Info : CSI) {
741 unsigned FrameIdx =
Info.getFrameIdx();
745 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
746 int64_t
Offset = MFI.getObjectOffset(FrameIdx) - AFL.getOffsetOfLocalArea();
747 CFIBuilder.buildOffset(
Info.getReg(),
Offset);
751void AArch64PrologueEmitter::emitCalleeSavedSVELocations(
753 MachineFunction &MF = *MBB.getParent();
754 MachineFrameInfo &MFI = MF.getFrameInfo();
757 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
761 const TargetSubtargetInfo &STI = MF.getSubtarget();
762 const TargetRegisterInfo &
TRI = *STI.getRegisterInfo();
763 AArch64FunctionInfo &AFI = *MF.getInfo<AArch64FunctionInfo>();
766 std::optional<int64_t> IncomingVGOffsetFromDefCFA;
767 if (AFL.requiresSaveVG(MF)) {
769 reverse(CSI), [](
auto &
Info) {
return Info.getReg() == AArch64::VG; });
770 IncomingVGOffsetFromDefCFA = MFI.getObjectOffset(IncomingVG.getFrameIdx()) -
771 AFL.getOffsetOfLocalArea();
774 for (
const auto &
Info : CSI) {
780 assert(!
Info.isSpilledToReg() &&
"Spilling to registers not implemented");
781 MCRegister
Reg =
Info.getReg();
782 if (!
static_cast<const AArch64RegisterInfo &
>(
TRI).regNeedsCFI(
Reg,
Reg))
789 CFIBuilder.insertCFIInst(
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declaration of the AArch64PrologueEmitter class, which is is used to emit the ...
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
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
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
bool needsDwarfUnwindInfo(const MachineFunction &MF) const
void emitPrologue()
Emit the prologue.
AArch64PrologueEmitter(MachineFunction &MF, MachineBasicBlock &MBB, const AArch64FrameLowering &AFL)
Helper class for creating CFI instructions and inserting them into MIR.
void insertCFIInst(const MCCFIInstruction &CFIInst) const
A set of physical registers with utility functions to track liveness when walking backward/forward th...
MachineInstrBundleIterator< MachineInstr > iterator
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 & 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
Representation of each machine instruction.
static MachineOperand CreateImm(int64_t Val)
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)
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
@ 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 ==...
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.
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.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
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.
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.
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.