diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -880,6 +880,8 @@ SHT_MSP430_ATTRIBUTES = 0x70000003U, + SHT_RISCV_ATTRIBUTES = 0x70000003U, + SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type. SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. SHT_HIUSER = 0xffffffff // Highest type reserved for applications. diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -28,8 +28,8 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/ARMAttributeParser.h" -#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/ELFBuildAttributes.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" @@ -64,7 +64,7 @@ virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0; virtual Expected 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; @@ -365,19 +365,21 @@ (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] != ELFBuildAttrs::Format_Version || + Contents.size() == 1) return Error::success(); Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); diff --git a/llvm/include/llvm/Support/ARMAttributeParser.h b/llvm/include/llvm/Support/ARMAttributeParser.h --- a/llvm/include/llvm/Support/ARMAttributeParser.h +++ b/llvm/include/llvm/Support/ARMAttributeParser.h @@ -1,4 +1,4 @@ -//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===// +//===- ARMAttributeParser.h - ARM Attribute Information Printer -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,131 +10,68 @@ #define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H #include "ARMBuildAttributes.h" +#include "ELFAttributeParser.h" #include "ScopedPrinter.h" -#include - namespace llvm { -class StringRef; - -class ARMAttributeParser { - ScopedPrinter *SW; - - std::map Attributes; - +class ARMAttributeParser : public ELFAttributeParser { struct DisplayHandler { ARMBuildAttrs::AttrType Attribute; - void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType, - const uint8_t *, uint32_t &); + void (ARMAttributeParser::*Routine)(unsigned, const uint8_t *, uint32_t &); }; static const DisplayHandler DisplayRoutines[]; - uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset); - StringRef ParseString(const uint8_t *Data, uint32_t &Offset); - - void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - - void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc); - - void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void MVE_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + bool Handler(unsigned Tag, const uint8_t *Data, uint32_t &Offset) override; + + void CPU_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void CPU_arch_profile(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ARM_ISA_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void THUMB_ISA_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void FP_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void WMMX_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void Advanced_SIMD_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void MVE_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void PCS_config(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_PCS_R9_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_PCS_RW_data(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_PCS_RO_data(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_PCS_GOT_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_PCS_wchar_t(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_FP_rounding(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_FP_denormal(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_FP_exceptions(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_FP_user_exceptions(unsigned Tag, const uint8_t *Data, uint32_t &Offset); - void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + void ABI_FP_number_model(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_align_needed(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_align_preserved(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_enum_size(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_HardFP_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_VFP_args(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_WMMX_args(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_optimization_goals(unsigned Tag, const uint8_t *Data, uint32_t &Offset); - void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag, - const uint8_t *Data, uint32_t &Offset); - void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + void ABI_FP_optimization_goals(unsigned Tag, const uint8_t *Data, + uint32_t &Offset); + void compatibility(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void CPU_unaligned_access(unsigned Tag, const uint8_t *Data, uint32_t &Offset); - void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void DSP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); + void FP_HP_extension(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void ABI_FP_16bit_format(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void MPextension_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void DIV_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void DSP_extension(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void T2EE_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void Virtualization_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void nodefaults(unsigned Tag, const uint8_t *Data, uint32_t &Offset); - void ParseAttributeList(const uint8_t *Data, uint32_t &Offset, - uint32_t Length); - void ParseIndexList(const uint8_t *Data, uint32_t &Offset, - SmallVectorImpl &IndexList); - void ParseSubsection(const uint8_t *Data, uint32_t Length); public: - ARMAttributeParser(ScopedPrinter *SW) : SW(SW) {} - - ARMAttributeParser() : SW(nullptr) { } - - void Parse(ArrayRef Section, bool isLittle); + ARMAttributeParser(ScopedPrinter *SW) + : ELFAttributeParser(SW, ARMBuildAttrs::ARMAttributeTags, "aeabi") {} - bool hasAttribute(unsigned Tag) const { - return Attributes.count(Tag); - } - - unsigned getAttributeValue(unsigned Tag) const { - return Attributes.find(Tag)->second; - } + ARMAttributeParser() + : ELFAttributeParser(ARMBuildAttrs::ARMAttributeTags, "aeabi") {} }; - } #endif diff --git a/llvm/include/llvm/Support/ARMBuildAttributes.h b/llvm/include/llvm/Support/ARMBuildAttributes.h --- a/llvm/include/llvm/Support/ARMBuildAttributes.h +++ b/llvm/include/llvm/Support/ARMBuildAttributes.h @@ -18,11 +18,13 @@ #ifndef LLVM_SUPPORT_ARMBUILDATTRIBUTES_H #define LLVM_SUPPORT_ARMBUILDATTRIBUTES_H -namespace llvm { -class StringRef; +#include "llvm/Support/ELFBuildAttributes.h" +namespace llvm { namespace ARMBuildAttrs { +extern 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. @@ -82,15 +84,6 @@ MPextension_use_old = 70 // recoded to MPextension_use (ABI r2.08) }; -StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix = true); -StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix = true); -int AttrTypeFromString(StringRef Tag); - -// Magic numbers for .ARM.attributes -enum AttrMagic { - Format_Version = 0x41 -}; - // Legal Values for CPU_arch, (=6), uleb128 enum CPUArch { Pre_v4 = 0, diff --git a/llvm/include/llvm/Support/ELFAttributeParser.h b/llvm/include/llvm/Support/ELFAttributeParser.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/ELFAttributeParser.h @@ -0,0 +1,66 @@ +//===- 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 "ELFBuildAttributes.h" +#include "ScopedPrinter.h" + +#include + +namespace llvm { +class StringRef; + +class ELFAttributeParser { + StringRef Vendor; + std::map Attributes; + std::map AttributesStr; + + virtual bool Handler(unsigned Tag, const uint8_t *Data, uint32_t &Offset) = 0; + +protected: + ScopedPrinter *SW; + TagNameMap TagToStringMap; + + uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset); + StringRef ParseString(const uint8_t *Data, uint32_t &Offset); + + void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc); + + void ParseAttributeList(const uint8_t *Data, uint32_t &Offset, + uint32_t Length); + void ParseIndexList(const uint8_t *Data, uint32_t &Offset, + SmallVectorImpl &IndexList); + void ParseSubsection(const uint8_t *Data, uint32_t Length); + +public: + void IntegerAttribute(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void StringAttribute(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + + ELFAttributeParser(ScopedPrinter *SW, TagNameMap Map, StringRef Vendor) + : Vendor(Vendor), SW(SW), TagToStringMap(Map) {} + + ELFAttributeParser(TagNameMap Map, StringRef Vendor) + : Vendor(Vendor), SW(nullptr), TagToStringMap(Map) {} + + void Parse(ArrayRef Section, bool isLittle); + + bool hasAttribute(unsigned Tag) const { return Attributes.count(Tag); } + bool hasAttributeStr(unsigned Tag) const { return AttributesStr.count(Tag); } + + unsigned getAttributeValue(unsigned Tag) const { + return Attributes.find(Tag)->second; + } + StringRef getAttributeString(unsigned Tag) const { + return AttributesStr.find(Tag)->second; + } +}; + +} // namespace llvm +#endif diff --git a/llvm/include/llvm/Support/ELFBuildAttributes.h b/llvm/include/llvm/Support/ELFBuildAttributes.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/ELFBuildAttributes.h @@ -0,0 +1,40 @@ +//===-- ELFBuildAttributes.h - ELF Build 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_ELFBUILDATTRIBUTES_H +#define LLVM_SUPPORT_ELFBUILDATTRIBUTES_H + +#include "llvm/ADT/DenseMap.h" + +namespace llvm { +class StringRef; + +struct TagNameItem { + unsigned Attr; + StringRef TagName; +}; + +using TagNameMap = ArrayRef; + +namespace ELFBuildAttrs { + +enum AttrType { File = 1, Section = 2, Symbol = 3 }; + +StringRef AttrTypeAsString(unsigned Attr, TagNameMap Map, + bool HasTagPrefix = true); +StringRef AttrTypeAsString(AttrType Attr, TagNameMap Map, + bool HasTagPrefix = true); +int AttrTypeFromString(StringRef Tag, TagNameMap Map); + +// Magic numbers for ELF attributes +enum AttrMagic { Format_Version = 0x41 }; + +} // namespace ELFBuildAttrs +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/RISCVAttributeParser.h b/llvm/include/llvm/Support/RISCVAttributeParser.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/RISCVAttributeParser.h @@ -0,0 +1,39 @@ +//===- 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; + void (RISCVAttributeParser::*Routine)(unsigned, const uint8_t *, + uint32_t &); + }; + static const DisplayHandler DisplayRoutines[]; + + bool Handler(unsigned Tag, const uint8_t *Data, uint32_t &Offset) override; + + void Unaligned_access(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + void Stack_align(unsigned Tag, const uint8_t *Data, uint32_t &Offset); + +public: + RISCVAttributeParser(ScopedPrinter *SW) + : ELFAttributeParser(SW, RISCVAttrs::RISCVAttributeTags, "riscv") {} + RISCVAttributeParser() + : ELFAttributeParser(RISCVAttrs::RISCVAttributeTags, "riscv") {} +}; + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/RISCVAttributes.h b/llvm/include/llvm/Support/RISCVAttributes.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/RISCVAttributes.h @@ -0,0 +1,40 @@ +//===-- 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/ELFBuildAttributes.h" + +namespace llvm { +namespace RISCVAttrs { + +extern TagNameMap RISCVAttributeTags; + +enum AttrType { + // Rest correspond to ELF/.riscv.attributes + Stack_align = 4, + Arch = 5, + Unaligned_access = 6, + Priv_spec = 8, + Priv_spec_minor = 10, + Priv_spec_revision = 12, +}; + +} // namespace RISCVAttrs +} // namespace llvm + +#endif diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -223,6 +223,9 @@ STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS); } break; + case ELF::EM_RISCV: + switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_RISCV_ATTRIBUTES); } + break; default: break; } diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -23,6 +23,8 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/RISCVAttributeParser.h" +#include "llvm/Support/RISCVAttributes.h" #include "llvm/Support/TargetRegistry.h" #include #include @@ -283,6 +285,48 @@ Features.AddFeature("c"); } + RISCVAttributeParser Attributes; + if (Error E = getBuildAttributes(Attributes)) + return Features; + + if (Attributes.hasAttributeStr(RISCVAttrs::Arch)) { + // 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 = Attributes.getAttributeString(RISCVAttrs::Arch); + if (Arch.startswith("rv32")) + Features.AddFeature("64bit", false); + else if (Arch.startswith("rv64")) + Features.AddFeature("64bit"); + else + return Features; + Arch = Arch.drop_front(4); // Discard "rv[32|64]" + + while (!Arch.empty()) { + switch (Arch[0]) { + default: + llvm_unreachable("Unknown extension in Arch attribute."); + 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: To take care version numbers. + Arch = Arch.drop_until([](char c) { return c == '_' || c == '\0'; }); + Arch = Arch.drop_while([](char c) { return c == '_'; }); + } + } + return Features; } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -500,6 +500,8 @@ ECase(SHT_MIPS_DWARF); ECase(SHT_MIPS_ABIFLAGS); break; + case ELF::EM_RISCV: + ECase(SHT_RISCV_ATTRIBUTES); default: // Nothing to do. break; diff --git a/llvm/lib/Support/ARMAttributeParser.cpp b/llvm/lib/Support/ARMAttributeParser.cpp --- a/llvm/lib/Support/ARMAttributeParser.cpp +++ b/llvm/lib/Support/ARMAttributeParser.cpp @@ -1,4 +1,4 @@ -//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===// +//==- ARMAttributeParser.cpp - ARM Attribute Information Printer -*- C++ -*-==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -15,120 +15,54 @@ using namespace llvm; using namespace llvm::ARMBuildAttrs; - -static const EnumEntry TagNames[] = { - { "Tag_File", ARMBuildAttrs::File }, - { "Tag_Section", ARMBuildAttrs::Section }, - { "Tag_Symbol", ARMBuildAttrs::Symbol }, -}; - namespace llvm { #define ATTRIBUTE_HANDLER(Attr_) \ { ARMBuildAttrs::Attr_, &ARMAttributeParser::Attr_ } -const ARMAttributeParser::DisplayHandler -ARMAttributeParser::DisplayRoutines[] = { - { ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::StringAttribute, }, - { ARMBuildAttrs::CPU_name, &ARMAttributeParser::StringAttribute }, - ATTRIBUTE_HANDLER(CPU_arch), - ATTRIBUTE_HANDLER(CPU_arch_profile), - ATTRIBUTE_HANDLER(ARM_ISA_use), - ATTRIBUTE_HANDLER(THUMB_ISA_use), - ATTRIBUTE_HANDLER(FP_arch), - ATTRIBUTE_HANDLER(WMMX_arch), - ATTRIBUTE_HANDLER(Advanced_SIMD_arch), - ATTRIBUTE_HANDLER(MVE_arch), - ATTRIBUTE_HANDLER(PCS_config), - ATTRIBUTE_HANDLER(ABI_PCS_R9_use), - ATTRIBUTE_HANDLER(ABI_PCS_RW_data), - ATTRIBUTE_HANDLER(ABI_PCS_RO_data), - ATTRIBUTE_HANDLER(ABI_PCS_GOT_use), - ATTRIBUTE_HANDLER(ABI_PCS_wchar_t), - ATTRIBUTE_HANDLER(ABI_FP_rounding), - ATTRIBUTE_HANDLER(ABI_FP_denormal), - ATTRIBUTE_HANDLER(ABI_FP_exceptions), - ATTRIBUTE_HANDLER(ABI_FP_user_exceptions), - ATTRIBUTE_HANDLER(ABI_FP_number_model), - ATTRIBUTE_HANDLER(ABI_align_needed), - ATTRIBUTE_HANDLER(ABI_align_preserved), - ATTRIBUTE_HANDLER(ABI_enum_size), - ATTRIBUTE_HANDLER(ABI_HardFP_use), - ATTRIBUTE_HANDLER(ABI_VFP_args), - ATTRIBUTE_HANDLER(ABI_WMMX_args), - ATTRIBUTE_HANDLER(ABI_optimization_goals), - ATTRIBUTE_HANDLER(ABI_FP_optimization_goals), - ATTRIBUTE_HANDLER(compatibility), - ATTRIBUTE_HANDLER(CPU_unaligned_access), - ATTRIBUTE_HANDLER(FP_HP_extension), - ATTRIBUTE_HANDLER(ABI_FP_16bit_format), - ATTRIBUTE_HANDLER(MPextension_use), - ATTRIBUTE_HANDLER(DIV_use), - ATTRIBUTE_HANDLER(DSP_extension), - ATTRIBUTE_HANDLER(T2EE_use), - ATTRIBUTE_HANDLER(Virtualization_use), - ATTRIBUTE_HANDLER(nodefaults) -}; +const ARMAttributeParser::DisplayHandler ARMAttributeParser::DisplayRoutines[] = + {{ARMBuildAttrs::CPU_raw_name, &ELFAttributeParser::StringAttribute}, + {ARMBuildAttrs::CPU_name, &ELFAttributeParser::StringAttribute}, + ATTRIBUTE_HANDLER(CPU_arch), + ATTRIBUTE_HANDLER(CPU_arch_profile), + ATTRIBUTE_HANDLER(ARM_ISA_use), + ATTRIBUTE_HANDLER(THUMB_ISA_use), + ATTRIBUTE_HANDLER(FP_arch), + ATTRIBUTE_HANDLER(WMMX_arch), + ATTRIBUTE_HANDLER(Advanced_SIMD_arch), + ATTRIBUTE_HANDLER(MVE_arch), + ATTRIBUTE_HANDLER(PCS_config), + ATTRIBUTE_HANDLER(ABI_PCS_R9_use), + ATTRIBUTE_HANDLER(ABI_PCS_RW_data), + ATTRIBUTE_HANDLER(ABI_PCS_RO_data), + ATTRIBUTE_HANDLER(ABI_PCS_GOT_use), + ATTRIBUTE_HANDLER(ABI_PCS_wchar_t), + ATTRIBUTE_HANDLER(ABI_FP_rounding), + ATTRIBUTE_HANDLER(ABI_FP_denormal), + ATTRIBUTE_HANDLER(ABI_FP_exceptions), + ATTRIBUTE_HANDLER(ABI_FP_user_exceptions), + ATTRIBUTE_HANDLER(ABI_FP_number_model), + ATTRIBUTE_HANDLER(ABI_align_needed), + ATTRIBUTE_HANDLER(ABI_align_preserved), + ATTRIBUTE_HANDLER(ABI_enum_size), + ATTRIBUTE_HANDLER(ABI_HardFP_use), + ATTRIBUTE_HANDLER(ABI_VFP_args), + ATTRIBUTE_HANDLER(ABI_WMMX_args), + ATTRIBUTE_HANDLER(ABI_optimization_goals), + ATTRIBUTE_HANDLER(ABI_FP_optimization_goals), + ATTRIBUTE_HANDLER(compatibility), + ATTRIBUTE_HANDLER(CPU_unaligned_access), + ATTRIBUTE_HANDLER(FP_HP_extension), + ATTRIBUTE_HANDLER(ABI_FP_16bit_format), + ATTRIBUTE_HANDLER(MPextension_use), + ATTRIBUTE_HANDLER(DIV_use), + ATTRIBUTE_HANDLER(DSP_extension), + ATTRIBUTE_HANDLER(T2EE_use), + ATTRIBUTE_HANDLER(Virtualization_use), + ATTRIBUTE_HANDLER(nodefaults)}; #undef ATTRIBUTE_HANDLER -uint64_t ARMAttributeParser::ParseInteger(const uint8_t *Data, - uint32_t &Offset) { - unsigned DecodeLength; - uint64_t Value = decodeULEB128(Data + Offset, &DecodeLength); - Offset += DecodeLength; - return Value; -} - -StringRef ARMAttributeParser::ParseString(const uint8_t *Data, - uint32_t &Offset) { - const char *String = reinterpret_cast(Data + Offset); - size_t Length = std::strlen(String); - Offset = Offset + Length + 1; - return StringRef(String, Length); -} - -void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data, - uint32_t &Offset) { - - uint64_t Value = ParseInteger(Data, Offset); - Attributes.insert(std::make_pair(Tag, Value)); - - if (SW) - SW->printNumber(ARMBuildAttrs::AttrTypeAsString(Tag), Value); -} - -void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data, - uint32_t &Offset) { - StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false); - StringRef ValueDesc = ParseString(Data, Offset); - - if (SW) { - DictScope AS(*SW, "Attribute"); - SW->printNumber("Tag", Tag); - if (!TagName.empty()) - SW->printString("TagName", TagName); - SW->printString("Value", ValueDesc); - } -} - -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); - } -} - -void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::CPU_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6", @@ -144,7 +78,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::CPU_arch_profile(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { uint64_t Encoded = ParseInteger(Data, Offset); @@ -161,7 +95,7 @@ PrintAttribute(Tag, Encoded, Profile); } -void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ARM_ISA_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Permitted" }; @@ -171,7 +105,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::THUMB_ISA_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" }; @@ -181,7 +115,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::FP_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4", @@ -194,7 +128,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::WMMX_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" }; @@ -204,7 +138,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::Advanced_SIMD_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON", "ARMv8.1-a NEON" @@ -216,7 +150,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::MVE_arch(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::MVE_arch(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "MVE integer", "MVE integer and float" @@ -228,7 +162,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::PCS_config(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004", @@ -241,7 +175,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_PCS_R9_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "v6", "Static Base", "TLS", "Unused" }; @@ -251,7 +185,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_PCS_RW_data(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Absolute", "PC-relative", "SB-relative", "Not Permitted" @@ -263,7 +197,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_PCS_RO_data(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Absolute", "PC-relative", "Not Permitted" @@ -275,7 +209,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_PCS_GOT_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Direct", "GOT-Indirect" @@ -287,7 +221,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_PCS_wchar_t(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte" @@ -299,7 +233,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_FP_rounding(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "IEEE-754", "Runtime" }; @@ -309,7 +243,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_FP_denormal(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Unsupported", "IEEE-754", "Sign Only" @@ -321,7 +255,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_FP_exceptions(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "IEEE-754" }; @@ -331,7 +265,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag, +void ARMAttributeParser::ABI_FP_user_exceptions(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "IEEE-754" }; @@ -342,7 +276,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_FP_number_model(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Finite Only", "RTABI", "IEEE-754" @@ -354,7 +288,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_align_needed(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved" @@ -374,7 +308,7 @@ PrintAttribute(Tag, Value, Description); } -void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_align_preserved(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Required", "8-byte data alignment", "8-byte data and code alignment", @@ -395,7 +329,7 @@ PrintAttribute(Tag, Value, Description); } -void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_enum_size(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Packed", "Int32", "External Int32" @@ -407,7 +341,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_HardFP_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)" @@ -419,7 +353,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_VFP_args(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "AAPCS", "AAPCS VFP", "Custom", "Not Permitted" @@ -431,7 +365,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_WMMX_args(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "AAPCS", "iWMMX", "Custom" }; @@ -441,7 +375,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_optimization_goals(AttrType Tag, +void ARMAttributeParser::ABI_optimization_goals(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { @@ -455,7 +389,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag, +void ARMAttributeParser::ABI_FP_optimization_goals(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { @@ -469,7 +403,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::compatibility(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { uint64_t Integer = ParseInteger(Data, Offset); StringRef String = ParseString(Data, Offset); @@ -478,7 +412,8 @@ DictScope AS(*SW, "Attribute"); SW->printNumber("Tag", Tag); SW->startLine() << "Value: " << Integer << ", " << String << '\n'; - SW->printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false)); + SW->printString("TagName", ELFBuildAttrs::AttrTypeAsString( + Tag, TagToStringMap, /*TagPrefix*/ false)); switch (Integer) { case 0: SW->printString("Description", StringRef("No Specific Requirements")); @@ -493,7 +428,7 @@ } } -void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::CPU_unaligned_access(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "v6-style" }; @@ -503,7 +438,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::FP_HP_extension(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "If Available", "Permitted" }; @@ -513,7 +448,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::ABI_FP_16bit_format(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" }; @@ -523,7 +458,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::MPextension_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Permitted" }; @@ -533,7 +468,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::DIV_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "If Available", "Not Permitted", "Permitted" @@ -545,7 +480,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::DSP_extension(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::DSP_extension(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Permitted" }; @@ -555,7 +490,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::T2EE_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "Permitted" }; @@ -565,7 +500,7 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::Virtualization_use(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { "Not Permitted", "TrustZone", "Virtualization Extensions", @@ -578,150 +513,24 @@ PrintAttribute(Tag, Value, ValueDesc); } -void ARMAttributeParser::nodefaults(AttrType Tag, const uint8_t *Data, +void ARMAttributeParser::nodefaults(unsigned Tag, const uint8_t *Data, uint32_t &Offset) { uint64_t Value = ParseInteger(Data, Offset); PrintAttribute(Tag, Value, "Unspecified Tags UNDEFINED"); } -void ARMAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset, - SmallVectorImpl &IndexList) { - for (;;) { - unsigned DecodeLength; - uint64_t Value = decodeULEB128(Data + Offset, &DecodeLength); - Offset += DecodeLength; - if (Value == 0) - break; - IndexList.push_back(Value); - } -} - -void ARMAttributeParser::ParseAttributeList(const uint8_t *Data, - uint32_t &Offset, uint32_t Length) { - while (Offset < Length) { - unsigned DecodeLength; - uint64_t Tag = decodeULEB128(Data + Offset, &DecodeLength); - Offset += DecodeLength; - - bool Handled = false; - for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines); - AHI != AHE && !Handled; ++AHI) { - if (uint64_t(DisplayRoutines[AHI].Attribute) == Tag) { - (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag), - Data, Offset); - Handled = true; - break; - } - } - if (!Handled) { - if (Tag < 32) { - errs() << "unhandled AEABI Tag " << Tag - << " (" << ARMBuildAttrs::AttrTypeAsString(Tag) << ")\n"; - continue; - } - - if (Tag % 2 == 0) - IntegerAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset); - else - StringAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset); - } - } -} - -void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) { - uint32_t Offset = sizeof(uint32_t); /* SectionLength */ - - const char *VendorName = reinterpret_cast(Data + Offset); - size_t VendorNameLength = std::strlen(VendorName); - Offset = Offset + VendorNameLength + 1; - - if (SW) { - SW->printNumber("SectionLength", Length); - SW->printString("Vendor", StringRef(VendorName, VendorNameLength)); - } - - if (StringRef(VendorName, VendorNameLength).lower() != "aeabi") { - return; - } - - while (Offset < Length) { - /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size - uint8_t Tag = Data[Offset]; - Offset = Offset + sizeof(Tag); - - uint32_t Size = - *reinterpret_cast(Data + Offset); - Offset = Offset + sizeof(Size); - - if (SW) { - SW->printEnum("Tag", Tag, makeArrayRef(TagNames)); - SW->printNumber("Size", Size); - } - - if (Size > Length) { - errs() << "subsection length greater than section length\n"; - return; - } - - StringRef ScopeName, IndexName; - SmallVector Indicies; - switch (Tag) { - case ARMBuildAttrs::File: - ScopeName = "FileAttributes"; - break; - case ARMBuildAttrs::Section: - ScopeName = "SectionAttributes"; - IndexName = "Sections"; - ParseIndexList(Data, Offset, Indicies); - break; - case ARMBuildAttrs::Symbol: - ScopeName = "SymbolAttributes"; - IndexName = "Symbols"; - ParseIndexList(Data, Offset, Indicies); +bool ARMAttributeParser::Handler(unsigned Tag, const uint8_t *Data, + uint32_t &Offset) { + bool Handled = false; + for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines); + AHI != AHE && !Handled; ++AHI) { + if (uint64_t(DisplayRoutines[AHI].Attribute) == Tag) { + (this->*DisplayRoutines[AHI].Routine)(Tag, Data, Offset); + Handled = true; break; - default: - errs() << "unrecognised tag: 0x" << Twine::utohexstr(Tag) << '\n'; - return; - } - - if (SW) { - DictScope ASS(*SW, ScopeName); - if (!Indicies.empty()) - SW->printList(IndexName, Indicies); - ParseAttributeList(Data, Offset, Length); - } else { - ParseAttributeList(Data, Offset, Length); } } -} - -void ARMAttributeParser::Parse(ArrayRef Section, bool isLittle) { - uint64_t Offset = 1; - unsigned SectionNumber = 0; - while (Offset < Section.size()) { - uint32_t SectionLength = isLittle ? - support::endian::read32le(Section.data() + Offset) : - support::endian::read32be(Section.data() + Offset); - - if (SW) { - SW->startLine() << "Section " << ++SectionNumber << " {\n"; - SW->indent(); - } - - if (SectionLength == 0 || (SectionLength + Offset) > Section.size()) { - errs() << "invalid subsection length " << SectionLength << " at offset " - << Offset << "\n"; - return; - } - - ParseSubsection(Section.data() + Offset, SectionLength); - Offset = Offset + SectionLength; - - if (SW) { - SW->unindent(); - SW->startLine() << "}\n"; - } - } + return Handled; } } diff --git a/llvm/lib/Support/ARMBuildAttrs.cpp b/llvm/lib/Support/ARMBuildAttrs.cpp --- a/llvm/lib/Support/ARMBuildAttrs.cpp +++ b/llvm/lib/Support/ARMBuildAttrs.cpp @@ -1,4 +1,4 @@ -//===-- ARMBuildAttrs.cpp - ARM Build Attributes --------------------------===// +//===-- ARMBuildAttrs.cpp - ARM Build 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. @@ -6,97 +6,62 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringRef.h" #include "llvm/Support/ARMBuildAttributes.h" -using namespace llvm; - -namespace { -const struct { - ARMBuildAttrs::AttrType Attr; - StringRef TagName; -} ARMAttributeTags[] = { - { ARMBuildAttrs::File, "Tag_File" }, - { ARMBuildAttrs::Section, "Tag_Section" }, - { ARMBuildAttrs::Symbol, "Tag_Symbol" }, - { ARMBuildAttrs::CPU_raw_name, "Tag_CPU_raw_name" }, - { ARMBuildAttrs::CPU_name, "Tag_CPU_name" }, - { ARMBuildAttrs::CPU_arch, "Tag_CPU_arch" }, - { ARMBuildAttrs::CPU_arch_profile, "Tag_CPU_arch_profile" }, - { ARMBuildAttrs::ARM_ISA_use, "Tag_ARM_ISA_use" }, - { ARMBuildAttrs::THUMB_ISA_use, "Tag_THUMB_ISA_use" }, - { ARMBuildAttrs::FP_arch, "Tag_FP_arch" }, - { ARMBuildAttrs::WMMX_arch, "Tag_WMMX_arch" }, - { ARMBuildAttrs::Advanced_SIMD_arch, "Tag_Advanced_SIMD_arch" }, - { ARMBuildAttrs::MVE_arch, "Tag_MVE_arch" }, - { ARMBuildAttrs::PCS_config, "Tag_PCS_config" }, - { ARMBuildAttrs::ABI_PCS_R9_use, "Tag_ABI_PCS_R9_use" }, - { ARMBuildAttrs::ABI_PCS_RW_data, "Tag_ABI_PCS_RW_data" }, - { ARMBuildAttrs::ABI_PCS_RO_data, "Tag_ABI_PCS_RO_data" }, - { ARMBuildAttrs::ABI_PCS_GOT_use, "Tag_ABI_PCS_GOT_use" }, - { ARMBuildAttrs::ABI_PCS_wchar_t, "Tag_ABI_PCS_wchar_t" }, - { ARMBuildAttrs::ABI_FP_rounding, "Tag_ABI_FP_rounding" }, - { ARMBuildAttrs::ABI_FP_denormal, "Tag_ABI_FP_denormal" }, - { ARMBuildAttrs::ABI_FP_exceptions, "Tag_ABI_FP_exceptions" }, - { ARMBuildAttrs::ABI_FP_user_exceptions, "Tag_ABI_FP_user_exceptions" }, - { ARMBuildAttrs::ABI_FP_number_model, "Tag_ABI_FP_number_model" }, - { ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align_needed" }, - { ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align_preserved" }, - { ARMBuildAttrs::ABI_enum_size, "Tag_ABI_enum_size" }, - { ARMBuildAttrs::ABI_HardFP_use, "Tag_ABI_HardFP_use" }, - { ARMBuildAttrs::ABI_VFP_args, "Tag_ABI_VFP_args" }, - { ARMBuildAttrs::ABI_WMMX_args, "Tag_ABI_WMMX_args" }, - { ARMBuildAttrs::ABI_optimization_goals, "Tag_ABI_optimization_goals" }, - { ARMBuildAttrs::ABI_FP_optimization_goals, "Tag_ABI_FP_optimization_goals" }, - { ARMBuildAttrs::compatibility, "Tag_compatibility" }, - { ARMBuildAttrs::CPU_unaligned_access, "Tag_CPU_unaligned_access" }, - { ARMBuildAttrs::FP_HP_extension, "Tag_FP_HP_extension" }, - { ARMBuildAttrs::ABI_FP_16bit_format, "Tag_ABI_FP_16bit_format" }, - { ARMBuildAttrs::MPextension_use, "Tag_MPextension_use" }, - { ARMBuildAttrs::DIV_use, "Tag_DIV_use" }, - { ARMBuildAttrs::DSP_extension, "Tag_DSP_extension" }, - { ARMBuildAttrs::nodefaults, "Tag_nodefaults" }, - { ARMBuildAttrs::also_compatible_with, "Tag_also_compatible_with" }, - { ARMBuildAttrs::T2EE_use, "Tag_T2EE_use" }, - { ARMBuildAttrs::conformance, "Tag_conformance" }, - { ARMBuildAttrs::Virtualization_use, "Tag_Virtualization_use" }, - - // Legacy Names - { ARMBuildAttrs::FP_arch, "Tag_VFP_arch" }, - { ARMBuildAttrs::FP_HP_extension, "Tag_VFP_HP_extension" }, - { 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(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 ""; -} +TagNameMap ARMAttributeTags = { + {ARMBuildAttrs::File, "Tag_File"}, + {ARMBuildAttrs::Section, "Tag_Section"}, + {ARMBuildAttrs::Symbol, "Tag_Symbol"}, + {ARMBuildAttrs::CPU_raw_name, "Tag_CPU_raw_name"}, + {ARMBuildAttrs::CPU_name, "Tag_CPU_name"}, + {ARMBuildAttrs::CPU_arch, "Tag_CPU_arch"}, + {ARMBuildAttrs::CPU_arch_profile, "Tag_CPU_arch_profile"}, + {ARMBuildAttrs::ARM_ISA_use, "Tag_ARM_ISA_use"}, + {ARMBuildAttrs::THUMB_ISA_use, "Tag_THUMB_ISA_use"}, + {ARMBuildAttrs::FP_arch, "Tag_FP_arch"}, + {ARMBuildAttrs::WMMX_arch, "Tag_WMMX_arch"}, + {ARMBuildAttrs::Advanced_SIMD_arch, "Tag_Advanced_SIMD_arch"}, + {ARMBuildAttrs::MVE_arch, "Tag_MVE_arch"}, + {ARMBuildAttrs::PCS_config, "Tag_PCS_config"}, + {ARMBuildAttrs::ABI_PCS_R9_use, "Tag_ABI_PCS_R9_use"}, + {ARMBuildAttrs::ABI_PCS_RW_data, "Tag_ABI_PCS_RW_data"}, + {ARMBuildAttrs::ABI_PCS_RO_data, "Tag_ABI_PCS_RO_data"}, + {ARMBuildAttrs::ABI_PCS_GOT_use, "Tag_ABI_PCS_GOT_use"}, + {ARMBuildAttrs::ABI_PCS_wchar_t, "Tag_ABI_PCS_wchar_t"}, + {ARMBuildAttrs::ABI_FP_rounding, "Tag_ABI_FP_rounding"}, + {ARMBuildAttrs::ABI_FP_denormal, "Tag_ABI_FP_denormal"}, + {ARMBuildAttrs::ABI_FP_exceptions, "Tag_ABI_FP_exceptions"}, + {ARMBuildAttrs::ABI_FP_user_exceptions, "Tag_ABI_FP_user_exceptions"}, + {ARMBuildAttrs::ABI_FP_number_model, "Tag_ABI_FP_number_model"}, + {ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align_needed"}, + {ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align_preserved"}, + {ARMBuildAttrs::ABI_enum_size, "Tag_ABI_enum_size"}, + {ARMBuildAttrs::ABI_HardFP_use, "Tag_ABI_HardFP_use"}, + {ARMBuildAttrs::ABI_VFP_args, "Tag_ABI_VFP_args"}, + {ARMBuildAttrs::ABI_WMMX_args, "Tag_ABI_WMMX_args"}, + {ARMBuildAttrs::ABI_optimization_goals, "Tag_ABI_optimization_goals"}, + {ARMBuildAttrs::ABI_FP_optimization_goals, "Tag_ABI_FP_optimization_goals"}, + {ARMBuildAttrs::compatibility, "Tag_compatibility"}, + {ARMBuildAttrs::CPU_unaligned_access, "Tag_CPU_unaligned_access"}, + {ARMBuildAttrs::FP_HP_extension, "Tag_FP_HP_extension"}, + {ARMBuildAttrs::ABI_FP_16bit_format, "Tag_ABI_FP_16bit_format"}, + {ARMBuildAttrs::MPextension_use, "Tag_MPextension_use"}, + {ARMBuildAttrs::DIV_use, "Tag_DIV_use"}, + {ARMBuildAttrs::DSP_extension, "Tag_DSP_extension"}, + {ARMBuildAttrs::nodefaults, "Tag_nodefaults"}, + {ARMBuildAttrs::also_compatible_with, "Tag_also_compatible_with"}, + {ARMBuildAttrs::T2EE_use, "Tag_T2EE_use"}, + {ARMBuildAttrs::conformance, "Tag_conformance"}, + {ARMBuildAttrs::Virtualization_use, "Tag_Virtualization_use"}, -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; -} -} + // Legacy Names + {ARMBuildAttrs::FP_arch, "Tag_VFP_arch"}, + {ARMBuildAttrs::FP_HP_extension, "Tag_VFP_HP_extension"}, + {ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align8_needed"}, + {ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align8_preserved"}, +}; } - +} // namespace llvm diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -87,6 +87,8 @@ DeltaAlgorithm.cpp DAGDeltaAlgorithm.cpp DJB.cpp + ELFAttributeParser.cpp + ELFBuildAttrs.cpp Error.cpp ErrorHandling.cpp FileCheck.cpp @@ -121,6 +123,8 @@ PrettyStackTrace.cpp RandomNumberGenerator.cpp Regex.cpp + RISCVAttributes.cpp + RISCVAttributeParser.cpp ScaledNumber.cpp ScopedPrinter.cpp SHA1.cpp diff --git a/llvm/lib/Support/ELFAttributeParser.cpp b/llvm/lib/Support/ELFAttributeParser.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/ELFAttributeParser.cpp @@ -0,0 +1,221 @@ +//===--- ELFAttributeParser.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ELFAttributeParser.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::ELFBuildAttrs; + +static const EnumEntry TagNames[] = { + {"Tag_File", ELFBuildAttrs::File}, + {"Tag_Section", ELFBuildAttrs::Section}, + {"Tag_Symbol", ELFBuildAttrs::Symbol}, +}; + +namespace llvm { +uint64_t ELFAttributeParser::ParseInteger(const uint8_t *Data, + uint32_t &Offset) { + unsigned DecodeLength; + uint64_t Value = decodeULEB128(Data + Offset, &DecodeLength); + Offset += DecodeLength; + return Value; +} + +StringRef ELFAttributeParser::ParseString(const uint8_t *Data, + uint32_t &Offset) { + const char *String = reinterpret_cast(Data + Offset); + size_t Length = std::strlen(String); + Offset = Offset + Length + 1; + return StringRef(String, Length); +} + +void ELFAttributeParser::IntegerAttribute(unsigned Tag, const uint8_t *Data, + uint32_t &Offset) { + StringRef TagName = + ELFBuildAttrs::AttrTypeAsString(Tag, TagToStringMap, /*TagPrefix=*/false); + uint64_t Value = ParseInteger(Data, Offset); + Attributes.insert(std::make_pair(Tag, Value)); + + if (SW) { + DictScope AS(*SW, "Attribute"); + SW->printNumber("Tag", Tag); + if (!TagName.empty()) + SW->printString("TagName", TagName); + SW->printNumber("Value", Value); + } +} + +void ELFAttributeParser::StringAttribute(unsigned Tag, const uint8_t *Data, + uint32_t &Offset) { + StringRef TagName = + ELFBuildAttrs::AttrTypeAsString(Tag, TagToStringMap, /*TagPrefix=*/false); + StringRef Value = ParseString(Data, Offset); + AttributesStr.insert(std::make_pair(Tag, Value)); + + if (SW) { + DictScope AS(*SW, "Attribute"); + SW->printNumber("Tag", Tag); + if (!TagName.empty()) + SW->printString("TagName", TagName); + SW->printString("Value", Value); + } +} + +void ELFAttributeParser::PrintAttribute(unsigned Tag, unsigned Value, + StringRef ValueDesc) { + Attributes.insert(std::make_pair(Tag, Value)); + + if (SW) { + StringRef TagName = ELFBuildAttrs::AttrTypeAsString(Tag, TagToStringMap, + /*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); + } +} + +void ELFAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset, + SmallVectorImpl &IndexList) { + for (;;) { + unsigned DecodeLength; + uint64_t Value = decodeULEB128(Data + Offset, &DecodeLength); + Offset += DecodeLength; + if (Value == 0) + break; + IndexList.push_back(Value); + } +} + +void ELFAttributeParser::ParseAttributeList(const uint8_t *Data, + uint32_t &Offset, uint32_t Length) { + while (Offset < Length) { + unsigned DecodeLength; + uint64_t Tag = decodeULEB128(Data + Offset, &DecodeLength); + Offset += DecodeLength; + + bool Handled = Handler(Tag, Data, Offset); + if (!Handled) { + if (Tag < 32) { + errs() << "unhandled Tag " << Tag << " (" + << ELFBuildAttrs::AttrTypeAsString(Tag, TagToStringMap) << ")\n"; + continue; + } + + if (Tag % 2 == 0) + IntegerAttribute(Tag, Data, Offset); + else + StringAttribute(Tag, Data, Offset); + } + } +} + +void ELFAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) { + uint32_t Offset = sizeof(uint32_t); // SectionLength + + const char *VendorName = reinterpret_cast(Data + Offset); + size_t VendorNameLength = std::strlen(VendorName); + Offset = Offset + VendorNameLength + 1; + + if (SW) { + SW->printNumber("SectionLength", Length); + SW->printString("Vendor", StringRef(VendorName, VendorNameLength)); + } + + if (StringRef(VendorName, VendorNameLength).lower() != Vendor) { + return; + } + + while (Offset < Length) { + /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size + uint8_t Tag = Data[Offset]; + Offset = Offset + sizeof(Tag); + + uint32_t Size = + *reinterpret_cast(Data + Offset); + Offset = Offset + sizeof(Size); + + if (SW) { + SW->printEnum("Tag", Tag, makeArrayRef(TagNames)); + SW->printNumber("Size", Size); + } + + if (Size > Length) { + errs() << "subsection length greater than section length\n"; + return; + } + + StringRef ScopeName, IndexName; + SmallVector Indicies; + switch (Tag) { + case ELFBuildAttrs::File: + ScopeName = "FileAttributes"; + break; + case ELFBuildAttrs::Section: + ScopeName = "SectionAttributes"; + IndexName = "Sections"; + ParseIndexList(Data, Offset, Indicies); + break; + case ELFBuildAttrs::Symbol: + ScopeName = "SymbolAttributes"; + IndexName = "Symbols"; + ParseIndexList(Data, Offset, Indicies); + break; + default: + errs() << "unrecognised tag: 0x" << Twine::utohexstr(Tag) << '\n'; + return; + } + + if (SW) { + DictScope ASS(*SW, ScopeName); + if (!Indicies.empty()) + SW->printList(IndexName, Indicies); + ParseAttributeList(Data, Offset, Length); + } else { + ParseAttributeList(Data, Offset, Length); + } + } +} + +void ELFAttributeParser::Parse(ArrayRef Section, bool isLittle) { + uint64_t Offset = 1; + unsigned SectionNumber = 0; + + while (Offset < Section.size()) { + uint32_t SectionLength = + isLittle ? support::endian::read32le(Section.data() + Offset) + : support::endian::read32be(Section.data() + Offset); + + if (SW) { + SW->startLine() << "Section " << ++SectionNumber << " {\n"; + SW->indent(); + } + + if (SectionLength == 0 || (SectionLength + Offset) > Section.size()) { + errs() << "invalid subsection length " << SectionLength << " at offset " + << Offset << "\n"; + return; + } + + ParseSubsection(Section.data() + Offset, SectionLength); + Offset = Offset + SectionLength; + + if (SW) { + SW->unindent(); + SW->startLine() << "}\n"; + } + } +} +} // namespace llvm diff --git a/llvm/lib/Support/ELFBuildAttrs.cpp b/llvm/lib/Support/ELFBuildAttrs.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/ELFBuildAttrs.cpp @@ -0,0 +1,41 @@ +//===-- ELFBuildAttrs.cpp - ELF Build 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ELFBuildAttributes.h" + +using namespace llvm; + +namespace llvm { +namespace ELFBuildAttrs { +StringRef AttrTypeAsString(unsigned Attr, TagNameMap Map, bool HasTagPrefix) { + return AttrTypeAsString(static_cast(Attr), Map, HasTagPrefix); +} + +StringRef AttrTypeAsString(AttrType Attr, TagNameMap Map, bool HasTagPrefix) { + for (auto TI = Map.begin(), TE = Map.end(); TI != TE; ++TI) { + if (TI->Attr == Attr) { + auto TagName = TI->TagName; + return HasTagPrefix ? TagName : TagName.drop_front(4); + } + } + return ""; +} + +int AttrTypeFromString(StringRef Tag, TagNameMap Map) { + bool HasTagPrefix = Tag.startswith("Tag_"); + for (auto TI = Map.begin(), TE = Map.end(); TI != TE; ++TI) { + auto TagName = TI->TagName; + if (TagName.drop_front(HasTagPrefix ? 0 : 4) == Tag) { + return TI->Attr; + } + } + return -1; +} +} // namespace ELFBuildAttrs +} // namespace llvm diff --git a/llvm/lib/Support/RISCVAttributeParser.cpp b/llvm/lib/Support/RISCVAttributeParser.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/RISCVAttributeParser.cpp @@ -0,0 +1,77 @@ +//===--- RISCVAttributeParser.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/RISCVAttributeParser.h" +#include "llvm/ADT/StringExtras.h" + +using namespace llvm; +using namespace llvm::RISCVAttrs; + +namespace llvm { +#define ATTRIBUTE_HANDLER(Attr_) \ + { RISCVAttrs::Attr_, &RISCVAttributeParser::Attr_ } + +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, + }, + ATTRIBUTE_HANDLER(Stack_align), + ATTRIBUTE_HANDLER(Unaligned_access)}; + +#undef ATTRIBUTE_HANDLER + +void RISCVAttributeParser::Unaligned_access(unsigned Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *const Strings[] = {"No unaligned access", + "Unaligned access"}; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void RISCVAttributeParser::Stack_align(unsigned Tag, const uint8_t *Data, + uint32_t &Offset) { + uint64_t Value = ParseInteger(Data, Offset); + std::string Description = + "Stack alignment is " + utostr(Value) + std::string("-bytes"); + + PrintAttribute(Tag, Value, Description); +} + +bool RISCVAttributeParser::Handler(unsigned Tag, const uint8_t *Data, + uint32_t &Offset) { + bool Handled = false; + for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines); + AHI != AHE && !Handled; ++AHI) { + if (uint64_t(DisplayRoutines[AHI].Attribute) == Tag) { + (this->*DisplayRoutines[AHI].Routine)(Tag, Data, Offset); + Handled = true; + break; + } + } + + return Handled; +} + +} // namespace llvm diff --git a/llvm/lib/Support/RISCVAttributes.cpp b/llvm/lib/Support/RISCVAttributes.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/RISCVAttributes.cpp @@ -0,0 +1,24 @@ +//===-- RISCVAttributes.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/RISCVAttributes.h" + +namespace llvm { +namespace RISCVAttrs { + +TagNameMap RISCVAttributeTags = { + {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"}, +}; + +} // namespace RISCVAttrs +} // namespace llvm diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -10859,7 +10859,8 @@ TagLoc = Parser.getTok().getLoc(); if (Parser.getTok().is(AsmToken::Identifier)) { StringRef Name = Parser.getTok().getIdentifier(); - Tag = ARMBuildAttrs::AttrTypeFromString(Name); + Tag = ELFBuildAttrs::AttrTypeFromString(Name, + ARMBuildAttrs::ARMAttributeTags); if (Tag == -1) { Error(TagLoc, "attribute name not recognised: " + Name); return false; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -177,7 +177,8 @@ void ARMTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) { OS << "\t.eabi_attribute\t" << Attribute << ", " << Twine(Value); if (IsVerboseAsm) { - StringRef Name = ARMBuildAttrs::AttrTypeAsString(Attribute); + StringRef Name = ELFBuildAttrs::AttrTypeAsString( + Attribute, ARMBuildAttrs::ARMAttributeTags); if (!Name.empty()) OS << "\t@ " << Name; } @@ -193,7 +194,8 @@ default: OS << "\t.eabi_attribute\t" << Attribute << ", \"" << String << "\""; if (IsVerboseAsm) { - StringRef Name = ARMBuildAttrs::AttrTypeAsString(Attribute); + StringRef Name = ELFBuildAttrs::AttrTypeAsString( + Attribute, ARMBuildAttrs::ARMAttributeTags); if (!Name.empty()) OS << "\t@ " << Name; } @@ -212,7 +214,9 @@ if (!StringValue.empty()) OS << ", \"" << StringValue << "\""; if (IsVerboseAsm) - OS << "\t@ " << ARMBuildAttrs::AttrTypeAsString(Attribute); + OS << "\t@ " + << ELFBuildAttrs::AttrTypeAsString(Attribute, + ARMBuildAttrs::ARMAttributeTags); break; } OS << "\n"; diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -32,6 +32,7 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Casting.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/RISCVAttributes.h" #include "llvm/Support/TargetRegistry.h" #include @@ -146,6 +147,7 @@ bool parseOperand(OperandVector &Operands, StringRef Mnemonic); bool parseDirectiveOption(); + bool parseDirectiveAttribute(); void setFeatureBits(uint64_t Feature, StringRef FeatureString) { if (!(getSTI().getFeatureBits()[Feature])) { @@ -1579,6 +1581,8 @@ if (IDVal == ".option") return parseDirectiveOption(); + else if (IDVal == ".attribute") + return parseDirectiveAttribute(); return true; } @@ -1677,6 +1681,117 @@ return false; } +/// parseDirectiveAttribute +/// ::= .attribute int, int [, "str"] +/// ::= .attribute Tag_name, int [, "str"] +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(); + Tag = + ELFBuildAttrs::AttrTypeFromString(Name, RISCVAttrs::RISCVAttributeTags); + if (Tag == -1) { + Error(TagLoc, "attribute name not recognised: " + Name); + return false; + } + Parser.Lex(); + } else { + const MCExpr *AttrExpr; + + TagLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(AttrExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast(AttrExpr); + if (check(!CE, TagLoc, "expected numeric constant")) + return true; + + Tag = CE->getValue(); + } + + if (Parser.parseToken(AsmToken::Comma, "comma expected")) + return true; + + StringRef StringValue = ""; + bool IsStringValue = false; + + int64_t IntegerValue = 0; + bool IsIntegerValue = false; + + if (Tag == RISCVAttrs::Arch) + IsStringValue = true; + else + IsIntegerValue = true; + + if (IsIntegerValue) { + const MCExpr *ValueExpr; + SMLoc ValueExprLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(ValueExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast(ValueExpr); + if (!CE) + return Error(ValueExprLoc, "expected numeric constant"); + IntegerValue = CE->getValue(); + } + + if (IsStringValue) { + if (Parser.getTok().isNot(AsmToken::String)) + return Error(Parser.getTok().getLoc(), "bad string constant"); + + StringValue = Parser.getTok().getStringContents(); + Parser.Lex(); + } + + if (Parser.parseToken(AsmToken::EndOfStatement, + "unexpected token in '.attribute' directive")) + return true; + + if (IsIntegerValue) + getTargetStreamer().emitAttribute(Tag, IntegerValue); + else if (IsStringValue) + getTargetStreamer().emitTextAttribute(Tag, StringValue); + + if (Tag == RISCVAttrs::Arch) { + StringRef Arch = StringValue; + if (Arch.startswith("rv32")) + clearFeatureBits(RISCV::Feature64Bit, "64bit"); + else if (Arch.startswith("rv64")) + setFeatureBits(RISCV::Feature64Bit, "64bit"); + else + return Error(Parser.getTok().getLoc(), "bad string constant"); + Arch = Arch.drop_front(4); // Discard "rv[32|64]" + + while (!Arch.empty()) { + if (Arch[0] == 'i') + clearFeatureBits(RISCV::FeatureRV32E, "e"); + else if (Arch[0] == 'e') + setFeatureBits(RISCV::FeatureRV32E, "e"); + 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(Parser.getTok().getLoc(), "bad string constant"); + + Arch = Arch.drop_until([](char c) { return c == '_' || c == '"'; }); + Arch = Arch.drop_while([](char c) { return c == '_'; }); + } + } + + return false; +} + void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) { MCInst CInst; bool Res = compressInst(CInst, Inst, getSTI(), S.getContext()); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -15,6 +15,90 @@ namespace llvm { class RISCVTargetELFStreamer : public RISCVTargetStreamer { +private: + struct AttributeItem { + enum { + HiddenAttribute = 0, + NumericAttribute, + TextAttribute, + NumericAndTextAttributes + } Type; + unsigned Tag; + unsigned IntValue; + std::string StringValue; + }; + + StringRef CurrentVendor; + SmallVector 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 = AttributeItem::NumericAttribute; + Item->IntValue = Value; + return; + } + + // Create new attribute item + AttributeItem Item = {AttributeItem::NumericAttribute, Attribute, Value, + std::string(StringRef(""))}; + Contents.push_back(Item); + } + + void setAttributeItem(unsigned Attribute, StringRef Value, + bool OverwriteExisting) { + // Look for existing attribute item + if (AttributeItem *Item = getAttributeItem(Attribute)) { + if (!OverwriteExisting) + return; + Item->Type = AttributeItem::TextAttribute; + Item->StringValue = std::string(Value); + return; + } + + // Create new attribute item + AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0, + std::string(Value)}; + Contents.push_back(Item); + } + + 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 = AttributeItem::NumericAndTextAttributes; + Item->IntValue = IntValue; + Item->StringValue = std::string(StringValue); + return; + } + + // Create new attribute item + AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute, + IntValue, std::string(StringValue)}; + Contents.push_back(Item); + } + + 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); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -15,14 +15,18 @@ #include "RISCVMCTargetDesc.h" #include "Utils/RISCVBaseInfo.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/RISCVAttributes.h" using namespace llvm; // This part is for ELF object output. RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) - : RISCVTargetStreamer(S) { + : RISCVTargetStreamer(S), CurrentVendor("riscv") { MCAssembler &MCA = getStreamer().getAssembler(); const FeatureBitset &Features = STI.getFeatureBits(); auto &MAB = static_cast(MCA.getBackend()); @@ -66,3 +70,100 @@ 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.EmitIntValue(ELFBuildAttrs::Format_Version, 1); + } + + // 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.EmitIntValue(VendorHeaderSize + TagHeaderSize + ContentsSize, 4); + Streamer.EmitBytes(CurrentVendor); + Streamer.EmitIntValue(0, 1); // '\0' + + Streamer.EmitIntValue(ELFBuildAttrs::File, 1); + Streamer.EmitIntValue(TagHeaderSize + ContentsSize, 4); + + // Size should have been accounted for already, now + // emit each field as its type (ULEB or String) + for (size_t i = 0; i < Contents.size(); ++i) { + AttributeItem item = Contents[i]; + Streamer.EmitULEB128IntValue(item.Tag); + switch (item.Type) { + default: + llvm_unreachable("Invalid attribute type"); + case AttributeItem::NumericAttribute: + Streamer.EmitULEB128IntValue(item.IntValue); + break; + case AttributeItem::TextAttribute: + Streamer.EmitBytes(item.StringValue); + Streamer.EmitIntValue(0, 1); // '\0' + break; + case AttributeItem::NumericAndTextAttributes: + Streamer.EmitULEB128IntValue(item.IntValue); + Streamer.EmitBytes(item.StringValue); + Streamer.EmitIntValue(0, 1); // '\0' + break; + } + } + + Contents.clear(); +} + +size_t RISCVTargetELFStreamer::calculateContentSize() const { + size_t Result = 0; + for (size_t i = 0; i < Contents.size(); ++i) { + AttributeItem item = Contents[i]; + switch (item.Type) { + case AttributeItem::HiddenAttribute: + break; + case AttributeItem::NumericAttribute: + Result += getULEB128Size(item.Tag); + Result += getULEB128Size(item.IntValue); + break; + case AttributeItem::TextAttribute: + Result += getULEB128Size(item.Tag); + Result += item.StringValue.size() + 1; // string + '\0' + break; + case AttributeItem::NumericAndTextAttributes: + Result += getULEB128Size(item.Tag); + Result += getULEB128Size(item.IntValue); + Result += item.StringValue.size() + 1; // string + '\0'; + break; + } + } + return Result; +} diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h @@ -10,12 +10,14 @@ #define LLVM_LIB_TARGET_RISCV_RISCVTARGETSTREAMER_H #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" namespace llvm { class RISCVTargetStreamer : public MCTargetStreamer { public: RISCVTargetStreamer(MCStreamer &S); + void finish() override; virtual void emitDirectiveOptionPush() = 0; virtual void emitDirectiveOptionPop() = 0; @@ -23,12 +25,25 @@ virtual void emitDirectiveOptionNoRVC() = 0; virtual void emitDirectiveOptionRelax() = 0; virtual void emitDirectiveOptionNoRelax() = 0; + virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0; + virtual void finishAttributeSection() = 0; + virtual void emitTextAttribute(unsigned Attribute, StringRef String) = 0; + virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, + StringRef StringValue = "") = 0; + + void emitTargetAttributes(const MCSubtargetInfo &STI); }; // This part is for ascii assembly output class RISCVTargetAsmStreamer : public RISCVTargetStreamer { formatted_raw_ostream &OS; + void finishAttributeSection() override; + void emitAttribute(unsigned Attribute, unsigned Value) override; + void emitTextAttribute(unsigned Attribute, StringRef String) override; + void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, + StringRef StringValue) override; + public: RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -11,12 +11,50 @@ //===----------------------------------------------------------------------===// #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, 4); + else + emitAttribute(RISCVAttrs::Stack_align, 16); + + std::string Arch = Twine("rv32").str(); + + if (STI.hasFeature(RISCV::Feature64Bit)) + Arch = Twine("rv64").str(); + + if (STI.hasFeature(RISCV::FeatureRV32E)) + Arch = (Twine(Arch) + "e1p9").str(); + else + Arch = (Twine(Arch) + "i2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtM)) + Arch = (Twine(Arch) + "_m2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtA)) + Arch = (Twine(Arch) + "_a2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtF)) + Arch = (Twine(Arch) + "_f2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtD)) + Arch = (Twine(Arch) + "_d2p0").str(); + + if (STI.hasFeature(RISCV::FeatureStdExtC)) + Arch = (Twine(Arch) + "_c2p0").str(); + + emitTextAttribute(RISCVAttrs::Arch, Arch); +} + // This part is for ascii assembly output RISCVTargetAsmStreamer::RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS) @@ -45,3 +83,19 @@ void RISCVTargetAsmStreamer::emitDirectiveOptionNoRelax() { OS << "\t.option\tnorelax\n"; } + +void RISCVTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) { + OS << "\t.attribute\t" << Attribute << ", " << Twine(Value) << "\n"; +} + +void RISCVTargetAsmStreamer::emitTextAttribute(unsigned Attribute, + StringRef String) { + OS << "\t.attribute\t" << Attribute << ", \"" << String << "\"" + << "\n"; +} + +void RISCVTargetAsmStreamer::emitIntTextAttribute(unsigned Attribute, + unsigned IntValue, + StringRef StringValue) {} + +void RISCVTargetAsmStreamer::finishAttributeSection() {} diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -11,9 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "RISCV.h" #include "MCTargetDesc/RISCVInstPrinter.h" #include "MCTargetDesc/RISCVMCExpr.h" +#include "MCTargetDesc/RISCVTargetStreamer.h" +#include "RISCV.h" #include "RISCVTargetMachine.h" #include "TargetInfo/RISCVTargetInfo.h" #include "llvm/ADT/Statistic.h" @@ -59,6 +60,12 @@ 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(); }; } @@ -154,6 +161,36 @@ return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); } +void RISCVAsmPrinter::EmitStartOfAsmFile(Module &M) { + const Triple &TT = TM.getTargetTriple(); + + if (TT.isOSBinFormatELF()) + emitAttributes(); +} + +void RISCVAsmPrinter::EmitEndOfAsmFile(Module &M) { + const Triple &TT = TM.getTargetTriple(); + MCTargetStreamer &TS = *OutStreamer->getTargetStreamer(); + RISCVTargetStreamer &RTS = static_cast(TS); + + if (TT.isOSBinFormatELF()) { + RTS.finishAttributeSection(); + } +} + +void RISCVAsmPrinter::emitAttributes() { + MCTargetStreamer &TS = *OutStreamer->getTargetStreamer(); + RISCVTargetStreamer &RTS = static_cast(TS); + + const Triple &TT = TM.getTargetTriple(); + StringRef CPU = TM.getTargetCPU(); + StringRef FS = TM.getTargetFeatureString(); + const RISCVTargetMachine &RTM = static_cast(TM); + const RISCVSubtarget STI(TT, CPU, FS, /*ABIName=*/"", RTM); + + RTS.emitTargetAttributes(STI); +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() { RegisterAsmPrinter X(getTheRISCV32Target()); diff --git a/llvm/test/MC/RISCV/attribute-with-insts.s b/llvm/test/MC/RISCV/attribute-with-insts.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/attribute-with-insts.s @@ -0,0 +1,34 @@ +## Test .attribute effects. +## We do not provide '-mattr=' and '.option rvc' and enable extensions through +## '.attribute arch'. + +# RUN: llvm-mc -triple riscv32 -filetype=obj %s \ +# RUN: | llvm-objdump -triple riscv32 -d -M no-aliases - \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s + +# RUN: llvm-mc -triple riscv64 -filetype=obj %s \ +# RUN: | llvm-objdump -triple riscv64 -d -M no-aliases - \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s + +.attribute arch, "rv64i2p0_m2p0_a2p0_d2p0_c2p0" + +# CHECK-INST: lr.w t0, (t1) +lr.w t0, (t1) + +# CHECK-INST: c.addi a3, -32 +c.addi a3, -32 + +# CHECK-INST: fmadd.d fa0, fa1, fa2, fa3, dyn +fmadd.d f10, f11, f12, f13, dyn + +# CHECK-INST: fmadd.s fa0, fa1, fa2, fa3, dyn +fmadd.s f10, f11, f12, f13, dyn + +# CHECK-INST: addi ra, sp, 2 +addi ra, sp, 2 + +# CHECK-INST: mul a4, ra, s0 +mul a4, ra, s0 + +# CHECK-INST: addw a2, a3, a4 +addw a2, a3, a4 diff --git a/llvm/test/MC/RISCV/attribute.s b/llvm/test/MC/RISCV/attribute.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/attribute.s @@ -0,0 +1,24 @@ +# Test llvm-mc could handle .attribute correctly. + +# RUN: llvm-mc %s -triple=riscv32 -filetype=asm \ +# RUN: | FileCheck %s +# RUN: llvm-mc %s -triple=riscv64 -filetype=asm \ +# RUN: | FileCheck %s + +.attribute stack_align, 16 +# CHECK: attribute 4, 16 + +.attribute arch, "rv32i2p0_m2p0_a2p0_c2p0" +# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_c2p0" + +.attribute unaligned_access, 0 +# CHECK: attribute 6, 0 + +.attribute priv_spec, 2 +# CHECK: attribute 8, 2 + +.attribute priv_spec_minor, 0 +# CHECK: attribute 10, 0 + +.attribute priv_spec_revision, 0 +# CHECK: attribute 12, 0 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.test @@ -0,0 +1,69 @@ +## Test llvm-readobj decodes RISCV attributes correctly. + +# RUN: yaml2obj %s -D BITS=32 -o %t.32.o +# RUN: llvm-readobj --arch-specific %t.32.o \ +# RUN: | FileCheck %s --check-prefixes=CHECK-OBJ32,BOTH +# RUN: yaml2obj %s -D BITS=64 -o %t.64.o +# RUN: llvm-readobj --arch-specific %t.64.o \ +# RUN: | FileCheck %s --check-prefixes=CHECK-OBJ64,BOTH + +# CHECK-OBJ32: Format: ELF32-riscv +# CHECK-OBJ32-NEXT: Arch: riscv32 +# CHECK-OBJ32-NEXT: AddressSize: 32bit +# CHECK-OBJ64: Format: ELF64-riscv +# CHECK-OBJ64-NEXT: Arch: riscv64 +# CHECK-OBJ64-NEXT: AddressSize: 64bit +# BOTH: BuildAttributes { +# BOTH-NEXT: FormatVersion: 0x41 +# BOTH-NEXT: Section 1 { +# BOTH-NEXT: SectionLength: 50 +# BOTH-NEXT: Vendor: riscv +# BOTH-NEXT: Tag: Tag_File (0x1) +# BOTH-NEXT: Size: 40 +# BOTH-NEXT: FileAttributes { +# BOTH-NEXT: Attribute { +# BOTH-NEXT: Tag: 4 +# BOTH-NEXT: Value: 16 +# BOTH-NEXT: TagName: stack_align +# BOTH-NEXT: Description: Stack alignment is 16-bytes +# BOTH-NEXT: } +# BOTH-NEXT: Attribute { +# BOTH-NEXT: Tag: 5 +# BOTH-NEXT: TagName: arch +# BOTH-NEXT: Value: rv32i2p0_m2p0_a2p0_c2p0 +# BOTH-NEXT: } +# BOTH-NEXT: Attribute { +# BOTH-NEXT: Tag: 6 +# BOTH-NEXT: Value: 0 +# BOTH-NEXT: TagName: unaligned_access +# BOTH-NEXT: Description: No unaligned access +# BOTH-NEXT: } +# BOTH-NEXT: Attribute { +# BOTH-NEXT: Tag: 8 +# BOTH-NEXT: TagName: priv_spec +# BOTH-NEXT: Value: 2 +# BOTH-NEXT: } +# BOTH-NEXT: Attribute { +# BOTH-NEXT: Tag: 10 +# BOTH-NEXT: TagName: priv_spec_minor +# BOTH-NEXT: Value: 0 +# BOTH-NEXT: } +# BOTH-NEXT: Attribute { +# BOTH-NEXT: Tag: 12 +# BOTH-NEXT: TagName: priv_spec_revision +# BOTH-NEXT: Value: 0 +# BOTH-NEXT: } +# BOTH-NEXT: } +# BOTH-NEXT: } +# BOTH-NEXT: } + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS]] + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES + Content: 4132000000726973637600012800000004100572763332693270305F6D3270305F613270305F6332703000060008020A000C00 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/lit.local.cfg b/llvm/test/tools/llvm-readobj/ELF/RISCV/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'RISCV' in config.root.targets: + config.unsupported = True diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -52,6 +52,8 @@ #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MipsABIFlags.h" +#include "llvm/Support/RISCVAttributeParser.h" +#include "llvm/Support/RISCVAttributes.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include @@ -2589,6 +2591,7 @@ const ELFFile *Obj = ObjF->getELFFile(); switch (Obj->getHeader()->e_machine) { case EM_ARM: + case EM_RISCV: printAttributes(); break; case EM_MIPS: { @@ -2609,38 +2612,44 @@ } } -template void ELFDumper::printAttributes() { - W.startLine() << "Attributes not implemented.\n"; -} - namespace { -template <> void ELFDumper::printAttributes() { - const ELFFile *Obj = ObjF->getELFFile(); - if (Obj->getHeader()->e_machine != EM_ARM) { +template void ELFDumper::printAttributes() { + const ELFFile *Obj = ObjF->getELFFile(); + if (!Obj->isLE()) { + W.startLine() << "Attributes not implemented.\n"; + return; + } + + if (Obj->getHeader()->e_machine != EM_ARM && + Obj->getHeader()->e_machine != EM_RISCV) { W.startLine() << "Attributes not implemented.\n"; return; } DictScope BA(W, "BuildAttributes"); - for (const ELFO::Elf_Shdr &Sec : + for (const auto &Sec : unwrapOrError(ObjF->getFileName(), Obj->sections())) { - if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES) + if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES && + Sec.sh_type != ELF::SHT_RISCV_ATTRIBUTES) continue; ArrayRef Contents = unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec)); - if (Contents[0] != ARMBuildAttrs::Format_Version) { + if (Contents[0] != ELFBuildAttrs::Format_Version) { errs() << "unrecognised FormatVersion: 0x" << Twine::utohexstr(Contents[0]) << '\n'; continue; } - W.printHex("FormatVersion", Contents[0]); if (Contents.size() == 1) continue; - ARMAttributeParser(&W).Parse(Contents, true); + if (Obj->getHeader()->e_machine == EM_ARM) { + ARMAttributeParser(&W).Parse(Contents, Obj->isLE()); + } else if (Obj->getHeader()->e_machine == EM_RISCV) { + RISCVAttributeParser(&W).Parse(Contents, Obj->isLE()); + } } } diff --git a/llvm/unittests/Support/ARMAttributeParser.cpp b/llvm/unittests/Support/ARMAttributeParser.cpp --- a/llvm/unittests/Support/ARMAttributeParser.cpp +++ b/llvm/unittests/Support/ARMAttributeParser.cpp @@ -1,5 +1,6 @@ #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/ELFBuildAttributes.h" #include "gtest/gtest.h" #include @@ -41,7 +42,8 @@ } bool testTagString(unsigned Tag, const char *name) { - return ARMBuildAttrs::AttrTypeAsString(Tag).str() == name; + return ELFBuildAttrs::AttrTypeAsString(Tag, ARMBuildAttrs::ARMAttributeTags) + .str() == name; } TEST(CPUArchBuildAttr, testBuildAttr) {