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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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