]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Allow iropt to pass helper function calls back to the front end
authorJulian Seward <jseward@acm.org>
Mon, 23 Aug 2004 16:16:08 +0000 (16:16 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 23 Aug 2004 16:16:08 +0000 (16:16 +0000)
in the hope of getting specialised versions thereof.

Use this mechanism to greatly improve handling of condition
codes.  Various ensuing small changes.

git-svn-id: svn://svn.valgrind.org/vex/trunk@194

VEX/priv/guest-x86/gdefs.h
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/priv/ir/iropt.c
VEX/priv/ir/iropt.h
VEX/priv/main/vex_main.c
VEX/pub/libvex_ir.h
VEX/test_main.c

index 4e29f4e63834ff65cc78f5280d5c47256bc708f3..0c9ecb91becb58d225c85550cbdcaa6fd3ae0ee1 100644 (file)
@@ -31,6 +31,11 @@ IRBB* bbToIR_X86Instr ( UChar* x86code,
 extern
 Addr64 x86guest_findhelper ( Char* function_name );
 
+/* Used by the optimiser to specialise calls to helpers. */
+extern
+IRExpr* x86guest_spechelper ( Char* function_name,
+                              IRExpr** args );
+
 
 /*---------------------------------------------------------*/
 /*--- Condition code stuff                              ---*/
@@ -103,6 +108,36 @@ enum {
     CC_OP_NUMBER
 };
 
+typedef
+   enum {
+      CondO      = 0,  /* overflow           */
+      CondNO     = 1,  /* no overflow        */
+
+      CondB      = 2,  /* below              */
+      CondNB     = 3,  /* not below          */
+
+      CondZ      = 4,  /* zero               */
+      CondNZ     = 5,  /* not zero           */
+
+      CondBE     = 6,  /* below or equal     */
+      CondNBE    = 7,  /* not below or equal */
+
+      CondS      = 8,  /* negative           */
+      CondNS     = 9,  /* not negative       */
+
+      CondP      = 10, /* parity even        */
+      CondNP     = 11, /* not parity even    */
+
+      CondL      = 12, /* jump less          */
+      CondNL     = 13, /* not less           */
+
+      CondLE     = 14, /* less or equal      */
+      CondNLE    = 15, /* not less or equal  */
+
+      CondAlways = 16  /* HACK */
+   }
+   Condcode;
+
 
 /*---------------------------------------------------------*/
 /*--- Simulated state offsets                           ---*/
index d9ef4d91a64c9560567654bc9657695061fd9760..3199ff620c2bcc31ff3156d910b332e9dc9ab098 100644 (file)
    permission.  
 */
 
+/* Set to 1 to get detailed profiling info about use of the flag
+   machinery. */
+#define PROFILE_EFLAGS 0
+
+
 typedef UChar uint8_t;
 typedef UInt  uint32_t;
 
@@ -293,9 +298,76 @@ static inline int lshift(int x, int n)
 }
 
 
+
+#define CC_SHIFT_C 0
+#define CC_SHIFT_P 2
+#define CC_SHIFT_A 4
+#define CC_SHIFT_Z 6
+#define CC_SHIFT_S 7
+#define CC_SHIFT_O 13
+
+#if PROFILE_EFLAGS
+
+static UInt tabc[CC_OP_NUMBER];
+static UInt tab[CC_OP_NUMBER][16];
+static Bool initted      = False;
+static UInt n_calc_cond = 0;
+static UInt n_calc_all  = 0;
+static UInt n_calc_c    = 0;
+
+static void showCounts ( void )
+{
+   Int op, co;
+   Char ch;
+   vex_printf("\nALL=%d   COND=%d   C=%d\n",
+              n_calc_all-n_calc_cond-n_calc_c, n_calc_cond, n_calc_c);
+   vex_printf("      CARRY    O   NO    B   NB    Z   NZ   BE  NBE"
+              "    S   NS    P   NP    L   NL   LE  NLE\n");
+   vex_printf("     ----------------------------------------------"
+              "----------------------------------------\n");
+   for (op = 0; op < CC_OP_NUMBER; op++) {
+
+      ch = ' ';
+      if (op > 0 && (op-1) % 3 == 2) 
+         ch = 'L';
+
+      vex_printf("%2d%c: ", op, ch);
+      vex_printf("%6d ", tabc[op]);
+      for (co = 0; co < 16; co++) {
+         Int n = tab[op][co];
+         if (n >= 1000) {
+            vex_printf(" %3dK", n / 1000);
+         } else 
+         if (n >= 0) {
+           vex_printf(" %3d ", n );
+         } else {
+            vex_printf("     ");
+         }
+      }
+      vex_printf("\n");
+   }
+   vex_printf("\n");
+}
+
+static void initCounts ( void )
+{
+   Int op, co;
+   initted = True;
+   for (op = 0; op < CC_OP_NUMBER; op++) {
+      tabc[op] = 0;
+      for (co = 0; co < 16; co++)
+         tab[op][co] = 0;
+   }
+}
+
+#endif /* PROFILE_EFLAGS */
+
 /* CALLED FROM GENERATED CODE */
 /*static*/ UInt calculate_eflags_all ( UInt cc_op, UInt cc_src, UInt cc_dst )
 {
+#  if PROFILE_EFLAGS
+   n_calc_all++;
+#  endif
    switch (cc_op) {
       case CC_OP_COPY:
          return cc_src & (CC_MASK_O | CC_MASK_S | CC_MASK_Z 
@@ -364,10 +436,95 @@ static inline int lshift(int x, int n)
 /* CALLED FROM GENERATED CODE */
 static UInt calculate_eflags_c ( UInt cc_op, UInt cc_src, UInt cc_dst )
 {
+#  if PROFILE_EFLAGS
+   if (!initted)
+      initCounts();
+   tabc[cc_op]++;
+
+   n_calc_c++;
+#  endif
+
    return calculate_eflags_all(cc_op,cc_src,cc_dst) & CC_MASK_C;
 }
 
 
+/* CALLED FROM GENERATED CODE */
+/* returns 1 or 0 */
+/*static*/ UInt calculate_condition ( UInt/*Condcode*/ cond, 
+                                      UInt cc_op, UInt cc_src, UInt cc_dst )
+{
+   UInt eflags = calculate_eflags_all(cc_op, cc_src, cc_dst);
+   UInt of,sf,zf,cf,pf;
+   UInt inv = cond & 1;
+
+#  if PROFILE_EFLAGS
+   if (!initted)
+     initCounts();
+
+   tab[cc_op][cond]++;
+   n_calc_cond++;
+
+   if (0 == ((n_calc_all+n_calc_c) & 0xFF)) showCounts();
+#  endif
+
+   switch (cond) {
+      case CondNO:
+      case CondO: /* OF == 1 */
+         of = eflags >> CC_SHIFT_O;
+         return 1 & (inv ^ of);
+
+      case CondNZ:
+      case CondZ: /* ZF == 1 */
+         zf = eflags >> CC_SHIFT_Z;
+         return 1 & (inv ^ zf);
+
+      case CondNB:
+      case CondB: /* CF == 1 */
+         cf = eflags >> CC_SHIFT_C;
+         return 1 & (inv ^ cf);
+         break;
+
+      case CondNBE:
+      case CondBE: /* (CF or ZF) == 1 */
+         cf = eflags >> CC_SHIFT_C;
+         zf = eflags >> CC_SHIFT_Z;
+         return 1 & (inv ^ (cf | zf));
+         break;
+
+      case CondNS:
+      case CondS: /* SF == 1 */
+         sf = eflags >> CC_SHIFT_S;
+         return 1 & (inv ^ sf);
+
+      case CondNP:
+      case CondP: /* PF == 1 */
+         pf = eflags >> CC_SHIFT_P;
+         return 1 & (inv ^ pf);
+
+      case CondNL:
+      case CondL: /* (SF xor OF) == 1 */
+         sf = eflags >> CC_SHIFT_S;
+         of = eflags >> CC_SHIFT_O;
+         return 1 & (inv ^ (sf ^ of));
+         break;
+
+      case CondNLE:
+      case CondLE: /* ((SF xor OF) or ZF)  == 1 */
+         sf = eflags >> CC_SHIFT_S;
+         of = eflags >> CC_SHIFT_O;
+         zf = eflags >> CC_SHIFT_Z;
+         return 1 & (inv ^ ((sf ^ of) | zf));
+         break;
+
+      default:
+         /* shouldn't really make these calls from generated code */
+         vex_printf("calculate_condition( %d, %d, 0x%x, 0x%x )\n",
+                    cond, cc_op, cc_src, cc_dst );
+         vpanic("calculate_condition");
+   }
+}
+
+
 /* The only exported function. */
 
 Addr64 x86guest_findhelper ( Char* function_name )
@@ -376,10 +533,159 @@ Addr64 x86guest_findhelper ( Char* function_name )
       return (Addr64)(& calculate_eflags_all);
    if (vex_streq(function_name, "calculate_eflags_c"))
       return (Addr64)(& calculate_eflags_c);
+   if (vex_streq(function_name, "calculate_condition"))
+      return (Addr64)(& calculate_condition);
    vex_printf("\nx86 guest: can't find helper: %s\n", function_name);
    vpanic("x86guest_findhelper");
 }
 
+/* Used by the optimiser to try specialisations.  Returns an
+   equivalent expression, or NULL if none. */
+
+static Bool isU32 ( IRExpr* e, UInt n )
+{
+   return e->tag == Iex_Const
+          && e->Iex.Const.con->tag == Ico_U32
+          && e->Iex.Const.con->Ico.U32 == n;
+}
+
+IRExpr* x86guest_spechelper ( Char* function_name,
+                              IRExpr** args )
+{
+#  define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
+#  define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
+#  define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
+
+   Int i, arity = 0;
+   for (i = 0; args[i]; i++)
+      arity++;
+#  if 0
+   vex_printf("spec request:\n");
+   vex_printf("   %s  ", function_name);
+   for (i = 0; i < arity; i++) {
+      vex_printf("  ");
+      ppIRExpr(args[i]);
+   }
+   vex_printf("\n");
+#  endif
+
+   if (vex_streq(function_name, "calculate_eflags_c")) {
+      /* specialise calls to above "calculate_eflags_c" function */
+      IRExpr *cc_op, *cc_src, *cc_dst;
+      vassert(arity == 3);
+      cc_op = args[0];
+      cc_src = args[1];
+      cc_dst = args[2];
+
+      if (isU32(cc_op, CC_OP_LOGICL)) {
+         /* cflag after logic is zero */
+         return mkU32(0);
+      }
+      if (isU32(cc_op, CC_OP_DECL) || isU32(cc_op, CC_OP_INCL)) {
+         /* If the thunk is dec or inc, the cflag is supplied as CC_SRC. */
+         return cc_src;
+      }
+      if (isU32(cc_op, CC_OP_SUBL)) {
+         /* C after sub denotes unsigned less than */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLT32U, binop(Iop_Add32,cc_src,cc_dst), 
+                                         cc_src));
+      }
+#     if 0
+      if (cc_op->tag == Iex_Const) {
+         vex_printf("CFLAG "); ppIRExpr(cc_op); vex_printf("\n");
+      }
+#     endif
+
+      return NULL;
+   }
+
+   if (vex_streq(function_name, "calculate_condition")) {
+      /* specialise calls to above "calculate condition" function */
+      IRExpr *cond, *cc_op, *cc_src, *cc_dst;
+      vassert(arity == 4);
+      cond = args[0];
+      cc_op = args[1];
+      cc_src = args[2];
+      cc_dst = args[3];
+
+      if (isU32(cc_op, CC_OP_LOGICB) && isU32(cond, CondZ)) {
+         /* byte and/or/xor, then Z --> test dst==0 */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpEQ32, binop(Iop_And32,cc_dst,mkU32(255)), 
+                                        mkU32(0)));
+      }
+
+      if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondZ)) {
+         /* byte sub/cmp, then Z --> test dst==0 */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpEQ32, binop(Iop_And32,cc_dst,mkU32(255)), 
+                                        mkU32(0)));
+      }
+
+      if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondNZ)) {
+         /* byte sub/cmp, then Z --> test dst==0 */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpNE32, binop(Iop_And32,cc_dst,mkU32(255)), 
+                                        mkU32(0)));
+      }
+
+      if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondZ)) {
+         /* long and/or/xor, then Z --> test dst==0 */
+         return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dst, mkU32(0)));
+      }
+
+      if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondLE)) {
+         /* long and/or/xor, then LE
+            This is pretty subtle.  LOGIC sets SF and ZF according to the
+            result and makes OF be zero.  LE computes (SZ ^ OF) | ZF, but
+            OF is zero, so this reduces to SZ | ZF -- which will be 1 iff
+            the result is <=signed 0.  Hence ...
+         */
+         return unop(Iop_1Uto32,binop(Iop_CmpLE32S, cc_dst, mkU32(0)));
+      }
+
+      if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondZ)) {
+         /* long sub/cmp, then Z --> test dst==0 */
+         return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dst, mkU32(0)));
+      }
+
+      if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondL)) {
+         /* long sub/cmp, then L (signed less than) */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLT32S, binop(Iop_Add32,cc_src,cc_dst), 
+                                         cc_src));
+      }
+
+      if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondLE)) {
+         /* long sub/cmp, then LE (signed less than or equal) */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLE32S, binop(Iop_Add32,cc_src,cc_dst), 
+                                         cc_src));
+      }
+
+      if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondBE)) {
+         /* long sub/cmp, then BE (unsigned less than or equal) */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLE32U, binop(Iop_Add32,cc_src,cc_dst), 
+                                         cc_src));
+      }
+
+      if (isU32(cc_op, CC_OP_DECL) && isU32(cond, CondZ)) {
+         /* dec L, then Z --> test dst == 0 */
+         return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dst, mkU32(0)));
+      }
+
+      return NULL;
+   }
+
+#  undef unop
+#  undef binop
+#  undef mkU32
+
+   return NULL;
+}
+
 
 /*---------------------------------------------------------------*/
 /*--- end                                guest-x86/ghelpers.c ---*/
