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. */
}
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))) );
}
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);
#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 ---*/
/*---------------------------------------------------------*/
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);
*/
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 );
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;
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;
}
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:
break;
}
+ /* --------- GETs --------- */
case Iex_Get: {
if (ty == Ity_I32) {
HReg dst = newVRegI(env);
break;
}
+ /* --------- CCALLs --------- */
case Iex_CCall: {
Int i, nargs;
UInt target;
return hregX86_EAX();
}
+ /* --------- LITERALs --------- */
/* 32/16/8-bit literals */
case Iex_Const: {
X86RMI* rmi = iselIntExpr_RMI ( env, 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));
}
+/* 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 ---*/
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;
}
));
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;
}
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;
}
vex_printf("\n");
ri = iselIntExpr_RI(env, next);
- addInstr(env, X86Instr_GotoNZ(False,ri));
+ addInstr(env, X86Instr_Goto(Xcc_ALWAYS,ri));
}
}
+/* --------- 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 ) {
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;
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;
op->Xri.Imm.imm32 = imm32;
return op;
}
-
X86RI* X86RI_Reg ( HReg reg ) {
X86RI* op = LibVEX_Alloc(sizeof(X86RI));
op->tag = Xri_Reg;
op->Xrm.Reg.reg = reg;
return op;
}
-
X86RM* X86RM_Mem ( X86AMode* am ) {
X86RM* op = LibVEX_Alloc(sizeof(X86RM));
op->tag = Xrm_Mem;
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;
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;
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;
i->Xin.CMovZ.dst = dst;
return i;
}
-
X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
X86AMode* src, HReg dst ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
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 ) {
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 ");
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:
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");
}
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:
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);
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
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;
X86RI* src;
X86AMode* dst;
} Alu32M;
+ struct {
+ X86RM* dst;
+ } Not32;
struct {
X86ShiftOp op;
UInt src; /* shift amount, or 0 means %cl */
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 {
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* );
{
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);
/* 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;
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");
{
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 );
}
/* 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;
Int i;
vassert(vex_initdone);
- LibVEX_Clear(False);
+ LibVEX_ClearTemporary(False);
/* First off, check that the guest and host insn sets
are supported. */
if (irbb == NULL) {
/* Access failure. */
- LibVEX_Clear(False);
+ LibVEX_ClearTemporary(False);
return TransAccessFail;
}
sanityCheckIRBB(irbb, Ity_I32);
/* 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++) {
vex_printf("\n");
/* Assemble, etc. */
- LibVEX_Clear(True);
+ LibVEX_ClearTemporary(True);
return TransOK;
}
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. */
} 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;
}
/* 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 );
| 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;
struct _IRExpr {
IRExprTag tag;
union {
+ struct {
+ Int binder;
+ } Binder;
struct {
Int offset;
IRType ty;
}
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* );
IRExpr* data;
} STle;
struct {
- IRExpr* cond;
+ IRExpr* cond;
IRConst* dst;
} Exit;
} Ist;