use classify_Const()
[libfirm] / ir / ir / iropt.c
index 42ade93..c47d72a 100644 (file)
@@ -990,7 +990,7 @@ static ir_node *equivalent_node_idempotent_unop(ir_node *n) {
        /* optimize symmetric unop */
        if (get_irn_op(pred) == get_irn_op(n)) {
                n = get_unop_op(pred);
-               DBG_OPT_ALGSIM2(oldn, pred, n);
+               DBG_OPT_ALGSIM2(oldn, pred, n, FS_OPT_IDEM_UNARY);
        }
        return n;
 }  /* equivalent_node_idempotent_unop */
@@ -2364,15 +2364,123 @@ static ir_node *transform_node_Cond(ir_node *n) {
        return n;
 }  /* transform_node_Cond */
 
+typedef ir_node* (*recursive_transform) (ir_node *n);
+
+/**
+ * makes use of distributive laws for and, or, eor
+ *     and(a OP c, b OP c) -> and(a, b) OP c
+ */
+static ir_node *transform_bitwise_distributive(ir_node *n,
+                                               recursive_transform trans_func)
+{
+       ir_node *oldn    = n;
+       ir_node *a       = get_binop_left(n);
+       ir_node *b       = get_binop_right(n);
+       ir_op   *op      = get_irn_op(a);
+       ir_op   *op_root = get_irn_op(n);
+
+       if(op != get_irn_op(b))
+               return n;
+
+       if (op == op_Conv) {
+               ir_node *a_op   = get_Conv_op(a);
+               ir_node *b_op   = get_Conv_op(b);
+               ir_mode *a_mode = get_irn_mode(a_op);
+               ir_mode *b_mode = get_irn_mode(b_op);
+               if(a_mode == b_mode && (mode_is_int(a_mode) || a_mode == mode_b)) {
+                       ir_node *blk = get_irn_n(n, -1);
+
+                       n = exact_copy(n);
+                       set_binop_left(n, a_op);
+                       set_binop_right(n, b_op);
+                       set_irn_mode(n, a_mode);
+                       n = trans_func(n);
+                       n = new_r_Conv(current_ir_graph, blk, n, get_irn_mode(oldn));
+
+                       DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_SHIFT_AND);
+                       return n;
+               }
+       }
+
+       if (op == op_Eor) {
+               /* nothing to gain here */
+               return n;
+       }
+
+       if (op == op_Shrs || op == op_Shr || op == op_Shl
+                       || op == op_And || op == op_Or || op == op_Eor) {
+               ir_node *a_left  = get_binop_left(a);
+               ir_node *a_right = get_binop_right(a);
+               ir_node *b_left  = get_binop_left(b);
+               ir_node *b_right = get_binop_right(b);
+               ir_node *c       = NULL;
+               ir_node *op1, *op2;
+
+               if (is_op_commutative(op)) {
+                       if (a_left == b_left) {
+                               c   = a_left;
+                               op1 = a_right;
+                               op2 = b_right;
+                       } else if(a_left == b_right) {
+                               c   = a_left;
+                               op1 = a_right;
+                               op2 = b_left;
+                       } else if(a_right == b_left) {
+                               c   = a_right;
+                               op1 = a_left;
+                               op2 = b_right;
+                       }
+               }
+               if(a_right == b_right) {
+                       c   = a_right;
+                       op1 = a_left;
+                       op2 = b_left;
+               }
+
+               if (c != NULL) {
+                       /* (a sop c) & (b sop c) => (a & b) sop c */
+                       ir_node *blk = get_irn_n(n, -1);
+
+                       ir_node *new_n = exact_copy(n);
+                       set_binop_left(new_n, op1);
+                       set_binop_right(new_n, op2);
+                       new_n = trans_func(new_n);
+
+                       if(op_root == op_Eor && op == op_Or) {
+                               dbg_info  *dbgi = get_irn_dbg_info(n);
+                               ir_graph  *irg  = current_ir_graph;
+                               ir_mode   *mode = get_irn_mode(c);
+
+                               c = new_rd_Not(dbgi, irg, blk, c, mode);
+                               n = new_rd_And(dbgi, irg, blk, new_n, c, mode);
+                       } else {
+                               n = exact_copy(a);
+                               set_irn_n(n, -1, blk);
+                               set_binop_left(n, new_n);
+                               set_binop_right(n, c);
+                       }
+
+
+                       DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_SHIFT_AND);
+                       return n;
+               }
+       }
+
+       return n;
+}
+
 /**
  * Transform an And.
  */
 static ir_node *transform_node_And(ir_node *n) {
-       ir_node *c, *oldn = n;
+       ir_node *c, *oldn;
        ir_node *a = get_And_left(n);
        ir_node *b = get_And_right(n);
 
        HANDLE_BINOP_PHI(tarval_and, a,b,c);
+
+       n = transform_bitwise_distributive(n, transform_node_And);
+
        return n;
 }  /* transform_node_And */
 
