]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Loads more x86 insn selector hacking.
authorJulian Seward <jseward@acm.org>
Sun, 18 Jul 2004 23:06:45 +0000 (23:06 +0000)
committerJulian Seward <jseward@acm.org>
Sun, 18 Jul 2004 23:06:45 +0000 (23:06 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@94

VEX/priv/guest-x86/x86toIR.c
VEX/priv/host-x86/isel_x86.c
VEX/priv/host-x86/x86h_defs.c
VEX/priv/host-x86/x86h_defs.h
VEX/priv/ir/ir_defs.c
VEX/priv/main/vex_main.c
VEX/priv/main/vex_util.c
VEX/pub/libvex.h
VEX/pub/libvex_ir.h

index 0e27cd401f0a178a1e40939504df92b3aa522302..1cd4da11b2a8b478e46ebc497e783198abd83a8b 100644 (file)
@@ -389,6 +389,17 @@ static IRExpr* mk_calculate_eflags_c ( void )
    Ity_Bit, and the thunk is only updated iff guard evaluates to 1 at
    run-time.  If guard is NULL, the update is always done. */
 
+static IRExpr* widenUTo32 ( IRExpr* e )
+{
+   switch (typeOfIRExpr(irbb->tyenv,e)) {
+      case Ity_I32: return e;
+      case Ity_I16: return unop(Iop_16Uto32,e);
+      case Ity_I8:  return unop(Iop_8Uto32,e);
+      default: vpanic("widenUto32");
+   }
+}
+
+
 /* This is for add/sub/adc/sbb/and/or/xor, where we need to
    store the result value and the non-lvalue operand. */
 
@@ -413,8 +424,8 @@ static void setFlags_SRC_DST1 ( IROp    op8,
    }
    stmt( IRStmt_Put( OFFB_CC_OP,  mkU32(ccOp)) );
    stmt( IRStmt_Put( OFFB_CC_SRC, logic ? mkU32(0) 
-                                              : mkexpr(src)) );
-   stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(dst1)) );
+                                        : widenUTo32(mkexpr(src))) );
+   stmt( IRStmt_Put( OFFB_CC_DST, widenUTo32(mkexpr(dst1))) );
 }
 
 
@@ -422,23 +433,13 @@ static void setFlags_SRC_DST1 ( IROp    op8,
    result except shifted one bit less.  And then only when the guard
    says we can. */
 
-static IRExpr* widenUTo32 ( IRExpr* e )
-{
-   switch (typeOfIRExpr(irbb->tyenv,e)) {
-      case Ity_I32: return e;
-      case Ity_I16: return unop(Iop_16Uto32,e);
-      case Ity_I8:  return unop(Iop_8Uto32,e);
-      default: vpanic("widenUto32");
-   }
-}
-
 static void setFlags_DSTus_DST1 ( IROp    op8,
                                   IRTemp  dstUS,
                                   IRTemp  dst1,
                                   IRType  ty,
                                   IRTemp  guard )
 {
-   Int ccOp  = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
+   Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
 
    vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
    vassert(guard);
index 24014a873eff26fe79b6fff6e413e744444fab3b..0c39dfdba32950cd89a447e4205d3a85afe0f813 100644 (file)
 #include "x86h_defs.h"
 
 
+/*---------------------------------------------------------*/
+/*--- Stuff for pattern matching on IR.  This isn't     ---*/
+/*--- x86 specific, and should be moved elsewhere.      ---*/
+/*---------------------------------------------------------*/
+
+#define DECLARE_PATTERN(_patt) \
+   static IRExpr* _patt = NULL
+
+#define DEFINE_PATTERN(_patt,_expr)                            \
+   do {                                                        \
+      if (!(_patt)) {                                          \
+         vassert(LibVEX_GetAllocMode() == AllocModeTEMPORARY); \
+         LibVEX_SetAllocMode(AllocModePERMANENT);              \
+         _patt = (_expr);                                      \
+         LibVEX_SetAllocMode(AllocModeTEMPORARY);              \
+         vassert(LibVEX_GetAllocMode() == AllocModeTEMPORARY); \
+      }                                                        \
+   } while (0)
+
+
+#define N_MATCH_BINDERS 4
+typedef
+   struct {
+      IRExpr* bindee[N_MATCH_BINDERS];
+   }
+   MatchInfo;
+
+
+static void setBindee ( MatchInfo* mi, Int n, IRExpr* bindee )
+{
+   if (n < 0 || n >= N_MATCH_BINDERS)
+      vpanic("setBindee: out of range index");
+   if (mi->bindee[n] != NULL)
+      vpanic("setBindee: bindee already set");
+   mi->bindee[n] = bindee;
+}
+
+static Bool matchWrk ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ )
+{
+   switch (p->tag) {
+      case Iex_Binder: /* aha, what we were looking for. */
+         setBindee(mi, p->Iex.Binder.binder, e);
+         return True;
+      case Iex_Unop:
+         if (e->tag != Iex_Unop) return False;
+         if (p->Iex.Unop.op != e->Iex.Unop.op) return False;
+         if (!matchWrk(mi, p->Iex.Unop.arg, e->Iex.Unop.arg))
+            return False;
+         return True;
+      case Iex_Binop:
+         if (e->tag != Iex_Binop) return False;
+         if (p->Iex.Binop.op != e->Iex.Binop.op) return False;
+        if (!matchWrk(mi, p->Iex.Binop.arg1, e->Iex.Binop.arg1))
+            return False;
+        if (!matchWrk(mi, p->Iex.Binop.arg2, e->Iex.Binop.arg2))
+            return False;
+         return True;
+      case Iex_Const:
+       if (e->tag != Iex_Const) return False;
+       switch (p->Iex.Const.con->tag) {
+           case Ico_U8: return e->Iex.Const.con->tag==Ico_U8 
+                                  ? (p->Iex.Const.con->Ico.U8 
+                                     == e->Iex.Const.con->Ico.U8) 
+                                  : False;
+           case Ico_U16: return e->Iex.Const.con->tag==Ico_U16 
+                                   ? (p->Iex.Const.con->Ico.U16 
+                                      == e->Iex.Const.con->Ico.U16) 
+                                   : False;
+           case Ico_U32: return e->Iex.Const.con->tag==Ico_U32 
+                                   ? (p->Iex.Const.con->Ico.U32 
+                                      == e->Iex.Const.con->Ico.U32) 
+                                   : False;
+           case Ico_U64: return e->Iex.Const.con->tag==Ico_U64 
+                                   ? (p->Iex.Const.con->Ico.U64 
+                                      == e->Iex.Const.con->Ico.U64) 
+                                   : False;
+       }
+        vpanic("matchIRExpr.Iex_Const");
+        /*NOTREACHED*/
+      default: 
+         ppIRExpr(p);
+         vpanic("match");
+   }
+}
+
+static Bool matchIRExpr ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ )
+{
+   Int i;
+   for (i = 0; i < N_MATCH_BINDERS; i++)
+      mi->bindee[i] = NULL;
+   return matchWrk(mi, p, e);
+}
+
+/*-----*/
+/* These are duplicated in x86toIR.c */
+static IRExpr* unop ( IROp op, IRExpr* a )
+{
+   return IRExpr_Unop(op, a);
+}
+
+static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
+{
+   return IRExpr_Binop(op, a1, a2);
+}
+
+static IRExpr* bind ( Int binder )
+{
+   return IRExpr_Binder(binder);
+}
+
+
+
+
 /*---------------------------------------------------------*/
 /*--- ISelEnv                                           ---*/
 /*---------------------------------------------------------*/
