LLVM 22.0.0git
AArch64PrologueEpilogue.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
12#include "AArch64Subtarget.h"
14#include "llvm/ADT/Statistic.h"
17#include "llvm/MC/MCContext.h"
18
19#define DEBUG_TYPE "frame-info"
20
21STATISTIC(NumRedZoneFunctions, "Number of functions using red zone");
22
23namespace llvm {
24
27 const AArch64FrameLowering &AFL)
28 : MF(MF), MBB(MBB), F(MF.getFunction()), MFI(MF.getFrameInfo()),
29 Subtarget(MF.getSubtarget<AArch64Subtarget>()), AFL(AFL),
30 RegInfo(*Subtarget.getRegisterInfo()) {
31 TII = Subtarget.getInstrInfo();
32 AFI = MF.getInfo<AArch64FunctionInfo>();
33
34 EmitCFI = AFI->needsDwarfUnwindInfo(MF);
35 EmitAsyncCFI = AFI->needsAsyncDwarfUnwindInfo(MF);
36 HasFP = AFL.hasFP(MF);
37 NeedsWinCFI = AFL.needsWinCFI(MF);
38 IsFunclet = MBB.isEHFuncletEntry();
39 HomPrologEpilog = AFL.homogeneousPrologEpilog(MF);
40
41#ifndef NDEBUG
42 collectBlockLiveins();
43#endif
44}
45
46#ifndef NDEBUG
47/// Collect live registers from the end of \p MI's parent up to (including) \p
48/// MI in \p LiveRegs.
50 LivePhysRegs &LiveRegs) {
51
52 MachineBasicBlock &MBB = *MI.getParent();
53 LiveRegs.addLiveOuts(MBB);
54 for (const MachineInstr &MI :
55 reverse(make_range(MI.getIterator(), MBB.instr_end())))
56 LiveRegs.stepBackward(MI);
57}
58
59void AArch64PrologueEmitter::collectBlockLiveins() {
60 // Collect live register from the end of MBB up to the start of the existing
61 // frame setup instructions.
62 PrologueEndI = MBB.begin();
63 while (PrologueEndI != MBB.end() &&
64 PrologueEndI->getFlag(MachineInstr::FrameSetup))
65 ++PrologueEndI;
66
67 if (PrologueEndI != MBB.end()) {
68 getLivePhysRegsUpTo(*PrologueEndI, RegInfo, LiveRegs);
69 // Ignore registers used for stack management for now.
70 LiveRegs.removeReg(AArch64::SP);
71 LiveRegs.removeReg(AArch64::X19);
72 LiveRegs.removeReg(AArch64::FP);
73 LiveRegs.removeReg(AArch64::LR);
74
75 // X0 will be clobbered by a call to __arm_get_current_vg in the prologue.
76 // This is necessary to spill VG if required where SVE is unavailable, but
77 // X0 is preserved around this call.
78 if (AFL.requiresGetVGCall(MF))
79 LiveRegs.removeReg(AArch64::X0);
80 }
81}
82
83void AArch64PrologueEmitter::verifyPrologueClobbers() const {
84 if (PrologueEndI == MBB.end())
85 return;
86 // Check if any of the newly instructions clobber any of the live registers.
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");
93 }
94}
95#endif
96
97void AArch64PrologueEmitter::determineLocalsStackSize(
98 uint64_t StackSize, uint64_t PrologueSaveSize) {
99 AFI->setLocalStackSize(StackSize - PrologueSaveSize);
100 CombineSPBump = AFL.shouldCombineCSRLocalStackBump(MF, StackSize);
101}
102
104 const MachineBasicBlock::iterator PrologueBeginI = MBB.begin();
105 const MachineBasicBlock::iterator EndI = MBB.end();
106
107 // At this point, we're going to decide whether or not the function uses a
108 // redzone. In most cases, the function doesn't have a redzone so let's
109 // assume that's false and set it to true in the case that there's a redzone.
110 AFI->setHasRedZone(false);
111
112 // Debug location must be unknown since the first debug location is used
113 // to determine the end of the prologue.
114 DebugLoc DL;
115
116 if (AFI->shouldSignReturnAddress(MF)) {
117 // If pac-ret+leaf is in effect, PAUTH_PROLOGUE pseudo instructions
118 // are inserted by emitPacRetPlusLeafHardening().
119 if (!AFL.shouldSignReturnAddressEverywhere(MF)) {
120 BuildMI(MBB, PrologueBeginI, DL, TII->get(AArch64::PAUTH_PROLOGUE))
122 }
123 // AArch64PointerAuth pass will insert SEH_PACSignLR
124 HasWinCFI |= NeedsWinCFI;
125 }
126
127 if (AFI->needsShadowCallStackPrologueEpilogue(MF)) {
128 emitShadowCallStackPrologue(PrologueBeginI, DL);
129 HasWinCFI |= NeedsWinCFI;
130 }
131
132 if (EmitCFI && AFI->isMTETagged())
133 BuildMI(MBB, PrologueBeginI, DL, TII->get(AArch64::EMITMTETAGGED))
135
136 // We signal the presence of a Swift extended frame to external tools by
137 // storing FP with 0b0001 in bits 63:60. In normal userland operation a simple
138 // ORR is sufficient, it is assumed a Swift kernel would initialize the TBI
139 // bits so that is still true.
140 if (HasFP && AFI->hasSwiftAsyncContext())
141 emitSwiftAsyncContextFramePointer(PrologueBeginI, DL);
142
143 // All calls are tail calls in GHC calling conv, and functions have no
144 // prologue/epilogue.
145 if (MF.getFunction().getCallingConv() == CallingConv::GHC)
146 return;
147
148 // Set tagged base pointer to the requested stack slot. Ideally it should
149 // match SP value after prologue.
150 if (std::optional<int> TBPI = AFI->getTaggedBasePointerIndex())
151 AFI->setTaggedBasePointerOffset(-MFI.getObjectOffset(*TBPI));
152 else
153 AFI->setTaggedBasePointerOffset(MFI.getStackSize());
154
155 // getStackSize() includes all the locals in its size calculation. We don't
156 // include these locals when computing the stack size of a funclet, as they
157 // are allocated in the parent's stack frame and accessed via the frame
158 // pointer from the funclet. We only save the callee saved registers in the
159 // funclet, which are really the callee saved registers of the parent
160 // function, including the funclet.
161 int64_t NumBytes =
162 IsFunclet ? AFL.getWinEHFuncletFrameSize(MF) : MFI.getStackSize();
163 if (!AFI->hasStackFrame() && !AFL.windowsRequiresStackProbe(MF, NumBytes))
164 return emitEmptyStackFramePrologue(NumBytes, PrologueBeginI, DL);
165
166 bool IsWin64 = Subtarget.isCallingConvWin64(F.getCallingConv(), F.isVarArg());
167 unsigned FixedObject = AFL.getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
168
169 // Windows unwind can't represent the required stack adjustments if we have
170 // both SVE callee-saves and dynamic stack allocations, and the frame
171 // pointer is before the SVE spills. The allocation of the frame pointer
172 // must be the last instruction in the prologue so the unwinder can restore
173 // the stack pointer correctly. (And there isn't any unwind opcode for
174 // `addvl sp, x29, -17`.)
175 //
176 // Because of this, we do spills in the opposite order on Windows: first SVE,
177 // then GPRs. The main side-effect of this is that it makes accessing
178 // parameters passed on the stack more expensive.
179 //
180 // We could consider rearranging the spills for simpler cases.
181 bool FPAfterSVECalleeSaves =
182 Subtarget.isTargetWindows() && AFI->getSVECalleeSavedStackSize();
183
184 if (FPAfterSVECalleeSaves && AFI->hasStackHazardSlotIndex())
185 reportFatalUsageError("SME hazard padding is not supported on Windows");
186
187 auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
188 // All of the remaining stack allocations are for locals.
189 determineLocalsStackSize(NumBytes, PrologueSaveSize);
190
191 MachineBasicBlock::iterator FirstGPRSaveI = PrologueBeginI;
192 if (FPAfterSVECalleeSaves) {
193 // If we're doing SVE saves first, we need to immediately allocate space
194 // for fixed objects, then space for the SVE callee saves.
195 //
196 // Windows unwind requires that the scalable size is a multiple of 16;
197 // that's handled when the callee-saved size is computed.
198 auto SaveSize =
199 StackOffset::getScalable(AFI->getSVECalleeSavedStackSize()) +
200 StackOffset::getFixed(FixedObject);
201 AFL.allocateStackSpace(MBB, PrologueBeginI, 0, SaveSize, NeedsWinCFI,
202 &HasWinCFI,
203 /*EmitCFI=*/false, StackOffset{},
204 /*FollowupAllocs=*/true);
205 NumBytes -= FixedObject;
206
207 // Now allocate space for the GPR callee saves.
208 MachineBasicBlock::iterator MBBI = PrologueBeginI;
209 while (MBBI != EndI && AFL.isSVECalleeSave(MBBI))
210 ++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");
217 emitFrameOffset(MBB, PrologueBeginI, DL, AArch64::SP, AArch64::SP,
218 StackOffset::getFixed(-NumBytes), TII,
219 MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI,
220 EmitAsyncCFI);
221 NumBytes = 0;
222 } else if (HomPrologEpilog) {
223 // Stack has been already adjusted.
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;
230 }
231 assert(NumBytes >= 0 && "Negative stack allocation size!?");
232
233 // Move past the saves of the callee-saved registers, fixing up the offsets
234 // and pre-inc if we decided to combine the callee-save and local stack
235 // pointer bump above.
236 auto &TLI = *MF.getSubtarget().getTargetLowering();
237
238 MachineBasicBlock::iterator AfterGPRSavesI = FirstGPRSaveI;
239 while (AfterGPRSavesI != EndI &&
240 AfterGPRSavesI->getFlag(MachineInstr::FrameSetup) &&
241 !AFL.isSVECalleeSave(AfterGPRSavesI)) {
242 if (CombineSPBump &&
243 // Only fix-up frame-setup load/store instructions.
244 (!AFL.requiresSaveVG(MF) || !AFL.isVGInstruction(AfterGPRSavesI, TLI)))
245 AFL.fixupCalleeSaveRestoreStackOffset(
246 *AfterGPRSavesI, AFI->getLocalStackSize(), NeedsWinCFI, &HasWinCFI);
247 ++AfterGPRSavesI;
248 }
249
250 // For funclets the FP belongs to the containing function. Only set up FP if
251 // we actually need to.
252 if (!IsFunclet && HasFP)
253 emitFramePointerSetup(AfterGPRSavesI, DL, FixedObject);
254
255 // Now emit the moves for whatever callee saved regs we have (including FP,
256 // LR if those are saved). Frame instructions for SVE register are emitted
257 // later, after the instruction which actually save SVE regs.
258 if (EmitAsyncCFI)
259 emitCalleeSavedGPRLocations(AfterGPRSavesI);
260
261 // Alignment is required for the parent frame, not the funclet
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
267 : 0;
268
269 if (AFL.windowsRequiresStackProbe(MF, NumBytes + RealignmentPadding))
270 emitWindowsStackProbe(AfterGPRSavesI, DL, NumBytes, RealignmentPadding);
271
272 StackOffset SVEStackSize = AFL.getSVEStackSize(MF);
273 StackOffset SVECalleeSavesSize = {}, SVELocalsSize = SVEStackSize;
274 MachineBasicBlock::iterator CalleeSavesEnd = AfterGPRSavesI;
275
276 StackOffset CFAOffset =
277 StackOffset::getFixed((int64_t)MFI.getStackSize() - NumBytes);
278
279 // Process the SVE callee-saves to determine what space needs to be
280 // allocated.
281 MachineBasicBlock::iterator AfterSVESavesI = AfterGPRSavesI;
282 if (int64_t CalleeSavedSize = AFI->getSVECalleeSavedStackSize()) {
283 LLVM_DEBUG(dbgs() << "SVECalleeSavedStackSize = " << CalleeSavedSize
284 << "\n");
285 SVECalleeSavesSize = StackOffset::getScalable(CalleeSavedSize);
286 SVELocalsSize = SVEStackSize - SVECalleeSavesSize;
287 // Find callee save instructions in frame.
288 // Note: With FPAfterSVECalleeSaves the callee saves have already been
289 // allocated.
290 if (!FPAfterSVECalleeSaves) {
291 MachineBasicBlock::iterator CalleeSavesBegin = AfterGPRSavesI;
292 assert(AFL.isSVECalleeSave(CalleeSavesBegin) && "Unexpected instruction");
293 while (AFL.isSVECalleeSave(AfterSVESavesI) &&
294 AfterSVESavesI != MBB.getFirstTerminator())
295 ++AfterSVESavesI;
296 CalleeSavesEnd = AfterSVESavesI;
297
298 StackOffset LocalsSize = SVELocalsSize + StackOffset::getFixed(NumBytes);
299 // Allocate space for the callee saves (if any).
300 AFL.allocateStackSpace(MBB, CalleeSavesBegin, 0, SVECalleeSavesSize,
301 false, nullptr, EmitAsyncCFI && !HasFP, CFAOffset,
302 MFI.hasVarSizedObjects() || LocalsSize);
303 }
304 }
305 CFAOffset += SVECalleeSavesSize;
306
307 if (EmitAsyncCFI)
308 emitCalleeSavedSVELocations(CalleeSavesEnd);
309
310 // Allocate space for the rest of the frame including SVE locals. Align the
311 // stack as necessary.
312 assert(!(AFL.canUseRedZone(MF) && NeedsRealignment) &&
313 "Cannot use redzone with stack realignment");
314 if (!AFL.canUseRedZone(MF)) {
315 // FIXME: in the case of dynamic re-alignment, NumBytes doesn't have
316 // the correct value here, as NumBytes also includes padding bytes,
317 // which shouldn't be counted here.
318 AFL.allocateStackSpace(MBB, CalleeSavesEnd, RealignmentPadding,
319 SVELocalsSize + StackOffset::getFixed(NumBytes),
320 NeedsWinCFI, &HasWinCFI, EmitAsyncCFI && !HasFP,
321 CFAOffset, MFI.hasVarSizedObjects());
322 }
323
324 // If we need a base pointer, set it up here. It's whatever the value of the
325 // stack pointer is at this point. Any variable size objects will be allocated
326 // after this, so we can still use the base pointer to reference locals.
327 //
328 // FIXME: Clarify FrameSetup flags here.
329 // Note: Use emitFrameOffset() like above for FP if the FrameSetup flag is
330 // needed.
331 // For funclets the BP belongs to the containing function.
332 if (!IsFunclet && RegInfo.hasBasePointer(MF)) {
333 TII->copyPhysReg(MBB, AfterSVESavesI, DL, RegInfo.getBaseRegister(),
334 AArch64::SP, false);
335 if (NeedsWinCFI) {
336 HasWinCFI = true;
337 BuildMI(MBB, AfterSVESavesI, DL, TII->get(AArch64::SEH_Nop))
339 }
340 }
341
342 // The very last FrameSetup instruction indicates the end of prologue. Emit a
343 // SEH opcode indicating the prologue end.
344 if (NeedsWinCFI && HasWinCFI) {
345 BuildMI(MBB, AfterSVESavesI, DL, TII->get(AArch64::SEH_PrologEnd))
347 }
348
349 // SEH funclets are passed the frame pointer in X1. If the parent
350 // function uses the base register, then the base register is used
351 // directly, and is not retrieved from X1.
352 if (IsFunclet && F.hasPersonalityFn()) {
353 EHPersonality Per = classifyEHPersonality(F.getPersonalityFn());
355 BuildMI(MBB, AfterSVESavesI, DL, TII->get(TargetOpcode::COPY),
356 AArch64::FP)
357 .addReg(AArch64::X1)
359 MBB.addLiveIn(AArch64::X1);
360 }
361 }
362
363 if (EmitCFI && !EmitAsyncCFI) {
364 if (HasFP) {
365 emitDefineCFAWithFP(AfterSVESavesI, FixedObject);
366 } else {
367 StackOffset TotalSize =
368 SVEStackSize + StackOffset::getFixed((int64_t)MFI.getStackSize());
369 CFIInstBuilder CFIBuilder(MBB, AfterSVESavesI, MachineInstr::FrameSetup);
370 CFIBuilder.insertCFIInst(
371 createDefCFA(RegInfo, /*FrameReg=*/AArch64::SP, /*Reg=*/AArch64::SP,
372 TotalSize, /*LastAdjustmentWasScalable=*/false));
373 }
374 emitCalleeSavedGPRLocations(AfterSVESavesI);
375 emitCalleeSavedSVELocations(AfterSVESavesI);
376 }
377}
378
379void AArch64PrologueEmitter::emitShadowCallStackPrologue(
381 // Shadow call stack prolog: str x30, [x18], #8
382 BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXpost))
383 .addReg(AArch64::X18, RegState::Define)
384 .addReg(AArch64::LR)
385 .addReg(AArch64::X18)
386 .addImm(8)
388
389 // This instruction also makes x18 live-in to the entry block.
390 MBB.addLiveIn(AArch64::X18);
391
392 if (NeedsWinCFI)
393 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
395
396 if (EmitCFI) {
397 // Emit a CFI instruction that causes 8 to be subtracted from the value of
398 // x18 when unwinding past this frame.
399 static const char CFIInst[] = {
400 dwarf::DW_CFA_val_expression,
401 18, // register
402 2, // length
403 static_cast<char>(unsigned(dwarf::DW_OP_breg18)),
404 static_cast<char>(-8) & 0x7f, // addend (sleb128)
405 };
406 CFIInstBuilder(MBB, MBBI, MachineInstr::FrameSetup)
407 .buildEscape(StringRef(CFIInst, sizeof(CFIInst)));
408 }
409}
410
411void AArch64PrologueEmitter::emitSwiftAsyncContextFramePointer(
413 switch (MF.getTarget().Options.SwiftAsyncFramePointer) {
415 if (Subtarget.swiftAsyncContextIsDynamicallySet()) {
416 // The special symbol below is absolute and has a *value* that can be
417 // combined with the frame pointer to signal an extended frame.
418 BuildMI(MBB, MBBI, DL, TII->get(AArch64::LOADgot), AArch64::X16)
419 .addExternalSymbol("swift_async_extendedFramePointerFlags",
421 if (NeedsWinCFI) {
422 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
424 HasWinCFI = true;
425 }
426 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), AArch64::FP)
427 .addUse(AArch64::FP)
428 .addUse(AArch64::X16)
429 .addImm(Subtarget.isTargetILP32() ? 32 : 0);
430 if (NeedsWinCFI) {
431 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
433 HasWinCFI = true;
434 }
435 break;
436 }
437 [[fallthrough]];
438
440 // ORR x29, x29, #0x1000_0000_0000_0000
441 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXri), AArch64::FP)
442 .addUse(AArch64::FP)
443 .addImm(0x1100)
445 if (NeedsWinCFI) {
446 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
448 HasWinCFI = true;
449 }
450 break;
451
453 break;
454 }
455}
456
457void AArch64PrologueEmitter::emitEmptyStackFramePrologue(
458 int64_t NumBytes, MachineBasicBlock::iterator MBBI,
459 const DebugLoc &DL) const {
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");
463 // All of the stack allocation is for locals.
464 AFI->setLocalStackSize(NumBytes);
465 if (!NumBytes) {
466 if (NeedsWinCFI && HasWinCFI) {
467 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
469 }
470 return;
471 }
472 // REDZONE: If the stack size is less than 128 bytes, we don't need
473 // to actually allocate.
474 if (AFL.canUseRedZone(MF)) {
475 AFI->setHasRedZone(true);
476 ++NumRedZoneFunctions;
477 } else {
478 emitFrameOffset(MBB, MBBI, DL, AArch64::SP, AArch64::SP,
479 StackOffset::getFixed(-NumBytes), TII,
480 MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI);
481 if (EmitCFI) {
482 // Label used to tie together the PROLOG_LABEL and the MachineMoves.
483 MCSymbol *FrameLabel = MF.getContext().createTempSymbol();
484 // Encode the stack size of the leaf function.
485 CFIInstBuilder(MBB, MBBI, MachineInstr::FrameSetup)
486 .buildDefCFAOffset(NumBytes, FrameLabel);
487 }
488 }
489
490 if (NeedsWinCFI) {
491 HasWinCFI = true;
492 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
494 }
495}
496
497void AArch64PrologueEmitter::emitFramePointerSetup(
499 unsigned FixedObject) {
500 int64_t FPOffset = AFI->getCalleeSaveBaseToFrameRecordOffset();
501 if (CombineSPBump)
502 FPOffset += AFI->getLocalStackSize();
503
504 if (AFI->hasSwiftAsyncContext()) {
505 // Before we update the live FP we have to ensure there's a valid (or
506 // null) asynchronous context in its slot just before FP in the frame
507 // record, so store it now.
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))
514 .addUse(Reg)
515 .addUse(AArch64::SP)
516 .addImm(FPOffset - 8)
518 if (NeedsWinCFI) {
519 // WinCFI and arm64e, where StoreSwiftAsyncContext is expanded
520 // to multiple instructions, should be mutually-exclusive.
521 assert(Subtarget.getTargetTriple().getArchName() != "arm64e");
522 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
524 HasWinCFI = true;
525 }
526 }
527
528 if (HomPrologEpilog) {
529 auto Prolog = MBBI;
530 --Prolog;
531 assert(Prolog->getOpcode() == AArch64::HOM_Prolog);
532 Prolog->addOperand(MachineOperand::CreateImm(FPOffset));
533 } else {
534 // Issue sub fp, sp, FPOffset or
535 // mov fp,sp when FPOffset is zero.
536 // Note: All stores of callee-saved registers are marked as "FrameSetup".
537 // This code marks the instruction(s) that set the FP also.
538 emitFrameOffset(MBB, MBBI, DL, AArch64::FP, AArch64::SP,
539 StackOffset::getFixed(FPOffset), TII,
540 MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI);
541 if (NeedsWinCFI && HasWinCFI) {
542 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
544 // After setting up the FP, the rest of the prolog doesn't need to be
545 // included in the SEH unwind info.
546 NeedsWinCFI = false;
547 }
548 }
549 if (EmitAsyncCFI)
550 emitDefineCFAWithFP(MBBI, FixedObject);
551}
552
553// Define the current CFA rule to use the provided FP.
554void AArch64PrologueEmitter::emitDefineCFAWithFP(
555 MachineBasicBlock::iterator MBBI, unsigned FixedObject) const {
556 const AArch64RegisterInfo *TRI = Subtarget.getRegisterInfo();
557 const int OffsetToFirstCalleeSaveFromFP =
558 AFI->getCalleeSaveBaseToFrameRecordOffset() -
559 AFI->getCalleeSavedStackSize();
560 Register FramePtr = TRI->getFrameRegister(MF);
561 CFIInstBuilder(MBB, MBBI, MachineInstr::FrameSetup)
562 .buildDefCFA(FramePtr, FixedObject - OffsetToFirstCalleeSaveFromFP);
563}
564
565void AArch64PrologueEmitter::emitWindowsStackProbe(
566 MachineBasicBlock::iterator MBBI, const DebugLoc &DL, int64_t &NumBytes,
567 int64_t RealignmentPadding) const {
568 if (AFI->getSVECalleeSavedStackSize())
569 report_fatal_error("SVE callee saves not yet supported with stack probing");
570
571 // Find an available register to spill the value of X15 to, if X15 is being
572 // used already for nest.
573 unsigned X15Scratch = AArch64::NoRegister;
574 const AArch64Subtarget &STI = MF.getSubtarget<AArch64Subtarget>();
575 if (llvm::any_of(MBB.liveins(),
576 [&STI](const MachineBasicBlock::RegisterMaskPair &LiveIn) {
577 return STI.getRegisterInfo()->isSuperOrSubRegisterEq(
578 AArch64::X15, LiveIn.PhysReg);
579 })) {
580 X15Scratch = AFL.findScratchNonCalleeSaveRegister(&MBB, /*HasCall=*/true);
581 assert(X15Scratch != AArch64::NoRegister &&
582 (X15Scratch < AArch64::X15 || X15Scratch > AArch64::X17));
583#ifndef NDEBUG
584 LiveRegs.removeReg(AArch64::X15); // ignore X15 since we restore it
585#endif
586 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrr), X15Scratch)
587 .addReg(AArch64::XZR)
588 .addReg(AArch64::X15, RegState::Undef)
589 .addReg(AArch64::X15, RegState::Implicit)
591 }
592
593 uint64_t NumWords = (NumBytes + RealignmentPadding) >> 4;
594 if (NeedsWinCFI) {
595 HasWinCFI = true;
596 // alloc_l can hold at most 256MB, so assume that NumBytes doesn't
597 // exceed this amount. We need to move at most 2^24 - 1 into x15.
598 // This is at most two instructions, MOVZ followed by MOVK.
599 // TODO: Fix to use multiple stack alloc unwind codes for stacks
600 // exceeding 256MB in size.
601 if (NumBytes >= (1 << 28))
602 report_fatal_error("Stack size cannot exceed 256MB for stack "
603 "unwinding purposes");
604
605 uint32_t LowNumWords = NumWords & 0xFFFF;
606 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVZXi), AArch64::X15)
607 .addImm(LowNumWords)
610 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
612 if ((NumWords & 0xFFFF0000) != 0) {
613 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVKXi), AArch64::X15)
614 .addReg(AArch64::X15)
615 .addImm((NumWords & 0xFFFF0000) >> 16) // High half
618 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
620 }
621 } else {
622 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVi64imm), AArch64::X15)
623 .addImm(NumWords)
625 }
626
627 const char *ChkStk = Subtarget.getChkStkName();
628 switch (MF.getTarget().getCodeModel()) {
629 case CodeModel::Tiny:
630 case CodeModel::Small:
633 BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))
634 .addExternalSymbol(ChkStk)
635 .addReg(AArch64::X15, RegState::Implicit)
636 .addReg(AArch64::X16,
638 .addReg(AArch64::X17,
640 .addReg(AArch64::NZCV,
643 if (NeedsWinCFI) {
644 HasWinCFI = true;
645 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
647 }
648 break;
649 case CodeModel::Large:
650 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVaddrEXT))
651 .addReg(AArch64::X16, RegState::Define)
652 .addExternalSymbol(ChkStk)
653 .addExternalSymbol(ChkStk)
655 if (NeedsWinCFI) {
656 HasWinCFI = true;
657 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
659 }
660
661 BuildMI(MBB, MBBI, DL, TII->get(getBLRCallOpcode(MF)))
662 .addReg(AArch64::X16, RegState::Kill)
664 .addReg(AArch64::X16,
666 .addReg(AArch64::X17,
668 .addReg(AArch64::NZCV,
671 if (NeedsWinCFI) {
672 HasWinCFI = true;
673 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop))
675 }
676 break;
677 }
678
679 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SUBXrx64), AArch64::SP)
680 .addReg(AArch64::SP, RegState::Kill)
681 .addReg(AArch64::X15, RegState::Kill)
684 if (NeedsWinCFI) {
685 HasWinCFI = true;
686 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_StackAlloc))
687 .addImm(NumBytes)
689 }
690 NumBytes = 0;
691
692 if (RealignmentPadding > 0) {
693 if (RealignmentPadding >= 4096) {
694 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVi64imm))
695 .addReg(AArch64::X16, RegState::Define)
696 .addImm(RealignmentPadding)
698 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDXrx64), AArch64::X15)
699 .addReg(AArch64::SP)
700 .addReg(AArch64::X16, RegState::Kill)
703 } else {
704 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDXri), AArch64::X15)
705 .addReg(AArch64::SP)
706 .addImm(RealignmentPadding)
707 .addImm(0)
709 }
710
711 uint64_t AndMask = ~(MFI.getMaxAlign().value() - 1);
712 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ANDXri), AArch64::SP)
713 .addReg(AArch64::X15, RegState::Kill)
715 AFI->setStackRealigned(true);
716
717 // No need for SEH instructions here; if we're realigning the stack,
718 // we've set a frame pointer and already finished the SEH prologue.
719 assert(!NeedsWinCFI);
720 }
721 if (X15Scratch != AArch64::NoRegister) {
722 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrr), AArch64::X15)
723 .addReg(AArch64::XZR)
724 .addReg(X15Scratch, RegState::Undef)
725 .addReg(X15Scratch, RegState::Implicit)
727 }
728}
729
730void AArch64PrologueEmitter::emitCalleeSavedGPRLocations(
732 MachineFunction &MF = *MBB.getParent();
733 MachineFrameInfo &MFI = MF.getFrameInfo();
734
735 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
736 if (CSI.empty())
737 return;
738
739 CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameSetup);
740 for (const auto &Info : CSI) {
741 unsigned FrameIdx = Info.getFrameIdx();
742 if (MFI.getStackID(FrameIdx) == TargetStackID::ScalableVector)
743 continue;
744
745 assert(!Info.isSpilledToReg() && "Spilling to registers not implemented");
746 int64_t Offset = MFI.getObjectOffset(FrameIdx) - AFL.getOffsetOfLocalArea();
747 CFIBuilder.buildOffset(Info.getReg(), Offset);
748 }
749}
750
751void AArch64PrologueEmitter::emitCalleeSavedSVELocations(
753 MachineFunction &MF = *MBB.getParent();
754 MachineFrameInfo &MFI = MF.getFrameInfo();
755
756 // Add callee saved registers to move list.
757 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
758 if (CSI.empty())
759 return;
760
761 const TargetSubtargetInfo &STI = MF.getSubtarget();
762 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
763 AArch64FunctionInfo &AFI = *MF.getInfo<AArch64FunctionInfo>();
764 CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameSetup);
765
766 std::optional<int64_t> IncomingVGOffsetFromDefCFA;
767 if (AFL.requiresSaveVG(MF)) {
768 auto IncomingVG = *find_if(
769 reverse(CSI), [](auto &Info) { return Info.getReg() == AArch64::VG; });
770 IncomingVGOffsetFromDefCFA = MFI.getObjectOffset(IncomingVG.getFrameIdx()) -
771 AFL.getOffsetOfLocalArea();
772 }
773
774 for (const auto &Info : CSI) {
775 if (MFI.getStackID(Info.getFrameIdx()) != TargetStackID::ScalableVector)
776 continue;
777
778 // Not all unwinders may know about SVE registers, so assume the lowest
779 // common denominator.
780 assert(!Info.isSpilledToReg() && "Spilling to registers not implemented");
781 MCRegister Reg = Info.getReg();
782 if (!static_cast<const AArch64RegisterInfo &>(TRI).regNeedsCFI(Reg, Reg))
783 continue;
784
785 StackOffset Offset =
786 StackOffset::getScalable(MFI.getObjectOffset(Info.getFrameIdx())) -
787 StackOffset::getFixed(AFI.getCalleeSavedStackSize(MFI));
788
789 CFIBuilder.insertCFIInst(
790 createCFAOffset(TRI, Reg, Offset, IncomingVGOffsetFromDefCFA));
791 }
792}
793
794} // namespace llvm
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 & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
Analysis containing CSE Info
Definition CSEInfo.cpp:27
This file contains constants used for implementing Dwarf debug support.
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:167
#define LLVM_DEBUG(...)
Definition Debug.h:119
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
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 debug info location.
Definition DebugLoc.h:124
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.
Definition TypeSize.h:31
int64_t getFixed() const
Returns the fixed component of the stack.
Definition TypeSize.h:47
int64_t getScalable() const
Returns the scalable component of the stack.
Definition TypeSize.h:50
static StackOffset getFixed(int64_t Fixed)
Definition TypeSize.h:40
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).
Definition CallingConv.h:50
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Dead
Unused definition.
@ 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.
@ Offset
Definition DWP.cpp:477
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.
Definition STLExtras.h:1734
auto reverse(ContainerTy &&C)
Definition STLExtras.h:420
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.
@ 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.
Definition Debug.cpp:207
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)
Definition Error.cpp:167
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.
Definition STLExtras.h:1760
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:180
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39