removed critical_edges flag. Other code depends on remove_critical_edges() doing...
[libfirm] / ir / ir / irgopt.c
index 8bf933a..3592807 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"
@@ -148,19 +149,17 @@ local_optimize_graph (ir_graph *irg) {
 /**
  * Remember the new node in the old node by using a field all nodes have.
  */
-static INLINE void
-set_new_node (ir_node *old, ir_node *new)
-{
-  old->link = new;
-}
+#define set_new_node(oldn, newn)  set_irn_link(oldn, newn)
 
 /**
  * Get this new node, before the old node is forgotten.
  */
-static INLINE ir_node *
-get_new_node (ir_node * n) {
-  return n->link;
-}
+#define get_new_node(oldn) get_irn_link(oldn)
+
+/**
+ * Check if a new node was set.
+ */
+#define has_new_node(n) (get_new_node(n) != NULL)
 
 /**
  * We use the block_visited flag to mark that we have computed the
@@ -252,6 +251,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);
 }
 
 /**
@@ -325,26 +325,26 @@ copy_preds (ir_node *n, void *env) {
       set_irn_n (nn, i, get_new_node(get_irn_n(n, i)));
   }
   /* Now the new node is complete.  We can add it to the hash table for CSE.
-     @@@ inlinening aborts if we identify End. Why? */
+     @@@ inlining aborts if we identify End. Why? */
   if (get_irn_op(nn) != op_End)
     add_identities (current_ir_graph->value_table, nn);
 }
 
 /**
- * Copies the graph recursively, compacts the keepalive of the end node.
+ * Copies the graph recursively, compacts the keep-alives of the end node.
  *
+ * @param irg           the graph to be copied
  * @param copy_node_nr  If non-zero, the node number will be copied
  */
