/src/llvm-project/clang/lib/Basic/Targets/RISCV.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const { |
26 | | // clang-format off |
27 | 0 | static const char *const GCCRegNames[] = { |
28 | | // Integer registers |
29 | 0 | "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", |
30 | 0 | "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", |
31 | 0 | "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", |
32 | 0 | "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", |
33 | | |
34 | | // Floating point registers |
35 | 0 | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
36 | 0 | "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", |
37 | 0 | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
38 | 0 | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", |
39 | | |
40 | | // Vector registers |
41 | 0 | "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", |
42 | 0 | "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", |
43 | 0 | "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", |
44 | 0 | "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", |
45 | | |
46 | | // CSRs |
47 | 0 | "fflags", "frm", "vtype", "vl", "vxsat", "vxrm" |
48 | 0 | }; |
49 | | // clang-format on |
50 | 0 | return llvm::ArrayRef(GCCRegNames); |
51 | 0 | } |
52 | | |
53 | 0 | ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const { |
54 | 0 | static const TargetInfo::GCCRegAlias GCCRegAliases[] = { |
55 | 0 | {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"}, |
56 | 0 | {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"}, |
57 | 0 | {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"}, |
58 | 0 | {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"}, |
59 | 0 | {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"}, |
60 | 0 | {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"}, |
61 | 0 | {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"}, |
62 | 0 | {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"}, |
63 | 0 | {{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"}, |
64 | 0 | {{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"}, |
65 | 0 | {{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"}, |
66 | 0 | {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"}, |
67 | 0 | {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"}, |
68 | 0 | {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"}, |
69 | 0 | {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"}, |
70 | 0 | {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}}; |
71 | 0 | return llvm::ArrayRef(GCCRegAliases); |
72 | 0 | } |
73 | | |
74 | | bool RISCVTargetInfo::validateAsmConstraint( |
75 | 0 | const char *&Name, TargetInfo::ConstraintInfo &Info) const { |
76 | 0 | switch (*Name) { |
77 | 0 | default: |
78 | 0 | return false; |
79 | 0 | case 'I': |
80 | | // A 12-bit signed immediate. |
81 | 0 | Info.setRequiresImmediate(-2048, 2047); |
82 | 0 | return true; |
83 | 0 | case 'J': |
84 | | // Integer zero. |
85 | 0 | Info.setRequiresImmediate(0); |
86 | 0 | return true; |
87 | 0 | case 'K': |
88 | | // A 5-bit unsigned immediate for CSR access instructions. |
89 | 0 | Info.setRequiresImmediate(0, 31); |
90 | 0 | return true; |
91 | 0 | case 'f': |
92 | | // A floating-point register. |
93 | 0 | Info.setAllowsRegister(); |
94 | 0 | return true; |
95 | 0 | case 'A': |
96 | | // An address that is held in a general-purpose register. |
97 | 0 | Info.setAllowsMemory(); |
98 | 0 | return true; |
99 | 0 | case 'S': // A symbolic address |
100 | 0 | Info.setAllowsRegister(); |
101 | 0 | return true; |
102 | 0 | case 'v': |
103 | | // A vector register. |
104 | 0 | if (Name[1] == 'r' || Name[1] == 'm') { |
105 | 0 | Info.setAllowsRegister(); |
106 | 0 | Name += 1; |
107 | 0 | return true; |
108 | 0 | } |
109 | 0 | return false; |
110 | 0 | } |
111 | 0 | } |
112 | | |
113 | 0 | std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const { |
114 | 0 | std::string R; |
115 | 0 | switch (*Constraint) { |
116 | 0 | case 'v': |
117 | 0 | R = std::string("^") + std::string(Constraint, 2); |
118 | 0 | Constraint += 1; |
119 | 0 | break; |
120 | 0 | default: |
121 | 0 | R = TargetInfo::convertConstraint(Constraint); |
122 | 0 | break; |
123 | 0 | } |
124 | 0 | return R; |
125 | 0 | } |
126 | | |
127 | 0 | static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) { |
128 | 0 | return MajorVersion * 1000000 + MinorVersion * 1000; |
129 | 0 | } |
130 | | |
131 | | void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, |
132 | 0 | MacroBuilder &Builder) const { |
133 | 0 | Builder.defineMacro("__riscv"); |
134 | 0 | bool Is64Bit = getTriple().isRISCV64(); |
135 | 0 | Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32"); |
136 | 0 | StringRef CodeModel = getTargetOpts().CodeModel; |
137 | 0 | unsigned FLen = ISAInfo->getFLen(); |
138 | 0 | unsigned MinVLen = ISAInfo->getMinVLen(); |
139 | 0 | unsigned MaxELen = ISAInfo->getMaxELen(); |
140 | 0 | unsigned MaxELenFp = ISAInfo->getMaxELenFp(); |
141 | 0 | if (CodeModel == "default") |
142 | 0 | CodeModel = "small"; |
143 | |
|
144 | 0 | if (CodeModel == "small") |
145 | 0 | Builder.defineMacro("__riscv_cmodel_medlow"); |
146 | 0 | else if (CodeModel == "medium") |
147 | 0 | Builder.defineMacro("__riscv_cmodel_medany"); |
148 | |
|
149 | 0 | StringRef ABIName = getABI(); |
150 | 0 | if (ABIName == "ilp32f" || ABIName == "lp64f") |
151 | 0 | Builder.defineMacro("__riscv_float_abi_single"); |
152 | 0 | else if (ABIName == "ilp32d" || ABIName == "lp64d") |
153 | 0 | Builder.defineMacro("__riscv_float_abi_double"); |
154 | 0 | else |
155 | 0 | Builder.defineMacro("__riscv_float_abi_soft"); |
156 | |
|
157 | 0 | if (ABIName == "ilp32e" || ABIName == "lp64e") |
158 | 0 | Builder.defineMacro("__riscv_abi_rve"); |
159 | |
|
160 | 0 | Builder.defineMacro("__riscv_arch_test"); |
161 | |
|
162 | 0 | for (auto &Extension : ISAInfo->getExtensions()) { |
163 | 0 | auto ExtName = Extension.first; |
164 | 0 | auto ExtInfo = Extension.second; |
165 | |
|
166 | 0 | Builder.defineMacro(Twine("__riscv_", ExtName), |
167 | 0 | Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor))); |
168 | 0 | } |
169 | |
|
170 | 0 | if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul")) |
171 | 0 | Builder.defineMacro("__riscv_mul"); |
172 | |
|
173 | 0 | if (ISAInfo->hasExtension("m")) { |
174 | 0 | Builder.defineMacro("__riscv_div"); |
175 | 0 | Builder.defineMacro("__riscv_muldiv"); |
176 | 0 | } |
177 | |
|
178 | 0 | if (ISAInfo->hasExtension("a")) { |
179 | 0 | Builder.defineMacro("__riscv_atomic"); |
180 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); |
181 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); |
182 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); |
183 | 0 | if (Is64Bit) |
184 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); |
185 | 0 | } |
186 | |
|
187 | 0 | if (FLen) { |
188 | 0 | Builder.defineMacro("__riscv_flen", Twine(FLen)); |
189 | 0 | Builder.defineMacro("__riscv_fdiv"); |
190 | 0 | Builder.defineMacro("__riscv_fsqrt"); |
191 | 0 | } |
192 | |
|
193 | 0 | if (MinVLen) { |
194 | 0 | Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen)); |
195 | 0 | Builder.defineMacro("__riscv_v_elen", Twine(MaxELen)); |
196 | 0 | Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp)); |
197 | 0 | } |
198 | |
|
199 | 0 | if (ISAInfo->hasExtension("c")) |
200 | 0 | Builder.defineMacro("__riscv_compressed"); |
201 | |
|
202 | 0 | if (ISAInfo->hasExtension("zve32x")) { |
203 | 0 | Builder.defineMacro("__riscv_vector"); |
204 | | // Currently we support the v0.12 RISC-V V intrinsics. |
205 | 0 | Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12))); |
206 | 0 | } |
207 | |
|
208 | 0 | auto VScale = getVScaleRange(Opts); |
209 | 0 | if (VScale && VScale->first && VScale->first == VScale->second) |
210 | 0 | Builder.defineMacro("__riscv_v_fixed_vlen", |
211 | 0 | Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock)); |
212 | |
|
213 | 0 | if (FastUnalignedAccess) |
214 | 0 | Builder.defineMacro("__riscv_misaligned_fast"); |
215 | 0 | else |
216 | 0 | Builder.defineMacro("__riscv_misaligned_avoid"); |
217 | |
|
218 | 0 | if (ISAInfo->hasExtension("e")) { |
219 | 0 | if (Is64Bit) |
220 | 0 | Builder.defineMacro("__riscv_64e"); |
221 | 0 | else |
222 | 0 | Builder.defineMacro("__riscv_32e"); |
223 | 0 | } |
224 | 0 | } |
225 | | |
226 | | static constexpr Builtin::Info BuiltinInfo[] = { |
227 | | #define BUILTIN(ID, TYPE, ATTRS) \ |
228 | | {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, |
229 | | #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ |
230 | | {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, |
231 | | #include "clang/Basic/BuiltinsRISCVVector.def" |
232 | | #define BUILTIN(ID, TYPE, ATTRS) \ |
233 | | {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, |
234 | | #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ |
235 | | {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, |
236 | | #include "clang/Basic/BuiltinsRISCV.def" |
237 | | }; |
238 | | |
239 | 0 | ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const { |
240 | 0 | return llvm::ArrayRef(BuiltinInfo, |
241 | 0 | clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin); |
242 | 0 | } |
243 | | |
244 | | bool RISCVTargetInfo::initFeatureMap( |
245 | | llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, |
246 | 0 | const std::vector<std::string> &FeaturesVec) const { |
247 | |
|
248 | 0 | unsigned XLen = 32; |
249 | |
|
250 | 0 | if (getTriple().isRISCV64()) { |
251 | 0 | Features["64bit"] = true; |
252 | 0 | XLen = 64; |
253 | 0 | } else { |
254 | 0 | Features["32bit"] = true; |
255 | 0 | } |
256 | | |
257 | | // If a target attribute specified a full arch string, override all the ISA |
258 | | // extension target features. |
259 | 0 | const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride"); |
260 | 0 | if (I != FeaturesVec.end()) { |
261 | 0 | std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end()); |
262 | | |
263 | | // Add back any non ISA extension features, e.g. +relax. |
264 | 0 | auto IsNonISAExtFeature = [](StringRef Feature) { |
265 | 0 | assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-')); |
266 | 0 | StringRef Ext = Feature.substr(1); // drop the +/- |
267 | 0 | return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext); |
268 | 0 | }; |
269 | 0 | llvm::copy_if(llvm::make_range(FeaturesVec.begin(), I), |
270 | 0 | std::back_inserter(OverrideFeatures), IsNonISAExtFeature); |
271 | |
|
272 | 0 | return TargetInfo::initFeatureMap(Features, Diags, CPU, OverrideFeatures); |
273 | 0 | } |
274 | | |
275 | | // Otherwise, parse the features and add any implied extensions. |
276 | 0 | std::vector<std::string> AllFeatures = FeaturesVec; |
277 | 0 | auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec); |
278 | 0 | if (!ParseResult) { |
279 | 0 | std::string Buffer; |
280 | 0 | llvm::raw_string_ostream OutputErrMsg(Buffer); |
281 | 0 | handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { |
282 | 0 | OutputErrMsg << ErrMsg.getMessage(); |
283 | 0 | }); |
284 | 0 | Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); |
285 | 0 | return false; |
286 | 0 | } |
287 | | |
288 | | // Append all features, not just new ones, so we override any negatives. |
289 | 0 | llvm::append_range(AllFeatures, (*ParseResult)->toFeatures()); |
290 | 0 | return TargetInfo::initFeatureMap(Features, Diags, CPU, AllFeatures); |
291 | 0 | } |
292 | | |
293 | | std::optional<std::pair<unsigned, unsigned>> |
294 | 0 | RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const { |
295 | | // RISCV::RVVBitsPerBlock is 64. |
296 | 0 | unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; |
297 | |
|
298 | 0 | if (LangOpts.VScaleMin || LangOpts.VScaleMax) { |
299 | | // Treat Zvl*b as a lower bound on vscale. |
300 | 0 | VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin); |
301 | 0 | unsigned VScaleMax = LangOpts.VScaleMax; |
302 | 0 | if (VScaleMax != 0 && VScaleMax < VScaleMin) |
303 | 0 | VScaleMax = VScaleMin; |
304 | 0 | return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax); |
305 | 0 | } |
306 | | |
307 | 0 | if (VScaleMin > 0) { |
308 | 0 | unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; |
309 | 0 | return std::make_pair(VScaleMin, VScaleMax); |
310 | 0 | } |
311 | | |
312 | 0 | return std::nullopt; |
313 | 0 | } |
314 | | |
315 | | /// Return true if has this feature, need to sync with handleTargetFeatures. |
316 | 0 | bool RISCVTargetInfo::hasFeature(StringRef Feature) const { |
317 | 0 | bool Is64Bit = getTriple().isRISCV64(); |
318 | 0 | auto Result = llvm::StringSwitch<std::optional<bool>>(Feature) |
319 | 0 | .Case("riscv", true) |
320 | 0 | .Case("riscv32", !Is64Bit) |
321 | 0 | .Case("riscv64", Is64Bit) |
322 | 0 | .Case("32bit", !Is64Bit) |
323 | 0 | .Case("64bit", Is64Bit) |
324 | 0 | .Case("experimental", HasExperimental) |
325 | 0 | .Default(std::nullopt); |
326 | 0 | if (Result) |
327 | 0 | return *Result; |
328 | | |
329 | 0 | return ISAInfo->hasExtension(Feature); |
330 | 0 | } |
331 | | |
332 | | /// Perform initialization based on the user configured set of features. |
333 | | bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, |
334 | 0 | DiagnosticsEngine &Diags) { |
335 | 0 | unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; |
336 | 0 | auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); |
337 | 0 | if (!ParseResult) { |
338 | 0 | std::string Buffer; |
339 | 0 | llvm::raw_string_ostream OutputErrMsg(Buffer); |
340 | 0 | handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { |
341 | 0 | OutputErrMsg << ErrMsg.getMessage(); |
342 | 0 | }); |
343 | 0 | Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); |
344 | 0 | return false; |
345 | 0 | } else { |
346 | 0 | ISAInfo = std::move(*ParseResult); |
347 | 0 | } |
348 | | |
349 | 0 | if (ABI.empty()) |
350 | 0 | ABI = ISAInfo->computeDefaultABI().str(); |
351 | |
|
352 | 0 | if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx")) |
353 | 0 | HasLegalHalfType = true; |
354 | |
|
355 | 0 | FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access"); |
356 | |
|
357 | 0 | if (llvm::is_contained(Features, "+experimental")) |
358 | 0 | HasExperimental = true; |
359 | |
|
360 | 0 | if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) { |
361 | 0 | Diags.Report(diag::err_invalid_feature_combination) |
362 | 0 | << "ILP32E cannot be used with the D ISA extension"; |
363 | 0 | return false; |
364 | 0 | } |
365 | 0 | return true; |
366 | 0 | } |
367 | | |
368 | 0 | bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { |
369 | 0 | bool Is64Bit = getTriple().isArch64Bit(); |
370 | 0 | return llvm::RISCV::parseCPU(Name, Is64Bit); |
371 | 0 | } |
372 | | |
373 | | void RISCVTargetInfo::fillValidCPUList( |
374 | 0 | SmallVectorImpl<StringRef> &Values) const { |
375 | 0 | bool Is64Bit = getTriple().isArch64Bit(); |
376 | 0 | llvm::RISCV::fillValidCPUArchList(Values, Is64Bit); |
377 | 0 | } |
378 | | |
379 | 0 | bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const { |
380 | 0 | bool Is64Bit = getTriple().isArch64Bit(); |
381 | 0 | return llvm::RISCV::parseTuneCPU(Name, Is64Bit); |
382 | 0 | } |
383 | | |
384 | | void RISCVTargetInfo::fillValidTuneCPUList( |
385 | 0 | SmallVectorImpl<StringRef> &Values) const { |
386 | 0 | bool Is64Bit = getTriple().isArch64Bit(); |
387 | 0 | llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit); |
388 | 0 | } |
389 | | |
390 | | static void handleFullArchString(StringRef FullArchStr, |
391 | 0 | std::vector<std::string> &Features) { |
392 | 0 | Features.push_back("__RISCV_TargetAttrNeedOverride"); |
393 | 0 | auto RII = llvm::RISCVISAInfo::parseArchString( |
394 | 0 | FullArchStr, /* EnableExperimentalExtension */ true); |
395 | 0 | if (llvm::errorToBool(RII.takeError())) { |
396 | | // Forward the invalid FullArchStr. |
397 | 0 | Features.push_back("+" + FullArchStr.str()); |
398 | 0 | } else { |
399 | | // Append a full list of features, including any negative extensions so that |
400 | | // we override the CPU's features. |
401 | 0 | std::vector<std::string> FeatStrings = |
402 | 0 | (*RII)->toFeatures(/* AddAllExtensions */ true); |
403 | 0 | Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end()); |
404 | 0 | } |
405 | 0 | } |
406 | | |
407 | 0 | ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { |
408 | 0 | ParsedTargetAttr Ret; |
409 | 0 | if (Features == "default") |
410 | 0 | return Ret; |
411 | 0 | SmallVector<StringRef, 1> AttrFeatures; |
412 | 0 | Features.split(AttrFeatures, ";"); |
413 | 0 | bool FoundArch = false; |
414 | |
|
415 | 0 | for (auto &Feature : AttrFeatures) { |
416 | 0 | Feature = Feature.trim(); |
417 | 0 | StringRef AttrString = Feature.split("=").second.trim(); |
418 | |
|
419 | 0 | if (Feature.starts_with("arch=")) { |
420 | | // Override last features |
421 | 0 | Ret.Features.clear(); |
422 | 0 | if (FoundArch) |
423 | 0 | Ret.Duplicate = "arch="; |
424 | 0 | FoundArch = true; |
425 | |
|
426 | 0 | if (AttrString.starts_with("+")) { |
427 | | // EXTENSION like arch=+v,+zbb |
428 | 0 | SmallVector<StringRef, 1> Exts; |
429 | 0 | AttrString.split(Exts, ","); |
430 | 0 | for (auto Ext : Exts) { |
431 | 0 | if (Ext.empty()) |
432 | 0 | continue; |
433 | | |
434 | 0 | StringRef ExtName = Ext.substr(1); |
435 | 0 | std::string TargetFeature = |
436 | 0 | llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName); |
437 | 0 | if (!TargetFeature.empty()) |
438 | 0 | Ret.Features.push_back(Ext.front() + TargetFeature); |
439 | 0 | else |
440 | 0 | Ret.Features.push_back(Ext.str()); |
441 | 0 | } |
442 | 0 | } else { |
443 | | // full-arch-string like arch=rv64gcv |
444 | 0 | handleFullArchString(AttrString, Ret.Features); |
445 | 0 | } |
446 | 0 | } else if (Feature.starts_with("cpu=")) { |
447 | 0 | if (!Ret.CPU.empty()) |
448 | 0 | Ret.Duplicate = "cpu="; |
449 | |
|
450 | 0 | Ret.CPU = AttrString; |
451 | |
|
452 | 0 | if (!FoundArch) { |
453 | | // Update Features with CPU's features |
454 | 0 | StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU); |
455 | 0 | if (MarchFromCPU != "") { |
456 | 0 | Ret.Features.clear(); |
457 | 0 | handleFullArchString(MarchFromCPU, Ret.Features); |
458 | 0 | } |
459 | 0 | } |
460 | 0 | } else if (Feature.starts_with("tune=")) { |
461 | 0 | if (!Ret.Tune.empty()) |
462 | 0 | Ret.Duplicate = "tune="; |
463 | |
|
464 | 0 | Ret.Tune = AttrString; |
465 | 0 | } |
466 | 0 | } |
467 | 0 | return Ret; |
468 | 0 | } |