extend the x % 2 CMP 0 into x % 2^n CMP 0
[libfirm] / ir / ir / iropt.c
index 9b22543..94c3bfd 100644 (file)
@@ -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);
@@ -3055,7 +3056,14 @@ static ir_node *transform_node_Eor(ir_node *n) {
                DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT_BOOL);
        } else if (is_Const(b)) {
                if (is_Not(a)) { /* ~x ^ const -> x ^ ~const */
-                       n = new_Const(mode, tarval_not(get_Const_tarval(b)));
+                       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);
@@ -3090,7 +3098,13 @@ static ir_node *transform_node_Not(ir_node *n) {
        if  (is_Eor(a)) {
                ir_node *eor_b = get_Eor_right(a);
                if (is_Const(eor_b)) { /* ~(x ^ const) -> x ^ ~const */
-                       n = new_Const(mode, tarval_not(get_Const_tarval(eor_b)));
+                       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;
                }
        }
@@ -3664,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);
@@ -3760,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);