flow.c (find_basic_blocks): Remove do_cleanup argument.

* flow.c (find_basic_blocks): Remove do_cleanup argument.
        Break out that code ...
        (cleanup_cfg): ... here.
        (commit_one_edge_insertion): Detect a return instruction being
        emitted to an edge.  Emit a barrier following; clear fallthru.
        (commit_edge_insertions): Verify CFG consistency.
        * function.c (expand_function_start): Kill unused variable.
        (expand_function_end): Likewise.
        (thread_prologue_and_epilogue_insns): Use insert_insn_on_edge
        to insert the epilogue.

        * gcse.c (gcse_main): Adjust for find_basic_blocks change.
        (delete_null_pointer_checks): Likewise.
        * output.h: Likewise.
        * reg-stack.c (reg_to_stack): Likewise.
        * toplev.c (rest_of_compilation): Likewise.  Run
        thread_prologue_and_epilogue_insns after rebuilding the CFG.

From-SVN: r31676
This commit is contained in:
Richard Henderson 2000-01-28 14:22:50 -08:00 committed by Richard Henderson
parent 47e6ea667d
commit 19d3c25c9a
7 changed files with 125 additions and 154 deletions

View File

@ -1,3 +1,23 @@
2000-01-28 Richard Henderson <rth@cygnus.com>
* flow.c (find_basic_blocks): Remove do_cleanup argument.
Break out that code ...
(cleanup_cfg): ... here.
(commit_one_edge_insertion): Detect a return instruction being
emitted to an edge. Emit a barrier following; clear fallthru.
(commit_edge_insertions): Verify CFG consistency.
* function.c (expand_function_start): Kill unused variable.
(expand_function_end): Likewise.
(thread_prologue_and_epilogue_insns): Use insert_insn_on_edge
to insert the epilogue.
* gcse.c (gcse_main): Adjust for find_basic_blocks change.
(delete_null_pointer_checks): Likewise.
* output.h: Likewise.
* reg-stack.c (reg_to_stack): Likewise.
* toplev.c (rest_of_compilation): Likewise. Run
thread_prologue_and_epilogue_insns after rebuilding the CFG.
2000-01-28 Richard Henderson <rth@cygnus.com>
* Makefile.in (flow.o): Revert 24 Jan change.

View File

@ -372,11 +372,10 @@ int flow_loop_outside_edge_p PARAMS ((const struct loop *, edge));
numbers in use. */
void
find_basic_blocks (f, nregs, file, do_cleanup)
find_basic_blocks (f, nregs, file)
rtx f;
int nregs ATTRIBUTE_UNUSED;
FILE *file ATTRIBUTE_UNUSED;
int do_cleanup;
{
int max_uid;
@ -425,23 +424,8 @@ find_basic_blocks (f, nregs, file, do_cleanup)
compute_bb_for_insn (max_uid);
/* Discover the edges of our cfg. */
record_active_eh_regions (f);
make_edges (label_value_list);
/* Delete unreachable blocks, then merge blocks when possible. */
if (do_cleanup)
{
delete_unreachable_blocks ();
move_stray_eh_region_notes ();
record_active_eh_regions (f);
if (optimize)
try_merge_blocks ();
}
/* Mark critical edges. */
mark_critical_edges ();
/* Kill the data we won't maintain. */
@ -740,6 +724,19 @@ find_basic_blocks_1 (f)
return label_value_list;
}
/* Tidy the CFG by deleting unreachable code and whatnot. */
void
cleanup_cfg (f)
rtx f;
{
delete_unreachable_blocks ();
move_stray_eh_region_notes ();
record_active_eh_regions (f);
try_merge_blocks ();
mark_critical_edges ();
}
/* Create a new basic block consisting of the instructions between
HEAD and END inclusive. Reuses the note and basic block struct
in BB_NOTE, if any. */
@ -1552,9 +1549,13 @@ static void
commit_one_edge_insertion (e)
edge e;
{
rtx before = NULL_RTX, after = NULL_RTX, tmp;
rtx before = NULL_RTX, after = NULL_RTX, insns, tmp;
basic_block bb;
/* Pull the insns off the edge now since the edge might go away. */
insns = e->insns;
e->insns = NULL_RTX;
/* Figure out where to put these things. If the destination has
one predecessor, insert there. Except for the exit block. */
if (e->dest->pred->pred_next == NULL
@ -1611,28 +1612,50 @@ commit_one_edge_insertion (e)
}
/* Now that we've found the spot, do the insertion. */
tmp = e->insns;
e->insns = NULL_RTX;
/* Set the new block number for these insns, if structure is allocated. */
if (basic_block_for_insn)
{
rtx i;
for (i = tmp; i != NULL_RTX; i = NEXT_INSN (i))
for (i = insns; i != NULL_RTX; i = NEXT_INSN (i))
set_block_for_insn (i, bb);
}
if (before)
{
emit_insns_before (tmp, before);
emit_insns_before (insns, before);
if (before == bb->head)
bb->head = tmp;
bb->head = insns;
}
else
{
tmp = emit_insns_after (tmp, after);
rtx last = emit_insns_after (insns, after);
if (after == bb->end)
bb->end = tmp;
{
bb->end = last;
if (GET_CODE (last) == JUMP_INSN)
{
if (returnjump_p (last))
{
/* ??? Remove all outgoing edges from BB and add one
for EXIT. This is not currently a problem because
this only happens for the (single) epilogue, which
already has a fallthru edge to EXIT. */
e = bb->succ;
if (e->dest != EXIT_BLOCK_PTR
|| e->succ_next != NULL
|| (e->flags & EDGE_FALLTHRU) == 0)
abort ();
e->flags &= ~EDGE_FALLTHRU;
emit_barrier_after (last);
}
else
abort ();
}
}
}
}
@ -1644,6 +1667,10 @@ commit_edge_insertions ()
int i;
basic_block bb;
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
i = -1;
bb = ENTRY_BLOCK_PTR;
while (1)

