not marked as being read or modified by the helper cannot be
assumed to be up-to-date at the point where the helper is called.
- * Immediately prior to any load or store, those parts of the guest
+ * If iropt_register_updates == VexRegUpdUnwindregsAtMemAccess :
+ Immediately prior to any load or store, those parts of the guest
state marked as requiring precise exceptions will be up to date.
Also, guest memory will be up to date. Parts of the guest state
not marked as requiring precise exceptions cannot be assumed to
be up-to-date at the point of the load/store.
+ If iropt_register_updates == VexRegUpdAllregsAtMemAccess:
+ Same as minimal, but all the guest state is up to date at memory
+ exception points.
+
+ If iropt_register_updates == VexRegUpdAllregsAtEachInsn :
+ Guest state is up to date at each instruction.
+
The relative order of loads and stores (including loads/stores of
guest memory done by dirty helpers annotated as such) is not
changed. However, the relative order of loads with no intervening
of the environment corresponding to guest state that may not
be reordered with respect to memory references. That means
at least the stack pointer. */
- for (j = 0; j < env->used; j++) {
- if (!env->inuse[j])
- continue;
- if (vex_control.iropt_precise_memory_exns) {
- /* Precise exceptions required. Flush all guest state. */
- env->inuse[j] = False;
- } else {
- /* Just flush the minimal amount required, as computed by
- preciseMemExnsFn. */
- HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
- HWord k_hi = env->key[j] & 0xFFFF;
- if (preciseMemExnsFn( k_lo, k_hi ))
+ switch (vex_control.iropt_register_updates) {
+ case VexRegUpdAllregsAtMemAccess:
+ /* Precise exceptions required at mem access.
+ Flush all guest state. */
+ for (j = 0; j < env->used; j++)
env->inuse[j] = False;
- }
+ break;
+ case VexRegUpdUnwindregsAtMemAccess:
+ for (j = 0; j < env->used; j++) {
+ if (!env->inuse[j])
+ continue;
+ /* Just flush the minimal amount required, as computed by
+ preciseMemExnsFn. */
+ HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
+ HWord k_hi = env->key[j] & 0xFFFF;
+ if (preciseMemExnsFn( k_lo, k_hi ))
+ env->inuse[j] = False;
+ }
+ break;
+ default:
+ // VexRegUpdAllregsAtEachInsn cannot happen here.
+ // Neither any rubbish other value.
+ vassert(0);
}
} /* if (memRW) */
IRStmt* st;
UInt key = 0; /* keep gcc -O happy */
+ vassert
+ (vex_control.iropt_register_updates == VexRegUpdUnwindregsAtMemAccess
+ || vex_control.iropt_register_updates == VexRegUpdAllregsAtMemAccess);
+
HashHW* env = newHHW();
/* Initialise the running env with the fact that the final exit
Bool delete;
IRStmt *st, *stj;
+ vassert
+ (vex_control.iropt_register_updates == VexRegUpdUnwindregsAtMemAccess
+ || vex_control.iropt_register_updates == VexRegUpdAllregsAtMemAccess);
+
for (i = 0; i < bb->stmts_used; i++) {
st = bb->stmts[i];
if (st->tag != Ist_PutI)
ppIRSB(bb);
}
- redundant_put_removal_BB ( bb, preciseMemExnsFn );
+ if (vex_control.iropt_register_updates != VexRegUpdAllregsAtEachInsn) {
+ redundant_put_removal_BB ( bb, preciseMemExnsFn );
+ }
if (iropt_verbose) {
vex_printf("\n========= REDUNDANT PUT\n\n" );
ppIRSB(bb);
(void)do_cse_BB( bb );
collapse_AddSub_chains_BB( bb );
do_redundant_GetI_elimination( bb );
- do_redundant_PutI_elimination( bb );
+ if (vex_control.iropt_register_updates != VexRegUpdAllregsAtEachInsn) {
+ do_redundant_PutI_elimination( bb );
+ }
do_deadcode_BB( bb );
return bb;
}
work extra hard to get rid of it. */
bb = cprop_BB(bb);
bb = spec_helpers_BB ( bb, specHelper );
- redundant_put_removal_BB ( bb, preciseMemExnsFn );
+ if (vex_control.iropt_register_updates != VexRegUpdAllregsAtEachInsn) {
+ redundant_put_removal_BB ( bb, preciseMemExnsFn );
+ }
do_cse_BB( bb );
do_deadcode_BB( bb );
}
/*--- Control of Vex's optimiser (iropt). ---*/
/*-------------------------------------------------------*/
+
+/* VexRegisterUpdates specifies when to ensure that the guest state is
+ up to date.
+
+ VexRegUpdUnwindregsAtMemAccess : registers needed to make a stack trace are
+ up to date at memory exception points. Typically, these are PC/SP/FP. The
+ minimal registers are described by the arch specific functions
+ guest_<arch>_state_requires_precise_mem_exns.
+
+ VexRegUpdAllregsAtMemAccess : all registers up to date at memory exception
+ points.
+
+ VexRegUpdAllregsAtEachInsn : all registers up to date at each instruction. */
+typedef enum { VexRegUpdUnwindregsAtMemAccess,
+ VexRegUpdAllregsAtMemAccess,
+ VexRegUpdAllregsAtEachInsn } VexRegisterUpdates;
+
/* Control of Vex's optimiser. */
typedef
/* Control aggressiveness of iropt. 0 = no opt, 1 = simple
opts, 2 (default) = max optimisation. */
Int iropt_level;
- /* Ensure all integer registers are up to date at potential
- memory exception points? True(default)=yes, False=no, only
- the guest's stack pointer. */
- Bool iropt_precise_memory_exns;
+ /* Controls when registers are updated in guest state. */
+ VexRegisterUpdates iropt_register_updates;
/* How aggressive should iropt be in unrolling loops? Higher
numbers make it more enthusiastic about loop unrolling.
Default=120. A setting of zero disables unrolling. */