-static void
-copy_graph (int copy_node_nr) {
+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;
 
-  oe = get_irg_end(current_ir_graph);
+  oe = get_irg_end(irg);
   /* copy the end node by hand, allocate dynamic in array! */
   ne = new_ir_node(get_irn_dbg_info(oe),
-           current_ir_graph,
+           irg,
            NULL,
            op_End,
            mode_X,
@@ -355,9 +355,9 @@ copy_graph (int copy_node_nr) {
   set_new_node(oe, ne);
 
   /* copy the Bad node */
-  ob = get_irg_bad(current_ir_graph);
-  nb =  new_ir_node(get_irn_dbg_info(ob),
-           current_ir_graph,
+  ob = get_irg_bad(irg);
+  nb = new_ir_node(get_irn_dbg_info(ob),
+           irg,
            NULL,
            op_Bad,
            mode_T,
@@ -366,9 +366,9 @@ copy_graph (int copy_node_nr) {
   set_new_node(ob, nb);
 
   /* copy the NoMem node */
-  om = get_irg_no_mem(current_ir_graph);
-  nm =  new_ir_node(get_irn_dbg_info(om),
-           current_ir_graph,
+  om = get_irg_no_mem(irg);
+  nm = new_ir_node(get_irn_dbg_info(om),
+           irg,
            NULL,
            op_NoMem,
            mode_M,
@@ -387,23 +387,23 @@ copy_graph (int copy_node_nr) {
   irn_arity = get_irn_arity(oe);
   for (i = 0; i < irn_arity; i++) {
     ka = get_irn_intra_n(oe, i);
-    if ((get_irn_op(ka) == op_Block) &&
-        (get_irn_visited(ka) < get_irg_visited(current_ir_graph))) {
+    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(current_ir_graph, get_irg_visited(current_ir_graph)-1);
+      set_irg_visited(irg, get_irg_visited(irg)-1);
       irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
       add_End_keepalive(ne, get_new_node(ka));
     }
   }
 
-  /* Now pick the Phis.  Here we will keep all! */
+  /* Now pick other nodes.  Here we will keep all! */
   irn_arity = get_irn_arity(oe);
   for (i = 0; i < irn_arity; i++) {
     ka = get_irn_intra_n(oe, i);
-    if ((get_irn_op(ka) == op_Phi)) {
-      if (get_irn_visited(ka) < get_irg_visited(current_ir_graph)) {
-        /* We didn't copy the Phi yet.  */
-        set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1);
+    if (!is_Block(ka)) {
+      if (get_irn_visited(ka) < get_irg_visited(irg)) {
+        /* We didn't copy the node yet.  */
+        set_irg_visited(irg, get_irg_visited(irg)-1);
         irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
       }
       add_End_keepalive(ne, get_new_node(ka));
@@ -425,63 +425,70 @@ copy_graph (int copy_node_nr) {
  */
 static void
 copy_graph_env (int copy_node_nr) {
-  ir_node *old_end;
-  /* Not all nodes remembered in current_ir_graph might be reachable
+  ir_graph *irg = current_ir_graph;
+  ir_node *old_end, *n;
+  /* 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      (current_ir_graph), NULL);
-  set_irn_link(get_irg_globals    (current_ir_graph), NULL);
-  set_irn_link(get_irg_args       (current_ir_graph), NULL);
-  set_irn_link(get_irg_initial_mem(current_ir_graph), NULL);
-  set_irn_link(get_irg_bad        (current_ir_graph), NULL);
-  set_irn_link(get_irg_no_mem     (current_ir_graph), NULL);
+  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);
 
   /* we use the block walk flag for removing Bads from Blocks ins. */
-  inc_irg_block_visited(current_ir_graph);
+  inc_irg_block_visited(irg);
 
   /* copy the graph */
-  copy_graph(copy_node_nr);
+  copy_graph(irg, copy_node_nr);
 
-  /* fix the fields in current_ir_graph */
-  old_end = get_irg_end(current_ir_graph);
-  set_irg_end        (current_ir_graph, get_new_node(old_end));
-  set_irg_end_except (current_ir_graph, get_irg_end(current_ir_graph));
-  set_irg_end_reg    (current_ir_graph, get_irg_end(current_ir_graph));
+  /* 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  (current_ir_graph, get_new_node(get_irg_end_block(current_ir_graph)));
+  set_irg_end_block  (irg, get_new_node(get_irg_end_block(irg)));
 
-  if (get_irn_link(get_irg_frame(current_ir_graph)) == NULL) {
-    copy_node (get_irg_frame(current_ir_graph), INT_TO_PTR(copy_node_nr));
-    copy_preds(get_irg_frame(current_ir_graph), NULL);
+  n = get_irg_frame(irg);
+  if (!has_new_node(n)) {
+    copy_node (n, INT_TO_PTR(copy_node_nr));
+    copy_preds(n, NULL);
   }
-  if (get_irn_link(get_irg_globals(current_ir_graph)) == NULL) {
-    copy_node (get_irg_globals(current_ir_graph), INT_TO_PTR(copy_node_nr));
-    copy_preds(get_irg_globals(current_ir_graph), NULL);
+  n = get_irg_globals(irg);
+  if (!has_new_node(n)) {
+    copy_node (n, INT_TO_PTR(copy_node_nr));
+    copy_preds(n, NULL);
   }
-  if (get_irn_link(get_irg_initial_mem(current_ir_graph)) == NULL) {
-    copy_node (get_irg_initial_mem(current_ir_graph), INT_TO_PTR(copy_node_nr));
-    copy_preds(get_irg_initial_mem(current_ir_graph), 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);
   }
-  if (get_irn_link(get_irg_args(current_ir_graph)) == NULL) {
-    copy_node (get_irg_args(current_ir_graph), INT_TO_PTR(copy_node_nr));
-    copy_preds(get_irg_args(current_ir_graph), NULL);
+  n = get_irg_args(irg);
+  if (!has_new_node(n)) {
+    copy_node (n, INT_TO_PTR(copy_node_nr));
+    copy_preds(n, NULL);
   }
-  if (get_irn_link(get_irg_bad(current_ir_graph)) == NULL) {
-    copy_node(get_irg_bad(current_ir_graph), INT_TO_PTR(copy_node_nr));
-    copy_preds(get_irg_bad(current_ir_graph), NULL);
+  n = get_irg_bad(irg);
+  if (!has_new_node(n)) {
+    copy_node(n, INT_TO_PTR(copy_node_nr));
+    copy_preds(n, NULL);
   }
-  if (get_irn_link(get_irg_no_mem(current_ir_graph)) == NULL) {
-    copy_node(get_irg_no_mem(current_ir_graph), INT_TO_PTR(copy_node_nr));
-    copy_preds(get_irg_no_mem(current_ir_graph), 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      (current_ir_graph, get_new_node(get_irg_start(current_ir_graph)));
-  set_irg_start_block(current_ir_graph, get_new_node(get_irg_start_block(current_ir_graph)));
-  set_irg_frame      (current_ir_graph, get_new_node(get_irg_frame(current_ir_graph)));
-  set_irg_globals    (current_ir_graph, get_new_node(get_irg_globals(current_ir_graph)));
-  set_irg_initial_mem(current_ir_graph, get_new_node(get_irg_initial_mem(current_ir_graph)));
-  set_irg_args       (current_ir_graph, get_new_node(get_irg_args(current_ir_graph)));
-  set_irg_bad        (current_ir_graph, get_new_node(get_irg_bad(current_ir_graph)));
-  set_irg_no_mem     (current_ir_graph, get_new_node(get_irg_no_mem(current_ir_graph)));
+  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)));
 }
 
 /**
@@ -500,7 +507,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);
@@ -659,6 +666,118 @@ void remove_bad_predecessors(ir_graph *irg) {
 }
 
 
+/*
+        __                      _  __ __
+       (_     __    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;
+       }
+}
+
+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                                         */
 /*--------------------------------------------------------------------*/
@@ -674,19 +793,19 @@ void remove_bad_predecessors(ir_graph *irg) {
  */
 static INLINE void
 copy_node_inline (ir_node *n, void *env) {
-  ir_node *new;
-  type *frame_tp = (type *)env;
+  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;
   }
 }
 
@@ -707,7 +826,7 @@ static void find_addr(ir_node *node, void *env)
  */
 static int can_inline(ir_node *call, ir_graph *called_graph)
 {
-  type *call_type = get_Call_type(call);
+  ir_type *call_type = get_Call_type(call);
   int params, ress, i, res;
   assert(is_Method_type(call_type));
 
@@ -716,7 +835,7 @@ static int can_inline(ir_node *call, ir_graph *called_graph)
 
   /* check params */
   for (i = 0; i < params; ++i) {
-    type *p_type = get_method_param_type(call_type, i);
+    ir_type *p_type = get_method_param_type(call_type, i);
 
     if (is_compound_type(p_type))
       return 0;
@@ -724,7 +843,7 @@ static int can_inline(ir_node *call, ir_graph *called_graph)
 
   /* check res */
   for (i = 0; i < ress; ++i) {
-    type *r_type = get_method_res_type(call_type, i);
+    ir_type *r_type = get_method_res_type(call_type, i);
 
     if (is_compound_type(r_type))
       return 0;
@@ -746,7 +865,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
   ir_node *ret, *phi;
   int arity, n_ret, n_exc, n_res, i, j, rem_opt, irn_arity;
   int exc_handling;
-  type *called_frame;
+  ir_type *called_frame;
   irg_inline_property prop = get_irg_inline_property(called_graph);
 
   if ( (prop != irg_inline_forced) &&
@@ -781,7 +900,7 @@ int inline_method(ir_node *call, ir_graph *called_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)),
@@ -923,7 +1042,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++;
     }
@@ -937,7 +1056,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++;
     }
@@ -1003,7 +1122,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)) {
@@ -1126,7 +1245,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)) {
@@ -1139,7 +1258,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);