Fix x86 floating-point constant emission.

Previously, the basis of constant pooling was implemented, but two things were lacking:

1. The constant pools were not being emitted in the asm file.

2. A direct FP value was emitted in an FP instruction, e.g. "addss xmm0, 1.0000e00".  Curiously, at least for some FP constants, llvm-mc was accepting this syntax.

BUG= none
R=jfb@chromium.org

Review URL: https://codereview.chromium.org/291213003
diff --git a/src/IceDefs.h b/src/IceDefs.h
index 6c5cb1a..9870716 100644
--- a/src/IceDefs.h
+++ b/src/IceDefs.h
@@ -61,6 +61,7 @@
 typedef std::list<InstPhi *> PhiList;
 typedef std::vector<Variable *> VarList;
 typedef std::vector<CfgNode *> NodeList;
+typedef std::vector<Constant *> ConstantList;
 
 // SizeT is for holding small-ish limits like number of source
 // operands in an instruction.  It is used instead of size_t (which
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index ab63b4c..7a21b40 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -34,16 +34,27 @@
   TypePool &operator=(const TypePool &) LLVM_DELETED_FUNCTION;
 
 public:
-  TypePool() {}
+  TypePool() : NextPoolID(0) {}
   ValueType *getOrAdd(GlobalContext *Ctx, Type Ty, KeyType Key) {
     TupleType TupleKey = std::make_pair(Ty, Key);
     typename ContainerType::const_iterator Iter = Pool.find(TupleKey);
     if (Iter != Pool.end())
       return Iter->second;
-    ValueType *Result = ValueType::create(Ctx, Ty, Key);
+    ValueType *Result = ValueType::create(Ctx, Ty, Key, NextPoolID++);
     Pool[TupleKey] = Result;
     return Result;
   }
+  ConstantList getConstantPool() const {
+    ConstantList Constants;
+    Constants.reserve(Pool.size());
+    // TODO: replace the loop with std::transform + lambdas.
+    for (typename ContainerType::const_iterator I = Pool.begin(),
+                                                E = Pool.end();
+         I != E; ++I) {
+      Constants.push_back(I->second);
+    }
+    return Constants;
+  }
 
 private:
   typedef std::pair<Type, KeyType> TupleType;
@@ -58,6 +69,7 @@
   };
   typedef std::map<const TupleType, ValueType *, TupleCompare> ContainerType;
   ContainerType Pool;
+  uint32_t NextPoolID;
 };
 
 // The global constant pool bundles individual pools of each type of
@@ -171,6 +183,25 @@
       this, Ty, RelocatableTuple(Offset, Name, SuppressMangling));
 }
 
