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
22 using namespace clang;
23 using namespace clang::targets;
24
getGCCRegNames() const25 ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
26 // clang-format off
27 static const char *const GCCRegNames[] = {
28 // Integer registers
29 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
30 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
31 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
32 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
33
34 // Floating point registers
35 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
36 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
37 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
38 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
39
40 // Vector registers
41 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
42 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
43 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
44 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
45
46 // CSRs
47 "fflags", "frm", "vtype", "vl", "vxsat", "vxrm"
48 };
49 // clang-format on
50 return llvm::ArrayRef(GCCRegNames);
51 }
52
getGCCRegAliases() const53 ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
54 static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
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"}};
71 return llvm::ArrayRef(GCCRegAliases);
72 }
73
validateAsmConstraint(const char * & Name,TargetInfo::ConstraintInfo & Info) const74 bool 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(-2048, 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(0, 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': // A symbolic address
100 Info.setAllowsRegister();
101 return true;
102 case 'v':
103 // A vector register.
104 if (Name[1] == 'r' || Name[1] == 'm') {
105 Info.setAllowsRegister();
106 Name += 1;
107 return true;
108 }
109 return false;
110 }
111 }
112
convertConstraint(const char * & Constraint) const113 std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
114 std::string R;
115 switch (*Constraint) {
116 case 'v':
117 R = std::string("^") + std::string(Constraint, 2);
118 Constraint += 1;
119 break;
120 default:
121 R = TargetInfo::convertConstraint(Constraint);
122 break;
123 }
124 return R;
125 }
126
getVersionValue(unsigned MajorVersion,unsigned MinorVersion)127 static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
128 return MajorVersion * 1000000 + MinorVersion * 1000;
129 }
130
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const131 void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
132 MacroBuilder &Builder) const {
133 Builder.defineMacro("__riscv");
134 bool Is64Bit = getTriple().isRISCV64();
135 Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
136 StringRef CodeModel = getTargetOpts().CodeModel;
137 unsigned FLen = ISAInfo->getFLen();
138 unsigned MinVLen = ISAInfo->getMinVLen();
139 unsigned MaxELen = ISAInfo->getMaxELen();
140 unsigned MaxELenFp = ISAInfo->getMaxELenFp();
141 if (CodeModel == "default")
142 CodeModel = "small";
143
144 if (CodeModel == "small")
145 Builder.defineMacro("__riscv_cmodel_medlow");
146 else if (CodeModel == "medium")
147 Builder.defineMacro("__riscv_cmodel_medany");
148
149 StringRef ABIName = getABI();
150 if (ABIName == "ilp32f" || ABIName == "lp64f")
151 Builder.defineMacro("__riscv_float_abi_single");
152 else if (ABIName == "ilp32d" || ABIName == "lp64d")
153 Builder.defineMacro("__riscv_float_abi_double");
154 else
155 Builder.defineMacro("__riscv_float_abi_soft");
156
157 if (ABIName == "ilp32e" || ABIName == "lp64e")
158 Builder.defineMacro("__riscv_abi_rve");
159
160 Builder.defineMacro("__riscv_arch_test");
161
162 for (auto &Extension : ISAInfo->getExtensions()) {
163 auto ExtName = Extension.first;
164 auto ExtInfo = Extension.second;
165
166 Builder.defineMacro(Twine("__riscv_", ExtName),
167 Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor)));
168 }
169
170 if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul"))
171 Builder.defineMacro("__riscv_mul");
172
173 if (ISAInfo->hasExtension("m")) {
174 Builder.defineMacro("__riscv_div");
175 Builder.defineMacro("__riscv_muldiv");
176 }
177
178 if (ISAInfo->hasExtension("a")) {
179 Builder.defineMacro("__riscv_atomic");
180 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
181 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
182 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
183 if (Is64Bit)
184 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
185 }
186
187 if (FLen) {
188 Builder.defineMacro("__riscv_flen", Twine(FLen));
189 Builder.defineMacro("__riscv_fdiv");
190 Builder.defineMacro("__riscv_fsqrt");
191 }
192
193 if (MinVLen) {
194 Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
195 Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
196 Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
197 }
198
199 if (ISAInfo->hasExtension("c"))
200 Builder.defineMacro("__riscv_compressed");
201
202 if (ISAInfo->hasExtension("zve32x")) {
203 Builder.defineMacro("__riscv_vector");
204 // Currently we support the v0.12 RISC-V V intrinsics.
205 Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12)));
206 }
207
208 auto VScale = getVScaleRange(Opts);
209 if (VScale && VScale->first && VScale->first == VScale->second)
210 Builder.defineMacro("__riscv_v_fixed_vlen",
211 Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
212
213 if (FastUnalignedAccess)
214 Builder.defineMacro("__riscv_misaligned_fast");
215 else
216 Builder.defineMacro("__riscv_misaligned_avoid");
217
218 if (ISAInfo->hasExtension("e")) {
219 if (Is64Bit)
220 Builder.defineMacro("__riscv_64e");
221 else
222 Builder.defineMacro("__riscv_32e");
223 }
224 }
225
226 static constexpr Builtin::Info BuiltinInfo[] = {
227 #define BUILTIN(ID, TYPE, ATTRS) \
228 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
229 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
230 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
231 #include "clang/Basic/BuiltinsRISCVVector.def"
232 #define BUILTIN(ID, TYPE, ATTRS) \
233 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
234 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
235 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
236 #include "clang/Basic/BuiltinsRISCV.def"
237 };
238
getTargetBuiltins() const239 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
240 return llvm::ArrayRef(BuiltinInfo,
241 clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
242 }
243
initFeatureMap(llvm::StringMap<bool> & Features,DiagnosticsEngine & Diags,StringRef CPU,const std::vector<std::string> & FeaturesVec) const244 bool RISCVTargetInfo::initFeatureMap(
245 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
246 const std::vector<std::string> &FeaturesVec) const {
247
248 unsigned XLen = 32;
249
250 if (getTriple().isRISCV64()) {
251 Features["64bit"] = true;
252 XLen = 64;
253 } else {
254 Features["32bit"] = true;
255 }
256
257 // If a target attribute specified a full arch string, override all the ISA
258 // extension target features.
259 const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride");
260 if (I != FeaturesVec.end()) {
261 std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end());
262
263 // Add back any non ISA extension features, e.g. +relax.
264 auto IsNonISAExtFeature = [](StringRef Feature) {
265 assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));
266 StringRef Ext = Feature.substr(1); // drop the +/-
267 return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);
268 };
269 llvm::copy_if(llvm::make_range(FeaturesVec.begin(), I),
270 std::back_inserter(OverrideFeatures), IsNonISAExtFeature);
271
272 return TargetInfo::initFeatureMap(Features, Diags, CPU, OverrideFeatures);
273 }
274
275 // Otherwise, parse the features and add any implied extensions.
276 std::vector<std::string> AllFeatures = FeaturesVec;
277 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
278 if (!ParseResult) {
279 std::string Buffer;
280 llvm::raw_string_ostream OutputErrMsg(Buffer);
281 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
282 OutputErrMsg << ErrMsg.getMessage();
283 });
284 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
285 return false;
286 }
287
288 // Append all features, not just new ones, so we override any negatives.
289 llvm::append_range(AllFeatures, (*ParseResult)->toFeatures());
290 return TargetInfo::initFeatureMap(Features, Diags, CPU, AllFeatures);
291 }
292
293 std::optional<std::pair<unsigned, unsigned>>
getVScaleRange(const LangOptions & LangOpts) const294 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
295 // RISCV::RVVBitsPerBlock is 64.
296 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
297
298 if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
299 // Treat Zvl*b as a lower bound on vscale.
300 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
301 unsigned VScaleMax = LangOpts.VScaleMax;
302 if (VScaleMax != 0 && VScaleMax < VScaleMin)
303 VScaleMax = VScaleMin;
304 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
305 }
306
307 if (VScaleMin > 0) {
308 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
309 return std::make_pair(VScaleMin, VScaleMax);
310 }
311
312 return std::nullopt;
313 }
314
315 /// Return true if has this feature, need to sync with handleTargetFeatures.
hasFeature(StringRef Feature) const316 bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
317 bool Is64Bit = getTriple().isRISCV64();
318 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
319 .Case("riscv", true)
320 .Case("riscv32", !Is64Bit)
321 .Case("riscv64", Is64Bit)
322 .Case("32bit", !Is64Bit)
323 .Case("64bit", Is64Bit)
324 .Case("experimental", HasExperimental)
325 .Default(std::nullopt);
326 if (Result)
327 return *Result;
328
329 return ISAInfo->hasExtension(Feature);
330 }
331
332 /// Perform initialization based on the user configured set of features.
handleTargetFeatures(std::vector<std::string> & Features,DiagnosticsEngine & Diags)333 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
334 DiagnosticsEngine &Diags) {
335 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
336 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
337 if (!ParseResult) {
338 std::string Buffer;
339 llvm::raw_string_ostream OutputErrMsg(Buffer);
340 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
341 OutputErrMsg << ErrMsg.getMessage();
342 });
343 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
344 return false;
345 } else {
346 ISAInfo = std::move(*ParseResult);
347 }
348
349 if (ABI.empty())
350 ABI = ISAInfo->computeDefaultABI().str();
351
352 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
353 HasLegalHalfType = true;
354
355 FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access");
356
357 if (llvm::is_contained(Features, "+experimental"))
358 HasExperimental = true;
359
360 if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {
361 Diags.Report(diag::err_invalid_feature_combination)
362 << "ILP32E cannot be used with the D ISA extension";
363 return false;
364 }
365 return true;
366 }
367
isValidCPUName(StringRef Name) const368 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
369 bool Is64Bit = getTriple().isArch64Bit();
370 return llvm::RISCV::parseCPU(Name, Is64Bit);
371 }
372
fillValidCPUList(SmallVectorImpl<StringRef> & Values) const373 void RISCVTargetInfo::fillValidCPUList(
374 SmallVectorImpl<StringRef> &Values) const {
375 bool Is64Bit = getTriple().isArch64Bit();
376 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
377 }
378
isValidTuneCPUName(StringRef Name) const379 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
380 bool Is64Bit = getTriple().isArch64Bit();
381 return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
382 }
383
fillValidTuneCPUList(SmallVectorImpl<StringRef> & Values) const384 void RISCVTargetInfo::fillValidTuneCPUList(
385 SmallVectorImpl<StringRef> &Values) const {
386 bool Is64Bit = getTriple().isArch64Bit();
387 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
388 }
389
handleFullArchString(StringRef FullArchStr,std::vector<std::string> & Features)390 static void handleFullArchString(StringRef FullArchStr,
391 std::vector<std::string> &Features) {
392 Features.push_back("__RISCV_TargetAttrNeedOverride");
393 auto RII = llvm::RISCVISAInfo::parseArchString(
394 FullArchStr, /* EnableExperimentalExtension */ true);
395 if (llvm::errorToBool(RII.takeError())) {
396 // Forward the invalid FullArchStr.
397 Features.push_back("+" + FullArchStr.str());
398 } else {
399 // Append a full list of features, including any negative extensions so that
400 // we override the CPU's features.
401 std::vector<std::string> FeatStrings =
402 (*RII)->toFeatures(/* AddAllExtensions */ true);
403 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
404 }
405 }
406
parseTargetAttr(StringRef Features) const407 ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
408 ParsedTargetAttr Ret;
409 if (Features == "default")
410 return Ret;
411 SmallVector<StringRef, 1> AttrFeatures;
412 Features.split(AttrFeatures, ";");
413 bool FoundArch = false;
414
415 for (auto &Feature : AttrFeatures) {
416 Feature = Feature.trim();
417 StringRef AttrString = Feature.split("=").second.trim();
418
419 if (Feature.starts_with("arch=")) {
420 // Override last features
421 Ret.Features.clear();
422 if (FoundArch)
423 Ret.Duplicate = "arch=";
424 FoundArch = true;
425
426 if (AttrString.starts_with("+")) {
427 // EXTENSION like arch=+v,+zbb
428 SmallVector<StringRef, 1> Exts;
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 Ret.Features.push_back(Ext.front() + TargetFeature);
439 else
440 Ret.Features.push_back(Ext.str());
441 }
442 } else {
443 // full-arch-string like arch=rv64gcv
444 handleFullArchString(AttrString, Ret.Features);
445 }
446 } else if (Feature.starts_with("cpu=")) {
447 if (!Ret.CPU.empty())
448 Ret.Duplicate = "cpu=";
449
450 Ret.CPU = AttrString;
451
452 if (!FoundArch) {
453 // Update Features with CPU's features
454 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU);
455 if (MarchFromCPU != "") {
456 Ret.Features.clear();
457 handleFullArchString(MarchFromCPU, Ret.Features);
458 }
459 }
460 } else if (Feature.starts_with("tune=")) {
461 if (!Ret.Tune.empty())
462 Ret.Duplicate = "tune=";
463
464 Ret.Tune = AttrString;
465 }
466 }
467 return Ret;
468 }
469