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   return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
465 }
466 
467 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
468 RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
469                               bool ExperimentalExtensionVersionCheck) {
470   // RISC-V ISA strings must be lowercase.
471   if (llvm::any_of(Arch, isupper)) {
472     return createStringError(errc::invalid_argument,
473                              "string must be lowercase");
474   }
475 
476   bool HasRV64 = Arch.startswith("rv64");
477   // ISA string must begin with rv32 or rv64.
478   if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
479     return createStringError(errc::invalid_argument,
480                              "string must begin with rv32{i,e,g} or rv64{i,g}");
481   }
482 
483   unsigned XLen = HasRV64 ? 64 : 32;
484   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
485 
486   // The canonical order specified in ISA manual.
487   // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
488   StringRef StdExts = AllStdExts;
489   char Baseline = Arch[4];
490 
491   // First letter should be 'e', 'i' or 'g'.
492   switch (Baseline) {
493   default:
494     return createStringError(errc::invalid_argument,
495                              "first letter should be 'e', 'i' or 'g'");
496   case 'e': {
497     // Extension 'e' is not allowed in rv64.
498     if (HasRV64)
499       return createStringError(
500           errc::invalid_argument,
501           "standard user-level extension 'e' requires 'rv32'");
502     break;
503   }
504   case 'i':
505     break;
506   case 'g':
507     // g = imafd
508     StdExts = StdExts.drop_front(4);
509     break;
510   }
511 
512   // Skip rvxxx
513   StringRef Exts = Arch.substr(5);
514 
515   // Remove multi-letter standard extensions, non-standard extensions and
516   // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
517   // Parse them at the end.
518   // Find the very first occurrence of 's', 'x' or 'z'.
519   StringRef OtherExts;
520   size_t Pos = Exts.find_first_of("zsx");
521   if (Pos != StringRef::npos) {
522     OtherExts = Exts.substr(Pos);
523     Exts = Exts.substr(0, Pos);
524   }
525 
526   unsigned Major, Minor, ConsumeLength;
527   if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
528                                    ConsumeLength, EnableExperimentalExtension,
529                                    ExperimentalExtensionVersionCheck))
530     return std::move(E);
531 
532   if (Baseline == 'g') {
533     // No matter which version is given to `g`, we always set imafd to default
534     // version since the we don't have clear version scheme for that on
535     // ISA spec.
536     for (auto Ext : {"i", "m", "a", "f", "d"})
537       if (auto Version = findDefaultVersion(Ext))
538         ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
539       else
540         llvm_unreachable("Default extension version not found?");
541   } else
542     // Baseline is `i` or `e`
543     ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
544 
545   // Consume the base ISA version number and any '_' between rvxxx and the
546   // first extension
547   Exts = Exts.drop_front(ConsumeLength);
548   Exts.consume_front("_");
549 
550   // TODO: Use version number when setting target features
551 
552   auto StdExtsItr = StdExts.begin();
553   auto StdExtsEnd = StdExts.end();
554   for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
555     char C = *I;
556 
557     // Check ISA extensions are specified in the canonical order.
558     while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
559       ++StdExtsItr;
560 
561     if (StdExtsItr == StdExtsEnd) {
562       // Either c contains a valid extension but it was not given in
563       // canonical order or it is an invalid extension.
564       if (StdExts.contains(C)) {
565         return createStringError(
566             errc::invalid_argument,
567             "standard user-level extension not given in canonical order '%c'",
568             C);
569       }
570 
571       return createStringError(errc::invalid_argument,
572                                "invalid standard user-level extension '%c'", C);
573     }
574 
575     // Move to next char to prevent repeated letter.
576     ++StdExtsItr;
577 
578     std::string Next;
579     unsigned Major, Minor, ConsumeLength;
580     if (std::next(I) != E)
581       Next = std::string(std::next(I), E);
582     if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
583                                      ConsumeLength, EnableExperimentalExtension,
584                                      ExperimentalExtensionVersionCheck))
585       return std::move(E);
586 
587     // The order is OK, then push it into features.
588     // TODO: Use version number when setting target features
589     // Currently LLVM supports only "mafdcbv".
590     StringRef SupportedStandardExtension = "mafdcbv";
591     if (!SupportedStandardExtension.contains(C))
592       return createStringError(errc::invalid_argument,
593                                "unsupported standard user-level extension '%c'",
594                                C);
595     ISAInfo->addExtension(std::string(1, C), Major, Minor);
596 
597     // Consume full extension name and version, including any optional '_'
598     // between this extension and the next
599     ++I;
600     I += ConsumeLength;
601     if (*I == '_')
602       ++I;
603   }
604 
605   // Handle other types of extensions other than the standard
606   // general purpose and standard user-level extensions.
607   // Parse the ISA string containing non-standard user-level
608   // extensions, standard supervisor-level extensions and
609   // non-standard supervisor-level extensions.
610   // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
611   // canonical order, might have a version number (major, minor)
612   // and are separated by a single underscore '_'.
613   // Set the hardware features for the extensions that are supported.
614 
615   // Multi-letter extensions are seperated by a single underscore
616   // as described in RISC-V User-Level ISA V2.2.
617   SmallVector<StringRef, 8> Split;
618   OtherExts.split(Split, '_');
619 
620   SmallVector<StringRef, 8> AllExts;
621   std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
622   auto I = Prefix.begin();
623   auto E = Prefix.end();
624   if (Split.size() > 1 || Split[0] != "") {
625     for (StringRef Ext : Split) {
626       if (Ext.empty())
627         return createStringError(errc::invalid_argument,
628                                  "extension name missing after separator '_'");
629 
630       StringRef Type = getExtensionType(Ext);
631       StringRef Desc = getExtensionTypeDesc(Ext);
632       auto Pos = findFirstNonVersionCharacter(Ext) + 1;
633       StringRef Name(Ext.substr(0, Pos));
634       StringRef Vers(Ext.substr(Pos));
635 
636       if (Type.empty())
637         return createStringError(errc::invalid_argument,
638                                  "invalid extension prefix '" + Ext + "'");
639 
640       // Check ISA extensions are specified in the canonical order.
641       while (I != E && *I != Type)
642         ++I;
643 
644       if (I == E)
645         return createStringError(errc::invalid_argument,
646                                  "%s not given in canonical order '%s'",
647                                  Desc.str().c_str(), Ext.str().c_str());
648 
649       if (Name.size() == Type.size()) {
650         return createStringError(errc::invalid_argument,
651                                  "%s name missing after '%s'",
652                                  Desc.str().c_str(), Type.str().c_str());
653       }
654 
655       unsigned Major, Minor, ConsumeLength;
656       if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
657                                        EnableExperimentalExtension,
658                                        ExperimentalExtensionVersionCheck))
659         return std::move(E);
660 
661       // Check if duplicated extension.
662       if (llvm::is_contained(AllExts, Name))
663         return createStringError(errc::invalid_argument, "duplicated %s '%s'",
664                                  Desc.str().c_str(), Name.str().c_str());
665 
666       ISAInfo->addExtension(Name, Major, Minor);
667       // Extension format is correct, keep parsing the extensions.
668       // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
669       AllExts.push_back(Name);
670     }
671   }
672 
673   for (auto Ext : AllExts) {
674     if (!isSupportedExtension(Ext)) {
675       StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
676       return createStringError(errc::invalid_argument, "unsupported %s '%s'",
677                                Desc.str().c_str(), Ext.str().c_str());
678     }
679   }
680 
681   return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
682 }
683 
684 Error RISCVISAInfo::checkDependency() {
685   bool IsRv32 = XLen == 32;
686   bool HasE = Exts.count("e") != 0;
687   bool HasD = Exts.count("d") != 0;
688   bool HasF = Exts.count("f") != 0;
689   bool HasZve32x = Exts.count("zve32x") != 0;
690   bool HasZve32f = Exts.count("zve32f") != 0;
691   bool HasZve64d = Exts.count("zve64d") != 0;
692   bool HasV = Exts.count("v") != 0;
693   bool HasVector = HasZve32x || HasV;
694   bool HasZvl = MinVLen != 0;
695 
696   if (HasE && !IsRv32)
697     return createStringError(
698         errc::invalid_argument,
699         "standard user-level extension 'e' requires 'rv32'");
700 
701   // It's illegal to specify the 'd' (double-precision floating point)
702   // extension without also specifying the 'f' (single precision
703   // floating-point) extension.
704   // TODO: This has been removed in later specs, which specify that D implies F
705   if (HasD && !HasF)
706     return createStringError(errc::invalid_argument,
707                              "d requires f extension to also be specified");
708 
709   // FIXME: Consider Zfinx in the future
710   if (HasZve32f && !HasF)
711     return createStringError(
712         errc::invalid_argument,
713         "zve32f requires f extension to also be specified");
714 
715   // FIXME: Consider Zdinx in the future
716   if (HasZve64d && !HasD)
717     return createStringError(
718         errc::invalid_argument,
719         "zve64d requires d extension to also be specified");
720 
721   if (HasZvl && !HasVector)
722     return createStringError(
723         errc::invalid_argument,
724         "zvl*b requires v or zve* extension to also be specified");
725 
726   // Could not implement Zve* extension and the V extension at the same time.
727   if (HasZve32x && HasV)
728     return createStringError(
729         errc::invalid_argument,
730         "It is illegal to specify the v extension with zve* extensions");
731 
732   // Additional dependency checks.
733   // TODO: The 'q' extension requires rv64.
734   // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
735 
736   return Error::success();
737 }
738 
739 static const char *ImpliedExtsV[] = {"zvl128b", "f", "d"};
740 static const char *ImpliedExtsZfh[] = {"zfhmin"};
741 static const char *ImpliedExtsZve64d[] = {"zve64f"};
742 static const char *ImpliedExtsZve64f[] = {"zve64x", "zve32f"};
743 static const char *ImpliedExtsZve64x[] = {"zve32x", "zvl64b"};
744 static const char *ImpliedExtsZve32f[] = {"zve32x"};
745 static const char *ImpliedExtsZve32x[] = {"zvl32b"};
746 static const char *ImpliedExtsZvl65536b[] = {"zvl32768b"};
747 static const char *ImpliedExtsZvl32768b[] = {"zvl16384b"};
748 static const char *ImpliedExtsZvl16384b[] = {"zvl8192b"};
749 static const char *ImpliedExtsZvl8192b[] = {"zvl4096b"};
750 static const char *ImpliedExtsZvl4096b[] = {"zvl2048b"};
751 static const char *ImpliedExtsZvl2048b[] = {"zvl1024b"};
752 static const char *ImpliedExtsZvl1024b[] = {"zvl512b"};
753 static const char *ImpliedExtsZvl512b[] = {"zvl256b"};
754 static const char *ImpliedExtsZvl256b[] = {"zvl128b"};
755 static const char *ImpliedExtsZvl128b[] = {"zvl64b"};
756 static const char *ImpliedExtsZvl64b[] = {"zvl32b"};
757 static const char *ImpliedExtsZk[] = {"zkn", "zkt", "zkr"};
758 static const char *ImpliedExtsZkn[] = {"zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"};
759 static const char *ImpliedExtsZks[] = {"zbkb", "zbkc", "zbkx", "zksed", "zksh"};
760 
761 struct ImpliedExtsEntry {
762   StringLiteral Name;
763   ArrayRef<const char *> Exts;
764 
765   bool operator<(const ImpliedExtsEntry &Other) const {
766     return Name < Other.Name;
767   }
768 
769   bool operator<(StringRef Other) const { return Name < Other; }
770 };
771 
772 static constexpr ImpliedExtsEntry ImpliedExts[] = {
773     {{"v"}, {ImpliedExtsV}},
774     {{"zfh"}, {ImpliedExtsZfh}},
775     {{"zk"}, {ImpliedExtsZk}},
776     {{"zkn"}, {ImpliedExtsZkn}},
777     {{"zks"}, {ImpliedExtsZks}},
778     {{"zve32f"}, {ImpliedExtsZve32f}},
779     {{"zve32x"}, {ImpliedExtsZve32x}},
780     {{"zve64d"}, {ImpliedExtsZve64d}},
781     {{"zve64f"}, {ImpliedExtsZve64f}},
782     {{"zve64x"}, {ImpliedExtsZve64x}},
783     {{"zvl1024b"}, {ImpliedExtsZvl1024b}},
784     {{"zvl128b"}, {ImpliedExtsZvl128b}},
785     {{"zvl16384b"}, {ImpliedExtsZvl16384b}},
786     {{"zvl2048b"}, {ImpliedExtsZvl2048b}},
787     {{"zvl256b"}, {ImpliedExtsZvl256b}},
788     {{"zvl32768b"}, {ImpliedExtsZvl32768b}},
789     {{"zvl4096b"}, {ImpliedExtsZvl4096b}},
790     {{"zvl512b"}, {ImpliedExtsZvl512b}},
791     {{"zvl64b"}, {ImpliedExtsZvl64b}},
792     {{"zvl65536b"}, {ImpliedExtsZvl65536b}},
793     {{"zvl8192b"}, {ImpliedExtsZvl8192b}},
794 };
795 
796 void RISCVISAInfo::updateImplication() {
797   bool HasE = Exts.count("e") != 0;
798   bool HasI = Exts.count("i") != 0;
799 
800   // If not in e extension and i extension does not exist, i extension is
801   // implied
802   if (!HasE && !HasI) {
803     auto Version = findDefaultVersion("i");
804     addExtension("i", Version->Major, Version->Minor);
805   }
806 
807   assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
808 
809   // This loop may execute over 1 iteration since implication can be layered
810   // Exits loop if no more implication is applied
811   SmallSetVector<StringRef, 16> WorkList;
812   for (auto const &Ext : Exts)
813     WorkList.insert(Ext.first);
814 
815   while (!WorkList.empty()) {
816     StringRef ExtName = WorkList.pop_back_val();
817     auto I = llvm::lower_bound(ImpliedExts, ExtName);
818     if (I != std::end(ImpliedExts) && I->Name == ExtName) {
819       for (const char *ImpliedExt : I->Exts) {
820         if (WorkList.count(ImpliedExt))
821           continue;
822         if (Exts.count(ImpliedExt))
823           continue;
824         auto Version = findDefaultVersion(ImpliedExt);
825         addExtension(ImpliedExt, Version->Major, Version->Minor);
826         WorkList.insert(ImpliedExt);
827       }
828     }
829   }
830 }
831 
832 void RISCVISAInfo::updateFLen() {
833   FLen = 0;
834   // TODO: Handle q extension.
835   if (Exts.count("d"))
836     FLen = 64;
837   else if (Exts.count("f"))
838     FLen = 32;
839 }
840 
841 void RISCVISAInfo::updateMinVLen() {
842   for (auto const &Ext : Exts) {
843     StringRef ExtName = Ext.first;
844     bool IsZvlExt = ExtName.consume_front("zvl") && ExtName.consume_back("b");
845     if (IsZvlExt) {
846       unsigned ZvlLen;
847       if (!ExtName.getAsInteger(10, ZvlLen))
848         MinVLen = std::max(MinVLen, ZvlLen);
849     }
850   }
851 }
852 
853 void RISCVISAInfo::updateMaxELen() {
854   // handles EEW restriction by sub-extension zve
855   for (auto const &Ext : Exts) {
856     StringRef ExtName = Ext.first;
857     bool IsZveExt = ExtName.consume_front("zve");
858     if (IsZveExt) {
859       if (ExtName.back() == 'f')
860         MaxELenFp = std::max(MaxELenFp, 32u);
861       if (ExtName.back() == 'd')
862         MaxELenFp = std::max(MaxELenFp, 64u);
863       ExtName = ExtName.drop_back();
864       unsigned ZveELen;
865       ExtName.getAsInteger(10, ZveELen);
866       MaxELen = std::max(MaxELen, ZveELen);
867     }
868     if (ExtName == "v") {
869       MaxELenFp = 64;
870       MaxELen = 64;
871       return;
872     }
873   }
874 }
875 
876 std::string RISCVISAInfo::toString() const {
877   std::string Buffer;
878   raw_string_ostream Arch(Buffer);
879 
880   Arch << "rv" << XLen;
881 
882   ListSeparator LS("_");
883   for (auto const &Ext : Exts) {
884     StringRef ExtName = Ext.first;
885     auto ExtInfo = Ext.second;
886     Arch << LS << ExtName;
887     Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
888   }
889 
890   return Arch.str();
891 }
892 
893 std::vector<std::string> RISCVISAInfo::toFeatureVector() const {
894   std::vector<std::string> FeatureVector;
895   for (auto const &Ext : Exts) {
896     std::string ExtName = Ext.first;
897     if (ExtName == "i") // i is not recognized in clang -cc1
898       continue;
899     std::string Feature = isExperimentalExtension(ExtName)
900                               ? "+experimental-" + ExtName
901                               : "+" + ExtName;
902     FeatureVector.push_back(Feature);
903   }
904   return FeatureVector;
905 }
906 
907 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
908 RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
909   ISAInfo->updateImplication();
910   ISAInfo->updateFLen();
911   ISAInfo->updateMinVLen();
912   ISAInfo->updateMaxELen();
913 
914   if (Error Result = ISAInfo->checkDependency())
915     return std::move(Result);
916   return std::move(ISAInfo);
917 }
918