]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Do a bit more x86 floating point. As a result, had to do 'bsf' and 'bsr'
authorJulian Seward <jseward@acm.org>
Tue, 31 Aug 2004 23:55:54 +0000 (23:55 +0000)
committerJulian Seward <jseward@acm.org>
Tue, 31 Aug 2004 23:55:54 +0000 (23:55 +0000)
which in turn meant two new IR primops, Iop_Clz32 and Iop_Ctz32, to count
leading and trailing zeroes on a 32-bit word.

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

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/pub/libvex_ir.h

index 9e57e779942bba7f58909f3d640f5006891afe33..32d858f731c092e71b409f0fce52f1958a18338d 100644 (file)
@@ -3296,6 +3296,12 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
               put_ST(0, mkexpr(t1));
                break;
 
+            case 0xE8: /* FLD1 */
+               DIP("fldz");
+               fp_push();
+               put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
+               break;
+
             case 0xEE: /* FLDZ */
                DIP("fldz");
                fp_push();
@@ -3316,14 +3322,29 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
 
           /* bits 5,4,3 are an opcode extension, and the modRM also
             specifies an address. */
+         IROp   fop;
          IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
          delta += len;
-
          switch (gregOfRM(modrm)) {
+
             case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
                DIP("fimull %s", dis_buf);
+              fop = Iop_MulF64;
+              goto do_fop_m32;
+
+            case 4: /* FISUB m32int */ /* ST(0) -= m32int */
+               DIP("fisubl %s", dis_buf);
+              fop = Iop_SubF64;
+              goto do_fop_m32;
+
+            case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
+               DIP("fisubl %s", dis_buf);
+              fop = Iop_DivF64;
+              goto do_fop_m32;
+
+            do_fop_m32:
                put_ST_UNCHECKED(0, 
-                  binop(Iop_MulF64
+                  binop(fop
                         get_ST(0),
                         unop(Iop_I64toF64,
                              unop(Iop_32Sto64,
@@ -4015,61 +4036,110 @@ UInt dis_SHLRD_Gv_Ev ( UChar sorb,
 //--  
 //--    return eip;
 //-- }
-//-- 
-//-- 
-//-- 
-//-- /* Handle BSF/BSR.  Only v-size seems necessary. */
-//-- static
-//-- Addr dis_bs_E_G ( UCodeBlock* cb, 
-//--                   UChar       sorb,
-//--                   Int sz, Addr eip, Bool fwds )
-//-- {
-//--    Int   t, t1, ta, helper;
-//--    UInt  pair;
-//--     Char dis_buf[50];
-//--    UChar modrm;
-//--    Bool  isReg;
-//-- 
-//--    vg_assert(sz == 2 || sz == 4);
-//-- 
-//--    if (fwds)
-//--       helper = sz == 2 ? VGOFF_(helper_bsfw) : VGOFF_(helper_bsfl);
-//--    else
-//--       helper = sz == 2 ? VGOFF_(helper_bsrw) : VGOFF_(helper_bsrl);
-//--    
-//--    modrm  = getUChar(eip);
-//--    t1     = newTemp(cb);
-//--    t      = newTemp(cb);
-//-- 
-//--    uInstr0(cb, CALLM_S, 0);
-//--    uInstr2(cb, GET,  sz, ArchReg, gregOfRM(modrm), TempReg, t1);
-//--    uInstr1(cb, PUSH, sz, TempReg, t1);
-//-- 
-//--    isReg = epartIsReg(modrm);
-//--    if (isReg) {
-//--       eip++;
-//--       uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
-//--    } else {
-//--       pair = disAMode ( cb, sorb, eip, dis_buf );
-//--       ta   = LOW24(pair);
-//--       eip  += HI8(pair);
-//--       uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
-//--    }
-//--    DIP("bs%c%c %s, %s\n",
-//--        fwds ? 'f' : 'r', nameISize(sz), 
-//--        ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ), 
-//--        nameIReg(sz, gregOfRM(modrm)));
-//-- 
-//--    uInstr1(cb, PUSH,  sz,  TempReg, t);
-//--    uInstr1(cb, CALLM, 0,   Lit16, helper);
-//--    uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
-//--    uInstr1(cb, POP,   sz,  TempReg, t);
-//--    uInstr1(cb, POP,   sz,  TempReg, t);
-//--    uInstr2(cb, PUT,   sz,  TempReg, t, ArchReg, gregOfRM(modrm));
-//--    uInstr0(cb, CALLM_E, 0);
-//-- 
-//--    return eip;
-//-- }
+
+
+
+/* Handle BSF/BSR.  Only v-size seems necessary. */
+static
+UInt dis_bs_E_G ( UChar sorb, Int sz, UInt delta, Bool fwds )
+{
+   Bool   isReg;
+   UChar  modrm;
+   Char   dis_buf[50];
+   
+   IRType ty  = szToITy(sz);
+   IRTemp src = newTemp(ty);
+   IRTemp dst = newTemp(ty);
+
+   IRTemp src32 = newTemp(Ity_I32);
+   IRTemp dst32 = newTemp(Ity_I32);
+   IRTemp src8  = newTemp(Ity_I8);
+
+   vassert(sz == 4 || sz == 2);
+   vassert(sz == 4);
+
+   modrm = getIByte(delta);
+
+   isReg = epartIsReg(modrm);
+   if (isReg) {
+      delta++;
+      assign( src, getIReg(sz, eregOfRM(modrm)) );
+   } else {
+      Int    len;
+      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
+      delta += len;
+      assign( src, loadLE(ty, mkexpr(addr)) );
+   }
+
+   DIP("bs%c%c %s, %s\n",
+       fwds ? 'f' : 'r', nameISize(sz), 
+       ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ), 
+       nameIReg(sz, gregOfRM(modrm)));
+
+   /* Generate an 8-bit expression which is zero iff the 
+      original is zero, and nonzero otherwise */
+   assign( src8,
+           unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
+                           mkexpr(src), mkU(ty,0))) );
+
+   /* Flags: Z is 1 iff source value is zero.  All others 
+      are undefined -- we force them to zero. */
+   stmt( IRStmt_Put( OFFB_CC_OP,  mkU32(CC_OP_COPY) ));
+   stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
+   stmt( IRStmt_Put( 
+            OFFB_CC_SRC,
+            IRExpr_Mux0X( mkexpr(src8),
+                          /* src==0 */
+                          mkU32(CC_MASK_Z),
+                          /* src!=0 */
+                          mkU32(0)
+                        )
+       ));
+
+   /* Result: iff source value is zero, we can't use
+      Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
+      But anyway, Intel x86 semantics say the result is undefined in
+      such situations.  Hence handle the zero case specially. */
+
+   /* Bleh.  What we compute:
+
+          bsf32:  if src == 0 then 0 else  Ctz32(src)
+          bsr32:  if src == 0 then 0 else  31 - Clz32(src)
+
+          bsf16:  if src == 0 then 0 else  Ctz32(16Uto32(src))
+          bsr16:  if src == 0 then 0 else  31 - Clz32(16Uto32(src))
+
+      First, widen src to 32 bits if it is not already.
+   */
+   if (sz == 2)
+      assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
+   else
+      assign( src32, mkexpr(src) );
+
+   /* The main computation, guarding against zero. */
+   assign( dst32,   
+           IRExpr_Mux0X( 
+              mkexpr(src8),
+              /* src == 0 */
+              mkU32(0),
+              /* src != 0 */
+              fwds ? unop(Iop_Ctz32, mkexpr(src32))
+                   : binop(Iop_Sub32, 
+                           mkU32(31), 
+                           unop(Iop_Clz32, mkexpr(src32)))
+           )
+         );
+
+   if (sz == 2)
+      assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
+   else
+      assign( dst, mkexpr(dst32) );
+
+   /* dump result back */
+   putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
+
+   return delta;
+}
 
 
 static 
@@ -7761,15 +7831,15 @@ static UInt disInstr ( UInt delta, Bool* isEnd )
 //--          d32   = getSDisp8(eip + am_sz);
 //--          eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
 //--          break;
-//-- 
-//--       /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
-//-- 
-//--       case 0xBC: /* BSF Gv,Ev */
-//--          eip = dis_bs_E_G ( cb, sorb, sz, eip, True );
-//--          break;
-//--       case 0xBD: /* BSR Gv,Ev */
-//--          eip = dis_bs_E_G ( cb, sorb, sz, eip, False );
-//--          break;
+
+      /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
+
+      case 0xBC: /* BSF Gv,Ev */
+         delta = dis_bs_E_G ( sorb, sz, delta, True );
+         break;
+      case 0xBD: /* BSR Gv,Ev */
+         delta = dis_bs_E_G ( sorb, sz, delta, False );
+         break;
 
       /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
 
@@ -7834,7 +7904,7 @@ static UInt disInstr ( UInt delta, Bool* isEnd )
       case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
       case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
       case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
-//--       case 0x48: /* CMOVSb (cmov negative) */
+      case 0x48: /* CMOVSb (cmov negative) */
       case 0x49: /* CMOVSb (cmov not negative) */
 //--       case 0x4A: /* CMOVP (cmov parity even) */
 //--       case 0x4B: /* CMOVNP (cmov parity odd) */
index 0c3bf5e9cac00e646590a769c984406515bfb0b5..8e90ac911e29295aa3e238fc607f432b9496ac32 100644 (file)
@@ -544,6 +544,15 @@ X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ) {
    i->Xin.Set32.dst  = dst;
    return i;
 }
+X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst )
+{
+   X86Instr* i          = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag               = Xin_Bsfr32;
+   i->Xin.Bsfr32.isFwds = isFwds;
+   i->Xin.Bsfr32.src    = src;
+   i->Xin.Bsfr32.dst    = dst;
+   return i;
+}
 X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) {
    X86Instr* i        = LibVEX_Alloc(sizeof(X86Instr));
    i->tag             = Xin_FpUnary;
@@ -695,6 +704,12 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf("setl%s ", showX86CondCode(i->Xin.Set32.cond));
          ppHRegX86(i->Xin.Set32.dst);
          return;
+      case Xin_Bsfr32:
+         vex_printf("bs%cl ", i->Xin.Bsfr32.isFwds ? 'f' : 'r');
+         ppHRegX86(i->Xin.Bsfr32.src);
+         vex_printf(",");
+         ppHRegX86(i->Xin.Bsfr32.dst);
+         return;
       case Xin_FpUnary:
          vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op));
          ppHRegX86(i->Xin.FpUnary.src);
