1 //===--- RISCV.cpp - Implement RISC-V target feature support --------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements RISC-V TargetInfo objects.
11 //===----------------------------------------------------------------------===//
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"
22 using namespace clang
;
23 using namespace clang::targets
;
25 ArrayRef
<const char *> RISCVTargetInfo::getGCCRegNames() const {
27 static const char *const GCCRegNames
[] = {
29 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
30 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
31 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
32 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
34 // Floating point registers
35 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
36 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
37 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
38 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
41 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
42 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
43 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
44 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
47 "fflags", "frm", "vtype", "vl", "vxsat", "vxrm"
50 return llvm::ArrayRef(GCCRegNames
);
53 ArrayRef
<TargetInfo::GCCRegAlias
> RISCVTargetInfo::getGCCRegAliases() const {
54 static const TargetInfo::GCCRegAlias GCCRegAliases
[] = {
55 {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"},
56 {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"},
57 {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"},
58 {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"},
59 {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"},
60 {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"},
61 {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},
62 {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"},
63 {{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"},
64 {{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"},
65 {{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"},
66 {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"},
67 {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"},
68 {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"},
69 {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},
70 {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};
71 return llvm::ArrayRef(GCCRegAliases
);
74 bool RISCVTargetInfo::validateAsmConstraint(
75 const char *&Name
, TargetInfo::ConstraintInfo
&Info
) const {
80 // A 12-bit signed immediate.
81 Info
.setRequiresImmediate(-2048, 2047);
85 Info
.setRequiresImmediate(0);
88 // A 5-bit unsigned immediate for CSR access instructions.
89 Info
.setRequiresImmediate(0, 31);
92 // A floating-point register.
93 Info
.setAllowsRegister();
96 // An address that is held in a general-purpose register.
97 Info
.setAllowsMemory();
99 case 'S': // A symbolic address
100 Info
.setAllowsRegister();
103 // A vector register.
104 if (Name
[1] == 'r' || Name
[1] == 'm') {
105 Info
.setAllowsRegister();
113 std::string
RISCVTargetInfo::convertConstraint(const char *&Constraint
) const {
115 switch (*Constraint
) {
117 R
= std::string("^") + std::string(Constraint
, 2);
121 R
= TargetInfo::convertConstraint(Constraint
);
127 static unsigned getVersionValue(unsigned MajorVersion
, unsigned MinorVersion
) {
128 return MajorVersion
* 1000000 + MinorVersion
* 1000;
131 void RISCVTargetInfo::getTargetDefines(const LangOptions
&Opts
,
132 MacroBuilder
&Builder
) const {
133 Builder
.defineMacro("__riscv");
134 bool Is64Bit
= getTriple().getArch() == llvm::Triple::riscv64
;
135 Builder
.defineMacro("__riscv_xlen", Is64Bit
? "64" : "32");
136 StringRef CodeModel
= getTargetOpts().CodeModel
;
137 unsigned FLen
= ISAInfo
->getFLen();
138 unsigned MinVLen
= ISAInfo
->getMinVLen();
139 unsigned MaxELen
= ISAInfo
->getMaxELen();
140 unsigned MaxELenFp
= ISAInfo
->getMaxELenFp();
141 if (CodeModel
== "default")
144 if (CodeModel
== "small")
145 Builder
.defineMacro("__riscv_cmodel_medlow");
146 else if (CodeModel
== "medium")
147 Builder
.defineMacro("__riscv_cmodel_medany");
149 StringRef ABIName
= getABI();
150 if (ABIName
== "ilp32f" || ABIName
== "lp64f")
151 Builder
.defineMacro("__riscv_float_abi_single");
152 else if (ABIName
== "ilp32d" || ABIName
== "lp64d")
153 Builder
.defineMacro("__riscv_float_abi_double");
155 Builder
.defineMacro("__riscv_float_abi_soft");
157 if (ABIName
== "ilp32e")
158 Builder
.defineMacro("__riscv_abi_rve");
160 Builder
.defineMacro("__riscv_arch_test");
162 for (auto &Extension
: ISAInfo
->getExtensions()) {
163 auto ExtName
= Extension
.first
;
164 auto ExtInfo
= Extension
.second
;
167 Twine("__riscv_", ExtName
),
168 Twine(getVersionValue(ExtInfo
.MajorVersion
, ExtInfo
.MinorVersion
)));
171 if (ISAInfo
->hasExtension("m") || ISAInfo
->hasExtension("zmmul"))
172 Builder
.defineMacro("__riscv_mul");
174 if (ISAInfo
->hasExtension("m")) {
175 Builder
.defineMacro("__riscv_div");
176 Builder
.defineMacro("__riscv_muldiv");
179 if (ISAInfo
->hasExtension("a")) {
180 Builder
.defineMacro("__riscv_atomic");
181 Builder
.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
182 Builder
.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
183 Builder
.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
185 Builder
.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
189 Builder
.defineMacro("__riscv_flen", Twine(FLen
));
190 Builder
.defineMacro("__riscv_fdiv");
191 Builder
.defineMacro("__riscv_fsqrt");
195 Builder
.defineMacro("__riscv_v_min_vlen", Twine(MinVLen
));
196 Builder
.defineMacro("__riscv_v_elen", Twine(MaxELen
));
197 Builder
.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp
));
200 if (ISAInfo
->hasExtension("c"))
201 Builder
.defineMacro("__riscv_compressed");
203 if (ISAInfo
->hasExtension("zve32x")) {
204 Builder
.defineMacro("__riscv_vector");
205 // Currently we support the v0.12 RISC-V V intrinsics.
206 Builder
.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12)));
209 auto VScale
= getVScaleRange(Opts
);
210 if (VScale
&& VScale
->first
&& VScale
->first
== VScale
->second
)
211 Builder
.defineMacro("__riscv_v_fixed_vlen",
212 Twine(VScale
->first
* llvm::RISCV::RVVBitsPerBlock
));
214 if (FastUnalignedAccess
)
215 Builder
.defineMacro("__riscv_misaligned_fast");
217 Builder
.defineMacro("__riscv_misaligned_avoid");
220 static constexpr Builtin::Info BuiltinInfo
[] = {
221 #define BUILTIN(ID, TYPE, ATTRS) \
222 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
223 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
224 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
225 #include "clang/Basic/BuiltinsRISCVVector.def"
226 #define BUILTIN(ID, TYPE, ATTRS) \
227 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
228 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
229 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
230 #include "clang/Basic/BuiltinsRISCV.def"
233 ArrayRef
<Builtin::Info
> RISCVTargetInfo::getTargetBuiltins() const {
234 return llvm::ArrayRef(BuiltinInfo
,
235 clang::RISCV::LastTSBuiltin
- Builtin::FirstTSBuiltin
);
238 bool RISCVTargetInfo::initFeatureMap(
239 llvm::StringMap
<bool> &Features
, DiagnosticsEngine
&Diags
, StringRef CPU
,
240 const std::vector
<std::string
> &FeaturesVec
) const {
244 if (getTriple().getArch() == llvm::Triple::riscv64
) {
245 Features
["64bit"] = true;
248 Features
["32bit"] = true;
251 auto ParseResult
= llvm::RISCVISAInfo::parseFeatures(XLen
, FeaturesVec
);
254 llvm::raw_string_ostream
OutputErrMsg(Buffer
);
255 handleAllErrors(ParseResult
.takeError(), [&](llvm::StringError
&ErrMsg
) {
256 OutputErrMsg
<< ErrMsg
.getMessage();
258 Diags
.Report(diag::err_invalid_feature_combination
) << OutputErrMsg
.str();
262 // RISCVISAInfo makes implications for ISA features
263 std::vector
<std::string
> ImpliedFeatures
= (*ParseResult
)->toFeatureVector();
264 // Add non-ISA features like `relax` and `save-restore` back
265 for (const std::string
&Feature
: FeaturesVec
)
266 if (!llvm::is_contained(ImpliedFeatures
, Feature
))
267 ImpliedFeatures
.push_back(Feature
);
269 return TargetInfo::initFeatureMap(Features
, Diags
, CPU
, ImpliedFeatures
);
272 std::optional
<std::pair
<unsigned, unsigned>>
273 RISCVTargetInfo::getVScaleRange(const LangOptions
&LangOpts
) const {
274 // RISCV::RVVBitsPerBlock is 64.
275 unsigned VScaleMin
= ISAInfo
->getMinVLen() / llvm::RISCV::RVVBitsPerBlock
;
277 if (LangOpts
.VScaleMin
|| LangOpts
.VScaleMax
) {
278 // Treat Zvl*b as a lower bound on vscale.
279 VScaleMin
= std::max(VScaleMin
, LangOpts
.VScaleMin
);
280 unsigned VScaleMax
= LangOpts
.VScaleMax
;
281 if (VScaleMax
!= 0 && VScaleMax
< VScaleMin
)
282 VScaleMax
= VScaleMin
;
283 return std::pair
<unsigned, unsigned>(VScaleMin
? VScaleMin
: 1, VScaleMax
);
287 unsigned VScaleMax
= ISAInfo
->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock
;
288 return std::make_pair(VScaleMin
, VScaleMax
);
294 /// Return true if has this feature, need to sync with handleTargetFeatures.
295 bool RISCVTargetInfo::hasFeature(StringRef Feature
) const {
296 bool Is64Bit
= getTriple().getArch() == llvm::Triple::riscv64
;
297 auto Result
= llvm::StringSwitch
<std::optional
<bool>>(Feature
)
299 .Case("riscv32", !Is64Bit
)
300 .Case("riscv64", Is64Bit
)
301 .Case("32bit", !Is64Bit
)
302 .Case("64bit", Is64Bit
)
303 .Default(std::nullopt
);
307 if (ISAInfo
->isSupportedExtensionFeature(Feature
))
308 return ISAInfo
->hasExtension(Feature
);
313 /// Perform initialization based on the user configured set of features.
314 bool RISCVTargetInfo::handleTargetFeatures(std::vector
<std::string
> &Features
,
315 DiagnosticsEngine
&Diags
) {
316 unsigned XLen
= getTriple().isArch64Bit() ? 64 : 32;
317 auto ParseResult
= llvm::RISCVISAInfo::parseFeatures(XLen
, Features
);
320 llvm::raw_string_ostream
OutputErrMsg(Buffer
);
321 handleAllErrors(ParseResult
.takeError(), [&](llvm::StringError
&ErrMsg
) {
322 OutputErrMsg
<< ErrMsg
.getMessage();
324 Diags
.Report(diag::err_invalid_feature_combination
) << OutputErrMsg
.str();
327 ISAInfo
= std::move(*ParseResult
);
331 ABI
= ISAInfo
->computeDefaultABI().str();
333 if (ISAInfo
->hasExtension("zfh") || ISAInfo
->hasExtension("zhinx"))
334 HasLegalHalfType
= true;
336 FastUnalignedAccess
= llvm::is_contained(Features
, "+unaligned-scalar-mem");
341 bool RISCVTargetInfo::isValidCPUName(StringRef Name
) const {
342 bool Is64Bit
= getTriple().isArch64Bit();
343 return llvm::RISCV::parseCPU(Name
, Is64Bit
);
346 void RISCVTargetInfo::fillValidCPUList(
347 SmallVectorImpl
<StringRef
> &Values
) const {
348 bool Is64Bit
= getTriple().isArch64Bit();
349 llvm::RISCV::fillValidCPUArchList(Values
, Is64Bit
);
352 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name
) const {
353 bool Is64Bit
= getTriple().isArch64Bit();
354 return llvm::RISCV::parseTuneCPU(Name
, Is64Bit
);
357 void RISCVTargetInfo::fillValidTuneCPUList(
358 SmallVectorImpl
<StringRef
> &Values
) const {
359 bool Is64Bit
= getTriple().isArch64Bit();
360 llvm::RISCV::fillValidTuneCPUArchList(Values
, Is64Bit
);