Index: clang/lib/Basic/Targets/RISCV.cpp =================================================================== --- clang/lib/Basic/Targets/RISCV.cpp +++ clang/lib/Basic/Targets/RISCV.cpp @@ -150,7 +150,8 @@ auto ExtName = Extension.first; auto ExtInfo = Extension.second; unsigned Version = - (ExtInfo.MajorVersion * 1000000) + (ExtInfo.MinorVersion * 1000); + (ExtInfo.Version.Major * 1000000) + + (ExtInfo.Version.Minor * 1000); Builder.defineMacro(Twine("__riscv_", ExtName), Twine(Version)); } @@ -223,10 +224,7 @@ if (Result.hasValue()) return Result.getValue(); - if (ISAInfo->isSupportedExtensionFeature(Feature)) - return ISAInfo->hasExtension(Feature); - - return false; + return ISAInfo->hasExtensionWithVersion(Feature); } /// Perform initialization based on the user configured set of features. Index: clang/lib/Driver/ToolChains/Arch/RISCV.cpp =================================================================== --- clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -41,8 +41,12 @@ return false; } - (*ISAInfo)->toFeatures( - Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); }); + std::vector ToFeatures; + (*ISAInfo)->toFeatures(ToFeatures); + + for (const auto &Feature : ToFeatures) + Features.push_back(Args.MakeArgString("+" + Feature)); + return true; } Index: clang/test/Driver/riscv-arch.c =================================================================== --- clang/test/Driver/riscv-arch.c +++ clang/test/Driver/riscv-arch.c @@ -453,3 +453,7 @@ // RUN: %clang -target riscv32-unknown-elf -march=rv32izvlsseg0p10 -menable-experimental-extensions -### %s -c 2>&1 | \ // RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS %s // RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS: "-target-feature" "+experimental-zvlsseg" + +// RUN: %clang -target riscv32-unknown-elf -march=rv32iv0p7 -menable-experimental-extensions -### %s -c 2>&1 | \ +// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-V07 %s +// RV32-EXPERIMENTAL-V07: "-target-feature" "+experimental-v0p7" \ No newline at end of file Index: llvm/include/llvm/Support/RISCVISAInfo.h =================================================================== --- llvm/include/llvm/Support/RISCVISAInfo.h +++ llvm/include/llvm/Support/RISCVISAInfo.h @@ -19,10 +19,29 @@ #include namespace llvm { + +/// Represents the major and version number components of a RISC-V extension +struct RISCVExtensionVersion { + unsigned Major; + unsigned Minor; + + bool operator==(const RISCVExtensionVersion &Version) const { + return Major == Version.Major && Minor == Version.Minor; + } + + bool operator!=(const RISCVExtensionVersion &Version) const { + return !operator==(Version); + } + + bool operator<(const RISCVExtensionVersion &Version) const { + return (Major < Version.Major) || + (Major == Version.Major && Minor < Version.Minor); + } +}; + struct RISCVExtensionInfo { std::string ExtName; - unsigned MajorVersion; - unsigned MinorVersion; + RISCVExtensionVersion Version; }; class RISCVISAInfo { @@ -47,15 +66,15 @@ /// Parse RISCV ISA info from arch string. static llvm::Expected> parseArchString(StringRef Arch, bool EnableExperimentalExtension, - bool ExperimentalExtensionVersionCheck = true); + bool ExperimentalExtensionVersionCheck = true, + bool IgnoreUnknownExtension = false); /// Parse RISCV ISA info from feature vector. static llvm::Expected> parseFeatures(unsigned XLen, const std::vector &Features); /// Convert RISCV ISA info to a feature vector. - void toFeatures(std::vector &Features, - std::function StrAlloc) const; + void toFeatures(std::vector &Features) const; const OrderedExtensionMap &getExtensions() const { return Exts; }; @@ -63,9 +82,11 @@ unsigned getFLen() const { return FLen; }; bool hasExtension(StringRef Ext) const; + bool hasExtensionWithVersion(StringRef Ext) const; std::string toString() const; - static bool isSupportedExtensionFeature(StringRef Ext); + static Optional + isSupportedExtensionFeature(StringRef Ext); static bool isSupportedExtension(StringRef Ext); static bool isSupportedExtension(StringRef Ext, unsigned MajorVersion, unsigned MinorVersion); Index: llvm/lib/Object/ELFObjectFile.cpp =================================================================== --- llvm/lib/Object/ELFObjectFile.cpp +++ llvm/lib/Object/ELFObjectFile.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/RISCVAttributeParser.h" #include "llvm/Support/RISCVAttributes.h" +#include "llvm/Support/RISCVISAInfo.h" #include #include #include @@ -309,35 +310,27 @@ // The Arch pattern is [rv32|rv64][i|e]version(_[m|a|f|d|c]version)* // Version string pattern is (major)p(minor). Major and minor are optional. // For example, a version number could be 2p0, 2, or p92. - StringRef Arch = Attr.getValue(); - if (Arch.consume_front("rv32")) + auto ParseResult = + llvm::RISCVISAInfo::parseArchString(Attr.getValue(), true, true, true); + if (!ParseResult) + return Features; + + auto &ISAInfo = *ParseResult; + + if (ISAInfo->getXLen() == 32) Features.AddFeature("64bit", false); - else if (Arch.consume_front("rv64")) + else if (ISAInfo->getXLen() == 64) Features.AddFeature("64bit"); - while (!Arch.empty()) { - switch (Arch[0]) { - default: - break; // Ignore unexpected features. - case 'i': - Features.AddFeature("e", false); - break; - case 'd': - Features.AddFeature("f"); // D-ext will imply F-ext. - LLVM_FALLTHROUGH; - case 'e': - case 'm': - case 'a': - case 'f': - case 'c': - Features.AddFeature(Arch.take_front()); - break; - } - - // FIXME: Handle version numbers. - Arch = Arch.drop_until([](char c) { return c == '_' || c == '\0'; }); - Arch = Arch.drop_while([](char c) { return c == '_'; }); + if (PlatformFlags & ELF::EF_RISCV_RVC) { + Features.AddFeature("c", false); } + + std::vector ToFeatures; + ISAInfo->toFeatures(ToFeatures); + + for (const auto &Feature : ToFeatures) + Features.AddFeature(Feature); } return Features; Index: llvm/lib/Support/RISCVISAInfo.cpp =================================================================== --- llvm/lib/Support/RISCVISAInfo.cpp +++ llvm/lib/Support/RISCVISAInfo.cpp @@ -22,11 +22,6 @@ using namespace llvm; namespace { -/// Represents the major and version number components of a RISC-V extension -struct RISCVExtensionVersion { - unsigned Major; - unsigned Minor; -}; struct RISCVSupportedExtension { const char *Name; @@ -50,6 +45,7 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = { {"v", RISCVExtensionVersion{0, 10}}, + {"v", RISCVExtensionVersion{0, 7}}, {"zba", RISCVExtensionVersion{1, 0}}, {"zbb", RISCVExtensionVersion{1, 0}}, {"zbc", RISCVExtensionVersion{1, 0}}, @@ -62,11 +58,17 @@ {"zbt", RISCVExtensionVersion{0, 93}}, {"zvlsseg", RISCVExtensionVersion{0, 10}}, + {"zvlsseg", RISCVExtensionVersion{0, 7}}, {"zfhmin", RISCVExtensionVersion{0, 1}}, {"zfh", RISCVExtensionVersion{0, 1}}, }; +static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, + unsigned &Minor, unsigned &ConsumeLength, + bool EnableExperimentalExtension, + bool ExperimentalExtensionVersionCheck); + static bool stripExperimentalPrefix(StringRef &Ext) { return Ext.consume_front("experimental-"); } @@ -120,8 +122,8 @@ unsigned MinorVersion) { RISCVExtensionInfo Ext; Ext.ExtName = ExtName.str(); - Ext.MajorVersion = MajorVersion; - Ext.MinorVersion = MinorVersion; + Ext.Version.Major = MajorVersion; + Ext.Version.Minor = MinorVersion; Exts[ExtName.str()] = Ext; } @@ -149,22 +151,46 @@ return StringRef(); } -static Optional isExperimentalExtension(StringRef Ext) { - auto ExtIterator = - llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext)); - if (ExtIterator == std::end(SupportedExperimentalExtensions)) - return None; +static std::vector isExperimentalExtension(StringRef Ext) { + std::vector Result; - return ExtIterator->Version; + for (auto& Extension : SupportedExperimentalExtensions) { + if (Extension.Name == Ext) + Result.push_back(Extension.Version); + } + + return Result; } -bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) { - bool IsExperimental = stripExperimentalPrefix(Ext); +Optional +RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) { + stripExperimentalPrefix(Ext); - if (IsExperimental) - return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext)); - else - return llvm::any_of(SupportedExtensions, FindByName(Ext)); + auto Pos = findFirstNonVersionCharacter(Ext) + 1; + StringRef Name(Ext.substr(0, Pos)); + StringRef Vers(Ext.substr(Pos)); + + unsigned Major, Minor, ConsumeLength; + if (Vers.empty()) { + auto Version = findDefaultVersion(Name); + if (!Version) + return None; + + Major = Version->Major; + Minor = Version->Minor; + + } else if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength, + true, false)) { + // Not all features is related to ISA extension, like `relax` or + // `save-restore`, skip those feature. + consumeError(std::move(E)); + return None; + } + + if (!isSupportedExtension(Name, Major, Minor)) + return None; + + return RISCVExtensionInfo{Name.str(), Major, Minor}; } bool RISCVISAInfo::isSupportedExtension(StringRef Ext) { @@ -191,6 +217,20 @@ return Exts.count(Ext.str()) != 0; } +bool RISCVISAInfo::hasExtensionWithVersion(StringRef Ext) const{ + auto Info = isSupportedExtensionFeature(Ext); + if(!Info) + return false; + + auto ExtInfoIt = Exts.find(Info->ExtName); + + if (ExtInfoIt == Exts.end()) + return false; + + return ExtInfoIt->second.Version.Major == Info->Version.Major && + ExtInfoIt->second.Version.Minor == Info->Version.Minor; +} + // Get the rank for single-letter extension, lower value meaning higher // priority. static int singleLetterExtensionRank(char Ext) { @@ -273,22 +313,36 @@ return LHS < RHS; } -void RISCVISAInfo::toFeatures( - std::vector &Features, - std::function StrAlloc) const { +static std::string addVersionSuffix(StringRef Suffix, + StringRef ExtName, unsigned Major, + unsigned Minor) { + if (auto DefaultVersion = findDefaultVersion(ExtName)) + if (DefaultVersion->Major == Major && DefaultVersion->Minor == Minor) + return (Twine(Suffix) + ExtName).str(); + + return (Suffix + ExtName + Twine(Major) + "p" + Twine(Minor)).str(); +} + +void RISCVISAInfo::toFeatures(std::vector &Features) const { + for (auto &Ext : Exts) { StringRef ExtName = Ext.first; + auto Extension = Ext.second; + unsigned Major = Ext.second.Version.Major; + unsigned Minor = Ext.second.Version.Minor; if (ExtName == "i") continue; if (ExtName == "zvlsseg") { - Features.push_back("+experimental-v"); - Features.push_back("+experimental-zvlsseg"); - } else if (isExperimentalExtension(ExtName)) { - Features.push_back(StrAlloc("+experimental-" + ExtName)); + Features.push_back(addVersionSuffix("experimental-", "v", Major, Minor)); + Features.push_back( + addVersionSuffix("experimental-", "zvlsseg", Major, Minor)); + } else if (isExperimentalExtension(ExtName).size()) { + Features.push_back( + addVersionSuffix("experimental-", ExtName, Major, Minor)); } else { - Features.push_back(StrAlloc("+" + ExtName)); + Features.push_back(addVersionSuffix("", ExtName, Major, Minor)); } } } @@ -346,7 +400,8 @@ } // If experimental extension, require use of current version number number - if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { + auto ExperimentalExtension = isExperimentalExtension(Ext); + if (ExperimentalExtension.size()) { if (!EnableExperimentalExtension) { std::string Error = "requires '-menable-experimental-extensions' for " "experimental extension '" + @@ -362,18 +417,27 @@ return createStringError(errc::invalid_argument, Error); } - auto SupportedVers = *ExperimentalExtension; - if (ExperimentalExtensionVersionCheck && - (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) { - std::string Error = "unsupported version number " + MajorStr.str(); - if (!MinorStr.empty()) - Error += "." + MinorStr.str(); - Error += " for experimental extension '" + Ext.str() + - "'(this compiler supports " + utostr(SupportedVers.Major) + "." + - utostr(SupportedVers.Minor) + ")"; - return createStringError(errc::invalid_argument, Error); + for (auto Version : ExperimentalExtension) { + if (Major == Version.Major && Minor == Version.Minor) + return Error::success(); } - return Error::success(); + + if (!ExperimentalExtensionVersionCheck) + return Error::success(); + + std::string Error = "unsupported version number " + MajorStr.str(); + if (!MinorStr.empty()) + Error += "." + MinorStr.str(); + Error += " for experimental extension '" + Ext.str() + + "'(this compiler supports "; + + ListSeparator LS; + for (auto Version : ExperimentalExtension) { + Error += LS; + Error += (utostr(Version.Major) + "." + utostr(Version.Minor)); + } + Error += ")"; + return createStringError(errc::invalid_argument, Error); } // Exception rule for `g`, we don't have clear version scheme for that on @@ -409,27 +473,19 @@ for (auto &Feature : Features) { StringRef ExtName = Feature; - bool Experimental = false; assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); bool Add = ExtName[0] == '+'; ExtName = ExtName.drop_front(1); // Drop '+' or '-' - Experimental = stripExperimentalPrefix(ExtName); - auto ExtensionInfos = Experimental - ? makeArrayRef(SupportedExperimentalExtensions) - : makeArrayRef(SupportedExtensions); - auto ExtensionInfoIterator = - llvm::find_if(ExtensionInfos, FindByName(ExtName)); - // Not all features is related to ISA extension, like `relax` or - // `save-restore`, skip those feature. - if (ExtensionInfoIterator == ExtensionInfos.end()) + auto Info = isSupportedExtensionFeature(ExtName); + if(!Info) continue; if (Add) - ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major, - ExtensionInfoIterator->Version.Minor); + ISAInfo->addExtension(Info->ExtName, Info->Version.Major, + Info->Version.Minor); else - ISAInfo->Exts.erase(ExtName.str()); + ISAInfo->Exts.erase(Info->ExtName); } ISAInfo->updateImplication(); @@ -443,7 +499,8 @@ llvm::Expected> RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension, - bool ExperimentalExtensionVersionCheck) { + bool ExperimentalExtensionVersionCheck, + bool IgnoreUnknownExtension) { // RISC-V ISA strings must be lowercase. if (llvm::any_of(Arch, isupper)) { return createStringError(errc::invalid_argument, @@ -544,9 +601,9 @@ "standard user-level extension not given in canonical order '%c'", C); } - - return createStringError(errc::invalid_argument, - "invalid standard user-level extension '%c'", C); + if (!IgnoreUnknownExtension) + return createStringError(errc::invalid_argument, + "invalid standard user-level extension '%c'", C); } // Move to next char to prevent repeated letter. @@ -558,18 +615,23 @@ Next = std::string(std::next(I), E); if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor, ConsumeLength, EnableExperimentalExtension, - ExperimentalExtensionVersionCheck)) - return std::move(E); - - // The order is OK, then push it into features. - // TODO: Use version number when setting target features - // Currently LLVM supports only "mafdcbv". - StringRef SupportedStandardExtension = "mafdcbv"; - if (SupportedStandardExtension.find(C) == StringRef::npos) - return createStringError(errc::invalid_argument, - "unsupported standard user-level extension '%c'", - C); - ISAInfo->addExtension(std::string(1, C), Major, Minor); + ExperimentalExtensionVersionCheck)) { + if (IgnoreUnknownExtension) + consumeError(std::move(E)); + else + return std::move(E); + } else { + // The order is OK, then push it into features. + // TODO: Use version number when setting target features + // Currently LLVM supports only "mafdcbv". + StringRef SupportedStandardExtension = "mafdcbv"; + if (SupportedStandardExtension.find(C) != StringRef::npos) + ISAInfo->addExtension(std::string(1, C), Major, Minor); + else if (!IgnoreUnknownExtension) + return createStringError(errc::invalid_argument, + "unsupported standard user-level extension '%c'", + C); + } // Consume full extension name and version, including any optional '_' // between this extension and the next @@ -724,10 +786,9 @@ for (auto &Ext : Exts) { auto I = llvm::lower_bound(ImpliedExts, Ext.first); if (I != std::end(ImpliedExts) && I->Name == Ext.first) { - for (auto &ImpliedExt : I->Exts) { - auto Version = findDefaultVersion(ImpliedExt); - addExtension(ImpliedExt, Version->Major, Version->Minor); - } + for (auto &ImpliedExt : I->Exts) + addExtension(ImpliedExt, + Ext.second.Version.Major, Ext.second.Version.Minor); } } } @@ -752,7 +813,8 @@ StringRef ExtName = Ext.first; auto ExtInfo = Ext.second; Arch << LS << ExtName; - Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion; + Arch << ExtInfo.Version.Major + << "p" << ExtInfo.Version.Minor; } return Arch.str(); Index: llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -2153,9 +2153,10 @@ } auto &ISAInfo = *ParseResult; - for (auto Feature : RISCVFeatureKV) - if (ISAInfo->hasExtension(Feature.Key)) + for (auto Feature : RISCVFeatureKV) { + if (ISAInfo->hasExtensionWithVersion(Feature.Key)) setFeatureBits(Feature.Value, Feature.Key); + } if (ISAInfo->getXLen() == 32) clearFeatureBits(RISCV::Feature64Bit, "64bit"); Index: llvm/lib/Target/RISCV/RISCV.td =================================================================== --- llvm/lib/Target/RISCV/RISCV.td +++ llvm/lib/Target/RISCV/RISCV.td @@ -13,28 +13,28 @@ //===----------------------------------------------------------------------===// def FeatureStdExtM - : SubtargetFeature<"m", "HasStdExtM", "true", + : SubtargetFeature<"m", "StdExtM", "RISCVExtensionVersion{2, 0}", "'M' (Integer Multiplication and Division)">; def HasStdExtM : Predicate<"Subtarget->hasStdExtM()">, AssemblerPredicate<(all_of FeatureStdExtM), "'M' (Integer Multiplication and Division)">; def FeatureStdExtA - : SubtargetFeature<"a", "HasStdExtA", "true", + : SubtargetFeature<"a", "StdExtA", "RISCVExtensionVersion{2, 0}", "'A' (Atomic Instructions)">; def HasStdExtA : Predicate<"Subtarget->hasStdExtA()">, AssemblerPredicate<(all_of FeatureStdExtA), "'A' (Atomic Instructions)">; def FeatureStdExtF - : SubtargetFeature<"f", "HasStdExtF", "true", + : SubtargetFeature<"f", "StdExtF", "RISCVExtensionVersion{2, 0}", "'F' (Single-Precision Floating-Point)">; def HasStdExtF : Predicate<"Subtarget->hasStdExtF()">, AssemblerPredicate<(all_of FeatureStdExtF), "'F' (Single-Precision Floating-Point)">; def FeatureStdExtD - : SubtargetFeature<"d", "HasStdExtD", "true", + : SubtargetFeature<"d", "StdExtD", "RISCVExtensionVersion{2, 0}", "'D' (Double-Precision Floating-Point)", [FeatureStdExtF]>; def HasStdExtD : Predicate<"Subtarget->hasStdExtD()">, @@ -42,7 +42,8 @@ "'D' (Double-Precision Floating-Point)">; def FeatureStdExtZfhmin - : SubtargetFeature<"experimental-zfhmin", "HasStdExtZfhmin", "true", + : SubtargetFeature<"experimental-zfhmin", "StdExtZfhmin", + "RISCVExtensionVersion{0, 1}", "'Zfhmin' (Half-Precision Floating-Point Minimal)", [FeatureStdExtF]>; def HasStdExtZfhmin : Predicate<"Subtarget->hasStdExtZfhmin()">, @@ -50,7 +51,8 @@ "'Zfhmin' (Half-Precision Floating-Point Minimal)">; def FeatureStdExtZfh - : SubtargetFeature<"experimental-zfh", "HasStdExtZfh", "true", + : SubtargetFeature<"experimental-zfh", "StdExtZfh", + "RISCVExtensionVersion{0, 1}", "'Zfh' (Half-Precision Floating-Point)", [FeatureStdExtZfhmin, FeatureStdExtF]>; def HasStdExtZfh : Predicate<"Subtarget->hasStdExtZfh()">, @@ -58,14 +60,15 @@ "'Zfh' (Half-Precision Floating-Point)">; def FeatureStdExtC - : SubtargetFeature<"c", "HasStdExtC", "true", + : SubtargetFeature<"c", "StdExtC", "RISCVExtensionVersion{2, 0}", "'C' (Compressed Instructions)">; def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">, AssemblerPredicate<(all_of FeatureStdExtC), "'C' (Compressed Instructions)">; def FeatureStdExtZba - : SubtargetFeature<"experimental-zba", "HasStdExtZba", "true", + : SubtargetFeature<"experimental-zba", "StdExtZba", + "RISCVExtensionVersion{1, 0}", "'Zba' (Address calculation 'B' Instructions)">; def HasStdExtZba : Predicate<"Subtarget->hasStdExtZba()">, AssemblerPredicate<(all_of FeatureStdExtZba), @@ -73,63 +76,72 @@ def NotHasStdExtZba : Predicate<"!Subtarget->hasStdExtZba()">; def FeatureStdExtZbb - : SubtargetFeature<"experimental-zbb", "HasStdExtZbb", "true", + : SubtargetFeature<"experimental-zbb", "StdExtZbb", + "RISCVExtensionVersion{1, 0}", "'Zbb' (Base 'B' Instructions)">; def HasStdExtZbb : Predicate<"Subtarget->hasStdExtZbb()">, AssemblerPredicate<(all_of FeatureStdExtZbb), "'Zbb' (Base 'B' Instructions)">; def FeatureStdExtZbc - : SubtargetFeature<"experimental-zbc", "HasStdExtZbc", "true", + : SubtargetFeature<"experimental-zbc", "StdExtZbc", + "RISCVExtensionVersion{1, 0}", "'Zbc' (Carry-Less 'B' Instructions)">; def HasStdExtZbc : Predicate<"Subtarget->hasStdExtZbc()">, AssemblerPredicate<(all_of FeatureStdExtZbc), "'Zbc' (Carry-Less 'B' Instructions)">; def FeatureStdExtZbe - : SubtargetFeature<"experimental-zbe", "HasStdExtZbe", "true", + : SubtargetFeature<"experimental-zbe", "StdExtZbe", + "RISCVExtensionVersion{0, 93}", "'Zbe' (Extract-Deposit 'B' Instructions)">; def HasStdExtZbe : Predicate<"Subtarget->hasStdExtZbe()">, AssemblerPredicate<(all_of FeatureStdExtZbe), "'Zbe' (Extract-Deposit 'B' Instructions)">; def FeatureStdExtZbf - : SubtargetFeature<"experimental-zbf", "HasStdExtZbf", "true", + : SubtargetFeature<"experimental-zbf", "StdExtZbf", + "RISCVExtensionVersion{0, 93}", "'Zbf' (Bit-Field 'B' Instructions)">; def HasStdExtZbf : Predicate<"Subtarget->hasStdExtZbf()">, AssemblerPredicate<(all_of FeatureStdExtZbf), "'Zbf' (Bit-Field 'B' Instructions)">; def FeatureStdExtZbm - : SubtargetFeature<"experimental-zbm", "HasStdExtZbm", "true", + : SubtargetFeature<"experimental-zbm", "StdExtZbm", + "RISCVExtensionVersion{0, 93}", "'Zbm' (Matrix 'B' Instructions)">; def HasStdExtZbm : Predicate<"Subtarget->hasStdExtZbm()">, AssemblerPredicate<(all_of FeatureStdExtZbm), "'Zbm' (Matrix 'B' Instructions)">; def FeatureStdExtZbp - : SubtargetFeature<"experimental-zbp", "HasStdExtZbp", "true", + : SubtargetFeature<"experimental-zbp", "StdExtZbp", + "RISCVExtensionVersion{0, 93}", "'Zbp' (Permutation 'B' Instructions)">; def HasStdExtZbp : Predicate<"Subtarget->hasStdExtZbp()">, AssemblerPredicate<(all_of FeatureStdExtZbp), "'Zbp' (Permutation 'B' Instructions)">; def FeatureStdExtZbr - : SubtargetFeature<"experimental-zbr", "HasStdExtZbr", "true", + : SubtargetFeature<"experimental-zbr", "StdExtZbr", + "RISCVExtensionVersion{0, 93}", "'Zbr' (Polynomial Reduction 'B' Instructions)">; def HasStdExtZbr : Predicate<"Subtarget->hasStdExtZbr()">, AssemblerPredicate<(all_of FeatureStdExtZbr), "'Zbr' (Polynomial Reduction 'B' Instructions)">; def FeatureStdExtZbs - : SubtargetFeature<"experimental-zbs", "HasStdExtZbs", "true", + : SubtargetFeature<"experimental-zbs", "StdExtZbs", + "RISCVExtensionVersion{1, 0}", "'Zbs' (Single-Bit 'B' Instructions)">; def HasStdExtZbs : Predicate<"Subtarget->hasStdExtZbs()">, AssemblerPredicate<(all_of FeatureStdExtZbs), "'Zbs' (Single-Bit 'B' Instructions)">; def FeatureStdExtZbt - : SubtargetFeature<"experimental-zbt", "HasStdExtZbt", "true", + : SubtargetFeature<"experimental-zbt", "StdExtZbt", + "RISCVExtensionVersion{0, 93}", "'Zbt' (Ternary 'B' Instructions)">; def HasStdExtZbt : Predicate<"Subtarget->hasStdExtZbt()">, AssemblerPredicate<(all_of FeatureStdExtZbt), @@ -151,22 +163,37 @@ "RVC Hint Instructions">; def FeatureStdExtV - : SubtargetFeature<"experimental-v", "HasStdExtV", "true", + : SubtargetFeature<"experimental-v", "StdExtV", + "RISCVExtensionVersion{0, 10}", "'V' (Vector Instructions)">; -def HasStdExtV : Predicate<"Subtarget->hasStdExtV()">, - AssemblerPredicate<(all_of FeatureStdExtV), - "'V' (Vector Instructions)">; +def FeatureStdExtV0P7 + : SubtargetFeature<"experimental-v0p7", "StdExtV", + "RISCVExtensionVersion{0, 7}", + "'V' (Vector Instructions)">; + +def HasStdExtV + : Predicate<"Subtarget->hasStdExtV()">, + AssemblerPredicate<(any_of FeatureStdExtV, FeatureStdExtV0P7), + "'V' (Vector Instructions)">; def HasVInstructions : Predicate<"Subtarget->hasVInstructions()">; def HasVInstructionsAnyF : Predicate<"Subtarget->hasVInstructionsAnyF()">; def FeatureStdExtZvlsseg - : SubtargetFeature<"experimental-zvlsseg", "HasStdExtZvlsseg", "true", + : SubtargetFeature<"experimental-zvlsseg", "StdExtZvlsseg", + "RISCVExtensionVersion{0, 10}", "'Zvlsseg' (Vector segment load/store instructions)", [FeatureStdExtV]>; -def HasStdExtZvlsseg : Predicate<"Subtarget->hasStdExtZvlsseg()">, - AssemblerPredicate<(all_of FeatureStdExtZvlsseg), - "'Zvlsseg' (Vector segment load/store instructions)">; +def FeatureStdExtZvlsseg0P7 + : SubtargetFeature<"experimental-zvlsseg0p7", "StdExtZvlsseg", + "RISCVExtensionVersion{0, 7}", + "'Zvlsseg' (Vector segment load/store instructions)", + [FeatureStdExtV0P7]>; + +def HasStdExtZvlsseg + : Predicate<"Subtarget->hasStdExtZvlsseg()">, + AssemblerPredicate<(any_of FeatureStdExtZvlsseg, FeatureStdExtZvlsseg0P7), + "'Zvlsseg' (Vector segment load/store instructions)">; def Feature64Bit : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">; @@ -181,7 +208,7 @@ def RV64 : HwMode<"+64bit">; def FeatureRV32E - : SubtargetFeature<"e", "IsRV32E", "true", + : SubtargetFeature<"e", "StdExtE", "RISCVExtensionVersion{1, 9}", "Implements RV32E (provides 16 rather than 32 GPRs)">; def IsRV32E : Predicate<"Subtarget->isRV32E()">, AssemblerPredicate<(all_of FeatureRV32E)>; Index: llvm/lib/Target/RISCV/RISCVSubtarget.h =================================================================== --- llvm/lib/Target/RISCV/RISCVSubtarget.h +++ llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -24,6 +24,7 @@ #include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Target/TargetMachine.h" #define GET_SUBTARGETINFO_HEADER @@ -34,27 +35,28 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { virtual void anchor(); - bool HasStdExtM = false; - bool HasStdExtA = false; - bool HasStdExtF = false; - bool HasStdExtD = false; - bool HasStdExtC = false; - bool HasStdExtZba = false; - bool HasStdExtZbb = false; - bool HasStdExtZbc = false; - bool HasStdExtZbe = false; - bool HasStdExtZbf = false; - bool HasStdExtZbm = false; - bool HasStdExtZbp = false; - bool HasStdExtZbr = false; - bool HasStdExtZbs = false; - bool HasStdExtZbt = false; - bool HasStdExtV = false; - bool HasStdExtZvlsseg = false; - bool HasStdExtZfhmin = false; - bool HasStdExtZfh = false; + RISCVExtensionVersion StdExtM = {0, 0}; + RISCVExtensionVersion StdExtA = {0, 0}; + RISCVExtensionVersion StdExtF = {0, 0}; + RISCVExtensionVersion StdExtD = {0, 0}; + RISCVExtensionVersion StdExtC = {0, 0}; + RISCVExtensionVersion StdExtZba = {0, 0}; + RISCVExtensionVersion StdExtZbb = {0, 0}; + RISCVExtensionVersion StdExtZbc = {0, 0}; + RISCVExtensionVersion StdExtZbe = {0, 0}; + RISCVExtensionVersion StdExtZbf = {0, 0}; + RISCVExtensionVersion StdExtZbm = {0, 0}; + RISCVExtensionVersion StdExtZbp = {0, 0}; + RISCVExtensionVersion StdExtZbr = {0, 0}; + RISCVExtensionVersion StdExtZbs = {0, 0}; + RISCVExtensionVersion StdExtZbt = {0, 0}; + RISCVExtensionVersion StdExtV = {0, 0}; + RISCVExtensionVersion StdExtZvlsseg = {0, 0}; + RISCVExtensionVersion StdExtZvamo = {0, 0}; + RISCVExtensionVersion StdExtZfhmin = {0, 0}; + RISCVExtensionVersion StdExtZfh = {0, 0}; + RISCVExtensionVersion StdExtE = {0, 0}; bool HasRV64 = false; - bool IsRV32E = false; bool EnableLinkerRelax = false; bool EnableRVCHintInstrs = true; bool EnableSaveRestore = false; @@ -69,6 +71,7 @@ RISCVTargetLowering TLInfo; SelectionDAGTargetInfo TSInfo; + void initializeEnvironment(); /// Initializes using the passed in CPU and feature strings so that we can /// use initializer lists for subtarget initialization. RISCVSubtarget &initializeSubtargetDependencies(const Triple &TT, @@ -100,27 +103,31 @@ return &TSInfo; } bool enableMachineScheduler() const override { return true; } - bool hasStdExtM() const { return HasStdExtM; } - bool hasStdExtA() const { return HasStdExtA; } - bool hasStdExtF() const { return HasStdExtF; } - bool hasStdExtD() const { return HasStdExtD; } - bool hasStdExtC() const { return HasStdExtC; } - bool hasStdExtZba() const { return HasStdExtZba; } - bool hasStdExtZbb() const { return HasStdExtZbb; } - bool hasStdExtZbc() const { return HasStdExtZbc; } - bool hasStdExtZbe() const { return HasStdExtZbe; } - bool hasStdExtZbf() const { return HasStdExtZbf; } - bool hasStdExtZbm() const { return HasStdExtZbm; } - bool hasStdExtZbp() const { return HasStdExtZbp; } - bool hasStdExtZbr() const { return HasStdExtZbr; } - bool hasStdExtZbs() const { return HasStdExtZbs; } - bool hasStdExtZbt() const { return HasStdExtZbt; } - bool hasStdExtV() const { return HasStdExtV; } - bool hasStdExtZvlsseg() const { return HasStdExtZvlsseg; } - bool hasStdExtZfhmin() const { return HasStdExtZfhmin; } - bool hasStdExtZfh() const { return HasStdExtZfh; } + bool hasStdExtM() const { return StdExtM != RISCVExtensionVersion{0, 0}; } + bool hasStdExtA() const { return StdExtA != RISCVExtensionVersion{0, 0}; } + bool hasStdExtF() const { return StdExtF != RISCVExtensionVersion{0, 0}; } + bool hasStdExtD() const { return StdExtD != RISCVExtensionVersion{0, 0}; } + bool hasStdExtC() const { return StdExtC != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZba() const { return StdExtZba != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbb() const { return StdExtZbb != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbc() const { return StdExtZbc != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbe() const { return StdExtZbe != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbf() const { return StdExtZbf != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbm() const { return StdExtZbm != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbp() const { return StdExtZbp != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbr() const { return StdExtZbr != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbs() const { return StdExtZbs != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZbt() const { return StdExtZbt != RISCVExtensionVersion{0, 0}; } + bool hasStdExtV() const { return StdExtV != RISCVExtensionVersion{0, 0}; } + bool hasStdExtZvlsseg() const { + return StdExtZvlsseg != RISCVExtensionVersion{0, 0}; + } + bool hasStdExtZfhmin() const { + return StdExtZfhmin != RISCVExtensionVersion{0, 0}; + } + bool hasStdExtZfh() const { return StdExtZfh != RISCVExtensionVersion{0, 0}; } bool is64Bit() const { return HasRV64; } - bool isRV32E() const { return IsRV32E; } + bool isRV32E() const { return StdExtE != RISCVExtensionVersion{0, 0}; } bool enableLinkerRelax() const { return EnableLinkerRelax; } bool enableRVCHintInstrs() const { return EnableRVCHintInstrs; } bool enableSaveRestore() const { return EnableSaveRestore; } @@ -133,11 +140,21 @@ } // Vector codegen related methods. - bool hasVInstructions() const { return HasStdExtV; } - bool hasVInstructionsI64() const { return HasStdExtV; } - bool hasVInstructionsF16() const { return HasStdExtV && hasStdExtZfh(); } - bool hasVInstructionsF32() const { return HasStdExtV && hasStdExtF(); } - bool hasVInstructionsF64() const { return HasStdExtV && hasStdExtD(); } + bool hasVInstructions() const { + return StdExtV != RISCVExtensionVersion{0, 0}; + } + bool hasVInstructionsI64() const { + return StdExtV != RISCVExtensionVersion{0, 0}; + } + bool hasVInstructionsF16() const { + return StdExtV != RISCVExtensionVersion{0, 0} && hasStdExtZfh(); + } + bool hasVInstructionsF32() const { + return StdExtV != RISCVExtensionVersion{0, 0} && hasStdExtF(); + } + bool hasVInstructionsF64() const { + return StdExtV != RISCVExtensionVersion{0, 0} && hasStdExtD(); + } // F16 and F64 both require F32. bool hasVInstructionsAnyF() const { return hasVInstructionsF32(); } unsigned getMaxInterleaveFactor() const { Index: llvm/lib/Target/RISCV/RISCVSubtarget.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -52,10 +52,43 @@ void RISCVSubtarget::anchor() {} +void RISCVSubtarget::initializeEnvironment() { + StdExtM = {0, 0}; + StdExtA = {0, 0}; + StdExtF = {0, 0}; + StdExtD = {0, 0}; + StdExtC = {0, 0}; + StdExtZba = {0, 0}; + StdExtZbb = {0, 0}; + StdExtZbc = {0, 0}; + StdExtZbe = {0, 0}; + StdExtZbf = {0, 0}; + StdExtZbm = {0, 0}; + StdExtZbp = {0, 0}; + StdExtZbr = {0, 0}; + StdExtZbs = {0, 0}; + StdExtZbt = {0, 0}; + StdExtV = {0, 0}; + StdExtZvlsseg = {0, 0}; + StdExtZvamo = {0, 0}; + StdExtZfhmin = {0, 0}; + StdExtZfh = {0, 0}; + StdExtE = {0, 0}; + HasRV64 = false; + EnableLinkerRelax = false; + EnableRVCHintInstrs = true; + EnableSaveRestore = false; + XLen = 32; + XLenVT = MVT::i32; + MaxInterleaveFactor = 2; + TargetABI = RISCVABI::ABI_Unknown; +} + RISCVSubtarget & RISCVSubtarget::initializeSubtargetDependencies(const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS, StringRef ABIName) { + initializeEnvironment(); // Determine default and user-specified characteristics bool Is64Bit = TT.isArch64Bit(); if (CPU.empty()) @@ -66,7 +99,6 @@ if (TuneCPU.empty()) TuneCPU = CPU; - ParseSubtargetFeatures(CPU, TuneCPU, FS); if (Is64Bit) { XLenVT = MVT::i64; Index: llvm/test/CodeGen/RISCV/attributes.ll =================================================================== --- llvm/test/CodeGen/RISCV/attributes.ll +++ llvm/test/CodeGen/RISCV/attributes.ll @@ -17,6 +17,7 @@ ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbr %s -o - | FileCheck --check-prefix=RV32ZBR %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbs %s -o - | FileCheck --check-prefix=RV32ZBS %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbt %s -o - | FileCheck --check-prefix=RV32ZBT %s +; RUN: llc -mtriple=riscv32 -mattr=+experimental-v0p7 %s -o - | FileCheck --check-prefix=RV32V0P7 %s ; RUN: llc -mtriple=riscv64 -mattr=+m %s -o - | FileCheck --check-prefix=RV64M %s ; RUN: llc -mtriple=riscv64 -mattr=+a %s -o - | FileCheck --check-prefix=RV64A %s ; RUN: llc -mtriple=riscv64 -mattr=+f %s -o - | FileCheck --check-prefix=RV64F %s @@ -34,6 +35,7 @@ ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbr %s -o - | FileCheck --check-prefix=RV64ZBR %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbs %s -o - | FileCheck --check-prefix=RV64ZBS %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbt %s -o - | FileCheck --check-prefix=RV64ZBT %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-v0p7 %s -o - | FileCheck --check-prefix=RV64V0P7 %s ; RV32M: .attribute 5, "rv32i2p0_m2p0" ; RV32A: .attribute 5, "rv32i2p0_a2p0" @@ -53,6 +55,7 @@ ; RV32ZBR: .attribute 5, "rv32i2p0_zbr0p93" ; RV32ZBS: .attribute 5, "rv32i2p0_zbs1p0" ; RV32ZBT: .attribute 5, "rv32i2p0_zbt0p93" +; RV32V0P7: .attribute 5, "rv32i2p0_v0p7_zvlsseg0p7" ; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh0p1_zfhmin0p1_zbb1p0_zvlsseg0p10" ; RV64M: .attribute 5, "rv64i2p0_m2p0" @@ -73,6 +76,7 @@ ; RV64ZBS: .attribute 5, "rv64i2p0_zbs1p0" ; RV64ZBT: .attribute 5, "rv64i2p0_zbt0p93" ; RV64V: .attribute 5, "rv64i2p0_v0p10_zvlsseg0p10" +; RV64V0P7: .attribute 5, "rv64i2p0_v0p7_zvlsseg0p7" ; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh0p1_zfhmin0p1_zbb1p0_zvlsseg0p10" Index: llvm/test/MC/RISCV/attribute-arch.s =================================================================== --- llvm/test/MC/RISCV/attribute-arch.s +++ llvm/test/MC/RISCV/attribute-arch.s @@ -76,3 +76,6 @@ .attribute arch, "rv32iv0p10zvlsseg0p10" # CHECK: attribute 5, "rv32i2p0_v0p10_zvlsseg0p10" + +.attribute arch, "rv32iv0p7zvlsseg0p7" +# CHECK: attribute 5, "rv32i2p0_v0p7_zvlsseg0p7" Index: llvm/test/tools/llvm-objdump/ELF/RISCV/unknown-arch-attr.test =================================================================== --- llvm/test/tools/llvm-objdump/ELF/RISCV/unknown-arch-attr.test +++ llvm/test/tools/llvm-objdump/ELF/RISCV/unknown-arch-attr.test @@ -3,7 +3,7 @@ ## The expected behavior is to ignore the unrecognized arch feature and ## continue to process the following arch features. ## -## The object file has the "rv32i2p0_x1p0_m2p0" arch feature. "x1p0" is an +## The object file has the "rv32i2p0_y1p0_m2p0" arch feature. "y1p0" is an ## unrecognized architecture extension. llvm-objdump will ignore it and decode ## "mul" instruction correctly according to "m2p0" in the arch feature. ## @@ -34,5 +34,5 @@ Content: 3385C502 - Name: .riscv.attributes Type: SHT_RISCV_ATTRIBUTES -## The content is the encoding of the arch feature "rv32i2p0_x1p0_m2p0" - Content: 412300000072697363760001190000000572763332693270305F783170305F6D32703000 +## The content is the encoding of the arch feature "rv32i2p0_y1p0_m2p0" + Content: 412300000072697363760001190000000572763332693270305F793170305F6D32703000