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