Path: blob/main/contrib/llvm-project/llvm/lib/TargetParser/RISCVISAInfo.cpp
35233 views
//===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ----------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/TargetParser/RISCVISAInfo.h"9#include "llvm/ADT/STLExtras.h"10#include "llvm/ADT/StringExtras.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/Support/Errc.h"13#include "llvm/Support/Error.h"14#include "llvm/Support/raw_ostream.h"1516#include <array>17#include <atomic>18#include <optional>19#include <string>20#include <vector>2122using namespace llvm;2324namespace {2526struct RISCVSupportedExtension {27const char *Name;28/// Supported version.29RISCVISAUtils::ExtensionVersion Version;3031bool operator<(const RISCVSupportedExtension &RHS) const {32return StringRef(Name) < StringRef(RHS.Name);33}34};3536struct RISCVProfile {37StringLiteral Name;38StringLiteral MArch;3940bool operator<(const RISCVProfile &RHS) const {41return StringRef(Name) < StringRef(RHS.Name);42}43};4445} // end anonymous namespace4647static const char *RISCVGImplications[] = {48"i", "m", "a", "f", "d", "zicsr", "zifencei"49};5051#define GET_SUPPORTED_EXTENSIONS52#include "llvm/TargetParser/RISCVTargetParserDef.inc"5354#define GET_SUPPORTED_PROFILES55#include "llvm/TargetParser/RISCVTargetParserDef.inc"5657static void verifyTables() {58#ifndef NDEBUG59static std::atomic<bool> TableChecked(false);60if (!TableChecked.load(std::memory_order_relaxed)) {61assert(llvm::is_sorted(SupportedExtensions) &&62"Extensions are not sorted by name");63assert(llvm::is_sorted(SupportedExperimentalExtensions) &&64"Experimental extensions are not sorted by name");65assert(llvm::is_sorted(SupportedProfiles) &&66"Profiles are not sorted by name");67assert(llvm::is_sorted(SupportedExperimentalProfiles) &&68"Experimental profiles are not sorted by name");69TableChecked.store(true, std::memory_order_relaxed);70}71#endif72}7374static void PrintExtension(StringRef Name, StringRef Version,75StringRef Description) {76outs().indent(4);77unsigned VersionWidth = Description.empty() ? 0 : 10;78outs() << left_justify(Name, 21) << left_justify(Version, VersionWidth)79<< Description << "\n";80}8182void RISCVISAInfo::printSupportedExtensions(StringMap<StringRef> &DescMap) {83outs() << "All available -march extensions for RISC-V\n\n";84PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));8586RISCVISAUtils::OrderedExtensionMap ExtMap;87for (const auto &E : SupportedExtensions)88ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};89for (const auto &E : ExtMap) {90std::string Version =91std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);92PrintExtension(E.first, Version, DescMap[E.first]);93}9495outs() << "\nExperimental extensions\n";96ExtMap.clear();97for (const auto &E : SupportedExperimentalExtensions)98ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};99for (const auto &E : ExtMap) {100std::string Version =101std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);102PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);103}104105outs() << "\nSupported Profiles\n";106for (const auto &P : SupportedProfiles)107outs().indent(4) << P.Name << "\n";108109outs() << "\nExperimental Profiles\n";110for (const auto &P : SupportedExperimentalProfiles)111outs().indent(4) << P.Name << "\n";112113outs() << "\nUse -march to specify the target's extension.\n"114"For example, clang -march=rv32i_v1p0\n";115}116117void RISCVISAInfo::printEnabledExtensions(118bool IsRV64, std::set<StringRef> &EnabledFeatureNames,119StringMap<StringRef> &DescMap) {120outs() << "Extensions enabled for the given RISC-V target\n\n";121PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));122123RISCVISAUtils::OrderedExtensionMap FullExtMap;124RISCVISAUtils::OrderedExtensionMap ExtMap;125for (const auto &E : SupportedExtensions)126if (EnabledFeatureNames.count(E.Name) != 0) {127FullExtMap[E.Name] = {E.Version.Major, E.Version.Minor};128ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};129}130for (const auto &E : ExtMap) {131std::string Version =132std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);133PrintExtension(E.first, Version, DescMap[E.first]);134}135136outs() << "\nExperimental extensions\n";137ExtMap.clear();138for (const auto &E : SupportedExperimentalExtensions) {139StringRef Name(E.Name);140if (EnabledFeatureNames.count("experimental-" + Name.str()) != 0) {141FullExtMap[E.Name] = {E.Version.Major, E.Version.Minor};142ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};143}144}145for (const auto &E : ExtMap) {146std::string Version =147std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);148PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);149}150151unsigned XLen = IsRV64 ? 64 : 32;152if (auto ISAString = RISCVISAInfo::createFromExtMap(XLen, FullExtMap))153outs() << "\nISA String: " << ISAString.get()->toString() << "\n";154}155156static bool stripExperimentalPrefix(StringRef &Ext) {157return Ext.consume_front("experimental-");158}159160// This function finds the last character that doesn't belong to a version161// (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will162// consume [0-9]*p[0-9]* starting from the backward. An extension name will not163// end with a digit or the letter 'p', so this function will parse correctly.164// NOTE: This function is NOT able to take empty strings or strings that only165// have version numbers and no extension name. It assumes the extension name166// will be at least more than one character.167static size_t findLastNonVersionCharacter(StringRef Ext) {168assert(!Ext.empty() &&169"Already guarded by if-statement in ::parseArchString");170171int Pos = Ext.size() - 1;172while (Pos > 0 && isDigit(Ext[Pos]))173Pos--;174if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {175Pos--;176while (Pos > 0 && isDigit(Ext[Pos]))177Pos--;178}179return Pos;180}181182namespace {183struct LessExtName {184bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) {185return StringRef(LHS.Name) < RHS;186}187bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) {188return LHS < StringRef(RHS.Name);189}190};191} // namespace192193static std::optional<RISCVISAUtils::ExtensionVersion>194findDefaultVersion(StringRef ExtName) {195// Find default version of an extension.196// TODO: We might set default version based on profile or ISA spec.197for (auto &ExtInfo : {ArrayRef(SupportedExtensions),198ArrayRef(SupportedExperimentalExtensions)}) {199auto I = llvm::lower_bound(ExtInfo, ExtName, LessExtName());200201if (I == ExtInfo.end() || I->Name != ExtName)202continue;203204return I->Version;205}206return std::nullopt;207}208209static StringRef getExtensionTypeDesc(StringRef Ext) {210if (Ext.starts_with('s'))211return "standard supervisor-level extension";212if (Ext.starts_with('x'))213return "non-standard user-level extension";214if (Ext.starts_with('z'))215return "standard user-level extension";216return StringRef();217}218219static StringRef getExtensionType(StringRef Ext) {220if (Ext.starts_with('s'))221return "s";222if (Ext.starts_with('x'))223return "x";224if (Ext.starts_with('z'))225return "z";226return StringRef();227}228229static std::optional<RISCVISAUtils::ExtensionVersion>230isExperimentalExtension(StringRef Ext) {231auto I =232llvm::lower_bound(SupportedExperimentalExtensions, Ext, LessExtName());233if (I == std::end(SupportedExperimentalExtensions) || I->Name != Ext)234return std::nullopt;235236return I->Version;237}238239bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {240bool IsExperimental = stripExperimentalPrefix(Ext);241242ArrayRef<RISCVSupportedExtension> ExtInfo =243IsExperimental ? ArrayRef(SupportedExperimentalExtensions)244: ArrayRef(SupportedExtensions);245246auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());247return I != ExtInfo.end() && I->Name == Ext;248}249250bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {251verifyTables();252253for (auto ExtInfo : {ArrayRef(SupportedExtensions),254ArrayRef(SupportedExperimentalExtensions)}) {255auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());256if (I != ExtInfo.end() && I->Name == Ext)257return true;258}259260return false;261}262263bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,264unsigned MinorVersion) {265for (auto ExtInfo : {ArrayRef(SupportedExtensions),266ArrayRef(SupportedExperimentalExtensions)}) {267auto Range =268std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, LessExtName());269for (auto I = Range.first, E = Range.second; I != E; ++I)270if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion)271return true;272}273274return false;275}276277bool RISCVISAInfo::hasExtension(StringRef Ext) const {278stripExperimentalPrefix(Ext);279280if (!isSupportedExtension(Ext))281return false;282283return Exts.count(Ext.str()) != 0;284}285286std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions,287bool IgnoreUnknown) const {288std::vector<std::string> Features;289for (const auto &[ExtName, _] : Exts) {290// i is a base instruction set, not an extension (see291// https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa)292// and is not recognized in clang -cc1293if (ExtName == "i")294continue;295if (IgnoreUnknown && !isSupportedExtension(ExtName))296continue;297298if (isExperimentalExtension(ExtName)) {299Features.push_back((llvm::Twine("+experimental-") + ExtName).str());300} else {301Features.push_back((llvm::Twine("+") + ExtName).str());302}303}304if (AddAllExtensions) {305for (const RISCVSupportedExtension &Ext : SupportedExtensions) {306if (Exts.count(Ext.Name))307continue;308Features.push_back((llvm::Twine("-") + Ext.Name).str());309}310311for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {312if (Exts.count(Ext.Name))313continue;314Features.push_back((llvm::Twine("-experimental-") + Ext.Name).str());315}316}317return Features;318}319320static Error getError(const Twine &Message) {321return createStringError(errc::invalid_argument, Message);322}323324static Error getErrorForInvalidExt(StringRef ExtName) {325if (ExtName.size() == 1) {326return getError("unsupported standard user-level extension '" + ExtName +327"'");328}329return getError("unsupported " + getExtensionTypeDesc(ExtName) + " '" +330ExtName + "'");331}332333// Extensions may have a version number, and may be separated by334// an underscore '_' e.g.: rv32i2_m2.335// Version number is divided into major and minor version numbers,336// separated by a 'p'. If the minor version is 0 then 'p0' can be337// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.338static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,339unsigned &Minor, unsigned &ConsumeLength,340bool EnableExperimentalExtension,341bool ExperimentalExtensionVersionCheck) {342StringRef MajorStr, MinorStr;343Major = 0;344Minor = 0;345ConsumeLength = 0;346MajorStr = In.take_while(isDigit);347In = In.substr(MajorStr.size());348349if (!MajorStr.empty() && In.consume_front("p")) {350MinorStr = In.take_while(isDigit);351In = In.substr(MajorStr.size() + MinorStr.size() - 1);352353// Expected 'p' to be followed by minor version number.354if (MinorStr.empty()) {355return getError("minor version number missing after 'p' for extension '" +356Ext + "'");357}358}359360if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))361return getError("Failed to parse major version number for extension '" +362Ext + "'");363364if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))365return getError("Failed to parse minor version number for extension '" +366Ext + "'");367368ConsumeLength = MajorStr.size();369370if (!MinorStr.empty())371ConsumeLength += MinorStr.size() + 1 /*'p'*/;372373// Expected multi-character extension with version number to have no374// subsequent characters (i.e. must either end string or be followed by375// an underscore).376if (Ext.size() > 1 && In.size())377return getError(378"multi-character extensions must be separated by underscores");379380// If experimental extension, require use of current version number381if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {382if (!EnableExperimentalExtension)383return getError("requires '-menable-experimental-extensions' "384"for experimental extension '" +385Ext + "'");386387if (ExperimentalExtensionVersionCheck &&388(MajorStr.empty() && MinorStr.empty()))389return getError(390"experimental extension requires explicit version number `" + Ext +391"`");392393auto SupportedVers = *ExperimentalExtension;394if (ExperimentalExtensionVersionCheck &&395(Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {396std::string Error = "unsupported version number " + MajorStr.str();397if (!MinorStr.empty())398Error += "." + MinorStr.str();399Error += " for experimental extension '" + Ext.str() +400"' (this compiler supports " + utostr(SupportedVers.Major) +401"." + utostr(SupportedVers.Minor) + ")";402return getError(Error);403}404return Error::success();405}406407// Exception rule for `g`, we don't have clear version scheme for that on408// ISA spec.409if (Ext == "g")410return Error::success();411412if (MajorStr.empty() && MinorStr.empty()) {413if (auto DefaultVersion = findDefaultVersion(Ext)) {414Major = DefaultVersion->Major;415Minor = DefaultVersion->Minor;416}417// No matter found or not, return success, assume other place will418// verify.419return Error::success();420}421422if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))423return Error::success();424425if (!RISCVISAInfo::isSupportedExtension(Ext))426return getErrorForInvalidExt(Ext);427428std::string Error = "unsupported version number " + MajorStr.str();429if (!MinorStr.empty())430Error += "." + MinorStr.str();431Error += " for extension '" + Ext.str() + "'";432return getError(Error);433}434435llvm::Expected<std::unique_ptr<RISCVISAInfo>>436RISCVISAInfo::createFromExtMap(unsigned XLen,437const RISCVISAUtils::OrderedExtensionMap &Exts) {438assert(XLen == 32 || XLen == 64);439std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));440441ISAInfo->Exts = Exts;442443return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));444}445446llvm::Expected<std::unique_ptr<RISCVISAInfo>>447RISCVISAInfo::parseFeatures(unsigned XLen,448const std::vector<std::string> &Features) {449assert(XLen == 32 || XLen == 64);450std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));451452for (auto &Feature : Features) {453StringRef ExtName = Feature;454assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));455bool Add = ExtName[0] == '+';456ExtName = ExtName.drop_front(1); // Drop '+' or '-'457bool Experimental = stripExperimentalPrefix(ExtName);458auto ExtensionInfos = Experimental459? ArrayRef(SupportedExperimentalExtensions)460: ArrayRef(SupportedExtensions);461auto ExtensionInfoIterator =462llvm::lower_bound(ExtensionInfos, ExtName, LessExtName());463464// Not all features is related to ISA extension, like `relax` or465// `save-restore`, skip those feature.466if (ExtensionInfoIterator == ExtensionInfos.end() ||467ExtensionInfoIterator->Name != ExtName)468continue;469470if (Add)471ISAInfo->Exts[ExtName.str()] = ExtensionInfoIterator->Version;472else473ISAInfo->Exts.erase(ExtName.str());474}475476return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));477}478479llvm::Expected<std::unique_ptr<RISCVISAInfo>>480RISCVISAInfo::parseNormalizedArchString(StringRef Arch) {481// RISC-V ISA strings must be [a-z0-9_]482if (!llvm::all_of(483Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; }))484return getError("string may only contain [a-z0-9_]");485486// Must start with a valid base ISA name.487unsigned XLen = 0;488if (Arch.consume_front("rv32"))489XLen = 32;490else if (Arch.consume_front("rv64"))491XLen = 64;492493if (XLen == 0 || Arch.empty() || (Arch[0] != 'i' && Arch[0] != 'e'))494return getError("arch string must begin with valid base ISA");495496std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));497498// Each extension is of the form ${name}${major_version}p${minor_version}499// and separated by _. Split by _ and then extract the name and version500// information for each extension.501while (!Arch.empty()) {502if (Arch[0] == '_') {503if (Arch.size() == 1 || Arch[1] == '_')504return getError("extension name missing after separator '_'");505Arch = Arch.drop_front();506}507508size_t Idx = Arch.find('_');509StringRef Ext = Arch.slice(0, Idx);510Arch = Arch.slice(Idx, StringRef::npos);511512StringRef Prefix, MinorVersionStr;513std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');514if (MinorVersionStr.empty())515return getError("extension lacks version in expected format");516unsigned MajorVersion, MinorVersion;517if (MinorVersionStr.getAsInteger(10, MinorVersion))518return getError("failed to parse minor version number");519520// Split Prefix into the extension name and the major version number521// (the trailing digits of Prefix).522size_t VersionStart = Prefix.size();523while (VersionStart != 0) {524if (!isDigit(Prefix[VersionStart - 1]))525break;526--VersionStart;527}528if (VersionStart == Prefix.size())529return getError("extension lacks version in expected format");530531if (VersionStart == 0)532return getError("missing extension name");533534StringRef ExtName = Prefix.slice(0, VersionStart);535StringRef MajorVersionStr = Prefix.slice(VersionStart, StringRef::npos);536if (MajorVersionStr.getAsInteger(10, MajorVersion))537return getError("failed to parse major version number");538539if ((ExtName[0] == 'z' || ExtName[0] == 's' || ExtName[0] == 'x') &&540(ExtName.size() == 1 || isDigit(ExtName[1])))541return getError("'" + Twine(ExtName[0]) +542"' must be followed by a letter");543544if (!ISAInfo->Exts545.emplace(546ExtName.str(),547RISCVISAUtils::ExtensionVersion{MajorVersion, MinorVersion})548.second)549return getError("duplicate extension '" + ExtName + "'");550}551ISAInfo->updateImpliedLengths();552return std::move(ISAInfo);553}554555llvm::Expected<std::unique_ptr<RISCVISAInfo>>556RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,557bool ExperimentalExtensionVersionCheck) {558// RISC-V ISA strings must be [a-z0-9_]559if (!llvm::all_of(560Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; }))561return getError("string may only contain [a-z0-9_]");562563// ISA string must begin with rv32, rv64, or a profile.564unsigned XLen = 0;565if (Arch.consume_front("rv32")) {566XLen = 32;567} else if (Arch.consume_front("rv64")) {568XLen = 64;569} else {570// Try parsing as a profile.571auto ProfileCmp = [](StringRef Arch, const RISCVProfile &Profile) {572return Arch < Profile.Name;573};574auto I = llvm::upper_bound(SupportedProfiles, Arch, ProfileCmp);575bool FoundProfile = I != std::begin(SupportedProfiles) &&576Arch.starts_with(std::prev(I)->Name);577if (!FoundProfile) {578I = llvm::upper_bound(SupportedExperimentalProfiles, Arch, ProfileCmp);579FoundProfile = (I != std::begin(SupportedExperimentalProfiles) &&580Arch.starts_with(std::prev(I)->Name));581if (FoundProfile && !EnableExperimentalExtension) {582return getError("requires '-menable-experimental-extensions' "583"for profile '" +584std::prev(I)->Name + "'");585}586}587if (FoundProfile) {588--I;589std::string NewArch = I->MArch.str();590StringRef ArchWithoutProfile = Arch.drop_front(I->Name.size());591if (!ArchWithoutProfile.empty()) {592if (ArchWithoutProfile.front() != '_')593return getError("additional extensions must be after separator '_'");594NewArch += ArchWithoutProfile.str();595}596return parseArchString(NewArch, EnableExperimentalExtension,597ExperimentalExtensionVersionCheck);598}599}600601if (XLen == 0 || Arch.empty())602return getError(603"string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "604"profile name");605606std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));607608// The canonical order specified in ISA manual.609// Ref: Table 22.1 in RISC-V User-Level ISA V2.2610char Baseline = Arch.front();611// Skip the baseline.612Arch = Arch.drop_front();613614unsigned Major, Minor, ConsumeLength;615616// First letter should be 'e', 'i' or 'g'.617switch (Baseline) {618default:619return getError("first letter after \'rv" + Twine(XLen) +620"\' should be 'e', 'i' or 'g'");621case 'e':622case 'i':623// Baseline is `i` or `e`624if (auto E = getExtensionVersion(625StringRef(&Baseline, 1), Arch, Major, Minor, ConsumeLength,626EnableExperimentalExtension, ExperimentalExtensionVersionCheck))627return std::move(E);628629ISAInfo->Exts[std::string(1, Baseline)] = {Major, Minor};630break;631case 'g':632// g expands to extensions in RISCVGImplications.633if (!Arch.empty() && isDigit(Arch.front()))634return getError("version not supported for 'g'");635636// Versions for g are disallowed, and this was checked for previously.637ConsumeLength = 0;638639// No matter which version is given to `g`, we always set imafd to default640// version since the we don't have clear version scheme for that on641// ISA spec.642for (const char *Ext : RISCVGImplications) {643auto Version = findDefaultVersion(Ext);644assert(Version && "Default extension version not found?");645// Postpone AddExtension until end of this function646ISAInfo->Exts[std::string(Ext)] = {Version->Major, Version->Minor};647}648break;649}650651// Consume the base ISA version number and any '_' between rvxxx and the652// first extension653Arch = Arch.drop_front(ConsumeLength);654655while (!Arch.empty()) {656if (Arch.front() == '_') {657if (Arch.size() == 1 || Arch[1] == '_')658return getError("extension name missing after separator '_'");659Arch = Arch.drop_front();660}661662size_t Idx = Arch.find('_');663StringRef Ext = Arch.slice(0, Idx);664Arch = Arch.slice(Idx, StringRef::npos);665666do {667StringRef Name, Vers, Desc;668if (RISCVISAUtils::AllStdExts.contains(Ext.front())) {669Name = Ext.take_front(1);670Ext = Ext.drop_front();671Vers = Ext;672Desc = "standard user-level extension";673} else if (Ext.front() == 'z' || Ext.front() == 's' ||674Ext.front() == 'x') {675// Handle other types of extensions other than the standard676// general purpose and standard user-level extensions.677// Parse the ISA string containing non-standard user-level678// extensions, standard supervisor-level extensions and679// non-standard supervisor-level extensions.680// These extensions start with 'z', 's', 'x' prefixes, might have a681// version number (major, minor) and are separated by a single682// underscore '_'. We do not enforce a canonical order for them.683StringRef Type = getExtensionType(Ext);684Desc = getExtensionTypeDesc(Ext);685auto Pos = findLastNonVersionCharacter(Ext) + 1;686Name = Ext.substr(0, Pos);687Vers = Ext.substr(Pos);688Ext = StringRef();689690assert(!Type.empty() && "Empty type?");691if (Name.size() == Type.size())692return getError(Desc + " name missing after '" + Type + "'");693} else {694return getError("invalid standard user-level extension '" +695Twine(Ext.front()) + "'");696}697698unsigned Major, Minor, ConsumeLength;699if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,700EnableExperimentalExtension,701ExperimentalExtensionVersionCheck))702return E;703704if (Name.size() == 1)705Ext = Ext.substr(ConsumeLength);706707if (!RISCVISAInfo::isSupportedExtension(Name))708return getErrorForInvalidExt(Name);709710// Insert and error for duplicates.711if (!ISAInfo->Exts712.emplace(Name.str(),713RISCVISAUtils::ExtensionVersion{Major, Minor})714.second)715return getError("duplicated " + Desc + " '" + Name + "'");716717} while (!Ext.empty());718}719720return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));721}722723Error RISCVISAInfo::checkDependency() {724bool HasE = Exts.count("e") != 0;725bool HasI = Exts.count("i") != 0;726bool HasC = Exts.count("c") != 0;727bool HasF = Exts.count("f") != 0;728bool HasD = Exts.count("d") != 0;729bool HasZfinx = Exts.count("zfinx") != 0;730bool HasVector = Exts.count("zve32x") != 0;731bool HasZvl = MinVLen != 0;732bool HasZcmt = Exts.count("zcmt") != 0;733734if (HasI && HasE)735return getError("'I' and 'E' extensions are incompatible");736737if (HasF && HasZfinx)738return getError("'f' and 'zfinx' extensions are incompatible");739740if (HasZvl && !HasVector)741return getError(742"'zvl*b' requires 'v' or 'zve*' extension to also be specified");743744if (Exts.count("zvbb") && !HasVector)745return getError(746"'zvbb' requires 'v' or 'zve*' extension to also be specified");747748if (Exts.count("zvbc") && !Exts.count("zve64x"))749return getError(750"'zvbc' requires 'v' or 'zve64*' extension to also be specified");751752if ((Exts.count("zvkb") || Exts.count("zvkg") || Exts.count("zvkned") ||753Exts.count("zvknha") || Exts.count("zvksed") || Exts.count("zvksh")) &&754!HasVector)755return getError(756"'zvk*' requires 'v' or 'zve*' extension to also be specified");757758if (Exts.count("zvknhb") && !Exts.count("zve64x"))759return getError(760"'zvknhb' requires 'v' or 'zve64*' extension to also be specified");761762if ((HasZcmt || Exts.count("zcmp")) && HasD && (HasC || Exts.count("zcd")))763return getError(Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +764"' extension is incompatible with '" +765(HasC ? "c" : "zcd") +766"' extension when 'd' extension is enabled");767768if (XLen != 32 && Exts.count("zcf"))769return getError("'zcf' is only supported for 'rv32'");770771if (Exts.count("zacas") && !(Exts.count("a") || Exts.count("zaamo")))772return getError(773"'zacas' requires 'a' or 'zaamo' extension to also be specified");774775if (Exts.count("zabha") && !(Exts.count("a") || Exts.count("zaamo")))776return getError(777"'zabha' requires 'a' or 'zaamo' extension to also be specified");778779if (Exts.count("xwchc") != 0) {780if (XLen != 32)781return getError("'Xwchc' is only supported for 'rv32'");782783if (HasD)784return getError("'D' and 'Xwchc' extensions are incompatible");785786if (Exts.count("zcb") != 0)787return getError("'Xwchc' and 'Zcb' extensions are incompatible");788}789790return Error::success();791}792793struct ImpliedExtsEntry {794StringLiteral Name;795const char *ImpliedExt;796797bool operator<(const ImpliedExtsEntry &Other) const {798return Name < Other.Name;799}800};801802static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) {803return LHS.Name < RHS;804}805806static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) {807return LHS < RHS.Name;808}809810#define GET_IMPLIED_EXTENSIONS811#include "llvm/TargetParser/RISCVTargetParserDef.inc"812813void RISCVISAInfo::updateImplication() {814bool HasE = Exts.count("e") != 0;815bool HasI = Exts.count("i") != 0;816817// If not in e extension and i extension does not exist, i extension is818// implied819if (!HasE && !HasI) {820auto Version = findDefaultVersion("i");821Exts["i"] = *Version;822}823824if (HasE && HasI)825Exts.erase("i");826827assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");828829// This loop may execute over 1 iteration since implication can be layered830// Exits loop if no more implication is applied831SmallVector<StringRef, 16> WorkList;832for (auto const &Ext : Exts)833WorkList.push_back(Ext.first);834835while (!WorkList.empty()) {836StringRef ExtName = WorkList.pop_back_val();837auto Range = std::equal_range(std::begin(ImpliedExts),838std::end(ImpliedExts), ExtName);839std::for_each(Range.first, Range.second,840[&](const ImpliedExtsEntry &Implied) {841const char *ImpliedExt = Implied.ImpliedExt;842if (Exts.count(ImpliedExt))843return;844auto Version = findDefaultVersion(ImpliedExt);845Exts[ImpliedExt] = *Version;846WorkList.push_back(ImpliedExt);847});848}849850// Add Zcf if Zce and F are enabled on RV32.851if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&852!Exts.count("zcf")) {853auto Version = findDefaultVersion("zcf");854Exts["zcf"] = *Version;855}856}857858static constexpr StringLiteral CombineIntoExts[] = {859{"zk"}, {"zkn"}, {"zks"}, {"zvkn"}, {"zvknc"},860{"zvkng"}, {"zvks"}, {"zvksc"}, {"zvksg"},861};862863void RISCVISAInfo::updateCombination() {864bool MadeChange = false;865do {866MadeChange = false;867for (StringRef CombineExt : CombineIntoExts) {868if (Exts.count(CombineExt.str()))869continue;870871// Look up the extension in the ImpliesExt table to find everything it872// depends on.873auto Range = std::equal_range(std::begin(ImpliedExts),874std::end(ImpliedExts), CombineExt);875bool HasAllRequiredFeatures = std::all_of(876Range.first, Range.second, [&](const ImpliedExtsEntry &Implied) {877return Exts.count(Implied.ImpliedExt);878});879if (HasAllRequiredFeatures) {880auto Version = findDefaultVersion(CombineExt);881Exts[CombineExt.str()] = *Version;882MadeChange = true;883}884}885} while (MadeChange);886}887888void RISCVISAInfo::updateImpliedLengths() {889assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 &&890"Expected lengths to be initialied to zero");891892// TODO: Handle q extension.893if (Exts.count("d"))894FLen = 64;895else if (Exts.count("f"))896FLen = 32;897898if (Exts.count("v")) {899MaxELenFp = std::max(MaxELenFp, 64u);900MaxELen = std::max(MaxELen, 64u);901}902903for (auto const &Ext : Exts) {904StringRef ExtName = Ext.first;905// Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d)906if (ExtName.consume_front("zve")) {907unsigned ZveELen;908if (ExtName.consumeInteger(10, ZveELen))909continue;910911if (ExtName == "f")912MaxELenFp = std::max(MaxELenFp, 32u);913else if (ExtName == "d")914MaxELenFp = std::max(MaxELenFp, 64u);915else if (ExtName != "x")916continue;917918MaxELen = std::max(MaxELen, ZveELen);919continue;920}921922// Infer MinVLen from zvl*b.923if (ExtName.consume_front("zvl")) {924unsigned ZvlLen;925if (ExtName.consumeInteger(10, ZvlLen))926continue;927928if (ExtName != "b")929continue;930931MinVLen = std::max(MinVLen, ZvlLen);932continue;933}934}935}936937std::string RISCVISAInfo::toString() const {938std::string Buffer;939raw_string_ostream Arch(Buffer);940941Arch << "rv" << XLen;942943ListSeparator LS("_");944for (auto const &Ext : Exts) {945StringRef ExtName = Ext.first;946auto ExtInfo = Ext.second;947Arch << LS << ExtName;948Arch << ExtInfo.Major << "p" << ExtInfo.Minor;949}950951return Arch.str();952}953954llvm::Expected<std::unique_ptr<RISCVISAInfo>>955RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {956ISAInfo->updateImplication();957ISAInfo->updateCombination();958ISAInfo->updateImpliedLengths();959960if (Error Result = ISAInfo->checkDependency())961return std::move(Result);962return std::move(ISAInfo);963}964965StringRef RISCVISAInfo::computeDefaultABI() const {966if (XLen == 32) {967if (Exts.count("e"))968return "ilp32e";969if (Exts.count("d"))970return "ilp32d";971if (Exts.count("f"))972return "ilp32f";973return "ilp32";974} else if (XLen == 64) {975if (Exts.count("e"))976return "lp64e";977if (Exts.count("d"))978return "lp64d";979if (Exts.count("f"))980return "lp64f";981return "lp64";982}983llvm_unreachable("Invalid XLEN");984}985986bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext) {987if (Ext.empty())988return false;989990auto Pos = findLastNonVersionCharacter(Ext) + 1;991StringRef Name = Ext.substr(0, Pos);992StringRef Vers = Ext.substr(Pos);993if (Vers.empty())994return false;995996unsigned Major, Minor, ConsumeLength;997if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,998true, true)) {999consumeError(std::move(E));1000return false;1001}10021003return true;1004}10051006std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {1007if (Ext.empty())1008return std::string();10091010auto Pos = findLastNonVersionCharacter(Ext) + 1;1011StringRef Name = Ext.substr(0, Pos);10121013if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))1014return std::string();10151016if (!isSupportedExtension(Name))1017return std::string();10181019return isExperimentalExtension(Name) ? "experimental-" + Name.str()1020: Name.str();1021}102210231024