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 DPRCSOffset = 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 DPRCSAlignGapSize = 0; |
93 | unsigned DPRCSSize = 0; |
94 | |
95 | /// NumAlignedDPRCS2Regs - The number of callee-saved DPRs that are saved in |
96 | /// the aligned portion of the stack frame. This is always a contiguous |
97 | /// sequence of D-registers starting from d8. |
98 | /// |
99 | /// We do not keep track of the frame indices used for these registers - they |
100 | /// behave like any other frame index in the aligned stack frame. These |
101 | /// registers also aren't included in DPRCSSize above. |
102 | unsigned NumAlignedDPRCS2Regs = 0; |
103 | |
104 | unsigned PICLabelUId = 0; |
105 | |
106 | /// VarArgsFrameIndex - FrameIndex for start of varargs area. |
107 | int VarArgsFrameIndex = 0; |
108 | |
109 | /// HasITBlocks - True if IT blocks have been inserted. |
110 | bool HasITBlocks = false; |
111 | |
112 | // Security Extensions |
113 | bool IsCmseNSEntry; |
114 | bool IsCmseNSCall; |
115 | |
116 | /// CPEClones - Track constant pool entries clones created by Constant Island |
117 | /// pass. |
118 | DenseMap<unsigned, unsigned> CPEClones; |
119 | |
120 | /// ArgumentStackSize - amount of bytes on stack consumed by the arguments |
121 | /// being passed on the stack |
122 | unsigned ArgumentStackSize = 0; |
123 | |
124 | /// ArgumentStackToRestore - amount of bytes on stack consumed that we must |
125 | /// restore on return. |
126 | unsigned ArgumentStackToRestore = 0; |
127 | |
128 | /// CoalescedWeights - mapping of basic blocks to the rolling counter of |
129 | /// coalesced weights. |
130 | DenseMap<const MachineBasicBlock*, unsigned> CoalescedWeights; |
131 | |
132 | /// True if this function has a subset of CSRs that is handled explicitly via |
133 | /// copies. |
134 | bool IsSplitCSR = false; |
135 | |
136 | /// Globals that have had their storage promoted into the constant pool. |
137 | SmallPtrSet<const GlobalVariable*,2> PromotedGlobals; |
138 | |
139 | /// The amount the literal pool has been increasedby due to promoted globals. |
140 | int PromotedGlobalsIncrease = 0; |
141 | |
142 | /// True if r0 will be preserved by a call to this function (e.g. C++ |
143 | /// con/destructors). |
144 | bool PreservesR0 = false; |
145 | |
146 | /// True if the function should sign its return address. |
147 | bool SignReturnAddress = false; |
148 | |
149 | /// True if the fucntion should sign its return address, even if LR is not |
150 | /// saved. |
151 | bool SignReturnAddressAll = false; |
152 | |
153 | /// True if BTI instructions should be placed at potential indirect jump |
154 | /// destinations. |
155 | bool BranchTargetEnforcement = false; |
156 | |
157 | public: |
158 | ARMFunctionInfo() = default; |
159 | |
160 | explicit ARMFunctionInfo(const Function &F, const ARMSubtarget *STI); |
161 | |
162 | MachineFunctionInfo * |
163 | clone(BumpPtrAllocator &Allocator, MachineFunction &DestMF, |
164 | const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) |
165 | const override; |
166 | |
167 | bool isThumbFunction() const { return isThumb; } |
168 | bool isThumb1OnlyFunction() const { return isThumb && !hasThumb2; } |
169 | bool isThumb2Function() const { return isThumb && hasThumb2; } |
170 | |
171 | bool isCmseNSEntryFunction() const { return IsCmseNSEntry; } |
172 | bool isCmseNSCallFunction() const { return IsCmseNSCall; } |
173 | |
174 | unsigned getArgRegsSaveSize() const { return ArgRegsSaveSize; } |
175 | void setArgRegsSaveSize(unsigned s) { ArgRegsSaveSize = s; } |
176 | |
177 | unsigned getReturnRegsCount() const { return ReturnRegsCount; } |
178 | void setReturnRegsCount(unsigned s) { ReturnRegsCount = s; } |
179 | |
180 | bool hasStackFrame() const { return HasStackFrame; } |
181 | void setHasStackFrame(bool s) { HasStackFrame = s; } |
182 | |
183 | bool shouldRestoreSPFromFP() const { return RestoreSPFromFP; } |
184 | void setShouldRestoreSPFromFP(bool s) { RestoreSPFromFP = s; } |
185 | |
186 | bool isLRSpilled() const { return LRSpilled; } |
187 | void setLRIsSpilled(bool s) { LRSpilled = s; } |
188 | |
189 | unsigned getFramePtrSpillOffset() const { return FramePtrSpillOffset; } |
190 | void setFramePtrSpillOffset(unsigned o) { FramePtrSpillOffset = o; } |
191 | |
192 | unsigned getNumAlignedDPRCS2Regs() const { return NumAlignedDPRCS2Regs; } |
193 | void setNumAlignedDPRCS2Regs(unsigned n) { NumAlignedDPRCS2Regs = n; } |
194 | |
195 | unsigned getGPRCalleeSavedArea1Offset() const { return GPRCS1Offset; } |
196 | unsigned getGPRCalleeSavedArea2Offset() const { return GPRCS2Offset; } |
197 | unsigned getDPRCalleeSavedAreaOffset() const { return DPRCSOffset; } |
198 | |
199 | void setGPRCalleeSavedArea1Offset(unsigned o) { GPRCS1Offset = o; } |
200 | void setGPRCalleeSavedArea2Offset(unsigned o) { GPRCS2Offset = o; } |
201 | void setDPRCalleeSavedAreaOffset(unsigned o) { DPRCSOffset = o; } |
202 | |
203 | unsigned getFPCXTSaveAreaSize() const { return FPCXTSaveSize; } |
204 | unsigned getFrameRecordSavedAreaSize() const { return FRSaveSize; } |
205 | unsigned getGPRCalleeSavedArea1Size() const { return GPRCS1Size; } |
206 | unsigned getGPRCalleeSavedArea2Size() const { return GPRCS2Size; } |
207 | unsigned getDPRCalleeSavedGapSize() const { return DPRCSAlignGapSize; } |
208 | unsigned getDPRCalleeSavedAreaSize() const { return DPRCSSize; } |
209 | |
210 | void setFPCXTSaveAreaSize(unsigned s) { FPCXTSaveSize = s; } |
211 | void setFrameRecordSavedAreaSize(unsigned s) { FRSaveSize = s; } |
212 | void setGPRCalleeSavedArea1Size(unsigned s) { GPRCS1Size = s; } |
213 | void setGPRCalleeSavedArea2Size(unsigned s) { GPRCS2Size = s; } |
214 | void setDPRCalleeSavedGapSize(unsigned s) { DPRCSAlignGapSize = s; } |
215 | void setDPRCalleeSavedAreaSize(unsigned s) { DPRCSSize = s; } |
216 | |
217 | unsigned getArgumentStackSize() const { return ArgumentStackSize; } |
218 | void setArgumentStackSize(unsigned size) { ArgumentStackSize = size; } |
219 | |
220 | unsigned getArgumentStackToRestore() const { return ArgumentStackToRestore; } |
221 | void setArgumentStackToRestore(unsigned v) { ArgumentStackToRestore = v; } |
222 | |
223 | void initPICLabelUId(unsigned UId) { |
224 | PICLabelUId = UId; |
225 | } |
226 | |
227 | unsigned getNumPICLabels() const { |
228 | return PICLabelUId; |
229 | } |
230 | |
231 | unsigned createPICLabelUId() { |
232 | return PICLabelUId++; |
233 | } |
234 | |
235 | int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } |
236 | void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } |
237 | |
238 | bool hasITBlocks() const { return HasITBlocks; } |
239 | void setHasITBlocks(bool h) { HasITBlocks = h; } |
240 | |
241 | bool isSplitCSR() const { return IsSplitCSR; } |
242 | void setIsSplitCSR(bool s) { IsSplitCSR = s; } |
243 | |
244 | void recordCPEClone(unsigned CPIdx, unsigned CPCloneIdx) { |
245 | if (!CPEClones.insert(KV: std::make_pair(x&: CPCloneIdx, y&: CPIdx)).second) |
246 | llvm_unreachable("Duplicate entries!" ); |
247 | } |
248 | |
249 | unsigned getOriginalCPIdx(unsigned CloneIdx) const { |
250 | DenseMap<unsigned, unsigned>::const_iterator I = CPEClones.find(Val: CloneIdx); |
251 | if (I != CPEClones.end()) |
252 | return I->second; |
253 | else |
254 | return -1U; |
255 | } |
256 | |
257 | DenseMap<const MachineBasicBlock*, unsigned>::iterator getCoalescedWeight( |
258 | MachineBasicBlock* MBB) { |
259 | auto It = CoalescedWeights.find(Val: MBB); |
260 | if (It == CoalescedWeights.end()) { |
261 | It = CoalescedWeights.insert(KV: std::make_pair(x&: MBB, y: 0)).first; |
262 | } |
263 | return It; |
264 | } |
265 | |
266 | /// Indicate to the backend that \c GV has had its storage changed to inside |
267 | /// a constant pool. This means it no longer needs to be emitted as a |
268 | /// global variable. |
269 | void markGlobalAsPromotedToConstantPool(const GlobalVariable *GV) { |
270 | PromotedGlobals.insert(Ptr: GV); |
271 | } |
272 | SmallPtrSet<const GlobalVariable*, 2>& getGlobalsPromotedToConstantPool() { |
273 | return PromotedGlobals; |
274 | } |
275 | int getPromotedConstpoolIncrease() const { |
276 | return PromotedGlobalsIncrease; |
277 | } |
278 | void setPromotedConstpoolIncrease(int Sz) { |
279 | PromotedGlobalsIncrease = Sz; |
280 | } |
281 | |
282 | DenseMap<unsigned, unsigned> EHPrologueRemappedRegs; |
283 | DenseMap<unsigned, unsigned> EHPrologueOffsetInRegs; |
284 | |
285 | void setPreservesR0() { PreservesR0 = true; } |
286 | bool getPreservesR0() const { return PreservesR0; } |
287 | |
288 | bool shouldSignReturnAddress() const { |
289 | return shouldSignReturnAddress(SpillsLR: LRSpilled); |
290 | } |
291 | |
292 | bool shouldSignReturnAddress(bool SpillsLR) const { |
293 | if (!SignReturnAddress) |
294 | return false; |
295 | if (SignReturnAddressAll) |
296 | return true; |
297 | return SpillsLR; |
298 | } |
299 | |
300 | bool branchTargetEnforcement() const { return BranchTargetEnforcement; } |
301 | |
302 | void initializeBaseYamlFields(const yaml::ARMFunctionInfo &YamlMFI); |
303 | }; |
304 | |
305 | namespace yaml { |
306 | struct ARMFunctionInfo final : public yaml::MachineFunctionInfo { |
307 | bool LRSpilled; |
308 | |
309 | ARMFunctionInfo() = default; |
310 | ARMFunctionInfo(const llvm::ARMFunctionInfo &MFI); |
311 | |
312 | void mappingImpl(yaml::IO &YamlIO) override; |
313 | ~ARMFunctionInfo() = default; |
314 | }; |
315 | |
316 | template <> struct MappingTraits<ARMFunctionInfo> { |
317 | static void mapping(IO &YamlIO, ARMFunctionInfo &MFI) { |
318 | YamlIO.mapOptional(Key: "isLRSpilled" , Val&: MFI.LRSpilled); |
319 | } |
320 | }; |
321 | |
322 | } // end namespace yaml |
323 | |
324 | } // end namespace llvm |
325 | |
326 | #endif // LLVM_LIB_TARGET_ARM_ARMMACHINEFUNCTIONINFO_H |
327 | |