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