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:
parent
47e6ea667d
commit
19d3c25c9a
@ -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.
|
||||
|
77
gcc/flow.c
77
gcc/flow.c
@ -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)
|
||||
|
148
gcc/function.c
148
gcc/function.c
@ -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 ();
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
23
gcc/toplev.c
23
gcc/toplev.c
@ -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);
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user