988 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			988 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- RISCVISAInfo.cpp - RISCV Arch String Parser --------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "llvm/Support/RISCVISAInfo.h"
 | |
| #include "llvm/ADT/None.h"
 | |
| #include "llvm/ADT/STLExtras.h"
 | |
| #include "llvm/ADT/SetVector.h"
 | |
| #include "llvm/ADT/StringExtras.h"
 | |
| #include "llvm/ADT/StringRef.h"
 | |
| #include "llvm/Support/Errc.h"
 | |
| #include "llvm/Support/Error.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| 
 | |
| #include <array>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| namespace {
 | |
| /// Represents the major and version number components of a RISC-V extension
 | |
| struct RISCVExtensionVersion {
 | |
|   unsigned Major;
 | |
|   unsigned Minor;
 | |
| };
 | |
| 
 | |
| struct RISCVSupportedExtension {
 | |
|   const char *Name;
 | |
|   /// Supported version.
 | |
|   RISCVExtensionVersion Version;
 | |
| };
 | |
| 
 | |
| } // end anonymous namespace
 | |
| 
 | |
| static constexpr StringLiteral AllStdExts = "mafdqlcbkjtpvn";
 | |
| 
 | |
| static const RISCVSupportedExtension SupportedExtensions[] = {
 | |
|     {"i", RISCVExtensionVersion{2, 0}},
 | |
|     {"e", RISCVExtensionVersion{1, 9}},
 | |
|     {"m", RISCVExtensionVersion{2, 0}},
 | |
|     {"a", RISCVExtensionVersion{2, 0}},
 | |
|     {"f", RISCVExtensionVersion{2, 0}},
 | |
|     {"d", RISCVExtensionVersion{2, 0}},
 | |
|     {"c", RISCVExtensionVersion{2, 0}},
 | |
| 
 | |
|     {"zihintpause", RISCVExtensionVersion{2, 0}},
 | |
| 
 | |
|     {"zfhmin", RISCVExtensionVersion{1, 0}},
 | |
|     {"zfh", RISCVExtensionVersion{1, 0}},
 | |
| 
 | |
|     {"zfinx", RISCVExtensionVersion{1, 0}},
 | |
|     {"zdinx", RISCVExtensionVersion{1, 0}},
 | |
|     {"zhinxmin", RISCVExtensionVersion{1, 0}},
 | |
|     {"zhinx", RISCVExtensionVersion{1, 0}},
 | |
| 
 | |
|     {"zba", RISCVExtensionVersion{1, 0}},
 | |
|     {"zbb", RISCVExtensionVersion{1, 0}},
 | |
|     {"zbc", RISCVExtensionVersion{1, 0}},
 | |
|     {"zbs", RISCVExtensionVersion{1, 0}},
 | |
| 
 | |
|     {"zbkb", RISCVExtensionVersion{1, 0}},
 | |
|     {"zbkc", RISCVExtensionVersion{1, 0}},
 | |
|     {"zbkx", RISCVExtensionVersion{1, 0}},
 | |
|     {"zknd", RISCVExtensionVersion{1, 0}},
 | |
|     {"zkne", RISCVExtensionVersion{1, 0}},
 | |
|     {"zknh", RISCVExtensionVersion{1, 0}},
 | |
|     {"zksed", RISCVExtensionVersion{1, 0}},
 | |
|     {"zksh", RISCVExtensionVersion{1, 0}},
 | |
|     {"zkr", RISCVExtensionVersion{1, 0}},
 | |
|     {"zkn", RISCVExtensionVersion{1, 0}},
 | |
|     {"zks", RISCVExtensionVersion{1, 0}},
 | |
|     {"zkt", RISCVExtensionVersion{1, 0}},
 | |
|     {"zk", RISCVExtensionVersion{1, 0}},
 | |
| 
 | |
|     {"zmmul", RISCVExtensionVersion{1, 0}},
 | |
| 
 | |
|     {"v", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl32b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl64b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl128b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl256b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl512b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl1024b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl2048b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl4096b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl8192b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl16384b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl32768b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zvl65536b", RISCVExtensionVersion{1, 0}},
 | |
|     {"zve32x", RISCVExtensionVersion{1, 0}},
 | |
|     {"zve32f", RISCVExtensionVersion{1, 0}},
 | |
|     {"zve64x", RISCVExtensionVersion{1, 0}},
 | |
|     {"zve64f", RISCVExtensionVersion{1, 0}},
 | |
|     {"zve64d", RISCVExtensionVersion{1, 0}},
 | |
| 
 | |
|     {"zicbom", RISCVExtensionVersion{1, 0}},
 | |
|     {"zicboz", RISCVExtensionVersion{1, 0}},
 | |
|     {"zicbop", RISCVExtensionVersion{1, 0}},
 | |
| };
 | |
| 
 | |
| static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
 | |
|     {"zihintntl", RISCVExtensionVersion{0, 2}},
 | |
| 
 | |
|     {"zbe", RISCVExtensionVersion{0, 93}},
 | |
|     {"zbf", RISCVExtensionVersion{0, 93}},
 | |
|     {"zbm", RISCVExtensionVersion{0, 93}},
 | |
|     {"zbp", RISCVExtensionVersion{0, 93}},
 | |
|     {"zbr", RISCVExtensionVersion{0, 93}},
 | |
|     {"zbt", RISCVExtensionVersion{0, 93}},
 | |
|     {"zca", RISCVExtensionVersion{0, 70}},
 | |
|     {"zvfh", RISCVExtensionVersion{0, 1}},
 | |
| };
 | |
| 
 | |
| static bool stripExperimentalPrefix(StringRef &Ext) {
 | |
|   return Ext.consume_front("experimental-");
 | |
| }
 | |
| 
 | |
| // This function finds the first character that doesn't belong to a version
 | |
