emitIAS for cvtt?.*2.*

BUG=none
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/640603002
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp
index e2d39c3..fd1f80d 100644
--- a/src/IceInstX8632.cpp
+++ b/src/IceInstX8632.cpp
@@ -230,8 +230,8 @@
 }
 
 InstX8632Cvt::InstX8632Cvt(Cfg *Func, Variable *Dest, Operand *Source,
-                           bool Trunc)
-    : InstX8632(Func, InstX8632::Cvt, 1, Dest), Trunc(Trunc) {
+                           CvtVariant Variant)
+    : InstX8632(Func, InstX8632::Cvt, 1, Dest), Variant(Variant) {
   addSource(Source);
 }
 
@@ -647,6 +647,35 @@
   emitIASBytes(Str, Asm, StartPosition);
 }
 
+template <typename DReg_t, typename SReg_t, DReg_t (*destEnc)(int32_t),
+          SReg_t (*srcEnc)(int32_t)>
+void emitIASCastRegOp(
+    const Cfg *Func, Type DispatchTy, const Variable *Dest, const Operand *Src,
+    const x86::AssemblerX86::CastEmitterRegOp<DReg_t, SReg_t> Emitter) {
+  x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
+  intptr_t StartPosition = Asm->GetPosition();
+  assert(Dest->hasReg());
+  DReg_t DestReg = destEnc(Dest->getRegNum());
+  if (const Variable *SrcVar = llvm::dyn_cast<Variable>(Src)) {
+    if (SrcVar->hasReg()) {
+      SReg_t SrcReg = srcEnc(SrcVar->getRegNum());
+      (Asm->*(Emitter.RegReg))(DispatchTy, DestReg, SrcReg);
+    } else {
+      x86::Address SrcStackAddr = static_cast<TargetX8632 *>(Func->getTarget())
+                                      ->stackVarToAsmOperand(SrcVar);
+      (Asm->*(Emitter.RegAddr))(DispatchTy, DestReg, SrcStackAddr);
+    }
+  } else if (const OperandX8632Mem *Mem =
+                 llvm::dyn_cast<OperandX8632Mem>(Src)) {
+    x86::Address SrcAddr = Mem->toAsmAddress(Asm);
+    (Asm->*(Emitter.RegAddr))(DispatchTy, DestReg, SrcAddr);
+  } else {
+    llvm_unreachable("Unexpected operand type");
+  }
+  Ostream &Str = Func->getContext()->getStrEmit();
+  emitIASBytes(Str, Asm, StartPosition);
+}
+
 void emitIASMovlikeXMM(const Cfg *Func, const Variable *Dest,
                        const Operand *Src,
                        const x86::AssemblerX86::XmmEmitterMovOps Emitter) {
@@ -1407,7 +1436,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(getSrcSize() == 1);
   Str << "\tcvt";
-  if (Trunc)
+  if (isTruncating())
     Str << "t";
   Str << TypeX8632Attributes[getSrc(0)->getType()].CvtString << "2"
       << TypeX8632Attributes[getDest()->getType()].CvtString << "\t";
@@ -1417,11 +1446,70 @@
   Str << "\n";
 }
 
