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 requiresSaveVG(const MachineFunction &MF) const;
162
163 /// Returns the size of the entire ZPR stackframe (calleesaves + spills).
164 StackOffset getZPRStackSize(const MachineFunction &MF) const;
165
166 /// Returns the size of the entire PPR stackframe (calleesaves + spills +
167 /// hazard padding).
168 StackOffset getPPRStackSize(const MachineFunction &MF) const;
169
170 /// Returns the size of the entire SVE stackframe (PPRs + ZPRs).
171 StackOffset getSVEStackSize(const MachineFunction &MF) const {
172 return getZPRStackSize(MF) + getPPRStackSize(MF);
173 }
174
175 friend class AArch64PrologueEpilogueCommon;
176 friend class AArch64PrologueEmitter;
177 friend class AArch64EpilogueEmitter;
178
179 // Windows unwind can't represent the required stack adjustments if we have
180 // both SVE callee-saves and dynamic stack allocations, and the frame
181 // pointer is before the SVE spills. The allocation of the frame pointer
182 // must be the last instruction in the prologue so the unwinder can restore
183 // the stack pointer correctly. (And there isn't any unwind opcode for
184 // `addvl sp, x29, -17`.)
185 //
186 // Because of this, we do spills in the opposite order on Windows: first SVE,
187 // then GPRs. The main side-effect of this is that it makes accessing
188 // parameters passed on the stack more expensive.
189 //
190 // We could consider rearranging the spills for simpler cases.
191 bool hasSVECalleeSavesAboveFrameRecord(const MachineFunction &MF) const;
192
193protected:
194 bool hasFPImpl(const MachineFunction &MF) const override;
195
196private:
197 /// Returns true if a homogeneous prolog or epilog code can be emitted
198 /// for the size optimization. If so, HOM_Prolog/HOM_Epilog pseudo
199 /// instructions are emitted in place. When Exit block is given, this check is
200 /// for epilog.
201 bool homogeneousPrologEpilog(MachineFunction &MF,
202 MachineBasicBlock *Exit = nullptr) const;
203
204 /// Returns true if CSRs should be paired.
205 bool producePairRegisters(MachineFunction &MF) const;
206
207 /// Make a determination whether a Hazard slot is used and create it if
208 /// needed.
209 void determineStackHazardSlot(MachineFunction &MF,
210 BitVector &SavedRegs) const;
211
212 /// Emit target zero call-used regs.
213 void emitZeroCallUsedRegs(BitVector RegsToZero, MachineBasicBlock &MBB,
214 RegScavenger *RS) const override;
215
216 /// Replace a StackProbe stub (if any) with the actual probe code inline
217 void inlineStackProbe(MachineFunction &MF,
218 MachineBasicBlock &PrologueMBB) const override;
219
220 void inlineStackProbeFixed(MachineBasicBlock::iterator MBBI,
221 Register ScratchReg, int64_t FrameSize,
222 StackOffset CFAOffset) const;
223
224 MachineBasicBlock::iterator
225 inlineStackProbeLoopExactMultiple(MachineBasicBlock::iterator MBBI,
226 int64_t NegProbeSize,
227 Register TargetReg) const;
228
229 void emitRemarks(const MachineFunction &MF,
230 MachineOptimizationRemarkEmitter *ORE) const override;
231
232 bool windowsRequiresStackProbe(const MachineFunction &MF,
233 uint64_t StackSizeInBytes) const;
234
235 bool shouldSignReturnAddressEverywhere(const MachineFunction &MF) const;
236
237 StackOffset getFPOffset(const MachineFunction &MF,
238 int64_t ObjectOffset) const;
239
240 StackOffset getStackOffset(const MachineFunction &MF,
241 int64_t ObjectOffset) const;
242
243 // Given a load or a store instruction, generate an appropriate unwinding SEH
244 // code on Windows.
245 MachineBasicBlock::iterator insertSEH(MachineBasicBlock::iterator MBBI,
246 const AArch64InstrInfo &TII,
247 MachineInstr::MIFlag Flag) const;
248
249 // Find a scratch register that we can use at the start of the prologue to
250 // re-align the stack pointer. We avoid using callee-save registers since
251 // they may appear to be free when this is called from canUseAsPrologue
252 // (during shrink wrapping), but then no longer be free when this is called
253 // from emitPrologue.
254 //
255 // FIXME: This is a bit conservative, since in the above case we could use one
256 // of the callee-save registers as a scratch temp to re-align the stack
257 // pointer, but we would then have to make sure that we were in fact saving at
258 // least one callee-save register in the prologue, which is additional
259 // complexity that doesn't seem worth the benefit.
260 Register findScratchNonCalleeSaveRegister(MachineBasicBlock *MBB,
261 bool HasCall = false) const;
262
263 /// Returns the size of the fixed object area (allocated next to sp on entry)
264 /// On Win64 this may include a var args area and an UnwindHelp object for EH.
265 unsigned getFixedObjectSize(const MachineFunction &MF,
266 const AArch64FunctionInfo *AFI, bool IsWin64,
267 bool IsFunclet) const;
268};
269
270} // End llvm namespace
271
272#endif
273