diff --git a/llvm/include/llvm/MC/SubtargetFeature.h b/llvm/include/llvm/MC/SubtargetFeature.h --- a/llvm/include/llvm/MC/SubtargetFeature.h +++ b/llvm/include/llvm/MC/SubtargetFeature.h @@ -189,6 +189,8 @@ /// Adds Features. void AddFeature(StringRef String, bool Enable = true); + void addFeaturesVector(const ArrayRef OtherFeatures); + /// Returns the vector of individual subtarget features. const std::vector &getFeatures() const { return Features; } diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h --- a/llvm/include/llvm/Object/COFF.h +++ b/llvm/include/llvm/Object/COFF.h @@ -980,7 +980,9 @@ StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; Expected getStartAddress() const override; - SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } + Expected getFeatures() const override { + return SubtargetFeatures(); + } import_directory_iterator import_directory_begin() const; import_directory_iterator import_directory_end() const; diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -55,7 +55,7 @@ SubtargetFeatures getMIPSFeatures() const; SubtargetFeatures getARMFeatures() const; - SubtargetFeatures getRISCVFeatures() const; + Expected getRISCVFeatures() const; SubtargetFeatures getLoongArchFeatures() const; StringRef getAMDGPUCPUName() const; @@ -87,7 +87,7 @@ static bool classof(const Binary *v) { return v->isELF(); } - SubtargetFeatures getFeatures() const override; + Expected getFeatures() const override; std::optional tryGetCPUName() const override; diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -514,7 +514,9 @@ StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; - SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } + Expected getFeatures() const override { + return SubtargetFeatures(); + } Triple getArchTriple(const char **McpuDefault = nullptr) const; relocation_iterator section_rel_begin(unsigned Index) const; diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -336,7 +336,7 @@ virtual StringRef getFileFormatName() const = 0; virtual Triple::ArchType getArch() const = 0; - virtual SubtargetFeatures getFeatures() const = 0; + virtual Expected getFeatures() const = 0; virtual std::optional tryGetCPUName() const { return std::nullopt; }; diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -203,7 +203,7 @@ uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; - SubtargetFeatures getFeatures() const override; + Expected getFeatures() const override; bool isRelocatableObject() const override; bool isSharedObject() const; diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -608,7 +608,7 @@ uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; - SubtargetFeatures getFeatures() const override; + Expected getFeatures() const override; Expected getStartAddress() const override; StringRef mapDebugSectionName(StringRef Name) const override; bool isRelocatableObject() const override; diff --git a/llvm/include/llvm/Support/RISCVISAInfo.h b/llvm/include/llvm/Support/RISCVISAInfo.h --- a/llvm/include/llvm/Support/RISCVISAInfo.h +++ b/llvm/include/llvm/Support/RISCVISAInfo.h @@ -45,7 +45,8 @@ /// Parse RISCV ISA info from arch string. static llvm::Expected> parseArchString(StringRef Arch, bool EnableExperimentalExtension, - bool ExperimentalExtensionVersionCheck = true); + bool ExperimentalExtensionVersionCheck = true, + bool IgnoreUnknown = false); /// Parse RISCV ISA info from feature vector. static llvm::Expected> diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp --- a/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp @@ -1145,9 +1145,14 @@ TT.setOS(Triple::UnknownOS); // Features to be passed to target/subtarget - SubtargetFeatures Features = Obj.getFeatures(); - - return loadGenericTargetInfo(TT.str(), Features.getString()); + Expected Features = Obj.getFeatures(); + SubtargetFeatures FeaturesValue; + if (!Features) { + consumeError(Features.takeError()); + FeaturesValue = SubtargetFeatures(); + } + FeaturesValue = *Features; + return loadGenericTargetInfo(TT.str(), FeaturesValue.getString()); } void LVELFReader::mapRangeAddress(const ObjectFile &Obj) { diff --git a/llvm/lib/MC/SubtargetFeature.cpp b/llvm/lib/MC/SubtargetFeature.cpp --- a/llvm/lib/MC/SubtargetFeature.cpp +++ b/llvm/lib/MC/SubtargetFeature.cpp @@ -42,6 +42,11 @@ : (Enable ? "+" : "-") + String.lower()); } +void SubtargetFeatures::addFeaturesVector( + const ArrayRef OtherFeatures) { + Features.insert(Features.cend(), OtherFeatures.begin(), OtherFeatures.end()); +} + SubtargetFeatures::SubtargetFeatures(StringRef Initial) { // Break up string into separate features Split(Features, Initial); diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/RISCVAttributeParser.h" #include "llvm/Support/RISCVAttributes.h" +#include "llvm/Support/RISCVISAInfo.h" #include #include #include @@ -286,7 +287,7 @@ return Features; } -SubtargetFeatures ELFObjectFileBase::getRISCVFeatures() const { +Expected ELFObjectFileBase::getRISCVFeatures() const { SubtargetFeatures Features; unsigned PlatformFlags = getPlatformFlags(); @@ -294,50 +295,33 @@ Features.AddFeature("c"); } - // Add features according to the ELF attribute section. - // If there are any unrecognized features, ignore them. RISCVAttributeParser Attributes; if (Error E = getBuildAttributes(Attributes)) { - // TODO Propagate Error. - consumeError(std::move(E)); - return Features; // Keep "c" feature if there is one in PlatformFlags. + return E; } std::optional Attr = Attributes.getAttributeString(RISCVAttrs::ARCH); + if (Attr) { - // 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; - if (Arch.consume_front("rv32")) + // Suppress version checking for experimental extensions to prevent erroring + // when getting any unknown version of experimental extension. + auto ParseResult = RISCVISAInfo::parseArchString( + *Attr, /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false, + /*IgnoreUnknown=*/true); + if (!ParseResult) + return ParseResult.takeError(); + 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"); + else + llvm_unreachable("XLEN should be 32 or 64."); - 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. - [[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 == '_'; }); - } + Features.addFeaturesVector(ISAInfo->toFeatureVector()); } return Features; @@ -361,7 +345,7 @@ return Features; } -SubtargetFeatures ELFObjectFileBase::getFeatures() const { +Expected ELFObjectFileBase::getFeatures() const { switch (getEMachine()) { case ELF::EM_MIPS: return getMIPSFeatures(); diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1833,7 +1833,7 @@ return HasMemory64 ? Triple::wasm64 : Triple::wasm32; } -SubtargetFeatures WasmObjectFile::getFeatures() const { +Expected WasmObjectFile::getFeatures() const { return SubtargetFeatures(); } diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -712,7 +712,7 @@ return is64Bit() ? Triple::ppc64 : Triple::ppc; } -SubtargetFeatures XCOFFObjectFile::getFeatures() const { +Expected XCOFFObjectFile::getFeatures() const { return SubtargetFeatures(); } diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -489,7 +489,8 @@ llvm::Expected> RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension, - bool ExperimentalExtensionVersionCheck) { + bool ExperimentalExtensionVersionCheck, + bool IgnoreUnknown) { // RISC-V ISA strings must be lowercase. if (llvm::any_of(Arch, isupper)) { return createStringError(errc::invalid_argument, @@ -574,6 +575,11 @@ auto StdExtsItr = StdExts.begin(); auto StdExtsEnd = StdExts.end(); + auto GoToNextExt = [](StringRef::iterator &I, unsigned ConsumeLength) { + I += 1 + ConsumeLength; + if (*I == '_') + ++I; + }; for (auto I = Exts.begin(), E = Exts.end(); I != E;) { char C = *I; @@ -604,25 +610,32 @@ Next = std::string(std::next(I), E); if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor, ConsumeLength, EnableExperimentalExtension, - ExperimentalExtensionVersionCheck)) + ExperimentalExtensionVersionCheck)) { + if (IgnoreUnknown) { + consumeError(std::move(E)); + GoToNextExt(I, ConsumeLength); + continue; + } 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 "mafdcv". - StringRef SupportedStandardExtension = "mafdcv"; - if (!SupportedStandardExtension.contains(C)) + if (!isSupportedExtension(StringRef(&C, 1))) { + if (IgnoreUnknown) { + GoToNextExt(I, ConsumeLength); + continue; + } return createStringError(errc::invalid_argument, "unsupported standard user-level extension '%c'", C); + } ISAInfo->addExtension(std::string(1, C), Major, Minor); // Consume full extension name and version, including any optional '_' // between this extension and the next - ++I; - I += ConsumeLength; - if (*I == '_') - ++I; + GoToNextExt(I, ConsumeLength); } // Handle other types of extensions other than the standard @@ -656,20 +669,28 @@ StringRef Name(Ext.substr(0, Pos)); StringRef Vers(Ext.substr(Pos)); - if (Type.empty()) + if (Type.empty()) { + if (IgnoreUnknown) + continue; return createStringError(errc::invalid_argument, "invalid extension prefix '" + Ext + "'"); + } // Check ISA extensions are specified in the canonical order. while (I != E && *I != Type) ++I; - if (I == E) + if (I == E) { + if (IgnoreUnknown) + continue; return createStringError(errc::invalid_argument, "%s not given in canonical order '%s'", Desc.str().c_str(), Ext.str().c_str()); + } - if (Name.size() == Type.size()) { + if (!IgnoreUnknown && Name.size() == Type.size()) { + if (IgnoreUnknown) + continue; return createStringError(errc::invalid_argument, "%s name missing after '%s'", Desc.str().c_str(), Type.str().c_str()); @@ -678,13 +699,21 @@ unsigned Major, Minor, ConsumeLength; if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength, EnableExperimentalExtension, - ExperimentalExtensionVersionCheck)) + ExperimentalExtensionVersionCheck)) { + if (IgnoreUnknown) { + consumeError(std::move(E)); + continue; + } return std::move(E); + } // Check if duplicated extension. - if (llvm::is_contained(AllExts, Name)) + if (!IgnoreUnknown && llvm::is_contained(AllExts, Name)) { + if (IgnoreUnknown) + continue; return createStringError(errc::invalid_argument, "duplicated %s '%s'", Desc.str().c_str(), Name.str().c_str()); + } ISAInfo->addExtension(Name, Major, Minor); // Extension format is correct, keep parsing the extensions. diff --git a/llvm/test/tools/llvm-objdump/ELF/RISCV/extensions.test b/llvm/test/tools/llvm-objdump/ELF/RISCV/extensions.test --- a/llvm/test/tools/llvm-objdump/ELF/RISCV/extensions.test +++ b/llvm/test/tools/llvm-objdump/ELF/RISCV/extensions.test @@ -9,13 +9,13 @@ # RUN: | FileCheck %s --check-prefixes=DISASM # DISASM-LABEL: -# DISASM: +# DISASM: clmul a0, a0, a1 # DISASM-LABEL: -# DISASM: +# DISASM: clmulh a0, a0, a1 # DISASM-LABEL: -# DISASM: +# DISASM: clmulr a0, a0, a1 --- !ELF FileHeader: diff --git a/llvm/test/tools/llvm-objdump/ELF/RISCV/objdump-instr-from-extensions.s b/llvm/test/tools/llvm-objdump/ELF/RISCV/objdump-instr-from-extensions.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ELF/RISCV/objdump-instr-from-extensions.s @@ -0,0 +1,34 @@ +# Objdump should decode instructions that are supported by extensions that are used in RISCV_ARCH attribute. + +# RUN: llvm-mc -filetype=obj -triple riscv64 %s | \ +# RUN: llvm-objdump -d -M no-aliases - | \ +# RUN: FileCheck %s + .attribute 5, "rv64gcv" +# CHECK-LABEL: : +foo: +# CHECK: vsetvli a3, a2, e8, m8, tu, mu + vsetvli a3, a2, e8, m8, tu, mu + +# CHECK: fadd.s fs10, fs11, ft8 +fadd.s f26, f27, f28 + +# CHECK: fld ft0, 12(a0) +fld f0, 12(a0) + +# CHECK: fmul.d ft0, ft1, ft2, dyn +fmul.d ft0, ft1, ft2, dyn + +# CHECK: vfsub.vv v8, v4, v20, v0.t +vfsub.vv v8, v4, v20, v0.t + +# CHECK: vfsub.vf v8, v4, fa0, v0.t +vfsub.vf v8, v4, fa0, v0.t + +# CHECK: vfrsub.vf v8, v4, fa0, v0.t +vfrsub.vf v8, v4, fa0, v0.t + +# CHECK: vfwsub.vv v8, v4, v20, v0.t +vfwsub.vv v8, v4, v20, v0.t + +# CHECK: vfwsub.vf v8, v4, fa0, v0.t +vfwsub.vf v8, v4, fa0, v0.t diff --git a/llvm/test/tools/llvm-objdump/ELF/RISCV/unknown-arch-attr.test b/llvm/test/tools/llvm-objdump/ELF/RISCV/unknown-arch-attr.test --- a/llvm/test/tools/llvm-objdump/ELF/RISCV/unknown-arch-attr.test +++ b/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_m2p0_x1p0" arch feature. "x1p0" 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_m2p0_x1p0" + Content: 412300000072697363760001190000000572763332693270305F6D3270305F7831703000 diff --git a/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp b/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp --- a/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp +++ b/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp @@ -96,7 +96,11 @@ } Analysis.ObjectTriple = Analysis.Object->makeTriple(); - Analysis.Features = Analysis.Object->getFeatures(); + Expected Features = Analysis.Object->getFeatures(); + if (!Features) + return Features.takeError(); + + Analysis.Features = *Features; // Init the rest of the object. if (auto InitResponse = Analysis.initialiseDisassemblyMembers()) diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2002,7 +2002,10 @@ const Target *TheTarget = getTarget(Obj); // Package up features to be passed to target/subtarget - SubtargetFeatures Features = Obj->getFeatures(); + Expected FeaturesValue = Obj->getFeatures(); + if (!FeaturesValue) + WithColor::error(errs(), ToolName) << FeaturesValue.takeError(); + SubtargetFeatures Features = *FeaturesValue; if (!MAttrs.empty()) { for (unsigned I = 0; I != MAttrs.size(); ++I) Features.AddFeature(MAttrs[I]); diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp --- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp +++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp @@ -560,9 +560,11 @@ if (!AsmInfo) exitWithError("no assembly info for target " + TripleName, FileName); - SubtargetFeatures Features = Obj->getFeatures(); - STI.reset( - TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString())); + Expected Features = Obj->getFeatures(); + if (!Features) + exitWithError(Features.takeError(), FileName); + STI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", + Features->getString())); if (!STI) exitWithError("no subtarget info for target " + TripleName, FileName);