From: Petar Jovanovic Date: Tue, 22 Aug 2017 13:53:15 +0000 (+0200) Subject: mips: reimplement handling of div, divu and ddivu X-Git-Tag: VALGRIND_3_14_0~280 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f3cc6c828a84683225c1ba14b4fc4c621c6b7d6;p=thirdparty%2Fvalgrind.git mips: reimplement handling of div, divu and ddivu 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. --- diff --git a/VEX/priv/guest_mips_toIR.c b/VEX/priv/guest_mips_toIR.c index a73b5dc344..d5215f1043 100644 --- a/VEX/priv/guest_mips_toIR.c +++ b/VEX/priv/guest_mips_toIR.c @@ -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 */ diff --git a/VEX/priv/host_mips_isel.c b/VEX/priv/host_mips_isel.c index 0c51c07030..2c49a6eb70 100644 --- a/VEX/priv/host_mips_isel.c +++ b/VEX/priv/host_mips_isel.c @@ -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); diff --git a/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index a853c2e9fc..8822800f11 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -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: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index fcac0430a9..57fa9b6b20 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -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 diff --git a/memcheck/mc_translate.c b/memcheck/mc_translate.c index 8429301fb6..980c1d7db4 100644 --- a/memcheck/mc_translate.c +++ b/memcheck/mc_translate.c @@ -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)); diff --git a/memcheck/tests/vbit-test/irops.c b/memcheck/tests/vbit-test/irops.c index d0e8298e81..946e93249e 100644 --- a/memcheck/tests/vbit-test/irops.c +++ b/memcheck/tests/vbit-test/irops.c @@ -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