Discussion:
vex: r3330 - in /branches/VEX_JIT_HACKS: priv/ir_defs.c pub/libvex_ir.h
(too old to reply)
s***@valgrind.org
2017-03-25 08:02:34 UTC
Permalink
Raw Message
Author: iraisr
Date: Sat Mar 25 08:02:31 2017
New Revision: 3330

Log:
Rework the VEX IR interface a bit.
Previous iteration had a design flaw which would make
certain transformations too expensive (lifting a leg of
"if-then-else" in case of constant condition).

Now we have a single global IRTypeEnv. Every IRStmtVec
has an IRTempDefSet which keeps track of IRTemp's defined
there.

So far these two files have been fitted. More will follow.

Modified:
branches/VEX_JIT_HACKS/priv/ir_defs.c
branches/VEX_JIT_HACKS/pub/libvex_ir.h

Modified: branches/VEX_JIT_HACKS/priv/ir_defs.c
==============================================================================
--- branches/VEX_JIT_HACKS/priv/ir_defs.c (original)
+++ branches/VEX_JIT_HACKS/priv/ir_defs.c Sat Mar 25 08:02:31 2017
@@ -113,10 +113,10 @@

void ppIRTemp ( IRTemp tmp )
{
- if (isIRTempInvalid(tmp))
+ if (tmp == IRTemp_INVALID)
vex_printf("IRTemp_INVALID");
else
- vex_printf("t%u:%u", tmp.id, tmp.index);
+ vex_printf("t%u", tmp);
}

