Subzero. Native 64-bit int arithmetic on x86-64.

This CL modifies the x86 instruction selection template to allow native
64-bit GPR support. It also enables x86-64 crosstests.

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

Review URL: https://codereview.chromium.org/1273153002.
diff --git a/src/IceInstX86BaseImpl.h b/src/IceInstX86BaseImpl.h
index 34417cf..4d26210 100644
--- a/src/IceInstX86BaseImpl.h
+++ b/src/IceInstX86BaseImpl.h
@@ -729,7 +729,8 @@
   } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
     (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue()));
   } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
-    AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc);
+    AssemblerFixup *Fixup =
+        Asm->createFixup(InstX86Base<Machine>::Traits::RelFixup, Reloc);
     (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Reloc->getOffset(), Fixup));
   } else if (const auto Split = llvm::dyn_cast<
                  typename InstX86Base<Machine>::Traits::VariableSplit>(Src)) {
@@ -758,7 +759,8 @@
   } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
     (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Imm->getValue()));
   } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
-    AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc);
+    AssemblerFixup *Fixup =
+        Asm->createFixup(InstX86Base<Machine>::Traits::RelFixup, Reloc);
     (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Reloc->getOffset(), Fixup));
   } else {
     llvm_unreachable("Unexpected operand type");
@@ -929,8 +931,8 @@
 
 template <class Machine, 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,
+void emitIASCastRegOp(const Cfg *Func, Type DestTy, const Variable *Dest,
+                      Type SrcTy, const Operand *Src,
                       const typename InstX86Base<Machine>::Traits::Assembler::
                           template CastEmitterRegOp<DReg_t, SReg_t> &Emitter) {
   typename InstX86Base<Machine>::Traits::Assembler *Asm =
@@ -940,18 +942,18 @@
   if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) {
     if (SrcVar->hasReg()) {
       SReg_t SrcReg = srcEnc(SrcVar->getRegNum());
-      (Asm->*(Emitter.RegReg))(DispatchTy, DestReg, SrcReg);
+      (Asm->*(Emitter.RegReg))(DestTy, DestReg, SrcTy, SrcReg);
     } else {
       typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
           static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
               Func->getTarget())
               ->stackVarToAsmOperand(SrcVar);
-      (Asm->*(Emitter.RegAddr))(DispatchTy, DestReg, SrcStackAddr);
+      (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, SrcStackAddr);
     }
   } else if (const auto Mem = llvm::dyn_cast<
                  typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
     Mem->emitSegmentOverride(Asm);
-    (Asm->*(Emitter.RegAddr))(DispatchTy, DestReg, Mem->toAsmAddress(Asm));
+    (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, Mem->toAsmAddress(Asm));
   } else {
     llvm_unreachable("Unexpected operand type");
   }
@@ -1387,17 +1389,26 @@
   case IceType_i8:
     assert(this->getDest()->getRegNum() ==
            InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
-    Str << "\tcbtw";
+    Str << "\t"
+        << "cbtw";
     break;
   case IceType_i16:
     assert(this->getDest()->getRegNum() ==
            InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
-    Str << "\tcwtd";
+    Str << "\t"
+        << "cwtd";
     break;
   case IceType_i32:
     assert(this->getDest()->getRegNum() ==
            InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
-    Str << "\tcltd";
+    Str << "\t"
+        << "cltd";
+    break;
+  case IceType_i64:
+    assert(this->getDest()->getRegNum() ==
+           InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
+    Str << "\t"
+        << "cdto";
     break;
   }
 }
@@ -1430,6 +1441,11 @@
            InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
     Asm->cdq();
     break;
+  case IceType_i64:
+    assert(this->getDest()->getRegNum() ==
+           InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
+    Asm->cqo();
+    break;
   }
 }
 
@@ -1592,7 +1608,8 @@
   assert(this->getSrcSize() == 2);
   Operand *Src = this->getSrc(1);
   Type SrcTy = Src->getType();
-  assert(SrcTy == IceType_i16 || SrcTy == IceType_i32);
+  assert(SrcTy == IceType_i16 || SrcTy == IceType_i32 ||
+         (InstX86Base<Machine>::Traits::Is64Bit));
   typename InstX86Base<Machine>::Traits::Assembler *Asm =
       Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
@@ -1814,7 +1831,11 @@
   switch (Variant) {
   case Si2ss: {
     assert(isScalarIntegerType(SrcTy));
-    assert(typeWidthInBytes(SrcTy) <= 4);
+    if (!InstX86Base<Machine>::Traits::Is64Bit) {
+      assert(typeWidthInBytes(SrcTy) <= 4);
+    } else {
+      assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
+    }
     assert(isScalarFloatingType(DestTy));
     static const typename InstX86Base<Machine>::Traits::Assembler::
         template CastEmitterRegOp<
@@ -1828,13 +1849,17 @@
         typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
         InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm,
         InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR>(
-        Func, DestTy, Dest, Src, Emitter);
+        Func, DestTy, Dest, SrcTy, Src, Emitter);
     return;
   }
   case Tss2si: {
     assert(isScalarFloatingType(SrcTy));
     assert(isScalarIntegerType(DestTy));
-    assert(typeWidthInBytes(DestTy) <= 4);
+    if (!InstX86Base<Machine>::Traits::Is64Bit) {
+      assert(typeWidthInBytes(DestTy) <= 4);
+    } else {
+      assert(DestTy == IceType_i32 || DestTy == IceType_i64);
+    }
     static const typename InstX86Base<Machine>::Traits::Assembler::
         template CastEmitterRegOp<
             typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
@@ -1847,7 +1872,7 @@
         typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
         InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR,
         InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>(
-        Func, SrcTy, Dest, Src, Emitter);
+        Func, DestTy, Dest, SrcTy, Src, Emitter);
     return;
   }
   case Float2float: {
@@ -2244,6 +2269,10 @@
   this->getDest()->emit(Func);
 }
 
+inline bool isIntegerConstant(const Operand *Op) {
+  return llvm::isa<ConstantInteger32>(Op) || llvm::isa<ConstantInteger64>(Op);
+}
+
 template <class Machine> void InstX86Mov<Machine>::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
@@ -2252,11 +2281,16 @@
   Operand *Src = this->getSrc(0);
   Type SrcTy = Src->getType();
   Type DestTy = this->getDest()->getType();
-  Str << "\tmov"
-      << (!isScalarFloatingType(DestTy)
-              ? this->getWidthString(SrcTy)
-              : InstX86Base<Machine>::Traits::TypeAttributes[DestTy].SdSsString)
-      << "\t";
+  if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 &&
+      isIntegerConstant(Src)) {
+    Str << "\tmovabs\t";
+  } else {
+    Str << "\tmov"
+        << (!isScalarFloatingType(DestTy)
+                ? this->getWidthString(SrcTy)
+                : InstX86Base<Machine>::Traits::TypeAttributes[DestTy]
+                      .SdSsString) << "\t";
+  }
   // For an integer truncation operation, src is wider than dest.
   // Ideally, we use a mov instruction whose data width matches the
   // narrower dest.  This is a problem if e.g. src is a register like
@@ -2320,6 +2354,20 @@
       assert(isScalarIntegerType(DestTy));
       // Widen DestTy for truncation (see above note). We should only do this
       // when both Src and Dest are integer types.
+      if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 &&
+          isIntegerConstant(Src)) {
+        uint64_t Value = -1;
+        if (const auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src)) {
+          Value = C64->getValue();
+        } else {
+          Value = llvm::cast<ConstantInteger32>(Src)->getValue();
+        }
+        Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>()
+            ->movabs(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
+                         Dest->getRegNum()),
+                     Value);
+        return;
+      }
       if (isScalarIntegerType(SrcTy)) {
         DestTy = SrcTy;
       }
@@ -2363,14 +2411,19 @@
   const auto SrcVar = llvm::cast<Variable>(this->getSrc(0));
   // For insert/extract element (one of Src/Dest is an Xmm vector and
   // the other is an int type).
-  if (SrcVar->getType() == IceType_i32) {
-    assert(isVectorType(Dest->getType()));
+  if (SrcVar->getType() == IceType_i32 ||
+      (InstX86Base<Machine>::Traits::Is64Bit &&
+       SrcVar->getType() == IceType_i64)) {
+    assert(isVectorType(Dest->getType()) ||
+           (isScalarFloatingType(Dest->getType()) &&
+            typeWidthInBytes(SrcVar->getType()) ==
+                typeWidthInBytes(Dest->getType())));
     assert(Dest->hasReg());
     typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg =
         InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
             Dest->getRegNum());
     if (SrcVar->hasReg()) {
-      Asm->movd(DestReg,
+      Asm->movd(SrcVar->getType(), DestReg,
                 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
                     SrcVar->getRegNum()));
     } else {
@@ -2378,17 +2431,23 @@
           static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
               Func->getTarget())
               ->stackVarToAsmOperand(SrcVar));
-      Asm->movd(DestReg, StackAddr);
+      Asm->movd(SrcVar->getType(), DestReg, StackAddr);
     }
   } else {
-    assert(isVectorType(SrcVar->getType()));
+    assert(isVectorType(SrcVar->getType()) ||
+           (isScalarFloatingType(SrcVar->getType()) &&
+            typeWidthInBytes(SrcVar->getType()) ==
+                typeWidthInBytes(Dest->getType())));
     assert(SrcVar->hasReg());
-    assert(Dest->getType() == IceType_i32);
+    assert(Dest->getType() == IceType_i32 ||
+           (InstX86Base<Machine>::Traits::Is64Bit &&
+            Dest->getType() == IceType_i64));
     typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
         InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
             SrcVar->getRegNum());
     if (Dest->hasReg()) {
-      Asm->movd(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
+      Asm->movd(Dest->getType(),
+                InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
                     Dest->getRegNum()),
                 SrcReg);
     } else {
@@ -2396,7 +2455,7 @@
           static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
               Func->getTarget())
               ->stackVarToAsmOperand(Dest));
-      Asm->movd(StackAddr, SrcReg);
+      Asm->movd(Dest->getType(), StackAddr, SrcReg);
     }
   }
 }