Add test functions for machine, machine_operand and machine_user bits
[libfirm] / ir / ir / irgopt.c
index 4ab6a0b..547dc81 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"
@@ -39,6 +40,7 @@
 #include "cgana.h"
 #include "trouts.h"
 
+
 #include "irflag_t.h"
 #include "irhooks.h"
 #include "iredges_t.h"
@@ -47,7 +49,7 @@
 /* Defined in iropt.c */
 pset *new_identities (void);
 void  del_identities (pset *value_table);
-void  add_identities   (pset *value_table, ir_node *node);
+void  add_identities (pset *value_table, ir_node *node);
 
 /*------------------------------------------------------------------*/
 /* apply optimizations of iropt to all nodes.                       */
@@ -95,8 +97,7 @@ static INLINE void do_local_optimize(ir_node *n) {
 
   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);
 
@@ -250,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);
 }
 
 /**
@@ -505,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);
@@ -664,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                                         */
 /*--------------------------------------------------------------------*/
@@ -679,19 +793,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;
   }
 }
 
@@ -780,13 +894,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)),
@@ -928,7 +1043,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 +1057,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 +1123,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 +1246,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 +1259,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);
 
@@ -1892,47 +2007,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);
+  }
+
 }