/// Adds Features.
void AddFeature(StringRef String, bool Enable = true);
+ void addFeaturesVector(const ArrayRef<std::string> OtherFeatures);
+
/// Returns the vector of individual subtarget features.
const std::vector<std::string> &getFeatures() const { return Features; }
StringRef getFileFormatName() const override;
Triple::ArchType getArch() const override;
Expected<uint64_t> getStartAddress() const override;
- SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); }
+ Expected<SubtargetFeatures> getFeatures() const override {
+ return SubtargetFeatures();
+ }
import_directory_iterator import_directory_begin() const;
import_directory_iterator import_directory_end() const;
SubtargetFeatures getMIPSFeatures() const;
SubtargetFeatures getARMFeatures() const;
- SubtargetFeatures getRISCVFeatures() const;
+ Expected<SubtargetFeatures> getRISCVFeatures() const;
SubtargetFeatures getLoongArchFeatures() const;
StringRef getAMDGPUCPUName() const;
static bool classof(const Binary *v) { return v->isELF(); }
- SubtargetFeatures getFeatures() const override;
+ Expected<SubtargetFeatures> getFeatures() const override;
std::optional<StringRef> tryGetCPUName() const override;
StringRef getFileFormatName() const override;
Triple::ArchType getArch() const override;
- SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); }
+ Expected<SubtargetFeatures> getFeatures() const override {
+ return SubtargetFeatures();
+ }
Triple getArchTriple(const char **McpuDefault = nullptr) const;
relocation_iterator section_rel_begin(unsigned Index) const;
virtual StringRef getFileFormatName() const = 0;
virtual Triple::ArchType getArch() const = 0;
- virtual SubtargetFeatures getFeatures() const = 0;
+ virtual Expected<SubtargetFeatures> getFeatures() const = 0;
virtual std::optional<StringRef> tryGetCPUName() const {
return std::nullopt;
};
uint8_t getBytesInAddress() const override;
StringRef getFileFormatName() const override;
Triple::ArchType getArch() const override;
- SubtargetFeatures getFeatures() const override;
+ Expected<SubtargetFeatures> getFeatures() const override;
bool isRelocatableObject() const override;
bool isSharedObject() const;
uint8_t getBytesInAddress() const override;
StringRef getFileFormatName() const override;
Triple::ArchType getArch() const override;
- SubtargetFeatures getFeatures() const override;
+ Expected<SubtargetFeatures> getFeatures() const override;
Expected<uint64_t> getStartAddress() const override;
StringRef mapDebugSectionName(StringRef Name) const override;
bool isRelocatableObject() const override;
/// Parse RISCV ISA info from arch string.
static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
parseArchString(StringRef Arch, bool EnableExperimentalExtension,
- bool ExperimentalExtensionVersionCheck = true);
+ bool ExperimentalExtensionVersionCheck = true,
+ bool IgnoreUnknown = false);
/// Parse RISCV ISA info from feature vector.
static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
TT.setOS(Triple::UnknownOS);
// Features to be passed to target/subtarget
- SubtargetFeatures Features = Obj.getFeatures();
-
- return loadGenericTargetInfo(TT.str(), Features.getString());
+ Expected<SubtargetFeatures> 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) {
: (Enable ? "+" : "-") + String.lower());
}
+void SubtargetFeatures::addFeaturesVector(
+ const ArrayRef<std::string> OtherFeatures) {
+ Features.insert(Features.cend(), OtherFeatures.begin(), OtherFeatures.end());
+}
+
SubtargetFeatures::SubtargetFeatures(StringRef Initial) {
// Break up string into separate features
Split(Features, Initial);
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/RISCVAttributeParser.h"
#include "llvm/Support/RISCVAttributes.h"
+#include "llvm/Support/RISCVISAInfo.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
return Features;
}
-SubtargetFeatures ELFObjectFileBase::getRISCVFeatures() const {
+Expected<SubtargetFeatures> ELFObjectFileBase::getRISCVFeatures() const {
SubtargetFeatures Features;
unsigned PlatformFlags = getPlatformFlags();
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<StringRef> 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;
return Features;
}
-SubtargetFeatures ELFObjectFileBase::getFeatures() const {
+Expected<SubtargetFeatures> ELFObjectFileBase::getFeatures() const {
switch (getEMachine()) {
case ELF::EM_MIPS:
return getMIPSFeatures();
return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
}
-SubtargetFeatures WasmObjectFile::getFeatures() const {
+Expected<SubtargetFeatures> WasmObjectFile::getFeatures() const {
return SubtargetFeatures();
}
return is64Bit() ? Triple::ppc64 : Triple::ppc;
}
-SubtargetFeatures XCOFFObjectFile::getFeatures() const {
+Expected<SubtargetFeatures> XCOFFObjectFile::getFeatures() const {
return SubtargetFeatures();
}
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
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,
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;
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 "mafdcvh".
- StringRef SupportedStandardExtension = "mafdcvh";
- 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
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());
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.
# RUN: | FileCheck %s --check-prefixes=DISASM
# DISASM-LABEL: <clmul>
-# DISASM: <unknown>
+# DISASM: clmul a0, a0, a1
# DISASM-LABEL: <clmulh>
-# DISASM: <unknown>
+# DISASM: clmulh a0, a0, a1
# DISASM-LABEL: <clmulr>
-# DISASM: <unknown>
+# DISASM: clmulr a0, a0, a1
--- !ELF
FileHeader:
--- /dev/null
+## llvm-objdump should decode instructions that are supported by extensions that are used in Tag_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>:
+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
\ No newline at end of file
## 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.
##
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
}
Analysis.ObjectTriple = Analysis.Object->makeTriple();
- Analysis.Features = Analysis.Object->getFeatures();
+ Expected<SubtargetFeatures> Features = Analysis.Object->getFeatures();
+ if (!Features)
+ return Features.takeError();
+
+ Analysis.Features = *Features;
// Init the rest of the object.
if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
const Target *TheTarget = getTarget(Obj);
// Package up features to be passed to target/subtarget
- SubtargetFeatures Features = Obj->getFeatures();
+ Expected<SubtargetFeatures> 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]);
if (!AsmInfo)
exitWithError("no assembly info for target " + TripleName, FileName);
- SubtargetFeatures Features = Obj->getFeatures();
+ Expected<SubtargetFeatures> Features = Obj->getFeatures();
+ if (!Features)
+ exitWithError(Features.takeError(), FileName);
STI.reset(
- TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString()));
+ TheTarget->createMCSubtargetInfo(TripleName, "", Features->getString()));
if (!STI)
exitWithError("no subtarget info for target " + TripleName, FileName);