emitIAS for fld and fstp

BUG=none
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/634333002
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp
index fd1f80d..d51eeca 100644
--- a/src/IceInstX8632.cpp
+++ b/src/IceInstX8632.cpp
@@ -1919,7 +1919,7 @@
   assert(Dest->hasReg() && Src->hasReg());
   x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
   intptr_t StartPosition = Asm->GetPosition();
-  Asm->movss(RegX8632::getEncodedXmm(Dest->getRegNum()),
+  Asm->movss(IceType_f32, RegX8632::getEncodedXmm(Dest->getRegNum()),
              RegX8632::getEncodedXmm(Src->getRegNum()));
   Ostream &Str = Func->getContext()->getStrEmit();
   emitIASBytes(Str, Asm, StartPosition);
@@ -2006,6 +2006,38 @@
   Str << "\n";
 }
 
+void InstX8632Fld::emitIAS(const Cfg *Func) const {
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  assert(getSrcSize() == 1);
+  const Operand *Src = getSrc(0);
+  Type Ty = Src->getType();
+  if (const auto Var = llvm::dyn_cast<Variable>(Src)) {
+    if (Var->hasReg()) {
+      // This is a physical xmm register, so we need to spill it to a
+      // temporary stack slot.
+      x86::Immediate Width(typeWidthInBytes(Ty));
+      Asm->sub(IceType_i32, RegX8632::Encoded_Reg_esp, Width);
+      x86::Address StackSlot = x86::Address(RegX8632::Encoded_Reg_esp, 0);
+      Asm->movss(Ty, StackSlot, RegX8632::getEncodedXmm(Var->getRegNum()));
+      Asm->fld(Ty, StackSlot);
+      Asm->add(IceType_i32, RegX8632::Encoded_Reg_esp, Width);
+    } else {
+      x86::Address StackAddr(static_cast<TargetX8632 *>(Func->getTarget())
+                                 ->stackVarToAsmOperand(Var));
+      Asm->fld(Ty, StackAddr);
+    }
+  } else if (const auto Mem = llvm::dyn_cast<OperandX8632Mem>(Src)) {
+    Asm->fld(Ty, Mem->toAsmAddress(Asm));
+  } else if (const auto Imm = llvm::dyn_cast<Constant>(Src)) {
+    Asm->fld(Ty, x86::Address::ofConstPool(Func->getContext(), Asm, Imm));
+  } else {
+    llvm_unreachable("Unexpected operand type");
+  }
+  Ostream &Str = Func->getContext()->getStrEmit();
+  emitIASBytes(Str, Asm, StartPosition);
+}
+
 void InstX8632Fld::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   Str << "fld." << getSrc(0)->getType() << " ";
