/*
- * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ * Copyright (C) 1995-2011 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
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;
static int casecmp(const void *a, const void *b)
{
- const case_data_t *cda = a;
- const case_data_t *cdb = b;
+ const case_data_t *cda = (const case_data_t*)a;
+ const case_data_t *cdb = (const case_data_t*)b;
/*
* Enforce unsigned sorting. Signed comparison will behave differently for
if (numcases == 0) {
/* zero cases: "goto default;" */
- ARR_APP1(ir_node*, env->defusers, new_Jmp());
+ ARR_APP1(ir_node*, env->defusers, new_r_Jmp(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);
} 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];
/* 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);
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;
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;
- int n_default_preds;
+ size_t n_default_preds;
int i;
ir_node *proj;
delta = env->switch_min;
env->switch_min = 0;
env->switch_max -= delta;
+ set_Cond_selector(cond, sel);
}
/* 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);
/* 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);
}
/* adapt default block */
n_default_preds = ARR_LEN(default_preds);
if (n_default_preds > 1) {
- int 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);
*/
static void find_cond_nodes(ir_node *block, void *ctx)
{
- walk_env_t *env = ctx;
+ walk_env_t *env = (walk_env_t *)ctx;
ir_node *projx;
ir_node *cond;
ir_node *sel;
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 */
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) {
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);
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);
}
}