1 //===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Support/RISCVISAInfo.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/SetVector.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Support/Errc.h"
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/raw_ostream.h"
28 struct RISCVSupportedExtension
{
30 /// Supported version.
31 RISCVISAInfo::ExtensionVersion Version
;
33 bool operator<(const RISCVSupportedExtension
&RHS
) const {
34 return StringRef(Name
) < StringRef(RHS
.Name
);
38 } // end anonymous namespace
40 static constexpr StringLiteral AllStdExts
= "mafdqlcbkjtpvnh";
42 static const char *RISCVGImplications
[] = {
43 "i", "m", "a", "f", "d", "zicsr", "zifencei"
46 // NOTE: This table should be sorted alphabetically by extension name.
47 static const RISCVSupportedExtension SupportedExtensions
[] = {
66 // vendor-defined ('X') extensions
69 {"xcvbitmanip", {1, 0}},
75 {"xsfvfnrclipxfqf", {1, 0}},
76 {"xsfvfwmaccqqq", {1, 0}},
77 {"xsfvqmaccdod", {1, 0}},
78 {"xsfvqmaccqoq", {1, 0}},
82 {"xtheadcmo", {1, 0}},
83 {"xtheadcondmov", {1, 0}},
84 {"xtheadfmemidx", {1, 0}},
85 {"xtheadmac", {1, 0}},
86 {"xtheadmemidx", {1, 0}},
87 {"xtheadmempair", {1, 0}},
88 {"xtheadsync", {1, 0}},
89 {"xtheadvdot", {1, 0}},
90 {"xventanacondops", {1, 0}},
120 {"zhinxmin", {1, 0}},
126 {"ziccamoa", {1, 0}},
133 {"zifencei", {2, 0}},
134 {"zihintntl", {1, 0}},
135 {"zihintpause", {2, 0}},
179 {"zvl1024b", {1, 0}},
181 {"zvl16384b", {1, 0}},
182 {"zvl2048b", {1, 0}},
184 {"zvl32768b", {1, 0}},
186 {"zvl4096b", {1, 0}},
189 {"zvl65536b", {1, 0}},
190 {"zvl8192b", {1, 0}},
193 // NOTE: This table should be sorted alphabetically by extension name.
194 static const RISCVSupportedExtension SupportedExperimentalExtensions
[] = {
208 {"zvfbfmin", {1, 0}},
209 {"zvfbfwma", {1, 0}},
212 static void verifyTables() {
214 static std::atomic
<bool> TableChecked(false);
215 if (!TableChecked
.load(std::memory_order_relaxed
)) {
216 assert(llvm::is_sorted(SupportedExtensions
) &&
217 "Extensions are not sorted by name");
218 assert(llvm::is_sorted(SupportedExperimentalExtensions
) &&
219 "Experimental extensions are not sorted by name");
220 TableChecked
.store(true, std::memory_order_relaxed
);
225 static void PrintExtension(StringRef Name
, StringRef Version
,
226 StringRef Description
) {
228 unsigned VersionWidth
= Description
.empty() ? 0 : 10;
229 outs() << left_justify(Name
, 20) << left_justify(Version
, VersionWidth
)
230 << Description
<< "\n";
233 void llvm::riscvExtensionsHelp(StringMap
<StringRef
> DescMap
) {
235 outs() << "All available -march extensions for RISC-V\n\n";
236 PrintExtension("Name", "Version", (DescMap
.empty() ? "" : "Description"));
238 RISCVISAInfo::OrderedExtensionMap ExtMap
;
239 for (const auto &E
: SupportedExtensions
)
240 ExtMap
[E
.Name
] = {E
.Version
.Major
, E
.Version
.Minor
};
241 for (const auto &E
: ExtMap
) {
242 std::string Version
=
243 std::to_string(E
.second
.Major
) + "." + std::to_string(E
.second
.Minor
);
244 PrintExtension(E
.first
, Version
, DescMap
[E
.first
]);
247 outs() << "\nExperimental extensions\n";
249 for (const auto &E
: SupportedExperimentalExtensions
)
250 ExtMap
[E
.Name
] = {E
.Version
.Major
, E
.Version
.Minor
};
251 for (const auto &E
: ExtMap
) {
252 std::string Version
=
253 std::to_string(E
.second
.Major
) + "." + std::to_string(E
.second
.Minor
);
254 PrintExtension(E
.first
, Version
, DescMap
["experimental-" + E
.first
]);
257 outs() << "\nUse -march to specify the target's extension.\n"
258 "For example, clang -march=rv32i_v1p0\n";
261 static bool stripExperimentalPrefix(StringRef
&Ext
) {
262 return Ext
.consume_front("experimental-");
265 // This function finds the last character that doesn't belong to a version
266 // (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
267 // consume [0-9]*p[0-9]* starting from the backward. An extension name will not
268 // end with a digit or the letter 'p', so this function will parse correctly.
269 // NOTE: This function is NOT able to take empty strings or strings that only
270 // have version numbers and no extension name. It assumes the extension name
271 // will be at least more than one character.
272 static size_t findLastNonVersionCharacter(StringRef Ext
) {
273 assert(!Ext
.empty() &&
274 "Already guarded by if-statement in ::parseArchString");
276 int Pos
= Ext
.size() - 1;
277 while (Pos
> 0 && isDigit(Ext
[Pos
]))
279 if (Pos
> 0 && Ext
[Pos
] == 'p' && isDigit(Ext
[Pos
- 1])) {
281 while (Pos
> 0 && isDigit(Ext
[Pos
]))
289 bool operator()(const RISCVSupportedExtension
&LHS
, StringRef RHS
) {
290 return StringRef(LHS
.Name
) < RHS
;
292 bool operator()(StringRef LHS
, const RISCVSupportedExtension
&RHS
) {
293 return LHS
< StringRef(RHS
.Name
);
298 static std::optional
<RISCVISAInfo::ExtensionVersion
>
299 findDefaultVersion(StringRef ExtName
) {
300 // Find default version of an extension.
301 // TODO: We might set default version based on profile or ISA spec.
302 for (auto &ExtInfo
: {ArrayRef(SupportedExtensions
),
303 ArrayRef(SupportedExperimentalExtensions
)}) {
304 auto I
= llvm::lower_bound(ExtInfo
, ExtName
, LessExtName());
306 if (I
== ExtInfo
.end() || I
->Name
!= ExtName
)
314 void RISCVISAInfo::addExtension(StringRef ExtName
,
315 RISCVISAInfo::ExtensionVersion Version
) {
316 Exts
[ExtName
.str()] = Version
;
319 static StringRef
getExtensionTypeDesc(StringRef Ext
) {
320 if (Ext
.starts_with("s"))
321 return "standard supervisor-level extension";
322 if (Ext
.starts_with("x"))
323 return "non-standard user-level extension";
324 if (Ext
.starts_with("z"))
325 return "standard user-level extension";
329 static StringRef
getExtensionType(StringRef Ext
) {
330 if (Ext
.starts_with("s"))
332 if (Ext
.starts_with("x"))
334 if (Ext
.starts_with("z"))
339 static std::optional
<RISCVISAInfo::ExtensionVersion
>
340 isExperimentalExtension(StringRef Ext
) {
342 llvm::lower_bound(SupportedExperimentalExtensions
, Ext
, LessExtName());
343 if (I
== std::end(SupportedExperimentalExtensions
) || I
->Name
!= Ext
)
349 bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext
) {
350 bool IsExperimental
= stripExperimentalPrefix(Ext
);
352 ArrayRef
<RISCVSupportedExtension
> ExtInfo
=
353 IsExperimental
? ArrayRef(SupportedExperimentalExtensions
)
354 : ArrayRef(SupportedExtensions
);
356 auto I
= llvm::lower_bound(ExtInfo
, Ext
, LessExtName());
357 return I
!= ExtInfo
.end() && I
->Name
== Ext
;
360 bool RISCVISAInfo::isSupportedExtension(StringRef Ext
) {
363 for (auto ExtInfo
: {ArrayRef(SupportedExtensions
),
364 ArrayRef(SupportedExperimentalExtensions
)}) {
365 auto I
= llvm::lower_bound(ExtInfo
, Ext
, LessExtName());
366 if (I
!= ExtInfo
.end() && I
->Name
== Ext
)
373 bool RISCVISAInfo::isSupportedExtension(StringRef Ext
, unsigned MajorVersion
,
374 unsigned MinorVersion
) {
375 for (auto ExtInfo
: {ArrayRef(SupportedExtensions
),
376 ArrayRef(SupportedExperimentalExtensions
)}) {
378 std::equal_range(ExtInfo
.begin(), ExtInfo
.end(), Ext
, LessExtName());
379 for (auto I
= Range
.first
, E
= Range
.second
; I
!= E
; ++I
)
380 if (I
->Version
.Major
== MajorVersion
&& I
->Version
.Minor
== MinorVersion
)
387 bool RISCVISAInfo::hasExtension(StringRef Ext
) const {
388 stripExperimentalPrefix(Ext
);
390 if (!isSupportedExtension(Ext
))
393 return Exts
.count(Ext
.str()) != 0;
396 // We rank extensions in the following order:
397 // -Single letter extensions in canonical order.
398 // -Unknown single letter extensions in alphabetical order.
399 // -Multi-letter extensions starting with 'z' sorted by canonical order of
400 // the second letter then sorted alphabetically.
401 // -Multi-letter extensions starting with 's' in alphabetical order.
402 // -(TODO) Multi-letter extensions starting with 'zxm' in alphabetical order.
403 // -X extensions in alphabetical order.
404 // These flags are used to indicate the category. The first 6 bits store the
405 // single letter extension rank for single letter and multi-letter extensions
406 // starting with 'z'.
408 RF_Z_EXTENSION
= 1 << 6,
409 RF_S_EXTENSION
= 1 << 7,
410 RF_X_EXTENSION
= 1 << 8,
413 // Get the rank for single-letter extension, lower value meaning higher
415 static unsigned singleLetterExtensionRank(char Ext
) {
416 assert(Ext
>= 'a' && Ext
<= 'z');
424 size_t Pos
= AllStdExts
.find(Ext
);
425 if (Pos
!= StringRef::npos
)
426 return Pos
+ 2; // Skip 'e' and 'i' from above.
428 // If we got an unknown extension letter, then give it an alphabetical
429 // order, but after all known standard extensions.
430 return 2 + AllStdExts
.size() + (Ext
- 'a');
433 // Get the rank for multi-letter extension, lower value meaning higher
434 // priority/order in canonical order.
435 static unsigned getExtensionRank(const std::string
&ExtName
) {
436 assert(ExtName
.size() >= 1);
437 switch (ExtName
[0]) {
439 return RF_S_EXTENSION
;
441 assert(ExtName
.size() >= 2);
442 // `z` extension must be sorted by canonical order of second letter.
443 // e.g. zmx has higher rank than zax.
444 return RF_Z_EXTENSION
| singleLetterExtensionRank(ExtName
[1]);
446 return RF_X_EXTENSION
;
448 assert(ExtName
.size() == 1);
449 return singleLetterExtensionRank(ExtName
[0]);
453 // Compare function for extension.
454 // Only compare the extension name, ignore version comparison.
455 bool RISCVISAInfo::compareExtension(const std::string
&LHS
,
456 const std::string
&RHS
) {
457 unsigned LHSRank
= getExtensionRank(LHS
);
458 unsigned RHSRank
= getExtensionRank(RHS
);
460 // If the ranks differ, pick the lower rank.
461 if (LHSRank
!= RHSRank
)
462 return LHSRank
< RHSRank
;
464 // If the rank is same, it must be sorted by lexicographic order.
468 std::vector
<std::string
> RISCVISAInfo::toFeatures(bool AddAllExtensions
,
469 bool IgnoreUnknown
) const {
470 std::vector
<std::string
> Features
;
471 for (const auto &[ExtName
, _
] : Exts
) {
472 // i is a base instruction set, not an extension (see
473 // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa)
474 // and is not recognized in clang -cc1
477 if (IgnoreUnknown
&& !isSupportedExtension(ExtName
))
480 if (isExperimentalExtension(ExtName
)) {
481 Features
.push_back((llvm::Twine("+experimental-") + ExtName
).str());
483 Features
.push_back((llvm::Twine("+") + ExtName
).str());
486 if (AddAllExtensions
) {
487 for (const RISCVSupportedExtension
&Ext
: SupportedExtensions
) {
488 if (Exts
.count(Ext
.Name
))
490 Features
.push_back((llvm::Twine("-") + Ext
.Name
).str());
493 for (const RISCVSupportedExtension
&Ext
: SupportedExperimentalExtensions
) {
494 if (Exts
.count(Ext
.Name
))
496 Features
.push_back((llvm::Twine("-experimental-") + Ext
.Name
).str());
502 // Extensions may have a version number, and may be separated by
503 // an underscore '_' e.g.: rv32i2_m2.
504 // Version number is divided into major and minor version numbers,
505 // separated by a 'p'. If the minor version is 0 then 'p0' can be
506 // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
507 static Error
getExtensionVersion(StringRef Ext
, StringRef In
, unsigned &Major
,
508 unsigned &Minor
, unsigned &ConsumeLength
,
509 bool EnableExperimentalExtension
,
510 bool ExperimentalExtensionVersionCheck
) {
511 StringRef MajorStr
, MinorStr
;
515 MajorStr
= In
.take_while(isDigit
);
516 In
= In
.substr(MajorStr
.size());
518 if (!MajorStr
.empty() && In
.consume_front("p")) {
519 MinorStr
= In
.take_while(isDigit
);
520 In
= In
.substr(MajorStr
.size() + MinorStr
.size() - 1);
522 // Expected 'p' to be followed by minor version number.
523 if (MinorStr
.empty()) {
524 return createStringError(
525 errc::invalid_argument
,
526 "minor version number missing after 'p' for extension '" + Ext
+ "'");
530 if (!MajorStr
.empty() && MajorStr
.getAsInteger(10, Major
))
531 return createStringError(
532 errc::invalid_argument
,
533 "Failed to parse major version number for extension '" + Ext
+ "'");
535 if (!MinorStr
.empty() && MinorStr
.getAsInteger(10, Minor
))
536 return createStringError(
537 errc::invalid_argument
,
538 "Failed to parse minor version number for extension '" + Ext
+ "'");
540 ConsumeLength
= MajorStr
.size();
542 if (!MinorStr
.empty())
543 ConsumeLength
+= MinorStr
.size() + 1 /*'p'*/;
545 // Expected multi-character extension with version number to have no
546 // subsequent characters (i.e. must either end string or be followed by
548 if (Ext
.size() > 1 && In
.size()) {
550 "multi-character extensions must be separated by underscores";
551 return createStringError(errc::invalid_argument
, Error
);
554 // If experimental extension, require use of current version number
555 if (auto ExperimentalExtension
= isExperimentalExtension(Ext
)) {
556 if (!EnableExperimentalExtension
) {
557 std::string Error
= "requires '-menable-experimental-extensions' for "
558 "experimental extension '" +
560 return createStringError(errc::invalid_argument
, Error
);
563 if (ExperimentalExtensionVersionCheck
&&
564 (MajorStr
.empty() && MinorStr
.empty())) {
566 "experimental extension requires explicit version number `" +
568 return createStringError(errc::invalid_argument
, Error
);
571 auto SupportedVers
= *ExperimentalExtension
;
572 if (ExperimentalExtensionVersionCheck
&&
573 (Major
!= SupportedVers
.Major
|| Minor
!= SupportedVers
.Minor
)) {
574 std::string Error
= "unsupported version number " + MajorStr
.str();
575 if (!MinorStr
.empty())
576 Error
+= "." + MinorStr
.str();
577 Error
+= " for experimental extension '" + Ext
.str() +
578 "' (this compiler supports " + utostr(SupportedVers
.Major
) +
579 "." + utostr(SupportedVers
.Minor
) + ")";
580 return createStringError(errc::invalid_argument
, Error
);
582 return Error::success();
585 // Exception rule for `g`, we don't have clear version scheme for that on
588 return Error::success();
590 if (MajorStr
.empty() && MinorStr
.empty()) {
591 if (auto DefaultVersion
= findDefaultVersion(Ext
)) {
592 Major
= DefaultVersion
->Major
;
593 Minor
= DefaultVersion
->Minor
;
595 // No matter found or not, return success, assume other place will
597 return Error::success();
600 if (RISCVISAInfo::isSupportedExtension(Ext
, Major
, Minor
))
601 return Error::success();
603 std::string Error
= "unsupported version number " + std::string(MajorStr
);
604 if (!MinorStr
.empty())
605 Error
+= "." + MinorStr
.str();
606 Error
+= " for extension '" + Ext
.str() + "'";
607 return createStringError(errc::invalid_argument
, Error
);
610 llvm::Expected
<std::unique_ptr
<RISCVISAInfo
>>
611 RISCVISAInfo::parseFeatures(unsigned XLen
,
612 const std::vector
<std::string
> &Features
) {
613 assert(XLen
== 32 || XLen
== 64);
614 std::unique_ptr
<RISCVISAInfo
> ISAInfo(new RISCVISAInfo(XLen
));
616 for (auto &Feature
: Features
) {
617 StringRef ExtName
= Feature
;
618 bool Experimental
= false;
619 assert(ExtName
.size() > 1 && (ExtName
[0] == '+' || ExtName
[0] == '-'));
620 bool Add
= ExtName
[0] == '+';
621 ExtName
= ExtName
.drop_front(1); // Drop '+' or '-'
622 Experimental
= stripExperimentalPrefix(ExtName
);
623 auto ExtensionInfos
= Experimental
624 ? ArrayRef(SupportedExperimentalExtensions
)
625 : ArrayRef(SupportedExtensions
);
626 auto ExtensionInfoIterator
=
627 llvm::lower_bound(ExtensionInfos
, ExtName
, LessExtName());
629 // Not all features is related to ISA extension, like `relax` or
630 // `save-restore`, skip those feature.
631 if (ExtensionInfoIterator
== ExtensionInfos
.end() ||
632 ExtensionInfoIterator
->Name
!= ExtName
)
636 ISAInfo
->addExtension(ExtName
, ExtensionInfoIterator
->Version
);
638 ISAInfo
->Exts
.erase(ExtName
.str());
641 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo
));
644 llvm::Expected
<std::unique_ptr
<RISCVISAInfo
>>
645 RISCVISAInfo::parseNormalizedArchString(StringRef Arch
) {
646 if (llvm::any_of(Arch
, isupper
)) {
647 return createStringError(errc::invalid_argument
,
648 "string must be lowercase");
650 // Must start with a valid base ISA name.
652 if (Arch
.starts_with("rv32i") || Arch
.starts_with("rv32e"))
654 else if (Arch
.starts_with("rv64i") || Arch
.starts_with("rv64e"))
657 return createStringError(errc::invalid_argument
,
658 "arch string must begin with valid base ISA");
659 std::unique_ptr
<RISCVISAInfo
> ISAInfo(new RISCVISAInfo(XLen
));
660 // Discard rv32/rv64 prefix.
661 Arch
= Arch
.substr(4);
663 // Each extension is of the form ${name}${major_version}p${minor_version}
664 // and separated by _. Split by _ and then extract the name and version
665 // information for each extension.
666 SmallVector
<StringRef
, 8> Split
;
667 Arch
.split(Split
, '_');
668 for (StringRef Ext
: Split
) {
669 StringRef Prefix
, MinorVersionStr
;
670 std::tie(Prefix
, MinorVersionStr
) = Ext
.rsplit('p');
671 if (MinorVersionStr
.empty())
672 return createStringError(errc::invalid_argument
,
673 "extension lacks version in expected format");
674 unsigned MajorVersion
, MinorVersion
;
675 if (MinorVersionStr
.getAsInteger(10, MinorVersion
))
676 return createStringError(errc::invalid_argument
,
677 "failed to parse minor version number");
679 // Split Prefix into the extension name and the major version number
680 // (the trailing digits of Prefix).
681 int TrailingDigits
= 0;
682 StringRef ExtName
= Prefix
;
683 while (!ExtName
.empty()) {
684 if (!isDigit(ExtName
.back()))
686 ExtName
= ExtName
.drop_back(1);
690 return createStringError(errc::invalid_argument
,
691 "extension lacks version in expected format");
693 StringRef MajorVersionStr
= Prefix
.take_back(TrailingDigits
);
694 if (MajorVersionStr
.getAsInteger(10, MajorVersion
))
695 return createStringError(errc::invalid_argument
,
696 "failed to parse major version number");
697 ISAInfo
->addExtension(ExtName
, {MajorVersion
, MinorVersion
});
699 ISAInfo
->updateFLen();
700 ISAInfo
->updateMinVLen();
701 ISAInfo
->updateMaxELen();
702 return std::move(ISAInfo
);
705 llvm::Expected
<std::unique_ptr
<RISCVISAInfo
>>
706 RISCVISAInfo::parseArchString(StringRef Arch
, bool EnableExperimentalExtension
,
707 bool ExperimentalExtensionVersionCheck
,
708 bool IgnoreUnknown
) {
709 // RISC-V ISA strings must be lowercase.
710 if (llvm::any_of(Arch
, isupper
)) {
711 return createStringError(errc::invalid_argument
,
712 "string must be lowercase");
715 bool HasRV64
= Arch
.starts_with("rv64");
716 // ISA string must begin with rv32 or rv64.
717 if (!(Arch
.starts_with("rv32") || HasRV64
) || (Arch
.size() < 5)) {
718 return createStringError(
719 errc::invalid_argument
,
720 "string must begin with rv32{i,e,g} or rv64{i,e,g}");
723 unsigned XLen
= HasRV64
? 64 : 32;
724 std::unique_ptr
<RISCVISAInfo
> ISAInfo(new RISCVISAInfo(XLen
));
726 // The canonical order specified in ISA manual.
727 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
728 StringRef StdExts
= AllStdExts
;
729 char Baseline
= Arch
[4];
731 // First letter should be 'e', 'i' or 'g'.
734 return createStringError(errc::invalid_argument
,
735 "first letter should be 'e', 'i' or 'g'");
740 // g expands to extensions in RISCVGImplications.
741 if (Arch
.size() > 5 && isDigit(Arch
[5]))
742 return createStringError(errc::invalid_argument
,
743 "version not supported for 'g'");
744 StdExts
= StdExts
.drop_front(4);
748 if (Arch
.back() == '_')
749 return createStringError(errc::invalid_argument
,
750 "extension name missing after separator '_'");
753 StringRef Exts
= Arch
.substr(5);
755 // Remove multi-letter standard extensions, non-standard extensions and
756 // supervisor-level extensions. They have 'z', 'x', 's' prefixes.
757 // Parse them at the end.
758 // Find the very first occurrence of 's', 'x' or 'z'.
760 size_t Pos
= Exts
.find_first_of("zsx");
761 if (Pos
!= StringRef::npos
) {
762 OtherExts
= Exts
.substr(Pos
);
763 Exts
= Exts
.substr(0, Pos
);
766 unsigned Major
, Minor
, ConsumeLength
;
767 if (Baseline
== 'g') {
768 // Versions for g are disallowed, and this was checked for previously.
771 // No matter which version is given to `g`, we always set imafd to default
772 // version since the we don't have clear version scheme for that on
774 for (const auto *Ext
: RISCVGImplications
) {
775 if (auto Version
= findDefaultVersion(Ext
))
776 ISAInfo
->addExtension(Ext
, *Version
);
778 llvm_unreachable("Default extension version not found?");
781 // Baseline is `i` or `e`
782 if (auto E
= getExtensionVersion(
783 StringRef(&Baseline
, 1), Exts
, Major
, Minor
, ConsumeLength
,
784 EnableExperimentalExtension
, ExperimentalExtensionVersionCheck
)) {
787 // If IgnoreUnknown, then ignore an unrecognised version of the baseline
788 // ISA and just use the default supported version.
789 consumeError(std::move(E
));
790 auto Version
= findDefaultVersion(StringRef(&Baseline
, 1));
791 Major
= Version
->Major
;
792 Minor
= Version
->Minor
;
795 ISAInfo
->addExtension(StringRef(&Baseline
, 1), {Major
, Minor
});
798 // Consume the base ISA version number and any '_' between rvxxx and the
800 Exts
= Exts
.drop_front(ConsumeLength
);
801 Exts
.consume_front("_");
803 auto StdExtsItr
= StdExts
.begin();
804 auto StdExtsEnd
= StdExts
.end();
805 auto GoToNextExt
= [](StringRef::iterator
&I
, unsigned ConsumeLength
,
806 StringRef::iterator E
) {
807 I
+= 1 + ConsumeLength
;
808 if (I
!= E
&& *I
== '_')
811 for (auto I
= Exts
.begin(), E
= Exts
.end(); I
!= E
;) {
814 // Check ISA extensions are specified in the canonical order.
815 while (StdExtsItr
!= StdExtsEnd
&& *StdExtsItr
!= C
)
818 if (StdExtsItr
== StdExtsEnd
) {
819 // Either c contains a valid extension but it was not given in
820 // canonical order or it is an invalid extension.
821 if (StdExts
.contains(C
)) {
822 return createStringError(
823 errc::invalid_argument
,
824 "standard user-level extension not given in canonical order '%c'",
828 return createStringError(errc::invalid_argument
,
829 "invalid standard user-level extension '%c'", C
);
832 // Move to next char to prevent repeated letter.
836 unsigned Major
, Minor
, ConsumeLength
;
837 if (std::next(I
) != E
)
838 Next
= StringRef(std::next(I
), E
- std::next(I
));
839 if (auto E
= getExtensionVersion(StringRef(&C
, 1), Next
, Major
, Minor
,
840 ConsumeLength
, EnableExperimentalExtension
,
841 ExperimentalExtensionVersionCheck
)) {
843 consumeError(std::move(E
));
844 GoToNextExt(I
, ConsumeLength
, Exts
.end());
850 // The order is OK, then push it into features.
851 // Currently LLVM supports only "mafdcvh".
852 if (!isSupportedExtension(StringRef(&C
, 1))) {
854 GoToNextExt(I
, ConsumeLength
, Exts
.end());
857 return createStringError(errc::invalid_argument
,
858 "unsupported standard user-level extension '%c'",
861 ISAInfo
->addExtension(StringRef(&C
, 1), {Major
, Minor
});
863 // Consume full extension name and version, including any optional '_'
864 // between this extension and the next
865 GoToNextExt(I
, ConsumeLength
, Exts
.end());
868 // Handle other types of extensions other than the standard
869 // general purpose and standard user-level extensions.
870 // Parse the ISA string containing non-standard user-level
871 // extensions, standard supervisor-level extensions and
872 // non-standard supervisor-level extensions.
873 // These extensions start with 'z', 's', 'x' prefixes, might have a version
874 // number (major, minor) and are separated by a single underscore '_'. We do
875 // not enforce a canonical order for them.
876 // Set the hardware features for the extensions that are supported.
878 // Multi-letter extensions are seperated by a single underscore
879 // as described in RISC-V User-Level ISA V2.2.
880 SmallVector
<StringRef
, 8> Split
;
881 OtherExts
.split(Split
, '_');
883 SmallVector
<StringRef
, 8> AllExts
;
884 if (Split
.size() > 1 || Split
[0] != "") {
885 for (StringRef Ext
: Split
) {
887 return createStringError(errc::invalid_argument
,
888 "extension name missing after separator '_'");
890 StringRef Type
= getExtensionType(Ext
);
891 StringRef Desc
= getExtensionTypeDesc(Ext
);
892 auto Pos
= findLastNonVersionCharacter(Ext
) + 1;
893 StringRef
Name(Ext
.substr(0, Pos
));
894 StringRef
Vers(Ext
.substr(Pos
));
899 return createStringError(errc::invalid_argument
,
900 "invalid extension prefix '" + Ext
+ "'");
903 if (!IgnoreUnknown
&& Name
.size() == Type
.size()) {
904 return createStringError(errc::invalid_argument
,
905 "%s name missing after '%s'",
906 Desc
.str().c_str(), Type
.str().c_str());
909 unsigned Major
, Minor
, ConsumeLength
;
910 if (auto E
= getExtensionVersion(Name
, Vers
, Major
, Minor
, ConsumeLength
,
911 EnableExperimentalExtension
,
912 ExperimentalExtensionVersionCheck
)) {
914 consumeError(std::move(E
));
920 // Check if duplicated extension.
921 if (!IgnoreUnknown
&& llvm::is_contained(AllExts
, Name
)) {
922 return createStringError(errc::invalid_argument
, "duplicated %s '%s'",
923 Desc
.str().c_str(), Name
.str().c_str());
926 if (IgnoreUnknown
&& !isSupportedExtension(Name
))
929 ISAInfo
->addExtension(Name
, {Major
, Minor
});
930 // Extension format is correct, keep parsing the extensions.
931 // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
932 AllExts
.push_back(Name
);
936 for (auto Ext
: AllExts
) {
937 if (!isSupportedExtension(Ext
)) {
938 StringRef Desc
= getExtensionTypeDesc(getExtensionType(Ext
));
939 return createStringError(errc::invalid_argument
, "unsupported %s '%s'",
940 Desc
.str().c_str(), Ext
.str().c_str());
944 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo
));
947 Error
RISCVISAInfo::checkDependency() {
948 bool HasC
= Exts
.count("c") != 0;
949 bool HasF
= Exts
.count("f") != 0;
950 bool HasZfinx
= Exts
.count("zfinx") != 0;
951 bool HasVector
= Exts
.count("zve32x") != 0;
952 bool HasZvl
= MinVLen
!= 0;
953 bool HasZcmt
= Exts
.count("zcmt") != 0;
955 if (HasF
&& HasZfinx
)
956 return createStringError(errc::invalid_argument
,
957 "'f' and 'zfinx' extensions are incompatible");
959 if (HasZvl
&& !HasVector
)
960 return createStringError(
961 errc::invalid_argument
,
962 "'zvl*b' requires 'v' or 'zve*' extension to also be specified");
964 if (Exts
.count("zvbb") && !HasVector
)
965 return createStringError(
966 errc::invalid_argument
,
967 "'zvbb' requires 'v' or 'zve*' extension to also be specified");
969 if (Exts
.count("zvbc") && !Exts
.count("zve64x"))
970 return createStringError(
971 errc::invalid_argument
,
972 "'zvbc' requires 'v' or 'zve64*' extension to also be specified");
974 if ((Exts
.count("zvkg") || Exts
.count("zvkned") || Exts
.count("zvknha") ||
975 Exts
.count("zvksed") || Exts
.count("zvksh")) &&
977 return createStringError(
978 errc::invalid_argument
,
979 "'zvk*' requires 'v' or 'zve*' extension to also be specified");
981 if (Exts
.count("zvknhb") && !Exts
.count("zve64x"))
982 return createStringError(
983 errc::invalid_argument
,
984 "'zvknhb' requires 'v' or 'zve64*' extension to also be specified");
986 if ((HasZcmt
|| Exts
.count("zcmp")) && Exts
.count("d") &&
987 (HasC
|| Exts
.count("zcd")))
988 return createStringError(
989 errc::invalid_argument
,
990 Twine("'") + (HasZcmt
? "zcmt" : "zcmp") +
991 "' extension is incompatible with '" + (HasC
? "c" : "zcd") +
992 "' extension when 'd' extension is enabled");
994 if (XLen
!= 32 && Exts
.count("zcf"))
995 return createStringError(errc::invalid_argument
,
996 "'zcf' is only supported for 'rv32'");
998 return Error::success();
1001 static const char *ImpliedExtsD
[] = {"f"};
1002 static const char *ImpliedExtsF
[] = {"zicsr"};
1003 static const char *ImpliedExtsV
[] = {"zvl128b", "zve64d"};
1004 static const char *ImpliedExtsXTHeadVdot
[] = {"v"};
1005 static const char *ImpliedExtsXSfvcp
[] = {"zve32x"};
1006 static const char *ImpliedExtsXSfvfnrclipxfqf
[] = {"zve32f"};
1007 static const char *ImpliedExtsXSfvfwmaccqqq
[] = {"zvfbfmin"};
1008 static const char *ImpliedExtsXSfvqmaccdod
[] = {"zve32x"};
1009 static const char *ImpliedExtsXSfvqmaccqoq
[] = {"zve32x"};
1010 static const char *ImpliedExtsZacas
[] = {"a"};
1011 static const char *ImpliedExtsZcb
[] = {"zca"};
1012 static const char *ImpliedExtsZcd
[] = {"d", "zca"};
1013 static const char *ImpliedExtsZce
[] = {"zcb", "zcmp", "zcmt"};
1014 static const char *ImpliedExtsZcf
[] = {"f", "zca"};
1015 static const char *ImpliedExtsZcmop
[] = {"zca"};
1016 static const char *ImpliedExtsZcmp
[] = {"zca"};
1017 static const char *ImpliedExtsZcmt
[] = {"zca", "zicsr"};
1018 static const char *ImpliedExtsZdinx
[] = {"zfinx"};
1019 static const char *ImpliedExtsZfa
[] = {"f"};
1020 static const char *ImpliedExtsZfbfmin
[] = {"f"};
1021 static const char *ImpliedExtsZfh
[] = {"zfhmin"};
1022 static const char *ImpliedExtsZfhmin
[] = {"f"};
1023 static const char *ImpliedExtsZfinx
[] = {"zicsr"};
1024 static const char *ImpliedExtsZhinx
[] = {"zhinxmin"};
1025 static const char *ImpliedExtsZhinxmin
[] = {"zfinx"};
1026 static const char *ImpliedExtsZicntr
[] = {"zicsr"};
1027 static const char *ImpliedExtsZicfiss
[] = {"zicsr", "zimop"};
1028 static const char *ImpliedExtsZihpm
[] = {"zicsr"};
1029 static const char *ImpliedExtsZk
[] = {"zkn", "zkt", "zkr"};
1030 static const char *ImpliedExtsZkn
[] = {"zbkb", "zbkc", "zbkx",
1031 "zkne", "zknd", "zknh"};
1032 static const char *ImpliedExtsZks
[] = {"zbkb", "zbkc", "zbkx", "zksed", "zksh"};
1033 static const char *ImpliedExtsZvbb
[] = {"zvkb"};
1034 static const char *ImpliedExtsZve32f
[] = {"zve32x", "f"};
1035 static const char *ImpliedExtsZve32x
[] = {"zvl32b", "zicsr"};
1036 static const char *ImpliedExtsZve64d
[] = {"zve64f", "d"};
1037 static const char *ImpliedExtsZve64f
[] = {"zve64x", "zve32f"};
1038 static const char *ImpliedExtsZve64x
[] = {"zve32x", "zvl64b"};
1039 static const char *ImpliedExtsZvfbfmin
[] = {"zve32f"};
1040 static const char *ImpliedExtsZvfbfwma
[] = {"zvfbfmin", "zfbfmin"};
1041 static const char *ImpliedExtsZvfh
[] = {"zvfhmin", "zfhmin"};
1042 static const char *ImpliedExtsZvfhmin
[] = {"zve32f"};
1043 static const char *ImpliedExtsZvkn
[] = {"zvkb", "zvkned", "zvknhb", "zvkt"};
1044 static const char *ImpliedExtsZvknc
[] = {"zvbc", "zvkn"};
1045 static const char *ImpliedExtsZvkng
[] = {"zvkg", "zvkn"};
1046 static const char *ImpliedExtsZvknhb
[] = {"zve64x"};
1047 static const char *ImpliedExtsZvks
[] = {"zvkb", "zvksed", "zvksh", "zvkt"};
1048 static const char *ImpliedExtsZvksc
[] = {"zvbc", "zvks"};
1049 static const char *ImpliedExtsZvksg
[] = {"zvkg", "zvks"};
1050 static const char *ImpliedExtsZvl1024b
[] = {"zvl512b"};
1051 static const char *ImpliedExtsZvl128b
[] = {"zvl64b"};
1052 static const char *ImpliedExtsZvl16384b
[] = {"zvl8192b"};
1053 static const char *ImpliedExtsZvl2048b
[] = {"zvl1024b"};
1054 static const char *ImpliedExtsZvl256b
[] = {"zvl128b"};
1055 static const char *ImpliedExtsZvl32768b
[] = {"zvl16384b"};
1056 static const char *ImpliedExtsZvl4096b
[] = {"zvl2048b"};
1057 static const char *ImpliedExtsZvl512b
[] = {"zvl256b"};
1058 static const char *ImpliedExtsZvl64b
[] = {"zvl32b"};
1059 static const char *ImpliedExtsZvl65536b
[] = {"zvl32768b"};
1060 static const char *ImpliedExtsZvl8192b
[] = {"zvl4096b"};
1062 struct ImpliedExtsEntry
{
1064 ArrayRef
<const char *> Exts
;
1066 bool operator<(const ImpliedExtsEntry
&Other
) const {
1067 return Name
< Other
.Name
;
1070 bool operator<(StringRef Other
) const { return Name
< Other
; }
1073 // Note: The table needs to be sorted by name.
1074 static constexpr ImpliedExtsEntry ImpliedExts
[] = {
1075 {{"d"}, {ImpliedExtsD
}},
1076 {{"f"}, {ImpliedExtsF
}},
1077 {{"v"}, {ImpliedExtsV
}},
1078 {{"xsfvcp"}, {ImpliedExtsXSfvcp
}},
1079 {{"xsfvfnrclipxfqf"}, {ImpliedExtsXSfvfnrclipxfqf
}},
1080 {{"xsfvfwmaccqqq"}, {ImpliedExtsXSfvfwmaccqqq
}},
1081 {{"xsfvqmaccdod"}, {ImpliedExtsXSfvqmaccdod
}},
1082 {{"xsfvqmaccqoq"}, {ImpliedExtsXSfvqmaccqoq
}},
1083 {{"xtheadvdot"}, {ImpliedExtsXTHeadVdot
}},
1084 {{"zacas"}, {ImpliedExtsZacas
}},
1085 {{"zcb"}, {ImpliedExtsZcb
}},
1086 {{"zcd"}, {ImpliedExtsZcd
}},
1087 {{"zce"}, {ImpliedExtsZce
}},
1088 {{"zcf"}, {ImpliedExtsZcf
}},
1089 {{"zcmop"}, {ImpliedExtsZcmop
}},
1090 {{"zcmp"}, {ImpliedExtsZcmp
}},
1091 {{"zcmt"}, {ImpliedExtsZcmt
}},
1092 {{"zdinx"}, {ImpliedExtsZdinx
}},
1093 {{"zfa"}, {ImpliedExtsZfa
}},
1094 {{"zfbfmin"}, {ImpliedExtsZfbfmin
}},
1095 {{"zfh"}, {ImpliedExtsZfh
}},
1096 {{"zfhmin"}, {ImpliedExtsZfhmin
}},
1097 {{"zfinx"}, {ImpliedExtsZfinx
}},
1098 {{"zhinx"}, {ImpliedExtsZhinx
}},
1099 {{"zhinxmin"}, {ImpliedExtsZhinxmin
}},
1100 {{"zicfiss"}, {ImpliedExtsZicfiss
}},
1101 {{"zicntr"}, {ImpliedExtsZicntr
}},
1102 {{"zihpm"}, {ImpliedExtsZihpm
}},
1103 {{"zk"}, {ImpliedExtsZk
}},
1104 {{"zkn"}, {ImpliedExtsZkn
}},
1105 {{"zks"}, {ImpliedExtsZks
}},
1106 {{"zvbb"}, {ImpliedExtsZvbb
}},
1107 {{"zve32f"}, {ImpliedExtsZve32f
}},
1108 {{"zve32x"}, {ImpliedExtsZve32x
}},
1109 {{"zve64d"}, {ImpliedExtsZve64d
}},
1110 {{"zve64f"}, {ImpliedExtsZve64f
}},
1111 {{"zve64x"}, {ImpliedExtsZve64x
}},
1112 {{"zvfbfmin"}, {ImpliedExtsZvfbfmin
}},
1113 {{"zvfbfwma"}, {ImpliedExtsZvfbfwma
}},
1114 {{"zvfh"}, {ImpliedExtsZvfh
}},
1115 {{"zvfhmin"}, {ImpliedExtsZvfhmin
}},
1116 {{"zvkn"}, {ImpliedExtsZvkn
}},
1117 {{"zvknc"}, {ImpliedExtsZvknc
}},
1118 {{"zvkng"}, {ImpliedExtsZvkng
}},
1119 {{"zvknhb"}, {ImpliedExtsZvknhb
}},
1120 {{"zvks"}, {ImpliedExtsZvks
}},
1121 {{"zvksc"}, {ImpliedExtsZvksc
}},
1122 {{"zvksg"}, {ImpliedExtsZvksg
}},
1123 {{"zvl1024b"}, {ImpliedExtsZvl1024b
}},
1124 {{"zvl128b"}, {ImpliedExtsZvl128b
}},
1125 {{"zvl16384b"}, {ImpliedExtsZvl16384b
}},
1126 {{"zvl2048b"}, {ImpliedExtsZvl2048b
}},
1127 {{"zvl256b"}, {ImpliedExtsZvl256b
}},
1128 {{"zvl32768b"}, {ImpliedExtsZvl32768b
}},
1129 {{"zvl4096b"}, {ImpliedExtsZvl4096b
}},
1130 {{"zvl512b"}, {ImpliedExtsZvl512b
}},
1131 {{"zvl64b"}, {ImpliedExtsZvl64b
}},
1132 {{"zvl65536b"}, {ImpliedExtsZvl65536b
}},
1133 {{"zvl8192b"}, {ImpliedExtsZvl8192b
}},
1136 void RISCVISAInfo::updateImplication() {
1137 bool HasE
= Exts
.count("e") != 0;
1138 bool HasI
= Exts
.count("i") != 0;
1140 // If not in e extension and i extension does not exist, i extension is
1142 if (!HasE
&& !HasI
) {
1143 auto Version
= findDefaultVersion("i");
1144 addExtension("i", Version
.value());
1147 assert(llvm::is_sorted(ImpliedExts
) && "Table not sorted by Name");
1149 // This loop may execute over 1 iteration since implication can be layered
1150 // Exits loop if no more implication is applied
1151 SmallSetVector
<StringRef
, 16> WorkList
;
1152 for (auto const &Ext
: Exts
)
1153 WorkList
.insert(Ext
.first
);
1155 while (!WorkList
.empty()) {
1156 StringRef ExtName
= WorkList
.pop_back_val();
1157 auto I
= llvm::lower_bound(ImpliedExts
, ExtName
);
1158 if (I
!= std::end(ImpliedExts
) && I
->Name
== ExtName
) {
1159 for (const char *ImpliedExt
: I
->Exts
) {
1160 if (WorkList
.count(ImpliedExt
))
1162 if (Exts
.count(ImpliedExt
))
1164 auto Version
= findDefaultVersion(ImpliedExt
);
1165 addExtension(ImpliedExt
, Version
.value());
1166 WorkList
.insert(ImpliedExt
);
1171 // Add Zcf if Zce and F are enabled on RV32.
1172 if (XLen
== 32 && Exts
.count("zce") && Exts
.count("f") &&
1173 !Exts
.count("zcf")) {
1174 auto Version
= findDefaultVersion("zcf");
1175 addExtension("zcf", Version
.value());
1179 struct CombinedExtsEntry
{
1180 StringLiteral CombineExt
;
1181 ArrayRef
<const char *> RequiredExts
;
1184 static constexpr CombinedExtsEntry CombineIntoExts
[] = {
1185 {{"zk"}, {ImpliedExtsZk
}},
1186 {{"zkn"}, {ImpliedExtsZkn
}},
1187 {{"zks"}, {ImpliedExtsZks
}},
1188 {{"zvkn"}, {ImpliedExtsZvkn
}},
1189 {{"zvknc"}, {ImpliedExtsZvknc
}},
1190 {{"zvkng"}, {ImpliedExtsZvkng
}},
1191 {{"zvks"}, {ImpliedExtsZvks
}},
1192 {{"zvksc"}, {ImpliedExtsZvksc
}},
1193 {{"zvksg"}, {ImpliedExtsZvksg
}},
1196 void RISCVISAInfo::updateCombination() {
1197 bool IsNewCombine
= false;
1199 IsNewCombine
= false;
1200 for (CombinedExtsEntry CombineIntoExt
: CombineIntoExts
) {
1201 auto CombineExt
= CombineIntoExt
.CombineExt
;
1202 auto RequiredExts
= CombineIntoExt
.RequiredExts
;
1203 if (hasExtension(CombineExt
))
1205 bool IsAllRequiredFeatureExist
= true;
1206 for (const char *Ext
: RequiredExts
)
1207 IsAllRequiredFeatureExist
&= hasExtension(Ext
);
1208 if (IsAllRequiredFeatureExist
) {
1209 auto Version
= findDefaultVersion(CombineExt
);
1210 addExtension(CombineExt
, Version
.value());
1211 IsNewCombine
= true;
1214 } while (IsNewCombine
);
1217 void RISCVISAInfo::updateFLen() {
1219 // TODO: Handle q extension.
1220 if (Exts
.count("d"))
1222 else if (Exts
.count("f"))
1226 void RISCVISAInfo::updateMinVLen() {
1227 for (auto const &Ext
: Exts
) {
1228 StringRef ExtName
= Ext
.first
;
1229 bool IsZvlExt
= ExtName
.consume_front("zvl") && ExtName
.consume_back("b");
1232 if (!ExtName
.getAsInteger(10, ZvlLen
))
1233 MinVLen
= std::max(MinVLen
, ZvlLen
);
1238 void RISCVISAInfo::updateMaxELen() {
1239 // handles EEW restriction by sub-extension zve
1240 for (auto const &Ext
: Exts
) {
1241 StringRef ExtName
= Ext
.first
;
1242 bool IsZveExt
= ExtName
.consume_front("zve");
1244 if (ExtName
.back() == 'f')
1245 MaxELenFp
= std::max(MaxELenFp
, 32u);
1246 if (ExtName
.back() == 'd')
1247 MaxELenFp
= std::max(MaxELenFp
, 64u);
1248 ExtName
= ExtName
.drop_back();
1250 ExtName
.getAsInteger(10, ZveELen
);
1251 MaxELen
= std::max(MaxELen
, ZveELen
);
1256 std::string
RISCVISAInfo::toString() const {
1258 raw_string_ostream
Arch(Buffer
);
1260 Arch
<< "rv" << XLen
;
1262 ListSeparator
LS("_");
1263 for (auto const &Ext
: Exts
) {
1264 StringRef ExtName
= Ext
.first
;
1265 auto ExtInfo
= Ext
.second
;
1266 Arch
<< LS
<< ExtName
;
1267 Arch
<< ExtInfo
.Major
<< "p" << ExtInfo
.Minor
;
1273 llvm::Expected
<std::unique_ptr
<RISCVISAInfo
>>
1274 RISCVISAInfo::postProcessAndChecking(std::unique_ptr
<RISCVISAInfo
> &&ISAInfo
) {
1275 ISAInfo
->updateImplication();
1276 ISAInfo
->updateCombination();
1277 ISAInfo
->updateFLen();
1278 ISAInfo
->updateMinVLen();
1279 ISAInfo
->updateMaxELen();
1281 if (Error Result
= ISAInfo
->checkDependency())
1282 return std::move(Result
);
1283 return std::move(ISAInfo
);
1286 StringRef
RISCVISAInfo::computeDefaultABI() const {
1288 if (hasExtension("e"))
1290 if (hasExtension("d"))
1292 if (hasExtension("f"))
1295 } else if (XLen
== 64) {
1296 if (hasExtension("e"))
1298 if (hasExtension("d"))
1300 if (hasExtension("f"))
1304 llvm_unreachable("Invalid XLEN");
1307 bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext
) {
1311 auto Pos
= findLastNonVersionCharacter(Ext
) + 1;
1312 StringRef Name
= Ext
.substr(0, Pos
);
1313 StringRef Vers
= Ext
.substr(Pos
);
1317 unsigned Major
, Minor
, ConsumeLength
;
1318 if (auto E
= getExtensionVersion(Name
, Vers
, Major
, Minor
, ConsumeLength
,
1320 consumeError(std::move(E
));
1327 std::string
RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext
) {
1329 return std::string();
1331 auto Pos
= findLastNonVersionCharacter(Ext
) + 1;
1332 StringRef Name
= Ext
.substr(0, Pos
);
1334 if (Pos
!= Ext
.size() && !isSupportedExtensionWithVersion(Ext
))
1335 return std::string();
1337 if (!isSupportedExtension(Name
))
1338 return std::string();
1340 return isExperimentalExtension(Name
) ? "experimental-" + Name
.str()