simplify/rework lower_calls interface and code
[libfirm] / ir / lower / lower_switch.c
index 8235df9..4ff2737 100644 (file)
@@ -44,6 +44,7 @@
 
 typedef struct walk_env_t {
        unsigned      spare_size; /**< the allowed spare size for table switches */
+       unsigned      small_switch;
        bool          allow_out_of_bounds;
        bool          changed;    /**< indicates whether a change was performed */
        ir_nodeset_t  processed;
@@ -143,9 +144,9 @@ static void create_if_cascade(cond_env_t *env, dbg_info *dbgi, ir_node *block,
        } else if (numcases == 1) {
                /* only one case: "if (sel == val) goto target else goto default;" */
                ir_node *val       = new_r_Const_long(irg, cmp_mode, curcases[0].value);
-               ir_node *cmp       = new_rd_Cmp(dbgi, block, cmp_sel, val);
-               ir_node *proj      = new_r_Proj(cmp, mode_b, pn_Cmp_Eq);
-               ir_node *cond      = new_rd_Cond(dbgi, block, proj);
+               ir_node *cmp       = new_rd_Cmp(dbgi, block, cmp_sel, val,
+                                               ir_relation_equal);
+               ir_node *cond      = new_rd_Cond(dbgi, block, cmp);
                ir_node *trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
                ir_node *falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
 
@@ -154,9 +155,9 @@ static void create_if_cascade(cond_env_t *env, dbg_info *dbgi, ir_node *block,
        } else if (numcases == 2) {
                /* only two cases: "if (sel == val[0]) goto target[0];" */
                ir_node *val       = new_r_Const_long(irg, cmp_mode, curcases[0].value);
-               ir_node *cmp       = new_rd_Cmp(dbgi, block, cmp_sel, val);
-               ir_node *proj      = new_r_Proj(cmp, mode_b, pn_Cmp_Eq);
-               ir_node *cond      = new_rd_Cond(dbgi, block, proj);
+               ir_node *cmp       = new_rd_Cmp(dbgi, block, cmp_sel, val,
+                                               ir_relation_equal);
+               ir_node *cond      = new_rd_Cond(dbgi, block, cmp);
                ir_node *trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
                ir_node *falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
                ir_node *in[1];
@@ -169,9 +170,8 @@ static void create_if_cascade(cond_env_t *env, dbg_info *dbgi, ir_node *block,
 
                /* second part: "else if (sel == val[1]) goto target[1] else goto default;" */
                val       = new_r_Const_long(irg, cmp_mode, curcases[1].value);
-               cmp       = new_rd_Cmp(dbgi, neblock, cmp_sel, val);
-               proj      = new_r_Proj(cmp, mode_b, pn_Cmp_Eq);
-               cond      = new_rd_Cond(dbgi, neblock, proj);
+               cmp       = new_rd_Cmp(dbgi, neblock, cmp_sel, val, ir_relation_equal);
+               cond      = new_rd_Cond(dbgi, neblock, cmp);
                trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
                falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
                set_Block_cfgpred(curcases[1].target, 0, trueproj);
@@ -181,9 +181,8 @@ static void create_if_cascade(cond_env_t *env, dbg_info *dbgi, ir_node *block,
                int midcase = numcases / 2;
                ir_node *val  = new_r_Const_long(irg, cmp_mode,
                                                 curcases[midcase].value);
-               ir_node *cmp  = new_rd_Cmp(dbgi, block, cmp_sel, val);
-               ir_node *proj = new_r_Proj(cmp, mode_b, pn_Cmp_Lt);
-               ir_node *cond = new_rd_Cond(dbgi, block, proj);
+               ir_node *cmp  = new_rd_Cmp(dbgi, block, cmp_sel, val, ir_relation_less);
+               ir_node *cond = new_rd_Cond(dbgi, block, cmp);
                ir_node *in[1];
                ir_node *ltblock;
                ir_node *geblock;
@@ -208,13 +207,12 @@ static void create_out_of_bounds_check(cond_env_t *env, ir_node *cond)
        ir_node       *block         = get_nodes_block(cond);
        ir_mode       *cmp_mode      = get_irn_mode(sel);
        ir_node      **default_preds = NEW_ARR_F(ir_node*, 0);
-       unsigned long  default_pn    = get_Cond_default_proj(cond);
+       long           default_pn    = get_Cond_default_proj(cond);
        long           delta         = 0;
        ir_node       *max_const;
        ir_node       *proj_true;
        ir_node       *proj_false;
        ir_node       *cmp;
-       ir_node       *proj_cmp;
        ir_node       *oob_cond;
        ir_node       *in[1];
        ir_node       *new_block;
@@ -240,9 +238,8 @@ static void create_out_of_bounds_check(cond_env_t *env, ir_node *cond)
 
        /* check for out-of-bounds */
        max_const  = new_r_Const_long(irg, cmp_mode, env->switch_max);
-       cmp        = new_rd_Cmp(dbgi, block, sel, max_const);
-       proj_cmp   = new_r_Proj(cmp, mode_b, pn_Cmp_Le);
-       oob_cond   = new_rd_Cond(dbgi, block, proj_cmp);
+       cmp        = new_rd_Cmp(dbgi, block, sel, max_const, ir_relation_less_equal);
+       oob_cond   = new_rd_Cond(dbgi, block, cmp);
        proj_true  = new_r_Proj(oob_cond, mode_X, pn_Cond_true);
        proj_false = new_r_Proj(oob_cond, mode_X, pn_Cond_false);
 
@@ -255,16 +252,10 @@ static void create_out_of_bounds_check(cond_env_t *env, ir_node *cond)
 
        /* adapt projs */
        foreach_out_irn(cond, i, proj) {
-               unsigned long pn     = get_Proj_proj(proj);
-               unsigned long new_pn = pn - delta;
+               long pn     = get_Proj_proj(proj);
+               long new_pn = pn - delta;
                if (pn == default_pn) {
-                       /* we might have to choose a new default_pn */
-                       if (pn < (unsigned long) env->switch_max) {
-                               new_pn = env->switch_max + 1;
-                               set_Cond_default_proj(cond, new_pn);
-                       } else {
-                               new_pn = default_pn;
-                       }
+                       set_Cond_default_proj(cond, new_pn);
                        ARR_APP1(ir_node*, default_preds, proj);
                }
 
@@ -275,18 +266,18 @@ static void create_out_of_bounds_check(cond_env_t *env, ir_node *cond)
        /* adapt default block */
        n_default_preds = ARR_LEN(default_preds);
        if (n_default_preds > 1) {
-               size_t i;
+               size_t p;
 
                /* create new intermediate blocks so we don't have critical edges */
-               for (i = 0; i < n_default_preds; ++i) {
-                       ir_node *proj = default_preds[i];
-                       ir_node *block;
-                       ir_node *in[1];
+               for (p = 0; p < n_default_preds; ++p) {
+                       ir_node *pred = default_preds[p];
+                       ir_node *split_block;
+                       ir_node *block_in[1];
 
-                       in[0] = proj;
-                       block = new_r_Block(irg, 1, in);
+                       block_in[0] = pred;
+                       split_block = new_r_Block(irg, 1, block_in);
 
-                       default_preds[i] = new_r_Jmp(block);
+                       default_preds[p] = new_r_Jmp(split_block);
                }
        }
        set_irn_in(env->default_block, n_default_preds, default_preds);
@@ -315,6 +306,7 @@ static void find_cond_nodes(ir_node *block, void *ctx)
        dbg_info    *dbgi;
        cond_env_t   cond_env;
        unsigned long spare;
+       bool         lower_switch = false;
 
        /* because we split critical blocks only blocks with 1 predecessors may
         * contain Proj->Cond nodes */
@@ -353,7 +345,10 @@ static void find_cond_nodes(ir_node *block, void *ctx)
        spare = (unsigned long) cond_env.switch_max
                - (unsigned long) cond_env.switch_min
                - (unsigned long) cond_env.num_cases + 1;
-       if (spare < env->spare_size) {
+       lower_switch |= spare >= env->spare_size;
+       lower_switch |= cond_env.num_cases <= env->small_switch;
+
+       if (!lower_switch) {
                /* we won't decompose the switch. But we might have to add
                 * out-of-bounds checking */
                if (!env->allow_out_of_bounds) {
@@ -409,11 +404,13 @@ static void find_cond_nodes(ir_node *block, void *ctx)
        DEL_ARR_F(cond_env.defusers);
 }
 
-void lower_switch(ir_graph *irg, unsigned spare_size, int allow_out_of_bounds)
+void lower_switch(ir_graph *irg, unsigned small_switch, unsigned spare_size,
+                  int allow_out_of_bounds)
 {
        walk_env_t env;
        env.changed             = false;
        env.spare_size          = spare_size;
+       env.small_switch        = small_switch;
        env.allow_out_of_bounds = allow_out_of_bounds;
        ir_nodeset_init(&env.processed);
 
@@ -425,9 +422,7 @@ void lower_switch(ir_graph *irg, unsigned spare_size, int allow_out_of_bounds)
 
        if (env.changed) {
                /* control flow changed */
-               set_irg_outs_inconsistent(irg);
                set_irg_doms_inconsistent(irg);
                set_irg_extblk_inconsistent(irg);
-               set_irg_loopinfo_inconsistent(irg);
        }
 }