@@ -2015,6 +2047,10 @@
 void InstX8632Fstp::emit(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(getSrcSize() == 0);
+  // TODO(jvoung,stichnot): Utilize this by setting Dest to NULL to
+  // "partially" delete the fstp if the Dest is unused.
+  // Even if Dest is unused, the fstp should be kept for the SideEffects
+  // of popping the stack.
   if (getDest() == NULL) {
     Str << "\tfstp\tst(0)\n";
     return;
@@ -2039,6 +2075,42 @@
   Str << "\tadd\tesp, " << Width << "\n";
 }
 
+void InstX8632Fstp::emitIAS(const Cfg *Func) const {
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  assert(getSrcSize() == 0);
+  const Variable *Dest = getDest();
+  // TODO(jvoung,stichnot): Utilize this by setting Dest to NULL to
+  // "partially" delete the fstp if the Dest is unused.
+  // Even if Dest is unused, the fstp should be kept for the SideEffects
+  // of popping the stack.
+  if (Dest == NULL) {
+    Asm->fstp(RegX8632::getEncodedSTReg(0));
+    Ostream &Str = Func->getContext()->getStrEmit();
+    emitIASBytes(Str, Asm, StartPosition);
+    return;
+  }
+  Type Ty = Dest->getType();
+  if (!Dest->hasReg()) {
+    x86::Address StackAddr(static_cast<TargetX8632 *>(Func->getTarget())
+                               ->stackVarToAsmOperand(Dest));
+    Asm->fstp(Ty, StackAddr);
+  } else {
+    // Dest is a physical (xmm) register, so st(0) needs to go through
+    // memory.  Hack this by creating a temporary stack slot, spilling
+    // st(0) there, loading it into the xmm register, and deallocating
+    // the stack slot.
+    x86::Immediate Width(typeWidthInBytes(Ty));
+    Asm->sub(IceType_i32, RegX8632::Encoded_Reg_esp, Width);
+    x86::Address StackSlot = x86::Address(RegX8632::Encoded_Reg_esp, 0);
+    Asm->fstp(Ty, StackSlot);
+    Asm->movss(Ty, RegX8632::getEncodedXmm(Dest->getRegNum()), StackSlot);
+    Asm->add(IceType_i32, RegX8632::Encoded_Reg_esp, Width);
+  }
+  Ostream &Str = Func->getContext()->getStrEmit();
+  emitIASBytes(Str, Asm, StartPosition);
+}
+
 void InstX8632Fstp::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   dumpDest(Func);
diff --git a/src/IceInstX8632.def b/src/IceInstX8632.def
index 8e7df05..e48db41 100644
--- a/src/IceInstX8632.def
+++ b/src/IceInstX8632.def
@@ -88,6 +88,21 @@
   X(SegReg_GS, "gs")        \
 //#define X(val, name)
 
+// X87 ST(n) registers.
+#define X87ST_REGX8632_TABLE         \
+  /* enum value, encode, name */     \
+  X(X87ST_First, = 0, "st(0)")       \
+  X(X87ST_0, = 0, "st(0)")           \
+  X(X87ST_1, = 1, "st(1)")           \
+  X(X87ST_2, = 2, "st(2)")           \
+  X(X87ST_3, = 3, "st(3)")           \
+  X(X87ST_4, = 4, "st(4)")           \
+  X(X87ST_5, = 5, "st(5)")           \
+  X(X87ST_6, = 6, "st(6)")           \
+  X(X87ST_7, = 7, "st(7)")           \
+  X(X87ST_Last, = 7, "st(7)")        \
+//#define X(val, encode, name)
+
 #define ICEINSTX8632BR_TABLE   \
   /* enum value, encode, opposite, dump, emit */ \
   X(Br_o,  = 0,       Br_no,    "o",  "jo")                \
diff --git a/src/IceInstX8632.h b/src/IceInstX8632.h
index abce706..96978d4 100644
--- a/src/IceInstX8632.h
+++ b/src/IceInstX8632.h
@@ -1352,6 +1352,7 @@
     return new (Func->allocate<InstX8632Fld>()) InstX8632Fld(Func, Src);
   }
   void emit(const Cfg *Func) const override;
+  void emitIAS(const Cfg *Func) const override;
   void dump(const Cfg *Func) const override;
   static bool classof(const Inst *Inst) { return isClassof(Inst, Fld); }
 
@@ -1369,6 +1370,7 @@
     return new (Func->allocate<InstX8632Fstp>()) InstX8632Fstp(Func, Dest);
   }
   void emit(const Cfg *Func) const override;
+  void emitIAS(const Cfg *Func) const override;
   void dump(const Cfg *Func) const override;
   static bool classof(const Inst *Inst) { return isClassof(Inst, Fstp); }
 
diff --git a/src/IceRegistersX8632.h b/src/IceRegistersX8632.h
index 851908c..86ace82 100644
--- a/src/IceRegistersX8632.h
+++ b/src/IceRegistersX8632.h
@@ -36,7 +36,7 @@
 #undef X
 };
 
-// An enum of GPR Registers. The enum value does match encoding used
+// An enum of GPR Registers. The enum value does match the encoding used
 // to binary encode register operands in instructions.
 enum GPRRegister {
 #define X(val, encode, name, name16, name8, scratch, preserved, stackptr,      \
@@ -47,7 +47,7 @@
       Encoded_Not_GPR = -1
 };
 
-// An enum of XMM Registers. The enum value does match encoding used
+// An enum of XMM Registers. The enum value does match the encoding used
 // to binary encode register operands in instructions.
 enum XmmRegister {
 #define X(val, encode, name, name16, name8, scratch, preserved, stackptr,      \
@@ -58,7 +58,7 @@
       Encoded_Not_Xmm = -1
 };
 
-// An enum of Byte Registers. The enum value does match encoding used
+// An enum of Byte Registers. The enum value does match the encoding used
 // to binary encode register operands in instructions.
 enum ByteRegister {
 #define X(val, encode) Encoded_##val encode,
@@ -67,6 +67,15 @@
       Encoded_Not_ByteReg = -1
 };
 
