summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLogan Chien <tzuhsiang.chien@gmail.com>2013-10-28 17:51:12 +0000
committerLogan Chien <tzuhsiang.chien@gmail.com>2013-10-28 17:51:12 +0000
commit23125d02d929758e1b0dbb30b13f1deff7a5ea4b (patch)
tree4c77dc2e41386fde9ae2f6529488c71689c50616
parent790b973f80c8fd41f0908536409538336242f74d (diff)
downloadllvm-23125d02d929758e1b0dbb30b13f1deff7a5ea4b.tar.gz
llvm-23125d02d929758e1b0dbb30b13f1deff7a5ea4b.tar.bz2
llvm-23125d02d929758e1b0dbb30b13f1deff7a5ea4b.tar.xz
[arm] Implement eabi_attribute, cpu, and fpu directives.
This commit allows the ARM integrated assembler to parse and assemble the code with .eabi_attribute, .cpu, and .fpu directives. To implement the feature, this commit moves the code from AttrEmitter to ARMTargetStreamers, and several new test cases related to cortex-m4, cortex-r5, and cortex-a15 are added. Besides, this commit also change the Subtarget->isFPOnlySP() to Subtarget->hasD16() to match the usage of .fpu directive. This commit changes the test cases: * Several .eabi_attribute directives in 2010-09-29-mc-asm-header-test.ll are removed because the .fpu directive already cover the functionality. * In the Cortex-A15 test case, the value for Tag_Advanced_SIMD_arch has be changed from 1 to 2, which is more precise. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193524 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/MC/MCStreamer.h6
-rw-r--r--lib/Target/ARM/ARM.td5
-rw-r--r--lib/Target/ARM/ARMAsmPrinter.cpp302
-rw-r--r--lib/Target/ARM/ARMBuildAttrs.h30
-rw-r--r--lib/Target/ARM/ARMFPUName.def32
-rw-r--r--lib/Target/ARM/ARMFPUName.h26
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp51
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp333
-rw-r--r--test/CodeGen/ARM/2010-09-29-mc-asm-header-test.ll33
-rw-r--r--test/CodeGen/ARM/2010-10-19-mc-elf-objheader.ll264
-rw-r--r--test/MC/ARM/directive-cpu.s26
-rw-r--r--test/MC/ARM/directive-eabi_attribute.s56
-rw-r--r--test/MC/ARM/directive-fpu-multiple.s26
-rw-r--r--test/MC/ARM/directive-fpu.s26
14 files changed, 913 insertions, 303 deletions
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h
index 47d798dd8b..04af407a44 100644
--- a/include/llvm/MC/MCStreamer.h
+++ b/include/llvm/MC/MCStreamer.h
@@ -87,6 +87,12 @@ public:
virtual void emitPad(int64_t Offset) = 0;
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
bool isVector) = 0;
+
+ virtual void switchVendor(StringRef Vendor) = 0;
+ virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0;
+ virtual void emitTextAttribute(unsigned Attribute, StringRef String) = 0;
+ virtual void emitFPU(unsigned FPU) = 0;
+ virtual void finishAttributeSection() = 0;
};
/// MCStreamer - Streaming machine code generation interface. This interface
diff --git a/lib/Target/ARM/ARM.td b/lib/Target/ARM/ARM.td
index a0592f23d3..bf12c323fa 100644
--- a/lib/Target/ARM/ARM.td
+++ b/lib/Target/ARM/ARM.td
@@ -309,7 +309,7 @@ def : ProcessorModel<"cortex-r5", CortexA8Model,
[ProcR5, HasV7Ops, FeatureDB,
FeatureVFP3, FeatureDSPThumb2,
FeatureHasRAS, FeatureVFPOnlySP,
- FeatureRClass]>;
+ FeatureD16, FeatureRClass]>;
// V7M Processors.
def : ProcNoItin<"cortex-m3", [HasV7Ops,
@@ -321,7 +321,8 @@ def : ProcNoItin<"cortex-m4", [HasV7Ops,
FeatureThumb2, FeatureNoARM, FeatureDB,
FeatureHWDiv, FeatureDSPThumb2,
FeatureT2XtPk, FeatureVFP4,
- FeatureVFPOnlySP, FeatureMClass]>;
+ FeatureVFPOnlySP, FeatureD16,
+ FeatureMClass]>;
// Swift uArch Processors.
def : ProcessorModel<"swift", SwiftModel,
diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp
index 4899a5dece..d1f1d3ed1b 100644
--- a/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -17,6 +17,7 @@
#include "ARM.h"
#include "ARMBuildAttrs.h"
#include "ARMConstantPoolValue.h"
+#include "ARMFPUName.h"
#include "ARMMachineFunctionInfo.h"
#include "ARMTargetMachine.h"
#include "ARMTargetObjectFile.h"
@@ -55,164 +56,6 @@
#include <cctype>
using namespace llvm;
-namespace {
-
- // Per section and per symbol attributes are not supported.
- // To implement them we would need the ability to delay this emission
- // until the assembly file is fully parsed/generated as only then do we
- // know the symbol and section numbers.
- class AttributeEmitter {
- public:
- virtual void MaybeSwitchVendor(StringRef Vendor) = 0;
- virtual void EmitAttribute(unsigned Attribute, unsigned Value) = 0;
- virtual void EmitTextAttribute(unsigned Attribute, StringRef String) = 0;
- virtual void Finish() = 0;
- virtual ~AttributeEmitter() {}
- };
-
- class AsmAttributeEmitter : public AttributeEmitter {
- MCStreamer &Streamer;
-
- public:
- AsmAttributeEmitter(MCStreamer &Streamer_) : Streamer(Streamer_) {}
- void MaybeSwitchVendor(StringRef Vendor) { }
-
- void EmitAttribute(unsigned Attribute, unsigned Value) {
- Streamer.EmitRawText("\t.eabi_attribute " +
- Twine(Attribute) + ", " + Twine(Value));
- }
-
- void EmitTextAttribute(unsigned Attribute, StringRef String) {
- switch (Attribute) {
- default: llvm_unreachable("Unsupported Text attribute in ASM Mode");
- case ARMBuildAttrs::CPU_name:
- Streamer.EmitRawText(StringRef("\t.cpu ") + String.lower());
- break;
- /* GAS requires .fpu to be emitted regardless of EABI attribute */
- case ARMBuildAttrs::Advanced_SIMD_arch:
- case ARMBuildAttrs::VFP_arch:
- Streamer.EmitRawText(StringRef("\t.fpu ") + String.lower());
- break;
- }
- }
- void Finish() { }
- };
-
- class ObjectAttributeEmitter : public AttributeEmitter {
- // This structure holds all attributes, accounting for
- // their string/numeric value, so we can later emmit them
- // in declaration order, keeping all in the same vector
- struct AttributeItemType {
- enum {
- HiddenAttribute = 0,
- NumericAttribute,
- TextAttribute
- } Type;
- unsigned Tag;
- unsigned IntValue;
- StringRef StringValue;
- };
-
- MCObjectStreamer &Streamer;
- StringRef CurrentVendor;
- SmallVector<AttributeItemType, 64> Contents;
-
- // Account for the ULEB/String size of each item,
- // not just the number of items
- size_t ContentsSize;
- // FIXME: this should be in a more generic place, but
- // getULEBSize() is in MCAsmInfo and will be moved to MCDwarf
- size_t getULEBSize(int Value) {
- size_t Size = 0;
- do {
- Value >>= 7;
- Size += sizeof(int8_t); // Is this really necessary?
- } while (Value);
- return Size;
- }
-
- public:
- ObjectAttributeEmitter(MCObjectStreamer &Streamer_) :
- Streamer(Streamer_), CurrentVendor(""), ContentsSize(0) { }
-
- void MaybeSwitchVendor(StringRef Vendor) {
- assert(!Vendor.empty() && "Vendor cannot be empty.");
-
- if (CurrentVendor.empty())
- CurrentVendor = Vendor;
- else if (CurrentVendor == Vendor)
- return;
- else
- Finish();
-
- CurrentVendor = Vendor;
-
- assert(Contents.size() == 0);
- }
-
- void EmitAttribute(unsigned Attribute, unsigned Value) {
- AttributeItemType attr = {
- AttributeItemType::NumericAttribute,
- Attribute,
- Value,
- StringRef("")
- };
- ContentsSize += getULEBSize(Attribute);
- ContentsSize += getULEBSize(Value);
- Contents.push_back(attr);
- }
-
- void EmitTextAttribute(unsigned Attribute, StringRef String) {
- AttributeItemType attr = {
- AttributeItemType::TextAttribute,
- Attribute,
- 0,
- String
- };
- ContentsSize += getULEBSize(Attribute);
- // String + \0
- ContentsSize += String.size()+1;
-
- Contents.push_back(attr);
- }
-
- void Finish() {
- // Vendor size + Vendor name + '\0'
- const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1;
-
- // Tag + Tag Size
- const size_t TagHeaderSize = 1 + 4;
-
- Streamer.EmitIntValue(VendorHeaderSize + TagHeaderSize + ContentsSize, 4);
- Streamer.EmitBytes(CurrentVendor);
- Streamer.EmitIntValue(0, 1); // '\0'
-
- Streamer.EmitIntValue(ARMBuildAttrs::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 (unsigned int i=0; i<Contents.size(); ++i) {
- AttributeItemType item = Contents[i];
- Streamer.EmitULEB128IntValue(item.Tag);
- switch (item.Type) {
- default: llvm_unreachable("Invalid attribute type");
- case AttributeItemType::NumericAttribute:
- Streamer.EmitULEB128IntValue(item.IntValue);
- break;
- case AttributeItemType::TextAttribute:
- Streamer.EmitBytes(item.StringValue.upper());
- Streamer.EmitIntValue(0, 1); // '\0'
- break;
- }
- }
-
- Contents.clear();
- }
- };
-
-} // end of anonymous namespace
-
/// EmitDwarfRegOp - Emit dwarf register operation.
void ARMAsmPrinter::EmitDwarfRegOp(const MachineLocation &MLoc,
bool Indirect) const {
@@ -768,149 +611,102 @@ static ARMBuildAttrs::CPUArch getArchForCPU(StringRef CPU,
}
void ARMAsmPrinter::emitAttributes() {
+ MCTargetStreamer &TS = OutStreamer.getTargetStreamer();
+ ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
- emitARMAttributeSection();
-
- /* GAS expect .fpu to be emitted, regardless of VFP build attribute */
- bool emitFPU = false;
- AttributeEmitter *AttrEmitter;
- if (OutStreamer.hasRawTextSupport()) {
- AttrEmitter = new AsmAttributeEmitter(OutStreamer);
- emitFPU = true;
- } else {
- MCObjectStreamer &O = static_cast<MCObjectStreamer&>(OutStreamer);
- AttrEmitter = new ObjectAttributeEmitter(O);
- }
-
- AttrEmitter->MaybeSwitchVendor("aeabi");
+ ATS.switchVendor("aeabi");
std::string CPUString = Subtarget->getCPUString();
if (CPUString != "generic")
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::CPU_name, CPUString);
+ ATS.emitTextAttribute(ARMBuildAttrs::CPU_name, CPUString);
- AttrEmitter->EmitAttribute(ARMBuildAttrs::CPU_arch,
- getArchForCPU(CPUString, Subtarget));
+ ATS.emitAttribute(ARMBuildAttrs::CPU_arch,
+ getArchForCPU(CPUString, Subtarget));
if (Subtarget->isAClass()) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::CPU_arch_profile,
- ARMBuildAttrs::ApplicationProfile);
+ ATS.emitAttribute(ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::ApplicationProfile);
} else if (Subtarget->isRClass()) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::CPU_arch_profile,
- ARMBuildAttrs::RealTimeProfile);
+ ATS.emitAttribute(ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::RealTimeProfile);
} else if (Subtarget->isMClass()){
- AttrEmitter->EmitAttribute(ARMBuildAttrs::CPU_arch_profile,
- ARMBuildAttrs::MicroControllerProfile);
+ ATS.emitAttribute(ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::MicroControllerProfile);
}
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ARM_ISA_use, Subtarget->hasARMOps() ?
- ARMBuildAttrs::Allowed : ARMBuildAttrs::Not_Allowed);
+ ATS.emitAttribute(ARMBuildAttrs::ARM_ISA_use, Subtarget->hasARMOps() ?
+ ARMBuildAttrs::Allowed : ARMBuildAttrs::Not_Allowed);
if (Subtarget->isThumb1Only()) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::THUMB_ISA_use,
- ARMBuildAttrs::Allowed);
+ ATS.emitAttribute(ARMBuildAttrs::THUMB_ISA_use,
+ ARMBuildAttrs::Allowed);
} else if (Subtarget->hasThumb2()) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::THUMB_ISA_use,
- ARMBuildAttrs::AllowThumb32);
+ ATS.emitAttribute(ARMBuildAttrs::THUMB_ISA_use,
+ ARMBuildAttrs::AllowThumb32);
}
- if (Subtarget->hasNEON() && emitFPU) {
+ if (Subtarget->hasNEON()) {
/* NEON is not exactly a VFP architecture, but GAS emit one of
* neon/neon-fp-armv8/neon-vfpv4/vfpv3/vfpv2 for .fpu parameters */
if (Subtarget->hasFPARMv8()) {
if (Subtarget->hasCrypto())
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::Advanced_SIMD_arch,
- "crypto-neon-fp-armv8");
+ ATS.emitFPU(ARM::CRYPTO_NEON_FP_ARMV8);
else
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::Advanced_SIMD_arch,
- "neon-fp-armv8");
+ ATS.emitFPU(ARM::NEON_FP_ARMV8);
}
else if (Subtarget->hasVFP4())
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::Advanced_SIMD_arch,
- "neon-vfpv4");
+ ATS.emitFPU(ARM::NEON_VFPV4);
else
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::Advanced_SIMD_arch, "neon");
- /* If emitted for NEON, omit from VFP below, since you can have both
- * NEON and VFP in build attributes but only one .fpu */
- emitFPU = false;
- }
-
- /* FPARMv8 + .fpu */
- if (Subtarget->hasFPARMv8()) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch,
- ARMBuildAttrs::AllowFPARMv8A);
- if (emitFPU)
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::VFP_arch, "fp-armv8");
- /* VFPv4 + .fpu */
- } else if (Subtarget->hasVFP4()) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch,
- Subtarget->isFPOnlySP() ? ARMBuildAttrs::AllowFPv4B :
- ARMBuildAttrs::AllowFPv4A);
- if (emitFPU)
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::VFP_arch, "vfpv4");
-
- /* VFPv3 + .fpu */
- } else if (Subtarget->hasVFP3()) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch,
- Subtarget->isFPOnlySP() ? ARMBuildAttrs::AllowFPv3B :
- ARMBuildAttrs::AllowFPv3A);
- if (emitFPU)
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::VFP_arch, "vfpv3");
-
- /* VFPv2 + .fpu */
- } else if (Subtarget->hasVFP2()) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch,
- ARMBuildAttrs::AllowFPv2);
- if (emitFPU)
- AttrEmitter->EmitTextAttribute(ARMBuildAttrs::VFP_arch, "vfpv2");
- }
-
- /* TODO: ARMBuildAttrs::Allowed is not completely accurate,
- * since NEON can have 1 (allowed) or 2 (MAC operations) */
- if (Subtarget->hasNEON()) {
+ ATS.emitFPU(ARM::NEON);
+ // Emit Tag_Advanced_SIMD_arch for ARMv8 architecture
if (Subtarget->hasV8Ops())
- AttrEmitter->EmitAttribute(ARMBuildAttrs::Advanced_SIMD_arch,
- ARMBuildAttrs::AllowedNeonV8);
- else
- AttrEmitter->EmitAttribute(ARMBuildAttrs::Advanced_SIMD_arch,
- ARMBuildAttrs::Allowed);
+ ATS.emitAttribute(ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeonARMv8);
+ } else {
+ if (Subtarget->hasFPARMv8())
+ ATS.emitFPU(ARM::FP_ARMV8);
+ else if (Subtarget->hasVFP4())
+ ATS.emitFPU(Subtarget->hasD16() ? ARM::VFPV4_D16 : ARM::VFPV4);
+ else if (Subtarget->hasVFP3())
+ ATS.emitFPU(Subtarget->hasD16() ? ARM::VFPV3_D16 : ARM::VFPV3);
+ else if (Subtarget->hasVFP2())
+ ATS.emitFPU(ARM::VFPV2);
}
// Signal various FP modes.
if (!TM.Options.UnsafeFPMath) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_denormal,
- ARMBuildAttrs::Allowed);
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_exceptions,
- ARMBuildAttrs::Allowed);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal, ARMBuildAttrs::Allowed);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_exceptions,
+ ARMBuildAttrs::Allowed);
}
if (TM.Options.NoInfsFPMath && TM.Options.NoNaNsFPMath)
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_number_model,
- ARMBuildAttrs::Allowed);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::Allowed);
else
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_number_model,
- ARMBuildAttrs::AllowIEE754);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::AllowIEE754);
// FIXME: add more flags to ARMBuildAttrs.h
// 8-bytes alignment stuff.
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_align8_needed, 1);
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_align8_preserved, 1);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_align8_needed, 1);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_align8_preserved, 1);
// Hard float. Use both S and D registers and conform to AAPCS-VFP.
if (Subtarget->isAAPCS_ABI() && TM.Options.FloatABIType == FloatABI::Hard) {
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_HardFP_use, 3);
- AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_VFP_args, 1);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_HardFP_use, 3);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_VFP_args, 1);
}
// FIXME: Should we signal R9 usage?
if (Subtarget->hasDivide()) {
// Check if hardware divide is only available in thumb2 or ARM as well.
- AttrEmitter->EmitAttribute(ARMBuildAttrs::DIV_use,
+ ATS.emitAttribute(ARMBuildAttrs::DIV_use,
Subtarget->hasDivideInARMMode() ? ARMBuildAttrs::AllowDIVExt :
ARMBuildAttrs::AllowDIVIfExists);
}
- AttrEmitter->Finish();
- delete AttrEmitter;
+ ATS.finishAttributeSection();
}
void ARMAsmPrinter::emitARMAttributeSection() {
diff --git a/lib/Target/ARM/ARMBuildAttrs.h b/lib/Target/ARM/ARMBuildAttrs.h
index 44fbf3d0c9..93edc55d51 100644
--- a/lib/Target/ARM/ARMBuildAttrs.h
+++ b/lib/Target/ARM/ARMBuildAttrs.h
@@ -15,11 +15,13 @@
#ifndef __TARGET_ARMBUILDATTRS_H__
#define __TARGET_ARMBUILDATTRS_H__
+namespace llvm {
namespace ARMBuildAttrs {
+
enum SpecialAttr {
// This is for the .cpu asm attr. It translates into one or more
// AttrType (below) entries in the .ARM.attributes section in the ELF.
- SEL_CPU
+ SEL_CPU
};
enum AttrType {
@@ -93,7 +95,7 @@ namespace ARMBuildAttrs {
v8 = 14 // v8, AArch32
};
- enum CPUArchProfile { // (=7), uleb128
+ enum CPUArchProfile { // (=7), uleb128
Not_Applicable = 0, // pre v7, or cross-profile code
ApplicationProfile = (0x41), // 'A' (e.g. for Cortex A8)
RealTimeProfile = (0x52), // 'R' (e.g. for Cortex R4)
@@ -102,40 +104,50 @@ namespace ARMBuildAttrs {
};
// The following have a lot of common use cases
- enum {
+ enum {
//ARMISAUse (=8), uleb128 and THUMBISAUse (=9), uleb128
Not_Allowed = 0,
Allowed = 1,
- AllowedNeonV8 = 3,
// FP_arch (=10), uleb128 (formerly Tag_VFP_arch = 10)
AllowFPv2 = 2, // v2 FP ISA permitted (implies use of the v1 FP ISA)
AllowFPv3A = 3, // v3 FP ISA permitted (implies use of the v2 FP ISA)
- AllowFPv3B = 4, // v3 FP ISA permitted, but only D0-D15, S0-S31
- AllowFPv4A = 5, // v4 FP ISA permitted (implies use of v3 FP ISA)
+ AllowFPv3B = 4, // v3 FP ISA permitted, but only D0-D15, S0-S31
+ AllowFPv4A = 5, // v4 FP ISA permitted (implies use of v3 FP ISA)
AllowFPv4B = 6, // v4 FP ISA was permitted, but only D0-D15, S0-S31
AllowFPARMv8A = 7, // Use of the ARM v8-A FP ISA was permitted
AllowFPARMv8B = 8, // Use of the ARM v8-A FP ISA was permitted, but only D0-D15, S0-S31
// Tag_WMMX_arch, (=11), uleb128
AllowThumb32 = 2, // 32-bit Thumb (implies 16-bit instructions)
-
+
// Tag_WMMX_arch, (=11), uleb128
AllowWMMXv1 = 2, // The user permitted this entity to use WMMX v2
- // Tag_ABI_FP_denormal, (=20), uleb128
+ // Tag_Advanced_SIMD_arch, (=12), uleb128
+ AllowNeon = 1, // SIMDv1 was permitted
+ AllowNeon2 = 2, // SIMDv2 was permitted (Half-precision FP, MAC operations)
+ AllowNeonARMv8 = 3, // ARM v8-A SIMD was permitted
+
+ // Tag_ABI_FP_denormal, (=20), uleb128
PreserveFPSign = 2, // sign when flushed-to-zero is preserved
// Tag_ABI_FP_number_model, (=23), uleb128
AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI])
AllowIEE754 = 3, // this code to use all the IEEE 754-defined FP encodings
+ // Tag_ABI_HardFP_use, (=27), uleb128
+ HardFPSinglePrecision = 1, // Single-precision only
+ HardFPImplied = 3, // FP use should be implied by Tag_FP_arch
+
// Tag_DIV_use, (=44), uleb128
AllowDIVIfExists = 0, // Allow hardware divide if available in arch, or no info exists.
DisallowDIV = 1, // Hardware divide explicitly disallowed
AllowDIVExt = 2 // Allow hardware divide as optional architecture extension above
// the base arch specified by Tag_CPU_arch and Tag_CPU_arch_profile.
};
-}
+
+} // namespace ARMBuildAttrs
+} // namespace llvm
#endif // __TARGET_ARMBUILDATTRS_H__
diff --git a/lib/Target/ARM/ARMFPUName.def b/lib/Target/ARM/ARMFPUName.def
new file mode 100644
index 0000000000..9a1bbe703d
--- /dev/null
+++ b/lib/Target/ARM/ARMFPUName.def
@@ -0,0 +1,32 @@
+//===-- ARMFPUName.def - List of the ARM FPU names --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the list of the supported ARM FPU names.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+#ifndef ARM_FPU_NAME
+#error "You must define ARM_FPU_NAME(NAME, ID) before including ARMFPUName.h"
+#endif
+
+ARM_FPU_NAME("vfp", VFP)
+ARM_FPU_NAME("vfpv2", VFPV2)
+ARM_FPU_NAME("vfpv3", VFPV3)
+ARM_FPU_NAME("vfpv3-d16", VFPV3_D16)
+ARM_FPU_NAME("vfpv4", VFPV4)
+ARM_FPU_NAME("vfpv4-d16", VFPV4_D16)
+ARM_FPU_NAME("fp-armv8", FP_ARMV8)
+ARM_FPU_NAME("neon", NEON)
+ARM_FPU_NAME("neon-vfpv4", NEON_VFPV4)
+ARM_FPU_NAME("neon-fp-armv8", NEON_FP_ARMV8)
+ARM_FPU_NAME("crypto-neon-fp-armv8", CRYPTO_NEON_FP_ARMV8)
+
+#undef ARM_FPU_NAME
diff --git a/lib/Target/ARM/ARMFPUName.h b/lib/Target/ARM/ARMFPUName.h
new file mode 100644
index 0000000000..2a64cce488
--- /dev/null
+++ b/lib/Target/ARM/ARMFPUName.h
@@ -0,0 +1,26 @@
+//===-- ARMFPUName.h - List of the ARM FPU names ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ARMFPUNAME_H
+#define ARMFPUNAME_H
+
+namespace llvm {
+namespace ARM {
+
+enum FPUKind {
+ INVALID_FPU = 0
+
+#define ARM_FPU_NAME(NAME, ID) , ID
+#include "ARMFPUName.def"
+};
+
+} // namespace ARM
+} // namespace llvm
+
+#endif // ARMFPUNAME_H
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index ed71b37b47..ba6075e91d 100644
--- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+#include "ARMBuildAttrs.h"
+#include "ARMFPUName.h"
#include "ARMFeatures.h"
#include "llvm/MC/MCTargetAsmParser.h"
#include "MCTargetDesc/ARMAddressingModes.h"
@@ -137,6 +139,8 @@ class ARMAsmParser : public MCTargetAsmParser {
bool parseDirectiveUnreq(SMLoc L);
bool parseDirectiveArch(SMLoc L);
bool parseDirectiveEabiAttr(SMLoc L);
+ bool parseDirectiveCPU(SMLoc L);
+ bool parseDirectiveFPU(SMLoc L);
bool parseDirectiveFnStart(SMLoc L);
bool parseDirectiveFnEnd(SMLoc L);
bool parseDirectiveCantUnwind(SMLoc L);
@@ -7765,6 +7769,10 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
return parseDirectiveArch(DirectiveID.getLoc());
else if (IDVal == ".eabi_attribute")
return parseDirectiveEabiAttr(DirectiveID.getLoc());
+ else if (IDVal == ".cpu")
+ return parseDirectiveCPU(DirectiveID.getLoc());
+ else if (IDVal == ".fpu")
+ return parseDirectiveFPU(DirectiveID.getLoc());
else if (IDVal == ".fnstart")
return parseDirectiveFnStart(DirectiveID.getLoc());
else if (IDVal == ".fnend")
@@ -7987,7 +7995,48 @@ bool ARMAsmParser::parseDirectiveArch(SMLoc L) {
/// parseDirectiveEabiAttr
/// ::= .eabi_attribute int, int
bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) {
- return true;
+ if (Parser.getTok().isNot(AsmToken::Integer))
+ return Error(L, "integer expected");
+ int64_t Tag = Parser.getTok().getIntVal();
+ Parser.Lex(); // eat tag integer
+
+ if (Parser.getTok().isNot(AsmToken::Comma))
+ return Error(L, "comma expected");
+ Parser.Lex(); // skip comma
+
+ L = Parser.getTok().getLoc();
+ if (Parser.getTok().isNot(AsmToken::Integer))
+ return Error(L, "integer expected");
+ int64_t Value = Parser.getTok().getIntVal();
+ Parser.Lex(); // eat value integer
+
+ getTargetStreamer().emitAttribute(Tag, Value);
+ return false;
+}
+
+/// parseDirectiveCPU
+/// ::= .cpu str
+bool ARMAsmParser::parseDirectiveCPU(SMLoc L) {
+ StringRef CPU = getParser().parseStringToEndOfStatement().trim();
+ getTargetStreamer().emitTextAttribute(ARMBuildAttrs::CPU_name, CPU);
+ return false;
+}
+
+/// parseDirectiveFPU
+/// ::= .fpu str
+bool ARMAsmParser::parseDirectiveFPU(SMLoc L) {
+ StringRef FPU = getParser().parseStringToEndOfStatement().trim();
+
+ unsigned ID = StringSwitch<unsigned>(FPU)
+#define ARM_FPU_NAME(NAME, ID) .Case(NAME, ARM::ID)
+#include "ARMFPUName.def"
+ .Default(ARM::INVALID_FPU);
+
+ if (ID == ARM::INVALID_FPU)
+ return Error(L, "Unknown FPU name");
+
+ getTargetStreamer().emitFPU(ID);
+ return false;
}
/// parseDirectiveFnStart
diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index d4110a45d6..471897de5c 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -13,6 +13,8 @@
//
//===----------------------------------------------------------------------===//
+#include "ARMBuildAttrs.h"
+#include "ARMFPUName.h"
#include "ARMRegisterInfo.h"
#include "ARMUnwindOp.h"
#include "ARMUnwindOpAsm.h"
@@ -39,6 +41,7 @@
#include "llvm/Support/ELF.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
using namespace llvm;
@@ -47,6 +50,17 @@ static std::string GetAEABIUnwindPersonalityName(unsigned Index) {
return (Twine("__aeabi_unwind_cpp_pr") + Twine(Index)).str();
}
+static const char *GetFPUName(unsigned ID) {
+ switch (ID) {
+ default:
+ llvm_unreachable("Unknown FPU kind");
+ break;
+#define ARM_FPU_NAME(NAME, ID) case ARM::ID: return NAME;
+#include "ARMFPUName.def"
+ }
+ return NULL;
+}
+
namespace {
class ARMELFStreamer;
@@ -65,6 +79,12 @@ class ARMTargetAsmStreamer : public ARMTargetStreamer {
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
bool isVector);
+ virtual void switchVendor(StringRef Vendor);
+ virtual void emitAttribute(unsigned Attribute, unsigned Value);
+ virtual void emitTextAttribute(unsigned Attribute, StringRef String);
+ virtual void emitFPU(unsigned FPU);
+ virtual void finishAttributeSection();
+
public:
ARMTargetAsmStreamer(formatted_raw_ostream &OS, MCInstPrinter &InstPrinter);
};
@@ -109,9 +129,114 @@ void ARMTargetAsmStreamer::emitRegSave(const SmallVectorImpl<unsigned> &RegList,
OS << "}\n";
}
+void ARMTargetAsmStreamer::switchVendor(StringRef Vendor) {
+}
+void ARMTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
+ OS << "\t.eabi_attribute\t" << Attribute << ", " << Twine(Value) << "\n";
+}
+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";
+ break;
+ }
+}
+void ARMTargetAsmStreamer::emitFPU(unsigned FPU) {
+ OS << "\t.fpu\t" << GetFPUName(FPU) << "\n";
+}
+void ARMTargetAsmStreamer::finishAttributeSection() {
+}
class ARMTargetELFStreamer : public ARMTargetStreamer {
+private:
+ // This structure holds all attributes, accounting for
+ // their string/numeric value, so we can later emmit them
+ // in declaration order, keeping all in the same vector
+ struct AttributeItem {
+ enum {
+ HiddenAttribute = 0,
+ NumericAttribute,
+ TextAttribute
+ } Type;
+ unsigned Tag;
+ unsigned IntValue;
+ StringRef StringValue;
+
+ static bool LessTag(const AttributeItem &LHS, const AttributeItem &RHS) {
+ return (LHS.Tag < RHS.Tag);
+ }
+ };
+
+ StringRef CurrentVendor;
+ unsigned FPU;
+ SmallVector<AttributeItem, 64> Contents;
+
+ const MCSection *AttributeSection;
+
+ // FIXME: this should be in a more generic place, but
+ // getULEBSize() is in MCAsmInfo and will be moved to MCDwarf
+ static size_t getULEBSize(int Value) {
+ size_t Size = 0;
+ do {
+ Value >>= 7;
+ Size += sizeof(int8_t); // Is this really necessary?
+ } while (Value);
+ return Size;
+ }
+
+ AttributeItem *getAttributeItem(unsigned Attribute) {
+ for (size_t i = 0; i < Contents.size(); ++i)
+ if (Contents[i].Tag == Attribute)
+ return &Contents[i];
+ return 0;
+ }
+
+ void setAttributeItem(unsigned Attribute, unsigned Value,
+ bool OverwriteExisting) {
+ // Look for existing attribute item
+ if (AttributeItem *Item = getAttributeItem(Attribute)) {
+ if (!OverwriteExisting)
+ return;
+ Item->IntValue = Value;
+ return;
+ }
+
+ // Create new attribute item
+ AttributeItem Item = {
+ AttributeItem::NumericAttribute,
+ Attribute,
+ Value,
+ StringRef("")
+ };
+ Contents.push_back(Item);
+ }
+
+ void setAttributeItem(unsigned Attribute, StringRef Value,
+ bool OverwriteExisting) {
+ // Look for existing attribute item
+ if (AttributeItem *Item = getAttributeItem(Attribute)) {
+ if (!OverwriteExisting)
+ return;
+ Item->StringValue = Value;
+ return;
+ }
+
+ // Create new attribute item
+ AttributeItem Item = {
+ AttributeItem::TextAttribute,
+ Attribute,
+ 0,
+ Value
+ };
+ Contents.push_back(Item);
+ }
+
+ void emitFPUDefaultAttributes();
+
ARMELFStreamer &getStreamer();
+
virtual void emitFnStart();
virtual void emitFnEnd();
virtual void emitCantUnwind();
@@ -121,6 +246,20 @@ class ARMTargetELFStreamer : public ARMTargetStreamer {
virtual void emitPad(int64_t Offset);
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
bool isVector);
+
+ virtual void switchVendor(StringRef Vendor);
+ virtual void emitAttribute(unsigned Attribute, unsigned Value);
+ virtual void emitTextAttribute(unsigned Attribute, StringRef String);
+ virtual void emitFPU(unsigned FPU);
+ virtual void finishAttributeSection();
+
+ size_t calculateContentSize() const;
+
+public:
+ ARMTargetELFStreamer()
+ : ARMTargetStreamer(), CurrentVendor("aeabi"), FPU(ARM::INVALID_FPU),
+ AttributeSection(0) {
+ }
};
/// Extend the generic ELFStreamer class so that it can emit mapping symbols at
@@ -149,6 +288,8 @@ public:
~ARMELFStreamer() {}
+ virtual void FinishImpl();
+
// ARM exception handling directives
void emitFnStart();
void emitFnEnd();
@@ -329,6 +470,198 @@ void ARMTargetELFStreamer::emitRegSave(const SmallVectorImpl<unsigned> &RegList,
bool isVector) {
getStreamer().emitRegSave(RegList, isVector);
}
+void ARMTargetELFStreamer::switchVendor(StringRef Vendor) {
+ assert(!Vendor.empty() && "Vendor cannot be empty.");
+
+ if (CurrentVendor == Vendor)
+ return;
+
+ if (!CurrentVendor.empty())
+ finishAttributeSection();
+
+ assert(Contents.empty() &&
+ ".ARM.attributes should be flushed before changing vendor");
+ CurrentVendor = Vendor;
+
+}
+void ARMTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
+ setAttributeItem(Attribute, Value, /* OverwriteExisting= */ true);
+}
+void ARMTargetELFStreamer::emitTextAttribute(unsigned Attribute,
+ StringRef Value) {
+ setAttributeItem(Attribute, Value, /* OverwriteExisting= */ true);
+}
+void ARMTargetELFStreamer::emitFPU(unsigned Value) {
+ FPU = Value;
+}
+void ARMTargetELFStreamer::emitFPUDefaultAttributes() {
+ switch (FPU) {
+ case ARM::VFP:
+ case ARM::VFPV2:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPv2,
+ /* OverwriteExisting= */ false);
+ break;
+
+ case ARM::VFPV3:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPv3A,
+ /* OverwriteExisting= */ false);
+ break;
+
+ case ARM::VFPV3_D16:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPv3B,
+ /* OverwriteExisting= */ false);
+ break;
+
+ case ARM::VFPV4:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPv4A,
+ /* OverwriteExisting= */ false);
+ break;
+
+ case ARM::VFPV4_D16:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPv4B,
+ /* OverwriteExisting= */ false);
+ break;
+
+ case ARM::FP_ARMV8:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPARMv8A,
+ /* OverwriteExisting= */ false);
+ break;
+
+ case ARM::NEON:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPv3A,
+ /* OverwriteExisting= */ false);
+ setAttributeItem(ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeon,
+ /* OverwriteExisting= */ false);
+ break;
+
+ case ARM::NEON_VFPV4:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPv4A,
+ /* OverwriteExisting= */ false);
+ setAttributeItem(ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeon2,
+ /* OverwriteExisting= */ false);
+ break;
+
+ case ARM::NEON_FP_ARMV8:
+ case ARM::CRYPTO_NEON_FP_ARMV8:
+ setAttributeItem(ARMBuildAttrs::VFP_arch,
+ ARMBuildAttrs::AllowFPARMv8A,
+ /* OverwriteExisting= */ false);
+ setAttributeItem(ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeonARMv8,
+ /* OverwriteExisting= */ false);
+ break;
+
+ default:
+ report_fatal_error("Unknown FPU: " + Twine(FPU));
+ break;
+ }
+}
+size_t ARMTargetELFStreamer::calculateContentSize() const {
+ size_t Result = 0;
+ for (size_t i = 0; i < Contents.size(); ++i) {
+ AttributeItem item = Contents[i];
+ switch (item.Type) {
+ case AttributeItem::HiddenAttribute:
+ break;
+ case AttributeItem::NumericAttribute:
+ Result += getULEBSize(item.Tag);
+ Result += getULEBSize(item.IntValue);
+ break;
+ case AttributeItem::TextAttribute:
+ Result += getULEBSize(item.Tag);
+ Result += item.StringValue.size() + 1; // string + '\0'
+ break;
+ }
+ }
+ return Result;
+}
+void ARMTargetELFStreamer::finishAttributeSection() {
+ // <format-version>
+ // [ <section-length> "vendor-name"
+ // [ <file-tag> <size> <attribute>*
+ // | <section-tag> <size> <section-number>* 0 <attribute>*
+ // | <symbol-tag> <size> <symbol-number>* 0 <attribute>*
+ // ]+
+ // ]*
+
+ if (FPU != ARM::INVALID_FPU)
+ emitFPUDefaultAttributes();
+
+ if (Contents.empty())
+ return;
+
+ std::sort(Contents.begin(), Contents.end(), AttributeItem::LessTag);
+
+ ARMELFStreamer &Streamer = getStreamer();
+
+ // Switch to .ARM.attributes section
+ if (AttributeSection) {
+ Streamer.SwitchSection(AttributeSection);
+ } else {
+ AttributeSection =
+ Streamer.getContext().getELFSection(".ARM.attributes",
+ ELF::SHT_ARM_ATTRIBUTES,
+ 0,
+ SectionKind::getMetadata());
+ Streamer.SwitchSection(AttributeSection);
+
+ // Format version
+ Streamer.EmitIntValue(0x41, 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(ARMBuildAttrs::File, 1);
+ Streamer.EmitIntValue(TagHeaderSize + ContentsSize, 4);
+
+ // Size should have been accounted for already, now
+ // emit each field as its type (ULEB or String)
+ for (size_t i = 0; i < Contents.size(); ++i) {
+ AttributeItem item = Contents[i];
+ Streamer.EmitULEB128IntValue(item.Tag);
+ switch (item.Type) {
+ default: llvm_unreachable("Invalid attribute type");
+ case AttributeItem::NumericAttribute:
+ Streamer.EmitULEB128IntValue(item.IntValue);
+ break;
+ case AttributeItem::TextAttribute:
+ Streamer.EmitBytes(item.StringValue.upper());
+ Streamer.EmitIntValue(0, 1); // '\0'
+ break;
+ }
+ }
+
+ Contents.clear();
+ FPU = ARM::INVALID_FPU;
+}
+
+void ARMELFStreamer::FinishImpl() {
+ MCTargetStreamer &TS = getTargetStreamer();
+ ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
+ ATS.finishAttributeSection();
+
+ MCELFStreamer::FinishImpl();
+}
inline void ARMELFStreamer::SwitchToEHSection(const char *Prefix,
unsigned Type,
diff --git a/test/CodeGen/ARM/2010-09-29-mc-asm-header-test.ll b/test/CodeGen/ARM/2010-09-29-mc-asm-header-test.ll
index e9e9def8d3..925d0cd366 100644
--- a/test/CodeGen/ARM/2010-09-29-mc-asm-header-test.ll
+++ b/test/CodeGen/ARM/2010-09-29-mc-asm-header-test.ll
@@ -1,3 +1,6 @@
+; This tests that MC/asm header conversion is smooth and that the
+; build attributes are correct
+
; RUN: llc < %s -mtriple=armv6-linux-gnueabi | FileCheck %s --check-prefix=V6
; RUN: llc < %s -mtriple=thumbv6m-linux-gnueabi | FileCheck %s --check-prefix=V6M
; RUN: llc < %s -mtriple=armv6-linux-gnueabi -mcpu=arm1156t2f-s | FileCheck %s --check-prefix=ARM1156T2F-S
@@ -10,13 +13,12 @@
; RUN: llc < %s -mtriple=armv8-linux-gnueabi -mattr=-crypto | FileCheck %s --check-prefix=V8-FPARMv8-NEON
; RUN: llc < %s -mtriple=armv8-linux-gnueabi | FileCheck %s --check-prefix=V8-FPARMv8-NEON-CRYPTO
; RUN: llc < %s -mtriple=armv7-linux-gnueabi -mcpu=cortex-a9 | FileCheck %s --check-prefix=CORTEX-A9
+; RUN: llc < %s -mtriple=armv7-linux-gnueabi -mcpu=cortex-a15 | FileCheck %s --check-prefix=CORTEX-A15
; RUN: llc < %s -mtriple=thumbv6m-linux-gnueabi -mcpu=cortex-m0 | FileCheck %s --check-prefix=CORTEX-M0
; RUN: llc < %s -mtriple=thumbv7m-linux-gnueabi -mcpu=cortex-m4 | FileCheck %s --check-prefix=CORTEX-M4
; RUN: llc < %s -mtriple=armv7r-linux-gnueabi -mcpu=cortex-r5 | FileCheck %s --check-prefix=CORTEX-R5
; RUN: llc < %s -mtriple=armv8-linux-gnueabi -mcpu=cortex-a53 | FileCheck %s --check-prefix=CORTEX-A53
; RUN: llc < %s -mtriple=armv8-linux-gnueabi -mcpu=cortex-a57 | FileCheck %s --check-prefix=CORTEX-A57
-; This tests that MC/asm header conversion is smooth and that build attributes are correct
-;
; V6: .eabi_attribute 6, 6
; V6: .eabi_attribute 8, 1
@@ -34,7 +36,6 @@
; ARM1156T2F-S: .eabi_attribute 6, 8
; ARM1156T2F-S: .eabi_attribute 8, 1
; ARM1156T2F-S: .eabi_attribute 9, 2
-; ARM1156T2F-S: .eabi_attribute 10, 2
; ARM1156T2F-S: .fpu vfpv2
; ARM1156T2F-S: .eabi_attribute 20, 1
; ARM1156T2F-S: .eabi_attribute 21, 1
@@ -66,7 +67,6 @@
; V8-FPARMv8: .syntax unified
; V8-FPARMv8: .eabi_attribute 6, 14
-; V8-FPARMv8: .eabi_attribute 10, 7
; V8-FPARMv8: .fpu fp-armv8
; V8-NEON: .syntax unified
@@ -77,13 +77,11 @@
; V8-FPARMv8-NEON: .syntax unified
; V8-FPARMv8-NEON: .eabi_attribute 6, 14
; V8-FPARMv8-NEON: .fpu neon-fp-armv8
-; V8-FPARMv8-NEON: .eabi_attribute 10, 7
; V8-FPARMv8-NEON: .eabi_attribute 12, 3
; V8-FPARMv8-NEON-CRYPTO: .syntax unified
; V8-FPARMv8-NEON-CRYPTO: .eabi_attribute 6, 14
; V8-FPARMv8-NEON-CRYPTO: .fpu crypto-neon-fp-armv8
-; V8-FPARMv8-NEON-CRYPTO: .eabi_attribute 10, 7
; V8-FPARMv8-NEON-CRYPTO: .eabi_attribute 12, 3
; CORTEX-A9: .cpu cortex-a9
@@ -92,14 +90,25 @@
; CORTEX-A9: .eabi_attribute 8, 1
; CORTEX-A9: .eabi_attribute 9, 2
; CORTEX-A9: .fpu neon
-; CORTEX-A9: .eabi_attribute 10, 3
-; CORTEX-A9: .eabi_attribute 12, 1
; CORTEX-A9: .eabi_attribute 20, 1
; CORTEX-A9: .eabi_attribute 21, 1
; CORTEX-A9: .eabi_attribute 23, 3
; CORTEX-A9: .eabi_attribute 24, 1
; CORTEX-A9: .eabi_attribute 25, 1
+; CORTEX-A15: .cpu cortex-a15
+; CORTEX-A15: .eabi_attribute 6, 10
+; CORTEX-A15: .eabi_attribute 7, 65
+; CORTEX-A15: .eabi_attribute 8, 1
+; CORTEX-A15: .eabi_attribute 9, 2
+; CORTEX-A15: .fpu neon-vfpv4
+; CORTEX-A15: .eabi_attribute 20, 1
+; CORTEX-A15: .eabi_attribute 21, 1
+; CORTEX-A15: .eabi_attribute 23, 3
+; CORTEX-A15: .eabi_attribute 24, 1
+; CORTEX-A15: .eabi_attribute 25, 1
+; CORTEX-A15: .eabi_attribute 44, 2
+
; CORTEX-M0: .cpu cortex-m0
; CORTEX-M0: .eabi_attribute 6, 12
; CORTEX-M0: .eabi_attribute 7, 77
@@ -113,8 +122,7 @@
; CORTEX-M4: .eabi_attribute 7, 77
; CORTEX-M4: .eabi_attribute 8, 0
; CORTEX-M4: .eabi_attribute 9, 2
-; CORTEX-M4: .eabi_attribute 10, 6
-; CORTEX-M4: .fpu vfpv4
+; CORTEX-M4: .fpu vfpv4-d16
; CORTEX-M4: .eabi_attribute 20, 1
; CORTEX-M4: .eabi_attribute 21, 1
; CORTEX-M4: .eabi_attribute 23, 3
@@ -127,8 +135,7 @@
; CORTEX-R5: .eabi_attribute 7, 82
; CORTEX-R5: .eabi_attribute 8, 1
; CORTEX-R5: .eabi_attribute 9, 2
-; CORTEX-R5: .eabi_attribute 10, 4
-; CORTEX-R5: .fpu vfpv3
+; CORTEX-R5: .fpu vfpv3-d16
; CORTEX-R5: .eabi_attribute 20, 1
; CORTEX-R5: .eabi_attribute 21, 1
; CORTEX-R5: .eabi_attribute 23, 3
@@ -142,7 +149,6 @@
; CORTEX-A53: .eabi_attribute 8, 1
; CORTEX-A53: .eabi_attribute 9, 2
; CORTEX-A53: .fpu crypto-neon-fp-armv8
-; CORTEX-A53: .eabi_attribute 10, 7
; CORTEX-A53: .eabi_attribute 12, 3
; CORTEX-A53: .eabi_attribute 24, 1
; CORTEX-A53: .eabi_attribute 25, 1
@@ -154,7 +160,6 @@
; CORTEX-A57: .eabi_attribute 8, 1
; CORTEX-A57: .eabi_attribute 9, 2
; CORTEX-A57: .fpu crypto-neon-fp-armv8
-; CORTEX-A57: .eabi_attribute 10, 7
; CORTEX-A57: .eabi_attribute 12, 3
; CORTEX-A57: .eabi_attribute 24, 1
; CORTEX-A57: .eabi_attribute 25, 1
diff --git a/test/CodeGen/ARM/2010-10-19-mc-elf-objheader.ll b/test/CodeGen/ARM/2010-10-19-mc-elf-objheader.ll
index 09246917e2..4efccabf0c 100644
--- a/test/CodeGen/ARM/2010-10-19-mc-elf-objheader.ll
+++ b/test/CodeGen/ARM/2010-10-19-mc-elf-objheader.ll
@@ -1,13 +1,36 @@
-; RUN: llc %s -mtriple=arm-linux-gnueabi -filetype=obj -o - | \
-; RUN: llvm-readobj -s -sd | FileCheck -check-prefix=BASIC %s
-; RUN: llc %s -mtriple=armv7-linux-gnueabi -march=arm -mcpu=cortex-a8 \
-; RUN: -mattr=-neon,-vfp3,+vfp2 \
-; RUN: -arm-reserve-r9 -filetype=obj -o - | \
-; RUN: llvm-readobj -s -sd | FileCheck -check-prefix=CORTEXA8 %s
+; This tests that the expected ARM attributes are emitted.
+; RUN: llc < %s -mtriple=arm-linux-gnueabi -filetype=obj -o - \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=BASIC
+; RUN: llc < %s -mtriple=armv7-linux-gnueabi -march=arm -mcpu=cortex-a8 \
+; RUN: -mattr=-neon,-vfp3,+vfp2 -arm-reserve-r9 -filetype=obj -o - \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=CORTEX-A8
+; RUN: llc < %s -mtriple=armv7-linux-gnueabi -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=V7
+; RUN: llc < %s -mtriple=armv8-linux-gnueabi -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=V8
+; RUN: llc < %s -mtriple=thumbv8-linux-gnueabi -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=Vt8
+; RUN: llc < %s -mtriple=armv8-linux-gnueabi \
+; RUN: -mattr=-neon,-crypto -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=V8-FPARMv8
+; RUN: llc < %s -mtriple=armv8-linux-gnueabi \
+; RUN: -mattr=-fp-armv8,-crypto -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=V8-NEON
+; RUN: llc < %s -mtriple=armv8-linux-gnueabi \
+; RUN: -mattr=-crypto -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=V8-FPARMv8-NEON
+; RUN: llc < %s -mtriple=armv7-linux-gnueabi -mcpu=cortex-a9 -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=CORTEX-A9
+; RUN: llc < %s -mtriple=armv7-linux-gnueabi -mcpu=cortex-a15 -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=CORTEX-A15
+; RUN: llc < %s -mtriple=thumbv6m-linux-gnueabi -mcpu=cortex-m0 -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=CORTEX-M0
+; RUN: llc < %s -mtriple=thumbv7m-linux-gnueabi -mcpu=cortex-m4 -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=CORTEX-M4
+; RUN: llc < %s -mtriple=armv7r-linux-gnueabi -mcpu=cortex-r5 -filetype=obj \
+; RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=CORTEX-R5
-; This tests that the extpected ARM attributes are emitted.
-;
; BASIC: Section {
; BASIC: Name: .ARM.attributes
; BASIC-NEXT: Type: SHT_ARM_ATTRIBUTES
@@ -25,22 +48,215 @@
; BASIC-NEXT: 0010: 06010801 14011501 17031801 1901
; BASIC-NEXT: )
-; CORTEXA8: Name: .ARM.attributes
-; CORTEXA8-NEXT: Type: SHT_ARM_ATTRIBUTES
-; CORTEXA8-NEXT: Flags [ (0x0)
-; CORTEXA8-NEXT: ]
-; CORTEXA8-NEXT: Address: 0x0
-; CORTEXA8-NEXT: Offset: 0x3C
-; CORTEXA8-NEXT: Size: 47
-; CORTEXA8-NEXT: Link: 0
-; CORTEXA8-NEXT: Info: 0
-; CORTEXA8-NEXT: AddressAlignment: 1
-; CORTEXA8-NEXT: EntrySize: 0
-; CORTEXA8-NEXT: SectionData (
-; CORTEXA8-NEXT: 0000: 412E0000 00616561 62690001 24000000
-; CORTEXA8-NEXT: 0010: 05434F52 5445582D 41380006 0A074108
-; CORTEXA8-NEXT: 0020: 0109020A 02140115 01170318 011901
-; CORTEXA8-NEXT: )
+; CORTEX-A8: Name: .ARM.attributes
+; CORTEX-A8-NEXT: Type: SHT_ARM_ATTRIBUTES
+; CORTEX-A8-NEXT: Flags [ (0x0)
+; CORTEX-A8-NEXT: ]
+; CORTEX-A8-NEXT: Address: 0x0
+; CORTEX-A8-NEXT: Offset: 0x3C
+; CORTEX-A8-NEXT: Size: 47
+; CORTEX-A8-NEXT: Link: 0
+; CORTEX-A8-NEXT: Info: 0
+; CORTEX-A8-NEXT: AddressAlignment: 1
+; CORTEX-A8-NEXT: EntrySize: 0
+; CORTEX-A8-NEXT: SectionData (
+; CORTEX-A8-NEXT: 0000: 412E0000 00616561 62690001 24000000
+; CORTEX-A8-NEXT: 0010: 05434F52 5445582D 41380006 0A074108
+; CORTEX-A8-NEXT: 0020: 0109020A 02140115 01170318 011901
+; CORTEX-A8-NEXT: )
+
+; V7: Name: .ARM.attributes
+; V7-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; V7-NEXT: Flags [ (0x0)
+; V7-NEXT: ]
+; V7-NEXT: Address: 0x0
+; V7-NEXT: Offset: 0x3C
+; V7-NEXT: Size: 36
+; V7-NEXT: Link: 0
+; V7-NEXT: Info: 0
+; V7-NEXT: AddressAlignment: 1
+; V7-NEXT: EntrySize: 0
+; V7-NEXT: SectionData (
+; V7-NEXT: 0000: 41230000 00616561 62690001 19000000
+; V7-NEXT: 0010: 060A0801 09020A03 0C011401 15011703
+; V7-NEXT: 0020: 18011901
+; V7-NEXT: )
+
+; V8: Name: .ARM.attributes
+; V8-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; V8-NEXT: Flags [ (0x0)
+; V8-NEXT: ]
+; V8-NEXT: Address: 0x0
+; V8-NEXT: Offset: 0x3C
+; V8-NEXT: Size: 38
+; V8-NEXT: Link: 0
+; V8-NEXT: Info: 0
+; V8-NEXT: AddressAlignment: 1
+; V8-NEXT: EntrySize: 0
+; V8-NEXT: SectionData (
+; V8-NEXT: 0000: 41250000 00616561 62690001 1B000000
+; V8-NEXT: 0010: 060E0801 09020A07 0C031401 15011703
+; V8-NEXT: 0020: 18011901 2C02
+; V8-NEXT: )
+
+; Vt8: Name: .ARM.attributes
+; Vt8-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; Vt8-NEXT: Flags [ (0x0)
+; Vt8-NEXT: ]
+; Vt8-NEXT: Address: 0x0
+; Vt8-NEXT: Offset: 0x38
+; Vt8-NEXT: Size: 38
+; Vt8-NEXT: Link: 0
+; Vt8-NEXT: Info: 0
+; Vt8-NEXT: AddressAlignment: 1
+; Vt8-NEXT: EntrySize: 0
+; Vt8-NEXT: SectionData (
+; Vt8-NEXT: 0000: 41250000 00616561 62690001 1B000000
+; Vt8-NEXT: 0010: 060E0801 09020A07 0C031401 15011703
+; Vt8-NEXT: 0020: 18011901 2C02
+; Vt8-NEXT: )
+
+
+; V8-FPARMv8: Name: .ARM.attributes
+; V8-FPARMv8-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; V8-FPARMv8-NEXT: Flags [ (0x0)
+; V8-FPARMv8-NEXT: ]
+; V8-FPARMv8-NEXT: Address: 0x0
+; V8-FPARMv8-NEXT: Offset: 0x3C
+; V8-FPARMv8-NEXT: Size: 36
+; V8-FPARMv8-NEXT: Link: 0
+; V8-FPARMv8-NEXT: Info: 0
+; V8-FPARMv8-NEXT: AddressAlignment: 1
+; V8-FPARMv8-NEXT: EntrySize: 0
+; V8-FPARMv8-NEXT: SectionData (
+; V8-FPARMv8-NEXT: 0000: 41230000 00616561 62690001 19000000
+; V8-FPARMv8-NEXT: 0010: 060E0801 09020A07 14011501 17031801
+; V8-FPARMv8-NEXT: 0020: 19012C02
+; V8-FPARMv8-NEXT: )
+
+
+; V8-NEON: Name: .ARM.attributes
+; V8-NEON-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; V8-NEON-NEXT: Flags [ (0x0)
+; V8-NEON-NEXT: ]
+; V8-NEON-NEXT: Address: 0x0
+; V8-NEON-NEXT: Offset: 0x3C
+; V8-NEON-NEXT: Size: 38
+; V8-NEON-NEXT: Link: 0
+; V8-NEON-NEXT: Info: 0
+; V8-NEON-NEXT: AddressAlignment: 1
+; V8-NEON-NEXT: EntrySize: 0
+; V8-NEON-NEXT: SectionData (
+; V8-NEON-NEXT: 0000: 41250000 00616561 62690001 1B000000
+; V8-NEON-NEXT: 0010: 060E0801 09020A05 0C031401 15011703
+; V8-NEON-NEXT: 0020: 18011901 2C02
+; V8-NEON-NEXT: )
+
+; V8-FPARMv8-NEON: Name: .ARM.attributes
+; V8-FPARMv8-NEON-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; V8-FPARMv8-NEON-NEXT: Flags [ (0x0)
+; V8-FPARMv8-NEON-NEXT: ]
+; V8-FPARMv8-NEON-NEXT: Address: 0x0
+; V8-FPARMv8-NEON-NEXT: Offset: 0x3C
+; V8-FPARMv8-NEON-NEXT: Size: 38
+; V8-FPARMv8-NEON-NEXT: Link: 0
+; V8-FPARMv8-NEON-NEXT: Info: 0
+; V8-FPARMv8-NEON-NEXT: AddressAlignment: 1
+; V8-FPARMv8-NEON-NEXT: EntrySize: 0
+; V8-FPARMv8-NEON-NEXT: SectionData (
+; V8-FPARMv8-NEON-NEXT: 0000: 41250000 00616561 62690001 1B000000
+; V8-FPARMv8-NEON-NEXT: 0010: 060E0801 09020A07 0C031401 15011703
+; V8-FPARMv8-NEON-NEXT: 0020: 18011901 2C02
+; V8-FPARMv8-NEON-NEXT: )
+
+; CORTEX-A9: Name: .ARM.attributes
+; CORTEX-A9-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; CORTEX-A9-NEXT: Flags [ (0x0)
+; CORTEX-A9-NEXT: ]
+; CORTEX-A9-NEXT: Address: 0x0
+; CORTEX-A9-NEXT: Offset: 0x3C
+; CORTEX-A9-NEXT: Size: 49
+; CORTEX-A9-NEXT: Link: 0
+; CORTEX-A9-NEXT: Info: 0
+; CORTEX-A9-NEXT: AddressAlignment: 1
+; CORTEX-A9-NEXT: EntrySize: 0
+; CORTEX-A9-NEXT: SectionData (
+; CORTEX-A9-NEXT: 0000: 41300000 00616561 62690001 26000000
+; CORTEX-A9-NEXT: 0010: 05434F52 5445582D 41390006 0A074108
+; CORTEX-A9-NEXT: 0020: 0109020A 030C0114 01150117 03180119
+; CORTEX-A9-NEXT: 0030: 01
+; CORTEX-A9-NEXT: )
+
+; CORTEX-A15: Name: .ARM.attributes
+; CORTEX-A15-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; CORTEX-A15-NEXT: Flags [ (0x0)
+; CORTEX-A15-NEXT: ]
+; CORTEX-A15-NEXT: Address: 0x0
+; CORTEX-A15-NEXT: Offset: 0x3C
+; CORTEX-A15-NEXT: Size: 52
+; CORTEX-A15-NEXT: Link: 0
+; CORTEX-A15-NEXT: Info: 0
+; CORTEX-A15-NEXT: AddressAlignment: 1
+; CORTEX-A15-NEXT: EntrySize: 0
+; CORTEX-A15-NEXT: SectionData (
+; CORTEX-A15-NEXT: 0000: 41330000 00616561 62690001 29000000
+; CORTEX-A15-NEXT: 0010: 05434F52 5445582D 41313500 060A0741
+; CORTEX-A15-NEXT: 0020: 08010902 0A050C02 14011501 17031801
+; CORTEX-A15-NEXT: 0030: 19012C02
+; CORTEX-A15-NEXT: )
+
+; CORTEX-M0: Name: .ARM.attributes
+; CORTEX-M0-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; CORTEX-M0-NEXT: Flags [ (0x0)
+; CORTEX-M0-NEXT: ]
+; CORTEX-M0-NEXT: Address: 0x0
+; CORTEX-M0-NEXT: Offset: 0x38
+; CORTEX-M0-NEXT: Size: 45
+; CORTEX-M0-NEXT: Link: 0
+; CORTEX-M0-NEXT: Info: 0
+; CORTEX-M0-NEXT: AddressAlignment: 1
+; CORTEX-M0-NEXT: EntrySize: 0
+; CORTEX-M0-NEXT: SectionData (
+; CORTEX-M0-NEXT: 0000: 412C0000 00616561 62690001 22000000
+; CORTEX-M0-NEXT: 0010: 05434F52 5445582D 4D300006 0C074D08
+; CORTEX-M0-NEXT: 0020: 00090114 01150117 03180119 01
+; CORTEX-M0-NEXT: )
+
+; CORTEX-M4: Name: .ARM.attributes
+; CORTEX-M4-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; CORTEX-M4-NEXT: Flags [ (0x0)
+; CORTEX-M4-NEXT: ]
+; CORTEX-M4-NEXT: Address: 0x0
+; CORTEX-M4-NEXT: Offset: 0x38
+; CORTEX-M4-NEXT: Size: 49
+; CORTEX-M4-NEXT: Link: 0
+; CORTEX-M4-NEXT: Info: 0
+; CORTEX-M4-NEXT: AddressAlignment: 1
+; CORTEX-M4-NEXT: EntrySize: 0
+; CORTEX-M4-NEXT: SectionData (
+; CORTEX-M4-NEXT: 0000: 41300000 00616561 62690001 26000000
+; CORTEX-M4-NEXT: 0010: 05434F52 5445582D 4D340006 0D074D08
+; CORTEX-M4-NEXT: 0020: 0009020A 06140115 01170318 0119012C
+; CORTEX-M4-NEXT: 0030: 00
+; CORTEX-M4-NEXT: )
+
+; CORTEX-R5: Name: .ARM.attributes
+; CORTEX-R5-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+; CORTEX-R5-NEXT: Flags [ (0x0)
+; CORTEX-R5-NEXT: ]
+; CORTEX-R5-NEXT: Address: 0x0
+; CORTEX-R5-NEXT: Offset: 0x3C
+; CORTEX-R5-NEXT: Size: 49
+; CORTEX-R5-NEXT: Link: 0
+; CORTEX-R5-NEXT: Info: 0
+; CORTEX-R5-NEXT: AddressAlignment: 1
+; CORTEX-R5-NEXT: EntrySize: 0
+; CORTEX-R5-NEXT: SectionData (
+; CORTEX-R5-NEXT: 0000: 41300000 00616561 62690001 26000000
+; CORTEX-R5-NEXT: 0010: 05434F52 5445582D 52350006 0A075208
+; CORTEX-R5-NEXT: 0020: 0109020A 04140115 01170318 0119012C
+; CORTEX-R5-NEXT: 0030: 02
+; CORTEX-R5-NEXT: )
define i32 @f(i64 %z) {
ret i32 0
diff --git a/test/MC/ARM/directive-cpu.s b/test/MC/ARM/directive-cpu.s
new file mode 100644
index 0000000000..952dd93f37
--- /dev/null
+++ b/test/MC/ARM/directive-cpu.s
@@ -0,0 +1,26 @@
+@ RUN: llvm-mc < %s -triple armv7-unknown-linux-gnueabi -filetype=obj -o - \
+@ RUN: | llvm-readobj -s -sd | FileCheck %s
+
+@ CHECK: Name: .ARM.attribute
+@ CHECK: SectionData (
+
+@ <format-version>
+@ CHECK: 41
+
+@ <section-length>
+@ CHECK: 1A0000 00
+
+@ <vendor-name> "aeabi\0"
+@ CHECK: 616561 626900
+
+@ <file-tag>
+@ CHECK: 01
+
+@ <size>
+@ CHECK: 10000000
+
+ .cpu cortex-a8
+@ CHECK: 05
+@ CHECK: 434F52 5445582D 413800
+
+@ CHECK: )
diff --git a/test/MC/ARM/directive-eabi_attribute.s b/test/MC/ARM/directive-eabi_attribute.s
new file mode 100644
index 0000000000..c060b809c8
--- /dev/null
+++ b/test/MC/ARM/directive-eabi_attribute.s
@@ -0,0 +1,56 @@
+@ RUN: llvm-mc < %s -triple armv7-unknown-linux-gnueabi -filetype=obj -o - \
+@ RUN: | llvm-readobj -s -sd | FileCheck %s
+
+@ CHECK: Name: .ARM.attribute
+@ CHECK: SectionData (
+
+@ <format-version>
+@ CHECK: 41
+
+@ <section-length>
+@ CHECK: 250000 00
+
+@ <vendor-name> "aeabi\0"
+@ CHECK: 616561 626900
+
+@ <file-tag>
+@ CHECK: 01
+
+@ <size>
+@ CHECK: 1B000000
+
+@ <attribute>*
+
+ .eabi_attribute 6, 10
+@ CHECK: 060A
+
+ .eabi_attribute 7, 65
+@ CHECK: 0741
+
+ .eabi_attribute 8, 1
+@ CHECK: 0801
+
+ .eabi_attribute 9, 2
+@ CHECK: 0902
+
+ .eabi_attribute 10, 3
+@ CHECK: 0A03
+
+ .eabi_attribute 12, 1
+@ CHECK: 0C01
+
+ .eabi_attribute 20, 1
+@ CHECK: 1401
+
+ .eabi_attribute 21, 1
+@ CHECK: 1501
+
+ .eabi_attribute 23, 3
+@ CHECK: 1703
+
+ .eabi_attribute 24, 1
+@ CHECK: 1801
+
+ .eabi_attribute 25, 1
+@ CHECK: 1901
+@ CHECK: )
diff --git a/test/MC/ARM/directive-fpu-multiple.s b/test/MC/ARM/directive-fpu-multiple.s
new file mode 100644
index 0000000000..6a93f24682
--- /dev/null
+++ b/test/MC/ARM/directive-fpu-multiple.s
@@ -0,0 +1,26 @@
+@ Check multiple .fpu directives.
+
+@ The later .fpu directive should overwrite the earlier one.
+@ See also: directive-fpu-multiple2.s.
+
+@ RUN: llvm-mc < %s -triple arm-unknown-linux-gnueabi -filetype=obj \
+@ RUN: | llvm-readobj -s -sd | FileCheck %s
+
+ .fpu neon
+ .fpu vfpv4
+
+@ CHECK: Name: .ARM.attributes
+@ CHECK-NEXT: Type: SHT_ARM_ATTRIBUTES (0x70000003)
+@ CHECK-NEXT: Flags [ (0x0)
+@ CHECK-NEXT: ]
+@ CHECK-NEXT: Address: 0x0
+@ CHECK-NEXT: Offset: 0x34
+@ CHECK-NEXT: Size: 18
+@ CHECK-NEXT: Link: 0
+@ CHECK-NEXT: Info: 0
+@ CHECK-NEXT: AddressAlignment: 1
+@ CHECK-NEXT: EntrySize: 0
+@ CHECK-NEXT: SectionData (
+@ CHECK-NEXT: 0000: 41110000 00616561 62690001 07000000
+@ CHECK-NEXT: 0010: 0A05
+@ CHECK-NEXT: )
diff --git a/test/MC/ARM/directive-fpu.s b/test/MC/ARM/directive-fpu.s
new file mode 100644
index 0000000000..24e159c74f
--- /dev/null
+++ b/test/MC/ARM/directive-fpu.s
@@ -0,0 +1,26 @@
+@ RUN: llvm-mc < %s -triple armv7-unknown-linux-gnueabi -filetype=obj -o - \
+@ RUN: | llvm-readobj -s -sd | FileCheck %s
+
+@ CHECK: Name: .ARM.attribute
+@ CHECK: SectionData (
+
+@ <format-version>
+@ CHECK: 41
+
+@ <section-length>
+@ CHECK: 130000 00
+
+@ <vendor-name> "aeabi\0"
+@ CHECK: 616561 626900
+
+@ <file-tag>
+@ CHECK: 01
+
+@ <size>
+@ CHECK: 09000000
+
+ .fpu neon
+@ CHECK: 0A03
+@ CHECK: 0C01
+
+@ CHECK: )