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" |
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 | |
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", |
33 | |
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", |
39 | |
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", |
45 | |
46 | // CSRs |
47 | "fflags", "frm", "vtype", "vl", "vxsat", "vxrm", "sf.vcix_state" |
48 | }; |
49 | // clang-format on |
50 | return llvm::ArrayRef(GCCRegNames); |
51 | } |
52 | |
53 | ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const { |
54 | static const TargetInfo::GCCRegAlias GCCRegAliases[] = { |
55 | {.Aliases: {"zero"}, .Register: "x0"}, {.Aliases: { "ra"}, .Register: "x1"}, {.Aliases: { "sp"}, .Register: "x2"}, {.Aliases: { "gp"}, .Register: "x3"}, |
56 | {.Aliases: {"tp"}, .Register: "x4"}, {.Aliases: { "t0"}, .Register: "x5"}, {.Aliases: { "t1"}, .Register: "x6"}, {.Aliases: { "t2"}, .Register: "x7"}, |
57 | {.Aliases: {"s0"}, .Register: "x8"}, {.Aliases: { "s1"}, .Register: "x9"}, {.Aliases: { "a0"}, .Register: "x10"}, {.Aliases: { "a1"}, .Register: "x11"}, |
58 | {.Aliases: {"a2"}, .Register: "x12"}, {.Aliases: { "a3"}, .Register: "x13"}, {.Aliases: { "a4"}, .Register: "x14"}, {.Aliases: { "a5"}, .Register: "x15"}, |
59 | {.Aliases: {"a6"}, .Register: "x16"}, {.Aliases: { "a7"}, .Register: "x17"}, {.Aliases: { "s2"}, .Register: "x18"}, {.Aliases: { "s3"}, .Register: "x19"}, |
60 | {.Aliases: {"s4"}, .Register: "x20"}, {.Aliases: { "s5"}, .Register: "x21"}, {.Aliases: { "s6"}, .Register: "x22"}, {.Aliases: { "s7"}, .Register: "x23"}, |
61 | {.Aliases: {"s8"}, .Register: "x24"}, {.Aliases: { "s9"}, .Register: "x25"}, {.Aliases: { "s10"}, .Register: "x26"}, {.Aliases: { "s11"}, .Register: "x27"}, |
62 | {.Aliases: {"t3"}, .Register: "x28"}, {.Aliases: { "t4"}, .Register: "x29"}, {.Aliases: { "t5"}, .Register: "x30"}, {.Aliases: { "t6"}, .Register: "x31"}, |
63 | {.Aliases: {"ft0"}, .Register: "f0"}, {.Aliases: { "ft1"}, .Register: "f1"}, {.Aliases: { "ft2"}, .Register: "f2"}, {.Aliases: { "ft3"}, .Register: "f3"}, |
64 | {.Aliases: {"ft4"}, .Register: "f4"}, {.Aliases: { "ft5"}, .Register: "f5"}, {.Aliases: { "ft6"}, .Register: "f6"}, {.Aliases: { "ft7"}, .Register: "f7"}, |
65 | {.Aliases: {"fs0"}, .Register: "f8"}, {.Aliases: { "fs1"}, .Register: "f9"}, {.Aliases: { "fa0"}, .Register: "f10"}, {.Aliases: { "fa1"}, .Register: "f11"}, |
66 | {.Aliases: {"fa2"}, .Register: "f12"}, {.Aliases: { "fa3"}, .Register: "f13"}, {.Aliases: { "fa4"}, .Register: "f14"}, {.Aliases: { "fa5"}, .Register: "f15"}, |
67 | {.Aliases: {"fa6"}, .Register: "f16"}, {.Aliases: { "fa7"}, .Register: "f17"}, {.Aliases: { "fs2"}, .Register: "f18"}, {.Aliases: { "fs3"}, .Register: "f19"}, |
68 | {.Aliases: {"fs4"}, .Register: "f20"}, {.Aliases: { "fs5"}, .Register: "f21"}, {.Aliases: { "fs6"}, .Register: "f22"}, {.Aliases: { "fs7"}, .Register: "f23"}, |
69 | {.Aliases: {"fs8"}, .Register: "f24"}, {.Aliases: { "fs9"}, .Register: "f25"}, {.Aliases: { "fs10"}, .Register: "f26"}, {.Aliases: { "fs11"}, .Register: "f27"}, |
70 | {.Aliases: {"ft8"}, .Register: "f28"}, {.Aliases: { "ft9"}, .Register: "f29"}, {.Aliases: { "ft10"}, .Register: "f30"}, {.Aliases: { "ft11"}, .Register: "f31"}}; |
71 | return llvm::ArrayRef(GCCRegAliases); |
72 | } |
73 | |
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(Min: -2048, Max: 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(Min: 0, Max: 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': |
100 | case 'S': // A symbol or label reference with a constant offset |
101 | Info.setAllowsRegister(); |
102 | return true; |
103 | case 'c': |
104 | // A RVC register - GPR or FPR |
105 | if (Name[1] == 'r' || Name[1] == 'R' || Name[1] == 'f') { |
106 | Info.setAllowsRegister(); |
107 | Name += 1; |
108 | return true; |
109 | } |
110 | return false; |
111 | case 'R': |
112 | // An even-odd GPR pair |
113 | Info.setAllowsRegister(); |
114 | return true; |
115 | case 'v': |
116 | // A vector register. |
117 | if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') { |
118 | Info.setAllowsRegister(); |
119 | Name += 1; |
120 | return true; |
121 | } |
122 | return false; |
123 | } |
124 | } |
125 | |
126 | std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const { |
127 | std::string R; |
128 | switch (*Constraint) { |
129 | // c* and v* are two-letter constraints on RISC-V. |
130 | case 'c': |
131 | case 'v': |
132 | R = std::string("^") + std::string(Constraint, 2); |
133 | Constraint += 1; |
134 | break; |
135 | default: |
136 | R = TargetInfo::convertConstraint(Constraint); |
137 | break; |
138 | } |
139 | return R; |
140 | } |
141 | |
142 | static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) { |
143 | return MajorVersion * 1000000 + MinorVersion * 1000; |
144 | } |
145 | |
146 | void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, |
147 | MacroBuilder &Builder) const { |
148 | Builder.defineMacro(Name: "__riscv"); |
149 | bool Is64Bit = getTriple().isRISCV64(); |
150 | Builder.defineMacro(Name: "__riscv_xlen", Value: Is64Bit ? "64": "32"); |
151 | StringRef CodeModel = getTargetOpts().CodeModel; |
152 | unsigned FLen = ISAInfo->getFLen(); |
153 | unsigned MinVLen = ISAInfo->getMinVLen(); |
154 | unsigned MaxELen = ISAInfo->getMaxELen(); |
155 | unsigned MaxELenFp = ISAInfo->getMaxELenFp(); |
156 | if (CodeModel == "default") |
157 | CodeModel = "small"; |
158 | |
159 | if (CodeModel == "small") |
160 | Builder.defineMacro(Name: "__riscv_cmodel_medlow"); |
161 | else if (CodeModel == "medium") |
162 | Builder.defineMacro(Name: "__riscv_cmodel_medany"); |
163 | else if (CodeModel == "large") |
164 | Builder.defineMacro(Name: "__riscv_cmodel_large"); |
165 | |
166 | StringRef ABIName = getABI(); |
167 | if (ABIName == "ilp32f"|| ABIName == "lp64f") |
168 | Builder.defineMacro(Name: "__riscv_float_abi_single"); |
169 | else if (ABIName == "ilp32d"|| ABIName == "lp64d") |
170 | Builder.defineMacro(Name: "__riscv_float_abi_double"); |
171 | else |
172 | Builder.defineMacro(Name: "__riscv_float_abi_soft"); |
173 | |
174 | if (ABIName == "ilp32e"|| ABIName == "lp64e") |
175 | Builder.defineMacro(Name: "__riscv_abi_rve"); |
176 | |
177 | Builder.defineMacro(Name: "__riscv_arch_test"); |
178 | |
179 | for (auto &Extension : ISAInfo->getExtensions()) { |
180 | auto ExtName = Extension.first; |
181 | auto ExtInfo = Extension.second; |
182 | |
183 | Builder.defineMacro(Name: Twine("__riscv_", ExtName), |
184 | Value: Twine(getVersionValue(MajorVersion: ExtInfo.Major, MinorVersion: ExtInfo.Minor))); |
185 | } |
186 | |
187 | if (ISAInfo->hasExtension(Ext: "zmmul")) |
188 | Builder.defineMacro(Name: "__riscv_mul"); |
189 | |
190 | if (ISAInfo->hasExtension(Ext: "m")) { |
191 | Builder.defineMacro(Name: "__riscv_div"); |
192 | Builder.defineMacro(Name: "__riscv_muldiv"); |
193 | } |
194 | |
195 | if (ISAInfo->hasExtension(Ext: "a")) { |
196 | Builder.defineMacro(Name: "__riscv_atomic"); |
197 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); |
198 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); |
199 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); |
200 | if (Is64Bit) |
201 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); |
202 | } |
203 | |
204 | if (FLen) { |
205 | Builder.defineMacro(Name: "__riscv_flen", Value: Twine(FLen)); |
206 | Builder.defineMacro(Name: "__riscv_fdiv"); |
207 | Builder.defineMacro(Name: "__riscv_fsqrt"); |
208 | } |
209 | |
210 | if (MinVLen) { |
211 | Builder.defineMacro(Name: "__riscv_v_min_vlen", Value: Twine(MinVLen)); |
212 | Builder.defineMacro(Name: "__riscv_v_elen", Value: Twine(MaxELen)); |
213 | Builder.defineMacro(Name: "__riscv_v_elen_fp", Value: Twine(MaxELenFp)); |
214 | } |
215 | |
216 | if (ISAInfo->hasExtension(Ext: "c")) |
217 | Builder.defineMacro(Name: "__riscv_compressed"); |
218 | |
219 | if (ISAInfo->hasExtension(Ext: "zve32x")) |
220 | Builder.defineMacro(Name: "__riscv_vector"); |
221 | |
222 | // Currently we support the v1.0 RISC-V V intrinsics. |
223 | Builder.defineMacro(Name: "__riscv_v_intrinsic", Value: Twine(getVersionValue(MajorVersion: 1, MinorVersion: 0))); |
224 | |
225 | auto VScale = getVScaleRange(LangOpts: Opts, IsArmStreamingFunction: false); |
226 | if (VScale && VScale->first && VScale->first == VScale->second) |
227 | Builder.defineMacro(Name: "__riscv_v_fixed_vlen", |
228 | Value: Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock)); |
229 | |
230 | if (FastScalarUnalignedAccess) |
231 | Builder.defineMacro(Name: "__riscv_misaligned_fast"); |
232 | else |
233 | Builder.defineMacro(Name: "__riscv_misaligned_avoid"); |
234 | |
235 | if (ISAInfo->hasExtension(Ext: "e")) { |
236 | if (Is64Bit) |
237 | Builder.defineMacro(Name: "__riscv_64e"); |
238 | else |
239 | Builder.defineMacro(Name: "__riscv_32e"); |
240 | } |
241 | |
242 | if (Opts.CFProtectionReturn && ISAInfo->hasExtension(Ext: "zicfiss")) |
243 | Builder.defineMacro(Name: "__riscv_shadow_stack"); |
244 | |
245 | if (Opts.CFProtectionBranch) { |
246 | auto Scheme = Opts.getCFBranchLabelScheme(); |
247 | if (Scheme == CFBranchLabelSchemeKind::Default) |
248 | Scheme = getDefaultCFBranchLabelScheme(); |
249 | |
250 | Builder.defineMacro(Name: "__riscv_landing_pad"); |
251 | switch (Scheme) { |
252 | case CFBranchLabelSchemeKind::Unlabeled: |
253 | Builder.defineMacro(Name: "__riscv_landing_pad_unlabeled"); |
254 | break; |
255 | case CFBranchLabelSchemeKind::FuncSig: |
256 | // TODO: Define macros after the func-sig scheme is implemented |
257 | break; |
258 | case CFBranchLabelSchemeKind::Default: |
259 | llvm_unreachable("default cf-branch-label scheme should already be " |
260 | "transformed to other scheme"); |
261 | } |
262 | } |
263 | } |
264 | |
265 | static constexpr int NumRVVBuiltins = |
266 | RISCVVector::FirstSiFiveBuiltin - Builtin::FirstTSBuiltin; |
267 | static constexpr int NumRVVSiFiveBuiltins = |
268 | RISCVVector::FirstAndesBuiltin - RISCVVector::FirstSiFiveBuiltin; |
269 | static constexpr int NumRVVAndesBuiltins = |
270 | RISCVVector::FirstTSBuiltin - RISCVVector::FirstAndesBuiltin; |
271 | static constexpr int NumRISCVBuiltins = |
272 | RISCV::LastTSBuiltin - RISCVVector::FirstTSBuiltin; |
273 | static constexpr int NumBuiltins = |
274 | RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin; |
275 | static_assert(NumBuiltins == (NumRVVBuiltins + NumRVVSiFiveBuiltins + |
276 | NumRVVAndesBuiltins + NumRISCVBuiltins)); |
277 | |
278 | namespace RVV { |
279 | #define GET_RISCVV_BUILTIN_STR_TABLE |
280 | #include "clang/Basic/riscv_vector_builtins.inc" |
281 | #undef GET_RISCVV_BUILTIN_STR_TABLE |
282 | static_assert(BuiltinStrings.size() < 100'000); |
283 | |
284 | static constexpr std::array<Builtin::Info, NumRVVBuiltins> BuiltinInfos = { |
285 | #define GET_RISCVV_BUILTIN_INFOS |
286 | #include "clang/Basic/riscv_vector_builtins.inc" |
287 | #undef GET_RISCVV_BUILTIN_INFOS |
288 | }; |
289 | } // namespace RVV |
290 | |
291 | namespace RVVSiFive { |
292 | #define GET_RISCVV_BUILTIN_STR_TABLE |
293 | #include "clang/Basic/riscv_sifive_vector_builtins.inc" |
294 | #undef GET_RISCVV_BUILTIN_STR_TABLE |
295 | |
296 | static constexpr std::array<Builtin::Info, NumRVVSiFiveBuiltins> BuiltinInfos = |
297 | { |
298 | #define GET_RISCVV_BUILTIN_INFOS |
299 | #include "clang/Basic/riscv_sifive_vector_builtins.inc" |
300 | #undef GET_RISCVV_BUILTIN_INFOS |
301 | }; |
302 | } // namespace RVVSiFive |
303 | |
304 | namespace RVVAndes { |
305 | #define GET_RISCVV_BUILTIN_STR_TABLE |
306 | #include "clang/Basic/riscv_andes_vector_builtins.inc" |
307 | #undef GET_RISCVV_BUILTIN_STR_TABLE |
308 | |
309 | static constexpr std::array<Builtin::Info, NumRVVAndesBuiltins> BuiltinInfos = |
310 | { |
311 | #define GET_RISCVV_BUILTIN_INFOS |
312 | #include "clang/Basic/riscv_andes_vector_builtins.inc" |
313 | #undef GET_RISCVV_BUILTIN_INFOS |
314 | }; |
315 | } // namespace RVVAndes |
316 | |
317 | #define GET_BUILTIN_STR_TABLE |
318 | #include "clang/Basic/BuiltinsRISCV.inc" |
319 | #undef GET_BUILTIN_STR_TABLE |
320 | |
321 | static constexpr Builtin::Info BuiltinInfos[] = { |
322 | #define GET_BUILTIN_INFOS |
323 | #include "clang/Basic/BuiltinsRISCV.inc" |
324 | #undef GET_BUILTIN_INFOS |
325 | }; |
326 | static_assert(std::size(BuiltinInfos) == NumRISCVBuiltins); |
327 | |
328 | llvm::SmallVector<Builtin::InfosShard> |
329 | RISCVTargetInfo::getTargetBuiltins() const { |
330 | return { |
331 | {&RVV::BuiltinStrings, RVV::BuiltinInfos, "__builtin_rvv_"}, |
332 | {&RVVSiFive::BuiltinStrings, RVVSiFive::BuiltinInfos, "__builtin_rvv_"}, |
333 | {&RVVAndes::BuiltinStrings, RVVAndes::BuiltinInfos, "__builtin_rvv_"}, |
334 | {&BuiltinStrings, BuiltinInfos}, |
335 | }; |
336 | } |
337 | |
338 | bool RISCVTargetInfo::initFeatureMap( |
339 | llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, |
340 | const std::vector<std::string> &FeaturesVec) const { |
341 | |
342 | unsigned XLen = 32; |
343 | |
344 | if (getTriple().isRISCV64()) { |
345 | Features["64bit"] = true; |
346 | XLen = 64; |
347 | } else { |
348 | Features["32bit"] = true; |
349 | } |
350 | |
351 | std::vector<std::string> AllFeatures = FeaturesVec; |
352 | auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features: FeaturesVec); |
353 | if (!ParseResult) { |
354 | std::string Buffer; |
355 | llvm::raw_string_ostream OutputErrMsg(Buffer); |
356 | handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) { |
357 | OutputErrMsg << ErrMsg.getMessage(); |
358 | }); |
359 | Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); |
360 | return false; |
361 | } |
362 | |
363 | // Append all features, not just new ones, so we override any negatives. |
364 | llvm::append_range(C&: AllFeatures, R: (*ParseResult)->toFeatures()); |
365 | return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: AllFeatures); |
366 | } |
367 | |
368 | std::optional<std::pair<unsigned, unsigned>> |
369 | RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts, |
370 | bool IsArmStreamingFunction, |
371 | llvm::StringMap<bool> *FeatureMap) const { |
372 | // RISCV::RVVBitsPerBlock is 64. |
373 | unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; |
374 | |
375 | if (LangOpts.VScaleMin || LangOpts.VScaleMax) { |
376 | // Treat Zvl*b as a lower bound on vscale. |
377 | VScaleMin = std::max(a: VScaleMin, b: LangOpts.VScaleMin); |
378 | unsigned VScaleMax = LangOpts.VScaleMax; |
379 | if (VScaleMax != 0 && VScaleMax < VScaleMin) |
380 | VScaleMax = VScaleMin; |
381 | return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax); |
382 | } |
383 | |
384 | if (VScaleMin > 0) { |
385 | unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; |
386 | return std::make_pair(x&: VScaleMin, y&: VScaleMax); |
387 | } |
388 | |
389 | return std::nullopt; |
390 | } |
391 | |
392 | /// Return true if has this feature, need to sync with handleTargetFeatures. |
393 | bool RISCVTargetInfo::hasFeature(StringRef Feature) const { |
394 | bool Is64Bit = getTriple().isRISCV64(); |
395 | auto Result = llvm::StringSwitch<std::optional<bool>>(Feature) |
396 | .Case(S: "riscv", Value: true) |
397 | .Case(S: "riscv32", Value: !Is64Bit) |
398 | .Case(S: "riscv64", Value: Is64Bit) |
399 | .Case(S: "32bit", Value: !Is64Bit) |
400 | .Case(S: "64bit", Value: Is64Bit) |
401 | .Case(S: "experimental", Value: HasExperimental) |
402 | .Default(Value: std::nullopt); |
403 | if (Result) |
404 | return *Result; |
405 | |
406 | return ISAInfo->hasExtension(Ext: Feature); |
407 | } |
408 | |
409 | /// Perform initialization based on the user configured set of features. |
410 | bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, |
411 | DiagnosticsEngine &Diags) { |
412 | unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; |
413 | auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); |
414 | if (!ParseResult) { |
415 | std::string Buffer; |
416 | llvm::raw_string_ostream OutputErrMsg(Buffer); |
417 | handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) { |
418 | OutputErrMsg << ErrMsg.getMessage(); |
419 | }); |
420 | Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); |
421 | return false; |
422 | } else { |
423 | ISAInfo = std::move(*ParseResult); |
424 | } |
425 | |
426 | if (ABI.empty()) |
427 | ABI = ISAInfo->computeDefaultABI().str(); |
428 | |
429 | if (ISAInfo->hasExtension(Ext: "zfh") || ISAInfo->hasExtension(Ext: "zhinx")) |
430 | HasLegalHalfType = true; |
431 | |
432 | FastScalarUnalignedAccess = |
433 | llvm::is_contained(Range&: Features, Element: "+unaligned-scalar-mem"); |
434 | |
435 | if (llvm::is_contained(Range&: Features, Element: "+experimental")) |
436 | HasExperimental = true; |
437 | |
438 | if (ABI == "ilp32e"&& ISAInfo->hasExtension(Ext: "d")) { |
439 | Diags.Report(diag::err_invalid_feature_combination) |
440 | << "ILP32E cannot be used with the D ISA extension"; |
441 | return false; |
442 | } |
443 | return true; |
444 | } |
445 | |
446 | bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { |
447 | bool Is64Bit = getTriple().isArch64Bit(); |
448 | return llvm::RISCV::parseCPU(CPU: Name, IsRV64: Is64Bit); |
449 | } |
450 | |
451 | void RISCVTargetInfo::fillValidCPUList( |
452 | SmallVectorImpl<StringRef> &Values) const { |
453 | bool Is64Bit = getTriple().isArch64Bit(); |
454 | llvm::RISCV::fillValidCPUArchList(Values, IsRV64: Is64Bit); |
455 | } |
456 | |
457 | bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const { |
458 | bool Is64Bit = getTriple().isArch64Bit(); |
459 | return llvm::RISCV::parseTuneCPU(CPU: Name, IsRV64: Is64Bit); |
460 | } |
461 | |
462 | void RISCVTargetInfo::fillValidTuneCPUList( |
463 | SmallVectorImpl<StringRef> &Values) const { |
464 | bool Is64Bit = getTriple().isArch64Bit(); |
465 | llvm::RISCV::fillValidTuneCPUArchList(Values, IsRV64: Is64Bit); |
466 | } |
467 | |
468 | static void populateNegativeRISCVFeatures(std::vector<std::string> &Features) { |
469 | auto RII = llvm::RISCVISAInfo::parseArchString( |
470 | Arch: "rv64i", /* EnableExperimentalExtension */ true); |
471 | |
472 | if (llvm::errorToBool(Err: RII.takeError())) |
473 | llvm_unreachable("unsupport rv64i"); |
474 | |
475 | std::vector<std::string> FeatStrings = |
476 | (*RII)->toFeatures(/* AddAllExtensions */ true); |
477 | llvm::append_range(C&: Features, R&: FeatStrings); |
478 | } |
479 | |
480 | static void handleFullArchString(StringRef FullArchStr, |
481 | std::vector<std::string> &Features) { |
482 | auto RII = llvm::RISCVISAInfo::parseArchString( |
483 | Arch: FullArchStr, /* EnableExperimentalExtension */ true); |
484 | if (llvm::errorToBool(Err: RII.takeError())) { |
485 | // Forward the invalid FullArchStr. |
486 | Features.push_back(x: FullArchStr.str()); |
487 | } else { |
488 | // Append a full list of features, including any negative extensions so that |
489 | // we override the CPU's features. |
490 | populateNegativeRISCVFeatures(Features); |
491 | std::vector<std::string> FeatStrings = |
492 | (*RII)->toFeatures(/* AddAllExtensions */ true); |
493 | llvm::append_range(C&: Features, R&: FeatStrings); |
494 | } |
495 | } |
496 | |
497 | ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { |
498 | ParsedTargetAttr Ret; |
499 | if (Features == "default") |
500 | return Ret; |
501 | SmallVector<StringRef, 1> AttrFeatures; |
502 | Features.split(A&: AttrFeatures, Separator: ";"); |
503 | bool FoundArch = false; |
504 | |
505 | auto handleArchExtension = [](StringRef AttrString, |
506 | std::vector<std::string> &Features) { |
507 | SmallVector<StringRef, 1> Exts; |
508 | AttrString.split(A&: Exts, Separator: ","); |
509 | for (auto Ext : Exts) { |
510 | if (Ext.empty()) |
511 | continue; |
512 | |
513 | StringRef ExtName = Ext.substr(Start: 1); |
514 | std::string TargetFeature = |
515 | llvm::RISCVISAInfo::getTargetFeatureForExtension(Ext: ExtName); |
516 | if (!TargetFeature.empty()) |
517 | Features.push_back(x: Ext.front() + TargetFeature); |
518 | else |
519 | Features.push_back(x: Ext.str()); |
520 | } |
521 | }; |
522 | |
523 | for (auto &Feature : AttrFeatures) { |
524 | Feature = Feature.trim(); |
525 | StringRef AttrString = Feature.split(Separator: "=").second.trim(); |
526 | |
527 | if (Feature.starts_with(Prefix: "arch=")) { |
528 | // Override last features |
529 | Ret.Features.clear(); |
530 | if (FoundArch) |
531 | Ret.Duplicate = "arch="; |
532 | FoundArch = true; |
533 | |
534 | if (AttrString.starts_with(Prefix: "+")) { |
535 | // EXTENSION like arch=+v,+zbb |
536 | handleArchExtension(AttrString, Ret.Features); |
537 | } else { |
538 | // full-arch-string like arch=rv64gcv |
539 | handleFullArchString(FullArchStr: AttrString, Features&: Ret.Features); |
540 | } |
541 | } else if (Feature.starts_with(Prefix: "cpu=")) { |
542 | if (!Ret.CPU.empty()) |
543 | Ret.Duplicate = "cpu="; |
544 | |
545 | Ret.CPU = AttrString; |
546 | |
547 | if (!FoundArch) { |
548 | // Update Features with CPU's features |
549 | StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU: Ret.CPU); |
550 | if (MarchFromCPU != "") { |
551 | Ret.Features.clear(); |
552 | handleFullArchString(FullArchStr: MarchFromCPU, Features&: Ret.Features); |
553 | } |
554 | } |
555 | } else if (Feature.starts_with(Prefix: "tune=")) { |
556 | if (!Ret.Tune.empty()) |
557 | Ret.Duplicate = "tune="; |
558 | |
559 | Ret.Tune = AttrString; |
560 | } else if (Feature.starts_with(Prefix: "priority")) { |
561 | // Skip because it only use for FMV. |
562 | } else if (Feature.starts_with(Prefix: "+")) { |
563 | // Handle target_version/target_clones attribute strings |
564 | // that are already delimited by ',' |
565 | handleArchExtension(Feature, Ret.Features); |
566 | } |
567 | } |
568 | return Ret; |
569 | } |
570 | |
571 | uint64_t RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { |
572 | // Priority is explicitly specified on RISC-V unlike on other targets, where |
573 | // it is derived by all the features of a specific version. Therefore if a |
574 | // feature contains the priority string, then return it immediately. |
575 | for (StringRef Feature : Features) { |
576 | auto [LHS, RHS] = Feature.rsplit(Separator: ';'); |
577 | if (LHS.consume_front(Prefix: "priority=")) |
578 | Feature = LHS; |
579 | else if (RHS.consume_front(Prefix: "priority=")) |
580 | Feature = RHS; |
581 | else |
582 | continue; |
583 | uint64_t Priority; |
584 | if (!Feature.getAsInteger(Radix: 0, Result&: Priority)) |
585 | return Priority; |
586 | } |
587 | // Default Priority is zero. |
588 | return 0; |
589 | } |
590 | |
591 | TargetInfo::CallingConvCheckResult |
592 | RISCVTargetInfo::checkCallingConvention(CallingConv CC) const { |
593 | switch (CC) { |
594 | default: |
595 | return CCCR_Warning; |
596 | case CC_C: |
597 | case CC_RISCVVectorCall: |
598 | case CC_RISCVVLSCall_32: |
599 | case CC_RISCVVLSCall_64: |
600 | case CC_RISCVVLSCall_128: |
601 | case CC_RISCVVLSCall_256: |
602 | case CC_RISCVVLSCall_512: |
603 | case CC_RISCVVLSCall_1024: |
604 | case CC_RISCVVLSCall_2048: |
605 | case CC_RISCVVLSCall_4096: |
606 | case CC_RISCVVLSCall_8192: |
607 | case CC_RISCVVLSCall_16384: |
608 | case CC_RISCVVLSCall_32768: |
609 | case CC_RISCVVLSCall_65536: |
610 | return CCCR_OK; |
611 | } |
612 | } |
613 | |
614 | bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const { |
615 | // Only allow extensions we have a known bit position for in the |
616 | // __riscv_feature_bits structure. |
617 | return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitsInfo(Ext: Feature).second; |
618 | } |
619 | |
620 | bool RISCVTargetInfo::isValidFeatureName(StringRef Name) const { |
621 | return llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext: Name); |
622 | } |
623 | |
624 | bool RISCVTargetInfo::validateGlobalRegisterVariable( |
625 | StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const { |
626 | if (RegName == "ra"|| RegName == "sp"|| RegName == "gp"|| |
627 | RegName == "tp"|| RegName.starts_with(Prefix: "x") || RegName.starts_with(Prefix: "a") || |
628 | RegName.starts_with(Prefix: "s") || RegName.starts_with(Prefix: "t")) { |
629 | unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; |
630 | HasSizeMismatch = RegSize != XLen; |
631 | return true; |
632 | } |
633 | return false; |
634 | } |
635 | |
636 | bool RISCVTargetInfo::validateCpuIs(StringRef CPUName) const { |
637 | assert(getTriple().isOSLinux() && |
638 | "__builtin_cpu_is() is only supported for Linux."); |
639 | |
640 | return llvm::RISCV::hasValidCPUModel(CPU: CPUName); |
641 | } |
642 |
Definitions
- getGCCRegNames
- getGCCRegAliases
- validateAsmConstraint
- convertConstraint
- getVersionValue
- getTargetDefines
- NumRVVBuiltins
- NumRVVSiFiveBuiltins
- NumRVVAndesBuiltins
- NumRISCVBuiltins
- NumBuiltins
- BuiltinInfos
- BuiltinInfos
- BuiltinInfos
- BuiltinInfos
- getTargetBuiltins
- initFeatureMap
- getVScaleRange
- hasFeature
- handleTargetFeatures
- isValidCPUName
- fillValidCPUList
- isValidTuneCPUName
- fillValidTuneCPUList
- populateNegativeRISCVFeatures
- handleFullArchString
- parseTargetAttr
- getFMVPriority
- checkCallingConvention
- validateCpuSupports
- isValidFeatureName
- validateGlobalRegisterVariable
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more