extend the x % 2 CMP 0 into x % 2^n CMP 0
[libfirm] / ir / ir / iropt.c
index b3039cf..94c3bfd 100644 (file)
@@ -1908,7 +1908,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 +1943,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);
@@ -2035,7 +2035,7 @@ static ir_node *transform_node_Add(ir_node *n) {
                                ir_node *op = get_Not_op(b);
 
                                if (op == a) {
-                                       /* ~x + x = -1 */
+                                       /* x + ~x = -1 */
                                        ir_node *blk = get_irn_n(n, -1);
                                        n = new_r_Const(current_ir_graph, blk, mode, get_mode_minus_one(mode));
                                        DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_X_NOT_X);
@@ -2247,7 +2247,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 +2283,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 +2309,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);
@@ -3023,7 +3024,7 @@ static ir_node *transform_node_Eor(ir_node *n) {
        HANDLE_BINOP_PHI(tarval_eor, a,b,c);
 
        /* 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 +3054,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);
        }
@@ -3071,28 +3080,51 @@ static ir_node *transform_node_Eor(ir_node *n) {
  */
 static ir_node *transform_node_Not(ir_node *n) {
        ir_node *c, *oldn = n;
-       ir_node *a = get_Not_op(n);
+       ir_node *a    = get_Not_op(n);
+       ir_mode *mode = get_irn_mode(n);
 
        HANDLE_UNOP_PHI(tarval_not,a,c);
 
        /* check for a boolean Not */
-       if (get_irn_mode(n) == mode_b &&
+       if (mode == mode_b &&
                        is_Proj(a) &&
                        is_Cmp(get_Proj_pred(a))) {
                /* We negate a Cmp. The Cmp has the negated result anyways! */
                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_Sub(a)) {
-               ir_node *sub_r = get_Sub_right(a);
-               if (is_Const(sub_r) && is_Const_one(sub_r)) {
-                       /* ~(x-1) = -x */
-                       ir_node *op = get_Sub_left(a);
-                       ir_node *blk = get_irn_n(n, -1);
-                       n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, blk, op, get_irn_mode(n));
-                       DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_MINUS_1);
+       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 */
+                       dbg_info *dbg   = get_irn_dbg_info(n);
+                       ir_graph *irg   = current_ir_graph;
+                       ir_node  *block = get_nodes_block(n);
+                       ir_node  *add_l = get_Minus_op(a);
+                       ir_node  *add_r = new_rd_Const(dbg, irg, block, mode, get_mode_minus_one(mode));
+                       n = new_rd_Add(dbg, irg, block, add_l, add_r, mode);
+               } else if (is_Add(a)) {
+                       ir_node *add_r = get_Add_right(a);
+                       if (is_Const(add_r) && is_Const_all_one(add_r)) {
+                               /* ~(x + -1) = -x */
+                               ir_node *op = get_Add_left(a);
+                               ir_node *blk = get_irn_n(n, -1);
+                               n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, blk, op, get_irn_mode(n));
+                               DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_MINUS_1);
+                       }
                }
        }
        return n;
@@ -3168,6 +3200,20 @@ 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);
+                       return n;
+               }
+       }
+
        return n;
 }  /* transform_node_Minus */
 
@@ -3632,7 +3678,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) {
 
                                        /* 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);
@@ -3728,12 +3774,36 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) {
                } /* 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;
+                               }
+                       }
+               }
+       }
+
        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);