xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp (revision a4e5e0106ac7145f56eb39a691e302cabb4635be)
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   static const char *const GCCRegNames[] = {
27       // Integer registers
28       "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
29       "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
30       "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
31       "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
32 
33       // Floating point registers
34       "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
35       "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
36       "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
37       "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
38 
39       // Vector registers
40       "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
41       "v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15",
42       "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
43       "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"};
44   return llvm::ArrayRef(GCCRegNames);
45 }
46 
47 ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
48   static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
49       {{"zero"}, "x0"}, {{"ra"}, "x1"},   {{"sp"}, "x2"},    {{"gp"}, "x3"},
50       {{"tp"}, "x4"},   {{"t0"}, "x5"},   {{"t1"}, "x6"},    {{"t2"}, "x7"},
51       {{"s0"}, "x8"},   {{"s1"}, "x9"},   {{"a0"}, "x10"},   {{"a1"}, "x11"},
52       {{"a2"}, "x12"},  {{"a3"}, "x13"},  {{"a4"}, "x14"},   {{"a5"}, "x15"},
53       {{"a6"}, "x16"},  {{"a7"}, "x17"},  {{"s2"}, "x18"},   {{"s3"}, "x19"},
54       {{"s4"}, "x20"},  {{"s5"}, "x21"},  {{"s6"}, "x22"},   {{"s7"}, "x23"},
55       {{"s8"}, "x24"},  {{"s9"}, "x25"},  {{"s10"}, "x26"},  {{"s11"}, "x27"},
56       {{"t3"}, "x28"},  {{"t4"}, "x29"},  {{"t5"}, "x30"},   {{"t6"}, "x31"},
57       {{"ft0"}, "f0"},  {{"ft1"}, "f1"},  {{"ft2"}, "f2"},   {{"ft3"}, "f3"},
58       {{"ft4"}, "f4"},  {{"ft5"}, "f5"},  {{"ft6"}, "f6"},   {{"ft7"}, "f7"},
59       {{"fs0"}, "f8"},  {{"fs1"}, "f9"},  {{"fa0"}, "f10"},  {{"fa1"}, "f11"},
60       {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"},  {{"fa5"}, "f15"},
61       {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"},  {{"fs3"}, "f19"},
62       {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"},  {{"fs7"}, "f23"},
63       {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},
64       {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};
65   return llvm::ArrayRef(GCCRegAliases);
66 }
67 
68 bool RISCVTargetInfo::validateAsmConstraint(
69     const char *&Name, TargetInfo::ConstraintInfo &Info) const {
70   switch (*Name) {
71   default:
72     return false;
73   case 'I':
74     // A 12-bit signed immediate.
75     Info.setRequiresImmediate(-2048, 2047);
76     return true;
77   case 'J':
78     // Integer zero.
79     Info.setRequiresImmediate(0);
80     return true;
81   case 'K':
82     // A 5-bit unsigned immediate for CSR access instructions.
83     Info.setRequiresImmediate(0, 31);
84     return true;
85   case 'f':
86     // A floating-point register.
87     Info.setAllowsRegister();
88     return true;
89   case 'A':
90     // An address that is held in a general-purpose register.
91     Info.setAllowsMemory();
92     return true;
93   case 'S': // A symbolic address
94     Info.setAllowsRegister();
95     return true;
96   case 'v':
97     // A vector register.
98     if (Name[1] == 'r' || Name[1] == 'm') {
99       Info.setAllowsRegister();
100       Name += 1;
101       return true;
102     }
103     return false;
104   }
105 }
106 
107 std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
108   std::string R;
109   switch (*Constraint) {
110   case 'v':
111     R = std::string("^") + std::string(Constraint, 2);
112     Constraint += 1;
113     break;
114   default:
115     R = TargetInfo::convertConstraint(Constraint);
116     break;
117   }
118   return R;
119 }
120 
121 static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
122   return MajorVersion * 1000000 + MinorVersion * 1000;
123 }
124 
125 void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
126                                        MacroBuilder &Builder) const {
127   Builder.defineMacro("__riscv");
128   bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
129   Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
130   StringRef CodeModel = getTargetOpts().CodeModel;
131   unsigned FLen = ISAInfo->getFLen();
132   unsigned MinVLen = ISAInfo->getMinVLen();
133   unsigned MaxELen = ISAInfo->getMaxELen();
134   unsigned MaxELenFp = ISAInfo->getMaxELenFp();
135   if (CodeModel == "default")
136     CodeModel = "small";
137 
138   if (CodeModel == "small")
139     Builder.defineMacro("__riscv_cmodel_medlow");
140   else if (CodeModel == "medium")
141     Builder.defineMacro("__riscv_cmodel_medany");
142 
143   StringRef ABIName = getABI();
144   if (ABIName == "ilp32f" || ABIName == "lp64f")
145     Builder.defineMacro("__riscv_float_abi_single");
146   else if (ABIName == "ilp32d" || ABIName == "lp64d")
147     Builder.defineMacro("__riscv_float_abi_double");
148   else
149     Builder.defineMacro("__riscv_float_abi_soft");
150 
151   if (ABIName == "ilp32e")
152     Builder.defineMacro("__riscv_abi_rve");
153 
154   Builder.defineMacro("__riscv_arch_test");
155 
156   for (auto &Extension : ISAInfo->getExtensions()) {
157     auto ExtName = Extension.first;
158     auto ExtInfo = Extension.second;
159 
160     Builder.defineMacro(
161         Twine("__riscv_", ExtName),
162         Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion)));
163   }
164 
165   if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul"))
166     Builder.defineMacro("__riscv_mul");
167 
168   if (ISAInfo->hasExtension("m")) {
169     Builder.defineMacro("__riscv_div");
170     Builder.defineMacro("__riscv_muldiv");
171   }
172 
173   if (ISAInfo->hasExtension("a")) {
174     Builder.defineMacro("__riscv_atomic");
175     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
176     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
177     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
178     if (Is64Bit)
179       Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
180   }
181 
182   if (FLen) {
183     Builder.defineMacro("__riscv_flen", Twine(FLen));
184     Builder.defineMacro("__riscv_fdiv");
185     Builder.defineMacro("__riscv_fsqrt");
186   }
187 
188   if (MinVLen) {
189     Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
190     Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
191     Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
192   }
193 
194   if (ISAInfo->hasExtension("c"))
195     Builder.defineMacro("__riscv_compressed");
196 
197   if (ISAInfo->hasExtension("zve32x")) {
198     Builder.defineMacro("__riscv_vector");
199     // Currently we support the v0.12 RISC-V V intrinsics.
200     Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12)));
201   }
202 
203   auto VScale = getVScaleRange(Opts);
204   if (VScale && VScale->first && VScale->first == VScale->second)
205     Builder.defineMacro("__riscv_v_fixed_vlen",
206                         Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
207 }
208 
209 static constexpr Builtin::Info BuiltinInfo[] = {
210 #define BUILTIN(ID, TYPE, ATTRS)                                               \
211   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
212 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
213   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
214 #include "clang/Basic/BuiltinsRISCVVector.def"
215 #define BUILTIN(ID, TYPE, ATTRS)                                               \
216   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
217 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
218   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
219 #include "clang/Basic/BuiltinsRISCV.def"
220 };
221 
222 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
223   return llvm::ArrayRef(BuiltinInfo,
224                         clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
225 }
226 
227 bool RISCVTargetInfo::initFeatureMap(
228     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
229     const std::vector<std::string> &FeaturesVec) const {
230 
231   unsigned XLen = 32;
232 
233   if (getTriple().getArch() == llvm::Triple::riscv64) {
234     Features["64bit"] = true;
235     XLen = 64;
236   } else {
237     Features["32bit"] = true;
238   }
239 
240   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
241   if (!ParseResult) {
242     std::string Buffer;
243     llvm::raw_string_ostream OutputErrMsg(Buffer);
244     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
245       OutputErrMsg << ErrMsg.getMessage();
246     });
247     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
248     return false;
249   }
250 
251   // RISCVISAInfo makes implications for ISA features
252   std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();
253   // Add non-ISA features like `relax` and `save-restore` back
254   for (const std::string &Feature : FeaturesVec)
255     if (!llvm::is_contained(ImpliedFeatures, Feature))
256       ImpliedFeatures.push_back(Feature);
257 
258   return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures);
259 }
260 
261 std::optional<std::pair<unsigned, unsigned>>
262 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
263   // RISCV::RVVBitsPerBlock is 64.
264   unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
265 
266   if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
267     // Treat Zvl*b as a lower bound on vscale.
268     VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
269     unsigned VScaleMax = LangOpts.VScaleMax;
270     if (VScaleMax != 0 && VScaleMax < VScaleMin)
271       VScaleMax = VScaleMin;
272     return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
273   }
274 
275   if (VScaleMin > 0) {
276     unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
277     return std::make_pair(VScaleMin, VScaleMax);
278   }
279 
280   return std::nullopt;
281 }
282 
283 /// Return true if has this feature, need to sync with handleTargetFeatures.
284 bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
285   bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
286   auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
287                     .Case("riscv", true)
288                     .Case("riscv32", !Is64Bit)
289                     .Case("riscv64", Is64Bit)
290                     .Case("32bit", !Is64Bit)
291                     .Case("64bit", Is64Bit)
292                     .Default(std::nullopt);
293   if (Result)
294     return *Result;
295 
296   if (ISAInfo->isSupportedExtensionFeature(Feature))
297     return ISAInfo->hasExtension(Feature);
298 
299   return false;
300 }
301 
302 /// Perform initialization based on the user configured set of features.
303 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
304                                            DiagnosticsEngine &Diags) {
305   unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
306   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
307   if (!ParseResult) {
308     std::string Buffer;
309     llvm::raw_string_ostream OutputErrMsg(Buffer);
310     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
311       OutputErrMsg << ErrMsg.getMessage();
312     });
313     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
314     return false;
315   } else {
316     ISAInfo = std::move(*ParseResult);
317   }
318 
319   if (ABI.empty())
320     ABI = ISAInfo->computeDefaultABI().str();
321 
322   if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
323     HasLegalHalfType = true;
324 
325   return true;
326 }
327 
328 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
329   bool Is64Bit = getTriple().isArch64Bit();
330   return llvm::RISCV::parseCPU(Name, Is64Bit);
331 }
332 
333 void RISCVTargetInfo::fillValidCPUList(
334     SmallVectorImpl<StringRef> &Values) const {
335   bool Is64Bit = getTriple().isArch64Bit();
336   llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
337 }
338 
339 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
340   bool Is64Bit = getTriple().isArch64Bit();
341   return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
342 }
343 
344 void RISCVTargetInfo::fillValidTuneCPUList(
345     SmallVectorImpl<StringRef> &Values) const {
346   bool Is64Bit = getTriple().isArch64Bit();
347   llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
348 }
349