cdep: Remove unnecessary start block test.
[libfirm] / ir / ana / irconsconfirm.c
index c2821fb..9c10ca3 100644 (file)
@@ -22,7 +22,6 @@
  * @brief    Construction of Confirm nodes
  * @author   Michael Beck
  * @date     6.2005
- * @version  $Id$
  */
 #include "config.h"
 
@@ -41,6 +40,7 @@
 #include "irtools.h"
 #include "array_t.h"
 #include "debug.h"
+#include "error.h"
 #include "irflag.h"
 
 /**
@@ -75,32 +75,51 @@ static ir_node *get_effective_use_block(ir_node *node, int pos)
        return get_nodes_block(node);
 }
 
+static ir_node *get_case_value(ir_node *switchn, long pn)
+{
+       ir_graph              *irg       = get_irn_irg(switchn);
+       const ir_switch_table *table     = get_Switch_table(switchn);
+       size_t                 n_entries = ir_switch_table_get_n_entries(table);
+       ir_tarval             *val       = NULL;
+       size_t                 e;
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               if (entry->pn != pn)
+                       continue;
+               /* multiple matching entries gets too complicated for a single
+                * Confirm */
+               if (val != NULL)
+                       return NULL;
+               /* case ranges are too complicated too */
+               if (entry->min != entry->max)
+                       return NULL;
+               val = entry->min;
+       }
+       assert(val != NULL);
+       return new_r_Const(irg, val);
+}
+
 /**
  * Handle a CASE-branch.
  *
- * @param block   the block which is entered by the branch
- * @param irn     the node expressing the switch value
- * @param nr      the branch label
- * @param env     statistical environment
- *
  * Branch labels are a simple case. We can replace the value
  * by a Const with the branch label.
  */
-static void handle_case(ir_node *block, ir_node *irn, long nr, env_t *env)
+static void handle_case(ir_node *block, ir_node *switchn, long pn, env_t *env)
 {
-       const ir_edge_t *edge, *next;
        ir_node *c = NULL;
+       ir_node *selector = get_Switch_selector(switchn);
 
-       if (is_Bad(irn))
+       /* we can't do usefull things with the default label */
+       if (pn == pn_Switch_default)
                return;
 
-       for (edge = get_irn_out_edge_first(irn); edge; edge = next) {
+       foreach_out_edge_safe(selector, edge) {
                ir_node *succ = get_edge_src_irn(edge);
                int     pos   = get_edge_src_pos(edge);
                ir_node *blk  = get_effective_use_block(succ, pos);
 
-               next = get_irn_out_edge_next(irn, edge);
-
                if (block_dominates(block, blk)) {
                        /*
                         * Ok, we found a user of irn that is placed
@@ -108,21 +127,17 @@ static void handle_case(ir_node *block, ir_node *irn, long nr, env_t *env)
                         * We can replace the input with the Constant
                         * branch label.
                         */
-
-                       if (! c) {
-                               ir_mode   *mode = get_irn_mode(irn);
-                               ir_tarval *tv   = new_tarval_from_long(nr, mode);
-                               c = new_r_Const(current_ir_graph, tv);
-                       }
+                       if (c == NULL)
+                               c = get_case_value(switchn, pn);
 
                        set_irn_n(succ, pos, c);
-                       DBG_OPT_CONFIRM_C(irn, c);
+                       DBG_OPT_CONFIRM_C(selector, c);
                        DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
 
                        env->num_consts += 1;
                }
        }
-}  /* handle_case */
+}
 
 /**
  * Handle a mode_b input of Cond nodes.
@@ -136,14 +151,12 @@ static void handle_modeb(ir_node *block, ir_node *selector, pn_Cond pnc, env_t *
 {
        ir_node *cond, *old, *other_blk = NULL, *con = NULL;
        ir_node *c_b = NULL, *c_o = NULL;
-       const ir_edge_t *edge, *next;
 
-       for (edge = get_irn_out_edge_first(selector); edge; edge = next) {
+       foreach_out_edge_safe(selector, edge) {
                ir_node *user     = get_edge_src_irn(edge);
                int     pos       = get_edge_src_pos(edge);
                ir_node *user_blk = get_effective_use_block(user, pos);
 
-               next = get_irn_out_edge_next(selector, edge);
                if (block_dominates(block, user_blk)) {
                        /*
                         * Ok, we found a usage of selector in a block
@@ -253,22 +266,18 @@ static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
        ir_node *left  = get_Cmp_left(cmp);
        ir_node *right = get_Cmp_right(cmp);
        ir_node *cond_block;
-       ir_op *op;
-       const ir_edge_t *edge, *next;
 
        /* Beware of Bads */
        if (is_Bad(left) || is_Bad(right))
                return;
 
