1 | //===-- ARMMachineFunctionInfo.h - ARM machine function info ----*- 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 | // This file declares ARM-specific per-machine-function information. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_LIB_TARGET_ARM_ARMMACHINEFUNCTIONINFO_H |
14 | #define LLVM_LIB_TARGET_ARM_ARMMACHINEFUNCTIONINFO_H |
15 | |
16 | #include "llvm/ADT/DenseMap.h" |
17 | #include "llvm/ADT/SmallPtrSet.h" |
18 | #include "llvm/CodeGen/MIRYamlMapping.h" |
19 | #include "llvm/CodeGen/MachineFunction.h" |
20 | #include "llvm/IR/GlobalVariable.h" |
21 | #include "llvm/Support/ErrorHandling.h" |
22 | #include <utility> |
23 | |
24 | namespace llvm { |
25 | |
26 | namespace yaml { |
27 | struct ARMFunctionInfo; |
28 | } // end namespace yaml |
29 | |
30 | class ARMSubtarget; |
31 | |
32 | /// ARMFunctionInfo - This class is derived from MachineFunctionInfo and |
33 | /// contains private ARM-specific information for each MachineFunction. |
34 | class ARMFunctionInfo : public MachineFunctionInfo { |
35 | virtual void anchor(); |
36 | |
37 | /// isThumb - True if this function is compiled under Thumb mode. |
38 | /// Used to initialized Align, so must precede it. |
39 | bool isThumb = false; |
40 | |
41 | /// hasThumb2 - True if the target architecture supports Thumb2. Do not use |
42 | /// to determine if function is compiled under Thumb mode, for that use |
43 | /// 'isThumb'. |
44 | bool hasThumb2 = false; |
45 | |
46 | /// ArgsRegSaveSize - Size of the register save area for vararg functions or |
47 | /// those making guaranteed tail calls that need more stack argument space |
48 | /// than is provided by this functions incoming parameters. |
49 | /// |
50 | unsigned ArgRegsSaveSize = 0; |
51 | |
52 | /// ReturnRegsCount - Number of registers used up in the return. |
53 | unsigned ReturnRegsCount = 0; |
54 | |
55 | /// HasStackFrame - True if this function has a stack frame. Set by |
56 | /// determineCalleeSaves(). |
57 | bool HasStackFrame = false; |
58 | |
59 | /// RestoreSPFromFP - True if epilogue should restore SP from FP. Set by |
60 | /// emitPrologue. |
61 | bool RestoreSPFromFP = false; |
62 | |
63 | /// LRSpilled - True if the LR register has been for spilled for |
64 | /// any reason, so it's legal to emit an ARM::tBfar (i.e. "bl"). |
65 | bool LRSpilled = false; |
66 | |
67 | /// FramePtrSpillOffset - If HasStackFrame, this records the frame pointer |
68 | /// spill stack offset. |
69 | unsigned FramePtrSpillOffset = 0; |
70 | |
71 | /// GPRCS1Offset, GPRCS2Offset, DPRCSOffset - Starting offset of callee saved |
72 | /// register spills areas. For Mac OS X: |
73 | /// |
74 | /// GPR callee-saved (1) : r4, r5, r6, r7, lr |
75 | /// -------------------------------------------- |
76 | /// GPR callee-saved (2) : r8, r10, r11 |
77 | /// -------------------------------------------- |
78 | /// DPR callee-saved : d8 - d15 |
79 | /// |
80 | /// Also see AlignedDPRCSRegs below. Not all D-regs need to go in area 3. |
81 | /// Some may be spilled after the stack has been realigned. |
82 | unsigned GPRCS1Offset = 0; |
83 | unsigned GPRCS2Offset = 0; |
84 | unsigned DPRCS1Offset = 0; |
85 | |
86 | /// GPRCS1Size, GPRCS2Size, DPRCSSize - Sizes of callee saved register spills |
87 | /// areas. |
88 | unsigned FPCXTSaveSize = 0; |
89 | unsigned FRSaveSize = 0; |
90 | unsigned GPRCS1Size = 0; |
91 | unsigned GPRCS2Size = 0; |
92 | unsigned FPStatusSize = 0; |
93 | unsigned DPRCSAlignGapSize = 0; |
94 | unsigned DPRCS1Size = 0; |
95 | unsigned GPRCS3Size = 0; |
96 | |
97 | /// NumAlignedDPRCS2Regs - The number of callee-saved DPRs that are saved in |
98 | /// the aligned portion of the stack frame. This is always a contiguous |
99 | /// sequence of D-registers starting from d8. |
100 | /// |
101 | /// We do not keep track of the frame indices used for these registers - they |
102 | /// behave like any other frame index in the aligned stack frame. These |
103 | /// registers also aren't included in DPRCSSize above. |
104 | unsigned NumAlignedDPRCS2Regs = 0; |
105 | |
106 | unsigned PICLabelUId = 0; |
107 | |
108 | /// VarArgsFrameIndex - FrameIndex for start of varargs area. |
109 | int VarArgsFrameIndex = 0; |
110 | |
111 | /// HasITBlocks - True if IT blocks have been inserted. |
112 | bool HasITBlocks = false; |
113 | |
114 | // Security Extensions |
115 | bool IsCmseNSEntry; |
116 | bool IsCmseNSCall; |
117 | |
118 | /// CPEClones - Track constant pool entries clones created by Constant Island |
119 | /// pass. |
120 | DenseMap<unsigned, unsigned> CPEClones; |
121 | |
122 | /// ArgumentStackSize - amount of bytes on stack consumed by the arguments |
123 | /// being passed on the stack |
124 | unsigned ArgumentStackSize = 0; |
125 | |
126 | /// ArgumentStackToRestore - amount of bytes on stack consumed that we must |
127 | /// restore on return. |
128 | unsigned ArgumentStackToRestore = 0; |
129 | |
130 | /// CoalescedWeights - mapping of basic blocks to the rolling counter of |
131 | /// coalesced weights. |
132 | DenseMap<const MachineBasicBlock*, unsigned> CoalescedWeights; |
133 | |
134 | /// True if this function has a subset of CSRs that is handled explicitly via |
135 | /// copies. |
136 | bool IsSplitCSR = false; |
137 | |
138 | /// Globals that have had their storage promoted into the constant pool. |
139 | SmallPtrSet<const GlobalVariable*,2> PromotedGlobals; |
140 | |
141 | /// The amount the literal pool has been increasedby due to promoted globals. |
142 | int PromotedGlobalsIncrease = 0; |
143 | |
144 | /// True if r0 will be preserved by a call to this function (e.g. C++ |
145 | /// con/destructors). |
146 | bool PreservesR0 = false; |
147 | |
148 | /// True if the function should sign its return address. |
149 | bool SignReturnAddress = false; |
150 | |
151 | /// True if the fucntion should sign its return address, even if LR is not |
152 | /// saved. |
153 | bool SignReturnAddressAll = false; |
154 | |
155 | /// True if BTI instructions should be placed at potential indirect jump |
156 | /// destinations. |
157 | bool BranchTargetEnforcement = false; |
158 | |
159 | public: |
160 | ARMFunctionInfo() = default; |
161 | |
162 | explicit ARMFunctionInfo(const Function &F, const ARMSubtarget *STI); |
163 | |
164 | MachineFunctionInfo * |
165 | clone(BumpPtrAllocator &Allocator, MachineFunction &DestMF, |
166 | const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) |
167 | const override; |
168 | |
169 | bool isThumbFunction() const { return isThumb; } |
170 | bool isThumb1OnlyFunction() const { return isThumb && !hasThumb2; } |
171 | bool isThumb2Function() const { return isThumb && hasThumb2; } |
172 | |
173 | bool isCmseNSEntryFunction() const { return IsCmseNSEntry; } |
174 | bool isCmseNSCallFunction() const { return IsCmseNSCall; } |
175 | |
176 | unsigned getArgRegsSaveSize() const { return ArgRegsSaveSize; } |
177 | void setArgRegsSaveSize(unsigned s) { ArgRegsSaveSize = s; } |
178 | |
179 | unsigned getReturnRegsCount() const { return ReturnRegsCount; } |
180 | void setReturnRegsCount(unsigned s) { ReturnRegsCount = s; } |
181 | |
182 | bool hasStackFrame() const { return HasStackFrame; } |
183 | void setHasStackFrame(bool s) { HasStackFrame = s; } |
184 | |
185 | bool shouldRestoreSPFromFP() const { return RestoreSPFromFP; } |
186 | void setShouldRestoreSPFromFP(bool s) { RestoreSPFromFP = s; } |
187 | |
188 | bool isLRSpilled() const { return LRSpilled; } |
189 | void setLRIsSpilled(bool s) { LRSpilled = s; } |
190 | |
191 | unsigned getFramePtrSpillOffset() const { return FramePtrSpillOffset; } |
192 | void setFramePtrSpillOffset(unsigned o) { FramePtrSpillOffset = o; } |
193 | |
194 | unsigned getNumAlignedDPRCS2Regs() const { return NumAlignedDPRCS2Regs; } |
195 | void setNumAlignedDPRCS2Regs(unsigned n) { NumAlignedDPRCS2Regs = n; } |
196 | |
197 | unsigned getGPRCalleeSavedArea1Offset() const { return GPRCS1Offset; } |
198 | unsigned getGPRCalleeSavedArea2Offset() const { return GPRCS2Offset; } |
199 | unsigned getDPRCalleeSavedArea1Offset() const { return DPRCS1Offset; } |
200 | |
201 | void setGPRCalleeSavedArea1Offset(unsigned o) { GPRCS1Offset = o; } |
202 | void setGPRCalleeSavedArea2Offset(unsigned o) { GPRCS2Offset = o; } |
203 | void setDPRCalleeSavedArea1Offset(unsigned o) { DPRCS1Offset = o; } |
204 | |
205 | unsigned getFPCXTSaveAreaSize() const { return FPCXTSaveSize; } |
206 | unsigned getFrameRecordSavedAreaSize() const { return FRSaveSize; } |
207 | unsigned getGPRCalleeSavedArea1Size() const { return GPRCS1Size; } |
208 | unsigned getGPRCalleeSavedArea2Size() const { return GPRCS2Size; } |
209 | unsigned getFPStatusSavesSize() const { return FPStatusSize; } |
210 | unsigned getDPRCalleeSavedGapSize() const { return DPRCSAlignGapSize; } |
211 | unsigned getDPRCalleeSavedArea1Size() const { return DPRCS1Size; } |
212 | unsigned getGPRCalleeSavedArea3Size() const { return GPRCS3Size; } |
213 | |
214 | void setFPCXTSaveAreaSize(unsigned s) { FPCXTSaveSize = s; } |
215 | void setFrameRecordSavedAreaSize(unsigned s) { FRSaveSize = s; } |
216 | void setGPRCalleeSavedArea1Size(unsigned s) { GPRCS1Size = s; } |
217 | void setGPRCalleeSavedArea2Size(unsigned s) { GPRCS2Size = s; } |
218 | void setFPStatusSavesSize(unsigned s) { FPStatusSize = s; } |
219 | void setDPRCalleeSavedGapSize(unsigned s) { DPRCSAlignGapSize = s; } |
220 | void setDPRCalleeSavedArea1Size(unsigned s) { DPRCS1Size = s; } |
221 | void setGPRCalleeSavedArea3Size(unsigned s) { GPRCS3Size = s; } |
222 | |
223 | unsigned getArgumentStackSize() const { return ArgumentStackSize; } |
224 | void setArgumentStackSize(unsigned size) { ArgumentStackSize = size; } |
225 | |
226 | unsigned getArgumentStackToRestore() const { return ArgumentStackToRestore; } |
227 | void setArgumentStackToRestore(unsigned v) { ArgumentStackToRestore = v; } |
228 | |
229 | void initPICLabelUId(unsigned UId) { |
230 | PICLabelUId = UId; |
231 | } |
232 | |
233 | unsigned getNumPICLabels() const { |
234 | return PICLabelUId; |
235 | } |
236 | |
237 | unsigned createPICLabelUId() { |
238 | return PICLabelUId++; |
239 | } |
240 | |
241 | int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } |
242 | void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } |
243 | |
244 | bool hasITBlocks() const { return HasITBlocks; } |
245 | void setHasITBlocks(bool h) { HasITBlocks = h; } |
246 | |
247 | bool isSplitCSR() const { return IsSplitCSR; } |
248 | void setIsSplitCSR(bool s) { IsSplitCSR = s; } |
249 | |
250 | void recordCPEClone(unsigned CPIdx, unsigned CPCloneIdx) { |
251 | if (!CPEClones.insert(KV: std::make_pair(x&: CPCloneIdx, y&: CPIdx)).second) |
252 | llvm_unreachable("Duplicate entries!" ); |
253 | } |
254 | |
255 | unsigned getOriginalCPIdx(unsigned CloneIdx) const { |
256 | DenseMap<unsigned, unsigned>::const_iterator I = CPEClones.find(Val: CloneIdx); |
257 | if (I != CPEClones.end()) |
258 | return I->second; |
259 | else |
260 | return -1U; |
261 | } |
262 | |
263 | DenseMap<const MachineBasicBlock *, unsigned>::iterator |
264 | getCoalescedWeight(MachineBasicBlock *MBB) { |
265 | return CoalescedWeights.try_emplace(Key: MBB, Args: 0).first; |
266 | } |
267 | |
268 | /// Indicate to the backend that \c GV has had its storage changed to inside |
269 | /// a constant pool. This means it no longer needs to be emitted as a |
270 | /// global variable. |
271 | void markGlobalAsPromotedToConstantPool(const GlobalVariable *GV) { |
272 | PromotedGlobals.insert(Ptr: GV); |
273 | } |
274 | SmallPtrSet<const GlobalVariable*, 2>& getGlobalsPromotedToConstantPool() { |
275 | return PromotedGlobals; |
276 | } |
277 | int getPromotedConstpoolIncrease() const { |
278 | return PromotedGlobalsIncrease; |
279 | } |
280 | void setPromotedConstpoolIncrease(int Sz) { |
281 | PromotedGlobalsIncrease = Sz; |
282 | } |
283 | |
284 | DenseMap<unsigned, unsigned> EHPrologueRemappedRegs; |
285 | DenseMap<unsigned, unsigned> EHPrologueOffsetInRegs; |
286 | |
287 | void setPreservesR0() { PreservesR0 = true; } |
288 | bool getPreservesR0() const { return PreservesR0; } |
289 | |
290 | bool shouldSignReturnAddress() const { |
291 | return shouldSignReturnAddress(SpillsLR: LRSpilled); |
292 | } |
293 | |
294 | bool shouldSignReturnAddress(bool SpillsLR) const { |
295 | if (!SignReturnAddress) |
296 | return false; |
297 | if (SignReturnAddressAll) |
298 | return true; |
299 | return SpillsLR; |
300 | } |
301 | |
302 | bool branchTargetEnforcement() const { return BranchTargetEnforcement; } |
303 | |
304 | void initializeBaseYamlFields(const yaml::ARMFunctionInfo &YamlMFI); |
305 | }; |
306 | |
307 | namespace yaml { |
308 | struct ARMFunctionInfo final : public yaml::MachineFunctionInfo { |
309 | bool LRSpilled; |
310 | |
311 | ARMFunctionInfo() = default; |
312 | ARMFunctionInfo(const llvm::ARMFunctionInfo &MFI); |
313 | |
314 | void mappingImpl(yaml::IO &YamlIO) override; |
315 | ~ARMFunctionInfo() = default; |
316 | }; |
317 | |
318 | template <> struct MappingTraits<ARMFunctionInfo> { |
319 | static void mapping(IO &YamlIO, ARMFunctionInfo &MFI) { |
320 | YamlIO.mapOptional(Key: "isLRSpilled" , Val&: MFI.LRSpilled); |
321 | } |
322 | }; |
323 | |
324 | } // end namespace yaml |
325 | |
326 | } // end namespace llvm |
327 | |
328 | #endif // LLVM_LIB_TARGET_ARM_ARMMACHINEFUNCTIONINFO_H |
329 | |