1 | //===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ----------------------===// |
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 | #include "llvm/TargetParser/RISCVISAInfo.h" |
10 | #include "llvm/ADT/STLExtras.h" |
11 | #include "llvm/ADT/StringExtras.h" |
12 | #include "llvm/ADT/StringRef.h" |
13 | #include "llvm/Support/Errc.h" |
14 | #include "llvm/Support/Error.h" |
15 | #include "llvm/Support/raw_ostream.h" |
16 | |
17 | #include <array> |
18 | #include <atomic> |
19 | #include <optional> |
20 | #include <string> |
21 | #include <vector> |
22 | |
23 | using namespace llvm; |
24 | |
25 | namespace { |
26 | |
27 | struct RISCVSupportedExtension { |
28 | const char *Name; |
29 | /// Supported version. |
30 | RISCVISAUtils::ExtensionVersion Version; |
31 | |
32 | bool operator<(const RISCVSupportedExtension &RHS) const { |
33 | return StringRef(Name) < StringRef(RHS.Name); |
34 | } |
35 | }; |
36 | |
37 | struct RISCVProfile { |
38 | StringLiteral Name; |
39 | StringLiteral MArch; |
40 | |
41 | bool operator<(const RISCVProfile &RHS) const { |
42 | return StringRef(Name) < StringRef(RHS.Name); |
43 | } |
44 | }; |
45 | |
46 | } // end anonymous namespace |
47 | |
48 | static const char *RISCVGImplications[] = {"i" , "m" , "a" , "f" , "d" }; |
49 | static const char *RISCVGImplicationsZi[] = {"zicsr" , "zifencei" }; |
50 | |
51 | #define GET_SUPPORTED_EXTENSIONS |
52 | #include "llvm/TargetParser/RISCVTargetParserDef.inc" |
53 | |
54 | #define GET_SUPPORTED_PROFILES |
55 | #include "llvm/TargetParser/RISCVTargetParserDef.inc" |
56 | |
57 | static void verifyTables() { |
58 | #ifndef NDEBUG |
59 | static std::atomic<bool> TableChecked(false); |
60 | if (!TableChecked.load(std::memory_order_relaxed)) { |
61 | assert(llvm::is_sorted(SupportedExtensions) && |
62 | "Extensions are not sorted by name" ); |
63 | assert(llvm::is_sorted(SupportedExperimentalExtensions) && |
64 | "Experimental extensions are not sorted by name" ); |
65 | assert(llvm::is_sorted(SupportedProfiles) && |
66 | "Profiles are not sorted by name" ); |
67 | assert(llvm::is_sorted(SupportedExperimentalProfiles) && |
68 | "Experimental profiles are not sorted by name" ); |
69 | TableChecked.store(true, std::memory_order_relaxed); |
70 | } |
71 | #endif |
72 | } |
73 | |
74 | static void PrintExtension(StringRef Name, StringRef Version, |
75 | StringRef Description) { |
76 | outs().indent(NumSpaces: 4); |
77 | unsigned VersionWidth = Description.empty() ? 0 : 10; |
78 | outs() << left_justify(Str: Name, Width: 21) << left_justify(Str: Version, Width: VersionWidth) |
79 | << Description << "\n" ; |
80 | } |
81 | |
82 | void RISCVISAInfo::printSupportedExtensions(StringMap<StringRef> &DescMap) { |
83 | outs() << "All available -march extensions for RISC-V\n\n" ; |
84 | PrintExtension(Name: "Name" , Version: "Version" , Description: (DescMap.empty() ? "" : "Description" )); |
85 | |
86 | RISCVISAUtils::OrderedExtensionMap ExtMap; |
87 | for (const auto &E : SupportedExtensions) |
88 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
89 | for (const auto &E : ExtMap) { |
90 | std::string Version = |
91 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
92 | PrintExtension(Name: E.first, Version, Description: DescMap[E.first]); |
93 | } |
94 | |
95 | outs() << "\nExperimental extensions\n" ; |
96 | ExtMap.clear(); |
97 | for (const auto &E : SupportedExperimentalExtensions) |
98 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
99 | for (const auto &E : ExtMap) { |
100 | std::string Version = |
101 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
102 | PrintExtension(Name: E.first, Version, Description: DescMap["experimental-" + E.first]); |
103 | } |
104 | |
105 | outs() << "\nSupported Profiles\n" ; |
106 | for (const auto &P : SupportedProfiles) |
107 | outs().indent(NumSpaces: 4) << P.Name << "\n" ; |
108 | |
109 | outs() << "\nExperimental Profiles\n" ; |
110 | for (const auto &P : SupportedExperimentalProfiles) |
111 | outs().indent(NumSpaces: 4) << P.Name << "\n" ; |
112 | |
113 | outs() << "\nUse -march to specify the target's extension.\n" |
114 | "For example, clang -march=rv32i_v1p0\n" ; |
115 | } |
116 | |
117 | void RISCVISAInfo::printEnabledExtensions( |
118 | bool IsRV64, std::set<StringRef> &EnabledFeatureNames, |
119 | StringMap<StringRef> &DescMap) { |
120 | outs() << "Extensions enabled for the given RISC-V target\n\n" ; |
121 | PrintExtension(Name: "Name" , Version: "Version" , Description: (DescMap.empty() ? "" : "Description" )); |
122 | |
123 | RISCVISAUtils::OrderedExtensionMap FullExtMap; |
124 | RISCVISAUtils::OrderedExtensionMap ExtMap; |
125 | for (const auto &E : SupportedExtensions) |
126 | if (EnabledFeatureNames.count(x: E.Name) != 0) { |
127 | FullExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
128 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
129 | } |
130 | for (const auto &E : ExtMap) { |
131 | std::string Version = |
132 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
133 | PrintExtension(Name: E.first, Version, Description: DescMap[E.first]); |
134 | } |
135 | |
136 | outs() << "\nExperimental extensions\n" ; |
137 | ExtMap.clear(); |
138 | for (const auto &E : SupportedExperimentalExtensions) { |
139 | StringRef Name(E.Name); |
140 | if (EnabledFeatureNames.count(x: "experimental-" + Name.str()) != 0) { |
141 | FullExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
142 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
143 | } |
144 | } |
145 | for (const auto &E : ExtMap) { |
146 | std::string Version = |
147 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
148 | PrintExtension(Name: E.first, Version, Description: DescMap["experimental-" + E.first]); |
149 | } |
150 | |
151 | unsigned XLen = IsRV64 ? 64 : 32; |
152 | if (auto ISAString = RISCVISAInfo::createFromExtMap(XLen, Exts: FullExtMap)) |
153 | outs() << "\nISA String: " << ISAString.get()->toString() << "\n" ; |
154 | } |
155 | |
156 | static bool stripExperimentalPrefix(StringRef &Ext) { |
157 | return Ext.consume_front(Prefix: "experimental-" ); |
158 | } |
159 | |
160 | // This function finds the last character that doesn't belong to a version |
161 | // (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will |
162 | // consume [0-9]*p[0-9]* starting from the backward. An extension name will not |
163 | // end with a digit or the letter 'p', so this function will parse correctly. |
164 | // NOTE: This function is NOT able to take empty strings or strings that only |
165 | // have version numbers and no extension name. It assumes the extension name |
166 | // will be at least more than one character. |
167 | static size_t findLastNonVersionCharacter(StringRef Ext) { |
168 | assert(!Ext.empty() && |
169 | "Already guarded by if-statement in ::parseArchString" ); |
170 | |
171 | int Pos = Ext.size() - 1; |
172 | while (Pos > 0 && isDigit(C: Ext[Pos])) |
173 | Pos--; |
174 | if (Pos > 0 && Ext[Pos] == 'p' && isDigit(C: Ext[Pos - 1])) { |
175 | Pos--; |
176 | while (Pos > 0 && isDigit(C: Ext[Pos])) |
177 | Pos--; |
178 | } |
179 | return Pos; |
180 | } |
181 | |
182 | namespace { |
183 | struct LessExtName { |
184 | bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) { |
185 | return StringRef(LHS.Name) < RHS; |
186 | } |
187 | bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) { |
188 | return LHS < StringRef(RHS.Name); |
189 | } |
190 | }; |
191 | } // namespace |
192 | |
193 | static std::optional<RISCVISAUtils::ExtensionVersion> |
194 | findDefaultVersion(StringRef ExtName) { |
195 | // Find default version of an extension. |
196 | // TODO: We might set default version based on profile or ISA spec. |
197 | for (auto &ExtInfo : {ArrayRef(SupportedExtensions), |
198 | ArrayRef(SupportedExperimentalExtensions)}) { |
199 | auto I = llvm::lower_bound(Range: ExtInfo, Value&: ExtName, C: LessExtName()); |
200 | |
201 | if (I == ExtInfo.end() || I->Name != ExtName) |
202 | continue; |
203 | |
204 | return I->Version; |
205 | } |
206 | return std::nullopt; |
207 | } |
208 | |
209 | static StringRef getExtensionTypeDesc(StringRef Ext) { |
210 | if (Ext.starts_with(Prefix: 's')) |
211 | return "standard supervisor-level extension" ; |
212 | if (Ext.starts_with(Prefix: 'x')) |
213 | return "non-standard user-level extension" ; |
214 | if (Ext.starts_with(Prefix: 'z')) |
215 | return "standard user-level extension" ; |
216 | return StringRef(); |
217 | } |
218 | |
219 | static StringRef getExtensionType(StringRef Ext) { |
220 | if (Ext.starts_with(Prefix: 's')) |
221 | return "s" ; |
222 | if (Ext.starts_with(Prefix: 'x')) |
223 | return "x" ; |
224 | if (Ext.starts_with(Prefix: 'z')) |
225 | return "z" ; |
226 | return StringRef(); |
227 | } |
228 | |
229 | static std::optional<RISCVISAUtils::ExtensionVersion> |
230 | isExperimentalExtension(StringRef Ext) { |
231 | auto I = |
232 | llvm::lower_bound(Range: SupportedExperimentalExtensions, Value&: Ext, C: LessExtName()); |
233 | if (I == std::end(arr: SupportedExperimentalExtensions) || I->Name != Ext) |
234 | return std::nullopt; |
235 | |
236 | return I->Version; |
237 | } |
238 | |
239 | bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) { |
240 | bool IsExperimental = stripExperimentalPrefix(Ext); |
241 | |
242 | ArrayRef<RISCVSupportedExtension> ExtInfo = |
243 | IsExperimental ? ArrayRef(SupportedExperimentalExtensions) |
244 | : ArrayRef(SupportedExtensions); |
245 | |
246 | auto I = llvm::lower_bound(Range&: ExtInfo, Value&: Ext, C: LessExtName()); |
247 | return I != ExtInfo.end() && I->Name == Ext; |
248 | } |
249 | |
250 | bool RISCVISAInfo::isSupportedExtension(StringRef Ext) { |
251 | verifyTables(); |
252 | |
253 | for (auto ExtInfo : {ArrayRef(SupportedExtensions), |
254 | ArrayRef(SupportedExperimentalExtensions)}) { |
255 | auto I = llvm::lower_bound(Range&: ExtInfo, Value&: Ext, C: LessExtName()); |
256 | if (I != ExtInfo.end() && I->Name == Ext) |
257 | return true; |
258 | } |
259 | |
260 | return false; |
261 | } |
262 | |
263 | bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion, |
264 | unsigned MinorVersion) { |
265 | for (auto ExtInfo : {ArrayRef(SupportedExtensions), |
266 | ArrayRef(SupportedExperimentalExtensions)}) { |
267 | auto Range = |
268 | std::equal_range(first: ExtInfo.begin(), last: ExtInfo.end(), val: Ext, comp: LessExtName()); |
269 | for (auto I = Range.first, E = Range.second; I != E; ++I) |
270 | if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion) |
271 | return true; |
272 | } |
273 | |
274 | return false; |
275 | } |
276 | |
277 | bool RISCVISAInfo::hasExtension(StringRef Ext) const { |
278 | stripExperimentalPrefix(Ext); |
279 | |
280 | if (!isSupportedExtension(Ext)) |
281 | return false; |
282 | |
283 | return Exts.count(x: Ext.str()) != 0; |
284 | } |
285 | |
286 | std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions, |
287 | bool IgnoreUnknown) const { |
288 | std::vector<std::string> Features; |
289 | for (const auto &[ExtName, _] : Exts) { |
290 | // i is a base instruction set, not an extension (see |
291 | // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa) |
292 | // and is not recognized in clang -cc1 |
293 | if (ExtName == "i" ) |
294 | continue; |
295 | if (IgnoreUnknown && !isSupportedExtension(Ext: ExtName)) |
296 | continue; |
297 | |
298 | if (isExperimentalExtension(Ext: ExtName)) { |
299 | Features.push_back(x: (llvm::Twine("+experimental-" ) + ExtName).str()); |
300 | } else { |
301 | Features.push_back(x: (llvm::Twine("+" ) + ExtName).str()); |
302 | } |
303 | } |
304 | if (AddAllExtensions) { |
305 | for (const RISCVSupportedExtension &Ext : SupportedExtensions) { |
306 | if (Exts.count(x: Ext.Name)) |
307 | continue; |
308 | Features.push_back(x: (llvm::Twine("-" ) + Ext.Name).str()); |
309 | } |
310 | |
311 | for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) { |
312 | if (Exts.count(x: Ext.Name)) |
313 | continue; |
314 | Features.push_back(x: (llvm::Twine("-experimental-" ) + Ext.Name).str()); |
315 | } |
316 | } |
317 | return Features; |
318 | } |
319 | |
320 | static Error getError(const Twine &Message) { |
321 | return createStringError(EC: errc::invalid_argument, S: Message); |
322 | } |
323 | |
324 | static Error getErrorForInvalidExt(StringRef ExtName) { |
325 | if (ExtName.size() == 1) { |
326 | return getError(Message: "unsupported standard user-level extension '" + ExtName + |
327 | "'" ); |
328 | } |
329 | return getError(Message: "unsupported " + getExtensionTypeDesc(Ext: ExtName) + " '" + |
330 | ExtName + "'" ); |
331 | } |
332 | |
333 | // Extensions may have a version number, and may be separated by |
334 | // an underscore '_' e.g.: rv32i2_m2. |
335 | // Version number is divided into major and minor version numbers, |
336 | // separated by a 'p'. If the minor version is 0 then 'p0' can be |
337 | // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. |
338 | static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, |
339 | unsigned &Minor, unsigned &ConsumeLength, |
340 | bool EnableExperimentalExtension, |
341 | bool ExperimentalExtensionVersionCheck) { |
342 | StringRef MajorStr, MinorStr; |
343 | Major = 0; |
344 | Minor = 0; |
345 | ConsumeLength = 0; |
346 | MajorStr = In.take_while(F: isDigit); |
347 | In = In.substr(Start: MajorStr.size()); |
348 | |
349 | if (!MajorStr.empty() && In.consume_front(Prefix: "p" )) { |
350 | MinorStr = In.take_while(F: isDigit); |
351 | In = In.substr(Start: MajorStr.size() + MinorStr.size() - 1); |
352 | |
353 | // Expected 'p' to be followed by minor version number. |
354 | if (MinorStr.empty()) { |
355 | return getError(Message: "minor version number missing after 'p' for extension '" + |
356 | Ext + "'" ); |
357 | } |
358 | } |
359 | |
360 | if (!MajorStr.empty() && MajorStr.getAsInteger(Radix: 10, Result&: Major)) |
361 | return getError(Message: "Failed to parse major version number for extension '" + |
362 | Ext + "'" ); |
363 | |
364 | if (!MinorStr.empty() && MinorStr.getAsInteger(Radix: 10, Result&: Minor)) |
365 | return getError(Message: "Failed to parse minor version number for extension '" + |
366 | Ext + "'" ); |
367 | |
368 | ConsumeLength = MajorStr.size(); |
369 | |
370 | if (!MinorStr.empty()) |
371 | ConsumeLength += MinorStr.size() + 1 /*'p'*/; |
372 | |
373 | // Expected multi-character extension with version number to have no |
374 | // subsequent characters (i.e. must either end string or be followed by |
375 | // an underscore). |
376 | if (Ext.size() > 1 && In.size()) |
377 | return getError( |
378 | Message: "multi-character extensions must be separated by underscores" ); |
379 | |
380 | // If experimental extension, require use of current version number |
381 | if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { |
382 | if (!EnableExperimentalExtension) |
383 | return getError(Message: "requires '-menable-experimental-extensions' " |
384 | "for experimental extension '" + |
385 | Ext + "'" ); |
386 | |
387 | if (ExperimentalExtensionVersionCheck && |
388 | (MajorStr.empty() && MinorStr.empty())) |
389 | return getError( |
390 | Message: "experimental extension requires explicit version number `" + Ext + |
391 | "`" ); |
392 | |
393 | auto SupportedVers = *ExperimentalExtension; |
394 | if (ExperimentalExtensionVersionCheck && |
395 | (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) { |
396 | std::string Error = "unsupported version number " + MajorStr.str(); |
397 | if (!MinorStr.empty()) |
398 | Error += "." + MinorStr.str(); |
399 | Error += " for experimental extension '" + Ext.str() + |
400 | "' (this compiler supports " + utostr(X: SupportedVers.Major) + |
401 | "." + utostr(X: SupportedVers.Minor) + ")" ; |
402 | return getError(Message: Error); |
403 | } |
404 | return Error::success(); |
405 | } |
406 | |
407 | // Exception rule for `g`, we don't have clear version scheme for that on |
408 | // ISA spec. |
409 | if (Ext == "g" ) |
410 | return Error::success(); |
411 | |
412 | if (MajorStr.empty() && MinorStr.empty()) { |
413 | if (auto DefaultVersion = findDefaultVersion(ExtName: Ext)) { |
414 | Major = DefaultVersion->Major; |
415 | Minor = DefaultVersion->Minor; |
416 | } |
417 | // No matter found or not, return success, assume other place will |
418 | // verify. |
419 | return Error::success(); |
420 | } |
421 | |
422 | if (RISCVISAInfo::isSupportedExtension(Ext, MajorVersion: Major, MinorVersion: Minor)) |
423 | return Error::success(); |
424 | |
425 | if (!RISCVISAInfo::isSupportedExtension(Ext)) |
426 | return getErrorForInvalidExt(ExtName: Ext); |
427 | |
428 | std::string Error = "unsupported version number " + MajorStr.str(); |
429 | if (!MinorStr.empty()) |
430 | Error += "." + MinorStr.str(); |
431 | Error += " for extension '" + Ext.str() + "'" ; |
432 | return getError(Message: Error); |
433 | } |
434 | |
435 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
436 | RISCVISAInfo::createFromExtMap(unsigned XLen, |
437 | const RISCVISAUtils::OrderedExtensionMap &Exts) { |
438 | assert(XLen == 32 || XLen == 64); |
439 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
440 | |
441 | ISAInfo->Exts = Exts; |
442 | |
443 | return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo)); |
444 | } |
445 | |
446 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
447 | RISCVISAInfo::parseFeatures(unsigned XLen, |
448 | const std::vector<std::string> &Features) { |
449 | assert(XLen == 32 || XLen == 64); |
450 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
451 | |
452 | for (StringRef ExtName : Features) { |
453 | assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); |
454 | bool Add = ExtName[0] == '+'; |
455 | ExtName = ExtName.drop_front(N: 1); // Drop '+' or '-' |
456 | bool Experimental = stripExperimentalPrefix(Ext&: ExtName); |
457 | auto ExtensionInfos = Experimental |
458 | ? ArrayRef(SupportedExperimentalExtensions) |
459 | : ArrayRef(SupportedExtensions); |
460 | auto ExtensionInfoIterator = |
461 | llvm::lower_bound(Range&: ExtensionInfos, Value&: ExtName, C: LessExtName()); |
462 | |
463 | // Not all features is related to ISA extension, like `relax` or |
464 | // `save-restore`, skip those feature. |
465 | if (ExtensionInfoIterator == ExtensionInfos.end() || |
466 | ExtensionInfoIterator->Name != ExtName) |
467 | continue; |
468 | |
469 | if (Add) |
470 | ISAInfo->Exts[ExtName.str()] = ExtensionInfoIterator->Version; |
471 | else |
472 | ISAInfo->Exts.erase(x: ExtName.str()); |
473 | } |
474 | |
475 | return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo)); |
476 | } |
477 | |
478 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
479 | RISCVISAInfo::parseNormalizedArchString(StringRef Arch) { |
480 | // RISC-V ISA strings must be [a-z0-9_] |
481 | if (!llvm::all_of( |
482 | Range&: Arch, P: [](char C) { return isDigit(C) || isLower(C) || C == '_'; })) |
483 | return getError(Message: "string may only contain [a-z0-9_]" ); |
484 | |
485 | // Must start with a valid base ISA name. |
486 | unsigned XLen = 0; |
487 | if (Arch.consume_front(Prefix: "rv32" )) |
488 | XLen = 32; |
489 | else if (Arch.consume_front(Prefix: "rv64" )) |
490 | XLen = 64; |
491 | |
492 | if (XLen == 0 || Arch.empty() || (Arch[0] != 'i' && Arch[0] != 'e')) |
493 | return getError(Message: "arch string must begin with valid base ISA" ); |
494 | |
495 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
496 | |
497 | // Each extension is of the form ${name}${major_version}p${minor_version} |
498 | // and separated by _. Split by _ and then extract the name and version |
499 | // information for each extension. |
500 | while (!Arch.empty()) { |
501 | if (Arch[0] == '_') { |
502 | if (Arch.size() == 1 || Arch[1] == '_') |
503 | return getError(Message: "extension name missing after separator '_'" ); |
504 | Arch = Arch.drop_front(); |
505 | } |
506 | |
507 | size_t Idx = Arch.find(C: '_'); |
508 | StringRef Ext = Arch.slice(Start: 0, End: Idx); |
509 | Arch = Arch.substr(Start: Idx); |
510 | |
511 | StringRef Prefix, MinorVersionStr; |
512 | std::tie(args&: Prefix, args&: MinorVersionStr) = Ext.rsplit(Separator: 'p'); |
513 | if (MinorVersionStr.empty()) |
514 | return getError(Message: "extension lacks version in expected format" ); |
515 | unsigned MajorVersion, MinorVersion; |
516 | if (MinorVersionStr.getAsInteger(Radix: 10, Result&: MinorVersion)) |
517 | return getError(Message: "failed to parse minor version number" ); |
518 | |
519 | // Split Prefix into the extension name and the major version number |
520 | // (the trailing digits of Prefix). |
521 | size_t VersionStart = Prefix.size(); |
522 | while (VersionStart != 0) { |
523 | if (!isDigit(C: Prefix[VersionStart - 1])) |
524 | break; |
525 | --VersionStart; |
526 | } |
527 | if (VersionStart == Prefix.size()) |
528 | return getError(Message: "extension lacks version in expected format" ); |
529 | |
530 | if (VersionStart == 0) |
531 | return getError(Message: "missing extension name" ); |
532 | |
533 | StringRef ExtName = Prefix.slice(Start: 0, End: VersionStart); |
534 | StringRef MajorVersionStr = Prefix.substr(Start: VersionStart); |
535 | if (MajorVersionStr.getAsInteger(Radix: 10, Result&: MajorVersion)) |
536 | return getError(Message: "failed to parse major version number" ); |
537 | |
538 | if ((ExtName[0] == 'z' || ExtName[0] == 's' || ExtName[0] == 'x') && |
539 | (ExtName.size() == 1 || isDigit(C: ExtName[1]))) |
540 | return getError(Message: "'" + Twine(ExtName[0]) + |
541 | "' must be followed by a letter" ); |
542 | |
543 | if (!ISAInfo->Exts |
544 | .emplace( |
545 | args: ExtName.str(), |
546 | args: RISCVISAUtils::ExtensionVersion{.Major: MajorVersion, .Minor: MinorVersion}) |
547 | .second) |
548 | return getError(Message: "duplicate extension '" + ExtName + "'" ); |
549 | } |
550 | ISAInfo->updateImpliedLengths(); |
551 | return std::move(ISAInfo); |
552 | } |
553 | |
554 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
555 | RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension, |
556 | bool ExperimentalExtensionVersionCheck) { |
557 | // RISC-V ISA strings must be [a-z0-9_] |
558 | if (!llvm::all_of( |
559 | Range&: Arch, P: [](char C) { return isDigit(C) || isLower(C) || C == '_'; })) |
560 | return getError(Message: "string may only contain [a-z0-9_]" ); |
561 | |
562 | // ISA string must begin with rv32, rv64, or a profile. |
563 | unsigned XLen = 0; |
564 | if (Arch.consume_front(Prefix: "rv32" )) { |
565 | XLen = 32; |
566 | } else if (Arch.consume_front(Prefix: "rv64" )) { |
567 | XLen = 64; |
568 | } else { |
569 | // Try parsing as a profile. |
570 | auto ProfileCmp = [](StringRef Arch, const RISCVProfile &Profile) { |
571 | return Arch < Profile.Name; |
572 | }; |
573 | auto I = llvm::upper_bound(Range: SupportedProfiles, Value&: Arch, C: ProfileCmp); |
574 | bool FoundProfile = I != std::begin(arr: SupportedProfiles) && |
575 | Arch.starts_with(Prefix: std::prev(x: I)->Name); |
576 | if (!FoundProfile) { |
577 | I = llvm::upper_bound(Range: SupportedExperimentalProfiles, Value&: Arch, C: ProfileCmp); |
578 | FoundProfile = (I != std::begin(arr: SupportedExperimentalProfiles) && |
579 | Arch.starts_with(Prefix: std::prev(x: I)->Name)); |
580 | if (FoundProfile && !EnableExperimentalExtension) { |
581 | return getError(Message: "requires '-menable-experimental-extensions' " |
582 | "for profile '" + |
583 | std::prev(x: I)->Name + "'" ); |
584 | } |
585 | } |
586 | if (FoundProfile) { |
587 | --I; |
588 | std::string NewArch = I->MArch.str(); |
589 | StringRef ArchWithoutProfile = Arch.drop_front(N: I->Name.size()); |
590 | if (!ArchWithoutProfile.empty()) { |
591 | if (ArchWithoutProfile.front() != '_') |
592 | return getError(Message: "additional extensions must be after separator '_'" ); |
593 | NewArch += ArchWithoutProfile.str(); |
594 | } |
595 | return parseArchString(Arch: NewArch, EnableExperimentalExtension, |
596 | ExperimentalExtensionVersionCheck); |
597 | } |
598 | } |
599 | |
600 | if (XLen == 0 || Arch.empty()) |
601 | return getError( |
602 | Message: "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported " |
603 | "profile name" ); |
604 | |
605 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
606 | |
607 | // The canonical order specified in ISA manual. |
608 | // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 |
609 | char Baseline = Arch.front(); |
610 | // Skip the baseline. |
611 | Arch = Arch.drop_front(); |
612 | |
613 | unsigned Major, Minor, ConsumeLength; |
614 | |
615 | // First letter should be 'e', 'i' or 'g'. |
616 | switch (Baseline) { |
617 | default: |
618 | return getError(Message: "first letter after \'rv" + Twine(XLen) + |
619 | "\' should be 'e', 'i' or 'g'" ); |
620 | case 'e': |
621 | case 'i': |
622 | // Baseline is `i` or `e` |
623 | if (auto E = getExtensionVersion( |
624 | Ext: StringRef(&Baseline, 1), In: Arch, Major, Minor, ConsumeLength, |
625 | EnableExperimentalExtension, ExperimentalExtensionVersionCheck)) |
626 | return std::move(E); |
627 | |
628 | ISAInfo->Exts[std::string(1, Baseline)] = {.Major: Major, .Minor: Minor}; |
629 | break; |
630 | case 'g': |
631 | // g expands to extensions in RISCVGImplications. |
632 | if (!Arch.empty() && isDigit(C: Arch.front())) |
633 | return getError(Message: "version not supported for 'g'" ); |
634 | |
635 | // Versions for g are disallowed, and this was checked for previously. |
636 | ConsumeLength = 0; |
637 | |
638 | // No matter which version is given to `g`, we always set imafd to default |
639 | // version since the we don't have clear version scheme for that on |
640 | // ISA spec. |
641 | for (const char *Ext : RISCVGImplications) { |
642 | auto Version = findDefaultVersion(ExtName: Ext); |
643 | assert(Version && "Default extension version not found?" ); |
644 | ISAInfo->Exts[std::string(Ext)] = {.Major: Version->Major, .Minor: Version->Minor}; |
645 | } |
646 | break; |
647 | } |
648 | |
649 | // Consume the base ISA version number and any '_' between rvxxx and the |
650 | // first extension |
651 | Arch = Arch.drop_front(N: ConsumeLength); |
652 | |
653 | while (!Arch.empty()) { |
654 | if (Arch.front() == '_') { |
655 | if (Arch.size() == 1 || Arch[1] == '_') |
656 | return getError(Message: "extension name missing after separator '_'" ); |
657 | Arch = Arch.drop_front(); |
658 | } |
659 | |
660 | size_t Idx = Arch.find(C: '_'); |
661 | StringRef Ext = Arch.slice(Start: 0, End: Idx); |
662 | Arch = Arch.substr(Start: Idx); |
663 | |
664 | do { |
665 | StringRef Name, Vers, Desc; |
666 | if (RISCVISAUtils::AllStdExts.contains(C: Ext.front())) { |
667 | Name = Ext.take_front(N: 1); |
668 | Ext = Ext.drop_front(); |
669 | Vers = Ext; |
670 | Desc = "standard user-level extension" ; |
671 | } else if (Ext.front() == 'z' || Ext.front() == 's' || |
672 | Ext.front() == 'x') { |
673 | // Handle other types of extensions other than the standard |
674 | // general purpose and standard user-level extensions. |
675 | // Parse the ISA string containing non-standard user-level |
676 | // extensions, standard supervisor-level extensions and |
677 | // non-standard supervisor-level extensions. |
678 | // These extensions start with 'z', 's', 'x' prefixes, might have a |
679 | // version number (major, minor) and are separated by a single |
680 | // underscore '_'. We do not enforce a canonical order for them. |
681 | StringRef Type = getExtensionType(Ext); |
682 | Desc = getExtensionTypeDesc(Ext); |
683 | auto Pos = findLastNonVersionCharacter(Ext) + 1; |
684 | Name = Ext.substr(Start: 0, N: Pos); |
685 | Vers = Ext.substr(Start: Pos); |
686 | Ext = StringRef(); |
687 | |
688 | assert(!Type.empty() && "Empty type?" ); |
689 | if (Name.size() == Type.size()) |
690 | return getError(Message: Desc + " name missing after '" + Type + "'" ); |
691 | } else { |
692 | return getError(Message: "invalid standard user-level extension '" + |
693 | Twine(Ext.front()) + "'" ); |
694 | } |
695 | |
696 | unsigned Major, Minor, ConsumeLength; |
697 | if (auto E = getExtensionVersion(Ext: Name, In: Vers, Major, Minor, ConsumeLength, |
698 | EnableExperimentalExtension, |
699 | ExperimentalExtensionVersionCheck)) |
700 | return E; |
701 | |
702 | if (Name.size() == 1) |
703 | Ext = Ext.substr(Start: ConsumeLength); |
704 | |
705 | if (!RISCVISAInfo::isSupportedExtension(Ext: Name)) |
706 | return getErrorForInvalidExt(ExtName: Name); |
707 | |
708 | // Insert and error for duplicates. |
709 | if (!ISAInfo->Exts |
710 | .emplace(args: Name.str(), |
711 | args: RISCVISAUtils::ExtensionVersion{.Major: Major, .Minor: Minor}) |
712 | .second) |
713 | return getError(Message: "duplicated " + Desc + " '" + Name + "'" ); |
714 | |
715 | } while (!Ext.empty()); |
716 | } |
717 | |
718 | // We add Zicsr/Zifenci as final to allow duplicated "zicsr"/"zifencei" like |
719 | // "rv64g_zicsr_zifencei". |
720 | if (Baseline == 'g') { |
721 | for (const char *Ext : RISCVGImplicationsZi) { |
722 | if (ISAInfo->Exts.count(x: Ext)) |
723 | continue; |
724 | |
725 | auto Version = findDefaultVersion(ExtName: Ext); |
726 | assert(Version && "Default extension version not found?" ); |
727 | ISAInfo->Exts[std::string(Ext)] = {.Major: Version->Major, .Minor: Version->Minor}; |
728 | } |
729 | } |
730 | |
731 | return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo)); |
732 | } |
733 | |
734 | static Error getIncompatibleError(StringRef Ext1, StringRef Ext2) { |
735 | return getError(Message: "'" + Ext1 + "' and '" + Ext2 + |
736 | "' extensions are incompatible" ); |
737 | } |
738 | |
739 | static Error getExtensionRequiresError(StringRef Ext, StringRef ReqExt) { |
740 | return getError(Message: "'" + Ext + "' requires '" + ReqExt + |
741 | "' extension to also be specified" ); |
742 | } |
743 | |
744 | Error RISCVISAInfo::checkDependency() { |
745 | bool HasE = Exts.count(x: "e" ) != 0; |
746 | bool HasI = Exts.count(x: "i" ) != 0; |
747 | bool HasC = Exts.count(x: "c" ) != 0; |
748 | bool HasF = Exts.count(x: "f" ) != 0; |
749 | bool HasD = Exts.count(x: "d" ) != 0; |
750 | bool HasZfinx = Exts.count(x: "zfinx" ) != 0; |
751 | bool HasVector = Exts.count(x: "zve32x" ) != 0; |
752 | bool HasZvl = MinVLen != 0; |
753 | bool HasZcmp = Exts.count(x: "zcmp" ) != 0; |
754 | bool HasXqccmp = Exts.count(x: "xqccmp" ) != 0; |
755 | |
756 | static constexpr StringLiteral XqciExts[] = { |
757 | {"xqcia" }, {"xqciac" }, {"xqcibi" }, {"xqcibm" }, {"xqcicli" }, |
758 | {"xqcicm" }, {"xqcics" }, {"xqcicsr" }, {"xqciint" }, {"xqciio" }, |
759 | {"xqcilb" }, {"xqcili" }, {"xqcilia" }, {"xqcilo" }, {"xqcilsm" }, |
760 | {"xqcisim" }, {"xqcisls" }, {"xqcisync" }}; |
761 | static constexpr StringLiteral ZcdOverlaps[] = { |
762 | {"zcmt" }, {"zcmp" }, {"xqccmp" }, {"xqciac" }, {"xqcicm" }}; |
763 | |
764 | if (HasI && HasE) |
765 | return getIncompatibleError(Ext1: "i" , Ext2: "e" ); |
766 | |
767 | if (HasF && HasZfinx) |
768 | return getIncompatibleError(Ext1: "f" , Ext2: "zfinx" ); |
769 | |
770 | if (HasZvl && !HasVector) |
771 | return getExtensionRequiresError(Ext: "zvl*b" , ReqExt: "v' or 'zve*" ); |
772 | |
773 | if (HasD && (HasC || Exts.count(x: "zcd" ))) |
774 | for (auto Ext : ZcdOverlaps) |
775 | if (Exts.count(x: Ext.str())) |
776 | return getError( |
777 | Message: Twine("'" ) + Ext + "' extension is incompatible with '" + |
778 | (HasC ? "c" : "zcd" ) + "' extension when 'd' extension is enabled" ); |
779 | |
780 | if (XLen != 32 && Exts.count(x: "zcf" )) |
781 | return getError(Message: "'zcf' is only supported for 'rv32'" ); |
782 | |
783 | if (Exts.count(x: "xwchc" ) != 0) { |
784 | if (XLen != 32) |
785 | return getError(Message: "'xwchc' is only supported for 'rv32'" ); |
786 | |
787 | if (HasD) |
788 | return getIncompatibleError(Ext1: "d" , Ext2: "xwchc" ); |
789 | |
790 | if (Exts.count(x: "zcb" ) != 0) |
791 | return getIncompatibleError(Ext1: "xwchc" , Ext2: "zcb" ); |
792 | } |
793 | |
794 | if (Exts.count(x: "zclsd" ) != 0) { |
795 | if (XLen != 32) |
796 | return getError(Message: "'zclsd' is only supported for 'rv32'" ); |
797 | |
798 | if (Exts.count(x: "zcf" ) != 0) |
799 | return getIncompatibleError(Ext1: "zclsd" , Ext2: "zcf" ); |
800 | } |
801 | |
802 | if (XLen != 32 && Exts.count(x: "zilsd" ) != 0) |
803 | return getError(Message: "'zilsd' is only supported for 'rv32'" ); |
804 | |
805 | for (auto Ext : XqciExts) |
806 | if (Exts.count(x: Ext.str()) && (XLen != 32)) |
807 | return getError(Message: "'" + Twine(Ext) + "'" + " is only supported for 'rv32'" ); |
808 | |
809 | if (HasZcmp && HasXqccmp) |
810 | return getIncompatibleError(Ext1: "zcmp" , Ext2: "xqccmp" ); |
811 | |
812 | return Error::success(); |
813 | } |
814 | |
815 | struct ImpliedExtsEntry { |
816 | StringLiteral Name; |
817 | const char *ImpliedExt; |
818 | |
819 | bool operator<(const ImpliedExtsEntry &Other) const { |
820 | return Name < Other.Name; |
821 | } |
822 | }; |
823 | |
824 | static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) { |
825 | return LHS.Name < RHS; |
826 | } |
827 | |
828 | static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) { |
829 | return LHS < RHS.Name; |
830 | } |
831 | |
832 | #define GET_IMPLIED_EXTENSIONS |
833 | #include "llvm/TargetParser/RISCVTargetParserDef.inc" |
834 | |
835 | void RISCVISAInfo::updateImplication() { |
836 | bool HasE = Exts.count(x: "e" ) != 0; |
837 | bool HasI = Exts.count(x: "i" ) != 0; |
838 | |
839 | // If not in e extension and i extension does not exist, i extension is |
840 | // implied |
841 | if (!HasE && !HasI) { |
842 | auto Version = findDefaultVersion(ExtName: "i" ); |
843 | Exts["i" ] = *Version; |
844 | } |
845 | |
846 | if (HasE && HasI) |
847 | Exts.erase(x: "i" ); |
848 | |
849 | assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name" ); |
850 | |
851 | // This loop may execute over 1 iteration since implication can be layered |
852 | // Exits loop if no more implication is applied |
853 | SmallVector<StringRef, 16> WorkList; |
854 | for (auto const &Ext : Exts) |
855 | WorkList.push_back(Elt: Ext.first); |
856 | |
857 | while (!WorkList.empty()) { |
858 | StringRef ExtName = WorkList.pop_back_val(); |
859 | auto Range = std::equal_range(first: std::begin(arr: ImpliedExts), |
860 | last: std::end(arr: ImpliedExts), val: ExtName); |
861 | std::for_each(first: Range.first, last: Range.second, |
862 | f: [&](const ImpliedExtsEntry &Implied) { |
863 | const char *ImpliedExt = Implied.ImpliedExt; |
864 | auto [It, Inserted] = Exts.try_emplace(k: ImpliedExt); |
865 | if (!Inserted) |
866 | return; |
867 | auto Version = findDefaultVersion(ExtName: ImpliedExt); |
868 | It->second = *Version; |
869 | WorkList.push_back(Elt: ImpliedExt); |
870 | }); |
871 | } |
872 | |
873 | // Add Zcd if C and D are enabled. |
874 | if (Exts.count(x: "c" ) && Exts.count(x: "d" ) && !Exts.count(x: "zcd" )) { |
875 | auto Version = findDefaultVersion(ExtName: "zcd" ); |
876 | Exts["zcd" ] = *Version; |
877 | } |
878 | |
879 | // Add Zcf if C and F are enabled on RV32. |
880 | if (XLen == 32 && Exts.count(x: "c" ) && Exts.count(x: "f" ) && !Exts.count(x: "zcf" )) { |
881 | auto Version = findDefaultVersion(ExtName: "zcf" ); |
882 | Exts["zcf" ] = *Version; |
883 | } |
884 | |
885 | // Add Zcf if Zce and F are enabled on RV32. |
886 | if (XLen == 32 && Exts.count(x: "zce" ) && Exts.count(x: "f" ) && |
887 | !Exts.count(x: "zcf" )) { |
888 | auto Version = findDefaultVersion(ExtName: "zcf" ); |
889 | Exts["zcf" ] = *Version; |
890 | } |
891 | } |
892 | |
893 | static constexpr StringLiteral CombineIntoExts[] = { |
894 | {"b" }, {"zk" }, {"zkn" }, {"zks" }, {"zvkn" }, |
895 | {"zvknc" }, {"zvkng" }, {"zvks" }, {"zvksc" }, {"zvksg" }, |
896 | }; |
897 | |
898 | void RISCVISAInfo::updateCombination() { |
899 | bool MadeChange = false; |
900 | do { |
901 | MadeChange = false; |
902 | for (StringRef CombineExt : CombineIntoExts) { |
903 | if (Exts.count(x: CombineExt.str())) |
904 | continue; |
905 | |
906 | // Look up the extension in the ImpliesExt table to find everything it |
907 | // depends on. |
908 | auto Range = std::equal_range(first: std::begin(arr: ImpliedExts), |
909 | last: std::end(arr: ImpliedExts), val: CombineExt); |
910 | bool HasAllRequiredFeatures = std::all_of( |
911 | first: Range.first, last: Range.second, pred: [&](const ImpliedExtsEntry &Implied) { |
912 | return Exts.count(x: Implied.ImpliedExt); |
913 | }); |
914 | if (HasAllRequiredFeatures) { |
915 | auto Version = findDefaultVersion(ExtName: CombineExt); |
916 | Exts[CombineExt.str()] = *Version; |
917 | MadeChange = true; |
918 | } |
919 | } |
920 | } while (MadeChange); |
921 | } |
922 | |
923 | void RISCVISAInfo::updateImpliedLengths() { |
924 | assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 && |
925 | "Expected lengths to be initialied to zero" ); |
926 | |
927 | if (Exts.count(x: "q" )) |
928 | FLen = 128; |
929 | else if (Exts.count(x: "d" )) |
930 | FLen = 64; |
931 | else if (Exts.count(x: "f" )) |
932 | FLen = 32; |
933 | |
934 | if (Exts.count(x: "v" )) { |
935 | MaxELenFp = std::max(a: MaxELenFp, b: 64u); |
936 | MaxELen = std::max(a: MaxELen, b: 64u); |
937 | } |
938 | |
939 | for (auto const &Ext : Exts) { |
940 | StringRef ExtName = Ext.first; |
941 | // Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d) |
942 | if (ExtName.consume_front(Prefix: "zve" )) { |
943 | unsigned ZveELen; |
944 | if (ExtName.consumeInteger(Radix: 10, Result&: ZveELen)) |
945 | continue; |
946 | |
947 | if (ExtName == "f" ) |
948 | MaxELenFp = std::max(a: MaxELenFp, b: 32u); |
949 | else if (ExtName == "d" ) |
950 | MaxELenFp = std::max(a: MaxELenFp, b: 64u); |
951 | else if (ExtName != "x" ) |
952 | continue; |
953 | |
954 | MaxELen = std::max(a: MaxELen, b: ZveELen); |
955 | continue; |
956 | } |
957 | |
958 | // Infer MinVLen from zvl*b. |
959 | if (ExtName.consume_front(Prefix: "zvl" )) { |
960 | unsigned ZvlLen; |
961 | if (ExtName.consumeInteger(Radix: 10, Result&: ZvlLen)) |
962 | continue; |
963 | |
964 | if (ExtName != "b" ) |
965 | continue; |
966 | |
967 | MinVLen = std::max(a: MinVLen, b: ZvlLen); |
968 | continue; |
969 | } |
970 | } |
971 | } |
972 | |
973 | std::string RISCVISAInfo::toString() const { |
974 | std::string Buffer; |
975 | raw_string_ostream Arch(Buffer); |
976 | |
977 | Arch << "rv" << XLen; |
978 | |
979 | ListSeparator LS("_" ); |
980 | for (auto const &Ext : Exts) { |
981 | StringRef ExtName = Ext.first; |
982 | auto ExtInfo = Ext.second; |
983 | Arch << LS << ExtName; |
984 | Arch << ExtInfo.Major << "p" << ExtInfo.Minor; |
985 | } |
986 | |
987 | return Arch.str(); |
988 | } |
989 | |
990 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
991 | RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) { |
992 | ISAInfo->updateImplication(); |
993 | ISAInfo->updateCombination(); |
994 | ISAInfo->updateImpliedLengths(); |
995 | |
996 | if (Error Result = ISAInfo->checkDependency()) |
997 | return std::move(Result); |
998 | return std::move(ISAInfo); |
999 | } |
1000 | |
1001 | StringRef RISCVISAInfo::computeDefaultABI() const { |
1002 | if (XLen == 32) { |
1003 | if (Exts.count(x: "e" )) |
1004 | return "ilp32e" ; |
1005 | if (Exts.count(x: "d" )) |
1006 | return "ilp32d" ; |
1007 | if (Exts.count(x: "f" )) |
1008 | return "ilp32f" ; |
1009 | return "ilp32" ; |
1010 | } else if (XLen == 64) { |
1011 | if (Exts.count(x: "e" )) |
1012 | return "lp64e" ; |
1013 | if (Exts.count(x: "d" )) |
1014 | return "lp64d" ; |
1015 | if (Exts.count(x: "f" )) |
1016 | return "lp64f" ; |
1017 | return "lp64" ; |
1018 | } |
1019 | llvm_unreachable("Invalid XLEN" ); |
1020 | } |
1021 | |
1022 | bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext) { |
1023 | if (Ext.empty()) |
1024 | return false; |
1025 | |
1026 | auto Pos = findLastNonVersionCharacter(Ext) + 1; |
1027 | StringRef Name = Ext.substr(Start: 0, N: Pos); |
1028 | StringRef Vers = Ext.substr(Start: Pos); |
1029 | if (Vers.empty()) |
1030 | return false; |
1031 | |
1032 | unsigned Major, Minor, ConsumeLength; |
1033 | if (auto E = getExtensionVersion(Ext: Name, In: Vers, Major, Minor, ConsumeLength, |
1034 | EnableExperimentalExtension: true, ExperimentalExtensionVersionCheck: true)) { |
1035 | consumeError(Err: std::move(E)); |
1036 | return false; |
1037 | } |
1038 | |
1039 | return true; |
1040 | } |
1041 | |
1042 | std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) { |
1043 | if (Ext.empty()) |
1044 | return std::string(); |
1045 | |
1046 | auto Pos = findLastNonVersionCharacter(Ext) + 1; |
1047 | StringRef Name = Ext.substr(Start: 0, N: Pos); |
1048 | |
1049 | if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext)) |
1050 | return std::string(); |
1051 | |
1052 | if (!isSupportedExtension(Ext: Name)) |
1053 | return std::string(); |
1054 | |
1055 | return isExperimentalExtension(Ext: Name) ? "experimental-" + Name.str() |
1056 | : Name.str(); |
1057 | } |
1058 | |
1059 | struct RISCVExtBit { |
1060 | const StringLiteral ext; |
1061 | uint8_t groupid; |
1062 | uint8_t bitpos; |
1063 | }; |
1064 | |
1065 | struct RISCVExtensionBitmask { |
1066 | const char *Name; |
1067 | unsigned GroupID; |
1068 | unsigned BitPosition; |
1069 | }; |
1070 | |
1071 | #define GET_RISCVExtensionBitmaskTable_IMPL |
1072 | #include "llvm/TargetParser/RISCVTargetParserDef.inc" |
1073 | |
1074 | std::pair<int, int> RISCVISAInfo::getRISCVFeaturesBitsInfo(StringRef Ext) { |
1075 | // Note that this code currently accepts mixed case extension names, but |
1076 | // does not handle extension versions at all. That's probably fine because |
1077 | // there's only one extension version in the __riscv_feature_bits vector. |
1078 | for (auto E : ExtensionBitmask) |
1079 | if (Ext.equals_insensitive(RHS: E.Name)) |
1080 | return std::make_pair(x&: E.GroupID, y&: E.BitPosition); |
1081 | return std::make_pair(x: -1, y: -1); |
1082 | } |
1083 | |