@@ -98,7 +211,7 @@ static X86RM*    iselIntExpr_RM    ( ISelEnv* env, IRExpr* e );
 static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e );
 
 
-static X86Instr* mk_MOV_RR ( HReg src, HReg dst )
+static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst )
 {
    vassert(hregClass(src) == HRcInt);
    vassert(hregClass(dst) == HRcInt);
@@ -120,16 +233,21 @@ static X86Instr* mk_MOV_RR ( HReg src, HReg dst )
 */
 static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
 {
+   MatchInfo mi;
+   DECLARE_PATTERN(p_32to1_then_1Uto8);     
+
    vassert(e);
    IRType ty = typeOfIRExpr(env->type_env,e);
    vassert(ty == Ity_I32 || Ity_I16 || Ity_I8);
 
    switch (e->tag) {
 
+   /* --------- TEMPs --------- */
    case Iex_Tmp: {
       return lookupIRTemp(env, e->Iex.Tmp.tmp);
    }
 
+   /* --------- LOADs --------- */
    case Iex_LDle: {
       HReg dst = newVRegI(env);
       X86AMode* amode = iselIntExpr_AMode ( env, e->Iex.LDle.addr );
@@ -142,9 +260,14 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
          addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
          return dst;
       }
+      if (ty == Ity_I8) {
+         addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
+         return dst;
+      }
       break;
    }
 
+   /* --------- BINARY OPs --------- */
    case Iex_Binop: {
       X86AluOp   aluOp;
       X86ShiftOp shOp;
@@ -167,7 +290,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
          HReg dst    = newVRegI(env);
          HReg reg    = iselIntExpr_R(env, e->Iex.Binop.arg1);
          X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
-         addInstr(env, mk_MOV_RR(reg,dst));
+         addInstr(env, mk_MOVsd_RR(reg,dst));
          addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst));
          return dst;
       }
@@ -182,22 +305,45 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
          HReg dst    = newVRegI(env);
          HReg regL   = iselIntExpr_R(env, e->Iex.Binop.arg1);
          HReg regR   = iselIntExpr_R(env, e->Iex.Binop.arg2);
-         addInstr(env, mk_MOV_RR(regL,dst));
-         addInstr(env, mk_MOV_RR(regR,hregX86_ECX()));
+         addInstr(env, mk_MOVsd_RR(regL,dst));
+         addInstr(env, mk_MOVsd_RR(regR,hregX86_ECX()));
          addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, X86RM_Reg(dst)));
          return dst;
       }
       break;
    }
 
+   /* --------- UNARY OPs --------- */
    case Iex_Unop: {
+      /* 1Uto8(32to1(expr32)) */
+      DEFINE_PATTERN(p_32to1_then_1Uto8,
+                    unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
+      if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
+         IRExpr* expr32 = mi.bindee[0];
+        HReg dst = newVRegI(env);
+         HReg src = iselIntExpr_R(env, expr32);
+         addInstr(env, mk_MOVsd_RR(src,dst) );
+         addInstr(env, X86Instr_Alu32R(Xalu_AND,
+                                       X86RMI_Imm(1), dst));
+         return dst;
+      }
+
       switch (e->Iex.Unop.op) {
-         case Iop_8Uto32: {
+         case Iop_8Uto32:
+         case Iop_16Uto32: {
             HReg dst = newVRegI(env);
             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
-            addInstr(env, mk_MOV_RR(src,dst) );
+            UInt mask = e->Iex.Unop.op==Iop_8Uto32 ? 0xFF : 0xFFFF;
+            addInstr(env, mk_MOVsd_RR(src,dst) );
             addInstr(env, X86Instr_Alu32R(Xalu_AND,
-                                          X86RMI_Imm(0xFF), dst));
+                                          X86RMI_Imm(mask), dst));
+            return dst;
+         }
+         case Iop_Not32: {
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, mk_MOVsd_RR(src,dst) );
+            addInstr(env, X86Instr_Not32(X86RM_Reg(dst)));
             return dst;
          }
          default: 