+// An enum of X87 Stack Registers. The enum value does match the encoding used
+// to binary encode register operands in instructions.
+enum X87STRegister {
+#define X(val, encode, name) Encoded_##val encode,
+  X87ST_REGX8632_TABLE
+#undef X
+      Encoded_Not_X87STReg = -1
+};
+
 static inline GPRRegister getEncodedGPR(int32_t RegNum) {
   assert(Reg_GPR_First <= RegNum && RegNum <= Reg_GPR_Last);
   return GPRRegister(RegNum - Reg_GPR_First);
@@ -91,6 +100,11 @@
     return getEncodedGPR(RegNum);
 }
 
+static inline X87STRegister getEncodedSTReg(int32_t RegNum) {
+  assert(Encoded_X87ST_First <= RegNum && RegNum <= Encoded_X87ST_Last);
+  return X87STRegister(RegNum);
+}
+
 } // end of namespace RegX8632
 
 } // end of namespace Ice
diff --git a/src/assembler_ia32.cpp b/src/assembler_ia32.cpp
index bc59ca8..6fc7026 100644
--- a/src/assembler_ia32.cpp
+++ b/src/assembler_ia32.cpp
@@ -272,25 +272,25 @@
   EmitUint8(0xA4);
 }
 
-void AssemblerX86::movss(XmmRegister dst, const Address &src) {
+void AssemblerX86::movss(Type Ty, XmmRegister dst, const Address &src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF3);
+  EmitUint8(isFloat32Asserting32Or64(Ty) ? 0xF3 : 0xF2);
   EmitUint8(0x0F);
   EmitUint8(0x10);
   EmitOperand(dst, src);
 }
 
-void AssemblerX86::movss(const Address &dst, XmmRegister src) {
+void AssemblerX86::movss(Type Ty, const Address &dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF3);
+  EmitUint8(isFloat32Asserting32Or64(Ty) ? 0xF3 : 0xF2);
   EmitUint8(0x0F);
   EmitUint8(0x11);
   EmitOperand(src, dst);
 }
 
-void AssemblerX86::movss(XmmRegister dst, XmmRegister src) {
+void AssemblerX86::movss(Type Ty, XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF3);
+  EmitUint8(isFloat32Asserting32Or64(Ty) ? 0xF3 : 0xF2);
   EmitUint8(0x0F);
   EmitUint8(0x11);
   EmitXmmRegisterOperand(src, dst);
@@ -416,40 +416,22 @@
   EmitOperand(dst, src);
 }
 
-void AssemblerX86::flds(const Address &src) {
+void AssemblerX86::fld(Type Ty, const Address &src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xD9);
+  EmitUint8(isFloat32Asserting32Or64(Ty) ? 0xD9 : 0xDD);
   EmitOperand(0, src);
 }
 
-void AssemblerX86::fstps(const Address &dst) {
+void AssemblerX86::fstp(Type Ty, const Address &dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xD9);
+  EmitUint8(isFloat32Asserting32Or64(Ty) ? 0xD9 : 0xDD);
   EmitOperand(3, dst);
 }
 
-void AssemblerX86::movsd(XmmRegister dst, const Address &src) {
+void AssemblerX86::fstp(X87STRegister st) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF2);
-  EmitUint8(0x0F);
-  EmitUint8(0x10);
-  EmitOperand(dst, src);
-}
-
-void AssemblerX86::movsd(const Address &dst, XmmRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF2);
-  EmitUint8(0x0F);
-  EmitUint8(0x11);
-  EmitOperand(src, dst);
-}
-
-void AssemblerX86::movsd(XmmRegister dst, XmmRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF2);
-  EmitUint8(0x0F);
-  EmitUint8(0x11);
-  EmitXmmRegisterOperand(src, dst);
+  EmitUint8(0xDD);
+  EmitUint8(0xD8 + st);
 }
 
 void AssemblerX86::movaps(XmmRegister dst, XmmRegister src) {
@@ -1236,18 +1218,6 @@
   EmitUint8(static_cast<uint8_t>(mode) | 0x8);
 }
 
-void AssemblerX86::fldl(const Address &src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xDD);
-  EmitOperand(0, src);
-}
-
-void AssemblerX86::fstpl(const Address &dst) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xDD);
-  EmitOperand(3, dst);
-}
-
 void AssemblerX86::fnstcw(const Address &dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xD9);
