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/ADT/Twine.h"
19#include "llvm/Support/raw_ostream.h"
20#include "llvm/TargetParser/RISCVTargetParser.h"
21#include <optional>
22
23using namespace clang;
24using namespace clang::targets;
25
26ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
27 // clang-format off
28 static const char *const GCCRegNames[] = {
29 // Integer registers
30 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
31 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
32 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
33 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
34
35 // Floating point registers
36 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
37 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
38 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
39 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
40
41 // Vector registers
42 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
43 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
44 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
45 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
46
47 // CSRs
48 "fflags", "frm", "vtype", "vl", "vxsat", "vxrm", "sf.vcix_state"
49 };
50 // clang-format on
51 return llvm::ArrayRef(GCCRegNames);
52}
53
54ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
55 static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
56 {.Aliases: {"zero"}, .Register: "x0"}, {.Aliases: {"ra"}, .Register: "x1"}, {.Aliases: {"sp"}, .Register: "x2"}, {.Aliases: {"gp"}, .Register: "x3"},
57 {.Aliases: {"tp"}, .Register: "x4"}, {.Aliases: {"t0"}, .Register: "x5"}, {.Aliases: {"t1"}, .Register: "x6"}, {.Aliases: {"t2"}, .Register: "x7"},
58 {.Aliases: {"s0"}, .Register: "x8"}, {.Aliases: {"s1"}, .Register: "x9"}, {.Aliases: {"a0"}, .Register: "x10"}, {.Aliases: {"a1"}, .Register: "x11"},
59 {.Aliases: {"a2"}, .Register: "x12"}, {.Aliases: {"a3"}, .Register: "x13"}, {.Aliases: {"a4"}, .Register: "x14"}, {.Aliases: {"a5"}, .Register: "x15"},
60 {.Aliases: {"a6"}, .Register: "x16"}, {.Aliases: {"a7"}, .Register: "x17"}, {.Aliases: {"s2"}, .Register: "x18"}, {.Aliases: {"s3"}, .Register: "x19"},
61 {.Aliases: {"s4"}, .Register: "x20"}, {.Aliases: {"s5"}, .Register: "x21"}, {.Aliases: {"s6"}, .Register: "x22"}, {.Aliases: {"s7"}, .Register: "x23"},
62 {.Aliases: {"s8"}, .Register: "x24"}, {.Aliases: {"s9"}, .Register: "x25"}, {.Aliases: {"s10"}, .Register: "x26"}, {.Aliases: {"s11"}, .Register: "x27"},
63 {.Aliases: {"t3"}, .Register: "x28"}, {.Aliases: {"t4"}, .Register: "x29"}, {.Aliases: {"t5"}, .Register: "x30"}, {.Aliases: {"t6"}, .Register: "x31"},
64 {.Aliases: {"ft0"}, .Register: "f0"}, {.Aliases: {"ft1"}, .Register: "f1"}, {.Aliases: {"ft2"}, .Register: "f2"}, {.Aliases: {"ft3"}, .Register: "f3"},
65 {.Aliases: {"ft4"}, .Register: "f4"}, {.Aliases: {"ft5"}, .Register: "f5"}, {.Aliases: {"ft6"}, .Register: "f6"}, {.Aliases: {"ft7"}, .Register: "f7"},
66 {.Aliases: {"fs0"}, .Register: "f8"}, {.Aliases: {"fs1"}, .Register: "f9"}, {.Aliases: {"fa0"}, .Register: "f10"}, {.Aliases: {"fa1"}, .Register: "f11"},
67 {.Aliases: {"fa2"}, .Register: "f12"}, {.Aliases: {"fa3"}, .Register: "f13"}, {.Aliases: {"fa4"}, .Register: "f14"}, {.Aliases: {"fa5"}, .Register: "f15"},
68 {.Aliases: {"fa6"}, .Register: "f16"}, {.Aliases: {"fa7"}, .Register: "f17"}, {.Aliases: {"fs2"}, .Register: "f18"}, {.Aliases: {"fs3"}, .Register: "f19"},
69 {.Aliases: {"fs4"}, .Register: "f20"}, {.Aliases: {"fs5"}, .Register: "f21"}, {.Aliases: {"fs6"}, .Register: "f22"}, {.Aliases: {"fs7"}, .Register: "f23"},
70 {.Aliases: {"fs8"}, .Register: "f24"}, {.Aliases: {"fs9"}, .Register: "f25"}, {.Aliases: {"fs10"}, .Register: "f26"}, {.Aliases: {"fs11"}, .Register: "f27"},
71 {.Aliases: {"ft8"}, .Register: "f28"}, {.Aliases: {"ft9"}, .Register: "f29"}, {.Aliases: {"ft10"}, .Register: "f30"}, {.Aliases: {"ft11"}, .Register: "f31"}};
72 return llvm::ArrayRef(GCCRegAliases);
73}
74
75bool RISCVTargetInfo::validateAsmConstraint(
76 const char *&Name, TargetInfo::ConstraintInfo &Info) const {
77 switch (*Name) {
78 default:
79 return false;
80 case 'I':
81 // A 12-bit signed immediate.
82 Info.setRequiresImmediate(Min: -2048, Max: 2047);
83 return true;
84 case 'J':
85 // Integer zero.
86 Info.setRequiresImmediate(0);
87 return true;
88 case 'K':
89 // A 5-bit unsigned immediate for CSR access instructions.
90 Info.setRequiresImmediate(Min: 0, Max: 31);
91 return true;
92 case 'f':
93 // A floating-point register.
94 Info.setAllowsRegister();
95 return true;
96 case 'A':
97 // An address that is held in a general-purpose register.
98 Info.setAllowsMemory();
99 return true;
100 case 's':
101 case 'S': // A symbol or label reference with a constant offset
102 Info.setAllowsRegister();
103 return true;
104 case 'c':
105 // A RVC register - GPR or FPR
106 if (Name[1] == 'r' || Name[1] == 'R' || Name[1] == 'f') {
107 Info.setAllowsRegister();
108 Name += 1;
109 return true;
110 }
111 return false;
112 case 'R':
113 // An even-odd GPR pair
114 Info.setAllowsRegister();
115 return true;
116 case 'v':
117 // A vector register.
118 if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {
119 Info.setAllowsRegister();
120 Name += 1;
121 return true;
122 }
123 return false;
124 }
125}
126
127std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
128 std::string R;
129 switch (*Constraint) {
130 // c* and v* are two-letter constraints on RISC-V.
131 case 'c':
132 case 'v':
133 R = std::string("^") + std::string(Constraint, 2);
134 Constraint += 1;
135 break;
136 default:
137 R = TargetInfo::convertConstraint(Constraint);
138 break;
139 }
140 return R;
141}
142
143static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
144 return MajorVersion * 1000000 + MinorVersion * 1000;
145}
146
147void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
148 MacroBuilder &Builder) const {
149 Builder.defineMacro(Name: "__riscv");
150 bool Is64Bit = getTriple().isRISCV64();
151 Builder.defineMacro(Name: "__riscv_xlen", Value: Is64Bit ? "64" : "32");
152 StringRef CodeModel = getTargetOpts().CodeModel;
153 unsigned FLen = ISAInfo->getFLen();
154 unsigned MinVLen = ISAInfo->getMinVLen();
155 unsigned MaxELen = ISAInfo->getMaxELen();
156 unsigned MaxELenFp = ISAInfo->getMaxELenFp();
157 if (CodeModel == "default")
158 CodeModel = "small";
159
160 if (CodeModel == "small")
161 Builder.defineMacro(Name: "__riscv_cmodel_medlow");
162 else if (CodeModel == "medium")
163 Builder.defineMacro(Name: "__riscv_cmodel_medany");
164 else if (CodeModel == "large")
165 Builder.defineMacro(Name: "__riscv_cmodel_large");
166
167 StringRef ABIName = getABI();
168 if (ABIName == "ilp32f" || ABIName == "lp64f")
169 Builder.defineMacro(Name: "__riscv_float_abi_single");
170 else if (ABIName == "ilp32d" || ABIName == "lp64d")
171 Builder.defineMacro(Name: "__riscv_float_abi_double");
172 else
173 Builder.defineMacro(Name: "__riscv_float_abi_soft");
174
175 if (ABIName == "ilp32e" || ABIName == "lp64e")
176 Builder.defineMacro(Name: "__riscv_abi_rve");
177
178 Builder.defineMacro(Name: "__riscv_arch_test");
179
180 for (auto &Extension : ISAInfo->getExtensions()) {
181 auto ExtName = Extension.first;
182 auto ExtInfo = Extension.second;
183
184 Builder.defineMacro(Name: Twine("__riscv_", ExtName),
185 Value: Twine(getVersionValue(MajorVersion: ExtInfo.Major, MinorVersion: ExtInfo.Minor)));
186 }
187
188 if (ISAInfo->hasExtension(Ext: "zmmul"))
189 Builder.defineMacro(Name: "__riscv_mul");
190
191 if (ISAInfo->hasExtension(Ext: "m")) {
192 Builder.defineMacro(Name: "__riscv_div");
193 Builder.defineMacro(Name: "__riscv_muldiv");
194 }
195
196 // The "a" extension is composed of "zalrsc" and "zaamo"
197 if (ISAInfo->hasExtension(Ext: "a"))
198 Builder.defineMacro(Name: "__riscv_atomic");
199
200 if (ISAInfo->hasExtension(Ext: "zalrsc")) {
201 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
202 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
203 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
204 if (Is64Bit)
205 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
206 }
207
208 if (FLen) {
209 Builder.defineMacro(Name: "__riscv_flen", Value: Twine(FLen));
210 Builder.defineMacro(Name: "__riscv_fdiv");
211 Builder.defineMacro(Name: "__riscv_fsqrt");
212 }
213
214 if (MinVLen) {
215 Builder.defineMacro(Name: "__riscv_v_min_vlen", Value: Twine(MinVLen));
216 Builder.defineMacro(Name: "__riscv_v_elen", Value: Twine(MaxELen));
217 Builder.defineMacro(Name: "__riscv_v_elen_fp", Value: Twine(MaxELenFp));
218 }
219
220 if (ISAInfo->hasExtension(Ext: "c"))
221 Builder.defineMacro(Name: "__riscv_compressed");
222
223 if (ISAInfo->hasExtension(Ext: "zve32x"))
224 Builder.defineMacro(Name: "__riscv_vector");
225
226 // Currently we support the v1.0 RISC-V V intrinsics.
227 Builder.defineMacro(Name: "__riscv_v_intrinsic", Value: Twine(getVersionValue(MajorVersion: 1, MinorVersion: 0)));
228
229 auto VScale = getVScaleRange(LangOpts: Opts, Mode: ArmStreamingKind::NotStreaming);
230 if (VScale && VScale->first && VScale->first == VScale->second)
231 Builder.defineMacro(Name: "__riscv_v_fixed_vlen",
232 Value: Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
233
234 if (FastScalarUnalignedAccess)
235 Builder.defineMacro(Name: "__riscv_misaligned_fast");
236 else
237 Builder.defineMacro(Name: "__riscv_misaligned_avoid");
238
239 if (ISAInfo->hasExtension(Ext: "e")) {
240 if (Is64Bit)
241 Builder.defineMacro(Name: "__riscv_64e");
242 else
243 Builder.defineMacro(Name: "__riscv_32e");
244 }
245
246 if (Opts.CFProtectionReturn && ISAInfo->hasExtension(Ext: "zicfiss"))
247 Builder.defineMacro(Name: "__riscv_shadow_stack");
248
249 if (Opts.CFProtectionBranch) {
250 auto Scheme = Opts.getCFBranchLabelScheme();
251 if (Scheme == CFBranchLabelSchemeKind::Default)
252 Scheme = getDefaultCFBranchLabelScheme();
253
254 Builder.defineMacro(Name: "__riscv_landing_pad");
255 switch (Scheme) {
256 case CFBranchLabelSchemeKind::Unlabeled:
257 Builder.defineMacro(Name: "__riscv_landing_pad_unlabeled");
258 break;
259 case CFBranchLabelSchemeKind::FuncSig:
260 // TODO: Define macros after the func-sig scheme is implemented
261 break;
262 case CFBranchLabelSchemeKind::Default:
263 llvm_unreachable("default cf-branch-label scheme should already be "
264 "transformed to other scheme");
265 }
266 }
267}
268
269static constexpr int NumRVVBuiltins =
270 RISCVVector::FirstSiFiveBuiltin - Builtin::FirstTSBuiltin;
271static constexpr int NumRVVSiFiveBuiltins =
272 RISCVVector::FirstAndesBuiltin - RISCVVector::FirstSiFiveBuiltin;
273static constexpr int NumRVVAndesBuiltins =
274 RISCVVector::FirstTSBuiltin - RISCVVector::FirstAndesBuiltin;
275static constexpr int NumRISCVBuiltins =
276 RISCV::LastTSBuiltin - RISCVVector::FirstTSBuiltin;
277static constexpr int NumBuiltins =
278 RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin;
279static_assert(NumBuiltins == (NumRVVBuiltins + NumRVVSiFiveBuiltins +
280 NumRVVAndesBuiltins + NumRISCVBuiltins));
281
282namespace RVV {
283#define GET_RISCVV_BUILTIN_STR_TABLE
284#include "clang/Basic/riscv_vector_builtins.inc"
285#undef GET_RISCVV_BUILTIN_STR_TABLE
286static_assert(BuiltinStrings.size() < 100'000);
287
288static constexpr std::array<Builtin::Info, NumRVVBuiltins> BuiltinInfos = {
289#define GET_RISCVV_BUILTIN_INFOS
290#include "clang/Basic/riscv_vector_builtins.inc"
291#undef GET_RISCVV_BUILTIN_INFOS
292};
293} // namespace RVV
294
295namespace RVVSiFive {
296#define GET_RISCVV_BUILTIN_STR_TABLE
297#include "clang/Basic/riscv_sifive_vector_builtins.inc"
298#undef GET_RISCVV_BUILTIN_STR_TABLE
299
300static constexpr std::array<Builtin::Info, NumRVVSiFiveBuiltins> BuiltinInfos =
301 {
302#define GET_RISCVV_BUILTIN_INFOS
303#include "clang/Basic/riscv_sifive_vector_builtins.inc"
304#undef GET_RISCVV_BUILTIN_INFOS
305};
306} // namespace RVVSiFive
307
308namespace RVVAndes {
309#define GET_RISCVV_BUILTIN_STR_TABLE
310#include "clang/Basic/riscv_andes_vector_builtins.inc"
311#undef GET_RISCVV_BUILTIN_STR_TABLE
312
313static constexpr std::array<Builtin::Info, NumRVVAndesBuiltins> BuiltinInfos =
314 {
315#define GET_RISCVV_BUILTIN_INFOS
316#include "clang/Basic/riscv_andes_vector_builtins.inc"
317#undef GET_RISCVV_BUILTIN_INFOS
318};
319} // namespace RVVAndes
320
321#define GET_BUILTIN_STR_TABLE
322#include "clang/Basic/BuiltinsRISCV.inc"
323#undef GET_BUILTIN_STR_TABLE
324
325static constexpr Builtin::Info BuiltinInfos[] = {
326#define GET_BUILTIN_INFOS
327#include "clang/Basic/BuiltinsRISCV.inc"
328#undef GET_BUILTIN_INFOS
329};
330static_assert(std::size(BuiltinInfos) == NumRISCVBuiltins);
331
332llvm::SmallVector<Builtin::InfosShard>
333RISCVTargetInfo::getTargetBuiltins() const {
334 return {
335 {.Strings: &RVV::BuiltinStrings, .Infos: RVV::BuiltinInfos, .NamePrefix: "__builtin_rvv_"},
336 {.Strings: &RVVSiFive::BuiltinStrings, .Infos: RVVSiFive::BuiltinInfos, .NamePrefix: "__builtin_rvv_"},
337 {.Strings: &RVVAndes::BuiltinStrings, .Infos: RVVAndes::BuiltinInfos, .NamePrefix: "__builtin_rvv_"},
338 {.Strings: &BuiltinStrings, .Infos: BuiltinInfos},
339 };
340}
341
342bool RISCVTargetInfo::initFeatureMap(
343 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
344 const std::vector<std::string> &FeaturesVec) const {
345
346 unsigned XLen = 32;
347
348 if (getTriple().isRISCV64()) {
349 Features["64bit"] = true;
350 XLen = 64;
351 } else {
352 Features["32bit"] = true;
353 }
354
355 std::vector<std::string> AllFeatures = FeaturesVec;
356 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features: FeaturesVec);
357 if (!ParseResult) {
358 std::string Buffer;
359 llvm::raw_string_ostream OutputErrMsg(Buffer);
360 handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) {
361 OutputErrMsg << ErrMsg.getMessage();
362 });
363 Diags.Report(DiagID: diag::err_invalid_feature_combination) << OutputErrMsg.str();
364 return false;
365 }
366
367 // Append all features, not just new ones, so we override any negatives.
368 llvm::append_range(C&: AllFeatures, R: (*ParseResult)->toFeatures());
369 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: AllFeatures);
370}
371
372std::optional<std::pair<unsigned, unsigned>>
373RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts,
374 ArmStreamingKind IsArmStreamingFunction,
375 llvm::StringMap<bool> *FeatureMap) const {
376 // RISCV::RVVBitsPerBlock is 64.
377 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
378
379 if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
380 // Treat Zvl*b as a lower bound on vscale.
381 VScaleMin = std::max(a: VScaleMin, b: LangOpts.VScaleMin);
382 unsigned VScaleMax = LangOpts.VScaleMax;
383 if (VScaleMax != 0 && VScaleMax < VScaleMin)
384 VScaleMax = VScaleMin;
385 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
386 }
387
388 if (VScaleMin > 0) {
389 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
390 return std::make_pair(x&: VScaleMin, y&: VScaleMax);
391 }
392
393 return std::nullopt;
394}
395
396/// Return true if has this feature, need to sync with handleTargetFeatures.
397bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
398 bool Is64Bit = getTriple().isRISCV64();
399 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
400 .Case(S: "riscv", Value: true)
401 .Case(S: "riscv32", Value: !Is64Bit)
402 .Case(S: "riscv64", Value: Is64Bit)
403 .Case(S: "32bit", Value: !Is64Bit)
404 .Case(S: "64bit", Value: Is64Bit)
405 .Case(S: "experimental", Value: HasExperimental)
406 .Default(Value: std::nullopt);
407 if (Result)
408 return *Result;
409
410 return ISAInfo->hasExtension(Ext: Feature);
411}
412
413/// Perform initialization based on the user configured set of features.
414bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
415 DiagnosticsEngine &Diags) {
416 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
417 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
418 if (!ParseResult) {
419 std::string Buffer;
420 llvm::raw_string_ostream OutputErrMsg(Buffer);
421 handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) {
422 OutputErrMsg << ErrMsg.getMessage();
423 });
424 Diags.Report(DiagID: diag::err_invalid_feature_combination) << OutputErrMsg.str();
425 return false;
426 } else {
427 ISAInfo = std::move(*ParseResult);
428 }
429
430 if (ABI.empty())
431 ABI = ISAInfo->computeDefaultABI().str();
432
433 if (ISAInfo->hasExtension(Ext: "zfh") || ISAInfo->hasExtension(Ext: "zhinx"))
434 HasFastHalfType = true;
435
436 FastScalarUnalignedAccess =
437 llvm::is_contained(Range&: Features, Element: "+unaligned-scalar-mem");
438
439 if (llvm::is_contained(Range&: Features, Element: "+experimental"))
440 HasExperimental = true;
441
442 if (ABI == "ilp32e" && ISAInfo->hasExtension(Ext: "d")) {
443 Diags.Report(DiagID: diag::err_invalid_feature_combination)
444 << "ILP32E cannot be used with the D ISA extension";
445 return false;
446 }
447 return true;
448}
449
450bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
451 bool Is64Bit = getTriple().isArch64Bit();
452 return llvm::RISCV::parseCPU(CPU: Name, IsRV64: Is64Bit);
453}
454
455void RISCVTargetInfo::fillValidCPUList(
456 SmallVectorImpl<StringRef> &Values) const {
457 bool Is64Bit = getTriple().isArch64Bit();
458 llvm::RISCV::fillValidCPUArchList(Values, IsRV64: Is64Bit);
459}
460
461bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
462 bool Is64Bit = getTriple().isArch64Bit();
463 return llvm::RISCV::parseTuneCPU(CPU: Name, IsRV64: Is64Bit);
464}
465
466void RISCVTargetInfo::fillValidTuneCPUList(
467 SmallVectorImpl<StringRef> &Values) const {
468 bool Is64Bit = getTriple().isArch64Bit();
469 llvm::RISCV::fillValidTuneCPUArchList(Values, IsRV64: Is64Bit);
470}
471
472static void populateNegativeRISCVFeatures(std::vector<std::string> &Features) {
473 auto RII = llvm::RISCVISAInfo::parseArchString(
474 Arch: "rv64i", /* EnableExperimentalExtension */ true);
475
476 if (llvm::errorToBool(Err: RII.takeError()))
477 llvm_unreachable("unsupport rv64i");
478
479 std::vector<std::string> FeatStrings =
480 (*RII)->toFeatures(/* AddAllExtensions */ true);
481 llvm::append_range(C&: Features, R&: FeatStrings);
482}
483
484static void handleFullArchString(StringRef FullArchStr,
485 std::vector<std::string> &Features) {
486 auto RII = llvm::RISCVISAInfo::parseArchString(
487 Arch: FullArchStr, /* EnableExperimentalExtension */ true);
488 if (llvm::errorToBool(Err: RII.takeError())) {
489 // Forward the invalid FullArchStr.
490 Features.push_back(x: FullArchStr.str());
491 } else {
492 // Append a full list of features, including any negative extensions so that
493 // we override the CPU's features.
494 populateNegativeRISCVFeatures(Features);
495 std::vector<std::string> FeatStrings =
496 (*RII)->toFeatures(/* AddAllExtensions */ true);
497 llvm::append_range(C&: Features, R&: FeatStrings);
498 }
499}
500
501ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
502 ParsedTargetAttr Ret;
503 if (Features == "default")
504 return Ret;
505 SmallVector<StringRef, 1> AttrFeatures;
506 Features.split(A&: AttrFeatures, Separator: ";");
507 bool FoundArch = false;
508
509 auto handleArchExtension = [](StringRef AttrString,
510 std::vector<std::string> &Features) {
511 SmallVector<StringRef, 1> Exts;
512 AttrString.split(A&: Exts, Separator: ",");
513 for (auto Ext : Exts) {
514 if (Ext.empty())
515 continue;
516
517 StringRef ExtName = Ext.substr(Start: 1);
518 std::string TargetFeature =
519 llvm::RISCVISAInfo::getTargetFeatureForExtension(Ext: ExtName);
520 if (!TargetFeature.empty())
521 Features.push_back(x: Ext.front() + TargetFeature);
522 else
523 Features.push_back(x: Ext.str());
524 }
525 };
526
527 for (auto &Feature : AttrFeatures) {
528 Feature = Feature.trim();
529 StringRef AttrString = Feature.split(Separator: "=").second.trim();
530
531 if (Feature.starts_with(Prefix: "arch=")) {
532 // Override last features
533 Ret.Features.clear();
534 if (FoundArch)
535 Ret.Duplicate = "arch=";
536 FoundArch = true;
537
538 if (AttrString.starts_with(Prefix: "+")) {
539 // EXTENSION like arch=+v,+zbb
540 handleArchExtension(AttrString, Ret.Features);
541 } else {
542 // full-arch-string like arch=rv64gcv
543 handleFullArchString(FullArchStr: AttrString, Features&: Ret.Features);
544 }
545 } else if (Feature.starts_with(Prefix: "cpu=")) {
546 if (!Ret.CPU.empty())
547 Ret.Duplicate = "cpu=";
548
549 Ret.CPU = AttrString;
550
551 if (!FoundArch) {
552 // Update Features with CPU's features
553 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU: Ret.CPU);
554 if (MarchFromCPU != "") {
555 Ret.Features.clear();
556 handleFullArchString(FullArchStr: MarchFromCPU, Features&: Ret.Features);
557 }
558 }
559 } else if (Feature.starts_with(Prefix: "tune=")) {
560 if (!Ret.Tune.empty())
561 Ret.Duplicate = "tune=";
562
563 Ret.Tune = AttrString;
564 } else if (Feature.starts_with(Prefix: "priority")) {
565 // Skip because it only use for FMV.
566 } else if (Feature.starts_with(Prefix: "+")) {
567 // Handle target_version/target_clones attribute strings
568 // that are already delimited by ','
569 handleArchExtension(Feature, Ret.Features);
570 }
571 }
572 return Ret;
573}
574
575llvm::APInt
576RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
577 // Priority is explicitly specified on RISC-V unlike on other targets, where
578 // it is derived by all the features of a specific version. Therefore if a
579 // feature contains the priority string, then return it immediately.
580 for (StringRef Feature : Features) {
581 auto [LHS, RHS] = Feature.rsplit(Separator: ';');
582 if (LHS.consume_front(Prefix: "priority="))
583 Feature = LHS;
584 else if (RHS.consume_front(Prefix: "priority="))
585 Feature = RHS;
586 else
587 continue;
588 unsigned Priority;
589 if (!Feature.getAsInteger(Radix: 0, Result&: Priority))
590 return llvm::APInt(32, Priority);
591 }
592 // Default Priority is zero.
593 return llvm::APInt::getZero(numBits: 32);
594}
595
596TargetInfo::CallingConvCheckResult
597RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
598 switch (CC) {
599 default:
600 return CCCR_Warning;
601 case CC_C:
602 case CC_RISCVVectorCall:
603 case CC_RISCVVLSCall_32:
604 case CC_RISCVVLSCall_64:
605 case CC_RISCVVLSCall_128:
606 case CC_RISCVVLSCall_256:
607 case CC_RISCVVLSCall_512:
608 case CC_RISCVVLSCall_1024:
609 case CC_RISCVVLSCall_2048:
610 case CC_RISCVVLSCall_4096:
611 case CC_RISCVVLSCall_8192:
612 case CC_RISCVVLSCall_16384:
613 case CC_RISCVVLSCall_32768:
614 case CC_RISCVVLSCall_65536:
615 return CCCR_OK;
616 }
617}
618
619bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const {
620 // Only allow extensions we have a known bit position for in the
621 // __riscv_feature_bits structure.
622 return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitsInfo(Ext: Feature).second;
623}
624
625bool RISCVTargetInfo::isValidFeatureName(StringRef Name) const {
626 return llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext: Name);
627}
628
629bool RISCVTargetInfo::validateGlobalRegisterVariable(
630 StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const {
631 if (RegName == "ra" || RegName == "sp" || RegName == "gp" ||
632 RegName == "tp" || RegName.starts_with(Prefix: "x") || RegName.starts_with(Prefix: "a") ||
633 RegName.starts_with(Prefix: "s") || RegName.starts_with(Prefix: "t")) {
634 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
635 HasSizeMismatch = RegSize != XLen;
636 return true;
637 }
638 return false;
639}
640
641bool RISCVTargetInfo::validateCpuIs(StringRef CPUName) const {
642 assert(getTriple().isOSLinux() &&
643 "__builtin_cpu_is() is only supported for Linux.");
644
645 return llvm::RISCV::hasValidCPUModel(CPU: CPUName);
646}
647
648bool RISCVTargetInfo::checkCFBranchLabelSchemeSupported(
649 const CFBranchLabelSchemeKind Scheme, DiagnosticsEngine &Diags) const {
650 // TODO: Allow the default func-sig scheme to be selected after backend
651 // implements it
652 switch (Scheme) {
653 case CFBranchLabelSchemeKind::Default:
654 Diags.Report(DiagID: diag::err_opt_not_valid_without_opt)
655 << "-fcf-protection=branch"
656 << (Twine("-mcf-branch-label-scheme=") +
657 getCFBranchLabelSchemeFlagVal(Scheme: CFBranchLabelSchemeKind::Unlabeled))
658 .str();
659 return false;
660 case CFBranchLabelSchemeKind::Unlabeled:
661 return true;
662 case CFBranchLabelSchemeKind::FuncSig:
663 Diags.Report(DiagID: diag::err_opt_unsupported_with_suggest)
664 << (Twine("-mcf-branch-label-scheme=") +
665 getCFBranchLabelSchemeFlagVal(Scheme: CFBranchLabelSchemeKind::FuncSig))
666 .str()
667 << (Twine("-mcf-branch-label-scheme=") +
668 getCFBranchLabelSchemeFlagVal(Scheme: CFBranchLabelSchemeKind::Unlabeled))
669 .str();
670 return false;
671 }
672 return TargetInfo::checkCFBranchLabelSchemeSupported(Scheme, Diags);
673}
674