From: Michael Beck Date: Fri, 8 May 2009 10:44:04 +0000 (+0000) Subject: - changed handling of Mux nodes: these are now optimized using the iropt instead... X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=79b409329e8b6e9f43ac71df6599372fa0dbe497;p=libfirm - changed handling of Mux nodes: these are now optimized using the iropt instead of additional runs in the if-conv if-conv: - through away analysis info only when graph was changed - fixed handling of Raise - removed useless dominator computation - add some docu [r25901] --- diff --git a/include/libfirm/firmstat.h b/include/libfirm/firmstat.h index 813bfc1b1..c784455f8 100644 --- a/include/libfirm/firmstat.h +++ b/include/libfirm/firmstat.h @@ -82,6 +82,8 @@ enum firmstat_optimizations_t { FS_OPT_CONV, /**< a Conv could be removed */ FS_OPT_CAST, /**< a Cast could be removed */ FS_OPT_MIN_MAX_EQ, /**< Min(a,a) = Max(a,a) = a */ + FS_OPT_MUX_COMBINE, /**< two Mux nodes where combined into one */ + FS_OPT_MUX_CONV, /**< MuxI(sel, 1, 0) = (I)sel */ FS_OPT_MUX_BOOL, /**< Muxb(sel, true, false) = sel */ FS_OPT_MUX_NOT_BOOL, /**< Muxb(sel, false, true) = Not(sel) */ FS_OPT_MUX_OR_BOOL, /**< Muxb(sel, true, x) = Or(sel, x) */ diff --git a/include/libfirm/irflag.h b/include/libfirm/irflag.h index b25127eb0..879151291 100644 --- a/include/libfirm/irflag.h +++ b/include/libfirm/irflag.h @@ -253,6 +253,12 @@ void set_opt_auto_create_sync(int value); */ void set_opt_normalize(int value); +/** + * Enable/Disable ConvB() nodes with a "semantic behavior", i.e. a real + * operation that must be executed. + */ +void set_opt_allow_conv_b(int value); + /** Enable/Disable precise exception context. * * If enabled, all exceptions form a barrier for values, as in the diff --git a/ir/ir/irflag_t.def b/ir/ir/irflag_t.def index e735997a7..ee167acea 100644 --- a/ir/ir/irflag_t.def +++ b/ir/ir/irflag_t.def @@ -75,6 +75,8 @@ E_FLAG(dyn_meth_dispatch , 11, ON) */ I_FLAG(normalize , 12, ON) +I_FLAG(allow_conv_b , 13, ON) + /** precise exception context */ I_FLAG(precise_exc_context , 15, ON) diff --git a/ir/ir/iropt.c b/ir/ir/iropt.c index f225d2522..08208afd6 100644 --- a/ir/ir/iropt.c +++ b/ir/ir/iropt.c @@ -1744,24 +1744,44 @@ static ir_node *equivalent_node_Id(ir_node *n) { static ir_node *equivalent_node_Mux(ir_node *n) { ir_node *oldn = n, *sel = get_Mux_sel(n); + ir_node *n_t, *n_f; tarval *ts = value_of(sel); /* Mux(true, f, t) == t */ if (ts == tarval_b_true) { n = get_Mux_true(n); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_C); + return n; } /* Mux(false, f, t) == f */ - else if (ts == tarval_b_false) { + if (ts == tarval_b_false) { n = get_Mux_false(n); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_C); + return n; + } + n_t = get_Mux_true(n); + n_f = get_Mux_false(n); + + /* Mux(v, x, T) == x */ + if (is_Unknown(n_f)) { + n = n_t; + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_EQ); + return n; } + /* Mux(v, T, x) == x */ + if (is_Unknown(n_t)) { + n = n_f; + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_EQ); + return n; + } + /* Mux(v, x, x) == x */ - else if (get_Mux_false(n) == get_Mux_true(n)) { - n = get_Mux_true(n); + if (n_t == n_f) { + n = n_t; DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_EQ); + return n; } - else if (is_Proj(sel) && !mode_honor_signed_zeros(get_irn_mode(n))) { + if (is_Proj(sel) && !mode_honor_signed_zeros(get_irn_mode(n))) { ir_node *cmp = get_Proj_pred(sel); long proj_nr = get_Proj_proj(sel); ir_node *f = get_Mux_false(n); @@ -5470,6 +5490,60 @@ static ir_node *transform_node_Mux(ir_node *n) { ir_node *f = get_Mux_false(n); ir_graph *irg = current_ir_graph; + if (is_Mux(t)) { + ir_node* block = get_nodes_block(n); + ir_node* c0 = sel; + ir_node* c1 = get_Mux_sel(t); + ir_node* t1 = get_Mux_true(t); + ir_node* f1 = get_Mux_false(t); + if (f == f1) { + /* Mux(c0, Mux(c1, x, y), y) -> typical if (c0 && c1) x else y */ + ir_node* and_ = new_r_And(irg, block, c0, c1, mode_b); + ir_node* new_mux = new_r_Mux(irg, block, and_, f1, t1, mode); + n = new_mux; + sel = and_; + f = f1; + t = t1; + DBG_OPT_ALGSIM0(oldn, t, FS_OPT_MUX_COMBINE); + } else if (f == t1) { + /* Mux(c0, Mux(c1, x, y), x) */ + ir_node* not_c1 = new_r_Not(irg, block, c1, mode_b); + ir_node* and_ = new_r_And(irg, block, c0, not_c1, mode_b); + ir_node* new_mux = new_r_Mux(irg, block, and_, t1, f1, mode); + n = new_mux; + sel = and_; + f = t1; + t = f1; + DBG_OPT_ALGSIM0(oldn, t, FS_OPT_MUX_COMBINE); + } + } else if (is_Mux(f)) { + ir_node* block = get_nodes_block(n); + ir_node* c0 = sel; + ir_node* c1 = get_Mux_sel(f); + ir_node* t1 = get_Mux_true(f); + ir_node* f1 = get_Mux_false(f); + if (t == t1) { + /* Mux(c0, x, Mux(c1, x, y)) -> typical if (c0 || c1) x else y */ + ir_node* or_ = new_r_Or(irg, block, c0, c1, mode_b); + ir_node* new_mux = new_r_Mux(irg, block, or_, f1, t1, mode); + n = new_mux; + sel = or_; + f = f1; + t = t1; + DBG_OPT_ALGSIM0(oldn, f, FS_OPT_MUX_COMBINE); + } else if (t == f1) { + /* Mux(c0, x, Mux(c1, y, x)) */ + ir_node* not_c1 = new_r_Not(irg, block, c1, mode_b); + ir_node* or_ = new_r_Or(irg, block, c0, not_c1, mode_b); + ir_node* new_mux = new_r_Mux(irg, block, or_, t1, f1, mode); + n = new_mux; + sel = or_; + f = t1; + t = f1; + DBG_OPT_ALGSIM0(oldn, f, FS_OPT_MUX_COMBINE); + } + } + /* first normalization step: move a possible zero to the false case */ if (is_Proj(sel)) { ir_node *cmp = get_Proj_pred(sel); @@ -5536,6 +5610,24 @@ static ir_node *transform_node_Mux(ir_node *n) { tarval *null = get_tarval_null(mode); tarval *diff, *min; + if (get_opt_allow_conv_b()) { + if (tarval_is_one(a) && tarval_is_null(b)) { + ir_node *block = get_nodes_block(n); + ir_node *conv = new_r_Conv(current_ir_graph, block, sel, mode); + n = conv; + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_CONV); + return n; + } else if (tarval_is_null(a) && tarval_is_one(b)) { + ir_node *block = get_nodes_block(n); + ir_node *not_ = new_r_Not(current_ir_graph, block, sel, mode_b); + ir_node *conv = new_r_Conv(current_ir_graph, block, not_, mode); + n = conv; + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_CONV); + return n; + } + } + /* TODO: it's not really clear if that helps in general or should be moved + * to backend, especially with the MUX->Conv transformation above */ if (tarval_cmp(a, b) & pn_Cmp_Gt) { diff = tarval_sub(a, b, NULL); min = b; @@ -5544,10 +5636,9 @@ static ir_node *transform_node_Mux(ir_node *n) { min = a; } - if (diff == get_tarval_one(mode) && min != null) { + if (diff == get_tarval_one(mode)) { dbg_info *dbg = get_irn_dbg_info(n); ir_node *block = get_nodes_block(n); - ir_graph *irg = current_ir_graph; ir_node *t = new_Const(tarval_sub(a, min, NULL)); ir_node *f = new_Const(tarval_sub(b, min, NULL)); n = new_rd_Mux(dbg, irg, block, sel, f, t, mode); diff --git a/ir/lower/lower_mode_b.c b/ir/lower/lower_mode_b.c index a186ce3ee..e591f951b 100644 --- a/ir/lower/lower_mode_b.c +++ b/ir/lower/lower_mode_b.c @@ -32,6 +32,7 @@ #include "irnode_t.h" #include "ircons_t.h" +#include "irflag.h" #include "irgwalk.h" #include "irtools.h" #include "iredges.h" @@ -406,6 +407,7 @@ void ir_lower_mode_b(ir_graph *irg, const lower_mode_b_config_t *nconfig) ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK); + set_opt_allow_conv_b(0); irg_walk_graph(irg, clear_links, NULL, NULL); irg_walk_graph(irg, lower_mode_b_walker, NULL, NULL); diff --git a/ir/opt/ifconv.c b/ir/opt/ifconv.c index 56e560799..1fda437c9 100644 --- a/ir/opt/ifconv.c +++ b/ir/opt/ifconv.c @@ -32,7 +32,6 @@ #include "irnode_t.h" #include "cdep.h" #include "ircons.h" -#include "irdom.h" #include "irgmod.h" #include "irgopt.h" #include "irgwalk.h" @@ -43,9 +42,19 @@ #include "irdump.h" #include "debug.h" +/** + * Environment for if-conversion. + */ +typedef struct walker_env { + const ir_settings_if_conv_t *params; /**< Conversion parameter. */ + int changed; /**< Set if the graph was changed. */ +} walker_env; + DEBUG_ONLY(static firm_dbg_module_t *dbg); -/** allow every Mux to be created. */ +/** + * Default callback for Mux creation: allows every Mux to be created. + */ static int default_allow_ifconv(ir_node *sel, ir_node* phi_list, int i, int j) { (void) sel; @@ -65,12 +74,23 @@ static const ir_settings_if_conv_t default_info = { /** * Returns non-zero if a Block can be emptied. + * + * @param block the block */ static int can_empty_block(ir_node *block) { return get_Block_mark(block) == 0; } - +/** + * Find the ProjX node leading from block dependency to block start. + * + * @param start a block that is control depended on dependency + * @param dependency the block that decides whether start is executed + * + * @return a ProjX node that represent the decision control flow or + * NULL is start is not dependent at all or a block on the way + * cannot be emptied + */ static ir_node* walk_to_projx(ir_node* start, const ir_node* dependency) { int arity; @@ -83,18 +103,21 @@ static ir_node* walk_to_projx(ir_node* start, const ir_node* dependency) arity = get_irn_arity(start); for (i = 0; i < arity; ++i) { ir_node* pred = get_irn_n(start, i); - ir_node* pred_block = get_nodes_block(pred); + ir_node* pred_block = get_nodes_block(skip_Proj(pred)); if (pred_block == dependency) { if (is_Proj(pred)) { assert(get_irn_mode(pred) == mode_X); + /* we found it */ return pred; } + /* Not a Proj? Should not happen. */ return NULL; } if (is_Proj(pred)) { assert(get_irn_mode(pred) == mode_X); + /* another Proj but not from the control block */ return NULL; } @@ -107,22 +130,37 @@ static ir_node* walk_to_projx(ir_node* start, const ir_node* dependency) /** - * Copies the DAG starting at node to the ith predecessor block of src_block - * -if the node isn't in the src_block, this is a nop and the node is returned - * -if the node is a phi in the src_block, the ith predecessor of the phi is - * returned - * otherwise returns the copy of the passed node + * Recursively copies the DAG starting at node to the i-th predecessor + * block of src_block + * - if node isn't in the src_block, recursion ends and node is returned + * - if node is a Phi in the src_block, the i-th predecessor of this Phi is + * returned and recursion ends + * otherwise returns a copy of the passed node created in the i-th predecessor of + * src_block. + * + * @param node a root of a DAG + * @param src_block the block of the DAG + * @param i the position of the predecessor the DAG + * is moved to + * + * @return the root of the copied DAG */ static ir_node* copy_to(ir_node* node, ir_node* src_block, int i) { ir_node* dst_block; ir_node* copy; - int arity; int j; - if (get_nodes_block(node) != src_block) return node; - if (get_irn_op(node) == op_Phi) return get_irn_n(node, i); + if (get_nodes_block(node) != src_block) { + /* already outside src_block, do not copy */ + return node; + } + if (is_Phi(node)) { + /* move through the Phi to the i-th predecessor */ + return get_irn_n(node, i); + } + /* else really need a copy */ copy = exact_copy(node); dst_block = get_nodes_block(get_irn_n(src_block, i)); set_nodes_block(copy, dst_block); @@ -130,8 +168,8 @@ static ir_node* copy_to(ir_node* node, ir_node* src_block, int i) DB((dbg, LEVEL_1, "Copying node %+F to block %+F, copy is %+F\n", node, dst_block, copy)); - arity = get_irn_arity(node); - for (j = 0; j < arity; ++j) { + /* move recursively all predecessors */ + for (j = get_irn_arity(node) - 1; j >= 0; --j) { set_irn_n(copy, j, copy_to(get_irn_n(node, j), src_block, i)); DB((dbg, LEVEL_2, "-- pred %d is %+F\n", j, get_irn_n(copy, j))); } @@ -140,7 +178,13 @@ static ir_node* copy_to(ir_node* node, ir_node* src_block, int i) /** - * Remove predecessors i and j from node and add predecessor new_pred + * Remove predecessors i and j (i < j) from a node and + * add an additional predecessor new_pred. + * + * @param node the node whose inputs are changed + * @param i the first index to remove + * @param j the second index to remove + * @param new_pred a node that is added as a new input to node */ static void rewire(ir_node* node, int i, int j, ir_node* new_pred) { @@ -162,7 +206,7 @@ static void rewire(ir_node* node, int i, int j, ir_node* new_pred) /** - * Remove the jth predecessors from the ith predecessor of block and add it to block + * Remove the j-th predecessors from the i-th predecessor of block and add it to block */ static void split_block(ir_node* block, int i, int j) { @@ -242,10 +286,12 @@ static void prepare_path(ir_node* block, int i, const ir_node* dependency) } } - -static void if_conv_walker(ir_node* block, void* env) +/** + * Block walker: Search for diamonds and do the if conversion. + */ +static void if_conv_walker(ir_node *block, void *ctx) { - ir_settings_if_conv_t* opt_info = env; + walker_env *env = ctx; int arity; int i; @@ -291,12 +337,14 @@ restart: if (projx1 == NULL) continue; phi = get_Block_phis(block); - if (!opt_info->allow_ifconv(get_Cond_selector(cond), phi, i, j)) continue; + if (!env->params->allow_ifconv(get_Cond_selector(cond), phi, i, j)) + continue; DB((dbg, LEVEL_1, "Found Cond %+F with proj %+F and %+F\n", cond, projx0, projx1 )); + env->changed = 1; prepare_path(block, i, dependency); prepare_path(block, j, dependency); arity = get_irn_arity(block); @@ -340,7 +388,6 @@ restart: } else { rewire(phi, i, j, mux); } - phi = next_phi; } while (phi != NULL); @@ -378,7 +425,7 @@ restart: } /** - * Block walker: clear block mark and Phi list + * Block walker: clear block marks and Phi lists. */ static void init_block_link(ir_node *block, void *env) { @@ -389,7 +436,7 @@ static void init_block_link(ir_node *block, void *env) /** - * Daisy-chain all phis in a block + * Daisy-chain all Phis in a block. * If a non-movable node is encountered set the has_pinned flag in its block. */ static void collect_phis(ir_node *node, void *env) { @@ -402,10 +449,9 @@ static void collect_phis(ir_node *node, void *env) { } else { if (is_no_Block(node) && get_irn_pinned(node) == op_pin_state_pinned) { /* - * Ignore control flow nodes, these will be removed. - * This ignores Raise. That is surely bad. FIXME. + * Ignore control flow nodes (except Raise), these will be removed. */ - if (!is_cfop(node)) { + if (!is_cfop(node) && !is_Raise(node)) { ir_node *block = get_nodes_block(node); DB((dbg, LEVEL_2, "Node %+F in block %+F is unmovable\n", node, block)); @@ -415,115 +461,13 @@ static void collect_phis(ir_node *node, void *env) { } } -static void optimise_muxs_0(ir_node* mux, void* env) -{ - ir_node* t; - ir_node* f; - - (void) env; - - if (!is_Mux(mux)) return; - - t = get_Mux_true(mux); - f = get_Mux_false(mux); - - DB((dbg, LEVEL_3, "Simplify %+F T=%+F F=%+F\n", mux, t, f)); - - if (is_Unknown(t)) { - DB((dbg, LEVEL_3, "Replace Mux with unknown operand by %+F\n", f)); - exchange(mux, f); - return; - } - if (is_Unknown(f)) { - DB((dbg, LEVEL_3, "Replace Mux with unknown operand by %+F\n", t)); - exchange(mux, t); - return; - } - - if (is_Mux(t)) { - ir_graph* irg = current_ir_graph; - ir_node* block = get_nodes_block(mux); - ir_mode* mode = get_irn_mode(mux); - ir_node* c0 = get_Mux_sel(mux); - ir_node* c1 = get_Mux_sel(t); - ir_node* t1 = get_Mux_true(t); - ir_node* f1 = get_Mux_false(t); - if (f == f1) { - /* Mux(c0, Mux(c1, x, y), y) -> typical if (c0 && c1) x else y */ - ir_node* and_ = new_r_And(irg, block, c0, c1, mode_b); - ir_node* new_mux = new_r_Mux(irg, block, and_, f1, t1, mode); - exchange(mux, new_mux); - } else if (f == t1) { - /* Mux(c0, Mux(c1, x, y), x) */ - ir_node* not_c1 = new_r_Not(irg, block, c1, mode_b); - ir_node* and_ = new_r_And(irg, block, c0, not_c1, mode_b); - ir_node* new_mux = new_r_Mux(irg, block, and_, t1, f1, mode); - exchange(mux, new_mux); - } - } else if (is_Mux(f)) { - ir_graph* irg = current_ir_graph; - ir_node* block = get_nodes_block(mux); - ir_mode* mode = get_irn_mode(mux); - ir_node* c0 = get_Mux_sel(mux); - ir_node* c1 = get_Mux_sel(f); - ir_node* t1 = get_Mux_true(f); - ir_node* f1 = get_Mux_false(f); - if (t == t1) { - /* Mux(c0, x, Mux(c1, x, y)) -> typical if (c0 || c1) x else y */ - ir_node* or_ = new_r_Or(irg, block, c0, c1, mode_b); - ir_node* new_mux = new_r_Mux(irg, block, or_, f1, t1, mode); - exchange(mux, new_mux); - } else if (t == f1) { - /* Mux(c0, x, Mux(c1, y, x)) */ - ir_node* not_c1 = new_r_Not(irg, block, c1, mode_b); - ir_node* or_ = new_r_Or(irg, block, c0, not_c1, mode_b); - ir_node* new_mux = new_r_Mux(irg, block, or_, t1, f1, mode); - exchange(mux, new_mux); - } - } -} - - -static void optimise_muxs_1(ir_node* mux, void* env) -{ - ir_node* t; - ir_node* f; - ir_mode* mode; - - (void) env; - - if (!is_Mux(mux)) return; - - t = get_Mux_true(mux); - f = get_Mux_false(mux); - - DB((dbg, LEVEL_3, "Simplify %+F T=%+F F=%+F\n", mux, t, f)); - - mode = get_irn_mode(mux); - - if (is_Const(t) && is_Const(f) && (mode_is_int(mode))) { - ir_node* block = get_nodes_block(mux); - ir_node* c = get_Mux_sel(mux); - tarval* tv_t = get_Const_tarval(t); - tarval* tv_f = get_Const_tarval(f); - if (tarval_is_one(tv_t) && tarval_is_null(tv_f)) { - ir_node* conv = new_r_Conv(current_ir_graph, block, c, mode); - exchange(mux, conv); - } else if (tarval_is_null(tv_t) && tarval_is_one(tv_f)) { - ir_node* not_ = new_r_Not(current_ir_graph, block, c, mode_b); - ir_node* conv = new_r_Conv(current_ir_graph, block, not_, mode); - exchange(mux, conv); - } - } -} - - void opt_if_conv(ir_graph *irg, const ir_settings_if_conv_t *params) { - ir_settings_if_conv_t p; + walker_env env; /* get the parameters */ - p = (params != NULL ? *params : default_info); + env.params = (params != NULL ? params : &default_info); + env.changed = 0; FIRM_DBG_REGISTER(dbg, "firm.opt.ifconv"); @@ -533,28 +477,24 @@ void opt_if_conv(ir_graph *irg, const ir_settings_if_conv_t *params) remove_critical_cf_edges(irg); compute_cdep(irg); - assure_doms(irg); ir_reserve_resources(irg, IR_RESOURCE_BLOCK_MARK | IR_RESOURCE_PHI_LIST); irg_block_walk_graph(irg, init_block_link, NULL, NULL); irg_walk_graph(irg, collect_phis, NULL, NULL); - irg_block_walk_graph(irg, NULL, if_conv_walker, &p); + irg_block_walk_graph(irg, NULL, if_conv_walker, &env); ir_free_resources(irg, IR_RESOURCE_BLOCK_MARK | IR_RESOURCE_PHI_LIST); - local_optimize_graph(irg); - - irg_walk_graph(irg, NULL, optimise_muxs_0, NULL); -#if 1 - irg_walk_graph(irg, NULL, optimise_muxs_1, NULL); -#endif + if (env.changed) { + local_optimize_graph(irg); - /* TODO: graph might be changed, handle more graceful */ - set_irg_outs_inconsistent(irg); - set_irg_extblk_inconsistent(irg); - set_irg_loopinfo_inconsistent(irg); - free_dom(irg); + /* graph has changed, invalidate analysis info */ + set_irg_outs_inconsistent(irg); + set_irg_extblk_inconsistent(irg); + set_irg_loopinfo_inconsistent(irg); + set_irg_doms_inconsistent(irg); + } free_cdep(irg); } diff --git a/ir/stat/stat_dmp.c b/ir/stat/stat_dmp.c index dba32d37f..9759b483c 100644 --- a/ir/stat/stat_dmp.c +++ b/ir/stat/stat_dmp.c @@ -99,6 +99,8 @@ static const struct { { FS_OPT_CONV, "algebraic simplification: Conv could be removed" }, { FS_OPT_CAST, "algebraic simplification: a Cast could be removed" }, { FS_OPT_MIN_MAX_EQ, "algebraic simplification: Min(a,a) = Max(a,a) = a" }, + { FS_OPT_MUX_COMBINE, "boolean simplification: two Mux nodes where combined into one" }, + { FS_OPT_MUX_CONV, "boolean simplification: MuxI(sel, 1, 0) = (I)sel" }, { FS_OPT_MUX_BOOL, "boolean simplification: Muxb(sel, true, false) = sel" }, { FS_OPT_MUX_NOT_BOOL, "boolean simplification: Muxb(sel, false, true) = Not(sel)" }, { FS_OPT_MUX_OR_BOOL, "boolean simplification: Muxb(sel, true, x) = Or(sel, x)" },