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" |
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 'v': |
104 | // A vector register. |
105 | if (Name[1] == 'r' || Name[1] == 'm') { |
106 | Info.setAllowsRegister(); |
107 | Name += 1; |
108 | return true; |
109 | } |
110 | return false; |
111 | } |
112 | } |
113 | |
114 | std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const { |
115 | std::string R; |
116 | switch (*Constraint) { |
117 | case 'v': |
118 | R = std::string("^" ) + std::string(Constraint, 2); |
119 | Constraint += 1; |
120 | break; |
121 | default: |
122 | R = TargetInfo::convertConstraint(Constraint); |
123 | break; |
124 | } |
125 | return R; |
126 | } |
127 | |
128 | static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) { |
129 | return MajorVersion * 1000000 + MinorVersion * 1000; |
130 | } |
131 | |
132 | void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, |
133 | MacroBuilder &Builder) const { |
134 | Builder.defineMacro(Name: "__riscv" ); |
135 | bool Is64Bit = getTriple().isRISCV64(); |
136 | Builder.defineMacro(Name: "__riscv_xlen" , Value: Is64Bit ? "64" : "32" ); |
137 | StringRef CodeModel = getTargetOpts().CodeModel; |
138 | unsigned FLen = ISAInfo->getFLen(); |
139 | unsigned MinVLen = ISAInfo->getMinVLen(); |
140 | unsigned MaxELen = ISAInfo->getMaxELen(); |
141 | unsigned MaxELenFp = ISAInfo->getMaxELenFp(); |
142 | if (CodeModel == "default" ) |
143 | CodeModel = "small" ; |
144 | |
145 | if (CodeModel == "small" ) |
146 | Builder.defineMacro(Name: "__riscv_cmodel_medlow" ); |
147 | else if (CodeModel == "medium" ) |
148 | Builder.defineMacro(Name: "__riscv_cmodel_medany" ); |
149 | |
150 | StringRef ABIName = getABI(); |
151 | if (ABIName == "ilp32f" || ABIName == "lp64f" ) |
152 | Builder.defineMacro(Name: "__riscv_float_abi_single" ); |
153 | else if (ABIName == "ilp32d" || ABIName == "lp64d" ) |
154 | Builder.defineMacro(Name: "__riscv_float_abi_double" ); |
155 | else |
156 | Builder.defineMacro(Name: "__riscv_float_abi_soft" ); |
157 | |
158 | if (ABIName == "ilp32e" || ABIName == "lp64e" ) |
159 | Builder.defineMacro(Name: "__riscv_abi_rve" ); |
160 | |
161 | Builder.defineMacro(Name: "__riscv_arch_test" ); |
162 | |
163 | for (auto &Extension : ISAInfo->getExtensions()) { |
164 | auto ExtName = Extension.first; |
165 | auto ExtInfo = Extension.second; |
166 | |
167 | Builder.defineMacro(Name: Twine("__riscv_" , ExtName), |
168 | Value: Twine(getVersionValue(MajorVersion: ExtInfo.Major, MinorVersion: ExtInfo.Minor))); |
169 | } |
170 | |
171 | if (ISAInfo->hasExtension(Ext: "m" ) || ISAInfo->hasExtension(Ext: "zmmul" )) |
172 | Builder.defineMacro(Name: "__riscv_mul" ); |
173 | |
174 | if (ISAInfo->hasExtension(Ext: "m" )) { |
175 | Builder.defineMacro(Name: "__riscv_div" ); |
176 | Builder.defineMacro(Name: "__riscv_muldiv" ); |
177 | } |
178 | |
179 | if (ISAInfo->hasExtension(Ext: "a" )) { |
180 | Builder.defineMacro(Name: "__riscv_atomic" ); |
181 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1" ); |
182 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2" ); |
183 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" ); |
184 | if (Is64Bit) |
185 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8" ); |
186 | } |
187 | |
188 | if (FLen) { |
189 | Builder.defineMacro(Name: "__riscv_flen" , Value: Twine(FLen)); |
190 | Builder.defineMacro(Name: "__riscv_fdiv" ); |
191 | Builder.defineMacro(Name: "__riscv_fsqrt" ); |
192 | } |
193 | |
194 | if (MinVLen) { |
195 | Builder.defineMacro(Name: "__riscv_v_min_vlen" , Value: Twine(MinVLen)); |
196 | Builder.defineMacro(Name: "__riscv_v_elen" , Value: Twine(MaxELen)); |
197 | Builder.defineMacro(Name: "__riscv_v_elen_fp" , Value: Twine(MaxELenFp)); |
198 | } |
199 | |
200 | if (ISAInfo->hasExtension(Ext: "c" )) |
201 | Builder.defineMacro(Name: "__riscv_compressed" ); |
202 | |
203 | if (ISAInfo->hasExtension(Ext: "zve32x" )) { |
204 | Builder.defineMacro(Name: "__riscv_vector" ); |
205 | // Currently we support the v0.12 RISC-V V intrinsics. |
206 | Builder.defineMacro(Name: "__riscv_v_intrinsic" , Value: Twine(getVersionValue(MajorVersion: 0, MinorVersion: 12))); |
207 | } |
208 | |
209 | auto VScale = getVScaleRange(LangOpts: Opts); |
210 | if (VScale && VScale->first && VScale->first == VScale->second) |
211 | Builder.defineMacro(Name: "__riscv_v_fixed_vlen" , |
212 | Value: Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock)); |
213 | |
214 | if (FastUnalignedAccess) |
215 | Builder.defineMacro(Name: "__riscv_misaligned_fast" ); |
216 | else |
217 | Builder.defineMacro(Name: "__riscv_misaligned_avoid" ); |
218 | |
219 | if (ISAInfo->hasExtension(Ext: "e" )) { |
220 | if (Is64Bit) |
221 | Builder.defineMacro(Name: "__riscv_64e" ); |
222 | else |
223 | Builder.defineMacro(Name: "__riscv_32e" ); |
224 | } |
225 | } |
226 | |
227 | static constexpr Builtin::Info BuiltinInfo[] = { |
228 | #define BUILTIN(ID, TYPE, ATTRS) \ |
229 | {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, |
230 | #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ |
231 | {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, |
232 | #include "clang/Basic/BuiltinsRISCVVector.def" |
233 | #define BUILTIN(ID, TYPE, ATTRS) \ |
234 | {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, |
235 | #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ |
236 | {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, |
237 | #include "clang/Basic/BuiltinsRISCV.inc" |
238 | }; |
239 | |
240 | ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const { |
241 | return llvm::ArrayRef(BuiltinInfo, |
242 | clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin); |
243 | } |
244 | |
245 | bool RISCVTargetInfo::initFeatureMap( |
246 | llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, |
247 | const std::vector<std::string> &FeaturesVec) const { |
248 | |
249 | unsigned XLen = 32; |
250 | |
251 | if (getTriple().isRISCV64()) { |
252 | Features["64bit" ] = true; |
253 | XLen = 64; |
254 | } else { |
255 | Features["32bit" ] = true; |
256 | } |
257 | |
258 | // If a target attribute specified a full arch string, override all the ISA |
259 | // extension target features. |
260 | const auto I = llvm::find(Range: FeaturesVec, Val: "__RISCV_TargetAttrNeedOverride" ); |
261 | if (I != FeaturesVec.end()) { |
262 | std::vector<std::string> OverrideFeatures(std::next(x: I), FeaturesVec.end()); |
263 | |
264 | // Add back any non ISA extension features, e.g. +relax. |
265 | auto IsNonISAExtFeature = [](StringRef Feature) { |
266 | assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-')); |
267 | StringRef Ext = Feature.substr(Start: 1); // drop the +/- |
268 | return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext); |
269 | }; |
270 | llvm::copy_if(Range: llvm::make_range(x: FeaturesVec.begin(), y: I), |
271 | Out: std::back_inserter(x&: OverrideFeatures), P: IsNonISAExtFeature); |
272 | |
273 | return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: OverrideFeatures); |
274 | } |
275 | |
276 | // Otherwise, parse the features and add any implied extensions. |
277 | std::vector<std::string> AllFeatures = FeaturesVec; |
278 | auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features: FeaturesVec); |
279 | if (!ParseResult) { |
280 | std::string Buffer; |
281 | llvm::raw_string_ostream OutputErrMsg(Buffer); |
282 | handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) { |
283 | OutputErrMsg << ErrMsg.getMessage(); |
284 | }); |
285 | Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); |
286 | return false; |
287 | } |
288 | |
289 | // Append all features, not just new ones, so we override any negatives. |
290 | llvm::append_range(C&: AllFeatures, R: (*ParseResult)->toFeatures()); |
291 | return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: AllFeatures); |
292 | } |
293 | |
294 | std::optional<std::pair<unsigned, unsigned>> |
295 | RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const { |
296 | // RISCV::RVVBitsPerBlock is 64. |
297 | unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; |
298 | |
299 | if (LangOpts.VScaleMin || LangOpts.VScaleMax) { |
300 | // Treat Zvl*b as a lower bound on vscale. |
301 | VScaleMin = std::max(a: VScaleMin, b: LangOpts.VScaleMin); |
302 | unsigned VScaleMax = LangOpts.VScaleMax; |
303 | if (VScaleMax != 0 && VScaleMax < VScaleMin) |
304 | VScaleMax = VScaleMin; |
305 | return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax); |
306 | } |
307 | |
308 | if (VScaleMin > 0) { |
309 | unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; |
310 | return std::make_pair(x&: VScaleMin, y&: VScaleMax); |
311 | } |
312 | |
313 | return std::nullopt; |
314 | } |
315 | |
316 | /// Return true if has this feature, need to sync with handleTargetFeatures. |
317 | bool RISCVTargetInfo::hasFeature(StringRef Feature) const { |
318 | bool Is64Bit = getTriple().isRISCV64(); |
319 | auto Result = llvm::StringSwitch<std::optional<bool>>(Feature) |
320 | .Case(S: "riscv" , Value: true) |
321 | .Case(S: "riscv32" , Value: !Is64Bit) |
322 | .Case(S: "riscv64" , Value: Is64Bit) |
323 | .Case(S: "32bit" , Value: !Is64Bit) |
324 | .Case(S: "64bit" , Value: Is64Bit) |
325 | .Case(S: "experimental" , Value: HasExperimental) |
326 | .Default(Value: std::nullopt); |
327 | if (Result) |
328 | return *Result; |
329 | |
330 | return ISAInfo->hasExtension(Ext: Feature); |
331 | } |
332 | |
333 | /// Perform initialization based on the user configured set of features. |
334 | bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, |
335 | DiagnosticsEngine &Diags) { |
336 | unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; |
337 | auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); |
338 | if (!ParseResult) { |
339 | std::string Buffer; |
340 | llvm::raw_string_ostream OutputErrMsg(Buffer); |
341 | handleAllErrors(E: ParseResult.takeError(), Handlers: [&](llvm::StringError &ErrMsg) { |
342 | OutputErrMsg << ErrMsg.getMessage(); |
343 | }); |
344 | Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); |
345 | return false; |
346 | } else { |
347 | ISAInfo = std::move(*ParseResult); |
348 | } |
349 | |
350 | if (ABI.empty()) |
351 | ABI = ISAInfo->computeDefaultABI().str(); |
352 | |
353 | if (ISAInfo->hasExtension(Ext: "zfh" ) || ISAInfo->hasExtension(Ext: "zhinx" )) |
354 | HasLegalHalfType = true; |
355 | |
356 | FastUnalignedAccess = llvm::is_contained(Range&: Features, Element: "+unaligned-scalar-mem" ) && |
357 | llvm::is_contained(Range&: Features, Element: "+unaligned-vector-mem" ); |
358 | |
359 | if (llvm::is_contained(Range&: Features, Element: "+experimental" )) |
360 | HasExperimental = true; |
361 | |
362 | if (ABI == "ilp32e" && ISAInfo->hasExtension(Ext: "d" )) { |
363 | Diags.Report(diag::err_invalid_feature_combination) |
364 | << "ILP32E cannot be used with the D ISA extension" ; |
365 | return false; |
366 | } |
367 | return true; |
368 | } |
369 | |
370 | bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { |
371 | bool Is64Bit = getTriple().isArch64Bit(); |
372 | return llvm::RISCV::parseCPU(CPU: Name, IsRV64: Is64Bit); |
373 | } |
374 | |
375 | void RISCVTargetInfo::fillValidCPUList( |
376 | SmallVectorImpl<StringRef> &Values) const { |
377 | bool Is64Bit = getTriple().isArch64Bit(); |
378 | llvm::RISCV::fillValidCPUArchList(Values, IsRV64: Is64Bit); |
379 | } |
380 | |
381 | bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const { |
382 | bool Is64Bit = getTriple().isArch64Bit(); |
383 | return llvm::RISCV::parseTuneCPU(CPU: Name, IsRV64: Is64Bit); |
384 | } |
385 | |
386 | void RISCVTargetInfo::fillValidTuneCPUList( |
387 | SmallVectorImpl<StringRef> &Values) const { |
388 | bool Is64Bit = getTriple().isArch64Bit(); |
389 | llvm::RISCV::fillValidTuneCPUArchList(Values, IsRV64: Is64Bit); |
390 | } |
391 | |
392 | static void handleFullArchString(StringRef FullArchStr, |
393 | std::vector<std::string> &Features) { |
394 | Features.push_back(x: "__RISCV_TargetAttrNeedOverride" ); |
395 | auto RII = llvm::RISCVISAInfo::parseArchString( |
396 | Arch: FullArchStr, /* EnableExperimentalExtension */ true); |
397 | if (llvm::errorToBool(Err: RII.takeError())) { |
398 | // Forward the invalid FullArchStr. |
399 | Features.push_back(x: "+" + FullArchStr.str()); |
400 | } else { |
401 | // Append a full list of features, including any negative extensions so that |
402 | // we override the CPU's features. |
403 | std::vector<std::string> FeatStrings = |
404 | (*RII)->toFeatures(/* AddAllExtensions */ true); |
405 | Features.insert(position: Features.end(), first: FeatStrings.begin(), last: FeatStrings.end()); |
406 | } |
407 | } |
408 | |
409 | ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { |
410 | ParsedTargetAttr Ret; |
411 | if (Features == "default" ) |
412 | return Ret; |
413 | SmallVector<StringRef, 1> AttrFeatures; |
414 | Features.split(A&: AttrFeatures, Separator: ";" ); |
415 | bool FoundArch = false; |
416 | |
417 | for (auto &Feature : AttrFeatures) { |
418 | Feature = Feature.trim(); |
419 | StringRef AttrString = Feature.split(Separator: "=" ).second.trim(); |
420 | |
421 | if (Feature.starts_with(Prefix: "arch=" )) { |
422 | // Override last features |
423 | Ret.Features.clear(); |
424 | if (FoundArch) |
425 | Ret.Duplicate = "arch=" ; |
426 | FoundArch = true; |
427 | |
428 | if (AttrString.starts_with(Prefix: "+" )) { |
429 | // EXTENSION like arch=+v,+zbb |
430 | SmallVector<StringRef, 1> Exts; |
431 | AttrString.split(A&: Exts, Separator: "," ); |
432 | for (auto Ext : Exts) { |
433 | if (Ext.empty()) |
434 | continue; |
435 | |
436 | StringRef ExtName = Ext.substr(Start: 1); |
437 | std::string TargetFeature = |
438 | llvm::RISCVISAInfo::getTargetFeatureForExtension(Ext: ExtName); |
439 | if (!TargetFeature.empty()) |
440 | Ret.Features.push_back(x: Ext.front() + TargetFeature); |
441 | else |
442 | Ret.Features.push_back(x: Ext.str()); |
443 | } |
444 | } else { |
445 | // full-arch-string like arch=rv64gcv |
446 | handleFullArchString(FullArchStr: AttrString, Features&: Ret.Features); |
447 | } |
448 | } else if (Feature.starts_with(Prefix: "cpu=" )) { |
449 | if (!Ret.CPU.empty()) |
450 | Ret.Duplicate = "cpu=" ; |
451 | |
452 | Ret.CPU = AttrString; |
453 | |
454 | if (!FoundArch) { |
455 | // Update Features with CPU's features |
456 | StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU: Ret.CPU); |
457 | if (MarchFromCPU != "" ) { |
458 | Ret.Features.clear(); |
459 | handleFullArchString(FullArchStr: MarchFromCPU, Features&: Ret.Features); |
460 | } |
461 | } |
462 | } else if (Feature.starts_with(Prefix: "tune=" )) { |
463 | if (!Ret.Tune.empty()) |
464 | Ret.Duplicate = "tune=" ; |
465 | |
466 | Ret.Tune = AttrString; |
467 | } |
468 | } |
469 | return Ret; |
470 | } |
471 | |
472 | TargetInfo::CallingConvCheckResult |
473 | RISCVTargetInfo::checkCallingConvention(CallingConv CC) const { |
474 | switch (CC) { |
475 | default: |
476 | return CCCR_Warning; |
477 | case CC_C: |
478 | case CC_RISCVVectorCall: |
479 | return CCCR_OK; |
480 | } |
481 | } |
482 | |