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