beloopana: Remove duplicate comments.
[libfirm] / ir / opt / gvn_pre.c
index 965417e..0bdd8fd 100644 (file)
@@ -1,20 +1,6 @@
 /*
- * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
- *
  * This file is part of libFirm.
- *
- * This file may be distributed and/or modified under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation and appearing in the file LICENSE.GPL included in the
- * packaging of this file.
- *
- * Licensees holding valid libFirm Professional Edition licenses may use
- * this file in accordance with the libFirm Commercial License.
- * Agreement provided with the Software.
- *
- * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
- * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE.
+ * Copyright (C) 2012 University of Karlsruhe.
  */
 
 /**
 #include "irpass.h"
 #include "valueset.h"
 #include "irloop.h"
+#include "firmstat_t.h"
 
 #include "irgraph_t.h"
 #include "irnode_t.h"
 #include "iropt_t.h"
 #include "plist.h"
 
+/* suggested by GVN-PRE authors */
 #define MAX_ANTIC_ITER 10
 #define MAX_INSERT_ITER 3
 
-#define HOIST_HIGH 0
-#define BETTER_GREED 0
+/* Stops antic iteration from processing endless loops. */
+#define IGNORE_INF_LOOPS 1
+/* Stops antic information to flow over infinite loop backedge */
+#define NO_INF_LOOPS 0
+
+/* Attempt to reduce register pressure and reduce code size
+   for hoisted nodes. */
+#define HOIST_HIGH 1
+#define COMMON_DOM 1
+
+/* Seamless implementation of handling loads and generally memory
+   dependent nodes with GVN-PRE. */
 #define LOADS 1
 #define DIVMODS 0
