1 //===-- RISCVISAInfo.cpp - RISCV 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/Support/RISCVISAInfo.h"
10 #include "llvm/ADT/None.h"
11 #include "llvm/ADT/STLExtras.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"
17 
18 #include <array>
19 #include <string>
20 #include <vector>
21 
22 using namespace llvm;
23 
24 namespace {
25 /// Represents the major and version number components of a RISC-V extension
26 struct RISCVExtensionVersion {
27   unsigned Major;
28   unsigned Minor;
29 };
30 
31 struct RISCVSupportedExtension {
32   const char *Name;
33   /// Supported version.
34   RISCVExtensionVersion Version;
35 };
36 
37 } // end anonymous namespace
38 
39 static constexpr StringLiteral AllStdExts = "mafdqlcbjtpvn";
40 
41 static const RISCVSupportedExtension SupportedExtensions[] = {
42     {"i", RISCVExtensionVersion{2, 0}},
43     {"e", RISCVExtensionVersion{1, 9}},
44     {"m", RISCVExtensionVersion{2, 0}},
45     {"a", RISCVExtensionVersion{2, 0}},
46     {"f", RISCVExtensionVersion{2, 0}},
47     {"d", RISCVExtensionVersion{2, 0}},
48     {"c", RISCVExtensionVersion{2, 0}},
49 };
50 
51 static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
52     {"v", RISCVExtensionVersion{0, 10}},
53     {"zba", RISCVExtensionVersion{1, 0}},
54     {"zbb", RISCVExtensionVersion{1, 0}},
55     {"zbc", RISCVExtensionVersion{1, 0}},
56     {"zbe", RISCVExtensionVersion{0, 93}},
57     {"zbf", RISCVExtensionVersion{0, 93}},
58     {"zbm", RISCVExtensionVersion{0, 93}},
59     {"zbp", RISCVExtensionVersion{0, 93}},
60     {"zbr", RISCVExtensionVersion{0, 93}},
61     {"zbs", RISCVExtensionVersion{1, 0}},
62     {"zbt", RISCVExtensionVersion{0, 93}},
63 
64     {"zvamo", RISCVExtensionVersion{0, 10}},
65     {"zvlsseg", RISCVExtensionVersion{0, 10}},
66 
67     {"zfhmin", RISCVExtensionVersion{0, 1}},
68     {"zfh", RISCVExtensionVersion{0, 1}},
69 };
70 
71 static bool stripExperimentalPrefix(StringRef &Ext) {
72   return Ext.consume_front("experimental-");
73 }
74 
75 struct FindByName {
76   FindByName(StringRef Ext) : Ext(Ext){};
77   StringRef Ext;
78   bool operator()(const RISCVSupportedExtension &ExtInfo) {
79     return ExtInfo.Name == Ext;
80   }
81 };
82 
83 static Optional<RISCVExtensionVersion> findDefaultVersion(StringRef ExtName) {
84   // Find default version of an extension.
85   // TODO: We might set default version based on profile or ISA spec.
86   for (auto &ExtInfo : {makeArrayRef(SupportedExtensions),
87                         makeArrayRef(SupportedExperimentalExtensions)}) {
88     auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName));
89 
90     if (ExtensionInfoIterator == ExtInfo.end()) {
91       continue;
92     }
93     return ExtensionInfoIterator->Version;
94   }
95   return None;
96 }
97 
98 void RISCVISAInfo::addExtension(StringRef ExtName, unsigned MajorVersion,
99                                 unsigned MinorVersion) {
100   RISCVExtensionInfo Ext;
101   Ext.ExtName = ExtName.str();
102   Ext.MajorVersion = MajorVersion;
103   Ext.MinorVersion = MinorVersion;
104   Exts[ExtName.str()] = Ext;
105 }
106 
107 static StringRef getExtensionTypeDesc(StringRef Ext) {
108   if (Ext.startswith("sx"))
109     return "non-standard supervisor-level extension";
110   if (Ext.startswith("s"))
111     return "standard supervisor-level extension";
112   if (Ext.startswith("x"))
113     return "non-standard user-level extension";
114   if (Ext.startswith("z"))
115     return "standard user-level extension";
116   return StringRef();
117 }
118 
119 static StringRef getExtensionType(StringRef Ext) {
120   if (Ext.startswith("sx"))
121     return "sx";
122   if (Ext.startswith("s"))
123     return "s";
124   if (Ext.startswith("x"))
125     return "x";
126   if (Ext.startswith("z"))
127     return "z";
128   return StringRef();
129 }
130 
131 static Optional<RISCVExtensionVersion> isExperimentalExtension(StringRef Ext) {
132   auto ExtIterator =
133       llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext));
134   if (ExtIterator == std::end(SupportedExperimentalExtensions))
135     return None;
136 
137   return ExtIterator->Version;
138 }
139 
140 bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
141   bool IsExperimental = stripExperimentalPrefix(Ext);
142 
143   if (IsExperimental)
144     return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
145   else
146     return llvm::any_of(SupportedExtensions, FindByName(Ext));
147 }
148 
149 bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
150   return llvm::any_of(SupportedExtensions, FindByName(Ext)) ||
151          llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
152 }
153 
154 bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
155                                         unsigned MinorVersion) {
156   auto FindByNameAndVersion = [=](const RISCVSupportedExtension &ExtInfo) {
157     return ExtInfo.Name == Ext && (MajorVersion == ExtInfo.Version.Major) &&
158            (MinorVersion == ExtInfo.Version.Minor);
159   };
160   return llvm::any_of(SupportedExtensions, FindByNameAndVersion) ||
161          llvm::any_of(SupportedExperimentalExtensions, FindByNameAndVersion);
162 }
163 
164 bool RISCVISAInfo::hasExtension(StringRef Ext) const {
165   stripExperimentalPrefix(Ext);
166 
167   if (!isSupportedExtension(Ext))
168     return false;
169 
170   return Exts.count(Ext.str()) != 0;
171 }
172 
173 // Get the rank for single-letter extension, lower value meaning higher
174 // priority.
175 static int singleLetterExtensionRank(char Ext) {
176   switch (Ext) {
177   case 'i':
178     return -2;
179   case 'e':
180     return -1;
181   default:
182     break;
183   }
184 
185   size_t Pos = AllStdExts.find(Ext);
186   int Rank;
187   if (Pos == StringRef::npos)
188     // If we got an unknown extension letter, then give it an alphabetical
189     // order, but after all known standard extensions.
190     Rank = AllStdExts.size() + (Ext - 'a');
191   else
192     Rank = Pos;
193 
194   return Rank;
195 }
196 
197 // Get the rank for multi-letter extension, lower value meaning higher
198 // priority/order in canonical order.
199 static int multiLetterExtensionRank(const std::string &ExtName) {
200   assert(ExtName.length() >= 2);
201   int HighOrder;
202   int LowOrder = 0;
203   // The order between multi-char extensions: s -> h -> z -> x.
204   char ExtClass = ExtName[0];
205   switch (ExtClass) {
206   case 's':
207     HighOrder = 0;
208     break;
209   case 'h':
210     HighOrder = 1;
211     break;
212   case 'z':
213     HighOrder = 2;
214     // `z` extension must be sorted by canonical order of second letter.
215     // e.g. zmx has higher rank than zax.
216     LowOrder = singleLetterExtensionRank(ExtName[1]);
217     break;
218   case 'x':
219     HighOrder = 3;
220     break;
221   default:
222     llvm_unreachable("Unknown prefix for multi-char extension");
223     return -1;
224   }
225 
226   return (HighOrder << 8) + LowOrder;
227 }
228 
229 // Compare function for extension.
230 // Only compare the extension name, ignore version comparison.
231 bool RISCVISAInfo::compareExtension(const std::string &LHS,
232                                     const std::string &RHS) {
233   size_t LHSLen = LHS.length();
234   size_t RHSLen = RHS.length();
235   if (LHSLen == 1 && RHSLen != 1)
236     return true;
237 
238   if (LHSLen != 1 && RHSLen == 1)
239     return false;
240 
241   if (LHSLen == 1 && RHSLen == 1)
242     return singleLetterExtensionRank(LHS[0]) <
243            singleLetterExtensionRank(RHS[0]);
244 
245   // Both are multi-char ext here.
246   int LHSRank = multiLetterExtensionRank(LHS);
247   int RHSRank = multiLetterExtensionRank(RHS);
248   if (LHSRank != RHSRank)
249     return LHSRank < RHSRank;
250 
251   // If the rank is same, it must be sorted by lexicographic order.
252   return LHS < RHS;
253 }
254 
255 void RISCVISAInfo::toFeatures(
256     std::vector<StringRef> &Features,
257     std::function<StringRef(const Twine &)> StrAlloc) const {
258   for (auto &Ext : Exts) {
259     StringRef ExtName = Ext.first;
260 
261     if (ExtName == "i")
262       continue;
263 
264     if (ExtName == "zvlsseg") {
265       Features.push_back("+experimental-v");
266       Features.push_back("+experimental-zvlsseg");
267     } else if (ExtName == "zvamo") {
268       Features.push_back("+experimental-v");
269       Features.push_back("+experimental-zvlsseg");
270       Features.push_back("+experimental-zvamo");
271     } else if (isExperimentalExtension(ExtName)) {
272       Features.push_back(StrAlloc("+experimental-" + ExtName));
273     } else {
274       Features.push_back(StrAlloc("+" + ExtName));
275     }
276   }
277 }
278 
279 // Extensions may have a version number, and may be separated by
280 // an underscore '_' e.g.: rv32i2_m2.
281 // Version number is divided into major and minor version numbers,
282 // separated by a 'p'. If the minor version is 0 then 'p0' can be
283 // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
284 static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
285                                  unsigned &Minor, unsigned &ConsumeLength,
286                                  bool EnableExperimentalExtension,
287                                  bool ExperimentalExtensionVersionCheck) {
288   StringRef MajorStr, MinorStr;
289   Major = 0;
290   Minor = 0;
291   ConsumeLength = 0;
292   MajorStr = In.take_while(isDigit);
293   In = In.substr(MajorStr.size());
294 
295   if (!MajorStr.empty() && In.consume_front("p")) {
296     MinorStr = In.take_while(isDigit);
297     In = In.substr(MajorStr.size() + 1);
298 
299     // Expected 'p' to be followed by minor version number.
300     if (MinorStr.empty()) {
301       return createStringError(
302           errc::invalid_argument,
303           "minor version number missing after 'p' for extension '" + Ext + "'");
304     }
305   }
306 
307   if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
308     return createStringError(
309         errc::invalid_argument,
310         "Failed to parse major version number for extension '" + Ext + "'");
311 
312   if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
313     return createStringError(
314         errc::invalid_argument,
315         "Failed to parse minor version number for extension '" + Ext + "'");
316 
317   ConsumeLength = MajorStr.size();
318 
319   if (!MinorStr.empty())
320     ConsumeLength += MinorStr.size() + 1 /*'p'*/;
321 
322   // Expected multi-character extension with version number to have no
323   // subsequent characters (i.e. must either end string or be followed by
324   // an underscore).
325   if (Ext.size() > 1 && In.size()) {
326     std::string Error =
327         "multi-character extensions must be separated by underscores";
328     return createStringError(errc::invalid_argument, Error);
329   }
330 
331   // If experimental extension, require use of current version number number
332   if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
333     if (!EnableExperimentalExtension) {
334       std::string Error = "requires '-menable-experimental-extensions' for "
335                           "experimental extension '" +
336                           Ext.str() + "'";
337       return createStringError(errc::invalid_argument, Error);
338     }
339 
340     if (ExperimentalExtensionVersionCheck &&
341         (MajorStr.empty() && MinorStr.empty())) {
342       std::string Error =
343           "experimental extension requires explicit version number `" +
344           Ext.str() + "`";
345       return createStringError(errc::invalid_argument, Error);
346     }
347 
348     auto SupportedVers = *ExperimentalExtension;
349     if (ExperimentalExtensionVersionCheck &&
350         (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
351       std::string Error = "unsupported version number " + MajorStr.str();
352       if (!MinorStr.empty())
353         Error += "." + MinorStr.str();
354       Error += " for experimental extension '" + Ext.str() +
355                "'(this compiler supports " + utostr(SupportedVers.Major) + "." +
356                utostr(SupportedVers.Minor) + ")";
357       return createStringError(errc::invalid_argument, Error);
358     }
359     return Error::success();
360   }
361 
362   // Exception rule for `g`, we don't have clear version scheme for that on
363   // ISA spec.
364   if (Ext == "g")
365     return Error::success();
366 
367   if (MajorStr.empty() && MinorStr.empty()) {
368     if (auto DefaultVersion = findDefaultVersion(Ext)) {
369       Major = DefaultVersion->Major;
370       Minor = DefaultVersion->Minor;
371     }
372     // No matter found or not, return success, assume other place will
373     // verify.
374     return Error::success();
375   }
376 
377   if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
378     return Error::success();
379 
380   std::string Error = "unsupported version number " + std::string(MajorStr);
381   if (!MinorStr.empty())
382     Error += "." + MinorStr.str();
383   Error += " for extension '" + Ext.str() + "'";
384   return createStringError(errc::invalid_argument, Error);
385 }
386 
387 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
388 RISCVISAInfo::parseFeatures(unsigned XLen,
389                             const std::vector<std::string> &Features) {
390   assert(XLen == 32 || XLen == 64);
391   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
392 
393   bool HasE = false;
394   for (auto &Feature : Features) {
395     StringRef ExtName = Feature;
396     bool Experimental = false;
397     assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
398     bool Add = ExtName[0] == '+';
399     ExtName = ExtName.drop_front(1); // Drop '+' or '-'
400     Experimental = stripExperimentalPrefix(ExtName);
401     auto ExtensionInfos = Experimental
402                               ? makeArrayRef(SupportedExperimentalExtensions)
403                               : makeArrayRef(SupportedExtensions);
404     auto ExtensionInfoIterator =
405         llvm::find_if(ExtensionInfos, FindByName(ExtName));
406 
407     // Not all features is related to ISA extension, like `relax` or
408     // `save-restore`, skip those feature.
409     if (ExtensionInfoIterator == ExtensionInfos.end())
410       continue;
411 
412     if (Add) {
413       if (ExtName == "e") {
414         if (XLen != 32)
415           return createStringError(
416               errc::invalid_argument,
417               "standard user-level extension 'e' requires 'rv32'");
418         HasE = true;
419       }
420 
421       ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
422                             ExtensionInfoIterator->Version.Minor);
423     } else
424       ISAInfo->Exts.erase(ExtName.str());
425   }
426   if (!HasE) {
427     if (auto Version = findDefaultVersion("i"))
428       ISAInfo->addExtension("i", Version->Major, Version->Minor);
429     else
430       llvm_unreachable("Default extension version for 'i' not found?");
431   }
432 
433   ISAInfo->updateFLen();
434 
435   return std::move(ISAInfo);
436 }
437 
438 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
439 RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
440                               bool ExperimentalExtensionVersionCheck) {
441   // RISC-V ISA strings must be lowercase.
442   if (llvm::any_of(Arch, isupper)) {
443     return createStringError(errc::invalid_argument,
444                              "string must be lowercase");
445   }
446 
447   bool HasRV64 = Arch.startswith("rv64");
448   // ISA string must begin with rv32 or rv64.
449   if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
450     return createStringError(errc::invalid_argument,
451                              "string must begin with rv32{i,e,g} or rv64{i,g}");
452   }
453 
454   unsigned XLen = HasRV64 ? 64 : 32;
455   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
456 
457   // The canonical order specified in ISA manual.
458   // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
459   StringRef StdExts = AllStdExts;
460   bool HasF = false, HasD = false;
461   char Baseline = Arch[4];
462 
463   // First letter should be 'e', 'i' or 'g'.
464   switch (Baseline) {
465   default:
466     return createStringError(errc::invalid_argument,
467                              "first letter should be 'e', 'i' or 'g'");
468   case 'e': {
469     // Extension 'e' is not allowed in rv64.
470     if (HasRV64)
471       return createStringError(
472           errc::invalid_argument,
473           "standard user-level extension 'e' requires 'rv32'");
474     break;
475   }
476   case 'i':
477     break;
478   case 'g':
479     // g = imafd
480     StdExts = StdExts.drop_front(4);
481     HasF = true;
482     HasD = true;
483     break;
484   }
485 
486   // Skip rvxxx
487   StringRef Exts = Arch.substr(5);
488 
489   // Remove multi-letter standard extensions, non-standard extensions and
490   // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
491   // Parse them at the end.
492   // Find the very first occurrence of 's', 'x' or 'z'.
493   StringRef OtherExts;
494   size_t Pos = Exts.find_first_of("zsx");
495   if (Pos != StringRef::npos) {
496     OtherExts = Exts.substr(Pos);
497     Exts = Exts.substr(0, Pos);
498   }
499 
500   unsigned Major, Minor, ConsumeLength;
501   if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
502                                    ConsumeLength, EnableExperimentalExtension,
503                                    ExperimentalExtensionVersionCheck))
504     return std::move(E);
505 
506   if (Baseline == 'g') {
507     // No matter which version is given to `g`, we always set imafd to default
508     // version since the we don't have clear version scheme for that on
509     // ISA spec.
510     for (auto Ext : {"i", "m", "a", "f", "d"})
511       if (auto Version = findDefaultVersion(Ext))
512         ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
513       else
514         llvm_unreachable("Default extension version not found?");
515   } else
516     // Baseline is `i` or `e`
517     ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
518 
519   // Consume the base ISA version number and any '_' between rvxxx and the
520   // first extension
521   Exts = Exts.drop_front(ConsumeLength);
522   Exts.consume_front("_");
523 
524   // TODO: Use version number when setting target features
525 
526   auto StdExtsItr = StdExts.begin();
527   auto StdExtsEnd = StdExts.end();
528   for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
529     char C = *I;
530 
531     // Check ISA extensions are specified in the canonical order.
532     while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
533       ++StdExtsItr;
534 
535     if (StdExtsItr == StdExtsEnd) {
536       // Either c contains a valid extension but it was not given in
537       // canonical order or it is an invalid extension.
538       if (StdExts.contains(C)) {
539         return createStringError(
540             errc::invalid_argument,
541             "standard user-level extension not given in canonical order '%c'",
542             C);
543       }
544 
545       return createStringError(errc::invalid_argument,
546                                "invalid standard user-level extension '%c'", C);
547     }
548 
549     // Move to next char to prevent repeated letter.
550     ++StdExtsItr;
551 
552     std::string Next;
553     unsigned Major, Minor, ConsumeLength;
554     if (std::next(I) != E)
555       Next = std::string(std::next(I), E);
556     if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
557                                      ConsumeLength, EnableExperimentalExtension,
558                                      ExperimentalExtensionVersionCheck))
559       return std::move(E);
560 
561     // The order is OK, then push it into features.
562     // TODO: Use version number when setting target features
563     switch (C) {
564     default:
565       // Currently LLVM supports only "mafdcbv".
566       return createStringError(errc::invalid_argument,
567                                "unsupported standard user-level extension '%c'",
568                                C);
569     case 'm':
570       ISAInfo->addExtension("m", Major, Minor);
571       break;
572     case 'a':
573       ISAInfo->addExtension("a", Major, Minor);
574       break;
575     case 'f':
576       ISAInfo->addExtension("f", Major, Minor);
577       HasF = true;
578       break;
579     case 'd':
580       ISAInfo->addExtension("d", Major, Minor);
581       HasD = true;
582       break;
583     case 'c':
584       ISAInfo->addExtension("c", Major, Minor);
585       break;
586     case 'v':
587       ISAInfo->addExtension("v", Major, Minor);
588       ISAInfo->addExtension("zvlsseg", Major, Minor);
589       break;
590     }
591     // Consume full extension name and version, including any optional '_'
592     // between this extension and the next
593     ++I;
594     I += ConsumeLength;
595     if (*I == '_')
596       ++I;
597   }
598   // Dependency check.
599   // It's illegal to specify the 'd' (double-precision floating point)
600   // extension without also specifying the 'f' (single precision
601   // floating-point) extension.
602   // TODO: This has been removed in later specs, which specify that D implies F
603   if (HasD && !HasF)
604     return createStringError(errc::invalid_argument,
605                              "d requires f extension to also be specified");
606 
607   // Additional dependency checks.
608   // TODO: The 'q' extension requires rv64.
609   // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
610 
611   if (OtherExts.empty())
612     return std::move(ISAInfo);
613 
614   // Handle other types of extensions other than the standard
615   // general purpose and standard user-level extensions.
616   // Parse the ISA string containing non-standard user-level
617   // extensions, standard supervisor-level extensions and
618   // non-standard supervisor-level extensions.
619   // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
620   // canonical order, might have a version number (major, minor)
621   // and are separated by a single underscore '_'.
622   // Set the hardware features for the extensions that are supported.
623 
624   // Multi-letter extensions are seperated by a single underscore
625   // as described in RISC-V User-Level ISA V2.2.
626   SmallVector<StringRef, 8> Split;
627   OtherExts.split(Split, '_');
628 
629   SmallVector<StringRef, 8> AllExts;
630   std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
631   auto I = Prefix.begin();
632   auto E = Prefix.end();
633 
634   for (StringRef Ext : Split) {
635     if (Ext.empty())
636       return createStringError(errc::invalid_argument,
637                                "extension name missing after separator '_'");
638 
639     StringRef Type = getExtensionType(Ext);
640     StringRef Desc = getExtensionTypeDesc(Ext);
641     auto Pos = Ext.find_if(isDigit);
642     StringRef Name(Ext.substr(0, Pos));
643     StringRef Vers(Ext.substr(Pos));
644 
645     if (Type.empty())
646       return createStringError(errc::invalid_argument,
647                                "invalid extension prefix '" + Ext + "'");
648 
649     // Check ISA extensions are specified in the canonical order.
650     while (I != E && *I != Type)
651       ++I;
652 
653     if (I == E)
654       return createStringError(errc::invalid_argument,
655                                "%s not given in canonical order '%s'",
656                                Desc.str().c_str(), Ext.str().c_str());
657 
658     if (Name.size() == Type.size()) {
659       return createStringError(errc::invalid_argument,
660                                "%s name missing after '%s'", Desc.str().c_str(),
661                                Type.str().c_str());
662     }
663 
664     unsigned Major, Minor, ConsumeLength;
665     if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
666                                      EnableExperimentalExtension,
667                                      ExperimentalExtensionVersionCheck))
668       return std::move(E);
669 
670     // Check if duplicated extension.
671     if (llvm::is_contained(AllExts, Name))
672       return createStringError(errc::invalid_argument, "duplicated %s '%s'",
673                                Desc.str().c_str(), Name.str().c_str());
674 
675     ISAInfo->addExtension(Name, Major, Minor);
676     // Extension format is correct, keep parsing the extensions.
677     // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
678     AllExts.push_back(Name);
679   }
680 
681   for (auto Ext : AllExts) {
682     if (!isSupportedExtension(Ext)) {
683       StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
684       return createStringError(errc::invalid_argument, "unsupported %s '%s'",
685                                Desc.str().c_str(), Ext.str().c_str());
686     }
687   }
688 
689   ISAInfo->updateFLen();
690 
691   return std::move(ISAInfo);
692 }
693 
694 void RISCVISAInfo::updateFLen() {
695   FLen = 0;
696   // TODO: Handle q extension.
697   if (Exts.count("d"))
698     FLen = 64;
699   else if (Exts.count("f"))
700     FLen = 32;
701 }
702 
703 std::string RISCVISAInfo::toString() const {
704   std::string Buffer;
705   raw_string_ostream Arch(Buffer);
706 
707   Arch << "rv" << XLen;
708 
709   ListSeparator LS("_");
710   for (auto &Ext : Exts) {
711     StringRef ExtName = Ext.first;
712     auto ExtInfo = Ext.second;
713     Arch << LS << ExtName;
714     Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
715   }
716 
717   return Arch.str();
718 }
719