[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:
Kai Wang
2020-02-04 22:20:10 +08:00
parent 86b4076027
commit 581ba35291
40 changed files with 1455 additions and 348 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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.

View File

@@ -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))

View File

@@ -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

View File

@@ -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,

View 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

View 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

View 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

View 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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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));

View File

@@ -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

View 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();
}

View 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;
}

View 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();
}

View 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));

View File

@@ -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;

View File

@@ -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";

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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() {}

View File

@@ -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);

View File

@@ -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());

View 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
}

View 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"

View 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

View 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

View 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

View File

@@ -0,0 +1,2 @@
if not 'RISCV' in config.root.targets:
config.unsupported = True

View 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

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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

View 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");
}

View 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));
}