]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Finally finish pissing around with x86 integer multiply instructions.
authorJulian Seward <jseward@acm.org>
Fri, 30 Jul 2004 10:17:50 +0000 (10:17 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 30 Jul 2004 10:17:50 +0000 (10:17 +0000)
The amount of random illogical crap in the x86 instruction set is just
mind-numbing.  Anyway, 8/16/32-bit multiply and multiply longs should
now work correctly, including setting the flags.

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

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

index 9ab4beb5b81c3b092a85acff26ac03643b0ac05a..64f86d2c2f16c2487f57df65e2b1af93158abd39 100644 (file)
@@ -345,9 +345,13 @@ static inline int lshift(int x, int n)
       case CC_OP_RORW:   ACTIONS_ROR( 16, UShort );
       case CC_OP_RORL:   ACTIONS_ROR( 32, UInt   );
 
-      case CC_OP_UMULL:  ACTIONS_UMUL( 32, UInt, ULong );
+      case CC_OP_UMULB:  ACTIONS_UMUL(  8, UChar,  UShort );
+      case CC_OP_UMULW:  ACTIONS_UMUL( 16, UShort, UInt   );
+      case CC_OP_UMULL:  ACTIONS_UMUL( 32, UInt,   ULong  );
 
-      case CC_OP_SMULL:  ACTIONS_SMUL( 32, Int,  Long );
+      case CC_OP_SMULB:  ACTIONS_SMUL(  8, Char,  Short );
+      case CC_OP_SMULW:  ACTIONS_SMUL( 16, Short, Int   );
+      case CC_OP_SMULL:  ACTIONS_SMUL( 32, Int,   Long  );
 
       default:
          /* shouldn't really make these calls from generated code */
index 0830474b57ec5d7f61732816e40860f88c2436b1..b760858057b8c494616b2f8b0998184b652ff7fe 100644 (file)
@@ -2459,30 +2459,37 @@ static void codegen_mulL_A_D ( Int sz, Bool syned,
    assign( t1, getIReg(sz, R_EAX) );
 
    switch (ty) {
-   case Ity_I32: {
-      IRTemp res64   = newTemp(Ity_I64);
-      IROp   mulOp   = syned ? Iop_MullS32 : Iop_MullU32;
-      UInt   thunkOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
-      setFlags_MUL ( Ity_I32, t1, tmp, thunkOp );
-      assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
-      putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64)));
-      putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64)));
-      break;
-   }
-#if 0
-   case Ity_I16: {
-      IRTemp res32   = newTemp(Ity_I32);
-      IROp   mulOp   = syned ? Iop_MullS16 : Iop_MullU16;
-      UInt   thunkOp = syned ? CC_OP_MULLSB : CC_OP_MULLUB;
-      setFlags_MUL ( Ity_I16, t1, tmp, thunkOp );
-      assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
-      putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32)));
-      putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32)));
-      break;
-   }
-#endif
-   default:
-      vpanic("codegen_mulL_A_D(x86)");
+      case Ity_I32: {
+         IRTemp res64   = newTemp(Ity_I64);
+         IROp   mulOp   = syned ? Iop_MullS32 : Iop_MullU32;
+         UInt   tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+         setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
+         assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
+         putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64)));
+         putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64)));
+         break;
+      }
+      case Ity_I16: {
+         IRTemp res32   = newTemp(Ity_I32);
+         IROp   mulOp   = syned ? Iop_MullS16 : Iop_MullU16;
+         UInt   tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+         setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
+         assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
+         putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32)));
+         putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32)));
+         break;
+      }
+      case Ity_I8: {
+         IRTemp res16   = newTemp(Ity_I16);
+         IROp   mulOp   = syned ? Iop_MullS8 : Iop_MullU8;
+         UInt   tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+         setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
+         assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
+         putIReg(2, R_EAX, mkexpr(res16));
+         break;
+      }
+      default:
+         vpanic("codegen_mulL_A_D(x86)");
    }
    DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
 }
