fixed warnigns
[libfirm] / ir / opt / gvn_pre.c
index d84a443..d154485 100644 (file)
@@ -1,19 +1,39 @@
 /*
- * Project:     libFIRM
- * File name:   ir/opt/gvn_pre.c
- * Purpose:     Global Value Numbering Partial Redundancy Elimination
- *              (VanDrunen Hosking 2004)
- * Author:      Michael Beck, Rubino Geiss
- * Created:
- * CVS-ID:      $Id$
- * Copyright:   (c) 1998-2006 Universität Karlsruhe
- * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
+ * Copyright (C) 1995-2007 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.
  */
 
+/**
+ * @file
+ * @brief   Global Value Numbering Partial Redundancy Elimination
+ *          (VanDrunen Hosking 2004)
+ * @author  Michael Beck, Rubino Geiss
+ * @version $Id$
+ * @summary
+ *
+ * Currently completely broken because our sets do NOT preserve
+ * the topological sort!
+ */
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
+#include "iroptimize.h"
+
 #include <assert.h>
 
 #include "irgraph_t.h"
@@ -21,6 +41,7 @@
 #include "irdom.h"
 #include "irouts.h"
 #include "pset.h"
+#include "set.h"
 #include "irgopt.h"
 #include "iropt_t.h"
 #include "irprintf.h"
 #include "ircons.h"
 #include "irgmod.h"
 #include "debug.h"
-#include "gvn_pre.h"
+#include "xmalloc.h"
+
+/** The debug module handle. */
+DEBUG_ONLY(static firm_dbg_module_t *dbg;)
+
+
+/** A value set. */
+typedef struct set value_set;
+
+/** A node set. */
+typedef struct pset node_set;
+
+/** An entry in the value set. */
+typedef struct value_entry {
+  ir_node *node;  /**< the node */
+  ir_node *value; /**< the value of the node */
+} value_entry;
 
-/* */
+/** Additional info we need for every block. */
 typedef struct block_info {
-  pset *nodes;        /**< the set of nodes per block */
-  pset *avail_out;    /**< the Avail_out set for a block */
-  pset *antic_in;     /**< the Antic_in set for a block */
-  pset *new_set;      /**< the set of all new values for a block */
-  ir_node *avail;     /**< the get_map(avail, block) result */
-  int not_found;      /**< non-zero, if avail was not found in this block */
-  struct block_info *next;
+  node_set *nodes;      /**< The set of nodes per block. */
+  value_set *avail_out; /**< The Avail_out set for a block. */
+  node_set *antic_in;   /**< The Antic_in set for a block. */
+  value_set *new_set;   /**< The set of all new values for a block. */
+  ir_node *avail;       /**< The get_map(avail, block) result. */
+  int not_found;        /**< Non-zero, if avail was not found in this block. */
+  struct block_info *next;  /**< Links all entries, so we can recover the sets easily. */
 } block_info;
 
+/**
+ * A pair of nodes that must be exchanged.
+ * We must defer the exchange because our hash-sets cannot
+ * find an already replace node else.
+ */
+typedef struct elim_pair {
+  ir_node *old_node;      /**< The old node that will be replaced. */
+  ir_node *new_node;      /**< The new node. */
+  struct elim_pair *next; /**< Links all entries in a list. */
+} elim_pair;
+
+/** The environment for the GVN-PRE algorithm */
 typedef struct pre_env {
-  struct obstack *obst;   /**< the obstack to allocate on */
-  ir_node *start_block;   /**< the start block of the current graph */
-  ir_node *end_block;     /**< the end block of the current graph */
-  block_info *list;       /**< links all block info entires for easier recovery */
-  int changes;            /**< non-zero, if calculation of Antic_in has changed */
+  struct obstack *obst;   /**< The obstack to allocate on. */
+  node_set *trans_set;    /**< The set of all translated values. */
+  ir_node *start_block;   /**< The start block of the current graph. */
+  ir_node *end_block;     /**< The end block of the current graph */
+  block_info *list;       /**< Links all block info entires for easier recovery. */
+  elim_pair *pairs;       /**< A list of node pairs that must be eliminated. */
+  char changes;           /**< Non-zero, if calculation of Antic_in has changed. */
+  char first_iter;        /**< non-zero for first iteration */
 } pre_env;
 
-/** The debug module handle. */
-static firm_dbg_module_t *dbg;
+/* ----------  Functions for Node sets ---------- */
+
+#define node_set_first(s)       pset_first(s)
+#define node_set_next(s)        pset_next(s)
+#define node_set_break(s)       pset_break(s)
+#define node_set_foreach(v, s)  for ((v) = node_set_first(s); (v); (v) = node_set_next(s))
 
 /**
- * returns non-zero if a node is movable.
+ * Creates a new node set.
  */
