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