void ppIROp ( IROp op )
@@ -1411,7 +1411,7 @@
void ppIRDirty ( const IRDirty* d )
{
Int i;
- if (!isIRTempInvalid(d->tmp)) {
+ if (d->tmp != IRTemp_INVALID) {
ppIRTemp(d->tmp);
vex_printf(" = ");
}
@@ -1453,7 +1453,7 @@
{
/* Print even structurally invalid constructions, as an aid to
debugging. */
- if (!isIRTempInvalid(cas->oldHi)) {
+ if (cas->oldHi != IRTemp_INVALID) {
ppIRTemp(cas->oldHi);
vex_printf(",");
}
@@ -1599,6 +1599,39 @@
ppIRPhiVec_wrk(phis, 0);
}

+static void ppIRTempDefSet_wrk(const IRTempDefSet* defd, UInt depth)
+{
+ UInt tmps_printed = 0;
+
+ for (UInt slot = 0; slot < defd->slots_used; slot++) {
+ UChar slot_value = defd->set[slot];
+ for (UInt bit = 0; bit < sizeof(UChar); bit++) {
+ if (slot_value & (1 << bit)) {
+ if (tmps_printed % 8 == 0)
+ print_depth(depth);
+
+ IRTemp tmp = slot * sizeof(UChar) + bit;
+ ppIRTemp(tmp);
+
+ if (tmps_printed % 8 == 7)
+ vex_printf("\n");
+ else
+ vex_printf(" ");
+
+ tmps_printed += 1;
+ }
+ }
+ }
+
+ if (tmps_printed > 0 && tmps_printed % 8 != 7)
+ vex_printf("\n");
+}
+
+void ppIRTempDefSet(const IRTempDefSet* defd)
+{
+ ppIRTempDefSet_wrk(defd, 0);
+}
+
void ppIRStmt_wrk(const IRStmt* s, UInt depth)
{
print_depth(depth);
@@ -1705,32 +1738,26 @@
ppIRStmt_wrk(s, 0);
}

-static void ppIRTypeEnv_wrk(const IRTypeEnv* env, UInt depth)
+void ppIRTypeEnv(const IRTypeEnv* env)
{
- for (UInt i = 0; i < env->types_used; i++) {
+ for (UInt i = 0; i < env->used; i++) {
if (i % 8 == 0)
- print_depth(depth);
- IRTemp temp = mkIRTemp(env->id, i);
- ppIRTemp(temp);
- vex_printf("=");
+ print_depth(1);
+ ppIRTemp(i);
+ vex_printf(":%u=", env->ids[i]);
ppIRType(env->types[i]);
if (i % 8 == 7)
vex_printf( "\n");
else
vex_printf( " ");
}
- if (env->types_used > 0 && env->types_used % 8 != 7)
+ if (env->used > 0 && env->used % 8 != 7)
vex_printf( "\n");
}

-void ppIRTypeEnv(const IRTypeEnv* env)
-{
- ppIRTypeEnv_wrk(env, 0);
-}
-
void ppIRStmtVec_wrk(const IRStmtVec* stmts, UInt depth)
{
- ppIRTypeEnv_wrk(stmts->tyenv, depth);
+ ppIRTempDefSet_wrk(stmts->def_set, depth);
vex_printf("\n");
for (UInt i = 0; i < stmts->stmts_used; i++) {
ppIRStmt_wrk(stmts->stmts[i], depth);
@@ -1748,6 +1775,7 @@
UInt depth = 0;

vex_printf("IRSB {\n");
+ ppIRTypeEnv(bb->tyenv);
ppIRStmtVec_wrk(bb->stmts, depth + 1);
print_depth(depth + 1);
vex_printf("PUT(%d) = ", bb->offsIP);
@@ -2123,16 +2151,15 @@
/* Constructors -- IRDirty */

IRDirty* emptyIRDirty ( void ) {
- IRDirty* d = LibVEX_Alloc_inline(sizeof(IRDirty));
- d->cee = NULL;
- d->guard = NULL;
- d->args = NULL;
- d->tmp.id = IRTyEnvID_INVALID;
- d->tmp.index = IRTyEnvIndex_INVALID;
- d->mFx = Ifx_None;
- d->mAddr = NULL;
- d->mSize = 0;
- d->nFxState = 0;
+ IRDirty* d = LibVEX_Alloc_inline(sizeof(IRDirty));
+ d->cee = NULL;
+ d->guard = NULL;
+ d->args = NULL;
+ d->tmp = IRTemp_INVALID;
+ d->mFx = Ifx_None;
+ d->mAddr = NULL;
+ d->mSize = 0;
+ d->nFxState = 0;
return d;
}

@@ -2217,6 +2244,16 @@
return vec;
}

+IRTempDefSet* emptyIRTempDefSet(void)
+{
+ IRTempDefSet* defset = LibVEX_Alloc_inline(sizeof(IRTempDefSet));
+ defset->slots_used = 0;
+ defset->slots_size = 8 / sizeof(UChar);
+ vassert(defset->slots_size >= 1);
+ defset->set = LibVEX_Alloc_inline(defset->slots_size * sizeof(UChar));
+ return defset;
+}
+
IRStmt* IRStmt_NoOp ( void )
{
/* Just use a single static closure. */
@@ -2340,13 +2377,13 @@

/* Constructors -- IRTypeEnv */

-IRTypeEnv* emptyIRTypeEnv ( void )
+static IRTypeEnv* emptyIRTypeEnv ( void )
{
IRTypeEnv* env = LibVEX_Alloc_inline(sizeof(IRTypeEnv));
env->types = LibVEX_Alloc_inline(8 * sizeof(IRType));
- env->types_size = 8;
- env->types_used = 0;
- env->id = IRTyEnvID_INVALID;
+ env->ids = LibVEX_Alloc_inline(8 * sizeof(IRStmtVecID));
+ env->size = 8;
+ env->used = 0;
return env;
}

@@ -2356,11 +2393,12 @@
IRStmtVec* emptyIRStmtVec(void)
{
IRStmtVec* stmts = LibVEX_Alloc_inline(sizeof(IRStmtVec));
- stmts->tyenv = emptyIRTypeEnv();
stmts->stmts_used = 0;
stmts->stmts_size = 8;
stmts->stmts = LibVEX_Alloc_inline(stmts->stmts_size * sizeof(IRStmt*));
+ stmts->id = IRStmtVecID_INVALID;
stmts->parent = NULL;
+ stmts->def_set = emptyIRTempDefSet();
return stmts;
}

@@ -2370,21 +2408,22 @@
IRSB* emptyIRSB ( void )
{
IRSB* bb = LibVEX_Alloc_inline(sizeof(IRSB));
+ bb->tyenv = emptyIRTypeEnv();
bb->stmts = emptyIRStmtVec();
bb->id_seq = 0;
bb->next = NULL;
bb->jumpkind = Ijk_Boring;
bb->offsIP = 0;

- bb->stmts->tyenv->id = nextIRTyEnvID(bb);
+ bb->stmts->id = nextIRStmtVecID(bb);
return bb;
}

-IRTyEnvID nextIRTyEnvID(IRSB* irsb)
+IRStmtVecID nextIRStmtVecID(IRSB* irsb)
{
- IRTyEnvID next = irsb->id_seq;
+ IRStmtVecID next = irsb->id_seq;
irsb->id_seq += 1;
- vassert(irsb->id_seq < IRTyEnvID_INVALID);
+ vassert(irsb->id_seq < IRStmtVecID_INVALID);
return next;
}

@@ -2648,8 +2687,9 @@
IRStmtVec* deepCopyIRStmtVec(const IRStmtVec* src, IRStmtVec* parent)
{
IRStmtVec* vec2 = LibVEX_Alloc_inline(sizeof(IRStmtVec));
- vec2->tyenv = deepCopyIRTypeEnv(src->tyenv);
+ vec2->id = src->id;
vec2->parent = parent;
+ vec2->def_set = deepCopyIRTempDefSet(src->def_set);
vec2->stmts_used = vec2->stmts_size = src->stmts_used;
IRStmt **stmts2 = LibVEX_Alloc_inline(vec2->stmts_used * sizeof(IRStmt*));
for (UInt i = 0; i < vec2->stmts_used; i++) {
@@ -2661,33 +2701,33 @@

IRTypeEnv* deepCopyIRTypeEnv(const IRTypeEnv* src)
{
- IRTypeEnv* dst = LibVEX_Alloc_inline(sizeof(IRTypeEnv));
- dst->types_size = src->types_size;
- dst->types_used = src->types_used;
- dst->types = LibVEX_Alloc_inline(dst->types_size * sizeof(IRType));
- for (UInt i = 0; i < src->types_used; i++)
+ IRTypeEnv* dst = LibVEX_Alloc_inline(sizeof(IRTypeEnv));
+ dst->size = src->size;
+ dst->used = src->used;
+ dst->types = LibVEX_Alloc_inline(dst->size * sizeof(IRType));
+ dst->ids = LibVEX_Alloc_inline(dst->size * sizeof(IRStmtVecID));
+ for (UInt i = 0; i < src->used; i++) {
dst->types[i] = src->types[i];
- dst->id = src->id;
+ dst->ids[i] = src->ids[i];
+ }
return dst;
}

IRSB* deepCopyIRSB ( const IRSB* bb )
{
IRSB* bb2 = deepCopyIRSBExceptStmts(bb);
- // TODO-JIT: does a deep copy of bb->stmts->tyenv once more
bb2->stmts = deepCopyIRStmtVec(bb->stmts, NULL);
return bb2;
}

IRSB* deepCopyIRSBExceptStmts ( const IRSB* bb )
{
- IRSB* bb2 = emptyIRSB();
- bb2->stmts = emptyIRStmtVec();
- bb2->stmts->tyenv = deepCopyIRTypeEnv(bb->stmts->tyenv);
- bb2->id_seq = bb->id_seq;
- bb2->next = deepCopyIRExpr(bb->next);
- bb2->jumpkind = bb->jumpkind;
- bb2->offsIP = bb->offsIP;
+ IRSB* bb2 = emptyIRSB();
+ bb2->tyenv = deepCopyIRTypeEnv(bb->tyenv);
+ bb2->id_seq = bb->id_seq;
+ bb2->next = deepCopyIRExpr(bb->next);
+ bb2->jumpkind = bb->jumpkind;
+ bb2->offsIP = bb->offsIP;
return bb2;
}

@@ -3721,6 +3761,34 @@


/*---------------------------------------------------------------*/
+/*--- Helper functions for the IR -- IR Temp Defined Set ---*/
+/*---------------------------------------------------------------*/
+
+void setIRTempDefined(IRTempDefSet* def_set, IRTemp tmp)
+{
+ vassert(!isIRTempDefined(def_set, tmp));
+
+ if (tmp / sizeof(UChar) >= def_set->slots_size) {
+ UChar* new_set = LibVEX_Alloc_inline(2 * def_set->slots_size);
+ for (UInt i = 0; i < def_set->slots_used; i++) {
+ new_set[i] = def_set->set[i];
+ }
+ def_set->set = new_set;
+ def_set->slots_size *= 2;
+ }
+
+ if (tmp / sizeof(UChar) >= def_set->slots_used) {
+ for (UInt i = def_set->slots_used; i < tmp / sizeof(UChar); i++) {
+ def_set->set[i] = 0;
+ }
+ def_set->slots_used = tmp / sizeof(UChar);
+ }
+
+ UInt mask = (1 << (tmp % sizeof(UChar)));
+ def_set->set[tmp / sizeof(UChar)] |= mask;
+}
+
+/*---------------------------------------------------------------*/
/*--- Helper functions for the IR -- IR Basic Blocks ---*/
/*---------------------------------------------------------------*/

@@ -3747,11 +3815,11 @@
IRStmt *addEmptyIfThenElse(IRSB* bb, IRStmtVec* parent, IRExpr* cond)
{
IRStmtVec* then_leg = emptyIRStmtVec();
- then_leg->tyenv->id = nextIRTyEnvID(bb);
+ then_leg->id = nextIRStmtVecID(bb);
then_leg->parent = parent;

IRStmtVec* else_leg = emptyIRStmtVec();
- else_leg->tyenv->id = nextIRTyEnvID(bb);
+ else_leg->id = nextIRStmtVecID(bb);
else_leg->parent = parent;

IRStmt* st = IRStmt_IfThenElse(cond, then_leg, else_leg, emptyIRPhiVec());
@@ -3763,30 +3831,33 @@
/*--- Helper functions for the IR -- IR Type Environments ---*/
/*---------------------------------------------------------------*/

-/* Allocate a new IRTemp, given its type. */
-
-IRTemp newIRTemp ( IRTypeEnv* env, IRType ty )
+IRTemp newIRTemp(IRTypeEnv* env, IRStmtVec* stmts, IRType ty)
{
- vassert(env);
- vassert(env->types_used >= 0);
- vassert(env->types_size >= 0);
- vassert(env->types_used <= env->types_size);
- vassert(env->id != IRTyEnvID_INVALID);
-
- if (env->types_used < env->types_size) {
- env->types[env->types_used] = ty;
- return mkIRTemp(env->id, env->types_used++);
- } else {
- Int i;
- Int new_size = env->types_size==0 ? 8 : 2*env->types_size;
- IRType* new_types
- = LibVEX_Alloc_inline(new_size * sizeof(IRType));
- for (i = 0; i < env->types_used; i++)
+ vassert(env != NULL);
+ vassert(stmts != NULL);
+ vassert(env->used >= 0);
+ vassert(env->size >= 0);
+ vassert(env->used <= env->size);
+
+ if (env->used == env->size) {
+ UInt new_size = 2 * env->size;
+ IRType* new_types = LibVEX_Alloc_inline(new_size * sizeof(IRType));
+ IRStmtVecID* new_ids = LibVEX_Alloc_inline(new_size * sizeof(IRStmtVecID));
+ for (UInt i = 0; i < env->used; i++) {
new_types[i] = env->types[i];
- env->types = new_types;
- env->types_size = new_size;
- return newIRTemp(env, ty);
+ new_ids[i] = env->ids[i];
+ }
+ env->types = new_types;
+ env->ids = new_ids;
+ env->size = new_size;
}
+
+ IRTemp tmp = env->used;
+ env->used += 1;
+ env->types[tmp] = ty;
+ env->ids[tmp] = stmts->id;
+ setIRTempDefined(stmts->def_set, tmp);
+ return tmp;
}


@@ -3795,19 +3866,11 @@
/*---------------------------------------------------------------*/

inline
-IRType typeOfIRTemp(const IRStmtVec* stmts, IRTemp tmp)
+IRType typeOfIRTemp ( const IRTypeEnv* env, IRTemp tmp )
{
- const IRTypeEnv* tyenv = stmts->tyenv;
- while (tyenv->id != tmp.id) {
- stmts = stmts->parent;
- vassert(stmts != NULL);
- tyenv = stmts->tyenv;
- }
-
- vassert(tyenv->id == tmp.id);
- vassert(tmp.index >= 0);
- vassert(tmp.index < tyenv->types_used);
- return tyenv->types[tmp.index];
+ vassert(tmp >= 0);
+ vassert(tmp < env->used);
+ return env->types[tmp];
}

IRType typeOfIRConst ( const IRConst* con )
@@ -3847,7 +3910,7 @@
}
}

-IRType typeOfIRExpr ( const IRStmtVec* stmts, const IRExpr* e )
+IRType typeOfIRExpr ( const IRTypeEnv* tyenv, const IRExpr* e )
{
IRType t_dst, t_arg1, t_arg2, t_arg3, t_arg4;
start:
@@ -3859,7 +3922,7 @@
case Iex_GetI:
return e->Iex.GetI.descr->elemTy;
case Iex_RdTmp:
- return typeOfIRTemp(stmts, e->Iex.RdTmp.tmp);
+ return typeOfIRTemp(tyenv, e->Iex.RdTmp.tmp);
case Iex_Const:
return typeOfIRConst(e->Iex.Const.con);
case Iex_Qop:
@@ -3883,7 +3946,7 @@
case Iex_ITE:
e = e->Iex.ITE.iffalse;
goto start;
- /* return typeOfIRExpr(stmts, e->Iex.ITE.iffalse); */
+ /* return typeOfIRExpr(tyenv, e->Iex.ITE.iffalse); */
case Iex_Binder:
vpanic("typeOfIRExpr: Binder is not a valid expression");
case Iex_VECRET:
@@ -4074,10 +4137,10 @@
bit expression, depending on the guest's word size.

Each temp is assigned only once, before its uses.
- Each temp is referenced from the right scope.
+ Each temp assigned and referenced is in scope.

Phi functions refer to existing, already assigned temporaries from
- [parent, then leg, else leg] type environments.
+ [parent, then leg, else leg].
*/

static inline Int countArgs ( IRExpr** args )
@@ -4141,62 +4204,60 @@
def_count is zero. Report any which are assigned more than once or assigned
after being used. */

-static Bool inRangeIRTemp(const IRStmtVec* stmts, IRTemp tmp)
+static Bool inRangeIRTemp(const IRTypeEnv* tyenv, IRTemp tmp)
{
- vassert(tmp.id != IRTyEnvID_INVALID);
-
- if (tmp.index >= 0 || tmp.index < stmts->tyenv->types_used) {
+ if (tmp >= 0 || tmp < tyenv->used) {
return True;
}
return False;
}

-static Bool inScopeIRTemp(const IRStmtVec* stmts, IRTemp tmp)
+static Bool inScopeIRTemp(const IRTypeEnv* tyenv, const IRStmtVec* stmts,
+ IRTemp tmp)
{
- vassert(tmp.id != IRTyEnvID_INVALID);
+ IRStmtVecID id = tyenv->ids[tmp];
+ vassert(id != IRStmtVecID_INVALID);

- const IRTypeEnv* tyenv = stmts->tyenv;
- while (tyenv->id != tmp.id) {
+ while (!(isIRTempDefined(stmts->def_set, tmp))) {
stmts = stmts->parent;
if (stmts == NULL)
return False;
- tyenv = stmts->tyenv;
}

- vassert(tyenv->id == tmp.id);
return True;
}

static
void useBeforeDef_Temp(const IRSB* bb, const IRStmtVec* stmts,
- const IRStmt* stmt, IRTemp tmp, UInt* def_counts[])
+ const IRStmt* stmt, IRTemp tmp, UInt def_counts[])
{
- vassert(tmp.id != IRTyEnvID_INVALID);
+ const IRTypeEnv* tyenv = bb->tyenv;

- if (!inRangeIRTemp(stmts, tmp))
+ if (!inRangeIRTemp(tyenv, tmp))
sanityCheckFail(bb, stmt, "out of range Temp in IRExpr");
- if (!inScopeIRTemp(stmts, tmp))
+ if (!inScopeIRTemp(tyenv, stmts, tmp))
sanityCheckFail(bb, stmt, "out of scope Temp in IRExpr");
- if (def_counts[tmp.id][tmp.index] < 1)
+
+ if (def_counts[tmp] < 1)
sanityCheckFail(bb, stmt, "IRTemp use before def in IRExpr");
}

static
void assignedOnce_Temp(const IRSB* bb, const IRStmtVec* stmts,
- const IRStmt* stmt, IRTemp tmp, UInt* def_counts[],
+ const IRStmt* stmt, IRTemp tmp, UInt def_counts[],
const HChar* err_msg_out_of_range,
const HChar* err_msg_out_of_scope,
const HChar* err_msg_assigned_more_than_once)
{
- vassert(tmp.id != IRTyEnvID_INVALID);
+ const IRTypeEnv* tyenv = bb->tyenv;

- if (!inRangeIRTemp(stmts, tmp))
+ if (!inRangeIRTemp(tyenv, tmp))
sanityCheckFail(bb, stmt, err_msg_out_of_range);
- if (!inScopeIRTemp(stmts, tmp))
+ if (!inScopeIRTemp(tyenv, stmts, tmp))
sanityCheckFail(bb, stmt, err_msg_out_of_scope);

- def_counts[tmp.id][tmp.index]++;
- if (def_counts[tmp.id][tmp.index] > 1) {
+ def_counts[tmp]++;
+ if (def_counts[tmp] > 1) {
sanityCheckFail(bb, stmt, err_msg_assigned_more_than_once);
}
}
@@ -4204,7 +4265,7 @@
static
void useBeforeDef_Expr(const IRSB *bb, const IRStmtVec* stmts,
const IRStmt* stmt, const IRExpr* expr,
- UInt* def_counts[])
+ UInt def_counts[])
{
Int i;
switch (expr->tag) {
@@ -4269,7 +4330,7 @@

static void useBeforeDef_IRPhi(const IRSB* bb, const IRStmtVec* stmts,
const IRStmt* stmt, const IRPhi* phi,
- UInt* def_counts[])
+ UInt def_counts[])
{
vassert(stmt->tag == Ist_IfThenElse);

@@ -4281,15 +4342,16 @@

/* Check also that referenced IRStmtVec's actually exist and belong to
"parent", "then", and "else", respectively. */
- if (phi->dst.id != stmts->tyenv->id) {
+ const IRTypeEnv* tyenv = bb->tyenv;
+ if (tyenv->ids[phi->dst] != stmts->id) {
sanityCheckFail(bb, stmt, "Istmt.IfThenElse.Phi.dst does not "
"reference parent IRStmtVec");
}
- if (phi->srcThen.id != then_leg->tyenv->id) {
+ if (tyenv->ids[phi->srcThen] != then_leg->id) {
sanityCheckFail(bb, stmt, "Istmt.IfThenElse.Phi.srcThen does not "
"reference \"then\" IRStmtVec leg");
}
- if (phi->srcElse.id != else_leg->tyenv->id) {
+ if (tyenv->ids[phi->srcElse] != else_leg->id) {
sanityCheckFail(bb, stmt, "Istmt.IfThenElse.Phi.srcElse does not "
"reference \"else\" IRStmtVec leg");
}
@@ -4297,7 +4359,7 @@

static
void useBeforeDef_Stmt(const IRSB* bb, const IRStmtVec* stmts,
- const IRStmt* stmt, UInt* def_counts[])
+ const IRStmt* stmt, UInt def_counts[])
{
Int i;
const IRDirty* d;
@@ -4388,7 +4450,7 @@

static
void assignedOnce_Stmt(const IRSB* bb, const IRStmtVec* stmts,
- const IRStmt* stmt, UInt* def_counts[])
+ const IRStmt* stmt, UInt def_counts[])
{
switch (stmt->tag) {
case Ist_WrTmp:
@@ -4406,7 +4468,7 @@
"IRStmt.LoadG: destination tmp is assigned more than once");
break;
case Ist_Dirty:
- if (!isIRTempInvalid(stmt->Ist.Dirty.details->tmp)) {
+ if (stmt->Ist.Dirty.details->tmp != IRTemp_INVALID) {
assignedOnce_Temp(
bb, stmts, stmt, stmt->Ist.Dirty.details->tmp, def_counts,
"IRStmt.Dirty: destination tmp is out of range",
@@ -4415,7 +4477,7 @@
}
break;
case Ist_CAS:
- if (!isIRTempInvalid(stmt->Ist.CAS.details->oldHi)) {
+ if (stmt->Ist.CAS.details->oldHi != IRTemp_INVALID) {
assignedOnce_Temp(
bb, stmts, stmt, stmt->Ist.CAS.details->oldHi, def_counts,
"IRStmt.CAS: destination tmpHi is out of range",
@@ -4451,7 +4513,7 @@

static void assignedOnce_IRPhi(const IRSB* bb, const IRStmtVec* stmts,
const IRStmt* stmt, const IRPhi* phi,
- UInt* def_counts[])
+ UInt def_counts[])
{
assignedOnce_Temp(bb, stmts, stmt, phi->dst, def_counts,
"IRStmt.IfThenElse.Phi: destination tmp is out of range",
@@ -4463,15 +4525,16 @@
void tcExpr(const IRSB* bb, const IRStmtVec* stmts, const IRStmt* stmt,
const IRExpr* expr, IRType gWordTy)
{
- Int i;
- IRType t_dst, t_arg1, t_arg2, t_arg3, t_arg4;
+ Int i;
+ IRType t_dst, t_arg1, t_arg2, t_arg3, t_arg4;
+ const IRTypeEnv* tyenv = bb->tyenv;
switch (expr->tag) {
case Iex_Get:
case Iex_RdTmp:
break;
case Iex_GetI:
tcExpr(bb, stmts, stmt, expr->Iex.GetI.ix, gWordTy);
- if (typeOfIRExpr(stmts, expr->Iex.GetI.ix) != Ity_I32)
+ if (typeOfIRExpr(tyenv, expr->Iex.GetI.ix) != Ity_I32)
sanityCheckFail(bb,stmt,"IRExpr.GetI.ix: not :: Ity_I32");
if (!saneIRRegArray(expr->Iex.GetI.descr))
sanityCheckFail(bb,stmt,"IRExpr.GetI.descr: invalid descr");
@@ -4494,10 +4557,10 @@
"Iex.Qop: wrong arity op\n"
"... name of op precedes BB printout\n");
}
- ttarg1 = typeOfIRExpr(stmts, qop->arg1);
- ttarg2 = typeOfIRExpr(stmts, qop->arg2);
- ttarg3 = typeOfIRExpr(stmts, qop->arg3);
- ttarg4 = typeOfIRExpr(stmts, qop->arg4);
+ ttarg1 = typeOfIRExpr(tyenv, qop->arg1);
+ ttarg2 = typeOfIRExpr(tyenv, qop->arg2);
+ ttarg3 = typeOfIRExpr(tyenv, qop->arg3);
+ ttarg4 = typeOfIRExpr(tyenv, qop->arg4);
if (t_arg1 != ttarg1 || t_arg2 != ttarg2
|| t_arg3 != ttarg3 || t_arg4 != ttarg4) {
vex_printf(" op name: ");
@@ -4545,9 +4608,9 @@
"Iex.Triop: wrong arity op\n"
"... name of op precedes BB printout\n");
}
- ttarg1 = typeOfIRExpr(stmts, triop->arg1);
- ttarg2 = typeOfIRExpr(stmts, triop->arg2);
- ttarg3 = typeOfIRExpr(stmts, triop->arg3);
+ ttarg1 = typeOfIRExpr(tyenv, triop->arg1);
+ ttarg2 = typeOfIRExpr(tyenv, triop->arg2);
+ ttarg3 = typeOfIRExpr(tyenv, triop->arg3);
if (t_arg1 != ttarg1 || t_arg2 != ttarg2 || t_arg3 != ttarg3) {
vex_printf(" op name: ");
ppIROp(triop->op);
@@ -4588,8 +4651,8 @@
"Iex.Binop: wrong arity op\n"
"... name of op precedes BB printout\n");
}
- ttarg1 = typeOfIRExpr(stmts, expr->Iex.Binop.arg1);
- ttarg2 = typeOfIRExpr(stmts, expr->Iex.Binop.arg2);
+ ttarg1 = typeOfIRExpr(tyenv, expr->Iex.Binop.arg1);
+ ttarg2 = typeOfIRExpr(tyenv, expr->Iex.Binop.arg2);
if (t_arg1 != ttarg1 || t_arg2 != ttarg2) {
vex_printf(" op name: ");
ppIROp(expr->Iex.Binop.op);
@@ -4618,12 +4681,12 @@
if (t_arg1 == Ity_INVALID || t_arg2 != Ity_INVALID
|| t_arg3 != Ity_INVALID || t_arg4 != Ity_INVALID)
sanityCheckFail(bb,stmt,"Iex.Unop: wrong arity op");
- if (t_arg1 != typeOfIRExpr(stmts, expr->Iex.Unop.arg))
+ if (t_arg1 != typeOfIRExpr(tyenv, expr->Iex.Unop.arg))
sanityCheckFail(bb,stmt,"Iex.Unop: arg ty doesn't match op ty");
break;
case Iex_Load:
tcExpr(bb, stmts, stmt, expr->Iex.Load.addr, gWordTy);
- if (typeOfIRExpr(stmts, expr->Iex.Load.addr) != gWordTy)
+ if (typeOfIRExpr(tyenv, expr->Iex.Load.addr) != gWordTy)
sanityCheckFail(bb,stmt,"Iex.Load.addr: not :: guest word type");
if (expr->Iex.Load.end != Iend_LE && expr->Iex.Load.end != Iend_BE)
sanityCheckFail(bb,stmt,"Iex.Load.end: bogus endianness");
@@ -4645,7 +4708,7 @@
sanityCheckFail(bb,stmt,
"Iex.CCall.retty: cannot return :: Ity_I1");
for (i = 0; expr->Iex.CCall.args[i]; i++)
- if (typeOfIRExpr(stmts, expr->Iex.CCall.args[i]) == Ity_I1)
+ if (typeOfIRExpr(tyenv, expr->Iex.CCall.args[i]) == Ity_I1)
sanityCheckFail(bb,stmt,"Iex.CCall.arg: arg :: Ity_I1");
break;
case Iex_Const:
@@ -4656,10 +4719,10 @@
tcExpr(bb, stmts, stmt, expr->Iex.ITE.cond, gWordTy);
tcExpr(bb, stmts, stmt, expr->Iex.ITE.iftrue, gWordTy);
tcExpr(bb, stmts, stmt, expr->Iex.ITE.iffalse, gWordTy);
- if (typeOfIRExpr(stmts, expr->Iex.ITE.cond) != Ity_I1)
+ if (typeOfIRExpr(tyenv, expr->Iex.ITE.cond) != Ity_I1)
sanityCheckFail(bb,stmt,"Iex.ITE.cond: cond :: Ity_I1");
- if (typeOfIRExpr(stmts, expr->Iex.ITE.iftrue)
- != typeOfIRExpr(stmts, expr->Iex.ITE.iffalse))
+ if (typeOfIRExpr(tyenv, expr->Iex.ITE.iftrue)
+ != typeOfIRExpr(tyenv, expr->Iex.ITE.iffalse))
sanityCheckFail(bb,stmt,"Iex.ITE: iftrue/iffalse mismatch");
break;
default:
@@ -4672,16 +4735,14 @@
const IRPhi* phi)
{
vassert(stmt->tag == Ist_IfThenElse);
- const IRStmtVec* then_leg = stmt->Ist.IfThenElse.then_leg;
- const IRStmtVec* else_leg = stmt->Ist.IfThenElse.else_leg;
+ const IRTypeEnv* tyenv = bb->tyenv;

- if (typeOfIRTemp(then_leg, phi->srcThen)
- != typeOfIRTemp(else_leg, phi->srcElse)) {
- sanityCheckFail(bb,stmt,"IRStmt.IfThenElse.Phi: 'then' and 'else' "
+ if (typeOfIRTemp(tyenv, phi->srcThen) != typeOfIRTemp(tyenv, phi->srcElse)) {
+ sanityCheckFail(bb, stmt, "IRStmt.IfThenElse.Phi: 'then' and 'else' "
"tmp do not match");
}
- if (typeOfIRTemp(stmts, phi->dst) != typeOfIRTemp(then_leg, phi->srcThen)) {
- sanityCheckFail(bb,stmt,"IRStmt.IfThenElse.Phi: 'dst' and 'then' "
+ if (typeOfIRTemp(tyenv, phi->dst) != typeOfIRTemp(tyenv, phi->srcThen)) {
+ sanityCheckFail(bb, stmt, "IRStmt.IfThenElse.Phi: 'dst' and 'then' "
"tmp do not match");
}
}
@@ -4690,7 +4751,8 @@
void tcStmt(const IRSB* bb, const IRStmtVec* stmts, const IRStmt* stmt,
Bool require_flat, IRType gWordTy)
{
- IRType tyExpd, tyData;
+ IRType tyExpd, tyData;
+ const IRTypeEnv* tyenv = bb->tyenv;
switch (stmt->tag) {
case Ist_IMark:
/* Somewhat heuristic, but rule out totally implausible
@@ -4701,28 +4763,28 @@
sanityCheckFail(bb,stmt,"IRStmt.IMark.delta: implausible");
break;
case Ist_AbiHint:
- if (typeOfIRExpr(stmts, stmt->Ist.AbiHint.base) != gWordTy)
+ if (typeOfIRExpr(tyenv, stmt->Ist.AbiHint.base) != gWordTy)
sanityCheckFail(bb,stmt,"IRStmt.AbiHint.base: "
"not :: guest word type");
- if (typeOfIRExpr(stmts, stmt->Ist.AbiHint.nia) != gWordTy)
+ if (typeOfIRExpr(tyenv, stmt->Ist.AbiHint.nia) != gWordTy)
sanityCheckFail(bb,stmt,"IRStmt.AbiHint.nia: "
"not :: guest word type");
break;
case Ist_Put:
tcExpr(bb, stmts, stmt, stmt->Ist.Put.data, gWordTy);
- if (typeOfIRExpr(stmts, stmt->Ist.Put.data) == Ity_I1)
+ if (typeOfIRExpr(tyenv, stmt->Ist.Put.data) == Ity_I1)
sanityCheckFail(bb,stmt,"IRStmt.Put.data: cannot Put :: Ity_I1");
break;
case Ist_PutI:{
const IRPutI* puti = stmt->Ist.PutI.details;
tcExpr(bb, stmts, stmt, puti->data, gWordTy);
tcExpr(bb, stmts, stmt, puti->ix, gWordTy);
- if (typeOfIRExpr(stmts, puti->data) == Ity_I1)
+ if (typeOfIRExpr(tyenv, puti->data) == Ity_I1)
sanityCheckFail(bb,stmt,
"IRStmt.PutI.data: cannot PutI :: Ity_I1");
- if (typeOfIRExpr(stmts, puti->data) != puti->descr->elemTy)
+ if (typeOfIRExpr(tyenv, puti->data) != puti->descr->elemTy)
sanityCheckFail(bb,stmt,"IRStmt.PutI.data: data ty != elem ty");
- if (typeOfIRExpr(stmts, puti->ix) != Ity_I32)
+ if (typeOfIRExpr(tyenv, puti->ix) != Ity_I32)
sanityCheckFail(bb,stmt,"IRStmt.PutI.ix: not :: Ity_I32");
if (!saneIRRegArray(puti->descr))
sanityCheckFail(bb,stmt,"IRStmt.PutI.descr: invalid descr");
@@ -4730,18 +4792,18 @@
}
case Ist_WrTmp:
tcExpr(bb, stmts, stmt, stmt->Ist.WrTmp.data, gWordTy);
- if (typeOfIRTemp(stmts, stmt->Ist.WrTmp.tmp)
- != typeOfIRExpr(stmts, stmt->Ist.WrTmp.data))
+ 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");
break;
case Ist_Store:
tcExpr(bb, stmts, stmt, stmt->Ist.Store.addr, gWordTy);
tcExpr(bb, stmts, stmt, stmt->Ist.Store.data, gWordTy);
- if (typeOfIRExpr(stmts, stmt->Ist.Store.addr) != gWordTy)
+ if (typeOfIRExpr(tyenv, stmt->Ist.Store.addr) != gWordTy)
sanityCheckFail(bb,stmt,
"IRStmt.Store.addr: not :: guest word type");
- if (typeOfIRExpr(stmts, stmt->Ist.Store.data) == Ity_I1)
+ if (typeOfIRExpr(tyenv, stmt->Ist.Store.data) == 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)
@@ -4752,11 +4814,11 @@
tcExpr(bb, stmts, stmt, sg->addr, gWordTy);
tcExpr(bb, stmts, stmt, sg->data, gWordTy);
tcExpr(bb, stmts, stmt, sg->guard, gWordTy);
- if (typeOfIRExpr(stmts, sg->addr) != gWordTy)
+ if (typeOfIRExpr(tyenv, sg->addr) != gWordTy)
sanityCheckFail(bb,stmt,"IRStmtG...addr: not :: guest word type");
- if (typeOfIRExpr(stmts, sg->data) == Ity_I1)
+ if (typeOfIRExpr(tyenv, sg->data) == Ity_I1)
sanityCheckFail(bb,stmt,"IRStmtG...data: cannot Store :: Ity_I1");
- if (typeOfIRExpr(stmts, sg->guard) != 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");
@@ -4767,28 +4829,28 @@
tcExpr(bb, stmts, stmt, lg->addr, gWordTy);
tcExpr(bb, stmts, stmt, lg->alt, gWordTy);
tcExpr(bb, stmts, stmt, lg->guard, gWordTy);
- if (typeOfIRExpr(stmts, lg->guard) != Ity_I1)
+ if (typeOfIRExpr(tyenv, lg->guard) != Ity_I1)
sanityCheckFail(bb,stmt,"IRStmt.LoadG.guard: not :: Ity_I1");
- if (typeOfIRExpr(stmts, lg->addr) != gWordTy)
+ if (typeOfIRExpr(tyenv, lg->addr) != gWordTy)
sanityCheckFail(bb,stmt,"IRStmt.LoadG.addr: not "
":: guest word type");
- if (typeOfIRExpr(stmts, lg->alt) != typeOfIRTemp(stmts, lg->dst))
+ if (typeOfIRExpr(tyenv, lg->alt) != typeOfIRTemp(tyenv, lg->dst))
sanityCheckFail(bb,stmt,"IRStmt.LoadG: dst/alt type mismatch");
IRType cvtRes = Ity_INVALID, cvtArg = Ity_INVALID;
typeOfIRLoadGOp(lg->cvt, &cvtRes, &cvtArg);
- if (cvtRes != typeOfIRTemp(stmts, lg->dst))
+ if (cvtRes != typeOfIRTemp(tyenv, lg->dst))
sanityCheckFail(bb,stmt,"IRStmt.LoadG: dst/loaded type mismatch");
break;
}
case Ist_CAS: {
const IRCAS* cas = stmt->Ist.CAS.details;
/* make sure it's definitely either a CAS or a DCAS */
- if (isIRTempInvalid(cas->oldHi)
+ if (cas->oldHi == IRTemp_INVALID
&& cas->expdHi == NULL && cas->dataHi == NULL) {
/* fine; it's a single cas */
}
else
- if (!isIRTempInvalid(cas->oldHi)
+ if (cas->oldHi != IRTemp_INVALID
&& cas->expdHi != NULL && cas->dataHi != NULL) {
/* fine; it's a double cas */
}
@@ -4798,12 +4860,12 @@
}
/* check the address type */
tcExpr(bb, stmts, stmt, cas->addr, gWordTy);
- if (typeOfIRExpr(stmts, cas->addr) != gWordTy) goto bad_cas;
+ if (typeOfIRExpr(tyenv, cas->addr) != gWordTy) goto bad_cas;
/* check types on the {old,expd,data}Lo components agree */
- tyExpd = typeOfIRExpr(stmts, cas->expdLo);
- tyData = typeOfIRExpr(stmts, cas->dataLo);
+ tyExpd = typeOfIRExpr(tyenv, cas->expdLo);
+ tyData = typeOfIRExpr(tyenv, cas->dataLo);
if (tyExpd != tyData) goto bad_cas;
- if (tyExpd != typeOfIRTemp(stmts, cas->oldLo))
+ if (tyExpd != typeOfIRTemp(tyenv, cas->oldLo))
goto bad_cas;
/* check the base element type is sane */
if (tyExpd == Ity_I8 || tyExpd == Ity_I16 || tyExpd == Ity_I32
@@ -4814,16 +4876,16 @@
}
/* If it's a DCAS, check types on the {old,expd,data}Hi
components too */
- if (!isIRTempInvalid(cas->oldHi)) {
- tyExpd = typeOfIRExpr(stmts, cas->expdHi);
- tyData = typeOfIRExpr(stmts, cas->dataHi);
+ if (cas->oldHi != IRTemp_INVALID) {
+ tyExpd = typeOfIRExpr(tyenv, cas->expdHi);
+ tyData = typeOfIRExpr(tyenv, cas->dataHi);
if (tyExpd != tyData) goto bad_cas;
- if (tyExpd != typeOfIRTemp(stmts, cas->oldHi))
+ if (tyExpd != typeOfIRTemp(tyenv, cas->oldHi))
goto bad_cas;
/* and finally check that oldLo and oldHi have the same
type. This forces equivalence amongst all 6 types. */
- if (typeOfIRTemp(stmts, cas->oldHi)
- != typeOfIRTemp(stmts, cas->oldLo))
+ if (typeOfIRTemp(tyenv, cas->oldHi)
+ != typeOfIRTemp(tyenv, cas->oldLo))
goto bad_cas;
}
break;
@@ -4833,11 +4895,11 @@
}
case Ist_LLSC: {
IRType tyRes;
- if (typeOfIRExpr(stmts, stmt->Ist.LLSC.addr) != gWordTy)
+ if (typeOfIRExpr(tyenv, stmt->Ist.LLSC.addr) != gWordTy)
sanityCheckFail(bb,stmt,"IRStmt.LLSC.addr: not :: guest word type");
if (stmt->Ist.LLSC.end != Iend_LE && stmt->Ist.LLSC.end != Iend_BE)
sanityCheckFail(bb,stmt,"Ist.LLSC.end: bogus endianness");
- tyRes = typeOfIRTemp(stmts, stmt->Ist.LLSC.result);
+ tyRes = typeOfIRTemp(tyenv, stmt->Ist.LLSC.result);
if (stmt->Ist.LLSC.storedata == NULL) {
/* it's a LL */
if (tyRes != Ity_I64 && tyRes != Ity_I32
@@ -4847,7 +4909,7 @@
/* it's a SC */
if (tyRes != Ity_I1)
sanityCheckFail(bb,stmt,"Ist.LLSC(SC).result: not :: Ity_I1");
- tyData = typeOfIRExpr(stmts, stmt->Ist.LLSC.storedata);
+ tyData = typeOfIRExpr(tyenv, stmt->Ist.LLSC.storedata);
if (tyData != Ity_I64 && tyData != Ity_I32
&& tyData != Ity_I16 && tyData != Ity_I8)
sanityCheckFail(bb,stmt,
@@ -4886,12 +4948,12 @@
/* check guard */
if (d->guard == NULL) goto bad_dirty;
tcExpr(bb, stmts, stmt, d->guard, gWordTy);
- if (typeOfIRExpr(stmts, d->guard) != Ity_I1)
+ if (typeOfIRExpr(tyenv, d->guard) != Ity_I1)
sanityCheckFail(bb,stmt,"IRStmt.Dirty.guard not :: Ity_I1");
/* check types, minimally */
IRType retTy = Ity_INVALID;
- if (!isIRTempInvalid(d->tmp)) {
- retTy = typeOfIRTemp(stmts, d->tmp);
+ if (d->tmp != IRTemp_INVALID) {
+ retTy = typeOfIRTemp(tyenv, d->tmp);
if (retTy == Ity_I1)
sanityCheckFail(bb,stmt,"IRStmt.Dirty.dst :: Ity_I1");
}
@@ -4905,7 +4967,7 @@
} else if (UNLIKELY(arg->tag == Iex_GSPTR)) {
nGSPTRs++;
} else {
- if (typeOfIRExpr(stmts, arg) == Ity_I1)
+ if (typeOfIRExpr(tyenv, arg) == Ity_I1)
sanityCheckFail(bb,stmt,"IRStmt.Dirty.arg[i] :: Ity_I1");
}
if (nGSPTRs > 1) {
@@ -4956,7 +5018,7 @@
break;
case Ist_Exit:
tcExpr(bb, stmts, stmt, stmt->Ist.Exit.guard, gWordTy);
- if (typeOfIRExpr(stmts,stmt->Ist.Exit.guard) != Ity_I1)
+ if (typeOfIRExpr(tyenv, stmt->Ist.Exit.guard) != Ity_I1)
sanityCheckFail(bb,stmt,"IRStmt.Exit.guard: not :: Ity_I1");
if (!saneIRConst(stmt->Ist.Exit.dst))
sanityCheckFail(bb,stmt,"IRStmt.Exit.dst: bad dst");
@@ -4968,7 +5030,7 @@
break;
case Ist_IfThenElse:
tcExpr(bb, stmts, stmt, stmt->Ist.IfThenElse.cond, gWordTy);
- if (typeOfIRExpr(stmts, stmt->Ist.IfThenElse.cond) != Ity_I1)
+ if (typeOfIRExpr(tyenv, stmt->Ist.IfThenElse.cond) != Ity_I1)
sanityCheckFail(bb,stmt,"IRStmt.IfThenElse.cond: not :: Ity_I1");
/* Traversing into legs and phi nodes driven from
sanityCheckIRStmtVec(). */
@@ -4979,7 +5041,7 @@
}

static void sanityCheckIRPhiNodes(const IRSB* bb, const IRStmtVec* stmts,
- const IRStmt* stmt, const IRPhiVec* phi_nodes, UInt *def_counts[])
+ const IRStmt* stmt, const IRPhiVec* phi_nodes, UInt def_counts[])
{
for (UInt i = 0; i < phi_nodes->phis_used; i++) {
const IRPhi* phi = phi_nodes->phis[i];
@@ -4991,51 +5053,32 @@

static
void sanityCheckIRStmtVec(const IRSB* bb, const IRStmtVec* stmts,
- Bool require_flat, UInt* def_counts[],
- UInt n_stmt_vecs, UInt id_counts[],
- IRType gWordTy)
-{
- const IRTypeEnv* tyenv = stmts->tyenv;
- IRTyEnvID id = tyenv->id;
- if (id == IRTyEnvID_INVALID) {
- vpanic("sanityCheckIRStmtVec: invalid IRTypeEnv ID");
+ Bool require_flat, UInt def_counts[],
+ UInt id_counts[], UInt n_ids, IRType gWordTy)
+{
+ IRStmtVecID id = stmts->id;
+ if (id == IRStmtVecID_INVALID) {
+ vpanic("sanityCheckIRStmtVec: invalid IRStmtVec ID");
}

- if (id >= n_stmt_vecs) {
- vex_printf("IRTypeEnv's ID (%u) is larger than number of IRStmtVec's "
- "(%u)\n", id, n_stmt_vecs);
- sanityCheckFail(bb, NULL, "IRTypeEnv's ID larger than number of "
+ if (id >= n_ids) {
+ vex_printf("IRStmtVec's ID (%u) is larger than number of IRStmtVec's "
+ "(%u)\n", id, n_ids);
+ sanityCheckFail(bb, NULL, "IRStmtVec's ID larger than number of "
"IRStmtVec's");
}

id_counts[id] += 1;
if (id_counts[id] > 1) {
- sanityCheckFail(bb, NULL, "the same IRTyEnv ID used more than once");
+ sanityCheckFail(bb, NULL, "the same IRStmtVec ID used more than once");
}

- UInt n_temps = tyenv->types_used;
- def_counts[id] = LibVEX_Alloc_inline(n_temps * sizeof(UInt));
- for (UInt i = 0; i < n_temps; i++)
- def_counts[id][i] = 0;
-
if (stmts->stmts_used < 0 || stmts->stmts_size < 8
|| stmts->stmts_used > stmts->stmts_size) {
/* this IRStmtVec is so strange we can't even print it */
vpanic("sanityCheckIRStmtVec: stmts array limits wierd");
}

- /* Ensure each temp has a plausible type. */
- for (UInt i = 0; i < n_temps; i++) {
- IRTemp temp = mkIRTemp(id, i);
- IRType ty = typeOfIRTemp(stmts, temp);
- if (!isPlausibleIRType(ty)) {
- vex_printf("Temp ");
- ppIRTemp(temp);
- vex_printf(" declared with implausible type 0x%x\n", (UInt) ty);
- sanityCheckFail(bb, NULL, "Temp declared with implausible type");
- }
- }
-
for (UInt i = 0; i < stmts->stmts_used; i++) {
const IRStmt *stmt = stmts->stmts[i];
if (stmt == NULL)
@@ -5074,36 +5117,52 @@
}

sanityCheckIRStmtVec(bb, then_leg, require_flat, def_counts,
- n_stmt_vecs, id_counts, gWordTy);
+ id_counts, n_ids, gWordTy);
sanityCheckIRStmtVec(bb, else_leg, require_flat, def_counts,
- n_stmt_vecs, id_counts, gWordTy);
+ id_counts, n_ids, gWordTy);
sanityCheckIRPhiNodes(bb, stmts, stmt,
stmt->Ist.IfThenElse.phi_nodes, def_counts);
}
}
}

-
/* Sanity checks basic block of IR.
Also checks for IRTyEnvID uniqueness. */
void sanityCheckIRSB(const IRSB* bb, const HChar* caller, Bool require_flat,
IRType gWordTy)
{
- UInt n_stmt_vecs = bb->id_seq;
- UInt **def_counts = LibVEX_Alloc_inline(n_stmt_vecs * sizeof(UInt *));
- UInt *id_counts = LibVEX_Alloc_inline(n_stmt_vecs * sizeof(UInt));
- for (UInt i = 0; i < n_stmt_vecs; i++) {
- def_counts[i] = NULL;
+ UInt n_ids = bb->id_seq + 1;
+ UInt *id_counts = LibVEX_Alloc_inline(n_ids * sizeof(UInt));
+ for (UInt i = 0; i < n_ids; i++) {
id_counts[i] = 0;
}

+ const IRTypeEnv* tyenv = bb->tyenv;
+ UInt n_temps = tyenv->used;
+ UInt *def_counts = LibVEX_Alloc_inline(n_temps * sizeof(UInt));
+ for (UInt i = 0; i < n_temps; i++) {
+ def_counts[i] = 0;
+ }
+
if (0)
vex_printf("sanityCheck: %s\n", caller);

vassert(gWordTy == Ity_I32 || gWordTy == Ity_I64);

- sanityCheckIRStmtVec(bb, bb->stmts, require_flat, def_counts, n_stmt_vecs,
- id_counts, gWordTy);
+ /* Ensure each temp has a plausible type. */
+ for (UInt i = 0; i < n_temps; i++) {
+ IRTemp temp = (IRTemp) i;
+ IRType ty = typeOfIRTemp(tyenv, temp);
+ if (!isPlausibleIRType(ty)) {
+ vex_printf("Temp ");
+ ppIRTemp(temp);
+ vex_printf(" declared with implausible type 0x%x\n", (UInt) ty);
+ sanityCheckFail(bb, NULL, "Temp declared with implausible type");
+ }
+ }
+
+ sanityCheckIRStmtVec(bb, bb->stmts, require_flat, def_counts, id_counts,
+ n_ids, gWordTy);

if (require_flat) {
if (!isIRAtom(bb->next)) {
@@ -5112,7 +5171,7 @@
}

/* Typecheck also next destination. */
- if (typeOfIRExpr(bb->stmts, bb->next) != gWordTy) {
+ if (typeOfIRExpr(bb->tyenv, bb->next) != gWordTy) {
sanityCheckFail(bb, NULL, "bb->next field has wrong type");
}
/* because it would intersect with host_EvC_* */
@@ -5231,7 +5290,7 @@
vassert(isIRAtom(a1));
vassert(isIRAtom(a2));
if (a1->tag == Iex_RdTmp && a2->tag == Iex_RdTmp)
- return eqIRTemp(a1->Iex.RdTmp.tmp, a2->Iex.RdTmp.tmp);
+ return toBool(a1->Iex.RdTmp.tmp == a2->Iex.RdTmp.tmp);
if (a1->tag == Iex_Const && a2->tag == Iex_Const)
return eqIRConst(a1->Iex.Const.con, a2->Iex.Const.con);
return False;

Modified: branches/VEX_JIT_HACKS/pub/libvex_ir.h
==============================================================================
--- branches/VEX_JIT_HACKS/pub/libvex_ir.h (original)
+++ branches/VEX_JIT_HACKS/pub/libvex_ir.h Sat Mar 25 08:02:31 2017
@@ -54,13 +54,13 @@
'IRSB'). Each code block typically represents from 1 to perhaps 50
instructions. IRSBs are single-entry, multiple-exit code blocks.
Each IRSB contains three things:
- - a vector of statements, which represent code, together with the associated
- type environment (which indicates the type of each temporary value present
- in statements)
+ - a type environment, which indicates the type of each temporary
+ value present in the IRSB
+ - a vector of statements, which represent code
- a jump that exits from the end of the IRSB
Flow control can leave the IRSB before the final exit only in a leg of an
- "if-then-else" statement. A leg of an "if-then-else" statement is de facto
- another vector of statements and as such has also its type environment.
+ "if-then-else" statement. A leg of an "if-then-else" statement is just
+ another vector of statements.
"If-then-else" statements can be nested, however this is currently not
supported.
IRSBs can cover multiple non-consecutive sequences of code (up to 3).
@@ -107,10 +107,10 @@
One Vex IR translation for this code would be this:

------ IMark(0x24F275, 7, 0) ------
- t0:3 = GET:I32(0) # get %eax, a 32-bit integer
- t0:2 = GET:I32(12) # get %ebx, a 32-bit integer
- t0:1 = Add32(t0:3,t0:2) # addl
- PUT(0) = t1:1 # put %eax
+ t3 = GET:I32(0) # get %eax, a 32-bit integer
+ t2 = GET:I32(12) # get %ebx, a 32-bit integer
+ t1 = Add32(t3,t2) # addl
+ PUT(0) = t1 # put %eax

(For simplicity, this ignores the effects on the condition codes, and
the update of the instruction pointer.)
@@ -124,7 +124,7 @@

The five statements in this example are:
- the IMark
- - three assignments to temporaries (they all belong to type environment ID 0)
+ - three assignments to temporaries
- one register write (put)

The six expressions in this example are:
@@ -150,11 +150,11 @@
updates):

------ IMark(0x4000ABA, 3, 0) ------
- t0:3 = Add32(GET:I32(0),0x4:I32)
- t0:2 = LDle:I32(t0:3)
- t0:1 = GET:I32(8)
- t0:0 = Add32(t0:2,t0:1)
- STle(t0:3) = t0:0
+ t3 = Add32(GET:I32(0),0x4:I32)
+ t2 = LDle:I32(t3)
+ t1 = GET:I32(8)
+ t0 = Add32(t2,t1)
+ STle(t3) = t0

The "le" in "LDle" and "STle" is short for "little-endian".

@@ -391,51 +391,17 @@

/* ------------------ Temporaries ------------------ */

-/* These represent IR SSA temporaries. A temporary is uniquely identified by its
- type environment id and local index, such as (3, 1). Such a temporary belongs
- to type environment id 3 and its local index within this type environment
- is 1. Shorter representation would be t3:1.
-
- The IR optimiser relies on the fact that IRTemps are 32-bit ints (16 bits for
- type environment id and 16 bits for local index). Do not change them to
- be ints of any other size. */
+/* This represents a temporary, eg. t1. The IR optimiser relies on the
+ fact that IRTemps are 32-bit ints. Do not change them to be ints of
+ any other size. */

-typedef UShort IRTyEnvID;
-typedef UShort IRTyEnvIndex;
-
-#define IRTyEnvID_INVALID ((IRTyEnvID) 0xFFFF)
-#define IRTyEnvIndex_INVALID ((IRTyEnvIndex) 0xFFFF)
-
-typedef
- struct {
- IRTyEnvID id;
- IRTyEnvIndex index;
- }
- IRTemp;
-
-static inline IRTemp mkIRTemp(IRTyEnvID id, IRTyEnvIndex index)
-{
- IRTemp tmp = {id, index};
- return tmp;
-}
-
-static inline IRTemp IRTemp_INVALID(void)
-{
- return mkIRTemp(IRTyEnvID_INVALID, IRTyEnvIndex_INVALID);
-}
+typedef UInt IRTemp;

/* Pretty-print an IRTemp. */
extern void ppIRTemp ( IRTemp );

-static inline Bool isIRTempInvalid(IRTemp tmp)
-{
- return (tmp.id == IRTyEnvID_INVALID && tmp.index == IRTyEnvIndex_INVALID);
-}
+#define IRTemp_INVALID ((IRTemp) 0xFFFFFFFF)

-static inline Bool eqIRTemp(IRTemp t1, IRTemp t2)
-{
- return toBool(t1.id == t2.id && t1.index == t2.index);
-}

/* --------------- Primops (arity 1,2,3 and 4) --------------- */

@@ -2730,18 +2696,18 @@
A "phi" function is special "phony" function that does not have its
corresponding machine operation. Let's consider this example:
if (cond) {
- t0:1 = 3
+ t1 = 0x3:I64
} else {
- t0:1 = 4
+ t1 = 0x4:I64
}
However this is not possible under SSA rules (a temporary cannot be assigned
more than once). Now the "phi" function comes handy:
if (cond) {
- t1:1 = 3
+ t2 = 0x3:I64
} else {
- t2:1 = 4
+ t3 = 0x4:I64
}
- t0:1 = phi(t1:1,t2:1)
+ t1 = phi(t2,t3)
*/
typedef
struct {
@@ -2768,33 +2734,47 @@

extern void addIRPhiToIRPhiVec(IRPhiVec* , IRPhi*);

+/* ----------------- IRTemp Defined Set ----------------- */

-/* ------------------ Type Environments ------------------ */
+/* An IRTemp is defined in an IRStmtVec. By keeping track of where every IRTemp
+ is defined, it is possible to reason about IRTemp's scope.

-/* Type environments: a bunch of statements, expressions, etc, are incomplete
- without an environment indicating the type of each IRTemp. So this provides
- one. The array, 0 .. n_types_used-1, is indexed by "local index" component
- of IR temporaries. The type environment ID is used to uniquely identify
- temporaries across multiple IRStmtVec in an IRSB.
-*/
+ Let's have this IRStmtVec hierarchy:
+ IRSB
+ |- IRStmtVec #0
+ |- IRStmtVec #1
+ |- IRStmtVec #2
+ |- IRStmtVec #3
+ So an IRTemp defined in IRStmtVec #2 is valid (in scope) only
+ in IRStmtVec's #2 and #3; and out of scope in IRStmtVec's #0 and #1.
+
+ Every IRStmtVec has its IRTempDefSet structure. This is a bit set indexed
+ by IRTemp; value 1 means that a particular IRTemp is defined there.
+
+ 'bits' array does not grow each time an IRTemp is added to IRSB; it grows
+ lazily only when an IRTemp is marked as defined in a particular IRStmtVec.
+ */
typedef
struct {
- IRType* types;
- Int types_size;
- Int types_used;
- IRTyEnvID id;
+ UChar* set; // a bit set, use isIRTempDefined() for access
+ UInt slots_used;
+ UInt slots_size;
}
- IRTypeEnv;
-
-/* Obtain a new IRTemp */
-extern IRTemp newIRTemp(IRTypeEnv*, IRType);
+ IRTempDefSet;

-/* Deep-copy a type environment */
-extern IRTypeEnv* deepCopyIRTypeEnv(const IRTypeEnv* src);
-
-/* Pretty-print a type environment */
-extern void ppIRTypeEnv(const IRTypeEnv*);
+static inline Bool isIRTempDefined(const IRTempDefSet* defd, IRTemp tmp)
+{
+ if (tmp / sizeof(UChar) < defd->slots_size) {
+ UInt mask = (1 << (tmp % sizeof(UChar)));
+ return toBool(defd->set[tmp / sizeof(UChar)] & mask);
+ }
+ return False;
+}

+extern void setIRTempDefined(IRTempDefSet* defd, IRTemp tmp);
+extern void ppIRTempDefSet(const IRTempDefSet* defd);
+extern IRTempDefSet* emptyIRTempDefSet(void);
+extern IRTempDefSet* deepCopyIRTempDefSet(const IRTempDefSet* defd);

/* ------------------ Statements ------------------ */

@@ -2803,30 +2783,36 @@
struct _IRStmt
IRStmt;

+/* Uniquely identifies IRStmtVec in an IRSB, no matter how deeply nested. */
+typedef UShort IRStmtVecID;
+
+#define IRStmtVecID_INVALID ((IRStmtVecID) 0xFFFF)
+
/* Vector of statements which contains:
- - Type environment
- - Statements
- - A unique IRTyEnvID
+ - Statements themselves
+ - A unique IRStmtVecID
- Parent, which points to the parent IRStmtVec. Because "if-then-else"
statements cannot be currently nested, the parent is either NULL or points
- to IRStmtVec with type environment ID #0.
+ to IRStmtVec #0.
+ - A set which keeps track of which IRTemp's are defined in this IRStmtVec.
*/
typedef
struct _IRStmtVec {
- IRTypeEnv* tyenv;
IRStmt** stmts;
UInt stmts_size;
UInt stmts_used;
+ IRStmtVecID id;
struct _IRStmtVec* parent;
+ IRTempDefSet* def_set;
}
IRStmtVec;

extern void ppIRStmtVec(const IRStmtVec*);
extern void ppIRStmtVec_wrk(const IRStmtVec*, UInt depth);

-/* Allocates an empty IRStmtVec with an invalid IRTyEnvID.
- Such an IRStmtVec needs to have a valid IRTyEnvId - get it from
- nextIRTyEnvID(). Only after this is done, then such an IRStmtVec is ready
+/* Allocates an empty IRStmtVec with an invalid IRStmtVecID.
+ Such an IRStmtVec needs to have a valid IRStmtVecID - get it from
+ nextIRStmtVecID(). Only after this is done, then such an IRStmtVec is ready
for newIRTemp() to give out new temporaries.
Nested IRStmtVec also needs to have correctly set its parent.

@@ -2927,7 +2913,7 @@
to help Memcheck to origin tracking.

ppIRStmt output: ====== AbiHint(<base>, <len>, <nia>) ======
- eg. ====== AbiHint(t1:7, 16, t1:2) ======
+ eg. ====== AbiHint(t1, 16, t2) ======
*/
struct {
IRExpr* base; /* Start of undefined chunk */
@@ -2936,7 +2922,7 @@
} AbiHint;

/* Write a guest register, at a fixed offset in the guest state.
- ppIRStmt output: PUT(<offset>) = <data>, eg. PUT(60) = t1:7
+ ppIRStmt output: PUT(<offset>) = <data>, eg. PUT(60) = t1
*/
struct {
Int offset; /* Offset into the guest state */
@@ -2948,7 +2934,7 @@
information.

ppIRStmt output: PUTI<descr>[<ix>,<bias>] = <data>,
- eg. PUTI(64:8xF64)[t5,0] = t1:7
+ eg. PUTI(64:8xF64)[t5,0] = t1
*/
struct {
IRPutI* details;
@@ -2959,7 +2945,7 @@
reject any block containing a temporary which is not assigned
to exactly once.

- ppIRStmt output: t<tmp> = <data>, eg. t1:7 = 3
+ ppIRStmt output: t<tmp> = <data>, eg. t1 = 3
*/
struct {
IRTemp tmp; /* Temporary (LHS of assignment) */
@@ -2969,7 +2955,7 @@
/* Write a value to memory. This is a normal store, not a
Store-Conditional. To represent a Store-Conditional,
instead use IRStmt.LLSC.
- ppIRStmt output: ST<end>(<addr>) = <data>, eg. STle(t1:7) = t1:6
+ ppIRStmt output: ST<end>(<addr>) = <data>, eg. STle(t1) = t2
*/
struct {
IREndness end; /* Endianness of the store */
@@ -3001,7 +2987,7 @@
ppIRStmt output:
t<tmp> = CAS<end>(<addr> :: <expected> -> <new>)
eg
- t0:1 = CASle(t0:2 :: t0:3->Add32(t0:3,1))
+ t1 = CASle(t2 :: t3->Add32(t3,1))
which denotes a 32-bit atomic increment
of a value at address t2

@@ -3026,7 +3012,7 @@
The data transfer type is the type of RESULT (I32, I64,
etc). ppIRStmt output:

- result = LD<end>-Linked(<addr>), eg. LDbe-Linked(t1:7)
+ result = LD<end>-Linked(<addr>), eg. LDbe-Linked(t1)

If STOREDATA is not NULL then this is a Store-Conditional,
hence:
@@ -3040,7 +3026,7 @@
if it fails. eg ppIRStmt output:

result = ( ST<end>-Cond(<addr>) = <storedata> )
- eg t3 = ( STbe-Cond(t1:1, t1:2) )
+ eg t3 = ( STbe-Cond(t1, t2) )

In all cases, the address must be naturally aligned for
the transfer type -- any misaligned addresses should be
@@ -3073,7 +3059,7 @@
::: <callee>(<args>)
eg.
t1 = DIRTY t27 RdFX-gst(16,4) RdFX-gst(60,4)
- ::: foo{0x380035f4}(t1:2)
+ ::: foo{0x380035f4}(t2)
*/
struct {
IRDirty* details;
@@ -3107,8 +3093,7 @@

/* If-Then-Else control flow diamond. It contains:
- Guard controling whether "then" or "else" leg is taken
- - "then" and "else" legs with vectors of statements, together
- with their associated type environments
+ - "then" and "else" legs with vectors of statements
At the moment, nested "if-then-else" statements are not supported.
- Phi nodes, which are used to merge temporaries from "then" and
"else" legs
@@ -3119,7 +3104,7 @@

ppIRIfThenElse output:
if (<cond>) then { <IRStmtVec> } else { <IRStmtVec> }
- eg. if (t0:3) then { <then-statements> } else { <else-statements> }
+ eg. if (t3) then { <then-statements> } else { <else-statements> }
*/
struct {
IRExpr* cond;
@@ -3160,13 +3145,43 @@
extern void ppIRStmt ( const IRStmt* );
extern void ppIRStmt_wrk(const IRStmt*, UInt depth);

+
/* ------------------ Basic Blocks ------------------ */

+/* Type environments: a bunch of statements, expressions, etc, are incomplete
+ without an environment indicating the type of each IRTemp and its scope.
+ So this provides one. IR temporaries are really just unsigned ints so they
+ can used to index these two arrays:
+ - 'types' which gives IRTemp's type
+ - 'ids' which gives ID of the defining IRStmtVec
+*/
+
+typedef
+ struct {
+ IRType* types;
+ IRStmtVecID* ids;
+ UInt size;
+ UInt used;
+ }
+ IRTypeEnv;
+
+/* Obtain a new IRTemp. New IRTemp is allocated from 'tyenv' and is marked
+ as defined in 'stmts'->def_set. */
+extern IRTemp newIRTemp(IRTypeEnv* tyenv, IRStmtVec* stmts, IRType);
+
+/* Deep-copy a type environment */
+extern IRTypeEnv* deepCopyIRTypeEnv ( const IRTypeEnv* );
+
+/* Pretty-print a type environment */
+extern void ppIRTypeEnv ( const IRTypeEnv* );
+
+
/* Code blocks, which in proper compiler terminology are superblocks
(single entry, multiple exit code sequences) contain:

- - A vector of statements, together with its type environment
- - A sequence used to get a unique IRTyEnvID for nested IRStmtVec's
+ - A type environment (giving type for each temp and where it is defined)
+ - A vector of statements
+ - A sequence used to get a unique IRStmtVecID for nested IRStmtVec's
- An expression of type 32 or 64 bits, depending on the
guest's word size, indicating the next destination if the block
executes all the way to the end, without a side exit
@@ -3179,15 +3194,16 @@
*/
typedef
struct {
- IRStmtVec* stmts;
- IRTyEnvID id_seq;
- IRExpr* next;
- IRJumpKind jumpkind;
- Int offsIP;
+ IRTypeEnv* tyenv;
+ IRStmtVec* stmts;
+ IRStmtVecID id_seq;
+ IRExpr* next;
+ IRJumpKind jumpkind;
+ Int offsIP;
}
IRSB;

-/* Allocates an empty IRSB. The corresponding type environment has ID #0. */
+/* Allocates an empty IRSB. The corresponding IRStmtVec has ID #0. */
extern IRSB* emptyIRSB ( void );

/* Deep-copy an IRSB */
@@ -3206,9 +3222,9 @@

extern void addStmtToIRStmtVec(IRStmtVec*, IRStmt*);

-extern IRTyEnvID nextIRTyEnvID(IRSB*);
+extern IRStmtVecID nextIRStmtVecID(IRSB*);

-/* Allocates an empty IfThenElse, assigns it a valid IRTyEnvID
+/* Allocates an empty IfThenElse, assigns it a valid IRStmtVecID
and sets the parent for both then and else legs.
The returned IRStmt is added to the parent IRStmtVec and ready to be used. */
extern IRStmt *addEmptyIfThenElse(IRSB* bb, IRStmtVec* parent, IRExpr* cond);
@@ -3217,15 +3233,10 @@
/*--- Helper functions for the IR ---*/
/*---------------------------------------------------------------*/

-/* Creates a new IR type environment with an invalid IRTyEnvID.
- Consult nextIRTyEnvID() function for getting a valid IRTyEnvID.
- Useful for messing with IR type environments. */
-extern IRTypeEnv *emptyIRTypeEnv(void);
-
/* What is the type of this expression? */
extern IRType typeOfIRConst ( const IRConst* );
-extern IRType typeOfIRTemp ( const IRStmtVec*, IRTemp );
-extern IRType typeOfIRExpr ( const IRStmtVec*, const IRExpr* );
+extern IRType typeOfIRTemp ( const IRTypeEnv*, IRTemp );
+extern IRType typeOfIRExpr ( const IRTypeEnv*, const IRExpr* );

/* What are the arg and result type for this IRLoadGOp? */
extern void typeOfIRLoadGOp ( IRLoadGOp cvt,

Loading...