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 bool hasReservedCallFrame(const MachineFunction &MF) const override;
91
92 bool
93 assignCalleeSavedSpillSlots(MachineFunction &MF,
94 const TargetRegisterInfo *TRI,
95 std::vector<CalleeSavedInfo> &CSI) const override;
96
97 void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
98 RegScavenger *RS) const override;
99
100 /// Returns true if the target will correctly handle shrink wrapping.
101 bool enableShrinkWrapping(const MachineFunction &MF) const override {
102 return true;
103 }
104
105 bool enableStackSlotScavenging(const MachineFunction &MF) const override;
106 TargetStackID::Value getStackIDForScalableVectors() const override;
107
108 void processFunctionBeforeFrameFinalized(MachineFunction &MF,
109 RegScavenger *RS) const override;
110
111 void
112 processFunctionBeforeFrameIndicesReplaced(MachineFunction &MF,
113 RegScavenger *RS) const override;
114
115 unsigned getWinEHParentFrameOffset(const MachineFunction &MF) const override;
116
117 unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const;
118
119 StackOffset
120 getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI,
121 Register &FrameReg,
122 bool IgnoreSPUpdates) const override;
123 StackOffset getNonLocalFrameIndexReference(const MachineFunction &MF,
124 int FI) const override;
125 int getSEHFrameIndexOffset(const MachineFunction &MF, int FI) const;
126
127 bool isSupportedStackID(TargetStackID::Value ID) const override {
128 switch (ID) {
129 default:
130 return false;
131 case TargetStackID::Default:
132 case TargetStackID::ScalableVector:
133 case TargetStackID::ScalablePredicateVector:
134 case TargetStackID::NoAlloc:
135 return true;
136 }
137 }
138
139 bool isStackIdSafeForLocalArea(unsigned StackId) const override {
140 // We don't support putting SVE objects into the pre-allocated local
141 // frame block at the moment.
142 return (StackId != TargetStackID::ScalableVector &&
143 StackId != TargetStackID::ScalablePredicateVector);
144 }
145
146 void
147 orderFrameObjects(const MachineFunction &MF,
148 SmallVectorImpl<int> &ObjectsToAllocate) const override;
149
150 bool isFPReserved(const MachineFunction &MF) const;
151
152 bool needsWinCFI(const MachineFunction &MF) const;
153
154 bool requiresSaveVG(const MachineFunction &MF) const;
155
156 /// Returns the size of the entire ZPR stackframe (calleesaves + spills).
157 StackOffset getZPRStackSize(const MachineFunction &MF) const;
158
159 /// Returns the size of the entire PPR stackframe (calleesaves + spills +
160 /// hazard padding).
161 StackOffset getPPRStackSize(const MachineFunction &MF) const;
162
163 /// Returns the size of the entire SVE stackframe (PPRs + ZPRs).
164 StackOffset getSVEStackSize(const MachineFunction &MF) const {
165 return getZPRStackSize(MF) + getPPRStackSize(MF);
166 }
167
168 friend class AArch64PrologueEpilogueCommon;
169 friend class AArch64PrologueEmitter;
170 friend class AArch64EpilogueEmitter;
171
172 // Windows unwind can't represent the required stack adjustments if we have
173 // both SVE callee-saves and dynamic stack allocations, and the frame
174 // pointer is before the SVE spills. The allocation of the frame pointer
175 // must be the last instruction in the prologue so the unwinder can restore
176 // the stack pointer correctly. (And there isn't any unwind opcode for
177 // `addvl sp, x29, -17`.)
178 //
179 // Because of this, we do spills in the opposite order on Windows: first SVE,
180 // then GPRs. The main side-effect of this is that it makes accessing
181 // parameters passed on the stack more expensive.
182 //
183 // We could consider rearranging the spills for simpler cases.
184 bool hasSVECalleeSavesAboveFrameRecord(const MachineFunction &MF) const;
185
186protected:
187 bool hasFPImpl(const MachineFunction &MF) const override;
188
189private:
190 /// Returns true if a homogeneous prolog or epilog code can be emitted
191 /// for the size optimization. If so, HOM_Prolog/HOM_Epilog pseudo
192 /// instructions are emitted in place. When Exit block is given, this check is
193 /// for epilog.
194 bool homogeneousPrologEpilog(MachineFunction &MF,
195 MachineBasicBlock *Exit = nullptr) const;
196
197 /// Returns true if CSRs should be paired.
198 bool producePairRegisters(MachineFunction &MF) const;
199
200 /// Make a determination whether a Hazard slot is used and create it if
201 /// needed.
202 void determineStackHazardSlot(MachineFunction &MF,
203 BitVector &SavedRegs) const;
204
205 /// Emit target zero call-used regs.
206 void emitZeroCallUsedRegs(BitVector RegsToZero,
207 MachineBasicBlock &MBB) const override;
208
209 /// Replace a StackProbe stub (if any) with the actual probe code inline
210 void inlineStackProbe(MachineFunction &MF,
211 MachineBasicBlock &PrologueMBB) const override;
212
213 void inlineStackProbeFixed(MachineBasicBlock::iterator MBBI,
214 Register ScratchReg, int64_t FrameSize,
215 StackOffset CFAOffset) const;
216
217 MachineBasicBlock::iterator
218 inlineStackProbeLoopExactMultiple(MachineBasicBlock::iterator MBBI,
219 int64_t NegProbeSize,
220 Register TargetReg) const;
221
222 void emitRemarks(const MachineFunction &MF,
223 MachineOptimizationRemarkEmitter *ORE) const override;
224
225 bool windowsRequiresStackProbe(const MachineFunction &MF,
226 uint64_t StackSizeInBytes) const;
227
228 bool shouldSignReturnAddressEverywhere(const MachineFunction &MF) const;
229
230 StackOffset getFPOffset(const MachineFunction &MF,
231 int64_t ObjectOffset) const;
232
233 StackOffset getStackOffset(const MachineFunction &MF,
234 int64_t ObjectOffset) const;
235
236 // Given a load or a store instruction, generate an appropriate unwinding SEH
237 // code on Windows.
238 MachineBasicBlock::iterator insertSEH(MachineBasicBlock::iterator MBBI,
239 const AArch64InstrInfo &TII,
240 MachineInstr::MIFlag Flag) const;
241
242 /// Returns how much of the incoming argument stack area (in bytes) we should
243 /// clean up in an epilogue. For the C calling convention this will be 0, for
244 /// guaranteed tail call conventions it can be positive (a normal return or a
245 /// tail call to a function that uses less stack space for arguments) or
246 /// negative (for a tail call to a function that needs more stack space than
247 /// us for arguments).
248 int64_t getArgumentStackToRestore(MachineFunction &MF,
249 MachineBasicBlock &MBB) 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