debug stuff and bugfixes
[libfirm] / ir / be / beirgmod.c
index 0bc90a2..73050d3 100644 (file)
 #include "beirgmod.h"
 
 #define DBG_MODULE firm_dbg_register("firm.be.irgmod")
+#define DBG_LEVEL 0
 
 struct _dom_front_info_t {
   pmap *df_map;
 };
 
+/**
+ * A wrapper for get_Block_idom.
+ * This function returns the block itself, if the block is the start
+ * block. Returning NULL would make any != comparison true which
+ * suggests, that the start block is dominated by some other node.
+ * @param bl The block.
+ * @return The immediate dominator of the block.
+ */
+static INLINE ir_node *get_idom(ir_node *bl)
+{
+  ir_node *idom = get_Block_idom(bl);
+  return idom == NULL ? bl : idom;
+}
+
 static void compute_df_local(ir_node *bl, void *data)
 {
   pmap *df_map = ((dom_front_info_t *) data)->df_map;
@@ -40,6 +55,15 @@ static void compute_df_local(ir_node *bl, void *data)
   pset *df = pmap_get(df_map, bl);
   int i, n;
 
+  /*
+   * In the case that the immediate dominator is NULL, the
+   * block is the start block and its immediate dominator
+   * must be itself, else it is inserted into its own
+   * dominance frontier.
+   */
+  if(idom == NULL)
+       idom = bl;
+
   /*
    * Create a new dom frot set for this node,
    * if none exists.
@@ -81,18 +105,58 @@ static void compute_df_up(ir_node *bl, void *data)
   }
 }
 
+static void compute_df(ir_node *n, pmap *df_map)
+{
+  ir_node *y, *c;
+  const ir_edge_t *edge;
+  pset *df = pset_new_ptr_default();
+
+  /* Add local dominance frontiers */
+  foreach_block_succ(n, edge) {
+    ir_node *y = edge->src;
+
+    if(get_idom(y) != n)
+      pset_insert_ptr(df, y);
+  }
+
+  /*
+   * Go recursively down the dominance tree and add all blocks
+   * int the dominance frontiers of the children, which are not
+   * dominated by the given block.
+   */
+  for(c = get_Block_dominated_first(n); c; c = get_Block_dominated_next(c)) {
+    pset *df_c;
+    ir_node *w;
+
+    compute_df(c, df_map);
+    df_c = pmap_get(df_map, c);
+
+    for(w = pset_first(df_c); w; w = pset_next(df_c)) {
+      if(!block_dominates(n, w))
+        pset_insert_ptr(df, w);
+    }
+  }
+
+  pmap_insert(df_map, n, df);
+
+}
+
 dom_front_info_t *be_compute_dominance_frontiers(ir_graph *irg)
 {
   dom_front_info_t *info = malloc(sizeof(*info));
 
+  edges_assure(irg);
   info->df_map = pmap_create();
+  compute_df(get_irg_start_block(irg), info->df_map);
 
+#if 0
   /*
    * This must be called as a post walker, since the dom front sets
    * of all predecessors must be created when a block is reached.
    */
   dom_tree_walk_irg(irg, NULL, compute_df_local, info);
   dom_tree_walk_irg(irg, NULL, compute_df_up, info);
+#endif
   return info;
 }
 