| // (e.g. zbe0p93 is extension 'zbe' of version '0p93'). So the function will
 | |
| // consume [0-9]*p[0-9]* starting from the backward. An extension name will not
 | |
| // end with a digit or the letter 'p', so this function will parse correctly.
 | |
| // NOTE: This function is NOT able to take empty strings or strings that only
 | |
| // have version numbers and no extension name. It assumes the extension name
 | |
| // will be at least more than one character.
 | |
| static size_t findFirstNonVersionCharacter(StringRef Ext) {
 | |
|    assert(!Ext.empty() &&
 | |
|           "Already guarded by if-statement in ::parseArchString");
 | |
| 
 | |
|   int Pos = Ext.size() - 1;
 | |
|   while (Pos > 0 && isDigit(Ext[Pos]))
 | |
|     Pos--;
 | |
|   if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
 | |
|     Pos--;
 | |
|     while (Pos > 0 && isDigit(Ext[Pos]))
 | |
|       Pos--;
 | |
|   }
 | |
|   return Pos;
 | |
| }
 | |
| 
 | |
| struct FindByName {
 | |
|   FindByName(StringRef Ext) : Ext(Ext){};
 | |
|   StringRef Ext;
 | |
|   bool operator()(const RISCVSupportedExtension &ExtInfo) {
 | |
|     return ExtInfo.Name == Ext;
 | |
|   }
 | |
| };
 | |
| 
 | |
| static Optional<RISCVExtensionVersion> findDefaultVersion(StringRef ExtName) {
 | |
|   // Find default version of an extension.
 | |
|   // TODO: We might set default version based on profile or ISA spec.
 | |
|   for (auto &ExtInfo : {makeArrayRef(SupportedExtensions),
 | |
|                         makeArrayRef(SupportedExperimentalExtensions)}) {
 | |
|     auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName));
 | |
| 
 | |
|     if (ExtensionInfoIterator == ExtInfo.end()) {
 | |
|       continue;
 | |
|     }
 | |
|     return ExtensionInfoIterator->Version;
 | |
|   }
 | |
|   return None;
 | |
| }
 | |
| 
 | |
| void RISCVISAInfo::addExtension(StringRef ExtName, unsigned MajorVersion,
 | |
|                                 unsigned MinorVersion) {
 | |
|   RISCVExtensionInfo Ext;
 | |
|   Ext.ExtName = ExtName.str();
 | |
|   Ext.MajorVersion = MajorVersion;
 | |
|   Ext.MinorVersion = MinorVersion;
 | |
|   Exts[ExtName.str()] = Ext;
 | |
| }
 | |
| 
 | |
| static StringRef getExtensionTypeDesc(StringRef Ext) {
 | |
|   if (Ext.startswith("sx"))
 | |
|     return "non-standard supervisor-level extension";
 | |
|   if (Ext.startswith("s"))
 | |
|     return "standard supervisor-level extension";
 | |
|   if (Ext.startswith("x"))
 | |
|     return "non-standard user-level extension";
 | |
|   if (Ext.startswith("z"))
 | |
|     return "standard user-level extension";
 | |
|   return StringRef();
 | |
| }
 | |
| 
 | |
| static StringRef getExtensionType(StringRef Ext) {
 | |
|   if (Ext.startswith("sx"))
 | |
|     return "sx";
 | |
|   if (Ext.startswith("s"))
 | |
|     return "s";
 | |
|   if (Ext.startswith("x"))
 | |
|     return "x";
 | |
|   if (Ext.startswith("z"))
 | |
|     return "z";
 | |
|   return StringRef();
 | |
| }
 | |
| 
 | |
| static Optional<RISCVExtensionVersion> isExperimentalExtension(StringRef Ext) {
 | |
|   auto ExtIterator =
 | |
|       llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext));
 | |
|   if (ExtIterator == std::end(SupportedExperimentalExtensions))
 | |
|     return None;
 | |
| 
 | |
|   return ExtIterator->Version;
 | |
| }
 | |
| 
 | |
| bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
 | |
|   bool IsExperimental = stripExperimentalPrefix(Ext);
 | |
| 
 | |
|   if (IsExperimental)
 | |
|     return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
 | |
|   else
 | |
|     return llvm::any_of(SupportedExtensions, FindByName(Ext));
 | |
| }
 | |
| 
 | |
| bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
 | |
|   return llvm::any_of(SupportedExtensions, FindByName(Ext)) ||
 | |
|          llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
 | |
| }
 | |
| 
 | |
| bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
 | |
|                                         unsigned MinorVersion) {
 | |
|   auto FindByNameAndVersion = [=](const RISCVSupportedExtension &ExtInfo) {
 | |
|     return ExtInfo.Name == Ext && (MajorVersion == ExtInfo.Version.Major) &&
 | |
|            (MinorVersion == ExtInfo.Version.Minor);
 | |
|   };
 | |
|   return llvm::any_of(SupportedExtensions, FindByNameAndVersion) ||
 | |
|          llvm::any_of(SupportedExperimentalExtensions, FindByNameAndVersion);
 | |
| }
 | |
| 
 | |
| bool RISCVISAInfo::hasExtension(StringRef Ext) const {
 | |
|   stripExperimentalPrefix(Ext);
 | |
| 
 | |
|   if (!isSupportedExtension(Ext))
 | |
|     return false;
 | |
| 
 | |
|   return Exts.count(Ext.str()) != 0;
 | |
| }
 | |
| 
 | |
| // Get the rank for single-letter extension, lower value meaning higher
 | |
| // priority.
 | |