@@ -206,6 +352,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
       break;
    }
 
+   /* --------- GETs --------- */
    case Iex_Get: {
       if (ty == Ity_I32) {
          HReg dst = newVRegI(env);
@@ -227,6 +374,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
       break;
    }
 
+   /* --------- CCALLs --------- */
    case Iex_CCall: {
       Int i, nargs;
       UInt target;
@@ -258,6 +406,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
       return hregX86_EAX();
    }
 
+   /* --------- LITERALs --------- */
    /* 32/16/8-bit literals */
    case Iex_Const: {
       X86RMI* rmi = iselIntExpr_RMI ( env, e );
@@ -266,13 +415,14 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
       return r;
    }
 
+   /* --------- MULTIPLEXes --------- */
    case Iex_Mux0X: {
       if (ty == Ity_I32 
          && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
        HReg rX   = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
        X86RM* r0 = iselIntExpr_RM(env, e->Iex.Mux0X.expr0);
        HReg dst = newVRegI(env);
-       addInstr(env, mk_MOV_RR(rX,dst));
+       addInstr(env, mk_MOVsd_RR(rX,dst));
        HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
        addInstr(env, X86Instr_Alu32R(Xalu_TEST,
                                      X86RMI_Imm(0xFF), r8));
@@ -431,6 +581,46 @@ static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e )
 }
 
 
+/* Generate code to evaluated a bit-typed expression, returning the
+   condition code which would correspond when the expression would
+   notionally have returned 1. */
+
+static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
+{
+   MatchInfo mi;
+   DECLARE_PATTERN(p_32to1);
+   DECLARE_PATTERN(p_eq32_zero);
+
+   vassert(e);
+   vassert(typeOfIRExpr(env->type_env,e) == Ity_Bit);
+
+   /* pattern: 32to1(expr32) */
+   DEFINE_PATTERN(p_32to1, 
+      unop(Iop_32to1,bind(0))
+   );
+   if (matchIRExpr(&mi,p_32to1,e)) {
+      HReg src = iselIntExpr_R(env, mi.bindee[0]);
+      HReg dst = newVRegI(env);
+      addInstr(env, mk_MOVsd_RR(src,dst));
+      addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst));
+      return Xcc_NZ;
+   }
+
+   /* pattern: CmpEQ32(expr32,0) */
+   DEFINE_PATTERN(p_eq32_zero, 
+      binop( Iop_CmpEQ32, bind(0), IRExpr_Const(IRConst_U32(0)) ) 
+   );
+   if (matchIRExpr(&mi,p_eq32_zero,e)) {
+      HReg src = iselIntExpr_R(env, mi.bindee[0]);
+      addInstr(env, X86Instr_Alu32R(Xalu_CMP,X86RMI_Imm(0),src));
+      return Xcc_NZ;
+   }
+
+   ppIRExpr(e);
+   vpanic("iselCondCode");
+}
+
+
 
 /*---------------------------------------------------------*/
 /*--- ISEL: Statements                                  ---*/
@@ -450,10 +640,17 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
       vassert(tya == Ity_I32);
       if (tyd == Ity_I32) {
          X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
-         X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data);
+         X86RI* ri    = iselIntExpr_RI(env, stmt->Ist.STle.data);
          addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am));
          return;
       }
+      if (tyd == Ity_I8) {
+         X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
+         HReg r       = iselIntExpr_R(env, stmt->Ist.STle.data);
+         addInstr(env, X86Instr_Store(1,r,am));
+         return;
+      }
+
       break;
    }
 
@@ -471,6 +668,16 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
                  ));
          return;
       }
+      if (ty == Ity_I8) {
+         /* We're going to write to memory, so compute the RHS into an
+            X86RI. */
+         HReg r  = iselIntExpr_R(env, stmt->Ist.Put.expr);
+         addInstr(env, X86Instr_Store(
+                          1,r,
+                          X86AMode_IR(stmt->Ist.Put.offset,
+                                      hregX86_EBP())));
+         return;
+      }
       break;
    }
 
@@ -489,19 +696,10 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
    case Ist_Exit: {
      if (stmt->Ist.Exit.dst->tag != Ico_U32)
         vpanic("isel_x86: Ist_Exit: dst is not a 32-bit value");
-     /* For the moment, only handle conditions of the form
-        32to1(...). */
-     IRExpr* cond = stmt->Ist.Exit.cond;
-     if (cond->tag == Iex_Unop && cond->Iex.Unop.op == Iop_32to1) {
-        cond = cond->Iex.Unop.arg;
-     } else {
-        break; /* give up */
-     }
-     HReg reg = iselIntExpr_R( env, cond );
-     /* Set the Z flag -- as the inverse of the lowest bit of cond */
-     addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),reg));
-     addInstr(env, X86Instr_GotoNZ(
-                      True, X86RI_Imm(stmt->Ist.Exit.dst->Ico.U32)));
+
+     X86RI* dst     = iselIntExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
+     X86CondCode cc = iselCondCode(env,stmt->Ist.Exit.cond);
+     addInstr(env, X86Instr_Goto(cc, dst));
      return;
    }
 
@@ -524,7 +722,7 @@ static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
    vex_printf("\n");
 
    ri = iselIntExpr_RI(env, next);
-   addInstr(env, X86Instr_GotoNZ(False,ri));
+   addInstr(env, X86Instr_Goto(Xcc_ALWAYS,ri));
 }
 
 
