Bug 1435249 - Generalized x86/x64 cmov encoding. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@gmail.com>
Fri, 02 Feb 2018 13:38:23 +0000
changeset 751769 61d73dd6b95fe42ee537635a9ed4656648c23b22
parent 751768 b88e2d95783789fa4b752b0e32ab71b55759925d
child 751770 44646ddb114772f27ad5081198fc0b2c4be5128b
push id98047
push userbmo:continuation@gmail.com
push dateTue, 06 Feb 2018 22:02:37 +0000
reviewersjandem
bugs1435249
milestone60.0a1
Bug 1435249 - Generalized x86/x64 cmov encoding. r=jandem
js/src/jit/x64/Assembler-x64.h
js/src/jit/x64/BaseAssembler-x64.h
js/src/jit/x86-shared/Assembler-x86-shared.cpp
js/src/jit/x86-shared/Assembler-x86-shared.h
js/src/jit/x86-shared/BaseAssembler-x86-shared.h
js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
js/src/jit/x86-shared/Encoding-x86-shared.h
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -457,31 +457,38 @@ class Assembler : public AssemblerX86Sha
     }
     void vmovq(FloatRegister src, Register dest) {
         masm.vmovq_rr(src.encoding(), dest.encoding());
     }
     void movq(Register src, Register dest) {
         masm.movq_rr(src.encoding(), dest.encoding());
     }
 
