improved safety: added a assert() if proj's are placed
[libfirm] / ir / ir / iropt.c
index 52faefd..c84d818 100644 (file)
@@ -27,9 +27,7 @@
 # include "config.h"
 #endif
 
-#ifdef HAVE_STRING_H
 #include <string.h>
-#endif
 
 #include "irnode_t.h"
 #include "irgraph_t.h"
@@ -47,8 +45,8 @@
 #include "irarch.h"
 #include "hashptr.h"
 #include "archop.h"
-#include "opt_polymorphy.h"
 #include "opt_confirms.h"
+#include "opt_polymorphy.h"
 #include "irtools.h"
 #include "xmalloc.h"
 
@@ -666,8 +664,7 @@ tarval *computed_value(ir_node *n) {
  * @return
  *    The operations.
  */
-static ir_op_ops *firm_set_default_computed_value(ir_opcode code, ir_op_ops *ops)
-{
+static ir_op_ops *firm_set_default_computed_value(ir_opcode code, ir_op_ops *ops) {
 #define CASE(a)                                    \
        case iro_##a:                                  \
                ops->computed_value  = computed_value_##a; \
@@ -955,40 +952,23 @@ static ir_node *equivalent_node_left_zero(ir_node *n) {
  */
 static ir_node *equivalent_node_Sub(ir_node *n) {
        ir_node *oldn = n;
-       ir_node *a, *b;
+       ir_node *b;
        ir_mode *mode = get_irn_mode(n);
 
        /* for FP these optimizations are only allowed if fp_strict_algebraic is disabled */
        if (mode_is_float(mode) && (get_irg_fp_model(current_ir_graph) & fp_strict_algebraic))
                return n;
 
-       a = get_Sub_left(n);
        b = get_Sub_right(n);
 
        /* Beware: modes might be different */
        if (classify_tarval(value_of(b)) == TV_CLASSIFY_NULL) {
+               ir_node *a = get_Sub_left(n);
                if (mode == get_irn_mode(a)) {
                        n = a;
 
                        DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_NEUTRAL_0);
                }
-       } else if (get_irn_op(a) == op_Add) {
-               if (mode_wrap_around(mode)) {
-                       ir_node *left  = get_Add_left(a);
-                       ir_node *right = get_Add_right(a);
-
-                       if (left == b) {
-                               if (mode == get_irn_mode(right)) {
-                                       n = right;
-                                       DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_SUB);
-                               }
-                       } else if (right == b) {
-                               if (mode == get_irn_mode(left)) {
-                                       n = left;
-                                       DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_SUB);
-                               }
-                       }
-               }
        }
        return n;
 }  /* equivalent_node_Sub */
@@ -1009,7 +989,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 */
@@ -1017,7 +997,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
 
@@ -1051,7 +1031,7 @@ static ir_node *equivalent_node_Div(ir_node *n) {
        if (classify_tarval(value_of(b)) == TV_CLASSIFY_ONE) { /* div(x, 1) == x */
                /* Turn Div into a tuple (mem, bad, a) */
                ir_node *mem = get_Div_mem(n);
-               ir_node *blk = get_nodes_block(n);
+               ir_node *blk = get_irn_n(n, -1);
                turn_into_tuple(n, pn_Div_max);
                set_Tuple_pred(n, pn_Div_M,         mem);
                set_Tuple_pred(n, pn_Div_X_regular, new_r_Jmp(current_ir_graph, blk));
@@ -1070,9 +1050,9 @@ static ir_node *equivalent_node_Quot(ir_node *n) {
 
        /* Div is not commutative. */
        if (classify_tarval(value_of(b)) == TV_CLASSIFY_ONE) { /* Quot(x, 1) == x */
-               /* Turn Quot into a tuple (mem, bad, a) */
+               /* Turn Quot into a tuple (mem, jmp, bad, a) */
                ir_node *mem = get_Quot_mem(n);
-               ir_node *blk = get_nodes_block(n);
+               ir_node *blk = get_irn_n(n, -1);
                turn_into_tuple(n, pn_Quot_max);
                set_Tuple_pred(n, pn_Quot_M,         mem);
                set_Tuple_pred(n, pn_Quot_X_regular, new_r_Jmp(current_ir_graph, blk));
@@ -1090,10 +1070,10 @@ static ir_node *equivalent_node_DivMod(ir_node *n) {
 
        /* Div is not commutative. */
        if (classify_tarval(value_of(b)) == TV_CLASSIFY_ONE) { /* div(x, 1) == x */
-               /* Turn DivMod into a tuple (mem, bad, a, 0) */
+               /* Turn DivMod into a tuple (mem, jmp, bad, a, 0) */
                ir_node *a = get_DivMod_left(n);
                ir_node *mem = get_Div_mem(n);
-               ir_node *blk = get_nodes_block(n);
+               ir_node *blk = get_irn_n(n, -1);
                ir_mode *mode = get_DivMod_resmode(n);
 
                turn_into_tuple(n, pn_DivMod_max);
@@ -1179,7 +1159,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);
@@ -1329,29 +1309,48 @@ static ir_node *equivalent_node_Sync(ir_node *n) {
  * Optimize Proj(Tuple) and gigo() for ProjX in Bad block,
  * ProjX(Load) and ProjX(Store).
  */
-static ir_node *equivalent_node_Proj(ir_node *n) {
-       ir_node *oldn = n;
-       ir_node *a = get_Proj_pred(n);
+static ir_node *equivalent_node_Proj(ir_node *proj) {
+       ir_node *oldn = proj;
+       ir_node *a = get_Proj_pred(proj);
 
-       if ( get_irn_op(a) == op_Tuple) {
+       if (get_irn_op(a) == op_Tuple) {
                /* Remove the Tuple/Proj combination. */
-               if ( get_Proj_proj(n) <= get_Tuple_n_preds(a) ) {
-                       n = get_Tuple_pred(a, get_Proj_proj(n));
-                       DBG_OPT_TUPLE(oldn, a, n);
+               if ( get_Proj_proj(proj) <= get_Tuple_n_preds(a) ) {
+                       proj = get_Tuple_pred(a, get_Proj_proj(proj));
+                       DBG_OPT_TUPLE(oldn, a, proj);
                } else {
-                       assert(0); /* This should not happen! */
-                       n = new_Bad();
+                        /* This should not happen! */
+                       assert(! "found a Proj with higher number than Tuple predecessors");
+                       proj = new_Bad();
                }
-       } else if (get_irn_mode(n) == mode_X) {
-               if (is_Block_dead(get_nodes_block(skip_Proj(n)))) {
+       } else if (get_irn_mode(proj) == mode_X) {
+               if (is_Block_dead(get_nodes_block(skip_Proj(proj)))) {
                        /* Remove dead control flow -- early gigo(). */
-                       n = new_Bad();
+                       proj = new_Bad();
                } else if (get_opt_ldst_only_null_ptr_exceptions()) {
                        ir_op *op = get_irn_op(a);
 
-                       if (op == op_Load || op == op_Store) {
+                       if (op == op_Load) {
+                               /* get the Load address */
+                               ir_node *addr = get_Load_ptr(a);
+                               ir_node *blk  = get_irn_n(a, -1);
+                               ir_node *confirm;
+
+                               if (value_not_null(addr, &confirm)) {
+                                       if (confirm == NULL) {
+                                               /* this node may float if it did not depend on a Confirm */
+                                               set_irn_pinned(a, op_pin_state_floats);
+                                       }
+                                       if (get_Proj_proj(proj) == pn_Load_X_except) {
+                                               DBG_OPT_EXC_REM(proj);
+                                               return new_Bad();
+                                       } else
+                                               return new_r_Jmp(current_ir_graph, blk);
+                               }
+                       } else if (op == op_Store) {
                                /* get the load/store address */
-                               ir_node *addr = get_irn_n(a, 1);
+                               ir_node *addr = get_Store_ptr(a);
+                               ir_node *blk  = get_irn_n(a, -1);
                                ir_node *confirm;
 
                                if (value_not_null(addr, &confirm)) {
@@ -1359,14 +1358,17 @@ static ir_node *equivalent_node_Proj(ir_node *n) {
                                                /* this node may float if it did not depend on a Confirm */
                                                set_irn_pinned(a, op_pin_state_floats);
                                        }
-                                       DBG_OPT_EXC_REM(n);
-                                       return new_Bad();
+                                       if (get_Proj_proj(proj) == pn_Store_X_except) {
+                                               DBG_OPT_EXC_REM(proj);
+                                               return new_Bad();
+                                       } else
+                                               return new_r_Jmp(current_ir_graph, blk);
                                }
                        }
                }
        }
 
-       return n;
+       return proj;
 }  /* equivalent_node_Proj */
 
 /**
@@ -1524,14 +1526,14 @@ static ir_node *equivalent_node_CopyB(ir_node *n) {
        ir_node *b = get_CopyB_src(n);
 
        if (a == b) {
-               /* Turn CopyB into a tuple (mem, bad, bad) */
+               /* Turn CopyB into a tuple (mem, jmp, bad, bad) */
                ir_node *mem = get_CopyB_mem(n);
                ir_node *blk = get_nodes_block(n);
                turn_into_tuple(n, pn_CopyB_max);
-               set_Tuple_pred(n, pn_CopyB_M,        mem);
+               set_Tuple_pred(n, pn_CopyB_M,         mem);
                set_Tuple_pred(n, pn_CopyB_X_regular, new_r_Jmp(current_ir_graph, blk));
-               set_Tuple_pred(n, pn_CopyB_X_except, new_Bad());        /* no exception */
-               set_Tuple_pred(n, pn_CopyB_M_except, new_Bad());
+               set_Tuple_pred(n, pn_CopyB_X_except,  new_Bad());        /* no exception */
+               set_Tuple_pred(n, pn_CopyB_M_except,  new_Bad());
        }
        return n;
 }  /* equivalent_node_CopyB */
@@ -1547,7 +1549,7 @@ static ir_node *equivalent_node_Bound(ir_node *n) {
        /* By definition lower < upper, so if idx == lower -->
        lower <= idx && idx < upper */
        if (idx == lower) {
-               /* Turn Bound into a tuple (mem, bad, idx) */
+               /* Turn Bound into a tuple (mem, jmp, bad, idx) */
                ret_tuple = 1;
        } else {
                ir_node *pred = skip_Proj(idx);
@@ -1563,15 +1565,15 @@ 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;
                        }
                }
        }
        if (ret_tuple) {
-               /* Turn Bound into a tuple (mem, bad, idx) */
+               /* Turn Bound into a tuple (mem, jmp, bad, idx) */
                ir_node *mem = get_Bound_mem(n);
                ir_node *blk = get_nodes_block(n);
                turn_into_tuple(n, pn_Bound_max);
@@ -1990,6 +1992,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 */
@@ -2011,16 +2021,61 @@ static ir_node *transform_node_Sub(ir_node *n) {
        a = get_Sub_left(n);
        b = get_Sub_right(n);
 
-       HANDLE_BINOP_PHI(tarval_sub, a,b,c);
-
        mode = get_irn_mode(n);
 
+restart:
+       HANDLE_BINOP_PHI(tarval_sub, a,b,c);
+
        /* for FP these optimizations are only allowed if fp_strict_algebraic is disabled */
        if (mode_is_float(mode) && (get_irg_fp_model(current_ir_graph) & fp_strict_algebraic))
                return n;
 
+       if (is_Add(a)) {
+               if (mode_wrap_around(mode)) {
+                       ir_node *left  = get_Add_left(a);
+                       ir_node *right = get_Add_right(a);
+
+                       /* FIXME: Does the Conv's word only for two complement or generally? */
+                       if (left == b) {
+                               if (mode != get_irn_mode(right)) {
+                                       /* This Sub is an effective Cast */
+                                       right = new_r_Conv(get_irn_irg(n), get_irn_n(n, -1), right, mode);
+                               }
+                               n = right;
+                               DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_SUB);
+                       } else if (right == b) {
+                               if (mode != get_irn_mode(left)) {
+                                       /* This Sub is an effective Cast */
+                                       left = new_r_Conv(get_irn_irg(n), get_irn_n(n, -1), left, mode);
+                               }
+                               n = left;
+                               DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_SUB);
+                       }
+               }
+       } else if (mode_is_int(mode) && is_Conv(a) && is_Conv(b)) {
+               ir_mode *mode = get_irn_mode(a);
+
+               if (mode == get_irn_mode(b)) {
+                       ir_mode *ma, *mb;
+
+                       a = get_Conv_op(a);
+                       b = get_Conv_op(b);
+
+                       /* check if it's allowed to skip the conv */
+                       ma = get_irn_mode(a);
+                       mb = get_irn_mode(b);
+
+                       if (mode_is_reference(ma) && mode_is_reference(mb)) {
+                               /* SubInt(ConvInt(aP), ConvInt(bP)) -> SubInt(aP,bP) */
+                               set_Sub_left(n, a);
+                               set_Sub_right(n, b);
+
+                               goto restart;
+                       }
+               }
+       }
        /* Beware of Sub(P, P) which cannot be optimized into a simple Minus ... */
-       if (mode_is_num(mode) && mode == get_irn_mode(a) && (classify_Const(a) == CNST_NULL)) {
+       else if (mode_is_num(mode) && mode == get_irn_mode(a) && (classify_Const(a) == CNST_NULL)) {
                n = new_rd_Minus(
                                get_irn_dbg_info(n),
                                current_ir_graph,
@@ -2094,7 +2149,6 @@ static ir_node *transform_node_Sub(ir_node *n) {
                set_Sub_right(n, add);
                DBG_OPT_ALGSIM0(n, n, FS_OPT_SUB_SUB_X_Y_Z);
        }
-
        return n;
 }  /* transform_node_Sub */
 
@@ -2145,9 +2199,9 @@ static ir_node *transform_node_Div(ir_node *n) {
                value = arch_dep_replace_div_by_const(n);
 
        if (value != n) {
-               /* Turn Div into a tuple (mem, bad, value) */
+               /* Turn Div into a tuple (mem, jmp, bad, value) */
                ir_node *mem = get_Div_mem(n);
-               ir_node *blk = get_nodes_block(n);
+               ir_node *blk = get_irn_n(n, -1);
 
                turn_into_tuple(n, pn_Div_max);
                set_Tuple_pred(n, pn_Div_M,         mem);
@@ -2175,9 +2229,9 @@ static ir_node *transform_node_Mod(ir_node *n) {
                value = arch_dep_replace_mod_by_const(n);
 
        if (value != n) {
-               /* Turn Mod into a tuple (mem, bad, value) */
+               /* Turn Mod into a tuple (mem, jmp, bad, value) */
                ir_node *mem = get_Mod_mem(n);
-               ir_node *blk = get_nodes_block(n);
+               ir_node *blk = get_irn_n(n, -1);
 
                turn_into_tuple(n, pn_Mod_max);
                set_Tuple_pred(n, pn_Mod_M,         mem);
@@ -2236,7 +2290,7 @@ static ir_node *transform_node_DivMod(ir_node *n) {
 
        if (evaluated) { /* replace by tuple */
                ir_node *mem = get_DivMod_mem(n);
-               ir_node *blk = get_nodes_block(n);
+               ir_node *blk = get_irn_n(n, -1);
                turn_into_tuple(n, pn_DivMod_max);
                set_Tuple_pred(n, pn_DivMod_M,         mem);
                set_Tuple_pred(n, pn_DivMod_X_regular, new_r_Jmp(current_ir_graph, blk));
@@ -2317,15 +2371,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 */
 
@@ -2362,6 +2524,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;
@@ -2373,30 +2537,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 */
 
@@ -2426,29 +2613,34 @@ static ir_node *transform_node_Cast(ir_node *n) {
  * Removes the exceptions and routes the memory to the NoMem node.
  */
 static ir_node *transform_node_Proj_Div(ir_node *proj) {
-       ir_node *n = get_Proj_pred(proj);
-       ir_node *b = get_Div_right(n);
-       ir_node *confirm;
+       ir_node *div = get_Proj_pred(proj);
+       ir_node *b   = get_Div_right(div);
+       ir_node *confirm, *res, *new_mem;
        long proj_nr;
 
        if (value_not_zero(b, &confirm)) {
                /* div(x, y) && y != 0 */
                proj_nr = get_Proj_proj(proj);
-               if (proj_nr == pn_Div_X_except) {
+               switch (proj_nr) {
+               case pn_Div_X_regular:
+                       return new_r_Jmp(current_ir_graph, get_irn_n(div, -1));
+
+               case pn_Div_X_except:
                        /* we found an exception handler, remove it */
                        DBG_OPT_EXC_REM(proj);
                        return new_Bad();
-               } else if (proj_nr == pn_Div_M) {
-                       ir_node *res = get_Div_mem(n);
-                       ir_node *new_mem = get_irg_no_mem(current_ir_graph);
+
+               case pn_Div_M:
+                       res = get_Div_mem(div);
+                       new_mem = get_irg_no_mem(current_ir_graph);
 
                        if (confirm) {
                                /* This node can only float up to the Confirm block */
                                new_mem = new_r_Pin(current_ir_graph, get_nodes_block(confirm), new_mem);
                        }
-                       set_irn_pinned(n, op_pin_state_floats);
+                       set_irn_pinned(div, op_pin_state_floats);
                        /* this is a Div without exception, we can remove the memory edge */
-                       set_Div_mem(n, new_mem);
+                       set_Div_mem(div, new_mem);
                        return res;
                }
        }
@@ -2460,38 +2652,46 @@ static ir_node *transform_node_Proj_Div(ir_node *proj) {
  * Removes the exceptions and routes the memory to the NoMem node.
  */
 static ir_node *transform_node_Proj_Mod(ir_node *proj) {
-       ir_node *n = get_Proj_pred(proj);
-       ir_node *b = get_Mod_right(n);
-       ir_node *confirm;
+       ir_node *mod = get_Proj_pred(proj);
+       ir_node *b   = get_Mod_right(mod);
+       ir_node *confirm, *res, *new_mem;
        long proj_nr;
 
        if (value_not_zero(b, &confirm)) {
                /* mod(x, y) && y != 0 */
                proj_nr = get_Proj_proj(proj);
 
-               if (proj_nr == pn_Mod_X_except) {
+               switch (proj_nr) {
+
+               case pn_Mod_X_regular:
+                       return new_r_Jmp(current_ir_graph, get_irn_n(mod, -1));
+
+               case pn_Mod_X_except:
                        /* we found an exception handler, remove it */
                        DBG_OPT_EXC_REM(proj);
                        return new_Bad();
-               } else if (proj_nr == pn_Mod_M) {
-                       ir_node *res = get_Mod_mem(n);
-                       ir_node *new_mem = get_irg_no_mem(current_ir_graph);
+
+               case pn_Mod_M:
+                       res = get_Mod_mem(mod);
+                       new_mem = get_irg_no_mem(current_ir_graph);
 
                        if (confirm) {
                                /* This node can only float up to the Confirm block */
                                new_mem = new_r_Pin(current_ir_graph, get_nodes_block(confirm), new_mem);
                        }
-                       set_irn_pinned(n, op_pin_state_floats);
+                       set_irn_pinned(mod, op_pin_state_floats);
                        /* this is a Mod without exception, we can remove the memory edge */
-                       set_Mod_mem(n, get_irg_no_mem(current_ir_graph));
-                       return res;
-               } else if (proj_nr == pn_Mod_res && get_Mod_left(n) == b) {
-                       /* a % a = 0 if a != 0 */
-                       ir_mode *mode = get_irn_mode(proj);
-                       ir_node *res  = new_Const(mode, get_mode_null(mode));
-
-                       DBG_OPT_CSTEVAL(n, res);
+                       set_Mod_mem(mod, get_irg_no_mem(current_ir_graph));
                        return res;
+               case pn_Mod_res:
+                       if (get_Mod_left(mod) == b) {
+                               /* a % a = 0 if a != 0 */
+                               ir_mode *mode = get_irn_mode(proj);
+                               ir_node *res  = new_Const(mode, get_mode_null(mode));
+
+                               DBG_OPT_CSTEVAL(mod, res);
+                               return res;
+                       }
                }
        }
        return proj;
@@ -2502,38 +2702,47 @@ static ir_node *transform_node_Proj_Mod(ir_node *proj) {
  * Removes the exceptions and routes the memory to the NoMem node.
  */
 static ir_node *transform_node_Proj_DivMod(ir_node *proj) {
-       ir_node *n = get_Proj_pred(proj);
-       ir_node *b = get_DivMod_right(n);
-       ir_node *confirm;
+       ir_node *divmod = get_Proj_pred(proj);
+       ir_node *b      = get_DivMod_right(divmod);
+       ir_node *confirm, *res, *new_mem;
        long proj_nr;
 
        if (value_not_zero(b, &confirm)) {
                /* DivMod(x, y) && y != 0 */
                proj_nr = get_Proj_proj(proj);
 
-               if (proj_nr == pn_DivMod_X_except) {
+               switch (proj_nr) {
+
+               case pn_DivMod_X_regular:
+                       return new_r_Jmp(current_ir_graph, get_irn_n(divmod, -1));
+
+               case pn_DivMod_X_except:
                        /* we found an exception handler, remove it */
                        DBG_OPT_EXC_REM(proj);
                        return new_Bad();
-               } else if (proj_nr == pn_DivMod_M) {
-                       ir_node *res = get_DivMod_mem(n);
-                       ir_node *new_mem = get_irg_no_mem(current_ir_graph);
+
+               case pn_DivMod_M:
+                       res = get_DivMod_mem(divmod);
+                       new_mem = get_irg_no_mem(current_ir_graph);
 
                        if (confirm) {
                                /* This node can only float up to the Confirm block */
                                new_mem = new_r_Pin(current_ir_graph, get_nodes_block(confirm), new_mem);
                        }
-                       set_irn_pinned(n, op_pin_state_floats);
+                       set_irn_pinned(divmod, op_pin_state_floats);
                        /* this is a DivMod without exception, we can remove the memory edge */
-                       set_DivMod_mem(n, get_irg_no_mem(current_ir_graph));
+                       set_DivMod_mem(divmod, get_irg_no_mem(current_ir_graph));
                        return res;
-               } else if (proj_nr == pn_DivMod_res_mod && get_DivMod_left(n) == b) {
-                       /* a % a = 0 if a != 0 */
-                       ir_mode *mode = get_irn_mode(proj);
-                       ir_node *res  = new_Const(mode, get_mode_null(mode));
 
-                       DBG_OPT_CSTEVAL(n, res);
-                       return res;
+               case pn_DivMod_res_mod:
+                       if (get_DivMod_left(divmod) == b) {
+                               /* a % a = 0 if a != 0 */
+                               ir_mode *mode = get_irn_mode(proj);
+                               ir_node *res  = new_Const(mode, get_mode_null(mode));
+
+                               DBG_OPT_CSTEVAL(divmod, res);
+                               return res;
+                       }
                }
        }
        return proj;
@@ -2633,10 +2842,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 */
@@ -2653,16 +2864,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 != */
@@ -2674,7 +2889,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) {
@@ -3081,6 +3298,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 */
@@ -3358,8 +3579,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 */
 
@@ -3426,7 +3658,7 @@ static int node_cmp_attr_Const(ir_node *a, ir_node *b) {
 
 /** Compares the attributes of two Proj nodes. */
 static int node_cmp_attr_Proj(ir_node *a, ir_node *b) {
-       return get_irn_proj_attr (a) != get_irn_proj_attr (b);
+       return get_irn_proj_attr(a) != get_irn_proj_attr(b);
 }  /* node_cmp_attr_Proj */
 
 /** Compares the attributes of two Filter nodes. */
@@ -3436,21 +3668,25 @@ static int node_cmp_attr_Filter(ir_node *a, ir_node *b) {
 
 /** Compares the attributes of two Alloc nodes. */
 static int node_cmp_attr_Alloc(ir_node *a, ir_node *b) {
-       return (get_irn_alloc_attr(a).where != get_irn_alloc_attr(b).where)
-           || (get_irn_alloc_attr(a).type != get_irn_alloc_attr(b).type);
+       const alloc_attr *pa = get_irn_alloc_attr(a);
+       const alloc_attr *pb = get_irn_alloc_attr(b);
+       return (pa->where != pb->where) || (pa->type != pb->type);
 }  /* node_cmp_attr_Alloc */
 
 /** Compares the attributes of two Free nodes. */
 static int node_cmp_attr_Free(ir_node *a, ir_node *b) {
-       return (get_irn_free_attr(a).where != get_irn_free_attr(b).where)
-           || (get_irn_free_attr(a).type != get_irn_free_attr(b).type);
+       const free_attr *pa = get_irn_free_attr(a);
+       const free_attr *pb = get_irn_free_attr(b);
+       return (pa->where != pb->where) || (pa->type != pb->type);
 }  /* node_cmp_attr_Free */
 
 /** Compares the attributes of two SymConst nodes. */
 static int node_cmp_attr_SymConst(ir_node *a, ir_node *b) {
-       return (get_irn_symconst_attr(a).num != get_irn_symconst_attr(b).num)
-           || (get_irn_symconst_attr(a).sym.type_p != get_irn_symconst_attr(b).sym.type_p)
-           || (get_irn_symconst_attr(a).tp != get_irn_symconst_attr(b).tp);
+       const symconst_attr *pa = get_irn_symconst_attr(a);
+       const symconst_attr *pb = get_irn_symconst_attr(b);
+       return (pa->num        != pb->num)
+           || (pa->sym.type_p != pb->sym.type_p)
+           || (pa->tp         != pb->tp);
 }  /* node_cmp_attr_SymConst */
 
 /** Compares the attributes of two Call nodes. */
@@ -3460,11 +3696,14 @@ static int node_cmp_attr_Call(ir_node *a, ir_node *b) {
 
 /** Compares the attributes of two Sel nodes. */
 static int node_cmp_attr_Sel(ir_node *a, ir_node *b) {
-       return (get_irn_sel_attr(a).ent->kind  != get_irn_sel_attr(b).ent->kind)
-           || (get_irn_sel_attr(a).ent->name    != get_irn_sel_attr(b).ent->name)
-           || (get_irn_sel_attr(a).ent->owner   != get_irn_sel_attr(b).ent->owner)
-           || (get_irn_sel_attr(a).ent->ld_name != get_irn_sel_attr(b).ent->ld_name)
-           || (get_irn_sel_attr(a).ent->type    != get_irn_sel_attr(b).ent->type);
+       const ir_entity *a_ent = get_Sel_entity(a);
+       const ir_entity *b_ent = get_Sel_entity(b);
+       return
+               (a_ent->kind    != b_ent->kind)    ||
+               (a_ent->name    != b_ent->name)    ||
+               (a_ent->owner   != b_ent->owner)   ||
+               (a_ent->ld_name != b_ent->ld_name) ||
+               (a_ent->type    != b_ent->type);
 }  /* node_cmp_attr_Sel */
 
 /** Compares the attributes of two Phi nodes. */
@@ -3510,6 +3749,52 @@ static int node_cmp_attr_Confirm(ir_node *a, ir_node *b) {
        return (get_Confirm_cmp(a) != get_Confirm_cmp(b));
 }  /* node_cmp_attr_Confirm */
 
+/** Compares the attributes of two ASM nodes. */
+static int node_cmp_attr_ASM(ir_node *a, ir_node *b) {
+       int i, n;
+       const ir_asm_constraint *ca;
+       const ir_asm_constraint *cb;
+       ident **cla, **clb;
+
+       if (get_ASM_text(a) != get_ASM_text(b))
+               return 1;
+
+       /* Should we really check the constraints here? Should be better, but is strange. */
+       n = get_ASM_n_input_constraints(a);
+       if (n != get_ASM_n_input_constraints(b))
+               return 0;
+
+       ca = get_ASM_input_constraints(a);
+       cb = get_ASM_input_constraints(b);
+       for (i = 0; i < n; ++i) {
+               if (ca[i].pos != cb[i].pos || ca[i].constraint != cb[i].constraint)
+                       return 1;
+       }
+
+       n = get_ASM_n_output_constraints(a);
+       if (n != get_ASM_n_output_constraints(b))
+               return 0;
+
+       ca = get_ASM_output_constraints(a);
+       cb = get_ASM_output_constraints(b);
+       for (i = 0; i < n; ++i) {
+               if (ca[i].pos != cb[i].pos || ca[i].constraint != cb[i].constraint)
+                       return 1;
+       }
+
+       n = get_ASM_n_clobbers(a);
+       if (n != get_ASM_n_clobbers(b))
+               return 0;
+
+       cla = get_ASM_clobbers(a);
+       clb = get_ASM_clobbers(b);
+       for (i = 0; i < n; ++i) {
+               if (cla[i] != clb[i])
+                       return 1;
+       }
+       return 0;
+}  /* node_cmp_attr_ASM */
+
 /**
  * Set the default node attribute compare operation for an ir_op_ops.
  *
@@ -3541,6 +3826,7 @@ static ir_op_ops *firm_set_default_node_cmp_attr(ir_opcode code, ir_op_ops *ops)
        CASE(Load);
        CASE(Store);
        CASE(Confirm);
+       CASE(ASM);
        default:
          /* leave NULL */;
        }
@@ -4033,10 +4319,104 @@ ir_node *optimize_in_place(ir_node *n) {
        return optimize_in_place_2(n);
 }  /* optimize_in_place */
 
+/**
+ * Return the block for all default nodes.
+ */
+static ir_node *get_block_default(const ir_node *self) {
+       return get_irn_n(self, -1);
+}
+
+/**
+ * Sets the block for all default nodes.
+ */
+static void set_block_default(ir_node *self, ir_node *blk) {
+       set_irn_n(self, -1, blk);
+}
+
+/**
+ * It's not allowed to get the block of a block. Anyway, returns
+ * the macroblock header in release mode.
+ */
+static ir_node *get_block_Block(const ir_node *self) {
+       assert(!"get_nodes_block() called for a block");
+       return get_irn_n(self, -1);
+}
+
+/**
+ * It's not allowed to set the block of a block. In release mode sets
+ * the macroblock header.
+ */
+static void set_block_Block(ir_node *self, ir_node *blk) {
+       assert(!"set_nodes_block() called for a block");
+       set_irn_n(self, -1, blk);
+}
+
+/**
+ * The anchor is always placed in the endblock or a graph.
+ */
+static ir_node *get_block_Anchor(const ir_node *self) {
+       return get_irn_n(self, anchor_end_block);
+}
+
+/**
+ * It's forbidden to set the anchor block.
+ */
+static void set_block_Anchor(ir_node *self, ir_node *blk) {
+       (void) self;
+       (void) blk;
+       assert(!"set_nodes_block() called for the Anchor");
+}
+
+/**
+ * Proj nodes are always in the block of it's predecessor.
+ */
+static ir_node *get_block_Proj(const ir_node *self) {
+       ir_node *pred = get_Proj_pred(self);
+       return get_nodes_block(pred);
+}
+
+/**
+ * Proj nodes silently ignore the block set request.
+ */
+static void set_block_Proj(ir_node *self, ir_node *blk) {
+       (void) self;
+       (void) blk;
+       assert(blk == get_block_Proj(self) && "trying to move Proj in another block!");
+}
+
+/**
+ * Set the default get_block operation.
+ */
+static  ir_op_ops *firm_set_default_get_block(ir_opcode code, ir_op_ops *ops) {
+#define CASE(a)                                    \
+       case iro_##a:                                  \
+               ops->get_block = get_block_##a; \
+               ops->set_block = set_block_##a; \
+               break
+
+       switch (code) {
+       CASE(Block);
+       CASE(Anchor);
+#ifndef CAN_PLACE_PROJS
+       CASE(Proj);
+#endif
+       default:
+               /* not allowed to be NULL */
+               if (! ops->get_block)
+                       ops->get_block = get_block_default;
+               if (! ops->set_block)
+                       ops->set_block = set_block_default;
+       }
+
+       return ops;
+#undef CASE
+}  /* firm_set_default_get_block */
+
 /*
  * Sets the default operation for an ir_ops.
  */
 ir_op_ops *firm_set_default_operations(ir_opcode code, ir_op_ops *ops) {
+       ops = firm_set_default_get_block(code, ops);
        ops = firm_set_default_computed_value(code, ops);
        ops = firm_set_default_equivalent_node(code, ops);
        ops = firm_set_default_transform_node(code, ops);