xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp (revision 2cb0fce24d64039090dc9243cdf0715ee80c91b1)
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 
25 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 
53 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 
74 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 
113 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 
127 static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
128   return MajorVersion * 1000000 + MinorVersion * 1000;
129 }
130 
131 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 
239 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
240   return llvm::ArrayRef(BuiltinInfo,
241                         clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
242 }
243 
244 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>>
294 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.
316 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.
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 
368 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
369   bool Is64Bit = getTriple().isArch64Bit();
370   return llvm::RISCV::parseCPU(Name, Is64Bit);
371 }
372 
373 void RISCVTargetInfo::fillValidCPUList(
374     SmallVectorImpl<StringRef> &Values) const {
375   bool Is64Bit = getTriple().isArch64Bit();
376   llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
377 }
378 
379 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
380   bool Is64Bit = getTriple().isArch64Bit();
381   return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
382 }
383 
384 void RISCVTargetInfo::fillValidTuneCPUList(
385     SmallVectorImpl<StringRef> &Values) const {
386   bool Is64Bit = getTriple().isArch64Bit();
387   llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
388 }
389 
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 
407 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