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/Option/ArgList.h"
15 #include "llvm/Support/Errc.h"
16 #include "llvm/Support/Error.h"
17 #include "llvm/Support/raw_ostream.h"
18 
19 #include <array>
20 #include <string>
21 #include <vector>
22 
23 using namespace llvm;
24 
25 namespace {
26 /// Represents the major and version number components of a RISC-V extension
27 struct RISCVExtensionVersion {
28   unsigned Major;
29   unsigned Minor;
30 };
31 
32 struct RISCVSupportedExtension {
33   const char *Name;
34   /// Supported version.
35   RISCVExtensionVersion Version;
36 };
37 
38 } // end anonymous namespace
39 
40 static constexpr StringLiteral AllStdExts = "mafdqlcbjtpvn";
41 
42 static const RISCVSupportedExtension SupportedExtensions[] = {
43     {"i", RISCVExtensionVersion{2, 0}},
44     {"e", RISCVExtensionVersion{1, 9}},
45     {"m", RISCVExtensionVersion{2, 0}},
46     {"a", RISCVExtensionVersion{2, 0}},
47     {"f", RISCVExtensionVersion{2, 0}},
48     {"d", RISCVExtensionVersion{2, 0}},
49     {"c", RISCVExtensionVersion{2, 0}},
50 };
51 
52 static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
53     {"v", RISCVExtensionVersion{0, 10}},
54     {"zba", RISCVExtensionVersion{1, 0}},
55     {"zbb", RISCVExtensionVersion{1, 0}},
56     {"zbc", RISCVExtensionVersion{1, 0}},
57     {"zbe", RISCVExtensionVersion{0, 93}},
58     {"zbf", RISCVExtensionVersion{0, 93}},
59     {"zbm", RISCVExtensionVersion{0, 93}},
60     {"zbp", RISCVExtensionVersion{0, 93}},
61     {"zbr", RISCVExtensionVersion{0, 93}},
62     {"zbs", RISCVExtensionVersion{1, 0}},
63     {"zbt", RISCVExtensionVersion{0, 93}},
64 
65     {"zvamo", RISCVExtensionVersion{0, 10}},
66     {"zvlsseg", RISCVExtensionVersion{0, 10}},
67 
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(const llvm::opt::ArgList &Args,
256                               std::vector<StringRef> &Features) const {
257   for (auto &Ext : Exts) {
258     StringRef ExtName = Ext.first;
259 
260     if (ExtName == "i")
261       continue;
262 
263     if (ExtName == "zvlsseg") {
264       Features.push_back("+experimental-v");
265       Features.push_back("+experimental-zvlsseg");
266     } else if (ExtName == "zvamo") {
267       Features.push_back("+experimental-v");
268       Features.push_back("+experimental-zvlsseg");
269       Features.push_back("+experimental-zvamo");
270     } else if (isExperimentalExtension(ExtName)) {
271       Features.push_back(Args.MakeArgString("+experimental-" + ExtName));
272     } else {
273       Features.push_back(Args.MakeArgString("+" + ExtName));
274     }
275   }
276 }
277 
278 // Extensions may have a version number, and may be separated by
279 // an underscore '_' e.g.: rv32i2_m2.
280 // Version number is divided into major and minor version numbers,
281 // separated by a 'p'. If the minor version is 0 then 'p0' can be
282 // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
283 static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
284                                  unsigned &Minor, unsigned &ConsumeLength,
285                                  bool EnableExperimentalExtension,
286                                  bool ExperimentalExtensionVersionCheck) {
287   StringRef MajorStr, MinorStr;
288   Major = 0;
289   Minor = 0;
290   ConsumeLength = 0;
291   MajorStr = In.take_while(isDigit);
292   In = In.substr(MajorStr.size());
293 
294   if (!MajorStr.empty() && In.consume_front("p")) {
295     MinorStr = In.take_while(isDigit);
296     In = In.substr(MajorStr.size() + 1);
297 
298     // Expected 'p' to be followed by minor version number.
299     if (MinorStr.empty()) {
300       return createStringError(
301           errc::invalid_argument,
302           "minor version number missing after 'p' for extension '" + Ext + "'");
303     }
304   }
305 
306   if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
307     return createStringError(
308         errc::invalid_argument,
309         "Failed to parse major version number for extension '" + Ext + "'");
310 
311   if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
312     return createStringError(
313         errc::invalid_argument,
314         "Failed to parse minor version number for extension '" + Ext + "'");
315 
316   ConsumeLength = MajorStr.size();
317 
318   if (!MinorStr.empty())
319     ConsumeLength += MinorStr.size() + 1 /*'p'*/;
320 
321   // Expected multi-character extension with version number to have no
322   // subsequent characters (i.e. must either end string or be followed by
323   // an underscore).
324   if (Ext.size() > 1 && In.size()) {
325     std::string Error =
326         "multi-character extensions must be separated by underscores";
327     return createStringError(errc::invalid_argument, Error);
328   }
329 
330   // If experimental extension, require use of current version number number
331   if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
332     if (!EnableExperimentalExtension) {
333       std::string Error = "requires '-menable-experimental-extensions' for "
334                           "experimental extension '" +
335                           Ext.str() + "'";
336       return createStringError(errc::invalid_argument, Error);
337     }
338 
339     if (ExperimentalExtensionVersionCheck &&
340         (MajorStr.empty() && MinorStr.empty())) {
341       std::string Error =
342           "experimental extension requires explicit version number `" +
343           Ext.str() + "`";
344       return createStringError(errc::invalid_argument, Error);
345     }
346 
347     auto SupportedVers = *ExperimentalExtension;
348     if (ExperimentalExtensionVersionCheck &&
349         (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
350       std::string Error = "unsupported version number " + MajorStr.str();
351       if (!MinorStr.empty())
352         Error += "." + MinorStr.str();
353       Error += " for experimental extension '" + Ext.str() +
354                "'(this compiler supports " + utostr(SupportedVers.Major) + "." +
355                utostr(SupportedVers.Minor) + ")";
356       return createStringError(errc::invalid_argument, Error);
357     }
358     return Error::success();
359   }
360 
361   // Exception rule for `g`, we don't have clear version scheme for that on
362   // ISA spec.
363   if (Ext == "g")
364     return Error::success();
365 
366   if (MajorStr.empty() && MinorStr.empty()) {
367     if (auto DefaultVersion = findDefaultVersion(Ext)) {
368       Major = DefaultVersion->Major;
369       Minor = DefaultVersion->Minor;
370     }
371     // No matter found or not, return success, assume other place will
372     // verify.
373     return Error::success();
374   }
375 
376   if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
377     return Error::success();
378 
379   std::string Error = "unsupported version number " + std::string(MajorStr);
380   if (!MinorStr.empty())
381     Error += "." + MinorStr.str();
382   Error += " for extension '" + Ext.str() + "'";
383   return createStringError(errc::invalid_argument, Error);
384 }
385 
386 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
387 RISCVISAInfo::parseFeatures(unsigned XLen,
388                             const std::vector<std::string> &Features) {
389   assert(XLen == 32 || XLen == 64);
390   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
391 
392   bool HasE = false;
393   for (auto &Feature : Features) {
394     StringRef ExtName = Feature;
395     bool Experimental = false;
396     assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
397     bool Add = ExtName[0] == '+';
398     ExtName = ExtName.drop_front(1); // Drop '+' or '-'
399     Experimental = stripExperimentalPrefix(ExtName);
400     auto ExtensionInfos = Experimental
401                               ? makeArrayRef(SupportedExperimentalExtensions)
402                               : makeArrayRef(SupportedExtensions);
403     auto ExtensionInfoIterator =
404         llvm::find_if(ExtensionInfos, FindByName(ExtName));
405 
406     // Not all features is related to ISA extension, like `relax` or
407     // `save-restore`, skip those feature.
408     if (ExtensionInfoIterator == ExtensionInfos.end())
409       continue;
410 
411     if (Add) {
412       if (ExtName == "e") {
413         if (XLen != 32)
414           return createStringError(
415               errc::invalid_argument,
416               "standard user-level extension 'e' requires 'rv32'");
417         HasE = true;
418       }
419 
420       ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
421                             ExtensionInfoIterator->Version.Minor);
422     } else
423       ISAInfo->Exts.erase(ExtName.str());
424   }
425   if (!HasE) {
426     if (auto Version = findDefaultVersion("i"))
427       ISAInfo->addExtension("i", Version->Major, Version->Minor);
428     else
429       llvm_unreachable("Default extension version for 'i' not found?");
430   }
431 
432   ISAInfo->updateFLen();
433 
434   return std::move(ISAInfo);
435 }
436 
437 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
438 RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
439                               bool ExperimentalExtensionVersionCheck) {
440   // RISC-V ISA strings must be lowercase.
441   if (llvm::any_of(Arch, isupper)) {
442     return createStringError(errc::invalid_argument,
443                              "string must be lowercase");
444   }
445 
446   bool HasRV64 = Arch.startswith("rv64");
447   // ISA string must begin with rv32 or rv64.
448   if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
449     return createStringError(errc::invalid_argument,
450                              "string must begin with rv32{i,e,g} or rv64{i,g}");
451   }
452 
453   unsigned XLen = HasRV64 ? 64 : 32;
454   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
455 
456   // The canonical order specified in ISA manual.
457   // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
458   StringRef StdExts = AllStdExts;
459   bool HasF = false, HasD = false;
460   char Baseline = Arch[4];
461 
462   // First letter should be 'e', 'i' or 'g'.
463   switch (Baseline) {
464   default:
465     return createStringError(errc::invalid_argument,
466                              "first letter should be 'e', 'i' or 'g'");
467   case 'e': {
468     // Extension 'e' is not allowed in rv64.
469     if (HasRV64)
470       return createStringError(
471           errc::invalid_argument,
472           "standard user-level extension 'e' requires 'rv32'");
473     break;
474   }
475   case 'i':
476     break;
477   case 'g':
478     // g = imafd
479     StdExts = StdExts.drop_front(4);
480     HasF = true;
481     HasD = true;
482     break;
483   }
484 
485   // Skip rvxxx
486   StringRef Exts = Arch.substr(5);
487 
488   // Remove multi-letter standard extensions, non-standard extensions and
489   // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
490   // Parse them at the end.
491   // Find the very first occurrence of 's', 'x' or 'z'.
492   StringRef OtherExts;
493   size_t Pos = Exts.find_first_of("zsx");
494   if (Pos != StringRef::npos) {
495     OtherExts = Exts.substr(Pos);
496     Exts = Exts.substr(0, Pos);
497   }
498 
499   unsigned Major, Minor, ConsumeLength;
500   if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
501                                    ConsumeLength, EnableExperimentalExtension,
502                                    ExperimentalExtensionVersionCheck))
503     return std::move(E);
504 
505   if (Baseline == 'g') {
506     // No matter which version is given to `g`, we always set imafd to default
507     // version since the we don't have clear version scheme for that on
508     // ISA spec.
509     for (auto Ext : {"i", "m", "a", "f", "d"})
510       if (auto Version = findDefaultVersion(Ext))
511         ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
512       else
513         llvm_unreachable("Default extension version not found?");
514   } else
515     // Baseline is `i` or `e`
516     ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
517 
518   // Consume the base ISA version number and any '_' between rvxxx and the
519   // first extension
520   Exts = Exts.drop_front(ConsumeLength);
521   Exts.consume_front("_");
522 
523   // TODO: Use version number when setting target features
524 
525   auto StdExtsItr = StdExts.begin();
526   auto StdExtsEnd = StdExts.end();
527   for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
528     char C = *I;
529 
530     // Check ISA extensions are specified in the canonical order.
531     while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
532       ++StdExtsItr;
533 
534     if (StdExtsItr == StdExtsEnd) {
535       // Either c contains a valid extension but it was not given in
536       // canonical order or it is an invalid extension.
537       if (StdExts.contains(C)) {
538         return createStringError(
539             errc::invalid_argument,
540             "standard user-level extension not given in canonical order '%c'",
541             C);
542       }
543 
544       return createStringError(errc::invalid_argument,
545                                "invalid standard user-level extension '%c'", C);
546     }
547 
548     // Move to next char to prevent repeated letter.
549     ++StdExtsItr;
550 
551     std::string Next;
552     unsigned Major, Minor, ConsumeLength;
553     if (std::next(I) != E)
554       Next = std::string(std::next(I), E);
555     if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
556                                      ConsumeLength, EnableExperimentalExtension,
557                                      ExperimentalExtensionVersionCheck))
558       return std::move(E);
559 
560     // The order is OK, then push it into features.
561     // TODO: Use version number when setting target features
562     switch (C) {
563     default:
564       // Currently LLVM supports only "mafdcbv".
565       return createStringError(errc::invalid_argument,
566                                "unsupported standard user-level extension '%c'",
567                                C);
568     case 'm':
569       ISAInfo->addExtension("m", Major, Minor);
570       break;
571     case 'a':
572       ISAInfo->addExtension("a", Major, Minor);
573       break;
574     case 'f':
575       ISAInfo->addExtension("f", Major, Minor);
576       HasF = true;
577       break;
578     case 'd':
579       ISAInfo->addExtension("d", Major, Minor);
580       HasD = true;
581       break;
582     case 'c':
583       ISAInfo->addExtension("c", Major, Minor);
584       break;
585     case 'v':
586       ISAInfo->addExtension("v", Major, Minor);
587       ISAInfo->addExtension("zvlsseg", Major, Minor);
588       break;
589     }
590     // Consume full extension name and version, including any optional '_'
591     // between this extension and the next
592     ++I;
593     I += ConsumeLength;
594     if (*I == '_')
595       ++I;
596   }
597   // Dependency check.
598   // It's illegal to specify the 'd' (double-precision floating point)
599   // extension without also specifying the 'f' (single precision
600   // floating-point) extension.
601   // TODO: This has been removed in later specs, which specify that D implies F
602   if (HasD && !HasF)
603     return createStringError(errc::invalid_argument,
604                              "d requires f extension to also be specified");
605 
606   // Additional dependency checks.
607   // TODO: The 'q' extension requires rv64.
608   // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
609 
610   if (OtherExts.empty())
611     return std::move(ISAInfo);
612 
613   // Handle other types of extensions other than the standard
614   // general purpose and standard user-level extensions.
615   // Parse the ISA string containing non-standard user-level
616   // extensions, standard supervisor-level extensions and
617   // non-standard supervisor-level extensions.
618   // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
619   // canonical order, might have a version number (major, minor)
620   // and are separated by a single underscore '_'.
621   // Set the hardware features for the extensions that are supported.
622 
623   // Multi-letter extensions are seperated by a single underscore
624   // as described in RISC-V User-Level ISA V2.2.
625   SmallVector<StringRef, 8> Split;
626   OtherExts.split(Split, '_');
627 
628   SmallVector<StringRef, 8> AllExts;
629   std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
630   auto I = Prefix.begin();
631   auto E = Prefix.end();
632 
633   for (StringRef Ext : Split) {
634     if (Ext.empty())
635       return createStringError(errc::invalid_argument,
636                                "extension name missing after separator '_'");
637 
638     StringRef Type = getExtensionType(Ext);
639     StringRef Desc = getExtensionTypeDesc(Ext);
640     auto Pos = Ext.find_if(isDigit);
641     StringRef Name(Ext.substr(0, Pos));
642     StringRef Vers(Ext.substr(Pos));
643 
644     if (Type.empty())
645       return createStringError(errc::invalid_argument,
646                                "invalid extension prefix '" + Ext + "'");
647 
648     // Check ISA extensions are specified in the canonical order.
649     while (I != E && *I != Type)
650       ++I;
651 
652     if (I == E)
653       return createStringError(errc::invalid_argument,
654                                "%s not given in canonical order '%s'",
655                                Desc.str().c_str(), Ext.str().c_str());
656 
657     if (Name.size() == Type.size()) {
658       return createStringError(errc::invalid_argument,
659                                "%s name missing after '%s'", Desc.str().c_str(),
660                                Type.str().c_str());
661     }
662 
663     unsigned Major, Minor, ConsumeLength;
664     if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
665                                      EnableExperimentalExtension,
666                                      ExperimentalExtensionVersionCheck))
667       return std::move(E);
668 
669     // Check if duplicated extension.
670     if (llvm::is_contained(AllExts, Name))
671       return createStringError(errc::invalid_argument, "duplicated %s '%s'",
672                                Desc.str().c_str(), Name.str().c_str());
673 
674     ISAInfo->addExtension(Name, Major, Minor);
675     // Extension format is correct, keep parsing the extensions.
676     // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
677     AllExts.push_back(Name);
678   }
679 
680   for (auto Ext : AllExts) {
681     if (!isSupportedExtension(Ext)) {
682       StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
683       return createStringError(errc::invalid_argument, "unsupported %s '%s'",
684                                Desc.str().c_str(), Ext.str().c_str());
685     }
686   }
687 
688   ISAInfo->updateFLen();
689 
690   return std::move(ISAInfo);
691 }
692 
693 void RISCVISAInfo::updateFLen() {
694   FLen = 0;
695   // TODO: Handle q extension.
696   if (Exts.count("d"))
697     FLen = 64;
698   else if (Exts.count("f"))
699     FLen = 32;
700 }
701 
702 std::string RISCVISAInfo::toString() const {
703   std::string Buffer;
704   raw_string_ostream Arch(Buffer);
705 
706   Arch << "rv" << XLen;
707 
708   ListSeparator LS("_");
709   for (auto &Ext : Exts) {
710     StringRef ExtName = Ext.first;
711     auto ExtInfo = Ext.second;
712     Arch << LS << ExtName;
713     Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
714   }
715 
716   return Arch.str();
717 }
718