@@ -155,13 +219,11 @@ static void place_phi_functions(ir_node *orig, pset *copies,
   /*
    * Fill the worklist queue and the rest of the orig blocks array.
    */
-  for(it = pset_first(copies), i = 0; it; it = pset_next(copies)) {
-    ir_node *copy_block = get_nodes_block(it);
+  for(it = pset_first(copy_blocks), i = 0; it; it = pset_next(copy_blocks)) {
+    ir_node *copy_block = it;
 
-    if(!block_dominates(orig_block, copy_block)) {
-       assert(block_dominates(orig_block, copy_block)
-               && "The block of the copy must be dominated by the block of the value");
-    }
+       assert(block_dominates(orig_block, copy_block)
+               && "The block of the copy must be dominated by the block of the value");
 
     pdeq_putr(worklist, copy_block);
     orig_blocks[i++] = copy_block;
@@ -172,6 +234,10 @@ static void place_phi_functions(ir_node *orig, pset *copies,
     ir_node *y;
     pset *df = be_get_dominance_frontier(df_info, bl);
 
+    DBG((dbg, LEVEL_3, "dom front of %+F\n", bl));
+    for(y = pset_first(df); y; y = pset_next(df))
+           DBG((dbg, LEVEL_3, "\t%+F\n", y));
+
     for(y = pset_first(df); y; y = pset_next(df)) {
       int n_preds = get_irn_arity(y);
 
@@ -190,7 +256,7 @@ static void place_phi_functions(ir_node *orig, pset *copies,
         /* Insert phi node */
         phi = new_r_Phi(irg, y, n_preds, ins, mode);
         DBG((dbg, LEVEL_2, "    inserting phi %+F with %d args in block %+F\n",
-              phi, n_preds, bl));
+              phi, n_preds, y));
 
         /*
          * The phi node itself is also a copy of the original
@@ -260,19 +326,21 @@ static ir_node *search_def(ir_node *usage, int pos, pset *copies, pset *copy_blo
 {
   ir_node *curr_bl;
   ir_node *start_irn;
+  firm_dbg_module_t *dbg = DBG_MODULE;
+  firm_dbg_set_mask(dbg, DBG_LEVEL);
 
   curr_bl = get_nodes_block(usage);
 
+
+  DBG((dbg, LEVEL_1, "Searching valid def for use %+F at pos %d\n", usage, pos));
   /*
    * If the usage is in a phi node, search the copy in the
    * predecessor denoted by pos.
    */
   if(is_Phi(usage)) {
-    curr_bl = get_nodes_block(get_irn_n(curr_bl, pos));
+    curr_bl = get_Block_cfgpred_block(curr_bl, pos);
     start_irn = sched_last(curr_bl);
-  }
-
-  else {
+  } else {
     start_irn = sched_prev(usage);
   }
 
@@ -328,7 +396,6 @@ static void fix_usages(ir_node *orig, pset *copies, pset *copy_blocks)
    * This is neccessary, since the outs would be modified while
    * interating on them what could bring the outs module in trouble.
    */
-  DBG((dbg, LEVEL_2, "  Users of %+F\n", orig));
   outs = malloc(n_outs * sizeof(outs[0]));
   foreach_out_edge(orig, edge) {
     outs[i].irn = get_edge_src_irn(edge);
@@ -345,7 +412,7 @@ static void fix_usages(ir_node *orig, pset *copies, pset *copy_blocks)
     int pos = outs[i].pos;
 
     def = search_def(irn, pos, copies, copy_blocks);
-    DBG((dbg, LEVEL_2, "    %+F(%d) -> %+F\n", irn, pos, def));
+    DBG((dbg, LEVEL_2, "\t%+F(%d) -> %+F\n", irn, pos, def));
 
     if(def != NULL)
       set_irn_n(irn, pos, def);
@@ -354,50 +421,35 @@ static void fix_usages(ir_node *orig, pset *copies, pset *copy_blocks)
   free(outs);
 }
 
-struct phi_collect_info {
-  const ir_node *orig;
-  pset *copies;
-  pset *copy_blocks;
-};
-
-static void add_all_phis_walker(ir_node *irn, void *data)
+/**
+ * Remove phis which are not neccesary.
+ * During place_phi_functions() phi functions are put on the dominance
+ * frontiers blindly. However some of them will never be used (these
+ * have at least one predecessor which is NULL, see search_def() for
+ * this case). Since place_phi_functions() enters them into the
+ * schedule, we have to remove them from there.
+ *
+ * @param copies The set of all copies made (including the phi functions).
+ */
+static void remove_odd_phis(pset *copies)
 {
-  if(is_Phi(irn)) {
-    int i, n;
-    struct phi_collect_info *info = data;
+  ir_node *irn;
 
-    /*
-     * Look at all operands of the phi. If one of them is the original
-     * node, insert the phi into the copies and copy_blocks set.
-     */
-    for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
-      if(get_irn_n(irn, i) == info->orig) {
-        pset_insert_ptr(info->copies, irn);
-        pset_insert_ptr(info->copy_blocks, get_nodes_block(irn));
-        break;
-      }
-    }
+  for(irn = pset_first(copies); irn; irn = pset_next(copies)) {
+    if(is_Phi(irn)) {
+      int i, n;
+      int illegal = 0;
 
+      assert(sched_is_scheduled(irn) && "phi must be scheduled");
+      for(i = 0, n = get_irn_arity(irn); i < n && !illegal; ++i)
+        illegal = is_Bad(get_irn_n(irn, i));
 
+      if(illegal)
+        sched_remove(irn);
+    }
   }
 }
 
-/**
- * Add all phis using a node to a set.
- * @param orig        The node the phis shall use.
- * @param copies      The set where the phis shall be put into.
- * @param copy_blocks The set the blocks of the phis shall be put into.
- */
-static void add_all_phis_using(const ir_node *orig, pset *copies, pset *copy_blocks)
-{
-  struct phi_collect_info info;
-
-  info.copies      = copies;
-  info.copy_blocks = copy_blocks;
-  info.orig        = orig;
-  irg_walk_graph(get_irn_irg(orig), add_all_phis_walker, NULL, &info);
-}
-
 void be_introduce_copies(dom_front_info_t *info, ir_node *orig, int n, ir_node *copy_nodes[])
 {
   pset *copies = pset_new_ptr(2 * n);
@@ -407,7 +459,7 @@ void be_introduce_copies(dom_front_info_t *info, ir_node *orig, int n, ir_node *
   firm_dbg_module_t *dbg = DBG_MODULE;
   int i;
 
-  firm_dbg_set_mask(dbg, -1);
+  firm_dbg_set_mask(dbg, DBG_LEVEL);
   DBG((dbg, LEVEL_1, "Introducing following copies of %+F\n", orig));
 
   /* Fill the sets. */
@@ -418,8 +470,6 @@ void be_introduce_copies(dom_front_info_t *info, ir_node *orig, int n, ir_node *
    * All phis using the original value are also copies of it
    * and must be present in the copies set.
    */
-  add_all_phis_using(orig, copies, copy_blocks);
-
   for(i = 0; i < n; ++i) {
     DBG((dbg, LEVEL_1,
           "  %+F in block %+F\n", copy_nodes[i], get_nodes_block(copy_nodes[i])));
@@ -439,6 +489,7 @@ void be_introduce_copies(dom_front_info_t *info, ir_node *orig, int n, ir_node *
    */
   place_phi_functions(orig, copies, copy_blocks, info);
   fix_usages(orig, copies, copy_blocks);
+  remove_odd_phis(copies);
 
   /* reset the optimizations */
   set_optimize(save_optimize);