+void InstX8632Cvt::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 1);
+  const Variable *Dest = getDest();
+  const Operand *Src = getSrc(0);
+  Type DestTy = Dest->getType();
+  Type SrcTy = Src->getType();
+  switch (Variant) {
+  case Si2ss: {
+    assert(isScalarIntegerType(SrcTy));
+    assert(typeWidthInBytes(SrcTy) <= 4);
+    assert(isScalarFloatingType(DestTy));
+    static const x86::AssemblerX86::CastEmitterRegOp<
+        RegX8632::XmmRegister, RegX8632::GPRRegister> Emitter = {
+        &x86::AssemblerX86::cvtsi2ss, &x86::AssemblerX86::cvtsi2ss};
+    emitIASCastRegOp<RegX8632::XmmRegister, RegX8632::GPRRegister,
+                     RegX8632::getEncodedXmm, RegX8632::getEncodedGPR>(
+        Func, DestTy, Dest, Src, Emitter);
+    return;
+  }
+  case Tss2si: {
+    assert(isScalarFloatingType(SrcTy));
+    assert(isScalarIntegerType(DestTy));
+    assert(typeWidthInBytes(DestTy) <= 4);
+    static const x86::AssemblerX86::CastEmitterRegOp<
+        RegX8632::GPRRegister, RegX8632::XmmRegister> Emitter = {
+        &x86::AssemblerX86::cvttss2si, &x86::AssemblerX86::cvttss2si};
+    emitIASCastRegOp<RegX8632::GPRRegister, RegX8632::XmmRegister,
+                     RegX8632::getEncodedGPR, RegX8632::getEncodedXmm>(
+        Func, SrcTy, Dest, Src, Emitter);
+    return;
+  }
+  case Float2float: {
+    assert(isScalarFloatingType(SrcTy));
+    assert(isScalarFloatingType(DestTy));
+    assert(DestTy != SrcTy);
+    static const x86::AssemblerX86::XmmEmitterRegOp Emitter = {
+        &x86::AssemblerX86::cvtfloat2float, &x86::AssemblerX86::cvtfloat2float};
+    emitIASRegOpTyXMM(Func, SrcTy, Dest, Src, Emitter);
+    return;
+  }
+  case Dq2ps: {
+    assert(isVectorIntegerType(SrcTy));
+    assert(isVectorFloatingType(DestTy));
+    static const x86::AssemblerX86::XmmEmitterRegOp Emitter = {
+        &x86::AssemblerX86::cvtdq2ps, &x86::AssemblerX86::cvtdq2ps};
+    emitIASRegOpTyXMM(Func, DestTy, Dest, Src, Emitter);
+    return;
+  }
+  case Tps2dq: {
+    assert(isVectorFloatingType(SrcTy));
+    assert(isVectorIntegerType(DestTy));
+    static const x86::AssemblerX86::XmmEmitterRegOp Emitter = {
+        &x86::AssemblerX86::cvttps2dq, &x86::AssemblerX86::cvttps2dq};
+    emitIASRegOpTyXMM(Func, DestTy, Dest, Src, Emitter);
+    return;
+  }
+  }
+}
+
 void InstX8632Cvt::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   dumpDest(Func);
   Str << " = cvt";
-  if (Trunc)
+  if (isTruncating())
     Str << "t";
   Str << TypeX8632Attributes[getSrc(0)->getType()].CvtString << "2"
       << TypeX8632Attributes[getDest()->getType()].CvtString << " ";
diff --git a/src/IceInstX8632.h b/src/IceInstX8632.h
index eb133c2..abce706 100644
--- a/src/IceInstX8632.h
+++ b/src/IceInstX8632.h
@@ -1109,18 +1109,21 @@
 // operand needs to be done separately.
 class InstX8632Cvt : public InstX8632 {
 public:
+  enum CvtVariant { Si2ss, Tss2si, Float2float, Dq2ps, Tps2dq };
   static InstX8632Cvt *create(Cfg *Func, Variable *Dest, Operand *Source,
-                              bool Trunc) {
+                              CvtVariant Variant) {
     return new (Func->allocate<InstX8632Cvt>())
-        InstX8632Cvt(Func, Dest, Source, Trunc);
+        InstX8632Cvt(Func, Dest, Source, Variant);
   }
   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, Cvt); }
+  bool isTruncating() const { return Variant == Tss2si || Variant == Tps2dq; }
 
 private:
-  bool Trunc;
-  InstX8632Cvt(Cfg *Func, Variable *Dest, Operand *Source, bool Trunc);
+  CvtVariant Variant;
+  InstX8632Cvt(Cfg *Func, Variable *Dest, Operand *Source, CvtVariant Variant);
   InstX8632Cvt(const InstX8632Cvt &) = delete;
   InstX8632Cvt &operator=(const InstX8632Cvt &) = delete;
   ~InstX8632Cvt() override {}
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 343113c..eb41b84 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -2058,7 +2058,7 @@
     Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
     // t1 = cvt Src0RM; Dest = t1
     Variable *T = makeReg(Dest->getType());