@@ -829,6 +844,10 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
       case Xin_Set32:
          addHRegUse(u, HRmWrite, i->Xin.Set32.dst);
          return;
+      case Xin_Bsfr32:
+         addHRegUse(u, HRmRead, i->Xin.Bsfr32.src);
+         addHRegUse(u, HRmWrite, i->Xin.Bsfr32.dst);
+         return;
       case Xin_FpUnary:
          addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
          addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
@@ -923,6 +942,10 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
       case Xin_Set32:
          mapReg(m, &i->Xin.Set32.dst);
          return;
+      case Xin_Bsfr32:
+         mapReg(m, &i->Xin.Bsfr32.src);
+         mapReg(m, &i->Xin.Bsfr32.dst);
+         return;
       case Xin_FpBinary:
          mapReg(m, &i->Xin.FpBinary.srcL);
          mapReg(m, &i->Xin.FpBinary.srcR);
@@ -1187,7 +1210,9 @@ static UChar* do_fop_st ( UChar* p, X86FpOp op, Int i )
    Int subopc;
    switch (op) {
       case Xfp_ADD: subopc = 0; break;
+      case Xfp_SUB: subopc = 4; break;
       case Xfp_MUL: subopc = 1; break;
+      case Xfp_DIV: subopc = 6; break;
       default: vpanic("do_fop_st: unknown op");
    }
    *p++ = 0xD8;
