]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement cmpxchg8b. Sheesh. What a total dog of an instruction.
authorJulian Seward <jseward@acm.org>
Fri, 12 Aug 2005 23:04:48 +0000 (23:04 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 12 Aug 2005 23:04:48 +0000 (23:04 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@1331

VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/isel.c

index 79321fcf721fd4004f90ba1c1d264e7458a03a6f..70b4cfa146a95ea388dd51a4df8d498db53869bc 100644 (file)
@@ -11709,10 +11709,72 @@ DisResult disInstr_X86_WRK (
       case 0xB1: /* CMPXCHG Gv,Ev */
          delta = dis_cmpxchg_G_E ( sorb, sz, delta );
          break;
-//--       case 0xC7: /* CMPXCHG8B Gv */
-//--          eip = dis_cmpxchg8b ( cb, sorb, eip );
-//--          break;
-//-- 
+
+      case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
+         IRTemp   m64_old = newTemp(Ity_I64);
+         IRTemp   m64_new = newTemp(Ity_I64);
+         IRTemp    da_old = newTemp(Ity_I64);
+         IRTemp    da_new = newTemp(Ity_I64);
+         IRTemp    cb_old = newTemp(Ity_I64);
+         IRTemp flags_old = newTemp(Ity_I32);
+         IRTemp flags_new = newTemp(Ity_I32);
+         IRTemp      cond = newTemp(Ity_I8);
+
+        /* Decode, and generate address. */
+         modrm = getIByte(delta);
+         if (epartIsReg(modrm)) goto decode_failure;
+         if (gregOfRM(modrm) != 1) goto decode_failure;
+         addr = disAMode ( &alen, sorb, delta, dis_buf );
+         delta += alen;
+
+        /* Fetch the old 64-bit values and compute the guard. */
+         assign( m64_old, loadLE(Ity_I64, mkexpr(addr) ));
+         assign( da_old,  binop(Iop_32HLto64, 
+                                getIReg(4,R_EDX), getIReg(4,R_EAX)) );
+         assign( cb_old,  binop(Iop_32HLto64, 
+                                getIReg(4,R_ECX), getIReg(4,R_EBX)) );
+
+        assign( cond, 
+                 unop(Iop_1Uto8, 
+                      binop(Iop_CmpEQ64, mkexpr(da_old), mkexpr(m64_old))) );
+
+         /* Compute new %edx:%eax and m64 values, and put in place */
+         assign( da_new, 
+                 IRExpr_Mux0X(mkexpr(cond), mkexpr(m64_old), mkexpr(da_old)));
+         assign( m64_new,
+                 IRExpr_Mux0X(mkexpr(cond), mkexpr(m64_old), mkexpr(cb_old)));
+
+         putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(da_new)) );
+         putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(da_new)) );
+         storeLE( mkexpr(addr), mkexpr(m64_new) );
+
+         /* Copy the guard into the Z flag and leave the others unchanged */
+         assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
+         assign( 
+            flags_new,
+            binop(Iop_Or32,
+                  binop(Iop_And32, mkexpr(flags_old), 
+                                   mkU32(~X86G_CC_MASK_Z)),
+                  binop(Iop_Shl32, 
+                        binop(Iop_And32, 
+                              unop(Iop_8Uto32, mkexpr(cond)), mkU32(1)), 
+                        mkU8(X86G_CC_SHIFT_Z)) ));
+
+         stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
+         stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
+         stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
+         /* Set NDEP even though it isn't used.  This makes
+            redundant-PUT elimination of previous stores to this field
+            work better. */
+         stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
+
+         /* Sheesh.  Aren't you glad it was me and not you that had to
+           write and validate all this grunge? */
+
+        DIP("cmpxchg8b %s\n", dis_buf);
+        break;
+      }
+
       /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
 
       case 0xA2: { /* CPUID */
index a821e82cf9c99b9867f14518ce9811aac4f32f62..33b501c7ba7a21ce1f594aefa73113efb85f8f4f 100644 (file)
@@ -1721,7 +1721,8 @@ static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
 
    /* CmpNE64 */
    if (e->tag == Iex_Binop 
-       && e->Iex.Binop.op == Iop_CmpNE64) {
+       && (e->Iex.Binop.op == Iop_CmpNE64
+           || e->Iex.Binop.op == Iop_CmpEQ64)) {
       HReg hi1, hi2, lo1, lo2;
       HReg tHi = newVRegI(env);
       HReg tLo = newVRegI(env);
@@ -1734,6 +1735,7 @@ static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
       addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(tHi), tLo));
       switch (e->Iex.Binop.op) {
          case Iop_CmpNE64:  return Xcc_NZ;
+         case Iop_CmpEQ64:  return Xcc_Z;
          default: vpanic("iselCondCode(x86): CmpXX64");
       }
    }