-#define NO_INF_LOOPS 0
+
+/* Experimental */
+
+/* Only optimize node directly after phi node if node is only successor. */
+#define MIN_CUT 0
+
+/* GVN is very limited. This enables optimize_node during value recognition.
+   GVN ist still very limited, since a+1+b+1 doesn't equal a+b+2.
+   TODO Broken for yet unknown reasons. */
+#define OPTIMIZE_NODES 0
+
 
 /** Additional info we need for every block. */
 typedef struct block_info {
        ir_valueset_t     *exp_gen;    /* contains this blocks clean expressions */
        ir_valueset_t     *avail_out;  /* available values at block end */
        ir_valueset_t     *antic_in;   /* clean anticipated values at block entry */
-       ir_valueset_t     *antic_done; /* keeps elements of antic_in after insert nodes phase*/
+       ir_valueset_t     *antic_done; /* keeps elements of antic_in after insert nodes phase */
        ir_valueset_t     *new_set;    /* new by hoisting made available values */
        ir_nodehashmap_t  *trans;      /* contains translated nodes translated into block */
        ir_node           *avail;      /* saves available node for insert node phase */
@@ -73,8 +81,8 @@ typedef struct block_info {
 
 /**
  * A pair of nodes to be exchanged.
- * We have to defer the exchange because our hash-sets cannot
- * find an already replaced node.
+ * We have to defer the exchange because there are still needed references
+ * to certain nodes.
  */
 typedef struct elim_pair {
        ir_node *old_node;      /* node that will be replaced */
@@ -86,7 +94,7 @@ typedef struct elim_pair {
 /** environment for the GVN-PRE algorithm */
 typedef struct pre_env {
        ir_graph       *graph;        /* current graph */
-       struct obstack *obst;         /* obstack to allocate on */
+       struct obstack  obst;         /* obstack to allocate on */
        ir_node        *start_block;  /* start block of the current graph */
        ir_node        *end_block;    /* end block of the current graph */
        ir_node        *end_node;     /* end node of the current graph */
@@ -96,10 +104,15 @@ typedef struct pre_env {
        unsigned        last_idx;     /* last node index of input graph */
        char            changes;      /* flag for fixed point iterations - non-zero if changes occurred */
        char            first_iter;   /* non-zero for first fixed point iteration */
-       char            insert_phase; /* non-zero for first fixed point iteration */
+       int             iteration;    /* iteration counter */
+#if OPTIMIZE_NODES
+       pset           *value_table;   /* standard value table*/
+       pset           *gvnpre_values; /* gvnpre value table */
+#endif
 } pre_env;
 
 static pre_env *environ;
+
 /* custom GVN value map */
 static ir_nodehashmap_t value_map;
 
@@ -126,20 +139,20 @@ typedef struct gvnpre_statistics {
        int infinite_loops;
 } gvnpre_statistics;
 
-gvnpre_statistics *gvnpre_stats = NULL;
+static gvnpre_statistics *gvnpre_stats = NULL;
 
-static void init_stats()
+static void init_stats(void)
 {
        gvnpre_stats = XMALLOCZ(gvnpre_statistics);
 }
 
-static void free_stats()
+static void free_stats(void)
 {
        free(gvnpre_stats);
        gvnpre_stats = NULL;
 }
 
-static void print_stats()
+static void print_stats(void)
 {
        gvnpre_statistics *stats = gvnpre_stats;
        DB((dbg, LEVEL_1, "replaced             : %d\n", stats->replaced));
@@ -187,7 +200,7 @@ static void dump_value_set(ir_valueset_t *set, const char *txt, ir_node *block)
                ++i;
        }
        DB((dbg, LEVEL_2, "\n}\n"));
-}  /* dump_value_set */
+}
 
 /**
  * Dump all exp_gen value sets.
@@ -231,15 +244,16 @@ static int compare_gvn_identities(const void *elt, const void *key)
        if (is_Phi(a) || is_Phi(b))
                return 1;
 
-       /* memops are not the same, even if we want optimize them
+       /* memops are not the same, even if we want to optimize them
           we have to take the order in account */
-       if (is_memop(a) || is_memop(b))
-               return 1;
-
-#if 0
-       if (is_Call(a) || is_Call(b))
-               return 1;
-#endif
+       if (is_memop(a) || is_memop(b) ||
+           get_irn_mode(a) == mode_T ||
+           get_irn_mode(b) == mode_T) {
+               /* Loads with the same predecessors are the same value;
+                  this should only happen after phi translation. */
+               if ((! is_Load(a) || ! is_Load(b)) && (! is_Store(a) || ! is_Store(b)))
+                       return 1;
+       }
 
        if ((get_irn_op(a) != get_irn_op(b)) ||
            (get_irn_mode(a) != get_irn_mode(b))) return 1;
@@ -253,15 +267,8 @@ static int compare_gvn_identities(const void *elt, const void *key)
        if (is_Block(a) || is_Block(b))
                return 1;
 
-       /* TODO depends on load optimization */
-       if (get_irn_pinned(a) == op_pin_state_pinned) {
-               /* for pinned nodes, the block inputs must be equal */
-               if (get_irn_n(a, -1) != get_irn_n(b, -1))
-                       return 1;
-       } else {
-               /* we need global values independently from their blocks */
-               assert(get_opt_global_cse());
-       }
+       /* should only be used with gcse enabled */
+       assert(get_opt_global_cse());
 
        /* compare a->in[0..ins] with b->in[0..ins] */
        for (i = 0; i < irn_arity_a; ++i) {
@@ -342,7 +349,7 @@ static ir_node *remember(ir_node *irn)
                in[i] = pred_value;
        }
 
-       if (changed) {
+       if (changed && !is_memop(irn) && get_irn_mode(irn) != mode_X) {
                /* create representative for */
                ir_node *nn = new_ir_node(
                        get_irn_dbg_info(irn),
@@ -354,6 +361,14 @@ static ir_node *remember(ir_node *irn)
                        in);
                copy_node_attr(environ->graph, irn, nn);
 
+#if OPTIMIZE_NODES
+               /* TODO optimize_node() uses the valuetable and thus the custom
+                  identify_cmp() and will fail trying. */
+               environ->graph->value_table = environ->value_table;
+               nn = optimize_node(nn);
+               environ->graph->value_table = environ->gvnpre_values;
+#endif
+
                /* now the value can be determined because the
                   predecessors are the leaders */
                value = identify_remember(nn);
@@ -368,8 +383,9 @@ static ir_node *remember(ir_node *irn)
        return value;
 }
 
-/** When the value map has been built we may lookup expressions
- *  and remember them if new.
+/**
+ * When the value map has been built we may lookup expressions
+ * and remember them if new.
  */
 static ir_node *identify_or_remember(ir_node *irn)
 {
@@ -393,7 +409,7 @@ static ir_node *identify_or_remember(ir_node *irn)
  */
 static void alloc_block_info(ir_node *block, pre_env *env)
 {
-       block_info *info = OALLOC(env->obst, block_info);
+       block_info *info = OALLOC(&env->obst, block_info);
 
        set_irn_link(block, info);
        info->exp_gen    = ir_valueset_new(16);
@@ -410,7 +426,7 @@ static void alloc_block_info(ir_node *block, pre_env *env)
 
        info->next = env->list;
        env->list  = info;
-}  /* alloc_block_info */
+}
 
 static void free_block_info(block_info *block_info)
 {
@@ -580,7 +596,7 @@ static void analyse_loops(ir_graph *irg)
        ir_free_resources(irg, IR_RESOURCE_BLOCK_MARK);
 }
 
-#if NO_INF_LOOPS
+#if IGNORE_INF_LOOPS || NO_INF_LOOPS
 /**
  * Returns non-zero if block is part of an infinite loop.
  */
@@ -605,21 +621,6 @@ static unsigned is_in_infinite_loop(ir_node *block)
  * --------------------------------------------------------
  */
 
-/**
- * Helper function to get the anti leader of node in block.
- */
-static ir_node *get_anti_leader(ir_node *node, ir_node *block)
-{
-       block_info *info   = get_block_info(block);
-       ir_node    *value  = identify(node);
-       ir_node    *leader = ir_valueset_lookup(info->antic_in, value);
-
-       if (leader)
-               return leader;
-       else
-               return node;
-}
-
 /**
  * Returns non-zero if a node is movable and a possible candidate for PRE.
  */
@@ -627,13 +628,11 @@ static unsigned is_nice_value(ir_node *n)
 {
        ir_mode *mode = get_irn_mode(n);
 
-       /* positive group */
-
        if (is_Phi(n))
                return 1;
 
 #if LOADS || DIVMODS
-       if (is_Proj(n))
+       if (is_Proj(n) && mode != mode_X && mode != mode_T)
                return 1;
 #else
        if (is_Proj(n))
@@ -642,11 +641,11 @@ static unsigned is_nice_value(ir_node *n)
 
 #if LOADS
        if (is_Load(n))
-               return (get_Load_volatility(n) == volatility_non_volatile);
+               return get_Load_volatility(n) == volatility_non_volatile;
+       if (is_Store(n))
+               return get_Store_volatility(n) == volatility_non_volatile;
 #endif
 
-       /* negative group */
-
        if (get_irn_pinned(n) == op_pin_state_pinned)
                return 0;
 
@@ -664,9 +663,9 @@ static unsigned is_nice_value(ir_node *n)
  * @param block  the block
  * @return non-zero value for clean node
  */
-static unsigned is_clean_in_block_expgen(ir_node *n, ir_node *block)
+static unsigned is_clean_in_block(ir_node *n, ir_node *block, ir_valueset_t *valueset)
 {
-       int i, arity;
+       int         i, arity;
 
        if (is_Phi(n))
                return 1;
@@ -674,22 +673,47 @@ static unsigned is_clean_in_block_expgen(ir_node *n, ir_node *block)
        if (! is_nice_value(n))
                return 0;
 
+#if LOADS
+       /* filter loads with no phi predecessor from antic_in */
+       if (is_Load(n) && ! is_Phi(get_Load_mem(n)))
+               return 0;
+       if (is_Store(n) && ! is_Phi(get_Store_mem(n)))
+               return 0;
+#endif
+
+#if DIVMODS
+       if (is_Div(n)) {
+               ir_node *mem = get_Div_mem(n);
+
+               mem = skip_Pin(mem);
+
+               if (! is_Phi(mem) && ! is_NoMem(mem))
+                       return 0;
+       }
+
+       if (is_Mod(n) && ! is_Phi(get_Mod_mem(n)))
+               return 0;
+#endif
+
        arity = get_irn_arity(n);
        for (i = 0; i < arity; ++i) {
-               ir_node *pred = get_irn_n(n, i);
+               ir_node *pred   = get_irn_n(n, i);
+               ir_node *value;
 
-               /* sufficient for exp_gen */
-               if (get_nodes_block(pred) != block)
+               if (is_Phi(pred))
                        continue;
 
-               /* predecessor is in block,
-                  so it needs to be clean */
-               if (get_irn_link(pred)) {
+               /* we only handle current block */
+               if (get_nodes_block(pred) != block)
                        continue;
-               } else {
-                       DB((dbg, LEVEL_3, "unclean %+F because pred %+F unclean\n", n, pred));
+
+               if (! is_nice_value(pred))
                        return 0;
-               }
+
+               value = identify(pred);
+               if (! ir_valueset_lookup(valueset, value))
+                       return 0;
+
        }
        return 1;
 }
@@ -711,31 +735,33 @@ static void topo_walker(ir_node *irn, void *ctx)
        if (is_Block(irn))
                return;
 
-       /* GVN step: remember the value. Predecessors need to be visited. */
+#if OPTIMIZE_NODES
+       environ->graph->value_table = environ->value_table;
+       identify_remember(irn);
+       environ->graph->value_table = environ->gvnpre_values;
+#endif
+
+       /* GVN step: remember the value. */
        value = remember(irn);
 
+       if (is_irn_constlike(irn))
+               return;
+
        block = get_nodes_block(irn);
        info  = get_block_info(block);
 
-
-       /* no need to put constants into the sets: they are always redundant */
-       if (! is_nice_value(irn)) {
-               /* filter unnecessary values from avail_out */
+       if (get_irn_mode(irn) != mode_X)
                ir_valueset_insert(info->avail_out, value, irn);
 
-               if (is_irn_constlike(irn))
-                       return;
-       }
+       /* values that are not in antic_in also dont't need to be in any other set */
 
-       if (is_clean_in_block_expgen(irn, block)) {
+       if (! is_nice_value(irn))
+               return;
+
+       if (is_clean_in_block(irn, block, info->exp_gen)) {
                DB((dbg, LEVEL_3, "%+F clean in block %+F\n", irn, block));
 
                ir_valueset_insert(info->exp_gen, value, irn);
-               /* flag irn as clean*/
-               set_irn_link(irn, irn);
-       } else {
-               /* flag irn as not clean */
-               set_irn_link(irn, NULL);
        }
 }
 
@@ -760,16 +786,6 @@ static ir_node *get_translated(ir_node *block, ir_node *node)
        return ir_nodehashmap_get(ir_node, get_block_info(block)->trans, node);
 }
 
-static ir_node *get_translated_pred(ir_node *block, int pos, ir_node *node)
-{
-       ir_node *pred_block;
-       if (is_irn_constlike(node))
-               return node;
-
-       pred_block = get_Block_cfgpred_block(block, pos);
-       return ir_nodehashmap_get(ir_node, get_block_info(pred_block)->trans, node);
-}
-
 /**
  * Saves result of phi translation of node into predecessor
  * at pos of block succ.
@@ -788,149 +804,6 @@ static void set_translated(ir_nodehashmap_t *map, ir_node *node, ir_node *trans)
        ir_nodehashmap_insert(map, node, trans);
 }
 
-/**
- * Checks if node is hoistable into block.
- *
- * A clean node in block block can be hoisted above block succ.
- * A node is not clean if its representative is killed in block block.
- * The node can still be hoisted into block block.
- *
- * @param n      the node to be checked
- * @param block  the block to be hoisted into
- * @returns      block which node can be hoisted above
- */
-static unsigned is_hoistable_above(ir_node *node, ir_node *block, unsigned translated)
-{
-       int i;
-       int arity = get_irn_arity(node);
-
-       /* make sure that node can be hoisted above block */
-
-       if (is_irn_constlike(node))
-               return 1;
-
-       for (i = 0; i < arity; ++i) {
-               block_info *info       = get_block_info(block);
-               ir_node    *pred       = get_irn_n(node, i);
-               ir_node    *pred_value = identify(pred);
-               ir_node    *pred_block = get_nodes_block(pred);
-
-               /* predecessor strictly dominating */
-               if (block_strictly_dominates(pred_block, block))
-                       continue;
-
-               /* if we didn't translate the exact representative we cannot translate */
-               if (translated && !get_translated(pred_block, pred))
-                       return 0;
-
-               if (! ir_valueset_lookup(info->antic_in, pred_value))
-                       return 0;
-       }
-       return 1;
-}
-
-#if LOADS || DIVMODS
-/* Helper function to compare the values of pred and avail_pred. */
-static unsigned match_pred(ir_node *pred, ir_node *avail_pred, ir_node *block, int pos)
-{
-       ir_node *avail_value  = identify(avail_pred);
-       ir_node *trans_pred   = get_translated_pred(block, pos, pred);
-       ir_node *value;
-
-       if (trans_pred == NULL)
-               trans_pred = pred;
-       value = identify(trans_pred);
-
-       DB((dbg, LEVEL_3, "manual compare %+F  %+F\n", pred, avail_pred));
-
-       return (value == avail_value);
-}
-#endif
-
-#if LOADS
-/**
- * Does phi translation for redundant load nodes only.
- * Returns NULL for non-redundant loads, which need to be phi translated.
- * Loads are compared by comparing their pointer values,
- * and assuring that they are adjacent.
- * This is equivalent to what phi_translation does,
- * when a new node is created and then GCSE optimized resulting
- * in an already available node.
- */
-static ir_node *phi_translate_load(ir_node *load, ir_node *block, int pos)
-{
-       ir_node *mem   = get_Load_mem(load);
-       ir_node *trans = get_translated_pred(block, pos, mem);
-
-       if (trans == NULL)
-               trans = mem;
-
-       /* no partial redundancy if this is a mode_M phi */
-       if (is_Proj(trans)) {
-               /* The last memory operation in predecessor block */
-               ir_node *avail_load = get_Proj_pred(trans);
-
-               /* memop is a load with matching type */
-               if (is_Load(avail_load) &&
-                           get_Load_mode(load) == get_Load_mode(avail_load)) {
-
-                       unsigned match = match_pred(get_Load_ptr(load), get_Load_ptr(avail_load), block, pos);
-
-                       if (match)
-                               return avail_load;
-               }
-       }
-       return NULL;
-}
-#endif
-
-#if DIVMODS
-/**
- * Does phi translation for redundant Div/Mod nodes only.
- * Returns NULL for non-redundant node, which needs to be phi translated.
- */
-static ir_node *phi_translate_divmod(ir_node *divmod, ir_node *block, int pos)
-{
-       ir_node *mem   = get_memop_mem(divmod);
-       ir_node *trans = get_translated_pred(block, pos, mem);
-
-       if (trans == NULL)
-               trans = mem;
-
-       /* no partial redundancy if this is a mode_M phi */
-       if (is_Proj(trans)) {
-               /* The last memory operation in predecessor block */
-               ir_node *avail_op = get_Proj_pred(trans);
-
-               if (get_irn_op(divmod) == get_irn_op(avail_op)) {
-                       unsigned left, right;
-
-                       if (is_Div(avail_op)) {
-                               if (get_Div_resmode(divmod) == get_Div_resmode(avail_op) &&
-                                   get_Div_no_remainder(divmod) == get_Div_no_remainder(avail_op)) {
-
-                                       left  = match_pred(get_Div_left(divmod), get_Div_left(avail_op), block, pos);
-                                       right = match_pred(get_Div_right(divmod), get_Div_right(avail_op), block, pos);
-
-                                       if (left && right)
-                                               return avail_op;
-                               }
-                       } else if (is_Mod(avail_op)) {
-                           if (get_Mod_resmode(divmod) == get_Mod_resmode(avail_op)) {
-
-                                       left  = match_pred(get_Mod_left(divmod), get_Mod_left(avail_op), block, pos);
-                                       right = match_pred(get_Mod_right(divmod), get_Mod_right(avail_op), block, pos);
-
-                                       if (left && right)
-                                               return avail_op;
-                               }
-                       }
-               }
-       }
-       return NULL;
-}
-#endif
-
 /**
  * Translates an expression above a Phi.
  *
@@ -940,14 +813,14 @@ static ir_node *phi_translate_divmod(ir_node *divmod, ir_node *block, int pos)
  *
  * @return a node representing the translated value
  */
-static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, ir_node *pred_block)
+static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, ir_valueset_t *leaderset)
 {
        int       i;
        int       arity;
        ir_node **in;
-       ir_node  *target_block;
+       ir_node  *pred_block = get_Block_cfgpred_block(block, pos);
        ir_node  *nn;
-       int       needed;
+       unsigned  needed;
 
        if (is_Phi(node)) {
                if (get_nodes_block(node) == block)
@@ -957,55 +830,72 @@ static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, ir_node *p
        }
        arity = get_irn_arity(node);
 
-#if LOADS
-       if (is_Load(node)) {
-               ir_node *avail_load = phi_translate_load(node, block, pos);
-               if (avail_load)
-                       return avail_load;
-       }
-#endif
-
-#if DIVMODS
-       if (is_Div(node) || is_Mod(node)) {
-               ir_node *avail_op = phi_translate_divmod(node, block, pos);
-               if (avail_op)
-                       return avail_op;
-       }
-#endif
-
        needed = 0;
-       /* insert phase enforces translation for previously not translated nodes */
-       if (environ->insert_phase)
-               needed = 1;
-
-       in = XMALLOCN(ir_node *, arity);
+       in = ALLOCANZ(ir_node *, arity);
 
        /* A value has several representatives. The anti leader is chosen to be
           the main representative. If we access a node as representative of a
           value we always use the anti leader. The anti leader can be found by
           antic_in(identify(node)). */
        for (i = 0; i < arity; ++i) {
-               /* get anti leader for pred to lookup its translated value */
-               ir_node    *pred        = get_irn_n(node, i);
-               ir_node    *anti_leader = get_anti_leader(pred, block);
+               ir_node *pred   = get_irn_n(node, i);
+               ir_node *value  = identify(pred);
+               /* get leader for pred to lookup its translated value */
+               ir_node *leader = ir_valueset_lookup(leaderset, value);
+               ir_node *pred_trans;
+               ir_node *new_pred;
+
+               if (! leader)
+                       leader = pred;
+
                /* we cannot find this value in antic_in, because the value
                   has (possibly) changed! */
-               ir_node    *pred_trans  = get_translated(pred_block, anti_leader);
-               ir_node    *expr;
+               pred_trans  = get_translated(pred_block, leader);
+
+
+#if DIVMODS
+               if (is_Div(node)) {
+                       ir_node *mem = get_Div_mem(node);
+
+                       mem = skip_Pin(mem);
 
+                       if (! is_Phi(mem))
+                               pred_trans = get_Div_mem(node);
+               }
+#endif
+
+               DB((dbg, LEVEL_3, "trans %+F of %+F is  %+F\n", leader, pred_block, pred_trans));
                if (pred_trans == NULL) {
-                       expr = pred;
+                       new_pred = pred;
                } else {
-                       expr = pred_trans;
-                       /* predecessor value changed, so translation is needed */
-                       if (identify(expr) != identify(pred))
+                       new_pred = pred_trans;
+
+                       /* loads: Predecessor is a memory phi, which translated yields a proj or
+                          another phi. In case of projection and a load predecessor,
+                          skip them and use the loads memory. */
+                       if (is_Proj(pred_trans) && get_irn_mode(pred_trans) == mode_M) {
+#if LOADS || DIVMODS
+                               ir_node *loadstore = get_Proj_pred(pred_trans);
+                               /* If we do not translate this node, we will get its value wrong. */
                                needed |= 1;
+
+                               if (is_Load(loadstore)) {
+                                       /* Put new load under the adjacent loads memory edge
+                                          such that GVN may compare them. */
+                                       new_pred = get_Load_mem(loadstore);
+                               } else if (is_Store(loadstore)) {
+                                       new_pred = get_Store_mem(loadstore);
+                               }
+#endif
+                       } else {
+                               /* predecessor value changed, so translation is needed */
+                               if (identify(new_pred) != identify(pred))
+                                       needed |= 1;
+                       }
                }
 
-               /* We need to build a value tree. But values cannot be translated,
-                  expressions can be. So we translate the expressions and let GVN
-                  identify their values. */
-               in[i] = expr;
+               DB((dbg, LEVEL_4, "in %+F\n", new_pred));
+               in[i] = new_pred;
        }
 
        if (! needed)
@@ -1013,24 +903,22 @@ static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, ir_node *p
 
        DB((dbg, LEVEL_3, "Translate\n"));
 
-       target_block = get_Block_cfgpred_block(block, pos);
        if (is_Proj(node))
-               target_block = get_nodes_block(in[0]);
+               pred_block = get_nodes_block(in[0]);
 
        /* copy node to represent the new value.
           We do not translate nodes that do not need translation,
           so we use the newly created nodes as value representatives only.
           Their block is not important, because we create new ones during
-          insert node phase. */
+          the insert node phase. */
        nn = new_ir_node(
                get_irn_dbg_info(node),
                environ->graph,
-               target_block,
+               pred_block,
                get_irn_op(node),
                get_irn_mode(node),
                arity,
                in);
-       free(in);
        /* We need the attribute copy here, because the Hash value of a
           node might depend on it. */
        copy_node_attr(environ->graph, node, nn);
@@ -1074,9 +962,10 @@ static void compute_antic(ir_node *block, void *ctx)
        size = ir_valueset_size(info->antic_in);
        n_succ = get_Block_n_cfg_outs(block);
 
-#if 0
+       /* add exp_gen */
        if (env->first_iter) {
-#if NO_INF_LOOPS
+#if IGNORE_INF_LOOPS
+               /* keep antic_in of infinite loops empty */
                if (! is_in_infinite_loop(block)) {
                        foreach_valueset(info->exp_gen, value, expr, iter) {
                                ir_valueset_insert(info->antic_in, value, expr);
@@ -1088,7 +977,6 @@ static void compute_antic(ir_node *block, void *ctx)
                }
 #endif
        }
-#endif
 
        /* successor might have phi nodes */
        if (n_succ == 1 && get_irn_arity(get_Block_cfg_out(block, 0)) > 1) {
@@ -1103,34 +991,38 @@ static void compute_antic(ir_node *block, void *ctx)
                }
 
                foreach_valueset(succ_info->antic_in, value, expr, iter) {
-                       /* we translate the expression over the phi node,
-                          remember() builds the value tree */
-                       ir_node *trans       = phi_translate(expr, succ, pos, block);
-                       /* create new value if necessary */
-                       ir_node *trans_value = identify_or_remember(trans);
+                       ir_node *trans = get_translated(block, expr);
+                       ir_node *trans_value;
                        ir_node *represent;
 
+                       if (trans == NULL)
+                               trans = phi_translate(expr, succ, pos, get_block_info(succ)->antic_in);
+
+                       /* create new value if necessary */
+                       trans_value = identify_or_remember(trans);
+
                        DB((dbg, LEVEL_3, "Translate %+F %+F to %d = %+F (%+F)\n", expr, succ, pos, trans, trans_value));
 
-                       /* on value change (phi present) we need the translated node
+                       /* On value change (phi present) we need the translated node
                           to represent the new value for possible further translation. */
                        if (value != trans_value)
                                represent = trans;
                        else
                                represent = expr;
 
-                       if (is_hoistable_above(expr, block, 1))
-                               ir_valueset_insert(info->antic_in, trans_value, represent);
-                       set_translated(info->trans, expr, represent);
-               }
-               /* add exp_gen */
-               if (env->first_iter) {
-                       foreach_valueset(info->exp_gen, value, expr, iter) {
-                               ir_valueset_insert(info->antic_in, value, expr);
+                       if (is_clean_in_block(expr, block, info->antic_in)) {
+#if NO_INF_LOOPS
+                               /* Prevent information flow over the backedge of endless loops. */
+                               if (env->iteration <= 2 || (is_backedge(succ, pos) && !is_in_infinite_loop(succ))) {
+                                       ir_valueset_replace(info->antic_in, trans_value, represent);
+                               }
+#else
+                               ir_valueset_replace(info->antic_in, trans_value, represent);
+#endif
                        }
+                       set_translated(info->trans, expr, represent);
                }
 
-
        } else if (n_succ > 1) {
                int         i;
                ir_node    *common     = NULL;
@@ -1150,21 +1042,12 @@ static void compute_antic(ir_node *block, void *ctx)
                                        break;
                        }
 
-                       if (common && is_hoistable_above(expr, block, 0)) {
-                               ir_valueset_insert(info->antic_in, value, expr);
-                               DB((dbg, LEVEL_3, "common and clean %+F(%+F) in %+F\n", expr, value, block));
-                       }
-               }
-               /* add exp_gen */
-               if (env->first_iter) {
-                       foreach_valueset(info->exp_gen, value, expr, iter) {
-                               ir_valueset_insert(info->antic_in, value, expr);
-                       }
+                       if (common && is_clean_in_block(expr, block, info->antic_in))
+                               ir_valueset_replace(info->antic_in, value, expr);
                }
        }
 
 
-
        DEBUG_ONLY(dump_value_set(info->antic_in, "Antic_in", block);)
 
        if (size != ir_valueset_size(info->antic_in))
@@ -1208,10 +1091,9 @@ static void compute_avail_top_down(ir_node *block, void *ctx)
                ir_node                *expr;
                ir_valueset_iterator_t  iter;
 
-               foreach_valueset(dom_info->avail_out, value, expr, iter) {
-                       /* use first available expr as leader */
+               foreach_valueset(dom_info->avail_out, value, expr, iter)
+                       /* replace: use the leader from dominator, not local exp_gen */
                        ir_valueset_replace(info->avail_out, value, expr);
-               }
        }
 
        DEBUG_ONLY(dump_value_set(info->avail_out, "Avail_out", block);)
@@ -1222,26 +1104,6 @@ static void compute_avail_top_down(ir_node *block, void *ctx)
  * --------------------------------------------------------
  */
 
-/**
- * Flags node irn redundant depending on redundant parameter.
- */
-static void flag_redundant(ir_node *irn, unsigned redundant)
-{
-       if (redundant) {
-               set_irn_link(irn, irn);
-       } else {
-               set_irn_link(irn, NULL);
-       }
-}
-
-/*
- * Returns redundant flag of node irn.
- */
-static unsigned is_redundant(ir_node *irn)
-{
-       return (get_irn_link(irn) != NULL);
-}
-
 /**
  * Returns a valid mode if the value of expr is a partially redundant value.
  *
@@ -1269,15 +1131,15 @@ static ir_mode *is_partially_redundant(ir_node *block, ir_node *expr, ir_node *v
                ir_node    *trans_value;
                ir_node    *avail_expr;
 
-               /* ignore bad blocks. */
-               if (is_Bad(pred_block))
-                       continue;
-
                pred_info  = get_block_info(pred_block);
                trans_expr = get_translated(pred_block, expr);
                trans_value = identify(trans_expr);
 
-               avail_expr = (ir_node*)ir_valueset_lookup(pred_info->avail_out, trans_value);
+               if (is_Const(trans_expr))
+                       avail_expr = trans_expr;
+               else
+                       avail_expr = (ir_node*)ir_valueset_lookup(pred_info->avail_out, trans_value);
+
                /* value might be available through a not yet existing constant */
                if (avail_expr == NULL && is_Const(trans_expr)) {
                        /* limit range of new constants */
@@ -1286,22 +1148,23 @@ static ir_mode *is_partially_redundant(ir_node *block, ir_node *expr, ir_node *v
                        ir_tarval *lower = new_tarval_from_long(-127, cmode);
                        ir_tarval *c     = get_Const_tarval(trans_expr);
 
-                       if (tarval_cmp(lower, c) != ir_relation_greater_equal &&
-                               tarval_cmp(c, upper) != ir_relation_greater_equal) {
-                               avail_expr = NULL;
-                       } else {
+                       /* tarval within range? */
+                       if (tarval_cmp(lower, c) == ir_relation_less_equal &&
+                               tarval_cmp(c, upper) == ir_relation_less_equal) {
                                avail_expr = trans_expr;
+                       } else {
+                               avail_expr = NULL;
                        }
            }
 
-               DB((dbg, LEVEL_3, "avail_expr %+F\n", avail_expr));
+               DB((dbg, LEVEL_3, "avail_expr %+F  trans_expr %+F\n", avail_expr, trans_expr));
 
                if (avail_expr == NULL) {
                        pred_info->avail = trans_expr;
                        pred_info->found = 0;
                        fully_redundant  = 0;
                } else {
-                       /* expr is available */
+                       /* expr is available, use the leader */
                        pred_info->avail    = avail_expr;
                        pred_info->found    = 1;
                        mode                = get_irn_mode(avail_expr);
@@ -1310,20 +1173,14 @@ static ir_mode *is_partially_redundant(ir_node *block, ir_node *expr, ir_node *v
                        if (first_avail == NULL)
                                first_avail = avail_expr;
                        else if (first_avail != avail_expr)
-                               /* Multiple different expressions are available */
+                               /* Multiple different expressions are available,
+                                  This is why we need no cut over avail_out sets. */
                                fully_redundant = 0;
 
                        DB((dbg, LEVEL_2, "Found %+F from block %+F as %+F in pred %+F\n", expr, block, avail_expr, pred_block));
                }
        }
 
-#if BETTER_GREED
-       /* value is redundant from last iteration,
-          but has not been removed from antic_in (is not optimized) */
-       if (! environ->first_iter && is_redundant(expr))
-               return mode;
-#endif
-
        /* If it is not the same value already existing along every predecessor
        and it is defined by some predecessor then it is partially redundant. */
        if (! partially_redundant || fully_redundant)
@@ -1357,7 +1214,7 @@ static void update_new_set(ir_node *block, ir_node *idom)
        if (updated)
                dump_value_set(curr_info->avail_out, "Updated [Avail_out]", block);
 #endif
-} /* update_new_set */
+}
 
 /**
  * Checks if hoisting irn is greedy.
@@ -1367,16 +1224,84 @@ static void update_new_set(ir_node *block, ir_node *idom)
  */
 static unsigned is_hoisting_greedy(ir_node *irn, ir_node *block)
 {
+       int block_arity = get_irn_arity(block);
        int arity = get_irn_arity(irn);
-       int i;
+       int pos, i;
+       block_info *info = get_block_info(block);
 
-       for (i = 0; i < arity; ++i) {
-               ir_node *pred        = get_irn_n(irn, i);
-               ir_node *anti_leader = get_anti_leader(pred, block);
+       /* As long as the predecessor values are available in all predecessor blocks,
+          we can hoist this value. */
+       for (pos = 0; pos < block_arity; ++pos) {
+               ir_node    *pred_block = get_Block_cfgpred_block(block, pos);
+               block_info *pred_info  = get_block_info(pred_block);
 
-               /* predecessor is on current path we have to ensure redundancy */
-               if (block_dominates(block, get_nodes_block(pred)) && ! is_redundant(anti_leader))
-                       return 1;
+               for (i = 0; i < arity; ++i) {
+                       ir_node *pred     = get_irn_n(irn, i);
+                       ir_node *value;
+                       ir_node *leader;
+                       ir_node *trans;
+                       ir_node *trans_val;
+                       ir_node *avail;
+
+#if MIN_CUT
+                       /* Very conservative min cut. Phi might only have 1 user. */
+                       if (is_Phi(pred) && get_irn_n_edges(pred) != 1)
+                               return 1;
+#endif
+
+                       if (is_Phi(pred) && get_nodes_block(pred) == block)
+                               continue;
+
+                       DB((dbg, LEVEL_3, "pred %+F\n", pred));
+                       value = identify(pred);
+                       leader = ir_valueset_lookup(info->antic_in, value);
+                       if (! leader)
+                               leader = pred;
+                       DB((dbg, LEVEL_3, "lead %+F\n", leader));
+                       trans   = get_translated(pred_block, leader);
+                       if (! trans)
+                               trans = pred;
+                       DB((dbg, LEVEL_3, "trans %+F\n", trans));
+
+                       trans_val = identify(trans);
+                       DB((dbg, LEVEL_3, "value %+F\n", trans_val));
+
+                       if (is_Const(trans_val) || is_SymConst(trans_val)) {
+                               /* existing constant */
+                               if (get_irn_idx(trans_val) < environ->last_idx) {
+                                       continue;
+                               } else {
+                                       /* limit range of new constants */
+                                       ir_mode   *cmode = get_irn_mode(trans);
+                                       ir_tarval *upper = new_tarval_from_long(128, cmode);
+                                       ir_tarval *lower = new_tarval_from_long(-128, cmode);
+                                       ir_tarval *c     = get_Const_tarval(trans);
+
+                                       /* tarval within range? */
+                                       if (tarval_cmp(lower, c) == ir_relation_less &&
+                                               tarval_cmp(c, upper) == ir_relation_less) {
+                                               continue;
+                                       } else {
+                                               return 1;
+                                       }
+                               }
+                       }
+
+                       /* */
+                       if (is_irn_constlike(trans_val))
+                               continue;
+
+                       avail = ir_valueset_lookup(pred_info->avail_out, trans_val);
+
+                       DB((dbg, LEVEL_3, "avail %+F\n", avail));
+                       if (! avail)
+                               return 1;
+#if MIN_CUT
+                       /* only optimize if predecessors have been optimized */
+                       if (ir_valueset_lookup(info->antic_done, value) == NULL)
+                               return 1;
+#endif
+               }
        }
        return 0;
 }
@@ -1407,9 +1332,6 @@ static void insert_nodes_walker(ir_node *block, void *ctx)
        ir_node                *idom;
        int                     pos;
        ir_valueset_iterator_t  iter;
-#if BETTER_GREED
-       plist_t *stack;
-#endif
 
        /* only blocks */
        if (! is_Block(block))
@@ -1434,14 +1356,6 @@ static void insert_nodes_walker(ir_node *block, void *ctx)
                return;
        }
 
-#if BETTER_GREED
-       stack = plist_new();
-       foreach_valueset(info->antic_in, value, expr, iter) {
-               /* inverse topologic */
-               plist_insert_front(stack, expr);
-       }
-#endif
-
        /* This is the main reason antic_in is preverred over antic_out;
           we may iterate over every anticipated value first and not
           over the predecessor blocks. */
@@ -1455,10 +1369,8 @@ static void insert_nodes_walker(ir_node *block, void *ctx)
                        continue;
 
                /* filter phi nodes from antic_in */
-               if (is_Phi(expr)) {
-                       flag_redundant(expr, 1);
+               if (is_Phi(expr))
                        continue;
-               }
 
                DB((dbg, LEVEL_2, "Insert for %+F (value %+F) in %+F\n", expr, value, block));
 
@@ -1468,32 +1380,18 @@ static void insert_nodes_walker(ir_node *block, void *ctx)
                        DB((dbg, LEVEL_2, "Fully redundant expr %+F value %+F\n", expr, value));
                        DEBUG_ONLY(inc_stats(gvnpre_stats->fully);)
 
-                       flag_redundant(expr, 1);
+                       ir_valueset_insert(info->antic_done, value, expr);
                        continue;
                }
 
