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