📄 iropt.c
字号:
); } case Iex_Mux0X: vassert(isIRAtom(ex->Iex.Mux0X.cond)); vassert(isIRAtom(ex->Iex.Mux0X.expr0)); vassert(isIRAtom(ex->Iex.Mux0X.exprX)); return IRExpr_Mux0X( subst_Expr(env, ex->Iex.Mux0X.cond), subst_Expr(env, ex->Iex.Mux0X.expr0), subst_Expr(env, ex->Iex.Mux0X.exprX) ); default: vex_printf("\n\n"); ppIRExpr(ex); vpanic("subst_Expr"); }}/* Apply the subst to stmt, then fold the result as much as possible. Much simplified due to stmt being previously flattened. As a result of this, the stmt may wind up being turned into a no-op. */static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st ){# if 0 vex_printf("\nsubst and fold stmt\n"); ppIRStmt(st); vex_printf("\n");# endif switch (st->tag) { case Ist_AbiHint: vassert(isIRAtom(st->Ist.AbiHint.base)); return IRStmt_AbiHint( fold_Expr(subst_Expr(env, st->Ist.AbiHint.base)), st->Ist.AbiHint.len ); case Ist_Put: vassert(isIRAtom(st->Ist.Put.data)); return IRStmt_Put( st->Ist.Put.offset, fold_Expr(subst_Expr(env, st->Ist.Put.data)) ); case Ist_PutI: vassert(isIRAtom(st->Ist.PutI.ix)); vassert(isIRAtom(st->Ist.PutI.data)); return IRStmt_PutI( st->Ist.PutI.descr, fold_Expr(subst_Expr(env, st->Ist.PutI.ix)), st->Ist.PutI.bias, fold_Expr(subst_Expr(env, st->Ist.PutI.data)) ); case Ist_Tmp: /* This is the one place where an expr (st->Ist.Tmp.data) is allowed to be more than just a constant or a tmp. */ return IRStmt_Tmp( st->Ist.Tmp.tmp, fold_Expr(subst_Expr(env, st->Ist.Tmp.data)) ); case Ist_Store: vassert(isIRAtom(st->Ist.Store.addr)); vassert(isIRAtom(st->Ist.Store.data)); return IRStmt_Store( st->Ist.Store.end, fold_Expr(subst_Expr(env, st->Ist.Store.addr)), fold_Expr(subst_Expr(env, st->Ist.Store.data)) ); case Ist_Dirty: { Int i; IRDirty *d, *d2; d = st->Ist.Dirty.details; d2 = emptyIRDirty(); *d2 = *d; d2->args = sopyIRExprVec(d2->args); if (d2->mFx != Ifx_None) { vassert(isIRAtom(d2->mAddr)); d2->mAddr = fold_Expr(subst_Expr(env, d2->mAddr)); } vassert(isIRAtom(d2->guard)); d2->guard = fold_Expr(subst_Expr(env, d2->guard)); for (i = 0; d2->args[i]; i++) { vassert(isIRAtom(d2->args[i])); d2->args[i] = fold_Expr(subst_Expr(env, d2->args[i])); } return IRStmt_Dirty(d2); } case Ist_IMark: return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len); case Ist_NoOp: return IRStmt_NoOp(); case Ist_MFence: return IRStmt_MFence(); case Ist_Exit: { IRExpr* fcond; vassert(isIRAtom(st->Ist.Exit.guard)); fcond = fold_Expr(subst_Expr(env, st->Ist.Exit.guard)); if (fcond->tag == Iex_Const) { /* Interesting. The condition on this exit has folded down to a constant. */ vassert(fcond->Iex.Const.con->tag == Ico_U1); vassert(fcond->Iex.Const.con->Ico.U1 == False || fcond->Iex.Const.con->Ico.U1 == True); if (fcond->Iex.Const.con->Ico.U1 == False) { /* exit is never going to happen, so dump the statement. */ return IRStmt_NoOp(); } else { vassert(fcond->Iex.Const.con->Ico.U1 == True); /* Hmmm. The exit has become unconditional. Leave it as it is for now, since we'd have to truncate the BB at this point, which is tricky. */ /* fall out into the reconstruct-the-exit code. */ if (vex_control.iropt_verbosity > 0) /* really a misuse of vex_control.iropt_verbosity */ vex_printf("vex iropt: IRStmt_Exit became unconditional\n"); } } return IRStmt_Exit(fcond, st->Ist.Exit.jk, st->Ist.Exit.dst); } default: vex_printf("\n"); ppIRStmt(st); vpanic("subst_and_fold_Stmt"); }}IRBB* cprop_BB ( IRBB* in ){ Int i; IRBB* out; IRStmt* st2; Int n_tmps = in->tyenv->types_used; IRExpr** env = LibVEX_Alloc(n_tmps * sizeof(IRExpr*)); out = emptyIRBB(); out->tyenv = dopyIRTypeEnv( in->tyenv ); /* Set up the env with which travels forward. This holds a substitution, mapping IRTemps to atoms, that is, IRExprs which are either IRTemps or IRConsts. Thus, copy and constant propagation is done. The environment is to be applied as we move along. Keys are IRTemps. Values are IRExpr*s. */ for (i = 0; i < n_tmps; i++) env[i] = NULL; /* For each original SSA-form stmt ... */ for (i = 0; i < in->stmts_used; i++) { /* First apply the substitution to the current stmt. This propagates in any constants and tmp-tmp assignments accumulated prior to this point. As part of the subst_Stmt call, also then fold any constant expressions resulting. */ st2 = in->stmts[i]; /* perhaps st2 is already a no-op? */ if (st2->tag == Ist_NoOp) continue; st2 = subst_and_fold_Stmt( env, st2 ); /* If the statement has been folded into a no-op, forget it. */ if (st2->tag == Ist_NoOp) continue; /* Now consider what the stmt looks like. If it's of the form 't = const' or 't1 = t2', add it to the running environment and not to the output BB. Otherwise, add it to the output BB. Note, we choose not to propagate const when const is an F64i, so that F64i literals can be CSE'd later. This helps x86 floating point code generation. */ if (st2->tag == Ist_Tmp && st2->Ist.Tmp.data->tag == Iex_Const && st2->Ist.Tmp.data->Iex.Const.con->tag != Ico_F64i) { /* 't = const' -- add to env. The pair (IRTemp, IRExpr*) is added. */ env[(Int)(st2->Ist.Tmp.tmp)] = st2->Ist.Tmp.data; } else if (st2->tag == Ist_Tmp && st2->Ist.Tmp.data->tag == Iex_Tmp) { /* 't1 = t2' -- add to env. The pair (IRTemp, IRExpr*) is added. */ env[(Int)(st2->Ist.Tmp.tmp)] = st2->Ist.Tmp.data; } else { /* Not interesting, copy st2 into the output block. */ addStmtToIRBB( out, st2 ); } } out->next = subst_Expr( env, in->next ); out->jumpkind = in->jumpkind; return out;}/*---------------------------------------------------------------*//*--- Dead code (t = E) removal ---*//*---------------------------------------------------------------*//* The type of the HashHW map is: a map from IRTemp to nothing -- really just operating a set or IRTemps.*/inlinestatic void addUses_Temp ( Bool* set, IRTemp tmp ){ set[(Int)tmp] = True;}static void addUses_Expr ( Bool* set, IRExpr* e ){ Int i; switch (e->tag) { case Iex_GetI: addUses_Expr(set, e->Iex.GetI.ix); return; case Iex_Mux0X: addUses_Expr(set, e->Iex.Mux0X.cond); addUses_Expr(set, e->Iex.Mux0X.expr0); addUses_Expr(set, e->Iex.Mux0X.exprX); return; case Iex_CCall: for (i = 0; e->Iex.CCall.args[i]; i++) addUses_Expr(set, e->Iex.CCall.args[i]); return; case Iex_Load: addUses_Expr(set, e->Iex.Load.addr); return; case Iex_Binop: addUses_Expr(set, e->Iex.Binop.arg1); addUses_Expr(set, e->Iex.Binop.arg2); return; case Iex_Unop: addUses_Expr(set, e->Iex.Unop.arg); return; case Iex_Tmp: addUses_Temp(set, e->Iex.Tmp.tmp); return; case Iex_Const: case Iex_Get: return; default: vex_printf("\n"); ppIRExpr(e); vpanic("addUses_Expr"); }}static void addUses_Stmt ( Bool* set, IRStmt* st ){ Int i; IRDirty* d; switch (st->tag) { case Ist_AbiHint: addUses_Expr(set, st->Ist.AbiHint.base); return; case Ist_PutI: addUses_Expr(set, st->Ist.PutI.ix); addUses_Expr(set, st->Ist.PutI.data); return; case Ist_Tmp: addUses_Expr(set, st->Ist.Tmp.data); return; case Ist_Put: addUses_Expr(set, st->Ist.Put.data); return; case Ist_Store: addUses_Expr(set, st->Ist.Store.addr); addUses_Expr(set, st->Ist.Store.data); return; case Ist_Dirty: d = st->Ist.Dirty.details; if (d->mFx != Ifx_None) addUses_Expr(set, d->mAddr); addUses_Expr(set, d->guard); for (i = 0; d->args[i] != NULL; i++) addUses_Expr(set, d->args[i]); return; case Ist_NoOp: case Ist_IMark: case Ist_MFence: return; case Ist_Exit: addUses_Expr(set, st->Ist.Exit.guard); return; default: vex_printf("\n"); ppIRStmt(st); vpanic("addUses_Stmt"); }}/* Is this literally IRExpr_Const(IRConst_U1(False)) ? */static Bool isZeroU1 ( IRExpr* e ){ return toBool( e->tag == Iex_Const && e->Iex.Const.con->tag == Ico_U1 && e->Iex.Const.con->Ico.U1 == False );}/* Note, this destructively modifies the given IRBB. *//* Scan backwards through statements, carrying a set of IRTemps which are known to be used after the current point. On encountering 't = E', delete the binding if it is not used. Otherwise, add any temp uses to the set and keep on moving backwards. *//* notstatic */ void do_deadcode_BB ( IRBB* bb ){ Int i; Int n_tmps = bb->tyenv->types_used; Bool* set = LibVEX_Alloc(n_tmps * sizeof(Bool)); IRStmt* st; for (i = 0; i < n_tmps; i++) set[i] = False; /* start off by recording IRTemp uses in the next field. */ addUses_Expr(set, bb->next); /* Work backwards through the stmts */ for (i = bb->stmts_used-1; i >= 0; i--) { st = bb->stmts[i]; if (st->tag == Ist_NoOp) continue; if (st->tag == Ist_Tmp && set[(Int)(st->Ist.Tmp.tmp)] == False) { /* it's an IRTemp which never got used. Delete it. */ if (DEBUG_IROPT) { vex_printf("DEAD: "); ppIRStmt(st); vex_printf("\n"); } bb->stmts[i] = IRStmt_NoOp(); } else if (st->tag == Ist_Dirty && st->Ist.Dirty.details->guard && isZeroU1(st->Ist.Dirty.details->guard)) { /* This is a dirty helper which will never get called. Delete it. */ bb->stmts[i] = IRStmt_NoOp(); } else { /* Note any IRTemp uses made by the current statement. */ addUses_Stmt(set, st); } }}/*---------------------------------------------------------------*//*--- Specialisation of helper function calls, in ---*//*--- collaboration with the front end ---*//*---------------------------------------------------------------*/static IRBB* spec_helpers_BB ( IRBB* bb, IRExpr* (*specHelper) ( HChar*, IRExpr**) ) { Int i; IRStmt* st; IRExpr* ex; Bool any = False; for (i = bb->stmts_used-1; i >=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -