Refactoring
[libfirm] / ir / lower / lower_switch.c
index bc6eed0..d12190a 100644 (file)
@@ -36,7 +36,7 @@
 #include "irouts.h"
 #include "irpass_t.h"
 
-#define foreach_out_irn(irn, i, outirn) for(i = get_irn_n_outs(irn) - 1;\
+#define foreach_out_irn(irn, i, outirn) for (i = get_irn_n_outs(irn) - 1;\
        i >= 0 && (outirn = get_irn_out(irn, i)); --i)
 
 typedef struct walk_env {
@@ -100,7 +100,14 @@ static int casecmp(const void *a, const void *b)
 {
        const case_data_t *cda = a;
        const case_data_t *cdb = b;
-       return (cda->value > cdb->value) - (cda->value < cdb->value);
+
+       /*
+        * Enforce unsigned sorting. Signed comparison will behave differently for
+        * 32-bit values, depending on sizeof(long). This will make the resulting
+        * array deterministic.
+        */
+       return ((unsigned long)cda->value > (unsigned long)cdb->value) -
+              ((unsigned long)cda->value < (unsigned long)cdb->value);
 }
 
 /**
@@ -109,6 +116,27 @@ static int casecmp(const void *a, const void *b)
 static void create_if_cascade(ifcas_env_t *env, ir_node *curblock,
                               case_data_t *curcases, int numcases)
 {
+    ir_mode *cmp_mode;
+    ir_node *cmp_sel;
+    ir_node *sel_block;
+
+    /* Get the mode and sel node for the comparison. */
+    cmp_mode  = get_irn_mode(env->sel);
+    cmp_sel   = env->sel;
+    sel_block = get_nodes_block(cmp_sel);
+
+    /*
+     * Make sure that an unsigned comparison is used, by converting the sel
+     * node to an unsigned mode and using that mode for the constants, too.
+     * This is important, because the qsort applied to the case labels uses
+     * an unsigned comparison and both comparison methods have to match.
+     */
+    if (mode_is_signed(cmp_mode))
+    {
+        cmp_mode = find_unsigned_mode(cmp_mode);
+        cmp_sel  = new_r_Conv(sel_block, cmp_sel, cmp_mode);
+    }
+
        assert(numcases >= 0);
 
        set_cur_block(curblock);
@@ -117,17 +145,17 @@ static void create_if_cascade(ifcas_env_t *env, ir_node *curblock,
                /* zero cases: "goto default;" */
                env->defusers[env->defindex++] = new_Jmp();
        } else if (numcases == 1) {
-               /* only one case: "if(sel == val) goto target else goto default;" */
-               ir_node *val  = new_Const_long(get_irn_mode(env->sel), curcases[0].value);
-               ir_node *cmp  = new_Cmp(env->sel, val);
+               /* only one case: "if (sel == val) goto target else goto default;" */
+               ir_node *val  = new_Const_long(cmp_mode, curcases[0].value);
+               ir_node *cmp  = new_Cmp(cmp_sel, val);
                ir_node *proj = new_Proj(cmp, mode_b, pn_Cmp_Eq);
                ir_node *cond = new_Cond(proj);
                set_Block_cfgpred(curcases[0].target, 0, new_Proj(cond, mode_X, pn_Cond_true));
                env->defusers[env->defindex++] = new_Proj(cond, mode_X, pn_Cond_false);
        } else if (numcases == 2) {
-               /* only two cases: "if(sel == val[0]) goto target[0];" */
-               ir_node *val  = new_Const_long(get_irn_mode(env->sel), curcases[0].value);
-               ir_node *cmp  = new_Cmp(env->sel, val);
+               /* only two cases: "if (sel == val[0]) goto target[0];" */
+               ir_node *val  = new_Const_long(cmp_mode, curcases[0].value);
+               ir_node *cmp  = new_Cmp(cmp_sel, val);
                ir_node *proj = new_Proj(cmp, mode_b, pn_Cmp_Eq);
                ir_node *cond = new_Cond(proj);
                ir_node *in[1];
@@ -138,9 +166,9 @@ static void create_if_cascade(ifcas_env_t *env, ir_node *curblock,
                neblock = new_Block(1, in);
                set_cur_block(neblock);
 
-               /* second part: "else if(sel == val[1]) goto target[1] else goto default;" */
-               val  = new_Const_long(get_irn_mode(env->sel), curcases[1].value);
-               cmp  = new_Cmp(env->sel, val);
+               /* second part: "else if (sel == val[1]) goto target[1] else goto default;" */
+               val  = new_Const_long(cmp_mode, curcases[1].value);
+               cmp  = new_Cmp(cmp_sel, val);
                proj = new_Proj(cmp, mode_b, pn_Cmp_Eq);
                cond = new_Cond(proj);
                set_Block_cfgpred(curcases[1].target, 0, new_Proj(cond, mode_X, pn_Cond_true));
@@ -148,8 +176,8 @@ static void create_if_cascade(ifcas_env_t *env, ir_node *curblock,
        } else {
                /* recursive case: split cases in the middle */
                int midcase = numcases / 2;
-               ir_node *val  = new_Const_long(get_irn_mode(env->sel), curcases[midcase].value);
-               ir_node *cmp  = new_Cmp(env->sel, val);
+               ir_node *val  = new_Const_long(cmp_mode, curcases[midcase].value);
+               ir_node *cmp  = new_Cmp(cmp_sel, val);
                ir_node *proj = new_Proj(cmp, mode_b, pn_Cmp_Lt);
                ir_node *cond = new_Cond(proj);
                ir_node *in[1];
@@ -289,7 +317,8 @@ struct pass_t {
 /**
  * Wrapper for running lower_switch() as a pass.
  */
-static int pass_wrapper(ir_graph *irg, void *context) {
+static int pass_wrapper(ir_graph *irg, void *context)
+{
        struct pass_t *pass = context;
 
        lower_switch(irg, pass->spare_size);
@@ -297,7 +326,8 @@ static int pass_wrapper(ir_graph *irg, void *context) {
 }
 
 /* creates a pass for lower_switch */
-ir_graph_pass_t *lower_switch_pass(const char *name, unsigned spare_size) {
+ir_graph_pass_t *lower_switch_pass(const char *name, unsigned spare_size)
+{
        struct pass_t *pass = XMALLOCZ(struct pass_t);
 
        pass->spare_size = spare_size;