From: Julian Seward Date: Sat, 23 Jul 2005 13:19:32 +0000 (+0000) Subject: An appallingly inefficient, but correct, implementation of rcr. On X-Git-Tag: svn/VALGRIND_3_0_1^2~42 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6e0e11fd1f0e704ce9ccf196d7795152837e46cb;p=thirdparty%2Fvalgrind.git An appallingly inefficient, but correct, implementation of rcr. On x86, rcr is a dog. On amd64 it is a mangy dog with fleas on. git-svn-id: svn://svn.valgrind.org/vex/trunk@1292 --- diff --git a/VEX/priv/guest-amd64/gdefs.h b/VEX/priv/guest-amd64/gdefs.h index 9e613b3c1d..d6a3e436d1 100644 --- a/VEX/priv/guest-amd64/gdefs.h +++ b/VEX/priv/guest-amd64/gdefs.h @@ -94,11 +94,9 @@ extern ULong amd64g_calculate_condition ( //extern ULong amd64g_calculate_FXAM ( ULong tag, ULong dbl ); -// Hmm. This is going to be a problem as it needs to return -// 64bits and rflags. -//extern ULong amd64g_calculate_RCR ( -// UInt arg, UInt rot_amt, UInt eflags_in, UInt sz -// ); +extern ULong amd64g_calculate_RCR ( + ULong arg, ULong rot_amt, ULong rflags_in, Long sz + ); extern ULong amd64g_check_fldcw ( ULong fpucw ); diff --git a/VEX/priv/guest-amd64/ghelpers.c b/VEX/priv/guest-amd64/ghelpers.c index 5ffc209287..ec6ccf1af4 100644 --- a/VEX/priv/guest-amd64/ghelpers.c +++ b/VEX/priv/guest-amd64/ghelpers.c @@ -1507,6 +1507,75 @@ void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* st ) } +ULong amd64g_calculate_RCR ( ULong arg, + ULong rot_amt, + ULong rflags_in, + Long szIN ) +{ + Bool wantRflags = toBool(szIN < 0); + ULong sz = wantRflags ? (-szIN) : szIN; + ULong tempCOUNT = rot_amt & (sz == 8 ? 0x3F : 0x1F); + ULong cf=0, of=0, tempcf; + + switch (sz) { + case 8: + cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1; + of = ((arg >> 63) ^ cf) & 1; + while (tempCOUNT > 0) { + tempcf = arg & 1; + arg = (arg >> 1) | (cf << 63); + cf = tempcf; + tempCOUNT--; + } + break; + case 4: + while (tempCOUNT >= 33) tempCOUNT -= 33; + cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1; + of = ((arg >> 31) ^ cf) & 1; + while (tempCOUNT > 0) { + tempcf = arg & 1; + arg = ((arg >> 1) & 0x7FFFFFFFULL) | (cf << 31); + cf = tempcf; + tempCOUNT--; + } + break; + case 2: + while (tempCOUNT >= 17) tempCOUNT -= 17; + cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1; + of = ((arg >> 15) ^ cf) & 1; + while (tempCOUNT > 0) { + tempcf = arg & 1; + arg = ((arg >> 1) & 0x7FFFULL) | (cf << 15); + cf = tempcf; + tempCOUNT--; + } + break; + case 1: + while (tempCOUNT >= 9) tempCOUNT -= 9; + cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1; + of = ((arg >> 7) ^ cf) & 1; + while (tempCOUNT > 0) { + tempcf = arg & 1; + arg = ((arg >> 1) & 0x7FULL) | (cf << 7); + cf = tempcf; + tempCOUNT--; + } + break; + default: + vpanic("calculate_RCR(amd64g): invalid size"); + } + + cf &= 1; + of &= 1; + rflags_in &= ~(AMD64G_CC_MASK_C | AMD64G_CC_MASK_O); + rflags_in |= (cf << AMD64G_CC_SHIFT_C) | (of << AMD64G_CC_SHIFT_O); + + /* caller can ask to have back either the resulting flags or + resulting value, but not both */ + return wantRflags ? rflags_in : arg; +} + + /*---------------------------------------------------------------*/ /*--- Helpers for MMX/SSE/SSE2. ---*/ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/guest-amd64/toIR.c b/VEX/priv/guest-amd64/toIR.c index 9b01e970df..cc301d683f 100644 --- a/VEX/priv/guest-amd64/toIR.c +++ b/VEX/priv/guest-amd64/toIR.c @@ -2922,30 +2922,59 @@ ULong dis_Grp2 ( Prefix pfx, } if (isRotateRC) { - vpanic("dis_Grp2(Reg,amd64): unhandled case(RotateRC)"); - vassert(0); -//.. /* call a helper; this insn is so ridiculous it does not deserve -//.. better */ -//.. IRTemp r64 = newTemp(Ity_I64); -//.. IRExpr** args -//.. = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */ -//.. widenUto32(shift_expr), /* rotate amount */ -//.. widenUto32(mk_x86g_calculate_eflags_all()), -//.. mkU32(sz) ); -//.. assign( r64, mkIRExprCCall( -//.. Ity_I64, -//.. 0/*regparm*/, -//.. "x86g_calculate_RCR", &x86g_calculate_RCR, -//.. args -//.. ) -//.. ); -//.. /* new eflags in hi half r64; new value in lo half r64 */ -//.. assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) ); -//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) )); -//.. stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) )); -//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) )); + /* Call a helper; this insn is so ridiculous it does not deserve + better. One problem is, the helper has to calculate both the + new value and the new flags. This is more than 64 bits, and + there is no way to return more than 64 bits from the helper. + Hence the crude and obvious solution is to call it twice, + using the sign of the sz field to indicate whether it is the + value or rflags result we want. + */ + IRExpr** argsVALUE; + IRExpr** argsRFLAGS; + + IRTemp new_value = newTemp(Ity_I64); + IRTemp new_rflags = newTemp(Ity_I64); + IRTemp old_rflags = newTemp(Ity_I64); + + assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) ); + + argsVALUE + = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */ + widenUto64(shift_expr), /* rotate amount */ + mkexpr(old_rflags), + mkU64(sz) ); + assign( new_value, + mkIRExprCCall( + Ity_I64, + 0/*regparm*/, + "amd64g_calculate_RCR", &amd64g_calculate_RCR, + argsVALUE + ) + ); + + argsRFLAGS + = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */ + widenUto64(shift_expr), /* rotate amount */ + mkexpr(old_rflags), + mkU64(-sz) ); + assign( new_rflags, + mkIRExprCCall( + Ity_I64, + 0/*regparm*/, + "amd64g_calculate_RCR", &amd64g_calculate_RCR, + argsRFLAGS + ) + ); + + assign( dst1, narrowTo(ty, mkexpr(new_value)) ); + stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) )); + stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) )); + stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) )); + stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) )); } + else if (isShift) { IRTemp pre64 = newTemp(Ity_I64);