start label number with 1, reserve the 0
[libfirm] / ir / ir / iropt.c
index dd995ec..64ff6b6 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 */
@@ -998,7 +998,7 @@ static ir_node *equivalent_node_idempotent_unop(ir_node *n) {
 /** Optimize Not(Not(x)) == x. */
 #define equivalent_node_Not    equivalent_node_idempotent_unop
 
-/** --x == x       ??? Is this possible or can --x raise an
+/** -(-x) == x       ??? Is this possible or can --x raise an
                        out of bounds exception if min =! max? */
 #define equivalent_node_Minus  equivalent_node_idempotent_unop
 
@@ -1144,9 +1144,20 @@ static ir_node *equivalent_node_Conv(ir_node *n) {
        ir_mode *a_mode = get_irn_mode(a);
 
        if (n_mode == a_mode) { /* No Conv necessary */
-               /* leave strict floating point Conv's */
-               if (get_Conv_strict(n))
-                       return n;
+               if (get_Conv_strict(n)) {
+                       /* special case: the predecessor might be a also a Conv */
+                       if (is_Conv(a)) {
+                               if (! get_Conv_strict(a)) {
+                                       /* first one is not strict, kick it */
+                                       set_Conv_op(n, get_Conv_op(a));
+                                       return n;
+                               }
+                               /* else both are strict conv, second is superflous */
+                       } else {
+                               /* leave strict floating point Conv's */
+                               return n;
+                       }
+               }
                n = a;
                DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV);
        } else if (get_irn_op(a) == op_Conv) { /* Conv(Conv(b)) */
@@ -1160,7 +1171,7 @@ static ir_node *equivalent_node_Conv(ir_node *n) {
                        if (n_mode == mode_b) {
                                n = b; /* Convb(Conv*(xxxb(...))) == xxxb(...) */
                                DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
-                       } else if (mode_is_int(n_mode) || mode_is_character(n_mode)) {
+                       } else if (mode_is_int(n_mode)) {
                                if (smaller_mode(b_mode, a_mode)){
                                        n = b;        /* ConvS(ConvL(xxxS(...))) == xxxS(...) */
                                        DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
@@ -1566,8 +1577,8 @@ static ir_node *equivalent_node_Bound(ir_node *n) {
                                /*
                                 * One could expect that we simply return the previous
                                 * Bound here. However, this would be wrong, as we could
-                                * add an exception Proj to a new location than.
-                                * So, we must turn in into a tuple
+                                * add an exception Proj to a new location then.
+                                * So, we must turn in into a tuple.
                                 */
                                ret_tuple = 1;
                        }
@@ -1993,6 +2004,14 @@ static ir_node *transform_node_Add(ir_node *n) {
                                DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_MUL_A_X_A);
                        }
                }
+               /* Here we rely on constants be on the RIGHT side */
+               else if (is_Not(a) && classify_Const(b) == CNST_ONE) {
+                       /* ~x + 1 = -x */
+                       ir_node *op = get_Not_op(a);
+                       ir_node *blk = get_irn_n(n, -1);
+                       n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, blk, op, mode);
+                       DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_PLUS_1);
+               }
        }
        return n;
 }  /* transform_node_Add */
@@ -2530,30 +2549,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 */
 
@@ -2941,7 +2983,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) {
                                 */
                                if ((proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) &&
                                    (get_irn_op(left) == op_And)) {
-                                       if (is_single_bit_tarval(tv)) {
+                                       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);
@@ -3410,6 +3452,44 @@ 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 (mode == mode_b) {
+               ir_node  *t     = get_Mux_true(n);
+               ir_node  *f     = get_Mux_false(n);
+               dbg_info *dbg   = get_irn_dbg_info(n);
+               ir_node  *block = get_irn_n(n, -1);
+               ir_graph *irg   = current_ir_graph;
+
+               if (is_Const(t)) {
+                       tarval *tv_t = get_Const_tarval(t);
+                       if (tv_t == tarval_b_true) {
+                               if (is_Const(f)) {
+                                       assert(get_Const_tarval(f) == tarval_b_false);
+                                       return sel;
+                               } else {
+                                       return new_rd_Or(dbg, irg, block, sel, f, mode_b);
+                               }
+                       } else {
+                               ir_node* not_sel = new_rd_Not(dbg, irg, block, sel, mode_b);
+                               assert(tv_t == tarval_b_false);
+                               if (is_Const(f)) {
+                                       assert(get_Const_tarval(f) == tarval_b_true);
+                                       return not_sel;
+                               } else {
+                                       return new_rd_And(dbg, irg, block, not_sel, f, mode_b);
+                               }
+                       }
+               } else if (is_Const(f)) {
+                       tarval *tv_f = get_Const_tarval(f);
+                       if (tv_f == tarval_b_true) {
+                               ir_node* not_sel = new_rd_Not(dbg, irg, block, sel, mode_b);
+                               return new_rd_Or(dbg, irg, block, not_sel, t, mode_b);
+                       } else {
+                               assert(tv_f == tarval_b_false);
+                               return new_rd_And(dbg, irg, block, sel, t, mode_b);
+                       }
+               }
+       }
+
        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);
@@ -3549,8 +3629,19 @@ static ir_node *transform_node_Psi(ir_node *n) {
  * not be freed even if the equivalent node isn't the old one.
  */
 static ir_node *transform_node(ir_node *n) {
-       if (n->op->ops.transform_node)
-               n = n->op->ops.transform_node(n);
+       ir_node *oldn;
+
+       /*
+        * Transform_node is the only "optimizing transformation" that might
+        * return a node with a different opcode. We iterate HERE until fixpoint
+        * to get the final result.
+        */
+       do {
+               oldn = n;
+               if (n->op->ops.transform_node)
+                       n = n->op->ops.transform_node(n);
+       } while (oldn != n);
+
        return n;
 }  /* transform_node */