1//==-- AArch64FrameLowering.h - TargetFrameLowering for AArch64 --*- C++ -*-==//
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//
9//
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
14#define LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
15
16#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
17#include "llvm/CodeGen/TargetFrameLowering.h"
18#include "llvm/Support/TypeSize.h"
19
20namespace llvm {
21
22class TargetLowering;
23class AArch64FunctionInfo;
24class AArch64InstrInfo;
25class AArch64PrologueEmitter;
26class AArch64EpilogueEmitter;
27
28struct SVEStackSizes {
29 uint64_t ZPRStackSize{0};
30 uint64_t PPRStackSize{0};
31};
32
33class AArch64FrameLowering : public TargetFrameLowering {
34public:
35 explicit AArch64FrameLowering()
36 : TargetFrameLowering(StackGrowsDown, Align(16), 0, Align(16),
37 true /*StackRealignable*/) {}
38
39 void resetCFIToInitialState(MachineBasicBlock &MBB) const override;
40
41 MachineBasicBlock::iterator
42 eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
43 MachineBasicBlock::iterator I) const override;
44
45 /// emitProlog/emitEpilog - These methods insert prolog and epilog code into
46 /// the function.
47 void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
48 void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
49
50 /// Harden the entire function with pac-ret.
51 ///
52 /// If pac-ret+leaf is requested, we want to harden as much code as possible.
53 /// This function inserts pac-ret hardening at the points where prologue and
54 /// epilogue are traditionally inserted, ignoring possible shrink-wrapping
55 /// optimization.
56 void emitPacRetPlusLeafHardening(MachineFunction &MF) const;
57
58 bool enableCFIFixup(const MachineFunction &MF) const override;
59
60 bool enableFullCFIFixup(const MachineFunction &MF) const override;
61
62 bool canUseAsPrologue(const MachineBasicBlock &MBB) const override;
63
64 StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
65 Register &FrameReg) const override;
66 StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
67 int FI) const override;
68 StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI,
69 Register &FrameReg, bool PreferFP,
70 bool ForSimm) const;
71 StackOffset resolveFrameOffsetReference(const MachineFunction &MF,
72 int64_t ObjectOffset, bool isFixed,
73 TargetStackID::Value StackID,
74 Register &FrameReg, bool PreferFP,
75 bool ForSimm) const;
76 bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
77 MachineBasicBlock::iterator MI,
78 ArrayRef<CalleeSavedInfo> CSI,
79 const TargetRegisterInfo *TRI) const override;
80
81 bool
82 restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
83 MachineBasicBlock::iterator MI,
84 MutableArrayRef<CalleeSavedInfo> CSI,
85 const TargetRegisterInfo *TRI) const override;
86
87 /// Can this function use the red zone for local allocations.
88 bool canUseRedZone(const MachineFunction &MF) const;
89
90 /// Returns how much of the incoming argument stack area (in bytes) we should
91 /// clean up in an epilogue. For the C calling convention this will be 0, for
92 /// guaranteed tail call conventions it can be positive (a normal return or a
93 /// tail call to a function that uses less stack space for arguments) or
94 /// negative (for a tail call to a function that needs more stack space than
95 /// us for arguments).
96 int64_t getArgumentStackToRestore(MachineFunction &MF,
97 MachineBasicBlock &MBB) const;
98
99 bool hasReservedCallFrame(const MachineFunction &MF) const override;
100
101 bool
102 assignCalleeSavedSpillSlots(MachineFunction &MF,
103 const TargetRegisterInfo *TRI,
104 std::vector<CalleeSavedInfo> &CSI) const override;
105
106 void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
107 RegScavenger *RS) const override;
108
109 /// Returns true if the target will correctly handle shrink wrapping.
110 bool enableShrinkWrapping(const MachineFunction &MF) const override {
111 return true;
112 }
113
114 bool enableStackSlotScavenging(const MachineFunction &MF) const override;
115 TargetStackID::Value getStackIDForScalableVectors() const override;
116
117 void processFunctionBeforeFrameFinalized(MachineFunction &MF,
118 RegScavenger *RS) const override;
119
120 void
121 processFunctionBeforeFrameIndicesReplaced(MachineFunction &MF,
122 RegScavenger *RS) const override;
123
124 unsigned getWinEHParentFrameOffset(const MachineFunction &MF) const override;
125
126 unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const;
127
128 StackOffset
129 getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI,
130 Register &FrameReg,
131 bool IgnoreSPUpdates) const override;
132 StackOffset getNonLocalFrameIndexReference(const MachineFunction &MF,
133 int FI) const override;
134 int getSEHFrameIndexOffset(const MachineFunction &MF, int FI) const;
135
136 bool isSupportedStackID(TargetStackID::Value ID) const override {
137 switch (ID) {
138 default:
139 return false;
140 case TargetStackID::Default:
141 case TargetStackID::ScalableVector:
142 case TargetStackID::ScalablePredicateVector:
143 case TargetStackID::NoAlloc:
144 return true;
145 }
146 }
147
148 bool isStackIdSafeForLocalArea(unsigned StackId) const override {
149 // We don't support putting SVE objects into the pre-allocated local
150 // frame block at the moment.
151 return (StackId != TargetStackID::ScalableVector &&
152 StackId != TargetStackID::ScalablePredicateVector);
153 }
154
155 void
156 orderFrameObjects(const MachineFunction &MF,
157 SmallVectorImpl<int> &ObjectsToAllocate) const override;
158
159 bool isFPReserved(const MachineFunction &MF) const;
160
161 bool needsWinCFI(const MachineFunction &MF) const;
162
163 bool requiresSaveVG(const MachineFunction &MF) const;
164
165 /// Returns the size of the entire ZPR stackframe (calleesaves + spills).
166 StackOffset getZPRStackSize(const MachineFunction &MF) const;
167
168 /// Returns the size of the entire PPR stackframe (calleesaves + spills +
169 /// hazard padding).
170 StackOffset getPPRStackSize(const MachineFunction &MF) const;
171
172 /// Returns the size of the entire SVE stackframe (PPRs + ZPRs).
173 StackOffset getSVEStackSize(const MachineFunction &MF) const {
174 return getZPRStackSize(MF) + getPPRStackSize(MF);
175 }
176
177 friend class AArch64PrologueEpilogueCommon;
178 friend class AArch64PrologueEmitter;
179 friend class AArch64EpilogueEmitter;
180
181 // Windows unwind can't represent the required stack adjustments if we have
182 // both SVE callee-saves and dynamic stack allocations, and the frame
183 // pointer is before the SVE spills. The allocation of the frame pointer
184 // must be the last instruction in the prologue so the unwinder can restore
185 // the stack pointer correctly. (And there isn't any unwind opcode for
186 // `addvl sp, x29, -17`.)
187 //
188 // Because of this, we do spills in the opposite order on Windows: first SVE,
189 // then GPRs. The main side-effect of this is that it makes accessing
190 // parameters passed on the stack more expensive.
191 //
192 // We could consider rearranging the spills for simpler cases.
193 bool hasSVECalleeSavesAboveFrameRecord(const MachineFunction &MF) const;
194
195protected:
196 bool hasFPImpl(const MachineFunction &MF) const override;
197
198private:
199 /// Returns true if a homogeneous prolog or epilog code can be emitted
200 /// for the size optimization. If so, HOM_Prolog/HOM_Epilog pseudo
201 /// instructions are emitted in place. When Exit block is given, this check is
202 /// for epilog.
203 bool homogeneousPrologEpilog(MachineFunction &MF,
204 MachineBasicBlock *Exit = nullptr) const;
205
206 /// Returns true if CSRs should be paired.
207 bool producePairRegisters(MachineFunction &MF) const;
208
209 /// Make a determination whether a Hazard slot is used and create it if
210 /// needed.
211 void determineStackHazardSlot(MachineFunction &MF,
212 BitVector &SavedRegs) const;
213
214 /// Emit target zero call-used regs.
215 void emitZeroCallUsedRegs(BitVector RegsToZero,
216 MachineBasicBlock &MBB) const override;
217
218 /// Replace a StackProbe stub (if any) with the actual probe code inline
219 void inlineStackProbe(MachineFunction &MF,
220 MachineBasicBlock &PrologueMBB) const override;
221
222 void inlineStackProbeFixed(MachineBasicBlock::iterator MBBI,
223 Register ScratchReg, int64_t FrameSize,
224 StackOffset CFAOffset) const;
225
226 MachineBasicBlock::iterator
227 inlineStackProbeLoopExactMultiple(MachineBasicBlock::iterator MBBI,
228 int64_t NegProbeSize,
229 Register TargetReg) const;
230
231 void emitRemarks(const MachineFunction &MF,
232 MachineOptimizationRemarkEmitter *ORE) const override;
233
234 bool windowsRequiresStackProbe(const MachineFunction &MF,
235 uint64_t StackSizeInBytes) const;
236
237 bool shouldSignReturnAddressEverywhere(const MachineFunction &MF) const;
238
239 StackOffset getFPOffset(const MachineFunction &MF,
240 int64_t ObjectOffset) const;
241
242 StackOffset getStackOffset(const MachineFunction &MF,
243 int64_t ObjectOffset) const;
244
245 // Given a load or a store instruction, generate an appropriate unwinding SEH
246 // code on Windows.
247 MachineBasicBlock::iterator insertSEH(MachineBasicBlock::iterator MBBI,
248 const AArch64InstrInfo &TII,
249 MachineInstr::MIFlag Flag) const;
250
251 // Find a scratch register that we can use at the start of the prologue to
252 // re-align the stack pointer. We avoid using callee-save registers since
253 // they may appear to be free when this is called from canUseAsPrologue
254 // (during shrink wrapping), but then no longer be free when this is called
255 // from emitPrologue.
256 //
257 // FIXME: This is a bit conservative, since in the above case we could use one
258 // of the callee-save registers as a scratch temp to re-align the stack
259 // pointer, but we would then have to make sure that we were in fact saving at
260 // least one callee-save register in the prologue, which is additional
261 // complexity that doesn't seem worth the benefit.
262 Register findScratchNonCalleeSaveRegister(MachineBasicBlock *MBB,
263 bool HasCall = false) const;
264
265 /// Returns the size of the fixed object area (allocated next to sp on entry)
266 /// On Win64 this may include a var args area and an UnwindHelp object for EH.
267 unsigned getFixedObjectSize(const MachineFunction &MF,
268 const AArch64FunctionInfo *AFI, bool IsWin64,
269 bool IsFunclet) const;
270};
271
272} // End llvm namespace
273
274#endif
275