xref: /freebsd/contrib/llvm-project/llvm/lib/TargetParser/RISCVISAInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1  //===-- RISCVISAInfo.cpp - RISC-V 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/TargetParser/RISCVISAInfo.h"
10  #include "llvm/ADT/STLExtras.h"
11  #include "llvm/ADT/StringExtras.h"
12  #include "llvm/ADT/StringRef.h"
13  #include "llvm/Support/Errc.h"
14  #include "llvm/Support/Error.h"
15  #include "llvm/Support/raw_ostream.h"
16  
17  #include <array>
18  #include <atomic>
19  #include <optional>
20  #include <string>
21  #include <vector>
22  
23  using namespace llvm;
24  
25  namespace {
26  
27  struct RISCVSupportedExtension {
28    const char *Name;
29    /// Supported version.
30    RISCVISAUtils::ExtensionVersion Version;
31  
operator <__anond3db02a30111::RISCVSupportedExtension32    bool operator<(const RISCVSupportedExtension &RHS) const {
33      return StringRef(Name) < StringRef(RHS.Name);
34    }
35  };
36  
37  struct RISCVProfile {
38    StringLiteral Name;
39    StringLiteral MArch;
40  
operator <__anond3db02a30111::RISCVProfile41    bool operator<(const RISCVProfile &RHS) const {
42      return StringRef(Name) < StringRef(RHS.Name);
43    }
44  };
45  
46  } // end anonymous namespace
47  
48  static const char *RISCVGImplications[] = {
49    "i", "m", "a", "f", "d", "zicsr", "zifencei"
50  };
51  
52  #define GET_SUPPORTED_EXTENSIONS
53  #include "llvm/TargetParser/RISCVTargetParserDef.inc"
54  
55  #define GET_SUPPORTED_PROFILES
56  #include "llvm/TargetParser/RISCVTargetParserDef.inc"
57  
verifyTables()58  static void verifyTables() {
59  #ifndef NDEBUG
60    static std::atomic<bool> TableChecked(false);
61    if (!TableChecked.load(std::memory_order_relaxed)) {
62      assert(llvm::is_sorted(SupportedExtensions) &&
63             "Extensions are not sorted by name");
64      assert(llvm::is_sorted(SupportedExperimentalExtensions) &&
65             "Experimental extensions are not sorted by name");
66      assert(llvm::is_sorted(SupportedProfiles) &&
67             "Profiles are not sorted by name");
68      assert(llvm::is_sorted(SupportedExperimentalProfiles) &&
69             "Experimental profiles are not sorted by name");
70      TableChecked.store(true, std::memory_order_relaxed);
71    }
72  #endif
73  }
74  
PrintExtension(StringRef Name,StringRef Version,StringRef Description)75  static void PrintExtension(StringRef Name, StringRef Version,
76                             StringRef Description) {
77    outs().indent(4);
78    unsigned VersionWidth = Description.empty() ? 0 : 10;
79    outs() << left_justify(Name, 21) << left_justify(Version, VersionWidth)
80           << Description << "\n";
81  }
82  
printSupportedExtensions(StringMap<StringRef> & DescMap)83  void RISCVISAInfo::printSupportedExtensions(StringMap<StringRef> &DescMap) {
84    outs() << "All available -march extensions for RISC-V\n\n";
85    PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));
86  
87    RISCVISAUtils::OrderedExtensionMap ExtMap;
88    for (const auto &E : SupportedExtensions)
89      ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
90    for (const auto &E : ExtMap) {
91      std::string Version =
92          std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
93      PrintExtension(E.first, Version, DescMap[E.first]);
94    }
95  
96    outs() << "\nExperimental extensions\n";
97    ExtMap.clear();
98    for (const auto &E : SupportedExperimentalExtensions)
99      ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
100    for (const auto &E : ExtMap) {
101      std::string Version =
102          std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
103      PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);
104    }
105  
106    outs() << "\nSupported Profiles\n";
107    for (const auto &P : SupportedProfiles)
108      outs().indent(4) << P.Name << "\n";
109  
110    outs() << "\nExperimental Profiles\n";
111    for (const auto &P : SupportedExperimentalProfiles)
112      outs().indent(4) << P.Name << "\n";
113  
114    outs() << "\nUse -march to specify the target's extension.\n"
115              "For example, clang -march=rv32i_v1p0\n";
116  }
117  
printEnabledExtensions(bool IsRV64,std::set<StringRef> & EnabledFeatureNames,StringMap<StringRef> & DescMap)118  void RISCVISAInfo::printEnabledExtensions(
119      bool IsRV64, std::set<StringRef> &EnabledFeatureNames,
120      StringMap<StringRef> &DescMap) {
121    outs() << "Extensions enabled for the given RISC-V target\n\n";
122    PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));
123  
124    RISCVISAUtils::OrderedExtensionMap FullExtMap;
125    RISCVISAUtils::OrderedExtensionMap ExtMap;
126    for (const auto &E : SupportedExtensions)
127      if (EnabledFeatureNames.count(E.Name) != 0) {
128        FullExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
129        ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
130      }
131    for (const auto &E : ExtMap) {
132      std::string Version =
133          std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
134      PrintExtension(E.first, Version, DescMap[E.first]);
135    }
136  
137    outs() << "\nExperimental extensions\n";
138    ExtMap.clear();
139    for (const auto &E : SupportedExperimentalExtensions) {
140      StringRef Name(E.Name);
141      if (EnabledFeatureNames.count("experimental-" + Name.str()) != 0) {
142        FullExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
143        ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
144      }
145    }
146    for (const auto &E : ExtMap) {
147      std::string Version =
148          std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
149      PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);
150    }
151  
152    unsigned XLen = IsRV64 ? 64 : 32;
153    if (auto ISAString = RISCVISAInfo::createFromExtMap(XLen, FullExtMap))
154      outs() << "\nISA String: " << ISAString.get()->toString() << "\n";
155  }
156  
stripExperimentalPrefix(StringRef & Ext)157  static bool stripExperimentalPrefix(StringRef &Ext) {
158    return Ext.consume_front("experimental-");
159  }
160  
161  // This function finds the last character that doesn't belong to a version
162  // (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
163  // consume [0-9]*p[0-9]* starting from the backward. An extension name will not
164  // end with a digit or the letter 'p', so this function will parse correctly.
165  // NOTE: This function is NOT able to take empty strings or strings that only
166  // have version numbers and no extension name. It assumes the extension name
167  // will be at least more than one character.
findLastNonVersionCharacter(StringRef Ext)168  static size_t findLastNonVersionCharacter(StringRef Ext) {
169    assert(!Ext.empty() &&
170           "Already guarded by if-statement in ::parseArchString");
171  
172    int Pos = Ext.size() - 1;
173    while (Pos > 0 && isDigit(Ext[Pos]))
174      Pos--;
175    if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
176      Pos--;
177      while (Pos > 0 && isDigit(Ext[Pos]))
178        Pos--;
179    }
180    return Pos;
181  }
182  
183  namespace {
184  struct LessExtName {
operator ()__anond3db02a30211::LessExtName185    bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) {
186      return StringRef(LHS.Name) < RHS;
187    }
operator ()__anond3db02a30211::LessExtName188    bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) {
189      return LHS < StringRef(RHS.Name);
190    }
191  };
192  } // namespace
193  
194  static std::optional<RISCVISAUtils::ExtensionVersion>
findDefaultVersion(StringRef ExtName)195  findDefaultVersion(StringRef ExtName) {
196    // Find default version of an extension.
197    // TODO: We might set default version based on profile or ISA spec.
198    for (auto &ExtInfo : {ArrayRef(SupportedExtensions),
199                          ArrayRef(SupportedExperimentalExtensions)}) {
200      auto I = llvm::lower_bound(ExtInfo, ExtName, LessExtName());
201  
202      if (I == ExtInfo.end() || I->Name != ExtName)
203        continue;
204  
205      return I->Version;
206    }
207    return std::nullopt;
208  }
209  
getExtensionTypeDesc(StringRef Ext)210  static StringRef getExtensionTypeDesc(StringRef Ext) {
211    if (Ext.starts_with('s'))
212      return "standard supervisor-level extension";
213    if (Ext.starts_with('x'))
214      return "non-standard user-level extension";
215    if (Ext.starts_with('z'))
216      return "standard user-level extension";
217    return StringRef();
218  }
219  
getExtensionType(StringRef Ext)220  static StringRef getExtensionType(StringRef Ext) {
221    if (Ext.starts_with('s'))
222      return "s";
223    if (Ext.starts_with('x'))
224      return "x";
225    if (Ext.starts_with('z'))
226      return "z";
227    return StringRef();
228  }
229  
230  static std::optional<RISCVISAUtils::ExtensionVersion>
isExperimentalExtension(StringRef Ext)231  isExperimentalExtension(StringRef Ext) {
232    auto I =
233        llvm::lower_bound(SupportedExperimentalExtensions, Ext, LessExtName());
234    if (I == std::end(SupportedExperimentalExtensions) || I->Name != Ext)
235      return std::nullopt;
236  
237    return I->Version;
238  }
239  
isSupportedExtensionFeature(StringRef Ext)240  bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
241    bool IsExperimental = stripExperimentalPrefix(Ext);
242  
243    ArrayRef<RISCVSupportedExtension> ExtInfo =
244        IsExperimental ? ArrayRef(SupportedExperimentalExtensions)
245                       : ArrayRef(SupportedExtensions);
246  
247    auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
248    return I != ExtInfo.end() && I->Name == Ext;
249  }
250  
isSupportedExtension(StringRef Ext)251  bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
252    verifyTables();
253  
254    for (auto ExtInfo : {ArrayRef(SupportedExtensions),
255                         ArrayRef(SupportedExperimentalExtensions)}) {
256      auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
257      if (I != ExtInfo.end() && I->Name == Ext)
258        return true;
259    }
260  
261    return false;
262  }
263  
isSupportedExtension(StringRef Ext,unsigned MajorVersion,unsigned MinorVersion)264  bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
265                                          unsigned MinorVersion) {
266    for (auto ExtInfo : {ArrayRef(SupportedExtensions),
267                         ArrayRef(SupportedExperimentalExtensions)}) {
268      auto Range =
269          std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, LessExtName());
270      for (auto I = Range.first, E = Range.second; I != E; ++I)
271        if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion)
272          return true;
273    }
274  
275    return false;
276  }
277  
hasExtension(StringRef Ext) const278  bool RISCVISAInfo::hasExtension(StringRef Ext) const {
279    stripExperimentalPrefix(Ext);
280  
281    if (!isSupportedExtension(Ext))
282      return false;
283  
284    return Exts.count(Ext.str()) != 0;
285  }
286  
toFeatures(bool AddAllExtensions,bool IgnoreUnknown) const287  std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions,
288                                                    bool IgnoreUnknown) const {
289    std::vector<std::string> Features;
290    for (const auto &[ExtName, _] : Exts) {
291      // i is a base instruction set, not an extension (see
292      // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa)
293      // and is not recognized in clang -cc1
294      if (ExtName == "i")
295        continue;
296      if (IgnoreUnknown && !isSupportedExtension(ExtName))
297        continue;
298  
299      if (isExperimentalExtension(ExtName)) {
300        Features.push_back((llvm::Twine("+experimental-") + ExtName).str());
301      } else {
302        Features.push_back((llvm::Twine("+") + ExtName).str());
303      }
304    }
305    if (AddAllExtensions) {
306      for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
307        if (Exts.count(Ext.Name))
308          continue;
309        Features.push_back((llvm::Twine("-") + Ext.Name).str());
310      }
311  
312      for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
313        if (Exts.count(Ext.Name))
314          continue;
315        Features.push_back((llvm::Twine("-experimental-") + Ext.Name).str());
316      }
317    }
318    return Features;
319  }
320  
getError(const Twine & Message)321  static Error getError(const Twine &Message) {
322    return createStringError(errc::invalid_argument, Message);
323  }
324  
getErrorForInvalidExt(StringRef ExtName)325  static Error getErrorForInvalidExt(StringRef ExtName) {
326    if (ExtName.size() == 1) {
327      return getError("unsupported standard user-level extension '" + ExtName +
328                      "'");
329    }
330    return getError("unsupported " + getExtensionTypeDesc(ExtName) + " '" +
331                    ExtName + "'");
332  }
333  
334  // Extensions may have a version number, and may be separated by
335  // an underscore '_' e.g.: rv32i2_m2.
336  // Version number is divided into major and minor version numbers,
337  // separated by a 'p'. If the minor version is 0 then 'p0' can be
338  // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
getExtensionVersion(StringRef Ext,StringRef In,unsigned & Major,unsigned & Minor,unsigned & ConsumeLength,bool EnableExperimentalExtension,bool ExperimentalExtensionVersionCheck)339  static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
340                                   unsigned &Minor, unsigned &ConsumeLength,
341                                   bool EnableExperimentalExtension,
342                                   bool ExperimentalExtensionVersionCheck) {
343    StringRef MajorStr, MinorStr;
344    Major = 0;
345    Minor = 0;
346    ConsumeLength = 0;
347    MajorStr = In.take_while(isDigit);
348    In = In.substr(MajorStr.size());
349  
350    if (!MajorStr.empty() && In.consume_front("p")) {
351      MinorStr = In.take_while(isDigit);
352      In = In.substr(MajorStr.size() + MinorStr.size() - 1);
353  
354      // Expected 'p' to be followed by minor version number.
355      if (MinorStr.empty()) {
356        return getError("minor version number missing after 'p' for extension '" +
357                        Ext + "'");
358      }
359    }
360  
361    if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
362      return getError("Failed to parse major version number for extension '" +
363                      Ext + "'");
364  
365    if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
366      return getError("Failed to parse minor version number for extension '" +
367                      Ext + "'");
368  
369    ConsumeLength = MajorStr.size();
370  
371    if (!MinorStr.empty())
372      ConsumeLength += MinorStr.size() + 1 /*'p'*/;
373  
374    // Expected multi-character extension with version number to have no
375    // subsequent characters (i.e. must either end string or be followed by
376    // an underscore).
377    if (Ext.size() > 1 && In.size())
378      return getError(
379          "multi-character extensions must be separated by underscores");
380  
381    // If experimental extension, require use of current version number
382    if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
383      if (!EnableExperimentalExtension)
384        return getError("requires '-menable-experimental-extensions' "
385                        "for experimental extension '" +
386                        Ext + "'");
387  
388      if (ExperimentalExtensionVersionCheck &&
389          (MajorStr.empty() && MinorStr.empty()))
390        return getError(
391            "experimental extension requires explicit version number `" + Ext +
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 getError(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    if (!RISCVISAInfo::isSupportedExtension(Ext))
427      return getErrorForInvalidExt(Ext);
428  
429    std::string Error = "unsupported version number " + MajorStr.str();
430    if (!MinorStr.empty())
431      Error += "." + MinorStr.str();
432    Error += " for extension '" + Ext.str() + "'";
433    return getError(Error);
434  }
435  
436  llvm::Expected<std::unique_ptr<RISCVISAInfo>>
createFromExtMap(unsigned XLen,const RISCVISAUtils::OrderedExtensionMap & Exts)437  RISCVISAInfo::createFromExtMap(unsigned XLen,
438                                 const RISCVISAUtils::OrderedExtensionMap &Exts) {
439    assert(XLen == 32 || XLen == 64);
440    std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
441  
442    ISAInfo->Exts = Exts;
443  
444    return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
445  }
446  
447  llvm::Expected<std::unique_ptr<RISCVISAInfo>>
parseFeatures(unsigned XLen,const std::vector<std::string> & Features)448  RISCVISAInfo::parseFeatures(unsigned XLen,
449                              const std::vector<std::string> &Features) {
450    assert(XLen == 32 || XLen == 64);
451    std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
452  
453    for (auto &Feature : Features) {
454      StringRef ExtName = Feature;
455      assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
456      bool Add = ExtName[0] == '+';
457      ExtName = ExtName.drop_front(1); // Drop '+' or '-'
458      bool Experimental = stripExperimentalPrefix(ExtName);
459      auto ExtensionInfos = Experimental
460                                ? ArrayRef(SupportedExperimentalExtensions)
461                                : ArrayRef(SupportedExtensions);
462      auto ExtensionInfoIterator =
463          llvm::lower_bound(ExtensionInfos, ExtName, LessExtName());
464  
465      // Not all features is related to ISA extension, like `relax` or
466      // `save-restore`, skip those feature.
467      if (ExtensionInfoIterator == ExtensionInfos.end() ||
468          ExtensionInfoIterator->Name != ExtName)
469        continue;
470  
471      if (Add)
472        ISAInfo->Exts[ExtName.str()] = ExtensionInfoIterator->Version;
473      else
474        ISAInfo->Exts.erase(ExtName.str());
475    }
476  
477    return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
478  }
479  
480  llvm::Expected<std::unique_ptr<RISCVISAInfo>>
parseNormalizedArchString(StringRef Arch)481  RISCVISAInfo::parseNormalizedArchString(StringRef Arch) {
482    // RISC-V ISA strings must be [a-z0-9_]
483    if (!llvm::all_of(
484            Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; }))
485      return getError("string may only contain [a-z0-9_]");
486  
487    // Must start with a valid base ISA name.
488    unsigned XLen = 0;
489    if (Arch.consume_front("rv32"))
490      XLen = 32;
491    else if (Arch.consume_front("rv64"))
492      XLen = 64;
493  
494    if (XLen == 0 || Arch.empty() || (Arch[0] != 'i' && Arch[0] != 'e'))
495      return getError("arch string must begin with valid base ISA");
496  
497    std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
498  
499    // Each extension is of the form ${name}${major_version}p${minor_version}
500    // and separated by _. Split by _ and then extract the name and version
501    // information for each extension.
502    while (!Arch.empty()) {
503      if (Arch[0] == '_') {
504        if (Arch.size() == 1 || Arch[1] == '_')
505          return getError("extension name missing after separator '_'");
506        Arch = Arch.drop_front();
507      }
508  
509      size_t Idx = Arch.find('_');
510      StringRef Ext = Arch.slice(0, Idx);
511      Arch = Arch.slice(Idx, StringRef::npos);
512  
513      StringRef Prefix, MinorVersionStr;
514      std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');
515      if (MinorVersionStr.empty())
516        return getError("extension lacks version in expected format");
517      unsigned MajorVersion, MinorVersion;
518      if (MinorVersionStr.getAsInteger(10, MinorVersion))
519        return getError("failed to parse minor version number");
520  
521      // Split Prefix into the extension name and the major version number
522      // (the trailing digits of Prefix).
523      size_t VersionStart = Prefix.size();
524      while (VersionStart != 0) {
525        if (!isDigit(Prefix[VersionStart - 1]))
526          break;
527        --VersionStart;
528      }
529      if (VersionStart == Prefix.size())
530        return getError("extension lacks version in expected format");
531  
532      if (VersionStart == 0)
533        return getError("missing extension name");
534  
535      StringRef ExtName = Prefix.slice(0, VersionStart);
536      StringRef MajorVersionStr = Prefix.slice(VersionStart, StringRef::npos);
537      if (MajorVersionStr.getAsInteger(10, MajorVersion))
538        return getError("failed to parse major version number");
539  
540      if ((ExtName[0] == 'z' || ExtName[0] == 's' || ExtName[0] == 'x') &&
541          (ExtName.size() == 1 || isDigit(ExtName[1])))
542        return getError("'" + Twine(ExtName[0]) +
543                        "' must be followed by a letter");
544  
545      if (!ISAInfo->Exts
546               .emplace(
547                   ExtName.str(),
548                   RISCVISAUtils::ExtensionVersion{MajorVersion, MinorVersion})
549               .second)
550        return getError("duplicate extension '" + ExtName + "'");
551    }
552    ISAInfo->updateImpliedLengths();
553    return std::move(ISAInfo);
554  }
555  
556  llvm::Expected<std::unique_ptr<RISCVISAInfo>>
parseArchString(StringRef Arch,bool EnableExperimentalExtension,bool ExperimentalExtensionVersionCheck)557  RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
558                                bool ExperimentalExtensionVersionCheck) {
559    // RISC-V ISA strings must be [a-z0-9_]
560    if (!llvm::all_of(
561            Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; }))
562      return getError("string may only contain [a-z0-9_]");
563  
564    // ISA string must begin with rv32, rv64, or a profile.
565    unsigned XLen = 0;
566    if (Arch.consume_front("rv32")) {
567      XLen = 32;
568    } else if (Arch.consume_front("rv64")) {
569      XLen = 64;
570    } else {
571      // Try parsing as a profile.
572      auto ProfileCmp = [](StringRef Arch, const RISCVProfile &Profile) {
573        return Arch < Profile.Name;
574      };
575      auto I = llvm::upper_bound(SupportedProfiles, Arch, ProfileCmp);
576      bool FoundProfile = I != std::begin(SupportedProfiles) &&
577                          Arch.starts_with(std::prev(I)->Name);
578      if (!FoundProfile) {
579        I = llvm::upper_bound(SupportedExperimentalProfiles, Arch, ProfileCmp);
580        FoundProfile = (I != std::begin(SupportedExperimentalProfiles) &&
581                        Arch.starts_with(std::prev(I)->Name));
582        if (FoundProfile && !EnableExperimentalExtension) {
583          return getError("requires '-menable-experimental-extensions' "
584                          "for profile '" +
585                          std::prev(I)->Name + "'");
586        }
587      }
588      if (FoundProfile) {
589        --I;
590        std::string NewArch = I->MArch.str();
591        StringRef ArchWithoutProfile = Arch.drop_front(I->Name.size());
592        if (!ArchWithoutProfile.empty()) {
593          if (ArchWithoutProfile.front() != '_')
594            return getError("additional extensions must be after separator '_'");
595          NewArch += ArchWithoutProfile.str();
596        }
597        return parseArchString(NewArch, EnableExperimentalExtension,
598                               ExperimentalExtensionVersionCheck);
599      }
600    }
601  
602    if (XLen == 0 || Arch.empty())
603      return getError(
604          "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
605          "profile name");
606  
607    std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
608  
609    // The canonical order specified in ISA manual.
610    // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
611    char Baseline = Arch.front();
612    // Skip the baseline.
613    Arch = Arch.drop_front();
614  
615    unsigned Major, Minor, ConsumeLength;
616  
617    // First letter should be 'e', 'i' or 'g'.
618    switch (Baseline) {
619    default:
620      return getError("first letter after \'rv" + Twine(XLen) +
621                      "\' should be 'e', 'i' or 'g'");
622    case 'e':
623    case 'i':
624      // Baseline is `i` or `e`
625      if (auto E = getExtensionVersion(
626              StringRef(&Baseline, 1), Arch, Major, Minor, ConsumeLength,
627              EnableExperimentalExtension, ExperimentalExtensionVersionCheck))
628        return std::move(E);
629  
630      ISAInfo->Exts[std::string(1, Baseline)] = {Major, Minor};
631      break;
632    case 'g':
633      // g expands to extensions in RISCVGImplications.
634      if (!Arch.empty() && isDigit(Arch.front()))
635        return getError("version not supported for 'g'");
636  
637      // Versions for g are disallowed, and this was checked for previously.
638      ConsumeLength = 0;
639  
640      // No matter which version is given to `g`, we always set imafd to default
641      // version since the we don't have clear version scheme for that on
642      // ISA spec.
643      for (const char *Ext : RISCVGImplications) {
644        auto Version = findDefaultVersion(Ext);
645        assert(Version && "Default extension version not found?");
646        // Postpone AddExtension until end of this function
647        ISAInfo->Exts[std::string(Ext)] = {Version->Major, Version->Minor};
648      }
649      break;
650    }
651  
652    // Consume the base ISA version number and any '_' between rvxxx and the
653    // first extension
654    Arch = Arch.drop_front(ConsumeLength);
655  
656    while (!Arch.empty()) {
657      if (Arch.front() == '_') {
658        if (Arch.size() == 1 || Arch[1] == '_')
659          return getError("extension name missing after separator '_'");
660        Arch = Arch.drop_front();
661      }
662  
663      size_t Idx = Arch.find('_');
664      StringRef Ext = Arch.slice(0, Idx);
665      Arch = Arch.slice(Idx, StringRef::npos);
666  
667      do {
668        StringRef Name, Vers, Desc;
669        if (RISCVISAUtils::AllStdExts.contains(Ext.front())) {
670          Name = Ext.take_front(1);
671          Ext = Ext.drop_front();
672          Vers = Ext;
673          Desc = "standard user-level extension";
674        } else if (Ext.front() == 'z' || Ext.front() == 's' ||
675                   Ext.front() == 'x') {
676          // Handle other types of extensions other than the standard
677          // general purpose and standard user-level extensions.
678          // Parse the ISA string containing non-standard user-level
679          // extensions, standard supervisor-level extensions and
680          // non-standard supervisor-level extensions.
681          // These extensions start with 'z', 's', 'x' prefixes, might have a
682          // version number (major, minor) and are separated by a single
683          // underscore '_'. We do not enforce a canonical order for them.
684          StringRef Type = getExtensionType(Ext);
685          Desc = getExtensionTypeDesc(Ext);
686          auto Pos = findLastNonVersionCharacter(Ext) + 1;
687          Name = Ext.substr(0, Pos);
688          Vers = Ext.substr(Pos);
689          Ext = StringRef();
690  
691          assert(!Type.empty() && "Empty type?");
692          if (Name.size() == Type.size())
693            return getError(Desc + " name missing after '" + Type + "'");
694        } else {
695          return getError("invalid standard user-level extension '" +
696                          Twine(Ext.front()) + "'");
697        }
698  
699        unsigned Major, Minor, ConsumeLength;
700        if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
701                                         EnableExperimentalExtension,
702                                         ExperimentalExtensionVersionCheck))
703          return E;
704  
705        if (Name.size() == 1)
706          Ext = Ext.substr(ConsumeLength);
707  
708        if (!RISCVISAInfo::isSupportedExtension(Name))
709          return getErrorForInvalidExt(Name);
710  
711        // Insert and error for duplicates.
712        if (!ISAInfo->Exts
713                 .emplace(Name.str(),
714                          RISCVISAUtils::ExtensionVersion{Major, Minor})
715                 .second)
716          return getError("duplicated " + Desc + " '" + Name + "'");
717  
718      } while (!Ext.empty());
719    }
720  
721    return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
722  }
723  
checkDependency()724  Error RISCVISAInfo::checkDependency() {
725    bool HasE = Exts.count("e") != 0;
726    bool HasI = Exts.count("i") != 0;
727    bool HasC = Exts.count("c") != 0;
728    bool HasF = Exts.count("f") != 0;
729    bool HasD = Exts.count("d") != 0;
730    bool HasZfinx = Exts.count("zfinx") != 0;
731    bool HasVector = Exts.count("zve32x") != 0;
732    bool HasZvl = MinVLen != 0;
733    bool HasZcmt = Exts.count("zcmt") != 0;
734  
735    if (HasI && HasE)
736      return getError("'I' and 'E' extensions are incompatible");
737  
738    if (HasF && HasZfinx)
739      return getError("'f' and 'zfinx' extensions are incompatible");
740  
741    if (HasZvl && !HasVector)
742      return getError(
743          "'zvl*b' requires 'v' or 'zve*' extension to also be specified");
744  
745    if (Exts.count("zvbb") && !HasVector)
746      return getError(
747          "'zvbb' requires 'v' or 'zve*' extension to also be specified");
748  
749    if (Exts.count("zvbc") && !Exts.count("zve64x"))
750      return getError(
751          "'zvbc' requires 'v' or 'zve64*' extension to also be specified");
752  
753    if ((Exts.count("zvkb") || Exts.count("zvkg") || Exts.count("zvkned") ||
754         Exts.count("zvknha") || Exts.count("zvksed") || Exts.count("zvksh")) &&
755        !HasVector)
756      return getError(
757          "'zvk*' requires 'v' or 'zve*' extension to also be specified");
758  
759    if (Exts.count("zvknhb") && !Exts.count("zve64x"))
760      return getError(
761          "'zvknhb' requires 'v' or 'zve64*' extension to also be specified");
762  
763    if ((HasZcmt || Exts.count("zcmp")) && HasD && (HasC || Exts.count("zcd")))
764      return getError(Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +
765                      "' extension is incompatible with '" +
766                      (HasC ? "c" : "zcd") +
767                      "' extension when 'd' extension is enabled");
768  
769    if (XLen != 32 && Exts.count("zcf"))
770      return getError("'zcf' is only supported for 'rv32'");
771  
772    if (Exts.count("zacas") && !(Exts.count("a") || Exts.count("zaamo")))
773      return getError(
774          "'zacas' requires 'a' or 'zaamo' extension to also be specified");
775  
776    if (Exts.count("zabha") && !(Exts.count("a") || Exts.count("zaamo")))
777      return getError(
778          "'zabha' requires 'a' or 'zaamo' extension to also be specified");
779  
780    if (Exts.count("xwchc") != 0) {
781      if (XLen != 32)
782        return getError("'Xwchc' is only supported for 'rv32'");
783  
784      if (HasD)
785        return getError("'D' and 'Xwchc' extensions are incompatible");
786  
787      if (Exts.count("zcb") != 0)
788        return getError("'Xwchc' and 'Zcb' extensions are incompatible");
789    }
790  
791    return Error::success();
792  }
793  
794  struct ImpliedExtsEntry {
795    StringLiteral Name;
796    const char *ImpliedExt;
797  
operator <ImpliedExtsEntry798    bool operator<(const ImpliedExtsEntry &Other) const {
799      return Name < Other.Name;
800    }
801  };
802  
operator <(const ImpliedExtsEntry & LHS,StringRef RHS)803  static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) {
804    return LHS.Name < RHS;
805  }
806  
operator <(StringRef LHS,const ImpliedExtsEntry & RHS)807  static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) {
808    return LHS < RHS.Name;
809  }
810  
811  #define GET_IMPLIED_EXTENSIONS
812  #include "llvm/TargetParser/RISCVTargetParserDef.inc"
813  
updateImplication()814  void RISCVISAInfo::updateImplication() {
815    bool HasE = Exts.count("e") != 0;
816    bool HasI = Exts.count("i") != 0;
817  
818    // If not in e extension and i extension does not exist, i extension is
819    // implied
820    if (!HasE && !HasI) {
821      auto Version = findDefaultVersion("i");
822      Exts["i"] = *Version;
823    }
824  
825    if (HasE && HasI)
826      Exts.erase("i");
827  
828    assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
829  
830    // This loop may execute over 1 iteration since implication can be layered
831    // Exits loop if no more implication is applied
832    SmallVector<StringRef, 16> WorkList;
833    for (auto const &Ext : Exts)
834      WorkList.push_back(Ext.first);
835  
836    while (!WorkList.empty()) {
837      StringRef ExtName = WorkList.pop_back_val();
838      auto Range = std::equal_range(std::begin(ImpliedExts),
839                                    std::end(ImpliedExts), ExtName);
840      std::for_each(Range.first, Range.second,
841                    [&](const ImpliedExtsEntry &Implied) {
842                      const char *ImpliedExt = Implied.ImpliedExt;
843                      if (Exts.count(ImpliedExt))
844                        return;
845                      auto Version = findDefaultVersion(ImpliedExt);
846                      Exts[ImpliedExt] = *Version;
847                      WorkList.push_back(ImpliedExt);
848                    });
849    }
850  
851    // Add Zcf if Zce and F are enabled on RV32.
852    if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
853        !Exts.count("zcf")) {
854      auto Version = findDefaultVersion("zcf");
855      Exts["zcf"] = *Version;
856    }
857  }
858  
859  static constexpr StringLiteral CombineIntoExts[] = {
860      {"zk"},    {"zkn"},  {"zks"},   {"zvkn"},  {"zvknc"},
861      {"zvkng"}, {"zvks"}, {"zvksc"}, {"zvksg"},
862  };
863  
updateCombination()864  void RISCVISAInfo::updateCombination() {
865    bool MadeChange = false;
866    do {
867      MadeChange = false;
868      for (StringRef CombineExt : CombineIntoExts) {
869        if (Exts.count(CombineExt.str()))
870          continue;
871  
872        // Look up the extension in the ImpliesExt table to find everything it
873        // depends on.
874        auto Range = std::equal_range(std::begin(ImpliedExts),
875                                      std::end(ImpliedExts), CombineExt);
876        bool HasAllRequiredFeatures = std::all_of(
877            Range.first, Range.second, [&](const ImpliedExtsEntry &Implied) {
878              return Exts.count(Implied.ImpliedExt);
879            });
880        if (HasAllRequiredFeatures) {
881          auto Version = findDefaultVersion(CombineExt);
882          Exts[CombineExt.str()] = *Version;
883          MadeChange = true;
884        }
885      }
886    } while (MadeChange);
887  }
888  
updateImpliedLengths()889  void RISCVISAInfo::updateImpliedLengths() {
890    assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 &&
891           "Expected lengths to be initialied to zero");
892  
893    // TODO: Handle q extension.
894    if (Exts.count("d"))
895      FLen = 64;
896    else if (Exts.count("f"))
897      FLen = 32;
898  
899    if (Exts.count("v")) {
900      MaxELenFp = std::max(MaxELenFp, 64u);
901      MaxELen = std::max(MaxELen, 64u);
902    }
903  
904    for (auto const &Ext : Exts) {
905      StringRef ExtName = Ext.first;
906      // Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d)
907      if (ExtName.consume_front("zve")) {
908        unsigned ZveELen;
909        if (ExtName.consumeInteger(10, ZveELen))
910          continue;
911  
912        if (ExtName == "f")
913          MaxELenFp = std::max(MaxELenFp, 32u);
914        else if (ExtName == "d")
915          MaxELenFp = std::max(MaxELenFp, 64u);
916        else if (ExtName != "x")
917          continue;
918  
919        MaxELen = std::max(MaxELen, ZveELen);
920        continue;
921      }
922  
923      // Infer MinVLen from zvl*b.
924      if (ExtName.consume_front("zvl")) {
925        unsigned ZvlLen;
926        if (ExtName.consumeInteger(10, ZvlLen))
927          continue;
928  
929        if (ExtName != "b")
930          continue;
931  
932        MinVLen = std::max(MinVLen, ZvlLen);
933        continue;
934      }
935    }
936  }
937  
toString() const938  std::string RISCVISAInfo::toString() const {
939    std::string Buffer;
940    raw_string_ostream Arch(Buffer);
941  
942    Arch << "rv" << XLen;
943  
944    ListSeparator LS("_");
945    for (auto const &Ext : Exts) {
946      StringRef ExtName = Ext.first;
947      auto ExtInfo = Ext.second;
948      Arch << LS << ExtName;
949      Arch << ExtInfo.Major << "p" << ExtInfo.Minor;
950    }
951  
952    return Arch.str();
953  }
954  
955  llvm::Expected<std::unique_ptr<RISCVISAInfo>>
postProcessAndChecking(std::unique_ptr<RISCVISAInfo> && ISAInfo)956  RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
957    ISAInfo->updateImplication();
958    ISAInfo->updateCombination();
959    ISAInfo->updateImpliedLengths();
960  
961    if (Error Result = ISAInfo->checkDependency())
962      return std::move(Result);
963    return std::move(ISAInfo);
964  }
965  
computeDefaultABI() const966  StringRef RISCVISAInfo::computeDefaultABI() const {
967    if (XLen == 32) {
968      if (Exts.count("e"))
969        return "ilp32e";
970      if (Exts.count("d"))
971        return "ilp32d";
972      if (Exts.count("f"))
973        return "ilp32f";
974      return "ilp32";
975    } else if (XLen == 64) {
976      if (Exts.count("e"))
977        return "lp64e";
978      if (Exts.count("d"))
979        return "lp64d";
980      if (Exts.count("f"))
981        return "lp64f";
982      return "lp64";
983    }
984    llvm_unreachable("Invalid XLEN");
985  }
986  
isSupportedExtensionWithVersion(StringRef Ext)987  bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext) {
988    if (Ext.empty())
989      return false;
990  
991    auto Pos = findLastNonVersionCharacter(Ext) + 1;
992    StringRef Name = Ext.substr(0, Pos);
993    StringRef Vers = Ext.substr(Pos);
994    if (Vers.empty())
995      return false;
996  
997    unsigned Major, Minor, ConsumeLength;
998    if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
999                                     true, true)) {
1000      consumeError(std::move(E));
1001      return false;
1002    }
1003  
1004    return true;
1005  }
1006  
getTargetFeatureForExtension(StringRef Ext)1007  std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {
1008    if (Ext.empty())
1009      return std::string();
1010  
1011    auto Pos = findLastNonVersionCharacter(Ext) + 1;
1012    StringRef Name = Ext.substr(0, Pos);
1013  
1014    if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1015      return std::string();
1016  
1017    if (!isSupportedExtension(Name))
1018      return std::string();
1019  
1020    return isExperimentalExtension(Name) ? "experimental-" + Name.str()
1021                                         : Name.str();
1022  }
1023