-       op = get_irn_op(left);
-
        /* Do not create Confirm nodes for Cmp(Const, Const) constructs.
           These are removed anyway */
-       if (op == op_Const && is_Const(right))
+       if (is_Const(left) && is_Const(right))
                return;
 
        /* try to place the constant on the right side for a Confirm */
-       if (op == op_Const || op == op_SymConst) {
+       if (is_Const(left) || is_SymConst(left)) {
                ir_node *t = left;
 
                left  = right;
@@ -283,12 +292,11 @@ static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
         */
        if (rel == ir_relation_equal) {
                cond_block = get_Block_cfgpred_block(block, 0);
-               for (edge = get_irn_out_edge_first(left); edge; edge = next) {
+               foreach_out_edge_safe(left, edge) {
                        ir_node *user = get_edge_src_irn(edge);
                        int     pos   = get_edge_src_pos(edge);
                        ir_node *blk  = get_effective_use_block(user, pos);
 
-                       next = get_irn_out_edge_next(left, edge);
                        if (block_dominates(block, blk)) {
                                /*
                                 * Ok, we found a usage of left in a block
@@ -308,14 +316,12 @@ static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
                                 * left == Const and we found a movable user of left in a
                                 * dominator of the Cond block
                                 */
-                               const ir_edge_t *edge, *next;
-                               for (edge = get_irn_out_edge_first(user); edge; edge = next) {
-                                       ir_node *usr_of_usr = get_edge_src_irn(edge);
-                                       int      npos = get_edge_src_pos(edge);
-                                       ir_node *blk  = get_effective_use_block(usr_of_usr, npos);
-
-                                       next = get_irn_out_edge_next(user, edge);
-                                       if (block_dominates(block, blk)) {
+                               foreach_out_edge_safe(user, user_edge) {
+                                       ir_node *usr_of_usr = get_edge_src_irn(user_edge);
+                                       int      npos       = get_edge_src_pos(user_edge);
+                                       ir_node *user_blk   = get_effective_use_block(usr_of_usr, npos);
+
+                                       if (block_dominates(block, user_blk)) {
                                                /*
                                                 * The user of the user is dominated by our true/false
                                                 * block. So, create a copy of user WITH the constant
@@ -342,7 +348,7 @@ static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
        } else { /* not ir_relation_equal cases */
                ir_node *c = NULL;
 
-               foreach_out_edge_safe(left, edge, next) {
+               foreach_out_edge_safe(left, edge) {
                        ir_node *succ = get_edge_src_irn(edge);
                        int     pos   = get_edge_src_pos(edge);
                        ir_node *blk  = get_effective_use_block(succ, pos);
@@ -369,7 +375,7 @@ static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
                        ir_node *rc = NULL;
 
                        rel = get_inversed_relation(rel);
-                       foreach_out_edge_safe(right, edge, next) {
+                       foreach_out_edge_safe(right, edge) {
                                ir_node *succ = get_edge_src_irn(edge);
                                int     pos;
                                ir_node *blk;
@@ -398,16 +404,16 @@ static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
                        }
                }
        }
-}  /* handle_if */
+}
 
 /**
  * Pre-block-walker: Called for every block to insert Confirm nodes
  */
 static void insert_Confirm_in_block(ir_node *block, void *data)
 {
-       ir_node *cond, *proj, *selector;
-       ir_mode *mode;
        env_t   *env = (env_t*) data;
+       ir_node *cond;
+       ir_node *proj;
 
        /*
         * we can only handle blocks with only ONE control flow
@@ -421,13 +427,11 @@ static void insert_Confirm_in_block(ir_node *block, void *data)
                return;
 
        cond = get_Proj_pred(proj);
-       if (! is_Cond(cond))
-               return;
-
-       selector = get_Cond_selector(cond);
-       mode = get_irn_mode(selector);
-
-       if (mode == mode_b) {
+       if (is_Switch(cond)) {
+               long proj_nr = get_Proj_proj(proj);
+               handle_case(block, cond, proj_nr, env);
+       } else if (is_Cond(cond)) {
+               ir_node *selector = get_Cond_selector(cond);
                ir_relation rel;
 
                handle_modeb(block, selector, (pn_Cond) get_Proj_proj(proj), env);
@@ -439,22 +443,13 @@ static void insert_Confirm_in_block(ir_node *block, void *data)
 
                if (get_Proj_proj(proj) != pn_Cond_true) {
                        /* it's the false branch */
-                       mode = get_irn_mode(get_Cmp_left(selector));
                        rel = get_negated_relation(rel);
                }
                DB((dbg, LEVEL_2, "At %+F using %+F Confirm %=\n", block, selector, rel));
 
                handle_if(block, selector, rel, env);
-       } else if (mode_is_int(mode)) {
-               long proj_nr = get_Proj_proj(proj);
-
-               /* this is a CASE, but we cannot handle the default case */
-               if (proj_nr == get_Cond_default_proj(cond))
-                       return;
-
-               handle_case(block, get_Cond_selector(cond), proj_nr, env);
        }
-}  /* insert_Confirm_in_block */
+}
 
 /**
  * Checks if a node is a non-null Confirm.
@@ -480,7 +475,7 @@ static int is_non_null_Confirm(const ir_node *ptr)
        if (is_SymConst_addr_ent(ptr))
                return 1;
        return 0;
-}  /* is_non_null_Confirm */
+}
 
 /**
  * The given pointer will be dereferenced, add non-null Confirms.
@@ -491,10 +486,9 @@ static int is_non_null_Confirm(const ir_node *ptr)
  */
 static void insert_non_null(ir_node *ptr, ir_node *block, env_t *env)
 {
-       const ir_edge_t *edge, *next;
-       ir_node         *c = NULL;
+       ir_node *c = NULL;
 
-       foreach_out_edge_safe(ptr, edge, next) {
+       foreach_out_edge_safe(ptr, edge) {
                ir_node *succ = get_edge_src_irn(edge);
                int     pos;
                ir_node *blk;
@@ -527,7 +521,7 @@ static void insert_non_null(ir_node *ptr, ir_node *block, env_t *env)
                        env->num_confirms += 1;
                }
        }
-}  /* insert_non_null */
+}
 
 /**
  * Pre-walker: Called for every node to insert Confirm nodes
@@ -554,31 +548,21 @@ static void insert_Confirm(ir_node *node, void *data)
        default:
                break;
        }
-}  /* insert_Confirm */
+}
 
-/*
- * Construct Confirm nodes
- */
 void construct_confirms(ir_graph *irg)
 {
        env_t env;
-       int edges_active = edges_activated(irg);
-
        FIRM_DBG_REGISTER(dbg, "firm.ana.confirm");
 
-       remove_critical_cf_edges(irg);
-
-       /* we need dominance info */
-       assure_doms(irg);
+       assure_irg_properties(irg,
+             IR_GRAPH_PROPERTY_CONSISTENT_OUT_EDGES
+               | IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE
+               | IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES);
 
        assert(get_irg_pinned(irg) == op_pin_state_pinned &&
               "Nodes must be placed to insert Confirms");
 
-       if (! edges_active) {
-               /* We need edges */
-               edges_activate(irg);
-       }
-
        env.num_confirms = 0;
        env.num_consts   = 0;
        env.num_eq       = 0;
@@ -592,29 +576,18 @@ void construct_confirms(ir_graph *irg)
                irg_block_walk_graph(irg, insert_Confirm_in_block, NULL, &env);
        }
 
-       if (env.num_confirms | env.num_consts | env.num_eq) {
-               /* we have add nodes or changed DF edges */
-               set_irg_outs_inconsistent(irg);
-
-               /* the new nodes are not in the loop info */
-               set_irg_loopinfo_inconsistent(irg);
-       }
-
        DB((dbg, LEVEL_1, "# Confirms inserted : %u\n", env.num_confirms));
        DB((dbg, LEVEL_1, "# Const replacements: %u\n", env.num_consts));
        DB((dbg, LEVEL_1, "# node equalities   : %u\n", env.num_eq));
        DB((dbg, LEVEL_1, "# non-null Confirms : %u\n", env.num_non_null));
 
-       /* deactivate edges if they where off */
-       if (! edges_active)
-               edges_deactivate(irg);
-}  /* construct_confirms */
+       confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
+}
 
-/* Construct a pass. */
 ir_graph_pass_t *construct_confirms_pass(const char *name)
 {
        return def_graph_pass(name ? name : "confirm", construct_confirms);
-}  /* construct_confirms_pass */
+}
 
 static void remove_confirm(ir_node *n, void *env)
 {
@@ -628,16 +601,13 @@ static void remove_confirm(ir_node *n, void *env)
        exchange(n, value);
 }
 
-/*
- * Remove all Confirm nodes from a graph.
- */
 void remove_confirms(ir_graph *irg)
 {
        irg_walk_graph(irg, NULL, remove_confirm, NULL);
-}  /* remove_confirms */
+       confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
+}
 
-/* Construct a pass. */
 ir_graph_pass_t *remove_confirms_pass(const char *name)
 {
        return def_graph_pass(name ? name : "rem_confirm", remove_confirms);
-}  /* remove_confirms_pass */
+}