- add more Mux optimization cases
[libfirm] / ir / ir / iropt.c
index 60ec67f..5383464 100644 (file)
@@ -722,10 +722,16 @@ static ir_op_ops *firm_set_default_computed_value(ir_opcode code, ir_op_ops *ops
 static ir_node *equivalent_node_Block(ir_node *n)
 {
        ir_node *oldn = n;
-       int n_preds   = get_Block_n_cfgpreds(n);
+       int     n_preds;
 
-       /* The Block constructor does not call optimize, but mature_immBlock
-       calls the optimization. */
+       /* don't optimize dead blocks */
+       if (is_Block_dead(n))
+               return n;
+
+       n_preds = get_Block_n_cfgpreds(n);
+
+       /* The Block constructor does not call optimize, but mature_immBlock()
+          calls the optimization. */
        assert(get_Block_matured(n));
 
        /* Straightening: a single entry Block following a single exit Block
@@ -862,7 +868,53 @@ static ir_node *equivalent_node_neutral_zero(ir_node *n)
 /**
  * Eor is commutative and has neutral 0.
  */
-#define equivalent_node_Eor  equivalent_node_neutral_zero
+static ir_node *equivalent_node_Eor(ir_node *n)
+{
+       ir_node *oldn = n;
+       ir_node *a;
+       ir_node *b;
+
+       n = equivalent_node_neutral_zero(n);
+       if (n != oldn) return n;
+
+       a = get_Eor_left(n);
+       b = get_Eor_right(n);
+
+       if (is_Eor(a)) {
+               ir_node *aa = get_Eor_left(a);
+               ir_node *ab = get_Eor_right(a);
+
+               if (aa == b) {
+                       /* (a ^ b) ^ a -> b */
+                       n = ab;
+                       DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_EOR_A_B_A);
+                       return n;
+               } else if (ab == b) {
+                       /* (a ^ b) ^ b -> a */
+                       n = aa;
+                       DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_EOR_A_B_A);
+                       return n;
+               }
+       }
+       if (is_Eor(b)) {
+               ir_node *ba = get_Eor_left(b);
+               ir_node *bb = get_Eor_right(b);
+
+               if (ba == a) {
+                       /* a ^ (a ^ b) -> b */
+                       n = bb;
+                       DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_EOR_A_B_A);
+                       return n;
+               } else if (bb == a) {
+                       /* a ^ (b ^ a) -> b */
+                       n = ba;
+                       DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_EOR_A_B_A);
+                       return n;
+               }
+       }
+
+       return n;
+}
 
 /*
  * Optimize a - 0 and (a - x) + x (for modes with wrap-around).
@@ -971,7 +1023,7 @@ static ir_node *equivalent_node_Sub(ir_node *n) {
 
 
 /**
- * Optimize an "idempotent unary op", ie op(op(n)) = n.
+ * Optimize an "self-inverse unary op", ie op(op(n)) = n.
  *
  * @todo
  *   -(-a) == a, but might overflow two times.
@@ -1172,7 +1224,7 @@ static ir_node *equivalent_node_Conv(ir_node *n) {
                                        set_Conv_op(n, get_Conv_op(a));
                                        return n;
                                }
-                               /* else both are strict conv, second is superflous */
+                               /* else both are strict conv, second is superfluous */
                        } else if(is_Proj(a)) {
                                ir_node *pred = get_Proj_pred(a);
                                if(is_Load(pred)) {
@@ -1232,7 +1284,7 @@ static ir_node *equivalent_node_Phi(ir_node *n) {
        int i, n_preds;
 
        ir_node *oldn = n;
-       ir_node *block = NULL;     /* to shutup gcc */
+       ir_node *block;
        ir_node *first_val = NULL; /* to shutup gcc */
 
        if (!get_opt_normalize()) return n;
@@ -1240,8 +1292,6 @@ static ir_node *equivalent_node_Phi(ir_node *n) {
        n_preds = get_Phi_n_preds(n);
 
        block = get_nodes_block(n);
-       /* @@@ fliegt 'raus, sollte aber doch immer wahr sein!!!
-       assert(get_irn_arity(block) == n_preds && "phi in wrong block!"); */
        if ((is_Block_dead(block)) ||                  /* Control dead */
                (block == get_irg_start_block(current_ir_graph)))  /* There should be no Phi nodes */
                return new_Bad();                                    /* in the Start Block. */
@@ -1299,45 +1349,36 @@ static ir_node *equivalent_node_Phi(ir_node *n) {
  *   themselves.
  */
 static ir_node *equivalent_node_Sync(ir_node *n) {
-       int i, n_preds;
-
-       ir_node *oldn = n;
-       ir_node *first_val = NULL; /* to shutup gcc */
-
-       if (!get_opt_normalize()) return n;
+       int arity = get_Sync_n_preds(n);
+       int i;
 
-       n_preds = get_Sync_n_preds(n);
+       for (i = 0; i < arity;) {
+               ir_node *pred = get_Sync_pred(n, i);
+               int      j;
 
-       /* Find first non-self-referencing input */
-       for (i = 0; i < n_preds; ++i) {
-               first_val = get_Sync_pred(n, i);
-               if ((first_val != n)  /* not self pointer */ &&
-                   (! is_Bad(first_val))
-                  ) {                /* value not dead */
-                       break;            /* then found first value. */
+               /* Remove Bad predecessors */
+               if (is_Bad(pred)) {
+                       del_Sync_n(n, i);
+                       --arity;
+                       continue;
                }
-       }
-
-       if (i >= n_preds)
-               /* A totally Bad or self-referencing Sync (we didn't break the above loop) */
-               return new_Bad();
 
-       /* search the rest of inputs, determine if any of these
-          are non-self-referencing */
-       while (++i < n_preds) {
-               ir_node *scnd_val = get_Sync_pred(n, i);
-               if ((scnd_val != n) &&
-                   (scnd_val != first_val) &&
-                   (! is_Bad(scnd_val))
-                  )
-                       break;
+               /* Remove duplicate predecessors */
+               for (j = 0;; ++j) {
+                       if (j >= i) {
+                               ++i;
+                               break;
+                       }
+                       if (get_Sync_pred(n, j) == pred) {
+                               del_Sync_n(n, i);
+                               --arity;
+                               break;
+                       }
+               }
        }
 
-       if (i >= n_preds) {
-               /* Fold, if no multiple distinct non-self-referencing inputs */
-               n = first_val;
-               DBG_OPT_SYNC(oldn, n);
-       }
+       if (arity == 0) return new_Bad();
+       if (arity == 1) return get_Sync_pred(n, 0);
        return n;
 }  /* equivalent_node_Sync */
 
@@ -1445,41 +1486,54 @@ static ir_node *equivalent_node_Mux(ir_node *n)
        else if (is_Proj(sel) && !mode_honor_signed_zeros(get_irn_mode(n))) {
                ir_node *cmp = get_Proj_pred(sel);
                long proj_nr = get_Proj_proj(sel);
-               ir_node *b   = get_Mux_false(n);
-               ir_node *a   = get_Mux_true(n);
+               ir_node *f   = get_Mux_false(n);
+               ir_node *t   = get_Mux_true(n);
 
                /*
-                * Note: normalization puts the constant on the right site,
-                * so we check only one case.
-                *
                 * Note further that these optimization work even for floating point
                 * with NaN's because -NaN == NaN.
                 * However, if +0 and -0 is handled differently, we cannot use the first one.
                 */
-               if (is_Cmp(cmp) && get_Cmp_left(cmp) == a) {
-                       ir_node *cmp_r = get_Cmp_right(cmp);
-                       if (is_Const(cmp_r) && is_Const_null(cmp_r)) {
-                               /* Mux(a CMP 0, X, a) */
-                               if (is_Minus(b) && get_Minus_op(b) == a) {
-                                       /* Mux(a CMP 0, -a, a) */
-                                       if (proj_nr == pn_Cmp_Eq) {
-                                               /* Mux(a == 0, -a, a)  ==>  -a */
-                                               n = b;
+               if (is_Cmp(cmp)) {
+                       ir_node *const cmp_l = get_Cmp_left(cmp);
+                       ir_node *const cmp_r = get_Cmp_right(cmp);
+
+                       switch (proj_nr) {
+                               case pn_Cmp_Eq:
+                                       if ((cmp_l == t && cmp_r == f) || /* Psi(t == f, t, f) -> f */
+                                                       (cmp_l == f && cmp_r == t)) { /* Psi(f == t, t, f) -> f */
+                                               n = f;
                                                DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_TRANSFORM);
-                                       } else if (proj_nr == pn_Cmp_Lg || proj_nr == pn_Cmp_Ne) {
-                                               /* Mux(a != 0, -a, a)  ==> a */
-                                               n = a;
+                                               return n;
+                                       }
+                                       break;
+
+                               case pn_Cmp_Lg:
+                               case pn_Cmp_Ne:
+                                       if ((cmp_l == t && cmp_r == f) || /* Psi(t != f, t, f) -> t */
+                                                       (cmp_l == f && cmp_r == t)) { /* Psi(f != t, t, f) -> t */
+                                               n = t;
                                                DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_TRANSFORM);
+                                               return n;
                                        }
-                               } else if (is_Const(b) && is_Const_null(b)) {
-                                       /* Mux(a CMP 0, 0, a) */
-                                       if (proj_nr == pn_Cmp_Lg || proj_nr == pn_Cmp_Ne) {
-                                               /* Mux(a != 0, 0, a) ==> a */
-                                               n = a;
+                                       break;
+                       }
+
+                       /*
+                        * Note: normalization puts the constant on the right side,
+                        * so we check only one case.
+                        */
+                       if (cmp_l == t && is_Const(cmp_r) && is_Const_null(cmp_r)) {
+                               /* Mux(t CMP 0, X, t) */
+                               if (is_Minus(f) && get_Minus_op(f) == t) {
+                                       /* Mux(t CMP 0, -t, t) */
+                                       if (proj_nr == pn_Cmp_Eq) {
+                                               /* Mux(t == 0, -t, t)  ==>  -t */
+                                               n = f;
                                                DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_TRANSFORM);
-                                       } else if (proj_nr == pn_Cmp_Eq) {
-                                               /* Mux(a == 0, 0, a) ==> 0 */
-                                               n = b;
+                                       } else if (proj_nr == pn_Cmp_Lg || proj_nr == pn_Cmp_Ne) {
+                                               /* Mux(t != 0, -t, t)  ==> t */
+                                               n = t;
                                                DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_TRANSFORM);
                                        }
                                }
@@ -1767,7 +1821,7 @@ static ir_node *apply_binop_on_2_phis(ir_node *a, ir_node *b, tarval *(*eval)(ta
        int      i, n;
 
        if (get_nodes_block(a) != get_nodes_block(b))
-      return NULL;
+               return NULL;
 
        n = get_irn_arity(a);
        NEW_ARR_A(void *, res, n);
@@ -1880,12 +1934,12 @@ static ir_node *transform_node_AddSub(ir_node *n) {
                unsigned ref_bits = get_mode_size_bits(mode);
 
                if (is_Conv(left)) {
-                       ir_mode *mode = get_irn_mode(left);
-                       unsigned bits = get_mode_size_bits(mode);
+                       ir_mode *lmode = get_irn_mode(left);
+                       unsigned bits = get_mode_size_bits(lmode);
 
                        if (ref_bits == bits &&
-                           mode_is_int(mode) &&
-                           get_mode_arithmetic(mode) == irma_twos_complement) {
+                           mode_is_int(lmode) &&
+                           get_mode_arithmetic(lmode) == irma_twos_complement) {
                                ir_node *pre      = get_Conv_op(left);
                                ir_mode *pre_mode = get_irn_mode(pre);
 
@@ -1903,12 +1957,12 @@ static ir_node *transform_node_AddSub(ir_node *n) {
                }
 
                if (is_Conv(right)) {
-                       ir_mode *mode = get_irn_mode(right);
-                       unsigned bits = get_mode_size_bits(mode);
+                       ir_mode *rmode = get_irn_mode(right);
+                       unsigned bits = get_mode_size_bits(rmode);
 
                        if (ref_bits == bits &&
-                               mode_is_int(mode) &&
-                               get_mode_arithmetic(mode) == irma_twos_complement) {
+                           mode_is_int(rmode) &&
+                           get_mode_arithmetic(rmode) == irma_twos_complement) {
                                ir_node *pre      = get_Conv_op(right);
                                ir_mode *pre_mode = get_irn_mode(pre);
 
@@ -1924,6 +1978,19 @@ static ir_node *transform_node_AddSub(ir_node *n) {
                                }
                        }
                }
+
+               /* let address arithmetic use unsigned modes */
+               if (is_Const(right)) {
+                       ir_mode *rmode = get_irn_mode(right);
+
+                       if (mode_is_signed(rmode) && get_mode_arithmetic(rmode) == irma_twos_complement) {
+                               /* convert a AddP(P, *s) into AddP(P, *u) */
+                               ir_mode *nm = get_reference_mode_unsigned_eq(mode);
+
+                               ir_node *pre = new_r_Conv(current_ir_graph, get_nodes_block(n), right, nm);
+                               set_binop_right(n, pre);
+                       }
+               }
        }
        return n;
 }  /* transform_node_AddSub */
@@ -2783,8 +2850,17 @@ static ir_node *transform_node_Quot(ir_node *n) {
 
                if (is_Const(b)) {
                        tarval *tv = get_Const_tarval(b);
+                       int rem;
 
+                       /*
+                        * Floating point constant folding might be disabled here to
+                        * prevent rounding.
+                        * However, as we check for exact result, doing it is safe.
+                        * Switch it on.
+                        */
+                       rem = tarval_enable_fp_ops(1);
                        tv = tarval_quo(get_mode_one(mode), tv);
+                       (void)tarval_enable_fp_ops(rem);
 
                        /* Do the transformation if the result is either exact or we are not
                           using strict rules. */
@@ -2829,7 +2905,8 @@ static ir_node *transform_node_Abs(ir_node *n) {
 
                /*
                 * We can replace the Abs by -x here.
-                * We even could add a new Confirm here.
+                * We even could add a new Confirm here
+                * (if not twos complement)
                 *
                 * Note that -x would create a new node, so we could
                 * not run it in the equivalent_node() context.
@@ -2880,7 +2957,8 @@ static ir_node *transform_node_Cond(ir_node *n) {
            (get_opt_unreachable_code())) {
                /* It's a boolean Cond, branching on a boolean constant.
                   Replace it by a tuple (Bad, Jmp) or (Jmp, Bad) */
-               jmp = new_r_Jmp(current_ir_graph, get_nodes_block(n));
+               ir_node *blk = get_nodes_block(n);
+               jmp = new_r_Jmp(current_ir_graph, blk);
                turn_into_tuple(n, pn_Cond_max);
                if (ta == tarval_b_true) {
                        set_Tuple_pred(n, pn_Cond_false, new_Bad());
@@ -2890,12 +2968,16 @@ static ir_node *transform_node_Cond(ir_node *n) {
                        set_Tuple_pred(n, pn_Cond_true, new_Bad());
                }
                /* We might generate an endless loop, so keep it alive. */
-               add_End_keepalive(get_irg_end(current_ir_graph), get_nodes_block(n));
+               add_End_keepalive(get_irg_end(current_ir_graph), blk);
        }
        return n;
 }  /* transform_node_Cond */
 
-typedef ir_node* (*recursive_transform) (ir_node *n);
+/**
+ * Prototype of a recursive transform function
+ * for bitwise distributive transformations.
+ */
+typedef ir_node* (*recursive_transform)(ir_node *n);
 
 /**
  * makes use of distributive laws for and, or, eor
@@ -3626,11 +3708,9 @@ 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 Casts of both sides */
+       left  = skip_Cast(left);
+       right = skip_Cast(right);
 
        /* Remove unnecessary conversions */
        /* TODO handle constants */
@@ -3665,7 +3745,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) {
                }
        }
 
-       /* remove operation of both sides if possible */
+       /* remove operation on both sides if possible */
        if (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) {
                /*
                 * The following operations are NOT safe for floating point operations, for instance
@@ -4717,17 +4797,17 @@ static ir_node *transform_node_End(ir_node *n) {
 
 /** returns 1 if a == -b */
 static int is_negated_value(ir_node *a, ir_node *b) {
-       if(is_Minus(a) && get_Minus_op(a) == b)
+       if (is_Minus(a) && get_Minus_op(a) == b)
                return 1;
-       if(is_Minus(b) && get_Minus_op(b) == a)
+       if (is_Minus(b) && get_Minus_op(b) == a)
                return 1;
-       if(is_Sub(a) && is_Sub(b)) {
+       if (is_Sub(a) && is_Sub(b)) {
                ir_node *a_left  = get_Sub_left(a);
                ir_node *a_right = get_Sub_right(a);
                ir_node *b_left  = get_Sub_left(b);
                ir_node *b_right = get_Sub_right(b);
 
-               if(a_left == b_right && a_right == b_left)
+               if (a_left == b_right && a_right == b_left)
                        return 1;
        }
 
@@ -4752,34 +4832,50 @@ static ir_node *transform_node_Mux(ir_node *n) {
                        tarval *tv_t = get_Const_tarval(t);
                        if (tv_t == tarval_b_true) {
                                if (is_Const(f)) {
+                                       /* Muxb(sel, true, false) = sel */
                                        assert(get_Const_tarval(f) == tarval_b_false);
+                                       DBG_OPT_ALGSIM0(oldn, sel, FS_OPT_MUX_BOOL);
                                        return sel;
                                } else {
-                                       return new_rd_Or(dbg, irg, block, sel, f, mode_b);
+                                       /* Muxb(sel, true, x) = Or(sel, x) */
+                                       n = new_rd_Or(dbg, irg, block, sel, f, mode_b);
+                                       DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_OR_BOOL);
+                                       return n;
                                }
                        } else {
                                ir_node* not_sel = new_rd_Not(dbg, irg, block, sel, mode_b);
                                assert(tv_t == tarval_b_false);
                                if (is_Const(f)) {
+                                       /* Muxb(sel, false, true) = Not(sel) */
                                        assert(get_Const_tarval(f) == tarval_b_true);
+                                       DBG_OPT_ALGSIM0(oldn, not_sel, FS_OPT_MUX_NOT_BOOL);
                                        return not_sel;
                                } else {
-                                       return new_rd_And(dbg, irg, block, not_sel, f, mode_b);
+                                       /* Muxb(sel, false, x) = And(Not(sel), x) */
+                                       n = new_rd_And(dbg, irg, block, not_sel, f, mode_b);
+                                       DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_ANDNOT_BOOL);
+                                       return n;
                                }
                        }
                } else if (is_Const(f)) {
                        tarval *tv_f = get_Const_tarval(f);
                        if (tv_f == tarval_b_true) {
+                               /* Muxb(sel, x, true) = Or(Not(sel), x) */
                                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);
+                               DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_ORNOT_BOOL);
+                               n = new_rd_Or(dbg, irg, block, not_sel, t, mode_b);
+                               return n;
                        } else {
+                               /* Muxb(sel, x, false) = And(sel, x) */
                                assert(tv_f == tarval_b_false);
-                               return new_rd_And(dbg, irg, block, sel, t, mode_b);
+                               n = new_rd_And(dbg, irg, block, sel, t, mode_b);
+                               DBG_OPT_ALGSIM0(oldn, n, FS_OPT_MUX_AND_BOOL);
+                               return n;
                        }
                }
        }
 
-       if (is_Proj(sel) && !mode_honor_signed_zeros(mode)) {
+       if (is_Proj(sel)) {
                ir_node *cmp = get_Proj_pred(sel);
                long     pn  = get_Proj_proj(sel);
                ir_node *f   = get_Mux_false(n);
@@ -4791,37 +4887,102 @@ static ir_node *transform_node_Mux(ir_node *n) {
                 *
                 * Note further that these optimization work even for floating point
                 * with NaN's because -NaN == NaN.
-                * However, if +0 and -0 is handled differently, we cannot use the first
-                * one.
+                * However, if +0 and -0 is handled differently, we cannot use the Abs/-Abs
+                * transformations.
                 */
                if (is_Cmp(cmp)) {
                        ir_node *cmp_r = get_Cmp_right(cmp);
                        if (is_Const(cmp_r) && is_Const_null(cmp_r)) {
-                               ir_node *block    = get_irn_n(n, -1);
+                               ir_node *block = get_nodes_block(n);
+                               ir_node *cmp_l = get_Cmp_left(cmp);
 
-                               if(is_negated_value(f, t)) {
-                                       ir_node *cmp_left = get_Cmp_left(cmp);
+                               if (mode_honor_signed_zeros(mode) && is_negated_value(f, t)) {
+                                       /* f = -t */
 
-                                       /* Psi(a >= 0, a, -a) = Psi(a <= 0, -a, a) ==> Abs(a) */
-                                       if ( (cmp_left == t && (pn == pn_Cmp_Ge || pn == pn_Cmp_Gt))
-                                               || (cmp_left == f && (pn == pn_Cmp_Le || pn == pn_Cmp_Lt)))
+                                       if ( (cmp_l == t && (pn == pn_Cmp_Ge || pn == pn_Cmp_Gt))
+                                               || (cmp_l == f && (pn == pn_Cmp_Le || pn == pn_Cmp_Lt)))
                                        {
+                                               /* Psi(a >/>= 0, a, -a) = Psi(a </<= 0, -a, a) ==> Abs(a) */
                                                n = new_rd_Abs(get_irn_dbg_info(n), current_ir_graph, block,
-                                                                                cmp_left, mode);
+                                                                                cmp_l, mode);
                                                DBG_OPT_ALGSIM1(oldn, cmp, sel, n, FS_OPT_MUX_TO_ABS);
                                                return n;
-                                       /* Psi(a <= 0, a, -a) = Psi(a >= 0, -a, a) ==> -Abs(a) */
-                                       } else if ((cmp_left == t && (pn == pn_Cmp_Le || pn == pn_Cmp_Lt))
-                                               || (cmp_left == f && (pn == pn_Cmp_Ge || pn == pn_Cmp_Gt)))
+                                       } else if ((cmp_l == t && (pn == pn_Cmp_Le || pn == pn_Cmp_Lt))
+                                               || (cmp_l == f && (pn == pn_Cmp_Ge || pn == pn_Cmp_Gt)))
                                        {
+                                               /* Psi(a </<= 0, a, -a) = Psi(a >/>= 0, -a, a) ==> -Abs(a) */
                                                n = new_rd_Abs(get_irn_dbg_info(n), current_ir_graph, block,
-                                                                                cmp_left, mode);
+                                                                                cmp_l, mode);
                                                n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph,
                                                                                                                 block, n, mode);
                                                DBG_OPT_ALGSIM1(oldn, cmp, sel, n, FS_OPT_MUX_TO_ABS);
                                                return n;
                                        }
                                }
+
+                               if (mode_is_int(mode)) {
+                                       /* integer only */
+                                       if (pn == pn_Cmp_Eq) {
+                                               ir_node *tmp = t;
+                                               t = f;
+                                               f = tmp;
+                                               pn = pn_Cmp_Lg;
+                                       }
+                                       if (pn == pn_Cmp_Lg && is_And(cmp_l)) {
+                                               /* Psi((a & b) != 0, c, 0) */
+                                               ir_node *and_r = get_And_right(cmp_l);
+                                               ir_node *and_l;
+
+                                               if (and_r == t && f == cmp_r) {
+                                                       if (is_Const(t) && tarval_is_single_bit(get_Const_tarval(t))) {
+                                                               /* Psi((a & 2^C) != 0, 2^C, 0) */
+                                                               n = cmp_l;
+                                                               return n;
+                                                       }
+                                               }
+                                               if (and_r == f && t == cmp_r) {
+                                                       if (is_Const(f) && tarval_is_single_bit(get_Const_tarval(f))) {
+                                                               /* Psi((a & 2^C) != 0, 0, 2^C) */
+                                                               n = new_rd_Eor(get_irn_dbg_info(n), current_ir_graph,
+                                                                       block, cmp_l, f, mode);
+                                                               return n;
+                                                       }
+                                               }
+                                               if (is_Shl(and_r)) {
+                                                       ir_node *shl_l = get_Shl_left(and_r);
+                                                       if (is_Const(shl_l) && is_Const_one(shl_l)) {
+                                                               if (and_r == t && f == cmp_r) {
+                                                                       /* (a & (1 << n)) != 0, (1 << n), 0) */
+                                                                       n = cmp_l;
+                                                                       return n;
+                                                               }
+                                                               else if (and_r == f && t == cmp_r) {
+                                                                       /* (a & (1 << n)) != 0, 0, (1 << n)) */
+                                                                       n = new_rd_Eor(get_irn_dbg_info(n), current_ir_graph,
+                                                                               block, cmp_l, f, mode);
+                                                                       return n;
+                                                               }
+                                                       }
+                                               }
+                                               and_l = get_And_left(cmp_l);
+                                               if (is_Shl(and_l)) {
+                                                       ir_node *shl_l = get_Shl_left(and_l);
+                                                       if (is_Const(shl_l) && is_Const_one(shl_l)) {
+                                                               if (and_l == t && f == cmp_r) {
+                                                                       /* ((1 << n) & a) != 0, (1 << n), 0) */
+                                                                       n = cmp_l;
+                                                                       return n;
+                                                               }
+                                                               else if (and_l == f && t == cmp_r) {
+                                                                       /* ((1 << n) & a) != 0, 0, (1 << n)) */
+                                                                       n = new_rd_Eor(get_irn_dbg_info(n), current_ir_graph,
+                                                                               block, cmp_l, f, mode);
+                                                                       return n;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
                        }
                }
        }
@@ -4843,28 +5004,35 @@ static ir_node *transform_node_Psi(ir_node *n) {
  * of the other sync to our own inputs
  */
 static ir_node *transform_node_Sync(ir_node *n) {
-       int i, arity;
+       int arity = get_Sync_n_preds(n);
+       int i;
 
-       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)) {
+       for (i = 0; i < arity;) {
+               ir_node *pred = get_Sync_pred(n, i);
+               int      pred_arity;
+               int      j;
+
+               if (!is_Sync(pred)) {
                        ++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++;
+               del_Sync_n(n, i);
+               --arity;
+
+               pred_arity = get_Sync_n_preds(pred);
+               for (j = 0; j < pred_arity; ++j) {
+                       ir_node *pred_pred = get_Sync_pred(pred, j);
+                       int      k;
+
+                       for (k = 0;; ++k) {
+                               if (k >= arity) {
+                                       add_irn_n(n, pred_pred);
+                                       ++arity;
+                                       break;
+                               }
+                               if (get_Sync_pred(n, k) == pred_pred) break;
+                       }
                }
        }
 
@@ -4990,7 +5158,7 @@ static int node_cmp_attr_Free(ir_node *a, ir_node *b) {
 static int node_cmp_attr_SymConst(ir_node *a, ir_node *b) {
        const symconst_attr *pa = get_irn_symconst_attr(a);
        const symconst_attr *pb = get_irn_symconst_attr(b);
-       return (pa->num        != pb->num)
+       return (pa->kind       != pb->kind)
            || (pa->sym.type_p != pb->sym.type_p)
            || (pa->tp         != pb->tp);
 }  /* node_cmp_attr_SymConst */