-#if !BETTER_GREED
                if (is_hoisting_greedy(expr, block)) {
-                       DB((dbg, LEVEL_2, "Greedy\n"));
-                       flag_redundant(expr, 0);
+                       DB((dbg, LEVEL_2, "greedy\n"));
                        continue;
                }
-#endif
 
                mode = is_partially_redundant(block, expr, value);
-               if (mode == NULL) {
-                       flag_redundant(expr, 0);
+               if (mode == NULL)
                        continue;
-               } else {
-                       flag_redundant(expr, 1);
-               }
-
-#if BETTER_GREED
-               if (is_hoisting_greedy(expr, block)) {
-                       DB((dbg, LEVEL_2, "Better greed: greedy\n"));
-                       continue;
-               }
-#endif
 
 #if LOADS || DIVMODS
                /* save old mode_M phis to remove keepalive edges later */
@@ -1511,7 +1409,7 @@ static void insert_nodes_walker(ir_node *block, void *ctx)
                                inc_stats(gvnpre_stats->first_iter_found);
                        inc_stats(gvnpre_stats->partially);
                }
-               if (is_Load(expr))
+               if (is_Load(expr) || is_Store(expr))
                        inc_stats(gvnpre_stats->loads);
                else if (is_Div(expr) || is_Mod(expr))
                        inc_stats(gvnpre_stats->divmods);
