1//===--- RISCV.cpp - Implement RISC-V target feature support --------------===//
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 implements RISC-V TargetInfo objects.
10//
11//===----------------------------------------------------------------------===//
12
13#include "RISCV.h"
14#include "clang/Basic/Diagnostic.h"
15#include "clang/Basic/MacroBuilder.h"
16#include "clang/Basic/TargetBuiltins.h"
17#include "llvm/ADT/StringSwitch.h"
18#include "llvm/Support/raw_ostream.h"
19#include "llvm/TargetParser/RISCVTargetParser.h"
20#include <optional>
21
22using namespace clang;
23using namespace clang::targets;
24
25ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
26 // clang-format off
27 static const char *const GCCRegNames[] = {
28 // Integer registers
29 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
30 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
31 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
32 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
33
34 // Floating point registers
35 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
36 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
37 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
38 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
39
40 // Vector registers
41 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
42 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
43 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
44 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
45
46 // CSRs
47 "fflags", "frm", "vtype", "vl", "vxsat", "vxrm"
48 };
49 // clang-format on
50 return llvm::ArrayRef(GCCRegNames);
51}
52
53ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
54 static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
55 {.Aliases: {"zero"}, .Register: "x0"}, {.Aliases: {"ra"}, .Register: "x1"}, {.Aliases: {"sp"}, .Register: "x2"}, {.Aliases: {"gp"}, .Register: "x3"},
56 {.Aliases: {"tp"}, .Register: "x4"}, {.Aliases: {"t0"}, .Register: "x5"}, {.Aliases: {"t1"}, .Register: "x6"}, {.Aliases: {"t2"}, .Register: "x7"},
57 {.Aliases: {"s0"}, .Register: "x8"}, {.Aliases: {"s1"}, .Register: "x9"}, {.Aliases: {"a0"}, .Register: "x10"}, {.Aliases: {"a1"}, .Register: "x11"},
58 {.Aliases: {"a2"}, .Register: "x12"}, {.Aliases: {"a3"}, .Register: "x13"}, {.Aliases: {"a4"}, .Register: "x14"}, {.Aliases: {"a5"}, .Register: "x15"},
59 {.Aliases: {"a6"}, .Register: "x16"}, {.Aliases: {"a7"}, .Register: "x17"}, {.Aliases: {"s2"}, .Register: "x18"}, {.Aliases: {"s3"}, .Register: "x19"},
60 {.Aliases: {"s4"}, .Register: "x20"}, {.Aliases: {"s5"}, .Register: "x21"}, {.Aliases: {"s6"}, .Register: "x22"}, {.Aliases: {"s7"}, .Register: "x23"},
61 {.Aliases: {"s8"}, .Register: "x24"}, {.Aliases: {"s9"}, .Register: "x25"}, {.Aliases: {"s10"}, .Register: "x26"}, {.Aliases: {"s11"}, .Register: "x27"},
62 {.Aliases: {"t3"}, .Register: "x28"}, {.Aliases: {"t4"}, .Register: "x29"}, {.Aliases: {"t5"}, .Register: "x30"}, {.Aliases: {"t6"}, .Register: "x31"},
63 {.Aliases: {"ft0"}, .Register: "f0"}, {.Aliases: {"ft1"}, .Register: "f1"}, {.Aliases: {"ft2"}, .Register: "f2"}, {.Aliases: {"ft3"}, .Register: "f3"},
64 {.Aliases: {"ft4"}, .Register: "f4"}, {.Aliases: {"ft5"}, .Register: "f5"}, {.Aliases: {"ft6"}, .Register: "f6"}, {.Aliases: {"ft7"}, .Register: "f7"},
65 {.Aliases: {"fs0"}, .Register: "f8"}, {.Aliases: {"fs1"}, .Register: "f9"}, {.Aliases: {"fa0"}, .Register: "f10"}, {.Aliases: {"fa1"}, .Register: "f11"},
66 {.Aliases: {"fa2"}, .Register: "f12"}, {.Aliases: {"fa3"}, .Register: "f13"}, {.Aliases: {"fa4"}, .Register: "f14"}, {.Aliases: {"fa5"}, .Register: "f15"},
67 {.Aliases: {"fa6"}, .Register: "f16"}, {.Aliases: {"fa7"}, .Register: "f17"}, {.Aliases: {"fs2"}, .Register: "f18"}, {.Aliases: {"fs3"}, .Register: "f19"},
68 {.Aliases: {"fs4"}, .Register: "f20"}, {.Aliases: {"fs5"}, .Register: "f21"}, {.Aliases: {"fs6"}, .Register: "f22"}, {.Aliases: {"fs7"}, .Register: "f23"},
69 {.Aliases: {"fs8"}, .Register: "f24"}, {.Aliases: {"fs9"}, .Register: "f25"}, {.Aliases: {"fs10"}, .Register: "f26"}, {.Aliases: {"fs11"}, .Register: "f27"},
70 {.Aliases: {"ft8"}, .Register: "f28"}, {.Aliases: {"ft9"}, .Register: "f29"}, {.Aliases: {"ft10"}, .Register: "f30"}, {.Aliases: {"ft11"}, .Register: "f31"}};
71 return llvm::ArrayRef(GCCRegAliases);
72}
73
74bool RISCVTargetInfo::validateAsmConstraint(
75 const char *&Name, TargetInfo::ConstraintInfo &Info) const {
76 switch (*Name) {
77 default:
78 return false;
79 case 'I':
80 // A 12-bit signed immediate.
81 Info.setRequiresImmediate(Min: -2048, Max: 2047);
82 return true;
83 case 'J':
84 // Integer zero.
85 Info.setRequiresImmediate(0);
86 return true;
87 case 'K':
88 // A 5-bit unsigned immediate for CSR access instructions.
89 Info.setRequiresImmediate(Min: 0, Max: 31);
90 return true;
91 case 'f':
92 // A floating-point register.
93 Info.setAllowsRegister();
94 return true;
95 case 'A':
96 // An address that is held in a general-purpose register.
97 Info.setAllowsMemory();
98 return true;
99 case 's':
100 case 'S': // A symbol or label reference with a constant offset
101 Info.setAllowsRegister();
102 return true;
103 case 'v':
104 // A vector register.
105 if (Name[1] == 'r' || Name[1] == 'm') {
106 Info.setAllowsRegister();
107 Name += 1;
108 return true;
109 }
110 return false;
111 }
112}
113
114std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
115 std::string R;
116 switch (*Constraint) {
117 case 'v':
118 R = std::string("^") + std::string(Constraint, 2);
119 Constraint += 1;
120 break;
121 default:
122 R = TargetInfo::convertConstraint(Constraint);
123 break;
124 }
125 return R;
126}
127
128static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
129 return MajorVersion * 1000000 + MinorVersion * 1000;
130}
131
132void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
133 MacroBuilder &Builder) const {
134 Builder.defineMacro(Name: "__riscv");
135 bool Is64Bit = getTriple().isRISCV64();
136 Builder.defineMacro(Name: "__riscv_xlen", Value: Is64Bit ? "64" : "32");
137 StringRef CodeModel = getTargetOpts().CodeModel;
138 unsigned FLen = ISAInfo->getFLen();
139 unsigned MinVLen = ISAInfo->getMinVLen();
140 unsigned MaxELen = ISAInfo->getMaxELen();
141 unsigned MaxELenFp = ISAInfo->getMaxELenFp();
142 if (CodeModel == "default")
143 CodeModel = "small";
144
145 if (CodeModel == "small")
146 Builder.defineMacro(Name: "__riscv_cmodel_medlow");
147 else if (CodeModel == "medium")
148 Builder.defineMacro(Name: "__riscv_cmodel_medany");
149
150 StringRef ABIName = getABI();
151 if (ABIName == "ilp32f" || ABIName == "lp64f")
152 Builder.defineMacro(Name: "__riscv_float_abi_single");
153 else if (ABIName == "ilp32d" || ABIName == "lp64d")
154 Builder.defineMacro(Name: "__riscv_float_abi_double");
155 else
156 Builder.defineMacro(Name: "__riscv_float_abi_soft");
157
158 if (ABIName == "ilp32e" || ABIName == "lp64e")
159 Builder.defineMacro(Name: "__riscv_abi_rve");
160
161 Builder.defineMacro(Name: "__riscv_arch_test");
162
163 for (auto &Extension : ISAInfo->getExtensions()) {
164 auto ExtName = Extension.first;
165 auto ExtInfo = Extension.second;
166
167 Builder.defineMacro(Name: Twine("__riscv_", ExtName),
168 Value: Twine(getVersionValue(MajorVersion: ExtInfo.Major, MinorVersion: ExtInfo.Minor)));
169 }
170
171 if (ISAInfo->hasExtension(Ext: "m") || ISAInfo->hasExtension(Ext: "zmmul"))
172 Builder.defineMacro(Name: "__riscv_mul");
173
174 if (ISAInfo->hasExtension(Ext: "m")) {
175 Builder.defineMacro(Name: "__riscv_div");
176 Builder.defineMacro(Name: "__riscv_muldiv");
177 }
178
179 if (ISAInfo->hasExtension(Ext: "a")) {
180 Builder.defineMacro(Name: "__riscv_atomic");
181 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
182 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
183 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
184 if (Is64Bit)
185 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
186 }
187
188 if (FLen) {
189 Builder.defineMacro(Name: "__riscv_flen", Value: Twine(FLen));
190 Builder.defineMacro(Name: "__riscv_fdiv");
191 Builder.defineMacro(Name: "__riscv_fsqrt");
192 }
193
194 if (MinVLen) {
195 Builder.defineMacro(Name: "__riscv_v_min_vlen", Value: Twine(MinVLen));
196 Builder.defineMacro(Name: "__riscv_v_elen", Value: Twine(MaxELen));
197 Builder.defineMacro(Name: "__riscv_v_elen_fp", Value: Twine(MaxELenFp));
198 }
199
200 if (ISAInfo->hasExtension(Ext: "c"))
201 Builder.defineMacro(Name: "__riscv_compressed");
202
203 if (ISAInfo->hasExtension(Ext: "zve32x")) {
204 Builder.defineMacro(Name: "__riscv_vector");
205 // Currently we support the v0.12 RISC-V V intrinsics.
206 Builder.defineMacro(Name: "__riscv_v_intrinsic", Value: Twine(getVersionValue(MajorVersion: 0, MinorVersion: 12)));
207 }
208
209 auto VScale = getVScaleRange(LangOpts: Opts);
210 if (VScale && VScale->first && VScale->first == VScale->second)
211 Builder.defineMacro(Name: "__riscv_v_fixed_vlen",
212 Value: Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
213
214 if (FastUnalignedAccess)
215 Builder.defineMacro(Name: "__riscv_misaligned_fast");
216 else
217 Builder.defineMacro(Name: "__riscv_misaligned_avoid");
218
219 if (ISAInfo->hasExtension(Ext: "e")) {
220 if (Is64Bit)
221 Builder.defineMacro(Name: "__riscv_64e");
222 else
223 Builder.defineMacro(Name: "__riscv_32e");
224 }
225}
226
227static constexpr Builtin::Info BuiltinInfo[] = {
228#define BUILTIN(ID, TYPE, ATTRS) \
229 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
230#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
231 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
232#include "clang/Basic/BuiltinsRISCVVector.def"
233#define BUILTIN(ID, TYPE, ATTRS) \
234 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
235#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
236 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
237#include "clang/Basic/BuiltinsRISCV.inc"
238};
239
240ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
241 return llvm::ArrayRef(BuiltinInfo,
242 clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
243}
244
245bool RISCVTargetInfo::initFeatureMap(
246 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
247 const std::vector<std::string> &FeaturesVec) const {
248
249 unsigned XLen = 32;
250
251 if (getTriple().isRISCV64()) {
252 Features["64bit"] = true;
253 XLen = 64;
254 } else {
255 Features["32bit"] = true;
256 }
257
258 // If a target attribute specified a full arch string, override all the ISA
259 // extension target features.
260 const auto I = llvm::find(Range: FeaturesVec, Val: "__RISCV_TargetAttrNeedOverride");
261 if (I != FeaturesVec.end()) {
262 std::vector<std::string> OverrideFeatures(std::next(x: I), FeaturesVec.end());
263
264 // Add back any non ISA extension features, e.g. +relax.
265 auto IsNonISAExtFeature = [](StringRef Feature) {
266 assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));
267 StringRef Ext = Feature.substr(Start: 1); // drop the +/-
268 return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);
269 };
270 llvm::copy_if(Range: llvm::make_range(x: FeaturesVec.begin(), y: I),
271 Out: std::back_inserter(x&: OverrideFeatures), P: IsNonISAExtFeature);
272
273 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: OverrideFeatures);
274 }
275
276 // Otherwise, parse the features and add any implied extensions.
277 std::vector<std::string> AllFeatures = FeaturesVec;
278 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features: FeaturesVec);
279 if (!ParseResult) {
280 std::string Buffer;
281 llvm::raw_string_ostream OutputErrMsg(Buffer);
282 handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) {
283 OutputErrMsg << ErrMsg.getMessage();
284 });
285 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
286 return false;
287 }
288
289 // Append all features, not just new ones, so we override any negatives.
290 llvm::append_range(C&: AllFeatures, R: (*ParseResult)->toFeatures());
291 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: AllFeatures);
292}
293
294std::optional<std::pair<unsigned, unsigned>>
295RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
296 // RISCV::RVVBitsPerBlock is 64.
297 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
298
299 if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
300 // Treat Zvl*b as a lower bound on vscale.
301 VScaleMin = std::max(a: VScaleMin, b: LangOpts.VScaleMin);
302 unsigned VScaleMax = LangOpts.VScaleMax;
303 if (VScaleMax != 0 && VScaleMax < VScaleMin)
304 VScaleMax = VScaleMin;
305 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
306 }
307
308 if (VScaleMin > 0) {
309 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
310 return std::make_pair(x&: VScaleMin, y&: VScaleMax);
311 }
312
313 return std::nullopt;
314}
315
316/// Return true if has this feature, need to sync with handleTargetFeatures.
317bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
318 bool Is64Bit = getTriple().isRISCV64();
319 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
320 .Case(S: "riscv", Value: true)
321 .Case(S: "riscv32", Value: !Is64Bit)
322 .Case(S: "riscv64", Value: Is64Bit)
323 .Case(S: "32bit", Value: !Is64Bit)
324 .Case(S: "64bit", Value: Is64Bit)
325 .Case(S: "experimental", Value: HasExperimental)
326 .Default(Value: std::nullopt);
327 if (Result)
328 return *Result;
329
330 return ISAInfo->hasExtension(Ext: Feature);
331}
332
333/// Perform initialization based on the user configured set of features.
334bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
335 DiagnosticsEngine &Diags) {
336 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
337 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
338 if (!ParseResult) {
339 std::string Buffer;
340 llvm::raw_string_ostream OutputErrMsg(Buffer);
341 handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) {
342 OutputErrMsg << ErrMsg.getMessage();
343 });
344 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
345 return false;
346 } else {
347 ISAInfo = std::move(*ParseResult);
348 }
349
350 if (ABI.empty())
351 ABI = ISAInfo->computeDefaultABI().str();
352
353 if (ISAInfo->hasExtension(Ext: "zfh") || ISAInfo->hasExtension(Ext: "zhinx"))
354 HasLegalHalfType = true;
355
356 FastUnalignedAccess = llvm::is_contained(Range&: Features, Element: "+unaligned-scalar-mem") &&
357 llvm::is_contained(Range&: Features, Element: "+unaligned-vector-mem");
358
359 if (llvm::is_contained(Range&: Features, Element: "+experimental"))
360 HasExperimental = true;
361
362 if (ABI == "ilp32e" && ISAInfo->hasExtension(Ext: "d")) {
363 Diags.Report(diag::err_invalid_feature_combination)
364 << "ILP32E cannot be used with the D ISA extension";
365 return false;
366 }
367 return true;
368}
369
370bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
371 bool Is64Bit = getTriple().isArch64Bit();
372 return llvm::RISCV::parseCPU(CPU: Name, IsRV64: Is64Bit);
373}
374
375void RISCVTargetInfo::fillValidCPUList(
376 SmallVectorImpl<StringRef> &Values) const {
377 bool Is64Bit = getTriple().isArch64Bit();
378 llvm::RISCV::fillValidCPUArchList(Values, IsRV64: Is64Bit);
379}
380
381bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
382 bool Is64Bit = getTriple().isArch64Bit();
383 return llvm::RISCV::parseTuneCPU(CPU: Name, IsRV64: Is64Bit);
384}
385
386void RISCVTargetInfo::fillValidTuneCPUList(
387 SmallVectorImpl<StringRef> &Values) const {
388 bool Is64Bit = getTriple().isArch64Bit();
389 llvm::RISCV::fillValidTuneCPUArchList(Values, IsRV64: Is64Bit);
390}
391
392static void handleFullArchString(StringRef FullArchStr,
393 std::vector<std::string> &Features) {
394 Features.push_back(x: "__RISCV_TargetAttrNeedOverride");
395 auto RII = llvm::RISCVISAInfo::parseArchString(
396 Arch: FullArchStr, /* EnableExperimentalExtension */ true);
397 if (llvm::errorToBool(Err: RII.takeError())) {
398 // Forward the invalid FullArchStr.
399 Features.push_back(x: "+" + FullArchStr.str());
400 } else {
401 // Append a full list of features, including any negative extensions so that
402 // we override the CPU's features.
403 std::vector<std::string> FeatStrings =
404 (*RII)->toFeatures(/* AddAllExtensions */ true);
405 Features.insert(position: Features.end(), first: FeatStrings.begin(), last: FeatStrings.end());
406 }
407}
408
409ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
410 ParsedTargetAttr Ret;
411 if (Features == "default")
412 return Ret;
413 SmallVector<StringRef, 1> AttrFeatures;
414 Features.split(A&: AttrFeatures, Separator: ";");
415 bool FoundArch = false;
416
417 for (auto &Feature : AttrFeatures) {
418 Feature = Feature.trim();
419 StringRef AttrString = Feature.split(Separator: "=").second.trim();
420
421 if (Feature.starts_with(Prefix: "arch=")) {
422 // Override last features
423 Ret.Features.clear();
424 if (FoundArch)
425 Ret.Duplicate = "arch=";
426 FoundArch = true;
427
428 if (AttrString.starts_with(Prefix: "+")) {
429 // EXTENSION like arch=+v,+zbb
430 SmallVector<StringRef, 1> Exts;
431 AttrString.split(A&: Exts, Separator: ",");
432 for (auto Ext : Exts) {
433 if (Ext.empty())
434 continue;
435
436 StringRef ExtName = Ext.substr(Start: 1);
437 std::string TargetFeature =
438 llvm::RISCVISAInfo::getTargetFeatureForExtension(Ext: ExtName);
439 if (!TargetFeature.empty())
440 Ret.Features.push_back(x: Ext.front() + TargetFeature);
441 else
442 Ret.Features.push_back(x: Ext.str());
443 }
444 } else {
445 // full-arch-string like arch=rv64gcv
446 handleFullArchString(FullArchStr: AttrString, Features&: Ret.Features);
447 }
448 } else if (Feature.starts_with(Prefix: "cpu=")) {
449 if (!Ret.CPU.empty())
450 Ret.Duplicate = "cpu=";
451
452 Ret.CPU = AttrString;
453
454 if (!FoundArch) {
455 // Update Features with CPU's features
456 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU: Ret.CPU);
457 if (MarchFromCPU != "") {
458 Ret.Features.clear();
459 handleFullArchString(FullArchStr: MarchFromCPU, Features&: Ret.Features);
460 }
461 }
462 } else if (Feature.starts_with(Prefix: "tune=")) {
463 if (!Ret.Tune.empty())
464 Ret.Duplicate = "tune=";
465
466 Ret.Tune = AttrString;
467 }
468 }
469 return Ret;
470}
471
472TargetInfo::CallingConvCheckResult
473RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
474 switch (CC) {
475 default:
476 return CCCR_Warning;
477 case CC_C:
478 case CC_RISCVVectorCall:
479 return CCCR_OK;
480 }
481}
482

source code of clang/lib/Basic/Targets/RISCV.cpp