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") || ISAInfo->hasExtension("zmmul"))
162     Builder.defineMacro("__riscv_mul");
163 
164   if (ISAInfo->hasExtension("m")) {
165     Builder.defineMacro("__riscv_div");
166     Builder.defineMacro("__riscv_muldiv");
167   }
168 
169   if (ISAInfo->hasExtension("a")) {
170     Builder.defineMacro("__riscv_atomic");
171     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
172     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
173     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
174     if (Is64Bit)
175       Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
176   }
177 
178   if (FLen) {
179     Builder.defineMacro("__riscv_flen", Twine(FLen));
180     Builder.defineMacro("__riscv_fdiv");
181     Builder.defineMacro("__riscv_fsqrt");
182   }
183 
184   if (MinVLen) {
185     Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
186     Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
187     Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
188   }
189 
190   if (ISAInfo->hasExtension("c"))
191     Builder.defineMacro("__riscv_compressed");
192 
193   if (ISAInfo->hasExtension("zve32x"))
194     Builder.defineMacro("__riscv_vector");
195 }
196 
197 const Builtin::Info RISCVTargetInfo::BuiltinInfo[] = {
198 #define BUILTIN(ID, TYPE, ATTRS)                                               \
199   {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
200 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
201     {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
202 #include "clang/Basic/BuiltinsRISCVVector.def"
203 #define BUILTIN(ID, TYPE, ATTRS)                                               \
204   {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
205 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
206     {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
207 #include "clang/Basic/BuiltinsRISCV.def"
208 };
209 
210 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
211   return llvm::makeArrayRef(BuiltinInfo, clang::RISCV::LastTSBuiltin -
212                                              Builtin::FirstTSBuiltin);
213 }
214 
215 bool RISCVTargetInfo::initFeatureMap(
216     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
217     const std::vector<std::string> &FeaturesVec) const {
218 
219   unsigned XLen = 32;
220 
221   if (getTriple().getArch() == llvm::Triple::riscv64) {
222     Features["64bit"] = true;
223     XLen = 64;
224   }
225 
226   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
227   if (!ParseResult) {
228     std::string Buffer;
229     llvm::raw_string_ostream OutputErrMsg(Buffer);
230     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
231       OutputErrMsg << ErrMsg.getMessage();
232     });
233     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
234     return false;
235   }
236 
237   // RISCVISAInfo makes implications for ISA features
238   std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();
239   // Add non-ISA features like `relax` and `save-restore` back
240   for (const std::string &Feature : FeaturesVec)
241     if (!llvm::is_contained(ImpliedFeatures, Feature))
242       ImpliedFeatures.push_back(Feature);
243 
244   return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures);
245 }
246 
247 /// Return true if has this feature, need to sync with handleTargetFeatures.
248 bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
249   bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
250   auto Result = llvm::StringSwitch<Optional<bool>>(Feature)
251                     .Case("riscv", true)
252                     .Case("riscv32", !Is64Bit)
253                     .Case("riscv64", Is64Bit)
254                     .Case("64bit", Is64Bit)
255                     .Default(None);
256   if (Result)
257     return Result.value();
258 
259   if (ISAInfo->isSupportedExtensionFeature(Feature))
260     return ISAInfo->hasExtension(Feature);
261 
262   return false;
263 }
264 
265 /// Perform initialization based on the user configured set of features.
266 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
267                                            DiagnosticsEngine &Diags) {
268   unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
269   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
270   if (!ParseResult) {
271     std::string Buffer;
272     llvm::raw_string_ostream OutputErrMsg(Buffer);
273     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
274       OutputErrMsg << ErrMsg.getMessage();
275     });
276     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
277     return false;
278   } else {
279     ISAInfo = std::move(*ParseResult);
280   }
281 
282   if (ABI.empty())
283     ABI = ISAInfo->computeDefaultABI().str();
284 
285   return true;
286 }
287 
288 bool RISCV32TargetInfo::isValidCPUName(StringRef Name) const {
289   return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
290                                    /*Is64Bit=*/false);
291 }
292 
293 void RISCV32TargetInfo::fillValidCPUList(
294     SmallVectorImpl<StringRef> &Values) const {
295   llvm::RISCV::fillValidCPUArchList(Values, false);
296 }
297 
298 bool RISCV32TargetInfo::isValidTuneCPUName(StringRef Name) const {
299   return llvm::RISCV::checkTuneCPUKind(
300       llvm::RISCV::parseTuneCPUKind(Name, false),
301       /*Is64Bit=*/false);
302 }
303 
304 void RISCV32TargetInfo::fillValidTuneCPUList(
305     SmallVectorImpl<StringRef> &Values) const {
306   llvm::RISCV::fillValidTuneCPUArchList(Values, false);
307 }
308 
309 bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const {
310   return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
311                                    /*Is64Bit=*/true);
312 }
313 
314 void RISCV64TargetInfo::fillValidCPUList(
315     SmallVectorImpl<StringRef> &Values) const {
316   llvm::RISCV::fillValidCPUArchList(Values, true);
317 }
318 
319 bool RISCV64TargetInfo::isValidTuneCPUName(StringRef Name) const {
320   return llvm::RISCV::checkTuneCPUKind(
321       llvm::RISCV::parseTuneCPUKind(Name, true),
322       /*Is64Bit=*/true);
323 }
324 
325 void RISCV64TargetInfo::fillValidTuneCPUList(
326     SmallVectorImpl<StringRef> &Values) const {
327   llvm::RISCV::fillValidTuneCPUArchList(Values, true);
328 }
329