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