]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
An appallingly inefficient, but correct, implementation of rcr. On
authorJulian Seward <jseward@acm.org>
Sat, 23 Jul 2005 13:19:32 +0000 (13:19 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 23 Jul 2005 13:19:32 +0000 (13:19 +0000)
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

VEX/priv/guest-amd64/gdefs.h
VEX/priv/guest-amd64/ghelpers.c
VEX/priv/guest-amd64/toIR.c

index 9e613b3c1d439ae4d11f1b94bd1691dff6ca9d15..d6a3e436d13b7f4a9c4cfb2ac6451634db273b94 100644 (file)
@@ -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 );
 
index 5ffc20928768782001b5412e82b0283d6ca9c598..ec6ccf1af407065f1251fa96ac82a0e9796ae2c1 100644 (file)
@@ -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.                               ---*/
 /*---------------------------------------------------------------*/
index 9b01e970df8445c229cfdcee496c63c5b2748406..cc301d683fbd04cf93cb0f0495581a42b1a0c2f0 100644 (file)
@@ -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);