xref: /freebsd-src/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp (revision 4824e7fd18a1223177218d4aec1b3c6c5c4a444e)
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   if (CodeModel == "default")
129     CodeModel = "small";
130 
131   if (CodeModel == "small")
132     Builder.defineMacro("__riscv_cmodel_medlow");
133   else if (CodeModel == "medium")
134     Builder.defineMacro("__riscv_cmodel_medany");
135 
136   StringRef ABIName = getABI();
137   if (ABIName == "ilp32f" || ABIName == "lp64f")
138     Builder.defineMacro("__riscv_float_abi_single");
139   else if (ABIName == "ilp32d" || ABIName == "lp64d")
140     Builder.defineMacro("__riscv_float_abi_double");
141   else
142     Builder.defineMacro("__riscv_float_abi_soft");
143 
144   if (ABIName == "ilp32e")
145     Builder.defineMacro("__riscv_abi_rve");
146 
147   Builder.defineMacro("__riscv_arch_test");
148 
149   for (auto &Extension : ISAInfo->getExtensions()) {
150     auto ExtName = Extension.first;
151     auto ExtInfo = Extension.second;
152     unsigned Version =
153         (ExtInfo.MajorVersion * 1000000) + (ExtInfo.MinorVersion * 1000);
154 
155     Builder.defineMacro(Twine("__riscv_", ExtName), Twine(Version));
156   }
157 
158   if (ISAInfo->hasExtension("m")) {
159     Builder.defineMacro("__riscv_mul");
160     Builder.defineMacro("__riscv_div");
161     Builder.defineMacro("__riscv_muldiv");
162   }
163 
164   if (ISAInfo->hasExtension("a")) {
165     Builder.defineMacro("__riscv_atomic");
166     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
167     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
168     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
169     if (Is64Bit)
170       Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
171   }
172 
173   if (FLen) {
174     Builder.defineMacro("__riscv_flen", Twine(FLen));
175     Builder.defineMacro("__riscv_fdiv");
176     Builder.defineMacro("__riscv_fsqrt");
177   }
178 
179   if (ISAInfo->hasExtension("c"))
180     Builder.defineMacro("__riscv_compressed");
181 
182   if (ISAInfo->hasExtension("v"))
183     Builder.defineMacro("__riscv_vector");
184 }
185 
186 const Builtin::Info RISCVTargetInfo::BuiltinInfo[] = {
187 #define BUILTIN(ID, TYPE, ATTRS)                                               \
188   {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
189 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
190     {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
191 #include "clang/Basic/BuiltinsRISCVVector.def"
192 #define BUILTIN(ID, TYPE, ATTRS)                                               \
193   {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
194 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
195     {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
196 #include "clang/Basic/BuiltinsRISCV.def"
197 };
198 
199 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
200   return llvm::makeArrayRef(BuiltinInfo, clang::RISCV::LastTSBuiltin -
201                                              Builtin::FirstTSBuiltin);
202 }
203 
204 bool RISCVTargetInfo::initFeatureMap(
205     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
206     const std::vector<std::string> &FeaturesVec) const {
207 
208   if (getTriple().getArch() == llvm::Triple::riscv64)
209     Features["64bit"] = true;
210 
211   return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
212 }
213 
214 /// Return true if has this feature, need to sync with handleTargetFeatures.
215 bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
216   bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
217   auto Result = llvm::StringSwitch<Optional<bool>>(Feature)
218                     .Case("riscv", true)
219                     .Case("riscv32", !Is64Bit)
220                     .Case("riscv64", Is64Bit)
221                     .Case("64bit", Is64Bit)
222                     .Default(None);
223   if (Result.hasValue())
224     return Result.getValue();
225 
226   if (ISAInfo->isSupportedExtensionFeature(Feature))
227     return ISAInfo->hasExtension(Feature);
228 
229   return false;
230 }
231 
232 /// Perform initialization based on the user configured set of features.
233 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
234                                            DiagnosticsEngine &Diags) {
235   unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
236   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
237   if (!ParseResult) {
238     std::string Buffer;
239     llvm::raw_string_ostream OutputErrMsg(Buffer);
240     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
241       OutputErrMsg << ErrMsg.getMessage();
242     });
243     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
244     return false;
245   } else {
246     ISAInfo = std::move(*ParseResult);
247   }
248 
249   return true;
250 }
251 
252 bool RISCV32TargetInfo::isValidCPUName(StringRef Name) const {
253   return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
254                                    /*Is64Bit=*/false);
255 }
256 
257 void RISCV32TargetInfo::fillValidCPUList(
258     SmallVectorImpl<StringRef> &Values) const {
259   llvm::RISCV::fillValidCPUArchList(Values, false);
260 }
261 
262 bool RISCV32TargetInfo::isValidTuneCPUName(StringRef Name) const {
263   return llvm::RISCV::checkTuneCPUKind(
264       llvm::RISCV::parseTuneCPUKind(Name, false),
265       /*Is64Bit=*/false);
266 }
267 
268 void RISCV32TargetInfo::fillValidTuneCPUList(
269     SmallVectorImpl<StringRef> &Values) const {
270   llvm::RISCV::fillValidTuneCPUArchList(Values, false);
271 }
272 
273 bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const {
274   return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
275                                    /*Is64Bit=*/true);
276 }
277 
278 void RISCV64TargetInfo::fillValidCPUList(
279     SmallVectorImpl<StringRef> &Values) const {
280   llvm::RISCV::fillValidCPUArchList(Values, true);
281 }
282 
283 bool RISCV64TargetInfo::isValidTuneCPUName(StringRef Name) const {
284   return llvm::RISCV::checkTuneCPUKind(
285       llvm::RISCV::parseTuneCPUKind(Name, true),
286       /*Is64Bit=*/true);
287 }
288 
289 void RISCV64TargetInfo::fillValidTuneCPUList(
290     SmallVectorImpl<StringRef> &Values) const {
291   llvm::RISCV::fillValidTuneCPUArchList(Values, true);
292 }
293