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, Mode: ArmStreamingKind::NotStreaming); |
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 | {.Strings: &RVV::BuiltinStrings, .Infos: RVV::BuiltinInfos, .NamePrefix: "__builtin_rvv_" }, |
332 | {.Strings: &RVVSiFive::BuiltinStrings, .Infos: RVVSiFive::BuiltinInfos, .NamePrefix: "__builtin_rvv_" }, |
333 | {.Strings: &RVVAndes::BuiltinStrings, .Infos: RVVAndes::BuiltinInfos, .NamePrefix: "__builtin_rvv_" }, |
334 | {.Strings: &BuiltinStrings, .Infos: 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(DiagID: 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 | ArmStreamingKind 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(DiagID: 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(DiagID: 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 | |