1 | //===-- RISCVCallingConv.cpp - RISC-V Custom CC Routines ------------------===// |
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 contains the custom routines for the RISC-V Calling Convention. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "RISCVCallingConv.h" |
14 | #include "RISCVSubtarget.h" |
15 | #include "llvm/IR/DataLayout.h" |
16 | #include "llvm/IR/Module.h" |
17 | #include "llvm/MC/MCRegister.h" |
18 | |
19 | using namespace llvm; |
20 | |
21 | // Calling Convention Implementation. |
22 | // The expectations for frontend ABI lowering vary from target to target. |
23 | // Ideally, an LLVM frontend would be able to avoid worrying about many ABI |
24 | // details, but this is a longer term goal. For now, we simply try to keep the |
25 | // role of the frontend as simple and well-defined as possible. The rules can |
26 | // be summarised as: |
27 | // * Never split up large scalar arguments. We handle them here. |
28 | // * If a hardfloat calling convention is being used, and the struct may be |
29 | // passed in a pair of registers (fp+fp, int+fp), and both registers are |
30 | // available, then pass as two separate arguments. If either the GPRs or FPRs |
31 | // are exhausted, then pass according to the rule below. |
32 | // * If a struct could never be passed in registers or directly in a stack |
33 | // slot (as it is larger than 2*XLEN and the floating point rules don't |
34 | // apply), then pass it using a pointer with the byval attribute. |
35 | // * If a struct is less than 2*XLEN, then coerce to either a two-element |
36 | // word-sized array or a 2*XLEN scalar (depending on alignment). |
37 | // * The frontend can determine whether a struct is returned by reference or |
38 | // not based on its size and fields. If it will be returned by reference, the |
39 | // frontend must modify the prototype so a pointer with the sret annotation is |
40 | // passed as the first argument. This is not necessary for large scalar |
41 | // returns. |
42 | // * Struct return values and varargs should be coerced to structs containing |
43 | // register-size fields in the same situations they would be for fixed |
44 | // arguments. |
45 | |
46 | static const MCPhysReg ArgFPR16s[] = {RISCV::F10_H, RISCV::F11_H, RISCV::F12_H, |
47 | RISCV::F13_H, RISCV::F14_H, RISCV::F15_H, |
48 | RISCV::F16_H, RISCV::F17_H}; |
49 | static const MCPhysReg ArgFPR32s[] = {RISCV::F10_F, RISCV::F11_F, RISCV::F12_F, |
50 | RISCV::F13_F, RISCV::F14_F, RISCV::F15_F, |
51 | RISCV::F16_F, RISCV::F17_F}; |
52 | static const MCPhysReg ArgFPR64s[] = {RISCV::F10_D, RISCV::F11_D, RISCV::F12_D, |
53 | RISCV::F13_D, RISCV::F14_D, RISCV::F15_D, |
54 | RISCV::F16_D, RISCV::F17_D}; |
55 | // This is an interim calling convention and it may be changed in the future. |
56 | static const MCPhysReg ArgVRs[] = { |
57 | RISCV::V8, RISCV::V9, RISCV::V10, RISCV::V11, RISCV::V12, RISCV::V13, |
58 | RISCV::V14, RISCV::V15, RISCV::V16, RISCV::V17, RISCV::V18, RISCV::V19, |
59 | RISCV::V20, RISCV::V21, RISCV::V22, RISCV::V23}; |
60 | static const MCPhysReg ArgVRM2s[] = {RISCV::V8M2, RISCV::V10M2, RISCV::V12M2, |
61 | RISCV::V14M2, RISCV::V16M2, RISCV::V18M2, |
62 | RISCV::V20M2, RISCV::V22M2}; |
63 | static const MCPhysReg ArgVRM4s[] = {RISCV::V8M4, RISCV::V12M4, RISCV::V16M4, |
64 | RISCV::V20M4}; |
65 | static const MCPhysReg ArgVRM8s[] = {RISCV::V8M8, RISCV::V16M8}; |
66 | static const MCPhysReg ArgVRN2M1s[] = { |
67 | RISCV::V8_V9, RISCV::V9_V10, RISCV::V10_V11, RISCV::V11_V12, |
68 | RISCV::V12_V13, RISCV::V13_V14, RISCV::V14_V15, RISCV::V15_V16, |
69 | RISCV::V16_V17, RISCV::V17_V18, RISCV::V18_V19, RISCV::V19_V20, |
70 | RISCV::V20_V21, RISCV::V21_V22, RISCV::V22_V23}; |
71 | static const MCPhysReg ArgVRN3M1s[] = { |
72 | RISCV::V8_V9_V10, RISCV::V9_V10_V11, RISCV::V10_V11_V12, |
73 | RISCV::V11_V12_V13, RISCV::V12_V13_V14, RISCV::V13_V14_V15, |
74 | RISCV::V14_V15_V16, RISCV::V15_V16_V17, RISCV::V16_V17_V18, |
75 | RISCV::V17_V18_V19, RISCV::V18_V19_V20, RISCV::V19_V20_V21, |
76 | RISCV::V20_V21_V22, RISCV::V21_V22_V23}; |
77 | static const MCPhysReg ArgVRN4M1s[] = { |
78 | RISCV::V8_V9_V10_V11, RISCV::V9_V10_V11_V12, RISCV::V10_V11_V12_V13, |
79 | RISCV::V11_V12_V13_V14, RISCV::V12_V13_V14_V15, RISCV::V13_V14_V15_V16, |
80 | RISCV::V14_V15_V16_V17, RISCV::V15_V16_V17_V18, RISCV::V16_V17_V18_V19, |
81 | RISCV::V17_V18_V19_V20, RISCV::V18_V19_V20_V21, RISCV::V19_V20_V21_V22, |
82 | RISCV::V20_V21_V22_V23}; |
83 | static const MCPhysReg ArgVRN5M1s[] = { |
84 | RISCV::V8_V9_V10_V11_V12, RISCV::V9_V10_V11_V12_V13, |
85 | RISCV::V10_V11_V12_V13_V14, RISCV::V11_V12_V13_V14_V15, |
86 | RISCV::V12_V13_V14_V15_V16, RISCV::V13_V14_V15_V16_V17, |
87 | RISCV::V14_V15_V16_V17_V18, RISCV::V15_V16_V17_V18_V19, |
88 | RISCV::V16_V17_V18_V19_V20, RISCV::V17_V18_V19_V20_V21, |
89 | RISCV::V18_V19_V20_V21_V22, RISCV::V19_V20_V21_V22_V23}; |
90 | static const MCPhysReg ArgVRN6M1s[] = { |
91 | RISCV::V8_V9_V10_V11_V12_V13, RISCV::V9_V10_V11_V12_V13_V14, |
92 | RISCV::V10_V11_V12_V13_V14_V15, RISCV::V11_V12_V13_V14_V15_V16, |
93 | RISCV::V12_V13_V14_V15_V16_V17, RISCV::V13_V14_V15_V16_V17_V18, |
94 | RISCV::V14_V15_V16_V17_V18_V19, RISCV::V15_V16_V17_V18_V19_V20, |
95 | RISCV::V16_V17_V18_V19_V20_V21, RISCV::V17_V18_V19_V20_V21_V22, |
96 | RISCV::V18_V19_V20_V21_V22_V23}; |
97 | static const MCPhysReg ArgVRN7M1s[] = { |
98 | RISCV::V8_V9_V10_V11_V12_V13_V14, RISCV::V9_V10_V11_V12_V13_V14_V15, |
99 | RISCV::V10_V11_V12_V13_V14_V15_V16, RISCV::V11_V12_V13_V14_V15_V16_V17, |
100 | RISCV::V12_V13_V14_V15_V16_V17_V18, RISCV::V13_V14_V15_V16_V17_V18_V19, |
101 | RISCV::V14_V15_V16_V17_V18_V19_V20, RISCV::V15_V16_V17_V18_V19_V20_V21, |
102 | RISCV::V16_V17_V18_V19_V20_V21_V22, RISCV::V17_V18_V19_V20_V21_V22_V23}; |
103 | static const MCPhysReg ArgVRN8M1s[] = {RISCV::V8_V9_V10_V11_V12_V13_V14_V15, |
104 | RISCV::V9_V10_V11_V12_V13_V14_V15_V16, |
105 | RISCV::V10_V11_V12_V13_V14_V15_V16_V17, |
106 | RISCV::V11_V12_V13_V14_V15_V16_V17_V18, |
107 | RISCV::V12_V13_V14_V15_V16_V17_V18_V19, |
108 | RISCV::V13_V14_V15_V16_V17_V18_V19_V20, |
109 | RISCV::V14_V15_V16_V17_V18_V19_V20_V21, |
110 | RISCV::V15_V16_V17_V18_V19_V20_V21_V22, |
111 | RISCV::V16_V17_V18_V19_V20_V21_V22_V23}; |
112 | static const MCPhysReg ArgVRN2M2s[] = {RISCV::V8M2_V10M2, RISCV::V10M2_V12M2, |
113 | RISCV::V12M2_V14M2, RISCV::V14M2_V16M2, |
114 | RISCV::V16M2_V18M2, RISCV::V18M2_V20M2, |
115 | RISCV::V20M2_V22M2}; |
116 | static const MCPhysReg ArgVRN3M2s[] = { |
117 | RISCV::V8M2_V10M2_V12M2, RISCV::V10M2_V12M2_V14M2, |
118 | RISCV::V12M2_V14M2_V16M2, RISCV::V14M2_V16M2_V18M2, |
119 | RISCV::V16M2_V18M2_V20M2, RISCV::V18M2_V20M2_V22M2}; |
120 | static const MCPhysReg ArgVRN4M2s[] = { |
121 | RISCV::V8M2_V10M2_V12M2_V14M2, RISCV::V10M2_V12M2_V14M2_V16M2, |
122 | RISCV::V12M2_V14M2_V16M2_V18M2, RISCV::V14M2_V16M2_V18M2_V20M2, |
123 | RISCV::V16M2_V18M2_V20M2_V22M2}; |
124 | static const MCPhysReg ArgVRN2M4s[] = {RISCV::V8M4_V12M4, RISCV::V12M4_V16M4, |
125 | RISCV::V16M4_V20M4}; |
126 | |
127 | ArrayRef<MCPhysReg> RISCV::getArgGPRs(const RISCVABI::ABI ABI) { |
128 | // The GPRs used for passing arguments in the ILP32* and LP64* ABIs, except |
129 | // the ILP32E ABI. |
130 | static const MCPhysReg ArgIGPRs[] = {RISCV::X10, RISCV::X11, RISCV::X12, |
131 | RISCV::X13, RISCV::X14, RISCV::X15, |
132 | RISCV::X16, RISCV::X17}; |
133 | // The GPRs used for passing arguments in the ILP32E/LP64E ABI. |
134 | static const MCPhysReg ArgEGPRs[] = {RISCV::X10, RISCV::X11, RISCV::X12, |
135 | RISCV::X13, RISCV::X14, RISCV::X15}; |
136 | |
137 | if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E) |
138 | return ArrayRef(ArgEGPRs); |
139 | |
140 | return ArrayRef(ArgIGPRs); |
141 | } |
142 | |
143 | static ArrayRef<MCPhysReg> getArgGPR16s(const RISCVABI::ABI ABI) { |
144 | // The GPRs used for passing arguments in the ILP32* and LP64* ABIs, except |
145 | // the ILP32E ABI. |
146 | static const MCPhysReg ArgIGPRs[] = {RISCV::X10_H, RISCV::X11_H, RISCV::X12_H, |
147 | RISCV::X13_H, RISCV::X14_H, RISCV::X15_H, |
148 | RISCV::X16_H, RISCV::X17_H}; |
149 | // The GPRs used for passing arguments in the ILP32E/LP64E ABI. |
150 | static const MCPhysReg ArgEGPRs[] = {RISCV::X10_H, RISCV::X11_H, |
151 | RISCV::X12_H, RISCV::X13_H, |
152 | RISCV::X14_H, RISCV::X15_H}; |
153 | |
154 | if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E) |
155 | return ArrayRef(ArgEGPRs); |
156 | |
157 | return ArrayRef(ArgIGPRs); |
158 | } |
159 | |
160 | static ArrayRef<MCPhysReg> getArgGPR32s(const RISCVABI::ABI ABI) { |
161 | // The GPRs used for passing arguments in the ILP32* and LP64* ABIs, except |
162 | // the ILP32E ABI. |
163 | static const MCPhysReg ArgIGPRs[] = {RISCV::X10_W, RISCV::X11_W, RISCV::X12_W, |
164 | RISCV::X13_W, RISCV::X14_W, RISCV::X15_W, |
165 | RISCV::X16_W, RISCV::X17_W}; |
166 | // The GPRs used for passing arguments in the ILP32E/LP64E ABI. |
167 | static const MCPhysReg ArgEGPRs[] = {RISCV::X10_W, RISCV::X11_W, |
168 | RISCV::X12_W, RISCV::X13_W, |
169 | RISCV::X14_W, RISCV::X15_W}; |
170 | |
171 | if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E) |
172 | return ArrayRef(ArgEGPRs); |
173 | |
174 | return ArrayRef(ArgIGPRs); |
175 | } |
176 | |
177 | static ArrayRef<MCPhysReg> getFastCCArgGPRs(const RISCVABI::ABI ABI) { |
178 | // The GPRs used for passing arguments in the FastCC, X5 and X6 might be used |
179 | // for save-restore libcall, so we don't use them. |
180 | // Don't use X7 for fastcc, since Zicfilp uses X7 as the label register. |
181 | static const MCPhysReg FastCCIGPRs[] = { |
182 | RISCV::X10, RISCV::X11, RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, |
183 | RISCV::X16, RISCV::X17, RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31}; |
184 | |
185 | // The GPRs used for passing arguments in the FastCC when using ILP32E/LP64E. |
186 | static const MCPhysReg FastCCEGPRs[] = {RISCV::X10, RISCV::X11, RISCV::X12, |
187 | RISCV::X13, RISCV::X14, RISCV::X15}; |
188 | |
189 | if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E) |
190 | return ArrayRef(FastCCEGPRs); |
191 | |
192 | return ArrayRef(FastCCIGPRs); |
193 | } |
194 | |
195 | static ArrayRef<MCPhysReg> getFastCCArgGPRF16s(const RISCVABI::ABI ABI) { |
196 | // The GPRs used for passing arguments in the FastCC, X5 and X6 might be used |
197 | // for save-restore libcall, so we don't use them. |
198 | // Don't use X7 for fastcc, since Zicfilp uses X7 as the label register. |
199 | static const MCPhysReg FastCCIGPRs[] = { |
200 | RISCV::X10_H, RISCV::X11_H, RISCV::X12_H, RISCV::X13_H, |
201 | RISCV::X14_H, RISCV::X15_H, RISCV::X16_H, RISCV::X17_H, |
202 | RISCV::X28_H, RISCV::X29_H, RISCV::X30_H, RISCV::X31_H}; |
203 | |
204 | // The GPRs used for passing arguments in the FastCC when using ILP32E/LP64E. |
205 | static const MCPhysReg FastCCEGPRs[] = {RISCV::X10_H, RISCV::X11_H, |
206 | RISCV::X12_H, RISCV::X13_H, |
207 | RISCV::X14_H, RISCV::X15_H}; |
208 | |
209 | if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E) |
210 | return ArrayRef(FastCCEGPRs); |
211 | |
212 | return ArrayRef(FastCCIGPRs); |
213 | } |
214 | |
215 | static ArrayRef<MCPhysReg> getFastCCArgGPRF32s(const RISCVABI::ABI ABI) { |
216 | // The GPRs used for passing arguments in the FastCC, X5 and X6 might be used |
217 | // for save-restore libcall, so we don't use them. |
218 | // Don't use X7 for fastcc, since Zicfilp uses X7 as the label register. |
219 | static const MCPhysReg FastCCIGPRs[] = { |
220 | RISCV::X10_W, RISCV::X11_W, RISCV::X12_W, RISCV::X13_W, |
221 | RISCV::X14_W, RISCV::X15_W, RISCV::X16_W, RISCV::X17_W, |
222 | RISCV::X28_W, RISCV::X29_W, RISCV::X30_W, RISCV::X31_W}; |
223 | |
224 | // The GPRs used for passing arguments in the FastCC when using ILP32E/LP64E. |
225 | static const MCPhysReg FastCCEGPRs[] = {RISCV::X10_W, RISCV::X11_W, |
226 | RISCV::X12_W, RISCV::X13_W, |
227 | RISCV::X14_W, RISCV::X15_W}; |
228 | |
229 | if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E) |
230 | return ArrayRef(FastCCEGPRs); |
231 | |
232 | return ArrayRef(FastCCIGPRs); |
233 | } |
234 | |
235 | // Pass a 2*XLEN argument that has been split into two XLEN values through |
236 | // registers or the stack as necessary. |
237 | static bool CC_RISCVAssign2XLen(unsigned XLen, CCState &State, CCValAssign VA1, |
238 | ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, |
239 | MVT ValVT2, MVT LocVT2, |
240 | ISD::ArgFlagsTy ArgFlags2, bool EABI) { |
241 | unsigned XLenInBytes = XLen / 8; |
242 | const RISCVSubtarget &STI = |
243 | State.getMachineFunction().getSubtarget<RISCVSubtarget>(); |
244 | ArrayRef<MCPhysReg> ArgGPRs = RISCV::getArgGPRs(ABI: STI.getTargetABI()); |
245 | |
246 | if (MCRegister Reg = State.AllocateReg(Regs: ArgGPRs)) { |
247 | // At least one half can be passed via register. |
248 | State.addLoc(V: CCValAssign::getReg(ValNo: VA1.getValNo(), ValVT: VA1.getValVT(), Reg, |
249 | LocVT: VA1.getLocVT(), HTP: CCValAssign::Full)); |
250 | } else { |
251 | // Both halves must be passed on the stack, with proper alignment. |
252 | // TODO: To be compatible with GCC's behaviors, we force them to have 4-byte |
253 | // alignment. This behavior may be changed when RV32E/ILP32E is ratified. |
254 | Align StackAlign(XLenInBytes); |
255 | if (!EABI || XLen != 32) |
256 | StackAlign = std::max(a: StackAlign, b: ArgFlags1.getNonZeroOrigAlign()); |
257 | State.addLoc( |
258 | V: CCValAssign::getMem(ValNo: VA1.getValNo(), ValVT: VA1.getValVT(), |
259 | Offset: State.AllocateStack(Size: XLenInBytes, Alignment: StackAlign), |
260 | LocVT: VA1.getLocVT(), HTP: CCValAssign::Full)); |
261 | State.addLoc(V: CCValAssign::getMem( |
262 | ValNo: ValNo2, ValVT: ValVT2, Offset: State.AllocateStack(Size: XLenInBytes, Alignment: Align(XLenInBytes)), |
263 | LocVT: LocVT2, HTP: CCValAssign::Full)); |
264 | return false; |
265 | } |
266 | |
267 | if (MCRegister Reg = State.AllocateReg(Regs: ArgGPRs)) { |
268 | // The second half can also be passed via register. |
269 | State.addLoc( |
270 | V: CCValAssign::getReg(ValNo: ValNo2, ValVT: ValVT2, Reg, LocVT: LocVT2, HTP: CCValAssign::Full)); |
271 | } else { |
272 | // The second half is passed via the stack, without additional alignment. |
273 | State.addLoc(V: CCValAssign::getMem( |
274 | ValNo: ValNo2, ValVT: ValVT2, Offset: State.AllocateStack(Size: XLenInBytes, Alignment: Align(XLenInBytes)), |
275 | LocVT: LocVT2, HTP: CCValAssign::Full)); |
276 | } |
277 | |
278 | return false; |
279 | } |
280 | |
281 | static MCRegister allocateRVVReg(MVT ValVT, unsigned ValNo, CCState &State, |
282 | const RISCVTargetLowering &TLI) { |
283 | const TargetRegisterClass *RC = TLI.getRegClassFor(VT: ValVT); |
284 | if (RC == &RISCV::VRRegClass) { |
285 | // Assign the first mask argument to V0. |
286 | // This is an interim calling convention and it may be changed in the |
287 | // future. |
288 | if (ValVT.getVectorElementType() == MVT::i1) |
289 | if (MCRegister Reg = State.AllocateReg(Reg: RISCV::V0)) |
290 | return Reg; |
291 | return State.AllocateReg(Regs: ArgVRs); |
292 | } |
293 | if (RC == &RISCV::VRM2RegClass) |
294 | return State.AllocateReg(Regs: ArgVRM2s); |
295 | if (RC == &RISCV::VRM4RegClass) |
296 | return State.AllocateReg(Regs: ArgVRM4s); |
297 | if (RC == &RISCV::VRM8RegClass) |
298 | return State.AllocateReg(Regs: ArgVRM8s); |
299 | if (RC == &RISCV::VRN2M1RegClass) |
300 | return State.AllocateReg(Regs: ArgVRN2M1s); |
301 | if (RC == &RISCV::VRN3M1RegClass) |
302 | return State.AllocateReg(Regs: ArgVRN3M1s); |
303 | if (RC == &RISCV::VRN4M1RegClass) |
304 | return State.AllocateReg(Regs: ArgVRN4M1s); |
305 | if (RC == &RISCV::VRN5M1RegClass) |
306 | return State.AllocateReg(Regs: ArgVRN5M1s); |
307 | if (RC == &RISCV::VRN6M1RegClass) |
308 | return State.AllocateReg(Regs: ArgVRN6M1s); |
309 | if (RC == &RISCV::VRN7M1RegClass) |
310 | return State.AllocateReg(Regs: ArgVRN7M1s); |
311 | if (RC == &RISCV::VRN8M1RegClass) |
312 | return State.AllocateReg(Regs: ArgVRN8M1s); |
313 | if (RC == &RISCV::VRN2M2RegClass) |
314 | return State.AllocateReg(Regs: ArgVRN2M2s); |
315 | if (RC == &RISCV::VRN3M2RegClass) |
316 | return State.AllocateReg(Regs: ArgVRN3M2s); |
317 | if (RC == &RISCV::VRN4M2RegClass) |
318 | return State.AllocateReg(Regs: ArgVRN4M2s); |
319 | if (RC == &RISCV::VRN2M4RegClass) |
320 | return State.AllocateReg(Regs: ArgVRN2M4s); |
321 | llvm_unreachable("Unhandled register class for ValueType" ); |
322 | } |
323 | |
324 | // Implements the RISC-V calling convention. Returns true upon failure. |
325 | bool llvm::CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT, |
326 | CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, |
327 | CCState &State, bool IsFixed, bool IsRet, Type *OrigTy) { |
328 | const MachineFunction &MF = State.getMachineFunction(); |
329 | const DataLayout &DL = MF.getDataLayout(); |
330 | const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>(); |
331 | const RISCVTargetLowering &TLI = *Subtarget.getTargetLowering(); |
332 | |
333 | unsigned XLen = Subtarget.getXLen(); |
334 | MVT XLenVT = Subtarget.getXLenVT(); |
335 | |
336 | if (ArgFlags.isNest()) { |
337 | // Static chain parameter must not be passed in normal argument registers, |
338 | // so we assign t2/t3 for it as done in GCC's |
339 | // __builtin_call_with_static_chain |
340 | bool HasCFBranch = |
341 | Subtarget.hasStdExtZicfilp() && |
342 | MF.getFunction().getParent()->getModuleFlag(Key: "cf-protection-branch" ); |
343 | |
344 | // Normal: t2, Branch control flow protection: t3 |
345 | const auto StaticChainReg = HasCFBranch ? RISCV::X28 : RISCV::X7; |
346 | |
347 | RISCVABI::ABI ABI = Subtarget.getTargetABI(); |
348 | if (HasCFBranch && |
349 | (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E)) |
350 | reportFatalUsageError( |
351 | reason: "Nested functions with control flow protection are not " |
352 | "usable with ILP32E or LP64E ABI." ); |
353 | if (MCRegister Reg = State.AllocateReg(Reg: StaticChainReg)) { |
354 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
355 | return false; |
356 | } |
357 | } |
358 | |
359 | // Any return value split in to more than two values can't be returned |
360 | // directly. Vectors are returned via the available vector registers. |
361 | if (!LocVT.isVector() && IsRet && ValNo > 1) |
362 | return true; |
363 | |
364 | // UseGPRForF16_F32 if targeting one of the soft-float ABIs, if passing a |
365 | // variadic argument, or if no F16/F32 argument registers are available. |
366 | bool UseGPRForF16_F32 = true; |
367 | // UseGPRForF64 if targeting soft-float ABIs or an FLEN=32 ABI, if passing a |
368 | // variadic argument, or if no F64 argument registers are available. |
369 | bool UseGPRForF64 = true; |
370 | |
371 | RISCVABI::ABI ABI = Subtarget.getTargetABI(); |
372 | switch (ABI) { |
373 | default: |
374 | llvm_unreachable("Unexpected ABI" ); |
375 | case RISCVABI::ABI_ILP32: |
376 | case RISCVABI::ABI_ILP32E: |
377 | case RISCVABI::ABI_LP64: |
378 | case RISCVABI::ABI_LP64E: |
379 | break; |
380 | case RISCVABI::ABI_ILP32F: |
381 | case RISCVABI::ABI_LP64F: |
382 | UseGPRForF16_F32 = !IsFixed; |
383 | break; |
384 | case RISCVABI::ABI_ILP32D: |
385 | case RISCVABI::ABI_LP64D: |
386 | UseGPRForF16_F32 = !IsFixed; |
387 | UseGPRForF64 = !IsFixed; |
388 | break; |
389 | } |
390 | |
391 | if ((LocVT == MVT::f16 || LocVT == MVT::bf16) && !UseGPRForF16_F32) { |
392 | if (MCRegister Reg = State.AllocateReg(Regs: ArgFPR16s)) { |
393 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
394 | return false; |
395 | } |
396 | } |
397 | |
398 | if (LocVT == MVT::f32 && !UseGPRForF16_F32) { |
399 | if (MCRegister Reg = State.AllocateReg(Regs: ArgFPR32s)) { |
400 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
401 | return false; |
402 | } |
403 | } |
404 | |
405 | if (LocVT == MVT::f64 && !UseGPRForF64) { |
406 | if (MCRegister Reg = State.AllocateReg(Regs: ArgFPR64s)) { |
407 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
408 | return false; |
409 | } |
410 | } |
411 | |
412 | if ((ValVT == MVT::f16 && Subtarget.hasStdExtZhinxmin())) { |
413 | if (MCRegister Reg = State.AllocateReg(Regs: getArgGPR16s(ABI))) { |
414 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
415 | return false; |
416 | } |
417 | } |
418 | |
419 | if (ValVT == MVT::f32 && Subtarget.hasStdExtZfinx()) { |
420 | if (MCRegister Reg = State.AllocateReg(Regs: getArgGPR32s(ABI))) { |
421 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
422 | return false; |
423 | } |
424 | } |
425 | |
426 | ArrayRef<MCPhysReg> ArgGPRs = RISCV::getArgGPRs(ABI); |
427 | |
428 | // Zdinx use GPR without a bitcast when possible. |
429 | if (LocVT == MVT::f64 && XLen == 64 && Subtarget.hasStdExtZdinx()) { |
430 | if (MCRegister Reg = State.AllocateReg(Regs: ArgGPRs)) { |
431 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
432 | return false; |
433 | } |
434 | } |
435 | |
436 | // FP smaller than XLen, uses custom GPR. |
437 | if (LocVT == MVT::f16 || LocVT == MVT::bf16 || |
438 | (LocVT == MVT::f32 && XLen == 64)) { |
439 | if (MCRegister Reg = State.AllocateReg(Regs: ArgGPRs)) { |
440 | LocVT = XLenVT; |
441 | State.addLoc( |
442 | V: CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
443 | return false; |
444 | } |
445 | } |
446 | |
447 | // Bitcast FP to GPR if we can use a GPR register. |
448 | if ((XLen == 32 && LocVT == MVT::f32) || (XLen == 64 && LocVT == MVT::f64)) { |
449 | if (MCRegister Reg = State.AllocateReg(Regs: ArgGPRs)) { |
450 | LocVT = XLenVT; |
451 | LocInfo = CCValAssign::BCvt; |
452 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
453 | return false; |
454 | } |
455 | } |
456 | |
457 | // If this is a variadic argument, the RISC-V calling convention requires |
458 | // that it is assigned an 'even' or 'aligned' register if it has 8-byte |
459 | // alignment (RV32) or 16-byte alignment (RV64). An aligned register should |
460 | // be used regardless of whether the original argument was split during |
461 | // legalisation or not. The argument will not be passed by registers if the |
462 | // original type is larger than 2*XLEN, so the register alignment rule does |
463 | // not apply. |
464 | // TODO: To be compatible with GCC's behaviors, we don't align registers |
465 | // currently if we are using ILP32E calling convention. This behavior may be |
466 | // changed when RV32E/ILP32E is ratified. |
467 | unsigned TwoXLenInBytes = (2 * XLen) / 8; |
468 | if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoXLenInBytes && |
469 | DL.getTypeAllocSize(Ty: OrigTy) == TwoXLenInBytes && |
470 | ABI != RISCVABI::ABI_ILP32E) { |
471 | unsigned RegIdx = State.getFirstUnallocated(Regs: ArgGPRs); |
472 | // Skip 'odd' register if necessary. |
473 | if (RegIdx != std::size(cont: ArgGPRs) && RegIdx % 2 == 1) |
474 | State.AllocateReg(Regs: ArgGPRs); |
475 | } |
476 | |
477 | SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs(); |
478 | SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags = |
479 | State.getPendingArgFlags(); |
480 | |
481 | assert(PendingLocs.size() == PendingArgFlags.size() && |
482 | "PendingLocs and PendingArgFlags out of sync" ); |
483 | |
484 | // Handle passing f64 on RV32D with a soft float ABI or when floating point |
485 | // registers are exhausted. |
486 | if (XLen == 32 && LocVT == MVT::f64) { |
487 | assert(PendingLocs.empty() && "Can't lower f64 if it is split" ); |
488 | // Depending on available argument GPRS, f64 may be passed in a pair of |
489 | // GPRs, split between a GPR and the stack, or passed completely on the |
490 | // stack. LowerCall/LowerFormalArguments/LowerReturn must recognise these |
491 | // cases. |
492 | MCRegister Reg = State.AllocateReg(Regs: ArgGPRs); |
493 | if (!Reg) { |
494 | int64_t StackOffset = State.AllocateStack(Size: 8, Alignment: Align(8)); |
495 | State.addLoc( |
496 | V: CCValAssign::getMem(ValNo, ValVT, Offset: StackOffset, LocVT, HTP: LocInfo)); |
497 | return false; |
498 | } |
499 | LocVT = MVT::i32; |
500 | State.addLoc(V: CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
501 | MCRegister HiReg = State.AllocateReg(Regs: ArgGPRs); |
502 | if (HiReg) { |
503 | State.addLoc( |
504 | V: CCValAssign::getCustomReg(ValNo, ValVT, Reg: HiReg, LocVT, HTP: LocInfo)); |
505 | } else { |
506 | int64_t StackOffset = State.AllocateStack(Size: 4, Alignment: Align(4)); |
507 | State.addLoc( |
508 | V: CCValAssign::getCustomMem(ValNo, ValVT, Offset: StackOffset, LocVT, HTP: LocInfo)); |
509 | } |
510 | return false; |
511 | } |
512 | |
513 | // Split arguments might be passed indirectly, so keep track of the pending |
514 | // values. Split vectors are passed via a mix of registers and indirectly, so |
515 | // treat them as we would any other argument. |
516 | if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) { |
517 | LocVT = XLenVT; |
518 | LocInfo = CCValAssign::Indirect; |
519 | PendingLocs.push_back( |
520 | Elt: CCValAssign::getPending(ValNo, ValVT, LocVT, HTP: LocInfo)); |
521 | PendingArgFlags.push_back(Elt: ArgFlags); |
522 | if (!ArgFlags.isSplitEnd()) { |
523 | return false; |
524 | } |
525 | } |
526 | |
527 | // If the split argument only had two elements, it should be passed directly |
528 | // in registers or on the stack. |
529 | if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() && |
530 | PendingLocs.size() <= 2) { |
531 | assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()" ); |
532 | // Apply the normal calling convention rules to the first half of the |
533 | // split argument. |
534 | CCValAssign VA = PendingLocs[0]; |
535 | ISD::ArgFlagsTy AF = PendingArgFlags[0]; |
536 | PendingLocs.clear(); |
537 | PendingArgFlags.clear(); |
538 | return CC_RISCVAssign2XLen( |
539 | XLen, State, VA1: VA, ArgFlags1: AF, ValNo2: ValNo, ValVT2: ValVT, LocVT2: LocVT, ArgFlags2: ArgFlags, |
540 | EABI: ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E); |
541 | } |
542 | |
543 | // Allocate to a register if possible, or else a stack slot. |
544 | MCRegister Reg; |
545 | unsigned StoreSizeBytes = XLen / 8; |
546 | Align StackAlign = Align(XLen / 8); |
547 | |
548 | if (ValVT.isVector() || ValVT.isRISCVVectorTuple()) { |
549 | Reg = allocateRVVReg(ValVT, ValNo, State, TLI); |
550 | if (Reg) { |
551 | // Fixed-length vectors are located in the corresponding scalable-vector |
552 | // container types. |
553 | if (ValVT.isFixedLengthVector()) { |
554 | LocVT = TLI.getContainerForFixedLengthVector(VT: LocVT); |
555 | State.addLoc( |
556 | V: CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
557 | return false; |
558 | } |
559 | } else { |
560 | // For return values, the vector must be passed fully via registers or |
561 | // via the stack. |
562 | // FIXME: The proposed vector ABI only mandates v8-v15 for return values, |
563 | // but we're using all of them. |
564 | if (IsRet) |
565 | return true; |
566 | // Try using a GPR to pass the address |
567 | if ((Reg = State.AllocateReg(Regs: ArgGPRs))) { |
568 | LocVT = XLenVT; |
569 | LocInfo = CCValAssign::Indirect; |
570 | } else if (ValVT.isScalableVector()) { |
571 | LocVT = XLenVT; |
572 | LocInfo = CCValAssign::Indirect; |
573 | } else { |
574 | StoreSizeBytes = ValVT.getStoreSize(); |
575 | // Align vectors to their element sizes, being careful for vXi1 |
576 | // vectors. |
577 | StackAlign = MaybeAlign(ValVT.getScalarSizeInBits() / 8).valueOrOne(); |
578 | } |
579 | } |
580 | } else { |
581 | Reg = State.AllocateReg(Regs: ArgGPRs); |
582 | } |
583 | |
584 | int64_t StackOffset = |
585 | Reg ? 0 : State.AllocateStack(Size: StoreSizeBytes, Alignment: StackAlign); |
586 | |
587 | // If we reach this point and PendingLocs is non-empty, we must be at the |
588 | // end of a split argument that must be passed indirectly. |
589 | if (!PendingLocs.empty()) { |
590 | assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()" ); |
591 | assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()" ); |
592 | |
593 | for (auto &It : PendingLocs) { |
594 | if (Reg) |
595 | It.convertToReg(Reg); |
596 | else |
597 | It.convertToMem(Offset: StackOffset); |
598 | State.addLoc(V: It); |
599 | } |
600 | PendingLocs.clear(); |
601 | PendingArgFlags.clear(); |
602 | return false; |
603 | } |
604 | |
605 | assert(((ValVT.isFloatingPoint() && !ValVT.isVector()) || LocVT == XLenVT || |
606 | (TLI.getSubtarget().hasVInstructions() && |
607 | (ValVT.isVector() || ValVT.isRISCVVectorTuple()))) && |
608 | "Expected an XLenVT or vector types at this stage" ); |
609 | |
610 | if (Reg) { |
611 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
612 | return false; |
613 | } |
614 | |
615 | State.addLoc(V: CCValAssign::getMem(ValNo, ValVT, Offset: StackOffset, LocVT, HTP: LocInfo)); |
616 | return false; |
617 | } |
618 | |
619 | // FastCC has less than 1% performance improvement for some particular |
620 | // benchmark. But theoretically, it may have benefit for some cases. |
621 | bool llvm::CC_RISCV_FastCC(unsigned ValNo, MVT ValVT, MVT LocVT, |
622 | CCValAssign::LocInfo LocInfo, |
623 | ISD::ArgFlagsTy ArgFlags, CCState &State, |
624 | bool IsFixed, bool IsRet, Type *OrigTy) { |
625 | const MachineFunction &MF = State.getMachineFunction(); |
626 | const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>(); |
627 | const RISCVTargetLowering &TLI = *Subtarget.getTargetLowering(); |
628 | RISCVABI::ABI ABI = Subtarget.getTargetABI(); |
629 | |
630 | if ((LocVT == MVT::f16 && Subtarget.hasStdExtZfhmin()) || |
631 | (LocVT == MVT::bf16 && Subtarget.hasStdExtZfbfmin())) { |
632 | static const MCPhysReg FPR16List[] = { |
633 | RISCV::F10_H, RISCV::F11_H, RISCV::F12_H, RISCV::F13_H, RISCV::F14_H, |
634 | RISCV::F15_H, RISCV::F16_H, RISCV::F17_H, RISCV::F0_H, RISCV::F1_H, |
635 | RISCV::F2_H, RISCV::F3_H, RISCV::F4_H, RISCV::F5_H, RISCV::F6_H, |
636 | RISCV::F7_H, RISCV::F28_H, RISCV::F29_H, RISCV::F30_H, RISCV::F31_H}; |
637 | if (MCRegister Reg = State.AllocateReg(Regs: FPR16List)) { |
638 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
639 | return false; |
640 | } |
641 | } |
642 | |
643 | if (LocVT == MVT::f32 && Subtarget.hasStdExtF()) { |
644 | static const MCPhysReg FPR32List[] = { |
645 | RISCV::F10_F, RISCV::F11_F, RISCV::F12_F, RISCV::F13_F, RISCV::F14_F, |
646 | RISCV::F15_F, RISCV::F16_F, RISCV::F17_F, RISCV::F0_F, RISCV::F1_F, |
647 | RISCV::F2_F, RISCV::F3_F, RISCV::F4_F, RISCV::F5_F, RISCV::F6_F, |
648 | RISCV::F7_F, RISCV::F28_F, RISCV::F29_F, RISCV::F30_F, RISCV::F31_F}; |
649 | if (MCRegister Reg = State.AllocateReg(Regs: FPR32List)) { |
650 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
651 | return false; |
652 | } |
653 | } |
654 | |
655 | if (LocVT == MVT::f64 && Subtarget.hasStdExtD()) { |
656 | static const MCPhysReg FPR64List[] = { |
657 | RISCV::F10_D, RISCV::F11_D, RISCV::F12_D, RISCV::F13_D, RISCV::F14_D, |
658 | RISCV::F15_D, RISCV::F16_D, RISCV::F17_D, RISCV::F0_D, RISCV::F1_D, |
659 | RISCV::F2_D, RISCV::F3_D, RISCV::F4_D, RISCV::F5_D, RISCV::F6_D, |
660 | RISCV::F7_D, RISCV::F28_D, RISCV::F29_D, RISCV::F30_D, RISCV::F31_D}; |
661 | if (MCRegister Reg = State.AllocateReg(Regs: FPR64List)) { |
662 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
663 | return false; |
664 | } |
665 | } |
666 | |
667 | MVT XLenVT = Subtarget.getXLenVT(); |
668 | |
669 | // Check if there is an available GPRF16 before hitting the stack. |
670 | if ((LocVT == MVT::f16 && Subtarget.hasStdExtZhinxmin())) { |
671 | if (MCRegister Reg = State.AllocateReg(Regs: getFastCCArgGPRF16s(ABI))) { |
672 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
673 | return false; |
674 | } |
675 | } |
676 | |
677 | // Check if there is an available GPRF32 before hitting the stack. |
678 | if (LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) { |
679 | if (MCRegister Reg = State.AllocateReg(Regs: getFastCCArgGPRF32s(ABI))) { |
680 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
681 | return false; |
682 | } |
683 | } |
684 | |
685 | // Check if there is an available GPR before hitting the stack. |
686 | if (LocVT == MVT::f64 && Subtarget.is64Bit() && Subtarget.hasStdExtZdinx()) { |
687 | if (MCRegister Reg = State.AllocateReg(Regs: getFastCCArgGPRs(ABI))) { |
688 | if (LocVT.getSizeInBits() != Subtarget.getXLen()) { |
689 | LocVT = XLenVT; |
690 | State.addLoc( |
691 | V: CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
692 | return false; |
693 | } |
694 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
695 | return false; |
696 | } |
697 | } |
698 | |
699 | ArrayRef<MCPhysReg> ArgGPRs = getFastCCArgGPRs(ABI); |
700 | |
701 | if (LocVT.isVector()) { |
702 | if (MCRegister Reg = allocateRVVReg(ValVT, ValNo, State, TLI)) { |
703 | // Fixed-length vectors are located in the corresponding scalable-vector |
704 | // container types. |
705 | if (LocVT.isFixedLengthVector()) { |
706 | LocVT = TLI.getContainerForFixedLengthVector(VT: LocVT); |
707 | State.addLoc( |
708 | V: CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
709 | return false; |
710 | } |
711 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
712 | return false; |
713 | } |
714 | |
715 | // Pass scalable vectors indirectly. Pass fixed vectors indirectly if we |
716 | // have a free GPR. |
717 | if (LocVT.isScalableVector() || |
718 | State.getFirstUnallocated(Regs: ArgGPRs) != ArgGPRs.size()) { |
719 | LocInfo = CCValAssign::Indirect; |
720 | LocVT = XLenVT; |
721 | } |
722 | } |
723 | |
724 | if (LocVT == XLenVT) { |
725 | if (MCRegister Reg = State.AllocateReg(Regs: getFastCCArgGPRs(ABI))) { |
726 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
727 | return false; |
728 | } |
729 | } |
730 | |
731 | if (LocVT == XLenVT || LocVT == MVT::f16 || LocVT == MVT::bf16 || |
732 | LocVT == MVT::f32 || LocVT == MVT::f64 || LocVT.isFixedLengthVector()) { |
733 | Align StackAlign = MaybeAlign(ValVT.getScalarSizeInBits() / 8).valueOrOne(); |
734 | int64_t Offset = State.AllocateStack(Size: LocVT.getStoreSize(), Alignment: StackAlign); |
735 | State.addLoc(V: CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, HTP: LocInfo)); |
736 | return false; |
737 | } |
738 | |
739 | return true; // CC didn't match. |
740 | } |
741 | |
742 | bool llvm::CC_RISCV_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, |
743 | CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, |
744 | CCState &State) { |
745 | if (ArgFlags.isNest()) { |
746 | report_fatal_error( |
747 | reason: "Attribute 'nest' is not supported in GHC calling convention" ); |
748 | } |
749 | |
750 | static const MCPhysReg GPRList[] = { |
751 | RISCV::X9, RISCV::X18, RISCV::X19, RISCV::X20, RISCV::X21, RISCV::X22, |
752 | RISCV::X23, RISCV::X24, RISCV::X25, RISCV::X26, RISCV::X27}; |
753 | |
754 | if (LocVT == MVT::i32 || LocVT == MVT::i64) { |
755 | // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, R6, R7, SpLim |
756 | // s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 |
757 | if (MCRegister Reg = State.AllocateReg(Regs: GPRList)) { |
758 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
759 | return false; |
760 | } |
761 | } |
762 | |
763 | const RISCVSubtarget &Subtarget = |
764 | State.getMachineFunction().getSubtarget<RISCVSubtarget>(); |
765 | |
766 | if (LocVT == MVT::f32 && Subtarget.hasStdExtF()) { |
767 | // Pass in STG registers: F1, ..., F6 |
768 | // fs0 ... fs5 |
769 | static const MCPhysReg FPR32List[] = {RISCV::F8_F, RISCV::F9_F, |
770 | RISCV::F18_F, RISCV::F19_F, |
771 | RISCV::F20_F, RISCV::F21_F}; |
772 | if (MCRegister Reg = State.AllocateReg(Regs: FPR32List)) { |
773 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
774 | return false; |
775 | } |
776 | } |
777 | |
778 | if (LocVT == MVT::f64 && Subtarget.hasStdExtD()) { |
779 | // Pass in STG registers: D1, ..., D6 |
780 | // fs6 ... fs11 |
781 | static const MCPhysReg FPR64List[] = {RISCV::F22_D, RISCV::F23_D, |
782 | RISCV::F24_D, RISCV::F25_D, |
783 | RISCV::F26_D, RISCV::F27_D}; |
784 | if (MCRegister Reg = State.AllocateReg(Regs: FPR64List)) { |
785 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
786 | return false; |
787 | } |
788 | } |
789 | |
790 | if (LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) { |
791 | static const MCPhysReg GPR32List[] = { |
792 | RISCV::X9_W, RISCV::X18_W, RISCV::X19_W, RISCV::X20_W, |
793 | RISCV::X21_W, RISCV::X22_W, RISCV::X23_W, RISCV::X24_W, |
794 | RISCV::X25_W, RISCV::X26_W, RISCV::X27_W}; |
795 | if (MCRegister Reg = State.AllocateReg(Regs: GPR32List)) { |
796 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
797 | return false; |
798 | } |
799 | } |
800 | |
801 | if (LocVT == MVT::f64 && Subtarget.hasStdExtZdinx() && Subtarget.is64Bit()) { |
802 | if (MCRegister Reg = State.AllocateReg(Regs: GPRList)) { |
803 | State.addLoc(V: CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, HTP: LocInfo)); |
804 | return false; |
805 | } |
806 | } |
807 | |
808 | report_fatal_error(reason: "No registers left in GHC calling convention" ); |
809 | return true; |
810 | } |
811 | |