+ConstantList GlobalContext::getConstantPool(Type Ty) const {
+  switch (Ty) {
+  case IceType_i1:
+  case IceType_i8:
+  case IceType_i16:
+  case IceType_i32:
+  case IceType_i64:
+    return ConstPool->Integers.getConstantPool();
+  case IceType_f32:
+    return ConstPool->Floats.getConstantPool();
+  case IceType_f64:
+    return ConstPool->Doubles.getConstantPool();
+  case IceType_void:
+  case IceType_NUM:
+    break;
+  }
+  llvm_unreachable("Unknown type");
+}
+
 void Timer::printElapsedUs(GlobalContext *Ctx, const IceString &Tag) const {
   if (Ctx->isVerbose(IceV_Timing)) {
     // Prefixing with '#' allows timing strings to be included
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index 1ad5f07..beb5bc0 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -77,6 +77,9 @@
   // Returns a symbolic constant.
   Constant *getConstantSym(Type Ty, int64_t Offset, const IceString &Name = "",
                            bool SuppressMangling = false);
+  // getConstantPool() returns a copy of the constant pool for
+  // constants of a given type.
+  ConstantList getConstantPool(Type Ty) const;
 
   // Allocate data of type T using the global allocator.
   template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
diff --git a/src/IceOperand.h b/src/IceOperand.h
index c75be78..ef4413f 100644
--- a/src/IceOperand.h
+++ b/src/IceOperand.h
@@ -80,6 +80,7 @@
 // constants are allocated from a global arena and are pooled.
 class Constant : public Operand {
 public:
+  uint32_t getPoolEntryID() const { return PoolEntryID; }
   virtual void emit(const Cfg *Func) const = 0;
   virtual void dump(const Cfg *Func) const = 0;
 
@@ -89,11 +90,16 @@
   }
 
 protected:
-  Constant(OperandKind Kind, Type Ty) : Operand(Kind, Ty) {
+  Constant(OperandKind Kind, Type Ty, uint32_t PoolEntryID)
+      : Operand(Kind, Ty), PoolEntryID(PoolEntryID) {
     Vars = NULL;
     NumVars = 0;
   }
   virtual ~Constant() {}
+  // PoolEntryID is an integer that uniquely identifies the constant
+  // within its constant pool.  It is used for building the constant
+  // pool in the object code and for referencing its entries.
+  const uint32_t PoolEntryID;
 
 private:
   Constant(const Constant &) LLVM_DELETED_FUNCTION;
@@ -104,9 +110,10 @@
 template <typename T, Operand::OperandKind K>
 class ConstantPrimitive : public Constant {
 public:
-  static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value) {
+  static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value,
+                                   uint32_t PoolEntryID) {
     return new (Ctx->allocate<ConstantPrimitive>())
-        ConstantPrimitive(Ty, Value);
+        ConstantPrimitive(Ty, Value, PoolEntryID);
   }
   T getValue() const { return Value; }
   virtual void emit(const Cfg *Func) const {
@@ -123,7 +130,8 @@
   }
 
 private:
-  ConstantPrimitive(Type Ty, T Value) : Constant(K, Ty), Value(Value) {}
+  ConstantPrimitive(Type Ty, T Value, uint32_t PoolEntryID)
+      : Constant(K, Ty, PoolEntryID), Value(Value) {}
   ConstantPrimitive(const ConstantPrimitive &) LLVM_DELETED_FUNCTION;
   ConstantPrimitive &operator=(const ConstantPrimitive &) LLVM_DELETED_FUNCTION;
   virtual ~ConstantPrimitive() {}
@@ -161,9 +169,10 @@
 class ConstantRelocatable : public Constant {
 public:
   static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty,
-                                     const RelocatableTuple &Tuple) {
+                                     const RelocatableTuple &Tuple,
+                                     uint32_t PoolEntryID) {
     return new (Ctx->allocate<ConstantRelocatable>()) ConstantRelocatable(
-        Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling);
+        Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling, PoolEntryID);
   }
   int64_t getOffset() const { return Offset; }
   IceString getName() const { return Name; }
@@ -179,9 +188,9 @@
 
 private:
   ConstantRelocatable(Type Ty, int64_t Offset, const IceString &Name,
-                      bool SuppressMangling)
-      : Constant(kConstRelocatable, Ty), Offset(Offset), Name(Name),
-        SuppressMangling(SuppressMangling) {}
+                      bool SuppressMangling, uint32_t PoolEntryID)
+      : Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset),
+        Name(Name), SuppressMangling(SuppressMangling) {}
   ConstantRelocatable(const ConstantRelocatable &) LLVM_DELETED_FUNCTION;
   ConstantRelocatable &
   operator=(const ConstantRelocatable &) LLVM_DELETED_FUNCTION;
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index a24c51d..92a36af 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -149,6 +149,8 @@
   virtual void addProlog(CfgNode *Node) = 0;
   virtual void addEpilog(CfgNode *Node) = 0;
 
+  virtual void emitConstants() const = 0;
+
   virtual ~TargetLowering() {}
 
 protected:
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 32246c4..8ee5ac9 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -562,6 +562,71 @@
   }
 }
 
