|
From: <sv...@va...> - 2012-11-25 15:14:52
|
sewardj 2012-11-25 15:14:44 +0000 (Sun, 25 Nov 2012)
New Revision: 2570
Log:
Add IR level definitions and associated iropt hackery, to support
direct representation of conditional (guarded) loads and stores in IR.
Modified files:
branches/COMEM/priv/ir_defs.c
branches/COMEM/priv/ir_opt.c
branches/COMEM/pub/libvex_ir.h
Modified: branches/COMEM/pub/libvex_ir.h (+138 -25)
===================================================================
--- branches/COMEM/pub/libvex_ir.h 2012-11-25 12:48:39 +00:00 (rev 2569)
+++ branches/COMEM/pub/libvex_ir.h 2012-11-25 15:14:44 +00:00 (rev 2570)
@@ -218,7 +218,7 @@
float, or a vector (SIMD) value. */
typedef
enum {
- Ity_INVALID=0x11000,
+ Ity_INVALID=0x1100,
Ity_I1,
Ity_I8,
Ity_I16,
@@ -248,7 +248,7 @@
/* IREndness is used in load IRExprs and store IRStmts. */
typedef
enum {
- Iend_LE=0x12000, /* little endian */
+ Iend_LE=0x1200, /* little endian */
Iend_BE /* big endian */
}
IREndness;
@@ -261,7 +261,7 @@
/* The various kinds of constant. */
typedef
enum {
- Ico_U1=0x13000,
+ Ico_U1=0x1300,
Ico_U8,
Ico_U16,
Ico_U32,
@@ -412,7 +412,7 @@
/* -- Do not change this ordering. The IR generators rely on
(eg) Iop_Add64 == IopAdd8 + 3. -- */
- Iop_INVALID=0x14000,
+ Iop_INVALID=0x1400,
Iop_Add8, Iop_Add16, Iop_Add32, Iop_Add64,
Iop_Sub8, Iop_Sub16, Iop_Sub32, Iop_Sub64,
/* Signless mul. MullS/MullU is elsewhere. */
@@ -1543,7 +1543,7 @@
in the comments for IRExpr. */
typedef
enum {
- Iex_Binder=0x15000,
+ Iex_Binder=0x1900,
Iex_Get,
Iex_GetI,
Iex_RdTmp,
@@ -1752,7 +1752,7 @@
} Iex;
};
-/* ------------------ A ternary expression ---------------------- */
+/* Expression auxiliaries: a ternary expression. */
struct _IRTriop {
IROp op; /* op-code */
IRExpr* arg1; /* operand 1 */
@@ -1760,7 +1760,7 @@
IRExpr* arg3; /* operand 3 */
};
-/* ------------------ A quarternary expression ------------------ */
+/* Expression auxiliaries: a quarternary expression. */
struct _IRQop {
IROp op; /* op-code */
IRExpr* arg1; /* operand 1 */
@@ -1865,7 +1865,7 @@
*/
typedef
enum {
- Ijk_INVALID=0x16000,
+ Ijk_INVALID=0x1A00,
Ijk_Boring, /* not interesting; just goto next */
Ijk_Call, /* guest is doing a call */
Ijk_Ret, /* guest is doing a return */
@@ -1912,19 +1912,21 @@
Dirty calls are statements rather than expressions for obvious
reasons. If a dirty call is marked as writing guest state, any
- values derived from the written parts of the guest state are
- invalid. Similarly, if the dirty call is stated as writing
- memory, any loaded values are invalidated by it.
+ pre-existing values derived from the written parts of the guest
+ state are invalid. Similarly, if the dirty call is stated as
+ writing memory, any pre-existing loaded values are invalidated by
+ it.
In order that instrumentation is possible, the call must state, and
state correctly:
- * whether it reads, writes or modifies memory, and if so where
- (only one chunk can be stated)
+ * whether it reads, writes or modifies memory, and if so where Only
+ one chunk can be stated, although it is allowed to repeat some
+ number of times at a fixed interval.
* whether it reads, writes or modifies guest state, and if so which
- pieces (several pieces may be stated, and currently their extents
- must be known at translation-time).
+ pieces. Several pieces may be stated, and their extents must be
+ known at translation-time.
Normally, code is generated to pass just the args to the helper.
However, if .needsBBP is set, then an extra first argument is
@@ -1934,9 +1936,11 @@
call does not access guest state.
IMPORTANT NOTE re GUARDS: Dirty calls are strict, very strict. The
- arguments are evaluated REGARDLESS of the guard value. The order of
- argument evaluation is unspecified. The guard expression is evaluated
- AFTER the arguments have been evaluated.
+ arguments, and 'mFx' are evaluated REGARDLESS of the guard value.
+ The order of argument evaluation is unspecified. The guard
+ expression is evaluated AFTER the arguments and 'mFx' have been
+ evaluated. 'mFx' is expected (by Memcheck) to be a defined value
+ even if the guard evaluates to false.
*/
#define VEX_N_FXSTATE 7 /* enough for FXSAVE/FXRSTOR on x86 */
@@ -1944,7 +1948,7 @@
/* Effects on resources (eg. registers, memory locations) */
typedef
enum {
- Ifx_None = 0x1700, /* no effect */
+ Ifx_None=0x1B00, /* no effect */
Ifx_Read, /* reads the resource */
Ifx_Write, /* writes the resource */
Ifx_Modify, /* modifies the resource */
@@ -1958,10 +1962,10 @@
typedef
struct _IRDirty {
/* What to call, and details of args/results. .guard must be
- non-NULL. If .tmp is not IRTemp_INVALID (that is, the call
- returns a result) then .guard must be demonstrably (at
- JIT-time) always true, that is, the call must be
- unconditional. Conditional calls that assign .tmp are not
+ non-NULL. If .tmp is not IRTemp_INVALID, then the call
+ returns a result which is placed in .tmp. If at runtime the
+ guard evaluates to false, .tmp has an all-ones bit pattern
+ written to it. Hence conditional calls that assign .tmp are
allowed. */
IRCallee* cee; /* where to call */
IRExpr* guard; /* :: Ity_Bit. Controls whether call happens */
@@ -2031,7 +2035,7 @@
typedef
enum {
- Imbe_Fence=0x18000,
+ Imbe_Fence=0x1C00,
/* Needed only on ARM. It cancels a reservation made by a
preceding Linked-Load, and needs to be handed through to the
back end, just as LL and SC themselves are. */
@@ -2131,6 +2135,7 @@
/* ------------------ Circular Array Put ------------------ */
+
typedef
struct {
IRRegArray* descr; /* Part of guest state treated as circular */
@@ -2147,6 +2152,85 @@
extern IRPutI* deepCopyIRPutI ( IRPutI* );
+/* --------------- Guarded loads and stores --------------- */
+
+/* Conditional stores are straightforward. They are the same as
+ normal stores, with an extra 'guard' field :: Ity_I1 that
+ determines whether or not the store actually happens. If not,
+ memory is unmodified.
+
+ The semantics of this is that 'addr' and 'data' are fully evaluated
+ even in the case where 'guard' evaluates to zero (false).
+*/
+typedef
+ struct {
+ IREndness end; /* Endianness of the store */
+ IRExpr* addr; /* store address */
+ IRExpr* data; /* value to write */
+ IRExpr* guard; /* Guarding value */
+ }
+ IRStoreG;
+
+/* Conditional loads are a little more complex. 'addr' is the
+ address, 'guard' is the guarding condition. If the load takes
+ place, the loaded value is placed in 'dst'. If it does not take
+ place, 'alt' is copied to 'dst'. However, the loaded value is not
+ placed directly in 'dst' -- it is first subjected to the conversion
+ specified by 'cvt'.
+
+ For example, imagine doing a conditional 8-bit load, in which the
+ loaded value is zero extended to 32 bits. Hence:
+ * 'dst' and 'alt' must have type I32
+ * 'cvt' must be a unary op which converts I8 to I32. In this
+ example, it would be ILGop_8Uto32.
+
+ There is no explicit indication of the type at which the load is
+ done, since that is inferrable from the arg type of 'cvt'. Note
+ that the types of 'alt' and 'dst' and the result type of 'cvt' must
+ all be the same.
+
+ Semantically, 'addr' is evaluated even in the case where 'guard'
+ evaluates to zero (false), and 'alt' is evaluated even when 'guard'
+ evaluates to one (true). That is, 'addr' and 'alt' are always
+ evaluated.
+*/
+typedef
+ enum {
+ ILGop_INVALID=0x1D00,
+ ILGop_Ident32, /* 32 bit, no conversion */
+ ILGop_16Uto32, /* 16 bit load, Z-widen to 32 */
+ ILGop_16Sto32, /* 16 bit load, S-widen to 32 */
+ ILGop_8Uto32, /* 8 bit load, Z-widen to 32 */
+ ILGop_8Sto32 /* 8 bit load, S-widen to 32 */
+ }
+ IRLoadGOp;
+
+typedef
+ struct {
+ IREndness end; /* Endianness of the load */
+ IRLoadGOp cvt; /* Conversion to apply to the loaded value */
+ IRTemp dst; /* Destination (LHS) of assignment */
+ IRExpr* addr; /* Address being loaded from */
+ IRExpr* alt; /* Value if load is not done. */
+ IRExpr* guard; /* Guarding value */
+ }
+ IRLoadG;
+
+extern void ppIRStoreG ( IRStoreG* sg );
+
+extern void ppIRLoadGOp ( IRLoadGOp cvt );
+
+extern void ppIRLoadG ( IRLoadG* lg );
+
+extern IRStoreG* mkIRStoreG ( IREndness end,
+ IRExpr* addr, IRExpr* data,
+ IRExpr* guard );
+
+extern IRLoadG* mkIRLoadG ( IREndness end, IRLoadGOp cvt,
+ IRTemp dst, IRExpr* addr, IRExpr* alt,
+ IRExpr* guard );
+
+
/* ------------------ Statements ------------------ */
/* The different kinds of statements. Their meaning is explained
@@ -2161,13 +2245,15 @@
typedef
enum {
- Ist_NoOp=0x19000,
+ Ist_NoOp=0x1E00,
Ist_IMark, /* META */
Ist_AbiHint, /* META */
Ist_Put,
Ist_PutI,
Ist_WrTmp,
Ist_Store,
+ Ist_LoadG,
+ Ist_StoreG,
Ist_CAS,
Ist_LLSC,
Ist_Dirty,
@@ -2288,6 +2374,24 @@
IRExpr* data; /* value to write */
} Store;
+ /* Guarded store. Note that this is defined to evaluate all
+ expression fields (addr, data) even if the guard evaluates
+ to false.
+ ppIRStmt output:
+ if (<guard>) ST<end>(<addr>) = <data> */
+ struct {
+ IRStoreG* details;
+ } StoreG;
+
+ /* Guarded load. Note that this is defined to evaluate all
+ expression fields (addr, alt) even if the guard evaluates
+ to false.
+ ppIRStmt output:
+ t<tmp> = if (<guard>) <cvt>(LD<end>(<addr>)) else <alt> */
+ struct {
+ IRLoadG* details;
+ } LoadG;
+
/* Do an atomic compare-and-swap operation. Semantics are
described above on a comment at the definition of IRCAS.
@@ -2407,6 +2511,10 @@
extern IRStmt* IRStmt_PutI ( IRPutI* details );
extern IRStmt* IRStmt_WrTmp ( IRTemp tmp, IRExpr* data );
extern IRStmt* IRStmt_Store ( IREndness end, IRExpr* addr, IRExpr* data );
+extern IRStmt* IRStmt_StoreG ( IREndness end, IRExpr* addr, IRExpr* data,
+ IRExpr* guard );
+extern IRStmt* IRStmt_LoadG ( IREndness end, IRLoadGOp cvt, IRTemp dst,
+ IRExpr* addr, IRExpr* alt, IRExpr* guard );
extern IRStmt* IRStmt_CAS ( IRCAS* details );
extern IRStmt* IRStmt_LLSC ( IREndness end, IRTemp result,
IRExpr* addr, IRExpr* storedata );
@@ -2504,6 +2612,11 @@
extern IRType typeOfIRTemp ( IRTypeEnv*, IRTemp );
extern IRType typeOfIRExpr ( IRTypeEnv*, IRExpr* );
+/* What are the arg and result type for this IRLoadGOp? */
+extern void typeOfIRLoadGOp ( IRLoadGOp cvt,
+ /*OUT*/IRType* t_res,
+ /*OUT*/IRType* t_arg );
+
/* Sanity check a BB of IR */
extern void sanityCheckIRSB ( IRSB* bb,
const HChar* caller,
Modified: branches/COMEM/priv/ir_defs.c (+192 -20)
===================================================================
--- branches/COMEM/priv/ir_defs.c 2012-11-25 12:48:39 +00:00 (rev 2569)
+++ branches/COMEM/priv/ir_defs.c 2012-11-25 15:14:44 +00:00 (rev 2570)
@@ -1217,6 +1217,42 @@
ppIRExpr(puti->data);
}
+void ppIRStoreG ( IRStoreG* sg )
+{
+ vex_printf("if (");
+ ppIRExpr(sg->guard);
+ vex_printf(") ST%s(", sg->end==Iend_LE ? "le" : "be");
+ ppIRExpr(sg->addr);
+ vex_printf(") = ");
+ ppIRExpr(sg->data);
+}
+
+void ppIRLoadGOp ( IRLoadGOp cvt )
+{
+ switch (cvt) {
+ case ILGop_INVALID: vex_printf("ILGop_INVALID"); break;
+ case ILGop_Ident32: vex_printf("Ident32"); break;
+ case ILGop_16Uto32: vex_printf("16Uto32"); break;
+ case ILGop_16Sto32: vex_printf("16Sto32"); break;
+ case ILGop_8Uto32: vex_printf("8Uto32"); break;
+ case ILGop_8Sto32: vex_printf("8Sto32"); break;
+ default: vpanic("ppIRLoadGOp");
+ }
+}
+
+void ppIRLoadG ( IRLoadG* lg )
+{
+ ppIRTemp(lg->dst);
+ vex_printf(" = if-strict (");
+ ppIRExpr(lg->guard);
+ vex_printf(") ");
+ ppIRLoadGOp(lg->cvt);
+ vex_printf("(LD%s(", lg->end==Iend_LE ? "le" : "be");
+ ppIRExpr(lg->addr);
+ vex_printf(")) else ");
+ ppIRExpr(lg->alt);
+}
+
void ppIRJumpKind ( IRJumpKind kind )
{
switch (kind) {
@@ -1298,6 +1334,12 @@
vex_printf( ") = ");
ppIRExpr(s->Ist.Store.data);
break;
+ case Ist_StoreG:
+ ppIRStoreG(s->Ist.StoreG.details);
+ break;
+ case Ist_LoadG:
+ ppIRLoadG(s->Ist.LoadG.details);
+ break;
case Ist_CAS:
ppIRCAS(s->Ist.CAS.details);
break;
@@ -1738,6 +1780,33 @@
}
+/* Constructors -- IRStoreG and IRLoadG */
+
+IRStoreG* mkIRStoreG ( IREndness end,
+ IRExpr* addr, IRExpr* data, IRExpr* guard )
+{
+ IRStoreG* sg = LibVEX_Alloc(sizeof(IRStoreG));
+ sg->end = end;
+ sg->addr = addr;
+ sg->data = data;
+ sg->guard = guard;
+ return sg;
+}
+
+IRLoadG* mkIRLoadG ( IREndness end, IRLoadGOp cvt,
+ IRTemp dst, IRExpr* addr, IRExpr* alt, IRExpr* guard )
+{
+ IRLoadG* lg = LibVEX_Alloc(sizeof(IRLoadG));
+ lg->end = end;
+ lg->cvt = cvt;
+ lg->dst = dst;
+ lg->addr = addr;
+ lg->alt = alt;
+ lg->guard = guard;
+ return lg;
+}
+
+
/* Constructors -- IRStmt */
IRStmt* IRStmt_NoOp ( void )
@@ -1792,6 +1861,21 @@
vassert(end == Iend_LE || end == Iend_BE);
return s;
}
+IRStmt* IRStmt_StoreG ( IREndness end, IRExpr* addr, IRExpr* data,
+ IRExpr* guard ) {
+ IRStmt* s = LibVEX_Alloc(sizeof(IRStmt));
+ s->tag = Ist_StoreG;
+ s->Ist.StoreG.details = mkIRStoreG(end, addr, data, guard);
+ vassert(end == Iend_LE || end == Iend_BE);
+ return s;
+}
+IRStmt* IRStmt_LoadG ( IREndness end, IRLoadGOp cvt, IRTemp dst,
+ IRExpr* addr, IRExpr* alt, IRExpr* guard ) {
+ IRStmt* s = LibVEX_Alloc(sizeof(IRStmt));
+ s->tag = Ist_LoadG;
+ s->Ist.LoadG.details = mkIRLoadG(end, cvt, dst, addr, alt, guard);
+ return s;
+}
IRStmt* IRStmt_CAS ( IRCAS* cas ) {
IRStmt* s = LibVEX_Alloc(sizeof(IRStmt));
s->tag = Ist_CAS;
@@ -2043,6 +2127,20 @@
return IRStmt_Store(s->Ist.Store.end,
deepCopyIRExpr(s->Ist.Store.addr),
deepCopyIRExpr(s->Ist.Store.data));
+ case Ist_StoreG: {
+ IRStoreG* sg = s->Ist.StoreG.details;
+ return IRStmt_StoreG(sg->end,
+ deepCopyIRExpr(sg->addr),
+ deepCopyIRExpr(sg->data),
+ deepCopyIRExpr(sg->guard));
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = s->Ist.LoadG.details;
+ return IRStmt_LoadG(lg->end, lg->cvt, lg->dst,
+ deepCopyIRExpr(lg->addr),
+ deepCopyIRExpr(lg->alt),
+ deepCopyIRExpr(lg->guard));
+ }
case Ist_CAS:
return IRStmt_CAS(deepCopyIRCAS(s->Ist.CAS.details));
case Ist_LLSC:
@@ -2929,7 +3027,6 @@
return env->types[tmp];
}
-
IRType typeOfIRConst ( IRConst* con )
{
switch (con->tag) {
@@ -2948,6 +3045,21 @@
}
}
+void typeOfIRLoadGOp ( IRLoadGOp cvt,
+ /*OUT*/IRType* t_res, /*OUT*/IRType* t_arg )
+{
+ switch (cvt) {
+ case ILGop_Ident32:
+ *t_res = Ity_I32; *t_arg = Ity_I32; break;
+ case ILGop_16Uto32: case ILGop_16Sto32:
+ *t_res = Ity_I32; *t_arg = Ity_I16; break;
+ case ILGop_8Uto32: case ILGop_8Sto32:
+ *t_res = Ity_I32; *t_arg = Ity_I8; break;
+ default:
+ vpanic("typeOfIRLoadGOp");
+ }
+}
+
IRType typeOfIRExpr ( IRTypeEnv* tyenv, IRExpr* e )
{
IRType t_dst, t_arg1, t_arg2, t_arg3, t_arg4;
@@ -3086,6 +3198,16 @@
case Ist_Store:
return toBool( isIRAtom(st->Ist.Store.addr)
&& isIRAtom(st->Ist.Store.data) );
+ case Ist_StoreG: {
+ IRStoreG* sg = st->Ist.StoreG.details;
+ return toBool( isIRAtom(sg->addr)
+ && isIRAtom(sg->data) && isIRAtom(sg->guard) );
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = st->Ist.LoadG.details;
+ return toBool( isIRAtom(lg->addr)
+ && isIRAtom(lg->alt) && isIRAtom(lg->guard) );
+ }
case Ist_CAS:
cas = st->Ist.CAS.details;
return toBool( isIRAtom(cas->addr)
@@ -3258,10 +3380,12 @@
static
void useBeforeDef_Stmt ( IRSB* bb, IRStmt* stmt, Int* def_counts )
{
- Int i;
- IRDirty* d;
- IRCAS* cas;
- IRPutI* puti;
+ Int i;
+ IRDirty* d;
+ IRCAS* cas;
+ IRPutI* puti;
+ IRLoadG* lg;
+ IRStoreG* sg;
switch (stmt->tag) {
case Ist_IMark:
break;
@@ -3284,6 +3408,18 @@
useBeforeDef_Expr(bb,stmt,stmt->Ist.Store.addr,def_counts);
useBeforeDef_Expr(bb,stmt,stmt->Ist.Store.data,def_counts);
break;
+ case Ist_StoreG:
+ sg = stmt->Ist.StoreG.details;
+ useBeforeDef_Expr(bb,stmt,sg->addr,def_counts);
+ useBeforeDef_Expr(bb,stmt,sg->data,def_counts);
+ useBeforeDef_Expr(bb,stmt,sg->guard,def_counts);
+ break;
+ case Ist_LoadG:
+ lg = stmt->Ist.LoadG.details;
+ useBeforeDef_Expr(bb,stmt,lg->addr,def_counts);
+ useBeforeDef_Expr(bb,stmt,lg->alt,def_counts);
+ useBeforeDef_Expr(bb,stmt,lg->guard,def_counts);
+ break;
case Ist_CAS:
cas = stmt->Ist.CAS.details;
useBeforeDef_Expr(bb,stmt,cas->addr,def_counts);
@@ -3571,18 +3707,54 @@
tcExpr( bb, stmt, stmt->Ist.WrTmp.data, gWordTy );
if (typeOfIRTemp(tyenv, stmt->Ist.WrTmp.tmp)
!= typeOfIRExpr(tyenv, stmt->Ist.WrTmp.data))
- sanityCheckFail(bb,stmt,"IRStmt.Put.Tmp: tmp and expr do not match");
+ sanityCheckFail(bb,stmt,
+ "IRStmt.Put.Tmp: tmp and expr do not match");
break;
case Ist_Store:
tcExpr( bb, stmt, stmt->Ist.Store.addr, gWordTy );
tcExpr( bb, stmt, stmt->Ist.Store.data, gWordTy );
if (typeOfIRExpr(tyenv, stmt->Ist.Store.addr) != gWordTy)
- sanityCheckFail(bb,stmt,"IRStmt.Store.addr: not :: guest word type");
+ sanityCheckFail(bb,stmt,
+ "IRStmt.Store.addr: not :: guest word type");
if (typeOfIRExpr(tyenv, stmt->Ist.Store.data) == Ity_I1)
- sanityCheckFail(bb,stmt,"IRStmt.Store.data: cannot Store :: Ity_I1");
+ sanityCheckFail(bb,stmt,
+ "IRStmt.Store.data: cannot Store :: Ity_I1");
if (stmt->Ist.Store.end != Iend_LE && stmt->Ist.Store.end != Iend_BE)
sanityCheckFail(bb,stmt,"Ist.Store.end: bogus endianness");
break;
+ case Ist_StoreG: {
+ IRStoreG* sg = stmt->Ist.StoreG.details;
+ tcExpr( bb, stmt, sg->addr, gWordTy );
+ tcExpr( bb, stmt, sg->data, gWordTy );
+ tcExpr( bb, stmt, sg->guard, gWordTy );
+ if (typeOfIRExpr(tyenv, sg->addr) != gWordTy)
+ sanityCheckFail(bb,stmt,"IRStmtG...addr: not :: guest word type");
+ if (typeOfIRExpr(tyenv, sg->data) == Ity_I1)
+ sanityCheckFail(bb,stmt,"IRStmtG...data: cannot Store :: Ity_I1");
+ if (typeOfIRExpr(tyenv, sg->guard) != Ity_I1)
+ sanityCheckFail(bb,stmt,"IRStmtG...guard: not :: Ity_I1");
+ if (sg->end != Iend_LE && sg->end != Iend_BE)
+ sanityCheckFail(bb,stmt,"IRStmtG...end: bogus endianness");
+ break;
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = stmt->Ist.LoadG.details;
+ tcExpr( bb, stmt, lg->addr, gWordTy );
+ tcExpr( bb, stmt, lg->alt, gWordTy );
+ tcExpr( bb, stmt, lg->guard, gWordTy );
+ if (typeOfIRExpr(tyenv, lg->guard) != Ity_I1)
+ sanityCheckFail(bb,stmt,"IRStmt.LoadG.guard: not :: Ity_I1");
+ if (typeOfIRExpr(tyenv, lg->addr) != gWordTy)
+ sanityCheckFail(bb,stmt,"IRStmt.LoadG.addr: not "
+ ":: guest word type");
+ if (typeOfIRExpr(tyenv, lg->alt) != typeOfIRTemp(tyenv, lg->dst))
+ sanityCheckFail(bb,stmt,"IRStmt.LoadG: dst/alt type mismatch");
+ IRTemp cvtRes = Ity_INVALID, cvtArg = Ity_INVALID;
+ typeOfIRLoadGOp(lg->cvt, &cvtRes, &cvtArg);
+ if (cvtRes != typeOfIRTemp(tyenv, lg->dst))
+ sanityCheckFail(bb,stmt,"IRStmt.LoadG: dst/loaded type mismatch");
+ break;
+ }
case Ist_CAS:
cas = stmt->Ist.CAS.details;
/* make sure it's definitely either a CAS or a DCAS */
@@ -3692,15 +3864,6 @@
tcExpr( bb, stmt, d->guard, gWordTy );
if (typeOfIRExpr(tyenv, d->guard) != Ity_I1)
sanityCheckFail(bb,stmt,"IRStmt.Dirty.guard not :: Ity_I1");
- /* A dirty helper that is executed conditionally (or not at
- all) may not return a value. Hence if .tmp is not
- IRTemp_INVALID, .guard must be manifestly True at JIT
- time. */
- if (d->tmp != IRTemp_INVALID
- && (d->guard->tag != Iex_Const
- || d->guard->Iex.Const.con->Ico.U1 == 0))
- sanityCheckFail(bb,stmt,"IRStmt.Dirty with a return value"
- " is executed under a condition");
/* check types, minimally */
if (d->tmp != IRTemp_INVALID
&& typeOfIRTemp(tyenv, d->tmp) == Ity_I1)
@@ -3793,6 +3956,7 @@
for (i = 0; i < bb->stmts_used; i++) {
IRDirty* d;
IRCAS* cas;
+ IRLoadG* lg;
stmt = bb->stmts[i];
/* Check any temps used by this statement. */
useBeforeDef_Stmt(bb,stmt,def_counts);
@@ -3808,11 +3972,19 @@
sanityCheckFail(bb, stmt,
"IRStmt.Tmp: destination tmp is assigned more than once");
break;
- case Ist_Store:
+ case Ist_LoadG:
+ lg = stmt->Ist.LoadG.details;
+ if (lg->dst < 0 || lg->dst >= n_temps)
+ sanityCheckFail(bb, stmt,
+ "IRStmt.LoadG: destination tmp is out of range");
+ def_counts[lg->dst]++;
+ if (def_counts[lg->dst] > 1)
+ sanityCheckFail(bb, stmt,
+ "IRStmt.LoadG: destination tmp is assigned more than once");
break;
case Ist_Dirty:
- if (stmt->Ist.Dirty.details->tmp != IRTemp_INVALID) {
- d = stmt->Ist.Dirty.details;
+ d = stmt->Ist.Dirty.details;
+ if (d->tmp != IRTemp_INVALID) {
if (d->tmp < 0 || d->tmp >= n_temps)
sanityCheckFail(bb, stmt,
"IRStmt.Dirty: destination tmp is out of range");
Modified: branches/COMEM/priv/ir_opt.c (+274 -27)
===================================================================
--- branches/COMEM/priv/ir_opt.c 2012-11-25 12:48:39 +00:00 (rev 2569)
+++ branches/COMEM/priv/ir_opt.c 2012-11-25 15:14:44 +00:00 (rev 2570)
@@ -400,10 +400,12 @@
static void flatten_Stmt ( IRSB* bb, IRStmt* st )
{
Int i;
- IRExpr *e1, *e2, *e3, *e4, *e5;
- IRDirty *d, *d2;
- IRCAS *cas, *cas2;
- IRPutI *puti, *puti2;
+ IRExpr *e1, *e2, *e3, *e4, *e5;
+ IRDirty *d, *d2;
+ IRCAS *cas, *cas2;
+ IRPutI *puti, *puti2;
+ IRLoadG *lg;
+ IRStoreG *sg;
switch (st->tag) {
case Ist_Put:
if (isIRAtom(st->Ist.Put.data)) {
@@ -439,6 +441,21 @@
e2 = flatten_Expr(bb, st->Ist.Store.data);
addStmtToIRSB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2));
break;
+ case Ist_StoreG:
+ sg = st->Ist.StoreG.details;
+ e1 = flatten_Expr(bb, sg->addr);
+ e2 = flatten_Expr(bb, sg->data);
+ e3 = flatten_Expr(bb, sg->guard);
+ addStmtToIRSB(bb, IRStmt_StoreG(sg->end, e1, e2, e3));
+ break;
+ case Ist_LoadG:
+ lg = st->Ist.LoadG.details;
+ e1 = flatten_Expr(bb, lg->addr);
+ e2 = flatten_Expr(bb, lg->alt);
+ e3 = flatten_Expr(bb, lg->guard);
+ addStmtToIRSB(bb, IRStmt_LoadG(lg->end, lg->cvt, lg->dst,
+ e1, e2, e3));
+ break;
case Ist_CAS:
cas = st->Ist.CAS.details;
e1 = flatten_Expr(bb, cas->addr);
@@ -763,7 +780,22 @@
vassert(isIRAtom(st->Ist.Store.data));
memRW = True;
break;
-
+ case Ist_StoreG: {
+ IRStoreG* sg = st->Ist.StoreG.details;
+ vassert(isIRAtom(sg->addr));
+ vassert(isIRAtom(sg->data));
+ vassert(isIRAtom(sg->guard));
+ memRW = True;
+ break;
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = st->Ist.LoadG.details;
+ vassert(isIRAtom(lg->addr));
+ vassert(isIRAtom(lg->alt));
+ vassert(isIRAtom(lg->guard));
+ memRW = True;
+ break;
+ }
case Ist_Exit:
vassert(isIRAtom(st->Ist.Exit.guard));
break;
@@ -2407,6 +2439,62 @@
fold_Expr(env, subst_Expr(env, st->Ist.Store.data))
);
+ case Ist_StoreG: {
+ IRStoreG* sg = st->Ist.StoreG.details;
+ vassert(isIRAtom(sg->addr));
+ vassert(isIRAtom(sg->data));
+ vassert(isIRAtom(sg->guard));
+ IRExpr* faddr = fold_Expr(env, subst_Expr(env, sg->addr));
+ IRExpr* fdata = fold_Expr(env, subst_Expr(env, sg->data));
+ IRExpr* fguard = fold_Expr(env, subst_Expr(env, sg->guard));
+ if (fguard->tag == Iex_Const) {
+ /* The condition on this store has folded down to a constant. */
+ vassert(fguard->Iex.Const.con->tag == Ico_U1);
+ if (fguard->Iex.Const.con->Ico.U1 == False) {
+ return IRStmt_NoOp();
+ } else {
+ vassert(fguard->Iex.Const.con->Ico.U1 == True);
+ return IRStmt_Store(sg->end, faddr, fdata);
+ }
+ }
+ return IRStmt_StoreG(sg->end, faddr, fdata, fguard);
+ }
+
+ case Ist_LoadG: {
+ /* This is complicated. If the guard folds down to 'false',
+ we can replace it with a NoOp, but if the guard folds down
+ to 'true', we can't conveniently replace it with an
+ unconditional load, because doing so requires generating a
+ new temporary, and that is not easy to do at this
+ point. */
+ IRLoadG* lg = st->Ist.LoadG.details;
+ vassert(isIRAtom(lg->addr));
+ vassert(isIRAtom(lg->alt));
+ vassert(isIRAtom(lg->guard));
+ IRExpr* faddr = fold_Expr(env, subst_Expr(env, lg->addr));
+ IRExpr* falt = fold_Expr(env, subst_Expr(env, lg->alt));
+ IRExpr* fguard = fold_Expr(env, subst_Expr(env, lg->guard));
+ if (fguard->tag == Iex_Const) {
+ /* The condition on this load has folded down to a constant. */
+ vassert(fguard->Iex.Const.con->tag == Ico_U1);
+ if (fguard->Iex.Const.con->Ico.U1 == False) {
+ /* The load is not going to happen -- instead 'alt' is
+ assigned to 'dst'. */
+ return IRStmt_WrTmp(lg->dst, falt);
+ } else {
+ vassert(fguard->Iex.Const.con->Ico.U1 == True);
+ /* The load is always going to happen. We want to
+ convert to an unconditional load and assign to 'dst'
+ (IRStmt_WrTmp). Problem is we need an extra temp to
+ hold the loaded value, but none is available.
+ Instead, reconstitute the conditional load (with
+ folded args, of course) and let the caller of this
+ routine deal with the problem. */
+ }
+ }
+ return IRStmt_LoadG(lg->end, lg->cvt, lg->dst, faddr, falt, fguard);
+ }
+
case Ist_CAS: {
IRCAS *cas, *cas2;
cas = st->Ist.CAS.details;
@@ -2480,8 +2568,6 @@
/* Interesting. The condition on this exit has folded down to
a constant. */
vassert(fcond->Iex.Const.con->tag == Ico_U1);
- vassert(fcond->Iex.Const.con->Ico.U1 == False
- || fcond->Iex.Const.con->Ico.U1 == True);
if (fcond->Iex.Const.con->Ico.U1 == False) {
/* exit is never going to happen, so dump the statement. */
return IRStmt_NoOp();
@@ -2515,6 +2601,11 @@
IRStmt* st2;
Int n_tmps = in->tyenv->types_used;
IRExpr** env = LibVEX_Alloc(n_tmps * sizeof(IRExpr*));
+ /* Keep track of IRStmt_LoadGs that we need to revisit after
+ processing all the other statements. */
+ const Int N_FIXUPS = 16;
+ Int fixups[N_FIXUPS]; /* indices in the stmt array of 'out' */
+ Int n_fixups = 0;
out = emptyIRSB();
out->tyenv = deepCopyIRTypeEnv( in->tyenv );
@@ -2542,40 +2633,124 @@
st2 = subst_and_fold_Stmt( env, st2 );
- /* If the statement has been folded into a no-op, forget it. */
- if (st2->tag == Ist_NoOp) continue;
+ /* Deal with some post-folding special cases. */
+ switch (st2->tag) {
- /* If the statement assigns to an IRTemp add it to the running
- environment. This is for the benefit of copy propagation
- and to allow sameIRExpr look through IRTemps. */
- if (st2->tag == Ist_WrTmp) {
- vassert(env[(Int)(st2->Ist.WrTmp.tmp)] == NULL);
- env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
+ /* If the statement has been folded into a no-op, forget
+ it. */
+ case Ist_NoOp:
+ continue;
- /* 't1 = t2' -- don't add to BB; will be optimized out */
- if (st2->Ist.WrTmp.data->tag == Iex_RdTmp) continue;
+ /* If the statement assigns to an IRTemp add it to the
+ running environment. This is for the benefit of copy
+ propagation and to allow sameIRExpr look through
+ IRTemps. */
+ case Ist_WrTmp: {
+ vassert(env[(Int)(st2->Ist.WrTmp.tmp)] == NULL);
+ env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
- /* 't = const' && 'const != F64i' -- don't add to BB
- Note, we choose not to propagate const when const is an
- F64i, so that F64i literals can be CSE'd later. This helps
- x86 floating point code generation. */
- if (st2->Ist.WrTmp.data->tag == Iex_Const
- && st2->Ist.WrTmp.data->Iex.Const.con->tag != Ico_F64i) continue;
+ /* 't1 = t2' -- don't add to BB; will be optimized out */
+ if (st2->Ist.WrTmp.data->tag == Iex_RdTmp)
+ continue;
+
+ /* 't = const' && 'const != F64i' -- don't add to BB
+ Note, we choose not to propagate const when const is an
+ F64i, so that F64i literals can be CSE'd later. This
+ helps x86 floating point code generation. */
+ if (st2->Ist.WrTmp.data->tag == Iex_Const
+ && st2->Ist.WrTmp.data->Iex.Const.con->tag != Ico_F64i) {
+ continue;
+ }
+ /* else add it to the output, as normal */
+ break;
+ }
+
+ case Ist_LoadG: {
+ IRLoadG* lg = st2->Ist.LoadG.details;
+ IRExpr* guard = lg->guard;
+ if (guard->tag == Iex_Const) {
+ /* The guard has folded to a constant, and that
+ constant must be 1:I1, since subst_and_fold_Stmt
+ folds out the case 0:I1 by itself. */
+ vassert(guard->Iex.Const.con->tag == Ico_U1);
+ vassert(guard->Iex.Const.con->Ico.U1 == True);
+ /* Add a NoOp here as a placeholder, and make a note of
+ where it is in the output block. Afterwards we'll
+ come back here and transform the NoOp and the LoadG
+ into a load-convert pair. The fixups[] entry
+ refers to the inserted NoOp, and we expect to find
+ the relevant LoadG immediately after it. */
+ vassert(n_fixups >= 0 && n_fixups <= N_FIXUPS);
+ if (n_fixups < N_FIXUPS) {
+ fixups[n_fixups++] = out->stmts_used;
+ addStmtToIRSB( out, IRStmt_NoOp() );
+ }
+ }
+ /* And always add the LoadG to the output, regardless. */
+ break;
+ }
+
+ default:
+ break;
}
/* Not interesting, copy st2 into the output block. */
addStmtToIRSB( out, st2 );
}
-#if STATS_IROPT
+# if STATS_IROPT
vex_printf("sameIRExpr: invoked = %u/%u equal = %u/%u max_nodes = %u\n",
invocation_count, recursion_count, success_count,
recursion_success_count, max_nodes_visited);
-#endif
+# endif
out->next = subst_Expr( env, in->next );
out->jumpkind = in->jumpkind;
out->offsIP = in->offsIP;
+
+ /* Process any leftover unconditional LoadGs that we noticed
+ in the main pass. */
+ vassert(n_fixups >= 0 && n_fixups <= N_FIXUPS);
+ for (i = 0; i < n_fixups; i++) {
+ Int ix = fixups[i];
+ /* Carefully verify that the LoadG has the expected form. */
+ vassert(ix >= 0 && ix+1 < out->stmts_used);
+ IRStmt* nop = out->stmts[ix];
+ IRStmt* lgu = out->stmts[ix+1];
+ vassert(nop->tag == Ist_NoOp);
+ vassert(lgu->tag == Ist_LoadG);
+ IRLoadG* lg = lgu->Ist.LoadG.details;
+ IRExpr* guard = lg->guard;
+ vassert(guard->Iex.Const.con->tag == Ico_U1);
+ vassert(guard->Iex.Const.con->Ico.U1 == True);
+ /* Figure out the load and result types, and the implied
+ conversion operation. */
+ IRType cvtRes = Ity_INVALID, cvtArg = Ity_INVALID;
+ typeOfIRLoadGOp(lg->cvt, &cvtRes, &cvtArg);
+ IROp cvtOp = Iop_INVALID;
+ switch (lg->cvt) {
+ case ILGop_Ident32: break;
+ case ILGop_8Uto32: cvtOp = Iop_8Uto32; break;
+ case ILGop_8Sto32: cvtOp = Iop_8Sto32; break;
+ case ILGop_16Uto32: cvtOp = Iop_16Uto32; break;
+ case ILGop_16Sto32: cvtOp = Iop_16Sto32; break;
+ default: vpanic("cprop_BB: unhandled ILGOp");
+ }
+ /* Replace the placeholder NoOp by the required unconditional
+ load. */
+ IRTemp tLoaded = newIRTemp(out->tyenv, cvtArg);
+ out->stmts[ix]
+ = IRStmt_WrTmp(tLoaded,
+ IRExpr_Load(lg->end, cvtArg, lg->addr));
+ /* Replace the LoadG by a conversion from the loaded value's
+ type to the required result type. */
+ out->stmts[ix+1]
+ = IRStmt_WrTmp(
+ lg->dst, cvtOp == Iop_INVALID
+ ? IRExpr_RdTmp(tLoaded)
+ : IRExpr_Unop(cvtOp, IRExpr_RdTmp(tLoaded)));
+ }
+
return out;
}
@@ -2671,6 +2846,20 @@
addUses_Expr(set, st->Ist.Store.addr);
addUses_Expr(set, st->Ist.Store.data);
return;
+ case Ist_StoreG: {
+ IRStoreG* sg = st->Ist.StoreG.details;
+ addUses_Expr(set, sg->addr);
+ addUses_Expr(set, sg->data);
+ addUses_Expr(set, sg->guard);
+ return;
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = st->Ist.LoadG.details;
+ addUses_Expr(set, lg->addr);
+ addUses_Expr(set, lg->alt);
+ addUses_Expr(set, lg->guard);
+ return;
+ }
case Ist_CAS:
cas = st->Ist.CAS.details;
addUses_Expr(set, cas->addr);
@@ -3477,7 +3666,7 @@
if (0) { ppIRSB(bb); vex_printf("\n\n"); }
/* Iterate forwards over the stmts.
- On seeing "t = E", where E is one of the 5 AvailExpr forms:
+ On seeing "t = E", where E is one of the AvailExpr forms:
let E' = apply tenv substitution to E
search aenv for E'
if a mapping E' -> q is found,
@@ -3507,11 +3696,12 @@
switch (st->tag) {
case Ist_Dirty: case Ist_Store: case Ist_MBE:
case Ist_CAS: case Ist_LLSC:
+ case Ist_StoreG:
paranoia = 2; break;
case Ist_Put: case Ist_PutI:
paranoia = 1; break;
case Ist_NoOp: case Ist_IMark: case Ist_AbiHint:
- case Ist_WrTmp: case Ist_Exit:
+ case Ist_WrTmp: case Ist_Exit: case Ist_LoadG:
paranoia = 0; break;
default:
vpanic("do_cse_BB(1)");
@@ -4212,6 +4402,21 @@
deltaIRExpr(st->Ist.Store.addr, delta);
deltaIRExpr(st->Ist.Store.data, delta);
break;
+ case Ist_StoreG: {
+ IRStoreG* sg = st->Ist.StoreG.details;
+ deltaIRExpr(sg->addr, delta);
+ deltaIRExpr(sg->data, delta);
+ deltaIRExpr(sg->guard, delta);
+ break;
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = st->Ist.LoadG.details;
+ lg->dst += delta;
+ deltaIRExpr(lg->addr, delta);
+ deltaIRExpr(lg->alt, delta);
+ deltaIRExpr(lg->guard, delta);
+ break;
+ }
case Ist_CAS:
if (st->Ist.CAS.details->oldHi != IRTemp_INVALID)
st->Ist.CAS.details->oldHi += delta;
@@ -4684,6 +4889,20 @@
aoccCount_Expr(uses, st->Ist.Store.addr);
aoccCount_Expr(uses, st->Ist.Store.data);
return;
+ case Ist_StoreG: {
+ IRStoreG* sg = st->Ist.StoreG.details;
+ aoccCount_Expr(uses, sg->addr);
+ aoccCount_Expr(uses, sg->data);
+ aoccCount_Expr(uses, sg->guard);
+ return;
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = st->Ist.LoadG.details;
+ aoccCount_Expr(uses, lg->addr);
+ aoccCount_Expr(uses, lg->alt);
+ aoccCount_Expr(uses, lg->guard);
+ return;
+ }
case Ist_CAS:
cas = st->Ist.CAS.details;
aoccCount_Expr(uses, cas->addr);
@@ -5000,6 +5219,20 @@
atbSubst_Expr(env, st->Ist.Store.addr),
atbSubst_Expr(env, st->Ist.Store.data)
);
+ case Ist_StoreG: {
+ IRStoreG* sg = st->Ist.StoreG.details;
+ return IRStmt_StoreG(sg->end,
+ atbSubst_Expr(env, sg->addr),
+ atbSubst_Expr(env, sg->data),
+ atbSubst_Expr(env, sg->guard));
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = st->Ist.LoadG.details;
+ return IRStmt_LoadG(lg->end, lg->cvt, lg->dst,
+ atbSubst_Expr(env, lg->addr),
+ atbSubst_Expr(env, lg->alt),
+ atbSubst_Expr(env, lg->guard));
+ }
case Ist_WrTmp:
return IRStmt_WrTmp(
st->Ist.WrTmp.tmp,
@@ -5411,6 +5644,20 @@
vassert(isIRAtom(st->Ist.Store.addr));
vassert(isIRAtom(st->Ist.Store.data));
break;
+ case Ist_StoreG: {
+ IRStoreG* sg = st->Ist.StoreG.details;
+ vassert(isIRAtom(sg->addr));
+ vassert(isIRAtom(sg->data));
+ vassert(isIRAtom(sg->guard));
+ break;
+ }
+ case Ist_LoadG: {
+ IRLoadG* lg = st->Ist.LoadG.details;
+ vassert(isIRAtom(lg->addr));
+ vassert(isIRAtom(lg->alt));
+ vassert(isIRAtom(lg->guard));
+ break;
+ }
case Ist_CAS:
cas = st->Ist.CAS.details;
vassert(isIRAtom(cas->addr));
|