X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fir%2Firopt.c;h=dcbe3baec97dc1f3a70cc1cec51775c1a04d78af;hb=637542932dc27dcdfc7def09b58d9d5d4c34fb77;hp=ccf7928d28b5228029ba2479665eb50460bb07ee;hpb=74bd8e51e078963b857515e45fb2192fafee239e;p=libfirm diff --git a/ir/ir/iropt.c b/ir/ir/iropt.c index ccf7928d2..dcbe3baec 100644 --- a/ir/ir/iropt.c +++ b/ir/ir/iropt.c @@ -39,6 +39,7 @@ # include "irhooks.h" # include "irarch.h" # include "hashptr.h" +# include "archop.h" # include "opt_polymorphy.h" /* Make types visible to allow most efficient access */ @@ -60,7 +61,7 @@ follow_Id (ir_node *n) */ static tarval *computed_value_Const(ir_node *n) { - return get_Const_tarval(n); + return get_Const_tarval(n); } /** @@ -438,7 +439,9 @@ static tarval *computed_value_Proj(ir_node *n) ab = get_Cmp_right(a); proj_nr = get_Proj_proj(n); - if (aa == ab && !mode_is_float(get_irn_mode(aa))) { /* 1.: */ + if (aa == ab && ( + !mode_is_float(get_irn_mode(aa)) || proj_nr == pn_Cmp_Lt || proj_nr == pn_Cmp_Gt) + ) { /* 1.: */ /* BEWARE: a == a is NOT always True for floating Point!!! */ /* This is a trick with the bits used for encoding the Cmp Proj numbers, the following statement is not the same: @@ -601,9 +604,26 @@ different_identity (ir_node *a, ir_node *b) } #endif +/** + * Returns a equivalent block for another block. + * If the block has only one predecessor, this is + * the equivalent one. If the only predecessor of a block is + * the block itself, this is a dead block. + * + * If both predecessors of a block are the branches of a binary + * Cond, the equivalent block is Cond's block. + * + * If all predecessors of a block are bad or lies in a dead + * block, the current block is dead as well. + * + * Note, that blocks are NEVER turned into Bad's, instead + * the dead_block flag is set. So, never test for is_Bad(block), + * always use is_dead_Block(block). + */ static ir_node *equivalent_node_Block(ir_node *n) { ir_node *oldn = n; + int n_preds = get_Block_n_cfgpreds(n); /* The Block constructor does not call optimize, but mature_immBlock calls the optimization. */ @@ -615,8 +635,7 @@ static ir_node *equivalent_node_Block(ir_node *n) This should be true, as the block is matured before optimize is called. But what about Phi-cycles with the Phi0/Id that could not be resolved? Remaining Phi nodes are just Ids. */ - if ((get_Block_n_cfgpreds(n) == 1) && - (get_irn_op(get_Block_cfgpred(n, 0)) == op_Jmp)) { + if ((n_preds == 1) && (get_irn_op(get_Block_cfgpred(n, 0)) == op_Jmp)) { ir_node *predblock = get_nodes_block(get_Block_cfgpred(n, 0)); if (predblock == oldn) { /* Jmp jumps into the block it is in -- deal self cycle. */ @@ -627,7 +646,7 @@ static ir_node *equivalent_node_Block(ir_node *n) DBG_OPT_STG(oldn, n); } } - else if ((get_Block_n_cfgpreds(n) == 1) && + else if ((n_preds == 1) && (get_irn_op(skip_Proj(get_Block_cfgpred(n, 0))) == op_Cond)) { ir_node *predblock = get_nodes_block(get_Block_cfgpred(n, 0)); if (predblock == oldn) { @@ -636,7 +655,7 @@ static ir_node *equivalent_node_Block(ir_node *n) DBG_OPT_DEAD(oldn, n); } } - else if ((get_Block_n_cfgpreds(n) == 2) && + else if ((n_preds == 2) && (get_opt_control_flow_weak_simplification())) { /* Test whether Cond jumps twice to this block @@@ we could do this also with two loops finding two preds from several ones. */ @@ -768,6 +787,10 @@ static ir_node *equivalent_node_left_zero(ir_node *n) /** * Er, a "symmetic unop", ie op(op(n)) = n. + * + * @fixme -(-a) == a, but might overflow two times. + * We handle it anyway here but the better way would be a + * flag. This would be needed for Pascal for instance. */ static ir_node *equivalent_node_symmetric_unop(ir_node *n) { @@ -938,7 +961,7 @@ static ir_node *equivalent_node_Conv(ir_node *n) /** * A Cast may be removed if the type of the previous node - * is already to type of the Cast. + * is already the type of the Cast. */ static ir_node *equivalent_node_Cast(ir_node *n) { ir_node *pred = get_Cast_op(n); @@ -1087,32 +1110,85 @@ static ir_node *equivalent_node_Mux(ir_node *n) ir_node *oldn = n, *sel = get_Mux_sel(n); tarval *ts = value_of(sel); + /* Mux(true, f, t) == t */ if (ts == get_tarval_b_true()) { n = get_Mux_true(n); DBG_OPT_ALGSIM0(oldn, n); } + /* Mux(false, f, t) == f */ else if (ts == get_tarval_b_false()) { n = get_Mux_false(n); DBG_OPT_ALGSIM0(oldn, n); } - else if(get_Mux_false(n) == get_Mux_true(n)) { - n = get_Mux_true(n); + /* Mux(v, x, x) == x */ + else if (get_Mux_false(n) == get_Mux_true(n)) { + n = get_Mux_true(n); DBG_OPT_ALGSIM0(oldn, n); } + else if (get_irn_op(sel) == op_Proj && !mode_honor_signed_zeros(get_irn_mode(n))) { + ir_node *cmp = get_Proj_pred(sel); + long proj_nr = get_Proj_proj(sel); + ir_node *b = get_Mux_false(n); + ir_node *a = get_Mux_true(n); + + /* + * Note: normalization puts the constant on the right site, + * so we check only one case. + * + * Note further that these optimization work even for floating point + * with NaN's because -NaN == NaN. + * However, if +0 and -0 is handled differently, we cannot use the first one. + */ + if (get_irn_op(cmp) == op_Cmp && get_Cmp_left(cmp) == a) { + if (classify_Const(get_Cmp_right(cmp)) == CNST_NULL) { + /* Mux(a CMP 0, X, a) */ + if (get_irn_op(b) == op_Minus && get_Minus_op(b) == a) { + /* Mux(a CMP 0, -a, a) */ + if (proj_nr == pn_Cmp_Eq) { + /* Mux(a == 0, -a, a) ==> -a */ + n = b; + DBG_OPT_ALGSIM0(oldn, n); + } + else if (proj_nr == pn_Cmp_Lg || proj_nr == pn_Cmp_Ne) { + /* Mux(a != 0, -a, a) ==> a */ + n = a; + DBG_OPT_ALGSIM0(oldn, n); + } + } + else if (classify_Const(b) == CNST_NULL) { + /* Mux(a CMP 0, 0, a) */ + if (proj_nr == pn_Cmp_Lg || proj_nr == pn_Cmp_Ne) { + /* Mux(a != 0, 0, a) ==> a */ + n = a; + DBG_OPT_ALGSIM0(oldn, n); + } + else if (proj_nr == pn_Cmp_Eq) { + /* Mux(a == 0, 0, a) ==> 0 */ + n = b; + DBG_OPT_ALGSIM0(oldn, n); + } + } + } + } + } return n; } /** * Optimize -a CMP -b into b CMP a. - * This works even for floating point + * This works only for for modes where unary Minus + * cannot Overflow. + * Note that two-complement integers can Overflow + * so it will NOT work. */ static ir_node *equivalent_node_Cmp(ir_node *n) { ir_node *left = get_Cmp_left(n); ir_node *right = get_Cmp_right(n); - if (get_irn_op(left) == op_Minus && get_irn_op(right) == op_Minus) { + if (get_irn_op(left) == op_Minus && get_irn_op(right) == op_Minus && + !mode_overflow_on_unary_Minus(get_irn_mode(left))) { left = get_Minus_op(left); right = get_Minus_op(right); set_Cmp_left(n, right); @@ -1318,16 +1394,14 @@ static ir_node *transform_node_Sub(ir_node *n) n = transform_node_AddSub(n); mode = get_irn_mode(n); - if (mode_is_num(mode)) { - if (classify_Const(get_Sub_left(n)) == CNST_NULL) { - n = new_rd_Minus( - get_irn_dbg_info(n), - current_ir_graph, - get_nodes_block(n), - get_Sub_right(n), - mode); - DBG_OPT_ALGSIM0(oldn, n); - } + if (mode_is_num(mode) && (classify_Const(get_Sub_left(n)) == CNST_NULL)) { + n = new_rd_Minus( + get_irn_dbg_info(n), + current_ir_graph, + get_nodes_block(n), + get_Sub_right(n), + mode); + DBG_OPT_ALGSIM0(oldn, n); } return n; @@ -1574,7 +1648,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(pred); + 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_nodes_block(pred), get_irn_mode(pred), @@ -1585,6 +1659,7 @@ static ir_node *transform_node_Cast(ir_node *n) { get_SymConst_kind(pred), tp); DBG_OPT_CSTEVAL(oldn, n); } + return n; } @@ -1597,7 +1672,7 @@ static ir_node *transform_node_Cast(ir_node *n) { * * Optimizes jump tables by removing all impossible cases. * - * Normalizes Cmp nodes. + * Normalizes and optimizes Cmp nodes. */ static ir_node *transform_node_Proj(ir_node *proj) { @@ -1746,21 +1821,32 @@ static ir_node *transform_node_Proj(ir_node *proj) tv = get_Const_tarval(c); if (tv != tarval_bad) { - /* the following optimization is possibe on non-int values either: - * -a CMP c ==> a swap(CMP) -c */ - if (get_opt_constant_folding() && get_irn_op(left) == op_Minus) { + /* the following optimization is possibe on modes without Overflow + * on Unary Minus or on == and !=: + * -a CMP c ==> a swap(CMP) -c + * + * Beware: for two-complement Overflow may occur, so only == and != can + * be optimized, see this: + * -MININT < 0 =/=> MININT > 0 !!! + */ + if (get_opt_constant_folding() && get_irn_op(left) == op_Minus && + (!mode_overflow_on_unary_Minus(mode) || + (mode_is_int(mode) && (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg)))) { left = get_Minus_op(left); - tv = tarval_sub(get_tarval_one(mode), tv); + tv = tarval_sub(get_tarval_null(mode), tv); proj_nr = get_swapped_pnc(proj_nr); changed |= 2; } + /* for integer modes, we have more */ if (mode_is_int(mode)) { /* Ne includes Unordered which is not possible on integers. * However, frontends often use this wrong, so fix it here */ - if (proj_nr == pn_Cmp_Ne) + if (proj_nr == pn_Cmp_Ne) { proj_nr = pn_Cmp_Lg; + set_Proj_proj(proj, proj_nr); + } /* c > 0 : a < c ==> a <= (c-1) a >= c ==> a > (c-1) */ if ((proj_nr == pn_Cmp_Lt || proj_nr == pn_Cmp_Ge) && @@ -1779,13 +1865,62 @@ static ir_node *transform_node_Proj(ir_node *proj) changed |= 2; } + /* the following reassociations work only for == and != */ + /* a-b == 0 ==> a == b, a-b != 0 ==> a != b */ if (classify_tarval(tv) == TV_CLASSIFY_NULL && get_irn_op(left) == op_Sub) { if (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) { right = get_Sub_right(left); left = get_Sub_left(left); - changed &= ~2; + tv = value_of(right); + changed = 1; + } + } + + if ((tv != tarval_bad) && (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg)) { + ir_op *op = get_irn_op(left); + + /* a-c1 == c2 ==> a == c2+c1, a-c1 != c2 ==> a != c2+c1 */ + if (op == op_Sub) { + ir_node *c1 = get_Sub_right(left); + tarval *tv2 = value_of(c1); + + if (tv2 != tarval_bad) { + tv2 = tarval_add(tv, value_of(c1)); + + if (tv2 != tarval_bad) { + left = get_Sub_left(left); + tv = tv2; + changed = 2; + } + } + } + /* a+c1 == c2 ==> a == c2-c1, a+c1 != c2 ==> a != c2-c1 */ + else if (op == op_Add) { + ir_node *a_l = get_Add_left(left); + ir_node *a_r = get_Add_right(left); + ir_node *a; + tarval *tv2; + + if (get_irn_op(a_l) == op_Const) { + a = a_r; + tv2 = value_of(a_l); + } + else { + a = a_l; + tv2 = value_of(a_r); + } + + if (tv2 != tarval_bad) { + tv2 = tarval_sub(tv, tv2); + + if (tv2 != tarval_bad) { + left = a; + tv = tv2; + changed = 2; + } + } } } } @@ -2105,11 +2240,16 @@ static ir_node *transform_node_shift(ir_node *n) return n; } -static ir_node * transform_node_End(ir_node *n) { +#define transform_node_Shr transform_node_shift +#define transform_node_Shrs transform_node_shift +#define transform_node_Shl transform_node_shift + +/** + * Remove dead blocks in keepalive list. We do not generate a new End node. + */ +static ir_node *transform_node_End(ir_node *n) { int i, n_keepalives = get_End_n_keepalives(n); - /* Remove dead blocks in keepalive list. - We do not generate a new End node. */ for (i = 0; i < n_keepalives; ++i) { ir_node *ka = get_End_keepalive(n, i); if (is_Block(ka) && is_Block_dead(ka)) @@ -2118,6 +2258,139 @@ static ir_node * transform_node_End(ir_node *n) { return n; } +/** + * Optimize a Mux into some simplier cases. + */ +static ir_node *transform_node_Mux(ir_node *n) +{ + ir_node *oldn = n, *sel = get_Mux_sel(n); + ir_mode *mode = get_irn_mode(n); + + if (get_irn_op(sel) == op_Proj && !mode_honor_signed_zeros(mode)) { + ir_node *cmp = get_Proj_pred(sel); + long proj_nr = get_Proj_proj(sel); + ir_node *f = get_Mux_false(n); + ir_node *t = get_Mux_true(n); + + if (get_irn_op(cmp) == op_Cmp && classify_Const(get_Cmp_right(cmp)) == CNST_NULL) { + ir_node *block = get_nodes_block(n); + + /* + * Note: normalization puts the constant on the right site, + * so we check only one case. + * + * Note further that these optimization work even for floating point + * with NaN's because -NaN == NaN. + * However, if +0 and -0 is handled differently, we cannot use the first one. + */ + if (get_irn_op(f) == op_Minus && + get_Minus_op(f) == t && + get_Cmp_left(cmp) == t) { + + if (proj_nr == pn_Cmp_Ge || proj_nr == pn_Cmp_Gt) { + /* Mux(a >=/> 0, -a, a) ==> Abs(a) */ + n = new_rd_Abs(get_irn_dbg_info(n), + current_ir_graph, + block, + t, mode); + DBG_OPT_ALGSIM1(oldn, cmp, sel, n); + return n; + } + else if (proj_nr == pn_Cmp_Le || proj_nr == pn_Cmp_Lt) { + /* Mux(a <=/< 0, -a, a) ==> Minus(Abs(a)) */ + n = new_rd_Abs(get_irn_dbg_info(n), + current_ir_graph, + block, + t, mode); + n = new_rd_Minus(get_irn_dbg_info(n), + current_ir_graph, + block, + n, mode); + + DBG_OPT_ALGSIM1(oldn, cmp, sel, n); + return n; + } + } + else if (get_irn_op(t) == op_Minus && + get_Minus_op(t) == f && + get_Cmp_left(cmp) == f) { + + if (proj_nr == pn_Cmp_Le || proj_nr == pn_Cmp_Lt) { + /* Mux(a <=/< 0, a, -a) ==> Abs(a) */ + n = new_rd_Abs(get_irn_dbg_info(n), + current_ir_graph, + block, + f, mode); + DBG_OPT_ALGSIM1(oldn, cmp, sel, n); + return n; + } + else if (proj_nr == pn_Cmp_Ge || proj_nr == pn_Cmp_Gt) { + /* Mux(a >=/> 0, a, -a) ==> Minus(Abs(a)) */ + n = new_rd_Abs(get_irn_dbg_info(n), + current_ir_graph, + block, + f, mode); + n = new_rd_Minus(get_irn_dbg_info(n), + current_ir_graph, + block, + n, mode); + + DBG_OPT_ALGSIM1(oldn, cmp, sel, n); + return n; + } + } + + if (mode_is_int(mode) && mode_is_signed(mode) && + get_mode_arithmetic(mode) == irma_twos_complement) { + ir_node *x = get_Cmp_left(cmp); + + /* the following optimization works only with signed integer two-complement mode */ + + if (mode == get_irn_mode(x)) { + /* + * FIXME: this restriction is two rigid, as it would still + * work if mode(x) = Hs and mode == Is, but at least it removes + * all wrong cases. + */ + if ((proj_nr == pn_Cmp_Lt || proj_nr == pn_Cmp_Le) && + classify_Const(t) == CNST_ALL_ONE && + classify_Const(f) == CNST_NULL) { + /* + * Mux(x:T Shrs(x, sizeof_bits(T) - 1) + * Conditions: + * T must be signed. + */ + n = new_rd_Shrs(get_irn_dbg_info(n), + current_ir_graph, block, x, + new_r_Const_long(current_ir_graph, block, mode_Iu, + get_mode_size_bits(mode) - 1), + mode); + DBG_OPT_ALGSIM1(oldn, cmp, sel, n); + return n; + } + else if ((proj_nr == pn_Cmp_Gt || proj_nr == pn_Cmp_Ge) && + classify_Const(t) == CNST_ONE && + classify_Const(f) == CNST_NULL) { + /* + * Mux(x:T >/>= 0, 0, 1) -> Shr(-x, sizeof_bits(T) - 1) + * Conditions: + * T must be signed. + */ + n = new_rd_Shr(get_irn_dbg_info(n), + current_ir_graph, block, + new_r_Minus(current_ir_graph, block, x, mode), + new_r_Const_long(current_ir_graph, block, mode_Iu, + get_mode_size_bits(mode) - 1), + mode); + DBG_OPT_ALGSIM1(oldn, cmp, sel, n); + return n; + } + } + } + } + } + return arch_transform_node_Mux(n); +} /** * Tries several [inplace] [optimizing] transformations and returns an @@ -2154,16 +2427,15 @@ static ir_op *firm_set_default_transform_node(ir_op *op) CASE(Not); CASE(Cast); CASE(Proj); + CASE(Sel); CASE(Or); + CASE(Shr); + CASE(Shrs); + CASE(Shl); CASE(End); - CASE(Sel); - case iro_Shr: - case iro_Shrs: - case iro_Shl: - op->transform_node = transform_node_shift; - break; + CASE(Mux); default: - op->transform_node = NULL; + op->transform_node = NULL; } return op;