mirror of
https://github.com/intel/llvm.git
synced 2026-01-25 10:55:58 +08:00
[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
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 @@ protected:
|
||||
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 @@ protected:
|
||||
(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))
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
72
llvm/include/llvm/Support/ELFAttributeParser.h
Normal file
72
llvm/include/llvm/Support/ELFAttributeParser.h
Normal file
@@ -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
|
||||
37
llvm/include/llvm/Support/ELFAttributes.h
Normal file
37
llvm/include/llvm/Support/ELFAttributes.h
Normal file
@@ -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
|
||||
38
llvm/include/llvm/Support/RISCVAttributeParser.h
Normal file
38
llvm/include/llvm/Support/RISCVAttributeParser.h
Normal file
@@ -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
|
||||
44
llvm/include/llvm/Support/RISCVAttributes.h
Normal file
44
llvm/include/llvm/Support/RISCVAttributes.h
Normal file
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
Optional<unsigned> Attr =
|
||||
Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
|
||||
if (Attr.hasValue())
|
||||
isV7 = Attr.getValue() == ARMBuildAttrs::v7;
|
||||
|
||||
if (Attributes.hasAttribute(ARMBuildAttrs::CPU_arch_profile)) {
|
||||
switch(Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile)) {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
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))
|
||||
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;
|
||||
} else if (Error e = parseAttributeList(size - 5))
|
||||
return e;
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
233
llvm/lib/Support/ELFAttributeParser.cpp
Normal file
233
llvm/lib/Support/ELFAttributeParser.cpp
Normal file
@@ -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();
|
||||
}
|
||||
34
llvm/lib/Support/ELFAttributes.cpp
Normal file
34
llvm/lib/Support/ELFAttributes.cpp
Normal file
@@ -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;
|
||||
}
|
||||
67
llvm/lib/Support/RISCVAttributeParser.cpp
Normal file
67
llvm/lib/Support/RISCVAttributeParser.cpp
Normal file
@@ -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();
|
||||
}
|
||||
25
llvm/lib/Support/RISCVAttributes.cpp
Normal file
25
llvm/lib/Support/RISCVAttributes.cpp
Normal file
@@ -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));
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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 @@ public:
|
||||
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);
|
||||
|
||||
|
||||
@@ -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 @@ public:
|
||||
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());
|
||||
|
||||
28
llvm/test/CodeGen/RISCV/attributes.ll
Normal file
28
llvm/test/CodeGen/RISCV/attributes.ll
Normal file
@@ -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
|
||||
}
|
||||
37
llvm/test/MC/RISCV/attribute-arch.s
Normal file
37
llvm/test/MC/RISCV/attribute-arch.s
Normal file
@@ -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"
|
||||
34
llvm/test/MC/RISCV/attribute-with-insts.s
Normal file
34
llvm/test/MC/RISCV/attribute-with-insts.s
Normal file
@@ -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
|
||||
22
llvm/test/MC/RISCV/attribute.s
Normal file
22
llvm/test/MC/RISCV/attribute.s
Normal file
@@ -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
|
||||
31
llvm/test/MC/RISCV/invalid-attribute.s
Normal file
31
llvm/test/MC/RISCV/invalid-attribute.s
Normal file
@@ -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
|
||||
2
llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg
Normal file
2
llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
if not 'RISCV' in config.root.targets:
|
||||
config.unsupported = True
|
||||
38
llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test
Normal file
38
llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test
Normal file
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
63
llvm/unittests/Support/ELFAttributeParserTest.cpp
Normal file
63
llvm/unittests/Support/ELFAttributeParserTest.cpp
Normal file
@@ -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");
|
||||
}
|
||||
70
llvm/unittests/Support/RISCVAttributeParserTest.cpp
Normal file
70
llvm/unittests/Support/RISCVAttributeParserTest.cpp
Normal file
@@ -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));
|
||||
}
|
||||
Reference in New Issue
Block a user