index e5fb70dce59fec51c26163cb3406f71f3eb64b5d..d30b4a21b0b1e91008aa2e8d40f27367cd70a262 100644 (file)
@@ -67,6 +67,33 @@ void getAllocableRegs_X86 ( Int* nregs, HReg** arr )
 }
 
 
+/* --------- Condition codes, Intel encoding. --------- */
+
+void ppX86CondCode ( X86CondCode cond )
+{
+   switch (cond) {
+      case Xcc_O:      vex_printf("o"); break;
+      case Xcc_NO:     vex_printf("no"); break;
+      case Xcc_B:      vex_printf("b"); break;
+      case Xcc_NB:     vex_printf("nb"); break;
+      case Xcc_Z:      vex_printf("z"); break;
+      case Xcc_NZ:     vex_printf("nz"); break;
+      case Xcc_BE:     vex_printf("be"); break;
+      case Xcc_NBE:    vex_printf("nbe"); break;
+      case Xcc_S:      vex_printf("s"); break;
+      case Xcc_NS:     vex_printf("ns"); break;
+      case Xcc_P:      vex_printf("p"); break;
+      case Xcc_NP:     vex_printf("np"); break;
+      case Xcc_L:      vex_printf("l"); break;
+      case Xcc_NL:     vex_printf("nl"); break;
+      case Xcc_LE:     vex_printf("le"); break;
+      case Xcc_NLE:    vex_printf("nle"); break;
+      case Xcc_ALWAYS: vex_printf("ALWAYS"); break;
+      default: vpanic("ppX86CondCode");
+   }
+}
+
+
 /* --------- X86AMode: memory address expressions. --------- */
 
 X86AMode* X86AMode_IR ( UInt imm32, HReg reg ) {
@@ -76,7 +103,6 @@ X86AMode* X86AMode_IR ( UInt imm32, HReg reg ) {
    am->Xam.IR.reg = reg;
    return am;
 }
-
 X86AMode* X86AMode_IRRS ( UInt imm32, HReg base, HReg index, Int shift ) {
    X86AMode* am = LibVEX_Alloc(sizeof(X86AMode));
    am->tag = Xam_IRRS;
@@ -143,14 +169,12 @@ X86RMI* X86RMI_Imm ( UInt imm32 ) {
    op->Xrmi.Imm.imm32 = imm32;
    return op;
 }
-
 X86RMI* X86RMI_Reg ( HReg reg ) {
    X86RMI* op       = LibVEX_Alloc(sizeof(X86RMI));
    op->tag          = Xrmi_Reg;
    op->Xrmi.Reg.reg = reg;
    return op;
 }
-
 X86RMI* X86RMI_Mem ( X86AMode* am ) {
    X86RMI* op      = LibVEX_Alloc(sizeof(X86RMI));
    op->tag         = Xrmi_Mem;
@@ -216,7 +240,6 @@ X86RI* X86RI_Imm ( UInt imm32 ) {
    op->Xri.Imm.imm32 = imm32;
    return op;
 }
-
 X86RI* X86RI_Reg ( HReg reg ) {
    X86RI* op       = LibVEX_Alloc(sizeof(X86RI));
    op->tag         = Xri_Reg;
@@ -273,7 +296,6 @@ X86RM* X86RM_Reg ( HReg reg ) {
    op->Xrm.Reg.reg = reg;
    return op;
 }
-
 X86RM* X86RM_Mem ( X86AMode* am ) {
    X86RM* op      = LibVEX_Alloc(sizeof(X86RM));
    op->tag        = Xrm_Mem;
@@ -370,7 +392,6 @@ X86Instr* X86Instr_Alu32R ( X86AluOp op, X86RMI* src, HReg dst ) {
    i->Xin.Alu32R.dst = dst;
    return i;
 }
-
 X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) {
    X86Instr* i       = LibVEX_Alloc(sizeof(X86Instr));
    i->tag            = Xin_Alu32M;
@@ -379,7 +400,12 @@ X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) {
    i->Xin.Alu32M.dst = dst;
    return i;
 }
-
+X86Instr* X86Instr_Not32  ( X86RM* dst ) {
+   X86Instr* i      = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag           = Xin_Not32;
+   i->Xin.Not32.dst = dst;
+   return i;
+}
 X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
    X86Instr* i     = LibVEX_Alloc(sizeof(X86Instr));
    i->tag          = Xin_Sh32;
@@ -388,29 +414,25 @@ X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
    i->Xin.Sh32.dst = dst;
    return i;
 }
-
 X86Instr* X86Instr_Push( X86RMI* src ) {
    X86Instr* i     = LibVEX_Alloc(sizeof(X86Instr));
    i->tag          = Xin_Push;
    i->Xin.Push.src = src;
    return i;
 }
-
 X86Instr* X86Instr_Call ( HReg target ) {
    X86Instr* i        = LibVEX_Alloc(sizeof(X86Instr));
    i->tag             = Xin_Call;
    i->Xin.Call.target = target;
    return i;
 }
-
-X86Instr* X86Instr_GotoNZ ( Bool onlyWhenNZ, X86RI* dst ) {
-   X86Instr* i              = LibVEX_Alloc(sizeof(X86Instr));
-   i->tag                   = Xin_GotoNZ;
-   i->Xin.GotoNZ.onlyWhenNZ = onlyWhenNZ;
-   i->Xin.GotoNZ.dst        = dst;
+X86Instr* X86Instr_Goto ( X86CondCode cond, X86RI* dst ) {
+   X86Instr* i      = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag           = Xin_Goto;
+   i->Xin.Goto.cond = cond;
+   i->Xin.Goto.dst  = dst;
    return i;
 }
-
 X86Instr* X86Instr_CMovZ  ( X86RM* src, HReg dst ) {
    X86Instr* i      = LibVEX_Alloc(sizeof(X86Instr));
    i->tag           = Xin_CMovZ;
@@ -418,7 +440,6 @@ X86Instr* X86Instr_CMovZ  ( X86RM* src, HReg dst ) {
    i->Xin.CMovZ.dst = dst;
    return i;
 }
-
 X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
                             X86AMode* src, HReg dst ) {
    X86Instr* i           = LibVEX_Alloc(sizeof(X86Instr));
@@ -430,6 +451,15 @@ X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
    vassert(szSmall == 1 || szSmall == 2);
    return i;
 }
+X86Instr* X86Instr_Store  ( UChar sz, HReg src, X86AMode* dst ) {
+   X86Instr* i      = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag           = Xin_Store;
+   i->Xin.Store.sz  = sz;
+   i->Xin.Store.src = src;
+   i->Xin.Store.dst = dst;
+   vassert(sz == 1 || sz == 2);
+   return i;
+}
 
 
 void ppX86Instr ( X86Instr* i ) {
@@ -448,6 +478,10 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf(",");
          ppX86AMode(i->Xin.Alu32M.dst);
          return;
+      case Xin_Not32:
+         vex_printf("notl ");
+         ppX86RM(i->Xin.Not32.dst);
+         return;
       case Xin_Sh32:
          ppX86ShiftOp(i->Xin.Sh32.op);
          vex_printf("l ");
@@ -465,15 +499,17 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf("call *");
          ppHRegX86(i->Xin.Call.target);
          break;
-      case Xin_GotoNZ:
-         if (i->Xin.GotoNZ.onlyWhenNZ) {
-            vex_printf("if (%%eflags.Z) { movl ");
-            ppX86RI(i->Xin.GotoNZ.dst);
-            vex_printf(",%%eax ; ret }");
-         } else {
+      case Xin_Goto:
+         if (i->Xin.Goto.cond == Xcc_ALWAYS) {
             vex_printf("movl ");
-            ppX86RI(i->Xin.GotoNZ.dst);
+            ppX86RI(i->Xin.Goto.dst);
             vex_printf(",%%eax ; ret");
+         } else {
+            vex_printf("if (%%eflags.");
+           ppX86CondCode(i->Xin.Goto.cond);
+            vex_printf(") { movl ");
+            ppX86RI(i->Xin.Goto.dst);
+            vex_printf(",%%eax ; ret }");
          }
          return;
       case Xin_CMovZ:
@@ -490,6 +526,12 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf(",");
          ppHRegX86(i->Xin.LoadEX.dst);
          return;
+      case Xin_Store:
+         vex_printf("mov%c ", i->Xin.Store.sz==1 ? 'b' : 'w');
+         ppHRegX86(i->Xin.Store.src);
+         vex_printf(",");
+         ppX86AMode(i->Xin.Store.dst);
+         return;
       default:
          vpanic("ppX86Instr");
    }
@@ -535,8 +577,8 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, HRmWrite, hregX86_ECX());
          addHRegUse(u, HRmWrite, hregX86_EDX());
          return;
-      case Xin_GotoNZ:
-         addRegUsage_X86RI(u, i->Xin.GotoNZ.dst);
+      case Xin_Goto:
+         addRegUsage_X86RI(u, i->Xin.Goto.dst);
          addHRegUse(u, HRmWrite, hregX86_EAX());
          return;
       default:
@@ -559,8 +601,8 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
       case Xin_Sh32:
          mapRegs_X86RM(m, i->Xin.Sh32.dst);
          return;
-      case Xin_GotoNZ:
-         mapRegs_X86RI(m, i->Xin.GotoNZ.dst);
+      case Xin_Goto:
+         mapRegs_X86RI(m, i->Xin.Goto.dst);
          return;
       default:
          ppX86Instr(i);
index 9bc4901edc4a3de59b40a1fb686903e1d675651f..97fdd8ba572195d2bc4911786c8c32d79ac13b54 100644 (file)
@@ -28,6 +28,41 @@ extern HReg hregX86_ESI ( void );
 extern HReg hregX86_EDI ( void );
 
 
+/* --------- Condition codes, Intel encoding. --------- */
+
+typedef
+   enum {
+      Xcc_O      = 0,  /* overflow           */
+      Xcc_NO     = 1,  /* no overflow        */
+
+      Xcc_B      = 2,  /* below              */
+      Xcc_NB     = 3,  /* not below          */
+
+      Xcc_Z      = 4,  /* zero               */
+      Xcc_NZ     = 5,  /* not zero           */
+
+      Xcc_BE     = 6,  /* below or equal     */
+      Xcc_NBE    = 7,  /* not below or equal */
+
+      Xcc_S      = 8,  /* negative           */
+      Xcc_NS     = 9,  /* not negative       */
+
+      Xcc_P      = 10, /* parity even        */
+      Xcc_NP     = 11, /* not parity even    */
+
+      Xcc_L      = 12, /* jump less          */
+      Xcc_NL     = 13, /* not less           */
+
+      Xcc_LE     = 14, /* less or equal      */
+      Xcc_NLE    = 15, /* not less or equal  */
+
+      Xcc_ALWAYS = 16  /* the usual hack     */
+   }
+   X86CondCode;
+
+extern void ppX86CondCode ( X86CondCode );
+
+
 /* --------- Memory address expressions (amodes). --------- */
 
 typedef
@@ -190,12 +225,14 @@ typedef
    enum {
       Xin_Alu32R,    /* 32-bit mov/arith/logical, dst=REG */
       Xin_Alu32M,    /* 32-bit mov/arith/logical, dst=MEM */
+      Xin_Not32,     /* 32-bit not */
       Xin_Sh32,      /* 32-bit shift/rotate, dst=REG or MEM */
       Xin_Push,      /* push (32-bit?) value on stack */
       Xin_Call,      /* call to address in register */
-      Xin_GotoNZ,    /* conditional/unconditional jmp to dst */
+      Xin_Goto,      /* conditional/unconditional jmp to dst */
       Xin_CMovZ,     /* conditional move when Z flag set */
-      Xin_LoadEX     /* mov{s,z}{b,w}l from mem to reg */
+      Xin_LoadEX,    /* mov{s,z}{b,w}l from mem to reg */
+      Xin_Store      /* store 16/8 bit value in memory */
    }
    X86InstrTag;
 
@@ -215,6 +252,9 @@ typedef
             X86RI*    src;
             X86AMode* dst;
          } Alu32M;
+         struct {
+            X86RM* dst;
+         } Not32;
          struct {
             X86ShiftOp op;
             UInt       src;  /* shift amount, or 0 means %cl */
@@ -226,12 +266,12 @@ typedef
          struct {
             HReg target;
          } Call;
-         /* Pseudo-insn.  Goto dst, optionally only when Z flag is
-            clear. */
+         /* Pseudo-insn.  Goto dst, on given condition (which could be
+            Xcc_ALWAYS). */
          struct {
-            Bool   onlyWhenNZ;
-            X86RI* dst;
-         } GotoNZ;
+            X86CondCode cond;
+            X86RI*      dst;
+         } Goto;
          /* Mov src to dst (both 32-bit regs?) when the Z flag is
             set. */
          struct {
@@ -245,20 +285,28 @@ typedef
             X86AMode* src;
             HReg      dst;
          } LoadEX;
+         /* 16/8 bit stores, which are troublesome (particularly
+            8-bit) */
+         struct {
+            UChar sz; /* only 1 or 2 */
+            HReg src;
+            X86AMode* dst;
+         } Store;
       } Xin;
    }
    X86Instr;
 
 extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg );
 extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*,  X86AMode* );
