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