| static int singleLetterExtensionRank(char Ext) {
 | |
|   switch (Ext) {
 | |
|   case 'i':
 | |
|     return -2;
 | |
|   case 'e':
 | |
|     return -1;
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   size_t Pos = AllStdExts.find(Ext);
 | |
|   int Rank;
 | |
|   if (Pos == StringRef::npos)
 | |
|     // If we got an unknown extension letter, then give it an alphabetical
 | |
|     // order, but after all known standard extensions.
 | |
|     Rank = AllStdExts.size() + (Ext - 'a');
 | |
|   else
 | |
|     Rank = Pos;
 | |
| 
 | |
|   return Rank;
 | |
| }
 | |
| 
 | |
| // Get the rank for multi-letter extension, lower value meaning higher
 | |
| // priority/order in canonical order.
 | |
| static int multiLetterExtensionRank(const std::string &ExtName) {
 | |
|   assert(ExtName.length() >= 2);
 | |
|   int HighOrder;
 | |
|   int LowOrder = 0;
 | |
|   // The order between multi-char extensions: s -> h -> z -> x.
 | |
|   char ExtClass = ExtName[0];
 | |
|   switch (ExtClass) {
 | |
|   case 's':
 | |
|     HighOrder = 0;
 | |
|     break;
 | |
|   case 'h':
 | |
|     HighOrder = 1;
 | |
|     break;
 | |
|   case 'z':
 | |
|     HighOrder = 2;
 | |
|     // `z` extension must be sorted by canonical order of second letter.
 | |
|     // e.g. zmx has higher rank than zax.
 | |
|     LowOrder = singleLetterExtensionRank(ExtName[1]);
 | |
|     break;
 | |
|   case 'x':
 | |
|     HighOrder = 3;
 | |
|     break;
 | |
|   default:
 | |
|     llvm_unreachable("Unknown prefix for multi-char extension");
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   return (HighOrder << 8) + LowOrder;
 | |
| }
 | |
| 
 | |
| // Compare function for extension.
 | |
| // Only compare the extension name, ignore version comparison.
 | |
| bool RISCVISAInfo::compareExtension(const std::string &LHS,
 | |
|                                     const std::string &RHS) {
 | |
|   size_t LHSLen = LHS.length();
 | |
|   size_t RHSLen = RHS.length();
 | |
|   if (LHSLen == 1 && RHSLen != 1)
 | |
|     return true;
 | |
| 
 | |
|   if (LHSLen != 1 && RHSLen == 1)
 | |
|     return false;
 | |
| 
 | |
|   if (LHSLen == 1 && RHSLen == 1)
 | |
|     return singleLetterExtensionRank(LHS[0]) <
 | |
|            singleLetterExtensionRank(RHS[0]);
 | |
| 
 | |
|   // Both are multi-char ext here.
 | |
|   int LHSRank = multiLetterExtensionRank(LHS);
 | |
|   int RHSRank = multiLetterExtensionRank(RHS);
 | |
|   if (LHSRank != RHSRank)
 | |
|     return LHSRank < RHSRank;
 | |
| 
 | |
|   // If the rank is same, it must be sorted by lexicographic order.
 | |
|   return LHS < RHS;
 | |
| }
 | |
| 
 | |
| void RISCVISAInfo::toFeatures(
 | |
|     std::vector<StringRef> &Features,
 | |
|     std::function<StringRef(const Twine &)> StrAlloc) const {
 | |
|   for (auto const &Ext : Exts) {
 | |
|     StringRef ExtName = Ext.first;
 | |
| 
 | |
|     if (ExtName == "i")
 | |
|       continue;
 | |
| 
 | |
|     if (isExperimentalExtension(ExtName)) {
 | |
|       Features.push_back(StrAlloc("+experimental-" + ExtName));
 | |
|     } else {
 | |
|       Features.push_back(StrAlloc("+" + ExtName));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| // Extensions may have a version number, and may be separated by
 | |
| // an underscore '_' e.g.: rv32i2_m2.
 | |
| // Version number is divided into major and minor version numbers,
 | |
| // separated by a 'p'. If the minor version is 0 then 'p0' can be
 | |
| // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
 | |
| static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
 | |
|                                  unsigned &Minor, unsigned &ConsumeLength,
 | |
|                                  bool EnableExperimentalExtension,
 | |
|                                  bool ExperimentalExtensionVersionCheck) {
 | |
|   StringRef MajorStr, MinorStr;
 | |
|   Major = 0;
 | |
|   Minor = 0;
 | |
|   ConsumeLength = 0;
 | |
|   MajorStr = In.take_while(isDigit);
 | |
|   In = In.substr(MajorStr.size());
 | |
| 
 | |
|   if (!MajorStr.empty() && In.consume_front("p")) {
 | |
|     MinorStr = In.take_while(isDigit);
 | |
|     In = In.substr(MajorStr.size() + MinorStr.size() - 1);
 | |
| 
 | |
|     // Expected 'p' to be followed by minor version number.
 | |
|     if (MinorStr.empty()) {
 | |
|       return createStringError(
 | |
|           errc::invalid_argument,
 | |
|           "minor version number missing after 'p' for extension '" + Ext + "'");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
 | |
|     return createStringError(
 | |
|         errc::invalid_argument,
 | |
|         "Failed to parse major version number for extension '" + Ext + "'");
 | |
| 
 | |
|   if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
 | |
|     return createStringError(
 | |
|         errc::invalid_argument,
 | |
|         "Failed to parse minor version number for extension '" + Ext + "'");
 | |
| 
 | |
|   ConsumeLength = MajorStr.size();
 | |
| 
 | |
|   if (!MinorStr.empty())
 | |
|     ConsumeLength += MinorStr.size() + 1 /*'p'*/;
 | |
| 
 | |
|   // Expected multi-character extension with version number to have no
 | |
|   // subsequent characters (i.e. must either end string or be followed by
 | |
|   // an underscore).
 | |
|   if (Ext.size() > 1 && In.size()) {
 | |
|     std::string Error =
 | |
|         "multi-character extensions must be separated by underscores";
 | |
|     return createStringError(errc::invalid_argument, Error);
 | |
|   }
 | |
| 
 | |
|   // If experimental extension, require use of current version number number
 | |
|   if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
 | |
|     if (!EnableExperimentalExtension) {
 | |
|       std::string Error = "requires '-menable-experimental-extensions' for "
 | |
|                           "experimental extension '" +
 | |
|                           Ext.str() + "'";
 | |
|       return createStringError(errc::invalid_argument, Error);
 | |
|     }
 | |
| 
 | |
|     if (ExperimentalExtensionVersionCheck &&
 | |
|         (MajorStr.empty() && MinorStr.empty())) {
 | |
|       std::string Error =
 | |
|           "experimental extension requires explicit version number `" +
 | |
|           Ext.str() + "`";
 | |
|       return createStringError(errc::invalid_argument, Error);
 | |
|     }
 | |
| 
 | |
|     auto SupportedVers = *ExperimentalExtension;
 | |
|     if (ExperimentalExtensionVersionCheck &&
 | |
|         (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
 | |
|       std::string Error = "unsupported version number " + MajorStr.str();
 | |
|       if (!MinorStr.empty())
 | |
|         Error += "." + MinorStr.str();
 | |
|       Error += " for experimental extension '" + Ext.str() +
 | |
|                "' (this compiler supports " + utostr(SupportedVers.Major) +
 | |
|                "." + utostr(SupportedVers.Minor) + ")";
 | |
|       return createStringError(errc::invalid_argument, Error);
 | |
|     }
 | |
|     return Error::success();
 | |
|   }
 | |
| 
 | |
|   // Exception rule for `g`, we don't have clear version scheme for that on
 | |
|   // ISA spec.
 | |
|   if (Ext == "g")
 | |
|     return Error::success();
 | |
| 
 | |
|   if (MajorStr.empty() && MinorStr.empty()) {
 | |
|     if (auto DefaultVersion = findDefaultVersion(Ext)) {
 | |
|       Major = DefaultVersion->Major;
 | |
|       Minor = DefaultVersion->Minor;
 | |
|     }
 | |
|     // No matter found or not, return success, assume other place will
 | |
|     // verify.
 | |
|     return Error::success();
 | |
|   }
 | |
| 
 | |
|   if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
 | |
|     return Error::success();
 | |
| 
 | |
|   std::string Error = "unsupported version number " + std::string(MajorStr);
 | |
|   if (!MinorStr.empty())
 | |
|     Error += "." + MinorStr.str();
 | |
|   Error += " for extension '" + Ext.str() + "'";
 | |
|   return createStringError(errc::invalid_argument, Error);
 | |
| }
 | |
| 
 | |
| llvm::Expected<std::unique_ptr<RISCVISAInfo>>
 | |
| RISCVISAInfo::parseFeatures(unsigned XLen,
 | |
|                             const std::vector<std::string> &Features) {
 | |
|   assert(XLen == 32 || XLen == 64);
 | |
|   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
 | |
| 
 | |
|   for (auto &Feature : Features) {
 | |
|     StringRef ExtName = Feature;
 | |
|     bool Experimental = false;
 | |
|     assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
 | |
|     bool Add = ExtName[0] == '+';
 | |
|     ExtName = ExtName.drop_front(1); // Drop '+' or '-'
 | |
|     Experimental = stripExperimentalPrefix(ExtName);
 | |
|     auto ExtensionInfos = Experimental
 | |
|                               ? makeArrayRef(SupportedExperimentalExtensions)
 | |
|                               : makeArrayRef(SupportedExtensions);
 | |
|     auto ExtensionInfoIterator =
 | |
|         llvm::find_if(ExtensionInfos, FindByName(ExtName));
 | |
| 
 | |
|     // Not all features is related to ISA extension, like `relax` or
 | |
|     // `save-restore`, skip those feature.
 | |
|     if (ExtensionInfoIterator == ExtensionInfos.end())
 | |
|       continue;
 | |
| 
 | |
|     if (Add)
 | |
|       ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
 | |
|                             ExtensionInfoIterator->Version.Minor);
 | |
|     else
 | |
|       ISAInfo->Exts.erase(ExtName.str());
 | |
|   }
 | |
| 
 | |
|   return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
 | |
| }
 | |
| 
 | |
| llvm::Expected<std::unique_ptr<RISCVISAInfo>>
 | |
| RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
 | |
|                               bool ExperimentalExtensionVersionCheck) {
 | |
|   // RISC-V ISA strings must be lowercase.
 | |
|   if (llvm::any_of(Arch, isupper)) {
 | |
|     return createStringError(errc::invalid_argument,
 | |
|                              "string must be lowercase");
 | |
|   }
 | |
| 
 | |
|   bool HasRV64 = Arch.startswith("rv64");
 | |
|   // ISA string must begin with rv32 or rv64.
 | |
|   if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
 | |
|     return createStringError(errc::invalid_argument,
 | |
|                              "string must begin with rv32{i,e,g} or rv64{i,g}");
 | |
|   }
 | |
| 
 | |
|   unsigned XLen = HasRV64 ? 64 : 32;
 | |
|   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
 | |
| 
 | |
|   // The canonical order specified in ISA manual.
 | |
|   // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
 | |
|   StringRef StdExts = AllStdExts;
 | |
|   char Baseline = Arch[4];
 | |
| 
 | |
|   // First letter should be 'e', 'i' or 'g'.
 | |
|   switch (Baseline) {
 | |
|   default:
 | |
|     return createStringError(errc::invalid_argument,
 | |
|                              "first letter should be 'e', 'i' or 'g'");
 | |
|   case 'e': {
 | |
|     // Extension 'e' is not allowed in rv64.
 | |
|     if (HasRV64)
 | |
|       return createStringError(
 | |
|           errc::invalid_argument,
 | |
|           "standard user-level extension 'e' requires 'rv32'");
 | |
|     break;
 | |
|   }
 | |
|   case 'i':
 | |
|     break;
 | |
|   case 'g':
 | |
|     // g = imafd
 | |
|     StdExts = StdExts.drop_front(4);
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   // Skip rvxxx
 | |
|   StringRef Exts = Arch.substr(5);
 | |
| 
 | |
|   // Remove multi-letter standard extensions, non-standard extensions and
 | |
|   // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
 | |
|   // Parse them at the end.
 | |
|   // Find the very first occurrence of 's', 'x' or 'z'.
 | |
|   StringRef OtherExts;
 | |
|   size_t Pos = Exts.find_first_of("zsx");
 | |
|   if (Pos != StringRef::npos) {
 | |
|     OtherExts = Exts.substr(Pos);
 | |
|     Exts = Exts.substr(0, Pos);
 | |
|   }
 | |
| 
 | |
|   unsigned Major, Minor, ConsumeLength;
 | |
|   if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
 | |
|                                    ConsumeLength, EnableExperimentalExtension,
 | |
|                                    ExperimentalExtensionVersionCheck))
 | |
|     return std::move(E);
 | |
| 
 | |
|   if (Baseline == 'g') {
 | |
|     // No matter which version is given to `g`, we always set imafd to default
 | |
|     // version since the we don't have clear version scheme for that on
 | |
|     // ISA spec.
 | |
|     for (const auto *Ext : {"i", "m", "a", "f", "d"})
 | |
|       if (auto Version = findDefaultVersion(Ext))
 | |
|         ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
 | |
|       else
 | |
|         llvm_unreachable("Default extension version not found?");
 | |
|   } else
 | |
|     // Baseline is `i` or `e`
 | |
|     ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
 | |
| 
 | |
|   // Consume the base ISA version number and any '_' between rvxxx and the
 | |
|   // first extension
 | |
|   Exts = Exts.drop_front(ConsumeLength);
 | |
|   Exts.consume_front("_");
 | |
| 
 | |
|   // TODO: Use version number when setting target features
 | |
| 
 | |
|   auto StdExtsItr = StdExts.begin();
 | |
|   auto StdExtsEnd = StdExts.end();
 | |
|   for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
 | |
|     char C = *I;
 | |
| 
 | |
|     // Check ISA extensions are specified in the canonical order.
 | |
|     while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
 | |
|       ++StdExtsItr;
 | |
| 
 | |
|     if (StdExtsItr == StdExtsEnd) {
 | |
|       // Either c contains a valid extension but it was not given in
 | |
|       // canonical order or it is an invalid extension.
 | |
|       if (StdExts.contains(C)) {
 | |
|         return createStringError(
 | |
|             errc::invalid_argument,
 | |
|             "standard user-level extension not given in canonical order '%c'",
 | |
|             C);
 | |
|       }
 | |
| 
 | |
|       return createStringError(errc::invalid_argument,
 | |
|                                "invalid standard user-level extension '%c'", C);
 | |
|     }
 | |
| 
 | |
|     // Move to next char to prevent repeated letter.
 | |
|     ++StdExtsItr;
 | |
| 
 | |
|     std::string Next;
 | |
|     unsigned Major, Minor, ConsumeLength;
 | |
|     if (std::next(I) != E)
 | |
|       Next = std::string(std::next(I), E);
 | |
|     if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
 | |
|                                      ConsumeLength, EnableExperimentalExtension,
 | |
|                                      ExperimentalExtensionVersionCheck))
 | |
|       return std::move(E);
 | |
| 
 | |
|     // The order is OK, then push it into features.
 | |
|     // TODO: Use version number when setting target features
 | |
|     // Currently LLVM supports only "mafdcbv".
 | |
|     StringRef SupportedStandardExtension = "mafdcbv";
 | |
|     if (!SupportedStandardExtension.contains(C))
 | |
|       return createStringError(errc::invalid_argument,
 | |
|                                "unsupported standard user-level extension '%c'",
 | |
|                                C);
 | |
|     ISAInfo->addExtension(std::string(1, C), Major, Minor);
 | |
| 
 | |
|     // Consume full extension name and version, including any optional '_'
 | |
|     // between this extension and the next
 | |
|     ++I;
 | |
|     I += ConsumeLength;
 | |
|     if (*I == '_')
 | |
|       ++I;
 | |
|   }
 | |
| 
 | |
|   // Handle other types of extensions other than the standard
 | |
|   // general purpose and standard user-level extensions.
 | |
|   // Parse the ISA string containing non-standard user-level
 | |
|   // extensions, standard supervisor-level extensions and
 | |
|   // non-standard supervisor-level extensions.
 | |
|   // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
 | |
|   // canonical order, might have a version number (major, minor)
 | |
|   // and are separated by a single underscore '_'.
 | |
|   // Set the hardware features for the extensions that are supported.
 | |
| 
 | |
|   // Multi-letter extensions are seperated by a single underscore
 | |
|   // as described in RISC-V User-Level ISA V2.2.
 | |
|   SmallVector<StringRef, 8> Split;
 | |
|   OtherExts.split(Split, '_');
 | |
| 
 | |
|   SmallVector<StringRef, 8> AllExts;
 | |
|   std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
 | |
|   auto I = Prefix.begin();
 | |
|   auto E = Prefix.end();
 | |
|   if (Split.size() > 1 || Split[0] != "") {
 | |
|     for (StringRef Ext : Split) {
 | |
|       if (Ext.empty())
 | |
|         return createStringError(errc::invalid_argument,
 | |
|                                  "extension name missing after separator '_'");
 | |
| 
 | |
|       StringRef Type = getExtensionType(Ext);
 | |
|       StringRef Desc = getExtensionTypeDesc(Ext);
 | |
|       auto Pos = findFirstNonVersionCharacter(Ext) + 1;
 | |
|       StringRef Name(Ext.substr(0, Pos));
 | |
|       StringRef Vers(Ext.substr(Pos));
 | |
| 
 | |
|       if (Type.empty())
 | |
|         return createStringError(errc::invalid_argument,
 | |
|                                  "invalid extension prefix '" + Ext + "'");
 | |
| 
 | |
|       // Check ISA extensions are specified in the canonical order.
 | |
|       while (I != E && *I != Type)
 | |
|         ++I;
 | |
| 
 | |
|       if (I == E)
 | |
|         return createStringError(errc::invalid_argument,
 | |
|                                  "%s not given in canonical order '%s'",
 | |
|                                  Desc.str().c_str(), Ext.str().c_str());
 | |
| 
 | |
|       if (Name.size() == Type.size()) {
 | |
|         return createStringError(errc::invalid_argument,
 | |
|                                  "%s name missing after '%s'",
 | |
|                                  Desc.str().c_str(), Type.str().c_str());
 | |
|       }
 | |
| 
 | |
|       unsigned Major, Minor, ConsumeLength;
 | |
|       if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
 | |
|                                        EnableExperimentalExtension,
 | |
|                                        ExperimentalExtensionVersionCheck))
 | |
|         return std::move(E);
 | |
| 
 | |
|       // Check if duplicated extension.
 | |
|       if (llvm::is_contained(AllExts, Name))
 | |
|         return createStringError(errc::invalid_argument, "duplicated %s '%s'",
 | |
|                                  Desc.str().c_str(), Name.str().c_str());
 | |
| 
 | |
|       ISAInfo->addExtension(Name, Major, Minor);
 | |
|       // Extension format is correct, keep parsing the extensions.
 | |
|       // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
 | |
|       AllExts.push_back(Name);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (auto Ext : AllExts) {
 | |
|     if (!isSupportedExtension(Ext)) {
 | |
|       StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
 | |
|       return createStringError(errc::invalid_argument, "unsupported %s '%s'",
 | |
|                                Desc.str().c_str(), Ext.str().c_str());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
 | |
| }
 | |
| 
 | |
| Error RISCVISAInfo::checkDependency() {
 | |
|   bool IsRv32 = XLen == 32;
 | |
|   bool HasE = Exts.count("e") != 0;
 | |
|   bool HasD = Exts.count("d") != 0;
 | |
|   bool HasF = Exts.count("f") != 0;
 | |
|   bool HasZfinx = Exts.count("zfinx") != 0;
 | |
|   bool HasZdinx = Exts.count("zdinx") != 0;
 | |
|   bool HasVector = Exts.count("zve32x") != 0;
 | |
|   bool HasZve32f = Exts.count("zve32f") != 0;
 | |
|   bool HasZve64d = Exts.count("zve64d") != 0;
 | |
|   bool HasZvl = MinVLen != 0;
 | |
| 
 | |
|   if (HasE && !IsRv32)
 | |
|     return createStringError(
 | |
|         errc::invalid_argument,
 | |
|         "standard user-level extension 'e' requires 'rv32'");
 | |
| 
 | |
|   // It's illegal to specify the 'd' (double-precision floating point)
 | |
|   // extension without also specifying the 'f' (single precision
 | |
|   // floating-point) extension.
 | |
|   // TODO: This has been removed in later specs, which specify that D implies F
 | |
|   if (HasD && !HasF)
 | |
|     return createStringError(errc::invalid_argument,
 | |
|                              "d requires f extension to also be specified");
 | |
| 
 | |
|   if (HasZve32f && !HasF && !HasZfinx)
 | |
|     return createStringError(
 | |
|         errc::invalid_argument,
 | |
|         "zve32f requires f or zfinx extension to also be specified");
 | |
| 
 | |
|   if (HasZve64d && !HasD && !HasZdinx)
 | |
|     return createStringError(
 | |
|         errc::invalid_argument,
 | |
|         "zve64d requires d or zdinx extension to also be specified");
 | |
| 
 | |
|   if (Exts.count("zvfh") && !Exts.count("zfh") && !Exts.count("zfhmin") &&
 | |
|       !Exts.count("zhinx") && !Exts.count("zhinxmin"))
 | |
|     return createStringError(
 | |
|         errc::invalid_argument,
 | |
|         "zvfh requires zfh, zfhmin, zhinx or zhinxmin extension to also be "
 | |
|         "specified");
 | |
| 
 | |
|   if (HasZvl && !HasVector)
 | |
|     return createStringError(
 | |
|         errc::invalid_argument,
 | |
|         "zvl*b requires v or zve* extension to also be specified");
 | |
| 
 | |
|   // Additional dependency checks.
 | |
|   // TODO: The 'q' extension requires rv64.
 | |
|   // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
 | |
| 
 | |
|   return Error::success();
 | |
| }
 | |
| 
 | |
| static const char *ImpliedExtsV[] = {"zvl128b", "zve64d", "f", "d"};
 | |
| static const char *ImpliedExtsZfhmin[] = {"f"};
 | |
| static const char *ImpliedExtsZfh[] = {"f"};
 | |
| static const char *ImpliedExtsZdinx[] = {"zfinx"};
 | |
| static const char *ImpliedExtsZhinxmin[] = {"zfinx"};
 | |
| static const char *ImpliedExtsZhinx[] = {"zfinx"};
 | |
| static const char *ImpliedExtsZve64d[] = {"zve64f"};
 | |
| static const char *ImpliedExtsZve64f[] = {"zve64x", "zve32f"};
 | |
| static const char *ImpliedExtsZve64x[] = {"zve32x", "zvl64b"};
 | |
| static const char *ImpliedExtsZve32f[] = {"zve32x"};
 | |
| static const char *ImpliedExtsZve32x[] = {"zvl32b"};
 | |
| static const char *ImpliedExtsZvl65536b[] = {"zvl32768b"};
 | |
| static const char *ImpliedExtsZvl32768b[] = {"zvl16384b"};
 | |
| static const char *ImpliedExtsZvl16384b[] = {"zvl8192b"};
 | |
| static const char *ImpliedExtsZvl8192b[] = {"zvl4096b"};
 | |
| static const char *ImpliedExtsZvl4096b[] = {"zvl2048b"};
 | |
| static const char *ImpliedExtsZvl2048b[] = {"zvl1024b"};
 | |
| static const char *ImpliedExtsZvl1024b[] = {"zvl512b"};
 | |
| static const char *ImpliedExtsZvl512b[] = {"zvl256b"};
 | |
| static const char *ImpliedExtsZvl256b[] = {"zvl128b"};
 | |
| static const char *ImpliedExtsZvl128b[] = {"zvl64b"};
 | |
| static const char *ImpliedExtsZvl64b[] = {"zvl32b"};
 | |
| static const char *ImpliedExtsZk[] = {"zkn", "zkt", "zkr"};
 | |
| static const char *ImpliedExtsZkn[] = {"zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"};
 | |
| static const char *ImpliedExtsZks[] = {"zbkb", "zbkc", "zbkx", "zksed", "zksh"};
 | |
| static const char *ImpliedExtsZvfh[] = {"zve32f"};
 | |
| 
 | |
| struct ImpliedExtsEntry {
 | |
|   StringLiteral Name;
 | |
|   ArrayRef<const char *> Exts;
 | |
| 
 | |
|   bool operator<(const ImpliedExtsEntry &Other) const {
 | |
|     return Name < Other.Name;
 | |
|   }
 | |
| 
 | |
|   bool operator<(StringRef Other) const { return Name < Other; }
 | |
| };
 | |
| 
 | |
| // Note: The table needs to be sorted by name.
 | |
| static constexpr ImpliedExtsEntry ImpliedExts[] = {
 | |
|     {{"v"}, {ImpliedExtsV}},
 | |
|     {{"zdinx"}, {ImpliedExtsZdinx}},
 | |
|     {{"zfh"}, {ImpliedExtsZfh}},
 | |
|     {{"zfhmin"}, {ImpliedExtsZfhmin}},
 | |
|     {{"zhinx"}, {ImpliedExtsZhinx}},
 | |
|     {{"zhinxmin"}, {ImpliedExtsZhinxmin}},
 | |
|     {{"zk"}, {ImpliedExtsZk}},
 | |
|     {{"zkn"}, {ImpliedExtsZkn}},
 | |
|     {{"zks"}, {ImpliedExtsZks}},
 | |
|     {{"zve32f"}, {ImpliedExtsZve32f}},
 | |
|     {{"zve32x"}, {ImpliedExtsZve32x}},
 | |
|     {{"zve64d"}, {ImpliedExtsZve64d}},
 | |
|     {{"zve64f"}, {ImpliedExtsZve64f}},
 | |
|     {{"zve64x"}, {ImpliedExtsZve64x}},
 | |
|     {{"zvfh"}, {ImpliedExtsZvfh}},
 | |
|     {{"zvl1024b"}, {ImpliedExtsZvl1024b}},
 | |
|     {{"zvl128b"}, {ImpliedExtsZvl128b}},
 | |
|     {{"zvl16384b"}, {ImpliedExtsZvl16384b}},
 | |
|     {{"zvl2048b"}, {ImpliedExtsZvl2048b}},
 | |
|     {{"zvl256b"}, {ImpliedExtsZvl256b}},
 | |
|     {{"zvl32768b"}, {ImpliedExtsZvl32768b}},
 | |
|     {{"zvl4096b"}, {ImpliedExtsZvl4096b}},
 | |
|     {{"zvl512b"}, {ImpliedExtsZvl512b}},
 | |
|     {{"zvl64b"}, {ImpliedExtsZvl64b}},
 | |
|     {{"zvl65536b"}, {ImpliedExtsZvl65536b}},
 | |
|     {{"zvl8192b"}, {ImpliedExtsZvl8192b}},
 | |
| };
 | |
| 
 | |
| void RISCVISAInfo::updateImplication() {
 | |
|   bool HasE = Exts.count("e") != 0;
 | |
|   bool HasI = Exts.count("i") != 0;
 | |
| 
 | |
|   // If not in e extension and i extension does not exist, i extension is
 | |
|   // implied
 | |
|   if (!HasE && !HasI) {
 | |
|     auto Version = findDefaultVersion("i");
 | |
|     addExtension("i", Version->Major, Version->Minor);
 | |
|   }
 | |
| 
 | |
|   assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
 | |
| 
 | |
|   // This loop may execute over 1 iteration since implication can be layered
 | |
|   // Exits loop if no more implication is applied
 | |
|   SmallSetVector<StringRef, 16> WorkList;
 | |
|   for (auto const &Ext : Exts)
 | |
|     WorkList.insert(Ext.first);
 | |
| 
 | |
|   while (!WorkList.empty()) {
 | |
|     StringRef ExtName = WorkList.pop_back_val();
 | |
|     auto I = llvm::lower_bound(ImpliedExts, ExtName);
 | |
|     if (I != std::end(ImpliedExts) && I->Name == ExtName) {
 | |
|       for (const char *ImpliedExt : I->Exts) {
 | |
|         if (WorkList.count(ImpliedExt))
 | |
|           continue;
 | |
|         if (Exts.count(ImpliedExt))
 | |
|           continue;
 | |
|         auto Version = findDefaultVersion(ImpliedExt);
 | |
|         addExtension(ImpliedExt, Version->Major, Version->Minor);
 | |
|         WorkList.insert(ImpliedExt);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| struct CombinedExtsEntry {
 | |
|   StringLiteral CombineExt;
 | |
|   ArrayRef<const char *> RequiredExts;
 | |
| };
 | |
| 
 | |
| static constexpr CombinedExtsEntry CombineIntoExts[] = {
 | |
|     {{"zk"}, {ImpliedExtsZk}},
 | |
|     {{"zkn"}, {ImpliedExtsZkn}},
 | |
|     {{"zks"}, {ImpliedExtsZks}},
 | |
| };
 | |
| 
 | |
| void RISCVISAInfo::updateCombination() {
 | |
|   bool IsNewCombine = false;
 | |
|   do {
 | |
|     IsNewCombine = false;
 | |
|     for (CombinedExtsEntry CombineIntoExt : CombineIntoExts) {
 | |
|       auto CombineExt = CombineIntoExt.CombineExt;
 | |
|       auto RequiredExts = CombineIntoExt.RequiredExts;
 | |
|       if (hasExtension(CombineExt))
 | |
|         continue;
 | |
|       bool IsAllRequiredFeatureExist = true;
 | |
|       for (const char *Ext : RequiredExts)
 | |
|         IsAllRequiredFeatureExist &= hasExtension(Ext);
 | |
|       if (IsAllRequiredFeatureExist) {
 | |
|         auto Version = findDefaultVersion(CombineExt);
 | |
|         addExtension(CombineExt, Version->Major, Version->Minor);
 | |
|         IsNewCombine = true;
 | |
|       }
 | |
|     }
 | |
|   } while (IsNewCombine);
 | |
| }
 | |
| 
 | |
| void RISCVISAInfo::updateFLen() {
 | |
|   FLen = 0;
 | |
|   // TODO: Handle q extension.
 | |
|   if (Exts.count("d"))
 | |
|     FLen = 64;
 | |
|   else if (Exts.count("f"))
 | |
|     FLen = 32;
 | |
| }
 | |
| 
 | |
| void RISCVISAInfo::updateMinVLen() {
 | |
|   for (auto const &Ext : Exts) {
 | |
|     StringRef ExtName = Ext.first;
 | |
|     bool IsZvlExt = ExtName.consume_front("zvl") && ExtName.consume_back("b");
 | |
|     if (IsZvlExt) {
 | |
|       unsigned ZvlLen;
 | |
|       if (!ExtName.getAsInteger(10, ZvlLen))
 | |
|         MinVLen = std::max(MinVLen, ZvlLen);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void RISCVISAInfo::updateMaxELen() {
 | |
|   // handles EEW restriction by sub-extension zve
 | |
|   for (auto const &Ext : Exts) {
 | |
|     StringRef ExtName = Ext.first;
 | |
|     bool IsZveExt = ExtName.consume_front("zve");
 | |
|     if (IsZveExt) {
 | |
|       if (ExtName.back() == 'f')
 | |
|         MaxELenFp = std::max(MaxELenFp, 32u);
 | |
|       if (ExtName.back() == 'd')
 | |
|         MaxELenFp = std::max(MaxELenFp, 64u);
 | |
|       ExtName = ExtName.drop_back();
 | |
|       unsigned ZveELen;
 | |
|       ExtName.getAsInteger(10, ZveELen);
 | |
|       MaxELen = std::max(MaxELen, ZveELen);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| std::string RISCVISAInfo::toString() const {
 | |
|   std::string Buffer;
 | |
|   raw_string_ostream Arch(Buffer);
 | |
| 
 | |
|   Arch << "rv" << XLen;
 | |
| 
 | |
|   ListSeparator LS("_");
 | |
|   for (auto const &Ext : Exts) {
 | |
|     StringRef ExtName = Ext.first;
 | |
|     auto ExtInfo = Ext.second;
 | |
|     Arch << LS << ExtName;
 | |
|     Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
 | |
|   }
 | |
| 
 | |
|   return Arch.str();
 | |
| }
 | |
| 
 | |
| std::vector<std::string> RISCVISAInfo::toFeatureVector() const {
 | |
|   std::vector<std::string> FeatureVector;
 | |
|   for (auto const &Ext : Exts) {
 | |
|     std::string ExtName = Ext.first;
 | |
|     if (ExtName == "i") // i is not recognized in clang -cc1
 | |
|       continue;
 | |
|     std::string Feature = isExperimentalExtension(ExtName)
 | |
|                               ? "+experimental-" + ExtName
 | |
|                               : "+" + ExtName;
 | |
|     FeatureVector.push_back(Feature);
 | |
|   }
 | |
|   return FeatureVector;
 | |
| }
 | |
| 
 | |
| llvm::Expected<std::unique_ptr<RISCVISAInfo>>
 | |
| RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
 | |
|   ISAInfo->updateImplication();
 | |
|   ISAInfo->updateCombination();
 | |
|   ISAInfo->updateFLen();
 | |
|   ISAInfo->updateMinVLen();
 | |
|   ISAInfo->updateMaxELen();
 | |
| 
 | |
|   if (Error Result = ISAInfo->checkDependency())
 | |
|     return std::move(Result);
 | |
|   return std::move(ISAInfo);
 | |
| }
 | |
| 
 | |
| StringRef RISCVISAInfo::computeDefaultABI() const {
 | |
|   if (XLen == 32) {
 | |
|     if (hasExtension("d"))
 | |
|       return "ilp32d";
 | |
|     if (hasExtension("e"))
 | |
|       return "ilp32e";
 | |
|     return "ilp32";
 | |
|   } else if (XLen == 64) {
 | |
|     if (hasExtension("d"))
 | |
|       return "lp64d";
 | |
|     return "lp64";
 | |
|   }
 | |
|   llvm_unreachable("Invalid XLEN");
 | |
| }
 |