summaryrefslogtreecommitdiff
path: root/gcc/cfganal.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cfganal.c')
-rw-r--r--gcc/cfganal.c179
1 files changed, 15 insertions, 164 deletions
diff --git a/gcc/cfganal.c b/gcc/cfganal.c
index 00771b47703..1a7d280513f 100644
--- a/gcc/cfganal.c
+++ b/gcc/cfganal.c
@@ -52,7 +52,6 @@ static void flow_dfs_compute_reverse_add_bb (depth_first_search_ds,
static basic_block flow_dfs_compute_reverse_execute (depth_first_search_ds);
static void flow_dfs_compute_reverse_finish (depth_first_search_ds);
static void remove_fake_successors (basic_block);
-static bool need_fake_edge_p (rtx);
static bool flow_active_insn_p (rtx);
/* Like active_insn_p, except keep the return value clobber around
@@ -242,169 +241,6 @@ set_edge_can_fallthru_flag (void)
}
}
-/* Return true if we need to add fake edge to exit.
- Helper function for the flow_call_edges_add. */
-
-static bool
-need_fake_edge_p (rtx insn)
-{
- if (!INSN_P (insn))
- return false;
-
- if ((GET_CODE (insn) == CALL_INSN
- && !SIBLING_CALL_P (insn)
- && !find_reg_note (insn, REG_NORETURN, NULL)
- && !find_reg_note (insn, REG_ALWAYS_RETURN, NULL)
- && !CONST_OR_PURE_CALL_P (insn)))
- return true;
-
- return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS
- && MEM_VOLATILE_P (PATTERN (insn)))
- || (GET_CODE (PATTERN (insn)) == PARALLEL
- && asm_noperands (insn) != -1
- && MEM_VOLATILE_P (XVECEXP (PATTERN (insn), 0, 0)))
- || GET_CODE (PATTERN (insn)) == ASM_INPUT);
-}
-
-/* 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
- that were split.
-
- The goal is to expose cases in which entering a basic block does not imply
- that all subsequent instructions must be executed. */
-
-int
-flow_call_edges_add (sbitmap blocks)
-{
- int i;
- int blocks_split = 0;
- int last_bb = last_basic_block;
- bool check_last_block = false;
-
- if (n_basic_blocks == 0)
- return 0;
-
- if (! blocks)
- check_last_block = true;
- else
- check_last_block = TEST_BIT (blocks, EXIT_BLOCK_PTR->prev_bb->index);
-
- /* In the last basic block, before epilogue generation, there will be
- a fallthru edge to EXIT. Special care is required if the last insn
- of the last basic block is a call because make_edge folds duplicate
- edges, which would result in the fallthru edge also being marked
- fake, which would result in the fallthru edge being removed by
- remove_fake_edges, which would result in an invalid CFG.
-
- Moreover, we can't elide the outgoing fake edge, since the block
- profiler needs to take this into account in order to solve the minimal
- 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)
- {
- basic_block bb = EXIT_BLOCK_PTR->prev_bb;
- rtx insn = BB_END (bb);
-
- /* Back up past insns that must be kept in the same block as a call. */
- while (insn != BB_HEAD (bb)
- && keep_with_call_p (insn))
- insn = PREV_INSN (insn);
-
- if (need_fake_edge_p (insn))
- {
- edge e;
-
- for (e = bb->succ; e; e = e->succ_next)
- if (e->dest == EXIT_BLOCK_PTR)
- {
- insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
- commit_edge_insertions ();
- break;
- }
- }
- }
-
- /* Now add fake edges to the function exit for any non constant
- calls since there is no way that we can determine if they will
- return or not... */
-
- for (i = 0; i < last_bb; i++)
- {
- basic_block bb = BASIC_BLOCK (i);
- rtx libcall_end = NULL_RTX;
- rtx insn;
- rtx prev_insn;
-
- if (!bb)
- continue;
-
- if (blocks && !TEST_BIT (blocks, i))
- continue;
-
- for (insn = BB_END (bb); ; insn = prev_insn)
- {
- prev_insn = PREV_INSN (insn);
- if (need_fake_edge_p (insn))
- {
- edge e;
- rtx split_at_insn = insn;
-
- /* Don't split libcalls. */
- if (libcall_end)
- split_at_insn = libcall_end;
-
- /* Don't split the block between a call and an insn that should
- remain in the same block as the call. */
- else if (GET_CODE (insn) == CALL_INSN)
- while (split_at_insn != BB_END (bb)
- && keep_with_call_p (NEXT_INSN (split_at_insn)))
- split_at_insn = NEXT_INSN (split_at_insn);
-
- /* 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 (split_at_insn == BB_END (bb))
- for (e = bb->succ; e; e = e->succ_next)
- if (e->dest == EXIT_BLOCK_PTR)
- abort ();
-#endif
-
- /* Note that the following may create a new basic block
- and renumber the existing basic blocks. */
- if (split_at_insn != BB_END (bb))
- {
- e = split_block (bb, split_at_insn);
- if (e)
- blocks_split++;
- }
-
- make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
- }
-
- /* Watch out for REG_LIBCALL/REG_RETVAL notes so that we know
- whether we are currently in a libcall or not. Remember that
- we are scanning backwards! */
- if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
- libcall_end = insn;
- if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
- libcall_end = NULL_RTX;
-
- if (insn == BB_HEAD (bb))
- break;
- }
- }
-
- if (blocks_split)
- verify_flow_info ();
-
- return blocks_split;
-}
-
/* Find unreachable blocks. An unreachable block will have 0 in
the reachable bit in block->flags. A nonzero value indicates the
block is reachable. */
@@ -603,6 +439,21 @@ verify_edge_list (FILE *f, struct edge_list *elist)
}
}
+/* Given PRED and SUCC blocks, return the edge which connects the blocks.
+ If no such edge exists, return NULL. */
+
+edge
+find_edge (basic_block pred, basic_block succ)
+{
+ edge e;
+
+ for (e = pred->succ; e; e = e->succ_next)
+ if (e->dest == succ)
+ return e;
+
+ return NULL;
+}
+
/* This routine will determine what, if any, edge there is between
a specified predecessor and successor. */