-    _cvt(T, Src0RM);
+    _cvt(T, Src0RM, InstX8632Cvt::Float2float);
     _mov(Dest, T);
     break;
   }
@@ -2068,7 +2068,7 @@
              Inst->getSrc(0)->getType() == IceType_v4f32);
       Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
       Variable *T = makeReg(Dest->getType());
-      _cvtt(T, Src0RM);
+      _cvt(T, Src0RM, InstX8632Cvt::Tps2dq);
       _movp(Dest, T);
     } else if (Dest->getType() == IceType_i64) {
       // Use a helper for converting floating-point values to 64-bit
@@ -2091,7 +2091,7 @@
       // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
       Variable *T_1 = makeReg(IceType_i32);
       Variable *T_2 = makeReg(Dest->getType());
-      _cvtt(T_1, Src0RM);
+      _cvt(T_1, Src0RM, InstX8632Cvt::Tss2si);
       _mov(T_2, T_1); // T_1 and T_2 may have different integer types
       if (Dest->getType() == IceType_i1)
         _and(T_2, Ctx->getConstantInt32(IceType_i1, 1));
@@ -2127,7 +2127,7 @@
       // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
       Variable *T_1 = makeReg(IceType_i32);
       Variable *T_2 = makeReg(Dest->getType());
-      _cvtt(T_1, Src0RM);
+      _cvt(T_1, Src0RM, InstX8632Cvt::Tss2si);
       _mov(T_2, T_1); // T_1 and T_2 may have different integer types
       if (Dest->getType() == IceType_i1)
         _and(T_2, Ctx->getConstantInt32(IceType_i1, 1));
@@ -2140,7 +2140,7 @@
              Inst->getSrc(0)->getType() == IceType_v4i32);
       Operand *Src0RM = legalize(Inst->getSrc(0), Legal_Reg | Legal_Mem);
       Variable *T = makeReg(Dest->getType());
-      _cvt(T, Src0RM);
+      _cvt(T, Src0RM, InstX8632Cvt::Dq2ps);
       _movp(Dest, T);
     } else if (Inst->getSrc(0)->getType() == IceType_i64) {
       // Use a helper for x86-32.
@@ -2163,7 +2163,7 @@
         _mov(T_1, Src0RM);
       else
         _movsx(T_1, Src0RM);
-      _cvt(T_2, T_1);
+      _cvt(T_2, T_1, InstX8632Cvt::Si2ss);
       _mov(Dest, T_2);
     }
     break;
@@ -2202,7 +2202,7 @@
         _mov(T_1, Src0RM);
       else
         _movzx(T_1, Src0RM);
-      _cvt(T_2, T_1);
+      _cvt(T_2, T_1, InstX8632Cvt::Si2ss);
       _mov(Dest, T_2);
     }
     break;
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index 271d4a2..82a8208 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -256,13 +256,8 @@
     Context.insert(InstFakeDef::create(Func, Edx));
     Context.insert(InstFakeDef::create(Func, Eax));
   }
-  void _cvt(Variable *Dest, Operand *Src0) {
-    const bool Trunc = false;
-    Context.insert(InstX8632Cvt::create(Func, Dest, Src0, Trunc));
-  }
-  void _cvtt(Variable *Dest, Operand *Src0) {
-    const bool Trunc = true;
-    Context.insert(InstX8632Cvt::create(Func, Dest, Src0, Trunc));
+  void _cvt(Variable *Dest, Operand *Src0, InstX8632Cvt::CvtVariant Variant) {
+    Context.insert(InstX8632Cvt::create(Func, Dest, Src0, Variant));
   }
   void _div(Variable *Dest, Operand *Src0, Operand *Src1) {
     Context.insert(InstX8632Div::create(Func, Dest, Src0, Src1));
diff --git a/src/assembler_ia32.cpp b/src/assembler_ia32.cpp
index 6bcbb9a..bc59ca8 100644
--- a/src/assembler_ia32.cpp
+++ b/src/assembler_ia32.cpp
@@ -948,21 +948,6 @@
   EmitXmmRegisterOperand(dst, dst);
 }
 
-void AssemblerX86::cvtps2pd(XmmRegister dst, XmmRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0x0F);
-  EmitUint8(0x5A);
-  EmitXmmRegisterOperand(dst, src);
-}
-
-void AssemblerX86::cvtpd2ps(XmmRegister dst, XmmRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0x66);
-  EmitUint8(0x0F);
-  EmitUint8(0x5A);
-  EmitXmmRegisterOperand(dst, src);
-}
-
 void AssemblerX86::shufpd(XmmRegister dst, XmmRegister src,
                           const Immediate &imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -974,76 +959,89 @@
   EmitUint8(imm.value());
 }
 
