1733a8778SCraig Topper //===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ----------------------===// 2733a8778SCraig Topper // 3733a8778SCraig Topper // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4733a8778SCraig Topper // See https://llvm.org/LICENSE.txt for license information. 5733a8778SCraig Topper // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6733a8778SCraig Topper // 7733a8778SCraig Topper //===----------------------------------------------------------------------===// 8733a8778SCraig Topper 9733a8778SCraig Topper #include "llvm/TargetParser/RISCVISAInfo.h" 10733a8778SCraig Topper #include "llvm/ADT/STLExtras.h" 11733a8778SCraig Topper #include "llvm/ADT/StringExtras.h" 12733a8778SCraig Topper #include "llvm/ADT/StringRef.h" 13733a8778SCraig Topper #include "llvm/Support/Errc.h" 14733a8778SCraig Topper #include "llvm/Support/Error.h" 15733a8778SCraig Topper #include "llvm/Support/raw_ostream.h" 16733a8778SCraig Topper 17733a8778SCraig Topper #include <array> 18733a8778SCraig Topper #include <atomic> 19733a8778SCraig Topper #include <optional> 20733a8778SCraig Topper #include <string> 21733a8778SCraig Topper #include <vector> 22733a8778SCraig Topper 23733a8778SCraig Topper using namespace llvm; 24733a8778SCraig Topper 25733a8778SCraig Topper namespace { 26733a8778SCraig Topper 27733a8778SCraig Topper struct RISCVSupportedExtension { 28733a8778SCraig Topper const char *Name; 29733a8778SCraig Topper /// Supported version. 30733a8778SCraig Topper RISCVISAUtils::ExtensionVersion Version; 31733a8778SCraig Topper 32733a8778SCraig Topper bool operator<(const RISCVSupportedExtension &RHS) const { 33733a8778SCraig Topper return StringRef(Name) < StringRef(RHS.Name); 34733a8778SCraig Topper } 35733a8778SCraig Topper }; 36733a8778SCraig Topper 37733a8778SCraig Topper struct RISCVProfile { 38733a8778SCraig Topper StringLiteral Name; 39733a8778SCraig Topper StringLiteral MArch; 4083f065d5SAlex Bradbury 4183f065d5SAlex Bradbury bool operator<(const RISCVProfile &RHS) const { 4283f065d5SAlex Bradbury return StringRef(Name) < StringRef(RHS.Name); 4383f065d5SAlex Bradbury } 44733a8778SCraig Topper }; 45733a8778SCraig Topper 46733a8778SCraig Topper } // end anonymous namespace 47733a8778SCraig Topper 48733a8778SCraig Topper static const char *RISCVGImplications[] = { 49733a8778SCraig Topper "i", "m", "a", "f", "d", "zicsr", "zifencei" 50733a8778SCraig Topper }; 51733a8778SCraig Topper 5280628ee0SCraig Topper #define GET_SUPPORTED_EXTENSIONS 5380628ee0SCraig Topper #include "llvm/TargetParser/RISCVTargetParserDef.inc" 54733a8778SCraig Topper 55c705c684SPengcheng Wang #define GET_SUPPORTED_PROFILES 56c705c684SPengcheng Wang #include "llvm/TargetParser/RISCVTargetParserDef.inc" 57733a8778SCraig Topper 58733a8778SCraig Topper static void verifyTables() { 59733a8778SCraig Topper #ifndef NDEBUG 60733a8778SCraig Topper static std::atomic<bool> TableChecked(false); 61733a8778SCraig Topper if (!TableChecked.load(std::memory_order_relaxed)) { 62733a8778SCraig Topper assert(llvm::is_sorted(SupportedExtensions) && 63733a8778SCraig Topper "Extensions are not sorted by name"); 64733a8778SCraig Topper assert(llvm::is_sorted(SupportedExperimentalExtensions) && 65733a8778SCraig Topper "Experimental extensions are not sorted by name"); 6683f065d5SAlex Bradbury assert(llvm::is_sorted(SupportedProfiles) && 6783f065d5SAlex Bradbury "Profiles are not sorted by name"); 6883f065d5SAlex Bradbury assert(llvm::is_sorted(SupportedExperimentalProfiles) && 6983f065d5SAlex Bradbury "Experimental profiles are not sorted by name"); 70733a8778SCraig Topper TableChecked.store(true, std::memory_order_relaxed); 71733a8778SCraig Topper } 72733a8778SCraig Topper #endif 73733a8778SCraig Topper } 74733a8778SCraig Topper 75733a8778SCraig Topper static void PrintExtension(StringRef Name, StringRef Version, 76733a8778SCraig Topper StringRef Description) { 77733a8778SCraig Topper outs().indent(4); 78733a8778SCraig Topper unsigned VersionWidth = Description.empty() ? 0 : 10; 79733a8778SCraig Topper outs() << left_justify(Name, 21) << left_justify(Version, VersionWidth) 80733a8778SCraig Topper << Description << "\n"; 81733a8778SCraig Topper } 82733a8778SCraig Topper 83eee5d2d3SMichael Maitland void RISCVISAInfo::printSupportedExtensions(StringMap<StringRef> &DescMap) { 84733a8778SCraig Topper outs() << "All available -march extensions for RISC-V\n\n"; 85733a8778SCraig Topper PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description")); 86733a8778SCraig Topper 87de375fbcSCraig Topper RISCVISAUtils::OrderedExtensionMap ExtMap; 88733a8778SCraig Topper for (const auto &E : SupportedExtensions) 89733a8778SCraig Topper ExtMap[E.Name] = {E.Version.Major, E.Version.Minor}; 90733a8778SCraig Topper for (const auto &E : ExtMap) { 91733a8778SCraig Topper std::string Version = 92733a8778SCraig Topper std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor); 93733a8778SCraig Topper PrintExtension(E.first, Version, DescMap[E.first]); 94733a8778SCraig Topper } 95733a8778SCraig Topper 96733a8778SCraig Topper outs() << "\nExperimental extensions\n"; 97733a8778SCraig Topper ExtMap.clear(); 98733a8778SCraig Topper for (const auto &E : SupportedExperimentalExtensions) 99733a8778SCraig Topper ExtMap[E.Name] = {E.Version.Major, E.Version.Minor}; 100733a8778SCraig Topper for (const auto &E : ExtMap) { 101733a8778SCraig Topper std::string Version = 102733a8778SCraig Topper std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor); 103733a8778SCraig Topper PrintExtension(E.first, Version, DescMap["experimental-" + E.first]); 104733a8778SCraig Topper } 105733a8778SCraig Topper 106ab8ac36fSCraig Topper outs() << "\nSupported Profiles\n"; 107ab8ac36fSCraig Topper for (const auto &P : SupportedProfiles) 108ab8ac36fSCraig Topper outs().indent(4) << P.Name << "\n"; 109ab8ac36fSCraig Topper 110891d6871SAlex Bradbury outs() << "\nExperimental Profiles\n"; 111891d6871SAlex Bradbury for (const auto &P : SupportedExperimentalProfiles) 112891d6871SAlex Bradbury outs().indent(4) << P.Name << "\n"; 113891d6871SAlex Bradbury 114733a8778SCraig Topper outs() << "\nUse -march to specify the target's extension.\n" 115733a8778SCraig Topper "For example, clang -march=rv32i_v1p0\n"; 116733a8778SCraig Topper } 117733a8778SCraig Topper 118eee5d2d3SMichael Maitland void RISCVISAInfo::printEnabledExtensions( 119eee5d2d3SMichael Maitland bool IsRV64, std::set<StringRef> &EnabledFeatureNames, 120eee5d2d3SMichael Maitland StringMap<StringRef> &DescMap) { 121eee5d2d3SMichael Maitland outs() << "Extensions enabled for the given RISC-V target\n\n"; 122eee5d2d3SMichael Maitland PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description")); 123eee5d2d3SMichael Maitland 124eee5d2d3SMichael Maitland RISCVISAUtils::OrderedExtensionMap FullExtMap; 125eee5d2d3SMichael Maitland RISCVISAUtils::OrderedExtensionMap ExtMap; 126eee5d2d3SMichael Maitland for (const auto &E : SupportedExtensions) 127eee5d2d3SMichael Maitland if (EnabledFeatureNames.count(E.Name) != 0) { 128eee5d2d3SMichael Maitland FullExtMap[E.Name] = {E.Version.Major, E.Version.Minor}; 129eee5d2d3SMichael Maitland ExtMap[E.Name] = {E.Version.Major, E.Version.Minor}; 130eee5d2d3SMichael Maitland } 131eee5d2d3SMichael Maitland for (const auto &E : ExtMap) { 132eee5d2d3SMichael Maitland std::string Version = 133eee5d2d3SMichael Maitland std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor); 134eee5d2d3SMichael Maitland PrintExtension(E.first, Version, DescMap[E.first]); 135eee5d2d3SMichael Maitland } 136eee5d2d3SMichael Maitland 137eee5d2d3SMichael Maitland outs() << "\nExperimental extensions\n"; 138eee5d2d3SMichael Maitland ExtMap.clear(); 139eee5d2d3SMichael Maitland for (const auto &E : SupportedExperimentalExtensions) { 140eee5d2d3SMichael Maitland StringRef Name(E.Name); 141eee5d2d3SMichael Maitland if (EnabledFeatureNames.count("experimental-" + Name.str()) != 0) { 142eee5d2d3SMichael Maitland FullExtMap[E.Name] = {E.Version.Major, E.Version.Minor}; 143eee5d2d3SMichael Maitland ExtMap[E.Name] = {E.Version.Major, E.Version.Minor}; 144eee5d2d3SMichael Maitland } 145eee5d2d3SMichael Maitland } 146eee5d2d3SMichael Maitland for (const auto &E : ExtMap) { 147eee5d2d3SMichael Maitland std::string Version = 148eee5d2d3SMichael Maitland std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor); 149eee5d2d3SMichael Maitland PrintExtension(E.first, Version, DescMap["experimental-" + E.first]); 150eee5d2d3SMichael Maitland } 151eee5d2d3SMichael Maitland 152eee5d2d3SMichael Maitland unsigned XLen = IsRV64 ? 64 : 32; 153eee5d2d3SMichael Maitland if (auto ISAString = RISCVISAInfo::createFromExtMap(XLen, FullExtMap)) 154cd6750faSShao-Ce SUN outs() << "\nISA String: " << ISAString.get()->toString() << "\n"; 155eee5d2d3SMichael Maitland } 156eee5d2d3SMichael Maitland 157733a8778SCraig Topper static bool stripExperimentalPrefix(StringRef &Ext) { 158733a8778SCraig Topper return Ext.consume_front("experimental-"); 159733a8778SCraig Topper } 160733a8778SCraig Topper 161733a8778SCraig Topper // This function finds the last character that doesn't belong to a version 162733a8778SCraig Topper // (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will 163733a8778SCraig Topper // consume [0-9]*p[0-9]* starting from the backward. An extension name will not 164733a8778SCraig Topper // end with a digit or the letter 'p', so this function will parse correctly. 165733a8778SCraig Topper // NOTE: This function is NOT able to take empty strings or strings that only 166733a8778SCraig Topper // have version numbers and no extension name. It assumes the extension name 167733a8778SCraig Topper // will be at least more than one character. 168733a8778SCraig Topper static size_t findLastNonVersionCharacter(StringRef Ext) { 169733a8778SCraig Topper assert(!Ext.empty() && 170733a8778SCraig Topper "Already guarded by if-statement in ::parseArchString"); 171733a8778SCraig Topper 172733a8778SCraig Topper int Pos = Ext.size() - 1; 173733a8778SCraig Topper while (Pos > 0 && isDigit(Ext[Pos])) 174733a8778SCraig Topper Pos--; 175733a8778SCraig Topper if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) { 176733a8778SCraig Topper Pos--; 177733a8778SCraig Topper while (Pos > 0 && isDigit(Ext[Pos])) 178733a8778SCraig Topper Pos--; 179733a8778SCraig Topper } 180733a8778SCraig Topper return Pos; 181733a8778SCraig Topper } 182733a8778SCraig Topper 183733a8778SCraig Topper namespace { 184733a8778SCraig Topper struct LessExtName { 185733a8778SCraig Topper bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) { 186733a8778SCraig Topper return StringRef(LHS.Name) < RHS; 187733a8778SCraig Topper } 188733a8778SCraig Topper bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) { 189733a8778SCraig Topper return LHS < StringRef(RHS.Name); 190733a8778SCraig Topper } 191733a8778SCraig Topper }; 192733a8778SCraig Topper } // namespace 193733a8778SCraig Topper 194733a8778SCraig Topper static std::optional<RISCVISAUtils::ExtensionVersion> 195733a8778SCraig Topper findDefaultVersion(StringRef ExtName) { 196733a8778SCraig Topper // Find default version of an extension. 197733a8778SCraig Topper // TODO: We might set default version based on profile or ISA spec. 198733a8778SCraig Topper for (auto &ExtInfo : {ArrayRef(SupportedExtensions), 199733a8778SCraig Topper ArrayRef(SupportedExperimentalExtensions)}) { 200733a8778SCraig Topper auto I = llvm::lower_bound(ExtInfo, ExtName, LessExtName()); 201733a8778SCraig Topper 202733a8778SCraig Topper if (I == ExtInfo.end() || I->Name != ExtName) 203733a8778SCraig Topper continue; 204733a8778SCraig Topper 205733a8778SCraig Topper return I->Version; 206733a8778SCraig Topper } 207733a8778SCraig Topper return std::nullopt; 208733a8778SCraig Topper } 209733a8778SCraig Topper 210733a8778SCraig Topper static StringRef getExtensionTypeDesc(StringRef Ext) { 211bd488c12SCraig Topper if (Ext.starts_with('s')) 212733a8778SCraig Topper return "standard supervisor-level extension"; 213bd488c12SCraig Topper if (Ext.starts_with('x')) 214733a8778SCraig Topper return "non-standard user-level extension"; 215bd488c12SCraig Topper if (Ext.starts_with('z')) 216733a8778SCraig Topper return "standard user-level extension"; 217733a8778SCraig Topper return StringRef(); 218733a8778SCraig Topper } 219733a8778SCraig Topper 220733a8778SCraig Topper static StringRef getExtensionType(StringRef Ext) { 221bd488c12SCraig Topper if (Ext.starts_with('s')) 222733a8778SCraig Topper return "s"; 223bd488c12SCraig Topper if (Ext.starts_with('x')) 224733a8778SCraig Topper return "x"; 225bd488c12SCraig Topper if (Ext.starts_with('z')) 226733a8778SCraig Topper return "z"; 227733a8778SCraig Topper return StringRef(); 228733a8778SCraig Topper } 229733a8778SCraig Topper 230733a8778SCraig Topper static std::optional<RISCVISAUtils::ExtensionVersion> 231733a8778SCraig Topper isExperimentalExtension(StringRef Ext) { 232733a8778SCraig Topper auto I = 233733a8778SCraig Topper llvm::lower_bound(SupportedExperimentalExtensions, Ext, LessExtName()); 234733a8778SCraig Topper if (I == std::end(SupportedExperimentalExtensions) || I->Name != Ext) 235733a8778SCraig Topper return std::nullopt; 236733a8778SCraig Topper 237733a8778SCraig Topper return I->Version; 238733a8778SCraig Topper } 239733a8778SCraig Topper 240733a8778SCraig Topper bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) { 241733a8778SCraig Topper bool IsExperimental = stripExperimentalPrefix(Ext); 242733a8778SCraig Topper 243733a8778SCraig Topper ArrayRef<RISCVSupportedExtension> ExtInfo = 244733a8778SCraig Topper IsExperimental ? ArrayRef(SupportedExperimentalExtensions) 245733a8778SCraig Topper : ArrayRef(SupportedExtensions); 246733a8778SCraig Topper 247733a8778SCraig Topper auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName()); 248733a8778SCraig Topper return I != ExtInfo.end() && I->Name == Ext; 249733a8778SCraig Topper } 250733a8778SCraig Topper 251733a8778SCraig Topper bool RISCVISAInfo::isSupportedExtension(StringRef Ext) { 252733a8778SCraig Topper verifyTables(); 253733a8778SCraig Topper 254733a8778SCraig Topper for (auto ExtInfo : {ArrayRef(SupportedExtensions), 255733a8778SCraig Topper ArrayRef(SupportedExperimentalExtensions)}) { 256733a8778SCraig Topper auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName()); 257733a8778SCraig Topper if (I != ExtInfo.end() && I->Name == Ext) 258733a8778SCraig Topper return true; 259733a8778SCraig Topper } 260733a8778SCraig Topper 261733a8778SCraig Topper return false; 262733a8778SCraig Topper } 263733a8778SCraig Topper 264733a8778SCraig Topper bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion, 265733a8778SCraig Topper unsigned MinorVersion) { 266733a8778SCraig Topper for (auto ExtInfo : {ArrayRef(SupportedExtensions), 267733a8778SCraig Topper ArrayRef(SupportedExperimentalExtensions)}) { 268733a8778SCraig Topper auto Range = 269733a8778SCraig Topper std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, LessExtName()); 270733a8778SCraig Topper for (auto I = Range.first, E = Range.second; I != E; ++I) 271733a8778SCraig Topper if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion) 272733a8778SCraig Topper return true; 273733a8778SCraig Topper } 274733a8778SCraig Topper 275733a8778SCraig Topper return false; 276733a8778SCraig Topper } 277733a8778SCraig Topper 278733a8778SCraig Topper bool RISCVISAInfo::hasExtension(StringRef Ext) const { 279733a8778SCraig Topper stripExperimentalPrefix(Ext); 280733a8778SCraig Topper 281733a8778SCraig Topper if (!isSupportedExtension(Ext)) 282733a8778SCraig Topper return false; 283733a8778SCraig Topper 284733a8778SCraig Topper return Exts.count(Ext.str()) != 0; 285733a8778SCraig Topper } 286733a8778SCraig Topper 287733a8778SCraig Topper std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions, 288733a8778SCraig Topper bool IgnoreUnknown) const { 289733a8778SCraig Topper std::vector<std::string> Features; 290733a8778SCraig Topper for (const auto &[ExtName, _] : Exts) { 291733a8778SCraig Topper // i is a base instruction set, not an extension (see 292733a8778SCraig Topper // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa) 293733a8778SCraig Topper // and is not recognized in clang -cc1 294733a8778SCraig Topper if (ExtName == "i") 295733a8778SCraig Topper continue; 296733a8778SCraig Topper if (IgnoreUnknown && !isSupportedExtension(ExtName)) 297733a8778SCraig Topper continue; 298733a8778SCraig Topper 299733a8778SCraig Topper if (isExperimentalExtension(ExtName)) { 300733a8778SCraig Topper Features.push_back((llvm::Twine("+experimental-") + ExtName).str()); 301733a8778SCraig Topper } else { 302733a8778SCraig Topper Features.push_back((llvm::Twine("+") + ExtName).str()); 303733a8778SCraig Topper } 304733a8778SCraig Topper } 305733a8778SCraig Topper if (AddAllExtensions) { 306733a8778SCraig Topper for (const RISCVSupportedExtension &Ext : SupportedExtensions) { 307733a8778SCraig Topper if (Exts.count(Ext.Name)) 308733a8778SCraig Topper continue; 309733a8778SCraig Topper Features.push_back((llvm::Twine("-") + Ext.Name).str()); 310733a8778SCraig Topper } 311733a8778SCraig Topper 312733a8778SCraig Topper for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) { 313733a8778SCraig Topper if (Exts.count(Ext.Name)) 314733a8778SCraig Topper continue; 315733a8778SCraig Topper Features.push_back((llvm::Twine("-experimental-") + Ext.Name).str()); 316733a8778SCraig Topper } 317733a8778SCraig Topper } 318733a8778SCraig Topper return Features; 319733a8778SCraig Topper } 320733a8778SCraig Topper 321c785eaecSCraig Topper static Error getError(const Twine &Message) { 322c785eaecSCraig Topper return createStringError(errc::invalid_argument, Message); 323733a8778SCraig Topper } 324c785eaecSCraig Topper 325c785eaecSCraig Topper static Error getErrorForInvalidExt(StringRef ExtName) { 326c785eaecSCraig Topper if (ExtName.size() == 1) { 327c785eaecSCraig Topper return getError("unsupported standard user-level extension '" + ExtName + 328c785eaecSCraig Topper "'"); 329c785eaecSCraig Topper } 330c785eaecSCraig Topper return getError("unsupported " + getExtensionTypeDesc(ExtName) + " '" + 331c785eaecSCraig Topper ExtName + "'"); 332733a8778SCraig Topper } 333733a8778SCraig Topper 334733a8778SCraig Topper // Extensions may have a version number, and may be separated by 335733a8778SCraig Topper // an underscore '_' e.g.: rv32i2_m2. 336733a8778SCraig Topper // Version number is divided into major and minor version numbers, 337733a8778SCraig Topper // separated by a 'p'. If the minor version is 0 then 'p0' can be 338733a8778SCraig Topper // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. 339733a8778SCraig Topper static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, 340733a8778SCraig Topper unsigned &Minor, unsigned &ConsumeLength, 341733a8778SCraig Topper bool EnableExperimentalExtension, 342733a8778SCraig Topper bool ExperimentalExtensionVersionCheck) { 343733a8778SCraig Topper StringRef MajorStr, MinorStr; 344733a8778SCraig Topper Major = 0; 345733a8778SCraig Topper Minor = 0; 346733a8778SCraig Topper ConsumeLength = 0; 347733a8778SCraig Topper MajorStr = In.take_while(isDigit); 348733a8778SCraig Topper In = In.substr(MajorStr.size()); 349733a8778SCraig Topper 350733a8778SCraig Topper if (!MajorStr.empty() && In.consume_front("p")) { 351733a8778SCraig Topper MinorStr = In.take_while(isDigit); 352733a8778SCraig Topper In = In.substr(MajorStr.size() + MinorStr.size() - 1); 353733a8778SCraig Topper 354733a8778SCraig Topper // Expected 'p' to be followed by minor version number. 355733a8778SCraig Topper if (MinorStr.empty()) { 356c785eaecSCraig Topper return getError("minor version number missing after 'p' for extension '" + 357c785eaecSCraig Topper Ext + "'"); 358733a8778SCraig Topper } 359733a8778SCraig Topper } 360733a8778SCraig Topper 361733a8778SCraig Topper if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major)) 362c785eaecSCraig Topper return getError("Failed to parse major version number for extension '" + 363c785eaecSCraig Topper Ext + "'"); 364733a8778SCraig Topper 365733a8778SCraig Topper if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor)) 366c785eaecSCraig Topper return getError("Failed to parse minor version number for extension '" + 367c785eaecSCraig Topper Ext + "'"); 368733a8778SCraig Topper 369733a8778SCraig Topper ConsumeLength = MajorStr.size(); 370733a8778SCraig Topper 371733a8778SCraig Topper if (!MinorStr.empty()) 372733a8778SCraig Topper ConsumeLength += MinorStr.size() + 1 /*'p'*/; 373733a8778SCraig Topper 374733a8778SCraig Topper // Expected multi-character extension with version number to have no 375733a8778SCraig Topper // subsequent characters (i.e. must either end string or be followed by 376733a8778SCraig Topper // an underscore). 377733a8778SCraig Topper if (Ext.size() > 1 && In.size()) 378c785eaecSCraig Topper return getError( 379733a8778SCraig Topper "multi-character extensions must be separated by underscores"); 380733a8778SCraig Topper 381733a8778SCraig Topper // If experimental extension, require use of current version number 382733a8778SCraig Topper if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { 383733a8778SCraig Topper if (!EnableExperimentalExtension) 384c785eaecSCraig Topper return getError("requires '-menable-experimental-extensions' " 385733a8778SCraig Topper "for experimental extension '" + 386733a8778SCraig Topper Ext + "'"); 387733a8778SCraig Topper 388733a8778SCraig Topper if (ExperimentalExtensionVersionCheck && 389733a8778SCraig Topper (MajorStr.empty() && MinorStr.empty())) 390c785eaecSCraig Topper return getError( 391733a8778SCraig Topper "experimental extension requires explicit version number `" + Ext + 392733a8778SCraig Topper "`"); 393733a8778SCraig Topper 394733a8778SCraig Topper auto SupportedVers = *ExperimentalExtension; 395733a8778SCraig Topper if (ExperimentalExtensionVersionCheck && 396733a8778SCraig Topper (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) { 397733a8778SCraig Topper std::string Error = "unsupported version number " + MajorStr.str(); 398733a8778SCraig Topper if (!MinorStr.empty()) 399733a8778SCraig Topper Error += "." + MinorStr.str(); 400733a8778SCraig Topper Error += " for experimental extension '" + Ext.str() + 401733a8778SCraig Topper "' (this compiler supports " + utostr(SupportedVers.Major) + 402733a8778SCraig Topper "." + utostr(SupportedVers.Minor) + ")"; 403c785eaecSCraig Topper return getError(Error); 404733a8778SCraig Topper } 405733a8778SCraig Topper return Error::success(); 406733a8778SCraig Topper } 407733a8778SCraig Topper 408733a8778SCraig Topper // Exception rule for `g`, we don't have clear version scheme for that on 409733a8778SCraig Topper // ISA spec. 410733a8778SCraig Topper if (Ext == "g") 411733a8778SCraig Topper return Error::success(); 412733a8778SCraig Topper 413733a8778SCraig Topper if (MajorStr.empty() && MinorStr.empty()) { 414733a8778SCraig Topper if (auto DefaultVersion = findDefaultVersion(Ext)) { 415733a8778SCraig Topper Major = DefaultVersion->Major; 416733a8778SCraig Topper Minor = DefaultVersion->Minor; 417733a8778SCraig Topper } 418733a8778SCraig Topper // No matter found or not, return success, assume other place will 419733a8778SCraig Topper // verify. 420733a8778SCraig Topper return Error::success(); 421733a8778SCraig Topper } 422733a8778SCraig Topper 423733a8778SCraig Topper if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor)) 424733a8778SCraig Topper return Error::success(); 425733a8778SCraig Topper 426733a8778SCraig Topper if (!RISCVISAInfo::isSupportedExtension(Ext)) 427c785eaecSCraig Topper return getErrorForInvalidExt(Ext); 428733a8778SCraig Topper 429c785eaecSCraig Topper std::string Error = "unsupported version number " + MajorStr.str(); 430733a8778SCraig Topper if (!MinorStr.empty()) 431733a8778SCraig Topper Error += "." + MinorStr.str(); 432733a8778SCraig Topper Error += " for extension '" + Ext.str() + "'"; 433c785eaecSCraig Topper return getError(Error); 434733a8778SCraig Topper } 435733a8778SCraig Topper 436733a8778SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>> 43766470112SCraig Topper RISCVISAInfo::createFromExtMap(unsigned XLen, 43866470112SCraig Topper const RISCVISAUtils::OrderedExtensionMap &Exts) { 43966470112SCraig Topper assert(XLen == 32 || XLen == 64); 44066470112SCraig Topper std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); 44166470112SCraig Topper 44266470112SCraig Topper ISAInfo->Exts = Exts; 44366470112SCraig Topper 44466470112SCraig Topper return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo)); 44566470112SCraig Topper } 44666470112SCraig Topper 44766470112SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>> 448733a8778SCraig Topper RISCVISAInfo::parseFeatures(unsigned XLen, 449733a8778SCraig Topper const std::vector<std::string> &Features) { 450733a8778SCraig Topper assert(XLen == 32 || XLen == 64); 451733a8778SCraig Topper std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); 452733a8778SCraig Topper 453733a8778SCraig Topper for (auto &Feature : Features) { 454733a8778SCraig Topper StringRef ExtName = Feature; 455733a8778SCraig Topper assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); 456733a8778SCraig Topper bool Add = ExtName[0] == '+'; 457733a8778SCraig Topper ExtName = ExtName.drop_front(1); // Drop '+' or '-' 458326667d7SCraig Topper bool Experimental = stripExperimentalPrefix(ExtName); 459733a8778SCraig Topper auto ExtensionInfos = Experimental 460733a8778SCraig Topper ? ArrayRef(SupportedExperimentalExtensions) 461733a8778SCraig Topper : ArrayRef(SupportedExtensions); 462733a8778SCraig Topper auto ExtensionInfoIterator = 463733a8778SCraig Topper llvm::lower_bound(ExtensionInfos, ExtName, LessExtName()); 464733a8778SCraig Topper 465733a8778SCraig Topper // Not all features is related to ISA extension, like `relax` or 466733a8778SCraig Topper // `save-restore`, skip those feature. 467733a8778SCraig Topper if (ExtensionInfoIterator == ExtensionInfos.end() || 468733a8778SCraig Topper ExtensionInfoIterator->Name != ExtName) 469733a8778SCraig Topper continue; 470733a8778SCraig Topper 471733a8778SCraig Topper if (Add) 47208969ca1SCraig Topper ISAInfo->Exts[ExtName.str()] = ExtensionInfoIterator->Version; 473733a8778SCraig Topper else 474733a8778SCraig Topper ISAInfo->Exts.erase(ExtName.str()); 475733a8778SCraig Topper } 476733a8778SCraig Topper 477733a8778SCraig Topper return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo)); 478733a8778SCraig Topper } 479733a8778SCraig Topper 480733a8778SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>> 481733a8778SCraig Topper RISCVISAInfo::parseNormalizedArchString(StringRef Arch) { 482941eab10SCraig Topper // RISC-V ISA strings must be [a-z0-9_] 483941eab10SCraig Topper if (!llvm::all_of( 484941eab10SCraig Topper Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; })) 485c785eaecSCraig Topper return getError("string may only contain [a-z0-9_]"); 486f0cc3735SCraig Topper 487733a8778SCraig Topper // Must start with a valid base ISA name. 4881b942ae3SCraig Topper unsigned XLen = 0; 4891b942ae3SCraig Topper if (Arch.consume_front("rv32")) 490733a8778SCraig Topper XLen = 32; 4911b942ae3SCraig Topper else if (Arch.consume_front("rv64")) 492733a8778SCraig Topper XLen = 64; 4931b942ae3SCraig Topper 4941b942ae3SCraig Topper if (XLen == 0 || Arch.empty() || (Arch[0] != 'i' && Arch[0] != 'e')) 495c785eaecSCraig Topper return getError("arch string must begin with valid base ISA"); 4961b942ae3SCraig Topper 497733a8778SCraig Topper std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); 498733a8778SCraig Topper 499733a8778SCraig Topper // Each extension is of the form ${name}${major_version}p${minor_version} 500733a8778SCraig Topper // and separated by _. Split by _ and then extract the name and version 501733a8778SCraig Topper // information for each extension. 502d8f8ac8fSCraig Topper while (!Arch.empty()) { 503d8f8ac8fSCraig Topper if (Arch[0] == '_') { 504d8f8ac8fSCraig Topper if (Arch.size() == 1 || Arch[1] == '_') 505c785eaecSCraig Topper return getError("extension name missing after separator '_'"); 506d8f8ac8fSCraig Topper Arch = Arch.drop_front(); 507d8f8ac8fSCraig Topper } 508d8f8ac8fSCraig Topper 509d8f8ac8fSCraig Topper size_t Idx = Arch.find('_'); 510d8f8ac8fSCraig Topper StringRef Ext = Arch.slice(0, Idx); 51133e7cd6fSKazu Hirata Arch = Arch.substr(Idx); 512d8f8ac8fSCraig Topper 513733a8778SCraig Topper StringRef Prefix, MinorVersionStr; 514733a8778SCraig Topper std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p'); 515733a8778SCraig Topper if (MinorVersionStr.empty()) 516c785eaecSCraig Topper return getError("extension lacks version in expected format"); 517733a8778SCraig Topper unsigned MajorVersion, MinorVersion; 518733a8778SCraig Topper if (MinorVersionStr.getAsInteger(10, MinorVersion)) 519c785eaecSCraig Topper return getError("failed to parse minor version number"); 520733a8778SCraig Topper 521733a8778SCraig Topper // Split Prefix into the extension name and the major version number 522733a8778SCraig Topper // (the trailing digits of Prefix). 523500dda04SCraig Topper size_t VersionStart = Prefix.size(); 524500dda04SCraig Topper while (VersionStart != 0) { 525500dda04SCraig Topper if (!isDigit(Prefix[VersionStart - 1])) 526733a8778SCraig Topper break; 527500dda04SCraig Topper --VersionStart; 528733a8778SCraig Topper } 529500dda04SCraig Topper if (VersionStart == Prefix.size()) 530c785eaecSCraig Topper return getError("extension lacks version in expected format"); 531733a8778SCraig Topper 5325445a35dSCraig Topper if (VersionStart == 0) 533c785eaecSCraig Topper return getError("missing extension name"); 5345445a35dSCraig Topper 535500dda04SCraig Topper StringRef ExtName = Prefix.slice(0, VersionStart); 53633e7cd6fSKazu Hirata StringRef MajorVersionStr = Prefix.substr(VersionStart); 537733a8778SCraig Topper if (MajorVersionStr.getAsInteger(10, MajorVersion)) 538c785eaecSCraig Topper return getError("failed to parse major version number"); 5397a6847e0SCraig Topper 5406cba93f2SCraig Topper if ((ExtName[0] == 'z' || ExtName[0] == 's' || ExtName[0] == 'x') && 5416cba93f2SCraig Topper (ExtName.size() == 1 || isDigit(ExtName[1]))) 542c785eaecSCraig Topper return getError("'" + Twine(ExtName[0]) + 5436cba93f2SCraig Topper "' must be followed by a letter"); 5447a6847e0SCraig Topper 54508969ca1SCraig Topper if (!ISAInfo->Exts 54608969ca1SCraig Topper .emplace( 54708969ca1SCraig Topper ExtName.str(), 54808969ca1SCraig Topper RISCVISAUtils::ExtensionVersion{MajorVersion, MinorVersion}) 54908969ca1SCraig Topper .second) 550c785eaecSCraig Topper return getError("duplicate extension '" + ExtName + "'"); 551733a8778SCraig Topper } 552cf3c714eSCraig Topper ISAInfo->updateImpliedLengths(); 553733a8778SCraig Topper return std::move(ISAInfo); 554733a8778SCraig Topper } 555733a8778SCraig Topper 556733a8778SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>> 557733a8778SCraig Topper RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension, 55887de4975SCraig Topper bool ExperimentalExtensionVersionCheck) { 5590faf4942SCraig Topper // RISC-V ISA strings must be [a-z0-9_] 5600faf4942SCraig Topper if (!llvm::all_of( 5610faf4942SCraig Topper Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; })) 562c785eaecSCraig Topper return getError("string may only contain [a-z0-9_]"); 563733a8778SCraig Topper 56409f4b06dSCraig Topper // ISA string must begin with rv32, rv64, or a profile. 56509f4b06dSCraig Topper unsigned XLen = 0; 56609f4b06dSCraig Topper if (Arch.consume_front("rv32")) { 56709f4b06dSCraig Topper XLen = 32; 56809f4b06dSCraig Topper } else if (Arch.consume_front("rv64")) { 56909f4b06dSCraig Topper XLen = 64; 57009f4b06dSCraig Topper } else { 57109f4b06dSCraig Topper // Try parsing as a profile. 572891d6871SAlex Bradbury auto ProfileCmp = [](StringRef Arch, const RISCVProfile &Profile) { 573a7e07988SCraig Topper return Arch < Profile.Name; 574891d6871SAlex Bradbury }; 575891d6871SAlex Bradbury auto I = llvm::upper_bound(SupportedProfiles, Arch, ProfileCmp); 576891d6871SAlex Bradbury bool FoundProfile = I != std::begin(SupportedProfiles) && 577891d6871SAlex Bradbury Arch.starts_with(std::prev(I)->Name); 578891d6871SAlex Bradbury if (!FoundProfile) { 579891d6871SAlex Bradbury I = llvm::upper_bound(SupportedExperimentalProfiles, Arch, ProfileCmp); 580891d6871SAlex Bradbury FoundProfile = (I != std::begin(SupportedExperimentalProfiles) && 581891d6871SAlex Bradbury Arch.starts_with(std::prev(I)->Name)); 582891d6871SAlex Bradbury if (FoundProfile && !EnableExperimentalExtension) { 583c785eaecSCraig Topper return getError("requires '-menable-experimental-extensions' " 584891d6871SAlex Bradbury "for profile '" + 585891d6871SAlex Bradbury std::prev(I)->Name + "'"); 586891d6871SAlex Bradbury } 587891d6871SAlex Bradbury } 588891d6871SAlex Bradbury if (FoundProfile) { 589891d6871SAlex Bradbury --I; 590a7e07988SCraig Topper std::string NewArch = I->MArch.str(); 591a7e07988SCraig Topper StringRef ArchWithoutProfile = Arch.drop_front(I->Name.size()); 592733a8778SCraig Topper if (!ArchWithoutProfile.empty()) { 59309f4b06dSCraig Topper if (ArchWithoutProfile.front() != '_') 594c785eaecSCraig Topper return getError("additional extensions must be after separator '_'"); 595733a8778SCraig Topper NewArch += ArchWithoutProfile.str(); 596733a8778SCraig Topper } 597733a8778SCraig Topper return parseArchString(NewArch, EnableExperimentalExtension, 59887de4975SCraig Topper ExperimentalExtensionVersionCheck); 599733a8778SCraig Topper } 60009f4b06dSCraig Topper } 6011b942ae3SCraig Topper 6021b942ae3SCraig Topper if (XLen == 0 || Arch.empty()) 603c785eaecSCraig Topper return getError( 60409f4b06dSCraig Topper "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported " 60509f4b06dSCraig Topper "profile name"); 606733a8778SCraig Topper 607733a8778SCraig Topper std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); 608733a8778SCraig Topper 609733a8778SCraig Topper // The canonical order specified in ISA manual. 610733a8778SCraig Topper // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 6111b942ae3SCraig Topper char Baseline = Arch.front(); 612299d3ddcSCraig Topper // Skip the baseline. 6137aa906ddSCraig Topper Arch = Arch.drop_front(); 614299d3ddcSCraig Topper 615299d3ddcSCraig Topper unsigned Major, Minor, ConsumeLength; 616733a8778SCraig Topper 617733a8778SCraig Topper // First letter should be 'e', 'i' or 'g'. 618733a8778SCraig Topper switch (Baseline) { 619733a8778SCraig Topper default: 620c785eaecSCraig Topper return getError("first letter after \'rv" + Twine(XLen) + 6216f02120aSDavid Spickett "\' should be 'e', 'i' or 'g'"); 622733a8778SCraig Topper case 'e': 623733a8778SCraig Topper case 'i': 624733a8778SCraig Topper // Baseline is `i` or `e` 625733a8778SCraig Topper if (auto E = getExtensionVersion( 6267aa906ddSCraig Topper StringRef(&Baseline, 1), Arch, Major, Minor, ConsumeLength, 62787de4975SCraig Topper EnableExperimentalExtension, ExperimentalExtensionVersionCheck)) 628733a8778SCraig Topper return std::move(E); 629733a8778SCraig Topper 630c156d421SCraig Topper ISAInfo->Exts[std::string(1, Baseline)] = {Major, Minor}; 631299d3ddcSCraig Topper break; 632299d3ddcSCraig Topper case 'g': 633299d3ddcSCraig Topper // g expands to extensions in RISCVGImplications. 6347aa906ddSCraig Topper if (!Arch.empty() && isDigit(Arch.front())) 635c785eaecSCraig Topper return getError("version not supported for 'g'"); 636299d3ddcSCraig Topper 637299d3ddcSCraig Topper // Versions for g are disallowed, and this was checked for previously. 638299d3ddcSCraig Topper ConsumeLength = 0; 639299d3ddcSCraig Topper 640299d3ddcSCraig Topper // No matter which version is given to `g`, we always set imafd to default 641299d3ddcSCraig Topper // version since the we don't have clear version scheme for that on 642299d3ddcSCraig Topper // ISA spec. 643c156d421SCraig Topper for (const char *Ext : RISCVGImplications) { 644299d3ddcSCraig Topper auto Version = findDefaultVersion(Ext); 645299d3ddcSCraig Topper assert(Version && "Default extension version not found?"); 646299d3ddcSCraig Topper // Postpone AddExtension until end of this function 647c156d421SCraig Topper ISAInfo->Exts[std::string(Ext)] = {Version->Major, Version->Minor}; 648299d3ddcSCraig Topper } 649299d3ddcSCraig Topper break; 650733a8778SCraig Topper } 651733a8778SCraig Topper 652733a8778SCraig Topper // Consume the base ISA version number and any '_' between rvxxx and the 653733a8778SCraig Topper // first extension 6547aa906ddSCraig Topper Arch = Arch.drop_front(ConsumeLength); 655733a8778SCraig Topper 6567aa906ddSCraig Topper while (!Arch.empty()) { 6577aa906ddSCraig Topper if (Arch.front() == '_') { 6587aa906ddSCraig Topper if (Arch.size() == 1 || Arch[1] == '_') 659c785eaecSCraig Topper return getError("extension name missing after separator '_'"); 6607aa906ddSCraig Topper Arch = Arch.drop_front(); 66130aa49cbSCraig Topper } 66230aa49cbSCraig Topper 6637aa906ddSCraig Topper size_t Idx = Arch.find('_'); 6647aa906ddSCraig Topper StringRef Ext = Arch.slice(0, Idx); 66533e7cd6fSKazu Hirata Arch = Arch.substr(Idx); 6661aaab334SCraig Topper 6671aaab334SCraig Topper do { 668f906e3ddSCraig Topper StringRef Name, Vers, Desc; 6691aaab334SCraig Topper if (RISCVISAUtils::AllStdExts.contains(Ext.front())) { 670f906e3ddSCraig Topper Name = Ext.take_front(1); 671f906e3ddSCraig Topper Ext = Ext.drop_front(); 672f906e3ddSCraig Topper Vers = Ext; 673f906e3ddSCraig Topper Desc = "standard user-level extension"; 6741aaab334SCraig Topper } else if (Ext.front() == 'z' || Ext.front() == 's' || 6751aaab334SCraig Topper Ext.front() == 'x') { 676733a8778SCraig Topper // Handle other types of extensions other than the standard 677733a8778SCraig Topper // general purpose and standard user-level extensions. 678733a8778SCraig Topper // Parse the ISA string containing non-standard user-level 679733a8778SCraig Topper // extensions, standard supervisor-level extensions and 680733a8778SCraig Topper // non-standard supervisor-level extensions. 681733a8778SCraig Topper // These extensions start with 'z', 's', 'x' prefixes, might have a 682733a8778SCraig Topper // version number (major, minor) and are separated by a single 683733a8778SCraig Topper // underscore '_'. We do not enforce a canonical order for them. 684f906e3ddSCraig Topper StringRef Type = getExtensionType(Ext); 685f906e3ddSCraig Topper Desc = getExtensionTypeDesc(Ext); 686f906e3ddSCraig Topper auto Pos = findLastNonVersionCharacter(Ext) + 1; 687f906e3ddSCraig Topper Name = Ext.substr(0, Pos); 688f906e3ddSCraig Topper Vers = Ext.substr(Pos); 689f906e3ddSCraig Topper Ext = StringRef(); 690f906e3ddSCraig Topper 691f906e3ddSCraig Topper assert(!Type.empty() && "Empty type?"); 69287de4975SCraig Topper if (Name.size() == Type.size()) 693c785eaecSCraig Topper return getError(Desc + " name missing after '" + Type + "'"); 694733a8778SCraig Topper } else { 695c785eaecSCraig Topper return getError("invalid standard user-level extension '" + 6961aaab334SCraig Topper Twine(Ext.front()) + "'"); 697733a8778SCraig Topper } 698f906e3ddSCraig Topper 699f906e3ddSCraig Topper unsigned Major, Minor, ConsumeLength; 700f906e3ddSCraig Topper if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength, 701f906e3ddSCraig Topper EnableExperimentalExtension, 70287de4975SCraig Topper ExperimentalExtensionVersionCheck)) 703299d3ddcSCraig Topper return E; 704299d3ddcSCraig Topper 705f906e3ddSCraig Topper if (Name.size() == 1) 706f906e3ddSCraig Topper Ext = Ext.substr(ConsumeLength); 707f906e3ddSCraig Topper 708c156d421SCraig Topper if (!RISCVISAInfo::isSupportedExtension(Name)) 709c156d421SCraig Topper return getErrorForInvalidExt(Name); 710c156d421SCraig Topper 711c156d421SCraig Topper // Insert and error for duplicates. 712c156d421SCraig Topper if (!ISAInfo->Exts 713c156d421SCraig Topper .emplace(Name.str(), 714c156d421SCraig Topper RISCVISAUtils::ExtensionVersion{Major, Minor}) 715c156d421SCraig Topper .second) 716c785eaecSCraig Topper return getError("duplicated " + Desc + " '" + Name + "'"); 717f906e3ddSCraig Topper 7181aaab334SCraig Topper } while (!Ext.empty()); 719733a8778SCraig Topper } 720733a8778SCraig Topper 721733a8778SCraig Topper return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo)); 722733a8778SCraig Topper } 723733a8778SCraig Topper 72410a4f1efSCraig Topper static Error getIncompatibleError(StringRef Ext1, StringRef Ext2) { 72510a4f1efSCraig Topper return getError("'" + Ext1 + "' and '" + Ext2 + 72610a4f1efSCraig Topper "' extensions are incompatible"); 72710a4f1efSCraig Topper } 72810a4f1efSCraig Topper 72910a4f1efSCraig Topper static Error getExtensionRequiresError(StringRef Ext, StringRef ReqExt) { 73010a4f1efSCraig Topper return getError("'" + Ext + "' requires '" + ReqExt + 73110a4f1efSCraig Topper "' extension to also be specified"); 73210a4f1efSCraig Topper } 73310a4f1efSCraig Topper 734733a8778SCraig Topper Error RISCVISAInfo::checkDependency() { 735844355a8SVincentWu bool HasE = Exts.count("e") != 0; 736844355a8SVincentWu bool HasI = Exts.count("i") != 0; 737733a8778SCraig Topper bool HasC = Exts.count("c") != 0; 738733a8778SCraig Topper bool HasF = Exts.count("f") != 0; 7393c5f929aSR bool HasD = Exts.count("d") != 0; 740733a8778SCraig Topper bool HasZfinx = Exts.count("zfinx") != 0; 741733a8778SCraig Topper bool HasVector = Exts.count("zve32x") != 0; 742733a8778SCraig Topper bool HasZvl = MinVLen != 0; 743733a8778SCraig Topper bool HasZcmt = Exts.count("zcmt") != 0; 7446881c6d2SSudharsan Veeravalli static constexpr StringLiteral XqciExts[] = { 745171d3eddSquic_hchandel {"xqcia"}, {"xqciac"}, {"xqcicli"}, {"xqcicm"}, {"xqcics"}, 746*163935a4Squic_hchandel {"xqcicsr"}, {"xqciint"}, {"xqcilo"}, {"xqcilsm"}, {"xqcisls"}}; 747733a8778SCraig Topper 748844355a8SVincentWu if (HasI && HasE) 749371f936cSCraig Topper return getIncompatibleError("i", "e"); 750844355a8SVincentWu 751733a8778SCraig Topper if (HasF && HasZfinx) 75210a4f1efSCraig Topper return getIncompatibleError("f", "zfinx"); 753733a8778SCraig Topper 754733a8778SCraig Topper if (HasZvl && !HasVector) 75510a4f1efSCraig Topper return getExtensionRequiresError("zvl*b", "v' or 'zve*"); 756733a8778SCraig Topper 7573c5f929aSR if ((HasZcmt || Exts.count("zcmp")) && HasD && (HasC || Exts.count("zcd"))) 758c785eaecSCraig Topper return getError(Twine("'") + (HasZcmt ? "zcmt" : "zcmp") + 759c785eaecSCraig Topper "' extension is incompatible with '" + 760c785eaecSCraig Topper (HasC ? "c" : "zcd") + 761733a8778SCraig Topper "' extension when 'd' extension is enabled"); 762733a8778SCraig Topper 763733a8778SCraig Topper if (XLen != 32 && Exts.count("zcf")) 764c785eaecSCraig Topper return getError("'zcf' is only supported for 'rv32'"); 765733a8778SCraig Topper 7663c5f929aSR if (Exts.count("xwchc") != 0) { 7673c5f929aSR if (XLen != 32) 768371f936cSCraig Topper return getError("'xwchc' is only supported for 'rv32'"); 7693c5f929aSR 7703c5f929aSR if (HasD) 771371f936cSCraig Topper return getIncompatibleError("d", "xwchc"); 7723c5f929aSR 7733c5f929aSR if (Exts.count("zcb") != 0) 774371f936cSCraig Topper return getIncompatibleError("xwchc", "zcb"); 7753c5f929aSR } 7763c5f929aSR 7778fcbba82SSudharsan Veeravalli for (auto Ext : XqciExts) 7788fcbba82SSudharsan Veeravalli if (Exts.count(Ext.str()) && (XLen != 32)) 7798fcbba82SSudharsan Veeravalli return getError("'" + Twine(Ext) + "'" + " is only supported for 'rv32'"); 780c4645ffeSSudharsan Veeravalli 781733a8778SCraig Topper return Error::success(); 782733a8778SCraig Topper } 783733a8778SCraig Topper 784733a8778SCraig Topper struct ImpliedExtsEntry { 785733a8778SCraig Topper StringLiteral Name; 786451e853eSCraig Topper const char *ImpliedExt; 787733a8778SCraig Topper 788733a8778SCraig Topper bool operator<(const ImpliedExtsEntry &Other) const { 789733a8778SCraig Topper return Name < Other.Name; 790733a8778SCraig Topper } 791733a8778SCraig Topper }; 792733a8778SCraig Topper 793451e853eSCraig Topper static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) { 794451e853eSCraig Topper return LHS.Name < RHS; 795451e853eSCraig Topper } 796451e853eSCraig Topper 797451e853eSCraig Topper static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) { 798451e853eSCraig Topper return LHS < RHS.Name; 799451e853eSCraig Topper } 800451e853eSCraig Topper 80180628ee0SCraig Topper #define GET_IMPLIED_EXTENSIONS 80280628ee0SCraig Topper #include "llvm/TargetParser/RISCVTargetParserDef.inc" 803733a8778SCraig Topper 804733a8778SCraig Topper void RISCVISAInfo::updateImplication() { 805733a8778SCraig Topper bool HasE = Exts.count("e") != 0; 806733a8778SCraig Topper bool HasI = Exts.count("i") != 0; 807733a8778SCraig Topper 808733a8778SCraig Topper // If not in e extension and i extension does not exist, i extension is 809733a8778SCraig Topper // implied 810733a8778SCraig Topper if (!HasE && !HasI) { 811733a8778SCraig Topper auto Version = findDefaultVersion("i"); 81208969ca1SCraig Topper Exts["i"] = *Version; 813733a8778SCraig Topper } 814733a8778SCraig Topper 815844355a8SVincentWu if (HasE && HasI) 816844355a8SVincentWu Exts.erase("i"); 817844355a8SVincentWu 818733a8778SCraig Topper assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name"); 819733a8778SCraig Topper 820733a8778SCraig Topper // This loop may execute over 1 iteration since implication can be layered 821733a8778SCraig Topper // Exits loop if no more implication is applied 8220e938017SCraig Topper SmallVector<StringRef, 16> WorkList; 823733a8778SCraig Topper for (auto const &Ext : Exts) 8240e938017SCraig Topper WorkList.push_back(Ext.first); 825733a8778SCraig Topper 826733a8778SCraig Topper while (!WorkList.empty()) { 827733a8778SCraig Topper StringRef ExtName = WorkList.pop_back_val(); 828451e853eSCraig Topper auto Range = std::equal_range(std::begin(ImpliedExts), 829451e853eSCraig Topper std::end(ImpliedExts), ExtName); 830451e853eSCraig Topper std::for_each(Range.first, Range.second, 831451e853eSCraig Topper [&](const ImpliedExtsEntry &Implied) { 832451e853eSCraig Topper const char *ImpliedExt = Implied.ImpliedExt; 833733a8778SCraig Topper if (Exts.count(ImpliedExt)) 834451e853eSCraig Topper return; 835733a8778SCraig Topper auto Version = findDefaultVersion(ImpliedExt); 83608969ca1SCraig Topper Exts[ImpliedExt] = *Version; 8370e938017SCraig Topper WorkList.push_back(ImpliedExt); 838451e853eSCraig Topper }); 839733a8778SCraig Topper } 840733a8778SCraig Topper 841733a8778SCraig Topper // Add Zcf if Zce and F are enabled on RV32. 842733a8778SCraig Topper if (XLen == 32 && Exts.count("zce") && Exts.count("f") && 843733a8778SCraig Topper !Exts.count("zcf")) { 844733a8778SCraig Topper auto Version = findDefaultVersion("zcf"); 84508969ca1SCraig Topper Exts["zcf"] = *Version; 846733a8778SCraig Topper } 847733a8778SCraig Topper } 848733a8778SCraig Topper 849451e853eSCraig Topper static constexpr StringLiteral CombineIntoExts[] = { 850451e853eSCraig Topper {"zk"}, {"zkn"}, {"zks"}, {"zvkn"}, {"zvknc"}, 851451e853eSCraig Topper {"zvkng"}, {"zvks"}, {"zvksc"}, {"zvksg"}, 852733a8778SCraig Topper }; 853733a8778SCraig Topper 854733a8778SCraig Topper void RISCVISAInfo::updateCombination() { 855451e853eSCraig Topper bool MadeChange = false; 856733a8778SCraig Topper do { 857451e853eSCraig Topper MadeChange = false; 858451e853eSCraig Topper for (StringRef CombineExt : CombineIntoExts) { 859e069bb7fSCraig Topper if (Exts.count(CombineExt.str())) 860733a8778SCraig Topper continue; 861451e853eSCraig Topper 862451e853eSCraig Topper // Look up the extension in the ImpliesExt table to find everything it 863451e853eSCraig Topper // depends on. 864451e853eSCraig Topper auto Range = std::equal_range(std::begin(ImpliedExts), 865451e853eSCraig Topper std::end(ImpliedExts), CombineExt); 866451e853eSCraig Topper bool HasAllRequiredFeatures = std::all_of( 867451e853eSCraig Topper Range.first, Range.second, [&](const ImpliedExtsEntry &Implied) { 868e069bb7fSCraig Topper return Exts.count(Implied.ImpliedExt); 869451e853eSCraig Topper }); 870451e853eSCraig Topper if (HasAllRequiredFeatures) { 871733a8778SCraig Topper auto Version = findDefaultVersion(CombineExt); 87208969ca1SCraig Topper Exts[CombineExt.str()] = *Version; 873451e853eSCraig Topper MadeChange = true; 874733a8778SCraig Topper } 875733a8778SCraig Topper } 876451e853eSCraig Topper } while (MadeChange); 877733a8778SCraig Topper } 878733a8778SCraig Topper 879cf3c714eSCraig Topper void RISCVISAInfo::updateImpliedLengths() { 880cf3c714eSCraig Topper assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 && 881cf3c714eSCraig Topper "Expected lengths to be initialied to zero"); 882cf3c714eSCraig Topper 883733a8778SCraig Topper // TODO: Handle q extension. 884733a8778SCraig Topper if (Exts.count("d")) 885733a8778SCraig Topper FLen = 64; 886733a8778SCraig Topper else if (Exts.count("f")) 887733a8778SCraig Topper FLen = 32; 888733a8778SCraig Topper 88905d04f0aSCraig Topper if (Exts.count("v")) { 89005d04f0aSCraig Topper MaxELenFp = std::max(MaxELenFp, 64u); 89105d04f0aSCraig Topper MaxELen = std::max(MaxELen, 64u); 89205d04f0aSCraig Topper } 89305d04f0aSCraig Topper 894733a8778SCraig Topper for (auto const &Ext : Exts) { 895733a8778SCraig Topper StringRef ExtName = Ext.first; 896cf3c714eSCraig Topper // Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d) 897cf3c714eSCraig Topper if (ExtName.consume_front("zve")) { 898cf3c714eSCraig Topper unsigned ZveELen; 899cf3c714eSCraig Topper if (ExtName.consumeInteger(10, ZveELen)) 90005d04f0aSCraig Topper continue; 90105d04f0aSCraig Topper 902cf3c714eSCraig Topper if (ExtName == "f") 903cf3c714eSCraig Topper MaxELenFp = std::max(MaxELenFp, 32u); 904cf3c714eSCraig Topper else if (ExtName == "d") 905cf3c714eSCraig Topper MaxELenFp = std::max(MaxELenFp, 64u); 906cf3c714eSCraig Topper else if (ExtName != "x") 907cf3c714eSCraig Topper continue; 908cf3c714eSCraig Topper 909733a8778SCraig Topper MaxELen = std::max(MaxELen, ZveELen); 910cf3c714eSCraig Topper continue; 911cf3c714eSCraig Topper } 912cf3c714eSCraig Topper 913cf3c714eSCraig Topper // Infer MinVLen from zvl*b. 914cf3c714eSCraig Topper if (ExtName.consume_front("zvl")) { 915cf3c714eSCraig Topper unsigned ZvlLen; 916cf3c714eSCraig Topper if (ExtName.consumeInteger(10, ZvlLen)) 917cf3c714eSCraig Topper continue; 918cf3c714eSCraig Topper 919cf3c714eSCraig Topper if (ExtName != "b") 920cf3c714eSCraig Topper continue; 921cf3c714eSCraig Topper 922cf3c714eSCraig Topper MinVLen = std::max(MinVLen, ZvlLen); 923cf3c714eSCraig Topper continue; 924733a8778SCraig Topper } 925733a8778SCraig Topper } 926733a8778SCraig Topper } 927733a8778SCraig Topper 928733a8778SCraig Topper std::string RISCVISAInfo::toString() const { 929733a8778SCraig Topper std::string Buffer; 930733a8778SCraig Topper raw_string_ostream Arch(Buffer); 931733a8778SCraig Topper 932733a8778SCraig Topper Arch << "rv" << XLen; 933733a8778SCraig Topper 934733a8778SCraig Topper ListSeparator LS("_"); 935733a8778SCraig Topper for (auto const &Ext : Exts) { 936733a8778SCraig Topper StringRef ExtName = Ext.first; 937733a8778SCraig Topper auto ExtInfo = Ext.second; 938733a8778SCraig Topper Arch << LS << ExtName; 939733a8778SCraig Topper Arch << ExtInfo.Major << "p" << ExtInfo.Minor; 940733a8778SCraig Topper } 941733a8778SCraig Topper 942733a8778SCraig Topper return Arch.str(); 943733a8778SCraig Topper } 944733a8778SCraig Topper 945733a8778SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>> 946733a8778SCraig Topper RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) { 947733a8778SCraig Topper ISAInfo->updateImplication(); 948733a8778SCraig Topper ISAInfo->updateCombination(); 949cf3c714eSCraig Topper ISAInfo->updateImpliedLengths(); 950733a8778SCraig Topper 951733a8778SCraig Topper if (Error Result = ISAInfo->checkDependency()) 952733a8778SCraig Topper return std::move(Result); 953733a8778SCraig Topper return std::move(ISAInfo); 954733a8778SCraig Topper } 955733a8778SCraig Topper 956733a8778SCraig Topper StringRef RISCVISAInfo::computeDefaultABI() const { 957733a8778SCraig Topper if (XLen == 32) { 9587237bef5SCraig Topper if (Exts.count("e")) 959733a8778SCraig Topper return "ilp32e"; 9607237bef5SCraig Topper if (Exts.count("d")) 961733a8778SCraig Topper return "ilp32d"; 9627237bef5SCraig Topper if (Exts.count("f")) 963733a8778SCraig Topper return "ilp32f"; 964733a8778SCraig Topper return "ilp32"; 965733a8778SCraig Topper } else if (XLen == 64) { 9667237bef5SCraig Topper if (Exts.count("e")) 967733a8778SCraig Topper return "lp64e"; 9687237bef5SCraig Topper if (Exts.count("d")) 969733a8778SCraig Topper return "lp64d"; 9707237bef5SCraig Topper if (Exts.count("f")) 971733a8778SCraig Topper return "lp64f"; 972733a8778SCraig Topper return "lp64"; 973733a8778SCraig Topper } 974733a8778SCraig Topper llvm_unreachable("Invalid XLEN"); 975733a8778SCraig Topper } 976733a8778SCraig Topper 977733a8778SCraig Topper bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext) { 978733a8778SCraig Topper if (Ext.empty()) 979733a8778SCraig Topper return false; 980733a8778SCraig Topper 981733a8778SCraig Topper auto Pos = findLastNonVersionCharacter(Ext) + 1; 982733a8778SCraig Topper StringRef Name = Ext.substr(0, Pos); 983733a8778SCraig Topper StringRef Vers = Ext.substr(Pos); 984733a8778SCraig Topper if (Vers.empty()) 985733a8778SCraig Topper return false; 986733a8778SCraig Topper 987733a8778SCraig Topper unsigned Major, Minor, ConsumeLength; 988733a8778SCraig Topper if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength, 989733a8778SCraig Topper true, true)) { 990733a8778SCraig Topper consumeError(std::move(E)); 991733a8778SCraig Topper return false; 992733a8778SCraig Topper } 993733a8778SCraig Topper 994733a8778SCraig Topper return true; 995733a8778SCraig Topper } 996733a8778SCraig Topper 997733a8778SCraig Topper std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) { 998733a8778SCraig Topper if (Ext.empty()) 999733a8778SCraig Topper return std::string(); 1000733a8778SCraig Topper 1001733a8778SCraig Topper auto Pos = findLastNonVersionCharacter(Ext) + 1; 1002733a8778SCraig Topper StringRef Name = Ext.substr(0, Pos); 1003733a8778SCraig Topper 1004733a8778SCraig Topper if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext)) 1005733a8778SCraig Topper return std::string(); 1006733a8778SCraig Topper 1007733a8778SCraig Topper if (!isSupportedExtension(Name)) 1008733a8778SCraig Topper return std::string(); 1009733a8778SCraig Topper 1010733a8778SCraig Topper return isExperimentalExtension(Name) ? "experimental-" + Name.str() 1011733a8778SCraig Topper : Name.str(); 1012733a8778SCraig Topper } 1013d1e28e2aSPhilip Reames 1014d1e28e2aSPhilip Reames struct RISCVExtBit { 1015d1e28e2aSPhilip Reames const StringLiteral ext; 101682f52d9cSPiyou Chen uint8_t groupid; 1017d1e28e2aSPhilip Reames uint8_t bitpos; 1018d1e28e2aSPhilip Reames }; 1019d1e28e2aSPhilip Reames 102082f52d9cSPiyou Chen constexpr static RISCVExtBit RISCVBitPositions[] = { 102182f52d9cSPiyou Chen {"a", 0, 0}, {"c", 0, 2}, 102282f52d9cSPiyou Chen {"d", 0, 3}, {"f", 0, 5}, 102382f52d9cSPiyou Chen {"i", 0, 8}, {"m", 0, 12}, 102482f52d9cSPiyou Chen {"v", 0, 21}, {"zacas", 0, 26}, 102582f52d9cSPiyou Chen {"zba", 0, 27}, {"zbb", 0, 28}, 102682f52d9cSPiyou Chen {"zbc", 0, 29}, {"zbkb", 0, 30}, 102782f52d9cSPiyou Chen {"zbkc", 0, 31}, {"zbkx", 0, 32}, 102882f52d9cSPiyou Chen {"zbs", 0, 33}, {"zfa", 0, 34}, 102982f52d9cSPiyou Chen {"zfh", 0, 35}, {"zfhmin", 0, 36}, 103082f52d9cSPiyou Chen {"zicboz", 0, 37}, {"zicond", 0, 38}, 103182f52d9cSPiyou Chen {"zihintntl", 0, 39}, {"zihintpause", 0, 40}, 103282f52d9cSPiyou Chen {"zknd", 0, 41}, {"zkne", 0, 42}, 103382f52d9cSPiyou Chen {"zknh", 0, 43}, {"zksed", 0, 44}, 103482f52d9cSPiyou Chen {"zksh", 0, 45}, {"zkt", 0, 46}, 103582f52d9cSPiyou Chen {"ztso", 0, 47}, {"zvbb", 0, 48}, 103682f52d9cSPiyou Chen {"zvbc", 0, 49}, {"zvfh", 0, 50}, 103782f52d9cSPiyou Chen {"zvfhmin", 0, 51}, {"zvkb", 0, 52}, 103882f52d9cSPiyou Chen {"zvkg", 0, 53}, {"zvkned", 0, 54}, 103982f52d9cSPiyou Chen {"zvknha", 0, 55}, {"zvknhb", 0, 56}, 104082f52d9cSPiyou Chen {"zvksed", 0, 57}, {"zvksh", 0, 58}, 104182f52d9cSPiyou Chen {"zvkt", 0, 59}, {"zve32x", 0, 60}, 104282f52d9cSPiyou Chen {"zve32f", 0, 61}, {"zve64x", 0, 62}, 1043a2994dedSPiyou Chen {"zve64f", 0, 63}, {"zve64d", 1, 0}, 104482f52d9cSPiyou Chen {"zimop", 1, 1}, {"zca", 1, 2}, 104582f52d9cSPiyou Chen {"zcb", 1, 3}, {"zcd", 1, 4}, 104682f52d9cSPiyou Chen {"zcf", 1, 5}, {"zcmop", 1, 6}, 104782f52d9cSPiyou Chen {"zawrs", 1, 7}}; 104882f52d9cSPiyou Chen 104982f52d9cSPiyou Chen std::pair<int, int> RISCVISAInfo::getRISCVFeaturesBitsInfo(StringRef Ext) { 1050d1e28e2aSPhilip Reames // Note that this code currently accepts mixed case extension names, but 1051d1e28e2aSPhilip Reames // does not handle extension versions at all. That's probably fine because 1052d1e28e2aSPhilip Reames // there's only one extension version in the __riscv_feature_bits vector. 105382f52d9cSPiyou Chen for (auto E : RISCVBitPositions) 1054d1e28e2aSPhilip Reames if (E.ext.equals_insensitive(Ext)) 105582f52d9cSPiyou Chen return std::make_pair(E.groupid, E.bitpos); 105682f52d9cSPiyou Chen return std::make_pair(-1, -1); 1057d1e28e2aSPhilip Reames } 1058