|
From: <sv...@va...> - 2007-05-08 13:45:29
|
Author: sewardj
Date: 2007-05-08 14:45:27 +0100 (Tue, 08 May 2007)
New Revision: 1769
Log:
This commit provides a bunch of enhancements to the IR optimiser
(iropt) and to the various backend instruction selectors.
Unfortunately the changes are interrelated and cannot easily be
committed in pieces in any meaningful way. Between them and the
already-committed register allocation enhancements (r1765, r1767)
performance of Memcheck is improved by 0%-10%. Improvements are also
applicable to other tools to lesser extents.
Main changes are:
* Add new IR primops Iop_Left64/32/16/8 and Iop_CmpwNEZ64/32/16/8
which Memcheck uses to express some primitive operations on
definedness (V) bits:
Left(x) = set all bits to the left of the rightmost 1 bit to 1
CmpwNEZ(x) = if x == 0 then 0 else 0xFF...FF
Left and CmpwNEZ are detailed in the Usenix 2005 paper (in which
CmpwNEZ is called PCast). The new primops expose opportunities for
IR optimisation at tree-build time. Prior to this change Memcheck
expressed Left and CmpwNEZ in terms of lower level primitives
(logical or, negation, compares, various casts) which was simpler
but hindered further optimisation.
* Enhance the IR optimiser's tree builder so it can rewrite trees
as they are constructed, according to useful identities, for example:
CmpwNEZ64( Or64 ( CmpwNEZ64(x), y ) ) --> CmpwNEZ64( Or64( x, y ) )
which gets rid of a CmpwNEZ64 operation - a win as they are relatively
expensive. See functions fold_IRExpr_Binop and fold_IRExpr_Unop.
Allowing the tree builder to rewrite trees also makes it possible to
have a single implementation of certain transformation rules which
were previously duplicated in the x86, amd64 and ppc instruction
selectors. For example
32to1(1Uto32(x)) --> x
This simplifies the instruction selectors and gives a central place
to put such IR-level transformations, which is a Good Thing.
* Various minor refinements to the instruction selectors:
- ppc64 generates 32Sto64 into 1 instruction instead of 2
- x86 can now generate movsbl
- x86 handles 64-bit integer Mux0X better for cases typically
arising from Memchecking of FP code
- misc other patterns handled better
Overall these changes are a straight win - vex generates less code,
and does so a bit faster since its register allocator has to chew
through fewer instructions. The main risk is that of correctness:
making Left and CmpwNEZ explicit, and adding rewrite rules for them,
is a substantial change in the way Memcheck deals with undefined value
tracking, and I am concerned to ensure that the changes do not cause
false negatives. I _think_ it's all correct so far.
Modified:
branches/CGTUNE/priv/host-amd64/isel.c
branches/CGTUNE/priv/host-ppc/hdefs.c
branches/CGTUNE/priv/host-ppc/isel.c
branches/CGTUNE/priv/host-x86/hdefs.c
branches/CGTUNE/priv/host-x86/isel.c
branches/CGTUNE/priv/ir/irdefs.c
branches/CGTUNE/priv/ir/iropt.c
branches/CGTUNE/priv/main/vex_util.c
branches/CGTUNE/pub/libvex_ir.h
Modified: branches/CGTUNE/priv/host-amd64/isel.c
===================================================================
--- branches/CGTUNE/priv/host-amd64/isel.c 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/priv/host-amd64/isel.c 2007-05-08 13:45:27 UTC (rev 1769)
@@ -1460,6 +1460,43 @@
return dst;
}
+ case Iop_CmpwNEZ64: {
+ HReg dst = newVRegI(env);
+ HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVsd_RR(src,dst));
+ addInstr(env, AMD64Instr_Unary64(Aun_NEG,dst));
+ addInstr(env, AMD64Instr_Alu64R(Aalu_OR,
+ AMD64RMI_Reg(src), dst));
+ addInstr(env, AMD64Instr_Sh64(Ash_SAR, 63, dst));
+ return dst;
+ }
+
+ case Iop_CmpwNEZ32: {
+ HReg src = newVRegI(env);
+ HReg dst = newVRegI(env);
+ HReg pre = iselIntExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVsd_RR(pre,src));
+ addInstr(env, AMD64Instr_MovZLQ(src,src));
+ addInstr(env, mk_iMOVsd_RR(src,dst));
+ addInstr(env, AMD64Instr_Unary64(Aun_NEG,dst));
+ addInstr(env, AMD64Instr_Alu64R(Aalu_OR,
+ AMD64RMI_Reg(src), dst));
+ addInstr(env, AMD64Instr_Sh64(Ash_SAR, 63, dst));
+ return dst;
+ }
+
+ case Iop_Left8:
+ case Iop_Left16:
+ case Iop_Left32:
+ case Iop_Left64: {
+ HReg dst = newVRegI(env);
+ HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVsd_RR(src, dst));
+ addInstr(env, AMD64Instr_Unary64(Aun_NEG, dst));
+ addInstr(env, AMD64Instr_Alu64R(Aalu_OR, AMD64RMI_Reg(src), dst));
+ return dst;
+ }
+
case Iop_V128to32: {
HReg dst = newVRegI(env);
HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
@@ -1965,11 +2002,7 @@
static AMD64CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
{
MatchInfo mi;
-//.. DECLARE_PATTERN(p_1Uto32_then_32to1);
-//.. DECLARE_PATTERN(p_1Sto32_then_32to1);
- DECLARE_PATTERN(p_1Uto64_then_64to1);
-
vassert(e);
vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
@@ -2002,30 +2035,6 @@
/* --- patterns rooted at: 64to1 --- */
- /* 64to1(1Uto64(expr1)) ==> expr1 */
- DEFINE_PATTERN( p_1Uto64_then_64to1,
- unop(Iop_64to1, unop(Iop_1Uto64, bind(0))) );
- if (matchIRExpr(&mi,p_1Uto64_then_64to1,e)) {
- IRExpr* expr1 = mi.bindee[0];
- return iselCondCode(env, expr1);
- }
-
-//.. /* 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);
-//.. }
-//..
-//.. /* 32to1(1Sto32(expr1)) -- the casts are pointless, ignore them */
-//.. DEFINE_PATTERN(p_1Sto32_then_32to1,
-//.. unop(Iop_32to1,unop(Iop_1Sto32,bind(0))));
-//.. if (matchIRExpr(&mi,p_1Sto32_then_32to1,e)) {
-//.. IRExpr* expr1 = mi.bindee[0];
-//.. return iselCondCode(env, expr1);
-//.. }
-
/* 64to1 */
if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_64to1) {
HReg reg = iselIntExpr_R(env, e->Iex.Unop.arg);
@@ -2168,53 +2177,6 @@
}
}
-//.. /* CmpNE64(1Sto64(b), 0) ==> b */
-//.. {
-//.. DECLARE_PATTERN(p_CmpNE64_1Sto64);
-//.. DEFINE_PATTERN(
-//.. p_CmpNE64_1Sto64,
-//.. binop(Iop_CmpNE64, unop(Iop_1Sto64,bind(0)), mkU64(0)));
-//.. if (matchIRExpr(&mi, p_CmpNE64_1Sto64, e)) {
-//.. return iselCondCode(env, mi.bindee[0]);
-//.. }
-//.. }
-//..
-//.. /* CmpNE64(x, 0) */
-//.. {
-//.. DECLARE_PATTERN(p_CmpNE64_x_zero);
-//.. DEFINE_PATTERN(
-//.. p_CmpNE64_x_zero,
-//.. binop(Iop_CmpNE64, bind(0), mkU64(0)) );
-//.. if (matchIRExpr(&mi, p_CmpNE64_x_zero, e)) {
-//.. HReg hi, lo;
-//.. IRExpr* x = mi.bindee[0];
-//.. HReg tmp = newVRegI(env);
-//.. iselInt64Expr( &hi, &lo, env, x );
-//.. addInstr(env, mk_iMOVsd_RR(hi, tmp));
-//.. addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(lo), tmp));
-//.. return Xcc_NZ;
-//.. }
-//.. }
-//..
-//.. /* CmpNE64 */
-//.. if (e->tag == Iex_Binop
-//.. && e->Iex.Binop.op == Iop_CmpNE64) {
-//.. HReg hi1, hi2, lo1, lo2;
-//.. HReg tHi = newVRegI(env);
-//.. HReg tLo = newVRegI(env);
-//.. iselInt64Expr( &hi1, &lo1, env, e->Iex.Binop.arg1 );
-//.. iselInt64Expr( &hi2, &lo2, env, e->Iex.Binop.arg2 );
-//.. addInstr(env, mk_iMOVsd_RR(hi1, tHi));
-//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(hi2), tHi));
-//.. addInstr(env, mk_iMOVsd_RR(lo1, tLo));
-//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(lo2), tLo));
-//.. addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(tHi), tLo));
-//.. switch (e->Iex.Binop.op) {
-//.. case Iop_CmpNE64: return Xcc_NZ;
-//.. default: vpanic("iselCondCode(x86): CmpXX64");
-//.. }
-//.. }
-
ppIRExpr(e);
vpanic("iselCondCode(amd64)");
}
Modified: branches/CGTUNE/priv/host-ppc/hdefs.c
===================================================================
--- branches/CGTUNE/priv/host-ppc/hdefs.c 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/priv/host-ppc/hdefs.c 2007-05-08 13:45:27 UTC (rev 1769)
@@ -2706,7 +2706,13 @@
/* srawi (PPC32 p507) */
UInt n = srcR->Prh.Imm.imm16;
vassert(!srcR->Prh.Imm.syned);
- vassert(n > 0 && n < 32);
+ /* In 64-bit mode, we allow right shifts by zero bits
+ as that is a handy way to sign extend the lower 32
+ bits into the upper 32 bits. */
+ if (mode64)
+ vassert(n >= 0 && n < 32);
+ else
+ vassert(n > 0 && n < 32);
p = mkFormX(p, 31, r_srcL, r_dst, n, 824, 0);
} else {
/* sraw (PPC32 p506) */
Modified: branches/CGTUNE/priv/host-ppc/isel.c
===================================================================
--- branches/CGTUNE/priv/host-ppc/isel.c 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/priv/host-ppc/isel.c 2007-05-08 13:45:27 UTC (rev 1769)
@@ -1569,8 +1569,7 @@
return r_dst;
}
case Iop_8Sto64:
- case Iop_16Sto64:
- case Iop_32Sto64: {
+ case Iop_16Sto64: {
HReg r_dst = newVRegI(env);
HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
UShort amt = toUShort(op_unop==Iop_8Sto64 ? 56 :
@@ -1584,6 +1583,17 @@
r_dst, r_dst, PPCRH_Imm(False,amt)));
return r_dst;
}
+ case Iop_32Sto64: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ vassert(mode64);
+ /* According to the IBM docs, in 64 bit mode, srawi r,r,0
+ sign extends the lower 32 bits into the upper 32 bits. */
+ addInstr(env,
+ PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
+ r_dst, r_src, PPCRH_Imm(False,0)));
+ return r_dst;
+ }
case Iop_Not8:
case Iop_Not16:
case Iop_Not32:
@@ -1707,6 +1717,40 @@
return r_dst;
}
+ case Iop_Left8:
+ case Iop_Left32:
+ case Iop_Left64: {
+ HReg r_src, r_dst;
+ if (op_unop == Iop_Left64 && !mode64)
+ goto irreducible;
+ r_dst = newVRegI(env);
+ r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
+ addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
+ return r_dst;
+ }
+
+ case Iop_CmpwNEZ32: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
+ addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
+ addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
+ r_dst, r_dst, PPCRH_Imm(False, 31)));
+ return r_dst;
+ }
+
+ case Iop_CmpwNEZ64: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ if (!mode64) goto irreducible;
+ addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
+ addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
+ addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
+ r_dst, r_dst, PPCRH_Imm(False, 63)));
+ return r_dst;
+ }
+
case Iop_V128to32: {
HReg r_aligned16;
HReg dst = newVRegI(env);
@@ -2685,6 +2729,24 @@
if (e->tag == Iex_Unop) {
switch (e->Iex.Unop.op) {
+ /* CmpwNEZ64(e) */
+ case Iop_CmpwNEZ64: {
+ HReg argHi, argLo;
+ HReg tmp1 = newVRegI(env);
+ HReg tmp2 = newVRegI(env);
+ iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg);
+ /* tmp1 = argHi | argLo */
+ addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
+ /* tmp2 = (tmp1 | -tmp1) >>s 31 */
+ addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
+ addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
+ addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
+ tmp2, tmp2, PPCRH_Imm(False, 31)));
+ *rHi = tmp2;
+ *rLo = tmp2; /* yes, really tmp2 */
+ return;
+ }
+
/* 32Sto64(e) */
case Iop_32Sto64: {
HReg tHi = newVRegI(env);
Modified: branches/CGTUNE/priv/host-x86/hdefs.c
===================================================================
--- branches/CGTUNE/priv/host-x86/hdefs.c 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/priv/host-x86/hdefs.c 2007-05-08 13:45:27 UTC (rev 1769)
@@ -1612,7 +1612,7 @@
/* The given instruction reads the specified vreg exactly once, and
that vreg is currently located at the given spill offset. If
- possible, return a variant of the instruction which instead
+ possible, return a variant of the instruction to one which instead
references the spill slot directly. */
X86Instr* directReload_X86( X86Instr* i, HReg vreg, Short spill_off )
@@ -2407,6 +2407,13 @@
p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
goto done;
}
+ if (i->Xin.LoadEX.szSmall == 1 && i->Xin.LoadEX.syned) {
+ /* movsbl */
+ *p++ = 0x0F;
+ *p++ = 0xBE;
+ p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
+ goto done;
+ }
break;
case Xin_Set32:
Modified: branches/CGTUNE/priv/host-x86/isel.c
===================================================================
--- branches/CGTUNE/priv/host-x86/isel.c 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/priv/host-x86/isel.c 2007-05-08 13:45:27 UTC (rev 1769)
@@ -120,7 +120,14 @@
&& e->Iex.Const.con->Ico.U8 == 0;
}
+static Bool isZeroU64 ( IRExpr* e )
+{
+ return e->tag == Iex_Const
+ && e->Iex.Const.con->tag == Ico_U64
+ && e->Iex.Const.con->Ico.U64 == 0ULL;
+}
+
/*---------------------------------------------------------*/
/*--- ISelEnv ---*/
/*---------------------------------------------------------*/
@@ -730,7 +737,6 @@
static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
{
MatchInfo mi;
- DECLARE_PATTERN(p_32to1_then_1Uto8);
IRType ty = typeOfIRExpr(env->type_env,e);
vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
@@ -1011,21 +1017,53 @@
/* --------- UNARY OP --------- */
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_iMOVsd_RR(src,dst) );
- addInstr(env, X86Instr_Alu32R(Xalu_AND,
- X86RMI_Imm(1), dst));
- return dst;
+ if (e->Iex.Unop.op == Iop_1Uto8) {
+ DECLARE_PATTERN(p_32to1_then_1Uto8);
+ 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_iMOVsd_RR(src,dst) );
+ addInstr(env, X86Instr_Alu32R(Xalu_AND,
+ X86RMI_Imm(1), dst));
+ return dst;
+ }
}
+ /* 8Uto32(LDle(expr32)) */
+ if (e->Iex.Unop.op == Iop_8Uto32) {
+ DECLARE_PATTERN(p_LDle8_then_8Uto32);
+ DEFINE_PATTERN(p_LDle8_then_8Uto32,
+ unop(Iop_8Uto32,
+ IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
+ if (matchIRExpr(&mi,p_LDle8_then_8Uto32,e)) {
+ HReg dst = newVRegI(env);
+ X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
+ addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
+ return dst;
+ }
+ }
+
+ /* 8Sto32(LDle(expr32)) */
+ if (e->Iex.Unop.op == Iop_8Sto32) {
+ DECLARE_PATTERN(p_LDle8_then_8Sto32);
+ DEFINE_PATTERN(p_LDle8_then_8Sto32,
+ unop(Iop_8Sto32,
+ IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
+ if (matchIRExpr(&mi,p_LDle8_then_8Sto32,e)) {
+ HReg dst = newVRegI(env);
+ X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
+ addInstr(env, X86Instr_LoadEX(1,True,amode,dst));
+ return dst;
+ }
+ }
+
/* 16Uto32(LDle(expr32)) */
- {
+ if (e->Iex.Unop.op == Iop_16Uto32) {
DECLARE_PATTERN(p_LDle16_then_16Uto32);
DEFINE_PATTERN(p_LDle16_then_16Uto32,
unop(Iop_16Uto32,
@@ -1038,6 +1076,34 @@
}
}
+ /* 8Uto32(GET:I8) */
+ if (e->Iex.Unop.op == Iop_8Uto32) {
+ if (e->Iex.Unop.arg->tag == Iex_Get) {
+ HReg dst;
+ X86AMode* amode;
+ vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I8);
+ dst = newVRegI(env);
+ amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
+ hregX86_EBP());
+ addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
+ return dst;
+ }
+ }
+
+ /* 16to32(GET:I16) */
+ if (e->Iex.Unop.op == Iop_16Uto32) {
+ if (e->Iex.Unop.arg->tag == Iex_Get) {
+ HReg dst;
+ X86AMode* amode;
+ vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I16);
+ dst = newVRegI(env);
+ amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
+ hregX86_EBP());
+ addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
+ return dst;
+ }
+ }
+
switch (e->Iex.Unop.op) {
case Iop_8Uto16:
case Iop_8Uto32:
@@ -1138,6 +1204,27 @@
return dst;
}
+ case Iop_CmpwNEZ32: {
+ HReg dst = newVRegI(env);
+ HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVsd_RR(src,dst));
+ addInstr(env, X86Instr_Unary32(Xun_NEG,dst));
+ addInstr(env, X86Instr_Alu32R(Xalu_OR,
+ X86RMI_Reg(src), dst));
+ addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, dst));
+ return dst;
+ }
+ case Iop_Left8:
+ case Iop_Left16:
+ case Iop_Left32: {
+ HReg dst = newVRegI(env);
+ HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVsd_RR(src, dst));
+ addInstr(env, X86Instr_Unary32(Xun_NEG, dst));
+ addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(src), dst));
+ return dst;
+ }
+
case Iop_V128to32: {
HReg dst = newVRegI(env);
HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
@@ -1547,9 +1634,6 @@
static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
{
MatchInfo mi;
- DECLARE_PATTERN(p_32to1);
- DECLARE_PATTERN(p_1Uto32_then_32to1);
- DECLARE_PATTERN(p_1Sto32_then_32to1);
vassert(e);
vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
@@ -1582,28 +1666,9 @@
/* --- patterns rooted at: 32to1 --- */
- /* 32to1(1Uto32(e)) ==> e */
- 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);
- }
-
- /* 32to1(1Sto32(e)) ==> e */
- DEFINE_PATTERN(p_1Sto32_then_32to1,
- unop(Iop_32to1,unop(Iop_1Sto32,bind(0))));
- if (matchIRExpr(&mi,p_1Sto32_then_32to1,e)) {
- IRExpr* expr1 = mi.bindee[0];
- return iselCondCode(env, expr1);
- }
-
- /* 32to1(expr32) */
- DEFINE_PATTERN(p_32to1,
- unop(Iop_32to1,bind(0))
- );
- if (matchIRExpr(&mi,p_32to1,e)) {
- X86RM* rm = iselIntExpr_RM(env, mi.bindee[0]);
+ if (e->tag == Iex_Unop
+ && e->Iex.Unop.op == Iop_32to1) {
+ X86RM* rm = iselIntExpr_RM(env, e->Iex.Unop.arg);
addInstr(env, X86Instr_Test32(1,rm));
return Xcc_NZ;
}
@@ -1630,16 +1695,6 @@
/* --- patterns rooted at: CmpNEZ32 --- */
- /* CmpNEZ32(1Sto32(b)) ==> b */
- {
- DECLARE_PATTERN(p_CmpNEZ32_1Sto32);
- DEFINE_PATTERN(p_CmpNEZ32_1Sto32,
- unop(Iop_CmpNEZ32, unop(Iop_1Sto32,bind(0))));
- if (matchIRExpr(&mi, p_CmpNEZ32_1Sto32, e)) {
- return iselCondCode(env, mi.bindee[0]);
- }
- }
-
/* CmpNEZ32(And32(x,y)) */
{
DECLARE_PATTERN(p_CmpNEZ32_And32);
@@ -1670,6 +1725,16 @@
}
}
+ /* CmpNEZ32(GET(..):I32) */
+ if (e->tag == Iex_Unop
+ && e->Iex.Unop.op == Iop_CmpNEZ32
+ && e->Iex.Unop.arg->tag == Iex_Get) {
+ X86AMode* am = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
+ hregX86_EBP());
+ addInstr(env, X86Instr_Alu32M(Xalu_CMP, X86RI_Imm(0), am));
+ return Xcc_NZ;
+ }
+
/* CmpNEZ32(x) */
if (e->tag == Iex_Unop
&& e->Iex.Unop.op == Iop_CmpNEZ32) {
@@ -1681,17 +1746,6 @@
/* --- patterns rooted at: CmpNEZ64 --- */
- /* CmpNEZ64(1Sto64(b)) ==> b */
- {
- DECLARE_PATTERN(p_CmpNEZ64_1Sto64);
- DEFINE_PATTERN(
- p_CmpNEZ64_1Sto64,
- unop(Iop_CmpNEZ64, unop(Iop_1Sto64,bind(0))));
- if (matchIRExpr(&mi, p_CmpNEZ64_1Sto64, e)) {
- return iselCondCode(env, mi.bindee[0]);
- }
- }
-
/* CmpNEZ64(Or64(x,y)) */
{
DECLARE_PATTERN(p_CmpNEZ64_Or64);
@@ -1839,6 +1893,7 @@
/* DO NOT CALL THIS DIRECTLY ! */
static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
{
+ MatchInfo mi;
HWord fn = 0; /* helper fn for most SIMD64 stuff */
vassert(e);
vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
@@ -1915,18 +1970,59 @@
return;
}
- /* 64-bit Mux0X */
+ /* 64-bit Mux0X: Mux0X(g, expr, 0:I64) */
+ if (e->tag == Iex_Mux0X && isZeroU64(e->Iex.Mux0X.exprX)) {
+ X86RM* r8;
+ HReg e0Lo, e0Hi;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
+ iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0);
+ r8 = iselIntExpr_RM(env, e->Iex.Mux0X.cond);
+ addInstr(env, mk_iMOVsd_RR( e0Hi, tHi ) );
+ addInstr(env, mk_iMOVsd_RR( e0Lo, tLo ) );
+ addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
+ addInstr(env, X86Instr_Test32(0xFF, r8));
+ addInstr(env, X86Instr_CMov32(Xcc_NZ,X86RM_Mem(zero_esp),tHi));
+ addInstr(env, X86Instr_CMov32(Xcc_NZ,X86RM_Mem(zero_esp),tLo));
+ add_to_esp(env, 4);
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+ /* 64-bit Mux0X: Mux0X(g, 0:I64, expr) */
+ if (e->tag == Iex_Mux0X && isZeroU64(e->Iex.Mux0X.expr0)) {
+ X86RM* r8;
+ HReg e0Lo, e0Hi;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
+ iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.exprX);
+ r8 = iselIntExpr_RM(env, e->Iex.Mux0X.cond);
+ addInstr(env, mk_iMOVsd_RR( e0Hi, tHi ) );
+ addInstr(env, mk_iMOVsd_RR( e0Lo, tLo ) );
+ addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
+ addInstr(env, X86Instr_Test32(0xFF, r8));
+ addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Mem(zero_esp),tHi));
+ addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Mem(zero_esp),tLo));
+ add_to_esp(env, 4);
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ /* 64-bit Mux0X: Mux0X(g, expr, expr) */
if (e->tag == Iex_Mux0X) {
- X86RM* rm8;
- HReg e0Lo, e0Hi, eXLo, eXHi;
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
+ X86RM* r8;
+ HReg e0Lo, e0Hi, eXLo, eXHi;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0);
iselInt64Expr(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX);
addInstr(env, mk_iMOVsd_RR(eXHi, tHi));
addInstr(env, mk_iMOVsd_RR(eXLo, tLo));
- rm8 = iselIntExpr_RM(env, e->Iex.Mux0X.cond);
- addInstr(env, X86Instr_Test32(0xFF, rm8));
+ r8 = iselIntExpr_RM(env, e->Iex.Mux0X.cond);
+ addInstr(env, X86Instr_Test32(0xFF, r8));
/* This assumes the first cmov32 doesn't trash the condition
codes, so they are still available for the second cmov32 */
addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Reg(e0Hi),tHi));
@@ -1992,10 +2088,10 @@
: e->Iex.Binop.op==Iop_And64 ? Xalu_AND
: Xalu_XOR;
iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
+ iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
addInstr(env, mk_iMOVsd_RR(xHi, tHi));
+ addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yHi), tHi));
addInstr(env, mk_iMOVsd_RR(xLo, tLo));
- iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
- addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yHi), tHi));
addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yLo), tLo));
*rHi = tHi;
*rLo = tLo;
@@ -2416,6 +2512,65 @@
return;
}
+ /* --- patterns rooted at: CmpwNEZ64 --- */
+
+ /* CmpwNEZ64(e) */
+ case Iop_CmpwNEZ64: {
+
+ DECLARE_PATTERN(p_CmpwNEZ64_Or64);
+ DEFINE_PATTERN(p_CmpwNEZ64_Or64,
+ unop(Iop_CmpwNEZ64,binop(Iop_Or64,bind(0),bind(1))));
+ if (matchIRExpr(&mi, p_CmpwNEZ64_Or64, e)) {
+ /* CmpwNEZ64(Or64(x,y)) */
+ HReg xHi,xLo,yHi,yLo;
+ HReg xBoth = newVRegI(env);
+ HReg merged = newVRegI(env);
+ HReg tmp2 = newVRegI(env);
+
+ iselInt64Expr(&xHi,&xLo, env, mi.bindee[0]);
+ addInstr(env, mk_iMOVsd_RR(xHi,xBoth));
+ addInstr(env, X86Instr_Alu32R(Xalu_OR,
+ X86RMI_Reg(xLo),xBoth));
+
+ iselInt64Expr(&yHi,&yLo, env, mi.bindee[1]);
+ addInstr(env, mk_iMOVsd_RR(yHi,merged));
+ addInstr(env, X86Instr_Alu32R(Xalu_OR,
+ X86RMI_Reg(yLo),merged));
+ addInstr(env, X86Instr_Alu32R(Xalu_OR,
+ X86RMI_Reg(xBoth),merged));
+
+ /* tmp2 = (merged | -merged) >>s 31 */
+ addInstr(env, mk_iMOVsd_RR(merged,tmp2));
+ addInstr(env, X86Instr_Unary32(Xun_NEG,tmp2));
+ addInstr(env, X86Instr_Alu32R(Xalu_OR,
+ X86RMI_Reg(merged), tmp2));
+ addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, tmp2));
+ *rHi = tmp2;
+ *rLo = tmp2;
+ return;
+ } else {
+ /* CmpwNEZ64(e) */
+ HReg srcLo, srcHi;
+ HReg tmp1 = newVRegI(env);
+ HReg tmp2 = newVRegI(env);
+ /* srcHi:srcLo = arg */
+ iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
+ /* tmp1 = srcHi | srcLo */
+ addInstr(env, mk_iMOVsd_RR(srcHi,tmp1));
+ addInstr(env, X86Instr_Alu32R(Xalu_OR,
+ X86RMI_Reg(srcLo), tmp1));
+ /* tmp2 = (tmp1 | -tmp1) >>s 31 */
+ addInstr(env, mk_iMOVsd_RR(tmp1,tmp2));
+ addInstr(env, X86Instr_Unary32(Xun_NEG,tmp2));
+ addInstr(env, X86Instr_Alu32R(Xalu_OR,
+ X86RMI_Reg(tmp1), tmp2));
+ addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, tmp2));
+ *rHi = tmp2;
+ *rLo = tmp2;
+ return;
+ }
+ }
+
/* ReinterpF64asI64(e) */
/* Given an IEEE754 double, produce an I64 with the same bit
pattern. */
@@ -2829,12 +2984,12 @@
if (e->tag == Iex_Mux0X) {
if (ty == Ity_F64
&& typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
- X86RM* rm8 = iselIntExpr_RM(env, e->Iex.Mux0X.cond);
- HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX);
- HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
- HReg dst = newVRegF(env);
+ X86RM* r8 = iselIntExpr_RM(env, e->Iex.Mux0X.cond);
+ HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX);
+ HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
+ HReg dst = newVRegF(env);
addInstr(env, X86Instr_FpUnary(Xfp_MOV,rX,dst));
- addInstr(env, X86Instr_Test32(0xFF, rm8));
+ addInstr(env, X86Instr_Test32(0xFF, r8));
addInstr(env, X86Instr_FpCMov(Xcc_Z,r0,dst));
return dst;
}
@@ -3350,12 +3505,12 @@
} /* if (e->tag == Iex_Binop) */
if (e->tag == Iex_Mux0X) {
- X86RM* rm8 = iselIntExpr_RM(env, e->Iex.Mux0X.cond);
- HReg rX = iselVecExpr(env, e->Iex.Mux0X.exprX);
- HReg r0 = iselVecExpr(env, e->Iex.Mux0X.expr0);
- HReg dst = newVRegV(env);
+ X86RM* r8 = iselIntExpr_RM(env, e->Iex.Mux0X.cond);
+ HReg rX = iselVecExpr(env, e->Iex.Mux0X.exprX);
+ HReg r0 = iselVecExpr(env, e->Iex.Mux0X.expr0);
+ HReg dst = newVRegV(env);
addInstr(env, mk_vMOVsd_RR(rX,dst));
- addInstr(env, X86Instr_Test32(0xFF, rm8));
+ addInstr(env, X86Instr_Test32(0xFF, r8));
addInstr(env, X86Instr_SseCMov(Xcc_Z,r0,dst));
return dst;
}
Modified: branches/CGTUNE/priv/ir/irdefs.c
===================================================================
--- branches/CGTUNE/priv/ir/irdefs.c 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/priv/ir/irdefs.c 2007-05-08 13:45:27 UTC (rev 1769)
@@ -203,6 +203,14 @@
case Iop_CmpNEZ32: vex_printf("CmpNEZ32"); return;
case Iop_CmpNEZ64: vex_printf("CmpNEZ64"); return;
+ case Iop_CmpwNEZ32: vex_printf("CmpwNEZ32"); return;
+ case Iop_CmpwNEZ64: vex_printf("CmpwNEZ64"); return;
+
+ case Iop_Left8: vex_printf("Left8"); return;
+ case Iop_Left16: vex_printf("Left16"); return;
+ case Iop_Left32: vex_printf("Left32"); return;
+ case Iop_Left64: vex_printf("Left64"); return;
+
case Iop_CmpORD32U: vex_printf("CmpORD32U"); return;
case Iop_CmpORD32S: vex_printf("CmpORD32S"); return;
@@ -1547,6 +1555,11 @@
case Iop_CmpNEZ32: UNARY_COMPARISON(Ity_I32);
case Iop_CmpNEZ64: UNARY_COMPARISON(Ity_I64);
+ case Iop_Left8: UNARY(Ity_I8, Ity_I8);
+ case Iop_Left16: UNARY(Ity_I16,Ity_I16);
+ case Iop_CmpwNEZ32: case Iop_Left32: UNARY(Ity_I32,Ity_I32);
+ case Iop_CmpwNEZ64: case Iop_Left64: UNARY(Ity_I64,Ity_I64);
+
case Iop_MullU8: case Iop_MullS8:
BINARY(Ity_I8,Ity_I8, Ity_I16);
case Iop_MullU16: case Iop_MullS16:
Modified: branches/CGTUNE/priv/ir/iropt.c
===================================================================
--- branches/CGTUNE/priv/ir/iropt.c 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/priv/ir/iropt.c 2007-05-08 13:45:27 UTC (rev 1769)
@@ -1072,6 +1072,39 @@
)));
break;
+ case Iop_CmpwNEZ32: {
+ UInt w32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
+ if (w32 == 0)
+ e2 = IRExpr_Const(IRConst_U32( 0 ));
+ else
+ e2 = IRExpr_Const(IRConst_U32( 0xFFFFFFFF ));
+ break;
+ }
+ case Iop_CmpwNEZ64: {
+ ULong w64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
+ if (w64 == 0)
+ e2 = IRExpr_Const(IRConst_U64( 0 ));
+ else
+ e2 = IRExpr_Const(IRConst_U64( 0xFFFFFFFFFFFFFFFFULL ));
+ break;
+ }
+
+ case Iop_Left32: {
+ UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
+ Int s32 = (Int)(u32 & 0xFFFFFFFF);
+ s32 = (s32 | (-s32));
+ e2 = IRExpr_Const( IRConst_U32( (UInt)s32 ));
+ break;
+ }
+
+ case Iop_Left64: {
+ ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
+ Long s64 = (Long)u64;
+ s64 = (s64 | (-s64));
+ e2 = IRExpr_Const( IRConst_U64( (ULong)s64 ));
+ break;
+ }
+
default:
goto unhandled;
}
@@ -1465,13 +1498,20 @@
e2 = IRExpr_Const(IRConst_U32(0));
} else
- /* And32(0,x) ==> 0 */
- if (e->Iex.Binop.op == Iop_And32
+ /* And32/Shl32(0,x) ==> 0 */
+ if ((e->Iex.Binop.op == Iop_And32 || e->Iex.Binop.op == Iop_Shl32)
&& e->Iex.Binop.arg1->tag == Iex_Const
&& e->Iex.Binop.arg1->Iex.Const.con->Ico.U32 == 0) {
e2 = IRExpr_Const(IRConst_U32(0));
} else
+ /* Or8(0,x) ==> x */
+ if (e->Iex.Binop.op == Iop_Or8
+ && e->Iex.Binop.arg1->tag == Iex_Const
+ && e->Iex.Binop.arg1->Iex.Const.con->Ico.U8 == 0) {
+ e2 = e->Iex.Binop.arg2;
+ } else
+
/* Or32(0,x) ==> x */
if (e->Iex.Binop.op == Iop_Or32
&& e->Iex.Binop.arg1->tag == Iex_Const
@@ -3698,6 +3738,94 @@
'single-shot', so once a binding is used, it is marked as no longer
available, by setting its .bindee field to NULL. */
+static inline Bool is_Unop ( IRExpr* e, IROp op ) {
+ return e->tag == Iex_Unop && e->Iex.Unop.op == op;
+}
+static inline Bool is_Binop ( IRExpr* e, IROp op ) {
+ return e->tag == Iex_Binop && e->Iex.Binop.op == op;
+}
+
+static IRExpr* fold_IRExpr_Binop ( IROp op, IRExpr* a1, IRExpr* a2 )
+{
+ switch (op) {
+ case Iop_Or32:
+ /* Or32( CmpwNEZ32(x), CmpwNEZ32(y) ) --> CmpwNEZ32( Or32( x, y ) ) */
+ if (is_Unop(a1, Iop_CmpwNEZ32) && is_Unop(a2, Iop_CmpwNEZ32))
+ return IRExpr_Unop( Iop_CmpwNEZ32,
+ IRExpr_Binop( Iop_Or32, a1->Iex.Unop.arg,
+ a2->Iex.Unop.arg ) );
+ break;
+ default:
+ break;
+ }
+ /* no reduction rule applies */
+ return IRExpr_Binop( op, a1, a2 );
+}
+
+static IRExpr* fold_IRExpr_Unop ( IROp op, IRExpr* aa )
+{
+ switch (op) {
+ case Iop_CmpwNEZ64:
+ /* CmpwNEZ64( Or64 ( CmpwNEZ64(x), y ) ) --> CmpwNEZ64( Or64( x, y ) ) */
+ if (is_Binop(aa, Iop_Or64)
+ && is_Unop(aa->Iex.Binop.arg1, Iop_CmpwNEZ64))
+ return fold_IRExpr_Unop(
+ Iop_CmpwNEZ64,
+ IRExpr_Binop(Iop_Or64,
+ aa->Iex.Binop.arg1->Iex.Unop.arg,
+ aa->Iex.Binop.arg2));
+ /* CmpwNEZ64( Or64 ( x, CmpwNEZ64(y) ) ) --> CmpwNEZ64( Or64( x, y ) ) */
+ if (is_Binop(aa, Iop_Or64)
+ && is_Unop(aa->Iex.Binop.arg2, Iop_CmpwNEZ64))
+ return fold_IRExpr_Unop(
+ Iop_CmpwNEZ64,
+ IRExpr_Binop(Iop_Or64,
+ aa->Iex.Binop.arg1,
+ aa->Iex.Binop.arg2->Iex.Unop.arg));
+ break;
+ case Iop_CmpNEZ64:
+ /* CmpNEZ64( Left64(x) ) --> CmpNEZ64(x) */
+ if (is_Unop(aa, Iop_Left64))
+ return IRExpr_Unop(Iop_CmpNEZ64, aa->Iex.Unop.arg);
+ break;
+ case Iop_CmpwNEZ32:
+ /* CmpwNEZ32( CmpwNEZ32 ( x ) ) --> CmpwNEZ32 ( x ) */
+ if (is_Unop(aa, Iop_CmpwNEZ32))
+ return IRExpr_Unop( Iop_CmpwNEZ32, aa->Iex.Unop.arg );
+ break;
+ case Iop_CmpNEZ32:
+ /* CmpNEZ32( Left32(x) ) --> CmpNEZ32(x) */
+ if (is_Unop(aa, Iop_Left32))
+ return IRExpr_Unop(Iop_CmpNEZ32, aa->Iex.Unop.arg);
+ break;
+ case Iop_Left32:
+ /* Left32( Left32(x) ) --> Left32(x) */
+ if (is_Unop(aa, Iop_Left32))
+ return IRExpr_Unop( Iop_Left32, aa->Iex.Unop.arg );
+ break;
+ case Iop_32to1:
+ /* 32to1( 1Uto32 ( x ) ) --> x */
+ if (is_Unop(aa, Iop_1Uto32))
+ return aa->Iex.Unop.arg;
+ /* 32to1( CmpwNEZ32 ( x )) --> CmpNEZ32(x) */
+ if (is_Unop(aa, Iop_CmpwNEZ32))
+ return IRExpr_Unop( Iop_CmpNEZ32, aa->Iex.Unop.arg );
+ break;
+ case Iop_64to1:
+ /* 64to1( 1Uto64 ( x ) ) --> x */
+ if (is_Unop(aa, Iop_1Uto64))
+ return aa->Iex.Unop.arg;
+ /* 64to1( CmpwNEZ64 ( x )) --> CmpNEZ64(x) */
+ if (is_Unop(aa, Iop_CmpwNEZ64))
+ return IRExpr_Unop( Iop_CmpNEZ64, aa->Iex.Unop.arg );
+ break;
+ default:
+ break;
+ }
+ /* no reduction rule applies */
+ return IRExpr_Unop( op, aa );
+}
+
static IRExpr* atbSubst_Expr ( ATmpInfo* env, IRExpr* e )
{
IRExpr* e2;
@@ -3740,13 +3868,13 @@
atbSubst_Expr(env, e->Iex.Triop.arg3)
);
case Iex_Binop:
- return IRExpr_Binop(
+ return fold_IRExpr_Binop(
e->Iex.Binop.op,
atbSubst_Expr(env, e->Iex.Binop.arg1),
atbSubst_Expr(env, e->Iex.Binop.arg2)
);
case Iex_Unop:
- return IRExpr_Unop(
+ return fold_IRExpr_Unop(
e->Iex.Unop.op,
atbSubst_Expr(env, e->Iex.Unop.arg)
);
Modified: branches/CGTUNE/priv/main/vex_util.c
===================================================================
--- branches/CGTUNE/priv/main/vex_util.c 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/priv/main/vex_util.c 2007-05-08 13:45:27 UTC (rev 1769)
@@ -441,6 +441,10 @@
PAD(len1); PUT('0'); PUT('x'); PUTSTR(intbuf); PAD(len3);
break;
}
+ case '%': {
+ PUT('%');
+ break;
+ }
default:
/* no idea what it is. Print the format literally and
move on. */
Modified: branches/CGTUNE/pub/libvex_ir.h
===================================================================
--- branches/CGTUNE/pub/libvex_ir.h 2007-05-07 18:36:48 UTC (rev 1768)
+++ branches/CGTUNE/pub/libvex_ir.h 2007-05-08 13:45:27 UTC (rev 1769)
@@ -445,6 +445,8 @@
/* As a sop to Valgrind-Memcheck, the following are useful. */
Iop_CmpNEZ8, Iop_CmpNEZ16, Iop_CmpNEZ32, Iop_CmpNEZ64,
+ Iop_CmpwNEZ32, Iop_CmpwNEZ64, /* all-0s -> all-Os; other -> all-1s */
+ Iop_Left8, Iop_Left16, Iop_Left32, Iop_Left64, /* \x -> x | -x */
/* PowerPC-style 3-way integer comparisons. Without them it is
difficult to simulate PPC efficiently.
|