+extern X86Instr* X86Instr_Not32  ( X86RM* dst );
 extern X86Instr* X86Instr_Sh32   ( X86ShiftOp, UInt, X86RM* );
 extern X86Instr* X86Instr_Push   ( X86RMI* );
 extern X86Instr* X86Instr_Call   ( HReg );
-extern X86Instr* X86Instr_GotoNZ ( Bool onlyWhenNZ, X86RI* dst );
+extern X86Instr* X86Instr_Goto   ( X86CondCode cond, X86RI* dst );
 extern X86Instr* X86Instr_CMovZ  ( X86RM* src, HReg dst );
 extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
                                    X86AMode* src, HReg dst );
-
+extern X86Instr* X86Instr_Store  ( UChar sz, HReg src, X86AMode* dst );
 
 extern void ppX86Instr ( X86Instr* );
 
index 69129a1049afaf7bafbe010ea083bc70c91f5d90..4c13ea66006136591695e9dbd592214e11f8aecc 100644 (file)
@@ -120,6 +120,9 @@ void ppIRExpr ( IRExpr* e )
 {
   Int i;
   switch (e->tag) {
+    case Iex_Binder:
+      vex_printf("BIND-%d", e->Iex.Binder.binder);
+      break;
     case Iex_Get:
       vex_printf( "GET(%d,", e->Iex.Get.offset);
       ppIRType(e->Iex.Get.ty);
@@ -294,6 +297,12 @@ IRConst* IRConst_U64 ( ULong u64 )
 
 /* Constructors -- IRExpr */
 
+IRExpr* IRExpr_Binder ( Int binder ) {
+   IRExpr* e            = LibVEX_Alloc(sizeof(IRExpr));
+   e->tag               = Iex_Binder;
+   e->Iex.Binder.binder = binder;
+   return e;
+}
 IRExpr* IRExpr_Get ( Int off, IRType ty ) {
    IRExpr* e         = LibVEX_Alloc(sizeof(IRExpr));
    e->tag            = Iex_Get;
@@ -566,6 +575,8 @@ IRType typeOfIRExpr ( IRTypeEnv* tyenv, IRExpr* e )
          return e->Iex.CCall.retty;
       case Iex_Mux0X:
          return typeOfIRExpr(tyenv, e->Iex.Mux0X.expr0);
+      case Iex_Binder:
+         vpanic("typeOfIRExpr: Binder is not a valid expression");
       default:
          ppIRExpr(e);
          vpanic("typeOfIRExpr");
index fe7b2a6cf93cb3540c9ebb2cb2a7ce6fee5d0d98..2baa40567f46d703778fa13c372ea89b272b5a96 100644 (file)
@@ -39,17 +39,19 @@ void LibVEX_Init (
 {
    vassert(!vex_initdone);
    vassert(failure_exit);
-   vex_failure_exit = failure_exit;
    vassert(log_bytes);
-   vex_log_bytes = log_bytes;
    vassert(debuglevel >= 0);
-   vex_debuglevel = debuglevel;
    vassert(verbosity >= 0);
-   vex_verbosity = verbosity;
-   vex_valgrind_support = valgrind_support;
    vassert(guest_insns_per_bb >= 1 && guest_insns_per_bb <= 100);
+
+   vex_failure_exit       = failure_exit;
+   vex_log_bytes          = log_bytes;
+   vex_debuglevel         = debuglevel;
+   vex_verbosity          = verbosity;
+   vex_valgrind_support   = valgrind_support;
    vex_guest_insns_per_bb = guest_insns_per_bb;
-   vex_initdone = True;
+   vex_initdone           = True;
+   LibVEX_SetAllocMode ( AllocModeTEMPORARY );
 }
 
 
@@ -80,15 +82,16 @@ TranslateResult LibVEX_Translate (
    /* Stuff we need to know for reg-alloc. */
    HReg* available_real_regs;
    Int   n_available_real_regs;
-   Bool (*isMove) (HInstr*, HReg*, HReg*);
-   void (*getRegUsage) (HRegUsage*, HInstr*);
-   void (*mapRegs) (HRegRemap*, HInstr*);
-   HInstr* (*genSpill) ( HReg, Int );
-   HInstr* (*genReload) ( HReg, Int );
-   void (*ppInstr) ( HInstr* );
-   void (*ppReg) ( HReg );
-   HInstrArray* (*iselBB) ( IRBB* );
-   IRBB* (*bbToIR) ( UChar*, Addr64, Int*, Bool(*)(Addr64), Bool );
+   Bool         (*isMove)      (HInstr*, HReg*, HReg*);
+   void         (*getRegUsage) (HRegUsage*, HInstr*);
+   void         (*mapRegs)     (HRegRemap*, HInstr*);
+   HInstr*      (*genSpill)    ( HReg, Int );
+   HInstr*      (*genReload)   ( HReg, Int );
+   void         (*ppInstr)     ( HInstr* );
+   void         (*ppReg)       ( HReg );
+   HInstrArray* (*iselBB)      ( IRBB* );
+   IRBB*        (*bbToIR)      ( UChar*, Addr64, Int*, 
+                                         Bool(*)(Addr64), Bool );
 
    Bool         host_is_bigendian = False;
    IRBB*        irbb;
@@ -97,7 +100,7 @@ TranslateResult LibVEX_Translate (
    Int          i;
 
    vassert(vex_initdone);
-   LibVEX_Clear(False);
+   LibVEX_ClearTemporary(False);
 
    /* First off, check that the guest and host insn sets
       are supported. */
@@ -135,7 +138,7 @@ TranslateResult LibVEX_Translate (
 
    if (irbb == NULL) {
       /* Access failure. */
-      LibVEX_Clear(False);
+      LibVEX_ClearTemporary(False);
       return TransAccessFail;
    }
    sanityCheckIRBB(irbb, Ity_I32);
@@ -146,7 +149,7 @@ TranslateResult LibVEX_Translate (
 
    /* Turn it into virtual-registerised code. */
    vcode = iselBB ( irbb );
-LibVEX_Clear(True); return TransOK;
+LibVEX_ClearTemporary(True); return TransOK;
 
    vex_printf("\n-------- Virtual registerised code --------\n");
    for (i = 0; i < vcode->arr_used; i++) {
@@ -170,7 +173,7 @@ LibVEX_Clear(True); return TransOK;
    vex_printf("\n");
 
    /* Assemble, etc. */
-   LibVEX_Clear(True);
+   LibVEX_ClearTemporary(True);
 
    return TransOK;
 }
index cfb2c5ec624a5762caa1e5328988ff8e9edc1b6b..98f41c30a0945a5b0647d9642ae8825e056ea55c 100644 (file)
    MByte/sec.  Once the size increases enough to fall out of the cache
    into memory, the rate falls by about a factor of 3. 
 */
-#define N_STORAGE_BYTES 50000
+#define N_TEMPORARY_BYTES 50000
+
+static Char temporary[N_TEMPORARY_BYTES];
+static Int  temporary_used = 0;
+
+#define N_PERMANENT_BYTES 1000
+
+static Char permanent[N_TEMPORARY_BYTES];
+static Int  permanent_used = 0;
 
-static Char storage[N_STORAGE_BYTES];
-static Int  storage_used = 0;
 
 /* Gather statistics. */
-static Int storage_bytes_allocd = 0;
-static Int storage_count_allocs = 0;
+static Int temporary_bytes_allocd = 0;
+static Int temporary_count_allocs = 0;
+
+static ULong temporary_bytes_allocd_TOT = 0;
+static ULong temporary_count_allocs_TOT = 0;
+
+/* The current allocation mode. */
+static AllocMode mode = AllocModeTEMPORARY;
+
+
+/* Exported to library client. */
 
-static ULong storage_bytes_allocd_TOT = 0;
-static ULong storage_count_allocs_TOT = 0;
+void LibVEX_SetAllocMode ( AllocMode m )
+{
+   mode = m;
+}
 
+/* Exported to library client. */
 
+AllocMode LibVEX_GetAllocMode ( void )
+{
+   return mode;
+}
 
 /* Exported to library client. */
 
@@ -51,32 +73,41 @@ void* LibVEX_Alloc ( Int nbytes )
    } else {
       if (nbytes == 0) nbytes = 8;
       nbytes = (nbytes + 7) & ~7;
-      if (storage_used + nbytes > N_STORAGE_BYTES)
-         vpanic("VEX storage exhausted.\n"
-                "Increase N_STORAGE_BYTES and recompile.");
-      storage_count_allocs++;
-      storage_bytes_allocd += nbytes;
-      storage_used += nbytes;
-      return (void*)(&storage[storage_used - nbytes]);
+      if (mode == AllocModeTEMPORARY) {
+         if (temporary_used + nbytes > N_TEMPORARY_BYTES)
+            vpanic("VEX temporary storage exhausted.\n"
+                   "Increase N_TEMPORARY_BYTES and recompile.");
+         temporary_count_allocs++;
+         temporary_bytes_allocd += nbytes;
+         temporary_used += nbytes;
+         return (void*)(&temporary[temporary_used - nbytes]);
+      } else {
+         if (permanent_used + nbytes > N_PERMANENT_BYTES)
+            vpanic("VEX permanent storage exhausted.\n"
+                   "Increase N_PERMANENT_BYTES and recompile.");
+         permanent_used += nbytes;
+         return (void*)(&permanent[permanent_used - nbytes]);
+      }
    }
 }
 
 /* Exported to library client. */
 
-void LibVEX_Clear ( Bool verb )
+void LibVEX_ClearTemporary ( Bool verb )
 {
    vassert(vex_initdone);
-   storage_bytes_allocd_TOT += (ULong)storage_bytes_allocd;
-   storage_count_allocs_TOT += (ULong)storage_count_allocs;
+   temporary_bytes_allocd_TOT += (ULong)temporary_bytes_allocd;
+   temporary_count_allocs_TOT += (ULong)temporary_count_allocs;
    if (verb) {
-      vex_printf("vex storage: total %lld (%lld), curr %d (%d)\n",
-                (Long)storage_bytes_allocd_TOT, 
-                 (Long)storage_count_allocs_TOT,
-                storage_bytes_allocd, storage_count_allocs );
+      vex_printf("vex storage:  P %d,  T total %lld (%lld),  T curr %d (%d)\n",
+                 permanent_used,
+                (Long)temporary_bytes_allocd_TOT, 
+                 (Long)temporary_count_allocs_TOT,
+                temporary_bytes_allocd, temporary_count_allocs );
    }
-   storage_used = 0;
-   storage_bytes_allocd = 0;
-   storage_count_allocs = 0;
+   temporary_used = 0;
+   temporary_bytes_allocd = 0;
+   temporary_count_allocs = 0;
 }
 
 
index c797f74ffbd125895a8c544b9e6e62d926d5110d..7468fa2b59d288480d4743f978237b3d89697508 100644 (file)
@@ -40,7 +40,18 @@ extern void LibVEX_Init (
 
 /* Storage management: clear the area, and allocate from it. */
 
-extern void LibVEX_Clear ( Bool show_stats );
+/* By default allocation occurs in the temporary area.  However, it is
+   possible to switch to permanent area allocation if that's what you
+   want.  Permanent area allocation is very limited, tho. */
+
+typedef
+   enum { AllocModeTEMPORARY, AllocModePERMANENT }
+   AllocMode;
+
+extern void      LibVEX_SetAllocMode ( AllocMode );
+extern AllocMode LibVEX_GetAllocMode ( void );
+
+extern void LibVEX_ClearTemporary ( Bool show_stats );
 
 extern void* LibVEX_Alloc ( Int nbytes );
 
index e8bc2137e7c9b3a01c8a4a607a5ed7e0594db9b2..44d6b9cc95a3aa6849f50f2ad8204cb3b17100f7 100644 (file)
@@ -121,7 +121,9 @@ data Expr
    | CONST Const           -- 8/16/32/64-bit int constant
 */
 typedef
-   enum { Iex_Get, Iex_Tmp, Iex_Binop, Iex_Unop, Iex_LDle, 
+     enum { Iex_Binder, /* Used only in pattern matching.  
+                           Not an expression. */
+          Iex_Get, Iex_Tmp, Iex_Binop, Iex_Unop, Iex_LDle, 
           Iex_Const, Iex_CCall, Iex_Mux0X }
    IRExprTag;
 
@@ -129,6 +131,9 @@ typedef
    struct _IRExpr {
       IRExprTag tag;
       union {
+        struct {
+            Int binder;
+         } Binder;
          struct {
             Int    offset;
             IRType ty;
@@ -166,14 +171,15 @@ typedef
    }
    IRExpr;
 
-extern IRExpr* IRExpr_Get   ( Int off, IRType ty );
-extern IRExpr* IRExpr_Tmp   ( IRTemp tmp );
-extern IRExpr* IRExpr_Binop ( IROp op, IRExpr* arg1, IRExpr* arg2 );
-extern IRExpr* IRExpr_Unop  ( IROp op, IRExpr* arg );
-extern IRExpr* IRExpr_LDle  ( IRType ty, IRExpr* addr );
-extern IRExpr* IRExpr_Const ( IRConst* con );
-extern IRExpr* IRExpr_CCall ( Char* name, IRType retty, IRExpr** args );
-extern IRExpr* IRExpr_Mux0X ( IRExpr* cond, IRExpr* expr0, IRExpr* exprX );
+extern IRExpr* IRExpr_Binder ( Int binder );
+extern IRExpr* IRExpr_Get    ( Int off, IRType ty );
+extern IRExpr* IRExpr_Tmp    ( IRTemp tmp );
+extern IRExpr* IRExpr_Binop  ( IROp op, IRExpr* arg1, IRExpr* arg2 );
+extern IRExpr* IRExpr_Unop   ( IROp op, IRExpr* arg );
+extern IRExpr* IRExpr_LDle   ( IRType ty, IRExpr* addr );
+extern IRExpr* IRExpr_Const  ( IRConst* con );
+extern IRExpr* IRExpr_CCall  ( Char* name, IRType retty, IRExpr** args );
+extern IRExpr* IRExpr_Mux0X  ( IRExpr* cond, IRExpr* expr0, IRExpr* exprX );
 
 extern void ppIRExpr ( IRExpr* );
 
@@ -224,7 +230,7 @@ typedef
             IRExpr* data;
          } STle;
          struct {
-            IRExpr* cond;
+            IRExpr*  cond;
             IRConst* dst;
          } Exit;
       } Ist;