@@ -1648,6 +1673,16 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
       }
       goto done;
 
+   case Xin_Bsfr32:
+      *p++ = 0x0F;
+      if (i->Xin.Bsfr32.isFwds) {
+         *p++ = 0xBC;
+      } else {
+         *p++ = 0xBD;
+      }
+      p = doAMode_R(p, i->Xin.Bsfr32.dst, i->Xin.Bsfr32.src);
+      goto done;
+
    case Xin_Store:
       if (i->Xin.Store.sz == 2) {
          /* This case, at least, is simple, given that we can
index 145358f28e262fcf1e7d495fa078656598cc55d5..4b861363f324f42e222ee95daaa552139ce483a6 100644 (file)
@@ -274,6 +274,7 @@ typedef
       Xin_LoadEX,    /* mov{s,z}{b,w}l from mem to reg */
       Xin_Store,     /* store 16/8 bit value in memory */
       Xin_Set32,     /* convert condition code to 32-bit value */
+      Xin_Bsfr32,    /* 32-bit bsf/bsr */
       Xin_FpUnary,   /* FP fake unary op */
       Xin_FpBinary,  /* FP fake binary op */
       Xin_FpLdSt,    /* FP fake load/store */
@@ -373,6 +374,12 @@ typedef
             X86CondCode cond;
             HReg        dst;
          } Set32;
+         /* 32-bit bsf or bsr. */
+         struct {
+            Bool isFwds;
+            HReg src;
+            HReg dst;
+         } Bsfr32;
          /* X86 Floating point (fake 3-operand, "flat reg file" insns) */
          struct {
             X86FpOp op;
@@ -424,6 +431,7 @@ extern X86Instr* X86Instr_LoadEX   ( UChar szSmall, Bool syned,
                                      X86AMode* src, HReg dst );
 extern X86Instr* X86Instr_Store    ( UChar sz, HReg src, X86AMode* dst );
 extern X86Instr* X86Instr_Set32    ( X86CondCode cond, HReg dst );
+extern X86Instr* X86Instr_Bsfr32   ( Bool isFwds, HReg src, HReg dst );
 extern X86Instr* X86Instr_FpUnary  ( X86FpOp op, HReg src, HReg dst );
 extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst );
 extern X86Instr* X86Instr_FpLdSt   ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