+template <typename T> struct PoolTypeConverter {};
+
+template <> struct PoolTypeConverter<float> {
+  typedef float PrimitiveFpType;
+  typedef uint32_t PrimitiveIntType;
+  typedef ConstantFloat IceType;
+  static const Type Ty = IceType_f32;
+  static const char *TypeName;
+  static const char *AsmTag;
+  static const char *PrintfString;
+};
+const char *PoolTypeConverter<float>::TypeName = "float";
+const char *PoolTypeConverter<float>::AsmTag = ".long";
+const char *PoolTypeConverter<float>::PrintfString = "0x%x";
+
+template <> struct PoolTypeConverter<double> {
+  typedef double PrimitiveFpType;
+  typedef uint64_t PrimitiveIntType;
+  typedef ConstantDouble IceType;
+  static const Type Ty = IceType_f64;
+  static const char *TypeName;
+  static const char *AsmTag;
+  static const char *PrintfString;
+};
+const char *PoolTypeConverter<double>::TypeName = "double";
+const char *PoolTypeConverter<double>::AsmTag = ".quad";
+const char *PoolTypeConverter<double>::PrintfString = "0x%llx";
+
+template <typename T> void TargetX8632::emitConstantPool() const {
+  Ostream &Str = Ctx->getStrEmit();
+  Type Ty = T::Ty;
+  SizeT Align = typeAlignInBytes(Ty);
+  ConstantList Pool = Ctx->getConstantPool(Ty);
+
+  Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align
+      << "\n";
+  Str << "\t.align\t" << Align << "\n";
+  for (ConstantList::const_iterator I = Pool.begin(), E = Pool.end(); I != E;
+       ++I) {
+    typename T::IceType *Const = llvm::cast<typename T::IceType>(*I);
+    typename T::PrimitiveFpType Value = Const->getValue();
+    // Use memcpy() to copy bits from Value into RawValue in a way
+    // that avoids breaking strict-aliasing rules.
+    typename T::PrimitiveIntType RawValue;
+    memcpy(&RawValue, &Value, sizeof(Value));
+    char buf[30];
+    int CharsPrinted =
+        snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue);
+    assert(CharsPrinted >= 0 &&
+           (size_t)CharsPrinted < llvm::array_lengthof(buf));
+    (void)CharsPrinted; // avoid warnings if asserts are disabled
+    Str << "L$" << Ty << "$" << Const->getPoolEntryID() << ":\n";
+    Str << "\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " "
+        << Value << "\n";
+  }
+}
+
+void TargetX8632::emitConstants() const {
+  emitConstantPool<PoolTypeConverter<float> >();
+  emitConstantPool<PoolTypeConverter<double> >();
+
+  // No need to emit constants from the int pool since (for x86) they
+  // are embedded as immediates in the instructions.
+}
+
 void TargetX8632::split64(Variable *Var) {
   switch (Var->getType()) {
   default:
@@ -1878,4 +1943,16 @@
   }
 }
 
+template <> void ConstantFloat::emit(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrEmit();
+  // It would be better to prefix with ".L$" instead of "L$", but
+  // llvm-mc doesn't parse "dword ptr [.L$foo]".
+  Str << "dword ptr [L$" << IceType_f32 << "$" << getPoolEntryID() << "]";
+}
+
+template <> void ConstantDouble::emit(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrEmit();
+  Str << "qword ptr [L$" << IceType_f64 << "$" << getPoolEntryID() << "]";
+}
+
 } // end of namespace Ice
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index 38184de..e5f8be2 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -47,6 +47,7 @@
   virtual void emitVariable(const Variable *Var, const Cfg *Func) const;
   virtual void addProlog(CfgNode *Node);
   virtual void addEpilog(CfgNode *Node);
+  virtual void emitConstants() const;
   SizeT makeNextLabelNumber() { return NextLabelNumber++; }
   // Ensure that a 64-bit Variable has been split into 2 32-bit
   // Variables, creating them if necessary.  This is needed for all
@@ -261,8 +262,12 @@
   TargetX8632(const TargetX8632 &) LLVM_DELETED_FUNCTION;
   TargetX8632 &operator=(const TargetX8632 &) LLVM_DELETED_FUNCTION;
   virtual ~TargetX8632() {}
+  template <typename T> void emitConstantPool() const;
 };
 
