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", "sf.vcix_state"
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 'c':
104 // A RVC register - GPR or FPR
105 if (Name[1] == 'r' || Name[1] == 'R' || Name[1] == 'f') {
106 Info.setAllowsRegister();
107 Name += 1;
108 return true;
109 }
110 return false;
111 case 'R':
112 // An even-odd GPR pair
113 Info.setAllowsRegister();
114 return true;
115 case 'v':
116 // A vector register.
117 if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {
118 Info.setAllowsRegister();
119 Name += 1;
120 return true;
121 }
122 return false;
123 }
124}
125
126std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
127 std::string R;
128 switch (*Constraint) {
129 // c* and v* are two-letter constraints on RISC-V.
130 case 'c':
131 case 'v':
132 R = std::string("^") + std::string(Constraint, 2);
133 Constraint += 1;
134 break;
135 default:
136 R = TargetInfo::convertConstraint(Constraint);
137 break;
138 }
139 return R;
140}
141
142static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
143 return MajorVersion * 1000000 + MinorVersion * 1000;
144}
145
146void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
147 MacroBuilder &Builder) const {
148 Builder.defineMacro(Name: "__riscv");
149 bool Is64Bit = getTriple().isRISCV64();
150 Builder.defineMacro(Name: "__riscv_xlen", Value: Is64Bit ? "64" : "32");
151 StringRef CodeModel = getTargetOpts().CodeModel;
152 unsigned FLen = ISAInfo->getFLen();
153 unsigned MinVLen = ISAInfo->getMinVLen();
154 unsigned MaxELen = ISAInfo->getMaxELen();
155 unsigned MaxELenFp = ISAInfo->getMaxELenFp();
156 if (CodeModel == "default")
157 CodeModel = "small";
158
159 if (CodeModel == "small")
160 Builder.defineMacro(Name: "__riscv_cmodel_medlow");
161 else if (CodeModel == "medium")
162 Builder.defineMacro(Name: "__riscv_cmodel_medany");
163 else if (CodeModel == "large")
164 Builder.defineMacro(Name: "__riscv_cmodel_large");
165
166 StringRef ABIName = getABI();
167 if (ABIName == "ilp32f" || ABIName == "lp64f")
168 Builder.defineMacro(Name: "__riscv_float_abi_single");
169 else if (ABIName == "ilp32d" || ABIName == "lp64d")
170 Builder.defineMacro(Name: "__riscv_float_abi_double");
171 else
172 Builder.defineMacro(Name: "__riscv_float_abi_soft");
173
174 if (ABIName == "ilp32e" || ABIName == "lp64e")
175 Builder.defineMacro(Name: "__riscv_abi_rve");
176
177 Builder.defineMacro(Name: "__riscv_arch_test");
178
179 for (auto &Extension : ISAInfo->getExtensions()) {
180 auto ExtName = Extension.first;
181 auto ExtInfo = Extension.second;
182
183 Builder.defineMacro(Name: Twine("__riscv_", ExtName),
184 Value: Twine(getVersionValue(MajorVersion: ExtInfo.Major, MinorVersion: ExtInfo.Minor)));
185 }
186
187 if (ISAInfo->hasExtension(Ext: "zmmul"))
188 Builder.defineMacro(Name: "__riscv_mul");
189
190 if (ISAInfo->hasExtension(Ext: "m")) {
191 Builder.defineMacro(Name: "__riscv_div");
192 Builder.defineMacro(Name: "__riscv_muldiv");
193 }
194
195 // The "a" extension is composed of "zalrsc" and "zaamo"
196 if (ISAInfo->hasExtension(Ext: "a"))
197 Builder.defineMacro(Name: "__riscv_atomic");
198
199 if (ISAInfo->hasExtension(Ext: "zalrsc")) {
200 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
201 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
202 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
203 if (Is64Bit)
204 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
205 }
206
207 if (FLen) {
208 Builder.defineMacro(Name: "__riscv_flen", Value: Twine(FLen));
209 Builder.defineMacro(Name: "__riscv_fdiv");
210 Builder.defineMacro(Name: "__riscv_fsqrt");
211 }
212
213 if (MinVLen) {
214 Builder.defineMacro(Name: "__riscv_v_min_vlen", Value: Twine(MinVLen));
215 Builder.defineMacro(Name: "__riscv_v_elen", Value: Twine(MaxELen));
216 Builder.defineMacro(Name: "__riscv_v_elen_fp", Value: Twine(MaxELenFp));
217 }
218
219 if (ISAInfo->hasExtension(Ext: "c"))
220 Builder.defineMacro(Name: "__riscv_compressed");
221
222 if (ISAInfo->hasExtension(Ext: "zve32x"))
223 Builder.defineMacro(Name: "__riscv_vector");
224
225 // Currently we support the v1.0 RISC-V V intrinsics.
226 Builder.defineMacro(Name: "__riscv_v_intrinsic", Value: Twine(getVersionValue(MajorVersion: 1, MinorVersion: 0)));
227
228 auto VScale = getVScaleRange(LangOpts: Opts, Mode: ArmStreamingKind::NotStreaming);
229 if (VScale && VScale->first && VScale->first == VScale->second)
230 Builder.defineMacro(Name: "__riscv_v_fixed_vlen",
231 Value: Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
232
233 if (FastScalarUnalignedAccess)
234 Builder.defineMacro(Name: "__riscv_misaligned_fast");
235 else
236 Builder.defineMacro(Name: "__riscv_misaligned_avoid");
237
238 if (ISAInfo->hasExtension(Ext: "e")) {
239 if (Is64Bit)
240 Builder.defineMacro(Name: "__riscv_64e");
241 else
242 Builder.defineMacro(Name: "__riscv_32e");
243 }
244
245 if (Opts.CFProtectionReturn && ISAInfo->hasExtension(Ext: "zicfiss"))
246 Builder.defineMacro(Name: "__riscv_shadow_stack");
247
248 if (Opts.CFProtectionBranch) {
249 auto Scheme = Opts.getCFBranchLabelScheme();
250 if (Scheme == CFBranchLabelSchemeKind::Default)
251 Scheme = getDefaultCFBranchLabelScheme();
252
253 Builder.defineMacro(Name: "__riscv_landing_pad");
254 switch (Scheme) {
255 case CFBranchLabelSchemeKind::Unlabeled:
256 Builder.defineMacro(Name: "__riscv_landing_pad_unlabeled");
257 break;
258 case CFBranchLabelSchemeKind::FuncSig:
259 // TODO: Define macros after the func-sig scheme is implemented
260 break;
261 case CFBranchLabelSchemeKind::Default:
262 llvm_unreachable("default cf-branch-label scheme should already be "
263 "transformed to other scheme");
264 }
265 }
266}
267
268static constexpr int NumRVVBuiltins =
269 RISCVVector::FirstSiFiveBuiltin - Builtin::FirstTSBuiltin;
270static constexpr int NumRVVSiFiveBuiltins =
271 RISCVVector::FirstAndesBuiltin - RISCVVector::FirstSiFiveBuiltin;
272static constexpr int NumRVVAndesBuiltins =
273 RISCVVector::FirstTSBuiltin - RISCVVector::FirstAndesBuiltin;
274static constexpr int NumRISCVBuiltins =
275 RISCV::LastTSBuiltin - RISCVVector::FirstTSBuiltin;
276static constexpr int NumBuiltins =
277 RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin;
278static_assert(NumBuiltins == (NumRVVBuiltins + NumRVVSiFiveBuiltins +
279 NumRVVAndesBuiltins + NumRISCVBuiltins));
280
281namespace RVV {
282#define GET_RISCVV_BUILTIN_STR_TABLE
283#include "clang/Basic/riscv_vector_builtins.inc"
284#undef GET_RISCVV_BUILTIN_STR_TABLE
285static_assert(BuiltinStrings.size() < 100'000);
286
287static constexpr std::array<Builtin::Info, NumRVVBuiltins> BuiltinInfos = {
288#define GET_RISCVV_BUILTIN_INFOS
289#include "clang/Basic/riscv_vector_builtins.inc"
290#undef GET_RISCVV_BUILTIN_INFOS
291};
292} // namespace RVV
293
294namespace RVVSiFive {
295#define GET_RISCVV_BUILTIN_STR_TABLE
296#include "clang/Basic/riscv_sifive_vector_builtins.inc"
297#undef GET_RISCVV_BUILTIN_STR_TABLE
298
299static constexpr std::array<Builtin::Info, NumRVVSiFiveBuiltins> BuiltinInfos =
300 {
301#define GET_RISCVV_BUILTIN_INFOS
302#include "clang/Basic/riscv_sifive_vector_builtins.inc"
303#undef GET_RISCVV_BUILTIN_INFOS
304};
305} // namespace RVVSiFive
306
307namespace RVVAndes {
308#define GET_RISCVV_BUILTIN_STR_TABLE
309#include "clang/Basic/riscv_andes_vector_builtins.inc"
310#undef GET_RISCVV_BUILTIN_STR_TABLE
311
312static constexpr std::array<Builtin::Info, NumRVVAndesBuiltins> BuiltinInfos =
313 {
314#define GET_RISCVV_BUILTIN_INFOS
315#include "clang/Basic/riscv_andes_vector_builtins.inc"
316#undef GET_RISCVV_BUILTIN_INFOS
317};
318} // namespace RVVAndes
319
320#define GET_BUILTIN_STR_TABLE
321#include "clang/Basic/BuiltinsRISCV.inc"
322#undef GET_BUILTIN_STR_TABLE
323
324static constexpr Builtin::Info BuiltinInfos[] = {
325#define GET_BUILTIN_INFOS
326#include "clang/Basic/BuiltinsRISCV.inc"
327#undef GET_BUILTIN_INFOS
328};
329static_assert(std::size(BuiltinInfos) == NumRISCVBuiltins);
330
331llvm::SmallVector<Builtin::InfosShard>
332RISCVTargetInfo::getTargetBuiltins() const {
333 return {
334 {.Strings: &RVV::BuiltinStrings, .Infos: RVV::BuiltinInfos, .NamePrefix: "__builtin_rvv_"},
335 {.Strings: &RVVSiFive::BuiltinStrings, .Infos: RVVSiFive::BuiltinInfos, .NamePrefix: "__builtin_rvv_"},
336 {.Strings: &RVVAndes::BuiltinStrings, .Infos: RVVAndes::BuiltinInfos, .NamePrefix: "__builtin_rvv_"},
337 {.Strings: &BuiltinStrings, .Infos: BuiltinInfos},
338 };
339}
340
341bool RISCVTargetInfo::initFeatureMap(
342 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
343 const std::vector<std::string> &FeaturesVec) const {
344
345 unsigned XLen = 32;
346
347 if (getTriple().isRISCV64()) {
348 Features["64bit"] = true;
349 XLen = 64;
350 } else {
351 Features["32bit"] = true;
352 }
353
354 std::vector<std::string> AllFeatures = FeaturesVec;
355 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features: FeaturesVec);
356 if (!ParseResult) {
357 std::string Buffer;
358 llvm::raw_string_ostream OutputErrMsg(Buffer);
359 handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) {
360 OutputErrMsg << ErrMsg.getMessage();
361 });
362 Diags.Report(DiagID: diag::err_invalid_feature_combination) << OutputErrMsg.str();
363 return false;
364 }
365
366 // Append all features, not just new ones, so we override any negatives.
367 llvm::append_range(C&: AllFeatures, R: (*ParseResult)->toFeatures());
368 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: AllFeatures);
369}
370
371std::optional<std::pair<unsigned, unsigned>>
372RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts,
373 ArmStreamingKind IsArmStreamingFunction,
374 llvm::StringMap<bool> *FeatureMap) const {
375 // RISCV::RVVBitsPerBlock is 64.
376 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
377
378 if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
379 // Treat Zvl*b as a lower bound on vscale.
380 VScaleMin = std::max(a: VScaleMin, b: LangOpts.VScaleMin);
381 unsigned VScaleMax = LangOpts.VScaleMax;
382 if (VScaleMax != 0 && VScaleMax < VScaleMin)
383 VScaleMax = VScaleMin;
384 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
385 }
386
387 if (VScaleMin > 0) {
388 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
389 return std::make_pair(x&: VScaleMin, y&: VScaleMax);
390 }
391
392 return std::nullopt;
393}
394
395/// Return true if has this feature, need to sync with handleTargetFeatures.
396bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
397 bool Is64Bit = getTriple().isRISCV64();
398 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
399 .Case(S: "riscv", Value: true)
400 .Case(S: "riscv32", Value: !Is64Bit)
401 .Case(S: "riscv64", Value: Is64Bit)
402 .Case(S: "32bit", Value: !Is64Bit)
403 .Case(S: "64bit", Value: Is64Bit)
404 .Case(S: "experimental", Value: HasExperimental)
405 .Default(Value: std::nullopt);
406 if (Result)
407 return *Result;
408
409 return ISAInfo->hasExtension(Ext: Feature);
410}
411
412/// Perform initialization based on the user configured set of features.
413bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
414 DiagnosticsEngine &Diags) {
415 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
416 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
417 if (!ParseResult) {
418 std::string Buffer;
419 llvm::raw_string_ostream OutputErrMsg(Buffer);
420 handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) {
421 OutputErrMsg << ErrMsg.getMessage();
422 });
423 Diags.Report(DiagID: diag::err_invalid_feature_combination) << OutputErrMsg.str();
424 return false;
425 } else {
426 ISAInfo = std::move(*ParseResult);
427 }
428
429 if (ABI.empty())
430 ABI = ISAInfo->computeDefaultABI().str();
431
432 if (ISAInfo->hasExtension(Ext: "zfh") || ISAInfo->hasExtension(Ext: "zhinx"))
433 HasFastHalfType = true;
434
435 FastScalarUnalignedAccess =
436 llvm::is_contained(Range&: Features, Element: "+unaligned-scalar-mem");
437
438 if (llvm::is_contained(Range&: Features, Element: "+experimental"))
439 HasExperimental = true;
440
441 if (ABI == "ilp32e" && ISAInfo->hasExtension(Ext: "d")) {
442 Diags.Report(DiagID: diag::err_invalid_feature_combination)
443 << "ILP32E cannot be used with the D ISA extension";
444 return false;
445 }
446 return true;
447}
448
449bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
450 bool Is64Bit = getTriple().isArch64Bit();
451 return llvm::RISCV::parseCPU(CPU: Name, IsRV64: Is64Bit);
452}
453
454void RISCVTargetInfo::fillValidCPUList(
455 SmallVectorImpl<StringRef> &Values) const {
456 bool Is64Bit = getTriple().isArch64Bit();
457 llvm::RISCV::fillValidCPUArchList(Values, IsRV64: Is64Bit);
458}
459
460bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
461 bool Is64Bit = getTriple().isArch64Bit();
462 return llvm::RISCV::parseTuneCPU(CPU: Name, IsRV64: Is64Bit);
463}
464
465void RISCVTargetInfo::fillValidTuneCPUList(
466 SmallVectorImpl<StringRef> &Values) const {
467 bool Is64Bit = getTriple().isArch64Bit();
468 llvm::RISCV::fillValidTuneCPUArchList(Values, IsRV64: Is64Bit);
469}
470
471static void populateNegativeRISCVFeatures(std::vector<std::string> &Features) {
472 auto RII = llvm::RISCVISAInfo::parseArchString(
473 Arch: "rv64i", /* EnableExperimentalExtension */ true);
474
475 if (llvm::errorToBool(Err: RII.takeError()))
476 llvm_unreachable("unsupport rv64i");
477
478 std::vector<std::string> FeatStrings =
479 (*RII)->toFeatures(/* AddAllExtensions */ true);
480 llvm::append_range(C&: Features, R&: FeatStrings);
481}
482
483static void handleFullArchString(StringRef FullArchStr,
484 std::vector<std::string> &Features) {
485 auto RII = llvm::RISCVISAInfo::parseArchString(
486 Arch: FullArchStr, /* EnableExperimentalExtension */ true);
487 if (llvm::errorToBool(Err: RII.takeError())) {
488 // Forward the invalid FullArchStr.
489 Features.push_back(x: FullArchStr.str());
490 } else {
491 // Append a full list of features, including any negative extensions so that
492 // we override the CPU's features.
493 populateNegativeRISCVFeatures(Features);
494 std::vector<std::string> FeatStrings =
495 (*RII)->toFeatures(/* AddAllExtensions */ true);
496 llvm::append_range(C&: Features, R&: FeatStrings);
497 }
498}
499
500ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
501 ParsedTargetAttr Ret;
502 if (Features == "default")
503 return Ret;
504 SmallVector<StringRef, 1> AttrFeatures;
505 Features.split(A&: AttrFeatures, Separator: ";");
506 bool FoundArch = false;
507
508 auto handleArchExtension = [](StringRef AttrString,
509 std::vector<std::string> &Features) {
510 SmallVector<StringRef, 1> Exts;
511 AttrString.split(A&: Exts, Separator: ",");
512 for (auto Ext : Exts) {
513 if (Ext.empty())
514 continue;
515
516 StringRef ExtName = Ext.substr(Start: 1);
517 std::string TargetFeature =
518 llvm::RISCVISAInfo::getTargetFeatureForExtension(Ext: ExtName);
519 if (!TargetFeature.empty())
520 Features.push_back(x: Ext.front() + TargetFeature);
521 else
522 Features.push_back(x: Ext.str());
523 }
524 };
525
526 for (auto &Feature : AttrFeatures) {
527 Feature = Feature.trim();
528 StringRef AttrString = Feature.split(Separator: "=").second.trim();
529
530 if (Feature.starts_with(Prefix: "arch=")) {
531 // Override last features
532 Ret.Features.clear();
533 if (FoundArch)
534 Ret.Duplicate = "arch=";
535 FoundArch = true;
536
537 if (AttrString.starts_with(Prefix: "+")) {
538 // EXTENSION like arch=+v,+zbb
539 handleArchExtension(AttrString, Ret.Features);
540 } else {
541 // full-arch-string like arch=rv64gcv
542 handleFullArchString(FullArchStr: AttrString, Features&: Ret.Features);
543 }
544 } else if (Feature.starts_with(Prefix: "cpu=")) {
545 if (!Ret.CPU.empty())
546 Ret.Duplicate = "cpu=";
547
548 Ret.CPU = AttrString;
549
550 if (!FoundArch) {
551 // Update Features with CPU's features
552 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU: Ret.CPU);
553 if (MarchFromCPU != "") {
554 Ret.Features.clear();
555 handleFullArchString(FullArchStr: MarchFromCPU, Features&: Ret.Features);
556 }
557 }
558 } else if (Feature.starts_with(Prefix: "tune=")) {
559 if (!Ret.Tune.empty())
560 Ret.Duplicate = "tune=";
561
562 Ret.Tune = AttrString;
563 } else if (Feature.starts_with(Prefix: "priority")) {
564 // Skip because it only use for FMV.
565 } else if (Feature.starts_with(Prefix: "+")) {
566 // Handle target_version/target_clones attribute strings
567 // that are already delimited by ','
568 handleArchExtension(Feature, Ret.Features);
569 }
570 }
571 return Ret;
572}
573
574llvm::APInt
575RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
576 // Priority is explicitly specified on RISC-V unlike on other targets, where
577 // it is derived by all the features of a specific version. Therefore if a
578 // feature contains the priority string, then return it immediately.
579 for (StringRef Feature : Features) {
580 auto [LHS, RHS] = Feature.rsplit(Separator: ';');
581 if (LHS.consume_front(Prefix: "priority="))
582 Feature = LHS;
583 else if (RHS.consume_front(Prefix: "priority="))
584 Feature = RHS;
585 else
586 continue;
587 unsigned Priority;
588 if (!Feature.getAsInteger(Radix: 0, Result&: Priority))
589 return llvm::APInt(32, Priority);
590 }
591 // Default Priority is zero.
592 return llvm::APInt::getZero(numBits: 32);
593}
594
595TargetInfo::CallingConvCheckResult
596RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
597 switch (CC) {
598 default:
599 return CCCR_Warning;
600 case CC_C:
601 case CC_RISCVVectorCall:
602 case CC_RISCVVLSCall_32:
603 case CC_RISCVVLSCall_64:
604 case CC_RISCVVLSCall_128:
605 case CC_RISCVVLSCall_256:
606 case CC_RISCVVLSCall_512:
607 case CC_RISCVVLSCall_1024:
608 case CC_RISCVVLSCall_2048:
609 case CC_RISCVVLSCall_4096:
610 case CC_RISCVVLSCall_8192:
611 case CC_RISCVVLSCall_16384:
612 case CC_RISCVVLSCall_32768:
613 case CC_RISCVVLSCall_65536:
614 return CCCR_OK;
615 }
616}
617
618bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const {
619 // Only allow extensions we have a known bit position for in the
620 // __riscv_feature_bits structure.
621 return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitsInfo(Ext: Feature).second;
622}
623
624bool RISCVTargetInfo::isValidFeatureName(StringRef Name) const {
625 return llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext: Name);
626}
627
628bool RISCVTargetInfo::validateGlobalRegisterVariable(
629 StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const {
630 if (RegName == "ra" || RegName == "sp" || RegName == "gp" ||
631 RegName == "tp" || RegName.starts_with(Prefix: "x") || RegName.starts_with(Prefix: "a") ||
632 RegName.starts_with(Prefix: "s") || RegName.starts_with(Prefix: "t")) {
633 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
634 HasSizeMismatch = RegSize != XLen;
635 return true;
636 }
637 return false;
638}
639
640bool RISCVTargetInfo::validateCpuIs(StringRef CPUName) const {
641 assert(getTriple().isOSLinux() &&
642 "__builtin_cpu_is() is only supported for Linux.");
643
644 return llvm::RISCV::hasValidCPUModel(CPU: CPUName);
645}
646