flow.c (flow_delete_insn, [...]): Export.
* flow.c (flow_delete_insn, make_edge, remove_edge): Export. * basic-block.h: Declare them. * emit-rtl.h (active_insn_p): New. (next_active_insn, prev_active_insn): Use it. * rtl.h: Declare it. * function.c (emit_return_into_block): New. (thread_prologue_and_epilogue_insns): Insert return insns instead of epilogues when possible. * jump.c (jump_optimize_1): Remove code to insert a return insn on the fallthru to the exit block. From-SVN: r31826
This commit is contained in:
parent
52a75c3c22
commit
69732dcb9c
@ -1,3 +1,16 @@
|
||||
2000-02-06 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* flow.c (flow_delete_insn, make_edge, remove_edge): Export.
|
||||
* basic-block.h: Declare them.
|
||||
* emit-rtl.h (active_insn_p): New.
|
||||
(next_active_insn, prev_active_insn): Use it.
|
||||
* rtl.h: Declare it.
|
||||
* function.c (emit_return_into_block): New.
|
||||
(thread_prologue_and_epilogue_insns): Insert return insns instead
|
||||
of epilogues when possible.
|
||||
* jump.c (jump_optimize_1): Remove code to insert a return insn
|
||||
on the fallthru to the exit block.
|
||||
|
||||
2000-02-06 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* simplify-rtx.c (simplify_relational_operation): Canonicalize
|
||||
|
@ -222,7 +222,11 @@ extern void insert_insn_on_edge PARAMS ((rtx, edge));
|
||||
extern void commit_edge_insertions PARAMS ((void));
|
||||
extern void remove_fake_edges PARAMS ((void));
|
||||
extern void add_noreturn_fake_exit_edges PARAMS ((void));
|
||||
extern rtx flow_delete_insn PARAMS ((rtx));
|
||||
extern void flow_delete_insn_chain PARAMS ((rtx, rtx));
|
||||
extern void make_edge PARAMS ((sbitmap *, basic_block,
|
||||
basic_block, int));
|
||||
extern void remove_edge PARAMS ((edge));
|
||||
|
||||
|
||||
/* Structure to hold information for each natural loop. */
|
||||
|
@ -2084,6 +2084,17 @@ prev_real_insn (insn)
|
||||
does not look inside SEQUENCEs. Until reload has completed, this is the
|
||||
same as next_real_insn. */
|
||||
|
||||
int
|
||||
active_insn_p (insn)
|
||||
rtx insn;
|
||||
{
|
||||
return (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
|
||||
|| (GET_CODE (insn) == INSN
|
||||
&& (! reload_completed
|
||||
|| (GET_CODE (PATTERN (insn)) != USE
|
||||
&& GET_CODE (PATTERN (insn)) != CLOBBER))));
|
||||
}
|
||||
|
||||
rtx
|
||||
next_active_insn (insn)
|
||||
rtx insn;
|
||||
@ -2091,12 +2102,7 @@ next_active_insn (insn)
|
||||
while (insn)
|
||||
{
|
||||
insn = NEXT_INSN (insn);
|
||||
if (insn == 0
|
||||
|| GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
|
||||
|| (GET_CODE (insn) == INSN
|
||||
&& (! reload_completed
|
||||
|| (GET_CODE (PATTERN (insn)) != USE
|
||||
&& GET_CODE (PATTERN (insn)) != CLOBBER))))
|
||||
if (insn == 0 || active_insn_p (insn))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2114,12 +2120,7 @@ prev_active_insn (insn)
|
||||
while (insn)
|
||||
{
|
||||
insn = PREV_INSN (insn);
|
||||
if (insn == 0
|
||||
|| GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
|
||||
|| (GET_CODE (insn) == INSN
|
||||
&& (! reload_completed
|
||||
|| (GET_CODE (PATTERN (insn)) != USE
|
||||
&& GET_CODE (PATTERN (insn)) != CLOBBER))))
|
||||
if (insn == 0 || active_insn_p (insn))
|
||||
break;
|
||||
}
|
||||
|
||||
|
10
gcc/flow.c
10
gcc/flow.c
@ -285,8 +285,6 @@ static rtx find_basic_blocks_1 PARAMS ((rtx));
|
||||
static void create_basic_block PARAMS ((int, rtx, rtx, rtx));
|
||||
static void clear_edges PARAMS ((void));
|
||||
static void make_edges PARAMS ((rtx));
|
||||
static void make_edge PARAMS ((sbitmap *, basic_block,
|
||||
basic_block, int));
|
||||
static void make_label_edge PARAMS ((sbitmap *, basic_block,
|
||||
rtx, int));
|
||||
static void make_eh_edge PARAMS ((sbitmap *, eh_nesting_info *,
|
||||
@ -302,7 +300,6 @@ static void delete_eh_regions PARAMS ((void));
|
||||
static int can_delete_note_p PARAMS ((rtx));
|
||||
static int delete_block PARAMS ((basic_block));
|
||||
static void expunge_block PARAMS ((basic_block));
|
||||
static rtx flow_delete_insn PARAMS ((rtx));
|
||||
static int can_delete_label_p PARAMS ((rtx));
|
||||
static int merge_blocks_move_predecessor_nojumps PARAMS ((basic_block,
|
||||
basic_block));
|
||||
@ -346,7 +343,6 @@ static void count_reg_sets_1 PARAMS ((rtx));
|
||||
static void count_reg_sets PARAMS ((rtx));
|
||||
static void count_reg_references PARAMS ((rtx));
|
||||
static void invalidate_mems_from_autoinc PARAMS ((rtx));
|
||||
static void remove_edge PARAMS ((edge));
|
||||
static void remove_fake_successors PARAMS ((basic_block));
|
||||
static void flow_nodes_print PARAMS ((const char *, const sbitmap, FILE *));
|
||||
static void flow_exits_print PARAMS ((const char *, const edge *, int, FILE *));
|
||||
@ -1056,7 +1052,7 @@ make_edges (label_value_list)
|
||||
/* Create an edge between two basic blocks. FLAGS are auxiliary information
|
||||
about the edge that is accumulated between calls. */
|
||||
|
||||
static void
|
||||
void
|
||||
make_edge (edge_cache, src, dst, flags)
|
||||
sbitmap *edge_cache;
|
||||
basic_block src, dst;
|
||||
@ -1982,7 +1978,7 @@ expunge_block (b)
|
||||
|
||||
/* Delete INSN by patching it out. Return the next insn. */
|
||||
|
||||
static rtx
|
||||
rtx
|
||||
flow_delete_insn (insn)
|
||||
rtx insn;
|
||||
{
|
||||
@ -6215,7 +6211,7 @@ find_edge_index (edge_list, pred, succ)
|
||||
}
|
||||
|
||||
/* This function will remove an edge from the flow graph. */
|
||||
static void
|
||||
void
|
||||
remove_edge (e)
|
||||
edge e;
|
||||
{
|
||||
|
109
gcc/function.c
109
gcc/function.c
@ -271,6 +271,7 @@ static int all_blocks PARAMS ((tree, tree *));
|
||||
can always export `prologue_epilogue_contains'. */
|
||||
static int *record_insns PARAMS ((rtx)) ATTRIBUTE_UNUSED;
|
||||
static int contains PARAMS ((rtx, int *));
|
||||
static void emit_return_into_block PARAMS ((basic_block));
|
||||
static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
|
||||
static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
|
||||
struct hash_table *));
|
||||
@ -6577,6 +6578,27 @@ prologue_epilogue_contains (insn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Insert gen_return at the end of block BB. This also means updating
|
||||
block_for_insn appropriately. */
|
||||
|
||||
static void
|
||||
emit_return_into_block (bb)
|
||||
basic_block bb;
|
||||
{
|
||||
rtx p, end;
|
||||
|
||||
end = emit_jump_insn_after (gen_return (), bb->end);
|
||||
p = NEXT_INSN (bb->end);
|
||||
while (1)
|
||||
{
|
||||
set_block_for_insn (p, bb);
|
||||
if (p == end)
|
||||
break;
|
||||
p = NEXT_INSN (p);
|
||||
}
|
||||
bb->end = end;
|
||||
}
|
||||
|
||||
/* Generate the prologue and epilogue RTL if the machine supports it. Thread
|
||||
this into place with notes indicating where the prologue ends and where
|
||||
the epilogue begins. Update the basic block information when possible. */
|
||||
@ -6629,6 +6651,93 @@ thread_prologue_and_epilogue_insns (f)
|
||||
if (e == NULL)
|
||||
goto epilogue_done;
|
||||
|
||||
#ifdef HAVE_return
|
||||
if (optimize && HAVE_return)
|
||||
{
|
||||
/* If we're allowed to generate a simple return instruction,
|
||||
then by definition we don't need a full epilogue. Examine
|
||||
the block that falls through to EXIT. If it does not
|
||||
contain any code, examine its predecessors and try to
|
||||
emit (conditional) return instructions. */
|
||||
|
||||
basic_block last;
|
||||
edge e_next;
|
||||
rtx label;
|
||||
|
||||
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
|
||||
if (e->flags & EDGE_FALLTHRU)
|
||||
break;
|
||||
if (e == NULL)
|
||||
goto epilogue_done;
|
||||
last = e->src;
|
||||
|
||||
/* Verify that there are no active instructions in the last block. */
|
||||
label = last->end;
|
||||
while (label && GET_CODE (label) != CODE_LABEL)
|
||||
{
|
||||
if (active_insn_p (label))
|
||||
break;
|
||||
label = PREV_INSN (label);
|
||||
}
|
||||
|
||||
if (last->head == label && GET_CODE (label) == CODE_LABEL)
|
||||
{
|
||||
for (e = last->pred; e ; e = e_next)
|
||||
{
|
||||
basic_block bb = e->src;
|
||||
rtx jump;
|
||||
|
||||
e_next = e->pred_next;
|
||||
if (bb == ENTRY_BLOCK_PTR)
|
||||
continue;
|
||||
|
||||
jump = bb->end;
|
||||
if (GET_CODE (jump) != JUMP_INSN)
|
||||
continue;
|
||||
|
||||
/* If we have an unconditional jump, we can replace that
|
||||
with a simple return instruction. */
|
||||
if (simplejump_p (jump))
|
||||
{
|
||||
emit_return_into_block (bb);
|
||||
flow_delete_insn (jump);
|
||||
}
|
||||
|
||||
/* If we have a conditional jump, we can try to replace
|
||||
that with a conditional return instruction. */
|
||||
else if (condjump_p (jump))
|
||||
{
|
||||
rtx ret, *loc;
|
||||
|
||||
ret = SET_SRC (PATTERN (jump));
|
||||
if (GET_CODE (XEXP (ret, 1)) == LABEL_REF)
|
||||
loc = &XEXP (ret, 1);
|
||||
else
|
||||
loc = &XEXP (ret, 2);
|
||||
ret = gen_rtx_RETURN (VOIDmode);
|
||||
|
||||
if (! validate_change (jump, loc, ret, 0))
|
||||
continue;
|
||||
if (JUMP_LABEL (jump))
|
||||
LABEL_NUSES (JUMP_LABEL (jump))--;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
/* Fix up the CFG for the successful change we just made. */
|
||||
remove_edge (e);
|
||||
make_edge (NULL, bb, EXIT_BLOCK_PTR, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit a return insn for the exit fallthru block. Whether
|
||||
this is still reachable will be determined later. */
|
||||
|
||||
emit_barrier_after (last->end);
|
||||
emit_return_into_block (last);
|
||||
goto epilogue_done;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_epilogue
|
||||
if (HAVE_epilogue)
|
||||
{
|
||||
|
39
gcc/jump.c
39
gcc/jump.c
@ -232,25 +232,6 @@ jump_optimize_1 (f, cross_jump, noop_moves, after_regscan, mark_labels_only)
|
||||
|
||||
last_insn = delete_unreferenced_labels (f);
|
||||
|
||||
#ifdef HAVE_return
|
||||
if (optimize && HAVE_return)
|
||||
{
|
||||
/* If we fall through to the epilogue, see if we can insert a RETURN insn
|
||||
in front of it. If the machine allows it at this point (we might be
|
||||
after reload for a leaf routine), it will improve optimization for it
|
||||
to be there. */
|
||||
insn = get_last_insn ();
|
||||
while (insn && GET_CODE (insn) == NOTE)
|
||||
insn = PREV_INSN (insn);
|
||||
|
||||
if (insn && GET_CODE (insn) != BARRIER)
|
||||
{
|
||||
emit_jump_insn (gen_return ());
|
||||
emit_barrier ();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (noop_moves)
|
||||
delete_noop_moves (f);
|
||||
|
||||
@ -2142,26 +2123,6 @@ jump_optimize_1 (f, cross_jump, noop_moves, after_regscan, mark_labels_only)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_return
|
||||
if (HAVE_return)
|
||||
{
|
||||
/* If we fall through to the epilogue, see if we can insert a RETURN insn
|
||||
in front of it. If the machine allows it at this point (we might be
|
||||
after reload for a leaf routine), it will improve optimization for it
|
||||
to be there. We do this both here and at the start of this pass since
|
||||
the RETURN might have been deleted by some of our optimizations. */
|
||||
insn = get_last_insn ();
|
||||
while (insn && GET_CODE (insn) == NOTE)
|
||||
insn = PREV_INSN (insn);
|
||||
|
||||
if (insn && GET_CODE (insn) != BARRIER)
|
||||
{
|
||||
emit_jump_insn (gen_return ());
|
||||
emit_barrier ();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* CAN_REACH_END is persistent for each function. Once set it should
|
||||
not be cleared. This is especially true for the case where we
|
||||
delete the NOTE_FUNCTION_END note. CAN_REACH_END is cleared by
|
||||
|
@ -1051,6 +1051,7 @@ extern rtx prev_real_insn PARAMS ((rtx));
|
||||
extern rtx next_real_insn PARAMS ((rtx));
|
||||
extern rtx prev_active_insn PARAMS ((rtx));
|
||||
extern rtx next_active_insn PARAMS ((rtx));
|
||||
extern int active_insn_p PARAMS ((rtx));
|
||||
extern rtx prev_label PARAMS ((rtx));
|
||||
extern rtx next_label PARAMS ((rtx));
|
||||
extern rtx next_cc0_user PARAMS ((rtx));
|
||||
|
Loading…
Reference in New Issue
Block a user