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