clang 17.0.0git
RISCV.cpp
Go to the documentation of this file.
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.
10//
11//===----------------------------------------------------------------------===//
12
13#include "RISCV.h"
17#include "llvm/ADT/StringSwitch.h"
18#include "llvm/Support/raw_ostream.h"
19#include "llvm/TargetParser/RISCVTargetParser.h"
20#include <optional>
21
22using namespace clang;
23using namespace clang::targets;
24
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"};
45}
46
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
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.
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
107std::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
121static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
122 return MajorVersion * 1000000 + MinorVersion * 1000;
123}
124
126 MacroBuilder &Builder) const {
127 Builder.defineMacro("__riscv");
128 bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
129 Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
130 StringRef CodeModel = getTargetOpts().CodeModel;
131 unsigned FLen = ISAInfo->getFLen();
132 unsigned MinVLen = ISAInfo->getMinVLen();
133 unsigned MaxELen = ISAInfo->getMaxELen();
134 unsigned MaxELenFp = ISAInfo->getMaxELenFp();
135 if (CodeModel == "default")
136 CodeModel = "small";
137
138 if (CodeModel == "small")
139 Builder.defineMacro("__riscv_cmodel_medlow");
140 else if (CodeModel == "medium")
141 Builder.defineMacro("__riscv_cmodel_medany");
142
143 StringRef ABIName = getABI();
144 if (ABIName == "ilp32f" || ABIName == "lp64f")
145 Builder.defineMacro("__riscv_float_abi_single");
146 else if (ABIName == "ilp32d" || ABIName == "lp64d")
147 Builder.defineMacro("__riscv_float_abi_double");
148 else
149 Builder.defineMacro("__riscv_float_abi_soft");
150
151 if (ABIName == "ilp32e")
152 Builder.defineMacro("__riscv_abi_rve");
153
154 Builder.defineMacro("__riscv_arch_test");
155
156 for (auto &Extension : ISAInfo->getExtensions()) {
157 auto ExtName = Extension.first;
158 auto ExtInfo = Extension.second;
159
160 Builder.defineMacro(
161 Twine("__riscv_", ExtName),
162 Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion)));
163 }
164
165 if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul"))
166 Builder.defineMacro("__riscv_mul");
167
168 if (ISAInfo->hasExtension("m")) {
169 Builder.defineMacro("__riscv_div");
170 Builder.defineMacro("__riscv_muldiv");
171 }
172
173 if (ISAInfo->hasExtension("a")) {
174 Builder.defineMacro("__riscv_atomic");
175 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
176 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
177 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
178 if (Is64Bit)
179 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
180 }
181
182 if (FLen) {
183 Builder.defineMacro("__riscv_flen", Twine(FLen));
184 Builder.defineMacro("__riscv_fdiv");
185 Builder.defineMacro("__riscv_fsqrt");
186 }
187
188 if (MinVLen) {
189 Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
190 Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
191 Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
192 }
193
194 if (ISAInfo->hasExtension("c"))
195 Builder.defineMacro("__riscv_compressed");
196
197 if (ISAInfo->hasExtension("zve32x")) {
198 Builder.defineMacro("__riscv_vector");
199 // Currently we support the v0.11 RISC-V V intrinsics.
200 Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 11)));
201 }
202
203 auto VScale = getVScaleRange(Opts);
204 if (VScale && VScale->first && VScale->first == VScale->second)
205 Builder.defineMacro("__riscv_v_fixed_vlen",
206 Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
207}
208
209static constexpr Builtin::Info BuiltinInfo[] = {
210#define BUILTIN(ID, TYPE, ATTRS) \
211 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
212#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
213 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
214#include "clang/Basic/BuiltinsRISCVVector.def"
215#define BUILTIN(ID, TYPE, ATTRS) \
216 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
217#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
218 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
219#include "clang/Basic/BuiltinsRISCV.def"
220};
221
225}
226
228 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
229 const std::vector<std::string> &FeaturesVec) const {
230
231 unsigned XLen = 32;
232
233 if (getTriple().getArch() == llvm::Triple::riscv64) {
234 Features["64bit"] = true;
235 XLen = 64;
236 } else {
237 Features["32bit"] = true;
238 }
239
240 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
241 if (!ParseResult) {
242 std::string Buffer;
243 llvm::raw_string_ostream OutputErrMsg(Buffer);
244 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
245 OutputErrMsg << ErrMsg.getMessage();
246 });
247 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
248 return false;
249 }
250
251 // RISCVISAInfo makes implications for ISA features
252 std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();
253 // Add non-ISA features like `relax` and `save-restore` back
254 for (const std::string &Feature : FeaturesVec)
255 if (!llvm::is_contained(ImpliedFeatures, Feature))
256 ImpliedFeatures.push_back(Feature);
257
258 return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures);
259}
260
261std::optional<std::pair<unsigned, unsigned>>
263 // RISCV::RVVBitsPerBlock is 64.
264 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
265
266 if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
267 // Treat Zvl*b as a lower bound on vscale.
268 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
269 unsigned VScaleMax = LangOpts.VScaleMax;
270 if (VScaleMax != 0 && VScaleMax < VScaleMin)
271 VScaleMax = VScaleMin;
272 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
273 }
274
275 if (VScaleMin > 0) {
276 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
277 return std::make_pair(VScaleMin, VScaleMax);
278 }
279
280 return std::nullopt;
281}
282
283/// Return true if has this feature, need to sync with handleTargetFeatures.
284bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
285 bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
286 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
287 .Case("riscv", true)
288 .Case("riscv32", !Is64Bit)
289 .Case("riscv64", Is64Bit)
290 .Case("32bit", !Is64Bit)
291 .Case("64bit", Is64Bit)
292 .Default(std::nullopt);
293 if (Result)
294 return *Result;
295
296 if (ISAInfo->isSupportedExtensionFeature(Feature))
297 return ISAInfo->hasExtension(Feature);
298
299 return false;
300}
301
302/// Perform initialization based on the user configured set of features.
303bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
304 DiagnosticsEngine &Diags) {
305 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
306 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
307 if (!ParseResult) {
308 std::string Buffer;
309 llvm::raw_string_ostream OutputErrMsg(Buffer);
310 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
311 OutputErrMsg << ErrMsg.getMessage();
312 });
313 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
314 return false;
315 } else {
316 ISAInfo = std::move(*ParseResult);
317 }
318
319 if (ABI.empty())
320 ABI = ISAInfo->computeDefaultABI().str();
321
322 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
323 HasLegalHalfType = true;
324
325 return true;
326}
327
328bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
329 bool Is64Bit = getTriple().isArch64Bit();
330 return llvm::RISCV::parseCPU(Name, Is64Bit);
331}
332
334 SmallVectorImpl<StringRef> &Values) const {
335 bool Is64Bit = getTriple().isArch64Bit();
336 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
337}
338
339bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
340 bool Is64Bit = getTriple().isArch64Bit();
341 return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
342}
343
345 SmallVectorImpl<StringRef> &Values) const {
346 bool Is64Bit = getTriple().isArch64Bit();
347 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
348}
Defines the Diagnostic-related interfaces.
static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion)
Definition: RISCV.cpp:121
static constexpr Builtin::Info BuiltinInfo[]
Definition: Builtins.cpp:32
Defines the clang::MacroBuilder utility class.
Enumerates target-specific builtins in their own namespaces within namespace clang.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1542
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:82
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition: TargetInfo.h:283
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1197
virtual bool initFeatureMap(llvm::StringMap< bool > &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector< std::string > &FeatureVec) const
Initialize the map with the default set of target features for the CPU this should include all legal ...
Definition: TargetInfo.cpp:521
virtual std::string convertConstraint(const char *&Constraint) const
Definition: TargetInfo.h:1174
std::string CodeModel
Definition: TargetOptions.h:97
std::string convertConstraint(const char *&Constraint) const override
Definition: RISCV.cpp:107
void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override
===-— Other target property query methods -----------------------—===//
Definition: RISCV.cpp:125
ArrayRef< Builtin::Info > getTargetBuiltins() const override
Return information about target-specific builtins for the current primary target, and info about whic...
Definition: RISCV.cpp:222
bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override
Definition: RISCV.cpp:68
bool initFeatureMap(llvm::StringMap< bool > &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector< std::string > &FeaturesVec) const override
Initialize the map with the default set of target features for the CPU this should include all legal ...
Definition: RISCV.cpp:227
std::unique_ptr< llvm::RISCVISAInfo > ISAInfo
Definition: RISCV.h:30
void fillValidTuneCPUList(SmallVectorImpl< StringRef > &Values) const override
Fill a SmallVectorImpl with the valid values for tuning CPU.
Definition: RISCV.cpp:344
bool isValidTuneCPUName(StringRef Name) const override
brief Determine whether this TargetInfo supports the given CPU name for
Definition: RISCV.cpp:339
std::optional< std::pair< unsigned, unsigned > > getVScaleRange(const LangOptions &LangOpts) const override
Returns target-specific min and max values VScale_Range.
Definition: RISCV.cpp:262
ArrayRef< const char * > getGCCRegNames() const override
Definition: RISCV.cpp:25
ArrayRef< TargetInfo::GCCRegAlias > getGCCRegAliases() const override
Definition: RISCV.cpp:47
void fillValidCPUList(SmallVectorImpl< StringRef > &Values) const override
Fill a SmallVectorImpl with the valid values to setCPU.
Definition: RISCV.cpp:333
StringRef getABI() const override
Get the ABI currently in use.
Definition: RISCV.h:54
bool handleTargetFeatures(std::vector< std::string > &Features, DiagnosticsEngine &Diags) override
Perform initialization based on the user configured set of features.
Definition: RISCV.cpp:303
bool hasFeature(StringRef Feature) const override
Return true if has this feature, need to sync with handleTargetFeatures.
Definition: RISCV.cpp:284
bool isValidCPUName(StringRef Name) const override
brief Determine whether this TargetInfo supports the given CPU name.
Definition: RISCV.cpp:328
static const char *const GCCRegNames[]
Definition: X86.cpp:44
@ Result
The result type of a method or function.
void setRequiresImmediate(int Min, int Max)
Definition: TargetInfo.h:1094