IRTemp* tmpMap;
Int n_originalTmps; /* for range checking */
+ /* MODIFIED: indicates whether "bogus" literals have so far been
+ found. Starts off False, and may change to True. */
+ Bool bogusLiterals;
+
/* READONLY: the guest layout. This indicates which parts of
the guest state should be regarded as 'always defined'. */
VexGuestLayout* layout;
}
}
+/* --------- Accurate interpretation of CmpEQ/CmpNE. --------- */
+/*
+ Normally, we can do CmpEQ/CmpNE by doing UifU on the arguments, and
+ PCasting to Ity_U1. However, sometimes it is necessary to be more
+ accurate. The insight is that the result is defined if two
+ corresponding bits can be found, one from each argument, so that
+ both bits are defined but are different -- that makes EQ say "No"
+ and NE say "Yes". Hence, we compute an improvement term and DifD
+ it onto the "normal" (UifU) result.
+
+ The result is:
+
+ PCastTo<1> (
+ PCastTo<sz>( UifU<sz>(vxx, vyy) ) -- naive version
+ `DifD<sz>`
+ PCastTo<sz>( CmpEQ<sz>( vec, 1....1 ) ) -- improvement term
+ )
+ where
+ vec contains 0 (defined) bits where the corresponding arg bits
+ are defined but different, and 1 bits otherwise:
+
+ vec = UifU<sz>( vxx, vyy, Not<sz>(Xor<sz>( xx, yy )) )
+*/
+static IRAtom* expensiveCmpEQorNE ( MCEnv* mce,
+ IRType ty,
+ IRAtom* vxx, IRAtom* vyy,
+ IRAtom* xx, IRAtom* yy )
+{
+ IRAtom *naive, *vec, *vec_cmpd, *improved, *final_cast, *top;
+ IROp opDIFD, opUIFU, opXOR, opNOT, opCMP;
+
+ tl_assert(isShadowAtom(mce,vxx));
+ tl_assert(isShadowAtom(mce,vyy));
+ tl_assert(isOriginalAtom(mce,xx));
+ tl_assert(isOriginalAtom(mce,yy));
+ tl_assert(sameKindedAtoms(vxx,xx));
+ tl_assert(sameKindedAtoms(vyy,yy));
+
+ switch (ty) {
+ case Ity_I32:
+ opDIFD = Iop_And32;
+ opUIFU = Iop_Or32;
+ opNOT = Iop_Not32;
+ opXOR = Iop_Xor32;
+ opCMP = Iop_CmpEQ32;
+ top = mkU32(0xFFFFFFFF);
+ break;
+ default:
+ VG_(tool_panic)("expensiveCmpEQorNE");
+ }
+
+ naive
+ = mkPCastTo(mce,ty, assignNew(mce, ty, binop(opUIFU, vxx, vyy)));
+
+ vec
+ = assignNew(
+ mce,ty,
+ binop( opUIFU,
+ assignNew(mce,ty, binop(opUIFU, vxx, vyy)),
+ assignNew(
+ mce,ty,
+ unop( opNOT,
+ assignNew(mce,ty, binop(opXOR, xx, yy))))));
+
+ vec_cmpd
+ = mkPCastTo( mce,ty, assignNew(mce,Ity_I1, binop(opCMP, vec, top)));
+
+ improved
+ = assignNew( mce,ty, binop(opDIFD, naive, vec_cmpd) );
+
+ final_cast
+ = mkPCastTo( mce, Ity_I1, improved );
+
+ return final_cast;
+}
+
/*------------------------------------------------------------*/
/*--- Emit a test and complaint if something is undefined. ---*/
/*------------------------------------------------------------*/
static
-IRAtom* expensiveAdd32 ( MCEnv* mce, IRAtom* qaa, IRAtom* qbb,
- IRAtom* aa, IRAtom* bb )
+IRAtom* expensiveAddSub ( MCEnv* mce,
+ Bool add,
+ IRType ty,
+ IRAtom* qaa, IRAtom* qbb,
+ IRAtom* aa, IRAtom* bb )
{
IRAtom *a_min, *b_min, *a_max, *b_max;
- IRType ty;
- IROp opAND, opOR, opXOR, opNOT, opADD;
+ IROp opAND, opOR, opXOR, opNOT, opADD, opSUB;
tl_assert(isShadowAtom(mce,qaa));
tl_assert(isShadowAtom(mce,qbb));
tl_assert(sameKindedAtoms(qaa,aa));
tl_assert(sameKindedAtoms(qbb,bb));
- ty = Ity_I32;
- opAND = Iop_And32;
- opOR = Iop_Or32;
- opXOR = Iop_Xor32;
- opNOT = Iop_Not32;
- opADD = Iop_Add32;
+ switch (ty) {
+ case Ity_I32:
+ opAND = Iop_And32;
+ opOR = Iop_Or32;
+ opXOR = Iop_Xor32;
+ opNOT = Iop_Not32;
+ opADD = Iop_Add32;
+ opSUB = Iop_Sub32;
+ break;
+ default:
+ VG_(tool_panic)("expensiveAddSub");
+ }
// a_min = aa & ~qaa
a_min = assignNew(mce,ty,
// b_max = bb | qbb
b_max = assignNew(mce,ty, binop(opOR, bb, qbb));
- // result = (qaa | qbb) | ((a_min + b_min) ^ (a_max + b_max))
- return
- assignNew(mce,ty,
- binop( opOR,
- assignNew(mce,ty, binop(opOR, qaa, qbb)),
- assignNew(mce,ty,
- binop(opXOR, assignNew(mce,ty, binop(opADD, a_min, b_min)),
- assignNew(mce,ty, binop(opADD, a_max, b_max))
+ if (add) {
+ // result = (qaa | qbb) | ((a_min + b_min) ^ (a_max + b_max))
+ return
+ assignNew(mce,ty,
+ binop( opOR,
+ assignNew(mce,ty, binop(opOR, qaa, qbb)),
+ assignNew(mce,ty,
+ binop( opXOR,
+ assignNew(mce,ty, binop(opADD, a_min, b_min)),
+ assignNew(mce,ty, binop(opADD, a_max, b_max))
+ )
+ )
+ )
+ );
+ } else {
+ // result = (qaa | qbb) | ((a_min - b_max) ^ (a_max + b_min))
+ return
+ assignNew(mce,ty,
+ binop( opOR,
+ assignNew(mce,ty, binop(opOR, qaa, qbb)),
+ assignNew(mce,ty,
+ binop( opXOR,
+ assignNew(mce,ty, binop(opSUB, a_min, b_max)),
+ assignNew(mce,ty, binop(opSUB, a_max, b_min))
+ )
)
- )
- )
- );
+ )
+ );
+ }
+
}
}
case Iop_Add32:
-# if 0
- return expensiveAdd32(mce, vatom1,vatom2, atom1,atom2);
-# endif
+ if (mce->bogusLiterals)
+ return expensiveAddSub(mce,True,Ity_I32,
+ vatom1,vatom2, atom1,atom2);
+ else
+ goto cheap_AddSub32;
case Iop_Sub32:
+ if (mce->bogusLiterals)
+ return expensiveAddSub(mce,False,Ity_I32,
+ vatom1,vatom2, atom1,atom2);
+ else
+ goto cheap_AddSub32;
+
+ cheap_AddSub32:
case Iop_Mul32:
return mkLeft32(mce, mkUifU32(mce, vatom1,vatom2));
case Iop_Add8:
return mkLeft8(mce, mkUifU8(mce, vatom1,vatom2));
+ case Iop_CmpEQ32:
+ if (mce->bogusLiterals)
+ return expensiveCmpEQorNE(mce,Ity_I32, vatom1,vatom2, atom1,atom2 );
+ else
+ goto cheap_cmp32;
+
+ cheap_cmp32:
case Iop_CmpLE32S: case Iop_CmpLE32U:
case Iop_CmpLT32U: case Iop_CmpLT32S:
- case Iop_CmpEQ32: case Iop_CmpNE32:
+ case Iop_CmpNE32:
return mkPCastTo(mce, Ity_I1, mkUifU32(mce, vatom1,vatom2));
case Iop_CmpEQ16: case Iop_CmpNE16:
/*--- Memcheck main ---*/
/*------------------------------------------------------------*/
-#if 0 /* UNUSED */
static Bool isBogusAtom ( IRAtom* at )
{
ULong n = 0;
tl_assert(at->tag == Iex_Const);
con = at->Iex.Const.con;
switch (con->tag) {
- case Ico_U8: n = (ULong)con->Ico.U8; break;
- case Ico_U16: n = (ULong)con->Ico.U16; break;
- case Ico_U32: n = (ULong)con->Ico.U32; break;
- case Ico_U64: n = (ULong)con->Ico.U64; break;
+ case Ico_U1: return False;
+ case Ico_U8: n = (ULong)con->Ico.U8; break;
+ case Ico_U16: n = (ULong)con->Ico.U16; break;
+ case Ico_U32: n = (ULong)con->Ico.U32; break;
+ case Ico_U64: n = (ULong)con->Ico.U64; break;
+ case Ico_F64: return False;
+ case Ico_F64i: return False;
+ case Ico_V128: return False;
default: ppIRExpr(at); tl_assert(0);
}
/* VG_(printf)("%llx\n", n); */
return (n == 0xFEFEFEFF
- || n == 0x80808080
- || n == 0x1010101
- || n == 1010100);
+ || n == 0x80808080 /*
+ || n == 0x01010101
+ || n == 0x01010100*/);
}
static Bool checkForBogusLiterals ( /*FLAT*/ IRStmt* st )
{
- Int i;
- IRExpr* e;
+ Int i;
+ IRExpr* e;
+ IRDirty* d;
switch (st->tag) {
case Ist_Tmp:
e = st->Ist.Tmp.data;
case Iex_Get:
case Iex_Tmp:
return False;
+ case Iex_Const:
+ return isBogusAtom(e);
case Iex_Unop:
return isBogusAtom(e->Iex.Unop.arg);
+ case Iex_GetI:
+ return isBogusAtom(e->Iex.GetI.ix);
case Iex_Binop:
return isBogusAtom(e->Iex.Binop.arg1)
|| isBogusAtom(e->Iex.Binop.arg2);
default:
goto unhandled;
}
+ case Ist_Dirty:
+ d = st->Ist.Dirty.details;
+ for (i = 0; d->args[i]; i++)
+ if (isBogusAtom(d->args[i]))
+ return True;
+ if (d->guard && isBogusAtom(d->guard))
+ return True;
+ if (d->mAddr && isBogusAtom(d->mAddr))
+ return True;
+ return False;
case Ist_Put:
return isBogusAtom(st->Ist.Put.data);
+ case Ist_PutI:
+ return isBogusAtom(st->Ist.PutI.ix)
+ || isBogusAtom(st->Ist.PutI.data);
case Ist_STle:
return isBogusAtom(st->Ist.STle.addr)
|| isBogusAtom(st->Ist.STle.data);
case Ist_Exit:
- return isBogusAtom(st->Ist.Exit.cond);
+ return isBogusAtom(st->Ist.Exit.guard);
default:
unhandled:
ppIRStmt(st);
VG_(tool_panic)("hasBogusLiterals");
}
}
-#endif /* UNUSED */
IRBB* TL_(instrument) ( IRBB* bb_in, VexGuestLayout* layout, IRType hWordTy )
{
Bool verboze = False; //True;
- /* Bool hasBogusLiterals = False; */
-
- Int i, j, first_stmt;
+ Int i, j, first_stmt;
IRStmt* st;
- MCEnv mce;
+ MCEnv mce;
/* Set up BB */
IRBB* bb = emptyIRBB();
mce.layout = layout;
mce.n_originalTmps = bb->tyenv->types_used;
mce.hWordTy = hWordTy;
+ mce.bogusLiterals = False;
mce.tmpMap = LibVEX_Alloc(mce.n_originalTmps * sizeof(IRTemp));
for (i = 0; i < mce.n_originalTmps; i++)
mce.tmpMap[i] = IRTemp_INVALID;
tl_assert(isFlatIRStmt(st));
- /*
- if (!hasBogusLiterals) {
- hasBogusLiterals = checkForBogusLiterals(st);
- if (hasBogusLiterals) {
+ if (!mce.bogusLiterals) {
+ mce.bogusLiterals = checkForBogusLiterals(st);
+ if (0&& mce.bogusLiterals) {
VG_(printf)("bogus: ");
ppIRStmt(st);
VG_(printf)("\n");
}
}
- */
+
first_stmt = bb->stmts_used;
if (verboze) {
break;
case Ist_Exit:
- /* if (!hasBogusLiterals) */
- complainIfUndefined( &mce, st->Ist.Exit.guard );
+ complainIfUndefined( &mce, st->Ist.Exit.guard );
break;
case Ist_Dirty: