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 (const std::string &Feature : FeaturesVec)
239     if (!llvm::is_contained(ImpliedFeatures, Feature))
240       ImpliedFeatures.push_back(Feature);
241 
242   return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures);
243 }
244 
245 /// Return true if has this feature, need to sync with handleTargetFeatures.
246 bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
247   bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
248   auto Result = llvm::StringSwitch<Optional<bool>>(Feature)
249                     .Case("riscv", true)
250                     .Case("riscv32", !Is64Bit)
251                     .Case("riscv64", Is64Bit)
252                     .Case("64bit", Is64Bit)
253                     .Default(None);
254   if (Result.hasValue())
255     return Result.getValue();
256 
257   if (ISAInfo->isSupportedExtensionFeature(Feature))
258     return ISAInfo->hasExtension(Feature);
259 
260   return false;
261 }
262 
263 /// Perform initialization based on the user configured set of features.
264 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
265                                            DiagnosticsEngine &Diags) {
266   unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
267   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
268   if (!ParseResult) {
269     std::string Buffer;
270     llvm::raw_string_ostream OutputErrMsg(Buffer);
271     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
272       OutputErrMsg << ErrMsg.getMessage();
273     });
274     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
275     return false;
276   } else {
277     ISAInfo = std::move(*ParseResult);
278   }
279 
280   if (ABI.empty())
281     ABI = ISAInfo->computeDefaultABI().str();
282 
283   return true;
284 }
285 
286 bool RISCV32TargetInfo::isValidCPUName(StringRef Name) const {
287   return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
288                                    /*Is64Bit=*/false);
289 }
290 
291 void RISCV32TargetInfo::fillValidCPUList(
292     SmallVectorImpl<StringRef> &Values) const {
293   llvm::RISCV::fillValidCPUArchList(Values, false);
294 }
295 
296 bool RISCV32TargetInfo::isValidTuneCPUName(StringRef Name) const {
297   return llvm::RISCV::checkTuneCPUKind(
298       llvm::RISCV::parseTuneCPUKind(Name, false),
299       /*Is64Bit=*/false);
300 }
301 
302 void RISCV32TargetInfo::fillValidTuneCPUList(
303     SmallVectorImpl<StringRef> &Values) const {
304   llvm::RISCV::fillValidTuneCPUArchList(Values, false);
305 }
306 
307 bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const {
308   return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
309                                    /*Is64Bit=*/true);
310 }
311 
312 void RISCV64TargetInfo::fillValidCPUList(
313     SmallVectorImpl<StringRef> &Values) const {
314   llvm::RISCV::fillValidCPUArchList(Values, true);
315 }
316 
317 bool RISCV64TargetInfo::isValidTuneCPUName(StringRef Name) const {
318   return llvm::RISCV::checkTuneCPUKind(
319       llvm::RISCV::parseTuneCPUKind(Name, true),
320       /*Is64Bit=*/true);
321 }
322 
323 void RISCV64TargetInfo::fillValidTuneCPUList(
324     SmallVectorImpl<StringRef> &Values) const {
325   llvm::RISCV::fillValidTuneCPUArchList(Values, true);
326 }
327