-void AssemblerX86::cvtsi2ss(XmmRegister dst, GPRRegister src) {
+void AssemblerX86::cvtdq2ps(Type /* Ignore */, XmmRegister dst,
+                            XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF3);
   EmitUint8(0x0F);
-  EmitUint8(0x2A);
-  EmitOperand(dst, Operand(src));
-}
-
-void AssemblerX86::cvtsi2sd(XmmRegister dst, GPRRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF2);
-  EmitUint8(0x0F);
-  EmitUint8(0x2A);
-  EmitOperand(dst, Operand(src));
-}
-
-void AssemblerX86::cvtss2si(GPRRegister dst, XmmRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF3);
-  EmitUint8(0x0F);
-  EmitUint8(0x2D);
+  EmitUint8(0x5B);
   EmitXmmRegisterOperand(dst, src);
 }
 
-void AssemblerX86::cvtss2sd(XmmRegister dst, XmmRegister src) {
+void AssemblerX86::cvtdq2ps(Type /* Ignore */, XmmRegister dst,
+                            const Address &src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x5B);
+  EmitOperand(dst, src);
+}
+
+void AssemblerX86::cvttps2dq(Type /* Ignore */, XmmRegister dst,
+                             XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF3);
   EmitUint8(0x0F);
+  EmitUint8(0x5B);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+void AssemblerX86::cvttps2dq(Type /* Ignore */, XmmRegister dst,
+                             const Address &src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xF3);
+  EmitUint8(0x0F);
+  EmitUint8(0x5B);
+  EmitOperand(dst, src);
+}
+
+void AssemblerX86::cvtsi2ss(Type DestTy, XmmRegister dst, GPRRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(isFloat32Asserting32Or64(DestTy) ? 0xF3 : 0xF2);
+  EmitUint8(0x0F);
+  EmitUint8(0x2A);
+  EmitRegisterOperand(dst, src);
+}
+
+void AssemblerX86::cvtsi2ss(Type DestTy, XmmRegister dst, const Address &src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(isFloat32Asserting32Or64(DestTy) ? 0xF3 : 0xF2);
+  EmitUint8(0x0F);
+  EmitUint8(0x2A);
+  EmitOperand(dst, src);
+}
+
+void AssemblerX86::cvtfloat2float(Type SrcTy, XmmRegister dst,
+                                  XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  // ss2sd or sd2ss
+  EmitUint8(isFloat32Asserting32Or64(SrcTy) ? 0xF3 : 0xF2);
+  EmitUint8(0x0F);
   EmitUint8(0x5A);
   EmitXmmRegisterOperand(dst, src);
 }
 
-void AssemblerX86::cvtsd2si(GPRRegister dst, XmmRegister src) {
+void AssemblerX86::cvtfloat2float(Type SrcTy, XmmRegister dst,
+                                  const Address &src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF2);
-  EmitUint8(0x0F);
-  EmitUint8(0x2D);
-  EmitXmmRegisterOperand(dst, src);
-}
-
-void AssemblerX86::cvttss2si(GPRRegister dst, XmmRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF3);
-  EmitUint8(0x0F);
-  EmitUint8(0x2C);
-  EmitXmmRegisterOperand(dst, src);
-}
-
-void AssemblerX86::cvttsd2si(GPRRegister dst, XmmRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF2);
-  EmitUint8(0x0F);
-  EmitUint8(0x2C);
-  EmitXmmRegisterOperand(dst, src);
-}
-
-void AssemblerX86::cvtsd2ss(XmmRegister dst, XmmRegister src) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF2);
+  EmitUint8(isFloat32Asserting32Or64(SrcTy) ? 0xF3 : 0xF2);
   EmitUint8(0x0F);
   EmitUint8(0x5A);