index 6047173cb8eb130ec6ab6262ddd2a5070d6d93e5..58ac0aea3050c31d5e48a2d000b45b52ea408fc9 100644 (file)
@@ -358,7 +358,7 @@ static IRExpr* mk_calculate_eflags_all ( void )
    return IRExpr_CCall("calculate_eflags_all", Ity_I32, args);
 }
 
-/* Build IR to calculate just the carry flags from stored
+/* Build IR to calculate just the carry flag from stored
    CC_OP/CC_SRC/CC_DST.  Returns an expression :: Ity_I32. */
 static IRExpr* mk_calculate_eflags_c ( void )
 {
@@ -370,6 +370,20 @@ static IRExpr* mk_calculate_eflags_c ( void )
    return IRExpr_CCall("calculate_eflags_c", Ity_I32, args);
 }
 
+/* Build IR to calculate some particular condition from stored
+   CC_OP/CC_SRC/CC_DST.  Returns an expression :: Ity_Bit. */
+static IRExpr* calculate_condition ( Condcode cond )
+{
+   IRExpr** args = LibVEX_Alloc(5 * sizeof(IRExpr*));
+   args[0]       = mkU32(cond);
+   args[1]       = IRExpr_Get(OFFB_CC_OP,  Ity_I32);
+   args[2]       = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
+   args[3]       = IRExpr_Get(OFFB_CC_DST, Ity_I32);
+   args[4]       = NULL;
+   return unop(Iop_32to1, 
+               IRExpr_CCall("calculate_condition", Ity_I32, args));
+}
+
 
 /* -------------- Building the flags-thunk. -------------- */
 
