xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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':
100   case 'S': // A symbol or label reference with a constant offset
101     Info.setAllowsRegister();
102     return true;
103   case 'v':
104     // A vector register.
105     if (Name[1] == 'r' || Name[1] == 'm') {
106       Info.setAllowsRegister();
107       Name += 1;
108       return true;
109     }
110     return false;
111   }
112 }
113 
convertConstraint(const char * & Constraint) const114 std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
115   std::string R;
116   switch (*Constraint) {
117   case 'v':
118     R = std::string("^") + std::string(Constraint, 2);
119     Constraint += 1;
120     break;
121   default:
122     R = TargetInfo::convertConstraint(Constraint);
123     break;
124   }
125   return R;
126 }
127 
getVersionValue(unsigned MajorVersion,unsigned MinorVersion)128 static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
129   return MajorVersion * 1000000 + MinorVersion * 1000;
130 }
131 
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const132 void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
133                                        MacroBuilder &Builder) const {
134   Builder.defineMacro("__riscv");
135   bool Is64Bit = getTriple().isRISCV64();
136   Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
137   StringRef CodeModel = getTargetOpts().CodeModel;
138   unsigned FLen = ISAInfo->getFLen();
139   unsigned MinVLen = ISAInfo->getMinVLen();
140   unsigned MaxELen = ISAInfo->getMaxELen();
141   unsigned MaxELenFp = ISAInfo->getMaxELenFp();
142   if (CodeModel == "default")
143     CodeModel = "small";
144 
145   if (CodeModel == "small")
146     Builder.defineMacro("__riscv_cmodel_medlow");
147   else if (CodeModel == "medium")
148     Builder.defineMacro("__riscv_cmodel_medany");
149 
150   StringRef ABIName = getABI();
151   if (ABIName == "ilp32f" || ABIName == "lp64f")
152     Builder.defineMacro("__riscv_float_abi_single");
153   else if (ABIName == "ilp32d" || ABIName == "lp64d")
154     Builder.defineMacro("__riscv_float_abi_double");
155   else
156     Builder.defineMacro("__riscv_float_abi_soft");
157 
158   if (ABIName == "ilp32e" || ABIName == "lp64e")
159     Builder.defineMacro("__riscv_abi_rve");
160 
161   Builder.defineMacro("__riscv_arch_test");
162 
163   for (auto &Extension : ISAInfo->getExtensions()) {
164     auto ExtName = Extension.first;
165     auto ExtInfo = Extension.second;
166 
167     Builder.defineMacro(Twine("__riscv_", ExtName),
168                         Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor)));
169   }
170 
171   if (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 (FastScalarUnalignedAccess)
215     Builder.defineMacro("__riscv_misaligned_fast");
216   else
217     Builder.defineMacro("__riscv_misaligned_avoid");
218 
219   if (ISAInfo->hasExtension("e")) {
220     if (Is64Bit)
221       Builder.defineMacro("__riscv_64e");
222     else
223       Builder.defineMacro("__riscv_32e");
224   }
225 }
226 
227 static constexpr Builtin::Info BuiltinInfo[] = {
228 #define BUILTIN(ID, TYPE, ATTRS)                                               \
229   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
230 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
231   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
232 #include "clang/Basic/BuiltinsRISCVVector.def"
233 #define BUILTIN(ID, TYPE, ATTRS)                                               \
234   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
235 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
236   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
237 #include "clang/Basic/BuiltinsRISCV.inc"
238 };
239 
getTargetBuiltins() const240 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
241   return llvm::ArrayRef(BuiltinInfo,
242                         clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
243 }
244 
initFeatureMap(llvm::StringMap<bool> & Features,DiagnosticsEngine & Diags,StringRef CPU,const std::vector<std::string> & FeaturesVec) const245 bool RISCVTargetInfo::initFeatureMap(
246     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
247     const std::vector<std::string> &FeaturesVec) const {
248 
249   unsigned XLen = 32;
250 
251   if (getTriple().isRISCV64()) {
252     Features["64bit"] = true;
253     XLen = 64;
254   } else {
255     Features["32bit"] = true;
256   }
257 
258   // If a target attribute specified a full arch string, override all the ISA
259   // extension target features.
260   const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride");
261   if (I != FeaturesVec.end()) {
262     std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end());
263 
264     // Add back any non ISA extension features, e.g. +relax.
265     auto IsNonISAExtFeature = [](StringRef Feature) {
266       assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));
267       StringRef Ext = Feature.substr(1); // drop the +/-
268       return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);
269     };
270     llvm::copy_if(llvm::make_range(FeaturesVec.begin(), I),
271                   std::back_inserter(OverrideFeatures), IsNonISAExtFeature);
272 
273     return TargetInfo::initFeatureMap(Features, Diags, CPU, OverrideFeatures);
274   }
275 
276   // Otherwise, parse the features and add any implied extensions.
277   std::vector<std::string> AllFeatures = FeaturesVec;
278   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
279   if (!ParseResult) {
280     std::string Buffer;
281     llvm::raw_string_ostream OutputErrMsg(Buffer);
282     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
283       OutputErrMsg << ErrMsg.getMessage();
284     });
285     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
286     return false;
287   }
288 
289   // Append all features, not just new ones, so we override any negatives.
290   llvm::append_range(AllFeatures, (*ParseResult)->toFeatures());
291   return TargetInfo::initFeatureMap(Features, Diags, CPU, AllFeatures);
292 }
293 
294 std::optional<std::pair<unsigned, unsigned>>
getVScaleRange(const LangOptions & LangOpts) const295 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
296   // RISCV::RVVBitsPerBlock is 64.
297   unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
298 
299   if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
300     // Treat Zvl*b as a lower bound on vscale.
301     VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
302     unsigned VScaleMax = LangOpts.VScaleMax;
303     if (VScaleMax != 0 && VScaleMax < VScaleMin)
304       VScaleMax = VScaleMin;
305     return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
306   }
307 
308   if (VScaleMin > 0) {
309     unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
310     return std::make_pair(VScaleMin, VScaleMax);
311   }
312 
313   return std::nullopt;
314 }
315 
316 /// Return true if has this feature, need to sync with handleTargetFeatures.
hasFeature(StringRef Feature) const317 bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
318   bool Is64Bit = getTriple().isRISCV64();
319   auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
320                     .Case("riscv", true)
321                     .Case("riscv32", !Is64Bit)
322                     .Case("riscv64", Is64Bit)
323                     .Case("32bit", !Is64Bit)
324                     .Case("64bit", Is64Bit)
325                     .Case("experimental", HasExperimental)
326                     .Default(std::nullopt);
327   if (Result)
328     return *Result;
329 
330   return ISAInfo->hasExtension(Feature);
331 }
332 
333 /// Perform initialization based on the user configured set of features.
handleTargetFeatures(std::vector<std::string> & Features,DiagnosticsEngine & Diags)334 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
335                                            DiagnosticsEngine &Diags) {
336   unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
337   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
338   if (!ParseResult) {
339     std::string Buffer;
340     llvm::raw_string_ostream OutputErrMsg(Buffer);
341     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
342       OutputErrMsg << ErrMsg.getMessage();
343     });
344     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
345     return false;
346   } else {
347     ISAInfo = std::move(*ParseResult);
348   }
349 
350   if (ABI.empty())
351     ABI = ISAInfo->computeDefaultABI().str();
352 
353   if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
354     HasLegalHalfType = true;
355 
356   FastScalarUnalignedAccess =
357       llvm::is_contained(Features, "+unaligned-scalar-mem");
358 
359   if (llvm::is_contained(Features, "+experimental"))
360     HasExperimental = true;
361 
362   if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {
363     Diags.Report(diag::err_invalid_feature_combination)
364         << "ILP32E cannot be used with the D ISA extension";
365     return false;
366   }
367   return true;
368 }
369 
isValidCPUName(StringRef Name) const370 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
371   bool Is64Bit = getTriple().isArch64Bit();
372   return llvm::RISCV::parseCPU(Name, Is64Bit);
373 }
374 
fillValidCPUList(SmallVectorImpl<StringRef> & Values) const375 void RISCVTargetInfo::fillValidCPUList(
376     SmallVectorImpl<StringRef> &Values) const {
377   bool Is64Bit = getTriple().isArch64Bit();
378   llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
379 }
380 
isValidTuneCPUName(StringRef Name) const381 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
382   bool Is64Bit = getTriple().isArch64Bit();
383   return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
384 }
385 
fillValidTuneCPUList(SmallVectorImpl<StringRef> & Values) const386 void RISCVTargetInfo::fillValidTuneCPUList(
387     SmallVectorImpl<StringRef> &Values) const {
388   bool Is64Bit = getTriple().isArch64Bit();
389   llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
390 }
391 
handleFullArchString(StringRef FullArchStr,std::vector<std::string> & Features)392 static void handleFullArchString(StringRef FullArchStr,
393                                  std::vector<std::string> &Features) {
394   Features.push_back("__RISCV_TargetAttrNeedOverride");
395   auto RII = llvm::RISCVISAInfo::parseArchString(
396       FullArchStr, /* EnableExperimentalExtension */ true);
397   if (llvm::errorToBool(RII.takeError())) {
398     // Forward the invalid FullArchStr.
399     Features.push_back("+" + FullArchStr.str());
400   } else {
401     // Append a full list of features, including any negative extensions so that
402     // we override the CPU's features.
403     std::vector<std::string> FeatStrings =
404         (*RII)->toFeatures(/* AddAllExtensions */ true);
405     Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
406   }
407 }
408 
parseTargetAttr(StringRef Features) const409 ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
410   ParsedTargetAttr Ret;
411   if (Features == "default")
412     return Ret;
413   SmallVector<StringRef, 1> AttrFeatures;
414   Features.split(AttrFeatures, ";");
415   bool FoundArch = false;
416 
417   for (auto &Feature : AttrFeatures) {
418     Feature = Feature.trim();
419     StringRef AttrString = Feature.split("=").second.trim();
420 
421     if (Feature.starts_with("arch=")) {
422       // Override last features
423       Ret.Features.clear();
424       if (FoundArch)
425         Ret.Duplicate = "arch=";
426       FoundArch = true;
427 
428       if (AttrString.starts_with("+")) {
429         // EXTENSION like arch=+v,+zbb
430         SmallVector<StringRef, 1> Exts;
431         AttrString.split(Exts, ",");
432         for (auto Ext : Exts) {
433           if (Ext.empty())
434             continue;
435 
436           StringRef ExtName = Ext.substr(1);
437           std::string TargetFeature =
438               llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
439           if (!TargetFeature.empty())
440             Ret.Features.push_back(Ext.front() + TargetFeature);
441           else
442             Ret.Features.push_back(Ext.str());
443         }
444       } else {
445         // full-arch-string like arch=rv64gcv
446         handleFullArchString(AttrString, Ret.Features);
447       }
448     } else if (Feature.starts_with("cpu=")) {
449       if (!Ret.CPU.empty())
450         Ret.Duplicate = "cpu=";
451 
452       Ret.CPU = AttrString;
453 
454       if (!FoundArch) {
455         // Update Features with CPU's features
456         StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU);
457         if (MarchFromCPU != "") {
458           Ret.Features.clear();
459           handleFullArchString(MarchFromCPU, Ret.Features);
460         }
461       }
462     } else if (Feature.starts_with("tune=")) {
463       if (!Ret.Tune.empty())
464         Ret.Duplicate = "tune=";
465 
466       Ret.Tune = AttrString;
467     }
468   }
469   return Ret;
470 }
471 
472 TargetInfo::CallingConvCheckResult
checkCallingConvention(CallingConv CC) const473 RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
474   switch (CC) {
475   default:
476     return CCCR_Warning;
477   case CC_C:
478   case CC_RISCVVectorCall:
479     return CCCR_OK;
480   }
481 }
482