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