Simplify handling of unreachable code
[libfirm] / ir / opt / code_placement.c
index 577ad98..5ca8d40 100644 (file)
  */
 #include "config.h"
 
+#include "iroptimize.h"
 #include "adt/pdeq.h"
 #include "irnode_t.h"
 #include "irouts.h"
 #include "irgopt.h"
+#include "irpass.h"
 
-/**
- * Returns non-zero, is a block is not reachable from Start.
- *
- * @param block  the block to test
- */
-static int
-is_Block_unreachable(ir_node *block) {
-       return is_Block_dead(block) || get_Block_dom_depth(block) < 0;
+static int is_Block_unreachable(ir_node *block)
+{
+       return get_Block_dom_depth(block) < 0;
 }
 
 /**
@@ -53,7 +50,7 @@ is_Block_unreachable(ir_node *block) {
  * all "living" nodes into a living block. That's why we must
  * move nodes in dead block with "live" successors into a valid
  * block.
- * We move them just into the same block as it's successor (or
+ * We move them just into the same block as its successor (or
  * in case of a Phi into the effective use block). For Phi successors,
  * this may still be a dead block, but then there is no real use, as
  * the control flow will be dead later.
@@ -61,8 +58,8 @@ is_Block_unreachable(ir_node *block) {
  * @param n         the node to be placed
  * @param worklist  a worklist, predecessors of non-floating nodes are placed here
  */
-static void
-place_floats_early(ir_node *n, waitq *worklist) {
+static void place_floats_early(ir_node *n, waitq *worklist)
+{
        int i, irn_arity;
 
        /* we must not run into an infinite loop */
@@ -75,12 +72,13 @@ place_floats_early(ir_node *n, waitq *worklist) {
                int in_dead_block   = is_Block_unreachable(curr_block);
                int depth           = 0;
                ir_node *b          = NULL;   /* The block to place this node in */
+               ir_graph *irg       = get_irn_irg(n);
 
-               assert(is_no_Block(n));
+               assert(!is_Block(n));
 
                if (is_irn_start_block_placed(n)) {
                        /* These nodes will not be placed by the loop below. */
-                       b = get_irg_start_block(current_ir_graph);
+                       b = get_irg_start_block(irg);
                        depth = 1;
                }
 
@@ -95,9 +93,10 @@ place_floats_early(ir_node *n, waitq *worklist) {
 
                                /*
                                 * If the current node is NOT in a dead block, but one of its
-                                * predecessors is, we must move the predecessor to a live block.
-                                * Such thing can happen, if global CSE chose a node from a dead block.
-                                * We move it simply to our block.
+                                * predecessors is, we must move the predecessor to a live
+                                * block.
+                                * Such thing can happen, if global CSE chose a node from a
+                                * dead block. We move it simply to our block.
                                 * Note that neither Phi nor End nodes are floating, so we don't
                                 * need to handle them here.
                                 */
@@ -116,22 +115,22 @@ place_floats_early(ir_node *n, waitq *worklist) {
                        if (in_dead_block)
                                continue;
 
-                       /* 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!  */
+                       /* 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! */
                        pred_block = get_nodes_block(pred);
-                       if ((!is_Block_dead(pred_block)) &&
-                               (get_Block_dom_depth(pred_block) > depth)) {
+                       if (get_Block_dom_depth(pred_block) > depth) {
                                b = pred_block;
                                depth = get_Block_dom_depth(pred_block);
                        }
-                       /* Avoid that the node is placed in the Start block if we are not in the
-                          backend phase. */
+                       /* Avoid that the node is placed in the Start block if we are not
+                          in the backend phase. */
                        if (depth == 1 &&
                                        get_Block_dom_depth(get_nodes_block(n)) > 1 &&
-                                       get_irg_phase_state(current_ir_graph) != phase_backend) {
-                               b = get_Block_cfg_out(get_irg_start_block(current_ir_graph), 0);
-                               assert(b != get_irg_start_block(current_ir_graph));
+                                       get_irg_phase_state(irg) != phase_backend) {
+                               b = get_Block_cfg_out(get_irg_start_block(irg), 0);
+                               assert(b != get_irg_start_block(irg));
                                depth = 2;
                        }
                }
@@ -141,7 +140,8 @@ place_floats_early(ir_node *n, waitq *worklist) {
 
        /*
         * Add predecessors of non floating nodes and non-floating predecessors
-        * of floating nodes to worklist and fix their blocks if the are in dead block.
+        * of floating nodes to worklist and fix their blocks if the are in dead
+        * block.
         */
        irn_arity = get_irn_arity(n);
 
@@ -219,26 +219,28 @@ place_floats_early(ir_node *n, waitq *worklist) {
 
 /**
  * Floating nodes form subgraphs that begin at nodes as Const, Load,
- * Start, Call and that end at op_pin_state_pinned nodes as Store, Call.  Place_early
- * places all floating nodes reachable from its argument through floating
- * nodes and adds all beginnings at op_pin_state_pinned nodes to the worklist.
+ * Start, Call and that end at op_pin_state_pinned nodes as Store, Call.
+ * Place_early places all floating nodes reachable from its argument through
+ * floating nodes and adds all beginnings at op_pin_state_pinned nodes to the
+ * worklist.
  *
  * @param worklist   a worklist, used for the algorithm, empty on in/output
  */
-static void place_early(waitq *worklist) {
+static void place_early(ir_graph *irg, waitq *worklist)
+{
        assert(worklist);
-       inc_irg_visited(current_ir_graph);
+       inc_irg_visited(irg);
 
        /* this inits the worklist */
-       place_floats_early(get_irg_end(current_ir_graph), worklist);
+       place_floats_early(get_irg_end(irg), worklist);
 
        /* Work the content of the worklist. */
        while (!waitq_empty(worklist)) {
-               ir_node *n = waitq_get(worklist);
+               ir_node *n = (ir_node*)waitq_get(worklist);
                if (!irn_visited(n))
                        place_floats_early(n, worklist);
        }
-       set_irg_pinned(current_ir_graph, op_pin_state_pinned);
+       set_irg_pinned(irg, op_pin_state_pinned);
 }
 
 /**
@@ -250,15 +252,13 @@ static void place_early(waitq *worklist) {
  *
  * @return  the deepest common dominator tree ancestor of block and dca
  */
-static ir_node *calc_dom_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;
+static ir_node *calc_dom_dca(ir_node *dca, ir_node *block)
+{
+       assert(block != NULL);
 
        /* We found a first legal placement. */
-       if (!dca) return block;
+       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))
@@ -293,6 +293,8 @@ static ir_node *consumer_dom_dca(ir_node *dca, ir_node *consumer, ir_node *produ
                for (i = 0;  i < arity; i++) {
                        if (get_Phi_pred(consumer, i) == producer) {
                                ir_node *new_block = get_Block_cfgpred_block(phi_block, i);
+                               if (is_Bad(new_block))
+                                       continue;
 
                                if (!is_Block_unreachable(new_block))
                                        dca = calc_dom_dca(dca, new_block);
@@ -304,18 +306,20 @@ static ir_node *consumer_dom_dca(ir_node *dca, ir_node *consumer, ir_node *produ
        return dca;
 }
 
-static inline int get_block_loop_depth(ir_node *block) {
+static inline int get_block_loop_depth(ir_node *block)
+{
        return get_loop_depth(get_irn_loop(block));
 }
 
 /**
- * Move n to a block with less loop depth than it's current block. The
+ * Move n to a block with less loop depth than its 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) {
+static void move_out_of_loops(ir_node *n, ir_node *early)
+{
        ir_node *best, *dca;
        assert(n && early);
 
@@ -347,7 +351,8 @@ static void move_out_of_loops(ir_node *n, ir_node *early) {
  *
  * @return the deepest common dominator ancestor of all blocks of node's users
  */
-static ir_node *get_deepest_common_dom_ancestor(ir_node *node, ir_node *dca) {
+static ir_node *get_deepest_common_dom_ancestor(ir_node *node, ir_node *dca)
+{
        int i;
 
        for (i = get_irn_n_outs(node) - 1; i >= 0; --i) {
@@ -382,7 +387,8 @@ static ir_node *get_deepest_common_dom_ancestor(ir_node *node, ir_node *dca) {
  * @param node   the mode_T node
  * @param block  the block to put the Proj nodes to
  */
-static void set_projs_block(ir_node *node, ir_node *block) {
+static void set_projs_block(ir_node *node, ir_node *block)
+{
        int i;
 
        for (i = get_irn_n_outs(node) - 1; i >= 0; --i) {
@@ -409,7 +415,8 @@ static void set_projs_block(ir_node *node, ir_node *block) {
  * @param worklist  a worklist, all successors of non-floating nodes are
  *                  placed here
  */
-static void place_floats_late(ir_node *n, pdeq *worklist) {
+static void place_floats_late(ir_node *n, pdeq *worklist)
+{
        int i, n_outs;
        ir_node *early_blk;
 
@@ -421,6 +428,7 @@ static void place_floats_late(ir_node *n, pdeq *worklist) {
        if (!is_Block(n) &&
            (!is_cfop(n)) &&
            (get_irn_mode(n) != mode_X)) {
+           ir_op *op;
                /* Remember the early_blk placement of this block to move it
                   out of loop no further than the early_blk placement. */
                early_blk = get_nodes_block(n);
@@ -445,27 +453,25 @@ static void place_floats_late(ir_node *n, pdeq *worklist) {
                                place_floats_late(succ, worklist);
                }
 
-               if (! is_Block_dead(early_blk)) {
-                       /* do only move things that where not dead */
-                       ir_op *op = get_irn_op(n);
-
-                       /* We have to determine the final block of this node... except for
-                          constants and Projs */
-                       if ((get_irn_pinned(n) == op_pin_state_floats) &&
-                           (op != op_Const)    &&
-                           (op != op_SymConst) &&
-                           (op != op_Proj))
-                       {
-                               /* deepest common ancestor in the dominator tree of all nodes'
-                                  blocks depending on us; our final placement has to dominate
-                                  DCA. */
-                               ir_node *dca = get_deepest_common_dom_ancestor(n, NULL);
-                               if (dca != NULL) {
-                                       set_nodes_block(n, dca);
-                                       move_out_of_loops(n, early_blk);
-                                       if (get_irn_mode(n) == mode_T) {
-                                               set_projs_block(n, get_nodes_block(n));
-                                       }
+               /* do only move things that where not dead */
+               op = get_irn_op(n);
+
+               /* We have to determine the final block of this node... except for
+                  constants and Projs */
+               if ((get_irn_pinned(n) == op_pin_state_floats) &&
+                       (op != op_Const)    &&
+                       (op != op_SymConst) &&
+                       (op != op_Proj))
+               {
+                       /* deepest common ancestor in the dominator tree of all nodes'
+                          blocks depending on us; our final placement has to dominate
+                          DCA. */
+                       ir_node *dca = get_deepest_common_dom_ancestor(n, NULL);
+                       if (dca != NULL) {
+                               set_nodes_block(n, dca);
+                               move_out_of_loops(n, early_blk);
+                               if (get_irn_mode(n) == mode_T) {
+                                       set_projs_block(n, get_nodes_block(n));
                                }
                        }
                }
@@ -488,52 +494,64 @@ static void place_floats_late(ir_node *n, pdeq *worklist) {
  *
  * @param worklist   the worklist containing the nodes to place
  */
-static void place_late(waitq *worklist) {
+static void place_late(ir_graph *irg, waitq *worklist)
+{
        assert(worklist);
-       inc_irg_visited(current_ir_graph);
+       inc_irg_visited(irg);
 
        /* This fills the worklist initially. */
-       place_floats_late(get_irg_start_block(current_ir_graph), worklist);
+       place_floats_late(get_irg_start_block(irg), worklist);
 
        /* And now empty the worklist again... */
        while (!waitq_empty(worklist)) {
-               ir_node *n = waitq_get(worklist);
+               ir_node *n = (ir_node*)waitq_get(worklist);
                if (!irn_visited(n))
                        place_floats_late(n, worklist);
        }
 }
 
 /* Code Placement. */
-void place_code(ir_graph *irg) {
+void place_code(ir_graph *irg)
+{
        waitq *worklist;
-       ir_graph *rem = current_ir_graph;
 
-       current_ir_graph = irg;
        remove_critical_cf_edges(irg);
 
        /* Handle graph state */
        assert(get_irg_phase_state(irg) != phase_building);
+       assure_irg_outs(irg);
        assure_doms(irg);
-
-       if (1 || get_irg_loopinfo_state(irg) != loopinfo_consistent) {
-               free_loop_information(irg);
-               construct_cf_backedges(irg);
-       }
+       assure_cf_loop(irg);
 
        /* Place all floating nodes as early as possible. This guarantees
         a legal code placement. */
        worklist = new_waitq();
-       place_early(worklist);
+       place_early(irg, worklist);
 
        /* Note: place_early changes only blocks, no data edges. So, the
         * data out edges are still valid, no need to recalculate them here. */
 
        /* Now move the nodes down in the dominator tree. This reduces the
           unnecessary executions of the node. */
-       place_late(worklist);
+       place_late(irg, worklist);
 
        set_irg_outs_inconsistent(irg);
        set_irg_loopinfo_inconsistent(irg);
        del_waitq(worklist);
-       current_ir_graph = rem;
+}
+
+/**
+ * Wrapper for place_code() inside the place_code pass.
+ */
+static void place_code_wrapper(ir_graph *irg)
+{
+       set_opt_global_cse(1);
+       optimize_graph_df(irg);
+       place_code(irg);
+       set_opt_global_cse(0);
+}
+
+ir_graph_pass_t *place_code_pass(const char *name)
+{
+       return def_graph_pass(name ? name : "place", place_code_wrapper);
 }