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/raw_ostream.h"
19 #include "llvm/TargetParser/RISCVTargetParser.h"
20 #include <optional>
21
22 using namespace clang;
23 using namespace clang::targets;
24
getGCCRegNames() const25 ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
26 static const char *const GCCRegNames[] = {
27 // Integer registers
28 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
29 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
30 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
31 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
32
33 // Floating point registers
34 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
35 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
36 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
37 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
38
39 // Vector registers
40 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
41 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
42 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
43 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"};
44 return llvm::ArrayRef(GCCRegNames);
45 }
46
getGCCRegAliases() const47 ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
48 static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
49 {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"},
50 {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"},
51 {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"},
52 {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"},
53 {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"},
54 {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"},
55 {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},
56 {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"},
57 {{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"},
58 {{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"},
59 {{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"},
60 {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"},
61 {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"},
62 {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"},
63 {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},
64 {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};
65 return llvm::ArrayRef(GCCRegAliases);
66 }
67
validateAsmConstraint(const char * & Name,TargetInfo::ConstraintInfo & Info) const68 bool RISCVTargetInfo::validateAsmConstraint(
69 const char *&Name, TargetInfo::ConstraintInfo &Info) const {
70 switch (*Name) {
71 default:
72 return false;
73 case 'I':
74 // A 12-bit signed immediate.
75 Info.setRequiresImmediate(-2048, 2047);
76 return true;
77 case 'J':
78 // Integer zero.
79 Info.setRequiresImmediate(0);
80 return true;
81 case 'K':
82 // A 5-bit unsigned immediate for CSR access instructions.
83 Info.setRequiresImmediate(0, 31);
84 return true;
85 case 'f':
86 // A floating-point register.
87 Info.setAllowsRegister();
88 return true;
89 case 'A':
90 // An address that is held in a general-purpose register.
91 Info.setAllowsMemory();
92 return true;
93 case 'S': // A symbolic address
94 Info.setAllowsRegister();
95 return true;
96 case 'v':
97 // A vector register.
98 if (Name[1] == 'r' || Name[1] == 'm') {
99 Info.setAllowsRegister();
100 Name += 1;
101 return true;
102 }
103 return false;
104 }
105 }
106
convertConstraint(const char * & Constraint) const107 std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
108 std::string R;
109 switch (*Constraint) {
110 case 'v':
111 R = std::string("^") + std::string(Constraint, 2);
112 Constraint += 1;
113 break;
114 default:
115 R = TargetInfo::convertConstraint(Constraint);
116 break;
117 }
118 return R;
119 }
120
getVersionValue(unsigned MajorVersion,unsigned MinorVersion)121 static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
122 return MajorVersion * 1000000 + MinorVersion * 1000;
123 }
124
getTargetDefines(const LangOptions & Opts,MacroBuilder & Builder) const125 void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
126 MacroBuilder &Builder) const {
127 Builder.defineMacro("__ELF__");
128 Builder.defineMacro("__riscv");
129 bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
130 Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
131 StringRef CodeModel = getTargetOpts().CodeModel;
132 unsigned FLen = ISAInfo->getFLen();
133 unsigned MinVLen = ISAInfo->getMinVLen();
134 unsigned MaxELen = ISAInfo->getMaxELen();
135 unsigned MaxELenFp = ISAInfo->getMaxELenFp();
136 if (CodeModel == "default")
137 CodeModel = "small";
138
139 if (CodeModel == "small")
140 Builder.defineMacro("__riscv_cmodel_medlow");
141 else if (CodeModel == "medium")
142 Builder.defineMacro("__riscv_cmodel_medany");
143
144 StringRef ABIName = getABI();
145 if (ABIName == "ilp32f" || ABIName == "lp64f")
146 Builder.defineMacro("__riscv_float_abi_single");
147 else if (ABIName == "ilp32d" || ABIName == "lp64d")
148 Builder.defineMacro("__riscv_float_abi_double");
149 else
150 Builder.defineMacro("__riscv_float_abi_soft");
151
152 if (ABIName == "ilp32e")
153 Builder.defineMacro("__riscv_abi_rve");
154
155 Builder.defineMacro("__riscv_arch_test");
156
157 for (auto &Extension : ISAInfo->getExtensions()) {
158 auto ExtName = Extension.first;
159 auto ExtInfo = Extension.second;
160
161 Builder.defineMacro(
162 Twine("__riscv_", ExtName),
163 Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion)));
164 }
165
166 if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul"))
167 Builder.defineMacro("__riscv_mul");
168
169 if (ISAInfo->hasExtension("m")) {
170 Builder.defineMacro("__riscv_div");
171 Builder.defineMacro("__riscv_muldiv");
172 }
173
174 if (ISAInfo->hasExtension("a")) {
175 Builder.defineMacro("__riscv_atomic");
176 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
177 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
178 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
179 if (Is64Bit)
180 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
181 }
182
183 if (FLen) {
184 Builder.defineMacro("__riscv_flen", Twine(FLen));
185 Builder.defineMacro("__riscv_fdiv");
186 Builder.defineMacro("__riscv_fsqrt");
187 }
188
189 if (MinVLen) {
190 Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
191 Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
192 Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
193 }
194
195 if (ISAInfo->hasExtension("c"))
196 Builder.defineMacro("__riscv_compressed");
197
198 if (ISAInfo->hasExtension("zve32x")) {
199 Builder.defineMacro("__riscv_vector");
200 // Currently we support the v0.11 RISC-V V intrinsics.
201 Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 11)));
202 }
203 }
204
205 static constexpr Builtin::Info BuiltinInfo[] = {
206 #define BUILTIN(ID, TYPE, ATTRS) \
207 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
208 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
209 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
210 #include "clang/Basic/BuiltinsRISCVVector.def"
211 #define BUILTIN(ID, TYPE, ATTRS) \
212 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
213 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
214 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
215 #include "clang/Basic/BuiltinsRISCV.def"
216 };
217
getTargetBuiltins() const218 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
219 return llvm::ArrayRef(BuiltinInfo,
220 clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
221 }
222
initFeatureMap(llvm::StringMap<bool> & Features,DiagnosticsEngine & Diags,StringRef CPU,const std::vector<std::string> & FeaturesVec) const223 bool RISCVTargetInfo::initFeatureMap(
224 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
225 const std::vector<std::string> &FeaturesVec) const {
226
227 unsigned XLen = 32;
228
229 if (getTriple().getArch() == llvm::Triple::riscv64) {
230 Features["64bit"] = true;
231 XLen = 64;
232 } else {
233 Features["32bit"] = true;
234 }
235
236 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
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 }
246
247 // RISCVISAInfo makes implications for ISA features
248 std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();
249 // Add non-ISA features like `relax` and `save-restore` back
250 for (const std::string &Feature : FeaturesVec)
251 if (!llvm::is_contained(ImpliedFeatures, Feature))
252 ImpliedFeatures.push_back(Feature);
253
254 return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures);
255 }
256
257 std::optional<std::pair<unsigned, unsigned>>
getVScaleRange(const LangOptions & LangOpts) const258 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
259 // RISCV::RVVBitsPerBlock is 64.
260 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
261
262 if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
263 // Treat Zvl*b as a lower bound on vscale.
264 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
265 unsigned VScaleMax = LangOpts.VScaleMax;
266 if (VScaleMax != 0 && VScaleMax < VScaleMin)
267 VScaleMax = VScaleMin;
268 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
269 }
270
271 if (VScaleMin > 0) {
272 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
273 return std::make_pair(VScaleMin, VScaleMax);
274 }
275
276 return std::nullopt;
277 }
278
279 /// Return true if has this feature, need to sync with handleTargetFeatures.
hasFeature(StringRef Feature) const280 bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
281 bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
282 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
283 .Case("riscv", true)
284 .Case("riscv32", !Is64Bit)
285 .Case("riscv64", Is64Bit)
286 .Case("32bit", !Is64Bit)
287 .Case("64bit", Is64Bit)
288 .Default(std::nullopt);
289 if (Result)
290 return *Result;
291
292 if (ISAInfo->isSupportedExtensionFeature(Feature))
293 return ISAInfo->hasExtension(Feature);
294
295 return false;
296 }
297
298 /// Perform initialization based on the user configured set of features.
handleTargetFeatures(std::vector<std::string> & Features,DiagnosticsEngine & Diags)299 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
300 DiagnosticsEngine &Diags) {
301 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
302 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
303 if (!ParseResult) {
304 std::string Buffer;
305 llvm::raw_string_ostream OutputErrMsg(Buffer);
306 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
307 OutputErrMsg << ErrMsg.getMessage();
308 });
309 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
310 return false;
311 } else {
312 ISAInfo = std::move(*ParseResult);
313 }
314
315 if (ABI.empty())
316 ABI = ISAInfo->computeDefaultABI().str();
317
318 return true;
319 }
320
isValidCPUName(StringRef Name) const321 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
322 bool Is64Bit = getTriple().isArch64Bit();
323 return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name), Is64Bit);
324 }
325
fillValidCPUList(SmallVectorImpl<StringRef> & Values) const326 void RISCVTargetInfo::fillValidCPUList(
327 SmallVectorImpl<StringRef> &Values) const {
328 bool Is64Bit = getTriple().isArch64Bit();
329 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
330 }
331
isValidTuneCPUName(StringRef Name) const332 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
333 bool Is64Bit = getTriple().isArch64Bit();
334 return llvm::RISCV::checkTuneCPUKind(
335 llvm::RISCV::parseTuneCPUKind(Name, Is64Bit), Is64Bit);
336 }
337
fillValidTuneCPUList(SmallVectorImpl<StringRef> & Values) const338 void RISCVTargetInfo::fillValidTuneCPUList(
339 SmallVectorImpl<StringRef> &Values) const {
340 bool Is64Bit = getTriple().isArch64Bit();
341 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
342 }
343