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