diff options
author | Richard Henderson <rth@redhat.com> | 2004-07-21 17:45:54 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2004-07-21 17:45:54 -0700 |
commit | 224e770bb83f20c31314d51dbf4d0f40eba9e1ef (patch) | |
tree | f76180b06069421f5fd323fe2b9f515a1a0e8b83 /gcc/cfgexpand.c | |
parent | 7761cda3b43db109445811366799e8e269cd80df (diff) | |
download | gcc-224e770bb83f20c31314d51dbf4d0f40eba9e1ef.zip gcc-224e770bb83f20c31314d51dbf4d0f40eba9e1ef.tar.gz gcc-224e770bb83f20c31314d51dbf4d0f40eba9e1ef.tar.bz2 |
cfgexpand.c (expand_gimple_tailcall): Fix case where we need to create a new basic block.
* cfgexpand.c (expand_gimple_tailcall): Fix case where we need
to create a new basic block.
From-SVN: r85029
Diffstat (limited to 'gcc/cfgexpand.c')
-rw-r--r-- | gcc/cfgexpand.c | 128 |
1 files changed, 73 insertions, 55 deletions
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 5bcb59c..f4fe860 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -111,77 +111,95 @@ expand_gimple_cond_expr (basic_block bb, tree stmt) } /* A subroutine of expand_gimple_basic_block. Expand one CALL_EXPR - that has CALL_EXPR_TAILCALL set. Returns a new basic block if we've - terminated the current basic block and created a new one. */ + that has CALL_EXPR_TAILCALL set. Returns non-null if we actually + generated a tail call (something that might be denied by the ABI + rules governing the call; see calls.c). */ static basic_block expand_gimple_tailcall (basic_block bb, tree stmt) { rtx last = get_last_insn (); + edge e; + int probability; + gcov_type count; expand_expr_stmt (stmt); for (last = NEXT_INSN (last); last; last = NEXT_INSN (last)) - { - if (CALL_P (last) && SIBLING_CALL_P (last)) - { - edge e; - int probability = 0; - gcov_type count = 0; + if (CALL_P (last) && SIBLING_CALL_P (last)) + goto found; - do_pending_stack_adjust (); - e = bb->succ; - while (e) - { - edge next = e->succ_next; - - if (!(e->flags & (EDGE_ABNORMAL | EDGE_EH))) - { - if (e->dest != EXIT_BLOCK_PTR) - { - e->dest->count -= e->count; - e->dest->frequency -= EDGE_FREQUENCY (e); - if (e->dest->count < 0) - e->dest->count = 0; - if (e->dest->frequency < 0) - e->dest->frequency = 0; - } - count += e->count; - probability += e->probability; - remove_edge (e); - } - - e = next; - } + return NULL; + + found: + /* ??? Wouldn't it be better to just reset any pending stack adjust? + Any instructions emitted here are about to be deleted. */ + do_pending_stack_adjust (); - /* This is somewhat ugly: the call_expr expander often emits - instructions after the sibcall (to perform the function - return). These confuse the find_sub_basic_blocks code, - so we need to get rid of these. */ - last = NEXT_INSN (last); - if (!BARRIER_P (last)) - abort (); - while (NEXT_INSN (last)) + /* Remove any non-eh, non-abnormal edges that don't go to exit. */ + /* ??? I.e. the fallthrough edge. HOWEVER! If there were to be + EH or abnormal edges, we shouldn't have created a tail call in + the first place. So it seems to me we should just be removing + all edges here, or redirecting the existing fallthru edge to + the exit block. */ + + e = bb->succ; + probability = 0; + count = 0; + while (e) + { + edge next = e->succ_next; + + if (!(e->flags & (EDGE_ABNORMAL | EDGE_EH))) + { + if (e->dest != EXIT_BLOCK_PTR) { - /* For instance an sqrt builtin expander expands if with - sibcall in the then and label for `else`. */ - if (LABEL_P (NEXT_INSN (last))) - break; - delete_insn (NEXT_INSN (last)); + e->dest->count -= e->count; + e->dest->frequency -= EDGE_FREQUENCY (e); + if (e->dest->count < 0) + e->dest->count = 0; + if (e->dest->frequency < 0) + e->dest->frequency = 0; } - e = make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL | EDGE_SIBCALL); - e->probability += probability; - e->count += count; - BB_END (bb) = last; - update_bb_for_insn (bb); - if (NEXT_INSN (last)) - bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb); - else - return bb; + count += e->count; + probability += e->probability; + remove_edge (e); } + + e = next; } - return NULL; + /* This is somewhat ugly: the call_expr expander often emits instructions + after the sibcall (to perform the function return). These confuse the + find_sub_basic_blocks code, so we need to get rid of these. */ + last = NEXT_INSN (last); + if (!BARRIER_P (last)) + abort (); + while (NEXT_INSN (last)) + { + /* For instance an sqrt builtin expander expands if with + sibcall in the then and label for `else`. */ + if (LABEL_P (NEXT_INSN (last))) + break; + delete_insn (NEXT_INSN (last)); + } + + e = make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL | EDGE_SIBCALL); + e->probability += probability; + e->count += count; + BB_END (bb) = last; + update_bb_for_insn (bb); + + if (NEXT_INSN (last)) + { + bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb); + + last = BB_END (bb); + if (BARRIER_P (last)) + BB_END (bb) = PREV_INSN (last); + } + + return bb; } /* Expand basic block BB from GIMPLE trees to RTL. */ |