From 6968dd2f4397979534317906788f8a0e5b3c8655 Mon Sep 17 00:00:00 2001 From: Sam Parker Date: Fri, 13 Jan 2017 11:04:21 +0000 Subject: [PATCH] [ARM] Enable objdump to construct triple for ARM Now that The ARMAttributeParser has been moved into the library, it has been modified so that it can parse the attributes without printing them and stores them in a map. ELFObjectFile now queries the attributes to fill out the architecture details of a provided triple for 'arm' and 'thumb' targets. llvm-objdump uses this new functionality. Differential Revision: https://reviews.llvm.org/D28281 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291898 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/ELFObjectFile.h | 25 ++ include/llvm/Object/ObjectFile.h | 8 + include/llvm/Support/ARMAttributeParser.h | 20 +- include/llvm/Support/ARMBuildAttributes.h | 14 +- lib/Object/ELFObjectFile.cpp | 65 ++++ lib/Support/ARMAttributeParser.cpp | 121 +++--- lib/Target/ARM/ARMAsmPrinter.cpp | 2 +- test/tools/llvm-objdump/ARM/v5t-subarch.s | 10 + test/tools/llvm-objdump/ARM/v5te-subarch.s | 10 + test/tools/llvm-objdump/ARM/v5tej-subarch.s | 7 + test/tools/llvm-objdump/ARM/v6-subarch.s | 9 + test/tools/llvm-objdump/ARM/v6k-subarch.s | 9 + test/tools/llvm-objdump/ARM/v6m-subarch.s | 9 + test/tools/llvm-objdump/ARM/v6t2-subarch.s | 10 + test/tools/llvm-objdump/ARM/v7m-subarch.s | 10 + tools/llvm-objdump/llvm-objdump.cpp | 21 +- tools/llvm-readobj/ELFDumper.cpp | 2 +- unittests/Support/ARMAttributeParser.cpp | 384 ++++++++++++++++++++ unittests/Support/CMakeLists.txt | 1 + 19 files changed, 681 insertions(+), 56 deletions(-) create mode 100644 test/tools/llvm-objdump/ARM/v5t-subarch.s create mode 100644 test/tools/llvm-objdump/ARM/v5te-subarch.s create mode 100644 test/tools/llvm-objdump/ARM/v5tej-subarch.s create mode 100644 test/tools/llvm-objdump/ARM/v6-subarch.s create mode 100644 test/tools/llvm-objdump/ARM/v6k-subarch.s create mode 100644 test/tools/llvm-objdump/ARM/v6m-subarch.s create mode 100644 test/tools/llvm-objdump/ARM/v6t2-subarch.s create mode 100644 test/tools/llvm-objdump/ARM/v7m-subarch.s create mode 100644 unittests/Support/ARMAttributeParser.cpp diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index 69987d433e2d4..452b45835a6f5 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -26,6 +26,7 @@ #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" @@ -72,6 +73,8 @@ class ELFObjectFileBase : public ObjectFile { static inline bool classof(const Binary *v) { return v->isELF(); } SubtargetFeatures getFeatures() const override; + + void setARMSubArch(Triple &TheTriple) const override; }; class ELFSectionRef : public SectionRef { @@ -356,6 +359,28 @@ template class ELFObjectFile : public ELFObjectFileBase { return std::error_code(); } + std::error_code getBuildAttributes(ARMAttributeParser &Attributes) const override { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return errorToErrorCode(SectionsOrErr.takeError()); + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) { + auto ErrorOrContents = EF.getSectionContents(&Sec); + if (!ErrorOrContents) + return errorToErrorCode(ErrorOrContents.takeError()); + + auto Contents = ErrorOrContents.get(); + if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1) + return std::error_code(); + + Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); + break; + } + } + return std::error_code(); + } + const ELFFile *getELFFile() const { return &EF; } bool isDyldType() const { return isDyldELFObject; } diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 13d5845c3a717..b689dc2ac03ac 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -24,6 +24,8 @@ #include namespace llvm { +class ARMAttributeParser; + namespace object { class ObjectFile; @@ -265,6 +267,7 @@ class ObjectFile : public SymbolicFile { virtual StringRef getFileFormatName() const = 0; virtual /* Triple::ArchType */ unsigned getArch() const = 0; virtual SubtargetFeatures getFeatures() const = 0; + virtual void setARMSubArch(Triple &TheTriple) const { } /// Returns platform-specific object flags, if any. virtual std::error_code getPlatformFlags(unsigned &Result) const { @@ -272,6 +275,11 @@ class ObjectFile : public SymbolicFile { return object_error::invalid_file_type; } + virtual std::error_code + getBuildAttributes(ARMAttributeParser &Attributes) const { + return std::error_code(); + } + /// True if this is a relocatable object (.o/.obj). virtual bool isRelocatableObject() const = 0; diff --git a/include/llvm/Support/ARMAttributeParser.h b/include/llvm/Support/ARMAttributeParser.h index 48c6c8e912ef5..919f39721f866 100644 --- a/include/llvm/Support/ARMAttributeParser.h +++ b/include/llvm/Support/ARMAttributeParser.h @@ -13,11 +13,15 @@ #include "ARMBuildAttributes.h" #include "ScopedPrinter.h" +#include + namespace llvm { class StringRef; class ARMAttributeParser { - ScopedPrinter &SW; + ScopedPrinter *SW; + + std::map Attributes; struct DisplayHandler { ARMBuildAttrs::AttrType Attribute; @@ -115,9 +119,19 @@ class ARMAttributeParser { SmallVectorImpl &IndexList); void ParseSubsection(const uint8_t *Data, uint32_t Length); public: - ARMAttributeParser(ScopedPrinter &SW) : SW(SW) {} + ARMAttributeParser(ScopedPrinter *SW) : SW(SW) {} + + ARMAttributeParser() : SW(nullptr) { } + + void Parse(ArrayRef Section, bool isLittle); + + bool hasAttribute(unsigned Tag) const { + return Attributes.count(Tag); + } - void Parse(ArrayRef Section); + unsigned getAttributeValue(unsigned Tag) const { + return Attributes.find(Tag)->second; + } }; } diff --git a/include/llvm/Support/ARMBuildAttributes.h b/include/llvm/Support/ARMBuildAttributes.h index e25445790b0c8..6c83e447cb245 100644 --- a/include/llvm/Support/ARMBuildAttributes.h +++ b/include/llvm/Support/ARMBuildAttributes.h @@ -176,14 +176,25 @@ enum { WCharWidth2Bytes = 2, // sizeof(wchar_t) == 2 WCharWidth4Bytes = 4, // sizeof(wchar_t) == 4 + // Tag_ABI_align_needed, (=24), uleb128 + Align8Byte = 1, + Align4Byte = 2, + AlignReserved = 3, + + // Tag_ABI_align_needed, (=25), uleb128 + AlignNotPreserved = 0, + AlignPreserve8Byte = 1, + AlignPreserveAll = 2, + // Tag_ABI_FP_denormal, (=20), uleb128 PositiveZero = 0, IEEEDenormals = 1, PreserveFPSign = 2, // sign when flushed-to-zero is preserved // Tag_ABI_FP_number_model, (=23), uleb128 + AllowIEEENormal = 1, AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI]) - AllowIEE754 = 3, // this code to use all the IEEE 754-defined FP encodings + AllowIEEE754 = 3, // this code to use all the IEEE 754-defined FP encodings // Tag_ABI_enum_size, (=26), uleb128 EnumProhibited = 0, // The user prohibited the use of enums when building @@ -208,6 +219,7 @@ enum { // Tag_FP_16bit_format, (=38), uleb128 FP16FormatIEEE = 1, + FP16VFP3 = 2, // Tag_MPextension_use, (=42), uleb128 AllowMP = 1, // Allow use of MP extensions diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp index 4bd69e34e3c3b..d33da47d6cbbe 100644 --- a/lib/Object/ELFObjectFile.cpp +++ b/lib/Object/ELFObjectFile.cpp @@ -122,4 +122,69 @@ SubtargetFeatures ELFObjectFileBase::getFeatures() const { } } +// FIXME Encode from a tablegen description or target parser. +void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { + if (TheTriple.getSubArch() != Triple::NoSubArch) + return; + + ARMAttributeParser Attributes; + std::error_code EC = getBuildAttributes(Attributes); + if (EC) + return; + + std::string Triple; + // Default to ARM, but use the triple if it's been set. + if (TheTriple.getArch() == Triple::thumb || + TheTriple.getArch() == Triple::thumbeb) + Triple = "thumb"; + else + Triple = "arm"; + + switch(Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch)) { + case ARMBuildAttrs::v4: + Triple += "v4"; + break; + case ARMBuildAttrs::v4T: + Triple += "v4t"; + break; + case ARMBuildAttrs::v5T: + Triple += "v5t"; + break; + case ARMBuildAttrs::v5TE: + Triple += "v5te"; + break; + case ARMBuildAttrs::v5TEJ: + Triple += "v5tej"; + break; + case ARMBuildAttrs::v6: + Triple += "v6"; + break; + case ARMBuildAttrs::v6KZ: + Triple += "v6kz"; + break; + case ARMBuildAttrs::v6T2: + Triple += "v6t2"; + break; + case ARMBuildAttrs::v6K: + Triple += "v6k"; + break; + case ARMBuildAttrs::v7: + Triple += "v7"; + break; + case ARMBuildAttrs::v6_M: + Triple += "v6m"; + break; + case ARMBuildAttrs::v6S_M: + Triple += "v6sm"; + break; + case ARMBuildAttrs::v7E_M: + Triple += "v7em"; + break; + } + if (!isLittleEndian()) + Triple += "eb"; + + TheTriple.setArchName(Triple); +} + } // end namespace llvm diff --git a/lib/Support/ARMAttributeParser.cpp b/lib/Support/ARMAttributeParser.cpp index 792510e6b8496..5d9b2306b9aed 100644 --- a/lib/Support/ARMAttributeParser.cpp +++ b/lib/Support/ARMAttributeParser.cpp @@ -89,32 +89,43 @@ StringRef ARMAttributeParser::ParseString(const uint8_t *Data, void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - SW.printNumber(ARMBuildAttrs::AttrTypeAsString(Tag), - ParseInteger(Data, 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); - - DictScope AS(SW, "Attribute"); - SW.printNumber("Tag", Tag); - if (!TagName.empty()) - SW.printString("TagName", TagName); - SW.printString("Value", ParseString(Data, Offset)); + 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) { - 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); + 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, @@ -449,20 +460,22 @@ void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data, uint64_t Integer = ParseInteger(Data, Offset); StringRef String = ParseString(Data, Offset); - DictScope AS(SW, "Attribute"); - SW.printNumber("Tag", Tag); - SW.startLine() << "Value: " << Integer << ", " << String << '\n'; - SW.printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false)); - switch (Integer) { - case 0: - SW.printString("Description", StringRef("No Specific Requirements")); - break; - case 1: - SW.printString("Description", StringRef("AEABI Conformant")); - break; - default: - SW.printString("Description", StringRef("AEABI Non-Conformant")); - break; + if (SW) { + DictScope AS(*SW, "Attribute"); + SW->printNumber("Tag", Tag); + SW->startLine() << "Value: " << Integer << ", " << String << '\n'; + SW->printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false)); + switch (Integer) { + case 0: + SW->printString("Description", StringRef("No Specific Requirements")); + break; + case 1: + SW->printString("Description", StringRef("AEABI Conformant")); + break; + default: + SW->printString("Description", StringRef("AEABI Non-Conformant")); + break; + } } } @@ -604,27 +617,33 @@ void ARMAttributeParser::ParseAttributeList(const uint8_t *Data, void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) { uint32_t Offset = sizeof(uint32_t); /* SectionLength */ - SW.printNumber("SectionLength", Length); - const char *VendorName = reinterpret_cast(Data + Offset); size_t VendorNameLength = std::strlen(VendorName); - SW.printString("Vendor", StringRef(VendorName, VendorNameLength)); Offset = Offset + VendorNameLength + 1; - if (StringRef(VendorName, VendorNameLength).lower() != "aeabi") + 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]; - SW.printEnum("Tag", Tag, makeArrayRef(TagNames)); Offset = Offset + sizeof(Tag); uint32_t Size = *reinterpret_cast(Data + Offset); - SW.printNumber("Size", Size); 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; @@ -651,31 +670,37 @@ void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) { return; } - DictScope ASS(SW, ScopeName); - - if (!Indicies.empty()) - SW.printList(IndexName, Indicies); + if (SW) { + DictScope ASS(*SW, ScopeName); + if (!Indicies.empty()) + SW->printList(IndexName, Indicies); + } ParseAttributeList(Data, Offset, Length); } } -void ARMAttributeParser::Parse(ArrayRef Section) { +void ARMAttributeParser::Parse(ArrayRef Section, bool isLittle) { size_t Offset = 1; unsigned SectionNumber = 0; while (Offset < Section.size()) { - uint32_t SectionLength = - *reinterpret_cast(Section.data() + Offset); + uint32_t SectionLength = isLittle ? + *reinterpret_cast(Section.data() + Offset) : + *reinterpret_cast(Section.data() + Offset); - SW.startLine() << "Section " << ++SectionNumber << " {\n"; - SW.indent(); + if (SW) { + SW->startLine() << "Section " << ++SectionNumber << " {\n"; + SW->indent(); + } ParseSubsection(Section.data() + Offset, SectionLength); Offset = Offset + SectionLength; - SW.unindent(); - SW.startLine() << "}\n"; + if (SW) { + SW->unindent(); + SW->startLine() << "}\n"; + } } } } diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 8ec9cb02813cd..f852805408c19 100644 --- a/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -841,7 +841,7 @@ void ARMAsmPrinter::emitAttributes() { ARMBuildAttrs::Allowed); else ATS.emitAttribute(ARMBuildAttrs::ABI_FP_number_model, - ARMBuildAttrs::AllowIEE754); + ARMBuildAttrs::AllowIEEE754); if (STI.allowsUnalignedMem()) ATS.emitAttribute(ARMBuildAttrs::CPU_unaligned_access, diff --git a/test/tools/llvm-objdump/ARM/v5t-subarch.s b/test/tools/llvm-objdump/ARM/v5t-subarch.s new file mode 100644 index 0000000000000..c9ce2cf6cebd6 --- /dev/null +++ b/test/tools/llvm-objdump/ARM/v5t-subarch.s @@ -0,0 +1,10 @@ +@ RUN: llvm-mc < %s -triple armv5t-elf -filetype=obj | llvm-objdump -triple=arm -d - | FileCheck %s + +.arch armv5t + +clz: +clz r0, r1 + +@ CHECK-LABEL: clz +@ CHECK: 11 0f 6f e1 + diff --git a/test/tools/llvm-objdump/ARM/v5te-subarch.s b/test/tools/llvm-objdump/ARM/v5te-subarch.s new file mode 100644 index 0000000000000..87e8548fb0144 --- /dev/null +++ b/test/tools/llvm-objdump/ARM/v5te-subarch.s @@ -0,0 +1,10 @@ +@ RUN: llvm-mc < %s -triple armv5te-elf -filetype=obj | llvm-objdump -triple=arm -d - | FileCheck %s + +.arch armv5te + +strd: +strd r0, r1, [r2, +r3] + +@ CHECK-LABEL strd +@ CHECK: f3 00 82 e1 strd r0, r1, [r2, r3] + diff --git a/test/tools/llvm-objdump/ARM/v5tej-subarch.s b/test/tools/llvm-objdump/ARM/v5tej-subarch.s new file mode 100644 index 0000000000000..42dc87389a341 --- /dev/null +++ b/test/tools/llvm-objdump/ARM/v5tej-subarch.s @@ -0,0 +1,7 @@ +@ RUN: llvm-mc < %s -triple armv5tej-elf -filetype=obj | llvm-objdump -triple=arm -d - | FileCheck %s + +bxj: +bxj r0 + +@ CHECK-LABEL: bxj +@ CHECK: 20 ff 2f e1 bxj r0 diff --git a/test/tools/llvm-objdump/ARM/v6-subarch.s b/test/tools/llvm-objdump/ARM/v6-subarch.s new file mode 100644 index 0000000000000..c70761e7c8c52 --- /dev/null +++ b/test/tools/llvm-objdump/ARM/v6-subarch.s @@ -0,0 +1,9 @@ +@ RUN: llvm-mc < %s -triple armv6-elf -filetype=obj | llvm-objdump -triple=arm -d - | FileCheck %s + +.arch armv6 + +umaal: +umaal r0, r1, r2, r3 + +@ CHECK-LABEL:umaal +@ CHECK: 92 03 41 e0 umaal r0, r1, r2, r3 diff --git a/test/tools/llvm-objdump/ARM/v6k-subarch.s b/test/tools/llvm-objdump/ARM/v6k-subarch.s new file mode 100644 index 0000000000000..8df4ce5e25766 --- /dev/null +++ b/test/tools/llvm-objdump/ARM/v6k-subarch.s @@ -0,0 +1,9 @@ +@ RUN: llvm-mc < %s -triple armv6k-elf -filetype=obj | llvm-objdump -triple=arm -d - | FileCheck %s + +.arch armv6k + +clrex: +clrex + +@ CHECK-LABEL: clrex +@ CHECK: 1f f0 7f f5 clrex diff --git a/test/tools/llvm-objdump/ARM/v6m-subarch.s b/test/tools/llvm-objdump/ARM/v6m-subarch.s new file mode 100644 index 0000000000000..f4c56989c17ec --- /dev/null +++ b/test/tools/llvm-objdump/ARM/v6m-subarch.s @@ -0,0 +1,9 @@ +@ RUN: llvm-mc < %s -triple armv6m-elf -filetype=obj | llvm-objdump -triple=thumb -d - | FileCheck %s + +.arch armv6m + +dmb: +dmb + +@ CHECK-LABEL: dmb +@ CHECK: bf f3 5f 8f dmb sy diff --git a/test/tools/llvm-objdump/ARM/v6t2-subarch.s b/test/tools/llvm-objdump/ARM/v6t2-subarch.s new file mode 100644 index 0000000000000..36e134342972c --- /dev/null +++ b/test/tools/llvm-objdump/ARM/v6t2-subarch.s @@ -0,0 +1,10 @@ +@ RUN: llvm-mc < %s -triple armv6t2-elf -filetype=obj | llvm-objdump -triple=thumb -d - | FileCheck %s + +.arch armv6t2 + +.thumb +umaalt2: +umaal r0, r1, r2, r3 + +@ CHECK-LABEL: umaalt2 +@ CHECK: e2 fb 63 01 umaal r0, r1, r2, r3 diff --git a/test/tools/llvm-objdump/ARM/v7m-subarch.s b/test/tools/llvm-objdump/ARM/v7m-subarch.s new file mode 100644 index 0000000000000..8f6ff57e0ff30 --- /dev/null +++ b/test/tools/llvm-objdump/ARM/v7m-subarch.s @@ -0,0 +1,10 @@ +@ RUN: llvm-mc < %s -triple armv7m-elf -filetype=obj | llvm-objdump -triple=thumb -d - | FileCheck %s + +.arch armv7m + +umlal: +umlal r0, r1, r2, r3 + +@ CHECK-LABEL: umlal +@ CHECK: e2 fb 03 01 umlal r0, r1, r2, r3 + diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 8373f0ce3f1ef..6b8a43ea1bdd3 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -357,7 +357,16 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) { llvm::Triple TheTriple("unknown-unknown-unknown"); if (TripleName.empty()) { if (Obj) { - TheTriple.setArch(Triple::ArchType(Obj->getArch())); + auto Arch = Obj->getArch(); + TheTriple.setArch(Triple::ArchType(Arch)); + + // For ARM targets, try to use the build attributes to build determine + // the build target. Target features are also added, but later during + // disassembly. + if (Arch == Triple::arm || Arch == Triple::armeb) { + Obj->setARMSubArch(TheTriple); + } + // TheTriple defaults to ELF, and COFF doesn't have an environment: // the best we can do here is indicate that it is mach-o. if (Obj->isMachO()) @@ -369,8 +378,16 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) { TheTriple.setTriple("thumbv7-windows"); } } - } else + } else { TheTriple.setTriple(Triple::normalize(TripleName)); + // Use the triple, but also try to combine with ARM build attributes. + if (Obj) { + auto Arch = Obj->getArch(); + if (Arch == Triple::arm || Arch == Triple::armeb) { + Obj->setARMSubArch(TheTriple); + } + } + } // Get the target specific parser. std::string Error; diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 54ef7fbdd30cf..0a3cd7a4f62e4 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -1892,7 +1892,7 @@ template <> void ELFDumper>::printAttributes() { if (Contents.size() == 1) continue; - ARMAttributeParser(W).Parse(Contents); + ARMAttributeParser(&W).Parse(Contents, true); } } } diff --git a/unittests/Support/ARMAttributeParser.cpp b/unittests/Support/ARMAttributeParser.cpp new file mode 100644 index 0000000000000..82cbcd1fc153d --- /dev/null +++ b/unittests/Support/ARMAttributeParser.cpp @@ -0,0 +1,384 @@ +#include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/ARMAttributeParser.h" +#include "llvm/Support/LEB128.h" +#include "gtest/gtest.h" +#include + +using namespace llvm; + +struct AttributeSection { + unsigned Tag; + unsigned Value; + + AttributeSection(unsigned tag, unsigned value) : Tag(tag), Value(value) { } + + void write(raw_ostream &OS) { + OS.flush(); + // length = length + "aeabi\0" + TagFile + ByteSize + Tag + Value; + // length = 17 bytes + + OS << 'A' << (uint8_t)17 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0; + OS << "aeabi" << '\0'; + OS << (uint8_t)1 << (uint8_t)7 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0; + OS << (uint8_t)Tag << (uint8_t)Value; + + } +}; + +bool testBuildAttr(unsigned Tag, unsigned Value, + unsigned ExpectedTag, unsigned ExpectedValue) { + std::string buffer; + raw_string_ostream OS(buffer); + AttributeSection Section(Tag, Value); + Section.write(OS); + ArrayRef Bytes((uint8_t*)OS.str().c_str(), OS.str().size()); + + ARMAttributeParser Parser; + 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; +} + +TEST(CPUArchBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(6, "Tag_CPU_arch")); + + EXPECT_TRUE(testBuildAttr(6, 0, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::Pre_v4)); + EXPECT_TRUE(testBuildAttr(6, 1, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v4)); + EXPECT_TRUE(testBuildAttr(6, 2, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v4T)); + EXPECT_TRUE(testBuildAttr(6, 3, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v5T)); + EXPECT_TRUE(testBuildAttr(6, 4, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v5TE)); + EXPECT_TRUE(testBuildAttr(6, 5, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v5TEJ)); + EXPECT_TRUE(testBuildAttr(6, 6, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6)); + EXPECT_TRUE(testBuildAttr(6, 7, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6KZ)); + EXPECT_TRUE(testBuildAttr(6, 8, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6T2)); + EXPECT_TRUE(testBuildAttr(6, 9, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6K)); + EXPECT_TRUE(testBuildAttr(6, 10, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v7)); + EXPECT_TRUE(testBuildAttr(6, 11, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6_M)); + EXPECT_TRUE(testBuildAttr(6, 12, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6S_M)); + EXPECT_TRUE(testBuildAttr(6, 13, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v7E_M)); +} + +TEST(CPUArchProfileBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(7, "Tag_CPU_arch_profile")); + EXPECT_TRUE(testBuildAttr(7, 'A', ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::ApplicationProfile)); + EXPECT_TRUE(testBuildAttr(7, 'R', ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::RealTimeProfile)); + EXPECT_TRUE(testBuildAttr(7, 'M', ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::MicroControllerProfile)); + EXPECT_TRUE(testBuildAttr(7, 'S', ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::SystemProfile)); +} + +TEST(ARMISABuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(8, "Tag_ARM_ISA_use")); + EXPECT_TRUE(testBuildAttr(8, 0, ARMBuildAttrs::ARM_ISA_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(8, 1, ARMBuildAttrs::ARM_ISA_use, + ARMBuildAttrs::Allowed)); +} + +TEST(ThumbISABuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(9, "Tag_THUMB_ISA_use")); + EXPECT_TRUE(testBuildAttr(9, 0, ARMBuildAttrs::THUMB_ISA_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(9, 1, ARMBuildAttrs::THUMB_ISA_use, + ARMBuildAttrs::Allowed)); +} + +TEST(FPArchBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(10, "Tag_FP_arch")); + EXPECT_TRUE(testBuildAttr(10, 0, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(10, 1, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::Allowed)); + EXPECT_TRUE(testBuildAttr(10, 2, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv2)); + EXPECT_TRUE(testBuildAttr(10, 3, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv3A)); + EXPECT_TRUE(testBuildAttr(10, 4, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv3B)); + EXPECT_TRUE(testBuildAttr(10, 5, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv4A)); + EXPECT_TRUE(testBuildAttr(10, 6, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv4B)); + EXPECT_TRUE(testBuildAttr(10, 7, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPARMv8A)); + EXPECT_TRUE(testBuildAttr(10, 8, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPARMv8B)); +} + +TEST(WMMXBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(11, "Tag_WMMX_arch")); + EXPECT_TRUE(testBuildAttr(11, 0, ARMBuildAttrs::WMMX_arch, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(11, 1, ARMBuildAttrs::WMMX_arch, + ARMBuildAttrs::AllowWMMXv1)); + EXPECT_TRUE(testBuildAttr(11, 2, ARMBuildAttrs::WMMX_arch, + ARMBuildAttrs::AllowWMMXv2)); +} + +TEST(SIMDBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(12, "Tag_Advanced_SIMD_arch")); + EXPECT_TRUE(testBuildAttr(12, 0, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(12, 1, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeon)); + EXPECT_TRUE(testBuildAttr(12, 2, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeon2)); + EXPECT_TRUE(testBuildAttr(12, 3, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeonARMv8)); + EXPECT_TRUE(testBuildAttr(12, 4, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeonARMv8_1a)); +} + +TEST(FPHPBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(36, "Tag_FP_HP_extension")); + EXPECT_TRUE(testBuildAttr(36, 0, ARMBuildAttrs::FP_HP_extension, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(36, 1, ARMBuildAttrs::FP_HP_extension, + ARMBuildAttrs::AllowHPFP)); +} + +TEST(CPUAlignBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(34, "Tag_CPU_unaligned_access")); + EXPECT_TRUE(testBuildAttr(34, 0, ARMBuildAttrs::CPU_unaligned_access, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(34, 1, ARMBuildAttrs::CPU_unaligned_access, + ARMBuildAttrs::Allowed)); +} + +TEST(T2EEBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(66, "Tag_T2EE_use")); + EXPECT_TRUE(testBuildAttr(66, 0, ARMBuildAttrs::T2EE_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(66, 1, ARMBuildAttrs::T2EE_use, + ARMBuildAttrs::Allowed)); +} + +TEST(VirtualizationBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(68, "Tag_Virtualization_use")); + EXPECT_TRUE(testBuildAttr(68, 0, ARMBuildAttrs::Virtualization_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(68, 1, ARMBuildAttrs::Virtualization_use, + ARMBuildAttrs::AllowTZ)); + EXPECT_TRUE(testBuildAttr(68, 2, ARMBuildAttrs::Virtualization_use, + ARMBuildAttrs::AllowVirtualization)); + EXPECT_TRUE(testBuildAttr(68, 3, ARMBuildAttrs::Virtualization_use, + ARMBuildAttrs::AllowTZVirtualization)); +} + +TEST(MPBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(42, "Tag_MPextension_use")); + EXPECT_TRUE(testBuildAttr(42, 0, ARMBuildAttrs::MPextension_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(42, 1, ARMBuildAttrs::MPextension_use, + ARMBuildAttrs::AllowMP)); +} + +TEST(DivBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(44, "Tag_DIV_use")); + EXPECT_TRUE(testBuildAttr(44, 0, ARMBuildAttrs::DIV_use, + ARMBuildAttrs::AllowDIVIfExists)); + EXPECT_TRUE(testBuildAttr(44, 1, ARMBuildAttrs::DIV_use, + ARMBuildAttrs::DisallowDIV)); + EXPECT_TRUE(testBuildAttr(44, 2, ARMBuildAttrs::DIV_use, + ARMBuildAttrs::AllowDIVExt)); +} + +TEST(PCS_ConfigBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(13, "Tag_PCS_config")); + EXPECT_TRUE(testBuildAttr(13, 0, ARMBuildAttrs::PCS_config, 0)); + EXPECT_TRUE(testBuildAttr(13, 1, ARMBuildAttrs::PCS_config, 1)); + EXPECT_TRUE(testBuildAttr(13, 2, ARMBuildAttrs::PCS_config, 2)); + EXPECT_TRUE(testBuildAttr(13, 3, ARMBuildAttrs::PCS_config, 3)); + EXPECT_TRUE(testBuildAttr(13, 4, ARMBuildAttrs::PCS_config, 4)); + EXPECT_TRUE(testBuildAttr(13, 5, ARMBuildAttrs::PCS_config, 5)); + EXPECT_TRUE(testBuildAttr(13, 6, ARMBuildAttrs::PCS_config, 6)); + EXPECT_TRUE(testBuildAttr(13, 7, ARMBuildAttrs::PCS_config, 7)); +} + +TEST(PCS_R9BuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(14, "Tag_ABI_PCS_R9_use")); + EXPECT_TRUE(testBuildAttr(14, 0, ARMBuildAttrs::ABI_PCS_R9_use, + ARMBuildAttrs::R9IsGPR)); + EXPECT_TRUE(testBuildAttr(14, 1, ARMBuildAttrs::ABI_PCS_R9_use, + ARMBuildAttrs::R9IsSB)); + EXPECT_TRUE(testBuildAttr(14, 2, ARMBuildAttrs::ABI_PCS_R9_use, + ARMBuildAttrs::R9IsTLSPointer)); + EXPECT_TRUE(testBuildAttr(14, 3, ARMBuildAttrs::ABI_PCS_R9_use, + ARMBuildAttrs::R9Reserved)); +} + +TEST(PCS_RWBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(15, "Tag_ABI_PCS_RW_data")); + EXPECT_TRUE(testBuildAttr(15, 0, ARMBuildAttrs::ABI_PCS_RW_data, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(15, 1, ARMBuildAttrs::ABI_PCS_RW_data, + ARMBuildAttrs::AddressRWPCRel)); + EXPECT_TRUE(testBuildAttr(15, 2, ARMBuildAttrs::ABI_PCS_RW_data, + ARMBuildAttrs::AddressRWSBRel)); + EXPECT_TRUE(testBuildAttr(15, 3, ARMBuildAttrs::ABI_PCS_RW_data, + ARMBuildAttrs::AddressRWNone)); +} + +TEST(PCS_ROBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(16, "Tag_ABI_PCS_RO_data")); + EXPECT_TRUE(testBuildAttr(16, 0, ARMBuildAttrs::ABI_PCS_RO_data, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(16, 1, ARMBuildAttrs::ABI_PCS_RO_data, + ARMBuildAttrs::AddressROPCRel)); + EXPECT_TRUE(testBuildAttr(16, 2, ARMBuildAttrs::ABI_PCS_RO_data, + ARMBuildAttrs::AddressRONone)); +} + +TEST(PCS_GOTBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(17, "Tag_ABI_PCS_GOT_use")); + EXPECT_TRUE(testBuildAttr(17, 0, ARMBuildAttrs::ABI_PCS_GOT_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(17, 1, ARMBuildAttrs::ABI_PCS_GOT_use, + ARMBuildAttrs::AddressDirect)); + EXPECT_TRUE(testBuildAttr(17, 2, ARMBuildAttrs::ABI_PCS_GOT_use, + ARMBuildAttrs::AddressGOT)); +} + +TEST(PCS_WCharBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(18, "Tag_ABI_PCS_wchar_t")); + EXPECT_TRUE(testBuildAttr(18, 0, ARMBuildAttrs::ABI_PCS_wchar_t, + ARMBuildAttrs::WCharProhibited)); + EXPECT_TRUE(testBuildAttr(18, 2, ARMBuildAttrs::ABI_PCS_wchar_t, + ARMBuildAttrs::WCharWidth2Bytes)); + EXPECT_TRUE(testBuildAttr(18, 4, ARMBuildAttrs::ABI_PCS_wchar_t, + ARMBuildAttrs::WCharWidth4Bytes)); +} + +TEST(EnumSizeBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(26, "Tag_ABI_enum_size")); + EXPECT_TRUE(testBuildAttr(26, 0, ARMBuildAttrs::ABI_enum_size, + ARMBuildAttrs::EnumProhibited)); + EXPECT_TRUE(testBuildAttr(26, 1, ARMBuildAttrs::ABI_enum_size, + ARMBuildAttrs::EnumSmallest)); + EXPECT_TRUE(testBuildAttr(26, 2, ARMBuildAttrs::ABI_enum_size, + ARMBuildAttrs::Enum32Bit)); + EXPECT_TRUE(testBuildAttr(26, 3, ARMBuildAttrs::ABI_enum_size, + ARMBuildAttrs::Enum32BitABI)); +} + +TEST(AlignNeededBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(24, "Tag_ABI_align_needed")); + EXPECT_TRUE(testBuildAttr(24, 0, ARMBuildAttrs::ABI_align_needed, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(24, 1, ARMBuildAttrs::ABI_align_needed, + ARMBuildAttrs::Align8Byte)); + EXPECT_TRUE(testBuildAttr(24, 2, ARMBuildAttrs::ABI_align_needed, + ARMBuildAttrs::Align4Byte)); + EXPECT_TRUE(testBuildAttr(24, 3, ARMBuildAttrs::ABI_align_needed, + ARMBuildAttrs::AlignReserved)); +} + +TEST(AlignPreservedBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(25, "Tag_ABI_align_preserved")); + EXPECT_TRUE(testBuildAttr(25, 0, ARMBuildAttrs::ABI_align_preserved, + ARMBuildAttrs::AlignNotPreserved)); + EXPECT_TRUE(testBuildAttr(25, 1, ARMBuildAttrs::ABI_align_preserved, + ARMBuildAttrs::AlignPreserve8Byte)); + EXPECT_TRUE(testBuildAttr(25, 2, ARMBuildAttrs::ABI_align_preserved, + ARMBuildAttrs::AlignPreserveAll)); + EXPECT_TRUE(testBuildAttr(25, 3, ARMBuildAttrs::ABI_align_preserved, + ARMBuildAttrs::AlignReserved)); +} + +TEST(FPRoundingBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(19, "Tag_ABI_FP_rounding")); + EXPECT_TRUE(testBuildAttr(19, 0, ARMBuildAttrs::ABI_FP_rounding, 0)); + EXPECT_TRUE(testBuildAttr(19, 1, ARMBuildAttrs::ABI_FP_rounding, 1)); +} + +TEST(FPDenormalBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(20, "Tag_ABI_FP_denormal")); + EXPECT_TRUE(testBuildAttr(20, 0, ARMBuildAttrs::ABI_FP_denormal, + ARMBuildAttrs::PositiveZero)); + EXPECT_TRUE(testBuildAttr(20, 1, ARMBuildAttrs::ABI_FP_denormal, + ARMBuildAttrs::IEEEDenormals)); + EXPECT_TRUE(testBuildAttr(20, 2, ARMBuildAttrs::ABI_FP_denormal, + ARMBuildAttrs::PreserveFPSign)); +} + +TEST(FPExceptionsBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(21, "Tag_ABI_FP_exceptions")); + EXPECT_TRUE(testBuildAttr(21, 0, ARMBuildAttrs::ABI_FP_exceptions, 0)); + EXPECT_TRUE(testBuildAttr(21, 1, ARMBuildAttrs::ABI_FP_exceptions, 1)); +} + +TEST(FPUserExceptionsBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(22, "Tag_ABI_FP_user_exceptions")); + EXPECT_TRUE(testBuildAttr(22, 0, ARMBuildAttrs::ABI_FP_user_exceptions, 0)); + EXPECT_TRUE(testBuildAttr(22, 1, ARMBuildAttrs::ABI_FP_user_exceptions, 1)); +} + +TEST(FPNumberModelBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(23, "Tag_ABI_FP_number_model")); + EXPECT_TRUE(testBuildAttr(23, 0, ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(23, 1, ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::AllowIEEENormal)); + EXPECT_TRUE(testBuildAttr(23, 2, ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::AllowRTABI)); + EXPECT_TRUE(testBuildAttr(23, 3, ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::AllowIEEE754)); +} + +TEST(FP16BuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(38, "Tag_ABI_FP_16bit_format")); + EXPECT_TRUE(testBuildAttr(38, 0, ARMBuildAttrs::ABI_FP_16bit_format, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(38, 1, ARMBuildAttrs::ABI_FP_16bit_format, + ARMBuildAttrs::FP16FormatIEEE)); + EXPECT_TRUE(testBuildAttr(38, 2, ARMBuildAttrs::ABI_FP_16bit_format, + ARMBuildAttrs::FP16VFP3)); +} + +TEST(HardFPBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(27, "Tag_ABI_HardFP_use")); + EXPECT_TRUE(testBuildAttr(27, 0, ARMBuildAttrs::ABI_HardFP_use, + ARMBuildAttrs::HardFPImplied)); + EXPECT_TRUE(testBuildAttr(27, 1, ARMBuildAttrs::ABI_HardFP_use, + ARMBuildAttrs::HardFPSinglePrecision)); + EXPECT_TRUE(testBuildAttr(27, 2, ARMBuildAttrs::ABI_HardFP_use, 2)); +} + +TEST(VFPArgsBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(28, "Tag_ABI_VFP_args")); + EXPECT_TRUE(testBuildAttr(28, 0, ARMBuildAttrs::ABI_VFP_args, + ARMBuildAttrs::BaseAAPCS)); + EXPECT_TRUE(testBuildAttr(28, 1, ARMBuildAttrs::ABI_VFP_args, + ARMBuildAttrs::HardFPAAPCS)); + EXPECT_TRUE(testBuildAttr(28, 2, ARMBuildAttrs::ABI_VFP_args, 2)); + EXPECT_TRUE(testBuildAttr(28, 3, ARMBuildAttrs::ABI_VFP_args, 3)); +} + +TEST(WMMXArgsBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(29, "Tag_ABI_WMMX_args")); + EXPECT_TRUE(testBuildAttr(29, 0, ARMBuildAttrs::ABI_WMMX_args, 0)); + EXPECT_TRUE(testBuildAttr(29, 1, ARMBuildAttrs::ABI_WMMX_args, 1)); + EXPECT_TRUE(testBuildAttr(29, 2, ARMBuildAttrs::ABI_WMMX_args, 2)); +} diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index 6068de5514c7f..4c9bb5eea3858 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(SupportTests AlignOfTest.cpp AllocatorTest.cpp + ARMAttributeParser.cpp ArrayRecyclerTest.cpp BlockFrequencyTest.cpp BranchProbabilityTest.cpp