[clang-format] Fix a bug in aligning comments above PPDirective (#72791)
[llvm-project.git] / clang / lib / Basic / Targets / RISCV.cpp
blob0b9ebeaf5e75bbd1bbc7cc3600669dd884c738a6
1 //===--- RISCV.cpp - Implement RISC-V 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 RISC-V TargetInfo objects.
11 //===----------------------------------------------------------------------===//
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>
22 using namespace clang;
23 using namespace clang::targets;
25 ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
26 // clang-format off
27 static const char *const GCCRegNames[] = {
28 // Integer registers
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",
40 // Vector registers
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",
46 // CSRs
47 "fflags", "frm", "vtype", "vl", "vxsat", "vxrm"
49 // clang-format on
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 {
76 switch (*Name) {
77 default:
78 return false;
79 case 'I':
80 // A 12-bit signed immediate.
81 Info.setRequiresImmediate(-2048, 2047);
82 return true;
83 case 'J':
84 // Integer zero.
85 Info.setRequiresImmediate(0);
86 return true;
87 case 'K':
88 // A 5-bit unsigned immediate for CSR access instructions.
89 Info.setRequiresImmediate(0, 31);
90 return true;
91 case 'f':
92 // A floating-point register.
93 Info.setAllowsRegister();
94 return true;
95 case 'A':
96 // An address that is held in a general-purpose register.
97 Info.setAllowsMemory();
98 return true;
99 case 'S': // A symbolic address
100 Info.setAllowsRegister();
101 return true;
102 case 'v':
103 // A vector register.
104 if (Name[1] == 'r' || Name[1] == 'm') {
105 Info.setAllowsRegister();
106 Name += 1;
107 return true;
109 return false;
113 std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
114 std::string R;
115 switch (*Constraint) {
116 case 'v':
117 R = std::string("^") + std::string(Constraint, 2);
118 Constraint += 1;
119 break;
120 default:
121 R = TargetInfo::convertConstraint(Constraint);
122 break;
124 return R;
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")
142 CodeModel = "small";
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");
154 else
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;
166 Builder.defineMacro(
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");
184 if (Is64Bit)
185 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
188 if (FLen) {
189 Builder.defineMacro("__riscv_flen", Twine(FLen));
190 Builder.defineMacro("__riscv_fdiv");
191 Builder.defineMacro("__riscv_fsqrt");
194 if (MinVLen) {
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");
216 else
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 {
242 unsigned XLen = 32;
244 if (getTriple().getArch() == llvm::Triple::riscv64) {
245 Features["64bit"] = true;
246 XLen = 64;
247 } else {
248 Features["32bit"] = true;
251 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
252 if (!ParseResult) {
253 std::string Buffer;
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();
259 return false;
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);
286 if (VScaleMin > 0) {
287 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
288 return std::make_pair(VScaleMin, VScaleMax);
291 return std::nullopt;
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)
298 .Case("riscv", true)
299 .Case("riscv32", !Is64Bit)
300 .Case("riscv64", Is64Bit)
301 .Case("32bit", !Is64Bit)
302 .Case("64bit", Is64Bit)
303 .Default(std::nullopt);
304 if (Result)
305 return *Result;
307 if (ISAInfo->isSupportedExtensionFeature(Feature))
308 return ISAInfo->hasExtension(Feature);
310 return false;
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);
318 if (!ParseResult) {
319 std::string Buffer;
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();
325 return false;
326 } else {
327 ISAInfo = std::move(*ParseResult);
330 if (ABI.empty())
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");
338 return true;
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);