diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -842,7 +842,7 @@ break; ARMAttributeParser attributes; ArrayRef contents = check(this->getObj().getSectionContents(&sec)); - attributes.Parse(contents, /*isLittle*/ config->ekind == ELF32LEKind); + attributes.parse(contents, /*isLittle*/ config->ekind == ELF32LEKind); updateSupportedARMFeatures(attributes); updateARMVFPArgs(attributes, this); diff --git a/lld/test/ELF/Inputs/riscv-attributes1.s b/lld/test/ELF/Inputs/riscv-attributes1.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/riscv-attributes1.s @@ -0,0 +1,13 @@ +// Input that generates an object with a populated SHT_RISCV_ATTRIBUTES section. +.text +.attribute Tag_stack_align, 16 +.attribute arch, "rv32i2p0_m2p0_f2p0_d2p0" +.attribute unaligned_access, 0 +.attribute Tag_priv_spec, 2 +.attribute Tag_priv_spec_minor, 0 +.attribute Tag_priv_spec_revision, 0 + +.globl func +.type func, %function +func: + ret diff --git a/lld/test/ELF/riscv-attributes.s b/lld/test/ELF/riscv-attributes.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/riscv-attributes.s @@ -0,0 +1,44 @@ +# REQUIRES: riscv + +# RUN: llvm-mc -filetype=obj -triple=riscv32 %S/Inputs/riscv-attributes1.s -o %t1.rv32.o +# RUN: llvm-mc -filetype=obj -triple=riscv64 %S/Inputs/riscv-attributes1.s -o %t1.rv64.o +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t2.rv32.o +# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t2.rv64.o +# RUN: ld.lld %t1.rv32.o %t2.rv32.o -o %t.rv32 +# RUN: ld.lld %t1.rv64.o %t2.rv64.o -o %t.rv64 +# RUN: llvm-readobj -A %t.rv32 | FileCheck %s +# RUN: llvm-readobj -A %t.rv64 | FileCheck %s + +# CHECK: Tag: 4 +# CHECK-NEXT: Value: 16 +# CHECK-NEXT: TagName: stack_align +# CHECK-NEXT: Description: Stack alignment is 16-bytes +# CHECK: Tag: 5 +# CHECK-NEXT: TagName: arch +# CHECK-NEXT: Value: rv32i2p0_m2p0_f2p0_d2p0 +# CHECK: Tag: 6 +# CHECK-NEXT: Value: 0 +# CHECK-NEXT: TagName: unaligned_access +# CHECK-NEXT: Description: No unaligned access +# CHECK: Tag: 8 +# CHECK-NEXT: TagName: priv_spec +# CHECK-NEXT: Value: 2 +# CHECK: Tag: 10 +# CHECK-NEXT: TagName: priv_spec_minor +# CHECK-NEXT: Value: 0 +# CHECK: Tag: 12 +# CHECK-NEXT: TagName: priv_spec_revision +# CHECK-NEXT: Value: 0 + +.text +.attribute Tag_stack_align, 16 +.attribute arch, "rv32i2p0_m2p0_f2p0_d2p0" +.attribute unaligned_access, 0 +.attribute Tag_priv_spec, 2 +.attribute Tag_priv_spec_minor, 0 +.attribute Tag_priv_spec_revision, 0 + +.globl _start +_start: + .globl func + call func 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/ELFAttributes.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,22 +365,23 @@ (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(); - Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); + Attributes.parse(Contents, ELFT::TargetEndianness == support::little); break; } } 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,132 +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/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. @@ -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,67 @@ +//===- 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 + +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: + virtual ~ELFAttributeParser() {} + 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/ELFAttributes.h b/llvm/include/llvm/Support/ELFAttributes.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/ELFAttributes.h @@ -0,0 +1,39 @@ +//===-- 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; + +namespace ELFAttrs { + +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 ELFAttrs +} // 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/ELFAttributes.h" + +namespace llvm { +namespace RISCVAttrs { + +extern const 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,47 @@ 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.consume_front("rv32")) + Features.AddFeature("64bit", false); + else if (Arch.consume_front("rv64")) + Features.AddFeature("64bit"); + else + return Features; + + while (!Arch.empty()) { + switch (Arch[0]) { + default: + return 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: 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,9 @@ ECase(SHT_MIPS_DWARF); ECase(SHT_MIPS_ABIFLAGS); break; + case ELF::EM_RISCV: + ECase(SHT_RISCV_ATTRIBUTES); + break; default: // Nothing to do. break; diff --git a/llvm/lib/Support/ARMAttributeParser.cpp b/llvm/lib/Support/ARMAttributeParser.cpp --- a/llvm/lib/Support/ARMAttributeParser.cpp +++ b/llvm/lib/Support/ARMAttributeParser.cpp @@ -1,4 +1,4 @@ -//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===// +//===- ARMAttributeParser.cpp - ARM Attribute Information Printer ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -15,120 +15,53 @@ 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", @@ -138,15 +71,15 @@ "ARM v8.1-M Mainline" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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); + uint64_t Encoded = parseInteger(Data, Offset); StringRef Profile; switch (Encoded) { @@ -158,209 +91,209 @@ case 0: Profile = "None"; break; } - PrintAttribute(Tag, Encoded, Profile); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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", "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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", "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); std::string Description; if (Value < array_lengthof(Strings)) @@ -371,17 +304,17 @@ else Description = "Invalid"; - PrintAttribute(Tag, Value, Description); + 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", "Reserved" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); std::string Description; if (Value < array_lengthof(Strings)) @@ -392,56 +325,56 @@ else Description = "Invalid"; - PrintAttribute(Tag, Value, Description); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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)" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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[] = { @@ -449,13 +382,13 @@ "Best Debugging" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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[] = { @@ -463,22 +396,23 @@ "Best Accuracy" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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); + uint64_t Integer = parseInteger(Data, Offset); + StringRef String = parseString(Data, Offset); if (SW) { DictScope AS(*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, + /*TagPrefix=*/false)); switch (Integer) { case 0: SW->printString("Description", StringRef("No Specific Requirements")); @@ -493,235 +427,108 @@ } } -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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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", "TrustZone + Virtualization Extensions" }; - uint64_t Value = ParseInteger(Data, Offset); + uint64_t Value = parseInteger(Data, Offset); StringRef ValueDesc = (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; - PrintAttribute(Tag, Value, ValueDesc); + 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); - } + uint64_t Value = parseInteger(Data, Offset); + printAttribute(Tag, Value, "Unspecified Tags UNDEFINED"); } -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 @@ -6,97 +6,59 @@ // //===----------------------------------------------------------------------===// -#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" }, +const TagNameMap llvm::ARMBuildAttrs::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" }, + // 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 ""; -} - -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; -} -} -} - 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 + ELFAttributes.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,218 @@ +//===--- 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/LEB128.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::ELFAttrs; + +static const EnumEntry TagNames[] = { + {"Tag_File", ELFAttrs::File}, + {"Tag_Section", ELFAttrs::Section}, + {"Tag_Symbol", ELFAttrs::Symbol}, +}; + +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 = + ELFAttrs::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 = + ELFAttrs::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 = ELFAttrs::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 << " (" + << ELFAttrs::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 ELFAttrs::File: + ScopeName = "FileAttributes"; + break; + case ELFAttrs::Section: + ScopeName = "SectionAttributes"; + IndexName = "Sections"; + parseIndexList(Data, Offset, Indicies); + break; + case ELFAttrs::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"; + } + } +} diff --git a/llvm/lib/Support/ELFAttributes.cpp b/llvm/lib/Support/ELFAttributes.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/ELFAttributes.cpp @@ -0,0 +1,38 @@ +//===-- 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 Map, + bool HasTagPrefix) { + return attrTypeAsString(static_cast(Attr), Map, HasTagPrefix); +} + +StringRef ELFAttrs::attrTypeAsString(AttrType Attr, TagNameMap Map, + bool HasTagPrefix) { + for (auto TI = Map.begin(), TE = Map.end(); TI != TE; ++TI) { + if (TI->Attr == Attr) { + StringRef TagName = TI->TagName; + return HasTagPrefix ? TagName : TagName.drop_front(4); + } + } + return ""; +} + +int ELFAttrs::attrTypeFromString(StringRef Tag, TagNameMap Map) { + bool HasTagPrefix = Tag.startswith("Tag_"); + for (auto TI = Map.begin(), TE = Map.end(); TI != TE; ++TI) { + StringRef TagName = TI->TagName; + if (TagName.drop_front(HasTagPrefix ? 0 : 4) == Tag) + return TI->Attr; + } + return -1; +} 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,73 @@ +//===-- 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; + +#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; +} 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,21 @@ +//===-- 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; + +const TagNameMap llvm::RISCVAttrs::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"}, +}; 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 @@ -11105,7 +11105,7 @@ TagLoc = Parser.getTok().getLoc(); if (Parser.getTok().is(AsmToken::Identifier)) { StringRef Name = Parser.getTok().getIdentifier(); - Tag = ARMBuildAttrs::AttrTypeFromString(Name); + Tag = ELFAttrs::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 = + ELFAttrs::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 = ELFAttrs::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@ " + << ELFAttrs::attrTypeAsString(Attribute, + ARMBuildAttrs::ARMAttributeTags); break; } OS << "\n"; diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- 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])) { @@ -155,6 +157,10 @@ } } + 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 @@ if (IDVal == ".option") return parseDirectiveOption(); + else if (IDVal == ".attribute") + return parseDirectiveAttribute(); return true; } @@ -1677,6 +1685,147 @@ 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 = ELFAttrs::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 = ""; + int64_t IntegerValue = 0; + bool IsIntegerValue = true; + + if (Tag == RISCVAttrs::Arch) + IsIntegerValue = false; + + SMLoc ValueExprLoc = Parser.getTok().getLoc(); + if (IsIntegerValue) { + const MCExpr *ValueExpr; + if (Parser.parseExpression(ValueExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast(ValueExpr); + if (!CE) + return Error(ValueExprLoc, "expected numeric constant"); + IntegerValue = CE->getValue(); + } else { + if (Parser.getTok().isNot(AsmToken::String)) + return Error(Parser.getTok().getLoc(), "expected string constant"); + + StringValue = Parser.getTok().getStringContents(); + Parser.Lex(); + } + + if (Parser.parseToken(AsmToken::EndOfStatement, + "unexpected token in '.attribute' directive")) + return true; + + if (Tag == RISCVAttrs::Arch) { + StringRef Arch = StringValue; + if (Arch.consume_front("rv32")) + clearFeatureBits(RISCV::Feature64Bit, "64bit"); + else if (Arch.consume_front("rv64")) + setFeatureBits(RISCV::Feature64Bit, "64bit"); + else + return Error(ValueExprLoc, "bad arch string " + Arch); + + while (!Arch.empty()) { + if (Arch[0] == 'i') + clearFeatureBits(RISCV::FeatureRV32E, "e"); + else if (Arch[0] == 'e') + setFeatureBits(RISCV::FeatureRV32E, "e"); + else if (Arch[0] == 'g') { + clearFeatureBits(RISCV::FeatureRV32E, "e"); + setFeatureBits(RISCV::FeatureStdExtM, "m"); + setFeatureBits(RISCV::FeatureStdExtA, "a"); + setFeatureBits(RISCV::FeatureStdExtF, "f"); + setFeatureBits(RISCV::FeatureStdExtD, "d"); + } else if (Arch[0] == 'm') + setFeatureBits(RISCV::FeatureStdExtM, "m"); + else if (Arch[0] == 'a') + setFeatureBits(RISCV::FeatureStdExtA, "a"); + else if (Arch[0] == 'f') + setFeatureBits(RISCV::FeatureStdExtF, "f"); + else if (Arch[0] == 'd') { + setFeatureBits(RISCV::FeatureStdExtF, "f"); + setFeatureBits(RISCV::FeatureStdExtD, "d"); + } else if (Arch[0] == 'c') { + setFeatureBits(RISCV::FeatureStdExtC, "c"); + } else + return Error(ValueExprLoc, "bad arch string " + Arch); + + Arch = Arch.drop_front(1); + int major = 0; + int minor = 0; + Arch.consumeInteger(10, major); + Arch.consume_front("p"); + Arch.consumeInteger(10, minor); + if (major != 0 || minor != 0) { + Arch = Arch.drop_until([](char c) { return c == '_' || c == '"'; }); + Arch = Arch.drop_while([](char c) { return c == '_'; }); + } + } + } + + if (IsIntegerValue) + getTargetStreamer().emitAttribute(Tag, IntegerValue); + else { + if (Tag != RISCVAttrs::Arch) { + getTargetStreamer().emitTextAttribute(Tag, StringValue); + } else { + std::string formalArchStr = "rv32"; + if (getFeatureBits(RISCV::Feature64Bit)) + formalArchStr = "rv64"; + if (getFeatureBits(RISCV::FeatureRV32E)) + formalArchStr = (Twine(formalArchStr) + "e1p9").str(); + else + formalArchStr = (Twine(formalArchStr) + "i2p0").str(); + + if (getFeatureBits(RISCV::FeatureStdExtM)) + formalArchStr = (Twine(formalArchStr) + "_m2p0").str(); + if (getFeatureBits(RISCV::FeatureStdExtA)) + formalArchStr = (Twine(formalArchStr) + "_a2p0").str(); + if (getFeatureBits(RISCV::FeatureStdExtF)) + formalArchStr = (Twine(formalArchStr) + "_f2p0").str(); + if (getFeatureBits(RISCV::FeatureStdExtD)) + formalArchStr = (Twine(formalArchStr) + "_d2p0").str(); + if (getFeatureBits(RISCV::FeatureStdExtC)) + formalArchStr = (Twine(formalArchStr) + "_c2p0").str(); + + getTargetStreamer().emitTextAttribute(Tag, formalArchStr); + } + } + + return false; +} + void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) { MCInst CInst; bool Res = compressInst(CInst, Inst, getSTI(), S.getContext()); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.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,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 Contents; + + MCSection *AttributeSection = nullptr; + + AttributeItem *getAttributeItem(unsigned Attribute) { + for (size_t i = 0; i < Contents.size(); ++i) + if (Contents[i].Tag == Attribute) + return &Contents[i]; + return nullptr; + } + + void setAttributeItem(unsigned Attribute, unsigned Value, + bool OverwriteExisting) { + // Look for existing attribute item. + if (AttributeItem *Item = getAttributeItem(Attribute)) { + if (!OverwriteExisting) + return; + Item->Type = AttributeType::Numeric; + Item->IntValue = Value; + return; + } + + // Create new attribute item. + Contents.push_back({AttributeType::Numeric, Attribute, Value, ""}); + } + + void setAttributeItem(unsigned Attribute, StringRef Value, + bool OverwriteExisting) { + // Look for existing attribute item. + if (AttributeItem *Item = getAttributeItem(Attribute)) { + if (!OverwriteExisting) + return; + Item->Type = AttributeType::Text; + Item->StringValue = std::string(Value); + return; + } + + // Create new attribute item. + Contents.push_back({AttributeType::Text, Attribute, 0, std::string(Value)}); + } + + void setAttributeItems(unsigned Attribute, unsigned IntValue, + StringRef StringValue, bool OverwriteExisting) { + // Look for existing attribute item. + if (AttributeItem *Item = getAttributeItem(Attribute)) { + if (!OverwriteExisting) + return; + Item->Type = AttributeType::NumericAndText; + Item->IntValue = IntValue; + Item->StringValue = std::string(StringValue); + return; + } + + // Create new attribute item. + Contents.push_back({AttributeType::NumericAndText, Attribute, IntValue, + std::string(StringValue)}); + } + + void emitAttribute(unsigned Attribute, unsigned Value) override; + void emitTextAttribute(unsigned Attribute, StringRef String) override; + void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, + StringRef StringValue) override; + void finishAttributeSection() override; + size_t calculateContentSize() const; + public: MCELFStreamer &getStreamer(); RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); - virtual void emitDirectiveOptionPush(); - virtual void emitDirectiveOptionPop(); - virtual void emitDirectiveOptionRVC(); - virtual void emitDirectiveOptionNoRVC(); - virtual void emitDirectiveOptionRelax(); - virtual void emitDirectiveOptionNoRelax(); + void emitDirectiveOptionPush() override; + void emitDirectiveOptionPop() override; + void emitDirectiveOptionRVC() override; + void emitDirectiveOptionNoRVC() override; + void emitDirectiveOptionRelax() override; + void emitDirectiveOptionNoRelax() override; }; } #endif diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/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,98 @@ 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(ELFAttrs::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(ELFAttrs::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 (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.emitIntValue(0, 1); // '\0' + break; + case AttributeType::NumericAndText: + 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 (AttributeItem item : Contents) { + switch (item.Type) { + case AttributeType::Hidden: + break; + case AttributeType::Numeric: + Result += getULEB128Size(item.Tag); + Result += getULEB128Size(item.IntValue); + break; + case AttributeType::Text: + Result += getULEB128Size(item.Tag); + Result += item.StringValue.size() + 1; // string + '\0' + break; + case AttributeType::NumericAndText: + Result += getULEB128Size(item.Tag); + Result += getULEB128Size(item.IntValue); + Result += item.StringValue.size() + 1; // string + '\0'; + break; + } + } + return Result; +} diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/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 = "rv32"; + + if (STI.hasFeature(RISCV::Feature64Bit)) + Arch = "rv64"; + + 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,18 @@ 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/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/attributes.ll @@ -0,0 +1,29 @@ +;; 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) nounwind { + %1 = add i32 %a, 1 + ret i32 %1 +} + diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/attribute-arch.s @@ -0,0 +1,38 @@ +## Arch string without version. + +# RUN: llvm-mc %s -triple=riscv32 -filetype=asm | FileCheck %s +# RUN: llvm-mc %s -triple=riscv64 -filetype=asm | FileCheck %s + +.attribute arch, "rv32i" +# CHECK: attribute 5, "rv32i2p0" + +.attribute arch, "rv32i2" +# CHECK: attribute 5, "rv32i2p0" + +.attribute arch, "rv32i2p" +# CHECK: attribute 5, "rv32i2p0" + +.attribute arch, "rv32i2p0" +# CHECK: attribute 5, "rv32i2p0" + +.attribute arch, "rv32i2_m2" +# CHECK: attribute 5, "rv32i2p0_m2p0" + +.attribute arch, "rv32i2_ma" +# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0" + +.attribute arch, "rv32g" +# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0" + +.attribute arch, "rv32imafdc" +# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0" + +.attribute arch, "rv32i2p0_mafdc" +# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0" + +.attribute arch, "rv32ima2p0_fdc" +# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0" + +.attribute arch, "rv32ima2p_fdc" +# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0" + diff --git a/llvm/test/MC/RISCV/attribute-with-insts.s b/llvm/test/MC/RISCV/attribute-with-insts.s new file mode 100644 --- /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-with-option.s b/llvm/test/MC/RISCV/attribute-with-option.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/attribute-with-option.s @@ -0,0 +1,12 @@ +## Different/conflict arch between option and attribute. + +# RUN: llvm-mc %s -triple=riscv32 -mattr=+e -filetype=obj -o - \ +# RUN: | llvm-readobj -A - | FileCheck %s + +.attribute arch, "rv32i2p0" +# Invalid operand for RV32E. +lui x16, 1 + +# CHECK: Tag: 5 +# CHECK-NEXT: TagName: arch +# CHECK-NEXT: Value: rv32i2p0 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,22 @@ +## Test llvm-mc could handle .attribute correctly. + +# RUN: llvm-mc %s -triple=riscv32 -filetype=asm | FileCheck %s +# RUN: llvm-mc %s -triple=riscv64 -filetype=asm | FileCheck %s + +.attribute stack_align, 16 +# CHECK: attribute 4, 16 + +.attribute arch, "rv32i2p0_m2p0_a2p0_c2p0" +# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_c2p0" + +.attribute unaligned_access, 0 +# CHECK: attribute 6, 0 + +.attribute priv_spec, 2 +# CHECK: attribute 8, 2 + +.attribute priv_spec_minor, 0 +# CHECK: attribute 10, 0 + +.attribute priv_spec_revision, 0 +# CHECK: attribute 12, 0 diff --git a/llvm/test/MC/RISCV/invalid-attribute.s b/llvm/test/MC/RISCV/invalid-attribute.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/invalid-attribute.s @@ -0,0 +1,31 @@ +## Negative tests +## - Feed integer value to string type attribute +## - Feed string value to integer type attribute +## - Invalid arch string + +# RUN: not llvm-mc %s -triple=riscv32 -filetype=asm 2>&1 | FileCheck %s +# RUN: not llvm-mc %s -triple=riscv64 -filetype=asm 2>&1 | FileCheck %s + +.attribute arch, "foo" +# CHECK: [[@LINE-1]]:18: error: bad arch string foo + +.attribute arch, "rv32i2p0_y2p0" +# CHECK: [[@LINE-1]]:18: error: bad arch string y2p0 + +.attribute stack_align, "16" +# CHECK: [[@LINE-1]]:25: error: expected numeric constant + +.attribute unaligned_access, "0" +# CHECK: [[@LINE-1]]:30: error: expected numeric constant + +.attribute priv_spec, "2" +# CHECK: [[@LINE-1]]:23: error: expected numeric constant + +.attribute priv_spec_minor, "0" +# CHECK: [[@LINE-1]]:29: error: expected numeric constant + +.attribute priv_spec_revision, "0" +# CHECK: [[@LINE-1]]:32: error: expected numeric constant + +.attribute arch, 30 +# CHECK: [[@LINE-1]]:18: error: expected string constant diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.s b/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.s @@ -0,0 +1,44 @@ +## Test llvm-readobj & llvm-readelf to decode RISCV attributes correctly. + +# RUN: llvm-mc -triple riscv32 -filetype obj -o %t.rv32.o %s +# RUN: llvm-mc -triple riscv64 -filetype obj -o %t.rv64.o %s +# RUN: llvm-readobj --arch-specific %t.rv32.o \ +# RUN: | FileCheck %s --check-prefix=CHECK-OBJ +# RUN: llvm-readelf -A %t.rv32.o \ +# RUN: | FileCheck %s --check-prefix=CHECK-OBJ +# RUN: llvm-readobj --arch-specific %t.rv64.o \ +# RUN: | FileCheck %s --check-prefix=CHECK-OBJ +# RUN: llvm-readelf -A %t.rv64.o \ +# RUN: | FileCheck %s --check-prefix=CHECK-OBJ + +.attribute Tag_stack_align, 16 +# CHECK-OBJ: Tag: 4 +# CHECK-OBJ-NEXT: Value: 16 +# CHECK-OBJ-NEXT: TagName: stack_align +# CHECK-OBJ-NEXT: Description: Stack alignment is 16-bytes + +.attribute Tag_arch, "rv32i2p0_m2p0_a2p0_c2p0" +# CHECK-OBJ: Tag: 5 +# CHECK-OBJ-NEXT: TagName: arch +# CHECK-OBJ-NEXT: Value: rv32i2p0_m2p0_a2p0_c2p0 + +.attribute Tag_unaligned_access, 0 +# CHECK-OBJ: Tag: 6 +# CHECK-OBJ-NEXT: Value: 0 +# CHECK-OBJ-NEXT: TagName: unaligned_access +# CHECK-OBJ-NEXT: Description: No unaligned access + +.attribute Tag_priv_spec, 2 +# CHECK-OBJ: Tag: 8 +# CHECK-OBJ-NEXT: TagName: priv_spec +# CHECK-OBJ-NEXT: Value: 2 + +.attribute Tag_priv_spec_minor, 0 +# CHECK-OBJ: Tag: 10 +# CHECK-OBJ-NEXT: TagName: priv_spec_minor +# CHECK-OBJ-NEXT: Value: 0 + +.attribute Tag_priv_spec_revision, 0 +# CHECK-OBJ: Tag: 12 +# CHECK-OBJ-NEXT: TagName: priv_spec_revision +# CHECK-OBJ-NEXT: Value: 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/test/tools/llvm-readobj/ELF/RISCV/section-types.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/section-types.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/section-types.test @@ -0,0 +1,23 @@ +## Show that all RISCV specific section types are properly printed for both +## LLVM and GNU styles. + +# RUN: yaml2obj %s -o %t-riscv.o +# RUN: llvm-readobj --section-headers %t-riscv.o | FileCheck %s --check-prefix=LLVM +# RUN: llvm-readelf --section-headers %t-riscv.o | FileCheck %s --check-prefix=GNU + +# LLVM: Name: .riscv.attributes (1) +# LLVM-NEXT: Type: SHT_RISCV_ATTRIBUTES (0x70000003) + +# GNU: [ 0] NULL +# GNU-NEXT: [ 1] .riscv.attributes RISCV_ATTRIBUTES + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES + Content: 4132000000726973637600012800000004100572763332693270305F6D3270305F613270305F6332703000060008020A000C00 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 @@ -2637,6 +2639,7 @@ const ELFFile *Obj = ObjF->getELFFile(); switch (Obj->getHeader()->e_machine) { case EM_ARM: + case EM_RISCV: printAttributes(); break; case EM_MIPS: { @@ -2657,38 +2660,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] != ELFAttrs::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()); + } } } @@ -3517,6 +3526,11 @@ return "MIPS_ABIFLAGS"; } break; + case EM_RISCV: + switch (Type) { + case SHT_RISCV_ATTRIBUTES: + return "RISCV_ATTRIBUTES"; + } } switch (Type) { case SHT_NULL: 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/ELFAttributes.h" #include "gtest/gtest.h" #include @@ -34,14 +35,15 @@ reinterpret_cast(OS.str().c_str()), OS.str().size()); ARMAttributeParser Parser; - Parser.Parse(Bytes, true); + Parser.parse(Bytes, true); return (Parser.hasAttribute(ExpectedTag) && Parser.getAttributeValue(ExpectedTag) == ExpectedValue); } bool testTagString(unsigned Tag, const char *name) { - return ARMBuildAttrs::AttrTypeAsString(Tag).str() == name; + return ELFAttrs::attrTypeAsString(Tag, ARMBuildAttrs::ARMAttributeTags) + .str() == name; } TEST(CPUArchBuildAttr, testBuildAttr) {