clang: lib/Basic/Targets/RISCV.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
17#include "llvm/ADT/StringSwitch.h"
18#include "llvm/Support/raw_ostream.h"
19#include "llvm/TargetParser/RISCVTargetParser.h"
20#include
21
22using namespace clang;
24
26
27 static const char *const GCCRegNames[] = {
28
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
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
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
47 "fflags", "frm", "vtype", "vl", "vxsat", "vxrm", "sf.vcix_state"
48 };
49
51}
52
55 {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"},
56 {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"},
57 {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"},
58 {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"},
59 {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"},
60 {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"},
61 {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},
62 {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"},
63 {{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"},
64 {{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"},
65 {{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"},
66 {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"},
67 {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"},
68 {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"},
69 {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},
70 {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};
72}
73
76 switch (*Name) {
77 default:
78 return false;
79 case 'I':
80
82 return true;
83 case 'J':
84
86 return true;
87 case 'K':
88
90 return true;
91 case 'f':
92
94 return true;
95 case 'A':
96
98 return true;
99 case 's':
100 case 'S':
102 return true;
103 case 'c':
104
105 if (Name[1] == 'r' || Name[1] == 'f') {
107 Name += 1;
108 return true;
109 }
110 return false;
111 case 'R':
112
114 return true;
115 case 'v':
116
117 if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {
119 Name += 1;
120 return true;
121 }
122 return false;
123 }
124}
125
127 std::string R;
128 switch (*Constraint) {
129
130 case 'c':
131 case 'v':
132 R = std::string("^") + std::string(Constraint, 2);
133 Constraint += 1;
134 break;
135 default:
137 break;
138 }
139 return R;
140}
141
142static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
143 return MajorVersion * 1000000 + MinorVersion * 1000;
144}
145
148 Builder.defineMacro("__riscv");
149 bool Is64Bit = getTriple().isRISCV64();
150 Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
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("__riscv_cmodel_medlow");
161 else if (CodeModel == "medium")
162 Builder.defineMacro("__riscv_cmodel_medany");
163 else if (CodeModel == "large")
164 Builder.defineMacro("__riscv_cmodel_large");
165
166 StringRef ABIName = getABI();
167 if (ABIName == "ilp32f" || ABIName == "lp64f")
168 Builder.defineMacro("__riscv_float_abi_single");
169 else if (ABIName == "ilp32d" || ABIName == "lp64d")
170 Builder.defineMacro("__riscv_float_abi_double");
171 else
172 Builder.defineMacro("__riscv_float_abi_soft");
173
174 if (ABIName == "ilp32e" || ABIName == "lp64e")
175 Builder.defineMacro("__riscv_abi_rve");
176
177 Builder.defineMacro("__riscv_arch_test");
178
179 for (auto &Extension : ISAInfo->getExtensions()) {
180 auto ExtName = Extension.first;
181 auto ExtInfo = Extension.second;
182
183 Builder.defineMacro(Twine("__riscv_", ExtName),
185 }
186
187 if (ISAInfo->hasExtension("zmmul"))
188 Builder.defineMacro("__riscv_mul");
189
190 if (ISAInfo->hasExtension("m")) {
191 Builder.defineMacro("__riscv_div");
192 Builder.defineMacro("__riscv_muldiv");
193 }
194
195 if (ISAInfo->hasExtension("a")) {
196 Builder.defineMacro("__riscv_atomic");
197 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
198 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
199 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
200 if (Is64Bit)
201 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
202 }
203
204 if (FLen) {
205 Builder.defineMacro("__riscv_flen", Twine(FLen));
206 Builder.defineMacro("__riscv_fdiv");
207 Builder.defineMacro("__riscv_fsqrt");
208 }
209
210 if (MinVLen) {
211 Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
212 Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
213 Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
214 }
215
216 if (ISAInfo->hasExtension("c"))
217 Builder.defineMacro("__riscv_compressed");
218
219 if (ISAInfo->hasExtension("zve32x"))
220 Builder.defineMacro("__riscv_vector");
221
222
223 Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(1, 0)));
224
226 if (VScale && VScale->first && VScale->first == VScale->second)
227 Builder.defineMacro("__riscv_v_fixed_vlen",
228 Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
229
230 if (FastScalarUnalignedAccess)
231 Builder.defineMacro("__riscv_misaligned_fast");
232 else
233 Builder.defineMacro("__riscv_misaligned_avoid");
234
235 if (ISAInfo->hasExtension("e")) {
236 if (Is64Bit)
237 Builder.defineMacro("__riscv_64e");
238 else
239 Builder.defineMacro("__riscv_32e");
240 }
241}
242
244#define BUILTIN(ID, TYPE, ATTRS) \
245 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
246#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
247 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
248#include "clang/Basic/BuiltinsRISCVVector.def"
249#define BUILTIN(ID, TYPE, ATTRS) \
250 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
251#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
252 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
253#include "clang/Basic/BuiltinsRISCV.inc"
254};
255
259}
260
262 llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU,
263 const std::vectorstd::string &FeaturesVec) const {
264
265 unsigned XLen = 32;
266
268 Features["64bit"] = true;
269 XLen = 64;
270 } else {
271 Features["32bit"] = true;
272 }
273
274 std::vectorstd::string AllFeatures = FeaturesVec;
275 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
276 if (!ParseResult) {
277 std::string Buffer;
278 llvm::raw_string_ostream OutputErrMsg(Buffer);
279 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
280 OutputErrMsg << ErrMsg.getMessage();
281 });
282 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
283 return false;
284 }
285
286
287 llvm::append_range(AllFeatures, (*ParseResult)->toFeatures());
289}
290
291std::optional<std::pair<unsigned, unsigned>>
293
294 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
295
296 if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
297
298 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
299 unsigned VScaleMax = LangOpts.VScaleMax;
300 if (VScaleMax != 0 && VScaleMax < VScaleMin)
301 VScaleMax = VScaleMin;
302 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
303 }
304
305 if (VScaleMin > 0) {
306 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
307 return std::make_pair(VScaleMin, VScaleMax);
308 }
309
310 return std::nullopt;
311}
312
313
315 bool Is64Bit = getTriple().isRISCV64();
316 auto Result = llvm::StringSwitch<std::optional>(Feature)
317 .Case("riscv", true)
318 .Case("riscv32", !Is64Bit)
319 .Case("riscv64", Is64Bit)
320 .Case("32bit", !Is64Bit)
321 .Case("64bit", Is64Bit)
322 .Case("experimental", HasExperimental)
323 .Default(std::nullopt);
326
327 return ISAInfo->hasExtension(Feature);
328}
329
330
333 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
334 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
335 if (!ParseResult) {
336 std::string Buffer;
337 llvm::raw_string_ostream OutputErrMsg(Buffer);
338 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
339 OutputErrMsg << ErrMsg.getMessage();
340 });
341 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
342 return false;
343 } else {
344 ISAInfo = std::move(*ParseResult);
345 }
346
347 if (ABI.empty())
348 ABI = ISAInfo->computeDefaultABI().str();
349
350 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
352
353 FastScalarUnalignedAccess =
354 llvm::is_contained(Features, "+unaligned-scalar-mem");
355
356 if (llvm::is_contained(Features, "+experimental"))
357 HasExperimental = true;
358
359 if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {
360 Diags.Report(diag::err_invalid_feature_combination)
361 << "ILP32E cannot be used with the D ISA extension";
362 return false;
363 }
364 return true;
365}
366
368 bool Is64Bit = getTriple().isArch64Bit();
369 return llvm::RISCV::parseCPU(Name, Is64Bit);
370}
371
374 bool Is64Bit = getTriple().isArch64Bit();
375 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
376}
377
379 bool Is64Bit = getTriple().isArch64Bit();
380 return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
381}
382
385 bool Is64Bit = getTriple().isArch64Bit();
386 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
387}
388
390 auto RII = llvm::RISCVISAInfo::parseArchString(
391 "rv64i", true);
392
393 if (llvm::errorToBool(RII.takeError()))
394 llvm_unreachable("unsupport rv64i");
395
396 std::vectorstd::string FeatStrings =
397 (*RII)->toFeatures( true);
398 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
399}
400
402 std::vectorstd::string &Features) {
403 auto RII = llvm::RISCVISAInfo::parseArchString(
404 FullArchStr, true);
405 if (llvm::errorToBool(RII.takeError())) {
406
407 Features.push_back(FullArchStr.str());
408 } else {
409
410
412 std::vectorstd::string FeatStrings =
413 (*RII)->toFeatures( true);
414 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
415 }
416}
417
420 if (Features == "default")
421 return Ret;
423 Features.split(AttrFeatures, ";");
424 bool FoundArch = false;
425
426 auto handleArchExtension = [](StringRef AttrString,
427 std::vectorstd::string &Features) {
429 AttrString.split(Exts, ",");
430 for (auto Ext : Exts) {
431 if (Ext.empty())
432 continue;
433
434 StringRef ExtName = Ext.substr(1);
435 std::string TargetFeature =
436 llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
437 if (!TargetFeature.empty())
438 Features.push_back(Ext.front() + TargetFeature);
439 else
440 Features.push_back(Ext.str());
441 }
442 };
443
444 for (auto &Feature : AttrFeatures) {
445 Feature = Feature.trim();
446 StringRef AttrString = Feature.split("=").second.trim();
447
448 if (Feature.starts_with("arch=")) {
449
450 Ret.Features.clear();
451 if (FoundArch)
452 Ret.Duplicate = "arch=";
453 FoundArch = true;
454
455 if (AttrString.starts_with("+")) {
456
457 handleArchExtension(AttrString, Ret.Features);
458 } else {
459
461 }
462 } else if (Feature.starts_with("cpu=")) {
463 if (!Ret.CPU.empty())
464 Ret.Duplicate = "cpu=";
465
466 Ret.CPU = AttrString;
467
468 if (!FoundArch) {
469
470 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU);
471 if (MarchFromCPU != "") {
472 Ret.Features.clear();
474 }
475 }
476 } else if (Feature.starts_with("tune=")) {
477 if (!Ret.Tune.empty())
478 Ret.Duplicate = "tune=";
479
480 Ret.Tune = AttrString;
481 } else if (Feature.starts_with("priority")) {
482
483 } else if (Feature.starts_with("+")) {
484
485
486 handleArchExtension(Feature, Ret.Features);
487 }
488 }
489 return Ret;
490}
491
493
494
495
496 for (StringRef Feature : Features) {
497 auto [LHS, RHS] = Feature.rsplit(';');
498 if (LHS.consume_front("priority="))
499 Feature = LHS;
500 else if (RHS.consume_front("priority="))
501 Feature = RHS;
502 else
503 continue;
505 if (!Feature.getAsInteger(0, Priority))
507 }
508
509 return 0;
510}
511
514 switch (CC) {
515 default:
520 }
521}
522
524
525
526 return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitsInfo(Feature).second;
527}
528
530 return llvm::RISCVISAInfo::isSupportedExtensionFeature(Name);
531}
532
534 StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const {
535 if (RegName == "ra" || RegName == "sp" || RegName == "gp" ||
536 RegName == "tp" || RegName.starts_with("x") || RegName.starts_with("a") ||
537 RegName.starts_with("s") || RegName.starts_with("t")) {
538 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
539 HasSizeMismatch = RegSize != XLen;
540 return true;
541 }
542 return false;
543}
544
546 assert(getTriple().isOSLinux() &&
547 "__builtin_cpu_is() is only supported for Linux.");
548
549 return llvm::RISCV::hasValidCPUModel(CPUName);
550}
Defines the Diagnostic-related interfaces.
static void populateNegativeRISCVFeatures(std::vector< std::string > &Features)
static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion)
static void handleFullArchString(StringRef FullArchStr, std::vector< std::string > &Features)
static constexpr Builtin::Info BuiltinInfo[]
Defines the clang::MacroBuilder utility class.
Enumerates target-specific builtins in their own namespaces within namespace clang.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
TargetOptions & getTargetOpts() const
Retrieve the target options.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
virtual bool initFeatureMap(llvm::StringMap< bool > &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector< std::string > &FeatureVec) const
Initialize the map with the default set of target features for the CPU this should include all legal ...
virtual std::string convertConstraint(const char *&Constraint) const
bool isValidFeatureName(StringRef Name) const override
Determine whether this TargetInfo supports the given feature.
std::string convertConstraint(const char *&Constraint) const override
void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override
===-— Other target property query methods -----------------------—===//
ArrayRef< Builtin::Info > getTargetBuiltins() const override
Return information about target-specific builtins for the current primary target, and info about whic...
bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override
bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const override
Validate register name used for global register variables.
bool initFeatureMap(llvm::StringMap< bool > &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector< std::string > &FeaturesVec) const override
Initialize the map with the default set of target features for the CPU this should include all legal ...
std::unique_ptr< llvm::RISCVISAInfo > ISAInfo
void fillValidTuneCPUList(SmallVectorImpl< StringRef > &Values) const override
Fill a SmallVectorImpl with the valid values for tuning CPU.
bool isValidTuneCPUName(StringRef Name) const override
Determine whether this TargetInfo supports the given CPU name for tuning.
std::optional< std::pair< unsigned, unsigned > > getVScaleRange(const LangOptions &LangOpts) const override
Returns target-specific min and max values VScale_Range.
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override
Determines whether a given calling convention is valid for the target.
ArrayRef< const char * > getGCCRegNames() const override
ArrayRef< TargetInfo::GCCRegAlias > getGCCRegAliases() const override
void fillValidCPUList(SmallVectorImpl< StringRef > &Values) const override
Fill a SmallVectorImpl with the valid values to setCPU.
bool validateCpuSupports(StringRef Feature) const override
StringRef getABI() const override
Get the ABI currently in use.
uint64_t getFMVPriority(ArrayRef< StringRef > Features) const override
bool handleTargetFeatures(std::vector< std::string > &Features, DiagnosticsEngine &Diags) override
Perform initialization based on the user configured set of features.
ParsedTargetAttr parseTargetAttr(StringRef Str) const override
bool hasFeature(StringRef Feature) const override
Return true if has this feature, need to sync with handleTargetFeatures.
bool validateCpuIs(StringRef CPUName) const override
bool isValidCPUName(StringRef Name) const override
Determine whether this TargetInfo supports the given CPU name.
static const char *const GCCRegNames[]
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
CallingConv
CallingConv - Specifies the calling convention that a function uses.
Contains information gathered from parsing the contents of TargetAttr.
void setRequiresImmediate(int Min, int Max)