X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fopt%2Freturn.c;h=59530d9d29f6b1b8990aa1b855c1114a4395594d;hb=98c8808ee1d34300860bb78185558e1731a99368;hp=3fa0cd2c9ea558cbb87adc27a307eca0f8229af8;hpb=2e3826ef502d31da98bb9679df02555d121194d9;p=libfirm diff --git a/ir/opt/return.c b/ir/opt/return.c index 3fa0cd2c9..59530d9d2 100644 --- a/ir/opt/return.c +++ b/ir/opt/return.c @@ -94,12 +94,12 @@ void normalize_one_return(ir_graph *irg) /* save the return values and shuffle them */ for (k = 0; k < n_ret_vals; ++k) - retvals[j + k*n_ret_vals] = get_irn_n(ret, k); - - ++j; + retvals[j + k*n_rets] = get_irn_n(ret, k); set_Block_cfgpred(endbl, i, new_r_Bad(irg)); last_idx = i; + + ++j; } } @@ -193,8 +193,14 @@ void normalize_n_returns(ir_graph *irg) ir_node *final = NULL; ir_node **in; ir_node *endbl = get_irg_end_block(irg); + ir_node *end; - /* first, link all returns */ + /* + * First, link all returns: + * These must be predecessors of the endblock. + * Place Returns that can be moved on list, all others + * on final. + */ n = get_Block_n_cfgpreds(endbl); for (n_finals = n_rets = i = 0; i < n; ++i) { ir_node *ret = get_Block_cfgpred(endbl, i); @@ -224,39 +230,73 @@ void normalize_n_returns(ir_graph *irg) * new Returns), than we check if a newly created Return can be moved even further. * If yes, we simply add it to our work list, else to the final list. */ + end = get_irg_end(irg); n_ret_vals = get_irn_arity(list); in = alloca(sizeof(*in) * n_ret_vals); while (list) { ir_node *ret = list; ir_node *block = get_nodes_block(ret); + ir_node *phiM; list = get_irn_link(ret); --n_rets; n = get_Block_n_cfgpreds(block); for (i = 0; i < n; ++i) { - ir_node *jmp = get_Block_cfgpred(block, i); - ir_node *new_bl = get_nodes_block(jmp); - ir_node *new_ret; + ir_node *jmp = get_Block_cfgpred(block, i); + ir_node *new_bl, *new_ret; + + if (get_irn_op(jmp) != op_Jmp) + continue; + + new_bl = get_nodes_block(jmp); /* create the in-array for the new Ret */ for (j = 0; j < n_ret_vals; ++j) { ir_node *pred = get_irn_n(ret, j); - in[j] = is_Phi(pred) ? get_Phi_pred(pred, i) : pred; + in[j] = (is_Phi(pred) && get_nodes_block(pred) == block) ? get_Phi_pred(pred, i) : pred; } new_ret = new_r_Return(irg, new_bl, in[0], n_ret_vals - 1, &in[1]); - if (can_move_ret(new_ret)) { - set_irn_link(new_ret, list); - list = new_ret; - ++n_rets; + if (! is_Bad(new_ret)) { + /* + * The newly created node might be bad, if we + * create it in a block with only Bad predecessors. + * In that case ignore this block. + * + * We could even kill the jmp then ... + */ + if (can_move_ret(new_ret)) { + set_irn_link(new_ret, list); + list = new_ret; + ++n_rets; + } + else { + set_irn_link(new_ret, final); + final = new_ret; + ++n_finals; + } } - else { - set_irn_link(new_ret, final); - final = new_ret; - ++n_finals; + + /* remove the Jmp, we have placed a Return here */ + exchange(jmp, new_r_Bad(irg)); + } + + /* + * if the memory of the old Return is a PhiM, remove it + * from the keep-alives, or it will keep the block which + * will crash the dominator algorithm. + */ + phiM = get_Return_mem(ret); + if (is_Phi(phiM)) { + n = get_End_n_keepalives(end); + for (i = 0; i < n; ++i) { + if (get_End_keepalive(end, i) == phiM) { + set_End_keepalive(end, i, new_r_Bad(irg)); + break; + } } } }