]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fill in many x86 integer and FP cases, enough to get konqueror
authorJulian Seward <jseward@acm.org>
Sat, 11 Sep 2004 09:30:24 +0000 (09:30 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 11 Sep 2004 09:30:24 +0000 (09:30 +0000)
running.  This also involves adding some iropt const-folding rules.

git-svn-id: svn://svn.valgrind.org/vex/trunk@255

VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/hdefs.c
VEX/priv/host-x86/hdefs.h
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/priv/ir/iropt.c
VEX/pub/libvex_ir.h

index fda5c61fceed1fb90d411b644aedd0780f7b8900..6b42c9724156cddbd5c4fb01f752606a8a4d158d 100644 (file)
@@ -9,9 +9,10 @@
 /* TODO:
    SBB reg with itself
    is Iop_Neg* used?
-   xadd %reg,%reg fix
    MOVAPS fix (vg_to_ucode rev 1.143)
    check flag settings for cmpxchg
+   FUCOMI(P): what happens to A and S flags?  Currently are forced
+      to zero.
 */
 
 /* Translates x86 code to IR. */
@@ -3033,7 +3034,7 @@ UInt dis_imul_I_E_G ( UChar       sorb,
                       UInt        delta,
                       Int         litsize )
 {
-   Int    d32;
+   Int    d32, alen;
    Char   dis_buf[50];
    UChar  rm = getIByte(delta);
    IRType ty = szToITy(size);
@@ -3046,13 +3047,9 @@ UInt dis_imul_I_E_G ( UChar       sorb,
       assign(te, getIReg(size, eregOfRM(rm)));
       delta++;
    } else {
-      vassert(0);
-#if 0
-      UInt pair = disAMode ( cb, sorb, eip, dis_buf );
-      ta = LOW24(pair);
-      uInstr2(cb, LOAD,  size, TempReg, ta, TempReg, te);
-      eip += HI8(pair);
-#endif
+      IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
+      assign(te, loadLE(ty, mkexpr(addr)));
+      delta += alen;
    }
    d32 = getSDisp(litsize,delta);
    delta += litsize;
@@ -3317,7 +3314,7 @@ void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
 */
 static
 void fp_do_oprev_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf, 
-                         IROp op, Bool dbl )
+                            IROp op, Bool dbl )
 {
    DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
    if (dbl) {
@@ -3357,7 +3354,7 @@ void fp_do_op_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
 */
 static
 void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
-                      Bool pop_after )
+                         Bool pop_after )
 {
    DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
    put_ST_UNCHECKED( 
@@ -3524,23 +3521,28 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
                break;
 
-           case 0xE5: { /* FXAM */
-              /* This is an interesting one.  It examines %st(0),
-                 regardless of whether the tag says it's empty or not.
-                 Here, just pass both the tag (in our format) and the
-                 value (as a double, actually a ULong) to a helper
-                 function. */
-              IRExpr** args;
-              DIP("fxam");
-              args = LibVEX_Alloc(3 * sizeof(IRExpr*));
-              args[0] = unop(Iop_8Uto32, get_ST_TAG(0));
-              args[1] = get_ST_UNCHECKED_as_ULong(0);
-              args[2] = NULL;
-              put_C3210(IRExpr_CCall("calculate_FXAM", Ity_I32, args));
-              break;
-           }
-
-           case 0xE8: /* FLD1 */
+            case 0xE1: /* FABS */
+               DIP("fabs\n");
+               put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
+               break;
+
+            case 0xE5: { /* FXAM */
+               /* This is an interesting one.  It examines %st(0),
+                  regardless of whether the tag says it's empty or not.
+                  Here, just pass both the tag (in our format) and the
+                  value (as a double, actually a ULong) to a helper
+                  function. */
+               IRExpr** args;
+               DIP("fxam");
+               args = LibVEX_Alloc(3 * sizeof(IRExpr*));
+               args[0] = unop(Iop_8Uto32, get_ST_TAG(0));
+               args[1] = get_ST_UNCHECKED_as_ULong(0);
+               args[2] = NULL;
+               put_C3210(IRExpr_CCall("calculate_FXAM", Ity_I32, args));
+               break;
+            }
+
+            case 0xE8: /* FLD1 */
                DIP("fld1");
                fp_push();
                put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
@@ -3755,6 +3757,21 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
                break;
 
+            case 3: /* FCOMP double-real */
+               DIP("fcomp %s\n", dis_buf);
+               /* This forces C1 to zero, which isn't right. */
+               put_C3210( 
+                   binop( Iop_And32,
+                          binop(Iop_Shl32, 
+                                binop(Iop_CmpF64, 
+                                      get_ST(0),
+                                      loadLE(Ity_F64,mkexpr(addr))),
+                                mkU8(8)),
+                          mkU32(0x4500)
+                   ));
+               fp_pop();
+               break;  
+
             case 4: /* FSUB double-real */
                fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
                break;
@@ -3767,6 +3784,10 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
                break;
 
+            case 7: /* FDIVR double-real */
+               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
+               break;
+
             default:
                vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
                vex_printf("first_opcode == 0xDC\n");
@@ -3939,6 +3960,14 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
 
          switch (gregOfRM(modrm)) {
 
+            case 0: /* FILD m16int */
+               DIP("fildw %s\n", dis_buf);
+               fp_push();
+               put_ST(0, unop(Iop_I32toF64,
+                              unop(Iop_16Sto32,
+                                   loadLE(Ity_I16, mkexpr(addr)))));
+               break;
+
             case 3: /* FISTP m16 */
                DIP("fistps %s", dis_buf);
                storeLE( mkexpr(addr), 
@@ -3987,6 +4016,23 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                )));
                break;
 
+            case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
+               r_dst = (UInt)modrm - 0xE8;
+               DIP("fucomip %%st(0),%%st(%d)\n", r_dst);
+               /* This is a bit of a hack (and isn't really right).
+                  It sets Z,P,C,O correctly, but forces A and S to
+                  zero, whereas the Intel documentation implies A and
+                  S are unchanged. */
+               stmt( IRStmt_Put( OFFB_CC_OP,  mkU32(CC_OP_COPY) ));
+               stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
+               stmt( IRStmt_Put( OFFB_CC_SRC,
+                        binop( Iop_And32,
+                               binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
+                               mkU32(0x45)
+                     )));
+               fp_pop();
+               break;
+
             default: 
                goto decode_fail;
         }
