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