summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cfganal.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-05-09 20:02:13 +0000
committerobrien <obrien@FreeBSD.org>2002-05-09 20:02:13 +0000
commitc8f5fc7032940ad6633f932ac40cade82ec4d0cc (patch)
tree29a0f0a6c79a69ecc64f612947a0fe5904311713 /contrib/gcc/cfganal.c
parentc9ab9ae440a8066b2c2b85b157b1fdadcf09916a (diff)
downloadFreeBSD-src-c8f5fc7032940ad6633f932ac40cade82ec4d0cc.zip
FreeBSD-src-c8f5fc7032940ad6633f932ac40cade82ec4d0cc.tar.gz
Gcc 3.1.0 pre-release from the FSF anoncvs repo on 9-May-2002 15:57:15 EDT.
Diffstat (limited to 'contrib/gcc/cfganal.c')
-rw-r--r--contrib/gcc/cfganal.c77
1 files changed, 62 insertions, 15 deletions
diff --git a/contrib/gcc/cfganal.c b/contrib/gcc/cfganal.c
index 1c499f4..6009d59 100644
--- a/contrib/gcc/cfganal.c
+++ b/contrib/gcc/cfganal.c
@@ -25,9 +25,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "rtl.h"
#include "hard-reg-set.h"
#include "basic-block.h"
+#include "insn-config.h"
+#include "recog.h"
#include "toplev.h"
-
#include "obstack.h"
+#include "tm_p.h"
/* Store the data structures necessary for depth-first search. */
struct depth_first_search_dsS {
@@ -53,6 +55,7 @@ static void flow_dfs_compute_reverse_finish
PARAMS ((depth_first_search_ds));
static void remove_fake_successors PARAMS ((basic_block));
static bool need_fake_edge_p PARAMS ((rtx));
+static bool keep_with_call_p PARAMS ((rtx));
/* Return true if the block has no effect and only forwards control flow to
its single destination. */
@@ -209,6 +212,32 @@ need_fake_edge_p (insn)
|| GET_CODE (PATTERN (insn)) == ASM_INPUT);
}
+/* Return true if INSN should be kept in the same block as a preceding call.
+ This is done for a single-set whose destination is a fixed register or
+ whose source is the function return value. This is a helper function for
+ flow_call_edges_add. */
+
+static bool
+keep_with_call_p (insn)
+ rtx insn;
+{
+ rtx set;
+
+ if (INSN_P (insn) && (set = single_set (insn)) != NULL)
+ {
+ if (GET_CODE (SET_DEST (set)) == REG
+ && fixed_regs[REGNO (SET_DEST (set))]
+ && general_operand (SET_SRC (set), VOIDmode))
+ return true;
+ if (GET_CODE (SET_SRC (set)) == REG
+ && FUNCTION_VALUE_REGNO_P (REGNO (SET_SRC (set)))
+ && GET_CODE (SET_DEST (set)) == REG
+ && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
+ return true;
+ }
+ return false;
+}
+
/* Add fake edges to the function exit for any non constant and non noreturn
calls, volatile inline assembly in the bitmap of blocks specified by
BLOCKS or to the whole CFG if BLOCKS is zero. Return the number of blocks
@@ -259,17 +288,27 @@ flow_call_edges_add (blocks)
spanning tree in the case that the call doesn't return.
Handle this by adding a dummy instruction in a new last basic block. */
- if (check_last_block
- && need_fake_edge_p (BASIC_BLOCK (n_basic_blocks - 1)->end))
+ if (check_last_block)
{
- edge e;
+ basic_block bb = BASIC_BLOCK (n_basic_blocks - 1);
+ rtx insn = bb->end;
- for (e = BASIC_BLOCK (n_basic_blocks - 1)->succ; e; e = e->succ_next)
- if (e->dest == EXIT_BLOCK_PTR)
- break;
+ /* Back up past insns that must be kept in the same block as a call. */
+ while (insn != bb->head
+ && keep_with_call_p (insn))
+ insn = PREV_INSN (insn);
+
+ if (need_fake_edge_p (insn))
+ {
+ edge e;
- insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
- commit_edge_insertions ();
+ for (e = bb->succ; e; e = e->succ_next)
+ if (e->dest == EXIT_BLOCK_PTR)
+ break;
+
+ insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
+ commit_edge_insertions ();
+ }
}
/* Now add fake edges to the function exit for any non constant
@@ -288,14 +327,22 @@ flow_call_edges_add (blocks)
if (need_fake_edge_p (insn))
{
edge e;
+ rtx split_at_insn = insn;
+
+ /* Don't split the block between a call and an insn that should
+ remain in the same block as the call. */
+ if (GET_CODE (insn) == CALL_INSN)
+ while (split_at_insn != bb->end
+ && keep_with_call_p (NEXT_INSN (split_at_insn)))
+ split_at_insn = NEXT_INSN (split_at_insn);
- /* The above condition should be enough to verify that there is
- no edge to the exit block in CFG already. Calling make_edge
- in such case would make us to mark that edge as fake and
- remove it later. */
+ /* The handling above of the final block before the epilogue
+ should be enough to verify that there is no edge to the exit
+ block in CFG already. Calling make_edge in such case would
+ cause us to mark that edge as fake and remove it later. */
#ifdef ENABLE_CHECKING
- if (insn == bb->end)
+ if (split_at_insn == bb->end)
for (e = bb->succ; e; e = e->succ_next)
if (e->dest == EXIT_BLOCK_PTR)
abort ();
@@ -303,7 +350,7 @@ flow_call_edges_add (blocks)
/* Note that the following may create a new basic block
and renumber the existing basic blocks. */
- e = split_block (bb, insn);
+ e = split_block (bb, split_at_insn);
if (e)
blocks_split++;
OpenPOWER on IntegriCloud