@@ -1524,31 +1422,98 @@ static void insert_nodes_walker(ir_node *block, void *ctx)
                        ir_node    *pred_block = get_Block_cfgpred_block(block, pos);
                        block_info *pred_info;
 
-                       /* ignore bad blocks. */
-                       if (is_Bad(pred_block)) {
-                               ir_graph *irg = get_irn_irg(pred_block);
-                               phi_in[pos] = new_r_Bad(irg, mode);
-                               continue;
-                       }
                        pred_info = get_block_info(pred_block);
 
                        if (! pred_info->found) {
-                               ir_node *trans = get_translated(pred_block, expr);
-
-                               assert(trans);
-                               if (trans == expr) {
-                                       /* has been translated if ancestor had a phi and was translated */
-                                       /* also non phi descendants can be redundant, but have
-                                          not yet been (phi) translated. */
-                                       trans = phi_translate(expr, block, pos, pred_block);
-                                       set_translated(pred_info->trans, expr, trans);
+                               int i;
+                               int node_arity = get_irn_arity(expr);
+                               ir_node **in = XMALLOCNZ(ir_node *, node_arity);
+                               ir_node *trans;
+                               ir_node *new_value, *new_value2;
+                               ir_node *target_block = pred_block;
+
+                               for (i = 0; i < node_arity; ++i) {
+                                       ir_node *pred     = get_irn_n(expr, i);
+                                       ir_node *value    = identify(pred);
+                                       ir_node *leader;
+                                       ir_node *trans;
+                                       ir_node *trans_val;
+                                       ir_node *avail;
+
+                                       /* transform knowledge over the predecessor from
+                                          anti-leader world into leader world. */
+
+                                       DB((dbg, LEVEL_3, "pred %+F\n", pred));
+                                       value = identify(pred);
+
+                                       /* get leader for pred to lookup its translated value */
+                                       leader = ir_valueset_lookup(info->antic_in, value);
+                                       if (! leader)
+                                               leader = pred;
+                                       DB((dbg, LEVEL_3, "lead %+F\n", leader));
+
+                                       trans   = get_translated(pred_block, leader);
+                                       if (!trans)
+                                               trans = pred;
+                                       DB((dbg, LEVEL_3, "trans %+F\n", trans));
+
+                                       /* in case of phi, we are done */
+                                       if (is_Phi(pred) && get_nodes_block(pred) == block) {
+                                               in[i] = trans;
+                                               continue;
+                                       }
+
+                                       trans_val = identify(trans);
+                                       DB((dbg, LEVEL_3, "value %+F\n", trans_val));
+
+                                       /* constants are always available but not in avail set */
+                                       if (is_irn_constlike(trans_val)) {
+                                               in[i] = trans;
+                                               continue;
+                                       }
+
+                                       /* use the leader
+                                          In case of loads we need to make sure the hoisted
+                                          loads are found despite their unique value. */
+                                       avail = ir_valueset_lookup(pred_info->avail_out, trans_val);
+                                       DB((dbg, LEVEL_3, "avail %+F\n", avail));
+
+                                       assert(avail && "predecessor has to be available");
+                                       in[i] = avail;
                                }
 
-                               DB((dbg, LEVEL_3, "Use new %+F in %+F because expr %+F not available\n", trans, pred_block, expr));
+                               if (is_Proj(expr))
+                                       target_block = get_nodes_block(in[0]);
+
+                               /* Copy node to represent the new value.
+                                  We use translated nodes as value representatives only.
+                                  They have anti leaders as predecessors, not leaders!
+                                  So we have to create a new node using leaders. */
+                               trans = new_ir_node(
+                                       get_irn_dbg_info(expr),
+                                       environ->graph,
+                                       target_block,
+                                       get_irn_op(expr),
+                                       get_irn_mode(expr),
+                                       get_irn_arity(expr),
+                                       in);
+                               free(in);
+                               /* We need the attribute copy here, because the Hash value of a
+                                  node might depend on it. */
+                               copy_node_attr(environ->graph, expr, trans);
 
                                /* value is now available in target block through trans
                                   insert (not replace) because it has not been available */
-                               ir_valueset_insert(pred_info->avail_out, value, trans);
+                               new_value = identify_or_remember(trans);
+                               ir_valueset_insert(pred_info->avail_out, new_value, trans);
+                               DB((dbg, LEVEL_4, "avail%+F+= trans %+F(%+F)\n", pred_block, trans, new_value));
+
+                               new_value2 = identify(get_translated(pred_block, expr));
+                               ir_valueset_insert(pred_info->avail_out, new_value2, trans);
+                               DB((dbg, LEVEL_4, "avail%+F+= trans %+F(%+F)\n", pred_block, trans, new_value2));
+
+                               DB((dbg, LEVEL_3, "Use new %+F in %+F because %+F(%+F) not available\n", trans, pred_block, expr, value));
+
                                phi_in[pos] = trans;
                        } else {
                                /* value available */
@@ -1564,67 +1529,40 @@ static void insert_nodes_walker(ir_node *block, void *ctx)
                        phi = new_r_Phi(block, arity, phi_in, mode);
                        DB((dbg, LEVEL_3, "New %+F for redundant %+F created\n", phi, expr));
 
-                       /* this value is now available through the new phi */
+                       /* This value is now available through the new phi.
+                          insert || replace in avail_out */
                        ir_valueset_replace(info->avail_out, value, phi);
                        ir_valueset_insert(info->new_set, value, phi);
                }
                free(phi_in);
 
-#if 0
-               /* remove from antic_in, because expr is not anticipated
-                  anymore in this block */
-               ir_valueset_remove_iterator(info->antic_in, &iter);
-#endif
+               /* already optimized this value in this block */
                ir_valueset_insert(info->antic_done, value, expr);
-
                env->changes |= 1;
        }
+}
 
-#if BETTER_GREED
-       if (env->changes) {
-               plist_element_t *it;
-               /* iterate in inverse topological order */
-               foreach_plist(stack, it) {
-                       ir_node *irn   = (ir_node *)plist_element_get_value(it);
-                       ir_node *block = get_nodes_block(irn);
-                       int      j;
-                       char     redundant = 1;
-
-                       /* does irn only have redundant successors? */
-
-                       if (! get_irn_outs_computed(irn))
-                               continue;
-
-                       for (j = get_irn_n_outs(irn) - 1; j >= 0; --j) {
-                               ir_node *succ = get_irn_out(irn, j);
-
-                               /* if succ and irn are in the same block */
-                               if (get_nodes_block(succ) == block && is_redundant(succ)) {
-                                       continue;
-                               } else {
-                                       redundant = 0;
-                                       break;
-                               }
-                       }
+#if HOIST_HIGH
+static void update_new_set_walker(ir_node *block, void *ctx)
+{
+       pre_env *env = (pre_env*)ctx;
 
-                       if (redundant)
-                               flag_redundant(irn, 1);
-               }
-       }
-       plist_free(stack);
-#endif
+       if (! is_Block(block))
+               return;
+       if (block == env->start_block)
+               return;
 
+       update_new_set(block, get_Block_idom(block));
 }
 