-    void cmovzq(const Operand& src, Register dest) {
+    void cmovCCq(Condition cond, const Operand& src, Register dest) {
+        X86Encoding::Condition cc = static_cast<X86Encoding::Condition>(cond);
         switch (src.kind()) {
           case Operand::REG:
-            masm.cmovzq_rr(src.reg(), dest.encoding());
+            masm.cmovCCq_rr(cc, src.reg(), dest.encoding());
             break;
           case Operand::MEM_REG_DISP:
-            masm.cmovzq_mr(src.disp(), src.base(), dest.encoding());
+            masm.cmovCCq_mr(cc, src.disp(), src.base(), dest.encoding());
             break;
           case Operand::MEM_SCALE:
-            masm.cmovzq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
+            masm.cmovCCq_mr(cc, src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void cmovzq(const Operand& src, Register dest) {
+        cmovCCq(Condition::Zero, src, dest);
+    }
+    void cmovnzq(const Operand& src, Register dest) {
+        cmovCCq(Condition::NonZero, src, dest);
+    }
 
     template<typename T>
     void lock_addq(T src, const Operand& op) {
         masm.prefix_lock();
         addq(src, op);
     }
     template<typename T>
     void lock_subq(T src, const Operand& op) {
--- a/js/src/jit/x64/BaseAssembler-x64.h
+++ b/js/src/jit/x64/BaseAssembler-x64.h
@@ -554,30 +554,31 @@ class BaseAssemblerX64 : public BaseAsse
     {
         spew("testq      $0x%4x, " MEM_obs, rhs, ADDR_obs(offset, base, index, scale));
         m_formatter.oneByteOp64(OP_GROUP3_EvIz, offset, base, index, scale, GROUP3_OP_TEST);
         m_formatter.immediate32(rhs);
     }
 
     // Various move ops:
 
-    void cmovzq_rr(RegisterID src, RegisterID dst)
+    void cmovCCq_rr(Condition cond, RegisterID src, RegisterID dst)
     {
-        spew("cmovz     %s, %s", GPReg16Name(src), GPReg32Name(dst));
-        m_formatter.twoByteOp64(OP2_CMOVZ_GvEv, src, dst);
+        spew("cmov%s     %s, %s", CCName(cond), GPReg64Name(src), GPReg64Name(dst));
+        m_formatter.twoByteOp64(cmovccOpcode(cond), src, dst);
     }
-    void cmovzq_mr(int32_t offset, RegisterID base, RegisterID dst)
+    void cmovCCq_mr(Condition cond, int32_t offset, RegisterID base, RegisterID dst)
     {
-        spew("cmovz     " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst));
-        m_formatter.twoByteOp64(OP2_CMOVZ_GvEv, offset, base, dst);
+        spew("cmov%s     " MEM_ob ", %s", CCName(cond), ADDR_ob(offset, base), GPReg64Name(dst));
+        m_formatter.twoByteOp64(cmovccOpcode(cond), offset, base, dst);
     }
-    void cmovzq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+    void cmovCCq_mr(Condition cond, int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
     {
-        spew("cmovz     " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg32Name(dst));
-        m_formatter.twoByteOp64(OP2_CMOVZ_GvEv, offset, base, index, scale, dst);
+        spew("cmov%s     " MEM_obs ", %s", CCName(cond), ADDR_obs(offset, base, index, scale),
+             GPReg64Name(dst));
+        m_formatter.twoByteOp64(cmovccOpcode(cond), offset, base, index, scale, dst);
     }
 
     void cmpxchgq(RegisterID src, int32_t offset, RegisterID base)
     {
         spew("cmpxchgq   %s, " MEM_ob, GPReg64Name(src), ADDR_ob(offset, base));
         m_formatter.twoByteOp64(OP2_CMPXCHG_GvEw, offset, base, src);
     }
 
--- a/js/src/jit/x86-shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.cpp
@@ -361,18 +361,24 @@ CPUInfo::SetSSEVersion()
     // If the hardware supports AVX, check whether the OS supports it too.
     if (avxPresent) {
         size_t xcr0EAX = ReadXGETBV();
         static const int xcr0SSEBit = 1 << 1;
         static const int xcr0AVXBit = 1 << 2;
         avxPresent = (xcr0EAX & xcr0SSEBit) && (xcr0EAX & xcr0AVXBit);
     }
 
+    // CMOV instruction are supposed to be supported by all CPU which have SSE2
+    // enabled. While this might be true, this is not guaranteed by any
+    // documentation, nor AMD, nor Intel.
+    static const int CMOVBit = 1 << 15;
+    MOZ_RELEASE_ASSERT(flagsEDX & CMOVBit,
+                       "CMOVcc instruction is not recognized by this CPU.");
+
     static const int POPCNTBit = 1 << 23;
-
     popcntPresent = (flagsECX & POPCNTBit);
 
     // Check if we need to work around an AMD CPU bug (see bug 1281759).
     // We check for family 20 models 0-2. Intel doesn't use family 20 at
     // this point, so this should only match AMD CPUs.
     unsigned family = ((flagsEAX >> 20) & 0xff) + ((flagsEAX >> 8) & 0xf);
     unsigned model = (((flagsEAX >> 16) & 0xf) << 4) + ((flagsEAX >> 4) & 0xf);
     needAmdBugWorkaround = (family == 20 && model <= 2);
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -448,31 +448,38 @@ class AssemblerX86Shared : public Assemb
     void nopAlign(int alignment) {
         masm.nopAlign(alignment);
     }
     void writeCodePointer(CodeOffset* label) {
         // Use -1 as dummy value. This will be patched after codegen.
         masm.jumpTablePointer(-1);
         label->bind(masm.size());
     }
-    void cmovz(const Operand& src, Register dest) {
+    void cmovCCl(Condition cond, const Operand& src, Register dest) {
+        X86Encoding::Condition cc = static_cast<X86Encoding::Condition>(cond);
         switch (src.kind()) {
           case Operand::REG:
-            masm.cmovz_rr(src.reg(), dest.encoding());
+            masm.cmovCCl_rr(cc, src.reg(), dest.encoding());
             break;
           case Operand::MEM_REG_DISP:
-            masm.cmovz_mr(src.disp(), src.base(), dest.encoding());
+            masm.cmovCCl_mr(cc, src.disp(), src.base(), dest.encoding());
             break;
           case Operand::MEM_SCALE:
-            masm.cmovz_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
+            masm.cmovCCl_mr(cc, src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void cmovzl(const Operand& src, Register dest) {
+        cmovCCl(Condition::Zero, src, dest);
+    }
+    void cmovnzl(const Operand& src, Register dest) {
+        cmovCCl(Condition::NonZero, src, dest);
+    }
     void movl(Imm32 imm32, Register dest) {
         masm.movl_i32r(imm32.value, dest.encoding());
     }
     void movl(Register src, Register dest) {
         masm.movl_rr(src.encoding(), dest.encoding());
     }
     void movl(const Operand& src, Register dest) {
         switch (src.kind()) {
--- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
@@ -2089,30 +2089,31 @@ public:
         m_formatter.oneByteOp(OP_XCHG_GvEv, offset, base, src);
     }
     void xchgl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("xchgl      %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
         m_formatter.oneByteOp(OP_XCHG_GvEv, offset, base, index, scale, src);
     }
 
-    void cmovz_rr(RegisterID src, RegisterID dst)
-    {
-        spew("cmovz     %s, %s", GPReg16Name(src), GPReg32Name(dst));
-        m_formatter.twoByteOp(OP2_CMOVZ_GvEv, src, dst);
-    }
-    void cmovz_mr(int32_t offset, RegisterID base, RegisterID dst)
-    {
-        spew("cmovz     " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst));
-        m_formatter.twoByteOp(OP2_CMOVZ_GvEv, offset, base, dst);
-    }
-    void cmovz_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
-    {
-        spew("cmovz     " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg32Name(dst));
-        m_formatter.twoByteOp(OP2_CMOVZ_GvEv, offset, base, index, scale, dst);
+    void cmovCCl_rr(Condition cond, RegisterID src, RegisterID dst)
+    {
+        spew("cmov%s     %s, %s", CCName(cond), GPReg32Name(src), GPReg32Name(dst));
+        m_formatter.twoByteOp(cmovccOpcode(cond), src, dst);
+    }
+    void cmovCCl_mr(Condition cond, int32_t offset, RegisterID base, RegisterID dst)
+    {
+        spew("cmov%s     " MEM_ob ", %s", CCName(cond), ADDR_ob(offset, base), GPReg32Name(dst));
+        m_formatter.twoByteOp(cmovccOpcode(cond), offset, base, dst);
+    }
+    void cmovCCl_mr(Condition cond, int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+    {
+        spew("cmov%s     " MEM_obs ", %s", CCName(cond), ADDR_obs(offset, base, index, scale),
+             GPReg32Name(dst));
+        m_formatter.twoByteOp(cmovccOpcode(cond), offset, base, index, scale, dst);
     }
 
     void movl_rr(RegisterID src, RegisterID dst)
     {
         spew("movl       %s, %s", GPReg32Name(src), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_MOV_GvEv, src, dst);
     }
 
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -333,17 +333,17 @@ CodeGeneratorX86Shared::visitWasmSelect(
     Register cond = ToRegister(ins->condExpr());
     Operand falseExpr = ToOperand(ins->falseExpr());
 
     masm.test32(cond, cond);
 
     if (mirType == MIRType::Int32) {
         Register out = ToRegister(ins->output());
         MOZ_ASSERT(ToRegister(ins->trueExpr()) == out, "true expr input is reused for output");
-        masm.cmovz(falseExpr, out);
+        masm.cmovzl(falseExpr, out);
         return;
     }
 
     FloatRegister out = ToFloatRegister(ins->output());
     MOZ_ASSERT(ToFloatRegister(ins->trueExpr()) == out, "true expr input is reused for output");
 
     Label done;
     masm.j(Assembler::NonZero, &done);
--- a/js/src/jit/x86-shared/Encoding-x86-shared.h
+++ b/js/src/jit/x86-shared/Encoding-x86-shared.h
@@ -178,17 +178,17 @@ enum TwoByteOpcodeID {
     OP2_MOVLHPS_VqUq    = 0x16,
     OP2_MOVSHDUP_VpsWps = 0x16,
     OP2_MOVAPD_VsdWsd   = 0x28,
     OP2_MOVAPS_VsdWsd   = 0x28,
     OP2_MOVAPS_WsdVsd   = 0x29,
     OP2_CVTSI2SD_VsdEd  = 0x2A,
     OP2_CVTTSD2SI_GdWsd = 0x2C,
     OP2_UCOMISD_VsdWsd  = 0x2E,
-    OP2_CMOVZ_GvEv      = 0x44,
+    OP2_CMOVCC_GvEv     = 0x40,
     OP2_MOVMSKPD_EdVd   = 0x50,
     OP2_ANDPS_VpsWps    = 0x54,
     OP2_ANDNPS_VpsWps   = 0x55,
     OP2_ORPS_VpsWps     = 0x56,
     OP2_XORPS_VpsWps    = 0x57,
     OP2_ADDSD_VsdWsd    = 0x58,
     OP2_ADDPS_VpsWps    = 0x58,
     OP2_MULSD_VsdWsd    = 0x59,
@@ -342,16 +342,20 @@ inline OneByteOpcodeID jccRel8(Condition
 inline TwoByteOpcodeID jccRel32(Condition cond)
 {
     return TwoByteOpcodeID(OP2_JCC_rel32 + cond);
 }
 inline TwoByteOpcodeID setccOpcode(Condition cond)
 {
     return TwoByteOpcodeID(OP_SETCC + cond);
 }
+inline TwoByteOpcodeID cmovccOpcode(Condition cond)
+{
+    return TwoByteOpcodeID(OP2_CMOVCC_GvEv + cond);
+}
 
 enum GroupOpcodeID {
     GROUP1_OP_ADD = 0,
     GROUP1_OP_OR  = 1,
     GROUP1_OP_ADC = 2,
     GROUP1_OP_SBB = 3,
     GROUP1_OP_AND = 4,
     GROUP1_OP_SUB = 5,