@@ -539,36 +553,6 @@ void setFlags_MUL ( IRType ty, IRTemp src1, IRTemp src2, UInt base_op )
 
 /* Condition codes, using the Intel encoding.  */
 
-typedef
-   enum {
-      CondO      = 0,  /* overflow           */
-      CondNO     = 1,  /* no overflow        */
-
-      CondB      = 2,  /* below              */
-      CondNB     = 3,  /* not below          */
-
-      CondZ      = 4,  /* zero               */
-      CondNZ     = 5,  /* not zero           */
-
-      CondBE     = 6,  /* below or equal     */
-      CondNBE    = 7,  /* not below or equal */
-
-      CondS      = 8,  /* negative           */
-      CondNS     = 9,  /* not negative       */
-
-      CondP      = 10, /* parity even        */
-      CondNP     = 11, /* not parity even    */
-
-      CondL      = 12, /* jump less          */
-      CondNL     = 13, /* not less           */
-
-      CondLE     = 14, /* less or equal      */
-      CondNLE    = 15, /* not less or equal  */
-
-      CondAlways = 16  /* HACK */
-   }
-   Condcode;
-
 static Char* name_Condcode ( Condcode cond )
 {
    switch (cond) {
@@ -607,6 +591,8 @@ static Condcode positiveIse_Condcode ( Condcode  cond,
 }
 
 
+#if 0
+/* UNUSED -- DELETE */
 /* Get some particular flag to the lowest bit in a word.  It's not
    masked, tho. */
 static IRExpr* flag_to_bit0 ( UInt ccmask, IRTemp eflags )
@@ -691,6 +677,7 @@ static IRExpr* calculate_condition ( Condcode cond )
       invert ? unop(Iop_32to1, unop(Iop_Not32, e))
              : unop(Iop_32to1, e);
 }
+#endif
 
 
 /* -------------- Helpers for ADD/SUB with carry. -------------- */
index 9cf821ae8c77c63a8dcb0ccabd5ce822c186e7a8..045eeb09ce4bb512900c0c47498d8a31c2acddb4 100644 (file)
@@ -257,7 +257,7 @@ static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst )
 static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
 {
    MatchInfo mi;
-   DECLARE_PATTERN(p_32to1_then_1Uto8);     
+   DECLARE_PATTERN(p_32to1_then_1Uto8);
 
    IRType ty = typeOfIRExpr(env->type_env,e);
    vassert(ty == Ity_I32 || Ity_I16 || Ity_I8);
@@ -504,6 +504,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
             addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst)));
             return dst;
          }