+  EmitOperand(dst, src);
+}
+
+void AssemblerX86::cvttss2si(Type SrcTy, GPRRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(isFloat32Asserting32Or64(SrcTy) ? 0xF3 : 0xF2);
+  EmitUint8(0x0F);
+  EmitUint8(0x2C);
   EmitXmmRegisterOperand(dst, src);
 }
 
-void AssemblerX86::cvtdq2pd(XmmRegister dst, XmmRegister src) {
+void AssemblerX86::cvttss2si(Type SrcTy, GPRRegister dst, const Address &src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0xF3);
+  EmitUint8(isFloat32Asserting32Or64(SrcTy) ? 0xF3 : 0xF2);
   EmitUint8(0x0F);
-  EmitUint8(0xE6);
-  EmitXmmRegisterOperand(dst, src);
+  EmitUint8(0x2C);
+  EmitOperand(dst, src);
 }
 
 void AssemblerX86::ucomiss(Type Ty, XmmRegister a, XmmRegister b) {
diff --git a/src/assembler_ia32.h b/src/assembler_ia32.h
index 0080f33..22ecb6e 100644
--- a/src/assembler_ia32.h
+++ b/src/assembler_ia32.h
@@ -397,6 +397,15 @@
     TypedEmitXmmImm XmmImm;
   };
 
+  // Cross Xmm/GPR cast instructions.
+  template <typename DReg_t, typename SReg_t> struct CastEmitterRegOp {
+    typedef void (AssemblerX86::*TypedEmitRegs)(Type, DReg_t, SReg_t);
+    typedef void (AssemblerX86::*TypedEmitAddr)(Type, DReg_t, const Address &);
+
+    TypedEmitRegs RegReg;
+    TypedEmitAddr RegAddr;
+  };
+
   /*
    * Emit Machine Instructions.
    */
@@ -537,23 +546,22 @@
   void minpd(XmmRegister dst, XmmRegister src);
   void maxpd(XmmRegister dst, XmmRegister src);
   void sqrtpd(XmmRegister dst);
-  void cvtps2pd(XmmRegister dst, XmmRegister src);
-  void cvtpd2ps(XmmRegister dst, XmmRegister src);
   void shufpd(XmmRegister dst, XmmRegister src, const Immediate &mask);
 
-  void cvtsi2ss(XmmRegister dst, GPRRegister src);
-  void cvtsi2sd(XmmRegister dst, GPRRegister src);
+  void cvtdq2ps(Type, XmmRegister dst, XmmRegister src);
+  void cvtdq2ps(Type, XmmRegister dst, const Address &src);
 
-  void cvtss2si(GPRRegister dst, XmmRegister src);
-  void cvtss2sd(XmmRegister dst, XmmRegister src);
+  void cvttps2dq(Type, XmmRegister dst, XmmRegister src);
+  void cvttps2dq(Type, XmmRegister dst, const Address &src);
 
-  void cvtsd2si(GPRRegister dst, XmmRegister src);
-  void cvtsd2ss(XmmRegister dst, XmmRegister src);
+  void cvtsi2ss(Type DestTy, XmmRegister dst, GPRRegister src);
+  void cvtsi2ss(Type DestTy, XmmRegister dst, const Address &src);
 
-  void cvttss2si(GPRRegister dst, XmmRegister src);
-  void cvttsd2si(GPRRegister dst, XmmRegister src);
+  void cvtfloat2float(Type SrcTy, XmmRegister dst, XmmRegister src);
+  void cvtfloat2float(Type SrcTy, XmmRegister dst, const Address &src);
 
-  void cvtdq2pd(XmmRegister dst, XmmRegister src);
+  void cvttss2si(Type SrcTy, GPRRegister dst, XmmRegister src);
+  void cvttss2si(Type SrcTy, GPRRegister dst, const Address &src);
 
   void ucomiss(Type Ty, XmmRegister a, XmmRegister b);
   void ucomiss(Type Ty, XmmRegister a, const Address &b);