-static int is_nice_value(ir_node *n) {
-  ir_mode *mode = get_irn_mode(n);
+static node_set *new_node_set(void) {
+  return new_pset(identities_cmp, 8);
+}
 
-  if (!mode_is_data(mode))
-    return 0;
-  if (is_irn_constlike(n))
-    return 0;
-  return (get_irn_pinned(n) != op_pin_state_pinned);
+/**
+ * Deletes a node set.
+ */
+static void del_node_set(node_set *set) {
+  del_pset(set);
+}
+
+/**
+ * Add a node to the set.
+ */
+static ir_node *node_add(node_set *set, ir_node *node) {
+  return identify_remember(set, node);
+}
+
+/**
+ * Remove a node from a node set.
+ */
+static void node_set_remove(node_set *set, ir_node *node) {
+  pset_remove(set, node, ir_node_hash(node));
+}
+
+/**
+ * Return the number of entries in a node set.
+ */
+static int node_set_count(node_set *set) {
+  return pset_count(set);
+}
+
+#if 0
+/** computes dst = dst \/ src for node sets */
+static void node_union(node_set *dst, node_set *src)
+{
+  ir_node *entry;
+  node_set_foreach(entry, src) {
+    node_add(dst, entry);
+  }
+}
+#endif
+
+/**
+ * Lookup a node in a node set.
+ */
+static ir_node *node_lookup(node_set *set, ir_node *n)
+{
+  return pset_find(set, n, ir_node_hash(n));
+}
+
+
+/* ----------  Functions for Value sets ---------- */
+
+#define value_set_foreach(v, s) for ((v) = set_first(s); (v); (v) = set_next(s))
+
+/**
+ * calculate a hash value for a value represented by a node
+ */
+static unsigned value_hash(ir_node *value) {
+  return ir_node_hash(value);
+}
+
+/**
+ * Compare two value entries.
+ */
+static int value_cmp(const void *elt, const void *key, size_t size)
+{
+  const value_entry *e1 = elt;
+  const value_entry *e2 = key;
+  (void) size;
+
+  return identities_cmp(e1->value, e2->value);
+}
+
+/** Create a new value set. */
+static value_set *new_value_set(void) {
+  return new_set(value_cmp, 8);
+}
+
+/** Deletes a value set. */
+static void del_value_set(value_set *set) {
+  del_set(set);
+}
+
+/**
+ * Add a node node representing the value value to the set.
+ */
+static value_entry *value_add(value_set *set, ir_node *node, ir_node *value)
+{
+  value_entry key;
+  key.node  = node;
+  key.value = value;
+  return set_insert(set, &key, sizeof(key), value_hash(value));
+}
+
+/** computes dst = dst \/ src for value sets */
+static void value_union(value_set *dst, value_set *src)
+{
+  value_entry *entry;
+  value_set_foreach(entry, src)
+    value_add(dst, entry->node, entry->value);
+}
+
+/** computes dst = dst \/ (value_set)src for value sets */
+static void value_union_nodes(value_set *dst, node_set *src)
+{
+  ir_node *n;
+  node_set_foreach(n, src)
+    value_add(dst, n, n);
 }
 
-#define pset_foreach(v, s)  for ((v) = pset_first(s); (v); (v) = pset_next(s))
+/**
+ * Lookup a value in a value set.
+ */
+static ir_node *value_lookup(value_set *value_set, ir_node *n)
+{
+  value_entry key, *e;
 
-typedef unsigned (*HASH_FUNC)(void *);
+  key.value = n;
+  e = set_find(value_set, &key, sizeof(key), value_hash(n));
+  return e ? e->node : NULL;
+}
 
-/** computes dst = dst \/ src */
-static void pset_union(pset *dst, pset *src, HASH_FUNC hash)
+/**
+ * Add or replace a value in a set by an node computing the same
+ * value in a dominator block.
+ *
+ * @return non-zero if a replacement took place
+ */
+static int value_add_or_replace(value_set *set, ir_node *node, ir_node *value)
 {
-  void *entry;
+  value_entry *e = value_add(set, node, value);
+
+  if (e->node != node) {
+    /* node must dominate old one here */
+    assert(block_dominates(get_nodes_block(node), get_nodes_block(e->node)));
 
-  pset_foreach(entry, src) {
-    pset_insert(dst, entry, hash(entry));
+    e->node = node;
+    return 1;
   }
+  return 0;
 }
 
-#define pset_union(d, s)  pset_union(d, s, (HASH_FUNC)ir_node_hash)
+/**
+ * Returns non-zero if a node is movable.
+ */
+static int is_nice_value(ir_node *n) {
+  ir_mode *mode;
+
+  while (is_Proj(n))
+    n = get_Proj_pred(n);
+  mode = get_irn_mode(n);
+  /*
+   * FIXME: For now, we cannot handle Div/even if it's movable.
+   * That should be fixed.
+   */
+  if (!mode_is_data(mode))
+    return 0;
+  if (is_irn_constlike(n))
+    return 0;
+  return (get_irn_pinned(n) != op_pin_state_pinned);
+}
 
 #ifdef DEBUG_libfirm
 /**
- * Dump the Avail or Antic sets
+ * Dump a set.
  */
-static void dump_set(pset *set, char *txt, ir_node *block)
+static void dump_node_set(node_set *set, char *txt, ir_node *block)
 {
   ir_node *n;
   int i;
 
   DB((dbg, LEVEL_2, "%s(%+F) = {\n", txt, block));
   i = 0;
-  pset_foreach(n, set) {
+  node_set_foreach(n, set) {
     if ((i & 3) == 3)
       DB((dbg, LEVEL_2, "\n"));
     DB((dbg, LEVEL_2, " %+F,", n));
@@ -101,8 +295,31 @@ static void dump_set(pset *set, char *txt, ir_node *block)
   DB((dbg, LEVEL_2, "\n}\n"));
 }  /* dump_set */
 
+/**
+ * Dump a value set.
+ */
+static void dump_value_set(value_set *set, char *txt, ir_node *block)
+{
+  value_entry *e;
+  int i;
+
+  DB((dbg, LEVEL_2, "%s(%+F) = {\n", txt, block));
+  i = 0;
+  value_set_foreach(e, set) {
+    if ((i & 3) == 3)
+      DB((dbg, LEVEL_2, "\n"));
+    if (e->node != e->value)
+      DB((dbg, LEVEL_2, " %+F(%+F),", e->node, e->value));
+    else
+      DB((dbg, LEVEL_2, " %+F,", e->node));
+    ++i;
+  }
+  DB((dbg, LEVEL_2, "\n}\n"));
+}  /* dump_set */
+
 #else
-#define dump_set(set, txt, block)
+#define dump_node_set(set, txt, block)
+#define dump_value_set(set, txt, block)
 #endif /* DEBUG_libfirm */
 
 
@@ -114,7 +331,7 @@ static block_info *get_block_info(ir_node *block) {
 }
 
 /**
- * computes Avail_out(block):
+ * Computes Avail_out(block):
  *
  * Avail_in(block)  = Avail_out(dom(block))
  * Avail_out(block) = Avail_in(block) \/ Nodes(block)
@@ -134,9 +351,11 @@ static void compute_avail_top_down(ir_node *block, void *ctx)
   if (block == env->end_block)
     return;
 
-  pset_union(info->avail_out, info->nodes);
-
-  /* the root has no dominator */
+  /*
+   * First add all nodes from the dominator.
+   * This must be done to ensure that Antic_out contains the leader
+   * for every node. The root has no dominator.
+   */
   if (block != env->start_block) {
     dom_blk = get_Block_idom(block);
     assert(is_Block(dom_blk));
@@ -144,31 +363,147 @@ static void compute_avail_top_down(ir_node *block, void *ctx)
     dom_info = get_block_info(dom_blk);
     assert(dom_info);
 
-    pset_union(info->avail_out, dom_info->avail_out);
+    value_union(info->avail_out, dom_info->avail_out);
   }
-  dump_set(info->avail_out, "Avail_out", block);
+  value_union_nodes(info->avail_out, info->nodes);
+
+  dump_value_set(info->avail_out, "Avail_out", block);
 }
 
-/*
- * Implement phi_translate
+/**
+ * returns non-zero if a tree node must be copied because of
+ * a phi_translate.
  */
-static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, pre_env *env)
+static int need_copy(ir_node *node, ir_node *block)
 {
-  ir_node *pred_block;
+  int i, arity;
+
+  /* Phi always stop the recursion */
+  if (is_Phi(node))
+    return get_irn_intra_n(node, -1) == block;
+
+  if (! is_nice_value(node))
+    return 0;
+
+  /* check predecessor */
+  arity = get_irn_intra_arity(node);
+  for (i = 0; i < arity; ++i) {
+    ir_node *pred     = get_irn_intra_n(node, i);
+    ir_node *local_bl = get_irn_intra_n(pred, -1);
+    ir_node *leader   = value_lookup(get_block_info(local_bl)->avail_out, pred);
+
+    pred = leader != NULL ? leader : pred;
+    if (need_copy(pred, block))
+      return 1;
+  }
+  return 0;
+}
+
+/**
+ * Translate a node
+ */
+static ir_node *translate(ir_node *node, ir_node *block, int pos, pre_env *env)
+{
+  int i, arity, need_new;
+  ir_node *res, *nn, **in;
+
+  /* Phi always stop the recursion */
+  if (is_Phi(node)) {
+    if (get_irn_intra_n(node, -1) == block)
+      return get_Phi_pred(node, pos);
+    return node;
+  }
+
+  if (! is_nice_value(node))
+    return node;
+
+  arity = get_irn_intra_arity(node);
+  if (arity > 0) {
+    NEW_ARR_A(ir_node *, in, arity);
+    i = arity - 1;
+    need_new = 0;
+    do {
+      ir_node *pred = get_irn_intra_n(node, i);
+      ir_node *pred_blk = get_irn_intra_n(pred, -1);
+      ir_node *leader = value_lookup(get_block_info(pred_blk)->avail_out, pred);
+      in[i] = translate(leader ? leader : pred, block, pos, env);
+      need_new |= (in[i] != pred);
+      --i;
+    } while(i >= 0);
+    if (! need_new)
+      return node;
+
+    /* create a copy */
+    nn = new_ir_node(
+          get_irn_dbg_info(node),
+          current_ir_graph,
+          get_Block_cfgpred_block(block, pos),
+          get_irn_op(node),
+          get_irn_mode(node),
+          arity,
+          in);
+    /* We need the attribute copy here, because the Hash value of a
+       node might depend on that. */
+    copy_node_attr(node, nn);
+    res = node_add(env->trans_set, nn);
+    if (nn != res)
+      obstack_free(env->obst, nn);
+    else
+      DB((dbg, LEVEL_2, "--> Translate %+F in <%+F,%d> into %+F\n", node, block, pos, res));
+    return res;
+  }
+  return node;
+}
+
+#if 0
+/**
+ * Implements phi_translate.
+ */
+static ir_node *deep_phi_translate(ir_node *node, ir_node *block, int pos, pre_env *env)
+{
+  struct obstack *old;
   ir_node *res;
-  int i, arity = get_irn_intra_arity(node);
+
+  if (! need_copy(node, block))
+    return node;
+
+  /* Create a copy of the node in the pos'th predecessor block.
+     Use our environmental obstack, as these nodes are always
+     temporary. */
+  old = current_ir_graph->obst;
+  current_ir_graph->obst = env->obst;
+  res = translate(node, block, pos, env);
+  current_ir_graph->obst = old;
+
+  return res;
+}  /* phi_translate */
+#endif
+
+/**
+ * Implements phi_translate.
+ */
+static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, pre_env *env)
+{
+  ir_node *nn, *res;
+  int i, arity;
   struct obstack *old;
 
   if (is_Phi(node)) {
-    if (get_nodes_block(node) == block)
+    if (get_irn_intra_n(node, -1) == block)
       return get_Phi_pred(node, pos);
     return node;
   }
 
+  arity = get_irn_intra_arity(node);
+
   /* check if the node has at least one Phi predecessor */
   for (i = 0; i < arity; ++i) {
-    ir_node *phi = get_irn_intra_n(node, i);
-    if (is_Phi(phi) && get_nodes_block(phi) == block)
+    ir_node *pred    = get_irn_intra_n(node, i);
+    ir_node *pred_bl = get_irn_intra_n(pred, -1);
+    ir_node *leader  = value_lookup(get_block_info(pred_bl)->avail_out, pred);
+
+    leader = leader != NULL ? leader : pred;
+    if (is_Phi(leader) && get_irn_intra_n(pred, -1) == block)
       break;
   }
   if (i >= arity) {
@@ -176,41 +511,116 @@ static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, pre_env *e
     return node;
   }
 
-  pred_block = get_Block_cfgpred_block(block, pos);
-
   /* Create a copy of the node in the pos'th predecessor block.
      Use our environmental obstack, as these nodes are always
      temporary. */
   old = current_ir_graph->obst;
   current_ir_graph->obst = env->obst;
-  res   = new_ir_node(
-            get_irn_dbg_info(node),
-            current_ir_graph,
-            pred_block,
-            get_irn_op(node),
-            get_irn_mode(node),
-            arity,
-            get_irn_in(node));
+  nn = new_ir_node(
+          get_irn_dbg_info(node),
+          current_ir_graph,
+          NULL,
+          get_irn_op(node),
+          get_irn_mode(node),
+          arity,
+          get_irn_in(node));
   /* We need the attribute copy here, because the Hash value of a
      node might depend on that. */
-  copy_node_attr(node, res);
-  current_ir_graph->obst = old;
+  copy_node_attr(node, nn);
 
-  for (i = -1; i < arity; ++i) {
-    ir_node *pred = get_irn_intra_n(node, i);
+  set_irn_n(nn, -1, get_irn_intra_n(node, -1));
+  for (i = 0; i < arity; ++i) {
+    ir_node *pred    = get_irn_intra_n(node, i);
+    ir_node *pred_bl = get_irn_intra_n(pred, -1);
+    ir_node *leader  = value_lookup(get_block_info(pred_bl)->avail_out, pred);
 
-    if (! is_Phi(pred))
-      set_irn_n(res, i, pred);
+    leader = leader != NULL ? leader : pred;
+    if (is_Phi(leader) && get_irn_intra_n(pred, -1) == block)
+      set_irn_n(nn, i, get_Phi_pred(leader, pos));
     else
-      set_irn_n(res, i, get_Phi_pred(pred, pos));
+      set_irn_n(nn, i, leader);
   }
-  set_irn_link(res, NULL);
+  res = node_add(env->trans_set, nn);
+  current_ir_graph->obst = old;
+
+  if (nn != res)
+    obstack_free(env->obst, nn);
+  else {
+    DB((dbg, LEVEL_2, "--> Translate %+F in <%+F,%d> into %+F\n", node, block, pos, res));
+  }
+  return res;
+}  /* phi_translate */
+
+/**
+ * check if a node n is clean in block block.
+ */
+static int _is_clean(ir_node *n, ir_node *block)
+{
+  int i;
+
+  if (get_nodes_block(n) != block)
+    return 1;
+  if (is_Phi(n))
+    return 1;
+
+  if (irn_visited(n))
+    return 0;
+
+  if (! is_nice_value(n))
+    goto bad;
+  for (i = get_irn_arity(n) - 1; i >= 0; --i) {
+    ir_node *pred = get_irn_n(n, i);
+    if (! _is_clean(pred, block))
+      goto bad;
+  }
+  return 1;
+bad:
+  mark_irn_visited(n);
+  return 0;
+}
+
+/**
+ * check if a node n is clean.
+ */
+static int is_clean(ir_node *n)
+{
+  int res = _is_clean(n, get_nodes_block(n));
   return res;
 }
 
+/**
+ * Clean a node set.
+ * This function is called for node sets with is_clean
+ * nodes only, so we must just remove nodes that don't
+ * have available inputs
+ */
+static void clean_node_set(node_set *set, ir_node *blk)
+{
+  ir_node *n, *pred, *pred_blk;
+  int i;
+
+restart:
+  for (n = node_set_first(set); n; n = node_set_next(set)) {
+    for (i = get_irn_intra_arity(n) - 1; i >= 0; --i) {
+      pred = get_irn_intra_n(n, i);
+
+      pred_blk = get_irn_intra_n(pred, -1);
+      if (block_dominates(pred_blk, blk))
+        continue;
+      /* pred do not dominate it, but may be in the set */
+      if (node_lookup(set, pred) != NULL)
+        continue;
+      /* we found a node that must be removed */
+      node_set_break(set);
+      node_set_remove(set, n);
+      DB((dbg, LEVEL_2, "<-- Cleaning %+F\n", n));
+      goto restart;
+    }
+  }
+}
+
 /**
  * computes Antic_in(block):
- *
  */
 static void compute_antic(ir_node *block, void *ctx)
 {
@@ -224,18 +634,15 @@ static void compute_antic(ir_node *block, void *ctx)
   if (block == env->start_block)
     return;
 
-  size = pset_count(info->antic_in);
+  size = node_set_count(info->antic_in);
 
-  /* the root has no dominator */
+  /* the end block has no successor */
   if (block != env->end_block) {
     int n_succ = get_Block_n_cfg_outs(block);
 
     if (n_succ == 1) {
-      ir_node *node;
+      ir_node *node, *list;
       int i, pos = -1;
-      pset *nodes = new_pset(identities_cmp, 8);
-
-      pset_union(nodes, info->nodes);
 
       /* find blocks position in succ's block predecessors */
       succ = get_Block_cfg_out(block, 0);
@@ -248,26 +655,20 @@ static void compute_antic(ir_node *block, void *ctx)
       assert(pos >= 0);
 
       succ_info = get_block_info(succ);
-      for (node = pset_first(succ_info->antic_in);
-           node;
-           node = pset_next(succ_info->antic_in)) {
+      /* translate into list: we cannot insert into a set we iterate
+       * and succ might be equal to block for endless loops */
+      list = NULL;
+      node_set_foreach(node, succ_info->antic_in) {
+        set_irn_link(node, list);
+        list = node;
+      }
+      for (node = list; node; node = get_irn_link(node)) {
         ir_node *trans = phi_translate(node, succ, pos, env);
 
-        identify_remember(nodes, trans);
-
-        /* add all predecessors of node */
-        for (i = get_irn_arity(node) - 1; i >= 0; --i) {
-          ir_node *pred = get_irn_n(node, i);
-          ir_node *trans = phi_translate(pred, succ, pos, env);
-
-          if (is_nice_value(trans))
-            identify_remember(nodes, trans);
-        }
+        if (is_clean(trans))
+          node_add(info->antic_in, trans);
       }
-     /* this step calculates Antic_in(b) = Antic_out(b) \/ Nodes(b) */
-     pset_union(info->antic_in, nodes);
-     del_pset(nodes);
-   }
+    }
     else {
       ir_node *n, *succ0;
       block_info *succ0_info;
@@ -281,32 +682,44 @@ static void compute_antic(ir_node *block, void *ctx)
          first one. */
       succ0 = get_Block_cfg_out(block, 0);
       succ0_info = get_block_info(succ0);
-      for (n = pset_first(succ0_info->antic_in);
-           n;
-           n = pset_next(succ0_info->antic_in)) {
+      node_set_foreach(n, succ0_info->antic_in) {
         /* we need the disjoint */
         for (i = 1; i < n_succ; ++i) {
           ir_node *succ = get_Block_cfg_out(block, i);
           block_info *succ_info = get_block_info(succ);
-          if (pset_find(succ_info->antic_in, n, ir_node_hash(n)) == NULL)
+          if (node_lookup(succ_info->antic_in, n) == NULL)
             break;
         }
         if (i >= n_succ) {
           /* we found a node that is common in all Antic_in(succ(b)),
              put it in Antic_in(b) */
-          identify_remember(info->antic_in, n);
+          node_add(info->antic_in, n);
         }
       }
-      /* this step calculates Antic_in(b) = Antic_out(b) \/ Nodes(b) */
-      pset_union(info->antic_in, info->nodes);
+    }
+
+    /*
+     * This step calculates Antic_in(b) = Antic_out(b) \/ Nodes(b).
+     * It is enough to do this in the first iteration, because
+     * the set info->nodes is not changed anymore.
+     */
+    if (env->first_iter) {
+      ir_node *n;
+      node_set_foreach(n, info->nodes) {
+        if (is_clean(n))
+          node_add(info->antic_in, n);
+      }
     }
   }
 
-  if (size != pset_count(info->antic_in))
+//  clean_node_set(info->antic_in, block);
+  (void) clean_node_set;
+
+  dump_node_set(info->antic_in, "Antic_in", block);
+  if (size != node_set_count(info->antic_in)) {
     /* the Antic_in set has changed */
     env->changes |= 1;
-
-  dump_set(info->antic_in, "Antic_in", block);
+  }
 }  /* compute_antic */
 
 /**
@@ -316,76 +729,28 @@ static void alloc_blk_info(ir_node *block, void *ctx)
 {
   int i;
   pre_env *env = ctx;
-  block_info *info = obstack_alloc(env->obst, sizeof(block_info));
+  block_info *info = obstack_alloc(env->obst, sizeof(*info));
 
   set_irn_link(block, info);
-  info->nodes     = new_pset(identities_cmp, 8);
-  info->antic_in  = new_pset(identities_cmp, 8);
-  info->avail_out = new_pset(identities_cmp, 8);
+  info->nodes     = new_node_set();
+  info->antic_in  = new_node_set();
+  info->avail_out = new_value_set();
   info->avail     = NULL;
   info->not_found = 0;
   info->new_set   = NULL;
   info->next      = env->list;
-  env->list       = info->next;
+  env->list       = info;
 
   /* fill the nodes set, we will need it later */
   for (i = get_irn_n_outs(block) - 1; i >= 0; --i) {
     ir_node *n = get_irn_out(block, i);
 
-    /* clear the link field here, we need it later */
     set_irn_link(n, NULL);
 
     /* we cannot optimize pinned nodes, so do not remember them */
     if (is_nice_value(n))
-      identify_remember(info->nodes, n);
-    else if (is_Phi(n) && get_irn_mode(n) != mode_M) {
-      /*
-       * Phis are "temporaries" and must be handled special:
-       * They are avail, but are not in Antic_in
-       */
-      identify_remember(info->avail_out, n);
-    }
-  }
-}
-
-/**
- * Compare two nodes for equal operands.
- */
-static int operands_equal(ir_node *n1, ir_node *n2)
-{
-  int i, arity = get_irn_arity(n1);
-  assert(n1->op == n2->op && arity == get_irn_arity(n2));
-  for (i = 0; i < arity; ++i)
-    if (get_irn_n(n1, i) != get_irn_n(n2, i))
-      return 0;
-  return 1;
-}
-
-/**
- * Get the leader of an expression. In Firm, only
- * Phi nodes can be leaders, all other 'leader' are
- * handled by the identify_remember mechanism right.
- */
-static ir_node *find_leader(ir_node *n)
-{
-  ir_node *l = get_irn_link(n);
-
-  if (l) {
-    assert(is_Phi(l));
-    return l;
+      node_add(info->nodes, n);
   }
-  return n;
-}
-
-static ir_node *has_leader(ir_node *n)
-{
-  ir_node *l = get_irn_link(n);
-
-  if (l) {
-    assert(is_Phi(l));
-    return l;
-  }
-  return NULL;
 }
 
 /**
@@ -404,13 +769,17 @@ static ir_node *has_leader(ir_node *n)
 static void insert_nodes(ir_node *block, void *ctx)
 {
   pre_env *env = ctx;
-  ir_node *v, *idom, *first_s;
+  value_entry *entry;
+  ir_node *e, *idom, *first_s, *worklist;
   block_info *curr_info, *idom_info;
   int pos, arity = get_irn_intra_arity(block);
-  int all_same, by_some;
+  int all_same, by_some, updated;
 
+  /* ensure that even the start block has a new_set */
   curr_info = get_block_info(block);
-  curr_info->new_set = new_pset(identities_cmp, 8);
+  if (curr_info->new_set)
+    del_value_set(curr_info->new_set);
+  curr_info->new_set = new_value_set();
 
   if (block == env->start_block)
     return;
@@ -419,73 +788,73 @@ static void insert_nodes(ir_node *block, void *ctx)
   idom_info = get_block_info(idom);
 
   /* update the new_sets */
-  pset_union(curr_info->new_set, idom_info->new_set);
-  pset_foreach(v, idom_info->new_set) {
-    ir_node *old = identify_remember(idom_info->new_set, v);
-
-    if (old != v) {
-      /* v must dominate old here */
-      assert(block_dominates(get_nodes_block(v), get_nodes_block(old)));
-
-      pset_remove(curr_info->avail_out, old, ir_node_hash(old));
-      identify_remember(curr_info->avail_out, v);
-    }
+  updated = 0;
+  dump_value_set(idom_info->new_set, "[New Set]", idom);
+  value_set_foreach(entry, idom_info->new_set) {
+    updated |= value_add_or_replace(curr_info->avail_out, entry->node, entry->value);
   }
-  dump_set(curr_info->avail_out, "[Avail_out]", block);
+  if (updated)
+    dump_value_set(curr_info->avail_out, "Updated [Avail_out]", block);
 
   if (arity <= 1)
     return;
 
-  pset_foreach(v, curr_info->antic_in) {
-    /*
-     * If we already have a leader for this node,
-     * it is totally redundant.
-     */
-    if (has_leader(v))
-      continue;
+  /* convert the set into a list. This allows the removal of
+   * elements from the set */
+  worklist = NULL;
+  node_set_foreach(e, curr_info->antic_in) {
+    set_irn_link(e, worklist);
+    worklist = e;
+  }
+
+  for (e = worklist; e != NULL; e = get_irn_link(e)) {
+    ir_mode *mode;
 
     /* If the value was already computed in the dominator, then
        it is totally redundant.  Hence we have nothing to insert. */
-    if (pset_find(idom_info->avail_out, v, ir_node_hash(v))) {
+    if (value_lookup(idom_info->avail_out, e)) {
 //      DB((dbg, LEVEL_2, "Found %+F from block %+F avail in dom %+F\n", v, block, idom));
       continue;
     }
 
-    all_same = 1;
     by_some  = 0;
+    all_same = 1;
     first_s  = NULL;
+    mode     = NULL;
 
     /* for all predecessor blocks */
     for (pos = 0; pos < arity; ++pos) {
       block_info *pred_info;
       ir_node *pred_blk = get_Block_cfgpred_block(block, pos);
-      ir_node *trans, *found;
+      ir_node *e_prime, *v_prime, *e_dprime;
 
       /* ignore bad blocks. */
       if (is_Bad(pred_blk))
         continue;
 
-      trans = phi_translate(v, block, pos, env);
+      e_prime = phi_translate(e, block, pos, env);
+      v_prime = e_prime;
 
       pred_info = get_block_info(pred_blk);
-      found = pset_find(pred_info->avail_out, trans, ir_node_hash(trans));
+      e_dprime = value_lookup(pred_info->avail_out, v_prime);
 
-      if (found == NULL) {
+      if (e_dprime == NULL) {
         all_same = 0;
-        pred_info->avail = trans;
+        pred_info->avail = e_prime;
         pred_info->not_found = 1;
       }
       else {
-        found = find_leader(found);
-        pred_info->avail = found;
+        mode     = get_irn_mode(e_dprime);
+        e_dprime = e_dprime;
+        pred_info->avail = e_dprime;
         pred_info->not_found = 0;
         by_some = 1;
         if (first_s == NULL)
-          first_s = found;
-        else if (first_s != found)
+          first_s = e_dprime;
+        else if (first_s != e_dprime)
           all_same = 0;
 
-        DB((dbg, LEVEL_2, "Found %+F from block %+F as %+F in pred %+F\n", v, block, found, pred_blk));
+        DB((dbg, LEVEL_2, "Found %+F from block %+F as %+F in pred %+F\n", e, block, e_dprime, pred_blk));
       }  /* if */
     }  /* for */
 
@@ -493,8 +862,8 @@ static void insert_nodes(ir_node *block, void *ctx)
        it's defined by some predecessor, it is partially redundant. */
     if (! all_same && by_some) {
       ir_node *phi, **in;
-      ir_mode *mode = NULL;
-      DB((dbg, LEVEL_1, "Partial redundant %+F from block %+F found\n", v, block));
+
+      DB((dbg, LEVEL_1, "Partial redundant %+F from block %+F found\n", e, block));
 
       in = xmalloc(arity * sizeof(*in));
       /* for all predecessor blocks */
@@ -510,73 +879,131 @@ static void insert_nodes(ir_node *block, void *ctx)
 
         /* ignore blocks that already have the expression */
         if (pred_info->not_found) {
-          ir_node *avail = pred_info->avail;
+          ir_node *e_prime = pred_info->avail;
           ir_node *nn;
-          assert(! is_Phi(avail));
-
-          mode = get_irn_mode(avail);
-          nn = new_ir_node(
-            get_irn_dbg_info(avail),
-            current_ir_graph, pred_blk,
-            get_irn_op(avail),
-            mode,
-            get_irn_arity(avail),
-            get_irn_in(avail) + 1);
-
-          pred_info->avail = identify_remember(pred_info->avail_out, nn);
+          if (!is_Phi(e_prime)) {
+            mode = get_irn_mode(e_prime);
+            nn = new_ir_node(
+              get_irn_dbg_info(e_prime),
+              current_ir_graph, pred_blk,
+              get_irn_op(e_prime),
+              mode,
+              get_irn_arity(e_prime),
+              get_irn_in(e_prime) + 1);
+            copy_node_attr(e_prime, nn);
+
+            DB((dbg, LEVEL_2, "New node %+F in block %+F created\n", nn, pred_blk));
+            pred_info->avail = value_add(pred_info->avail_out, nn, e_prime)->node;
+          }
         }
         in[pos] = pred_info->avail;
       }  /* for */
       phi = new_r_Phi(current_ir_graph, block, arity, in, mode);
       free(in);
-      identify_remember(curr_info->avail_out, phi);
-      identify_remember(curr_info->new_set, phi);
-      /* v might be translated, so add it here */
-      identify_remember(curr_info->avail_out, v);
-      identify_remember(curr_info->new_set, v);
-      set_irn_link(v, phi);
-      DB((dbg, LEVEL_2, "New %+F for redundant %+F created\n", phi, v));
+      value_add_or_replace(curr_info->avail_out, phi, e);
+      value_add(curr_info->new_set, phi, e);
+      DB((dbg, LEVEL_2, "New %+F for redundant %+F created\n", phi, e));
+
+      /* the good case: we really replace an instruction */
+      node_set_remove(curr_info->antic_in, e);
+
       env->changes |= 1;
     }  /* if */
-  }  /* pset_foreach */
+  }  /* node_set_foreach */
 }  /* insert_nodes */
 
 /**
- * Do the elimination step
+ * Do the elimination step: collect all changes
+ * We cannot do the changes right here, as this would change
+ * the hash values of the nodes in the avail_out set!
  */
-static void eliminate_nodes(ir_node *block, void *ctx)
+static void collect_elim_pairs(ir_node *block, void *ctx)
 {
+  pre_env *env = ctx;
   block_info *curr_info = get_block_info(block);
   ir_node *v;
 
-  pset_foreach(v, curr_info->nodes) {
-    ir_node *l = identify_remember(curr_info->avail_out, v);
+  dump_node_set(curr_info->nodes, "Updating nodes", block);
+  node_set_foreach(v, curr_info->nodes) {
+    ir_node *l = value_lookup(curr_info->avail_out, v);
 
-    l = find_leader(l);
+    assert(l);
     if (l != v) {
-      DB((dbg, LEVEL_2, "Replacing %+F by %+F\n", v, l));
-      exchange(v, l);
+      elim_pair *p = obstack_alloc(env->obst, sizeof(*p));
+
+      p->old_node = v;
+      p->new_node = l;
+      p->next     = env->pairs;
+      env->pairs  = p;
+    }
+  }
+}
+
+/**
+ * Do all the recorded changes and optimize
+ * newly created Phi's.
+ */
+static void eliminate_nodes(elim_pair *pairs)
+{
+  elim_pair *p;
+
+  for (p = pairs; p != NULL; p = p->next) {
+    DB((dbg, LEVEL_2, "Replacing %+F by %+F\n", p->old_node, p->new_node));
+    /*
+     * PRE tends to create Phi(self, self, ... , x, self, self, ...)
+     * which we can optimize here
+     */
+    if (is_Phi(p->new_node)) {
+      int i;
+      ir_node *res = NULL;
+
+      for (i = get_irn_intra_arity(p->new_node) - 1; i >= 0; --i) {
+        ir_node *pred = get_irn_n(p->new_node, i);
+
+        if (pred != p->old_node) {
+          if (res) {
+            res = NULL;
+            break;
+          }
+          res = pred;
+        }
+      }
+      if (res)
+        p->new_node = res;
     }
+    exchange(p->old_node, p->new_node);
   }
 }
 
+/*
+ * Argh: Endless loops cause problems, because the
+ * insert algorithm did not terminate. We get translated nodes that
+ * references the origin. These nodes are translated again and again...
+ *
+ * The current fix is to use post-dominance. This simple ignores
+ * endless loops, ie we cannot optimize them.
+ */
 void do_gvn_pre(ir_graph *irg)
 {
   struct obstack obst;
   pre_env a_env;
   optimization_state_t state;
   block_info *p;
-  int iter = 0;
+  unsigned antic_iter, insert_iter;
+
+  assert(!"COMPLETELY BROKEN YET, DO NOT USE");
 
   /* register a debug mask */
-  dbg = firm_dbg_register("firm.opt.gvn_pre");
+  FIRM_DBG_REGISTER(dbg, "firm.opt.gvn_pre");
   firm_dbg_set_mask(dbg, SET_LEVEL_2);
 
   obstack_init(&obst);
   a_env.obst        = &obst;
+  a_env.trans_set   = new_node_set();
   a_env.list        = NULL;
   a_env.start_block = get_irg_start_block(irg);
   a_env.end_block   = get_irg_end_block(irg);
+  a_env.pairs       = NULL;
 
   /* Move Proj's into the same block as their args,
      else we would assign the result to wrong blocks */
@@ -585,11 +1012,12 @@ void do_gvn_pre(ir_graph *irg)
   /* critical edges MUST be removed */
   remove_critical_cf_edges(irg);
 
-  /* we need dominator AND post dominator information */
+  /* we need dominator for Antic_out calculation */
   if (get_irg_dom_state(irg) != dom_consistent)
     compute_doms(irg);
   if (get_irg_postdom_state(irg) != dom_consistent)
     compute_postdoms(irg);
+  /* we get all nodes of a block by following outs */
   if (get_irg_outs_state(irg) != outs_consistent)
     compute_irg_outs(irg);
 
@@ -600,6 +1028,9 @@ void do_gvn_pre(ir_graph *irg)
   save_optimization_state(&state);
   set_opt_global_cse(1);
 
+  DB((dbg, LEVEL_1, "Doing GVN-PRE for %e\n", get_irg_entity(irg)));
+  printf("Doing GVN-PRE for %s\n", get_entity_name(get_irg_entity(irg)));
+
   /* allocate block info for all blocks */
   irg_block_walk_graph(irg, NULL, alloc_blk_info, &a_env);
 
@@ -607,36 +1038,50 @@ void do_gvn_pre(ir_graph *irg)
   dom_tree_walk_irg(irg, compute_avail_top_down, NULL, &a_env);
 
   /* compute the anticipated value sets for all blocks */
+  inc_irg_visited(irg);
+  antic_iter = 0;
+  a_env.first_iter = 1;
   do {
-    DB((dbg, LEVEL_1, "Antic_in Iteration %d starts ...\n", ++iter));
+    DB((dbg, LEVEL_1, "Antic_in Iteration %d starts ...\n", ++antic_iter));
     a_env.changes = 0;
     irg_block_walk_graph(irg, compute_antic, NULL, &a_env);
 //    postdom_tree_walk_irg(irg, compute_antic, NULL, &a_env);
+    a_env.first_iter = 0;
     DB((dbg, LEVEL_1, "------------------------\n"));
   } while (a_env.changes != 0);
 
   /* compute redundant expressions */
-  iter = 0;
+  insert_iter = 0;
   do {
-    DB((dbg, LEVEL_1, "Insert Iteration %d starts ...\n", ++iter));
+    DB((dbg, LEVEL_1, "Insert Iteration %d starts ...\n", ++insert_iter));
     a_env.changes = 0;
     dom_tree_walk_irg(irg, insert_nodes, NULL, &a_env);
     DB((dbg, LEVEL_1, "------------------------\n"));
   } while (a_env.changes != 0);
 
   /* last step: eliminate nodes */
-  dom_tree_walk_irg(irg, eliminate_nodes, NULL, &a_env);
+  dom_tree_walk_irg(irg, collect_elim_pairs, NULL, &a_env);
+  eliminate_nodes(a_env.pairs);
 
   restore_optimization_state(&state);
 
   /* clean up: delete all sets */
   for (p = a_env.list; p != NULL; p = p->next) {
     if (p->antic_in)
-      del_pset(p->antic_in);
+      del_node_set(p->antic_in);
     if (p->avail_out)
-      del_pset(p->avail_out);
+      del_value_set(p->avail_out);
     if (p->nodes)
-      del_pset(p->nodes);
+      del_node_set(p->nodes);
+    if (p->new_set)
+      del_value_set(p->new_set);
   }
+  del_node_set(a_env.trans_set);
   obstack_free(&obst, NULL);
+  set_irg_pinned(irg, op_pin_state_pinned);
+
+  if (a_env.pairs) {
+    set_irg_outs_inconsistent(irg);
+    set_irg_loopinfo_inconsistent(irg);
+  }
 }  /* do_gvn_pre */