xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
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")
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(
167         Twine("__riscv_", ExtName),
168         Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion)));
169   }
170 
171   if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul"))
172     Builder.defineMacro("__riscv_mul");
173 
174   if (ISAInfo->hasExtension("m")) {
175     Builder.defineMacro("__riscv_div");
176     Builder.defineMacro("__riscv_muldiv");
177   }
178 
179   if (ISAInfo->hasExtension("a")) {
180     Builder.defineMacro("__riscv_atomic");
181     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
182     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
183     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
184     if (Is64Bit)
185       Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
186   }
187 
188   if (FLen) {
189     Builder.defineMacro("__riscv_flen", Twine(FLen));
190     Builder.defineMacro("__riscv_fdiv");
191     Builder.defineMacro("__riscv_fsqrt");
192   }
193 
194   if (MinVLen) {
195     Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
196     Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
197     Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
198   }
199 
200   if (ISAInfo->hasExtension("c"))
201     Builder.defineMacro("__riscv_compressed");
202 
203   if (ISAInfo->hasExtension("zve32x")) {
204     Builder.defineMacro("__riscv_vector");
205     // Currently we support the v0.12 RISC-V V intrinsics.
206     Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12)));
207   }
208 
209   auto VScale = getVScaleRange(Opts);
210   if (VScale && VScale->first && VScale->first == VScale->second)
211     Builder.defineMacro("__riscv_v_fixed_vlen",
212                         Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
213 
214   if (FastUnalignedAccess)
215     Builder.defineMacro("__riscv_misaligned_fast");
216   else
217     Builder.defineMacro("__riscv_misaligned_avoid");
218 }
219 
220 static constexpr Builtin::Info BuiltinInfo[] = {
221 #define BUILTIN(ID, TYPE, ATTRS)                                               \
222   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
223 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
224   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
225 #include "clang/Basic/BuiltinsRISCVVector.def"
226 #define BUILTIN(ID, TYPE, ATTRS)                                               \
227   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
228 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
229   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
230 #include "clang/Basic/BuiltinsRISCV.def"
231 };
232 
233 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
234   return llvm::ArrayRef(BuiltinInfo,
235                         clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
236 }
237 
238 static std::vector<std::string>
239 collectNonISAExtFeature(ArrayRef<std::string> FeaturesNeedOverride, int XLen) {
240   std::vector<std::string> NonISAExtFeatureVec;
241 
242   auto IsNonISAExtFeature = [](const std::string &Feature) {
243     assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));
244     StringRef Ext = StringRef(Feature).drop_front(); // drop the +/-
245     return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);
246   };
247   llvm::copy_if(FeaturesNeedOverride, std::back_inserter(NonISAExtFeatureVec),
248                 IsNonISAExtFeature);
249 
250   return NonISAExtFeatureVec;
251 }
252 
253 static std::vector<std::string>
254 resolveTargetAttrOverride(const std::vector<std::string> &FeaturesVec,
255                           int XLen) {
256   auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride");
257   if (I == FeaturesVec.end())
258     return FeaturesVec;
259 
260   ArrayRef<std::string> FeaturesNeedOverride(&*FeaturesVec.begin(), &*I);
261   std::vector<std::string> NonISAExtFeature =
262       collectNonISAExtFeature(FeaturesNeedOverride, XLen);
263 
264   std::vector<std::string> ResolvedFeature(++I, FeaturesVec.end());
265   ResolvedFeature.insert(ResolvedFeature.end(), NonISAExtFeature.begin(),
266                          NonISAExtFeature.end());
267 
268   return ResolvedFeature;
269 }
270 
271 bool RISCVTargetInfo::initFeatureMap(
272     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
273     const std::vector<std::string> &FeaturesVec) const {
274 
275   unsigned XLen = 32;
276 
277   if (getTriple().isRISCV64()) {
278     Features["64bit"] = true;
279     XLen = 64;
280   } else {
281     Features["32bit"] = true;
282   }
283 
284   std::vector<std::string> NewFeaturesVec =
285       resolveTargetAttrOverride(FeaturesVec, XLen);
286 
287   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, NewFeaturesVec);
288   if (!ParseResult) {
289     std::string Buffer;
290     llvm::raw_string_ostream OutputErrMsg(Buffer);
291     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
292       OutputErrMsg << ErrMsg.getMessage();
293     });
294     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
295     return false;
296   }
297 
298   // RISCVISAInfo makes implications for ISA features
299   std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatures();
300 
301   // parseFeatures normalizes the feature set by dropping any explicit
302   // negatives, and non-extension features.  We need to preserve the later
303   // for correctness and want to preserve the former for consistency.
304   for (auto &Feature : NewFeaturesVec) {
305      StringRef ExtName = Feature;
306      assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
307      ExtName = ExtName.drop_front(1); // Drop '+' or '-'
308      if (!llvm::is_contained(ImpliedFeatures, ("+" + ExtName).str()) &&
309          !llvm::is_contained(ImpliedFeatures, ("-" + ExtName).str()))
310        ImpliedFeatures.push_back(Feature);
311   }
312   return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures);
313 }
314 
315 std::optional<std::pair<unsigned, unsigned>>
316 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
317   // RISCV::RVVBitsPerBlock is 64.
318   unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
319 
320   if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
321     // Treat Zvl*b as a lower bound on vscale.
322     VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
323     unsigned VScaleMax = LangOpts.VScaleMax;
324     if (VScaleMax != 0 && VScaleMax < VScaleMin)
325       VScaleMax = VScaleMin;
326     return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
327   }
328 
329   if (VScaleMin > 0) {
330     unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
331     return std::make_pair(VScaleMin, VScaleMax);
332   }
333 
334   return std::nullopt;
335 }
336 
337 /// Return true if has this feature, need to sync with handleTargetFeatures.
338 bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
339   bool Is64Bit = getTriple().isRISCV64();
340   auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
341                     .Case("riscv", true)
342                     .Case("riscv32", !Is64Bit)
343                     .Case("riscv64", Is64Bit)
344                     .Case("32bit", !Is64Bit)
345                     .Case("64bit", Is64Bit)
346                     .Case("experimental", HasExperimental)
347                     .Default(std::nullopt);
348   if (Result)
349     return *Result;
350 
351   return ISAInfo->hasExtension(Feature);
352 }
353 
354 /// Perform initialization based on the user configured set of features.
355 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
356                                            DiagnosticsEngine &Diags) {
357   unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
358   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
359   if (!ParseResult) {
360     std::string Buffer;
361     llvm::raw_string_ostream OutputErrMsg(Buffer);
362     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
363       OutputErrMsg << ErrMsg.getMessage();
364     });
365     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
366     return false;
367   } else {
368     ISAInfo = std::move(*ParseResult);
369   }
370 
371   if (ABI.empty())
372     ABI = ISAInfo->computeDefaultABI().str();
373 
374   if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
375     HasLegalHalfType = true;
376 
377   FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access");
378 
379   if (llvm::is_contained(Features, "+experimental"))
380     HasExperimental = true;
381 
382   return true;
383 }
384 
385 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
386   bool Is64Bit = getTriple().isArch64Bit();
387   return llvm::RISCV::parseCPU(Name, Is64Bit);
388 }
389 
390 void RISCVTargetInfo::fillValidCPUList(
391     SmallVectorImpl<StringRef> &Values) const {
392   bool Is64Bit = getTriple().isArch64Bit();
393   llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
394 }
395 
396 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
397   bool Is64Bit = getTriple().isArch64Bit();
398   return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
399 }
400 
401 void RISCVTargetInfo::fillValidTuneCPUList(
402     SmallVectorImpl<StringRef> &Values) const {
403   bool Is64Bit = getTriple().isArch64Bit();
404   llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
405 }
406 
407 static void handleFullArchString(StringRef FullArchStr,
408                                  std::vector<std::string> &Features) {
409   Features.push_back("__RISCV_TargetAttrNeedOverride");
410   auto RII = llvm::RISCVISAInfo::parseArchString(
411       FullArchStr, /* EnableExperimentalExtension */ true);
412   if (llvm::errorToBool(RII.takeError())) {
413     // Forward the invalid FullArchStr.
414     Features.push_back("+" + FullArchStr.str());
415   } else {
416     std::vector<std::string> FeatStrings = (*RII)->toFeatures();
417     Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
418   }
419 }
420 
421 ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
422   ParsedTargetAttr Ret;
423   if (Features == "default")
424     return Ret;
425   SmallVector<StringRef, 1> AttrFeatures;
426   Features.split(AttrFeatures, ";");
427   bool FoundArch = false;
428 
429   for (auto &Feature : AttrFeatures) {
430     Feature = Feature.trim();
431     StringRef AttrString = Feature.split("=").second.trim();
432 
433     if (Feature.starts_with("arch=")) {
434       // Override last features
435       Ret.Features.clear();
436       if (FoundArch)
437         Ret.Duplicate = "arch=";
438       FoundArch = true;
439 
440       if (AttrString.starts_with("+")) {
441         // EXTENSION like arch=+v,+zbb
442         SmallVector<StringRef, 1> Exts;
443         AttrString.split(Exts, ",");
444         for (auto Ext : Exts) {
445           if (Ext.empty())
446             continue;
447 
448           StringRef ExtName = Ext.substr(1);
449           std::string TargetFeature =
450               llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
451           if (!TargetFeature.empty())
452             Ret.Features.push_back(Ext.front() + TargetFeature);
453           else
454             Ret.Features.push_back(Ext.str());
455         }
456       } else {
457         // full-arch-string like arch=rv64gcv
458         handleFullArchString(AttrString, Ret.Features);
459       }
460     } else if (Feature.starts_with("cpu=")) {
461       if (!Ret.CPU.empty())
462         Ret.Duplicate = "cpu=";
463 
464       Ret.CPU = AttrString;
465 
466       if (!FoundArch) {
467         // Update Features with CPU's features
468         StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU);
469         if (MarchFromCPU != "") {
470           Ret.Features.clear();
471           handleFullArchString(MarchFromCPU, Ret.Features);
472         }
473       }
474     } else if (Feature.starts_with("tune=")) {
475       if (!Ret.Tune.empty())
476         Ret.Duplicate = "tune=";
477 
478       Ret.Tune = AttrString;
479     }
480   }
481   return Ret;
482 }
483