X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fir%2Firopt.c;h=e02a230d15b0df590f1fa679e42f978b989bb032;hb=8518628459833d02e553bfbf126c5050aeddc326;hp=3cb3c17f9dd58871f42ef18aa6f470d5ee603471;hpb=898ae0d1c7843807fc2e1f778bc9827a2b0b1f44;p=libfirm diff --git a/ir/ir/iropt.c b/ir/ir/iropt.c index 3cb3c17f9..e02a230d1 100644 --- a/ir/ir/iropt.c +++ b/ir/ir/iropt.c @@ -178,7 +178,7 @@ static tarval *computed_value_Minus(ir_node *n) { ir_node *a = get_Minus_op(n); tarval *ta = value_of(a); - if ((ta != tarval_bad) && mode_is_signed(get_irn_mode(a))) + if (ta != tarval_bad) return tarval_neg(ta); return tarval_bad; @@ -1174,10 +1174,17 @@ static ir_node *equivalent_node_Conv(ir_node *n) { return n; } /* else both are strict conv, second is superflous */ - } else { - /* leave strict floating point Conv's */ - return n; + } else if(is_Proj(a)) { + ir_node *pred = get_Proj_pred(a); + if(is_Load(pred)) { + /* loads always return with the exact precision of n_mode */ + assert(get_Load_mode(pred) == n_mode); + return a; + } } + + /* leave strict floating point Conv's */ + return n; } n = a; DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV); @@ -1193,7 +1200,7 @@ static ir_node *equivalent_node_Conv(ir_node *n) { n = b; /* Convb(Conv*(xxxb(...))) == xxxb(...) */ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV); } else if (mode_is_int(n_mode)) { - if (smaller_mode(b_mode, a_mode)){ + if (get_mode_size_bits(b_mode) <= get_mode_size_bits(a_mode)) { n = b; /* ConvS(ConvL(xxxS(...))) == xxxS(...) */ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV); } @@ -1706,15 +1713,15 @@ static int is_const_Phi(ir_node *n) { * @param phi the Phi node * @param other the other operand * @param eval an evaluator function + * @param mode the mode of the result, may be different from the mode of the Phi! * @param left if non-zero, other is the left operand, else the right * * @return a new Phi node if the conversion was successful, NULL else */ -static ir_node *apply_binop_on_phi(ir_node *phi, tarval *other, tarval *(*eval)(tarval *, tarval *), int left) { +static ir_node *apply_binop_on_phi(ir_node *phi, tarval *other, tarval *(*eval)(tarval *, tarval *), ir_mode *mode, int left) { tarval *tv; void **res; ir_node *pred; - ir_mode *mode; ir_graph *irg; int i, n = get_irn_arity(phi); @@ -1744,7 +1751,6 @@ static ir_node *apply_binop_on_phi(ir_node *phi, tarval *other, tarval *(*eval)( res[i] = tv; } } - mode = get_irn_mode(phi); irg = current_ir_graph; for (i = 0; i < n; ++i) { pred = get_irn_n(phi, i); @@ -1792,6 +1798,41 @@ static ir_node *apply_unop_on_phi(ir_node *phi, tarval *(*eval)(tarval *)) { return new_r_Phi(irg, get_nodes_block(phi), n, (ir_node **)res, mode); } /* apply_unop_on_phi */ +/** + * Apply a conversion on a constant operator (a Phi). + * + * @param phi the Phi node + * + * @return a new Phi node if the conversion was successful, NULL else + */ +static ir_node *apply_conv_on_phi(ir_node *phi, ir_mode *mode) { + tarval *tv; + void **res; + ir_node *pred; + ir_graph *irg; + int i, n = get_irn_arity(phi); + + NEW_ARR_A(void *, res, n); + for (i = 0; i < n; ++i) { + pred = get_irn_n(phi, i); + tv = get_Const_tarval(pred); + tv = tarval_convert_to(tv, mode); + + if (tv == tarval_bad) { + /* folding failed, bad */ + return 0; + } + res[i] = tv; + } + irg = current_ir_graph; + for (i = 0; i < n; ++i) { + pred = get_irn_n(phi, i); + res[i] = new_r_Const_type(irg, get_irg_start_block(irg), + mode, res[i], get_Const_type(pred)); + } + return new_r_Phi(irg, get_nodes_block(phi), n, (ir_node **)res, mode); +} /* apply_conv_on_phi */ + /** * Transform AddP(P, ConvIs(Iu)), AddP(P, ConvIu(Is)) and * SubP(P, ConvIs(Iu)), SubP(P, ConvIu(Is)). @@ -1854,26 +1895,26 @@ static ir_node *transform_node_AddSub(ir_node *n) { return n; } /* transform_node_AddSub */ -#define HANDLE_BINOP_PHI(op,a,b,c) \ - c = NULL; \ - if (is_Const(b) && is_const_Phi(a)) { \ - /* check for Op(Phi, Const) */ \ - c = apply_binop_on_phi(a, get_Const_tarval(b), op, 0); \ - } \ - else if (is_Const(a) && is_const_Phi(b)) { \ - /* check for Op(Const, Phi) */ \ - c = apply_binop_on_phi(b, get_Const_tarval(a), op, 1); \ - } \ - if (c) { \ - DBG_OPT_ALGSIM0(oldn, c, FS_OPT_CONST_PHI); \ - return c; \ +#define HANDLE_BINOP_PHI(eval, a, b, c, mode) \ + c = NULL; \ + if (is_Const(b) && is_const_Phi(a)) { \ + /* check for Op(Phi, Const) */ \ + c = apply_binop_on_phi(a, get_Const_tarval(b), eval, mode, 0);\ + } \ + else if (is_Const(a) && is_const_Phi(b)) { \ + /* check for Op(Const, Phi) */ \ + c = apply_binop_on_phi(b, get_Const_tarval(a), eval, mode, 1);\ + } \ + if (c) { \ + DBG_OPT_ALGSIM0(oldn, c, FS_OPT_CONST_PHI); \ + return c; \ } -#define HANDLE_UNOP_PHI(op,a,c) \ +#define HANDLE_UNOP_PHI(eval, a, c) \ c = NULL; \ if (is_const_Phi(a)) { \ /* check for Op(Phi) */ \ - c = apply_unop_on_phi(a, op); \ + c = apply_unop_on_phi(a, eval); \ if (c) { \ DBG_OPT_ALGSIM0(oldn, c, FS_OPT_CONST_PHI); \ return c; \ @@ -1898,9 +1939,8 @@ static ir_node *transform_node_Add(ir_node *n) { a = get_Add_left(n); b = get_Add_right(n); - HANDLE_BINOP_PHI(tarval_add, a,b,c); - mode = get_irn_mode(n); + HANDLE_BINOP_PHI(tarval_add, a, b, c, mode); /* for FP these optimizations are only allowed if fp_strict_algebraic is disabled */ if (mode_is_float(mode) && (get_irg_fp_model(current_ir_graph) & fp_strict_algebraic)) @@ -1908,7 +1948,7 @@ static ir_node *transform_node_Add(ir_node *n) { if (mode_is_num(mode)) { /* the following code leads to endless recursion when Mul are replaced by a simple instruction chain */ - if (!get_opt_arch_dep_running() && a == b && mode_is_int(mode)) { + if (!is_arch_dep_running() && a == b && mode_is_int(mode)) { ir_node *block = get_irn_n(n, -1); n = new_rd_Mul( @@ -1943,7 +1983,7 @@ static ir_node *transform_node_Add(ir_node *n) { DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_MINUS_B); return n; } - if (! get_opt_reassociation()) { + if (! is_reassoc_running()) { /* do NOT execute this code if reassociation is enabled, it does the inverse! */ if (is_Mul(a)) { ir_node *ma = get_Mul_left(a); @@ -2047,7 +2087,9 @@ static ir_node *transform_node_Add(ir_node *n) { return n; } /* transform_node_Add */ -/* returns -cnst */ +/** + * returns -cnst or NULL if impossible + */ static ir_node *const_negate(ir_node *cnst) { tarval *tv = tarval_neg(get_Const_tarval(cnst)); dbg_info *dbgi = get_irn_dbg_info(cnst); @@ -2081,7 +2123,7 @@ static ir_node *transform_node_Sub(ir_node *n) { mode = get_irn_mode(n); restart: - HANDLE_BINOP_PHI(tarval_sub, a,b,c); + HANDLE_BINOP_PHI(tarval_sub, a, b, c, mode); /* for FP these optimizations are only allowed if fp_strict_algebraic is disabled */ if (mode_is_float(mode) && (get_irg_fp_model(current_ir_graph) & fp_strict_algebraic)) @@ -2106,7 +2148,6 @@ restart: dbg_info *dbg = get_irn_dbg_info(n); ir_node *block = get_nodes_block(n); ir_node *left = get_Minus_op(a); - ir_mode *mode = get_irn_mode(n); ir_node *add = new_rd_Add(dbg, irg, block, left, b, mode); n = new_rd_Minus(dbg, irg, block, add, mode); @@ -2117,7 +2158,6 @@ restart: dbg_info *dbg = get_irn_dbg_info(n); ir_node *block = get_nodes_block(n); ir_node *right = get_Minus_op(b); - ir_mode *mode = get_irn_mode(n); n = new_rd_Add(dbg, irg, block, a, right, mode); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_MINUS); @@ -2132,9 +2172,8 @@ restart: ir_node *sub = new_rd_Sub(s_dbg, irg, s_block, s_left, s_right, s_mode); dbg_info *a_dbg = get_irn_dbg_info(n); ir_node *a_block = get_nodes_block(n); - ir_mode *a_mode = get_irn_mode(n); - n = new_rd_Add(a_dbg, irg, a_block, a, sub, a_mode); + n = new_rd_Add(a_dbg, irg, a_block, a, sub, mode); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_TO_ADD); return n; } else if (is_Mul(b)) { /* a - (b * C) -> a + (b * -C) */ @@ -2150,9 +2189,8 @@ restart: ir_node *mul = new_rd_Mul(m_dbg, irg, m_block, m_left, cnst2, m_mode); dbg_info *a_dbg = get_irn_dbg_info(n); ir_node *a_block = get_nodes_block(n); - ir_mode *a_mode = get_irn_mode(n); - n = new_rd_Add(a_dbg, irg, a_block, a, mul, a_mode); + n = new_rd_Add(a_dbg, irg, a_block, a, mul, mode); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_TO_ADD); return n; } @@ -2247,7 +2285,7 @@ restart: } } /* do NOT execute this code if reassociation is enabled, it does the inverse! */ - if (get_opt_reassociation() && is_Mul(a)) { + if (!is_reassoc_running() && is_Mul(a)) { ir_node *ma = get_Mul_left(a); ir_node *mb = get_Mul_right(a); @@ -2283,21 +2321,22 @@ restart: return n; } } - if (is_Sub(a)) { - ir_node *x = get_Sub_left(a); - ir_node *y = get_Sub_right(a); - ir_node *blk = get_irn_n(n, -1); - ir_mode *m_b = get_irn_mode(b); - ir_mode *m_y = get_irn_mode(y); + if (is_Sub(a)) { /* (x - y) - b -> x - (y + b) */ + ir_node *x = get_Sub_left(a); + ir_node *y = get_Sub_right(a); + ir_node *blk = get_irn_n(n, -1); + ir_mode *m_b = get_irn_mode(b); + ir_mode *m_y = get_irn_mode(y); + ir_mode *add_mode; ir_node *add; /* Determine the right mode for the Add. */ if (m_b == m_y) - mode = m_b; + add_mode = m_b; else if (mode_is_reference(m_b)) - mode = m_b; + add_mode = m_b; else if (mode_is_reference(m_y)) - mode = m_y; + add_mode = m_y; else { /* * Both modes are different but none is reference, @@ -2308,7 +2347,7 @@ restart: return n; } - add = new_r_Add(current_ir_graph, blk, y, b, mode); + add = new_r_Add(current_ir_graph, blk, y, b, add_mode); n = new_rd_Sub(get_irn_dbg_info(n), current_ir_graph, blk, x, add, mode); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_SUB_X_Y_Z); @@ -2391,7 +2430,7 @@ static ir_node *transform_node_Mul(ir_node *n) { if (mode != get_irn_mode(a)) return transform_node_Mul2n(n, mode); - HANDLE_BINOP_PHI(tarval_mul, a,b,c); + HANDLE_BINOP_PHI(tarval_mul, a, b, c, mode); if (mode_is_signed(mode)) { ir_node *r = NULL; @@ -2708,12 +2747,15 @@ static ir_node *transform_node_Quot(ir_node *n) { * Optimize Abs(x) into -x if x is Confirmed <= 0 */ static ir_node *transform_node_Abs(ir_node *n) { - ir_node *oldn = n; - ir_node *a = get_Abs_op(n); - value_classify_sign sign = classify_value_sign(a); + ir_node *c, *oldn = n; + ir_node *a = get_Abs_op(n); + ir_mode *mode; - if (sign == value_classified_negative) { - ir_mode *mode = get_irn_mode(n); + HANDLE_UNOP_PHI(tarval_abs, a, c); + + switch (classify_value_sign(a)) { + case value_classified_negative: + mode = get_irn_mode(n); /* * We can replace the Abs by -x here. @@ -2726,14 +2768,16 @@ static ir_node *transform_node_Abs(ir_node *n) { get_irn_n(n, -1), a, mode); DBG_OPT_CONFIRM(oldn, n); - } else if (sign == value_classified_positive) { + return n; + case value_classified_positive: /* n is positive, Abs is not needed */ n = a; DBG_OPT_CONFIRM(oldn, n); + return n; + default: + return n; } - - return n; } /* transform_node_Abs */ /** @@ -2886,9 +2930,8 @@ static ir_node *transform_node_And(ir_node *n) { ir_node *b = get_And_right(n); ir_mode *mode; - HANDLE_BINOP_PHI(tarval_and, a,b,c); - mode = get_irn_mode(n); + HANDLE_BINOP_PHI(tarval_and, a, b, c, mode); /* we can evaluate 2 Projs of the same Cmp */ if (mode == mode_b && is_Proj(a) && is_Proj(b)) { @@ -3020,10 +3063,10 @@ static ir_node *transform_node_Eor(ir_node *n) { ir_node *b = get_Eor_right(n); ir_mode *mode = get_irn_mode(n); - HANDLE_BINOP_PHI(tarval_eor, a,b,c); + HANDLE_BINOP_PHI(tarval_eor, a, b, c, mode); /* we can evaluate 2 Projs of the same Cmp */ - if(get_irn_mode(n) == mode_b && is_Proj(a) && is_Proj(b)) { + if (mode == mode_b && is_Proj(a) && is_Proj(b)) { ir_node *pred_a = get_Proj_pred(a); ir_node *pred_b = get_Proj_pred(b); if(pred_a == pred_b) { @@ -3053,12 +3096,20 @@ static ir_node *transform_node_Eor(ir_node *n) { mode_b, get_negated_pnc(get_Proj_proj(a), mode)); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT_BOOL); - } else if (mode == mode_b && is_Const(b) && is_Const_one(b)) { - /* The Eor is a Not. Replace it by a Not. */ - /* ????!!!Extend to bitfield 1111111. */ - n = new_r_Not(current_ir_graph, get_irn_n(n, -1), a, mode_b); - - DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT); + } else if (is_Const(b)) { + if (is_Not(a)) { /* ~x ^ const -> x ^ ~const */ + ir_node *cnst = new_Const(mode, tarval_not(get_Const_tarval(b))); + ir_node *not_op = get_Not_op(a); + dbg_info *dbg = get_irn_dbg_info(n); + ir_graph *irg = current_ir_graph; + ir_node *block = get_nodes_block(n); + ir_mode *mode = get_irn_mode(n); + n = new_rd_Eor(dbg, irg, block, not_op, cnst, mode); + return n; + } else if (is_Const_all_one(b)) { /* x ^ 1...1 -> ~1 */ + n = new_r_Not(current_ir_graph, get_nodes_block(n), a, mode); + DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT); + } } else { n = transform_bitwise_distributive(n, transform_node_Eor); } @@ -3084,7 +3135,20 @@ static ir_node *transform_node_Not(ir_node *n) { n = new_r_Proj(current_ir_graph, get_irn_n(n, -1), get_Proj_pred(a), mode_b, get_negated_pnc(get_Proj_proj(a), mode_b)); DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_CMP); - return n; + return n; + } + if (is_Eor(a)) { + ir_node *eor_b = get_Eor_right(a); + if (is_Const(eor_b)) { /* ~(x ^ const) -> x ^ ~const */ + ir_node *cnst = new_Const(mode, tarval_not(get_Const_tarval(eor_b))); + ir_node *eor_a = get_Eor_left(a); + dbg_info *dbg = get_irn_dbg_info(n); + ir_graph *irg = current_ir_graph; + ir_node *block = get_nodes_block(n); + ir_mode *mode = get_irn_mode(n); + n = new_rd_Eor(dbg, irg, block, eor_a, cnst, mode); + return n; + } } if (get_mode_arithmetic(mode) == irma_twos_complement) { if (is_Minus(a)) { /* ~-x -> x + -1 */ @@ -3113,6 +3177,9 @@ static ir_node *transform_node_Not(ir_node *n) { * Optimize: * -(~x) = x + 1 * -(a-b) = b - a + * -(a >>u (size-1)) = a >>s (size-1) + * -(a >>s (size-1)) = a >>u (size-1) + * -(a * const) -> a * -const */ static ir_node *transform_node_Minus(ir_node *n) { ir_node *c, *oldn = n; @@ -3178,6 +3245,21 @@ static ir_node *transform_node_Minus(ir_node *n) { return n; } + if (is_Mul(a)) { /* -(a * const) -> a * -const */ + ir_node *mul_l = get_Mul_left(a); + ir_node *mul_r = get_Mul_right(a); + if (is_Const(mul_r)) { + tarval *tv = tarval_neg(get_Const_tarval(mul_r)); + ir_node *cnst = new_Const(mode, tv); + dbg_info *dbg = get_irn_dbg_info(a); + ir_graph *irg = current_ir_graph; + ir_node *block = get_nodes_block(a); + n = new_rd_Mul(dbg, irg, block, mul_l, cnst, mode); + DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_MINUS_MUL_C); + return n; + } + } + return n; } /* transform_node_Minus */ @@ -3214,6 +3296,15 @@ static ir_node *transform_node_Proj_Div(ir_node *proj) { if (value_not_zero(b, &confirm)) { /* div(x, y) && y != 0 */ + if (confirm == NULL) { + /* we are sure we have a Const != 0 */ + new_mem = get_Div_mem(div); + if (is_Pin(new_mem)) + new_mem = get_Pin_op(new_mem); + set_Div_mem(div, new_mem); + set_irn_pinned(div, op_pin_state_floats); + } + proj_nr = get_Proj_proj(proj); switch (proj_nr) { case pn_Div_X_regular: @@ -3255,6 +3346,15 @@ static ir_node *transform_node_Proj_Mod(ir_node *proj) { /* mod(x, y) && y != 0 */ proj_nr = get_Proj_proj(proj); + if (confirm == NULL) { + /* we are sure we have a Const != 0 */ + new_mem = get_Mod_mem(mod); + if (is_Pin(new_mem)) + new_mem = get_Pin_op(new_mem); + set_Mod_mem(mod, new_mem); + set_irn_pinned(mod, op_pin_state_floats); + } + switch (proj_nr) { case pn_Mod_X_regular: @@ -3273,9 +3373,8 @@ static ir_node *transform_node_Proj_Mod(ir_node *proj) { /* This node can only float up to the Confirm block */ new_mem = new_r_Pin(current_ir_graph, get_nodes_block(confirm), new_mem); } - set_irn_pinned(mod, op_pin_state_floats); /* this is a Mod without exception, we can remove the memory edge */ - set_Mod_mem(mod, get_irg_no_mem(current_ir_graph)); + set_Mod_mem(mod, new_mem); return res; case pn_Mod_res: if (get_Mod_left(mod) == b) { @@ -3305,6 +3404,15 @@ static ir_node *transform_node_Proj_DivMod(ir_node *proj) { /* DivMod(x, y) && y != 0 */ proj_nr = get_Proj_proj(proj); + if (confirm == NULL) { + /* we are sure we have a Const != 0 */ + new_mem = get_DivMod_mem(divmod); + if (is_Pin(new_mem)) + new_mem = get_Pin_op(new_mem); + set_DivMod_mem(divmod, new_mem); + set_irn_pinned(divmod, op_pin_state_floats); + } + switch (proj_nr) { case pn_DivMod_X_regular: @@ -3323,9 +3431,8 @@ static ir_node *transform_node_Proj_DivMod(ir_node *proj) { /* This node can only float up to the Confirm block */ new_mem = new_r_Pin(current_ir_graph, get_nodes_block(confirm), new_mem); } - set_irn_pinned(divmod, op_pin_state_floats); /* this is a DivMod without exception, we can remove the memory edge */ - set_DivMod_mem(divmod, get_irg_no_mem(current_ir_graph)); + set_DivMod_mem(divmod, new_mem); return res; case pn_DivMod_res_mod: @@ -3387,7 +3494,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { long proj_nr = get_Proj_proj(proj); /* we can evaluate this direct */ - switch(proj_nr) { + switch (proj_nr) { case pn_Cmp_False: return new_Const(mode_b, get_tarval_b_false()); case pn_Cmp_True: @@ -3400,6 +3507,12 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { break; } + /* remove Casts */ + if (is_Cast(left)) + left = get_Cast_op(left); + if (is_Cast(right)) + right = get_Cast_op(right); + /* Remove unnecessary conversions */ /* TODO handle constants */ if (is_Conv(left) && is_Conv(right)) { @@ -3417,39 +3530,21 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = op_left; right = op_right; changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV_CONV); } else if (smaller_mode(mode_left, mode_right)) { left = new_r_Conv(irg, block, op_left, mode_right); right = op_right; changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV); } else if (smaller_mode(mode_right, mode_left)) { left = op_left; right = new_r_Conv(irg, block, op_right, mode_left); changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV); } } } - /* TODO extend to arbitrary constants */ - if (is_Conv(left) && is_Const(right) && is_Const_null(right)) { - ir_mode* mode = get_irn_mode(left); - ir_node* op = get_Conv_op(left); - ir_mode* op_mode = get_irn_mode(op); - - if (get_mode_size_bits(mode) > get_mode_size_bits(op_mode) && - (mode_is_signed(mode) || !mode_is_signed(op_mode))) { - ir_node *null = new_Const(op_mode, get_mode_null(op_mode)); - set_Cmp_left( n, op); - set_Cmp_right(n, null); - return proj; - } - } - - /* remove Casts */ - if (is_Cast(left)) - left = get_Cast_op(left); - if (is_Cast(right)) - right = get_Cast_op(right); - /* remove operation of both sides if possible */ if (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) { ir_opcode lop = get_irn_opcode(left); @@ -3465,6 +3560,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = get_unop_op(left); right = get_unop_op(right); changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_OP); break; case iro_Add: ll = get_Add_left(left); @@ -3477,21 +3573,25 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = lr; right = rr; changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_OP); } else if (ll == rr) { /* X + a CMP b + X ==> a CMP b */ left = lr; right = rl; changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_OP); } else if (lr == rl) { /* a + X CMP X + b ==> a CMP b */ left = ll; right = rr; changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_OP); } else if (lr == rr) { /* a + X CMP b + X ==> a CMP b */ left = ll; right = rl; changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_OP); } break; case iro_Sub: @@ -3505,11 +3605,13 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = lr; right = rr; changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_OP); } else if (lr == rr) { /* a - X CMP b - X ==> a CMP b */ left = ll; right = rl; changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_OP); } break; case iro_Rot: @@ -3518,6 +3620,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = get_Rot_left(left); right = get_Rot_left(right); changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_OP); } break; default: @@ -3529,14 +3632,20 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { if (get_irn_mode(left) == mode_b) { ir_graph *irg = current_ir_graph; ir_node *block = get_nodes_block(n); + ir_node *bres; switch (proj_nr) { - case pn_Cmp_Le: return new_r_Or( irg, block, new_r_Not(irg, block, left, mode_b), right, mode_b); - case pn_Cmp_Lt: return new_r_And(irg, block, new_r_Not(irg, block, left, mode_b), right, mode_b); - case pn_Cmp_Ge: return new_r_Or( irg, block, left, new_r_Not(irg, block, right, mode_b), mode_b); - case pn_Cmp_Gt: return new_r_And(irg, block, left, new_r_Not(irg, block, right, mode_b), mode_b); - case pn_Cmp_Lg: return new_r_Eor(irg, block, left, right, mode_b); - case pn_Cmp_Eq: return new_r_Not(irg, block, new_r_Eor(irg, block, left, right, mode_b), mode_b); + case pn_Cmp_Le: bres = new_r_Or( irg, block, new_r_Not(irg, block, left, mode_b), right, mode_b); break; + case pn_Cmp_Lt: bres = new_r_And(irg, block, new_r_Not(irg, block, left, mode_b), right, mode_b); break; + case pn_Cmp_Ge: bres = new_r_Or( irg, block, left, new_r_Not(irg, block, right, mode_b), mode_b); break; + case pn_Cmp_Gt: bres = new_r_And(irg, block, left, new_r_Not(irg, block, right, mode_b), mode_b); break; + case pn_Cmp_Lg: bres = new_r_Eor(irg, block, left, right, mode_b); break; + case pn_Cmp_Eq: bres = new_r_Not(irg, block, new_r_Eor(irg, block, left, right, mode_b), mode_b); break; + default: bres = NULL; + } + if (bres) { + DBG_OPT_ALGSIM0(n, bres, FS_OPT_CMP_TO_BOOL); + return bres; } } @@ -3552,10 +3661,12 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { */ if (is_Const(right)) { c = right; - } else if (is_Const(left)) { + } else if (is_irn_constlike(left)) { c = left; left = right; right = c; + if(!is_Const(c)) + c = NULL; proj_nr = get_inversed_pnc(proj_nr); changed |= 1; @@ -3579,6 +3690,25 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { mode = get_irn_mode(c); tv = get_Const_tarval(c); + /* TODO extend to arbitrary constants */ + if (is_Conv(left) && tarval_is_null(tv)) { + ir_node *op = get_Conv_op(left); + ir_mode *op_mode = get_irn_mode(op); + + /* + * UpConv(x) REL 0 ==> x REL 0 + */ + if (get_mode_size_bits(mode) > get_mode_size_bits(op_mode) && + ((proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) || + mode_is_signed(mode) || !mode_is_signed(op_mode))) { + tv = get_mode_null(op_mode); + left = op; + mode = op_mode; + changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV); + } + } + if (tv != tarval_bad) { /* the following optimization is possible on modes without Overflow * on Unary Minus or on == and !=: @@ -3597,13 +3727,16 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = get_Minus_op(left); proj_nr = get_inversed_pnc(proj_nr); changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_C); } } else if (is_Not(left) && (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg)) { + /* Not(a) ==/!= c ==> a ==/!= Not(c) */ tv = tarval_not(tv); if (tv != tarval_bad) { left = get_Not_op(left); changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_C); } } @@ -3624,6 +3757,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { if (tv != tarval_bad) { proj_nr ^= pn_Cmp_Eq; changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CNST_MAGN); } } /* c < 0 : a > c ==> a >= (c+1) a <= c ==> a < (c+1) */ @@ -3634,20 +3768,24 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { if (tv != tarval_bad) { proj_nr ^= pn_Cmp_Eq; changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CNST_MAGN); } } /* the following reassociations work only for == and != */ if (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) { +#if 0 /* Might be not that good in general */ /* a-b == 0 ==> a == b, a-b != 0 ==> a != b */ if (tarval_is_null(tv) && is_Sub(left)) { - right =get_Sub_right(left); + right = get_Sub_right(left); left = get_Sub_left(left); tv = value_of(right); changed = 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_C); } +#endif if (tv != tarval_bad) { /* a-c1 == c2 ==> a == c2+c1, a-c1 != c2 ==> a != c2+c1 */ @@ -3662,6 +3800,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = get_Sub_left(left); tv = tv2; changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_C); } } } @@ -3687,6 +3826,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = a; tv = tv2; changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_C); } } } @@ -3698,6 +3838,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) { left = get_Minus_op(left); tv = tv2; changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_OP_C); } } } @@ -3712,38 +3853,196 @@ 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) && is_And(left)) { - if (tarval_is_single_bit(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; + if (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) { + switch (get_irn_opcode(left)) { + ir_node *c1; + + case iro_And: + c1 = get_And_right(left); + if (is_Const(c1)) { + /* + * And(x, C1) == C2 ==> FALSE if C2 & C1 != C2 + * And(x, C1) != C2 ==> TRUE if C2 & C1 != C2 + */ + tarval *mask = tarval_and(get_Const_tarval(c1), tv); + if (mask != tv) { + /* TODO: move to constant evaluation */ + tv = proj_nr == pn_Cmp_Eq ? get_tarval_b_false() : get_tarval_b_true(); + c1 = new_Const(mode_b, tv); + DBG_OPT_CSTEVAL(proj, c1); + return c1; + } + + if (tarval_is_single_bit(tv)) { + /* + * 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. + */ + + /* check for Constant's match. We have check hare the tarvals, + because our const might be changed */ + if (get_Const_tarval(c1) == tv) { + /* fine: do the transformation */ + tv = get_mode_null(get_tarval_mode(tv)); + proj_nr ^= pn_Cmp_Leg; + changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CNST_MAGN); + } + } } - } + break; + case iro_Or: + c1 = get_Or_right(left); + if (is_Const(c1) && tarval_is_null(tv)) { + /* + * Or(x, C) == 0 && C != 0 ==> FALSE + * Or(x, C) != 0 && C != 0 ==> TRUE + */ + if (! tarval_is_null(get_Const_tarval(c1))) { + /* TODO: move to constant evaluation */ + tv = proj_nr == pn_Cmp_Eq ? get_tarval_b_false() : get_tarval_b_true(); + c1 = new_Const(mode_b, tv); + DBG_OPT_CSTEVAL(proj, c1); + return c1; + } + } + break; + case iro_Shl: + /* + * optimize x << c1 == c into x & (-1 >>u c1) == c >> c1 if c & (-1 << c1) == c + * FALSE else + * optimize x << c1 != c into x & (-1 >>u c1) != c >> c1 if c & (-1 << c1) == c + * TRUE else + */ + c1 = get_Shl_right(left); + if (is_Const(c1)) { + tarval *tv1 = get_Const_tarval(c1); + ir_mode *mode = get_irn_mode(left); + tarval *minus1 = get_mode_all_one(mode); + tarval *amask = tarval_shr(minus1, tv1); + tarval *cmask = tarval_shl(minus1, tv1); + ir_node *sl, *blk; + + if (tarval_and(tv, cmask) != tv) { + /* condition not met */ + tv = proj_nr == pn_Cmp_Eq ? get_tarval_b_false() : get_tarval_b_true(); + c1 = new_Const(mode_b, tv); + DBG_OPT_CSTEVAL(proj, c1); + return c1; + } + sl = get_Shl_left(left); + blk = get_nodes_block(n); + left = new_rd_And(get_irn_dbg_info(left), current_ir_graph, blk, sl, new_Const(mode, amask), mode); + tv = tarval_shr(tv, tv1); + changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_SHF_TO_AND); + } + break; + case iro_Shr: + /* + * optimize x >>u c1 == c into x & (-1 << c1) == c << c1 if c & (-1 >>u c1) == c + * FALSE else + * optimize x >>u c1 != c into x & (-1 << c1) != c << c1 if c & (-1 >>u c1) == c + * TRUE else + */ + c1 = get_Shr_right(left); + if (is_Const(c1)) { + tarval *tv1 = get_Const_tarval(c1); + ir_mode *mode = get_irn_mode(left); + tarval *minus1 = get_mode_all_one(mode); + tarval *amask = tarval_shl(minus1, tv1); + tarval *cmask = tarval_shr(minus1, tv1); + ir_node *sl, *blk; + + if (tarval_and(tv, cmask) != tv) { + /* condition not met */ + tv = proj_nr == pn_Cmp_Eq ? get_tarval_b_false() : get_tarval_b_true(); + c1 = new_Const(mode_b, tv); + DBG_OPT_CSTEVAL(proj, c1); + return c1; + } + sl = get_Shr_left(left); + blk = get_nodes_block(n); + left = new_rd_And(get_irn_dbg_info(left), current_ir_graph, blk, sl, new_Const(mode, amask), mode); + tv = tarval_shl(tv, tv1); + changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_SHF_TO_AND); + } + break; + case iro_Shrs: + /* + * optimize x >>s c1 == c into x & (-1 << c1) == c << c1 if (c >>s (BITS - c1)) \in {0,-1} + * FALSE else + * optimize x >>s c1 != c into x & (-1 << c1) != c << c1 if (c >>s (BITS - c1)) \in {0,-1} + * TRUE else + */ + c1 = get_Shrs_right(left); + if (is_Const(c1)) { + tarval *tv1 = get_Const_tarval(c1); + ir_mode *mode = get_irn_mode(left); + tarval *minus1 = get_mode_all_one(mode); + tarval *amask = tarval_shl(minus1, tv1); + tarval *cond = new_tarval_from_long(get_mode_size_bits(mode), get_tarval_mode(tv1)); + ir_node *sl, *blk; + + cond = tarval_sub(cond, tv1); + cond = tarval_shrs(tv, cond); + + if (!tarval_is_all_one(cond) && !tarval_is_null(cond)) { + /* condition not met */ + tv = proj_nr == pn_Cmp_Eq ? get_tarval_b_false() : get_tarval_b_true(); + c1 = new_Const(mode_b, tv); + DBG_OPT_CSTEVAL(proj, c1); + return c1; + } + sl = get_Shrs_left(left); + blk = get_nodes_block(n); + left = new_rd_And(get_irn_dbg_info(left), current_ir_graph, blk, sl, new_Const(mode, amask), mode); + tv = tarval_shl(tv, tv1); + changed |= 2; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_SHF_TO_AND); + } + break; + } /* switch */ } } /* tarval != bad */ } + if (changed & 2) /* need a new Const */ + right = new_Const(mode, tv); + + if ((proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) && is_Const(right) && is_Const_null(right) && is_Proj(left)) { + ir_node *op = get_Proj_pred(left); + + if ((is_Mod(op) && get_Proj_proj(left) == pn_Mod_res) || + (is_DivMod(op) && get_Proj_proj(left) == pn_DivMod_res_mod)) { + ir_node *c = get_binop_right(op); + + if (is_Const(c)) { + tarval *tv = get_Const_tarval(c); + + if (tarval_is_single_bit(tv)) { + /* special case: (x % 2^n) CMP 0 ==> x & (2^n-1) CMP 0 */ + ir_node *v = get_binop_left(op); + ir_node *blk = get_irn_n(op, -1); + ir_mode *mode = get_irn_mode(v); + + tv = tarval_sub(tv, get_mode_one(mode)); + left = new_rd_And(get_irn_dbg_info(op), current_ir_graph, blk, v, new_Const(mode, tv), mode); + changed |= 1; + DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_MOD_TO_AND); + } + } + } + } + if (changed) { ir_node *block = get_irn_n(n, -1); /* Beware of get_nodes_Block() */ - if (changed & 2) /* need a new Const */ - right = new_Const(mode, tv); - /* create a new compare */ n = new_rd_Cmp(get_irn_dbg_info(n), current_ir_graph, block, left, right); @@ -4062,12 +4361,13 @@ static ir_node *transform_node_Or(ir_node *n) { ir_node *c, *oldn = n; ir_node *a = get_Or_left(n); ir_node *b = get_Or_right(n); + ir_mode *mode; if (is_Not(a) && is_Not(b)) { /* ~a | ~b = ~(a&b) */ ir_node *block = get_nodes_block(n); - ir_mode *mode = get_irn_mode(n); + mode = get_irn_mode(n); a = get_Not_op(a); b = get_Not_op(b); n = new_rd_And(get_irn_dbg_info(n), current_ir_graph, block, a, b, mode); @@ -4093,7 +4393,8 @@ static ir_node *transform_node_Or(ir_node *n) { } } - HANDLE_BINOP_PHI(tarval_or, a,b,c); + mode = get_irn_mode(n); + HANDLE_BINOP_PHI(tarval_or, a, b, c, mode); n = transform_node_Or_bf_store(n); n = transform_node_Or_Rot(n); @@ -4110,7 +4411,7 @@ static ir_node *transform_node_Or(ir_node *n) { static ir_node *transform_node(ir_node *n); /** - * Optimize (a >> c1) >> c2), works for Shr, Shrs, Shl. + * Optimize (a >> c1) >> c2), works for Shr, Shrs, Shl, Rot. * * Should be moved to reassociation? */ @@ -4172,10 +4473,11 @@ static ir_node *transform_node_shift(ir_node *n) { */ static ir_node *transform_node_Shr(ir_node *n) { ir_node *c, *oldn = n; - ir_node *a = get_Shr_left(n); - ir_node *b = get_Shr_right(n); + ir_node *a = get_Shr_left(n); + ir_node *b = get_Shr_right(n); + ir_mode *mode = get_irn_mode(n); - HANDLE_BINOP_PHI(tarval_shr, a, b, c); + HANDLE_BINOP_PHI(tarval_shr, a, b, c, mode); return transform_node_shift(n); } /* transform_node_Shr */ @@ -4184,10 +4486,11 @@ static ir_node *transform_node_Shr(ir_node *n) { */ static ir_node *transform_node_Shrs(ir_node *n) { ir_node *c, *oldn = n; - ir_node *a = get_Shrs_left(n); - ir_node *b = get_Shrs_right(n); + ir_node *a = get_Shrs_left(n); + ir_node *b = get_Shrs_right(n); + ir_mode *mode = get_irn_mode(n); - HANDLE_BINOP_PHI(tarval_shrs, a, b, c); + HANDLE_BINOP_PHI(tarval_shrs, a, b, c, mode); return transform_node_shift(n); } /* transform_node_Shrs */ @@ -4196,13 +4499,44 @@ static ir_node *transform_node_Shrs(ir_node *n) { */ static ir_node *transform_node_Shl(ir_node *n) { ir_node *c, *oldn = n; - ir_node *a = get_Shl_left(n); - ir_node *b = get_Shl_right(n); + ir_node *a = get_Shl_left(n); + ir_node *b = get_Shl_right(n); + ir_mode *mode = get_irn_mode(n); - HANDLE_BINOP_PHI(tarval_shl, a, b, c); + HANDLE_BINOP_PHI(tarval_shl, a, b, c, mode); return transform_node_shift(n); } /* transform_node_Shl */ +/** + * Transform a Rot. + */ +static ir_node *transform_node_Rot(ir_node *n) { + ir_node *c, *oldn = n; + ir_node *a = get_Rot_left(n); + ir_node *b = get_Rot_right(n); + ir_mode *mode = get_irn_mode(n); + + HANDLE_BINOP_PHI(tarval_rot, a, b, c, mode); + return transform_node_shift(n); +} /* transform_node_Rot */ + +/** + * Transform a Conv. + */ +static ir_node *transform_node_Conv(ir_node *n) { + ir_node *c, *oldn = n; + ir_node *a = get_Conv_op(n); + + if (is_const_Phi(a)) { + c = apply_conv_on_phi(a, get_irn_mode(n)); + if (c) { + DBG_OPT_ALGSIM0(oldn, c, FS_OPT_CONST_PHI); + return c; + } + } + return n; +} /* transform_node_Conv */ + /** * Remove dead blocks and nodes in dead blocks * in keep alive list. We do not generate a new End node. @@ -4340,52 +4674,6 @@ static ir_node *transform_node_Mux(ir_node *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 ((pn == pn_Cmp_Lt || pn == pn_Cmp_Le) && - is_Const(t) && is_Const_all_one(t) && - is_Const(f) && is_Const_null(f)) { - /* - * 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, FS_OPT_MUX_TO_SHR); - return n; - } else if ((pn == pn_Cmp_Gt || pn == pn_Cmp_Ge) && - is_Const(t) && is_Const_one(t) && - is_Const(f) && is_Const_null(f)) { - /* - * 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, FS_OPT_MUX_TO_SHR); - return n; - } - } - } } } } @@ -4402,6 +4690,42 @@ static ir_node *transform_node_Psi(ir_node *n) { return n; } /* transform_node_Psi */ +/** + * optimize sync nodes that have other syncs as input we simply add the inputs + * of the other sync to our own inputs + */ +static ir_node *transform_node_Sync(ir_node *n) { + int i, arity; + + arity = get_irn_arity(n); + for(i = 0; i < get_irn_arity(n); /*empty*/) { + int i2, arity2; + ir_node *in = get_irn_n(n, i); + if(!is_Sync(in)) { + ++i; + continue; + } + + /* set sync input 0 instead of the sync */ + set_irn_n(n, i, get_irn_n(in, 0)); + /* so we check this input again for syncs */ + + /* append all other inputs of the sync to our sync */ + arity2 = get_irn_arity(in); + for(i2 = 1; i2 < arity2; ++i2) { + ir_node *in_in = get_irn_n(in, i2); + add_irn_n(n, in_in); + /* increase arity so we also check the new inputs for syncs */ + arity++; + } + } + + /* rehash the sync node */ + add_identities(current_ir_graph->value_table, n); + + return n; +} + /** * Tries several [inplace] [optimizing] transformations and returns an * equivalent node. The difference to equivalent_node() is that these @@ -4463,9 +4787,12 @@ static ir_op_ops *firm_set_default_transform_node(ir_opcode code, ir_op_ops *ops CASE(Shr); CASE(Shrs); CASE(Shl); + CASE(Rot); + CASE(Conv); CASE(End); CASE(Mux); CASE(Psi); + CASE(Sync); default: /* leave NULL */; }