aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@cygnus.com>2000-02-06 05:01:03 -0800
committerRichard Henderson <rth@gcc.gnu.org>2000-02-06 05:01:03 -0800
commit69732dcb9c663d68d2a5d433ce76ed8da43e5632 (patch)
tree14cb8de0063e0e21049d8e2193ad60c82320ff4c
parent52a75c3c22a68d2acdbdf6e2e5070b1f424bfc81 (diff)
downloadgcc-69732dcb9c663d68d2a5d433ce76ed8da43e5632.zip
gcc-69732dcb9c663d68d2a5d433ce76ed8da43e5632.tar.gz
gcc-69732dcb9c663d68d2a5d433ce76ed8da43e5632.tar.bz2
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
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/basic-block.h4
-rw-r--r--gcc/emit-rtl.c25
-rw-r--r--gcc/flow.c10
-rw-r--r--gcc/function.c109
-rw-r--r--gcc/jump.c39
-rw-r--r--gcc/rtl.h1
7 files changed, 143 insertions, 58 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3831f59..ac0c643 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,18 @@
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
constant to op1 for testing.
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index 57fb2a7f..5f95c31 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -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. */
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 7a40b82..26bfc44 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -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;
}
diff --git a/gcc/flow.c b/gcc/flow.c
index aa87451..1ce45f0 100644
--- a/gcc/flow.c
+++ b/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;
{
diff --git a/gcc/function.c b/gcc/function.c
index d466db8..9b2182e 100644
--- a/gcc/function.c
+++ b/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)
{
diff --git a/gcc/jump.c b/gcc/jump.c
index ad213bc..417425d 100644
--- a/gcc/jump.c
+++ b/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
diff --git a/gcc/rtl.h b/gcc/rtl.h
index f068fab..1518512 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -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));