From: Julian Seward Date: Wed, 18 Aug 2004 16:54:52 +0000 (+0000) Subject: Teach iropt to do dead code elimination. X-Git-Tag: svn/VALGRIND_3_0_1^2~1157 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b5330d446d13c0cf7fa60e2d956f1fd27e9ef394;p=thirdparty%2Fvalgrind.git Teach iropt to do dead code elimination. git-svn-id: svn://svn.valgrind.org/vex/trunk@177 --- diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index d876bd5c41..f97248db45 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -1265,7 +1265,8 @@ HInstrArray* iselBB_X86 ( IRBB* bb, Addr64(*find_helper)(Char*) ) /* Ok, finally we can iterate over the statements. */ for (i = 0; i < bb->stmts_used; i++) - iselStmt(env,bb->stmts[i]); + if (bb->stmts[i]) + iselStmt(env,bb->stmts[i]); iselNext(env,bb->next,bb->jumpkind); diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 7415517d22..abe97eeaef 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -278,8 +278,10 @@ void ppIRBB ( IRBB* bb ) ppIRTypeEnv(bb->tyenv); vex_printf("\n"); for (i = 0; i < bb->stmts_used; i++) { - vex_printf( " "); - ppIRStmt(bb->stmts[i]); + if (bb->stmts[i]) { + vex_printf( " "); + ppIRStmt(bb->stmts[i]); + } vex_printf( "\n"); } vex_printf( " goto {"); @@ -764,7 +766,7 @@ void useBeforeDef_Expr ( IRBB* bb, IRStmt* stmt, IRExpr* expr, Int* def_counts ) if (expr->Iex.Tmp.tmp < 0 || expr->Iex.Tmp.tmp >= bb->tyenv->types_used) sanityCheckFail(bb,stmt, "out of range Temp in IRExpr"); if (def_counts[expr->Iex.Tmp.tmp] < 1) - sanityCheckFail(bb,stmt, "IRTemp def before use in IRExpr"); + sanityCheckFail(bb,stmt, "IRTemp use before def in IRExpr"); break; case Iex_Binop: useBeforeDef_Expr(bb,stmt,expr->Iex.Binop.arg1,def_counts); @@ -980,6 +982,8 @@ void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ) for (i = 0; i < bb->stmts_used; i++) { stmt = bb->stmts[i]; + if (!stmt) + continue; useBeforeDef_Stmt(bb,stmt,def_counts); if (stmt->tag == Ist_Tmp) { if (stmt->Ist.Tmp.tmp < 0 || stmt->Ist.Tmp.tmp >= n_temps) @@ -992,7 +996,8 @@ void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ) /* Typecheck everything. */ for (i = 0; i < bb->stmts_used; i++) - tcStmt( bb, bb->stmts[i], guest_word_size ); + if (bb->stmts[i]) + tcStmt( bb, bb->stmts[i], guest_word_size ); if (typeOfIRExpr(bb->tyenv,bb->next) != guest_word_size) sanityCheckFail(bb, NULL, "bb->next field has wrong type"); } diff --git a/VEX/priv/ir/iropt.c b/VEX/priv/ir/iropt.c index c8ff64837c..d9a7bddf8a 100644 --- a/VEX/priv/ir/iropt.c +++ b/VEX/priv/ir/iropt.c @@ -51,7 +51,8 @@ static Bool lookupH64 ( Hash64* h, /*OUT*/ULong* val, ULong key ) //vex_printf("lookupH64(%llx)\n", key ); for (i = 0; i < h->used; i++) { if (h->inuse[i] && h->key[i] == key) { - *val = h->val[i]; + if (val) + *val = h->val[i]; return True; } } @@ -539,6 +540,111 @@ static IRBB* cprop_BB ( IRBB* in ) +/*---------------------------------------------------------------*/ +/*--- Dead code (t = E) removal ---*/ +/*---------------------------------------------------------------*/ + +/* The type of the Hash64 map is: a map from IRTemp to nothing + -- really just operating a set or IRTemps. +*/ + +static void addUses_Expr ( Hash64* set, IRExpr* e ) +{ + Int i; + switch (e->tag) { + 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_LDle: + addUses_Expr(set, e->Iex.LDle.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: + addToH64(set, (ULong)(e->Iex.Tmp.tmp), 0); + return; + case Iex_Const: + case Iex_Get: + return; + default: + vex_printf("\n"); + ppIRExpr(e); + vpanic("addUses_Expr"); + } +} + +static void addUses_Stmt ( Hash64* set, IRStmt* st ) +{ + switch (st->tag) { + case Ist_Exit: + addUses_Expr(set, st->Ist.Exit.cond); + return; + case Ist_Tmp: + addUses_Expr(set, st->Ist.Tmp.expr); + return; + case Ist_Put: + addUses_Expr(set, st->Ist.Put.expr); + return; + case Ist_STle: + addUses_Expr(set, st->Ist.STle.addr); + addUses_Expr(set, st->Ist.STle.data); + return; + default: + vex_printf("\n"); + ppIRStmt(st); + vpanic("addUses_Stmt"); + } +} + + + +/* 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. */ + +void dead_BB ( IRBB* bb ) +{ + Int i; + Hash64* set = newH64(); + IRStmt* st; + + /* 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_Tmp + && !lookupH64(set, NULL, (ULong)(st->Ist.Tmp.tmp))) { + /* it's an IRTemp which never got used. Delete it. */ + if (1) { + vex_printf("DEAD: "); + ppIRStmt(st); + vex_printf("\n"); + } + bb->stmts[i] = NULL; + } else { + /* Note any IRTemp uses made by the current statement. */ + addUses_Stmt(set, st); + } + } +} + + /*---------------------------------------------------------------*/ /*--- iropt main ---*/ /*---------------------------------------------------------------*/ @@ -565,6 +671,11 @@ IRBB* do_iropt_BB ( IRBB* bb0 ) vex_printf("\n========= CPROPD\n\n" ); ppIRBB(cpd); } + dead_BB ( cpd ); + if (verbose) { + vex_printf("\n========= DEAD\n\n" ); + ppIRBB(cpd); + } return cpd; }