Emit ARM build-attributes in the file scope (as header).

The ARM linker will check that .o files declare compatible
build attributes (e.g., all claim hard-float calling convention,
all claim VFP-vX ,etc.). Thus, in order to set up cross tests that
link LLC generated code against and Subzero generated code,
we need the build attributes to be compatible.

Pick ARMv7, hard-float calling convention, and neon, etc. which
we use for PNaCl LLVM.

Will probably have to reorganize to keep in sync once the ELF
writer also emits this.

BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076
R=kschimpf@google.com, stichnot@chromium.org

Review URL: https://codereview.chromium.org/1171563002.
diff --git a/src/IceCompiler.cpp b/src/IceCompiler.cpp
index da9172c..2db7abc 100644
--- a/src/IceCompiler.cpp
+++ b/src/IceCompiler.cpp
@@ -102,11 +102,7 @@
 
   TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx);
 
-  if (Ctx.getFlags().getOutFileType() == FT_Elf) {
-    TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
-    Ctx.getObjectWriter()->writeInitialELFHeader();
-  }
-
+  Ctx.emitFileHeader();
   Ctx.startWorkerThreads();
 
   std::unique_ptr<Translator> Translator;
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 87421bc..8ed4d76 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -400,6 +400,17 @@
 
 } // end of anonymous namespace
 
+void GlobalContext::emitFileHeader() {
+  TimerMarker T1(Ice::TimerStack::TT_emit, this);
+  if (getFlags().getOutFileType() == FT_Elf) {
+    getObjectWriter()->writeInitialELFHeader();
+  } else {
+    if (!ALLOW_DUMP)
+      llvm::report_fatal_error("emitFileHeader for non-ELF");
+    TargetHeaderLowering::createLowering(this)->lower();
+  }
+}
+
 void GlobalContext::emitItems() {
   const bool Threaded = !getFlags().isSequential();
   // Pending is a vector containing the reassembled, ordered list of
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index 9fb997c..763a75b 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -300,6 +300,9 @@
   // Notifies that no more work will be added to the work queue.
   void optQueueNotifyEnd() { OptQ.notifyEnd(); }
 
+  // Emit file header for output file.
+  void emitFileHeader();
+
   void emitQueueBlockingPush(EmitterWorkItem *Item);
   EmitterWorkItem *emitQueueBlockingPop();
   void emitQueueNotifyEnd() { EmitQ.notifyEnd(); }
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index b8f11bb..aefad00 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -437,13 +437,25 @@
   TargetArch Target = Ctx->getFlags().getTargetArch();
 #define SUBZERO_TARGET(X)                                                      \
   if (Target == Target_##X)                                                    \
-    return std::unique_ptr<TargetDataLowering>(TargetData##X::create(Ctx));
+    return TargetData##X::create(Ctx);
 #include "llvm/Config/SZTargets.def"
 
-  llvm_unreachable("Unsupported target data lowering");
-  return nullptr;
+  llvm::report_fatal_error("Unsupported target data lowering");
 }
 
 TargetDataLowering::~TargetDataLowering() {}
 
+std::unique_ptr<TargetHeaderLowering>
+TargetHeaderLowering::createLowering(GlobalContext *Ctx) {
+  TargetArch Target = Ctx->getFlags().getTargetArch();
+#define SUBZERO_TARGET(X)                                                      \
+  if (Target == Target_##X)                                                    \
+    return TargetHeader##X::create(Ctx);
+#include "llvm/Config/SZTargets.def"
+
+  llvm::report_fatal_error("Unsupported target header lowering");
+}
+
+TargetHeaderLowering::~TargetHeaderLowering() {}
+
 } // end of namespace Ice
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index a2eac4b..069b49e 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -389,6 +389,26 @@
   GlobalContext *Ctx;
 };
 
+// TargetHeaderLowering is used to "lower" the header of an output file.
+// It writes out the target-specific header attributes. E.g., for ARM
+// this writes out the build attributes (float ABI, etc.).
+class TargetHeaderLowering {
+  TargetHeaderLowering() = delete;
+  TargetHeaderLowering(const TargetHeaderLowering &) = delete;
+  TargetHeaderLowering &operator=(const TargetHeaderLowering &) = delete;
+
+public:
+  static std::unique_ptr<TargetHeaderLowering>
+  createLowering(GlobalContext *Ctx);
+  virtual ~TargetHeaderLowering();
+
+  virtual void lower() {}
+
+protected:
+  explicit TargetHeaderLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
+  GlobalContext *Ctx;
+};
+
 } // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICETARGETLOWERING_H
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 8f7c331..5b7bccc 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -2225,4 +2225,43 @@
   UnimplementedError(Ctx->getFlags());
 }
 
+TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx)
+    : TargetHeaderLowering(Ctx) {}
+
+void TargetHeaderARM32::lower() {
+  OstreamLocker L(Ctx);
+  Ostream &Str = Ctx->getStrEmit();
+  Str << ".syntax unified\n";
+  // Emit build attributes in format: .eabi_attribute TAG, VALUE.
+  // See Sec. 2 of "Addenda to, and Errata in the ABI for the ARM architecture"
+  // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_addenda.pdf
+  //
+  // Tag_conformance should be be emitted first in a file-scope
+  // sub-subsection of the first public subsection of the attributes.
+  Str << ".eabi_attribute 67, \"2.09\"      @ Tag_conformance\n";
+  // Chromebooks are at least A15, but do A9 for higher compat.
+  Str << ".cpu    cortex-a9\n"
+      << ".eabi_attribute 6, 10   @ Tag_CPU_arch: ARMv7\n"
+      << ".eabi_attribute 7, 65   @ Tag_CPU_arch_profile: App profile\n";
+  Str << ".eabi_attribute 8, 1    @ Tag_ARM_ISA_use: Yes\n"
+      << ".eabi_attribute 9, 2    @ Tag_THUMB_ISA_use: Thumb-2\n";
+  // TODO(jvoung): check other CPU features like HW div.
+  Str << ".fpu    neon\n"
+      << ".eabi_attribute 17, 1   @ Tag_ABI_PCS_GOT_use: permit directly\n"
+      << ".eabi_attribute 20, 1   @ Tag_ABI_FP_denormal\n"
+      << ".eabi_attribute 21, 1   @ Tag_ABI_FP_exceptions\n"
+      << ".eabi_attribute 23, 3   @ Tag_ABI_FP_number_model: IEEE 754\n"
+      << ".eabi_attribute 34, 1   @ Tag_CPU_unaligned_access\n"
+      << ".eabi_attribute 24, 1   @ Tag_ABI_align_needed: 8-byte\n"
+      << ".eabi_attribute 25, 1   @ Tag_ABI_align_preserved: 8-byte\n"
+      << ".eabi_attribute 28, 1   @ Tag_ABI_VFP_args\n"
+      << ".eabi_attribute 36, 1   @ Tag_FP_HP_extension\n"
+      << ".eabi_attribute 38, 1   @ Tag_ABI_FP_16bit_format\n"
+      << ".eabi_attribute 42, 1   @ Tag_MPextension_use\n"
+      << ".eabi_attribute 68, 1   @ Tag_Virtualization_use\n";
+  // Technically R9 is used for TLS with Sandboxing, and we reserve it.
+  // However, for compatibility with current NaCl LLVM, don't claim that.
+  Str << ".eabi_attribute 14, 3   @ Tag_ABI_PCS_R9_use: Not used\n";
+}
+
 } // end of namespace Ice
diff --git a/src/IceTargetLoweringARM32.h b/src/IceTargetLoweringARM32.h
index 53c9895..bd7d528 100644
--- a/src/IceTargetLoweringARM32.h
+++ b/src/IceTargetLoweringARM32.h
@@ -308,8 +308,8 @@
   TargetDataARM32 &operator=(const TargetDataARM32 &) = delete;
 
 public:
-  static TargetDataLowering *create(GlobalContext *Ctx) {
-    return new TargetDataARM32(Ctx);
+  static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) {
+    return std::unique_ptr<TargetDataLowering>(new TargetDataARM32(Ctx));
   }
 
   void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) const final;
@@ -324,6 +324,25 @@
   template <typename T> static void emitConstantPool(GlobalContext *Ctx);
 };
 
