X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fir%2Firopt.c;h=73756025585891bc03a0eddbd0b0e09e442a7a5a;hb=b78bdd4d94de46de4156272e6dbfe44e97933a5b;hp=1ed0e68179e70a3f5de88e4998307e96ecf2e940;hpb=f318665008f53ec4d268496ab9c765bcef0fc338;p=libfirm diff --git a/ir/ir/iropt.c b/ir/ir/iropt.c index 1ed0e6817..737560255 100644 --- a/ir/ir/iropt.c +++ b/ir/ir/iropt.c @@ -24,24 +24,25 @@ #include #endif -# include "irnode_t.h" -# include "irgraph_t.h" -# include "iredges_t.h" -# include "irmode_t.h" -# include "iropt_t.h" -# include "ircons_t.h" -# include "irgmod.h" -# include "irvrfy.h" -# include "tv_t.h" -# include "dbginfo_t.h" -# include "iropt_dbg.h" -# include "irflag_t.h" -# include "irhooks.h" -# include "irarch.h" -# include "hashptr.h" -# include "archop.h" -# include "opt_polymorphy.h" -# include "opt_confirms.h" +#include "irnode_t.h" +#include "irgraph_t.h" +#include "iredges_t.h" +#include "irmode_t.h" +#include "iropt_t.h" +#include "ircons_t.h" +#include "irgmod.h" +#include "irvrfy.h" +#include "tv_t.h" +#include "dbginfo_t.h" +#include "iropt_dbg.h" +#include "irflag_t.h" +#include "irhooks.h" +#include "irarch.h" +#include "hashptr.h" +#include "archop.h" +#include "opt_polymorphy.h" +#include "opt_confirms.h" +#include "irtools.h" /* Make types visible to allow most efficient access */ # include "entity_t.h" @@ -59,9 +60,22 @@ static tarval *computed_value_Const(ir_node *n) */ static tarval *computed_value_SymConst(ir_node *n) { - if ((get_SymConst_kind(n) == symconst_size) && - (get_type_state(get_SymConst_type(n))) == layout_fixed) - return new_tarval_from_long(get_type_size_bytes(get_SymConst_type(n)), get_irn_mode(n)); + ir_type *type; + + switch (get_SymConst_kind(n)) { + case symconst_type_size: + type = get_SymConst_type(n); + if (get_type_state(type) == layout_fixed) + return new_tarval_from_long(get_type_size_bytes(type), get_irn_mode(n)); + break; + case symconst_type_align: + type = get_SymConst_type(n); + if (get_type_state(type) == layout_fixed) + return new_tarval_from_long(get_type_alignment_bytes(type), get_irn_mode(n)); + break; + default: + break; + } return tarval_bad; } @@ -106,6 +120,51 @@ static tarval *computed_value_Sub(ir_node *n) return tarval_bad; } +/** + * return the value of a Carry + * Special : a op 0, 0 op b + */ +static tarval *computed_value_Carry(ir_node *n) +{ + ir_node *a = get_binop_left(n); + ir_node *b = get_binop_right(n); + ir_mode *m = get_irn_mode(n); + + tarval *ta = value_of(a); + tarval *tb = value_of(b); + + if ((ta != tarval_bad) && (tb != tarval_bad)) { + tarval_add(ta, tb); + return tarval_carry() ? get_mode_one(m) : get_mode_null(m); + } else { + if ( (classify_tarval(ta) == TV_CLASSIFY_NULL) + || (classify_tarval(tb) == TV_CLASSIFY_NULL)) + return get_mode_null(m); + } + return tarval_bad; +} + +/** + * return the value of a Borrow + * Special : a op 0 + */ +static tarval *computed_value_Borrow(ir_node *n) +{ + ir_node *a = get_binop_left(n); + ir_node *b = get_binop_right(n); + ir_mode *m = get_irn_mode(n); + + tarval *ta = value_of(a); + tarval *tb = value_of(b); + + if ((ta != tarval_bad) && (tb != tarval_bad)) { + return tarval_cmp(ta, tb) == pn_Cmp_Lt ? get_mode_one(m) : get_mode_null(m); + } else if (classify_tarval(ta) == TV_CLASSIFY_NULL) { + return get_mode_null(m); + } + return tarval_bad; +} + /** * return the value of an unary Minus */ @@ -512,7 +571,6 @@ static tarval *computed_value_Proj_Cmp(ir_node *n) return new_tarval_from_long(proj_nr & pn_Cmp_Ne, mode_b); } } - return computed_value_Cmp_Confirm(a, aa, ab, proj_nr); } @@ -573,6 +631,18 @@ static tarval *computed_value_Mux(ir_node *n) return tarval_bad; } +/** + * Calculate the value of a Psi: can be evaluated, if a condition is true + * and all previous conditions are false. If all conditions are false + * we evaluate to the default one. + */ +static tarval *computed_value_Psi(ir_node *n) +{ + if (is_Mux(n)) + return computed_value_Mux(n); + return tarval_bad; +} + /** * calculate the value of a Confirm: can be evaluated, * if it has the form Confirm(x, '=', Const). @@ -631,9 +701,12 @@ static ir_op_ops *firm_set_default_computed_value(opcode code, ir_op_ops *ops) CASE(Shr); CASE(Shrs); CASE(Rot); + CASE(Carry); + CASE(Borrow); CASE(Conv); CASE(Proj); CASE(Mux); + CASE(Psi); CASE(Confirm); default: /* leave NULL */; @@ -643,25 +716,6 @@ static ir_op_ops *firm_set_default_computed_value(opcode code, ir_op_ops *ops) #undef CASE } -#if 0 -/* returns 1 if the a and b are pointers to different locations. */ -static bool -different_identity (ir_node *a, ir_node *b) -{ - assert (mode_is_reference(get_irn_mode (a)) - && mode_is_reference(get_irn_mode (b))); - - if (get_irn_op (a) == op_Proj && get_irn_op(b) == op_Proj) { - ir_node *a1 = get_Proj_pred (a); - ir_node *b1 = get_Proj_pred (b); - if (a1 != b1 && get_irn_op (a1) == op_Alloc - && get_irn_op (b1) == op_Alloc) - return 1; - } - return 0; -} -#endif - /** * Returns a equivalent block for another block. * If the block has only one predecessor, this is @@ -734,8 +788,8 @@ static ir_node *equivalent_node_Block(ir_node *n) } } else if (get_opt_unreachable_code() && - (n != current_ir_graph->start_block) && - (n != current_ir_graph->end_block) ) { + (n != get_irg_start_block(current_ir_graph)) && + (n != get_irg_end_block(current_ir_graph)) ) { int i; /* If all inputs are dead, this block is dead too, except if it is @@ -766,7 +820,7 @@ static ir_node *equivalent_node_Block(ir_node *n) /** * Returns a equivalent node for a Jmp, a Bad :-) - * Of course this only happens if the Block of the Jmp is Bad. + * Of course this only happens if the Block of the Jmp is dead. */ static ir_node *equivalent_node_Jmp(ir_node *n) { @@ -777,7 +831,7 @@ static ir_node *equivalent_node_Jmp(ir_node *n) return n; } -/* Same for op_Raise */ +/** Raise is handled in the same way as Jmp. */ #define equivalent_node_Raise equivalent_node_Jmp @@ -825,6 +879,9 @@ static ir_node *equivalent_node_neutral_zero(ir_node *n) return n; } +/** + * Eor is commutative and has neutral 0. + */ #define equivalent_node_Eor equivalent_node_neutral_zero /* @@ -969,10 +1026,10 @@ static ir_node *equivalent_node_idempotent_unop(ir_node *n) return n; } -/* Not(Not(x)) == x */ +/** Not(Not(x)) == x */ #define equivalent_node_Not equivalent_node_idempotent_unop -/* --x == x */ /* ??? Is this possible or can --x raise an +/** --x == x ??? Is this possible or can --x raise an out of bounds exception if min =! max? */ #define equivalent_node_Minus equivalent_node_idempotent_unop @@ -1009,7 +1066,7 @@ static ir_node *equivalent_node_Div(ir_node *n) if (classify_tarval(value_of(b)) == TV_CLASSIFY_ONE) { /* div(x, 1) == x */ /* Turn Div into a tuple (mem, bad, a) */ ir_node *mem = get_Div_mem(n); - turn_into_tuple(n, 3); + turn_into_tuple(n, pn_Div_max); set_Tuple_pred(n, pn_Div_M, mem); set_Tuple_pred(n, pn_Div_X_except, new_Bad()); /* no exception */ set_Tuple_pred(n, pn_Div_res, a); @@ -1031,7 +1088,7 @@ static ir_node *equivalent_node_DivMod(ir_node *n) ir_node *mem = get_Div_mem(n); ir_mode *mode = get_irn_mode(b); - turn_into_tuple(n, 4); + turn_into_tuple(n, pn_DivMod_max); set_Tuple_pred(n, pn_DivMod_M, mem); set_Tuple_pred(n, pn_DivMod_X_except, new_Bad()); /* no exception */ set_Tuple_pred(n, pn_DivMod_res_div, a); @@ -1140,12 +1197,13 @@ static ir_node *equivalent_node_Cast(ir_node *n) { return n; } -/* Several optimizations: +/** + Several optimizations: - no Phi in start block. - remove Id operators that are inputs to Phi - fold Phi-nodes, iff they have only one predecessor except themselves. -*/ + */ static ir_node *equivalent_node_Phi(ir_node *n) { int i, n_preds; @@ -1153,7 +1211,6 @@ static ir_node *equivalent_node_Phi(ir_node *n) ir_node *oldn = n; ir_node *block = NULL; /* to shutup gcc */ ir_node *first_val = NULL; /* to shutup gcc */ - ir_node *scnd_val = NULL; /* to shutup gcc */ if (!get_opt_normalize()) return n; @@ -1163,8 +1220,8 @@ static ir_node *equivalent_node_Phi(ir_node *n) /* @@@ fliegt 'raus, sollte aber doch immer wahr sein!!! assert(get_irn_arity(block) == n_preds && "phi in wrong block!"); */ if ((is_Block_dead(block)) || /* Control dead */ - (block == current_ir_graph->start_block)) /* There should be no Phi nodes */ - return new_Bad(); /* in the Start Block. */ + (block == get_irg_start_block(current_ir_graph))) /* There should be no Phi nodes */ + return new_Bad(); /* in the Start Block. */ if (n_preds == 0) return n; /* Phi of dead Region without predecessors. */ @@ -1190,12 +1247,10 @@ static ir_node *equivalent_node_Phi(ir_node *n) return new_Bad(); } - scnd_val = NULL; - - /* follow_Id () for rest of inputs, determine if any of these + /* search for rest of inputs, determine if any of these are non-self-referencing */ while (++i < n_preds) { - scnd_val = get_Phi_pred(n, i); + ir_node *scnd_val = get_Phi_pred(n, i); if ( (scnd_val != n) && (scnd_val != first_val) #if 1 @@ -1210,16 +1265,64 @@ static ir_node *equivalent_node_Phi(ir_node *n) /* Fold, if no multiple distinct non-self-referencing inputs */ n = first_val; DBG_OPT_PHI(oldn, n); - } else { - /* skip the remaining Ids (done in get_Phi_pred). */ - /* superfluous, since we walk all to propagate Block's Bads. - while (++i < n_preds) get_Phi_pred(n, i); */ } return n; } /** - * optimize Proj(Tuple) and gigo() for ProjX in Bad block + Several optimizations: + - no Sync in start block. + - fold Sync-nodes, iff they have only one predecessor except + themselves. + @fixme: are there loop's in Sync's + */ +static ir_node *equivalent_node_Sync(ir_node *n) +{ + int i, n_preds; + + ir_node *oldn = n; + ir_node *first_val = NULL; /* to shutup gcc */ + + if (!get_opt_normalize()) return n; + + n_preds = get_Sync_n_preds(n); + + /* Find first non-self-referencing input */ + for (i = 0; i < n_preds; ++i) { + first_val = get_Sync_pred(n, i); + if ((first_val != n) /* not self pointer */ && + (! is_Bad(first_val)) + ) { /* value not dead */ + break; /* then found first value. */ + } + } + + if (i >= n_preds) + /* A totally Bad or self-referencing Sync (we didn't break the above loop) */ + return new_Bad(); + + /* search the rest of inputs, determine if any of these + are non-self-referencing */ + while (++i < n_preds) { + ir_node *scnd_val = get_Sync_pred(n, i); + if ((scnd_val != n) && + (scnd_val != first_val) && + (! is_Bad(scnd_val)) + ) + break; + } + + if (i >= n_preds) { + /* Fold, if no multiple distinct non-self-referencing inputs */ + n = first_val; + DBG_OPT_SYNC(oldn, n); + } + return n; +} + +/** + * optimize Proj(Tuple) and gigo() for ProjX in Bad block, + * ProjX(Load) and ProjX(Store) */ static ir_node *equivalent_node_Proj(ir_node *n) { @@ -1242,6 +1345,20 @@ static ir_node *equivalent_node_Proj(ir_node *n) /* Remove dead control flow -- early gigo(). */ n = new_Bad(); } + else if (get_opt_ldst_only_null_ptr_exceptions()) { + ir_op *op = get_irn_op(a); + + if (op == op_Load || op == op_Store) { + /* get the load/store address */ + ir_node *addr = get_irn_n(a, 1); + if (value_not_null(addr)) { + /* this node may float if it did not depend on a Confirm */ + set_irn_pinned(a, op_pin_state_floats); + DBG_OPT_EXC_REM(n); + return new_Bad(); + } + } + } } return n; @@ -1334,6 +1451,17 @@ static ir_node *equivalent_node_Mux(ir_node *n) return n; } +/** + * Returns a equivalent node of a Psi: if a condition is true + * and all previous conditions are false we know its value. + * If all conditions are false its value is the default one. + */ +static ir_node *equivalent_node_Psi(ir_node *n) { + if (is_Mux(n)) + return equivalent_node_Mux(n); + return n; +} + /** * Optimize -a CMP -b into b CMP a. * This works only for for modes where unary Minus @@ -1370,7 +1498,7 @@ static ir_node *equivalent_node_Confirm(ir_node *n) * rare case: two identical Confirms one after another, * replace the second one with the first. */ - return pred; + n = pred; } if (pnc == pn_Cmp_Eq) { ir_node *bound = get_Confirm_bound(n); @@ -1401,7 +1529,54 @@ static ir_node *equivalent_node_CopyB(ir_node *n) turn_into_tuple(n, pn_CopyB_max); set_Tuple_pred(n, pn_CopyB_M, mem); set_Tuple_pred(n, pn_CopyB_X_except, new_Bad()); /* no exception */ - set_Tuple_pred(n, pn_Call_M_except, new_Bad()); + set_Tuple_pred(n, pn_CopyB_M_except, new_Bad()); + } + return n; +} + +/** + * Optimize Bounds(idx, idx, upper) into idx. + */ +static ir_node *equivalent_node_Bound(ir_node *n) +{ + ir_node *idx = get_Bound_index(n); + ir_node *lower = get_Bound_lower(n); + int ret_tuple = 0; + + /* By definition lower < upper, so if idx == lower --> + lower <= idx && idx < upper */ + if (idx == lower) { + /* Turn Bound into a tuple (mem, bad, idx) */ + ret_tuple = 1; + } + else { + ir_node *pred = skip_Proj(idx); + + if (get_irn_op(pred) == op_Bound) { + /* + * idx was Bounds_check previously, it is still valid if + * lower <= pred_lower && pred_upper <= upper. + */ + ir_node *upper = get_Bound_upper(n); + if (get_Bound_lower(pred) == lower && + get_Bound_upper(pred) == upper) { + /* + * One could expect that we simply return the previous + * Bound here. However, this would be wrong, as we could + * add an exception Proj to a new location than. + * So, we must turn in into a tuple + */ + ret_tuple = 1; + } + } + } + if (ret_tuple) { + /* Turn Bound into a tuple (mem, bad, idx) */ + ir_node *mem = get_Bound_mem(n); + turn_into_tuple(n, pn_Bound_max); + set_Tuple_pred(n, pn_Bound_M, mem); + set_Tuple_pred(n, pn_Bound_X_except, new_Bad()); /* no exception */ + set_Tuple_pred(n, pn_Bound_res, idx); } return n; } @@ -1458,12 +1633,15 @@ static ir_op_ops *firm_set_default_equivalent_node(opcode code, ir_op_ops *ops) CASE(Conv); CASE(Cast); CASE(Phi); + CASE(Sync); CASE(Proj); CASE(Id); CASE(Mux); + CASE(Psi); CASE(Cmp); CASE(Confirm); CASE(CopyB); + CASE(Bound); default: /* leave NULL */; } @@ -1505,6 +1683,18 @@ optimize_preds(ir_node *n) { } /* end switch */ } +/** + * Returns non-zero if all Phi predecessors are constants + */ +static int is_const_Phi(ir_node *phi) { + int i; + + for (i = get_irn_arity(phi) - 1; i >= 0; --i) + if (! is_Const(get_irn_n(phi, i))) + return 0; + return 1; +} + /** * Transform AddP(P, ConvIs(Iu)), AddP(P, ConvIu(Is)) and * SubP(P, ConvIs(Iu)), SubP(P, ConvIu(Is)). @@ -1569,7 +1759,9 @@ static ir_node *transform_node_AddSub(ir_node *n) } /** - * Do the AddSub optimization, then Transform Add(a,a) into Mul(a, 2) + * Do the AddSub optimization, then Transform + * Add(a,a) -> Mul(a, 2) + * Add(Mul(a, x), a) -> Mul(a, x+1) * if the mode is integer or float. * Transform Add(a,-b) into Sub(a,b). * Reassociation might fold this further. @@ -1584,8 +1776,9 @@ static ir_node *transform_node_Add(ir_node *n) mode = get_irn_mode(n); if (mode_is_num(mode)) { ir_node *a = get_Add_left(n); + ir_node *b = get_Add_right(n); - if (a == get_Add_right(n)) { + if (a == b) { ir_node *block = get_irn_n(n, -1); n = new_rd_Mul( @@ -1597,28 +1790,88 @@ static ir_node *transform_node_Add(ir_node *n) mode); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_A); } - else { - ir_node *b = get_Add_right(n); - - if (get_irn_op(a) == op_Minus) { - n = new_rd_Sub( - get_irn_dbg_info(n), - current_ir_graph, - get_irn_n(n, -1), - b, - get_Minus_op(a), - mode); - DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_MINUS_B); + else if (get_irn_op(a) == op_Minus) { + n = new_rd_Sub( + get_irn_dbg_info(n), + current_ir_graph, + get_irn_n(n, -1), + b, + get_Minus_op(a), + mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_MINUS_B); + } + else if (get_irn_op(b) == op_Minus) { + n = new_rd_Sub( + get_irn_dbg_info(n), + current_ir_graph, + get_irn_n(n, -1), + a, + get_Minus_op(b), + mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_MINUS_B); + } + /* do NOT execute this code if reassociation is enabled, it does the inverse! */ + else if (!get_opt_reassociation() && get_irn_op(a) == op_Mul) { + ir_node *ma = get_Mul_left(a); + ir_node *mb = get_Mul_right(a); + + if (b == ma) { + ir_node *blk = get_irn_n(n, -1); + n = new_rd_Mul( + get_irn_dbg_info(n), current_ir_graph, blk, + ma, + new_rd_Add( + get_irn_dbg_info(n), current_ir_graph, blk, + mb, + new_r_Const_long(current_ir_graph, blk, mode, 1), + mode), + mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_MUL_A_X_A); } - else if (get_irn_op(b) == op_Minus) { - n = new_rd_Sub( - get_irn_dbg_info(n), - current_ir_graph, - get_irn_n(n, -1), - a, - get_Minus_op(b), - mode); - DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_MINUS_B); + else if (b == mb) { + ir_node *blk = get_irn_n(n, -1); + n = new_rd_Mul( + get_irn_dbg_info(n), current_ir_graph, blk, + mb, + new_rd_Add( + get_irn_dbg_info(n), current_ir_graph, blk, + ma, + new_r_Const_long(current_ir_graph, blk, mode, 1), + mode), + mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_MUL_A_X_A); + } + } + /* do NOT execute this code if reassociation is enabled, it does the inverse! */ + else if (!get_opt_reassociation() && get_irn_op(b) == op_Mul) { + ir_node *ma = get_Mul_left(b); + ir_node *mb = get_Mul_right(b); + + if (a == ma) { + ir_node *blk = get_irn_n(n, -1); + n = new_rd_Mul( + get_irn_dbg_info(n), current_ir_graph, blk, + ma, + new_rd_Add( + get_irn_dbg_info(n), current_ir_graph, blk, + mb, + new_r_Const_long(current_ir_graph, blk, mode, 1), + mode), + mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_MUL_A_X_A); + } + else if (a == mb) { + ir_node *blk = get_irn_n(n, -1); + n = new_rd_Mul( + get_irn_dbg_info(n), current_ir_graph, blk, + mb, + new_rd_Add( + get_irn_dbg_info(n), current_ir_graph, blk, + ma, + new_r_Const_long(current_ir_graph, blk, mode, 1), + mode), + mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_MUL_A_X_A); } } } @@ -1626,25 +1879,66 @@ static ir_node *transform_node_Add(ir_node *n) } /** - * Do the AddSub optimization, then Transform Sub(0,a) into Minus(a). + * Do the AddSub optimization, then Transform + * Sub(0,a) -> Minus(a) + * Sub(Mul(a, x), a) -> Mul(a, x-1) */ static ir_node *transform_node_Sub(ir_node *n) { ir_mode *mode; ir_node *oldn = n; + ir_node *a, *b; n = transform_node_AddSub(n); mode = get_irn_mode(n); - if (mode_is_num(mode) && (classify_Const(get_Sub_left(n)) == CNST_NULL)) { + a = get_Sub_left(n); + b = get_Sub_right(n); + if (mode_is_num(mode) && (classify_Const(a) == CNST_NULL)) { n = new_rd_Minus( get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1), - get_Sub_right(n), + b, mode); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_0_A); } + /* do NOT execute this code if reassociation is enabled, it does the inverse! */ + else if (get_opt_reassociation() && get_irn_op(a) == op_Mul) { + ir_node *ma = get_Mul_left(a); + ir_node *mb = get_Mul_right(a); + + if (ma == b) { + ir_node *blk = get_irn_n(n, -1); + n = new_rd_Mul( + get_irn_dbg_info(n), + current_ir_graph, blk, + ma, + new_rd_Sub( + get_irn_dbg_info(n), + current_ir_graph, blk, + mb, + new_r_Const_long(current_ir_graph, blk, mode, 1), + mode), + mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_MUL_A_X_A); + } + else if (mb == b) { + ir_node *blk = get_irn_n(n, -1); + n = new_rd_Mul( + get_irn_dbg_info(n), + current_ir_graph, blk, + mb, + new_rd_Sub( + get_irn_dbg_info(n), + current_ir_graph, blk, + ma, + new_r_Const_long(current_ir_graph, blk, mode, 1), + mode), + mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_MUL_A_X_A); + } + } return n; } @@ -1727,7 +2021,7 @@ static ir_node *transform_node_Mod(ir_node *n) /* Turn Mod into a tuple (mem, bad, value) */ ir_node *mem = get_Mod_mem(n); - turn_into_tuple(n, 3); + turn_into_tuple(n, pn_Mod_max); set_Tuple_pred(n, pn_Mod_M, mem); set_Tuple_pred(n, pn_Mod_X_except, new_Bad()); set_Tuple_pred(n, pn_Mod_res, value); @@ -1786,7 +2080,7 @@ static ir_node *transform_node_DivMod(ir_node *n) if (evaluated) { /* replace by tuple */ ir_node *mem = get_DivMod_mem(n); - turn_into_tuple(n, 4); + turn_into_tuple(n, pn_DivMod_max); set_Tuple_pred(n, pn_DivMod_M, mem); set_Tuple_pred(n, pn_DivMod_X_except, new_Bad()); /* no exception */ set_Tuple_pred(n, pn_DivMod_res_div, a); @@ -1852,7 +2146,7 @@ static ir_node *transform_node_Cond(ir_node *n) /* It's a boolean Cond, branching on a boolean constant. Replace it by a tuple (Bad, Jmp) or (Jmp, Bad) */ jmp = new_r_Jmp(current_ir_graph, get_nodes_block(n)); - turn_into_tuple(n, 2); + turn_into_tuple(n, pn_Cond_max); if (ta == tarval_b_true) { set_Tuple_pred(n, pn_Cond_false, new_Bad()); set_Tuple_pred(n, pn_Cond_true, jmp); @@ -1932,7 +2226,7 @@ static ir_node *transform_node_Not(ir_node *n) static ir_node *transform_node_Cast(ir_node *n) { ir_node *oldn = n; ir_node *pred = get_Cast_op(n); - type *tp = get_irn_type(n); + ir_type *tp = get_irn_type(n); if (get_irn_op(pred) == op_Const && get_Const_type(pred) != tp) { n = new_rd_Const_type(NULL, current_ir_graph, get_irn_n(pred, -1), get_irn_mode(pred), @@ -1961,17 +2255,22 @@ static ir_node *transform_node_Proj_Div(ir_node *proj) /* div(x, y) && y != 0 */ proj_nr = get_Proj_proj(proj); - /* this node may float */ + /* this node may float if it did not depend on a Confirm */ set_irn_pinned(n, op_pin_state_floats); if (proj_nr == pn_Div_X_except) { /* we found an exception handler, remove it */ + DBG_OPT_EXC_REM(proj); return new_Bad(); - } else if (proj_nr == pn_Div_M) { - /* the memory Proj can be removed */ + } + else if (proj_nr == pn_Div_M) { ir_node *res = get_Div_mem(n); - set_Div_mem(n, get_irg_no_mem(current_ir_graph)); - + /* the memory Proj can only be removed if we divide by a + real constant, but the node never produce a new memory */ + if (value_of(b) != tarval_bad) { + /* this is a Div by a const, we can remove the memory edge */ + set_Div_mem(n, get_irg_no_mem(current_ir_graph)); + } return res; } } @@ -1992,17 +2291,21 @@ static ir_node *transform_node_Proj_Mod(ir_node *proj) /* mod(x, y) && y != 0 */ proj_nr = get_Proj_proj(proj); - /* this node may float */ + /* this node may float if it did not depend on a Confirm */ set_irn_pinned(n, op_pin_state_floats); if (proj_nr == pn_Mod_X_except) { /* we found an exception handler, remove it */ + DBG_OPT_EXC_REM(proj); return new_Bad(); } else if (proj_nr == pn_Mod_M) { - /* the memory Proj can be removed */ ir_node *res = get_Mod_mem(n); - set_Mod_mem(n, get_irg_no_mem(current_ir_graph)); - + /* the memory Proj can only be removed if we divide by a + real constant, but the node never produce a new memory */ + if (value_of(b) != tarval_bad) { + /* this is a Mod by a const, we can remove the memory edge */ + set_Mod_mem(n, get_irg_no_mem(current_ir_graph)); + } return res; } else if (proj_nr == pn_Mod_res && get_Mod_left(n) == b) { @@ -2031,18 +2334,22 @@ static ir_node *transform_node_Proj_DivMod(ir_node *proj) /* DivMod(x, y) && y != 0 */ proj_nr = get_Proj_proj(proj); - /* this node may float */ + /* this node may float if it did not depend on a Confirm */ set_irn_pinned(n, op_pin_state_floats); if (proj_nr == pn_DivMod_X_except) { /* we found an exception handler, remove it */ + DBG_OPT_EXC_REM(proj); return new_Bad(); } else if (proj_nr == pn_DivMod_M) { - /* the memory Proj can be removed */ ir_node *res = get_DivMod_mem(n); - set_DivMod_mem(n, get_irg_no_mem(current_ir_graph)); - + /* the memory Proj can only be removed if we divide by a + real constant, but the node never produce a new memory */ + if (value_of(b) != tarval_bad) { + /* this is a DivMod by a const, we can remove the memory edge */ + set_DivMod_mem(n, get_irg_no_mem(current_ir_graph)); + } return res; } else if (proj_nr == pn_DivMod_res_mod && get_DivMod_left(n) == b) { @@ -2122,7 +2429,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) proj_nr = get_inversed_pnc(proj_nr); changed |= 1; } - else if (left > right) { + else if (get_irn_idx(left) > get_irn_idx(right)) { ir_node *t = left; left = right; @@ -2266,7 +2573,32 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) } } } /* mode_is_int */ - } + + /* + * optimization for AND: + * Optimize: + * And(x, C) == C ==> And(x, C) != 0 + * And(x, C) != C ==> And(X, C) == 0 + * + * if C is a single Bit constant. + */ + if ((proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) && + (get_irn_op(left) == op_And)) { + if (is_single_bit_tarval(tv)) { + /* check for Constant's match. We have check hare the tarvals, + because our const might be changed */ + ir_node *la = get_And_left(left); + ir_node *ra = get_And_right(left); + if ((is_Const(la) && get_Const_tarval(la) == tv) || + (is_Const(ra) && get_Const_tarval(ra) == tv)) { + /* fine: do the transformation */ + tv = get_mode_null(get_tarval_mode(tv)); + proj_nr ^= pn_Cmp_Leg; + changed |= 2; + } + } + } + } /* tarval != bad */ } if (changed) { @@ -2320,6 +2652,49 @@ static ir_node *transform_node_Proj(ir_node *proj) } } +/** + * Move Confirms down through Phi nodes. + */ +static ir_node *transform_node_Phi(ir_node *phi) { + int i, n; + ir_mode *mode = get_irn_mode(phi); + + if (mode_is_reference(mode)) { + n = get_irn_arity(phi); + + /* Beware of Phi0 */ + if (n > 0) { + ir_node *pred = get_irn_n(phi, 0); + ir_node *bound, *new_Phi, *block, **in; + pn_Cmp pnc; + + if (! is_Confirm(pred)) + return phi; + + bound = get_Confirm_bound(pred); + pnc = get_Confirm_cmp(pred); + + NEW_ARR_A(ir_node *, in, n); + in[0] = get_Confirm_value(pred); + + for (i = 1; i < n; ++i) { + pred = get_irn_n(phi, i); + + if (! is_Confirm(pred) || + get_Confirm_bound(pred) != bound || + get_Confirm_cmp(pred) != pnc) + return phi; + in[i] = get_Confirm_value(pred); + } + /* move the Confirm nodes "behind" the Phi */ + block = get_irn_n(phi, -1); + new_Phi = new_r_Phi(current_ir_graph, block, n, in, get_irn_mode(phi)); + return new_r_Confirm(current_ir_graph, block, new_Phi, bound, pnc); + } + } + return phi; +} + /** * returns the operands of a commutative bin-op, if one operand is * a const, it is returned as the second one. @@ -2764,6 +3139,16 @@ static ir_node *transform_node_Mux(ir_node *n) return arch_transform_node_Mux(n); } +/** + * Optimize a Psi into some simpler cases. + */ +static ir_node *transform_node_Psi(ir_node *n) { + if (is_Mux(n)) + return transform_node_Mux(n); + + return n; +} + /** * Tries several [inplace] [optimizing] transformations and returns an * equivalent node. The difference to equivalent_node() is that these @@ -2806,6 +3191,7 @@ static ir_op_ops *firm_set_default_transform_node(opcode code, ir_op_ops *ops) CASE(Not); CASE(Cast); CASE(Proj); + CASE(Phi); CASE(Sel); CASE(Or); CASE(Shr); @@ -2813,6 +3199,7 @@ static ir_op_ops *firm_set_default_transform_node(opcode code, ir_op_ops *ops) CASE(Shl); CASE(End); CASE(Mux); + CASE(Psi); default: /* leave NULL */; } @@ -2960,12 +3347,11 @@ static ir_op_ops *firm_set_default_node_cmp_attr(opcode code, ir_op_ops *ops) #undef CASE } -/** +/* * Compare function for two nodes in the hash table. Gets two * nodes as parameters. Returns 0 if the nodes are a cse. */ -static int -vt_cmp (const void *elt, const void *key) +int identities_cmp(const void *elt, const void *key) { ir_node *a, *b; int i, irn_arity_a; @@ -3042,7 +3428,7 @@ ir_node_hash (ir_node *node) pset * new_identities(void) { - return new_pset(vt_cmp, N_IR_NODES); + return new_pset(identities_cmp, N_IR_NODES); } void @@ -3058,8 +3444,7 @@ del_identities(pset *value_table) { * nodes are extremely time critical because of their frequent use in * constant string arrays. */ -static INLINE ir_node * -identify (pset *value_table, ir_node *n) +static INLINE ir_node *identify(pset *value_table, ir_node *n) { ir_node *o = NULL; @@ -3071,14 +3456,14 @@ identify (pset *value_table, ir_node *n) ir_node *r = get_binop_right(n); /* for commutative operators perform a OP b == b OP a */ - if (l > r) { + if (get_irn_idx(l) > get_irn_idx(r)) { set_binop_left(n, r); set_binop_right(n, l); } } } - o = pset_find (value_table, n, ir_node_hash (n)); + o = pset_find(value_table, n, ir_node_hash (n)); if (!o) return n; DBG_OPT_CSE(n, o); @@ -3091,8 +3476,7 @@ identify (pset *value_table, ir_node *n) * optimization is performed. The flag turning on procedure global cse could * be changed between two allocations. This way we are safe. */ -static INLINE ir_node * -identify_cons (pset *value_table, ir_node *n) { +static INLINE ir_node *identify_cons(pset *value_table, ir_node *n) { ir_node *old = n; n = identify(value_table, n); @@ -3101,13 +3485,12 @@ identify_cons (pset *value_table, ir_node *n) { return n; } -/** +/* * Return the canonical node computing the same value as n. * Looks up the node in a hash table, enters it in the table * if it isn't there yet. */ -static ir_node * -identify_remember (pset *value_table, ir_node *n) +ir_node *identify_remember(pset *value_table, ir_node *n) { ir_node *o = NULL; @@ -3136,18 +3519,28 @@ identify_remember (pset *value_table, ir_node *n) return o; } -void -add_identities (pset *value_table, ir_node *node) { - if (get_opt_cse() && (get_irn_opcode(node) != iro_Block)) - identify_remember (value_table, node); +/* Add a node to the identities value table. */ +void add_identities(pset *value_table, ir_node *node) { + if (get_opt_cse() && is_no_Block(node)) + identify_remember(value_table, node); +} + +/* Visit each node in the value table of a graph. */ +void visit_all_identities(ir_graph *irg, irg_walk_func visit, void *env) { + ir_node *node; + ir_graph *rem = current_ir_graph; + + current_ir_graph = irg; + foreach_pset(irg->value_table, node) + visit(node, env); + current_ir_graph = rem; } /** * garbage in, garbage out. If a node has a dead input, i.e., the * Bad node is input to the node, return the Bad node. */ -static INLINE ir_node * -gigo (ir_node *node) +static INLINE ir_node *gigo(ir_node *node) { int i, irn_arity; ir_op *op = get_irn_op(node); @@ -3189,8 +3582,15 @@ gigo (ir_node *node) if (is_Bad(pred)) return new_Bad(); +#if 0 + /* Propagating Unknowns here seems to be a bad idea, because + sometimes we need a node as a input and did not want that + it kills it's user. + However, i might be useful to move this into a later phase + (it you thing optimizing such code is useful). */ if (is_Unknown(pred) && mode_is_data(get_irn_mode(node))) return new_Unknown(get_irn_mode(node)); +#endif } } #if 0 @@ -3209,7 +3609,6 @@ gigo (ir_node *node) return node; } - /** * These optimizations deallocate nodes from the obstack. * It can only be called if it is guaranteed that no other nodes @@ -3217,8 +3616,7 @@ gigo (ir_node *node) * * current_ir_graph must be set to the graph of the node! */ -ir_node * -optimize_node(ir_node *n) +ir_node *optimize_node(ir_node *n) { tarval *tv; ir_node *oldn = n; @@ -3235,7 +3633,7 @@ optimize_node(ir_node *n) tv = computed_value(n); if (tv != tarval_bad) { ir_node *nw; - type *old_tp = get_irn_type(n); + ir_type *old_tp = get_irn_type(n); int i, arity = get_irn_arity(n); int node_size; @@ -3262,7 +3660,7 @@ optimize_node(ir_node *n) edges_node_deleted(n, current_ir_graph); /* evaluation was successful -- replace the node. */ - obstack_free(current_ir_graph->obst, n); + irg_kill_node(current_ir_graph, n); nw = new_Const(get_tarval_mode (tv), tv); if (old_tp && get_type_mode(old_tp) == get_tarval_mode (tv)) @@ -3297,8 +3695,7 @@ optimize_node(ir_node *n) edges_node_deleted(oldn, current_ir_graph); /* We found an existing, better node, so we can deallocate the old node. */ - obstack_free (current_ir_graph->obst, oldn); - + irg_kill_node(current_ir_graph, oldn); return n; } @@ -3329,8 +3726,7 @@ optimize_node(ir_node *n) * nodes lying on the obstack. Remove these by a dead node elimination, * i.e., a copying garbage collection. */ -ir_node * -optimize_in_place_2 (ir_node *n) +ir_node *optimize_in_place_2(ir_node *n) { tarval *tv; ir_node *oldn = n; @@ -3346,7 +3742,7 @@ optimize_in_place_2 (ir_node *n) tv = computed_value(n); if (tv != tarval_bad) { /* evaluation was successful -- replace the node. */ - type *old_tp = get_irn_type(n); + ir_type *old_tp = get_irn_type(n); int i, arity = get_irn_arity(n); /* @@ -3412,8 +3808,7 @@ optimize_in_place_2 (ir_node *n) /** * Wrapper for external use, set proper status bits after optimization. */ -ir_node * -optimize_in_place (ir_node *n) +ir_node *optimize_in_place(ir_node *n) { /* Handle graph state */ assert(get_irg_phase_state(current_ir_graph) != phase_building); @@ -3423,10 +3818,9 @@ optimize_in_place (ir_node *n) if (get_irg_outs_state(current_ir_graph) == outs_consistent) set_irg_outs_inconsistent(current_ir_graph); - /* Maybe we could also test whether optimizing the node can + /* FIXME: Maybe we could also test whether optimizing the node can change the control graph. */ - if (get_irg_dom_state(current_ir_graph) == dom_consistent) - set_irg_dom_inconsistent(current_ir_graph); + set_irg_doms_inconsistent(current_ir_graph); return optimize_in_place_2 (n); } @@ -3440,6 +3834,8 @@ ir_op_ops *firm_set_default_operations(opcode code, ir_op_ops *ops) ops = firm_set_default_transform_node(code, ops); ops = firm_set_default_node_cmp_attr(code, ops); ops = firm_set_default_get_type(code, ops); + ops = firm_set_default_get_type_attr(code, ops); + ops = firm_set_default_get_entity_attr(code, ops); return ops; }