-#if HOIST_HIGH
 /**
- * Dom tree block walker to insert nodes into the highest
- * possible block where their .
- *
+ * Domtree block walker to insert nodes with dying operands
+ * into the highest possible block whilst still being anticipated.
  */
 static void hoist_high(ir_node *block, void *ctx)
 {
-       pre_env                *env        = (pre_env*)ctx;
+       (void)ctx;
+
        block_info             *curr_info;
        ir_valueset_iterator_t  iter;
        ir_node                *expr;
@@ -1634,13 +1572,14 @@ static void hoist_high(ir_node *block, void *ctx)
        if (! is_Block(block))
                return;
 
-       if (arity < 2)
-               return;
+       curr_info = get_block_info(block);
 
-       if (block == env->start_block)
-               return;
+       if (curr_info->new_set)
+               ir_valueset_del(curr_info->new_set);
+       curr_info->new_set = ir_valueset_new(16);
 
-       curr_info = get_block_info(block);
+       if (arity < 2)
+               return;
 
        DB((dbg, LEVEL_2, "High hoisting %+F\n", block));
 
@@ -1648,16 +1587,18 @@ static void hoist_high(ir_node *block, void *ctx)
        foreach_valueset(curr_info->antic_done, value, expr, iter) {
                int pos;
 
+               /* TODO currently we cannot handle load and their projections */
                if (is_memop(expr) || is_Proj(expr))
                        continue;
 
+               DB((dbg, LEVEL_4, "leader %+F value %+F\n", expr, value));
+
                /* visit hoisted expressions */
                for (pos = 0; pos < arity; ++pos) {
                        /* standard target is predecessor block */
                        ir_node    *target     = get_Block_cfgpred_block(block, pos);
                        block_info *pred_info  = get_block_info(target);
                        ir_node    *avail;
-                       ir_node    *temp_target;
                        ir_node    *new_target;
                        ir_node    *trans_expr;
                        ir_node    *trans_value;
@@ -1665,105 +1606,142 @@ static void hoist_high(ir_node *block, void *ctx)
                        int         avail_arity;
                        int         i;
                        unsigned    nest_depth;
+                       block_info *dom_info;
 
                        /* get phi translated value */
                        trans_expr  = get_translated(target, expr);
                        trans_value = identify(trans_expr);
-                       avail = (ir_node*)ir_valueset_lookup(pred_info->avail_out, trans_value);
+                       avail       = (ir_node*)ir_valueset_lookup(pred_info->avail_out, trans_value);
 
                        /* get the used expr on this path */
+
+                       /* TODO when does this happen? */
                        if (avail == NULL)
-                               avail = trans_expr;
+                               continue;
 
+                       avail_arity = get_irn_arity(avail);
                        value = identify(avail);
 
                        /* anticipation border */
                        new_target  = NULL;
-                       temp_target = NULL;
                        nest_depth  = get_loop_depth(get_irn_loop(target));
+
+                       /* Either push the hoisted nodes up their path,
+                          or try to put them directly into their common dominator. */
+#if COMMON_DOM
+                       /* By using block (instead of target) as initial block,
+                          we only allow hoisting into a common block of
+                          both predecessor blocks. */
+                       dom         = block;
+#else
                        dom         = target;
+#endif
 
-                       while(dom != environ->start_block) {
-                               block_info *dom_info;
+                       while (dom && dom != get_Block_idom(block)) {
 
                                dom = get_Block_idom(dom);
                                dom_info = get_block_info(dom);
+                               DB((dbg, LEVEL_4, "testing dom %+F\n", dom));
 
-                               if (is_Bad(dom))
-                                       break;
+                               /* TODO Being in antic_in means hoistable above block,
+                                  but we need 'hoistable into block'.
+                                  This could be achieved by a flag for each valueset pair,
+                                  being set during antic computation. */
 
-                               /* check if available node ist still anticipated and clean
-                                  (clean is part of antic) */
-                               /* value may be hoisted abover block */
-                               if (! ir_valueset_lookup(dom_info->antic_in, value))
+                               /* check if available node ist still anticipated and clean */
+                               if (! ir_valueset_lookup(dom_info->antic_in, value)) {
+                                       DB((dbg, LEVEL_4, "%+F not antic in %+F\n", value, dom));
                                        break;
+                               }
 
                                nest_depth = get_loop_depth(get_irn_loop(dom));
 
                                /* do not hoist into loops */
-                               if (get_loop_depth(get_irn_loop(dom)) <= nest_depth)
-                                       new_target = dom;
-
-                               temp_target = dom;
-                       }
-
-                       /* No new target or does the available node already dominate the new_target? */
-                       if (new_target) {
-                               DB((dbg, LEVEL_2, "leader block %+F\n", get_nodes_block(avail)));
-                               /* already same block or dominating?*/
-                               if (block_dominates(get_nodes_block(avail), new_target)) {
-                                       DB((dbg, LEVEL_4, "fail: antic border %+F\n", block));
-                                       new_target = NULL;
+                               if (get_loop_depth(get_irn_loop(dom)) > nest_depth) {
+                                       DB((dbg, LEVEL_4, "%+F deeper nested\n", dom));
+                                       /* not a suitable location */
+                                       continue;
                                }
-                       }
 
-                       DB((dbg, LEVEL_2, "antic border %+F\n", new_target));
+                               /* check if operands die */
 
-                       avail_arity = get_irn_arity(avail);
-                       /* check for uses of available ins on current path*/
-                       for (i = 0; i < avail_arity; i++) {
-                               ir_node *pred       = get_irn_n(avail, i);
-                               int      j;
+                               /* check for uses on current path */
+                               for (i = 0; i < avail_arity; i++) {
+                                       ir_node   *pred       = get_irn_n(avail, i);
+                                       ir_node   *pred_value = identify(pred);
 
-                               if (new_target == NULL)
-                                       break;
+                                       if (dom == NULL)
+                                               break;
 
-                               /* TODO this might be a problem as we mainly operate on new nodes */
-                               if (! get_irn_outs_computed(pred)) {
-                                       new_target = NULL;
-                                       break;
-                               }
+                                       DB((dbg, LEVEL_4, "testing pred %+F\n", pred));
 
-#if 0
-                               if (! block_dominates(pred_block, new_target)) {
-                                       new_target = pred_block;
-                               }
-#endif
-                               /* check for every successor */
-                               for (j = get_irn_n_outs(pred) - 1; j >= 0; --j) {
-                                       ir_node *succ = get_irn_out(pred, j);
-
-                                       /* is succ on this path? */
-                                       if (block_dominates(new_target, get_nodes_block(succ))) {
-                                               ir_node *succ_value = identify(succ);
-
-                                               /* Do we have another user than avail?
-                                                  Then predecessor is not dead after removal of avail. */
-                                               if (succ_value != value) {
-                                                       DB((dbg, LEVEL_4, "fail: still used %+F\n", succ));
-                                                       new_target = NULL;
-                                                       break;
+                                       if (! ir_valueset_lookup(dom_info->avail_out, pred_value)) {
+                                               DB((dbg, LEVEL_4, "pred %+F not available\n", pred));
+                                               dom = NULL;
+                                               break;
+                                       }
+
+                                       /* check every successor */
+                                       foreach_out_edge(pred, edge) {
+                                               ir_node *succ = get_edge_src_irn(edge);
+                                               DB((dbg, LEVEL_4, "testing succ %+F\n", succ));
+
+                                               /* check only successors on current path to end */
+                                               if (block_dominates(dom, get_nodes_block(succ))) {
+                                                       ir_node *succ_value = identify(succ);
+
+                                                       /* Do we have another user than avail?
+                                                          Then predecessor is not dead after removal of avail. */
+                                                       if (succ_value != value) {
+                                                               DB((dbg, LEVEL_4, "still used in %+F\n", succ));
+                                                               dom = NULL;
+                                                               break;
+                                                       }
                                                }
                                        }
                                }
+                               if (dom)
+                                       new_target = dom;
+
+#if COMMON_DOM
+                               /* only try common dominator */
+                               break;
+#endif
                        }
 
-                       /* only one usage on our path */
+                       /* put node into new target block */
                        if (new_target) {
-                               /* push the available node up into */
-                               set_nodes_block(avail, new_target);
+                               block_info *target_info = get_block_info(new_target);
+                               int         nn_arity    = get_irn_arity(avail);
+                               ir_node   **in          = XMALLOCN(ir_node *, nn_arity);
+                               ir_node    *nn;
+                               int         i;
 
+                               DB((dbg, LEVEL_2, "Hoisting %+F into %+F\n", avail, new_target));
                                DEBUG_ONLY(inc_stats(gvnpre_stats->hoist_high);)
+
+                               for (i = 0; i < nn_arity; ++i) {
+                                       ir_node *pred       = get_irn_n(avail, i);
+                                       ir_node *avail_pred = ir_valueset_lookup(target_info->avail_out, identify(pred));
+                                       assert(avail_pred);
+                                       in[i] = avail_pred;
+                               }
+                               nn = new_ir_node(
+                                       get_irn_dbg_info(avail),
+                                       environ->graph,
+                                       new_target,
+                                       get_irn_op(avail),
+                                       get_irn_mode(avail),
+                                       nn_arity,
+                                       in);
+                               free(in);
+
+                               identify_or_remember(nn);
+                               /* TODO Nodes are inserted into a dominating block and should
+                                  be available from this point on. Currently we do not push
+                                  the availability information through during the walk. */
+                               ir_valueset_insert(target_info->new_set, value, nn);
+                               ir_valueset_insert(target_info->avail_out, value, nn);
                        }
                }
        }
@@ -1795,14 +1773,15 @@ static void eliminate(ir_node *irn, void *ctx)
 
                if (value != NULL) {
                        ir_node *expr = (ir_node*)ir_valueset_lookup(info->avail_out, value);
+                       DB((dbg, LEVEL_3, "Elim %+F(%+F) avail %+F\n", irn, value, expr));
 
                        if (expr != NULL && expr != irn) {
-                               elim_pair *p = OALLOC(env->obst, elim_pair);
+                               elim_pair *p = OALLOC(&env->obst, elim_pair);
 
                                p->old_node = irn;
                                p->new_node = expr;
                                p->next     = env->pairs;
-                               if (get_irn_idx(expr) >= env->last_idx)
+                               if (get_irn_idx(expr) > env->last_idx)
                                        p->reason = FS_OPT_GVN_PARTLY;
                                else
                                        p->reason = FS_OPT_GVN_FULLY;
@@ -1811,7 +1790,7 @@ static void eliminate(ir_node *irn, void *ctx)
                        }
                }
        }
-}  /* eliminate */
+}
 
 /**
  * Do all the recorded changes and optimize
@@ -1822,8 +1801,6 @@ static void eliminate(ir_node *irn, void *ctx)
 static void eliminate_nodes(elim_pair *pairs, ir_nodeset_t *keeps)
 {
        elim_pair             *p;
-       ir_nodeset_iterator_t  iter;
-       ir_node               *m_phi;
        ir_node               *end    = environ->end_node;
 
        for (p = pairs; p != NULL; p = p->next) {
@@ -1863,7 +1840,8 @@ static void eliminate_nodes(elim_pair *pairs, ir_nodeset_t *keeps)
        foreach_ir_nodeset(keeps, m_phi, iter) {
                remove_End_keepalive(end, m_phi);
        }
-}  /* eliminate_nodes */
+}
+
 
 /* --------------------------------------------------------
  * GVN PRE pass
@@ -1874,6 +1852,7 @@ static void eliminate_nodes(elim_pair *pairs, ir_nodeset_t *keeps)
  * Gvn_Pre algorithm.
  *
  * @param irg   the graph
+ * @param env   the environment
  */
 static void gvn_pre(ir_graph *irg, pre_env *env)
 {
@@ -1898,6 +1877,7 @@ static void gvn_pre(ir_graph *irg, pre_env *env)
        antic_iter      = 0;
        env->first_iter = 1;
 
+       env->iteration = 1;
        /* antic_in passes */
        do {
                ++antic_iter;
@@ -1906,15 +1886,14 @@ static void gvn_pre(ir_graph *irg, pre_env *env)
                irg_walk_blkwise_graph(irg, compute_antic, NULL, env);
                env->first_iter = 0;
                DB((dbg, LEVEL_2, "----------------------------------------------\n"));
+               env->iteration ++;
        } while (env->changes != 0 && antic_iter < MAX_ANTIC_ITER);
 
        DEBUG_ONLY(set_stats(gvnpre_stats->antic_iterations, antic_iter);)
 
        ir_nodeset_init(env->keeps);
        insert_iter       = 0;
-       env->insert_phase = 1;
        env->first_iter   = 1;
-       env->last_idx     = get_irg_last_idx(irg);
        /* compute redundant expressions */
        do {
                ++insert_iter;
@@ -1928,10 +1907,18 @@ static void gvn_pre(ir_graph *irg, pre_env *env)
        DEBUG_ONLY(set_stats(gvnpre_stats->insert_iterations, insert_iter);)
 
 #if HOIST_HIGH
-       dom_tree_walk_irg(irg, hoist_high, NULL, env);
+       /* An attempt to reduce lifetimes by hoisting already hoisted values
+          even higher if their operands die. */
+       dom_tree_walk_irg(irg, hoist_high, NULL, NULL);
+       /* update avail_out for elimination */
+       dom_tree_walk_irg(irg, update_new_set_walker, NULL, env);
 #endif
 
-       /* last step: eliminate nodes */
+       /* Deactivate edges to prevent intelligent removal of nodes,
+          or else we will get deleted nodes which we try to exchange. */
+       edges_deactivate(environ->graph);
+
+       /* eliminate nodes */
        irg_walk_graph(irg, NULL, eliminate, env);
        eliminate_nodes(env->pairs, env->keeps);
 
@@ -1945,16 +1932,14 @@ static void gvn_pre(ir_graph *irg, pre_env *env)
  */
 void do_gvn_pre(ir_graph *irg)
 {
-       struct obstack        obst;
        pre_env               env;
        ir_nodeset_t          keeps;
        optimization_state_t  state;
        block_info           *block_info;
 
-       /* bads and unreachables cause too much trouble with dominance
-          dominance
-          loop info for endless loop detection
-          no critical edges is GVN-PRE precondition
+       /* bads and unreachables cause too much trouble with dominance,
+          loop info for endless loop detection,
+          no critical edges is PRE precondition
         */
        assure_irg_properties(irg,
                IR_GRAPH_PROPERTY_NO_BADS
@@ -1968,38 +1953,45 @@ void do_gvn_pre(ir_graph *irg)
        FIRM_DBG_REGISTER(dbg, "firm.opt.gvn_pre");
 
        save_optimization_state(&state);
-       environ = &env;
-
-       /* edges will crash if enabled due to our allocate on other obstack trick */
-       edges_deactivate(irg);
        ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_LOOP_LINK);
 
+       edges_activate(irg);
+
+       environ = &env;
        DEBUG_ONLY(init_stats();)
 
        /* setup environment */
-       obstack_init(&obst);
        env.graph        = irg;
-       env.obst         = &obst;
        env.list         = NULL;
        env.start_block  = get_irg_start_block(irg);
        env.end_block    = get_irg_end_block(irg);
        env.end_node     = get_irg_end(irg);
        env.pairs        = NULL;
        env.keeps        = &keeps;
-       env.insert_phase = 0;
+       env.last_idx     = get_irg_last_idx(irg);
+       obstack_init(&env.obst);
 
        /* Detect and set links of infinite loops to non-zero. */
        analyse_loops(irg);
 
+#if OPTIMIZE_NODES
+       new_identities(irg);
+       env.value_table = irg->value_table;
+       irg->value_table = NULL;
+#endif
+
        /* Switch on GCSE. We need it to correctly compute
           the value of a node, which is independent from
           its block. */
        set_opt_global_cse(1);
-       /* new_identities */
+       /* new_identities() */
        if (irg->value_table != NULL)
                del_pset(irg->value_table);
        /* initially assumed nodes in pset are 512 */
        irg->value_table = new_pset(compare_gvn_identities, 512);
+#if OPTIMIZE_NODES
+       env.gvnpre_values = irg->value_table;
+#endif
 
        /* do GVN-PRE pass */
        gvn_pre(irg, &env);
@@ -2012,7 +2004,7 @@ void do_gvn_pre(ir_graph *irg)
 
        DEBUG_ONLY(free_stats();)
        ir_nodehashmap_destroy(&value_map);
-       obstack_free(&obst, NULL);
+       obstack_free(&env.obst, NULL);
        ir_free_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_LOOP_LINK);
 
        /* Pin the graph again.
@@ -2021,8 +2013,19 @@ void do_gvn_pre(ir_graph *irg)
        restore_optimization_state(&state);
        confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_NONE);
 
-       /* TODO there are optimizations that try to use the existing value_table */
+#if OPTIMIZE_NODES
+       irg->value_table = env.value_table;
+       del_pset(irg->value_table);
+       irg->value_table = env.gvnpre_values;
+#endif
+
+       /* TODO There seem to be optimizations that try to use the existing
+          value_table. */
        new_identities(irg);
+
+       /* TODO assure nothing else breaks. */
+       set_opt_global_cse(0);
+       edges_activate(irg);
 }
 
 /* Creates an ir_graph pass for do_gvn_pre. */