summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/MC/MCStreamer.h2
-rw-r--r--lib/Target/ARM/ARMAsmPrinter.cpp2
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp109
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMBuildAttrs.cpp96
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMBuildAttrs.h (renamed from lib/Target/ARM/ARMBuildAttrs.h)7
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp64
-rw-r--r--lib/Target/ARM/MCTargetDesc/CMakeLists.txt1
-rw-r--r--test/CodeGen/ARM/build-attributes-encoding.s10
-rw-r--r--test/MC/ARM/directive-eabi_attribute-2.s91
-rw-r--r--test/MC/ARM/directive-eabi_attribute-diagnostics.s36
10 files changed, 394 insertions, 24 deletions
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h
index e26b4116bb..5579186ec9 100644
--- a/include/llvm/MC/MCStreamer.h
+++ b/include/llvm/MC/MCStreamer.h
@@ -92,6 +92,8 @@ public:
virtual void switchVendor(StringRef Vendor) = 0;
virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0;
virtual void emitTextAttribute(unsigned Attribute, StringRef String) = 0;
+ virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+ StringRef StringValue = "") = 0;
virtual void emitFPU(unsigned FPU) = 0;
virtual void emitArch(unsigned Arch) = 0;
virtual void finishAttributeSection() = 0;
diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp
index 296bb0dcee..a0d2b75c03 100644
--- a/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -15,7 +15,6 @@
#define DEBUG_TYPE "asm-printer"
#include "ARMAsmPrinter.h"
#include "ARM.h"
-#include "ARMBuildAttrs.h"
#include "ARMConstantPoolValue.h"
#include "ARMFPUName.h"
#include "ARMMachineFunctionInfo.h"
@@ -23,6 +22,7 @@
#include "ARMTargetObjectFile.h"
#include "InstPrinter/ARMInstPrinter.h"
#include "MCTargetDesc/ARMAddressingModes.h"
+#include "MCTargetDesc/ARMBuildAttrs.h"
#include "MCTargetDesc/ARMMCExpr.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index be148ca7d2..81cad168ae 100644
--- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -7,11 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "ARMBuildAttrs.h"
#include "ARMFPUName.h"
#include "ARMFeatures.h"
#include "llvm/MC/MCTargetAsmParser.h"
#include "MCTargetDesc/ARMAddressingModes.h"
+#include "MCTargetDesc/ARMBuildAttrs.h"
#include "MCTargetDesc/ARMArchName.h"
#include "MCTargetDesc/ARMBaseInfo.h"
#include "MCTargetDesc/ARMMCExpr.h"
@@ -8189,30 +8189,109 @@ bool ARMAsmParser::parseDirectiveArch(SMLoc L) {
}
/// parseDirectiveEabiAttr
-/// ::= .eabi_attribute int, int
+/// ::= .eabi_attribute int, int [, "str"]
+/// ::= .eabi_attribute Tag_name, int [, "str"]
bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) {
- if (Parser.getTok().isNot(AsmToken::Integer)) {
- Error(L, "integer expected");
- return false;
+ int64_t Tag;
+ SMLoc TagLoc;
+
+ TagLoc = Parser.getTok().getLoc();
+ if (Parser.getTok().is(AsmToken::Identifier)) {
+ StringRef Name = Parser.getTok().getIdentifier();
+ Tag = ARMBuildAttrs::AttrTypeFromString(Name);
+ if (Tag == -1) {
+ Error(TagLoc, "attribute name not recognised: " + Name);
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+ Parser.Lex();
+ } else {
+ const MCExpr *AttrExpr;
+
+ TagLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(AttrExpr)) {
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr);
+ if (!CE) {
+ Error(TagLoc, "expected numeric constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ Tag = CE->getValue();
}
- int64_t Tag = Parser.getTok().getIntVal();
- Parser.Lex(); // eat tag integer
if (Parser.getTok().isNot(AsmToken::Comma)) {
- Error(L, "comma expected");
+ Error(Parser.getTok().getLoc(), "comma expected");
+ Parser.eatToEndOfStatement();
return false;
}
Parser.Lex(); // skip comma
- L = Parser.getTok().getLoc();
- if (Parser.getTok().isNot(AsmToken::Integer)) {
- Error(L, "integer expected");
- return false;
+ StringRef StringValue = "";
+ bool IsStringValue = false;
+
+ int64_t IntegerValue = 0;
+ bool IsIntegerValue = false;
+
+ if (Tag == ARMBuildAttrs::CPU_raw_name || Tag == ARMBuildAttrs::CPU_name)
+ IsStringValue = true;
+ else if (Tag == ARMBuildAttrs::compatibility) {
+ IsStringValue = true;
+ IsIntegerValue = true;
+ } else if (Tag == ARMBuildAttrs::nodefaults || Tag < 32 || Tag % 2 == 0)
+ IsIntegerValue = true;
+ else if (Tag % 2 == 1)
+ IsStringValue = true;
+ else
+ llvm_unreachable("invalid tag type");
+
+ if (IsIntegerValue) {
+ const MCExpr *ValueExpr;
+ SMLoc ValueExprLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(ValueExpr)) {
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr);
+ if (!CE) {
+ Error(ValueExprLoc, "expected numeric constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ IntegerValue = CE->getValue();
+ }
+
+ if (Tag == ARMBuildAttrs::compatibility) {
+ if (Parser.getTok().isNot(AsmToken::Comma))
+ IsStringValue = false;
+ else
+ Parser.Lex();
+ }
+
+ if (IsStringValue) {
+ if (Parser.getTok().isNot(AsmToken::String)) {
+ Error(Parser.getTok().getLoc(), "bad string constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ StringValue = Parser.getTok().getStringContents();
+ Parser.Lex();
}
- int64_t Value = Parser.getTok().getIntVal();
- Parser.Lex(); // eat value integer
- getTargetStreamer().emitAttribute(Tag, Value);
+ if (IsIntegerValue && IsStringValue) {
+ assert(Tag == ARMBuildAttrs::compatibility);
+ getTargetStreamer().emitIntTextAttribute(Tag, IntegerValue, StringValue);
+ } else if (IsIntegerValue)
+ getTargetStreamer().emitAttribute(Tag, IntegerValue);
+ else if (IsStringValue)
+ getTargetStreamer().emitTextAttribute(Tag, StringValue);
return false;
}
diff --git a/lib/Target/ARM/MCTargetDesc/ARMBuildAttrs.cpp b/lib/Target/ARM/MCTargetDesc/ARMBuildAttrs.cpp
new file mode 100644
index 0000000000..9bb5072d7d
--- /dev/null
+++ b/lib/Target/ARM/MCTargetDesc/ARMBuildAttrs.cpp
@@ -0,0 +1,96 @@
+//===-- ARMBuildAttrs.cpp - ARM Build Attributes --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARMBuildAttrs.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+namespace {
+const struct {
+ ARMBuildAttrs::AttrType Attr;
+ const char *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::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_align8_needed, "Tag_ABI_align8_needed" },
+ { ARMBuildAttrs::ABI_align8_preserved, "Tag_ABI_align8_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::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::ABI_align8_needed, "Tag_ABI_align_needed" },
+ { ARMBuildAttrs::ABI_align8_preserved, "Tag_ABI_align_preserved" },
+ { ARMBuildAttrs::FP_HP_extension, "Tag_VFP_HP_extension" },
+};
+}
+
+namespace llvm {
+namespace ARMBuildAttrs {
+StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix) {
+ return AttrTypeAsString(static_cast<AttrType>(Attr), HasTagPrefix);
+}
+
+StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix) {
+ for (unsigned TI = 0, TE = sizeof(ARMAttributeTags) / sizeof(*ARMAttributeTags);
+ TI != TE; ++TI)
+ if (ARMAttributeTags[TI].Attr == Attr)
+ return ARMAttributeTags[TI].TagName + (HasTagPrefix ? 0 : 4);
+ return "";
+}
+
+int AttrTypeFromString(StringRef Tag) {
+ bool HasTagPrefix = Tag.startswith("Tag_");
+ for (unsigned TI = 0, TE = sizeof(ARMAttributeTags) / sizeof(*ARMAttributeTags);
+ TI != TE; ++TI)
+ if (StringRef(ARMAttributeTags[TI].TagName + (HasTagPrefix ? 0 : 4)) == Tag)
+ return ARMAttributeTags[TI].Attr;
+ return -1;
+}
+}
+}
+
diff --git a/lib/Target/ARM/ARMBuildAttrs.h b/lib/Target/ARM/MCTargetDesc/ARMBuildAttrs.h
index c80659f86d..98cfecfb71 100644
--- a/lib/Target/ARM/ARMBuildAttrs.h
+++ b/lib/Target/ARM/MCTargetDesc/ARMBuildAttrs.h
@@ -16,6 +16,9 @@
#define __TARGET_ARMBUILDATTRS_H__
namespace llvm {
+
+class StringRef;
+
namespace ARMBuildAttrs {
enum SpecialAttr {
@@ -71,6 +74,10 @@ namespace ARMBuildAttrs {
MPextension_use_old = 70
};
+ 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
diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index 3c0f82fd40..1fb3beabd9 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -125,6 +125,8 @@ class ARMTargetAsmStreamer : public ARMTargetStreamer {
virtual void switchVendor(StringRef Vendor);
virtual void emitAttribute(unsigned Attribute, unsigned Value);
virtual void emitTextAttribute(unsigned Attribute, StringRef String);
+ virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+ StringRef StrinValue);
virtual void emitArch(unsigned Arch);
virtual void emitFPU(unsigned FPU);
virtual void emitInst(uint32_t Inst, char Suffix = '\0');
@@ -182,11 +184,27 @@ void ARMTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
void ARMTargetAsmStreamer::emitTextAttribute(unsigned Attribute,
StringRef String) {
switch (Attribute) {
- default: llvm_unreachable("Unsupported Text attribute in ASM Mode");
case ARMBuildAttrs::CPU_name:
- OS << "\t.cpu\t" << String.lower() << "\n";
+ OS << "\t.cpu\t" << String.lower();
+ break;
+ default:
+ OS << "\t.eabi_attribute\t" << Attribute << ", \"" << String << "\"";
break;
}
+ OS << "\n";
+}
+void ARMTargetAsmStreamer::emitIntTextAttribute(unsigned Attribute,
+ unsigned IntValue,
+ StringRef StringValue) {
+ switch (Attribute) {
+ default: llvm_unreachable("unsupported multi-value attribute in asm mode");
+ case ARMBuildAttrs::compatibility:
+ OS << "\t.eabi_attribute\t" << Attribute << ", " << IntValue;
+ if (!StringValue.empty())
+ OS << ", \"" << StringValue << "\"";
+ break;
+ }
+ OS << "\n";
}
void ARMTargetAsmStreamer::emitArch(unsigned Arch) {
OS << "\t.arch\t" << GetArchName(Arch) << "\n";
@@ -213,7 +231,8 @@ private:
enum {
HiddenAttribute = 0,
NumericAttribute,
- TextAttribute
+ TextAttribute,
+ NumericAndTextAttributes
} Type;
unsigned Tag;
unsigned IntValue;
@@ -289,6 +308,27 @@ private:
Contents.push_back(Item);
}
+ void setAttributeItems(unsigned Attribute, unsigned IntValue,
+ StringRef StringValue, bool OverwriteExisting) {
+ // Look for existing attribute item
+ if (AttributeItem *Item = getAttributeItem(Attribute)) {
+ if (!OverwriteExisting)
+ return;
+ Item->IntValue = IntValue;
+ Item->StringValue = StringValue;
+ return;
+ }
+
+ // Create new attribute item
+ AttributeItem Item = {
+ AttributeItem::NumericAndTextAttributes,
+ Attribute,
+ IntValue,
+ StringValue
+ };
+ Contents.push_back(Item);
+ }
+
void emitArchDefaultAttributes();
void emitFPUDefaultAttributes();
@@ -307,6 +347,8 @@ private:
virtual void switchVendor(StringRef Vendor);
virtual void emitAttribute(unsigned Attribute, unsigned Value);
virtual void emitTextAttribute(unsigned Attribute, StringRef String);
+ virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+ StringRef StringValue);
virtual void emitArch(unsigned Arch);
virtual void emitFPU(unsigned FPU);
virtual void emitInst(uint32_t Inst, char Suffix = '\0');
@@ -588,6 +630,12 @@ void ARMTargetELFStreamer::emitTextAttribute(unsigned Attribute,
StringRef Value) {
setAttributeItem(Attribute, Value, /* OverwriteExisting= */ true);
}
+void ARMTargetELFStreamer::emitIntTextAttribute(unsigned Attribute,
+ unsigned IntValue,
+ StringRef StringValue) {
+ setAttributeItems(Attribute, IntValue, StringValue,
+ /* OverwriteExisting= */ true);
+}
void ARMTargetELFStreamer::emitArch(unsigned Value) {
Arch = Value;
}
@@ -771,6 +819,11 @@ size_t ARMTargetELFStreamer::calculateContentSize() const {
Result += getULEBSize(item.Tag);
Result += item.StringValue.size() + 1; // string + '\0'
break;
+ case AttributeItem::NumericAndTextAttributes:
+ Result += getULEBSize(item.Tag);
+ Result += getULEBSize(item.IntValue);
+ Result += item.StringValue.size() + 1; // string + '\0';
+ break;
}
}
return Result;
@@ -841,6 +894,11 @@ void ARMTargetELFStreamer::finishAttributeSection() {
Streamer.EmitBytes(item.StringValue.upper());
Streamer.EmitIntValue(0, 1); // '\0'
break;
+ case AttributeItem::NumericAndTextAttributes:
+ Streamer.EmitULEB128IntValue(item.IntValue);
+ Streamer.EmitBytes(item.StringValue.upper());
+ Streamer.EmitIntValue(0, 1); // '\0'
+ break;
}
}
diff --git a/lib/Target/ARM/MCTargetDesc/CMakeLists.txt b/lib/Target/ARM/MCTargetDesc/CMakeLists.txt
index 162de7d21e..a65f6ab896 100644
--- a/lib/Target/ARM/MCTargetDesc/CMakeLists.txt
+++ b/lib/Target/ARM/MCTargetDesc/CMakeLists.txt
@@ -1,5 +1,6 @@
add_llvm_library(LLVMARMDesc
ARMAsmBackend.cpp
+ ARMBuildAttrs.cpp
ARMELFObjectWriter.cpp
ARMELFStreamer.cpp
ARMMCAsmInfo.cpp
diff --git a/test/CodeGen/ARM/build-attributes-encoding.s b/test/CodeGen/ARM/build-attributes-encoding.s
index 5ad51b2841..34a1ad38fb 100644
--- a/test/CodeGen/ARM/build-attributes-encoding.s
+++ b/test/CodeGen/ARM/build-attributes-encoding.s
@@ -4,7 +4,7 @@
// RUN: | llvm-readobj -s -sd | FileCheck %s
// Tag_CPU_name (=5)
-.cpu Cortex-A8
+.cpu cortex-a8
// Tag_CPU_arch (=6)
.eabi_attribute 6, 10
@@ -61,7 +61,7 @@
.eabi_attribute 110, 160
// Check that tags > 128 are encoded properly
-.eabi_attribute 129, 1
+.eabi_attribute 129, "1"
.eabi_attribute 250, 1
// CHECK: Section {
@@ -71,15 +71,15 @@
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x0
// CHECK-NEXT: Offset: 0x34
-// CHECK-NEXT: Size: 70
+// CHECK-NEXT: Size: 71
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 41450000 00616561 62690001 3B000000
+// CHECK-NEXT: 0000: 41460000 00616561 62690001 3C000000
// CHECK-NEXT: 0010: 05434F52 5445582D 41380006 0A074108
// CHECK-NEXT: 0020: 0109020A 030C0214 01150117 01180119
// CHECK-NEXT: 0030: 011B001C 0124012A 012C0244 036EA001
-// CHECK-NEXT: 0040: 810101FA 0101
+// CHECK-NEXT: 0040: 81013100 FA0101
// CHECK-NEXT: )
diff --git a/test/MC/ARM/directive-eabi_attribute-2.s b/test/MC/ARM/directive-eabi_attribute-2.s
new file mode 100644
index 0000000000..fc8dc6149a
--- /dev/null
+++ b/test/MC/ARM/directive-eabi_attribute-2.s
@@ -0,0 +1,91 @@
+@ RUN: llvm-mc -triple armv7-elf -filetype asm -o - %s | FileCheck %s
+
+ .syntax unified
+ .thumb
+
+ .eabi_attribute Tag_CPU_raw_name, "Cortex-A9"
+@ CHECK: .eabi_attribute 4, "Cortex-A9"
+ .eabi_attribute Tag_CPU_name, "cortex-a9"
+@ CHECK: .cpu cortex-a9
+ .eabi_attribute Tag_CPU_arch, 10
+@ CHECK: .eabi_attribute 6, 10
+ .eabi_attribute Tag_CPU_arch_profile, 'A'
+@ CHECK: .eabi_attribute 7, 65
+ .eabi_attribute Tag_ARM_ISA_use, 0
+@ CHECK: .eabi_attribute 8, 0
+ .eabi_attribute Tag_THUMB_ISA_use, 2
+@ CHECK: .eabi_attribute 9, 2
+ .eabi_attribute Tag_FP_arch, 3
+@ CHECK: .eabi_attribute 10, 3
+ .eabi_attribute Tag_WMMX_arch, 0
+@ CHECK: .eabi_attribute 11, 0
+ .eabi_attribute Tag_Advanced_SIMD_arch, 1
+@ CHECK: .eabi_attribute 12, 1
+ .eabi_attribute Tag_PCS_config, 2
+@ CHECK: .eabi_attribute 13, 2
+ .eabi_attribute Tag_ABI_PCS_R9_use, 0
+@ CHECK: .eabi_attribute 14, 0
+ .eabi_attribute Tag_ABI_PCS_RW_data, 0
+@ CHECK: .eabi_attribute 15, 0
+ .eabi_attribute Tag_ABI_PCS_RO_data, 0
+@ CHECK: .eabi_attribute 16, 0
+ .eabi_attribute Tag_ABI_PCS_GOT_use, 0
+@ CHECK: .eabi_attribute 17, 0
+ .eabi_attribute Tag_ABI_PCS_wchar_t, 4
+@ CHECK: .eabi_attribute 18, 4
+ .eabi_attribute Tag_ABI_FP_rounding, 1
+@ CHECK: .eabi_attribute 19, 1
+ .eabi_attribute Tag_ABI_FP_denormal, 2
+@ CHECK: .eabi_attribute 20, 2
+ .eabi_attribute Tag_ABI_FP_exceptions, 1
+@ CHECK: .eabi_attribute 21, 1
+ .eabi_attribute Tag_ABI_FP_user_exceptions, 1
+@ CHECK: .eabi_attribute 22, 1
+ .eabi_attribute Tag_ABI_FP_number_model, 3
+@ CHECK: .eabi_attribute 23, 3
+ .eabi_attribute Tag_ABI_align8_needed, 1
+@ CHECK: .eabi_attribute 24, 1
+ .eabi_attribute Tag_ABI_align8_preserved, 2
+@ CHECK: .eabi_attribute 25, 2
+ .eabi_attribute Tag_ABI_enum_size, 3
+@ CHECK: .eabi_attribute 26, 3
+ .eabi_attribute Tag_ABI_HardFP_use, 0
+@ CHECK: .eabi_attribute 27, 0
+ .eabi_attribute Tag_ABI_VFP_args, 1
+@ CHECK: .eabi_attribute 28, 1
+ .eabi_attribute Tag_ABI_WMMX_args, 0
+@ CHECK: .eabi_attribute 29, 0
+ .eabi_attribute Tag_ABI_FP_optimization_goals, 1
+@ CHECK: .eabi_attribute 31, 1
+ .eabi_attribute Tag_compatibility, 1
+@ CHECK: .eabi_attribute 32, 1
+ .eabi_attribute Tag_compatibility, 1, "aeabi"
+@ CHECK: .eabi_attribute 32, 1, "aeabi"
+ .eabi_attribute Tag_CPU_unaligned_access, 0
+@ CHECK: .eabi_attribute 34, 0
+ .eabi_attribute Tag_FP_HP_extension, 0
+@ CHECK: .eabi_attribute 36, 0
+ .eabi_attribute Tag_ABI_FP_16bit_format, 0
+@ CHECK: .eabi_attribute 38, 0
+ .eabi_attribute Tag_MPextension_use, 0
+@ CHECK: .eabi_attribute 42, 0
+ .eabi_attribute Tag_DIV_use, 0
+@ CHECK: .eabi_attribute 44, 0
+ .eabi_attribute Tag_nodefaults, 0
+@ CHECK: .eabi_attribute 64, 0
+ .eabi_attribute Tag_also_compatible_with, "gnu"
+@ CHECK: .eabi_attribute 65, "gnu"
+ .eabi_attribute Tag_T2EE_use, 0
+@ CHECK: .eabi_attribute 66, 0
+ .eabi_attribute Tag_conformance, "2.09"
+@ CHECK: .eabi_attribute 67, "2.09"
+ .eabi_attribute Tag_Virtualization_use, 0
+@ CHECK: .eabi_attribute 68, 0
+
+@ ===--- GNU AS Compatibility Checks ---===
+
+ .eabi_attribute 2 * 2 + 1, "cortex-a9"
+@ CHECK: .cpu cortex-a9
+ .eabi_attribute 2 * 2 + 2, 5 * 2
+@ CHECK: .eabi_attribute 6, 10
+
diff --git a/test/MC/ARM/directive-eabi_attribute-diagnostics.s b/test/MC/ARM/directive-eabi_attribute-diagnostics.s
new file mode 100644
index 0000000000..d1ae352b25
--- /dev/null
+++ b/test/MC/ARM/directive-eabi_attribute-diagnostics.s
@@ -0,0 +1,36 @@
+@ RUN: not llvm-mc -triple armv7-elf -filetype asm -o /dev/null %s 2>&1 \
+@ RUN: | FileCheck %s
+
+ .syntax unified
+ .thumb
+
+ .eabi_attribute Tag_unknown_name, 0
+@ CHECK: error: attribute name not recognised: Tag_unknown_name
+@ CHECK: .eabi_attribute Tag_unknown_name
+@ CHECK: ^
+
+ .eabi_attribute [non_constant_expression], 0
+@ CHECK: error: expected numeric constant
+@ CHECK: .eabi_attribute [non_constant_expression], 0
+@ CHECK: ^
+
+ .eabi_attribute 42, "forty two"
+@ CHECK: error: expected numeric constant
+@ CHECK: .eabi_attribute 42, "forty two"
+@ CHECK: ^
+
+ .eabi_attribute 43, 43
+@ CHECK: error: bad string constant
+@ CHECK: .eabi_attribute 43, 43
+@ CHECK: ^
+
+ .eabi_attribute 0
+@ CHECK: error: comma expected
+@ CHECK: .eabi_attribute 0
+@ CHECK: ^
+
+ .eabi_attribute Tag_MPextension_use_old, 0
+@ CHECK: error: attribute name not recognised: Tag_MPextension_use_old
+@ CHECK: .eabi_attribute Tag_MPextension_use_old, 0
+@ CHECK: ^
+