diff --git a/src/assembler_ia32.h b/src/assembler_ia32.h
index 22ecb6e..676f4f6 100644
--- a/src/assembler_ia32.h
+++ b/src/assembler_ia32.h
@@ -36,6 +36,7 @@
 using RegX8632::GPRRegister;
 using RegX8632::XmmRegister;
 using RegX8632::ByteRegister;
+using RegX8632::X87STRegister;
 
 namespace x86 {
 
@@ -455,9 +456,9 @@
 
   void rep_movsb();
 
-  void movss(XmmRegister dst, const Address &src);
-  void movss(const Address &dst, XmmRegister src);
-  void movss(XmmRegister dst, XmmRegister src);
+  void movss(Type Ty, XmmRegister dst, const Address &src);
+  void movss(Type Ty, const Address &dst, XmmRegister src);
+  void movss(Type Ty, XmmRegister dst, XmmRegister src);
 
   void movd(XmmRegister dst, GPRRegister src);
   void movd(XmmRegister dst, const Address &src);
@@ -477,10 +478,6 @@
   void divss(Type Ty, XmmRegister dst, XmmRegister src);
   void divss(Type Ty, XmmRegister dst, const Address &src);
 
-  void movsd(XmmRegister dst, const Address &src);
-  void movsd(const Address &dst, XmmRegister src);
-  void movsd(XmmRegister dst, XmmRegister src);
-
   void movaps(XmmRegister dst, XmmRegister src);
 
   void movups(XmmRegister dst, XmmRegister src);
@@ -598,11 +595,9 @@
   };
   void roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode);
 
-  void flds(const Address &src);
-  void fstps(const Address &dst);
-
-  void fldl(const Address &src);
-  void fstpl(const Address &dst);
+  void fld(Type Ty, const Address &src);
+  void fstp(Type Ty, const Address &dst);
+  void fstp(X87STRegister st);
 
   void fnstcw(const Address &dst);
   void fldcw(const Address &src);
diff --git a/tests_lit/llvm2ice_tests/fp.pnacl.ll b/tests_lit/llvm2ice_tests/fp.pnacl.ll
index 8376ebd..474961a 100644
--- a/tests_lit/llvm2ice_tests/fp.pnacl.ll
+++ b/tests_lit/llvm2ice_tests/fp.pnacl.ll
@@ -416,7 +416,7 @@
 ; CALLTARGETS-LABEL: signed64ToDouble
 ; CHECK: call -4
 ; CALLTARGETS: call cvtsi64tod
-; CHECK: fstp
+; CHECK: fstp qword
 
 define internal float @signed64ToFloat(i64 %a) {
 entry:
@@ -427,7 +427,7 @@
 ; CALLTARGETS-LABEL: signed64ToFloat
 ; CHECK: call -4
 ; CALLTARGETS: call cvtsi64tof
-; CHECK: fstp
+; CHECK: fstp dword
 
 define internal double @unsigned64ToDouble(i64 %a) {
 entry:
@@ -500,7 +500,7 @@
 ; CALLTARGETS-LABEL: unsigned32ToDouble
 ; CHECK: call -4
 ; CALLTARGETS: call cvtui32tod
-; CHECK: fstp
+; CHECK: fstp qword
 
 define internal float @unsigned32ToFloat(i32 %a) {
 entry:
@@ -511,7 +511,7 @@
 ; CALLTARGETS-LABEL: unsigned32ToFloat
 ; CHECK: call -4
 ; CALLTARGETS: call cvtui32tof
-; CHECK: fstp
+; CHECK: fstp dword
 
 define internal double @signed16ToDouble(i32 %a) {
 entry:
@@ -521,7 +521,7 @@
 }
 ; CHECK-LABEL: signed16ToDouble
 ; CHECK: cvtsi2sd
-; CHECK: fld
+; CHECK: fld qword
 
 define internal float @signed16ToFloat(i32 %a) {
 entry:
@@ -531,7 +531,7 @@
 }
 ; CHECK-LABEL: signed16ToFloat
 ; CHECK: cvtsi2ss
-; CHECK: fld
+; CHECK: fld dword
 
 define internal double @unsigned16ToDouble(i32 %a) {
 entry: