iropt.c

来自「The Valgrind distribution has multiple t」· C语言 代码 · 共 1,868 行 · 第 1/5 页

C
1,868
字号
         return ex;      default:         vex_printf("\n");         ppIRExpr(ex);          vex_printf("\n");         vpanic("flatten_Expr");   }}/* Append a completely flattened form of 'st' to the end of 'bb'. */static void flatten_Stmt ( IRBB* bb, IRStmt* st ){   Int i;   IRExpr  *e1, *e2;   IRDirty *d,  *d2;   switch (st->tag) {      case Ist_Put:         if (isIRAtom(st->Ist.Put.data)) {            /* optimisation to reduce the amount of heap wasted               by the flattener */            addStmtToIRBB(bb, st);         } else {            /* general case, always correct */            e1 = flatten_Expr(bb, st->Ist.Put.data);            addStmtToIRBB(bb, IRStmt_Put(st->Ist.Put.offset, e1));         }         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

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?