]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
mips: reimplement handling of div, divu and ddivu
authorPetar Jovanovic <mips32r2@gmail.com>
Tue, 22 Aug 2017 13:53:15 +0000 (15:53 +0200)
committerPetar Jovanovic <mips32r2@gmail.com>
Tue, 22 Aug 2017 13:53:15 +0000 (15:53 +0200)
Previous implementation misused some opcodes, and a side effect was
dead code emission.
To reimplement handling of these instructions, three new IoPs have been
introduced:

      Iop_DivModU64to64, // :: I64,I64 -> I128
                         // of which lo half is div and hi half is mod
      Iop_DivModS32to32, // :: I32,I32 -> I64
                         // of which lo half is div and hi half is mod
      Iop_DivModU32to32, // :: I32,I32 -> I64
                         // of which lo half is div and hi half is mod

Patch by Aleksandra Karadzic and Tamara Vlahovic.

VEX/priv/guest_mips_toIR.c
VEX/priv/host_mips_isel.c
VEX/priv/ir_defs.c
VEX/pub/libvex_ir.h
memcheck/mc_translate.c
memcheck/tests/vbit-test/irops.c

index a73b5dc3440fc912af8e842fc4886ffa38d5818a..d5215f1043740ec657bb1c54a448cdcc8f1ebae0 100644 (file)
@@ -15661,20 +15661,19 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
          if (mode64) {
             t2 = newTemp(Ity_I64);
 
-            assign(t2, binop(Iop_DivModS64to32,
-                             getIReg(rs), mkNarrowTo32(ty, getIReg(rt))));
+            assign(t2, binop(Iop_DivModS32to32,
+                             mkNarrowTo32(ty, getIReg(rs)),
+                             mkNarrowTo32(ty, getIReg(rt))));
 
             putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
             putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
          } else {
             t1 = newTemp(Ity_I64);
-            t2 = newTemp(Ity_I64);
 
-            assign(t1, unop(Iop_32Sto64, getIReg(rs)));
-            assign(t2, binop(Iop_DivModS64to32, mkexpr(t1), getIReg(rt)));
+            assign(t1, binop(Iop_DivModS32to32, getIReg(rs), getIReg(rt)));
 
-            putHI(unop(Iop_64HIto32, mkexpr(t2)));
-            putLO(unop(Iop_64to32, mkexpr(t2)));
+            putHI(unop(Iop_64HIto32, mkexpr(t1)));
+            putLO(unop(Iop_64to32, mkexpr(t1)));
          }
          break;
 
@@ -15683,18 +15682,18 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
          if (mode64) {
             t2 = newTemp(Ity_I64);
 
-            assign(t2, binop(Iop_DivModU64to32,
-                             getIReg(rs), mkNarrowTo32(ty, getIReg(rt))));
+            assign(t2, binop(Iop_DivModU32to32,
+                             mkNarrowTo32(ty, getIReg(rs)),
+                             mkNarrowTo32(ty, getIReg(rt))));
 
             putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
             putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
          } else {
             t1 = newTemp(Ity_I64);
-            t2 = newTemp(Ity_I64);
-            assign(t1, unop(Iop_32Uto64, getIReg(rs)));
-            assign(t2, binop(Iop_DivModU64to32, mkexpr(t1), getIReg(rt)));
-            putHI(unop(Iop_64HIto32, mkexpr(t2)));
-            putLO(unop(Iop_64to32, mkexpr(t2)));
+
+            assign(t1, binop(Iop_DivModU32to32, getIReg(rs), getIReg(rt)));
+            putHI(unop(Iop_64HIto32, mkexpr(t1)));
+            putLO(unop(Iop_64to32, mkexpr(t1)));
          }
          break;
 
@@ -15731,14 +15730,11 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
       case 0x1F:  /* Doubleword Divide Unsigned DDIVU; MIPS64 check this */
          DIP("ddivu r%u, r%u", rs, rt);
          t1 = newTemp(Ity_I128);
-         t2 = newTemp(Ity_I128);
 
-         assign(t1, binop(Iop_64HLto128, mkU64(0), getIReg(rs)));
+         assign(t1, binop(Iop_DivModU64to64, getIReg(rs), getIReg(rt)));
 
-         assign(t2, binop(Iop_DivModU128to64, mkexpr(t1), getIReg(rt)));
-
-         putHI(unop(Iop_128HIto64, mkexpr(t2)));
-         putLO(unop(Iop_128to64, mkexpr(t2)));
+         putHI(unop(Iop_128HIto64, mkexpr(t1)));
+         putLO(unop(Iop_128to64, mkexpr(t1)));
          break;
 
       case 0x10: {  /* MFHI */
index 0c51c07030060442df2b84ba2e071591a51aafe6..2c49a6eb701e0e7ce61b671dfa34a89784e1b815 100644 (file)
@@ -1218,6 +1218,36 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
             return r_dst;
          }
 
+         if (e->Iex.Binop.op == Iop_DivModU32to32 ||
+             e->Iex.Binop.op == Iop_DivModS32to32) {
+            HReg tLo = newVRegI(env);
+            HReg tHi = newVRegI(env);
+            HReg mask = newVRegI(env);
+            HReg tLo_1 = newVRegI(env);
+            HReg tHi_1 = newVRegI(env);
+            HReg r_dst = newVRegI(env);
+            Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS32to32);
+
+            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+
+            addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
+            addInstr(env, MIPSInstr_Mfhi(tHi));
+            addInstr(env, MIPSInstr_Mflo(tLo));
+
+            addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
+                                         MIPSRH_Imm(False, 32)));
+
+            addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
+            addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
+                          MIPSRH_Reg(mask)));
+
+            addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
+                          MIPSRH_Reg(tLo_1)));
+
+            return r_dst;
+         }
+
          if (e->Iex.Binop.op == Iop_8HLto16
              || e->Iex.Binop.op == Iop_16HLto32) {
             HReg tHi   = iselWordExpr_R(env, e->Iex.Binop.arg1);
@@ -2216,6 +2246,7 @@ static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
             *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
             return;
 
+         case Iop_DivModU64to64:
          case Iop_DivModS64to64: {
             HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
             HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
@@ -2462,6 +2493,22 @@ static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
             return;
          }
 
+         case Iop_DivModU32to32:
+         case Iop_DivModS32to32: {
+            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+            HReg tLo = newVRegI(env);
+            HReg tHi = newVRegI(env);
+            Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS32to32);
+
+            addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
+            addInstr(env, MIPSInstr_Mfhi(tHi));
+            addInstr(env, MIPSInstr_Mflo(tLo));
+            *rHi = tHi;
+            *rLo = tLo;
+            return;
+         }
+
          /* 32HLto64(e1,e2) */
          case Iop_32HLto64:
             *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
index a853c2e9fc6a92843b01a243cf272bead0299fe4..8822800f119652cf9c84684c2e9f21e86c825a59 100644 (file)
@@ -236,10 +236,14 @@ void ppIROp ( IROp op )
       case Iop_DivModU64to32: vex_printf("DivModU64to32"); return;
       case Iop_DivModS64to32: vex_printf("DivModS64to32"); return;
 
+      case Iop_DivModU32to32: vex_printf("DivModU32to32"); return;
+      case Iop_DivModS32to32: vex_printf("DivModS32to32"); return;
+
       case Iop_DivModU128to64: vex_printf("DivModU128to64"); return;
       case Iop_DivModS128to64: vex_printf("DivModS128to64"); return;
 
       case Iop_DivModS64to64: vex_printf("DivModS64to64"); return;
+      case Iop_DivModU64to64: vex_printf("DivModU64to64"); return;
 
       case Iop_16HIto8:  vex_printf("16HIto8"); return;
       case Iop_16to8:    vex_printf("16to8");   return;