+         case Iop_1Uto32:
          case Iop_1Uto8: {
             HReg dst         = newVRegI(env);
             X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
@@ -773,10 +774,20 @@ static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
    MatchInfo mi;
    DECLARE_PATTERN(p_32to1);
    DECLARE_PATTERN(p_eq32_zero);
+   DECLARE_PATTERN(p_ne32_zero);
+   DECLARE_PATTERN(p_1Uto32_then_32to1);
 
    vassert(e);
    vassert(typeOfIRExpr(env->type_env,e) == Ity_Bit);
 
+   /* 32to1(1Uto32(expr1)) -- the casts are pointless, ignore them */
+   DEFINE_PATTERN(p_1Uto32_then_32to1,
+                  unop(Iop_32to1,unop(Iop_1Uto32,bind(0))));
+   if (matchIRExpr(&mi,p_1Uto32_then_32to1,e)) {
+      IRExpr* expr1 = mi.bindee[0];
+      return iselCondCode(env, expr1);
+   }
+
    /* pattern: 32to1(expr32) */
    DEFINE_PATTERN(p_32to1, 
       unop(Iop_32to1,bind(0))
@@ -797,6 +808,34 @@ static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
       return Xcc_Z;
    }
 
+   /* pattern: CmpNE32(expr32,0) */
+   DEFINE_PATTERN(p_ne32_zero, 
+      binop( Iop_CmpNE32, bind(0), IRExpr_Const(IRConst_U32(0)) ) 
+   );
+   if (matchIRExpr(&mi,p_ne32_zero,e)) {
+      HReg src = iselIntExpr_R(env, mi.bindee[0]);
+      addInstr(env, X86Instr_Alu32R(Xalu_CMP,X86RMI_Imm(0),src));
+      return Xcc_NZ;
+   }
+
+   /* CmpLT32S(x,y) or CmpLE32S(x,y) */
+   if (e->tag == Iex_Binop 
+       && (e->Iex.Binop.op == Iop_CmpLT32S
+           || e->Iex.Binop.op == Iop_CmpLT32U
+           || e->Iex.Binop.op == Iop_CmpLE32S
+           || e->Iex.Binop.op == Iop_CmpLE32U)) {
+      HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
+      X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
+      addInstr(env, X86Instr_Alu32R(Xalu_CMP,rmi2,r1));
+      switch (e->Iex.Binop.op) {
+         case Iop_CmpLT32S: return Xcc_L;
+         case Iop_CmpLT32U: return Xcc_B;
+         case Iop_CmpLE32S: return Xcc_LE;
+         case Iop_CmpLE32U: return Xcc_BE;
+         default: vpanic("iselCondCode(x86): CmpXX");
+      }
+   }
+
    /* var */
    if (e->tag == Iex_Tmp) {
       HReg r32 = lookupIRTemp(env, e->Iex.Tmp.tmp);
index 7ff7bcfd27d9b9d091d7da5a2946f10c08ecdcee..2efb84440c946b1d82994f8cce7335b2d671b200 100644 (file)
@@ -96,6 +96,7 @@ void ppIROp ( IROp op )
       case Iop_32to8:    vex_printf("32to8");   return;
       case Iop_32to1:    vex_printf("32to1");   return;
       case Iop_1Uto8:    vex_printf("1Uto8");   return;
+      case Iop_1Uto32:   vex_printf("1Uto32");  return;
 
       case Iop_MullS8:   vex_printf("MullS8");  return;
       case Iop_MullS16:  vex_printf("MullS16"); return;
@@ -104,6 +105,11 @@ void ppIROp ( IROp op )
       case Iop_MullU16:  vex_printf("MullU16"); return;
       case Iop_MullU32:  vex_printf("MullU32"); return;
 
+      case Iop_CmpLT32S: vex_printf("CmpLT32S"); return;
+      case Iop_CmpLE32S: vex_printf("CmpLE32S"); return;
+      case Iop_CmpLT32U: vex_printf("CmpLT32U"); return;
+      case Iop_CmpLE32U: vex_printf("CmpLE32U"); return;
+
       case Iop_DivModU64to32: vex_printf("DivModU64to32"); return;
       case Iop_DivModS64to32: vex_printf("DivModS64to32"); return;
 
@@ -548,6 +554,10 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_CmpEQ16: case Iop_CmpNE16:
          COMPARISON(Ity_I16);
       case Iop_CmpEQ32: case Iop_CmpNE32:
+      case Iop_CmpLT32S:
+      case Iop_CmpLE32S:
+      case Iop_CmpLT32U:
+      case Iop_CmpLE32U:
          COMPARISON(Ity_I32);
       case Iop_CmpEQ64: case Iop_CmpNE64:
          COMPARISON(Ity_I64);
@@ -579,6 +589,7 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
          BINARY(Ity_I64,Ity_I32,Ity_I32);
 
       case Iop_1Uto8:   UNARY(Ity_I8,Ity_Bit);
+      case Iop_1Uto32:  UNARY(Ity_I32,Ity_Bit);
       case Iop_32to1:   UNARY(Ity_Bit,Ity_I32);
       case Iop_8Uto32:  UNARY(Ity_I32,Ity_I8);
       case Iop_8Sto32:  UNARY(Ity_I32,Ity_I8);
index 3268d73cbdc92632200a93ba507145ccb7d82601..cbb70c2a701a8406c815ea62b53ff7a627df867e 100644 (file)
@@ -770,6 +770,8 @@ static void dead_BB ( IRBB* bb )
    /* Work backwards through the stmts */
    for (i = bb->stmts_used-1; i >= 0; i--) {
       st = bb->stmts[i];
+      if (!st)
+         continue;
       if (st->tag == Ist_Tmp
           && !lookupH64(set, NULL, (ULong)(st->Ist.Tmp.tmp))) {
           /* it's an IRTemp which never got used.  Delete it. */
@@ -1067,6 +1069,47 @@ static void redundant_put_removal_BB ( IRBB* bb )
 }
 
 
+/*---------------------------------------------------------------*/
+/*--- Specialisation of helper function calls, in             ---*/
+/*--- collaboration with the front end                        ---*/
+/*---------------------------------------------------------------*/
+
+static 
+void spec_helpers_BB ( IRBB* bb,
+                       IRExpr* (*specHelper) ( Char*, IRExpr**) )   
+{
+   Int i;
+   IRStmt* st;
+   IRExpr* ex;
+
+   for (i = bb->stmts_used-1; i >= 0; i--) {
+      st = bb->stmts[i];
+
+      if (!st 
+          || st->tag != Ist_Tmp
+          || st->Ist.Tmp.expr->tag != Iex_CCall)
+       continue;
+
+      ex = (*specHelper)( st->Ist.Tmp.expr->Iex.CCall.name,
+                          st->Ist.Tmp.expr->Iex.CCall.args );
+      if (!ex)
+       /* the front end can't think of a suitable replacement */
+       continue;
+
+      /* We got something better.  Install it in the bb. */
+      bb->stmts[i]
+         = IRStmt_Tmp(st->Ist.Tmp.tmp, ex);
+
+      if (0) {
+         vex_printf("SPEC: ");
+         ppIRExpr(st->Ist.Tmp.expr);
+         vex_printf("  -->  ");
+         ppIRExpr(ex);
+         vex_printf("\n");
+      }
+   }
+}
+
 
 /*---------------------------------------------------------------*/
 /*--- The tree builder                                        ---*/
@@ -1075,7 +1118,8 @@ static void redundant_put_removal_BB ( IRBB* bb )
 typedef
    struct { 
       Int     occ;          /* occurrence count for this tmp */
-      IRExpr* expr;         /* expr it is bound to, or NULL if already 'used' */
+      IRExpr* expr;         /* expr it is bound to, 
+                               or NULL if already 'used' */
       Bool    eDoesLoad;    /* True <=> expr reads mem */
       Bool    eDoesGet;     /* True <=> expr reads guest state */
       Bool    invalidateMe; /* used when dumping bindings */
@@ -1401,6 +1445,9 @@ static void treebuild_BB ( IRBB* bb )
          continue;
 
       if (!lookupH64(env, &res, (ULong)(st->Ist.Tmp.tmp))) {
+         vex_printf("\n");
+         ppIRTemp(st->Ist.Tmp.tmp);
+         vex_printf("\n");
          vpanic("treebuild_BB (phase 2): unmapped IRTemp");
       }
       ti = (TmpInfo*)res;
@@ -1515,7 +1562,8 @@ static void treebuild_BB ( IRBB* bb )
 */
 
 /* exported from this file */
-IRBB* do_iropt_BB ( IRBB* bb0 )
+IRBB* do_iropt_BB ( IRBB* bb0,
+                    IRExpr* (*specHelper) ( Char*, IRExpr**) )
 {
    Bool verbose = False;
    IRBB *flat, *cpd;
@@ -1545,18 +1593,23 @@ IRBB* do_iropt_BB ( IRBB* bb0 )
    }
 
    dead_BB ( cpd );
-   if (0||verbose) {
+   if (verbose) {
       vex_printf("\n========= DEAD\n\n" );
       ppIRBB(cpd);
    }
 
-#if 1
+   spec_helpers_BB ( cpd, specHelper );
+   dead_BB ( cpd );
+   if (verbose) {
+      vex_printf("\n========= SPECd \n\n" );
+      ppIRBB(cpd);
+   }
+
    treebuild_BB ( cpd );
-   if (0||verbose) {
+   if (verbose) {
       vex_printf("\n========= TREEd \n\n" );
       ppIRBB(cpd);
    }
-#endif
 
    return cpd;
 
index d086765c50b7b7b4f2e239e8521c31bce8969056..1a6831ce2994dc63a5a35db569b3d0b6ef3c1e2b 100644 (file)
@@ -11,7 +11,8 @@
 #include "libvex.h"
 
 
-extern IRBB* do_iropt_BB ( IRBB* );
+extern IRBB* do_iropt_BB ( IRBB* bb,
+                           IRExpr* (*specHelper) ( Char*, IRExpr**) );
 
 /*---------------------------------------------------------------*/
 /*--- end                                          ir/iropt.h ---*/
index fb88ae4cc09480ef4402b038b5e368ad1592714f..1becac351bc24c4cadf098280541397afceee5e7 100644 (file)
@@ -99,6 +99,7 @@ TranslateResult LibVEX_Translate (
                                          Bool(*)(Addr64), Bool );
    Int          (*emit)        ( UChar*, Int, HInstr* );
    Addr64       (*findHelper)  ( Char* );
+   IRExpr*      (*specHelper)  ( Char*, IRExpr** );
 
    Bool         host_is_bigendian = False;
    IRBB*        irbb;
@@ -120,6 +121,7 @@ TranslateResult LibVEX_Translate (
    bbToIR                 = NULL;
    emit                   = NULL;
    findHelper             = NULL;
+   specHelper             = NULL;
 
    saved_verbosity = vex_verbosity;
    if (bb_verbosity > 0)
@@ -153,6 +155,7 @@ TranslateResult LibVEX_Translate (
       case InsnSetX86:
          bbToIR     = bbToIR_X86Instr;
          findHelper = x86guest_findhelper;
+         specHelper = x86guest_spechelper;
          break;
       default:
          vpanic("LibVEX_Translate: unsupported guest insn set");
@@ -173,7 +176,7 @@ TranslateResult LibVEX_Translate (
    sanityCheckIRBB(irbb, Ity_I32);
 
    /* Clean it up, hopefully a lot. */
-   irbb = do_iropt_BB ( irbb );
+   irbb = do_iropt_BB ( irbb, specHelper );
    sanityCheckIRBB(irbb, Ity_I32);
 
    if (vex_verbosity > 0) {
index 3bb2be19d4be05a2aa1eee7e7284feac0fe6d9ff..c048144d7d1c4f894aa9fc716d1975c31a9af347 100644 (file)
@@ -96,6 +96,10 @@ typedef
       Iop_MullS8, Iop_MullS16, Iop_MullS32,
       Iop_MullU8, Iop_MullU16, Iop_MullU32,
       /* Ordering not important after here. */
+      Iop_CmpLT32S,
+      Iop_CmpLE32S,
+      Iop_CmpLT32U,
+      Iop_CmpLE32U,
       /* Division */
       Iop_DivModU64to32, // :: I64,I32 -> I64
                          // of which lo half is div and hi half is mod
@@ -118,8 +122,9 @@ typedef
       Iop_64HIto32,   // :: I64 -> I32, high half
       Iop_32HLto64,   // :: (I32,I32) -> I64
       /* 1-bit stuff */
-      Iop_32to1, /* :: Ity_I32 -> Ity_Bit, just select bit[0] */
-      Iop_1Uto8, /* :: Ity_Bit -> Ity_I8, unsigned widen */
+      Iop_32to1,  /* :: Ity_I32 -> Ity_Bit, just select bit[0] */
+      Iop_1Uto8,  /* :: Ity_Bit -> Ity_I8, unsigned widen */
+      Iop_1Uto32, /* :: Ity_Bit -> Ity_I32, unsigned widen */
       /* FP stuff */
       Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64,
       Iop_SqrtF64,
index 4482e9b4240a680f2cf316d1af07d5329401d712..736ac7e4bd0ec609cb59dff5c721dec4699b861c 100644 (file)
@@ -65,7 +65,7 @@ int main ( int argc, char** argv )
 
    LibVEX_Init ( &failure_exit, &log_bytes, 
                  1,  /* debug_paranoia */ 
-                 0,  /* verbosity */
+                 1,  /* verbosity */
                  //False, 
                 True, 
                  100 );