|
From: <sv...@va...> - 2005-07-23 13:20:23
|
Author: sewardj
Date: 2005-07-23 14:19:32 +0100 (Sat, 23 Jul 2005)
New Revision: 1292
Log:
An appallingly inefficient, but correct, implementation of rcr. On
x86, rcr is a dog. On amd64 it is a mangy dog with fleas on.
Modified:
trunk/priv/guest-amd64/gdefs.h
trunk/priv/guest-amd64/ghelpers.c
trunk/priv/guest-amd64/toIR.c
Modified: trunk/priv/guest-amd64/gdefs.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/priv/guest-amd64/gdefs.h 2005-07-23 12:07:37 UTC (rev 1291)
+++ trunk/priv/guest-amd64/gdefs.h 2005-07-23 13:19:32 UTC (rev 1292)
@@ -94,11 +94,9 @@
=20
//extern ULong amd64g_calculate_FXAM ( ULong tag, ULong dbl );
=20
-// Hmm. This is going to be a problem as it needs to return
-// 64bits and rflags.
-//extern ULong amd64g_calculate_RCR (=20
-// UInt arg, UInt rot_amt, UInt eflags_in, UInt sz=20
-// );
+extern ULong amd64g_calculate_RCR (=20
+ ULong arg, ULong rot_amt, ULong rflags_in, Long sz=20
+ );
=20
extern ULong amd64g_check_fldcw ( ULong fpucw );
=20
Modified: trunk/priv/guest-amd64/ghelpers.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/priv/guest-amd64/ghelpers.c 2005-07-23 12:07:37 UTC (rev 1291)
+++ trunk/priv/guest-amd64/ghelpers.c 2005-07-23 13:19:32 UTC (rev 1292)
@@ -1507,6 +1507,75 @@
}
=20
=20
+ULong amd64g_calculate_RCR ( ULong arg,=20
+ ULong rot_amt,=20
+ ULong rflags_in,=20
+ Long szIN )
+{
+ Bool wantRflags =3D toBool(szIN < 0);
+ ULong sz =3D wantRflags ? (-szIN) : szIN;
+ ULong tempCOUNT =3D rot_amt & (sz =3D=3D 8 ? 0x3F : 0x1F);
+ ULong cf=3D0, of=3D0, tempcf;
+
+ switch (sz) {
+ case 8:
+ cf =3D (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
+ of =3D ((arg >> 63) ^ cf) & 1;
+ while (tempCOUNT > 0) {
+ tempcf =3D arg & 1;
+ arg =3D (arg >> 1) | (cf << 63);
+ cf =3D tempcf;
+ tempCOUNT--;
+ }
+ break;
+ case 4:
+ while (tempCOUNT >=3D 33) tempCOUNT -=3D 33;
+ cf =3D (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
+ of =3D ((arg >> 31) ^ cf) & 1;
+ while (tempCOUNT > 0) {
+ tempcf =3D arg & 1;
+ arg =3D ((arg >> 1) & 0x7FFFFFFFULL) | (cf << 31);
+ cf =3D tempcf;
+ tempCOUNT--;
+ }
+ break;
+ case 2:
+ while (tempCOUNT >=3D 17) tempCOUNT -=3D 17;
+ cf =3D (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
+ of =3D ((arg >> 15) ^ cf) & 1;
+ while (tempCOUNT > 0) {
+ tempcf =3D arg & 1;
+ arg =3D ((arg >> 1) & 0x7FFFULL) | (cf << 15);
+ cf =3D tempcf;
+ tempCOUNT--;
+ }
+ break;
+ case 1:
+ while (tempCOUNT >=3D 9) tempCOUNT -=3D 9;
+ cf =3D (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
+ of =3D ((arg >> 7) ^ cf) & 1;
+ while (tempCOUNT > 0) {
+ tempcf =3D arg & 1;
+ arg =3D ((arg >> 1) & 0x7FULL) | (cf << 7);
+ cf =3D tempcf;
+ tempCOUNT--;
+ }
+ break;
+ default:
+ vpanic("calculate_RCR(amd64g): invalid size");
+ }
+
+ cf &=3D 1;
+ of &=3D 1;
+ rflags_in &=3D ~(AMD64G_CC_MASK_C | AMD64G_CC_MASK_O);
+ rflags_in |=3D (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. ---*/
/*---------------------------------------------------------------*/
Modified: trunk/priv/guest-amd64/toIR.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/priv/guest-amd64/toIR.c 2005-07-23 12:07:37 UTC (rev 1291)
+++ trunk/priv/guest-amd64/toIR.c 2005-07-23 13:19:32 UTC (rev 1292)
@@ -2922,30 +2922,59 @@
}
=20
if (isRotateRC) {
- vpanic("dis_Grp2(Reg,amd64): unhandled case(RotateRC)");
- vassert(0);
-//.. /* call a helper; this insn is so ridiculous it does not dese=
rve
-//.. better */
-//.. IRTemp r64 =3D newTemp(Ity_I64);
-//.. IRExpr** args=20
-//.. =3D mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to r=
otate */
-//.. widenUto32(shift_expr), /* rotate amoun=
t */
-//.. widenUto32(mk_x86g_calculate_eflags_all()=
),
-//.. mkU32(sz) );
-//.. assign( r64, mkIRExprCCall(
-//.. Ity_I64,=20
-//.. 0/*regparm*/,=20
-//.. "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 =3D newTemp(Ity_I64);
+ IRTemp new_rflags =3D newTemp(Ity_I64);
+ IRTemp old_rflags =3D newTemp(Ity_I64);
+
+ assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) )=
;
+
+ argsVALUE
+ =3D mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate=
*/
+ widenUto64(shift_expr), /* rotate amount */
+ mkexpr(old_rflags),
+ mkU64(sz) );
+ assign( new_value,=20
+ mkIRExprCCall(
+ Ity_I64,=20
+ 0/*regparm*/,=20
+ "amd64g_calculate_RCR", &amd64g_calculate_RCR,
+ argsVALUE
+ )
+ );
+ =20
+ argsRFLAGS
+ =3D mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate=
*/
+ widenUto64(shift_expr), /* rotate amount */
+ mkexpr(old_rflags),
+ mkU64(-sz) );
+ assign( new_rflags,=20
+ mkIRExprCCall(
+ Ity_I64,=20
+ 0/*regparm*/,=20
+ "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) ));
}
=20
+ else
if (isShift) {
=20
IRTemp pre64 =3D newTemp(Ity_I64);
|