+class TargetHeaderARM32 final : public TargetHeaderLowering {
+  TargetHeaderARM32() = delete;
+  TargetHeaderARM32(const TargetHeaderARM32 &) = delete;
+  TargetHeaderARM32 &operator=(const TargetHeaderARM32 &) = delete;
+
+public:
+  static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) {
+    return std::unique_ptr<TargetHeaderLowering>(new TargetHeaderARM32(Ctx));
+  }
+
+  void lower();
+
+protected:
+  explicit TargetHeaderARM32(GlobalContext *Ctx);
+
+private:
+  ~TargetHeaderARM32() = default;
+};
+
 } // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICETARGETLOWERINGARM32_H
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 9ca10b7..494f233 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -702,4 +702,7 @@
   llvm::report_fatal_error("Not yet implemented");
 }
 
+TargetHeaderMIPS32::TargetHeaderMIPS32(GlobalContext *Ctx)
+    : TargetHeaderLowering(Ctx) {}
+
 } // end of namespace Ice
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index cb583b5..b6c325a 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -56,18 +56,23 @@
 
   const char *getConstantPrefix() const final { return ""; }
   void emit(const ConstantUndef *C) const final {
+    (void)C;
     llvm::report_fatal_error("Not yet implemented");
   }
   void emit(const ConstantInteger32 *C) const final {
+    (void)C;
     llvm::report_fatal_error("Not yet implemented");
   }
   void emit(const ConstantInteger64 *C) const final {
+    (void)C;
     llvm::report_fatal_error("Not yet implemented");
   }
   void emit(const ConstantFloat *C) const final {
+    (void)C;
     llvm::report_fatal_error("Not yet implemented");
   }
   void emit(const ConstantDouble *C) const final {
+    (void)C;
     llvm::report_fatal_error("Not yet implemented");
   }
 
@@ -128,8 +133,8 @@
   TargetDataMIPS32 &operator=(const TargetDataMIPS32 &) = delete;
 
 public:
-  static TargetDataLowering *create(GlobalContext *Ctx) {
-    return new TargetDataMIPS32(Ctx);
+  static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) {
+    return std::unique_ptr<TargetDataLowering>(new TargetDataMIPS32(Ctx));
   }
 
   void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) const final;
@@ -144,6 +149,23 @@
   template <typename T> static void emitConstantPool(GlobalContext *Ctx);
 };
 
+class TargetHeaderMIPS32 final : public TargetHeaderLowering {
+  TargetHeaderMIPS32() = delete;
+  TargetHeaderMIPS32(const TargetHeaderMIPS32 &) = delete;
+  TargetHeaderMIPS32 &operator=(const TargetHeaderMIPS32 &) = delete;
+
+public:
+  static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) {
+    return std::unique_ptr<TargetHeaderLowering>(new TargetHeaderMIPS32(Ctx));
+  }
+
+protected:
+  explicit TargetHeaderMIPS32(GlobalContext *Ctx);
+
+private:
+  ~TargetHeaderMIPS32() = default;
+};
+
 } // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICETARGETLOWERINGMIPS32_H
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 90bb0e3..506b315 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -5016,4 +5016,7 @@
   }
 }
 
+TargetHeaderX8632::TargetHeaderX8632(GlobalContext *Ctx)
+    : TargetHeaderLowering(Ctx) {}
+
 } // end of namespace Ice
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index def9dcd..ca26fe1 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -581,8 +581,8 @@
   TargetDataX8632 &operator=(const TargetDataX8632 &) = delete;
 
 public:
-  static TargetDataLowering *create(GlobalContext *Ctx) {
-    return new TargetDataX8632(Ctx);
+  static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) {
+    return std::unique_ptr<TargetDataLowering>(new TargetDataX8632(Ctx));
   }
 
   void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) const final;
@@ -597,6 +597,23 @@
   template <typename T> static void emitConstantPool(GlobalContext *Ctx);
 };
 
+class TargetHeaderX8632 final : public TargetHeaderLowering {
+  TargetHeaderX8632() = delete;
+  TargetHeaderX8632(const TargetHeaderX8632 &) = delete;
+  TargetHeaderX8632 &operator=(const TargetHeaderX8632 &) = delete;
+
+public:
+  static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) {
+    return std::unique_ptr<TargetHeaderLowering>(new TargetHeaderX8632(Ctx));
+  }
+
+protected:
+  explicit TargetHeaderX8632(GlobalContext *Ctx);
+
+private:
+  ~TargetHeaderX8632() = default;
+};
+
 } // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICETARGETLOWERINGX8632_H