* @version $Id$
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <limits.h>
+#include "array_t.h"
#include "ircons.h"
#include "irgopt.h"
#include "irgwalk.h"
#include "irnode_t.h"
#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 {
if (get_irn_n_outs(cond) <= 4)
return 0;
- default_pn = get_Cond_defaultProj(cond);
+ default_pn = get_Cond_default_proj(cond);
foreach_out_irn(cond, i, proj) {
long pn = get_Proj_proj(proj);
{
const case_data_t *cda = a;
const case_data_t *cdb = b;
- return 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);
}
/**
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);
/* 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];
set_Block_cfgpred(curcases[0].target, 0, new_Proj(cond, mode_X, pn_Cond_true));
in[0] = new_Proj(cond, mode_X, pn_Cond_false);
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));
} 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];
set_cur_block(curblock);
in[0] = new_Proj(cond, mode_X, pn_Cond_false);
geblock = new_Block(1, in);
+ set_cur_block(geblock);
create_if_cascade(env, ltblock, curcases, midcase);
create_if_cascade(env, geblock, curcases + midcase, numcases - midcase);
numcases = get_irn_n_outs(cond) - 1; // does not contain default case
NEW_ARR_A(case_data_t, cases, numcases);
- default_pn = get_Cond_defaultProj(cond);
+ default_pn = get_Cond_default_proj(cond);
ifcas_env.sel = sel;
ifcas_env.defindex = 0;
NEW_ARR_A(ir_node*, ifcas_env.defusers, numcases);
}
current_ir_graph = rem;
}
+
+struct pass_t {
+ ir_graph_pass_t pass;
+ unsigned spare_size;
+};
+
+/**
+ * Wrapper for running lower_switch() as a pass.
+ */
+static int pass_wrapper(ir_graph *irg, void *context)
+{
+ struct pass_t *pass = context;
+
+ lower_switch(irg, pass->spare_size);
+ return 0;
+}
+
+/* creates a pass for lower_switch */
+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;
+ return def_graph_pass_constructor(
+ &pass->pass, name ? name : "lower_switch", pass_wrapper);
+}