Fixed a bug
[libfirm] / ir / ir / irgopt.c
index 4bd87a2..0ec7ad2 100644 (file)
@@ -198,41 +198,34 @@ static INLINE void new_backedge_info(ir_node *n) {
   }
 }
 
-/**
- * Copies the node to the new obstack. The Ins of the new node point to
- * the predecessors on the old obstack.  For block/phi nodes not all
- * predecessors might be copied.  n->link points to the new node.
+/*
+ * Copies a node to the current_ir_graph. The Ins of the new node point to
+ * the predecessors on the graph of the old node.  For block/phi nodes not all
+ * predecessors might be copied.
  * For Phi and Block nodes the function allocates in-arrays with an arity
  * only for useful predecessors.  The arity is determined by counting
  * the non-bad predecessors of the block.
- *
- * @param n    The node to be copied
- * @param env  if non-NULL, the node number attribute will be copied to the new node
- *
- * Note: Also used for loop unrolling.
  */
-static void
-firm_copy_node (ir_node *n, void *env) {
+ir_node *copy_irn(ir_node *n, int copy_node_nr) {
   ir_node *nn, *block;
   int new_arity;
-  opcode op = get_irn_opcode(n);
-  int copy_node_nr = env != NULL;
+  ir_op *op = get_irn_op(n);
 
   /* The end node looses it's flexible in array.  This doesn't matter,
      as dead node elimination builds End by hand, inlineing doesn't use
      the End node. */
-  /* assert(n->op == op_End ||  ((_ARR_DESCR(n->in))->cookie != ARR_F_MAGIC)); */
+  /* assert(op == op_End ||  ((_ARR_DESCR(n->in))->cookie != ARR_F_MAGIC)); */
 
-  if (op == iro_Bad) {
+  if (op == op_Bad) {
     /* node copied already */
-    return;
-  } else if (op == iro_Block) {
+    return NULL;
+  } else if (op == op_Block) {
     block = NULL;
     new_arity = compute_new_arity(n);
     n->attr.block.graph_arr = NULL;
   } else {
     block = get_nodes_block(n);
-    if (get_irn_opcode(n) == iro_Phi) {
+    if (op == op_Phi) {
       new_arity = compute_new_arity(block);
     } else {
       new_arity = get_irn_arity(n);
@@ -241,16 +234,15 @@ firm_copy_node (ir_node *n, void *env) {
   nn = new_ir_node(get_irn_dbg_info(n),
            current_ir_graph,
            block,
-           get_irn_op(n),
+           op,
            get_irn_mode(n),
            new_arity,
-           get_irn_in(n));
+           get_irn_in(n) + 1);
   /* Copy the attributes.  These might point to additional data.  If this
      was allocated on the old obstack the pointers now are dangling.  This
      frees e.g. the memory of the graph_arr allocated in new_immBlock. */
   copy_node_attr(n, nn);
   new_backedge_info(nn);
-  set_new_node(n, nn);
 
 #if DEBUG_libfirm
   if (copy_node_nr) {
@@ -259,10 +251,30 @@ firm_copy_node (ir_node *n, void *env) {
   }
 #endif
 
-  /*  printf("\n old node: "); DDMSG2(n);
-      printf(" new node: "); DDMSG2(nn); */
+  return nn;
 }
 
+/**
+ * Copies the node to the new obstack. The Ins of the new node point to
+ * the predecessors on the old obstack.  For block/phi nodes not all
+ * predecessors might be copied.  n->link points to the new node.
+ * For Phi and Block nodes the function allocates in-arrays with an arity
+ * only for useful predecessors.  The arity is determined by counting
+ * the non-bad predecessors of the block.
+ *
+ * @param n    The node to be copied
+ * @param env  if non-NULL, the node number attribute will be copied to the new node
+ *
+ * Note: Also used for loop unrolling.
+ */
+static void firm_copy_node (ir_node *n, void *env) {
+  ir_node *nn = copy_irn(n, env != NULL);
+
+  if (nn)
+    set_new_node(n, nn);
+}
+
+
 /**
  * Copies new predecessors of old node to new node remembered in link.
  * Spare the Bad predecessors of Phi and Block nodes.
@@ -278,12 +290,12 @@ copy_preds (ir_node *n, void *env) {
      printf(" new node: "); DDMSG2(nn);
      printf(" arities: old: %d, new: %d\n", get_irn_arity(n), get_irn_arity(nn)); */
 
-  if (get_irn_opcode(n) == iro_Block) {
+  if (is_Block(n)) {
     /* Don't copy Bad nodes. */
     j = 0;
     irn_arity = get_irn_arity(n);
     for (i = 0; i < irn_arity; i++)
-      if (get_irn_opcode(get_irn_n(n, i)) != iro_Bad) {
+      if (! is_Bad(get_irn_n(n, i))) {
         set_irn_n (nn, j, get_new_node(get_irn_n(n, i)));
         /*if (is_backedge(n, i)) set_backedge(nn, j);*/
         j++;
@@ -308,7 +320,7 @@ copy_preds (ir_node *n, void *env) {
         exchange(nn, old);
       }
     }
-  } else if (get_irn_opcode(n) == iro_Phi) {
+  } else if (get_irn_op(n) == op_Phi) {
     /* Don't copy node if corresponding predecessor in block is Bad.
        The Block itself should not be Bad. */
     block = get_nodes_block(n);
@@ -316,7 +328,7 @@ copy_preds (ir_node *n, void *env) {
     j = 0;
     irn_arity = get_irn_arity(n);
     for (i = 0; i < irn_arity; i++)
-      if (get_irn_opcode(get_irn_n(block, i)) != iro_Bad) {
+      if (! is_Bad(get_irn_n(block, i))) {
         set_irn_n (nn, j, get_new_node(get_irn_n(n, i)));
         /*if (is_backedge(n, i)) set_backedge(nn, j);*/
         j++;
@@ -326,8 +338,8 @@ copy_preds (ir_node *n, void *env) {
     set_Block_block_visited(get_nodes_block(n), 0);
     /* Compacting the Phi's ins might generate Phis with only one
        predecessor. */
-    if (get_irn_arity(n) == 1)
-      exchange(n, get_irn_n(n, 0));
+    if (get_irn_arity(nn) == 1)
+      exchange(nn, get_irn_n(nn, 0));
   } else {
     irn_arity = get_irn_arity(n);
     for (i = -1; i < irn_arity; i++)
@@ -335,7 +347,7 @@ copy_preds (ir_node *n, void *env) {
   }
   /* Now the new node is complete.  We can add it to the hash table for CSE.
      @@@ inlinening aborts if we identify End. Why? */
-  if(get_irn_op(nn) != op_End)
+  if (get_irn_op(nn) != op_End)
     add_identities (current_ir_graph->value_table, nn);
 }
 
@@ -523,7 +535,7 @@ dead_node_elimination(ir_graph *irg) {
   /* Handle graph state */
   assert(get_irg_phase_state(current_ir_graph) != phase_building);
   free_callee_info(current_ir_graph);
-  free_outs(current_ir_graph);
+  free_irg_outs(current_ir_graph);
   free_trouts();
   /* @@@ so far we loose loops when copying */
   free_loop_information(current_ir_graph);
@@ -1423,9 +1435,20 @@ void inline_leave_functions(int maxsize, int leavesize, int size) {
 /*  will be executed only if needed.                               */
 /*******************************************************************/
 
+/**
+ * Returns non-zero, is a block is not reachable from Start.
+ */
+static int
+is_Block_unreachable(ir_node *block) {
+  return is_Block_dead(block) || get_Block_dom_depth(block) < 0;
+}
+
 /**
  * Find the earliest correct block for N.  --- Place N into the
  * same Block as its dominance-deepest Input.
+ *
+ * We have to avoid calls to get_nodes_block() here
+ * because the graph is floating.
  */
 static void
 place_floats_early(ir_node *n, pdeq *worklist)
@@ -1439,8 +1462,8 @@ place_floats_early(ir_node *n, pdeq *worklist)
   /* Place floating nodes. */
   if (get_irn_pinned(n) == op_pin_state_floats) {
     int depth         = 0;
-    ir_node *b        = new_Bad();   /* The block to place this node in */
-    int bad_recursion = is_Bad(get_nodes_block(n));
+    ir_node *b        = NULL;   /* The block to place this node in */
+    int bad_recursion = is_Block_unreachable(get_irn_n(n, -1));
 
     assert(get_irn_op(n) != op_Block);
 
@@ -1474,20 +1497,21 @@ place_floats_early(ir_node *n, pdeq *worklist)
       /* Because all loops contain at least one op_pin_state_pinned node, now all
          our inputs are either op_pin_state_pinned or place_early has already
          been finished on them.  We do not have any unfinished inputs!  */
-      dep_block = get_nodes_block(dep);
-      if ((!is_Bad(dep_block)) &&
+      dep_block = get_irn_n(dep, -1);
+      if ((!is_Block_dead(dep_block)) &&
           (get_Block_dom_depth(dep_block) > depth)) {
         b = dep_block;
         depth = get_Block_dom_depth(dep_block);
       }
       /* Avoid that the node is placed in the Start block */
-      if ((depth == 1) && (get_Block_dom_depth(get_nodes_block(n)) > 1)) {
+      if ((depth == 1) && (get_Block_dom_depth(get_irn_n(n, -1)) > 1)) {
         b = get_Block_cfg_out(get_irg_start_block(current_ir_graph), 0);
         assert(b != get_irg_start_block(current_ir_graph));
         depth = 2;
       }
     }
-    set_nodes_block(n, b);
+    if (b)
+      set_nodes_block(n, b);
   }
 
   /* Add predecessors of non floating nodes on worklist. */
@@ -1524,16 +1548,28 @@ static INLINE void place_early(pdeq *worklist) {
   current_ir_graph->op_pin_state_pinned = op_pin_state_pinned;
 }
 
-/** Compute the deepest common ancestor of block and dca. */
+/**
+ * Compute the deepest common ancestor of block and dca.
+ */
 static ir_node *calc_dca(ir_node *dca, ir_node *block)
 {
   assert(block);
+
+  /* we do not want to place nodes in dead blocks */
+  if (is_Block_dead(block))
+    return dca;
+
+  /* We found a first legal placement. */
   if (!dca) return block;
+
+  /* Find a placement that is dominates both, dca and block. */
   while (get_Block_dom_depth(block) > get_Block_dom_depth(dca))
     block = get_Block_idom(block);
+
   while (get_Block_dom_depth(dca) > get_Block_dom_depth(block)) {
     dca = get_Block_idom(dca);
   }
+
   while (block != dca)
     { block = get_Block_idom(block); dca = get_Block_idom(dca); }
 
@@ -1562,9 +1598,14 @@ consumer_dom_dca (ir_node *dca, ir_node *consumer, ir_node *producer)
       if (get_irn_n(consumer, i) == producer) {
         ir_node *new_block = get_nodes_block(get_Block_cfgpred(phi_block, i));
 
-        block = calc_dca(block, new_block);
+        if (! is_Block_unreachable(new_block))
+          block = calc_dca(block, new_block);
       }
     }
+
+    if (! block)
+      block = get_irn_n(producer, -1);
+
   } else {
     assert(is_no_Block(consumer));
     block = get_nodes_block(consumer);
@@ -1583,6 +1624,9 @@ static INLINE int get_irn_loop_depth(ir_node *n) {
 /**
  * Move n to a block with less loop depth than it's current block. The
  * new block must be dominated by early.
+ *
+ * @param n      the node that should be moved
+ * @param early  the earliest block we can n move to
  */
 static void
 move_out_of_loops (ir_node *n, ir_node *early)
@@ -1595,6 +1639,7 @@ move_out_of_loops (ir_node *n, ir_node *early)
      dca with the least loop nesting depth, but still dominated
      by our early placement. */
   dca = get_nodes_block(n);
+
   best = dca;
   while (dca != early) {
     dca = get_Block_idom(dca);
@@ -1638,12 +1683,13 @@ place_floats_late(ir_node *n, pdeq *worklist)
       (get_irn_mode(n) != mode_X)) {
     /* Remember the early placement of this block to move it
        out of loop no further than the early placement. */
-    early = get_nodes_block(n);
+    early = get_irn_n(n, -1);
 
-    /* Do not move code not reachable from Start.  For
-     * these we could not compute dominator information. */
-    if (is_Bad(early) || get_Block_dom_depth(early) == -1)
-      return;
+    /*
+     * BEWARE: Here we also get code, that is live, but
+     * was in a dead block.  If the node is life, but because
+     * of CSE in a dead block, we still might need it.
+     */
 
     /* Assure that our users are all placed, except the Phi-nodes.
        --- Each data flow cycle contains at least one Phi-node.  We
@@ -1653,7 +1699,7 @@ place_floats_late(ir_node *n, pdeq *worklist)
        final region of our users, which is OK with Phi-nodes, as they
        are op_pin_state_pinned, and they never have to be placed after a
        producer of one of their inputs in the same block anyway. */
-    for (i = 0; i < get_irn_n_outs(n); i++) {
+    for (i = get_irn_n_outs(n) - 1; i >= 0; --i) {
       ir_node *succ = get_irn_out(n, i);
       if (irn_not_visited(succ) && (get_irn_op(succ) != op_Phi))
         place_floats_late(succ, worklist);
@@ -1668,17 +1714,25 @@ place_floats_late(ir_node *n, pdeq *worklist)
                    dominator tree of all nodes'
                    blocks depending on us; our final
                    placement has to dominate DCA. */
-      for (i = 0; i < get_irn_n_outs(n); i++) {
+      for (i = get_irn_n_outs(n) - 1; i >= 0; --i) {
         ir_node *out = get_irn_out(n, i);
+
+        if (get_irn_op(out) == op_End) {
+          /*
+           * This consumer is the End node, a keep alive edge.
+           * This is not a real consumer, so we ignore it
+           */
+          continue;
+        }
+
         /* ignore if out is in dead code */
-        ir_node *outbl = get_nodes_block(out);
-        if (is_Bad(outbl) || get_Block_dom_depth(outbl) == -1)
+        ir_node *outbl = get_irn_n(out, -1);
+        if (is_Block_unreachable(outbl))
           continue;
-        dca = consumer_dom_dca (dca, out, n);
+        dca = consumer_dom_dca(dca, out, n);
       }
       if (dca) {
         set_nodes_block(n, dca);
-
         move_out_of_loops (n, early);
       }
       /* else all outs are in dead code */
@@ -1686,7 +1740,7 @@ place_floats_late(ir_node *n, pdeq *worklist)
   }
 
   /* Add predecessors of all non-floating nodes on list. (Those of floating
-     nodes are placeed already and therefore are marked.)  */
+     nodes are placed already and therefore are marked.)  */
   for (i = 0; i < get_irn_n_outs(n); i++) {
     ir_node *succ = get_irn_out(n, i);
     if (irn_not_visited(get_irn_out(n, i))) {
@@ -1733,7 +1787,7 @@ void place_code(ir_graph *irg) {
   place_early(worklist);
 
   /* place_early invalidates the outs, place_late needs them. */
-  compute_outs(irg);
+  compute_irg_outs(irg);
   /* Now move the nodes down in the dominator tree. This reduces the
      unnecessary executions of the node. */
   place_late(worklist);