|
From: <sv...@va...> - 2009-05-21 21:31:56
|
Author: sewardj
Date: 2009-05-21 22:31:49 +0100 (Thu, 21 May 2009)
New Revision: 1891
Log:
Handle IRStmt_IRCAS in basic routines and in the optimiser pipeline.
Modified:
branches/DCAS/priv/ir/irdefs.c
branches/DCAS/priv/ir/iropt.c
Modified: branches/DCAS/priv/ir/irdefs.c
===================================================================
--- branches/DCAS/priv/ir/irdefs.c 2009-05-21 21:27:40 UTC (rev 1890)
+++ branches/DCAS/priv/ir/irdefs.c 2009-05-21 21:31:49 UTC (rev 1891)
@@ -723,6 +723,32 @@
vex_printf(")");
}
+void ppIRCAS ( IRCAS* cas )
+{
+ /* Print even structurally invalid constructions, as an aid to
+ debugging. */
+ if (cas->oldHi != IRTemp_INVALID) {
+ ppIRTemp(cas->oldHi);
+ vex_printf(",");
+ }
+ ppIRTemp(cas->oldLo);
+ vex_printf(" = CAS%s(", cas->end==Iend_LE ? "le" : "be" );
+ ppIRExpr(cas->addr);
+ vex_printf("::");
+ if (cas->expdHi) {
+ ppIRExpr(cas->expdHi);
+ vex_printf(",");
+ }
+ ppIRExpr(cas->expdLo);
+ vex_printf("->");
+ if (cas->dataHi) {
+ ppIRExpr(cas->dataHi);
+ vex_printf(",");
+ }
+ ppIRExpr(cas->dataLo);
+ vex_printf(")");
+}
+
void ppIRJumpKind ( IRJumpKind kind )
{
switch (kind) {
@@ -805,6 +831,9 @@
vex_printf( ") = ");
ppIRExpr(s->Ist.Store.data);
break;
+ case Ist_CAS:
+ ppIRCAS(s->Ist.CAS.details);
+ break;
case Ist_Dirty:
ppIRDirty(s->Ist.Dirty.details);
break;
@@ -1151,6 +1180,25 @@
}
+/* Constructors -- IRCAS */
+
+IRCAS* mkIRCAS ( IRTemp oldHi, IRTemp oldLo,
+ IREndness end, IRExpr* addr,
+ IRExpr* expdHi, IRExpr* expdLo,
+ IRExpr* dataHi, IRExpr* dataLo ) {
+ IRCAS* cas = LibVEX_Alloc(sizeof(IRCAS));
+ cas->oldHi = oldHi;
+ cas->oldLo = oldLo;
+ cas->end = end;
+ cas->addr = addr;
+ cas->expdHi = expdHi;
+ cas->expdLo = expdLo;
+ cas->dataHi = dataHi;
+ cas->dataLo = dataLo;
+ return cas;
+}
+
+
/* Constructors -- IRStmt */
IRStmt* IRStmt_NoOp ( void )
@@ -1208,6 +1256,12 @@
vassert(end == Iend_LE || end == Iend_BE);
return s;
}
+IRStmt* IRStmt_CAS ( IRCAS* cas ) {
+ IRStmt* s = LibVEX_Alloc(sizeof(IRStmt));
+ s->tag = Ist_CAS;
+ s->Ist.CAS.details = cas;
+ return s;
+}
IRStmt* IRStmt_Dirty ( IRDirty* d )
{
IRStmt* s = LibVEX_Alloc(sizeof(IRStmt));
@@ -1389,6 +1443,16 @@
return d2;
}
+IRCAS* deepCopyIRCAS ( IRCAS* cas )
+{
+ return mkIRCAS( cas->oldHi, cas->oldLo, cas->end,
+ deepCopyIRExpr(cas->addr),
+ deepCopyIRExpr(cas->expdHi),
+ deepCopyIRExpr(cas->expdLo),
+ deepCopyIRExpr(cas->dataHi),
+ deepCopyIRExpr(cas->dataLo) );
+}
+
IRStmt* deepCopyIRStmt ( IRStmt* s )
{
switch (s->tag) {
@@ -1415,6 +1479,8 @@
return IRStmt_Store(s->Ist.Store.end,
deepCopyIRExpr(s->Ist.Store.addr),
deepCopyIRExpr(s->Ist.Store.data));
+ case Ist_CAS:
+ return IRStmt_CAS(deepCopyIRCAS(s->Ist.CAS.details));
case Ist_Dirty:
return IRStmt_Dirty(deepCopyIRDirty(s->Ist.Dirty.details));
case Ist_MBE:
@@ -1996,6 +2062,7 @@
Int i;
IRExpr* e;
IRDirty* di;
+ IRCAS* cas;
switch (st->tag) {
case Ist_AbiHint:
@@ -2046,6 +2113,13 @@
case Ist_Store:
return toBool( isIRAtom(st->Ist.Store.addr)
&& isIRAtom(st->Ist.Store.data) );
+ case Ist_CAS:
+ cas = st->Ist.CAS.details;
+ return toBool( isIRAtom(cas->addr)
+ && (cas->expdHi ? isIRAtom(cas->expdHi) : True)
+ && isIRAtom(cas->expdLo)
+ && (cas->dataHi ? isIRAtom(cas->dataHi) : True)
+ && isIRAtom(cas->dataLo) );
case Ist_Dirty:
di = st->Ist.Dirty.details;
if (!isIRAtom(di->guard))
@@ -2205,6 +2279,7 @@
{
Int i;
IRDirty* d;
+ IRCAS* cas;
switch (stmt->tag) {
case Ist_IMark:
break;
@@ -2226,6 +2301,16 @@
useBeforeDef_Expr(bb,stmt,stmt->Ist.Store.addr,def_counts);
useBeforeDef_Expr(bb,stmt,stmt->Ist.Store.data,def_counts);
break;
+ case Ist_CAS:
+ cas = stmt->Ist.CAS.details;
+ useBeforeDef_Expr(bb,stmt,cas->addr,def_counts);
+ if (cas->expdHi)
+ useBeforeDef_Expr(bb,stmt,cas->expdHi,def_counts);
+ useBeforeDef_Expr(bb,stmt,cas->expdLo,def_counts);
+ if (cas->dataHi)
+ useBeforeDef_Expr(bb,stmt,cas->dataHi,def_counts);
+ useBeforeDef_Expr(bb,stmt,cas->dataLo,def_counts);
+ break;
case Ist_Dirty:
d = stmt->Ist.Dirty.details;
for (i = 0; d->args[i] != NULL; i++)
@@ -2452,6 +2537,8 @@
{
Int i;
IRDirty* d;
+ IRCAS* cas;
+ IRType tyExpd, tyData;
IRTypeEnv* tyenv = bb->tyenv;
switch (stmt->tag) {
case Ist_IMark:
@@ -2502,6 +2589,56 @@
if (stmt->Ist.Store.end != Iend_LE && stmt->Ist.Store.end != Iend_BE)
sanityCheckFail(bb,stmt,"Ist.Store.end: bogus endianness");
break;
+ case Ist_CAS:
+ cas = stmt->Ist.CAS.details;
+ /* make sure it's definitely either a CAS or a DCAS */
+ if (cas->oldHi == IRTemp_INVALID
+ && cas->expdHi == NULL && cas->dataHi == NULL) {
+ /* fine; it's a single cas */
+ }
+ else
+ if (cas->oldHi != IRTemp_INVALID
+ && cas->expdHi != NULL && cas->dataHi != NULL) {
+ /* fine; it's a double cas */
+ }
+ else {
+ /* it's some el-mutanto hybrid */
+ goto bad_cas;
+ }
+ /* check the address type */
+ tcExpr( bb, stmt, cas->addr, gWordTy );
+ if (typeOfIRExpr(tyenv, cas->addr) != gWordTy) goto bad_cas;
+ /* check types on the {old,expd,data}Lo components agree */
+ tyExpd = typeOfIRExpr(tyenv, cas->expdLo);
+ tyData = typeOfIRExpr(tyenv, cas->dataLo);
+ if (tyExpd != tyData) goto bad_cas;
+ 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
+ || (gWordTy == Ity_I64 && tyExpd == Ity_I64)) {
+ /* fine */
+ } else {
+ goto bad_cas;
+ }
+ /* If it's a DCAS, check types on the {old,expd,data}Hi
+ components too */
+ if (cas->oldHi != IRTemp_INVALID) {
+ tyExpd = typeOfIRExpr(tyenv, cas->expdHi);
+ tyData = typeOfIRExpr(tyenv, cas->dataHi);
+ if (tyExpd != tyData) goto bad_cas;
+ 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(tyenv, cas->oldHi)
+ != typeOfIRTemp(tyenv, cas->oldLo))
+ goto bad_cas;
+ }
+ break;
+ bad_cas:
+ sanityCheckFail(bb,stmt,"IRStmt.CAS: ill-formed");
+ break;
case Ist_Dirty:
/* Mostly check for various kinds of ill-formed dirty calls. */
d = stmt->Ist.Dirty.details;
@@ -2540,6 +2677,7 @@
break;
bad_dirty:
sanityCheckFail(bb,stmt,"IRStmt.Dirty: ill-formed");
+ break;
case Ist_NoOp:
break;
case Ist_MBE:
@@ -2614,10 +2752,15 @@
def_counts[i] = 0;
for (i = 0; i < bb->stmts_used; i++) {
+ IRDirty* d;
+ IRCAS* cas;
stmt = bb->stmts[i];
+ /* Check any temps used by this statement. */
useBeforeDef_Stmt(bb,stmt,def_counts);
- if (stmt->tag == Ist_WrTmp) {
+ /* Now make note of any temps defd by this statement. */
+ switch (stmt->tag) {
+ case Ist_WrTmp:
if (stmt->Ist.WrTmp.tmp < 0 || stmt->Ist.WrTmp.tmp >= n_temps)
sanityCheckFail(bb, stmt,
"IRStmt.Tmp: destination tmp is out of range");
@@ -2625,19 +2768,43 @@
if (def_counts[stmt->Ist.WrTmp.tmp] > 1)
sanityCheckFail(bb, stmt,
"IRStmt.Tmp: destination tmp is assigned more than once");
+ break;
+ case Ist_Dirty:
+ if (stmt->Ist.Dirty.details->tmp != IRTemp_INVALID) {
+ d = stmt->Ist.Dirty.details;
+ if (d->tmp < 0 || d->tmp >= n_temps)
+ sanityCheckFail(bb, stmt,
+ "IRStmt.Dirty: destination tmp is out of range");
+ def_counts[d->tmp]++;
+ if (def_counts[d->tmp] > 1)
+ sanityCheckFail(bb, stmt,
+ "IRStmt.Dirty: destination tmp is assigned more than once");
+ }
+ break;
+ case Ist_CAS:
+ cas = stmt->Ist.CAS.details;
+
+ if (cas->oldHi != IRTemp_INVALID) {
+ if (cas->oldHi < 0 || cas->oldHi >= n_temps)
+ sanityCheckFail(bb, stmt,
+ "IRStmt.CAS: destination tmpHi is out of range");
+ def_counts[cas->oldHi]++;
+ if (def_counts[cas->oldHi] > 1)
+ sanityCheckFail(bb, stmt,
+ "IRStmt.CAS: destination tmpHi is assigned more than once");
+ }
+ if (cas->oldLo < 0 || cas->oldLo >= n_temps)
+ sanityCheckFail(bb, stmt,
+ "IRStmt.CAS: destination tmpLo is out of range");
+ def_counts[cas->oldLo]++;
+ if (def_counts[cas->oldLo] > 1)
+ sanityCheckFail(bb, stmt,
+ "IRStmt.CAS: destination tmpLo is assigned more than once");
+ break;
+ default:
+ /* explicitly handle the rest, so as to keep gcc quiet */
+ break;
}
- else
- if (stmt->tag == Ist_Dirty
- && stmt->Ist.Dirty.details->tmp != IRTemp_INVALID) {
- IRDirty* d = stmt->Ist.Dirty.details;
- if (d->tmp < 0 || d->tmp >= n_temps)
- sanityCheckFail(bb, stmt,
- "IRStmt.Dirty: destination tmp is out of range");
- def_counts[d->tmp]++;
- if (def_counts[d->tmp] > 1)
- sanityCheckFail(bb, stmt,
- "IRStmt.Dirty: destination tmp is assigned more than once");
- }
}
/* Typecheck everything. */
Modified: branches/DCAS/priv/ir/iropt.c
===================================================================
--- branches/DCAS/priv/ir/iropt.c 2009-05-21 21:27:40 UTC (rev 1890)
+++ branches/DCAS/priv/ir/iropt.c 2009-05-21 21:31:49 UTC (rev 1891)
@@ -388,8 +388,9 @@
static void flatten_Stmt ( IRSB* bb, IRStmt* st )
{
Int i;
- IRExpr *e1, *e2;
+ IRExpr *e1, *e2, *e3, *e4, *e5;
IRDirty *d, *d2;
+ IRCAS *cas, *cas2;
switch (st->tag) {
case Ist_Put:
if (isIRAtom(st->Ist.Put.data)) {
@@ -426,6 +427,17 @@
e2 = flatten_Expr(bb, st->Ist.Store.data);
addStmtToIRSB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2));
break;
+ case Ist_CAS:
+ cas = st->Ist.CAS.details;
+ e1 = flatten_Expr(bb, cas->addr);
+ e2 = cas->expdHi ? flatten_Expr(bb, cas->expdHi) : NULL;
+ e3 = flatten_Expr(bb, cas->expdLo);
+ e4 = cas->dataHi ? flatten_Expr(bb, cas->dataHi) : NULL;
+ e5 = flatten_Expr(bb, cas->dataLo);
+ cas2 = mkIRCAS( cas->oldHi, cas->oldLo, cas->end,
+ e1, e2, e3, e4, e5 );
+ addStmtToIRSB(bb, IRStmt_CAS(cas2));
+ break;
case Ist_Dirty:
d = st->Ist.Dirty.details;
d2 = emptyIRDirty();
@@ -710,13 +722,14 @@
enough do a lot better if needed. */
/* Probably also overly-conservative, but also dump everything
if we hit a memory bus event (fence, lock, unlock). Ditto
- AbiHints.*/
+ AbiHints and CASs. */
case Ist_AbiHint:
vassert(isIRAtom(st->Ist.AbiHint.base));
vassert(isIRAtom(st->Ist.AbiHint.nia));
/* fall through */
case Ist_MBE:
case Ist_Dirty:
+ case Ist_CAS:
for (j = 0; j < env->used; j++)
env->inuse[j] = False;
break;
@@ -1751,6 +1764,25 @@
fold_Expr(subst_Expr(env, st->Ist.Store.data))
);
+ case Ist_CAS: {
+ IRCAS *cas, *cas2;
+ cas = st->Ist.CAS.details;
+ vassert(isIRAtom(cas->addr));
+ vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
+ vassert(isIRAtom(cas->expdLo));
+ vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
+ vassert(isIRAtom(cas->dataLo));
+ cas2 = mkIRCAS(
+ cas->oldHi, cas->oldLo, cas->end,
+ fold_Expr(subst_Expr(env, cas->addr)),
+ cas->expdHi ? fold_Expr(subst_Expr(env, cas->expdHi)) : NULL,
+ fold_Expr(subst_Expr(env, cas->expdLo)),
+ cas->dataHi ? fold_Expr(subst_Expr(env, cas->dataHi)) : NULL,
+ fold_Expr(subst_Expr(env, cas->dataLo))
+ );
+ return IRStmt_CAS(cas2);
+ }
+
case Ist_Dirty: {
Int i;
IRDirty *d, *d2;
@@ -1956,6 +1988,7 @@
{
Int i;
IRDirty* d;
+ IRCAS* cas;
switch (st->tag) {
case Ist_AbiHint:
addUses_Expr(set, st->Ist.AbiHint.base);
@@ -1975,6 +2008,16 @@
addUses_Expr(set, st->Ist.Store.addr);
addUses_Expr(set, st->Ist.Store.data);
return;
+ case Ist_CAS:
+ cas = st->Ist.CAS.details;
+ addUses_Expr(set, cas->addr);
+ if (cas->expdHi)
+ addUses_Expr(set, cas->expdHi);
+ addUses_Expr(set, cas->expdLo);
+ if (cas->dataHi)
+ addUses_Expr(set, cas->dataHi);
+ addUses_Expr(set, cas->dataLo);
+ return;
case Ist_Dirty:
d = st->Ist.Dirty.details;
if (d->mFx != Ifx_None)
@@ -2561,7 +2604,7 @@
to do the no-overlap assessments needed for Put/PutI.
*/
switch (st->tag) {
- case Ist_Dirty: case Ist_Store: case Ist_MBE:
+ case Ist_Dirty: case Ist_Store: case Ist_MBE: case Ist_CAS:
paranoia = 2; break;
case Ist_Put: case Ist_PutI:
paranoia = 1; break;
@@ -3248,6 +3291,18 @@
deltaIRExpr(st->Ist.Store.addr, delta);
deltaIRExpr(st->Ist.Store.data, delta);
break;
+ case Ist_CAS:
+ if (st->Ist.CAS.details->oldHi != IRTemp_INVALID)
+ st->Ist.CAS.details->oldHi += delta;
+ st->Ist.CAS.details->oldLo += delta;
+ deltaIRExpr(st->Ist.CAS.details->addr, delta);
+ if (st->Ist.CAS.details->expdHi)
+ deltaIRExpr(st->Ist.CAS.details->expdHi, delta);
+ deltaIRExpr(st->Ist.CAS.details->expdLo, delta);
+ if (st->Ist.CAS.details->dataHi)
+ deltaIRExpr(st->Ist.CAS.details->dataHi, delta);
+ deltaIRExpr(st->Ist.CAS.details->dataLo, delta);
+ break;
case Ist_Dirty:
d = st->Ist.Dirty.details;
deltaIRExpr(d->guard, delta);
@@ -3682,6 +3737,7 @@
{
Int i;
IRDirty* d;
+ IRCAS* cas;
switch (st->tag) {
case Ist_AbiHint:
aoccCount_Expr(uses, st->Ist.AbiHint.base);
@@ -3701,6 +3757,16 @@
aoccCount_Expr(uses, st->Ist.Store.addr);
aoccCount_Expr(uses, st->Ist.Store.data);
return;
+ case Ist_CAS:
+ cas = st->Ist.CAS.details;
+ aoccCount_Expr(uses, cas->addr);
+ if (cas->expdHi)
+ aoccCount_Expr(uses, cas->expdHi);
+ aoccCount_Expr(uses, cas->expdLo);
+ if (cas->dataHi)
+ aoccCount_Expr(uses, cas->dataHi);
+ aoccCount_Expr(uses, cas->dataLo);
+ return;
case Ist_Dirty:
d = st->Ist.Dirty.details;
if (d->mFx != Ifx_None)
@@ -3910,9 +3976,9 @@
static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st )
{
- Int i;
- IRDirty* d;
- IRDirty* d2;
+ Int i;
+ IRDirty *d, *d2;
+ IRCAS *cas, *cas2;
switch (st->tag) {
case Ist_AbiHint:
return IRStmt_AbiHint(
@@ -3956,6 +4022,17 @@
return IRStmt_NoOp();
case Ist_MBE:
return IRStmt_MBE(st->Ist.MBE.event);
+ case Ist_CAS:
+ cas = st->Ist.CAS.details;
+ cas2 = mkIRCAS(
+ cas->oldHi, cas->oldLo, cas->end,
+ atbSubst_Expr(env, cas->addr),
+ cas->expdHi ? atbSubst_Expr(env, cas->expdHi) : NULL,
+ atbSubst_Expr(env, cas->expdLo),
+ cas->dataHi ? atbSubst_Expr(env, cas->dataHi) : NULL,
+ atbSubst_Expr(env, cas->dataLo)
+ );
+ return IRStmt_CAS(cas2);
case Ist_Dirty:
d = st->Ist.Dirty.details;
d2 = emptyIRDirty();
@@ -4239,9 +4316,10 @@
/*OUT*/Bool* hasVorFtemps,
IRSB* bb )
{
- Int i, j;
- IRStmt* st;
+ Int i, j;
+ IRStmt* st;
IRDirty* d;
+ IRCAS* cas;
*hasGetIorPutI = False;
*hasVorFtemps = False;
@@ -4277,6 +4355,14 @@
vassert(isIRAtom(st->Ist.Store.addr));
vassert(isIRAtom(st->Ist.Store.data));
break;
+ case Ist_CAS:
+ cas = st->Ist.CAS.details;
+ vassert(isIRAtom(cas->addr));
+ vassert(cas->expdHi == NULL || isIRAtom(cas->expdHi));
+ vassert(isIRAtom(cas->expdLo));
+ vassert(cas->dataHi == NULL || isIRAtom(cas->dataHi));
+ vassert(isIRAtom(cas->dataLo));
+ break;
case Ist_Dirty:
d = st->Ist.Dirty.details;
vassert(isIRAtom(d->guard));
|