Index: VEX/priv/main_main.c =================================================================== --- VEX/priv/main_main.c (revision 2627) +++ VEX/priv/main_main.c (working copy) @@ -724,7 +724,7 @@ /* Turn it into virtual-registerised code. Build trees -- this also throws away any dead bindings. */ - max_ga = ado_treebuild_BB( irsb ); + max_ga = ado_treebuild_BB( irsb, preciseMemExnsFn ); if (vta->finaltidy) { irsb = vta->finaltidy(irsb); Index: VEX/priv/ir_opt.c =================================================================== --- VEX/priv/ir_opt.c (revision 2627) +++ VEX/priv/ir_opt.c (working copy) @@ -5075,25 +5075,80 @@ } inline -static Bool dirty_helper_puts ( const IRDirty *d ) +static Bool dirty_helper_puts ( const IRDirty *d, + Bool (*preciseMemExnsFn)(Int, Int), + Bool *requiresPreciseMemExns ) { Int i; /* Passing the guest state pointer opens the door to modifying the guest state under the covers. It's not allowed, but let's be extra conservative and assume the worst. */ - if (d->needsBBP) return True; + if (d->needsBBP) { + *requiresPreciseMemExns = True; + return True; + } /* Check the side effects on the guest state */ + Bool ret = False; + *requiresPreciseMemExns = False; + for (i = 0; i < d->nFxState; ++i) { - if (d->fxState[i].fx != Ifx_Read) return True; + if (d->fxState[i].fx != Ifx_Read) { + Int offset = d->fxState[i].offset; + Int size = d->fxState[i].size; + Int nRepeats = d->fxState[i].nRepeats; + Int repeatLen = d->fxState[i].repeatLen; + + if (preciseMemExnsFn(offset, offset + nRepeats * repeatLen + size)) { + *requiresPreciseMemExns = True; + return True; + } + ret = True; + } } - return False; + return ret; } -/* notstatic */ Addr64 ado_treebuild_BB ( IRSB* bb ) +/* Return true if st modifies the guest state. Via requiresPreciseMemExns + return whether or not that modification requires precise exceptions. */ +static Bool stmt_modifies_guest_state ( IRSB *bb, const IRStmt *st, + Bool (*preciseMemExnsFn)(Int,Int), + Bool *requiresPreciseMemExns ) { + switch (st->tag) { + case Ist_Put: { + Int offset = st->Ist.Put.offset; + Int size = sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Put.data)); + + *requiresPreciseMemExns = preciseMemExnsFn(offset, offset + size); + return True; + } + + case Ist_PutI: { + IRRegArray *descr = st->Ist.PutI.details->descr; + Int offset = descr->base; + Int size = sizeofIRType(descr->elemTy); + + *requiresPreciseMemExns = + preciseMemExnsFn(offset, offset + descr->nElems * size); + return True; + } + + case Ist_Dirty: + return dirty_helper_puts(st->Ist.Dirty.details, preciseMemExnsFn, + requiresPreciseMemExns); + + default: + *requiresPreciseMemExns = False; + return False; + } +} + +/* notstatic */ Addr64 ado_treebuild_BB ( IRSB* bb, + Bool (*preciseMemExnsFn)(Int,Int) ) +{ Int i, j, k, m; Bool stmtPuts, stmtStores, invalidateMe; IRStmt* st; @@ -5228,12 +5283,11 @@ /* stmtPuts/stmtStores characterise what the stmt under consideration does, or might do (sidely safe @ True). */ - stmtPuts - = toBool( st->tag == Ist_Put - || st->tag == Ist_PutI - || (st->tag == Ist_Dirty - && dirty_helper_puts(st->Ist.Dirty.details))); + Bool putRequiresPreciseMemExns; + stmtPuts = stmt_modifies_guest_state( bb, st, preciseMemExnsFn, + &putRequiresPreciseMemExns); + /* be True if this stmt writes memory or might do (==> we don't want to reorder other loads or stores relative to it). Also, both LL and SC fall under this classification, since we @@ -5257,12 +5311,15 @@ (env[k].doesLoad && stmtStores) /* a put invalidates get'd data */ || (env[k].doesGet && stmtPuts) - /* a put invalidates loaded data. Note, we could do - much better here in the sense that we only need to - invalidate trees containing loads if the Put in - question is marked as requiring precise - exceptions. */ - || (env[k].doesLoad && stmtPuts) + /* a put invalidates loaded data. That means, in essense, that + a load expression cannot be substituted into a statement + that follows the put. But there is nothing wrong doing so + except when the put statement requries precise exceptions. + Think of a load that is moved past a put where the put + updates the IP in the guest state. If the load generates + a segfault, the wrong address (line number) would be + reported. */ + || (env[k].doesLoad && stmtPuts && putRequiresPreciseMemExns) /* probably overly conservative: a memory bus event invalidates absolutely everything, so that all computation prior to it is forced to complete before Index: VEX/priv/ir_opt.h =================================================================== --- VEX/priv/ir_opt.h (revision 2627) +++ VEX/priv/ir_opt.h (working copy) @@ -64,7 +64,7 @@ the guest address of the highest addressed byte from any insn in this block, or Addr64_MAX if unknown (can that ever happen?) */ extern -Addr64 ado_treebuild_BB ( IRSB* bb ); +Addr64 ado_treebuild_BB ( IRSB* bb, Bool (*preciseMemExnsFn)(Int,Int) ); #endif /* ndef __VEX_IR_OPT_H */