+template <> void ConstantFloat::emit(const Cfg *Func) const;
+template <> void ConstantDouble::emit(const Cfg *Func) const;
+
 } // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICETARGETLOWERINGX8632_H
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index 08f90f8..e29637d 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -19,6 +19,7 @@
 #include "IceGlobalContext.h"
 #include "IceInst.h"
 #include "IceOperand.h"
+#include "IceTargetLowering.h"
 #include "IceTypes.h"
 
 #include "llvm/IR/Constant.h"
@@ -63,6 +64,7 @@
     SubzeroPointerType = Ice::IceType_i32;
   }
 
+  // Caller is expected to delete the returned Ice::Cfg object.
   Ice::Cfg *convertFunction(const Function *F) {
     VarMap.clear();
     NodeMap.clear();
@@ -618,14 +620,11 @@
 static cl::opt<bool> SubzeroTimingEnabled(
     "timing", cl::desc("Enable breakdown timing of Subzero translation"));
 
-static cl::opt<NaClFileFormat>
-InputFileFormat(
-    "bitcode-format",
-    cl::desc("Define format of input file:"),
-    cl::values(
-        clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
-        clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
-        clEnumValEnd),
+static cl::opt<NaClFileFormat> InputFileFormat(
+    "bitcode-format", cl::desc("Define format of input file:"),
+    cl::values(clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
+               clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
+               clEnumValEnd),
     cl::init(LLVMFormat));
 
 int main(int argc, char **argv) {
@@ -670,6 +669,15 @@
   raw_os_ostream *Ls = new raw_os_ostream(LogFilename == "-" ? std::cout : Lfs);
   Ls->SetUnbuffered();
 
+  // Ideally, Func would be declared inside the loop and its object
+  // would be automatically deleted at the end of the loop iteration.
+  // However, emitting the constant pool requires a valid Cfg object,
+  // so we need to defer deleting the last non-empty Cfg object until
+  // outside the loop and after emitting the constant pool.  TODO:
+  // Since all constants are globally pooled in the Ice::GlobalContext
+  // object, change all Ice::Constant related functions to use
+  // GlobalContext instead of Cfg, and then clean up this loop.
+  OwningPtr<Ice::Cfg> Func;
   Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix);
 
   for (Module::const_iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
@@ -678,7 +686,7 @@
     LLVM2ICEConverter FunctionConverter(&Ctx);
 
     Ice::Timer TConvert;
-    Ice::Cfg *Func = FunctionConverter.convertFunction(I);
+    Func.reset(FunctionConverter.convertFunction(I));
     if (DisableInternal)
       Func->setInternal(false);
 
@@ -713,5 +721,8 @@
     }
   }
 
+  if (!DisableTranslation && Func)
+    Func->getTarget()->emitConstants();
+
   return ExitStatus;
 }
diff --git a/tests_lit/llvm2ice_tests/fpconst.pnacl.ll b/tests_lit/llvm2ice_tests/fpconst.pnacl.ll
index 6ca41e4..9bbfe3b 100644
--- a/tests_lit/llvm2ice_tests/fpconst.pnacl.ll
+++ b/tests_lit/llvm2ice_tests/fpconst.pnacl.ll
@@ -6,6 +6,7 @@
 ; number in a reasonable number of digits".  See
 ; http://llvm.org/docs/LangRef.html#simple-constants .
 
+; RUN: %llvm2ice -Om1 --verbose none %s | FileCheck %s
 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
@@ -534,5 +535,16 @@
   ret double %retval.0
 }
 
+; The FP constant pool entries for each type are dumped in some
+; implementation-dependent order.  So for the purposes of lit, we just
+; pick one value for each type, and make sure it appears exactly once.
+
+; Check for float 0.5
+; CHECK:     .long   0x3f000000
+; CHECK-NOT: .long   0x3f000000
+; Check for double 0.5
+; CHECK:     .quad   0x3fe0000000000000
+; CHECK-NOT: .quad   0x3fe0000000000000
+
 ; ERRORS-NOT: ICE translation error
 ; DUMP-NOT: SZ