@@ -2758,12 +2762,15 @@ void typeOfPrimop ( IROp op,
          BINARY(Ity_I64,Ity_I64, Ity_I64);
 
       case Iop_DivModU64to32: case Iop_DivModS64to32:
-         BINARY(Ity_I64,Ity_I32, Ity_I64);
+         BINARY(Ity_I64, Ity_I32, Ity_I64);
+
+      case Iop_DivModU32to32: case Iop_DivModS32to32:
+         BINARY(Ity_I32, Ity_I32, Ity_I64);
 
       case Iop_DivModU128to64: case Iop_DivModS128to64:
          BINARY(Ity_I128,Ity_I64, Ity_I128);
 
-      case Iop_DivModS64to64:
+      case Iop_DivModU64to64: case Iop_DivModS64to64:
          BINARY(Ity_I64,Ity_I64, Ity_I128);
 
       case Iop_16HIto8: case Iop_16to8:
index fcac0430a92f4de45344b300dfceab1bb0edd63b..57fa9b6b205d8f5a3fc19ce0749912ff622a72d4 100644 (file)
@@ -503,6 +503,12 @@ typedef
 
       Iop_DivModS64to64, // :: I64,I64 -> I128
                          // of which lo half is div and hi half is mod
+      Iop_DivModU64to64, // :: I64,I64 -> I128
+                         // of which lo half is div and hi half is mod
+      Iop_DivModS32to32, // :: I32,I32 -> I64
+                         // of which lo half is div and hi half is mod
+      Iop_DivModU32to32, // :: I32,I32 -> I64
+                         // of which lo half is div and hi half is mod
 
       /* Integer conversions.  Some of these are redundant (eg
          Iop_64to8 is the same as Iop_64to32 and then Iop_32to8), but
index 8429301fb6b578d4e030d1232bb7e9588d06cf86..980c1d7db4a1eee370074cf3a43eb472a49cc15b 100644 (file)
@@ -3977,7 +3977,13 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce,
       case Iop_32HLto64:
          return assignNew('V', mce, Ity_I64, binop(op, vatom1, vatom2));
 
-      case Iop_DivModS64to64:
+      case Iop_DivModU64to64:
+      case Iop_DivModS64to64: {
+         IRAtom* vTmp64 = mkLazy2(mce, Ity_I64, vatom1, vatom2);
+         return assignNew('V', mce, Ity_I128,
+                          binop(Iop_64HLto128, vTmp64, vTmp64));
+      }
+
       case Iop_MullS64:
       case Iop_MullU64: {
          IRAtom* vLo64 = mkLeft64(mce, mkUifU64(mce, vatom1,vatom2));
@@ -3986,6 +3992,13 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce,
                           binop(Iop_64HLto128, vHi64, vLo64));
       }
 
+      case Iop_DivModU32to32:
+      case Iop_DivModS32to32: {
+         IRAtom* vTmp32 = mkLazy2(mce, Ity_I32, vatom1, vatom2);
+         return assignNew('V', mce, Ity_I64,
+                          binop(Iop_32HLto64, vTmp32, vTmp32));
+      }
+
       case Iop_MullS32:
       case Iop_MullU32: {
          IRAtom* vLo32 = mkLeft32(mce, mkUifU32(mce, vatom1,vatom2));
index d0e8298e81f774027bad45a26e87503817ca81ff..946e93249ebbc3b438ec95df70c0ac48ec1b2aa4 100644 (file)
@@ -146,9 +146,12 @@ static irop_t irops[] = {
   // So they cannot be tested in isolation on that platform.
   { DEFOP(Iop_DivModU64to32,  UNDEF_ALL), .s390x = 0, .amd64 = 1, .x86 = 1, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 1, .mips64 = 1 },
   { DEFOP(Iop_DivModS64to32,  UNDEF_ALL), .s390x = 0, .amd64 = 1, .x86 = 1, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 1, .mips64 = 1 },
+  { DEFOP(Iop_DivModU32to32,  UNDEF_ALL), .s390x = 0, .amd64 = 0, .x86 = 0, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 1, .mips64 = 1 },
+  { DEFOP(Iop_DivModS32to32,  UNDEF_ALL), .s390x = 0, .amd64 = 0, .x86 = 0, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 1, .mips64 = 1 },
   { DEFOP(Iop_DivModU128to64, UNDEF_ALL), .s390x = 0, .amd64 = 1, .x86 = 0, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 0, .mips64 = 1 }, // mips asserts
   { DEFOP(Iop_DivModS128to64, UNDEF_ALL), .s390x = 0, .amd64 = 1, .x86 = 0, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 0, .mips64 = 1 }, // mips asserts
-  { DEFOP(Iop_DivModS64to64,  UNDEF_ALL), .s390x = 0, .amd64 = 0, .x86 = 0, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 0, .mips64 = 0 }, // mips asserts
+  { DEFOP(Iop_DivModS64to64,  UNDEF_ALL), .s390x = 0, .amd64 = 0, .x86 = 0, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 0, .mips64 = 1 }, // mips asserts
+  { DEFOP(Iop_DivModU64to64,  UNDEF_ALL), .s390x = 0, .amd64 = 0, .x86 = 0, .arm = 0, .ppc64 = 0, .ppc32 = 0, .mips32 = 0, .mips64 = 1 }, // mips asserts
   { DEFOP(Iop_8Uto16,    UNDEF_ZEXT),   .s390x = 1, .amd64 = 1, .x86 = 1, .arm = 0, .ppc64 = 1, .ppc32 = 1, .mips32 = 1, .mips64 = 1 },
   { DEFOP(Iop_8Uto32,    UNDEF_ZEXT),   .s390x = 1, .amd64 = 1, .x86 = 1, .arm = 1, .ppc64 = 1, .ppc32 = 1, .mips32 = 1, .mips64 = 1 },
   { DEFOP(Iop_8Uto64,    UNDEF_ZEXT),   .s390x = 1, .amd64 = 1, .x86 = 0, .arm = 0, .ppc64 = 1, .ppc32 = 0, .mips32 = 0, .mips64 = 1 }, // ppc32 assert