| 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 | |