Commit 77b6e60b authored by Matthias Braun's avatar Matthias Braun
Browse files

changed condeval to handle Phibs

[r14952]
parent cee29ffc
...@@ -191,17 +191,20 @@ static void split_critical_edge(ir_node *block, int pos) { ...@@ -191,17 +191,20 @@ static void split_critical_edge(ir_node *block, int pos) {
set_Block_cfgpred(block, pos, new_jmp); set_Block_cfgpred(block, pos, new_jmp);
} }
typedef struct _condeval_env_t { typedef struct condeval_env_t {
ir_node *true_block; ir_node *true_block;
pn_Cmp pnc; pn_Cmp pnc;
ir_node *cnst; ir_node *cnst;
unsigned long visited_nr; tarval *tv;
unsigned long visited_nr;
ir_node *cnst_pred; /**< the block before the constant */
int cnst_pos; /**< the pos to the constant block (needed to kill that edge later) */ ir_node *cnst_pred; /**< the block before the constant */
int cnst_pos; /**< the pos to the constant block (needed to
kill that edge later) */
} condeval_env_t; } condeval_env_t;
static void copy_and_fix(ir_node *block, ir_node *copy_block, int j, const condeval_env_t *env) { static void copy_and_fix(const condeval_env_t *env, ir_node *block,
ir_node *copy_block, int j) {
const ir_edge_t *edge; const ir_edge_t *edge;
/* Look at all nodes in the cond_block and copy them into pred */ /* Look at all nodes in the cond_block and copy them into pred */
...@@ -213,8 +216,10 @@ static void copy_and_fix(ir_node *block, ir_node *copy_block, int j, const conde ...@@ -213,8 +216,10 @@ static void copy_and_fix(ir_node *block, ir_node *copy_block, int j, const conde
/* ignore control flow */ /* ignore control flow */
if (mode == mode_X || is_Cond(node)) if (mode == mode_X || is_Cond(node))
continue; continue;
/* we may not copy mode_b nodes, because this could produce phi with mode_bs which can't #if 1
be handled in all backends. Instead we duplicate the node and move it to it's users */ /* we may not copy mode_b nodes, because this could produce phi with
* mode_bs which can't be handled in all backends. Instead we duplicate
* the node and move it to it's users */
if (mode == mode_b) { if (mode == mode_b) {
const ir_edge_t *edge, *next; const ir_edge_t *edge, *next;
ir_node *pred; ir_node *pred;
...@@ -241,6 +246,7 @@ static void copy_and_fix(ir_node *block, ir_node *copy_block, int j, const conde ...@@ -241,6 +246,7 @@ static void copy_and_fix(ir_node *block, ir_node *copy_block, int j, const conde
} }
continue; continue;
} }
#endif
/* we can evaluate Phis right now, all other nodes get copied */ /* we can evaluate Phis right now, all other nodes get copied */
if (is_Phi(node)) { if (is_Phi(node)) {
...@@ -297,7 +303,8 @@ static int eval_cmp(pn_Cmp pnc, tarval *tv1, tarval *tv2) { ...@@ -297,7 +303,8 @@ static int eval_cmp(pn_Cmp pnc, tarval *tv1, tarval *tv2) {
return 1; return 1;
} }
static ir_node *find_phi_with_const(ir_node *jump, ir_node *value, condeval_env_t *env) { static ir_node *find_const(condeval_env_t *env, ir_node *jump, ir_node *value)
{
ir_node *block = get_nodes_block(jump); ir_node *block = get_nodes_block(jump);
if(irn_visited(value)) if(irn_visited(value))
...@@ -306,10 +313,11 @@ static ir_node *find_phi_with_const(ir_node *jump, ir_node *value, condeval_env_ ...@@ -306,10 +313,11 @@ static ir_node *find_phi_with_const(ir_node *jump, ir_node *value, condeval_env_
if(is_Const(value)) { if(is_Const(value)) {
tarval *tv_const = get_Const_tarval(env->cnst); tarval *tv_const = get_Const_tarval(env->cnst);
tarval *tv = get_Const_tarval(value); tarval *tv = get_Const_tarval(value);
if(!eval_cmp(env->pnc, tv, tv_const)) if(!eval_cmp(env->pnc, tv, tv_const)) {
return NULL; return NULL;
}
DB(( DB((
dbg, LEVEL_1, dbg, LEVEL_1,
...@@ -332,25 +340,26 @@ static ir_node *find_phi_with_const(ir_node *jump, ir_node *value, condeval_env_ ...@@ -332,25 +340,26 @@ static ir_node *find_phi_with_const(ir_node *jump, ir_node *value, condeval_env_
int i, arity; int i, arity;
// the phi has to be in the same block as the jump // the phi has to be in the same block as the jump
if(get_nodes_block(value) != block) if(get_nodes_block(value) != block) {
return NULL; return NULL;
}
arity = get_irn_arity(value); arity = get_irn_arity(value);
for(i = 0; i < arity; ++i) { for(i = 0; i < arity; ++i) {
ir_node *copy_block; ir_node *copy_block;
ir_node *phi_pred = get_Phi_pred(value, i); ir_node *phi_pred = get_Phi_pred(value, i);
ir_node *cfgpred = get_Block_cfgpred(block, i); ir_node *cfgpred = get_Block_cfgpred(block, i);
copy_block = find_phi_with_const(cfgpred, phi_pred, env); copy_block = find_const(env, cfgpred, phi_pred);
if(copy_block == NULL) if(copy_block == NULL)
continue; continue;
/* copy duplicated nodes in copy_block and fix SSA */ /* copy duplicated nodes in copy_block and fix SSA */
copy_and_fix(block, copy_block, i, env); copy_and_fix(env, block, copy_block, i);
if(copy_block == get_nodes_block(cfgpred)) { if(copy_block == get_nodes_block(cfgpred)) {
env->cnst_pred = block; env->cnst_pred = block;
env->cnst_pos = i; env->cnst_pos = i;
} }
// return now as we can't process more possibilities in 1 run // return now as we can't process more possibilities in 1 run
...@@ -361,94 +370,110 @@ static ir_node *find_phi_with_const(ir_node *jump, ir_node *value, condeval_env_ ...@@ -361,94 +370,110 @@ static ir_node *find_phi_with_const(ir_node *jump, ir_node *value, condeval_env_
return NULL; return NULL;
} }
static ir_node *find_candidate(condeval_env_t *env, ir_node *jump,
static int cond_eval_cmp(ir_node* proj_b, ir_node* block, ir_node* projx, ir_node* cond) ir_node *value)
{ {
ir_graph *irg = current_ir_graph; ir_node *block = get_nodes_block(jump);
ir_node *cmp = get_Proj_pred(proj_b);
ir_node *left; if(irn_visited(value)) {
ir_node *right; return NULL;
ir_node *cond_block;
ir_node *copy_block;
pn_Cmp pnc;
assert(is_Cmp(cmp));
left = get_Cmp_left(cmp);
right = get_Cmp_right(cmp);
assert(get_irn_mode(left) == get_irn_mode(right));
pnc = get_Proj_proj(proj_b);
/* we assume that the cond_block is the true case */
if (get_Proj_proj(projx) == pn_Cond_false) {
pnc = get_negated_pnc(pnc, get_irn_mode(left));
} }
mark_irn_visited(value);
if(is_Const(value)) {
tarval *tv = get_Const_tarval(value);
if(tv != env->tv)
return NULL;
DB((
dbg, LEVEL_1,
"> Found condition evaluation candidate %+F->%+F\n",
env->true_block, block
));
// adjust true_block to point directly towards our jump
add_pred(env->true_block, jump);
split_critical_edge(env->true_block, 0);
/* we assume that the constant is on the right side, swap left/right // we need a bigger visited nr when going back
* if needed */ env->visited_nr++;
if(is_Const(left)) {
ir_node *t = left;
left = right;
right = t;
pnc = get_inversed_pnc(pnc); return block;
} }
if(is_Phi(value)) {
int i, arity;
if(!is_Const(right)) // the phi has to be in the same block as the jump
return 0; if(get_nodes_block(value) != block)
return NULL;
cond_block = get_nodes_block(cond); arity = get_irn_arity(value);
for(i = 0; i < arity; ++i) {
ir_node *copy_block;
ir_node *phi_pred = get_Phi_pred(value, i);
ir_node *cfgpred = get_Block_cfgpred(block, i);
// special case: comparing a constant with a constant copy_block = find_candidate(env, cfgpred, phi_pred);
if(is_Const(left)) { if(copy_block == NULL)
tarval *tv1 = get_Const_tarval(left); continue;
tarval *tv2 = get_Const_tarval(right);
ir_node *pred; /* copy duplicated nodes in copy_block and fix SSA */
if(eval_cmp(pnc, tv1, tv2)) { copy_and_fix(env, block, copy_block, i);
pred = new_r_Jmp(irg, cond_block);
} else { if(copy_block == get_nodes_block(cfgpred)) {
pred = new_Bad(); env->cnst_pred = block;
env->cnst_pos = i;
}
// return now as we can't process more possibilities in 1 run
return copy_block;
} }
set_Block_cfgpred(block, 0, pred); }
} else { if(is_Proj(value)) {
condeval_env_t env; ir_node *left;
ir_node *right;
int pnc;
ir_node *cmp = get_Proj_pred(value);
if(!is_Cmp(cmp))
return NULL;
if(get_nodes_block(left) != cond_block) left = get_Cmp_left(cmp);
return 0; right = get_Cmp_right(cmp);
pnc = get_Proj_proj(value);
// (recursively) look if a pred of a phi is a constant /* we assume that the constant is on the right side, swap left/right
env.true_block = block; * if needed */
env.pnc = pnc; if(is_Const(left)) {
env.cnst = right; ir_node *t = left;
inc_irg_visited(current_ir_graph); left = right;
env.visited_nr = get_irg_visited(irg); right = t;
copy_block = find_phi_with_const(projx, left, &env); pnc = get_inversed_pnc(pnc);
}
if (copy_block == NULL) if(!is_Const(right))
return 0; return 0;
/* we have to remove the edge towards the pred as the pred now if(get_nodes_block(left) != block) {
* jumps into the true_block. We also have to shorten phis return 0;
* in our block because of this */ }
const ir_edge_t *edge, *next;
ir_node* bad = new_Bad();
size_t cnst_pos = env.cnst_pos;
/* shorten phis */
foreach_out_edge_safe(env.cnst_pred, edge, next) {
ir_node *node = get_edge_src_irn(edge);
if(is_Phi(node)) /* negate condition when we're looking for the false block */
set_Phi_pred(node, cnst_pos, bad); if(env->tv == get_tarval_b_false()) {
pnc = get_negated_pnc(pnc, get_irn_mode(right));
} }
set_Block_cfgpred(env.cnst_pred, cnst_pos, bad); // (recursively) look if a pred of a phi is a constant
env->pnc = pnc;
env->cnst = right;
return find_const(env, jump, left);
} }
/* the graph is changed now */
return 1;
}
return NULL;
}
/** /**
* Block-walker: searches for the following construct * Block-walker: searches for the following construct
...@@ -465,10 +490,15 @@ static int cond_eval_cmp(ir_node* proj_b, ir_node* block, ir_node* projx, ir_nod ...@@ -465,10 +490,15 @@ static int cond_eval_cmp(ir_node* proj_b, ir_node* block, ir_node* projx, ir_nod
*/ */
static void cond_eval(ir_node* block, void* data) static void cond_eval(ir_node* block, void* data)
{ {
condeval_env_t env;
int *changed = data; int *changed = data;
ir_node *pred; ir_node *selector;
ir_node *projx; ir_node *projx;
ir_node *cond; ir_node *cond;
ir_node *copy_block;
const ir_edge_t *edge, *next;
ir_node* bad;
size_t cnst_pos;
if(get_Block_n_cfgpreds(block) != 1) if(get_Block_n_cfgpreds(block) != 1)
return; return;
...@@ -482,15 +512,44 @@ static void cond_eval(ir_node* block, void* data) ...@@ -482,15 +512,44 @@ static void cond_eval(ir_node* block, void* data)
if (!is_Cond(cond)) if (!is_Cond(cond))
return; return;
pred = get_Cond_selector(cond); selector = get_Cond_selector(cond);
// TODO handle switches // TODO handle switch Conds
if (get_irn_mode(pred) != mode_b) if (get_irn_mode(selector) != mode_b)
return; return;
if (!is_Proj(pred))
if (get_Proj_proj(projx) == pn_Cond_false) {
env.tv = get_tarval_b_false();
} else {
env.tv = get_tarval_b_true();
}
// (recursively) look if a pred of a phi is a constant
env.true_block = block;
inc_irg_visited(current_ir_graph);
env.visited_nr = get_irg_visited(current_ir_graph);
copy_block = find_candidate(&env, projx, selector);
if (copy_block == NULL)
return; return;
if (cond_eval_cmp(pred, block, projx, cond)) /* we have to remove the edge towards the pred as the pred now
*changed = 1; * jumps into the true_block. We also have to shorten phis
* in our block because of this */
bad = new_Bad();
cnst_pos = env.cnst_pos;
/* shorten phis */
foreach_out_edge_safe(env.cnst_pred, edge, next) {
ir_node *node = get_edge_src_irn(edge);
if(is_Phi(node))
set_Phi_pred(node, cnst_pos, bad);
}
set_Block_cfgpred(env.cnst_pred, cnst_pos, bad);
/* the graph is changed now */
*changed = 1;
} }
void opt_cond_eval(ir_graph* irg) void opt_cond_eval(ir_graph* irg)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment