12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097 |
- //===-- RISCVISAInfo.cpp - RISCV Arch String Parser -------------*- C++ -*-===//
- //
- // 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/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 <optional>
- #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 = "mafdqlcbkjtpvnh";
- 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}},
- {"h", RISCVExtensionVersion{1, 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}},
- {"svnapot", RISCVExtensionVersion{1, 0}},
- {"svpbmt", RISCVExtensionVersion{1, 0}},
- {"svinval", RISCVExtensionVersion{1, 0}},
- {"xventanacondops", RISCVExtensionVersion{1, 0}},
- {"xtheadvdot", RISCVExtensionVersion{1, 0}},
- };
- static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
- {"zihintntl", RISCVExtensionVersion{0, 2}},
- {"zca", RISCVExtensionVersion{0, 70}},
- {"zcd", RISCVExtensionVersion{0, 70}},
- {"zcf", RISCVExtensionVersion{0, 70}},
- {"zvfh", RISCVExtensionVersion{0, 1}},
- {"zawrs", RISCVExtensionVersion{1, 0}},
- {"ztso", 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. zba1p0 is extension 'zba' of version '1p0'). 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;
- }
- namespace {
- struct FindByName {
- FindByName(StringRef Ext) : Ext(Ext){};
- StringRef Ext;
- bool operator()(const RISCVSupportedExtension &ExtInfo) {
- return ExtInfo.Name == Ext;
- }
- };
- } // namespace
- static std::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 : {ArrayRef(SupportedExtensions),
- ArrayRef(SupportedExperimentalExtensions)}) {
- auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName));
- if (ExtensionInfoIterator == ExtInfo.end()) {
- continue;
- }
- return ExtensionInfoIterator->Version;
- }
- return std::nullopt;
- }
- 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 std::optional<RISCVExtensionVersion>
- isExperimentalExtension(StringRef Ext) {
- auto ExtIterator =
- llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext));
- if (ExtIterator == std::end(SupportedExperimentalExtensions))
- return std::nullopt;
- 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 'z':
- HighOrder = 1;
- // `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 = 2;
- 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,
- llvm::function_ref<StringRef(const Twine &)> StrAlloc,
- bool AddAllExtensions) 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));
- }
- }
- if (AddAllExtensions) {
- for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
- if (Exts.count(Ext.Name))
- continue;
- Features.push_back(StrAlloc(Twine("-") + Ext.Name));
- }
- for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
- if (Exts.count(Ext.Name))
- continue;
- Features.push_back(StrAlloc(Twine("-experimental-") + Ext.Name));
- }
- }
- }
- // 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
- ? ArrayRef(SupportedExperimentalExtensions)
- : ArrayRef(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::parseNormalizedArchString(StringRef Arch) {
- if (llvm::any_of(Arch, isupper)) {
- return createStringError(errc::invalid_argument,
- "string must be lowercase");
- }
- // Must start with a valid base ISA name.
- unsigned XLen;
- if (Arch.startswith("rv32i") || Arch.startswith("rv32e"))
- XLen = 32;
- else if (Arch.startswith("rv64i") || Arch.startswith("rv64e"))
- XLen = 64;
- else
- return createStringError(errc::invalid_argument,
- "arch string must begin with valid base ISA");
- std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
- // Discard rv32/rv64 prefix.
- Arch = Arch.substr(4);
- // Each extension is of the form ${name}${major_version}p${minor_version}
- // and separated by _. Split by _ and then extract the name and version
- // information for each extension.
- SmallVector<StringRef, 8> Split;
- Arch.split(Split, '_');
- for (StringRef Ext : Split) {
- StringRef Prefix, MinorVersionStr;
- std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');
- if (MinorVersionStr.empty())
- return createStringError(errc::invalid_argument,
- "extension lacks version in expected format");
- unsigned MajorVersion, MinorVersion;
- if (MinorVersionStr.getAsInteger(10, MinorVersion))
- return createStringError(errc::invalid_argument,
- "failed to parse minor version number");
- // Split Prefix into the extension name and the major version number
- // (the trailing digits of Prefix).
- int TrailingDigits = 0;
- StringRef ExtName = Prefix;
- while (!ExtName.empty()) {
- if (!isDigit(ExtName.back()))
- break;
- ExtName = ExtName.drop_back(1);
- TrailingDigits++;
- }
- if (!TrailingDigits)
- return createStringError(errc::invalid_argument,
- "extension lacks version in expected format");
- StringRef MajorVersionStr = Prefix.take_back(TrailingDigits);
- if (MajorVersionStr.getAsInteger(10, MajorVersion))
- return createStringError(errc::invalid_argument,
- "failed to parse major version number");
- ISAInfo->addExtension(ExtName, MajorVersion, MinorVersion);
- }
- ISAInfo->updateFLen();
- ISAInfo->updateMinVLen();
- ISAInfo->updateMaxELen();
- return std::move(ISAInfo);
- }
- llvm::Expected<std::unique_ptr<RISCVISAInfo>>
- RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
- bool ExperimentalExtensionVersionCheck,
- bool IgnoreUnknown) {
- // 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();
- auto GoToNextExt = [](StringRef::iterator &I, unsigned ConsumeLength) {
- I += 1 + ConsumeLength;
- if (*I == '_')
- ++I;
- };
- 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)) {
- if (IgnoreUnknown) {
- consumeError(std::move(E));
- GoToNextExt(I, ConsumeLength);
- continue;
- }
- 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 "mafdcvh".
- if (!isSupportedExtension(StringRef(&C, 1))) {
- if (IgnoreUnknown) {
- GoToNextExt(I, ConsumeLength);
- continue;
- }
- 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
- GoToNextExt(I, ConsumeLength);
- }
- // 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()) {
- if (IgnoreUnknown)
- continue;
- 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) {
- if (IgnoreUnknown)
- continue;
- return createStringError(errc::invalid_argument,
- "%s not given in canonical order '%s'",
- Desc.str().c_str(), Ext.str().c_str());
- }
- if (!IgnoreUnknown && 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)) {
- if (IgnoreUnknown) {
- consumeError(std::move(E));
- continue;
- }
- return std::move(E);
- }
- // Check if duplicated extension.
- if (!IgnoreUnknown && 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"};
- static const char *ImpliedExtsXTHeadVdot[] = {"v"};
- 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}},
- {{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
- {{"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");
- }
|