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
getGCCRegNames() const24 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
getGCCRegAliases() const46 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
validateAsmConstraint(const char * & Name,TargetInfo::ConstraintInfo & Info) const67 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
convertConstraint(const char * & Constraint) const106 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
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const120 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
getTargetBuiltins() const210 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
211 return llvm::makeArrayRef(BuiltinInfo, clang::RISCV::LastTSBuiltin -
212 Builtin::FirstTSBuiltin);
213 }
214
initFeatureMap(llvm::StringMap<bool> & Features,DiagnosticsEngine & Diags,StringRef CPU,const std::vector<std::string> & FeaturesVec) const215 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.
hasFeature(StringRef Feature) const248 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.
handleTargetFeatures(std::vector<std::string> & Features,DiagnosticsEngine & Diags)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
isValidCPUName(StringRef Name) const288 bool RISCV32TargetInfo::isValidCPUName(StringRef Name) const {
289 return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
290 /*Is64Bit=*/false);
291 }
292
fillValidCPUList(SmallVectorImpl<StringRef> & Values) const293 void RISCV32TargetInfo::fillValidCPUList(
294 SmallVectorImpl<StringRef> &Values) const {
295 llvm::RISCV::fillValidCPUArchList(Values, false);
296 }
297
isValidTuneCPUName(StringRef Name) const298 bool RISCV32TargetInfo::isValidTuneCPUName(StringRef Name) const {
299 return llvm::RISCV::checkTuneCPUKind(
300 llvm::RISCV::parseTuneCPUKind(Name, false),
301 /*Is64Bit=*/false);
302 }
303
fillValidTuneCPUList(SmallVectorImpl<StringRef> & Values) const304 void RISCV32TargetInfo::fillValidTuneCPUList(
305 SmallVectorImpl<StringRef> &Values) const {
306 llvm::RISCV::fillValidTuneCPUArchList(Values, false);
307 }
308
isValidCPUName(StringRef Name) const309 bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const {
310 return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
311 /*Is64Bit=*/true);
312 }
313
fillValidCPUList(SmallVectorImpl<StringRef> & Values) const314 void RISCV64TargetInfo::fillValidCPUList(
315 SmallVectorImpl<StringRef> &Values) const {
316 llvm::RISCV::fillValidCPUArchList(Values, true);
317 }
318
isValidTuneCPUName(StringRef Name) const319 bool RISCV64TargetInfo::isValidTuneCPUName(StringRef Name) const {
320 return llvm::RISCV::checkTuneCPUKind(
321 llvm::RISCV::parseTuneCPUKind(Name, true),
322 /*Is64Bit=*/true);
323 }
324
fillValidTuneCPUList(SmallVectorImpl<StringRef> & Values) const325 void RISCV64TargetInfo::fillValidTuneCPUList(
326 SmallVectorImpl<StringRef> &Values) const {
327 llvm::RISCV::fillValidTuneCPUArchList(Values, true);
328 }
329