fixed equivalent_node_Quot()
[libfirm] / ir / ir / irgopt.c
index 4ab6a0b..47d00d6 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "array.h"
 #include "pset.h"
+#include "pmap.h"
 #include "eset.h"
 #include "pdeq.h"       /* Fuer code placement */
 #include "xmalloc.h"
 #include "cgana.h"
 #include "trouts.h"
 
+
 #include "irflag_t.h"
 #include "irhooks.h"
 #include "iredges_t.h"
 #include "irtools.h"
 
-/* Defined in iropt.c */
-pset *new_identities (void);
-void  del_identities (pset *value_table);
-void  add_identities   (pset *value_table, ir_node *node);
-
 /*------------------------------------------------------------------*/
 /* apply optimizations of iropt to all nodes.                       */
 /*------------------------------------------------------------------*/
 
-static void init_link (ir_node *n, void *env) {
-  set_irn_link(n, NULL);
-}
-
-#if 0   /* Old version. Avoids Ids.
-           This is not necessary:  we do a post walk, and get_irn_n
-           removes ids anyways.  So it's much cheaper to call the
-           optimization less often and use the exchange() algorithm. */
-static void
-optimize_in_place_wrapper (ir_node *n, void *env) {
-  int i, irn_arity;
-  ir_node *optimized, *old;
-
-  irn_arity = get_irn_arity(n);
-  for (i = 0; i < irn_arity; i++) {
-    /* get_irn_n skips Id nodes, so comparison old != optimized does not
-       show all optimizations. Therefore always set new predecessor. */
-    old = get_irn_intra_n(n, i);
-    optimized = optimize_in_place_2(old);
-    set_irn_n(n, i, optimized);
-  }
-
-  if (get_irn_op(n) == op_Block) {
-    optimized = optimize_in_place_2(n);
-    if (optimized != n) exchange (n, optimized);
-  }
-}
-#else
-static void
-optimize_in_place_wrapper (ir_node *n, void *env) {
+/**
+ * A wrapper around optimize_inplace_2() to be called from a walker.
+ */
+static void optimize_in_place_wrapper (ir_node *n, void *env) {
   ir_node *optimized = optimize_in_place_2(n);
   if (optimized != n) exchange (n, optimized);
 }
-#endif
-
 
+/**
+ * Do local optimizations for a node.
+ *
+ * @param n  the IR-node where to start. Typically the End node
+ *           of a graph
+ *
+ * @note current_ir_graph must be set
+ */
 static INLINE void do_local_optimize(ir_node *n) {
   /* Handle graph state */
   assert(get_irg_phase_state(current_ir_graph) != phase_building);
 
   if (get_opt_global_cse())
     set_irg_pinned(current_ir_graph, op_pin_state_floats);
-  if (get_irg_outs_state(current_ir_graph) == outs_consistent)
-    set_irg_outs_inconsistent(current_ir_graph);
+  set_irg_outs_inconsistent(current_ir_graph);
   set_irg_doms_inconsistent(current_ir_graph);
   set_irg_loopinfo_inconsistent(current_ir_graph);
 
@@ -105,9 +81,10 @@ static INLINE void do_local_optimize(ir_node *n) {
   current_ir_graph->value_table = new_identities();
 
   /* walk over the graph */
-  irg_walk(n, init_link, optimize_in_place_wrapper, NULL);
+  irg_walk(n, firm_clear_link, optimize_in_place_wrapper, NULL);
 }
 
+/* Applies local optimizations (see iropt.h) to all nodes reachable from node n */
 void local_optimize_node(ir_node *n) {
   ir_graph *rem = current_ir_graph;
   current_ir_graph = get_irn_irg(n);
@@ -122,8 +99,13 @@ void local_optimize_node(ir_node *n) {
  */
 static void kill_dead_blocks(ir_node *block, void *env)
 {
-  if (get_Block_dom_depth(block) < 0)
+  if (get_Block_dom_depth(block) < 0) {
+    /*
+     * Note that the new dominance code correctly handles
+     * the End block, i.e. it is always reachable from Start
+     */
     set_Block_dead(block);
+  }
 }
 
 void
@@ -131,10 +113,78 @@ local_optimize_graph (ir_graph *irg) {
   ir_graph *rem = current_ir_graph;
   current_ir_graph = irg;
 
+  if (get_irg_dom_state(irg) == dom_consistent)
+    irg_block_walk_graph(irg, NULL, kill_dead_blocks, NULL);
+
+  do_local_optimize(get_irg_end(irg));
+
+  current_ir_graph = rem;
+}
+
+/**
+ * Data flow optimization walker.
+ */
+static void opt_walker(ir_node *n, void *env) {
+  pdeq *waitq = env;
+  ir_node *optimized;
+
+  optimized = optimize_in_place_2(n);
+  set_irn_link(optimized, NULL);
+
+  if (optimized != n) {
+    const ir_edge_t *edge;
+
+    foreach_out_edge(n, edge) {
+      ir_node *succ = get_edge_src_irn(edge);
+
+      if (get_irn_link(succ) != waitq) {
+        pdeq_putr(waitq, succ);
+        set_irn_link(succ, waitq);
+      }
+    }
+    exchange(n, optimized);
+  }
+}
+
+void optimize_graph_df(ir_graph *irg) {
+  pdeq     *waitq = new_pdeq();
+  int      state = edges_activated(irg);
+  ir_graph *rem = current_ir_graph;
+
+  current_ir_graph = irg;
+
+  if (! state)
+    edges_activate(irg);
+
+  if (get_opt_global_cse())
+    set_irg_pinned(current_ir_graph, op_pin_state_floats);
+
+  /* Clean the value_table in irg for the CSE. */
+  del_identities(irg->value_table);
+  irg->value_table = new_identities();
+
   if (get_irg_dom_state(current_ir_graph) == dom_consistent)
     irg_block_walk_graph(irg, NULL, kill_dead_blocks, NULL);
 
-  do_local_optimize(irg->end);
+  /* invalidate info */
+  set_irg_outs_inconsistent(irg);
+  set_irg_doms_inconsistent(irg);
+  set_irg_loopinfo_inconsistent(irg);
+
+  /* walk over the graph */
+  irg_walk_graph(irg, NULL, opt_walker, waitq);
+
+  /* finish the wait queue */
+  while (! pdeq_empty(waitq)) {
+    ir_node *n = pdeq_getl(waitq);
+    if (! is_Bad(n))
+      opt_walker(n, waitq);
+  }
+
+  del_pdeq(waitq);
+
+  if (! state)
+    edges_deactivate(irg);
 
   current_ir_graph = rem;
 }
@@ -250,6 +300,7 @@ static void copy_node(ir_node *n, void *env) {
 #endif
 
   set_new_node(n, nn);
+  hook_dead_node_elim_subst(current_ir_graph, n, nn);
 }
 
 /**
@@ -338,8 +389,14 @@ static void copy_graph(ir_graph *irg, int copy_node_nr) {
   ir_node *oe, *ne, *ob, *nb, *om, *nm; /* old end, new end, old bad, new bad, old NoMem, new NoMem */
   ir_node *ka;      /* keep alive */
   int i, irn_arity;
+  unsigned long vfl;
+
+  /* Some nodes must be copied by hand, sigh */
+  vfl = get_irg_visited(irg);
+  set_irg_visited(irg, vfl + 1);
 
   oe = get_irg_end(irg);
+  mark_irn_visited(oe);
   /* copy the end node by hand, allocate dynamic in array! */
   ne = new_ir_node(get_irn_dbg_info(oe),
            irg,
@@ -354,6 +411,7 @@ static void copy_graph(ir_graph *irg, int copy_node_nr) {
 
   /* copy the Bad node */
   ob = get_irg_bad(irg);
+  mark_irn_visited(ob);
   nb = new_ir_node(get_irn_dbg_info(ob),
            irg,
            NULL,
@@ -361,10 +419,12 @@ static void copy_graph(ir_graph *irg, int copy_node_nr) {
            mode_T,
            0,
            NULL);
+  copy_node_attr(ob, nb);
   set_new_node(ob, nb);
 
   /* copy the NoMem node */
   om = get_irg_no_mem(irg);
+  mark_irn_visited(om);
   nm = new_ir_node(get_irn_dbg_info(om),
            irg,
            NULL,
@@ -372,36 +432,52 @@ static void copy_graph(ir_graph *irg, int copy_node_nr) {
            mode_M,
            0,
            NULL);
+  copy_node_attr(om, nm);
   set_new_node(om, nm);
 
   /* copy the live nodes */
+  set_irg_visited(irg, vfl);
   irg_walk(get_nodes_block(oe), copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
+
+  /* Note: from yet, the visited flag of the graph is equal to vfl + 1 */
+
+  /* visit the anchors as well */
+  for (i = anchor_max - 1; i >= 0; --i) {
+    ir_node *n = irg->anchors[i];
+
+    if (n && (get_irn_visited(n) <= vfl)) {
+      set_irg_visited(irg, vfl);
+      irg_walk(n, copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
+    }
+  }
+
   /* copy_preds for the end node ... */
   set_nodes_block(ne, get_new_node(get_nodes_block(oe)));
 
   /*- ... and now the keep alives. -*/
   /* First pick the not marked block nodes and walk them.  We must pick these
      first as else we will oversee blocks reachable from Phis. */
-  irn_arity = get_irn_arity(oe);
+  irn_arity = get_End_n_keepalives(oe);
   for (i = 0; i < irn_arity; i++) {
-    ka = get_irn_intra_n(oe, i);
-    if (is_Block(ka) &&
-        (get_irn_visited(ka) < get_irg_visited(irg))) {
-      /* We must keep the block alive and copy everything reachable */
-      set_irg_visited(irg, get_irg_visited(irg)-1);
-      irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
+    ka = get_End_keepalive(oe, i);
+    if (is_Block(ka)) {
+      if (get_irn_visited(ka) <= vfl) {
+        /* We must keep the block alive and copy everything reachable */
+        set_irg_visited(irg, vfl);
+        irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
+      }
       add_End_keepalive(ne, get_new_node(ka));
     }
   }
 
   /* Now pick other nodes.  Here we will keep all! */
-  irn_arity = get_irn_arity(oe);
+  irn_arity = get_End_n_keepalives(oe);
   for (i = 0; i < irn_arity; i++) {
-    ka = get_irn_intra_n(oe, i);
+    ka = get_End_keepalive(oe, i);
     if (!is_Block(ka)) {
-      if (get_irn_visited(ka) < get_irg_visited(irg)) {
+      if (get_irn_visited(ka) <= vfl) {
         /* We didn't copy the node yet.  */
-        set_irg_visited(irg, get_irg_visited(irg)-1);
+        set_irg_visited(irg, vfl);
         irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
       }
       add_End_keepalive(ne, get_new_node(ka));
@@ -425,15 +501,19 @@ static void
 copy_graph_env (int copy_node_nr) {
   ir_graph *irg = current_ir_graph;
   ir_node *old_end, *n;
+  int i;
+
+  /* remove end_except and end_reg nodes */
+  old_end = get_irg_end(irg);
+  set_irg_end_except (irg, old_end);
+  set_irg_end_reg    (irg, old_end);
+
   /* Not all nodes remembered in irg might be reachable
      from the end node.  Assure their link is set to NULL, so that
      we can test whether new nodes have been computed. */
-  set_irn_link(get_irg_frame      (irg), NULL);
-  set_irn_link(get_irg_globals    (irg), NULL);
-  set_irn_link(get_irg_args       (irg), NULL);
-  set_irn_link(get_irg_initial_mem(irg), NULL);
-  set_irn_link(get_irg_bad        (irg), NULL);
-  set_irn_link(get_irg_no_mem     (irg), NULL);
+  for (i = anchor_max - 1; i >= 0; --i)
+    if (irg->anchors[i])
+      set_new_node(irg->anchors[i], NULL);
 
   /* we use the block walk flag for removing Bads from Blocks ins. */
   inc_irg_block_visited(irg);
@@ -443,50 +523,12 @@ copy_graph_env (int copy_node_nr) {
 
   /* fix the fields in irg */
   old_end = get_irg_end(irg);
-  set_irg_end        (irg, get_new_node(old_end));
-  set_irg_end_except (irg, get_irg_end(irg));
-  set_irg_end_reg    (irg, get_irg_end(irg));
-  free_End(old_end);
-  set_irg_end_block  (irg, get_new_node(get_irg_end_block(irg)));
-
-  n = get_irg_frame(irg);
-  if (!has_new_node(n)) {
-    copy_node (n, INT_TO_PTR(copy_node_nr));
-    copy_preds(n, NULL);
-  }
-  n = get_irg_globals(irg);
-  if (!has_new_node(n)) {
-    copy_node (n, INT_TO_PTR(copy_node_nr));
-    copy_preds(n, NULL);
-  }
-  n = get_irg_initial_mem(irg);
-  if (!has_new_node(n)) {
-    copy_node (n, INT_TO_PTR(copy_node_nr));
-    copy_preds(n, NULL);
-  }
-  n = get_irg_args(irg);
-  if (!has_new_node(n)) {
-    copy_node (n, INT_TO_PTR(copy_node_nr));
-    copy_preds(n, NULL);
+  for (i = anchor_max - 1; i >= 0; --i) {
+    n = irg->anchors[i];
+    if (n)
+      irg->anchors[i] = get_new_node(n);
   }
-  n = get_irg_bad(irg);
-  if (!has_new_node(n)) {
-    copy_node(n, INT_TO_PTR(copy_node_nr));
-    copy_preds(n, NULL);
-  }
-  n = get_irg_no_mem(irg);
-  if (!has_new_node(n)) {
-    copy_node(n, INT_TO_PTR(copy_node_nr));
-    copy_preds(n, NULL);
-  }
-  set_irg_start      (irg, get_new_node(get_irg_start(irg)));
-  set_irg_start_block(irg, get_new_node(get_irg_start_block(irg)));
-  set_irg_frame      (irg, get_new_node(get_irg_frame(irg)));
-  set_irg_globals    (irg, get_new_node(get_irg_globals(irg)));
-  set_irg_initial_mem(irg, get_new_node(get_irg_initial_mem(irg)));
-  set_irg_args       (irg, get_new_node(get_irg_args(irg)));
-  set_irg_bad        (irg, get_new_node(get_irg_bad(irg)));
-  set_irg_no_mem     (irg, get_new_node(get_irg_no_mem(irg)));
+  free_End(old_end);
 }
 
 /**
@@ -505,7 +547,7 @@ dead_node_elimination(ir_graph *irg) {
   struct obstack *rebirth_obst   = NULL;
 
   if (get_opt_optimize() && get_opt_dead_node_elimination()) {
-    assert(! edges_activated(irg) && "dead node elimination requieres disabled edges");
+    assert(! edges_activated(irg) && "dead node elimination requires disabled edges");
 
     /* inform statistics that we started a dead-node elimination run */
     hook_dead_node_elim(irg, 1);
@@ -532,16 +574,17 @@ dead_node_elimination(ir_graph *irg) {
     graveyard_obst = irg->obst;
 
     /* A new obstack, where the reachable nodes will be copied to. */
-    rebirth_obst = xmalloc (sizeof(*rebirth_obst));
+    rebirth_obst = xmalloc(sizeof(*rebirth_obst));
     current_ir_graph->obst = rebirth_obst;
     obstack_init (current_ir_graph->obst);
+    current_ir_graph->last_node_idx = 0;
 
-    /* We also need a new hash table for cse */
-    del_identities (irg->value_table);
-    irg->value_table = new_identities ();
+    /* We also need a new value table for CSE */
+    del_identities(irg->value_table);
+    irg->value_table = new_identities();
 
     /* Copy the graph from the old to the new obstack */
-    copy_graph_env(1);
+    copy_graph_env(/*copy_node_nr=*/1);
 
     /* Free memory from old unoptimized obstack */
     obstack_free(graveyard_obst, 0);  /* First empty the obstack ... */
@@ -660,9 +703,124 @@ static void relink_bad_predecessors(ir_node *n, void *env) {
  * changes).
  */
 void remove_bad_predecessors(ir_graph *irg) {
-  irg_walk_graph(irg, init_link, relink_bad_predecessors, NULL);
+  irg_walk_graph(irg, firm_clear_link, relink_bad_predecessors, NULL);
+}
+
+
+/*
+   __                      _  __ __
+  (_     __    o     _    | \/  |_
+  __)|_| | \_/ | \_/(/_   |_/\__|__
+
+  The following stuff implements a facility that automatically patches
+  registered ir_node pointers to the new node when a dead node elimination occurs.
+*/
+
+struct _survive_dce_t {
+  struct obstack obst;
+  pmap *places;
+  pmap *new_places;
+  hook_entry_t dead_node_elim;
+  hook_entry_t dead_node_elim_subst;
+};
+
+typedef struct _survive_dce_list_t {
+  struct _survive_dce_list_t *next;
+  ir_node **place;
+} survive_dce_list_t;
+
+static void dead_node_hook(void *context, ir_graph *irg, int start)
+{
+  survive_dce_t *sd = context;
+
+  /* Create a new map before the dead node elimination is performed. */
+  if (start) {
+    sd->new_places = pmap_create_ex(pmap_count(sd->places));
+  }
+
+  /* Patch back all nodes if dead node elimination is over and something is to be done. */
+  else {
+    pmap_destroy(sd->places);
+    sd->places     = sd->new_places;
+    sd->new_places = NULL;
+  }
+}
+
+/**
+ * Hook called when dead node elimination replaces old by nw.
+ */
+static void dead_node_subst_hook(void *context, ir_graph *irg, ir_node *old, ir_node *nw)
+{
+  survive_dce_t *sd = context;
+  survive_dce_list_t *list = pmap_get(sd->places, old);
+
+  /* If the node is to be patched back, write the new address to all registered locations. */
+  if (list) {
+    survive_dce_list_t *p;
+
+    for(p = list; p; p = p->next)
+      *(p->place) = nw;
+
+    pmap_insert(sd->new_places, nw, list);
+  }
+}
+
+/**
+ * Make a new Survive DCE environment.
+ */
+survive_dce_t *new_survive_dce(void)
+{
+  survive_dce_t *res = xmalloc(sizeof(res[0]));
+  obstack_init(&res->obst);
+  res->places     = pmap_create();
+  res->new_places = NULL;
+
+  res->dead_node_elim.hook._hook_dead_node_elim = dead_node_hook;
+  res->dead_node_elim.context                   = res;
+  res->dead_node_elim.next                      = NULL;
+
+  res->dead_node_elim_subst.hook._hook_dead_node_elim_subst = dead_node_subst_hook;
+  res->dead_node_elim_subst.context = res;
+  res->dead_node_elim_subst.next    = NULL;
+
+  register_hook(hook_dead_node_elim, &res->dead_node_elim);
+  register_hook(hook_dead_node_elim_subst, &res->dead_node_elim_subst);
+  return res;
+}
+
+/**
+ * Free a Survive DCE environment.
+ */
+void free_survive_dce(survive_dce_t *sd)
+{
+  obstack_free(&sd->obst, NULL);
+  pmap_destroy(sd->places);
+  unregister_hook(hook_dead_node_elim, &sd->dead_node_elim);
+  unregister_hook(hook_dead_node_elim_subst, &sd->dead_node_elim_subst);
+  free(sd);
 }
 
+/**
+ * Register a node pointer to be patched upon DCE.
+ * When DCE occurs, the node pointer specified by @p place will be
+ * patched to the new address of the node it is pointing to.
+ *
+ * @param sd    The Survive DCE environment.
+ * @param place The address of the node pointer.
+ */
+void survive_dce_register_irn(survive_dce_t *sd, ir_node **place)
+{
+  if(*place != NULL) {
+    ir_node *irn      = *place;
+    survive_dce_list_t *curr = pmap_get(sd->places, irn);
+    survive_dce_list_t *nw   = obstack_alloc(&sd->obst, sizeof(nw));
+
+    nw->next  = curr;
+    nw->place = place;
+
+    pmap_insert(sd->places, irn, nw);
+  }
+}
 
 /*--------------------------------------------------------------------*/
 /*  Functionality for inlining                                         */
@@ -679,19 +837,19 @@ void remove_bad_predecessors(ir_graph *irg) {
  */
 static INLINE void
 copy_node_inline (ir_node *n, void *env) {
-  ir_node *new;
+  ir_node *nn;
   ir_type *frame_tp = (ir_type *)env;
 
   copy_node(n, NULL);
   if (get_irn_op(n) == op_Sel) {
-    new = get_new_node (n);
-    assert(get_irn_op(new) == op_Sel);
+    nn = get_new_node (n);
+    assert(is_Sel(nn));
     if (get_entity_owner(get_Sel_entity(n)) == frame_tp) {
-      set_Sel_entity(new, get_entity_link(get_Sel_entity(n)));
+      set_Sel_entity(nn, get_entity_link(get_Sel_entity(n)));
     }
   } else if (get_irn_op(n) == op_Block) {
-    new = get_new_node (n);
-    new->attr.block.irg = current_ir_graph;
+    nn = get_new_node (n);
+    nn->attr.block.irg = current_ir_graph;
   }
 }
 
@@ -744,7 +902,7 @@ static int can_inline(ir_node *call, ir_graph *called_graph)
 int inline_method(ir_node *call, ir_graph *called_graph) {
   ir_node *pre_call;
   ir_node *post_call, *post_bl;
-  ir_node *in[5];
+  ir_node *in[pn_Start_max];
   ir_node *end, *end_bl;
   ir_node **res_pred;
   ir_node **cf_pred;
@@ -754,7 +912,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
   ir_type *called_frame;
   irg_inline_property prop = get_irg_inline_property(called_graph);
 
-  if ( (prop != irg_inline_forced) &&
+  if ( (prop < irg_inline_forced) &&
        (!get_opt_optimize() || !get_opt_inline() || (prop == irg_inline_forbidden))) return 0;
 
   /* Do not inline variadic functions. */
@@ -780,13 +938,14 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
   assert(get_irg_phase_state(current_ir_graph) != phase_building);
   assert(get_irg_pinned(current_ir_graph) == op_pin_state_pinned);
   assert(get_irg_pinned(called_graph) == op_pin_state_pinned);
-  if (get_irg_outs_state(current_ir_graph) == outs_consistent)
-    set_irg_outs_inconsistent(current_ir_graph);
+  set_irg_outs_inconsistent(current_ir_graph);
+  set_irg_extblk_inconsistent(current_ir_graph);
+  set_irg_doms_inconsistent(current_ir_graph);
   set_irg_loopinfo_inconsistent(current_ir_graph);
   set_irg_callee_info_state(current_ir_graph, irg_callee_info_inconsistent);
 
   /* -- Check preconditions -- */
-  assert(get_irn_op(call) == op_Call);
+  assert(is_Call(call));
   /* @@@ does not work for InterfaceIII.java after cgana
      assert(get_Call_type(call) == get_entity_type(get_irg_entity(called_graph)));
      assert(smaller_type(get_entity_type(get_irg_entity(called_graph)),
@@ -826,14 +985,16 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
      graph. Both will end up being a tuple.  -- */
   post_bl = get_nodes_block(call);
   set_irg_current_block(current_ir_graph, post_bl);
-  /* XxMxPxP of Start + parameter of Call */
-  in[pn_Start_X_initial_exec] = new_Jmp();
-  in[pn_Start_M]              = get_Call_mem(call);
-  in[pn_Start_P_frame_base]   = get_irg_frame(current_ir_graph);
-  in[pn_Start_P_globals]      = get_irg_globals(current_ir_graph);
-  in[pn_Start_T_args]         = new_Tuple(get_Call_n_params(call), get_Call_param_arr(call));
+  /* XxMxPxPxPxT of Start + parameter of Call */
+  in[pn_Start_X_initial_exec]   = new_Jmp();
+  in[pn_Start_M]                = get_Call_mem(call);
+  in[pn_Start_P_frame_base]     = get_irg_frame(current_ir_graph);
+  in[pn_Start_P_globals]        = get_irg_globals(current_ir_graph);
+  in[pn_Start_P_tls]            = get_irg_tls(current_ir_graph);
+  in[pn_Start_T_args]           = new_Tuple(get_Call_n_params(call), get_Call_param_arr(call));
   /* in[pn_Start_P_value_arg_base] = ??? */
-  pre_call = new_Tuple(5, in);
+  assert(pn_Start_P_value_arg_base == pn_Start_max - 1 && "pn_Start_P_value_arg_base not supported, fix");
+  pre_call = new_Tuple(pn_Start_max - 1, in);
   post_call = call;
 
   /* --
@@ -928,7 +1089,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
   for (i = 0; i < arity; i++) {
     ir_node *ret;
     ret = get_irn_n(end_bl, i);
-    if (get_irn_op(ret) == op_Return) {
+    if (is_Return(ret)) {
       cf_pred[n_ret] = new_r_Jmp(current_ir_graph, get_nodes_block(ret));
       n_ret++;
     }
@@ -942,7 +1103,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
   n_ret = 0;
   for (i = 0; i < arity; i++) {
     ret = get_irn_n(end_bl, i);
-    if (get_irn_op(ret) == op_Return) {
+    if (is_Return(ret)) {
       cf_pred[n_ret] = get_Return_mem(ret);
       n_ret++;
     }
@@ -1008,7 +1169,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
       for (i = 0; i < arity; i++) {
         ir_node *ret;
         ret = skip_Proj(get_irn_n(end_bl, i));
-        if (get_irn_op(ret) == op_Call) {
+        if (is_Call(ret)) {
           cf_pred[n_exc] = new_r_Proj(current_ir_graph, get_nodes_block(ret), ret, mode_M, 3);
           n_exc++;
         } else if (is_fragile_op(ret)) {
@@ -1131,7 +1292,7 @@ static ir_graph *get_call_called_irg(ir_node *call) {
   ir_node *addr;
   ir_graph *called_irg = NULL;
 
-  assert(get_irn_op(call) == op_Call);
+  assert(is_Call(call));
 
   addr = get_Call_ptr(call);
   if ((get_irn_op(addr) == op_SymConst) && (get_SymConst_kind (addr) == symconst_addr_ent)) {
@@ -1144,7 +1305,7 @@ static ir_graph *get_call_called_irg(ir_node *call) {
 static void collect_calls(ir_node *call, void *env) {
   ir_node *addr;
 
-  if (get_irn_op(call) != op_Call) return;
+  if (! is_Call(call)) return;
 
   addr = get_Call_ptr(call);
 
@@ -1195,7 +1356,7 @@ void inline_small_irgs(ir_graph *irg, int size) {
       ir_graph *callee;
       callee = get_entity_irg(get_SymConst_entity(get_Call_ptr(env.calls[i])));
       if (((_obstack_memory_used(callee->obst) - (int)obstack_room(callee->obst)) < size) ||
-        (get_irg_inline_property(callee) == irg_inline_forced)) {
+        (get_irg_inline_property(callee) >= irg_inline_forced)) {
         inline_method(env.calls[i], callee);
       }
     }
@@ -1378,7 +1539,7 @@ void inline_leave_functions(int maxsize, int leavesize, int size) {
 
       if (callee &&
           ((is_smaller(callee, size) && (env->n_nodes < maxsize)) ||    /* small function */
-           (get_irg_inline_property(callee) == irg_inline_forced))) {
+           (get_irg_inline_property(callee) >= irg_inline_forced))) {
         if (!phiproj_computed) {
             phiproj_computed = 1;
             collect_phiprojs(current_ir_graph);
@@ -1860,8 +2021,7 @@ void place_code(ir_graph *irg) {
 
   /* Handle graph state */
   assert(get_irg_phase_state(irg) != phase_building);
-  if (get_irg_dom_state(irg) != dom_consistent)
-    compute_doms(irg);
+  assure_doms(irg);
 
   if (1 || get_irg_loopinfo_state(irg) != loopinfo_consistent) {
     free_loop_information(irg);
@@ -1892,47 +2052,48 @@ void place_code(ir_graph *irg) {
  * Place an empty block to an edge between a blocks of multiple
  * predecessors and a block of multiple successors.
  *
- * @param n IR node
- * @param env Environment of walker. This field is unused and has
- *            the value NULL.
+ * @param n   IR node
+ * @param env Environment of walker. The changed field.
  */
 static void walk_critical_cf_edges(ir_node *n, void *env) {
   int arity, i;
-  ir_node *pre, *block, **in, *jmp;
+  ir_node *pre, *block, *jmp;
+  int *changed = env;
 
   /* Block has multiple predecessors */
-  if ((op_Block == get_irn_op(n)) &&
-      (get_irn_arity(n) > 1)) {
-    arity = get_irn_arity(n);
-
+  if (is_Block(n) && (get_irn_arity(n) > 1)) {
     if (n == get_irg_end_block(current_ir_graph))
       return;  /*  No use to add a block here.      */
 
+    arity = get_irn_arity(n);
     for (i=0; i<arity; i++) {
       pre = get_irn_n(n, i);
-      /* Predecessor has multiple successors. Insert new flow edge */
-      if ((NULL != pre) &&
-    (op_Proj == get_irn_op(pre)) &&
-    op_Raise != get_irn_op(skip_Proj(pre))) {
-
-    /* set predecessor array for new block */
-    in = NEW_ARR_D (ir_node *, current_ir_graph->obst, 1);
-    /* set predecessor of new block */
-    in[0] = pre;
-    block = new_Block(1, in);
-    /* insert new jmp node to new block */
-    set_cur_block(block);
-    jmp = new_Jmp();
-    set_cur_block(n);
-    /* set successor of new block */
-    set_irn_n(n, i, jmp);
-
+      /* Predecessor has multiple successors. Insert new control flow edge. */
+      if (op_Raise != get_irn_op(skip_Proj(pre))) {
+        /* set predecessor of new block */
+        block = new_Block(1, &pre);
+        /* insert new jmp node to new block */
+        set_cur_block(block);
+        jmp = new_Jmp();
+        set_cur_block(n);
+        /* set successor of new block */
+        set_irn_n(n, i, jmp);
+        *changed = 1;
       } /* predecessor has multiple successors */
     } /* for all predecessors */
   } /* n is a block */
 }
 
 void remove_critical_cf_edges(ir_graph *irg) {
-  if (get_opt_critical_edges())
-    irg_walk_graph(irg, NULL, walk_critical_cf_edges, NULL);
+  int changed = 0;
+  irg_walk_graph(irg, NULL, walk_critical_cf_edges, &changed);
+
+  if (changed) {
+    /* control flow changed */
+    set_irg_outs_inconsistent(irg);
+    set_irg_extblk_inconsistent(irg);
+    set_irg_doms_inconsistent(current_ir_graph);
+    set_irg_loopinfo_inconsistent(current_ir_graph);
+  }
+
 }