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