]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - opencl/llvm.git/commitdiff
[arm] Implement eabi_attribute, cpu, and fpu directives.
authorLogan Chien <tzuhsiang.chien@gmail.com>
Mon, 28 Oct 2013 17:51:12 +0000 (17:51 +0000)
committerLogan Chien <tzuhsiang.chien@gmail.com>
Mon, 28 Oct 2013 17:51:12 +0000 (17:51 +0000)
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

14 files changed:
include/llvm/MC/MCStreamer.h
lib/Target/ARM/ARM.td
lib/Target/ARM/ARMAsmPrinter.cpp
lib/Target/ARM/ARMBuildAttrs.h
lib/Target/ARM/ARMFPUName.def [new file with mode: 0644]
lib/Target/ARM/ARMFPUName.h [new file with mode: 0644]
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
test/CodeGen/ARM/2010-09-29-mc-asm-header-test.ll
test/CodeGen/ARM/2010-10-19-mc-elf-objheader.ll
test/MC/ARM/directive-cpu.s [new file with mode: 0644]
test/MC/ARM/directive-eabi_attribute.s [new file with mode: 0644]
test/MC/ARM/directive-fpu-multiple.s [new file with mode: 0644]
test/MC/ARM/directive-fpu.s [new file with mode: 0644]

index 47d798dd8bd0fee82f75b1d3b4fe72669bc043e5..04af407a445e3535f2bd0f36b7d99a1906b1465e 100644 (file)
@@ -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
index a0592f23d35cb066989dedf5f44994e04f11a474..bf12c323fa6ab2f58d6ea5a10d574691141b81ed 100644 (file)
@@ -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,
index 4899a5decebb8bfdf142c833df4a90d7220c8e64..d1f1d3ed1bbc39b553593262c57c8af8380ce9b8 100644 (file)
@@ -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"
 #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() {
index 44fbf3d0c96d000d246c0b07b10d3e942f2e7873..93edc55d51ff0df94d39b7521529b97997bd0aa5 100644 (file)
 #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 (file)
index 0000000..9a1bbe7
--- /dev/null
@@ -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 (file)
index 0000000..2a64cce
--- /dev/null
@@ -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
index ed71b37b47170309b75898a8693ab0d34dd842ed..ba6075e91df0bcdf4110574c9a392e9124976d73 100644 (file)
@@ -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
index d4110a45d66c4029af3ffa641bab5ab8dba38d45..471897de5c1cb2114ff9b523f4c5c21e7729eca7 100644 (file)
@@ -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,
index e9e9def8d3b23c64a7e8aa00acbd0d92b83ff6ee..925d0cd3668a29107eaa8b55206186231e8112dd 100644 (file)
@@ -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
 ; 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
 ; 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
 ; 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
 ; 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
 ; 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
 ; 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
 ; 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
index 09246917e26b71a4210bcb578463537f5428668d..4efccabf0cba320d4df3b1e0ba49ec26f6f063be 100644 (file)
@@ -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
 ; 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 (file)
index 0000000..952dd93
--- /dev/null
@@ -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 (file)
index 0000000..c060b80
--- /dev/null
@@ -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 (file)
index 0000000..6a93f24
--- /dev/null
@@ -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 (file)
index 0000000..24e159c
--- /dev/null
@@ -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: )