index 146077f491a335cac88b11668c51f32c1d4b35d1..03bed0cf8e2b03c5669d0939022b5f88bfd9548c 100644 (file)
@@ -587,6 +587,27 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
             addInstr(env, X86Instr_Set32(cond,dst));
             return dst;
          }
+         case Iop_Ctz32: {
+            /* Count trailing zeroes, implemented by x86 'bsfl' */
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, X86Instr_Bsfr32(True,src,dst));
+            return dst;
+         }
+         case Iop_Clz32: {
+            /* Count leading zeroes.  Do 'bsrl' to establish the index
+               of the highest set bit, and subtract that value from
+               31. */
+            HReg tmp = newVRegI(env);
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, X86Instr_Bsfr32(False,src,tmp));
+            addInstr(env, X86Instr_Alu32R(Xalu_MOV, 
+                                          X86RMI_Imm(31), dst));
+            addInstr(env, X86Instr_Alu32R(Xalu_SUB,
+                                          X86RMI_Reg(tmp), dst));
+            return dst;
+         }
          case Iop_16to8:
          case Iop_32to8:
          case Iop_32to16:
@@ -1352,7 +1373,9 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
       X86FpOp fpop = Xfp_INVALID;
       switch (e->Iex.Binop.op) {
          case Iop_AddF64: fpop = Xfp_ADD; break;
+         case Iop_SubF64: fpop = Xfp_SUB; break;
          case Iop_MulF64: fpop = Xfp_MUL; break;
+         case Iop_DivF64: fpop = Xfp_DIV; break;
          default: break;
       }
       if (fpop != Xfp_INVALID) {
index accf6f7a13873cc40a955a939f6ab667a5990df6..9b1dfc3361e32cd7d2c58f92b97893066b928b37 100644 (file)
@@ -106,6 +106,9 @@ void ppIROp ( IROp op )
       case Iop_MullU16:  vex_printf("MullU16"); return;
       case Iop_MullU32:  vex_printf("MullU32"); return;
 
+      case Iop_Clz32:    vex_printf("Clz32"); return;
+      case Iop_Ctz32:    vex_printf("Ctz32"); return;
+
       case Iop_CmpLT32S: vex_printf("CmpLT32S"); return;
       case Iop_CmpLE32S: vex_printf("CmpLE32S"); return;
       case Iop_CmpLT32U: vex_printf("CmpLT32U"); return;
@@ -127,7 +130,9 @@ void ppIROp ( IROp op )
       case Iop_32HLto64: vex_printf("32HLto64"); return;
 
       case Iop_AddF64:   vex_printf("AddF64"); return;
+      case Iop_SubF64:   vex_printf("SubF64"); return;
       case Iop_MulF64:   vex_printf("MulF64"); return;
+      case Iop_DivF64:   vex_printf("DivF64"); return;
       case Iop_I64toF64: vex_printf("I64toF64"); return;
 
       default:           vpanic("ppIROp(1)");
@@ -577,6 +582,10 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_MullU32: case Iop_MullS32:
          BINARY(Ity_I64,Ity_I32,Ity_I32);
 
+      case Iop_Clz32:
+      case Iop_Ctz32:
+         UNARY(Ity_I32,Ity_I32);
+
       case Iop_DivModU64to32:
       case Iop_DivModS64to32:
          BINARY(Ity_I64,Ity_I64,Ity_I32);
@@ -606,7 +615,8 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_32Sto64: UNARY(Ity_I64,Ity_I32);
       case Iop_32to8:   UNARY(Ity_I8,Ity_I32);
 
-      case Iop_AddF64: case Iop_MulF64:
+      case Iop_AddF64: case Iop_SubF64: 
+      case Iop_MulF64: case Iop_DivF64:
          BINARY(Ity_F64,Ity_F64,Ity_F64);
       case Iop_I64toF64: UNARY(Ity_F64,Ity_I64);
 
index 6e211d8e08f8c9a95130f40efbff98c736984158..fc6814fc2a346f3049ffa7da42d7c59895f9c9ae 100644 (file)
@@ -98,6 +98,9 @@ typedef
       /* Widening multiplies */
       Iop_MullS8, Iop_MullS16, Iop_MullS32,
       Iop_MullU8, Iop_MullU16, Iop_MullU32,
+      /* Wierdo integer stuff */
+      Iop_Clz32,   /* count leading zeroes */
+      Iop_Ctz32,   /* count trailing zeros */
       /* Ordering not important after here. */
       Iop_CmpLT32S,
       Iop_CmpLE32S,
@@ -135,6 +138,11 @@ typedef
    }
    IROp;
 
+/* Notes.
+    Ctz32/Clz32 are UNDEFINED when given arguments of zero.
+    You must ensure they are never given a zero argument. 
+*/
+
 extern void ppIROp ( IROp );