becopyheur2: Cache the admissible registers eagerly.
[libfirm] / ir / ir / unreachable.c
index ea58a1e..dd13f87 100644 (file)
@@ -1,24 +1,19 @@
 /*
- * Copyright (C) 2011 University of Karlsruhe.  All right reserved.
- *
  * This file is part of libFirm.
- *
- * This file may be distributed and/or modified under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation and appearing in the file LICENSE.GPL included in the
- * packaging of this file.
- *
- * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
- * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE.
+ * Copyright (C) 2012 University of Karlsruhe.
  */
 
 /**
- * @brief    Convert all unreachable blocks into Bad nodes
+ * @brief    Remove unreachable code
  * @author   Andreas Zwinkau
+ *
+ * This is done by elminiating all edges into the unreachable code. So that
+ * after that the unreachable code should be dead.
  */
 #include "config.h"
 
+#include "irgopt.h"
+
 #include <assert.h>
 #include <stdbool.h>
 
 #include "irgwalk.h"
 #include "irtools.h"
 
+static bool is_block_unreachable(ir_node *block)
+{
+       return get_Block_dom_depth(block) < 0;
+}
+
 /**
- * Block-walker
+ * Eliminate block- and phi-inputs pointing to unreachable code
  */
 static void unreachable_to_bad(ir_node *node, void *env)
 {
        bool *changed = (bool *)env;
-       ir_graph *irg = get_irn_irg(node);
 
        if (is_Block(node)) {
-               if (get_Block_dom_depth(node) < 0) {
-                       exchange(node, new_r_Bad(irg, mode_BB));
+               ir_graph *irg;
+               int       arity;
+               int       i;
+               /* optimisation: we do not have to do anything inside the unreachable
+                * code */
+               if (is_block_unreachable(node))
+                       return;
+
+               arity = get_irn_arity(node);
+               irg   = get_irn_irg(node);
+               for (i = 0; i < arity; ++i) {
+                       ir_node *pred = get_Block_cfgpred(node, i);
+                       if (is_Bad(pred) || !is_block_unreachable(get_nodes_block(pred)))
+                               continue;
+                       set_irn_n(node, i, new_r_Bad(irg, mode_X));
                        *changed = true;
                }
-       } else if (is_Bad(node)) {
-               /* nothing to do */
-       } else {
-               ir_node *block = get_nodes_block(node);
-               if (is_Bad(block) || get_Block_dom_depth(block) < 0) {
-                       exchange(node, new_r_Bad(irg, get_irn_mode(node)));
+       } else if (is_Phi(node)) {
+               ir_node  *block = get_nodes_block(node);
+               int       arity;
+               int       i;
+               ir_graph *irg;
+               /* optimisation: we do not have to do anything inside the unreachable
+                * code */
+               if (is_block_unreachable(block))
+                       return;
+
+               irg   = get_irn_irg(node);
+               arity = get_irn_arity(node);
+               for (i = 0; i < arity; ++i) {
+                       ir_node *block_pred;
+                       ir_node *phi_pred = get_irn_n(node, i);
+                       if (is_Bad(phi_pred))
+                               continue;
+                       block_pred = get_Block_cfgpred(block, i);
+                       if (!is_Bad(block_pred) && !is_block_unreachable(get_nodes_block(block_pred)))
+                               continue;
+
+                       set_irn_n(node, i, new_r_Bad(irg, get_irn_mode(node)));
                        *changed = true;
                }
        }
 }
 
-/*
- * Transforms unreachable blocks and the nodes within into Bad nodes
+/**
+ * remove kept nodes in unreachable blocks
  */
-void remove_unreachable_blocks(ir_graph *irg)
+static void remove_unreachable_keeps(ir_graph *irg)
+{
+       ir_node  *end       = get_irg_end(irg);
+       int       arity     = get_irn_arity(end);
+       ir_node **new_in    = XMALLOCN(ir_node*, arity);
+       int       new_arity = 0;
+       int       i;
+
+       for (i = 0; i < arity; ++i) {
+               ir_node *ka    = get_End_keepalive(end, i);
+               ir_node *block = is_Block(ka) ? ka : get_nodes_block(ka);
+               if (is_block_unreachable(block))
+                       continue;
+               new_in[new_arity++] = ka;
+       }
+       if (new_arity != arity)
+               set_End_keepalives(end, new_arity, new_in);
+       free(new_in);
+}
+
+void remove_unreachable_code(ir_graph *irg)
 {
        bool changed = false;
 
-       assure_doms(irg);
+       assure_irg_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE);
 
        irg_walk_graph(irg, unreachable_to_bad, NULL, &changed);
+       remove_unreachable_keeps(irg);
 
-       if (changed) {
-               edges_deactivate(irg);
-               clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_OUTS);
-               clear_irg_state(irg, IR_GRAPH_STATE_NO_BAD_BLOCKS);
-       }
-       set_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE);
+       confirm_irg_properties(irg, changed
+               ? IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES
+               | IR_GRAPH_PROPERTY_NO_TUPLES
+               | IR_GRAPH_PROPERTY_ONE_RETURN
+               | IR_GRAPH_PROPERTY_MANY_RETURNS
+               : IR_GRAPH_PROPERTIES_ALL);
+       add_irg_properties(irg, IR_GRAPH_PROPERTY_NO_UNREACHABLE_CODE);
 }