View File

@ -5867,7 +5867,6 @@ expand_function_start (subr, parms_have_cleanups)
tree subr;
int parms_have_cleanups;
{
register int i;
tree tem;
rtx last_ptr = NULL_RTX;
@ -6171,7 +6170,6 @@ expand_function_end (filename, line, end_bindings)
int line;
int end_bindings;
{
register int i;
tree link;
#ifdef TRAMPOLINE_TEMPLATE
@ -6546,12 +6544,12 @@ thread_prologue_and_epilogue_insns (f)
rtx f ATTRIBUTE_UNUSED;
{
int insertted = 0;
edge e;
rtx seq;
#ifdef HAVE_prologue
if (HAVE_prologue)
{
rtx seq;
start_sequence ();
seq = gen_prologue();
emit_insn (seq);
@ -6581,129 +6579,47 @@ thread_prologue_and_epilogue_insns (f)
}
#endif
/* If the exit block has no non-fake predecessors, we don't need
an epilogue. */
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
if ((e->flags & EDGE_FAKE) == 0)
break;
if (e == NULL)
goto epilogue_done;
#ifdef HAVE_epilogue
if (HAVE_epilogue)
{
edge e;
basic_block bb = 0;
rtx tail = get_last_insn ();
/* Find the edge that falls through to EXIT. Other edges may exist
due to RETURN instructions, but those don't need epilogues.
There really shouldn't be a mixture -- either all should have
been converted or none, however... */
/* ??? This is gastly. If function returns were not done via uses,
but via mark_regs_live_at_end, we could use insert_insn_on_edge
and all of this uglyness would go away. */
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
if (e->flags & EDGE_FALLTHRU)
break;
if (e == NULL)
goto epilogue_done;
switch (optimize)
{
default:
/* If the exit block has no non-fake predecessors, we don't
need an epilogue. Furthermore, only pay attention to the
fallthru predecessors; if (conditional) return insns were
generated, by definition we do not need to emit epilogue
insns. */
start_sequence ();
emit_note (NULL, NOTE_INSN_EPILOGUE_BEG);
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
if ((e->flags & EDGE_FAKE) == 0
&& (e->flags & EDGE_FALLTHRU) != 0)
break;
if (e == NULL)
break;
seq = gen_epilogue ();
emit_jump_insn (seq);
/* We can't handle multiple epilogues -- if one is needed,
we won't be able to place it multiple times.
/* Retain a map of the epilogue insns. */
if (GET_CODE (seq) != SEQUENCE)
seq = get_insns ();
epilogue = record_insns (seq);
??? Fix epilogue expanders to not assume they are the
last thing done compiling the function. Either that
or copy_rtx each insn.
seq = gen_sequence ();
end_sequence();
??? Blah, it's not a simple expression to assert that
we've exactly one fallthru exit edge. */
bb = e->src;
tail = bb->end;
/* ??? If the last insn of the basic block is a jump, then we
are creating a new basic block. Wimp out and leave these
insns outside any block. */
if (GET_CODE (tail) == JUMP_INSN)
bb = 0;
/* FALLTHRU */
case 0:
{
rtx prev, seq, first_use;
/* Move the USE insns at the end of a function onto a list. */
prev = tail;
if (GET_CODE (prev) == BARRIER
|| GET_CODE (prev) == NOTE)
prev = prev_nonnote_insn (prev);
first_use = 0;
if (prev
&& GET_CODE (prev) == INSN
&& GET_CODE (PATTERN (prev)) == USE)
{
/* If the end of the block is the use, grab hold of something
else so that we emit barriers etc in the right place. */
if (prev == tail)
{
do
tail = PREV_INSN (tail);
while (GET_CODE (tail) == INSN
&& GET_CODE (PATTERN (tail)) == USE);
}
do
{
rtx use = prev;
prev = prev_nonnote_insn (prev);
remove_insn (use);
if (first_use)
{
NEXT_INSN (use) = first_use;
PREV_INSN (first_use) = use;
}
else
NEXT_INSN (use) = NULL_RTX;
first_use = use;
}
while (prev
&& GET_CODE (prev) == INSN
&& GET_CODE (PATTERN (prev)) == USE);
}
/* The last basic block ends with a NOTE_INSN_EPILOGUE_BEG, the
epilogue insns, the USE insns at the end of a function,
the jump insn that returns, and then a BARRIER. */
if (GET_CODE (tail) != BARRIER)
{
prev = next_nonnote_insn (tail);
if (!prev || GET_CODE (prev) != BARRIER)
emit_barrier_after (tail);
}
seq = gen_epilogue ();
prev = tail;
tail = emit_jump_insn_after (seq, tail);
/* Insert the USE insns immediately before the return insn, which
must be the last instruction emitted in the sequence. */
if (first_use)
emit_insns_before (first_use, tail);
emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev);
/* Update the tail of the basic block. */
if (bb)
bb->end = tail;
/* Retain a map of the epilogue insns. */
epilogue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : tail);
}
}
insert_insn_on_edge (seq, e);
insertted = 1;
}
#endif
epilogue_done:
if (insertted)
commit_edge_insertions ();

View File

@ -673,7 +673,8 @@ gcse_main (f, file)
/* Identify the basic block information for this function, including
successors and predecessors. */
max_gcse_regno = max_reg_num ();
find_basic_blocks (f, max_gcse_regno, file, 1);
find_basic_blocks (f, max_gcse_regno, file);
cleanup_cfg (f);
if (file)
dump_flow_info (file);
@ -5201,7 +5202,8 @@ delete_null_pointer_checks (f)
struct null_pointer_info npi;
/* First break the program into basic blocks. */
find_basic_blocks (f, max_reg_num (), NULL, 1);
find_basic_blocks (f, max_reg_num (), NULL);
cleanup_cfg (f);
/* If we have only a single block, then there's nothing to do. */
if (n_basic_blocks <= 1)

View File

@ -131,7 +131,8 @@ extern void allocate_for_life_analysis PARAMS ((void));
extern int regno_uninitialized PARAMS ((int));
extern int regno_clobbered_at_setjmp PARAMS ((int));
extern void dump_flow_info PARAMS ((FILE *));
extern void find_basic_blocks PARAMS ((rtx, int, FILE *, int));
extern void find_basic_blocks PARAMS ((rtx, int, FILE *));
extern void cleanup_cfg PARAMS ((rtx));
extern void calculate_loop_depth PARAMS ((FILE *));
extern void free_basic_block_vars PARAMS ((int));
extern void set_block_num PARAMS ((rtx, int));

View File

@ -430,7 +430,7 @@ reg_to_stack (first, file)
/* Ok, floating point instructions exist. If not optimizing,
build the CFG and run life analysis. */
find_basic_blocks (first, max_reg_num (), file, 0);
find_basic_blocks (first, max_reg_num (), file);
count_or_remove_death_notes (NULL, 1);
life_analysis (first, max_reg_num (), file, 0);

View File

@ -3216,7 +3216,8 @@ rest_of_compilation (decl)
TIMEVAR
(flow_time,
{
find_basic_blocks (insns, max_reg_num (), rtl_dump_file, 1);
find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
cleanup_cfg (insns);
if (optimize)
calculate_loop_depth (rtl_dump_file);
life_analysis (insns, max_reg_num (), rtl_dump_file, 1);
@ -3384,13 +3385,6 @@ rest_of_compilation (decl)
if (rebuild_label_notes_after_reload)
TIMEVAR (jump_time, rebuild_jump_labels (insns));
/* On some machines, the prologue and epilogue code, or parts thereof,
can be represented as RTL. Doing so lets us schedule insns between
it and the rest of the code and also allows delayed branch
scheduling to operate in the epilogue. */
thread_prologue_and_epilogue_insns (insns);
/* If optimizing and we are performing instruction scheduling after
reload, then go ahead and split insns now since we are about to
recompute flow information anyway.
@ -3412,12 +3406,23 @@ rest_of_compilation (decl)
if (flow2_dump)
open_dump_file (".14.flow2", decl_printable_name (decl, 2));
TIMEVAR (flow2_time,
{
find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
});
/* On some machines, the prologue and epilogue code, or parts thereof,
can be represented as RTL. Doing so lets us schedule insns between
it and the rest of the code and also allows delayed branch
scheduling to operate in the epilogue. */
thread_prologue_and_epilogue_insns (insns);
if (optimize)
{
TIMEVAR
(flow2_time,
{
find_basic_blocks (insns, max_reg_num (), rtl_dump_file, 1);
cleanup_cfg (insns);
life_analysis (insns, max_reg_num (), rtl_dump_file, 1);
});