@@ -2409,6 +2517,8 @@ static ir_node *transform_node_Eor(ir_node *n) {
                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 {
+               n = transform_bitwise_distributive(n, transform_node_Eor);
        }
 
        return n;
@@ -2420,30 +2530,53 @@ 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_op *op_a = get_irn_op(a);
 
        HANDLE_UNOP_PHI(tarval_not,a,c);
 
        /* check for a boolean Not */
        if (   (get_irn_mode(n) == mode_b)
-           && (get_irn_op(a) == op_Proj)
+           && (op_a == op_Proj)
            && (get_irn_mode(a) == mode_b)
            && (get_irn_op(get_Proj_pred(a)) == op_Cmp)) {
                /* 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;
+       }
+       if (op_a == op_Sub && classify_Const(get_Sub_right(a)) == CNST_ONE) {
+               /* ~(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);
        }
        return n;
 }  /* transform_node_Not */
 
 /**
  * Transform a Minus.
+ * Optimize:
+ *   -(~x) = x + 1
  */
 static ir_node *transform_node_Minus(ir_node *n) {
        ir_node *c, *oldn = n;
        ir_node *a = get_Minus_op(n);
 
        HANDLE_UNOP_PHI(tarval_neg,a,c);
+
+       if (is_Not(a)) {
+               /* -(~x) = x + 1 */
+               ir_node *op   = get_Not_op(a);
+               ir_mode *mode = get_irn_mode(op);
+               tarval *tv    = get_mode_one(mode);
+               ir_node *blk  = get_irn_n(n, -1);
+               ir_node *c    = new_r_Const(current_ir_graph, blk, mode, tv);
+               n = new_rd_Add(get_irn_dbg_info(n), current_ir_graph, blk, op, c, mode);
+               DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_MINUS_NOT);
+       }
+
        return n;
 }  /* transform_node_Minus */
 
@@ -2702,10 +2835,12 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) {
                                    (!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_mode_null(mode), tv);
+                                       tv = tarval_neg(tv);
 
-                                       proj_nr = get_inversed_pnc(proj_nr);
-                                       changed |= 2;
+                                       if (tv != tarval_bad) {
+                                               proj_nr = get_inversed_pnc(proj_nr);
+                                               changed |= 2;
+                                       }
                                }
 
                                /* for integer modes, we have more */
@@ -2722,16 +2857,20 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) {
                                                tarval_cmp(tv, get_mode_null(mode)) == pn_Cmp_Gt) {
                                                tv = tarval_sub(tv, get_mode_one(mode));
 
-                                               proj_nr ^= pn_Cmp_Eq;
-                                               changed |= 2;
+                                               if (tv != tarval_bad) {
+                                                       proj_nr ^= pn_Cmp_Eq;
+                                                       changed |= 2;
+                                               }
                                        }
                                        /* c < 0 : a > c  ==>  a >= (c+1)    a <= c  ==>  a < (c+1) */
                                        else if ((proj_nr == pn_Cmp_Gt || proj_nr == pn_Cmp_Le) &&
                                                tarval_cmp(tv, get_mode_null(mode)) == pn_Cmp_Lt) {
                                                tv = tarval_add(tv, get_mode_one(mode));
 
-                                               proj_nr ^= pn_Cmp_Eq;
-                                               changed |= 2;
+                                               if (tv != tarval_bad) {
+                                                       proj_nr ^= pn_Cmp_Eq;
+                                                       changed |= 2;
+                                               }
                                        }
 
                                        /* the following reassociations work only for == and != */
@@ -2743,7 +2882,9 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) {
                                                        left  = get_Sub_left(left);
 
                                                        tv = value_of(right);
-                                                       changed = 1;
+                                                       if (tv != tarval_bad) {
+                                                               changed = 1;
+                                                       }
                                                }
 
                                                if (tv != tarval_bad) {
@@ -3150,6 +3291,10 @@ static ir_node *transform_node_Or(ir_node *n) {
 
        n = transform_node_Or_bf_store(n);
        n = transform_node_Or_Rot(n);
+       if (n != oldn)
+               return n;
+
+       n = transform_bitwise_distributive(n, transform_node_Or);
 
        return n;
 }  /* transform_node_Or */