@@ -3029,14 +3036,15 @@ UInt dis_imul_I_E_G ( UChar       sorb,
                       UInt        delta,
                       Int         litsize )
 {
-   Int   d32;
-   Char  dis_buf[50];
-   UChar rm = getIByte(delta);
-    //   ta = INVALID_TEMPREG;
+   Int    d32;
+   Char   dis_buf[50];
+   UChar  rm = getIByte(delta);
    IRType ty = szToITy(size);
    IRTemp te = newTemp(ty);
    IRTemp tl = newTemp(ty);
 
+   vassert(size == 1 || size == 2 || size == 4);
+
    if (epartIsReg(rm)) {
       assign(te, getIReg(size, eregOfRM(rm)));
       delta++;
@@ -3052,6 +3060,9 @@ UInt dis_imul_I_E_G ( UChar       sorb,
    d32 = getSDisp(litsize,delta);
    delta += litsize;
 
+   if (size == 1) d32 &= 0xFF;
+   if (size == 2) d32 &= 0xFFFF;
+
    assign(tl, mkU(ty,d32));
    setFlags_MUL ( ty, te, tl, CC_OP_SMULB );
    putIReg(size, gregOfRM(rm), 
index 0fdf658075aca7092edbe9dca68afceda6b180af..460e2ba5baa69b091e8a4f5d9787bd82066d6a93 100644 (file)
@@ -294,8 +294,10 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
             aluOp = Xalu_OR; break;
          case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: 
             aluOp = Xalu_XOR; break;
-         case Iop_Mul32: aluOp = Xalu_MUL; break;
-         default:        aluOp = Xalu_INVALID; break;
+         case Iop_Mul16: case Iop_Mul32: 
+            aluOp = Xalu_MUL; break;
+         default:
+            aluOp = Xalu_INVALID; break;
       }
       /* For commutative ops we assume any literal
          values are on the second operand. */
@@ -356,6 +358,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
             nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
            vassert(nshift >= 0);
            if (nshift > 0)
+               /* Can't allow nshift==0 since that means %cl */
                addInstr(env, X86Instr_Sh32(
                                 shOp, 
                                 nshift,
@@ -383,6 +386,29 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
          return hi16;
       }
 
+      if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8
+          || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) {
+         HReg a16   = newVRegI(env);
+         HReg b16   = newVRegI(env);
+         HReg a16s  = iselIntExpr_R(env, e->Iex.Binop.arg1);
+         HReg b16s  = iselIntExpr_R(env, e->Iex.Binop.arg2);
+         Int  shift = (e->Iex.Binop.op == Iop_MullS8 
+                       || e->Iex.Binop.op == Iop_MullU8)
+                         ? 24 : 16;
+         X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8 
+                              || e->Iex.Binop.op == Iop_MullS16)
+                                ? Xsh_SAR : Xsh_SHR;
+
+         addInstr(env, mk_MOVsd_RR(a16s, a16));
+         addInstr(env, mk_MOVsd_RR(b16s, b16));
+         addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(a16)));
+         addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(b16)));
+         addInstr(env, X86Instr_Sh32(shr_op,  shift, X86RM_Reg(a16)));
+         addInstr(env, X86Instr_Sh32(shr_op,  shift, X86RM_Reg(b16)));
+         addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16));
+         return b16;
+      }
+
       break;
    }
 
@@ -441,16 +467,19 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
             iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg);
             return rLo; /* similar stupid comment to the above ... */
          }
+         case Iop_16HIto8:
          case Iop_32HIto16: {
-            HReg dst = newVRegI(env);
-            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            HReg dst  = newVRegI(env);
+            HReg src  = iselIntExpr_R(env, e->Iex.Unop.arg);
+            Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
             addInstr(env, mk_MOVsd_RR(src,dst) );
-            addInstr(env, X86Instr_Sh32(Xsh_SHR, 16, X86RM_Reg(dst)));
+            addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst)));
             return dst;
          }
+         case Iop_16to8:
          case Iop_32to8:
          case Iop_32to16:
-            /* These are both no-ops. */
+            /* These are no-ops. */
             return iselIntExpr_R(env, e->Iex.Unop.arg);
 
          default: 
index e9201a4cb34c6603547108c4ee9e2654f3f65502..00179e4ba21bc9ab8d2e5bfb6920d78f1a46cdc4 100644 (file)
@@ -102,6 +102,10 @@ void ppIROp ( IROp op )
       case Iop_DivModU64to32: vex_printf("DivModU64to32"); return;
       case Iop_DivModS64to32: vex_printf("DivModS64to32"); return;
 
+      case Iop_16HIto8:  vex_printf("16HIto8"); return;
+      case Iop_16to8:    vex_printf("16to8");   return;
+      case Iop_8HLto16:  vex_printf("8HLto16"); return;
+
       case Iop_32HIto16: vex_printf("32HIto16"); return;
       case Iop_32to16:   vex_printf("32to16");   return;
       case Iop_16HLto32: vex_printf("16HLto32"); return;
@@ -477,6 +481,10 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_CmpEQ64: case Iop_CmpNE64:
          COMPARISON(Ity_I64);
 
+      case Iop_MullU8: case Iop_MullS8:
+         BINARY(Ity_I16,Ity_I8,Ity_I8);
+      case Iop_MullU16: case Iop_MullS16:
+         BINARY(Ity_I32,Ity_I16,Ity_I16);
       case Iop_MullU32: case Iop_MullS32:
          BINARY(Ity_I64,Ity_I32,Ity_I32);
 
@@ -484,6 +492,11 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_DivModS64to32:
          BINARY(Ity_I64,Ity_I64,Ity_I32);
 
+      case Iop_16HIto8: case Iop_16to8:
+         UNARY(Ity_I8,Ity_I16);
+      case Iop_8HLto16:
+         BINARY(Ity_I16,Ity_I8,Ity_I8);
+
       case Iop_32HIto16: case Iop_32to16:
          UNARY(Ity_I16,Ity_I32);
       case Iop_16HLto32:
index 959a24f22876fc0c9b7a11026fc6d89091c6390f..c769d21340a511c334859691106c5ee9eef39dfa 100644 (file)
@@ -99,6 +99,10 @@ typedef
       Iop_8Sto16, Iop_8Sto32, Iop_16Sto32,
       /* Narrowing conversions */
       Iop_32to8,
+      /* 8 <-> 16 bit conversions */
+      Iop_16to8,      // :: I16 -> I8, low half
+      Iop_16HIto8,    // :: I16 -> I8, high half
+      Iop_8HLto16,    // :: (I8,I8) -> I16
       /* 16 <-> 32 bit conversions */
       Iop_32to16,     // :: I32 -> I16, low half
       Iop_32HIto16,   // :: I32 -> I16, high half