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"))
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   // RISCVISAInfo makes implications for ISA features
236   std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();
237   // Add non-ISA features like `relax` and `save-restore` back
238   for (std::string Feature : FeaturesVec) {
239     if (std::find(begin(ImpliedFeatures), end(ImpliedFeatures), Feature) ==
240         end(ImpliedFeatures))
241       ImpliedFeatures.push_back(Feature);
242   }
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.hasValue())
257     return Result.getValue();
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