[llvm] 581ba35 - [RISCV] ELF attribute section for RISC-V.
Kai Wang via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 31 01:16:30 PDT 2020
Author: Kai Wang
Date: 2020-03-31T16:16:19+08:00
New Revision: 581ba35291a658cd01e2cb39f6d415cac89a7656
URL: https://github.com/llvm/llvm-project/commit/581ba35291a658cd01e2cb39f6d415cac89a7656
DIFF: https://github.com/llvm/llvm-project/commit/581ba35291a658cd01e2cb39f6d415cac89a7656.diff
LOG: [RISCV] ELF attribute section for RISC-V.
Leverage ARM ELF build attribute section to create ELF attribute section
for RISC-V. Extract the common part of parsing logic for this section
into ELFAttributeParser.[cpp|h] and ELFAttributes.[cpp|h].
Differential Revision: https://reviews.llvm.org/D74023
Added:
llvm/include/llvm/Support/ELFAttributeParser.h
llvm/include/llvm/Support/ELFAttributes.h
llvm/include/llvm/Support/RISCVAttributeParser.h
llvm/include/llvm/Support/RISCVAttributes.h
llvm/lib/Support/ELFAttributeParser.cpp
llvm/lib/Support/ELFAttributes.cpp
llvm/lib/Support/RISCVAttributeParser.cpp
llvm/lib/Support/RISCVAttributes.cpp
llvm/test/CodeGen/RISCV/attributes.ll
llvm/test/MC/RISCV/attribute-arch.s
llvm/test/MC/RISCV/attribute-with-insts.s
llvm/test/MC/RISCV/attribute.s
llvm/test/MC/RISCV/invalid-attribute.s
llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg
llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test
llvm/unittests/Support/ELFAttributeParserTest.cpp
llvm/unittests/Support/RISCVAttributeParserTest.cpp
Modified:
lld/ELF/InputFiles.cpp
lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
llvm/include/llvm/BinaryFormat/ELF.h
llvm/include/llvm/Object/ELFObjectFile.h
llvm/include/llvm/Support/ARMAttributeParser.h
llvm/include/llvm/Support/ARMBuildAttributes.h
llvm/lib/Object/ELF.cpp
llvm/lib/Object/ELFObjectFile.cpp
llvm/lib/ObjectYAML/ELFYAML.cpp
llvm/lib/Support/ARMAttributeParser.cpp
llvm/lib/Support/ARMBuildAttrs.cpp
llvm/lib/Support/CMakeLists.txt
llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
llvm/tools/llvm-readobj/ELFDumper.cpp
llvm/unittests/Support/ARMAttributeParser.cpp
llvm/unittests/Support/CMakeLists.txt
Removed:
################################################################################
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 8c7ea91e05f0..6f63a34e40c1 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -669,7 +669,9 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) {
// the input objects have been compiled.
static void updateARMVFPArgs(const ARMAttributeParser &attributes,
const InputFile *f) {
- if (!attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args))
+ Optional<unsigned> attr =
+ attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args);
+ if (!attr.hasValue())
// If an ABI tag isn't present then it is implicitly given the value of 0
// which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files,
// including some in glibc that don't use FP args (and should have value 3)
@@ -677,7 +679,7 @@ static void updateARMVFPArgs(const ARMAttributeParser &attributes,
// as a clash.
return;
- unsigned vfpArgs = attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args);
+ unsigned vfpArgs = attr.getValue();
ARMVFPArgKind arg;
switch (vfpArgs) {
case ARMBuildAttrs::BaseAAPCS:
@@ -714,9 +716,11 @@ static void updateARMVFPArgs(const ARMAttributeParser &attributes,
// is compiled with an architecture that supports these features then lld is
// permitted to use them.
static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) {
- if (!attributes.hasAttribute(ARMBuildAttrs::CPU_arch))
+ Optional<unsigned> attr =
+ attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+ if (!attr.hasValue())
return;
- auto arch = attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+ auto arch = attr.getValue();
switch (arch) {
case ARMBuildAttrs::Pre_v4:
case ARMBuildAttrs::v4:
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 403aa5909bd6..2b3779ec7826 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -1239,7 +1239,7 @@ void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length,
lldb::offset_t Offset = 0;
uint8_t FormatVersion = data.GetU8(&Offset);
- if (FormatVersion != llvm::ARMBuildAttrs::Format_Version)
+ if (FormatVersion != llvm::ELFAttrs::Format_Version)
return;
Offset = Offset + sizeof(uint32_t); // Section Length
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index d72deebbe7fa..9bf5a3c99a55 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -881,6 +881,8 @@ enum : unsigned {
SHT_MSP430_ATTRIBUTES = 0x70000003U,
+ SHT_RISCV_ATTRIBUTES = 0x70000003U,
+
SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type.
SHT_LOUSER = 0x80000000, // Lowest type reserved for applications.
SHT_HIUSER = 0xffffffff // Highest type reserved for applications.
diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index e2c9b42e04b4..de18b7955c24 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -28,8 +28,8 @@
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/SymbolicFile.h"
#include "llvm/Support/ARMAttributeParser.h"
-#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/ELFAttributes.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
@@ -64,7 +64,7 @@ class ELFObjectFileBase : public ObjectFile {
virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0;
virtual Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0;
- virtual Error getBuildAttributes(ARMAttributeParser &Attributes) const = 0;
+ virtual Error getBuildAttributes(ELFAttributeParser &Attributes) const = 0;
public:
using elf_symbol_iterator_range = iterator_range<elf_symbol_iterator>;
@@ -365,19 +365,20 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_PROTECTED));
}
- Error getBuildAttributes(ARMAttributeParser &Attributes) const override {
+ Error getBuildAttributes(ELFAttributeParser &Attributes) const override {
auto SectionsOrErr = EF.sections();
if (!SectionsOrErr)
return SectionsOrErr.takeError();
for (const Elf_Shdr &Sec : *SectionsOrErr) {
- if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) {
+ if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES ||
+ Sec.sh_type == ELF::SHT_RISCV_ATTRIBUTES) {
auto ErrorOrContents = EF.getSectionContents(&Sec);
if (!ErrorOrContents)
return ErrorOrContents.takeError();
auto Contents = ErrorOrContents.get();
- if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1)
+ if (Contents[0] != ELFAttrs::Format_Version || Contents.size() == 1)
return Error::success();
if (Error E = Attributes.parse(Contents, ELFT::TargetEndianness))
diff --git a/llvm/include/llvm/Support/ARMAttributeParser.h b/llvm/include/llvm/Support/ARMAttributeParser.h
index c0f86ecd8b6a..bf85ea14cfe3 100644
--- a/llvm/include/llvm/Support/ARMAttributeParser.h
+++ b/llvm/include/llvm/Support/ARMAttributeParser.h
@@ -1,4 +1,4 @@
-//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===//
+//===- ARMAttributeParser.h - ARM Attribute Information Printer -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -10,36 +10,24 @@
#define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
#include "ARMBuildAttributes.h"
+#include "ELFAttributeParser.h"
#include "ScopedPrinter.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
-#include <map>
-
namespace llvm {
class StringRef;
-class ARMAttributeParser {
- ScopedPrinter *sw;
-
- std::map<unsigned, unsigned> attributes;
- DataExtractor de{ArrayRef<uint8_t>{}, true, 0};
- DataExtractor::Cursor cursor{0};
-
+class ARMAttributeParser : public ELFAttributeParser {
struct DisplayHandler {
ARMBuildAttrs::AttrType attribute;
Error (ARMAttributeParser::*routine)(ARMBuildAttrs::AttrType);
};
static const DisplayHandler displayRoutines[];
- Error parseAttributeList(uint32_t length);
- void parseIndexList(SmallVectorImpl<uint8_t> &indexList);
- Error parseSubsection(uint32_t length);
- Error parseStringAttribute(const char *name, ARMBuildAttrs::AttrType tag,
- const ArrayRef<const char *> array);
- void printAttribute(unsigned tag, unsigned value, StringRef valueDesc);
+ Error handler(uint64_t tag, bool &handled) override;
Error stringAttribute(ARMBuildAttrs::AttrType tag);
@@ -82,20 +70,11 @@ class ARMAttributeParser {
Error nodefaults(ARMBuildAttrs::AttrType tag);
public:
- ARMAttributeParser(ScopedPrinter *sw) : sw(sw) {}
- ARMAttributeParser() : sw(nullptr) {}
- ~ARMAttributeParser() { static_cast<void>(!cursor.takeError()); }
-
- Error parse(ArrayRef<uint8_t> section, support::endianness endian);
-
- bool hasAttribute(unsigned tag) const { return attributes.count(tag); }
-
- unsigned getAttributeValue(unsigned tag) const {
- return attributes.find(tag)->second;
- }
+ ARMAttributeParser(ScopedPrinter *sw)
+ : ELFAttributeParser(sw, ARMBuildAttrs::ARMAttributeTags, "aeabi") {}
+ ARMAttributeParser()
+ : ELFAttributeParser(ARMBuildAttrs::ARMAttributeTags, "aeabi") {}
};
-
}
#endif
-
diff --git a/llvm/include/llvm/Support/ARMBuildAttributes.h b/llvm/include/llvm/Support/ARMBuildAttributes.h
index dc0c3e3ea2ff..5a06fd6ca7be 100644
--- a/llvm/include/llvm/Support/ARMBuildAttributes.h
+++ b/llvm/include/llvm/Support/ARMBuildAttributes.h
@@ -18,18 +18,20 @@
#ifndef LLVM_SUPPORT_ARMBUILDATTRIBUTES_H
#define LLVM_SUPPORT_ARMBUILDATTRIBUTES_H
-namespace llvm {
-class StringRef;
+#include "llvm/Support/ELFAttributes.h"
+namespace llvm {
namespace ARMBuildAttrs {
+extern const TagNameMap ARMAttributeTags;
+
enum SpecialAttr {
// This is for the .cpu asm attr. It translates into one or more
// AttrType (below) entries in the .ARM.attributes section in the ELF.
SEL_CPU
};
-enum AttrType {
+enum AttrType : unsigned {
// Rest correspond to ELF/.ARM.attributes
File = 1,
CPU_raw_name = 4,
@@ -82,15 +84,6 @@ enum AttrType {
MPextension_use_old = 70 // recoded to MPextension_use (ABI r2.08)
};
-StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix = true);
-StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix = true);
-int AttrTypeFromString(StringRef Tag);
-
-// Magic numbers for .ARM.attributes
-enum AttrMagic {
- Format_Version = 0x41
-};
-
// Legal Values for CPU_arch, (=6), uleb128
enum CPUArch {
Pre_v4 = 0,
diff --git a/llvm/include/llvm/Support/ELFAttributeParser.h b/llvm/include/llvm/Support/ELFAttributeParser.h
new file mode 100644
index 000000000000..8bf87b2d84f0
--- /dev/null
+++ b/llvm/include/llvm/Support/ELFAttributeParser.h
@@ -0,0 +1,72 @@
+//===- ELF AttributeParser.h - ELF Attribute Parser -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
+
+#include "ELFAttributes.h"
+#include "ScopedPrinter.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Error.h"
+
+#include <unordered_map>
+
+namespace llvm {
+class StringRef;
+
+class ELFAttributeParser {
+ StringRef vendor;
+ std::unordered_map<unsigned, unsigned> attributes;
+ std::unordered_map<unsigned, StringRef> attributesStr;
+
+ virtual Error handler(uint64_t tag, bool &handled) = 0;
+
+protected:
+ ScopedPrinter *sw;
+ TagNameMap tagToStringMap;
+ DataExtractor de{ArrayRef<uint8_t>{}, true, 0};
+ DataExtractor::Cursor cursor{0};
+
+ void printAttribute(unsigned tag, unsigned value, StringRef valueDesc);
+
+ Error parseStringAttribute(const char *name, unsigned tag,
+ ArrayRef<const char *> strings);
+ Error parseAttributeList(uint32_t length);
+ void parseIndexList(SmallVectorImpl<uint8_t> &indexList);
+ Error parseSubsection(uint32_t length);
+
+public:
+ virtual ~ELFAttributeParser() { static_cast<void>(!cursor.takeError()); }
+ Error integerAttribute(unsigned tag);
+ Error stringAttribute(unsigned tag);
+
+ ELFAttributeParser(ScopedPrinter *sw, TagNameMap tagNameMap, StringRef vendor)
+ : vendor(vendor), sw(sw), tagToStringMap(tagNameMap) {}
+
+ ELFAttributeParser(TagNameMap tagNameMap, StringRef vendor)
+ : vendor(vendor), sw(nullptr), tagToStringMap(tagNameMap) {}
+
+ Error parse(ArrayRef<uint8_t> section, support::endianness endian);
+
+ Optional<unsigned> getAttributeValue(unsigned tag) const {
+ auto I = attributes.find(tag);
+ if (I == attributes.end())
+ return None;
+ return I->second;
+ }
+ Optional<StringRef> getAttributeString(unsigned tag) const {
+ auto I = attributesStr.find(tag);
+ if (I == attributesStr.end())
+ return None;
+ return I->second;
+ }
+};
+
+} // namespace llvm
+#endif
diff --git a/llvm/include/llvm/Support/ELFAttributes.h b/llvm/include/llvm/Support/ELFAttributes.h
new file mode 100644
index 000000000000..c8a7ae142b9a
--- /dev/null
+++ b/llvm/include/llvm/Support/ELFAttributes.h
@@ -0,0 +1,37 @@
+//===-- ELFAttributes.h - ELF Attributes ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELFATTRIBUTES_H
+#define LLVM_SUPPORT_ELFATTRIBUTES_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+struct TagNameItem {
+ unsigned attr;
+ StringRef tagName;
+};
+
+using TagNameMap = ArrayRef<TagNameItem>;
+
+namespace ELFAttrs {
+
+enum AttrType : unsigned { File = 1, Section = 2, Symbol = 3 };
+
+StringRef attrTypeAsString(unsigned attr, TagNameMap tagNameMap,
+ bool hasTagPrefix = true);
+Optional<unsigned> attrTypeFromString(StringRef tag, TagNameMap tagNameMap);
+
+// Magic numbers for ELF attributes.
+enum AttrMagic { Format_Version = 0x41 };
+
+} // namespace ELFAttrs
+} // namespace llvm
+#endif
diff --git a/llvm/include/llvm/Support/RISCVAttributeParser.h b/llvm/include/llvm/Support/RISCVAttributeParser.h
new file mode 100644
index 000000000000..89f660edcc77
--- /dev/null
+++ b/llvm/include/llvm/Support/RISCVAttributeParser.h
@@ -0,0 +1,38 @@
+//===-- RISCVAttributeParser.h - RISCV Attribute Parser ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H
+
+#include "ScopedPrinter.h"
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
+
+namespace llvm {
+class RISCVAttributeParser : public ELFAttributeParser {
+ struct DisplayHandler {
+ RISCVAttrs::AttrType attribute;
+ Error (RISCVAttributeParser::*routine)(unsigned);
+ };
+ static const DisplayHandler displayRoutines[];
+
+ Error handler(uint64_t tag, bool &handled) override;
+
+ Error unalignedAccess(unsigned tag);
+ Error stackAlign(unsigned tag);
+
+public:
+ RISCVAttributeParser(ScopedPrinter *sw)
+ : ELFAttributeParser(sw, RISCVAttrs::RISCVAttributeTags, "riscv") {}
+ RISCVAttributeParser()
+ : ELFAttributeParser(RISCVAttrs::RISCVAttributeTags, "riscv") {}
+};
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/Support/RISCVAttributes.h b/llvm/include/llvm/Support/RISCVAttributes.h
new file mode 100644
index 000000000000..caded9519b66
--- /dev/null
+++ b/llvm/include/llvm/Support/RISCVAttributes.h
@@ -0,0 +1,44 @@
+//===-- RISCVAttributes.h - RISCV Attributes --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains enumerations for RISCV attributes as defined in RISC-V
+// ELF psABI specification.
+//
+// RISC-V ELF psABI specification
+//
+// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_RISCVATTRIBUTES_H
+#define LLVM_SUPPORT_RISCVATTRIBUTES_H
+
+#include "llvm/Support/ELFAttributes.h"
+
+namespace llvm {
+namespace RISCVAttrs {
+
+extern const TagNameMap RISCVAttributeTags;
+
+enum AttrType : unsigned {
+ // Attribute types in ELF/.riscv.attributes.
+ STACK_ALIGN = 4,
+ ARCH = 5,
+ UNALIGNED_ACCESS = 6,
+ PRIV_SPEC = 8,
+ PRIV_SPEC_MINOR = 10,
+ PRIV_SPEC_REVISION = 12,
+};
+
+enum StackAlign { ALIGN_4 = 4, ALIGN_16 = 16 };
+
+enum { NOT_ALLOWED = 0, ALLOWED = 1 };
+
+} // namespace RISCVAttrs
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index d1bf469ad6b4..e58d62382a55 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -223,6 +223,9 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS);
}
break;
+ case ELF::EM_RISCV:
+ switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_RISCV_ATTRIBUTES); }
+ break;
default:
break;
}
diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp
index 855e032417fd..8627d1b3751b 100644
--- a/llvm/lib/Object/ELFObjectFile.cpp
+++ b/llvm/lib/Object/ELFObjectFile.cpp
@@ -23,6 +23,8 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
#include "llvm/Support/TargetRegistry.h"
#include <algorithm>
#include <cstddef>
@@ -164,12 +166,14 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
// both ARMv7-M and R have to support thumb hardware div
bool isV7 = false;
- if (Attributes.hasAttribute(ARMBuildAttrs::CPU_arch))
- isV7 = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch)
- == ARMBuildAttrs::v7;
-
- if (Attributes.hasAttribute(ARMBuildAttrs::CPU_arch_profile)) {
- switch(Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile)) {
+ Optional<unsigned> Attr =
+ Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+ if (Attr.hasValue())
+ isV7 = Attr.getValue() == ARMBuildAttrs::v7;
+
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
case ARMBuildAttrs::ApplicationProfile:
Features.AddFeature("aclass");
break;
@@ -186,8 +190,9 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
}
}
- if (Attributes.hasAttribute(ARMBuildAttrs::THUMB_ISA_use)) {
- switch(Attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use)) {
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
default:
break;
case ARMBuildAttrs::Not_Allowed:
@@ -200,8 +205,9 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
}
}
- if (Attributes.hasAttribute(ARMBuildAttrs::FP_arch)) {
- switch(Attributes.getAttributeValue(ARMBuildAttrs::FP_arch)) {
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::FP_arch);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
default:
break;
case ARMBuildAttrs::Not_Allowed:
@@ -223,8 +229,9 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
}
}
- if (Attributes.hasAttribute(ARMBuildAttrs::Advanced_SIMD_arch)) {
- switch(Attributes.getAttributeValue(ARMBuildAttrs::Advanced_SIMD_arch)) {
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::Advanced_SIMD_arch);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
default:
break;
case ARMBuildAttrs::Not_Allowed:
@@ -241,8 +248,9 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
}
}
- if (Attributes.hasAttribute(ARMBuildAttrs::MVE_arch)) {
- switch(Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch)) {
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
default:
break;
case ARMBuildAttrs::Not_Allowed:
@@ -259,8 +267,9 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
}
}
- if (Attributes.hasAttribute(ARMBuildAttrs::DIV_use)) {
- switch(Attributes.getAttributeValue(ARMBuildAttrs::DIV_use)) {
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::DIV_use);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
default:
break;
case ARMBuildAttrs::DisallowDIV:
@@ -285,6 +294,48 @@ SubtargetFeatures ELFObjectFileBase::getRISCVFeatures() const {
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))
+ return Features; // Keep "c" feature if there is one in PlatformFlags.
+
+ Optional<StringRef> Attr = Attributes.getAttributeString(RISCVAttrs::ARCH);
+ if (Attr.hasValue()) {
+ // 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"))
+ Features.AddFeature("64bit", false);
+ else if (Arch.consume_front("rv64"))
+ 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 == '_'; });
+ }
+ }
+
return Features;
}
@@ -320,8 +371,10 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const {
else
Triple = "arm";
- if (Attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) {
- switch(Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch)) {
+ Optional<unsigned> Attr =
+ Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
case ARMBuildAttrs::v4:
Triple += "v4";
break;
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index e9977b4899ee..7221d9b5736a 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -500,6 +500,9 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration(
ECase(SHT_MIPS_DWARF);
ECase(SHT_MIPS_ABIFLAGS);
break;
+ case ELF::EM_RISCV:
+ ECase(SHT_RISCV_ATTRIBUTES);
+ break;
default:
// Nothing to do.
break;
diff --git a/llvm/lib/Support/ARMAttributeParser.cpp b/llvm/lib/Support/ARMAttributeParser.cpp
index c7b8abe7ad2d..17ad38d22614 100644
--- a/llvm/lib/Support/ARMAttributeParser.cpp
+++ b/llvm/lib/Support/ARMAttributeParser.cpp
@@ -1,4 +1,4 @@
-//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===//
+//===- ARMAttributeParser.cpp - ARM Attribute Information Printer ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -16,12 +16,6 @@
using namespace llvm;
using namespace llvm::ARMBuildAttrs;
-static const EnumEntry<unsigned> tagNames[] = {
- {"Tag_File", ARMBuildAttrs::File},
- {"Tag_Section", ARMBuildAttrs::Section},
- {"Tag_Symbol", ARMBuildAttrs::Symbol},
-};
-
#define ATTRIBUTE_HANDLER(attr) \
{ ARMBuildAttrs::attr, &ARMAttributeParser::attr }
@@ -71,7 +65,8 @@ const ARMAttributeParser::DisplayHandler ARMAttributeParser::displayRoutines[] =
#undef ATTRIBUTE_HANDLER
Error ARMAttributeParser::stringAttribute(AttrType tag) {
- StringRef tagName = ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/false);
+ StringRef tagName =
+ ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*TagPrefix=*/false);
StringRef desc = de.getCStrRef(cursor);
if (sw) {
@@ -84,36 +79,6 @@ Error ARMAttributeParser::stringAttribute(AttrType tag) {
return Error::success();
}
-void ARMAttributeParser::printAttribute(unsigned tag, unsigned value,
- StringRef valueDesc) {
- attributes.insert(std::make_pair(tag, value));
-
- if (sw) {
- StringRef tagName =
- ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/false);
- DictScope as(*sw, "Attribute");
- sw->printNumber("Tag", tag);
- sw->printNumber("Value", value);
- if (!tagName.empty())
- sw->printString("TagName", tagName);
- if (!valueDesc.empty())
- sw->printString("Description", valueDesc);
- }
-}
-
-Error ARMAttributeParser::parseStringAttribute(const char *name, AttrType tag,
- ArrayRef<const char *> strings) {
- uint64_t value = de.getULEB128(cursor);
- if (value >= strings.size()) {
- printAttribute(tag, value, "");
- return createStringError(errc::invalid_argument,
- "unknown " + Twine(name) +
- " value: " + Twine(value));
- }
- printAttribute(tag, value, strings[value]);
- return Error::success();
-}
-
Error ARMAttributeParser::CPU_arch(AttrType tag) {
static const char *strings[] = {
"Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6",
@@ -323,7 +288,9 @@ Error ARMAttributeParser::compatibility(AttrType tag) {
DictScope scope(*sw, "Attribute");
sw->printNumber("Tag", tag);
sw->startLine() << "Value: " << integer << ", " << string << '\n';
- sw->printString("TagName", AttrTypeAsString(tag, /*TagPrefix*/ false));
+ sw->printString("TagName",
+ ELFAttrs::attrTypeAsString(tag, tagToStringMap,
+ /*hasTagPrefix=*/false));
switch (integer) {
case 0:
sw->printString("Description", StringRef("No Specific Requirements"));
@@ -389,167 +356,18 @@ Error ARMAttributeParser::nodefaults(AttrType tag) {
return Error::success();
}
-void ARMAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
- for (;;) {
- uint64_t value = de.getULEB128(cursor);
- if (!cursor || !value)
+Error ARMAttributeParser::handler(uint64_t tag, bool &handled) {
+ handled = false;
+ for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines); AHI != AHE;
+ ++AHI) {
+ if (uint64_t(displayRoutines[AHI].attribute) == tag) {
+ if (Error e =
+ (this->*displayRoutines[AHI].routine)(static_cast<AttrType>(tag)))
+ return e;
+ handled = true;
break;
- indexList.push_back(value);
- }
-}
-
-Error ARMAttributeParser::parseAttributeList(uint32_t length) {
- uint64_t pos;
- uint64_t end = cursor.tell() + length;
- while ((pos = cursor.tell()) < end) {
- uint64_t tag = de.getULEB128(cursor);
- bool handled = false;
- for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines);
- AHI != AHE && !handled; ++AHI) {
- if (uint64_t(displayRoutines[AHI].attribute) == tag) {
- if (Error e = (this->*displayRoutines[AHI].routine)(
- ARMBuildAttrs::AttrType(tag)))
- return e;
- handled = true;
- break;
- }
- }
- if (!handled) {
- if (tag < 32)
- return createStringError(errc::invalid_argument,
- "invalid AEABI tag 0x" +
- Twine::utohexstr(tag) + " at offset 0x" +
- Twine::utohexstr(pos));
-
- if (tag % 2 == 0) {
- uint64_t value = de.getULEB128(cursor);
- attributes.insert(std::make_pair(tag, value));
- if (sw)
- sw->printNumber(ARMBuildAttrs::AttrTypeAsString(tag), value);
- } else {
- StringRef tagName =
- ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/false);
- StringRef desc = de.getCStrRef(cursor);
-
- if (sw) {
- DictScope scope(*sw, "Attribute");
- sw->printNumber("Tag", tag);
- if (!tagName.empty())
- sw->printString("TagName", tagName);
- sw->printString("Value", desc);
- }
- }
}
}
- return Error::success();
-}
-
-Error ARMAttributeParser::parseSubsection(uint32_t length) {
- uint64_t end = cursor.tell() - sizeof(length) + length;
- StringRef vendorName = de.getCStrRef(cursor);
- if (sw) {
- sw->printNumber("SectionLength", length);
- sw->printString("Vendor", vendorName);
- }
-
- // Ignore unrecognized vendor-name.
- if (vendorName.lower() != "aeabi")
- return createStringError(errc::invalid_argument,
- "unrecognized vendor-name: " + vendorName);
-
- while (cursor.tell() < end) {
- /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
- uint8_t tag = de.getU8(cursor);
- uint32_t size = de.getU32(cursor);
- if (!cursor)
- return cursor.takeError();
-
- if (sw) {
- sw->printEnum("Tag", tag, makeArrayRef(tagNames));
- sw->printNumber("Size", size);
- }
- if (size < 5)
- return createStringError(errc::invalid_argument,
- "invalid attribute size " + Twine(size) +
- " at offset 0x" +
- Twine::utohexstr(cursor.tell() - 5));
-
- StringRef scopeName, indexName;
- SmallVector<uint8_t, 8> indicies;
- switch (tag) {
- case ARMBuildAttrs::File:
- scopeName = "FileAttributes";
- break;
- case ARMBuildAttrs::Section:
- scopeName = "SectionAttributes";
- indexName = "Sections";
- parseIndexList(indicies);
- break;
- case ARMBuildAttrs::Symbol:
- scopeName = "SymbolAttributes";
- indexName = "Symbols";
- parseIndexList(indicies);
- break;
- default:
- return createStringError(errc::invalid_argument,
- "unrecognized tag 0x" + Twine::utohexstr(tag) +
- " at offset 0x" +
- Twine::utohexstr(cursor.tell() - 5));
- }
- if (sw) {
- DictScope scope(*sw, scopeName);
- if (!indicies.empty())
- sw->printList(indexName, indicies);
- if (Error e = parseAttributeList(size - 5))
- return e;
- } else if (Error e = parseAttributeList(size - 5))
- return e;
- }
return Error::success();
}
-
-Error ARMAttributeParser::parse(ArrayRef<uint8_t> section,
- support::endianness endian) {
- unsigned sectionNumber = 0;
- de = DataExtractor(section, endian == support::little, 0);
-
- // For early returns, we have more specific errors, consume the Error in
- // cursor.
- struct ClearCursorError {
- DataExtractor::Cursor &cursor;
- ~ClearCursorError() { consumeError(cursor.takeError()); }
- } clear{cursor};
-
- // Unrecognized format-version.
- uint8_t formatVersion = de.getU8(cursor);
- if (formatVersion != 'A')
- return createStringError(errc::invalid_argument,
- "unrecognized format-version: 0x" +
- utohexstr(formatVersion));
-
- while (!de.eof(cursor)) {
- uint32_t sectionLength = de.getU32(cursor);
- if (!cursor)
- return cursor.takeError();
-
- if (sw) {
- sw->startLine() << "Section " << ++sectionNumber << " {\n";
- sw->indent();
- }
-
- if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size())
- return createStringError(errc::invalid_argument,
- "invalid subsection length " +
- Twine(sectionLength) + " at offset 0x" +
- utohexstr(cursor.tell() - 4));
- if (Error e = parseSubsection(sectionLength))
- return e;
- if (sw) {
- sw->unindent();
- sw->startLine() << "}\n";
- }
- }
-
- return cursor.takeError();
-}
diff --git a/llvm/lib/Support/ARMBuildAttrs.cpp b/llvm/lib/Support/ARMBuildAttrs.cpp
index 9a21bab8975c..5aaf0a4e7c62 100644
--- a/llvm/lib/Support/ARMBuildAttrs.cpp
+++ b/llvm/lib/Support/ARMBuildAttrs.cpp
@@ -6,16 +6,11 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ARMBuildAttributes.h"
using namespace llvm;
-namespace {
-const struct {
- ARMBuildAttrs::AttrType Attr;
- StringRef TagName;
-} ARMAttributeTags[] = {
+static const TagNameItem tagData[] = {
{ARMBuildAttrs::File, "Tag_File"},
{ARMBuildAttrs::Section, "Tag_Section"},
{ARMBuildAttrs::Symbol, "Tag_Symbol"},
@@ -67,35 +62,7 @@ const struct {
{ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align8_needed"},
{ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align8_preserved"},
};
-}
-namespace llvm {
-namespace ARMBuildAttrs {
-StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix) {
- return AttrTypeAsString(static_cast<AttrType>(Attr), HasTagPrefix);
-}
-
-StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix) {
- for (unsigned TI = 0, TE = sizeof(ARMAttributeTags) / sizeof(*ARMAttributeTags);
- TI != TE; ++TI)
- if (ARMAttributeTags[TI].Attr == Attr) {
- auto TagName = ARMAttributeTags[TI].TagName;
- return HasTagPrefix ? TagName : TagName.drop_front(4);
- }
- return "";
-}
-
-int AttrTypeFromString(StringRef Tag) {
- bool HasTagPrefix = Tag.startswith("Tag_");
- for (unsigned TI = 0,
- TE = sizeof(ARMAttributeTags) / sizeof(*ARMAttributeTags);
- TI != TE; ++TI) {
- auto TagName = ARMAttributeTags[TI].TagName;
- if (TagName.drop_front(HasTagPrefix ? 0 : 4) == Tag) {
- return ARMAttributeTags[TI].Attr;
- }
- }
- return -1;
-}
-}
-}
+const TagNameMap llvm::ARMBuildAttrs::ARMAttributeTags(tagData,
+ sizeof(tagData) /
+ sizeof(TagNameItem));
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 5ed816b21a61..25e1be673300 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -87,6 +87,8 @@ add_llvm_component_library(LLVMSupport
DeltaAlgorithm.cpp
DAGDeltaAlgorithm.cpp
DJB.cpp
+ ELFAttributeParser.cpp
+ ELFAttributes.cpp
Error.cpp
ErrorHandling.cpp
FileCheck.cpp
@@ -122,6 +124,8 @@ add_llvm_component_library(LLVMSupport
PrettyStackTrace.cpp
RandomNumberGenerator.cpp
Regex.cpp
+ RISCVAttributes.cpp
+ RISCVAttributeParser.cpp
ScaledNumber.cpp
ScopedPrinter.cpp
SHA1.cpp
diff --git a/llvm/lib/Support/ELFAttributeParser.cpp b/llvm/lib/Support/ELFAttributeParser.cpp
new file mode 100644
index 000000000000..93be0535d1b9
--- /dev/null
+++ b/llvm/lib/Support/ELFAttributeParser.cpp
@@ -0,0 +1,233 @@
+//===--- ELFAttributeParser.cpp - ELF Attribute Parser --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::ELFAttrs;
+
+static const EnumEntry<unsigned> tagNames[] = {
+ {"Tag_File", ELFAttrs::File},
+ {"Tag_Section", ELFAttrs::Section},
+ {"Tag_Symbol", ELFAttrs::Symbol},
+};
+
+Error ELFAttributeParser::parseStringAttribute(const char *name, unsigned tag,
+ ArrayRef<const char *> strings) {
+ uint64_t value = de.getULEB128(cursor);
+ if (value >= strings.size()) {
+ printAttribute(tag, value, "");
+ return createStringError(errc::invalid_argument,
+ "unknown " + Twine(name) +
+ " value: " + Twine(value));
+ }
+ printAttribute(tag, value, strings[value]);
+ return Error::success();
+}
+
+Error ELFAttributeParser::integerAttribute(unsigned tag) {
+ StringRef tagName =
+ ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
+ uint64_t value = de.getULEB128(cursor);
+ attributes.insert(std::make_pair(tag, value));
+
+ if (sw) {
+ DictScope scope(*sw, "Attribute");
+ sw->printNumber("Tag", tag);
+ if (!tagName.empty())
+ sw->printString("TagName", tagName);
+ sw->printNumber("Value", value);
+ }
+ return Error::success();
+}
+
+Error ELFAttributeParser::stringAttribute(unsigned tag) {
+ StringRef tagName =
+ ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
+ StringRef desc = de.getCStrRef(cursor);
+ attributesStr.insert(std::make_pair(tag, desc));
+
+ if (sw) {
+ DictScope scope(*sw, "Attribute");
+ sw->printNumber("Tag", tag);
+ if (!tagName.empty())
+ sw->printString("TagName", tagName);
+ sw->printString("Value", desc);
+ }
+ return Error::success();
+}
+
+void ELFAttributeParser::printAttribute(unsigned tag, unsigned value,
+ StringRef valueDesc) {
+ attributes.insert(std::make_pair(tag, value));
+
+ if (sw) {
+ StringRef tagName = ELFAttrs::attrTypeAsString(tag, tagToStringMap,
+ /*hasTagPrefix=*/false);
+ DictScope as(*sw, "Attribute");
+ sw->printNumber("Tag", tag);
+ sw->printNumber("Value", value);
+ if (!tagName.empty())
+ sw->printString("TagName", tagName);
+ if (!valueDesc.empty())
+ sw->printString("Description", valueDesc);
+ }
+}
+
+void ELFAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
+ for (;;) {
+ uint64_t value = de.getULEB128(cursor);
+ if (!cursor || !value)
+ break;
+ indexList.push_back(value);
+ }
+}
+
+Error ELFAttributeParser::parseAttributeList(uint32_t length) {
+ uint64_t pos;
+ uint64_t end = cursor.tell() + length;
+ while ((pos = cursor.tell()) < end) {
+ uint64_t tag = de.getULEB128(cursor);
+ bool handled;
+ if (Error e = handler(tag, handled))
+ return e;
+
+ if (!handled) {
+ if (tag < 32) {
+ return createStringError(errc::invalid_argument,
+ "invalid tag 0x" + Twine::utohexstr(tag) +
+ " at offset 0x" + Twine::utohexstr(pos));
+ }
+
+ if (tag % 2 == 0) {
+ if (Error e = integerAttribute(tag))
+ return e;
+ } else {
+ if (Error e = stringAttribute(tag))
+ return e;
+ }
+ }
+ }
+ return Error::success();
+}
+
+Error ELFAttributeParser::parseSubsection(uint32_t length) {
+ uint64_t end = cursor.tell() - sizeof(length) + length;
+ StringRef vendorName = de.getCStrRef(cursor);
+ if (sw) {
+ sw->printNumber("SectionLength", length);
+ sw->printString("Vendor", vendorName);
+ }
+
+ // Ignore unrecognized vendor-name.
+ if (vendorName.lower() != vendor)
+ return createStringError(errc::invalid_argument,
+ "unrecognized vendor-name: " + vendorName);
+
+ while (cursor.tell() < end) {
+ /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
+ uint8_t tag = de.getU8(cursor);
+ uint32_t size = de.getU32(cursor);
+ if (!cursor)
+ return cursor.takeError();
+
+ if (sw) {
+ sw->printEnum("Tag", tag, makeArrayRef(tagNames));
+ sw->printNumber("Size", size);
+ }
+ if (size < 5)
+ return createStringError(errc::invalid_argument,
+ "invalid attribute size " + Twine(size) +
+ " at offset 0x" +
+ Twine::utohexstr(cursor.tell() - 5));
+
+ StringRef scopeName, indexName;
+ SmallVector<uint8_t, 8> indicies;
+ switch (tag) {
+ case ELFAttrs::File:
+ scopeName = "FileAttributes";
+ break;
+ case ELFAttrs::Section:
+ scopeName = "SectionAttributes";
+ indexName = "Sections";
+ parseIndexList(indicies);
+ break;
+ case ELFAttrs::Symbol:
+ scopeName = "SymbolAttributes";
+ indexName = "Symbols";
+ parseIndexList(indicies);
+ break;
+ default:
+ return createStringError(errc::invalid_argument,
+ "unrecognized tag 0x" + Twine::utohexstr(tag) +
+ " at offset 0x" +
+ Twine::utohexstr(cursor.tell() - 5));
+ }
+
+ if (sw) {
+ DictScope scope(*sw, scopeName);
+ if (!indicies.empty())
+ sw->printList(indexName, indicies);
+ if (Error e = parseAttributeList(size - 5))
+ return e;
+ } else if (Error e = parseAttributeList(size - 5))
+ return e;
+ }
+ return Error::success();
+}
+
+Error ELFAttributeParser::parse(ArrayRef<uint8_t> section,
+ support::endianness endian) {
+ unsigned sectionNumber = 0;
+ de = DataExtractor(section, endian == support::little, 0);
+
+ // For early returns, we have more specific errors, consume the Error in
+ // cursor.
+ struct ClearCursorError {
+ DataExtractor::Cursor &cursor;
+ ~ClearCursorError() { consumeError(cursor.takeError()); }
+ } clear{cursor};
+
+ // Unrecognized format-version.
+ uint8_t formatVersion = de.getU8(cursor);
+ if (formatVersion != 'A')
+ return createStringError(errc::invalid_argument,
+ "unrecognized format-version: 0x" +
+ utohexstr(formatVersion));
+
+ while (!de.eof(cursor)) {
+ uint32_t sectionLength = de.getU32(cursor);
+ if (!cursor)
+ return cursor.takeError();
+
+ if (sw) {
+ sw->startLine() << "Section " << ++sectionNumber << " {\n";
+ sw->indent();
+ }
+
+ if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size())
+ return createStringError(errc::invalid_argument,
+ "invalid subsection length " +
+ Twine(sectionLength) + " at offset 0x" +
+ utohexstr(cursor.tell() - 4));
+
+ if (Error e = parseSubsection(sectionLength))
+ return e;
+ if (sw) {
+ sw->unindent();
+ sw->startLine() << "}\n";
+ }
+ }
+
+ return cursor.takeError();
+}
diff --git a/llvm/lib/Support/ELFAttributes.cpp b/llvm/lib/Support/ELFAttributes.cpp
new file mode 100644
index 000000000000..5be38825d6c6
--- /dev/null
+++ b/llvm/lib/Support/ELFAttributes.cpp
@@ -0,0 +1,34 @@
+//===-- ELFAttributes.cpp - ELF Attributes --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ELFAttributes.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace llvm;
+
+StringRef ELFAttrs::attrTypeAsString(unsigned attr, TagNameMap tagNameMap,
+ bool hasTagPrefix) {
+ auto tagNameIt = find_if(
+ tagNameMap, [attr](const TagNameItem item) { return item.attr == attr; });
+ if (tagNameIt == tagNameMap.end())
+ return "";
+ StringRef tagName = tagNameIt->tagName;
+ return hasTagPrefix ? tagName : tagName.drop_front(4);
+}
+
+Optional<unsigned> ELFAttrs::attrTypeFromString(StringRef tag,
+ TagNameMap tagNameMap) {
+ bool hasTagPrefix = tag.startswith("Tag_");
+ auto tagNameIt =
+ find_if(tagNameMap, [tag, hasTagPrefix](const TagNameItem item) {
+ return item.tagName.drop_front(hasTagPrefix ? 0 : 4) == tag;
+ });
+ if (tagNameIt == tagNameMap.end())
+ return None;
+ return tagNameIt->attr;
+}
diff --git a/llvm/lib/Support/RISCVAttributeParser.cpp b/llvm/lib/Support/RISCVAttributeParser.cpp
new file mode 100644
index 000000000000..393861c73a4a
--- /dev/null
+++ b/llvm/lib/Support/RISCVAttributeParser.cpp
@@ -0,0 +1,67 @@
+//===-- RISCVAttributeParser.cpp - RISCV Attribute Parser -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace llvm;
+
+const RISCVAttributeParser::DisplayHandler
+ RISCVAttributeParser::displayRoutines[] = {
+ {
+ RISCVAttrs::ARCH,
+ &ELFAttributeParser::stringAttribute,
+ },
+ {
+ RISCVAttrs::PRIV_SPEC,
+ &ELFAttributeParser::integerAttribute,
+ },
+ {
+ RISCVAttrs::PRIV_SPEC_MINOR,
+ &ELFAttributeParser::integerAttribute,
+ },
+ {
+ RISCVAttrs::PRIV_SPEC_REVISION,
+ &ELFAttributeParser::integerAttribute,
+ },
+ {
+ RISCVAttrs::STACK_ALIGN,
+ &RISCVAttributeParser::stackAlign,
+ },
+ {
+ RISCVAttrs::UNALIGNED_ACCESS,
+ &RISCVAttributeParser::unalignedAccess,
+ }};
+
+Error RISCVAttributeParser::unalignedAccess(unsigned tag) {
+ static const char *strings[] = {"No unaligned access", "Unaligned access"};
+ return parseStringAttribute("Unaligned_access", tag, makeArrayRef(strings));
+}
+
+Error RISCVAttributeParser::stackAlign(unsigned tag) {
+ uint64_t value = de.getULEB128(cursor);
+ std::string description =
+ "Stack alignment is " + utostr(value) + std::string("-bytes");
+ printAttribute(tag, value, description);
+ return Error::success();
+}
+
+Error RISCVAttributeParser::handler(uint64_t tag, bool &handled) {
+ handled = false;
+ for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines); AHI != AHE;
+ ++AHI) {
+ if (uint64_t(displayRoutines[AHI].attribute) == tag) {
+ if (Error e = (this->*displayRoutines[AHI].routine)(tag))
+ return e;
+ handled = true;
+ break;
+ }
+ }
+
+ return Error::success();
+}
diff --git a/llvm/lib/Support/RISCVAttributes.cpp b/llvm/lib/Support/RISCVAttributes.cpp
new file mode 100644
index 000000000000..201048e03009
--- /dev/null
+++ b/llvm/lib/Support/RISCVAttributes.cpp
@@ -0,0 +1,25 @@
+//===-- RISCVAttributes.cpp - RISCV Attributes ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/RISCVAttributes.h"
+
+using namespace llvm;
+using namespace llvm::RISCVAttrs;
+
+static const TagNameItem tagData[] = {
+ {STACK_ALIGN, "Tag_stack_align"},
+ {ARCH, "Tag_arch"},
+ {UNALIGNED_ACCESS, "Tag_unaligned_access"},
+ {PRIV_SPEC, "Tag_priv_spec"},
+ {PRIV_SPEC_MINOR, "Tag_priv_spec_minor"},
+ {PRIV_SPEC_REVISION, "Tag_priv_spec_revision"},
+};
+
+const TagNameMap llvm::RISCVAttrs::RISCVAttributeTags(tagData,
+ sizeof(tagData) /
+ sizeof(TagNameItem));
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index e273c17c2efd..80450983e513 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -11143,11 +11143,13 @@ bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) {
TagLoc = Parser.getTok().getLoc();
if (Parser.getTok().is(AsmToken::Identifier)) {
StringRef Name = Parser.getTok().getIdentifier();
- Tag = ARMBuildAttrs::AttrTypeFromString(Name);
- if (Tag == -1) {
+ Optional<unsigned> Ret =
+ ELFAttrs::attrTypeFromString(Name, ARMBuildAttrs::ARMAttributeTags);
+ if (!Ret.hasValue()) {
Error(TagLoc, "attribute name not recognised: " + Name);
return false;
}
+ Tag = Ret.getValue();
Parser.Lex();
} else {
const MCExpr *AttrExpr;
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index cca4d2fa5a7b..e75e7b7ee221 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -177,7 +177,8 @@ void ARMTargetAsmStreamer::switchVendor(StringRef Vendor) {}
void ARMTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
OS << "\t.eabi_attribute\t" << Attribute << ", " << Twine(Value);
if (IsVerboseAsm) {
- StringRef Name = ARMBuildAttrs::AttrTypeAsString(Attribute);
+ StringRef Name =
+ ELFAttrs::attrTypeAsString(Attribute, ARMBuildAttrs::ARMAttributeTags);
if (!Name.empty())
OS << "\t@ " << Name;
}
@@ -193,7 +194,8 @@ void ARMTargetAsmStreamer::emitTextAttribute(unsigned Attribute,
default:
OS << "\t.eabi_attribute\t" << Attribute << ", \"" << String << "\"";
if (IsVerboseAsm) {
- StringRef Name = ARMBuildAttrs::AttrTypeAsString(Attribute);
+ StringRef Name = ELFAttrs::attrTypeAsString(
+ Attribute, ARMBuildAttrs::ARMAttributeTags);
if (!Name.empty())
OS << "\t@ " << Name;
}
@@ -212,7 +214,9 @@ void ARMTargetAsmStreamer::emitIntTextAttribute(unsigned Attribute,
if (!StringValue.empty())
OS << ", \"" << StringValue << "\"";
if (IsVerboseAsm)
- OS << "\t@ " << ARMBuildAttrs::AttrTypeAsString(Attribute);
+ OS << "\t@ "
+ << ELFAttrs::attrTypeAsString(Attribute,
+ ARMBuildAttrs::ARMAttributeTags);
break;
}
OS << "\n";
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 62b6d9b12ee6..e5a98f4f71cc 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -32,6 +32,7 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/RISCVAttributes.h"
#include "llvm/Support/TargetRegistry.h"
#include <limits>
@@ -146,6 +147,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
bool parseDirectiveOption();
+ bool parseDirectiveAttribute();
void setFeatureBits(uint64_t Feature, StringRef FeatureString) {
if (!(getSTI().getFeatureBits()[Feature])) {
@@ -155,6 +157,10 @@ class RISCVAsmParser : public MCTargetAsmParser {
}
}
+ bool getFeatureBits(uint64_t Feature) {
+ return getSTI().getFeatureBits()[Feature];
+ }
+
void clearFeatureBits(uint64_t Feature, StringRef FeatureString) {
if (getSTI().getFeatureBits()[Feature]) {
MCSubtargetInfo &STI = copySTI();
@@ -1579,6 +1585,8 @@ bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) {
if (IDVal == ".option")
return parseDirectiveOption();
+ else if (IDVal == ".attribute")
+ return parseDirectiveAttribute();
return true;
}
@@ -1677,6 +1685,151 @@ bool RISCVAsmParser::parseDirectiveOption() {
return false;
}
+/// parseDirectiveAttribute
+/// ::= .attribute expression ',' ( expression | "string" )
+/// ::= .attribute identifier ',' ( expression | "string" )
+bool RISCVAsmParser::parseDirectiveAttribute() {
+ MCAsmParser &Parser = getParser();
+ int64_t Tag;
+ SMLoc TagLoc;
+ TagLoc = Parser.getTok().getLoc();
+ if (Parser.getTok().is(AsmToken::Identifier)) {
+ StringRef Name = Parser.getTok().getIdentifier();
+ Optional<unsigned> Ret =
+ ELFAttrs::attrTypeFromString(Name, RISCVAttrs::RISCVAttributeTags);
+ if (!Ret.hasValue()) {
+ Error(TagLoc, "attribute name not recognised: " + Name);
+ return false;
+ }
+ Tag = Ret.getValue();
+ Parser.Lex();
+ } else {
+ const MCExpr *AttrExpr;
+
+ TagLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(AttrExpr))
+ return true;
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr);
+ if (check(!CE, TagLoc, "expected numeric constant"))
+ return true;
+
+ Tag = CE->getValue();
+ }
+
+ if (Parser.parseToken(AsmToken::Comma, "comma expected"))
+ return true;
+
+ StringRef StringValue;
+ int64_t IntegerValue = 0;
+ bool IsIntegerValue = true;
+
+ // RISC-V attributes have a string value if the tag number is odd
+ // and an integer value if the tag number is even.
+ if (Tag % 2)
+ IsIntegerValue = false;
+
+ SMLoc ValueExprLoc = Parser.getTok().getLoc();
+ if (IsIntegerValue) {
+ const MCExpr *ValueExpr;
+ if (Parser.parseExpression(ValueExpr))
+ return true;
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr);
+ if (!CE)
+ return Error(ValueExprLoc, "expected numeric constant");
+ IntegerValue = CE->getValue();
+ } else {
+ if (Parser.getTok().isNot(AsmToken::String))
+ return Error(Parser.getTok().getLoc(), "expected string constant");
+
+ StringValue = Parser.getTok().getStringContents();
+ Parser.Lex();
+ }
+
+ if (Parser.parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.attribute' directive"))
+ return true;
+
+ if (Tag == RISCVAttrs::ARCH) {
+ StringRef Arch = StringValue;
+ if (Arch.consume_front("rv32"))
+ clearFeatureBits(RISCV::Feature64Bit, "64bit");
+ else if (Arch.consume_front("rv64"))
+ setFeatureBits(RISCV::Feature64Bit, "64bit");
+ else
+ return Error(ValueExprLoc, "bad arch string " + Arch);
+
+ while (!Arch.empty()) {
+ if (Arch[0] == 'i')
+ clearFeatureBits(RISCV::FeatureRV32E, "e");
+ else if (Arch[0] == 'e')
+ setFeatureBits(RISCV::FeatureRV32E, "e");
+ else if (Arch[0] == 'g') {
+ clearFeatureBits(RISCV::FeatureRV32E, "e");
+ setFeatureBits(RISCV::FeatureStdExtM, "m");
+ setFeatureBits(RISCV::FeatureStdExtA, "a");
+ setFeatureBits(RISCV::FeatureStdExtF, "f");
+ setFeatureBits(RISCV::FeatureStdExtD, "d");
+ } else if (Arch[0] == 'm')
+ setFeatureBits(RISCV::FeatureStdExtM, "m");
+ else if (Arch[0] == 'a')
+ setFeatureBits(RISCV::FeatureStdExtA, "a");
+ else if (Arch[0] == 'f')
+ setFeatureBits(RISCV::FeatureStdExtF, "f");
+ else if (Arch[0] == 'd') {
+ setFeatureBits(RISCV::FeatureStdExtF, "f");
+ setFeatureBits(RISCV::FeatureStdExtD, "d");
+ } else if (Arch[0] == 'c') {
+ setFeatureBits(RISCV::FeatureStdExtC, "c");
+ } else
+ return Error(ValueExprLoc, "bad arch string " + Arch);
+
+ Arch = Arch.drop_front(1);
+ int major = 0;
+ int minor = 0;
+ Arch.consumeInteger(10, major);
+ Arch.consume_front("p");
+ Arch.consumeInteger(10, minor);
+ if (major != 0 || minor != 0) {
+ Arch = Arch.drop_until([](char c) { return c == '_' || c == '"'; });
+ Arch = Arch.drop_while([](char c) { return c == '_'; });
+ }
+ }
+ }
+
+ if (IsIntegerValue)
+ getTargetStreamer().emitAttribute(Tag, IntegerValue);
+ else {
+ if (Tag != RISCVAttrs::ARCH) {
+ getTargetStreamer().emitTextAttribute(Tag, StringValue);
+ } else {
+ std::string formalArchStr = "rv32";
+ if (getFeatureBits(RISCV::Feature64Bit))
+ formalArchStr = "rv64";
+ if (getFeatureBits(RISCV::FeatureRV32E))
+ formalArchStr = (Twine(formalArchStr) + "e1p9").str();
+ else
+ formalArchStr = (Twine(formalArchStr) + "i2p0").str();
+
+ if (getFeatureBits(RISCV::FeatureStdExtM))
+ formalArchStr = (Twine(formalArchStr) + "_m2p0").str();
+ if (getFeatureBits(RISCV::FeatureStdExtA))
+ formalArchStr = (Twine(formalArchStr) + "_a2p0").str();
+ if (getFeatureBits(RISCV::FeatureStdExtF))
+ formalArchStr = (Twine(formalArchStr) + "_f2p0").str();
+ if (getFeatureBits(RISCV::FeatureStdExtD))
+ formalArchStr = (Twine(formalArchStr) + "_d2p0").str();
+ if (getFeatureBits(RISCV::FeatureStdExtC))
+ formalArchStr = (Twine(formalArchStr) + "_c2p0").str();
+
+ getTargetStreamer().emitTextAttribute(Tag, formalArchStr);
+ }
+ }
+
+ return false;
+}
+
void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) {
MCInst CInst;
bool Res = compressInst(CInst, Inst, getSTI(), S.getContext());
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
index 40fa195f3790..8382edf09231 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
@@ -15,14 +15,18 @@
#include "RISCVMCTargetDesc.h"
#include "Utils/RISCVBaseInfo.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/RISCVAttributes.h"
using namespace llvm;
// This part is for ELF object output.
RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S,
const MCSubtargetInfo &STI)
- : RISCVTargetStreamer(S) {
+ : RISCVTargetStreamer(S), CurrentVendor("riscv") {
MCAssembler &MCA = getStreamer().getAssembler();
const FeatureBitset &Features = STI.getFeatureBits();
auto &MAB = static_cast<RISCVAsmBackend &>(MCA.getBackend());
@@ -66,3 +70,98 @@ void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {}
void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {}
void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {}
+
+void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
+ setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true);
+}
+
+void RISCVTargetELFStreamer::emitTextAttribute(unsigned Attribute,
+ StringRef String) {
+ setAttributeItem(Attribute, String, /*OverwriteExisting=*/true);
+}
+
+void RISCVTargetELFStreamer::emitIntTextAttribute(unsigned Attribute,
+ unsigned IntValue,
+ StringRef StringValue) {
+ setAttributeItems(Attribute, IntValue, StringValue,
+ /*OverwriteExisting=*/true);
+}
+
+void RISCVTargetELFStreamer::finishAttributeSection() {
+ if (Contents.empty())
+ return;
+
+ if (AttributeSection) {
+ Streamer.SwitchSection(AttributeSection);
+ } else {
+ MCAssembler &MCA = getStreamer().getAssembler();
+ AttributeSection = MCA.getContext().getELFSection(
+ ".riscv.attributes", ELF::SHT_RISCV_ATTRIBUTES, 0);
+ Streamer.SwitchSection(AttributeSection);
+
+ Streamer.emitInt8(ELFAttrs::Format_Version);
+ }
+
+ // Vendor size + Vendor name + '\0'
+ const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1;
+
+ // Tag + Tag Size
+ const size_t TagHeaderSize = 1 + 4;
+
+ const size_t ContentsSize = calculateContentSize();
+
+ Streamer.emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize);
+ Streamer.emitBytes(CurrentVendor);
+ Streamer.emitInt8(0); // '\0'
+
+ Streamer.emitInt8(ELFAttrs::File);
+ Streamer.emitInt32(TagHeaderSize + ContentsSize);
+
+ // Size should have been accounted for already, now
+ // emit each field as its type (ULEB or String).
+ for (AttributeItem item : Contents) {
+ Streamer.emitULEB128IntValue(item.Tag);
+ switch (item.Type) {
+ default:
+ llvm_unreachable("Invalid attribute type");
+ case AttributeType::Numeric:
+ Streamer.emitULEB128IntValue(item.IntValue);
+ break;
+ case AttributeType::Text:
+ Streamer.emitBytes(item.StringValue);
+ Streamer.emitInt8(0); // '\0'
+ break;
+ case AttributeType::NumericAndText:
+ Streamer.emitULEB128IntValue(item.IntValue);
+ Streamer.emitBytes(item.StringValue);
+ Streamer.emitInt8(0); // '\0'
+ break;
+ }
+ }
+
+ Contents.clear();
+}
+
+size_t RISCVTargetELFStreamer::calculateContentSize() const {
+ size_t Result = 0;
+ for (AttributeItem item : Contents) {
+ switch (item.Type) {
+ case AttributeType::Hidden:
+ break;
+ case AttributeType::Numeric:
+ Result += getULEB128Size(item.Tag);
+ Result += getULEB128Size(item.IntValue);
+ break;
+ case AttributeType::Text:
+ Result += getULEB128Size(item.Tag);
+ Result += item.StringValue.size() + 1; // string + '\0'
+ break;
+ case AttributeType::NumericAndText:
+ Result += getULEB128Size(item.Tag);
+ Result += getULEB128Size(item.IntValue);
+ Result += item.StringValue.size() + 1; // string + '\0';
+ break;
+ }
+ }
+ return Result;
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
index 138df786eaf3..0221392054ce 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
@@ -15,16 +15,92 @@
namespace llvm {
class RISCVTargetELFStreamer : public RISCVTargetStreamer {
+private:
+ enum class AttributeType { Hidden, Numeric, Text, NumericAndText };
+
+ struct AttributeItem {
+ AttributeType Type;
+ unsigned Tag;
+ unsigned IntValue;
+ std::string StringValue;
+ };
+
+ StringRef CurrentVendor;
+ SmallVector<AttributeItem, 64> Contents;
+
+ MCSection *AttributeSection = nullptr;
+
+ AttributeItem *getAttributeItem(unsigned Attribute) {
+ for (size_t i = 0; i < Contents.size(); ++i)
+ if (Contents[i].Tag == Attribute)
+ return &Contents[i];
+ return nullptr;
+ }
+
+ void setAttributeItem(unsigned Attribute, unsigned Value,
+ bool OverwriteExisting) {
+ // Look for existing attribute item.
+ if (AttributeItem *Item = getAttributeItem(Attribute)) {
+ if (!OverwriteExisting)
+ return;
+ Item->Type = AttributeType::Numeric;
+ Item->IntValue = Value;
+ return;
+ }
+
+ // Create new attribute item.
+ Contents.push_back({AttributeType::Numeric, Attribute, Value, ""});
+ }
+
+ void setAttributeItem(unsigned Attribute, StringRef Value,
+ bool OverwriteExisting) {
+ // Look for existing attribute item.
+ if (AttributeItem *Item = getAttributeItem(Attribute)) {
+ if (!OverwriteExisting)
+ return;
+ Item->Type = AttributeType::Text;
+ Item->StringValue = std::string(Value);
+ return;
+ }
+
+ // Create new attribute item.
+ Contents.push_back({AttributeType::Text, Attribute, 0, std::string(Value)});
+ }
+
+ void setAttributeItems(unsigned Attribute, unsigned IntValue,
+ StringRef StringValue, bool OverwriteExisting) {
+ // Look for existing attribute item.
+ if (AttributeItem *Item = getAttributeItem(Attribute)) {
+ if (!OverwriteExisting)
+ return;
+ Item->Type = AttributeType::NumericAndText;
+ Item->IntValue = IntValue;
+ Item->StringValue = std::string(StringValue);
+ return;
+ }
+
+ // Create new attribute item.
+ Contents.push_back({AttributeType::NumericAndText, Attribute, IntValue,
+ std::string(StringValue)});
+ }
+
+ void emitAttribute(unsigned Attribute, unsigned Value) override;
+ void emitTextAttribute(unsigned Attribute, StringRef String) override;
+ void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+ StringRef StringValue) override;
+ void finishAttributeSection() override;
+ size_t calculateContentSize() const;
+
public:
MCELFStreamer &getStreamer();
RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
- virtual void emitDirectiveOptionPush();
- virtual void emitDirectiveOptionPop();
- virtual void emitDirectiveOptionRVC();
- virtual void emitDirectiveOptionNoRVC();
- virtual void emitDirectiveOptionRelax();
- virtual void emitDirectiveOptionNoRelax();
+ void emitDirectiveOptionPush() override;
+ void emitDirectiveOptionPop() override;
+ void emitDirectiveOptionRVC() override;
+ void emitDirectiveOptionNoRVC() override;
+ void emitDirectiveOptionRelax() override;
+ void emitDirectiveOptionNoRelax() override;
};
}
#endif
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
index 913e1f744192..b5b59c1227f6 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
@@ -11,12 +11,43 @@
//===----------------------------------------------------------------------===//
#include "RISCVTargetStreamer.h"
+#include "RISCVSubtarget.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/RISCVAttributes.h"
using namespace llvm;
RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
+void RISCVTargetStreamer::finish() { finishAttributeSection(); }
+
+void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) {
+ if (STI.hasFeature(RISCV::FeatureRV32E))
+ emitAttribute(RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_4);
+ else
+ emitAttribute(RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_16);
+
+ std::string Arch = "rv32";
+ if (STI.hasFeature(RISCV::Feature64Bit))
+ Arch = "rv64";
+ if (STI.hasFeature(RISCV::FeatureRV32E))
+ Arch += "e1p9";
+ else
+ Arch += "i2p0";
+ if (STI.hasFeature(RISCV::FeatureStdExtM))
+ Arch += "_m2p0";
+ if (STI.hasFeature(RISCV::FeatureStdExtA))
+ Arch += "_a2p0";
+ if (STI.hasFeature(RISCV::FeatureStdExtF))
+ Arch += "_f2p0";
+ if (STI.hasFeature(RISCV::FeatureStdExtD))
+ Arch += "_d2p0";
+ if (STI.hasFeature(RISCV::FeatureStdExtC))
+ Arch += "_c2p0";
+
+ emitTextAttribute(RISCVAttrs::ARCH, Arch);
+}
+
// This part is for ascii assembly output
RISCVTargetAsmStreamer::RISCVTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS)
@@ -45,3 +76,18 @@ void RISCVTargetAsmStreamer::emitDirectiveOptionRelax() {
void RISCVTargetAsmStreamer::emitDirectiveOptionNoRelax() {
OS << "\t.option\tnorelax\n";
}
+
+void RISCVTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
+ OS << "\t.attribute\t" << Attribute << ", " << Twine(Value) << "\n";
+}
+
+void RISCVTargetAsmStreamer::emitTextAttribute(unsigned Attribute,
+ StringRef String) {
+ OS << "\t.attribute\t" << Attribute << ", \"" << String << "\"\n";
+}
+
+void RISCVTargetAsmStreamer::emitIntTextAttribute(unsigned Attribute,
+ unsigned IntValue,
+ StringRef StringValue) {}
+
+void RISCVTargetAsmStreamer::finishAttributeSection() {}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
index 1becc134b2a2..f7c8db2edb01 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
@@ -10,12 +10,14 @@
#define LLVM_LIB_TARGET_RISCV_RISCVTARGETSTREAMER_H
#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
namespace llvm {
class RISCVTargetStreamer : public MCTargetStreamer {
public:
RISCVTargetStreamer(MCStreamer &S);
+ void finish() override;
virtual void emitDirectiveOptionPush() = 0;
virtual void emitDirectiveOptionPop() = 0;
@@ -23,12 +25,25 @@ class RISCVTargetStreamer : public MCTargetStreamer {
virtual void emitDirectiveOptionNoRVC() = 0;
virtual void emitDirectiveOptionRelax() = 0;
virtual void emitDirectiveOptionNoRelax() = 0;
+ virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0;
+ virtual void finishAttributeSection() = 0;
+ virtual void emitTextAttribute(unsigned Attribute, StringRef String) = 0;
+ virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+ StringRef StringValue) = 0;
+
+ void emitTargetAttributes(const MCSubtargetInfo &STI);
};
// This part is for ascii assembly output
class RISCVTargetAsmStreamer : public RISCVTargetStreamer {
formatted_raw_ostream &OS;
+ void finishAttributeSection() override;
+ void emitAttribute(unsigned Attribute, unsigned Value) override;
+ void emitTextAttribute(unsigned Attribute, StringRef String) override;
+ void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+ StringRef StringValue) override;
+
public:
RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index fc7e7c1efe1a..8955994b1c2e 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "RISCV.h"
#include "MCTargetDesc/RISCVInstPrinter.h"
#include "MCTargetDesc/RISCVMCExpr.h"
+#include "MCTargetDesc/RISCVTargetStreamer.h"
+#include "RISCV.h"
#include "RISCVTargetMachine.h"
#include "TargetInfo/RISCVTargetInfo.h"
#include "llvm/ADT/Statistic.h"
@@ -63,6 +64,12 @@ class RISCVAsmPrinter : public AsmPrinter {
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
return LowerRISCVMachineOperandToMCOperand(MO, MCOp, *this);
}
+
+ void emitStartOfAsmFile(Module &M) override;
+ void emitEndOfAsmFile(Module &M) override;
+
+private:
+ void emitAttributes();
};
}
@@ -170,6 +177,32 @@ bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
return false;
}
+void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
+ if (TM.getTargetTriple().isOSBinFormatELF())
+ emitAttributes();
+}
+
+void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
+ RISCVTargetStreamer &RTS =
+ static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
+
+ if (TM.getTargetTriple().isOSBinFormatELF())
+ RTS.finishAttributeSection();
+}
+
+void RISCVAsmPrinter::emitAttributes() {
+ RISCVTargetStreamer &RTS =
+ static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
+
+ const Triple &TT = TM.getTargetTriple();
+ StringRef CPU = TM.getTargetCPU();
+ StringRef FS = TM.getTargetFeatureString();
+ const RISCVTargetMachine &RTM = static_cast<const RISCVTargetMachine &>(TM);
+ const RISCVSubtarget STI(TT, CPU, FS, /*ABIName=*/"", RTM);
+
+ RTS.emitTargetAttributes(STI);
+}
+
// Force static initialization.
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll
new file mode 100644
index 000000000000..b36b4430f157
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/attributes.ll
@@ -0,0 +1,28 @@
+;; Generate ELF attributes from llc.
+
+; RUN: llc -mtriple=riscv32 -mattr=+m %s -o - | FileCheck --check-prefix=RV32M %s
+; RUN: llc -mtriple=riscv32 -mattr=+a %s -o - | FileCheck --check-prefix=RV32A %s
+; RUN: llc -mtriple=riscv32 -mattr=+f %s -o - | FileCheck --check-prefix=RV32F %s
+; RUN: llc -mtriple=riscv32 -mattr=+d %s -o - | FileCheck --check-prefix=RV32D %s
+; RUN: llc -mtriple=riscv32 -mattr=+c %s -o - | FileCheck --check-prefix=RV32C %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
+; RUN: llc -mtriple=riscv64 -mattr=+d %s -o - | FileCheck --check-prefix=RV64D %s
+; RUN: llc -mtriple=riscv64 -mattr=+c %s -o - | FileCheck --check-prefix=RV64C %s
+
+; RV32M: .attribute 5, "rv32i2p0_m2p0"
+; RV32A: .attribute 5, "rv32i2p0_a2p0"
+; RV32F: .attribute 5, "rv32i2p0_f2p0"
+; RV32D: .attribute 5, "rv32i2p0_f2p0_d2p0"
+; RV32C: .attribute 5, "rv32i2p0_c2p0"
+; RV64M: .attribute 5, "rv64i2p0_m2p0"
+; RV64A: .attribute 5, "rv64i2p0_a2p0"
+; RV64F: .attribute 5, "rv64i2p0_f2p0"
+; RV64D: .attribute 5, "rv64i2p0_f2p0_d2p0"
+; RV64C: .attribute 5, "rv64i2p0_c2p0"
+
+define i32 @addi(i32 %a) {
+ %1 = add i32 %a, 1
+ ret i32 %1
+}
diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
new file mode 100644
index 000000000000..4329290b33ba
--- /dev/null
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -0,0 +1,37 @@
+## Arch string without version.
+
+# RUN: llvm-mc %s -triple=riscv32 -filetype=asm | FileCheck %s
+# RUN: llvm-mc %s -triple=riscv64 -filetype=asm | FileCheck %s
+
+.attribute arch, "rv32i"
+# CHECK: attribute 5, "rv32i2p0"
+
+.attribute arch, "rv32i2"
+# CHECK: attribute 5, "rv32i2p0"
+
+.attribute arch, "rv32i2p"
+# CHECK: attribute 5, "rv32i2p0"
+
+.attribute arch, "rv32i2p0"
+# CHECK: attribute 5, "rv32i2p0"
+
+.attribute arch, "rv32i2_m2"
+# CHECK: attribute 5, "rv32i2p0_m2p0"
+
+.attribute arch, "rv32i2_ma"
+# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0"
+
+.attribute arch, "rv32g"
+# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0"
+
+.attribute arch, "rv32imafdc"
+# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+
+.attribute arch, "rv32i2p0_mafdc"
+# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+
+.attribute arch, "rv32ima2p0_fdc"
+# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+
+.attribute arch, "rv32ima2p_fdc"
+# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
diff --git a/llvm/test/MC/RISCV/attribute-with-insts.s b/llvm/test/MC/RISCV/attribute-with-insts.s
new file mode 100644
index 000000000000..9d9170a9f5aa
--- /dev/null
+++ b/llvm/test/MC/RISCV/attribute-with-insts.s
@@ -0,0 +1,34 @@
+## Test .attribute effects.
+## We do not provide '-mattr=' and '.option rvc' and enable extensions through
+## '.attribute arch'.
+
+# RUN: llvm-mc -triple riscv32 -filetype=obj %s \
+# RUN: | llvm-objdump --triple=riscv32 -d -M no-aliases - \
+# RUN: | FileCheck -check-prefix=CHECK-INST %s
+
+# RUN: llvm-mc -triple riscv64 -filetype=obj %s \
+# RUN: | llvm-objdump --triple=riscv64 -d -M no-aliases - \
+# RUN: | FileCheck -check-prefix=CHECK-INST %s
+
+.attribute arch, "rv64i2p0_m2p0_a2p0_d2p0_c2p0"
+
+# CHECK-INST: lr.w t0, (t1)
+lr.w t0, (t1)
+
+# CHECK-INST: c.addi a3, -32
+c.addi a3, -32
+
+# CHECK-INST: fmadd.d fa0, fa1, fa2, fa3, dyn
+fmadd.d f10, f11, f12, f13, dyn
+
+# CHECK-INST: fmadd.s fa0, fa1, fa2, fa3, dyn
+fmadd.s f10, f11, f12, f13, dyn
+
+# CHECK-INST: addi ra, sp, 2
+addi ra, sp, 2
+
+# CHECK-INST: mul a4, ra, s0
+mul a4, ra, s0
+
+# CHECK-INST: addw a2, a3, a4
+addw a2, a3, a4
diff --git a/llvm/test/MC/RISCV/attribute.s b/llvm/test/MC/RISCV/attribute.s
new file mode 100644
index 000000000000..b7ad98bb6fe2
--- /dev/null
+++ b/llvm/test/MC/RISCV/attribute.s
@@ -0,0 +1,22 @@
+## Test llvm-mc could handle .attribute correctly.
+
+# RUN: llvm-mc %s -triple=riscv32 -filetype=asm | FileCheck %s
+# RUN: llvm-mc %s -triple=riscv64 -filetype=asm | FileCheck %s
+
+.attribute stack_align, 16
+# CHECK: attribute 4, 16
+
+.attribute arch, "rv32i2p0_m2p0_a2p0_c2p0"
+# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_c2p0"
+
+.attribute unaligned_access, 0
+# CHECK: attribute 6, 0
+
+.attribute priv_spec, 2
+# CHECK: attribute 8, 2
+
+.attribute priv_spec_minor, 0
+# CHECK: attribute 10, 0
+
+.attribute priv_spec_revision, 0
+# CHECK: attribute 12, 0
diff --git a/llvm/test/MC/RISCV/invalid-attribute.s b/llvm/test/MC/RISCV/invalid-attribute.s
new file mode 100644
index 000000000000..e3cfe28fdf44
--- /dev/null
+++ b/llvm/test/MC/RISCV/invalid-attribute.s
@@ -0,0 +1,31 @@
+## Negative tests:
+## - Feed integer value to string type attribute.
+## - Feed string value to integer type attribute.
+## - Invalid arch string.
+
+# RUN: not llvm-mc %s -triple=riscv32 -filetype=asm 2>&1 | FileCheck %s
+# RUN: not llvm-mc %s -triple=riscv64 -filetype=asm 2>&1 | FileCheck %s
+
+.attribute arch, "foo"
+# CHECK: [[@LINE-1]]:18: error: bad arch string foo
+
+.attribute arch, "rv32i2p0_y2p0"
+# CHECK: [[@LINE-1]]:18: error: bad arch string y2p0
+
+.attribute stack_align, "16"
+# CHECK: [[@LINE-1]]:25: error: expected numeric constant
+
+.attribute unaligned_access, "0"
+# CHECK: [[@LINE-1]]:30: error: expected numeric constant
+
+.attribute priv_spec, "2"
+# CHECK: [[@LINE-1]]:23: error: expected numeric constant
+
+.attribute priv_spec_minor, "0"
+# CHECK: [[@LINE-1]]:29: error: expected numeric constant
+
+.attribute priv_spec_revision, "0"
+# CHECK: [[@LINE-1]]:32: error: expected numeric constant
+
+.attribute arch, 30
+# CHECK: [[@LINE-1]]:18: error: expected string constant
diff --git a/llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg b/llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg
new file mode 100644
index 000000000000..c63820126f8c
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg
@@ -0,0 +1,2 @@
+if not 'RISCV' in config.root.targets:
+ config.unsupported = True
diff --git a/llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test b/llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test
new file mode 100644
index 000000000000..23e10f8a110a
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test
@@ -0,0 +1,38 @@
+## Handle unrecognized arch attributes.
+## Encode an unrecognized arch feature into an object file and try to decode it.
+## 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
+## unrecognized architecture extension. llvm-objdump will ignore it and decode
+## "mul" instruction correctly according to "m2p0" in the arch feature.
+##
+## This test cannot be assembly because the test needs an unrecognized arch
+## feature and `llvm-mc` will filter out the unrecognized arch feature.
+
+# RUN: yaml2obj %s -D BITS=32 -o %t.32.o
+# RUN: llvm-objdump -d %t.32.o \
+# RUN: | FileCheck %s --check-prefixes=DISASM
+# RUN: yaml2obj %s -D BITS=64 -o %t.64.o
+# RUN: llvm-objdump -d %t.64.o \
+# RUN: | FileCheck %s --check-prefixes=DISASM
+
+# DISASM: mul a0, a1, a2
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS[[BITS]]
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_RISCV
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+## The content is the encoding of "mul a0, a1, a2".
+## The encoding could be decoded only when the "m" extension is enabled.
+ Content: 3385C502
+ - Name: .riscv.attributes
+ Type: SHT_RISCV_ATTRIBUTES
+## The content is the encoding of the arch feature "rv32i2p0_x1p0_m2p0"
+ Content: 412300000072697363760001190000000572763332693270305F783170305F6D32703000
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 72c0625ecb63..24f41ae49469 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -2719,7 +2719,7 @@ template <> void ELFDumper<ELF32LE>::printAttributes() {
ArrayRef<uint8_t> Contents =
unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec));
- if (Contents[0] != ARMBuildAttrs::Format_Version) {
+ if (Contents[0] != ELFAttrs::Format_Version) {
errs() << "unrecognised FormatVersion: 0x"
<< Twine::utohexstr(Contents[0]) << '\n';
continue;
diff --git a/llvm/unittests/Support/ARMAttributeParser.cpp b/llvm/unittests/Support/ARMAttributeParser.cpp
index 76a0407df6a6..88e3ce389a34 100644
--- a/llvm/unittests/Support/ARMAttributeParser.cpp
+++ b/llvm/unittests/Support/ARMAttributeParser.cpp
@@ -1,5 +1,6 @@
#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/ELFAttributes.h"
#include "gtest/gtest.h"
#include <string>
@@ -36,8 +37,8 @@ bool testBuildAttr(unsigned Tag, unsigned Value,
ARMAttributeParser Parser;
cantFail(Parser.parse(Bytes, support::little));
- return (Parser.hasAttribute(ExpectedTag) &&
- Parser.getAttributeValue(ExpectedTag) == ExpectedValue);
+ Optional<unsigned> Attr = Parser.getAttributeValue(ExpectedTag);
+ return Attr.hasValue() && Attr.getValue() == ExpectedValue;
}
void testParseError(ArrayRef<uint8_t> bytes, const char *msg) {
@@ -47,34 +48,8 @@ void testParseError(ArrayRef<uint8_t> bytes, const char *msg) {
}
bool testTagString(unsigned Tag, const char *name) {
- return ARMBuildAttrs::AttrTypeAsString(Tag).str() == name;
-}
-
-TEST(ARMAttributeParser, UnrecognizedFormatVersion) {
- static const uint8_t bytes[] = {1};
- testParseError(bytes, "unrecognized format-version: 0x1");
-}
-
-TEST(ARMAttributeParser, InvalidSubsectionLength) {
- static const uint8_t bytes[] = {'A', 3, 0, 0, 0};
- testParseError(bytes, "invalid subsection length 3 at offset 0x1");
-}
-
-TEST(ARMAttributeParser, UnrecognizedVendorName) {
- static const uint8_t bytes[] = {'A', 7, 0, 0, 0, 'x', 'y', 0};
- testParseError(bytes, "unrecognized vendor-name: xy");
-}
-
-TEST(ARMAttributeParser, InvalidAttributeSize) {
- static const uint8_t bytes[] = {'A', 15, 0, 0, 0, 'a', 'e', 'a',
- 'b', 'i', 0, 4, 4, 0, 0, 0};
- testParseError(bytes, "invalid attribute size 4 at offset 0xb");
-}
-
-TEST(ARMAttributeParser, UnrecognizedTag) {
- static const uint8_t bytes[] = {'A', 15, 0, 0, 0, 'a', 'e', 'a',
- 'b', 'i', 0, 4, 5, 0, 0, 0};
- testParseError(bytes, "unrecognized tag 0x4 at offset 0xb");
+ return ELFAttrs::attrTypeAsString(Tag, ARMBuildAttrs::ARMAttributeTags)
+ .str() == name;
}
TEST(ARMAttributeParser, UnknownCPU_arch) {
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 0f46858252c2..a570a0406d72 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -28,6 +28,7 @@ add_llvm_unittest(SupportTests
DJBTest.cpp
EndianStreamTest.cpp
EndianTest.cpp
+ ELFAttributeParserTest.cpp
ErrnoTest.cpp
ErrorOrTest.cpp
ErrorTest.cpp
@@ -59,6 +60,7 @@ add_llvm_unittest(SupportTests
RegexTest.cpp
ReverseIterationTest.cpp
ReplaceFileTest.cpp
+ RISCVAttributeParserTest.cpp
ScaledNumberTest.cpp
SourceMgrTest.cpp
SpecialCaseListTest.cpp
diff --git a/llvm/unittests/Support/ELFAttributeParserTest.cpp b/llvm/unittests/Support/ELFAttributeParserTest.cpp
new file mode 100644
index 000000000000..ad4e309d8953
--- /dev/null
+++ b/llvm/unittests/Support/ELFAttributeParserTest.cpp
@@ -0,0 +1,63 @@
+//===----- unittests/ELFAttributeParserTest.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace llvm;
+
+static const TagNameMap emptyTagNameMap;
+
+// This class is used to test the common part of the ELF attribute section.
+class AttributeHeaderParser : public ELFAttributeParser {
+ Error handler(uint64_t tag, bool &handled) {
+ // Treat all attributes as handled.
+ handled = true;
+ return Error::success();
+ }
+
+public:
+ AttributeHeaderParser(ScopedPrinter *printer)
+ : ELFAttributeParser(printer, emptyTagNameMap, "test") {}
+ AttributeHeaderParser() : ELFAttributeParser(emptyTagNameMap, "test") {}
+};
+
+static void testParseError(ArrayRef<uint8_t> bytes, const char *msg) {
+ AttributeHeaderParser parser;
+ Error e = parser.parse(bytes, support::little);
+ EXPECT_STREQ(toString(std::move(e)).c_str(), msg);
+}
+
+TEST(AttributeHeaderParser, UnrecognizedFormatVersion) {
+ static const uint8_t bytes[] = {1};
+ testParseError(bytes, "unrecognized format-version: 0x1");
+}
+
+TEST(AttributeHeaderParser, InvalidSubsectionLength) {
+ static const uint8_t bytes[] = {'A', 3, 0, 0, 0};
+ testParseError(bytes, "invalid subsection length 3 at offset 0x1");
+}
+
+TEST(AttributeHeaderParser, UnrecognizedVendorName) {
+ static const uint8_t bytes[] = {'A', 7, 0, 0, 0, 'x', 'y', 0};
+ testParseError(bytes, "unrecognized vendor-name: xy");
+}
+
+TEST(AttributeHeaderParser, UnrecognizedTag) {
+ static const uint8_t bytes[] = {'A', 14, 0, 0, 0, 't', 'e', 's',
+ 't', 0, 4, 5, 0, 0, 0};
+ testParseError(bytes, "unrecognized tag 0x4 at offset 0xa");
+}
+
+TEST(AttributeHeaderParser, InvalidAttributeSize) {
+ static const uint8_t bytes[] = {'A', 14, 0, 0, 0, 't', 'e', 's',
+ 't', 0, 1, 4, 0, 0, 0};
+ testParseError(bytes, "invalid attribute size 4 at offset 0xa");
+}
diff --git a/llvm/unittests/Support/RISCVAttributeParserTest.cpp b/llvm/unittests/Support/RISCVAttributeParserTest.cpp
new file mode 100644
index 000000000000..1458af604a5c
--- /dev/null
+++ b/llvm/unittests/Support/RISCVAttributeParserTest.cpp
@@ -0,0 +1,70 @@
+//===----- unittests/RISCVAttributeParserTest.cpp -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace llvm;
+
+struct RISCVAttributeSection {
+ unsigned Tag;
+ unsigned Value;
+
+ RISCVAttributeSection(unsigned tag, unsigned value)
+ : Tag(tag), Value(value) {}
+
+ void write(raw_ostream &OS) {
+ OS.flush();
+ // length = length + "riscv\0" + TagFile + ByteSize + Tag + Value;
+ // length = 17 bytes
+
+ OS << 'A' << (uint8_t)17 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0;
+ OS << "riscv" << '\0';
+ OS << (uint8_t)1 << (uint8_t)7 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0;
+ OS << (uint8_t)Tag << (uint8_t)Value;
+ }
+};
+
+static bool testAttribute(unsigned Tag, unsigned Value, unsigned ExpectedTag,
+ unsigned ExpectedValue) {
+ std::string buffer;
+ raw_string_ostream OS(buffer);
+ RISCVAttributeSection Section(Tag, Value);
+ Section.write(OS);
+ ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(OS.str().c_str()),
+ OS.str().size());
+
+ RISCVAttributeParser Parser;
+ cantFail(Parser.parse(Bytes, support::little));
+
+ Optional<unsigned> Attr = Parser.getAttributeValue(ExpectedTag);
+ return Attr.hasValue() && Attr.getValue() == ExpectedValue;
+}
+
+static bool testTagString(unsigned Tag, const char *name) {
+ return ELFAttrs::attrTypeAsString(Tag, RISCVAttrs::RISCVAttributeTags)
+ .str() == name;
+}
+
+TEST(StackAlign, testAttribute) {
+ EXPECT_TRUE(testTagString(4, "Tag_stack_align"));
+ EXPECT_TRUE(
+ testAttribute(4, 4, RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_4));
+ EXPECT_TRUE(
+ testAttribute(4, 16, RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_16));
+}
+
+TEST(UnalignedAccess, testAttribute) {
+ EXPECT_TRUE(testTagString(6, "Tag_unaligned_access"));
+ EXPECT_TRUE(testAttribute(6, 0, RISCVAttrs::UNALIGNED_ACCESS,
+ RISCVAttrs::NOT_ALLOWED));
+ EXPECT_TRUE(
+ testAttribute(6, 1, RISCVAttrs::UNALIGNED_ACCESS, RISCVAttrs::ALLOWED));
+}
More information about the llvm-commits
mailing list