1 | //=- RISCVMachineFunctionInfo.h - RISC-V 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 RISCV-specific per-machine-function information. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_LIB_TARGET_RISCV_RISCVMACHINEFUNCTIONINFO_H |
14 | #define LLVM_LIB_TARGET_RISCV_RISCVMACHINEFUNCTIONINFO_H |
15 | |
16 | #include "RISCVSubtarget.h" |
17 | #include "llvm/CodeGen/MIRYamlMapping.h" |
18 | #include "llvm/CodeGen/MachineFrameInfo.h" |
19 | #include "llvm/CodeGen/MachineFunction.h" |
20 | |
21 | namespace llvm { |
22 | |
23 | class RISCVMachineFunctionInfo; |
24 | |
25 | namespace yaml { |
26 | struct RISCVMachineFunctionInfo final : public yaml::MachineFunctionInfo { |
27 | int VarArgsFrameIndex; |
28 | int VarArgsSaveSize; |
29 | |
30 | RISCVMachineFunctionInfo() = default; |
31 | RISCVMachineFunctionInfo(const llvm::RISCVMachineFunctionInfo &MFI); |
32 | |
33 | void mappingImpl(yaml::IO &YamlIO) override; |
34 | ~RISCVMachineFunctionInfo() = default; |
35 | }; |
36 | |
37 | template <> struct MappingTraits<RISCVMachineFunctionInfo> { |
38 | static void mapping(IO &YamlIO, RISCVMachineFunctionInfo &MFI) { |
39 | YamlIO.mapOptional(Key: "varArgsFrameIndex" , Val&: MFI.VarArgsFrameIndex); |
40 | YamlIO.mapOptional(Key: "varArgsSaveSize" , Val&: MFI.VarArgsSaveSize); |
41 | } |
42 | }; |
43 | } // end namespace yaml |
44 | |
45 | /// RISCVMachineFunctionInfo - This class is derived from MachineFunctionInfo |
46 | /// and contains private RISCV-specific information for each MachineFunction. |
47 | class RISCVMachineFunctionInfo : public MachineFunctionInfo { |
48 | private: |
49 | /// FrameIndex for start of varargs area |
50 | int VarArgsFrameIndex = 0; |
51 | /// Size of the save area used for varargs |
52 | int VarArgsSaveSize = 0; |
53 | /// FrameIndex used for transferring values between 64-bit FPRs and a pair |
54 | /// of 32-bit GPRs via the stack. |
55 | int MoveF64FrameIndex = -1; |
56 | /// FrameIndex of the spill slot for the scratch register in BranchRelaxation. |
57 | int BranchRelaxationScratchFrameIndex = -1; |
58 | /// Size of any opaque stack adjustment due to save/restore libcalls. |
59 | unsigned LibCallStackSize = 0; |
60 | /// Size of RVV stack. |
61 | uint64_t RVVStackSize = 0; |
62 | /// Alignment of RVV stack. |
63 | Align RVVStackAlign; |
64 | /// Padding required to keep RVV stack aligned within the main stack. |
65 | uint64_t RVVPadding = 0; |
66 | /// Size of stack frame to save callee saved registers |
67 | unsigned CalleeSavedStackSize = 0; |
68 | /// Is there any vector argument or return? |
69 | bool IsVectorCall = false; |
70 | |
71 | /// Registers that have been sign extended from i32. |
72 | SmallVector<Register, 8> SExt32Registers; |
73 | |
74 | /// Size of stack frame for Zcmp PUSH/POP |
75 | unsigned RVPushStackSize = 0; |
76 | unsigned RVPushRegs = 0; |
77 | |
78 | /// Size of any opaque stack adjustment due to QCI Interrupt instructions. |
79 | unsigned QCIInterruptStackSize = 0; |
80 | |
81 | /// Store Frame Indexes for Interrupt-Related CSR Spills. |
82 | SmallVector<int, 2> InterruptCSRFrameIndexes; |
83 | |
84 | int64_t StackProbeSize = 0; |
85 | |
86 | /// Does it probe the stack for a dynamic allocation? |
87 | bool HasDynamicAllocation = false; |
88 | |
89 | public: |
90 | RISCVMachineFunctionInfo(const Function &F, const RISCVSubtarget *STI); |
91 | |
92 | MachineFunctionInfo * |
93 | clone(BumpPtrAllocator &Allocator, MachineFunction &DestMF, |
94 | const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) |
95 | const override; |
96 | |
97 | int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } |
98 | void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } |
99 | |
100 | unsigned getVarArgsSaveSize() const { return VarArgsSaveSize; } |
101 | void setVarArgsSaveSize(int Size) { VarArgsSaveSize = Size; } |
102 | |
103 | int getMoveF64FrameIndex(MachineFunction &MF) { |
104 | if (MoveF64FrameIndex == -1) |
105 | MoveF64FrameIndex = |
106 | MF.getFrameInfo().CreateStackObject(Size: 8, Alignment: Align(8), isSpillSlot: false); |
107 | return MoveF64FrameIndex; |
108 | } |
109 | |
110 | int getBranchRelaxationScratchFrameIndex() const { |
111 | return BranchRelaxationScratchFrameIndex; |
112 | } |
113 | void setBranchRelaxationScratchFrameIndex(int Index) { |
114 | BranchRelaxationScratchFrameIndex = Index; |
115 | } |
116 | |
117 | unsigned getReservedSpillsSize() const { |
118 | return LibCallStackSize + RVPushStackSize + QCIInterruptStackSize; |
119 | } |
120 | |
121 | unsigned getLibCallStackSize() const { return LibCallStackSize; } |
122 | void setLibCallStackSize(unsigned Size) { LibCallStackSize = Size; } |
123 | |
124 | bool useSaveRestoreLibCalls(const MachineFunction &MF) const { |
125 | // We cannot use fixed locations for the callee saved spill slots if the |
126 | // function uses a varargs save area, or is an interrupt handler. |
127 | return !isPushable(MF) && |
128 | MF.getSubtarget<RISCVSubtarget>().enableSaveRestore() && |
129 | VarArgsSaveSize == 0 && !MF.getFrameInfo().hasTailCall() && |
130 | !MF.getFunction().hasFnAttribute(Kind: "interrupt" ); |
131 | } |
132 | |
133 | uint64_t getRVVStackSize() const { return RVVStackSize; } |
134 | void setRVVStackSize(uint64_t Size) { RVVStackSize = Size; } |
135 | |
136 | Align getRVVStackAlign() const { return RVVStackAlign; } |
137 | void setRVVStackAlign(Align StackAlign) { RVVStackAlign = StackAlign; } |
138 | |
139 | uint64_t getRVVPadding() const { return RVVPadding; } |
140 | void setRVVPadding(uint64_t Padding) { RVVPadding = Padding; } |
141 | |
142 | unsigned getCalleeSavedStackSize() const { return CalleeSavedStackSize; } |
143 | void setCalleeSavedStackSize(unsigned Size) { CalleeSavedStackSize = Size; } |
144 | |
145 | enum class PushPopKind { None = 0, StdExtZcmp, VendorXqccmp }; |
146 | |
147 | PushPopKind getPushPopKind(const MachineFunction &MF) const; |
148 | |
149 | bool isPushable(const MachineFunction &MF) const { |
150 | return getPushPopKind(MF) != PushPopKind::None; |
151 | } |
152 | |
153 | unsigned getRVPushRegs() const { return RVPushRegs; } |
154 | void setRVPushRegs(unsigned Regs) { RVPushRegs = Regs; } |
155 | |
156 | unsigned getRVPushStackSize() const { return RVPushStackSize; } |
157 | void setRVPushStackSize(unsigned Size) { RVPushStackSize = Size; } |
158 | |
159 | enum class InterruptStackKind { |
160 | None = 0, |
161 | QCINest, |
162 | QCINoNest, |
163 | SiFiveCLICPreemptible, |
164 | SiFiveCLICStackSwap, |
165 | SiFiveCLICPreemptibleStackSwap |
166 | }; |
167 | |
168 | InterruptStackKind getInterruptStackKind(const MachineFunction &MF) const; |
169 | |
170 | bool useQCIInterrupt(const MachineFunction &MF) const { |
171 | InterruptStackKind Kind = getInterruptStackKind(MF); |
172 | return Kind == InterruptStackKind::QCINest || |
173 | Kind == InterruptStackKind::QCINoNest; |
174 | } |
175 | |
176 | unsigned getQCIInterruptStackSize() const { return QCIInterruptStackSize; } |
177 | void setQCIInterruptStackSize(unsigned Size) { QCIInterruptStackSize = Size; } |
178 | |
179 | bool useSiFiveInterrupt(const MachineFunction &MF) const { |
180 | InterruptStackKind Kind = getInterruptStackKind(MF); |
181 | return Kind == InterruptStackKind::SiFiveCLICPreemptible || |
182 | Kind == InterruptStackKind::SiFiveCLICStackSwap || |
183 | Kind == InterruptStackKind::SiFiveCLICPreemptibleStackSwap; |
184 | } |
185 | |
186 | bool isSiFivePreemptibleInterrupt(const MachineFunction &MF) const { |
187 | InterruptStackKind Kind = getInterruptStackKind(MF); |
188 | return Kind == InterruptStackKind::SiFiveCLICPreemptible || |
189 | Kind == InterruptStackKind::SiFiveCLICPreemptibleStackSwap; |
190 | } |
191 | |
192 | bool isSiFiveStackSwapInterrupt(const MachineFunction &MF) const { |
193 | InterruptStackKind Kind = getInterruptStackKind(MF); |
194 | return Kind == InterruptStackKind::SiFiveCLICStackSwap || |
195 | Kind == InterruptStackKind::SiFiveCLICPreemptibleStackSwap; |
196 | } |
197 | |
198 | void pushInterruptCSRFrameIndex(int FI) { |
199 | InterruptCSRFrameIndexes.push_back(Elt: FI); |
200 | } |
201 | int getInterruptCSRFrameIndex(size_t Idx) const { |
202 | return InterruptCSRFrameIndexes[Idx]; |
203 | } |
204 | |
205 | // Some Stack Management Variants automatically update FP in a frame-pointer |
206 | // convention compatible way - which means we don't need to manually update |
207 | // the FP, but we still need to emit the correct CFI information for |
208 | // calculating the CFA based on FP. |
209 | bool hasImplicitFPUpdates(const MachineFunction &MF) const; |
210 | |
211 | void initializeBaseYamlFields(const yaml::RISCVMachineFunctionInfo &YamlMFI); |
212 | |
213 | void addSExt32Register(Register Reg); |
214 | bool isSExt32Register(Register Reg) const; |
215 | |
216 | bool isVectorCall() const { return IsVectorCall; } |
217 | void setIsVectorCall() { IsVectorCall = true; } |
218 | |
219 | bool hasDynamicAllocation() const { return HasDynamicAllocation; } |
220 | void setDynamicAllocation() { HasDynamicAllocation = true; } |
221 | }; |
222 | |
223 | } // end namespace llvm |
224 | |
225 | #endif // LLVM_LIB_TARGET_RISCV_RISCVMACHINEFUNCTIONINFO_H |
226 | |