|
From: <sv...@va...> - 2013-01-20 03:54:24
|
florian 2013-01-20 03:51:04 +0000 (Sun, 20 Jan 2013)
New Revision: 2645
Log:
Improve the tree builder in IR optimisation. Allow load expressions to be
moved past Put/I statements and dirty helpers, when it is safe to do so.
It is safe, when the statement does not require exact memory exceptions.
New functions stmt_modifies_guest_state and dirty_helper_puts have been
added to determine the side effect on the guest state.
This optimisation enables the use of memory-to-memory insns on
architectures that have those.
Modified files:
trunk/priv/ir_opt.c
trunk/priv/ir_opt.h
trunk/priv/main_main.c
Modified: trunk/priv/ir_opt.h (+1 -1)
===================================================================
--- trunk/priv/ir_opt.h 2013-01-20 03:08:04 +00:00 (rev 2644)
+++ trunk/priv/ir_opt.h 2013-01-20 03:51:04 +00:00 (rev 2645)
@@ -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 */
Modified: trunk/priv/ir_opt.c (+77 -16)
===================================================================
--- trunk/priv/ir_opt.c 2013-01-20 03:08:04 +00:00 (rev 2644)
+++ trunk/priv/ir_opt.c 2013-01-20 03:51:04 +00:00 (rev 2645)
@@ -5300,25 +5300,84 @@
}
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 - 1)) {
+ *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 - 1);
+ return True;
+ }
+
+ case Ist_PutI: {
+ IRRegArray *descr = st->Ist.PutI.details->descr;
+ Int offset = descr->base;
+ Int size = sizeofIRType(descr->elemTy);
+
+ /* We quietly assume here that all segments are contiguous and there
+ are no holes. This is to avoid a loop. The assumption is conservative
+ in the sense that we might report that precise memory exceptions are
+ needed when in fact they are not. */
+ *requiresPreciseMemExns =
+ preciseMemExnsFn(offset, offset + descr->nElems * size - 1);
+ 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;
@@ -5453,12 +5512,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
@@ -5482,12 +5540,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
Modified: trunk/priv/main_main.c (+1 -1)
===================================================================
--- trunk/priv/main_main.c 2013-01-20 03:08:04 +00:00 (rev 2644)
+++ trunk/priv/main_main.c 2013-01-20 03:51:04 +00:00 (rev 2645)
@@ -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);
|