@@ -4869,7 +4915,7 @@ UInt dis_cmov_E_G ( UChar       sorb,
    UChar dis_buf[50];
    Int   len;
 
-   IRType ty = szToITy(sz);
+   IRType ty   = szToITy(sz);
    IRTemp tmps = newTemp(ty);
    IRTemp tmpd = newTemp(ty);
 
@@ -4910,44 +4956,48 @@ UInt dis_cmov_E_G ( UChar       sorb,
 }
 
 
-//-- static
-//-- Addr dis_xadd_G_E ( UCodeBlock* cb, 
-//--                     UChar       sorb,
-//--                     Int         sz, 
-//--                     Addr        eip0 )
-//-- {
-//--    UChar rm  = getUChar(eip0);
-//--    UChar dis_buf[50];
-//-- 
-//--    Int tmpd = newTemp(cb);   
-//--    Int tmpt = newTemp(cb);
-//-- 
-//--    if (epartIsReg(rm)) {
-//--       uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
-//--       uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
-//--       uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
-//--       setFlagsFromUOpcode(cb, ADD);
-//--       uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
-//--       uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
-//--       DIP("xadd%c %s, %s\n", 
-//--           nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
-//--       return 1+eip0;
-//--    } else {
-//--       UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
-//--       Int  tmpa  = LOW24(pair);
-//--       uInstr2(cb, LOAD, sz, TempReg, tmpa,          TempReg, tmpd);
-//--       uInstr2(cb, GET,  sz, ArchReg, gregOfRM(rm),  TempReg, tmpt);
-//--       uInstr2(cb,  ADD, sz, TempReg, tmpd, TempReg, tmpt);
-//--       setFlagsFromUOpcode(cb, ADD);
-//--       uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
-//--       uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
-//--       DIP("xadd%c %s, %s\n", 
-//--           nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
-//--       return HI8(pair)+eip0;
-//--    }
-//-- }
-//-- 
-//-- 
+static
+UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 )
+{
+   Int   len;
+   UChar rm = getIByte(delta0);
+   UChar dis_buf[50];
+
+   //   Int tmpd = newTemp(cb);
+   //Int tmpt = newTemp(cb);
+
+   IRType ty    = szToITy(sz);
+   IRTemp tmpd  = newTemp(ty);
+   IRTemp tmpt0 = newTemp(ty);
+   IRTemp tmpt1 = newTemp(ty);
+
+   if (epartIsReg(rm)) {
+     vassert(0);
+#if 0
+      uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
+      uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
+      uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
+      setFlagsFromUOpcode(cb, ADD);
+      uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
+      uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
+      DIP("xadd%c %s, %s\n",
+          nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
+      return 1+eip0;
+#endif
+   } else {
+      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
+      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
+      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
+      setFlags_ADD_SUB( Iop_Add8, tmpt0, tmpd, ty );
+      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
+      storeLE( mkexpr(addr), mkexpr(tmpt1) );
+      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
+      DIP("xadd%c %s, %s\n",
+          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
+      return len+delta0;
+   }
+}
+
 //-- /* Moves of Ew into a segment register.
 //--       mov Ew, Sw  meaning
 //--       mov reg-or-mem, reg
@@ -7835,7 +7885,7 @@ static UInt disInstr ( UInt delta, Bool* isEnd )
          correctly pushes the old value. */
       vassert(sz == 2 || sz == 4);
       ty = sz==2 ? Ity_I16 : Ity_I32;
-      t1 = newTemp(ty); t2 = newTemp(ty);
+      t1 = newTemp(ty); t2 = newTemp(Ity_I32);
       assign(t1, getIReg(sz, opc-0x50));
       assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
       putIReg(4, R_ESP, mkexpr(t2) );
@@ -7954,10 +8004,10 @@ static UInt disInstr ( UInt delta, Bool* isEnd )
 //--       dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
 //--       break;
 //-- 
-//--    case 0xAA: /* STOS, no REP prefix */
+   case 0xAA: /* STOS, no REP prefix */
 //--    case 0xAB:
-//--       dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
-//--       break;
+      dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
+      break;
 //--    
 //--    case 0xAC: /* LODS, no REP prefix */
 //--    case 0xAD:
@@ -8653,15 +8703,15 @@ static UInt disInstr ( UInt delta, Bool* isEnd )
                     "%cl", False );
          break;
 
-//--       /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
+//--       /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
 //-- 
 //--       case 0xC0: /* XADD Gb,Eb */
 //--          eip = dis_xadd_G_E ( cb, sorb, 1, eip );
 //--          break;
-//--       case 0xC1: /* XADD Gv,Ev */
-//--          eip = dis_xadd_G_E ( cb, sorb, sz, eip );
-//--          break;
-//-- 
+      case 0xC1: /* XADD Gv,Ev */
+         delta = dis_xadd_G_E ( sorb, sz, delta );
+         break;
+
 //--       /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
 //-- 
 //--       case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/
index 37707b2cd62e8c4242d11fba71fcdde8aaf59f1c..b7b89fa9aff0bd688f8bfed5b1d63fdbc3a1169c 100644 (file)
@@ -415,7 +415,8 @@ Char* showX86FpOp ( X86FpOp op ) {
       case Xfp_MUL:    return "mul";
       case Xfp_DIV:    return "div";
       case Xfp_SQRT:   return "sqrt";
-      case Xfp_NEGATE: return "chs";
+      case Xfp_NEG:    return "chs";
+      case Xfp_ABS:    return "abs";
       case Xfp_MOV:    return "mov";
       case Xfp_SIN:    return "sin";
       case Xfp_COS:    return "cos";
@@ -1258,7 +1259,8 @@ static UChar* do_fld_st ( UChar* p, Int i )
 static UChar* do_fop1_st ( UChar* p, X86FpOp op )
 {
    switch (op) {
-      case Xfp_NEGATE: *p++ = 0xD9; *p++ = 0xE0; break;
+      case Xfp_NEG:    *p++ = 0xD9; *p++ = 0xE0; break;
+      case Xfp_ABS:    *p++ = 0xD9; *p++ = 0xE1; break;
       case Xfp_SQRT:   *p++ = 0xD9; *p++ = 0xFA; break;
       case Xfp_ROUND:  *p++ = 0xD9; *p++ = 0xFC; break;
       case Xfp_SIN:    *p++ = 0xD9; *p++ = 0xFE; break;
index f40771576d2aec56ac8985e2b078119ced56a826..5e163e8ea4d839598e40600ac76ad49fd16a2c32 100644 (file)
@@ -249,7 +249,7 @@ typedef
       /* Binary */
       Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, Xfp_ATANYX,
       /* Unary */
-      Xfp_SQRT, Xfp_NEGATE, Xfp_MOV, Xfp_SIN, Xfp_COS,
+      Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS,
       Xfp_ROUND
    }
    X86FpOp;
index 713cc9ba39776999705a5422102863f40bb77416..9d9c29a083f84940a614db48e4ef35db21e7240a 100644 (file)
@@ -1669,7 +1669,8 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
    if (e->tag == Iex_Unop) {
       X86FpOp fpop = Xfp_INVALID;
       switch (e->Iex.Unop.op) {
-         case Iop_NegF64:  fpop = Xfp_NEGATE; break;
+         case Iop_NegF64:  fpop = Xfp_NEG; break;
+         case Iop_AbsF64:  fpop = Xfp_ABS; break;
          case Iop_SqrtF64: fpop = Xfp_SQRT; break;
          case Iop_SinF64:  fpop = Xfp_SIN; break;
          case Iop_CosF64:  fpop = Xfp_COS; break;
index cdb019238aaba05b0c3595812b28816d20282265..a930d70076b96a140e160d78478061fb7293456b 100644 (file)
@@ -136,6 +136,7 @@ void ppIROp ( IROp op )
       case Iop_DivF64:    vex_printf("DivF64"); return;
       case Iop_CmpF64:    vex_printf("CmpF64"); return;
       case Iop_NegF64:    vex_printf("NegF64"); return;
+      case Iop_AbsF64:    vex_printf("AbsF64"); return;
       case Iop_SqrtF64:   vex_printf("SqrtF64"); return;
       case Iop_SinF64:    vex_printf("SinF64"); return;
       case Iop_CosF64:    vex_printf("CosF64"); return;
@@ -637,7 +638,8 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
          BINARY(Ity_F64,Ity_F64,Ity_F64);
       case Iop_CmpF64:
          BINARY(Ity_I32,Ity_F64,Ity_F64);
-      case Iop_NegF64: case Iop_SqrtF64: case Iop_SinF64: case Iop_CosF64:
+      case Iop_NegF64: case Iop_AbsF64: case Iop_SqrtF64:
+      case Iop_SinF64: case Iop_CosF64:
          UNARY(Ity_F64,Ity_F64);
 
       case Iop_I32toF64: UNARY(Ity_F64,Ity_I32);
index 807fcaecee658c8f92ee5a14b27b2e488da785fa..59ebba9c58f8bf422759146da225a34176908451 100644 (file)
@@ -317,6 +317,13 @@ static IRExpr* fold_Expr ( IRExpr* e )
    if (e->tag == Iex_Unop
        && e->Iex.Unop.arg->tag == Iex_Const) {
       switch (e->Iex.Unop.op) {
+         case Iop_8Sto32: {
+            /* signed */ Int s32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
+            s32 <<= 24;
+            s32 >>= 24;
+            e2 = IRExpr_Const(IRConst_U32((UInt)s32));
+            break;
+         }
          case Iop_8Uto32:
             e2 = IRExpr_Const(IRConst_U32(
                     0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8));
@@ -325,6 +332,10 @@ static IRExpr* fold_Expr ( IRExpr* e )
             e2 = IRExpr_Const(IRConst_U32(
                     0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16));
             break;
+         case Iop_Not32:
+            e2 = IRExpr_Const(IRConst_U32(
+                    ~ (e->Iex.Unop.arg->Iex.Const.con->Ico.U32)));
+            break;
          default: 
             goto unhandled;
       }
@@ -336,6 +347,11 @@ static IRExpr* fold_Expr ( IRExpr* e )
           && e->Iex.Binop.arg2->tag == Iex_Const) {
          /* cases where both args are consts */
          switch (e->Iex.Binop.op) {
+            case Iop_Xor8:
+               e2 = IRExpr_Const(IRConst_U8(0xFF & 
+                       (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
+                        ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U8)));
+               break;
             case Iop_And8:
                e2 = IRExpr_Const(IRConst_U8(0xFF & 
                        (e->Iex.Binop.arg1->Iex.Const.con->Ico.U8
@@ -356,6 +372,11 @@ static IRExpr* fold_Expr ( IRExpr* e )
                        (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
                         + e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
                break;
+            case Iop_Xor32:
+               e2 = IRExpr_Const(IRConst_U32(
+                       (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
+                        ^ e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)));
+               break;
             case Iop_And32:
                e2 = IRExpr_Const(IRConst_U32(
                        (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32
@@ -414,8 +435,6 @@ static IRExpr* fold_Expr ( IRExpr* e )
                        | ((ULong)(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32)) 
                     ));
                break;
-            case Iop_MullS32:
-               break;
             default:
                goto unhandled;
          }
@@ -460,9 +479,16 @@ static IRExpr* fold_Expr ( IRExpr* e )
    return e2;
 
  unhandled:
+#  if 0
    vex_printf("\n\n");
    ppIRExpr(e);
    vpanic("fold_Expr: no rule for the above");
+#  else
+   vex_printf("vex iropt: fold_Expr: no rule for: ");
+   ppIRExpr(e);
+   vex_printf("\n");
+   return e2;
+#  endif
 }
 
 
index ce395166051d2d403de3519f55d3aaeee855e926..bda179440669acf8fd2fe95e63f3ea1be26e8fb1 100644 (file)
@@ -164,13 +164,13 @@ typedef
       Iop_AtanYXF64,
 
       /* Unary operations */
-      Iop_NegF64, Iop_SqrtF64, Iop_SinF64, Iop_CosF64,
+      Iop_NegF64, Iop_AbsF64, Iop_SqrtF64, Iop_SinF64, Iop_CosF64,
 
       /* Comparison, yielding GT/LT/EQ/UN(ordered), as per the following:
-            0x85 Unordered
+            0x45 Unordered
             0x01 LT
             0x00 GT
-            0x80 EQ
+            0x40 EQ
          This just happens to be the Intel encoding.  The values
          are recorded in the type IRCmpF64Result.
       */