📄 iropt.c
字号:
break; case Ist_PutI: e1 = flatten_Expr(bb, st->Ist.PutI.ix); e2 = flatten_Expr(bb, st->Ist.PutI.data); addStmtToIRBB(bb, IRStmt_PutI(st->Ist.PutI.descr, e1, st->Ist.PutI.bias, e2)); break; case Ist_Tmp: if (isFlat(st->Ist.Tmp.data)) { /* optimisation, to reduce the number of tmp-tmp copies generated */ addStmtToIRBB(bb, st); } else { /* general case, always correct */ e1 = flatten_Expr(bb, st->Ist.Tmp.data); addStmtToIRBB(bb, IRStmt_Tmp(st->Ist.Tmp.tmp, e1)); } break; case Ist_Store: e1 = flatten_Expr(bb, st->Ist.Store.addr); e2 = flatten_Expr(bb, st->Ist.Store.data); addStmtToIRBB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2)); break; case Ist_Dirty: d = st->Ist.Dirty.details; d2 = emptyIRDirty(); *d2 = *d; d2->args = sopyIRExprVec(d2->args); if (d2->mFx != Ifx_None) { d2->mAddr = flatten_Expr(bb, d2->mAddr); } else { vassert(d2->mAddr == NULL); } d2->guard = flatten_Expr(bb, d2->guard); for (i = 0; d2->args[i]; i++) d2->args[i] = flatten_Expr(bb, d2->args[i]); addStmtToIRBB(bb, IRStmt_Dirty(d2)); break; case Ist_NoOp: case Ist_MFence: case Ist_IMark: addStmtToIRBB(bb, st); break; case Ist_AbiHint: e1 = flatten_Expr(bb, st->Ist.AbiHint.base); addStmtToIRBB(bb, IRStmt_AbiHint(e1, st->Ist.AbiHint.len)); break; case Ist_Exit: e1 = flatten_Expr(bb, st->Ist.Exit.guard); addStmtToIRBB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk, st->Ist.Exit.dst)); break; default: vex_printf("\n"); ppIRStmt(st); vex_printf("\n"); vpanic("flatten_Stmt"); }}static IRBB* flatten_BB ( IRBB* in ){ Int i; IRBB* out; out = emptyIRBB(); out->tyenv = dopyIRTypeEnv( in->tyenv ); for (i = 0; i < in->stmts_used; i++) if (in->stmts[i]) flatten_Stmt( out, in->stmts[i] ); out->next = flatten_Expr( out, in->next ); out->jumpkind = in->jumpkind; return out;}/*---------------------------------------------------------------*//*--- In-place removal of redundant GETs ---*//*---------------------------------------------------------------*//* Scan forwards, building up an environment binding (min offset, max offset) pairs to values, which will either be temps or constants. On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the env and if it matches, replace the Get with the stored value. If there is no match, add a (minoff,maxoff) :-> t binding. On seeing 'Put (minoff,maxoff) = t or c', first remove in the env any binding which fully or partially overlaps with (minoff,maxoff). Then add a new (minoff,maxoff) :-> t or c binding. *//* Extract the min/max offsets from a guest state array descriptor. */inlinestatic void getArrayBounds ( IRArray* descr, UInt* minoff, UInt* maxoff ){ *minoff = descr->base; *maxoff = *minoff + descr->nElems*sizeofIRType(descr->elemTy) - 1; vassert((*minoff & ~0xFFFF) == 0); vassert((*maxoff & ~0xFFFF) == 0); vassert(*minoff <= *maxoff);}/* Create keys, of the form ((minoffset << 16) | maxoffset). */static UInt mk_key_GetPut ( Int offset, IRType ty ){ /* offset should fit in 16 bits. */ UInt minoff = offset; UInt maxoff = minoff + sizeofIRType(ty) - 1; vassert((minoff & ~0xFFFF) == 0); vassert((maxoff & ~0xFFFF) == 0); return (minoff << 16) | maxoff;}static UInt mk_key_GetIPutI ( IRArray* descr ){ UInt minoff, maxoff; getArrayBounds( descr, &minoff, &maxoff ); vassert((minoff & ~0xFFFF) == 0); vassert((maxoff & ~0xFFFF) == 0); return (minoff << 16) | maxoff;}/* Supposing h has keys of the form generated by mk_key_GetPut and mk_key_GetIPutI, invalidate any key which overlaps (k_lo .. k_hi). */static void invalidateOverlaps ( HashHW* h, UInt k_lo, UInt k_hi ){ Int j; UInt e_lo, e_hi; vassert(k_lo <= k_hi); /* invalidate any env entries which in any way overlap (k_lo .. k_hi) */ /* vex_printf("invalidate %d .. %d\n", k_lo, k_hi ); */ for (j = 0; j < h->used; j++) { if (!h->inuse[j]) continue; e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF; e_hi = ((UInt)h->key[j]) & 0xFFFF; vassert(e_lo <= e_hi); if (e_hi < k_lo || k_hi < e_lo) continue; /* no overlap possible */ else /* overlap; invalidate */ h->inuse[j] = False; }}static void redundant_get_removal_BB ( IRBB* bb ){ HashHW* env = newHHW(); UInt key = 0; /* keep gcc -O happy */ Int i, j; HWord val; for (i = 0; i < bb->stmts_used; i++) { IRStmt* st = bb->stmts[i]; if (st->tag == Ist_NoOp) continue; /* Deal with Gets */ if (st->tag == Ist_Tmp && st->Ist.Tmp.data->tag == Iex_Get) { /* st is 't = Get(...)'. Look up in the environment and see if the Get can be replaced. */ IRExpr* get = st->Ist.Tmp.data; key = (HWord)mk_key_GetPut( get->Iex.Get.offset, get->Iex.Get.ty ); if (lookupHHW(env, &val, (HWord)key)) { /* found it */ /* Note, we could do better here. If the types are different we don't do the substitution, since doing so could lead to invalidly-typed IR. An improvement would be to stick in a reinterpret-style cast, although that would make maintaining flatness more difficult. */ IRExpr* valE = (IRExpr*)val; Bool typesOK = toBool( typeOfIRExpr(bb->tyenv,valE) == st->Ist.Tmp.data->Iex.Get.ty ); if (typesOK && DEBUG_IROPT) { vex_printf("rGET: "); ppIRExpr(get); vex_printf(" -> "); ppIRExpr(valE); vex_printf("\n"); } if (typesOK) bb->stmts[i] = IRStmt_Tmp(st->Ist.Tmp.tmp, valE); } else { /* Not found, but at least we know that t and the Get(...) are now associated. So add a binding to reflect that fact. */ addToHHW( env, (HWord)key, (HWord)(void*)(IRExpr_Tmp(st->Ist.Tmp.tmp)) ); } } /* Deal with Puts: invalidate any env entries overlapped by this Put */ if (st->tag == Ist_Put || st->tag == Ist_PutI) { UInt k_lo, k_hi; if (st->tag == Ist_Put) { key = mk_key_GetPut( st->Ist.Put.offset, typeOfIRExpr(bb->tyenv,st->Ist.Put.data) ); } else { vassert(st->tag == Ist_PutI); key = mk_key_GetIPutI( st->Ist.PutI.descr ); } k_lo = (key >> 16) & 0xFFFF; k_hi = key & 0xFFFF; invalidateOverlaps(env, k_lo, k_hi); } else if (st->tag == Ist_Dirty) { /* Deal with dirty helpers which write or modify guest state. Invalidate the entire env. We could do a lot better here. */ IRDirty* d = st->Ist.Dirty.details; Bool writes = False; for (j = 0; j < d->nFxState; j++) { if (d->fxState[j].fx == Ifx_Modify || d->fxState[j].fx == Ifx_Write) writes = True; } if (writes) { /* dump the entire env (not clever, but correct ...) */ for (j = 0; j < env->used; j++) env->inuse[j] = False; if (0) vex_printf("rGET: trash env due to dirty helper\n"); } } /* add this one to the env, if appropriate */ if (st->tag == Ist_Put) { vassert(isIRAtom(st->Ist.Put.data)); addToHHW( env, (HWord)key, (HWord)(st->Ist.Put.data)); } } /* for (i = 0; i < bb->stmts_used; i++) */}/*---------------------------------------------------------------*//*--- In-place removal of redundant PUTs ---*//*---------------------------------------------------------------*//* Find any Get uses in st and invalidate any partially or fully overlapping ranges listed in env. Due to the flattening phase, the only stmt kind we expect to find a Get on is IRStmt_Tmp. */static void handle_gets_Stmt ( HashHW* env, IRStmt* st, Bool (*preciseMemExnsFn)(Int,Int) ){ Int j; UInt key = 0; /* keep gcc -O happy */ Bool isGet; Bool memRW = False; IRExpr* e; switch (st->tag) { /* This is the only interesting case. Deal with Gets in the RHS expression. */ case Ist_Tmp: e = st->Ist.Tmp.data; switch (e->tag) { case Iex_Get: isGet = True; key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty ); break; case Iex_GetI: isGet = True; key = mk_key_GetIPutI ( e->Iex.GetI.descr ); break; case Iex_Load: isGet = False; memRW = True; break; default: isGet = False; } if (isGet) { UInt k_lo, k_hi; k_lo = (key >> 16) & 0xFFFF; k_hi = key & 0xFFFF; invalidateOverlaps(env, k_lo, k_hi); } break; /* Be very conservative for dirty helper calls; dump the entire environment. The helper might read guest state, in which case it needs to be flushed first. Also, the helper might access guest memory, in which case all parts of the guest state requiring precise exceptions needs to be flushed. The crude solution is just to flush everything; we could easily enough do a lot better if needed. */ /* Probably also overly-conservative, but also dump everything if we hit a memory fence. Ditto AbiHints.*/ case Ist_AbiHint: vassert(isIRAtom(st->Ist.AbiHint.base)); /* fall through */ case Ist_MFence: case Ist_Dirty: for (j = 0; j < env->used; j++) env->inuse[j] = False; break; /* all other cases are boring. */ case Ist_Store: vassert(isIRAtom(st->Ist.Store.addr)); vassert(isIRAtom(st->Ist.Store.data)); memRW = True; break; case Ist_Exit: vassert(isIRAtom(st->Ist.Exit.guard)); break; case Ist_PutI: vassert(isIRAtom(st->Ist.PutI.ix)); vassert(isIRAtom(st->Ist.PutI.data)); break; case Ist_NoOp: case Ist_IMark: break; default: vex_printf("\n"); ppIRStmt(st); vex_printf("\n"); vpanic("handle_gets_Stmt"); } if (memRW) { /* This statement accesses memory. So we need to dump all parts 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 )) env->inuse[j] = False; } } } /* if (memRW) */}/* Scan backwards, building up a set of (min offset, max offset) pairs, indicating those parts of the guest state for which the next event is a write. On seeing a conditional exit, empty the set. On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is completely within the set, remove the Put. Otherwise, add (minoff,maxoff) to the set. On seeing 'Get (minoff,maxoff)', remove any part of the set overlapping (minoff,maxoff). The same has to happen for any events which implicitly read parts of the guest state: dirty helper calls and loads/stores.*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -