Index: gcc/gcc/cfgbuild.c |
diff --git a/gcc/gcc/cfgbuild.c b/gcc/gcc/cfgbuild.c |
index 519108e51dc6f94bbae8e96f8e135718ce8b24a8..b063f898507eee8e82e65d6d5a222ad211665318 100644 |
--- a/gcc/gcc/cfgbuild.c |
+++ b/gcc/gcc/cfgbuild.c |
@@ -19,16 +19,6 @@ You should have received a copy of the GNU General Public License |
along with GCC; see the file COPYING3. If not see |
<http://www.gnu.org/licenses/>. */ |
-/* find_basic_blocks divides the current function's rtl into basic |
- blocks and constructs the CFG. The blocks are recorded in the |
- basic_block_info array; the CFG exists in the edge structures |
- referenced by the blocks. |
- |
- find_basic_blocks also finds any unreachable loops and deletes them. |
- |
- Available functionality: |
- - CFG construction |
- find_basic_blocks */ |
#include "config.h" |
#include "system.h" |
@@ -43,11 +33,10 @@ along with GCC; see the file COPYING3. If not see |
#include "output.h" |
#include "function.h" |
#include "except.h" |
+#include "expr.h" |
#include "toplev.h" |
#include "timevar.h" |
-static int count_basic_blocks (const_rtx); |
-static void find_basic_blocks_1 (rtx); |
static void make_edges (basic_block, basic_block, int); |
static void make_label_edge (sbitmap, basic_block, rtx, int); |
static void find_bb_boundaries (basic_block); |
@@ -74,6 +63,7 @@ inside_basic_block_p (const_rtx insn) |
case CALL_INSN: |
case INSN: |
+ case DEBUG_INSN: |
return true; |
case BARRIER: |
@@ -91,12 +81,11 @@ inside_basic_block_p (const_rtx insn) |
bool |
control_flow_insn_p (const_rtx insn) |
{ |
- rtx note; |
- |
switch (GET_CODE (insn)) |
{ |
case NOTE: |
case CODE_LABEL: |
+ case DEBUG_INSN: |
return false; |
case JUMP_INSN: |
@@ -111,21 +100,20 @@ control_flow_insn_p (const_rtx insn) |
|| find_reg_note (insn, REG_NORETURN, 0)) |
&& GET_CODE (PATTERN (insn)) != COND_EXEC) |
return true; |
+ |
/* Call insn may return to the nonlocal goto handler. */ |
- return ((nonlocal_goto_handler_labels |
- && (0 == (note = find_reg_note (insn, REG_EH_REGION, |
- NULL_RTX)) |
- || INTVAL (XEXP (note, 0)) >= 0)) |
- /* Or may trap. */ |
- || can_throw_internal (insn)); |
+ if (can_nonlocal_goto (insn)) |
+ return true; |
+ break; |
case INSN: |
/* Treat trap instructions like noreturn calls (same provision). */ |
if (GET_CODE (PATTERN (insn)) == TRAP_IF |
&& XEXP (PATTERN (insn), 0) == const1_rtx) |
return true; |
- |
- return (flag_non_call_exceptions && can_throw_internal (insn)); |
+ if (!flag_non_call_exceptions) |
+ return false; |
+ break; |
case BARRIER: |
/* It is nonsense to reach barrier when looking for the |
@@ -136,47 +124,10 @@ control_flow_insn_p (const_rtx insn) |
default: |
gcc_unreachable (); |
} |
-} |
- |
-/* Count the basic blocks of the function. */ |
- |
-static int |
-count_basic_blocks (const_rtx f) |
-{ |
- int count = NUM_FIXED_BLOCKS; |
- bool saw_insn = false; |
- const_rtx insn; |
- |
- for (insn = f; insn; insn = NEXT_INSN (insn)) |
- { |
- /* Code labels and barriers causes current basic block to be |
- terminated at previous real insn. */ |
- if ((LABEL_P (insn) || BARRIER_P (insn)) |
- && saw_insn) |
- count++, saw_insn = false; |
- |
- /* Start basic block if needed. */ |
- if (!saw_insn && inside_basic_block_p (insn)) |
- saw_insn = true; |
- |
- /* Control flow insn causes current basic block to be terminated. */ |
- if (saw_insn && control_flow_insn_p (insn)) |
- count++, saw_insn = false; |
- } |
- |
- if (saw_insn) |
- count++; |
- |
- /* The rest of the compiler works a bit smoother when we don't have to |
- check for the edge case of do-nothing functions with no basic blocks. */ |
- if (count == NUM_FIXED_BLOCKS) |
- { |
- emit_use (const0_rtx); |
- count = NUM_FIXED_BLOCKS + 1; |
- } |
- return count; |
+ return can_throw_internal (insn); |
} |
+ |
/* Create an edge between two basic blocks. FLAGS are auxiliary information |
about the edge that is accumulated between calls. */ |
@@ -204,16 +155,23 @@ make_label_edge (sbitmap edge_cache, basic_block src, rtx label, int flags) |
void |
rtl_make_eh_edge (sbitmap edge_cache, basic_block src, rtx insn) |
{ |
- int is_call = CALL_P (insn) ? EDGE_ABNORMAL_CALL : 0; |
- rtx handlers, i; |
+ eh_landing_pad lp = get_eh_landing_pad_from_rtx (insn); |
- handlers = reachable_handlers (insn); |
+ if (lp) |
+ { |
+ rtx label = lp->landing_pad; |
- for (i = handlers; i; i = XEXP (i, 1)) |
- make_label_edge (edge_cache, src, XEXP (i, 0), |
- EDGE_ABNORMAL | EDGE_EH | is_call); |
+ /* During initial rtl generation, use the post_landing_pad. */ |
+ if (label == NULL) |
+ { |
+ gcc_assert (lp->post_landing_pad); |
+ label = label_rtx (lp->post_landing_pad); |
+ } |
- free_INSN_LIST_list (&handlers); |
+ make_label_edge (edge_cache, src, label, |
+ EDGE_ABNORMAL | EDGE_EH |
+ | (CALL_P (insn) ? EDGE_ABNORMAL_CALL : 0)); |
+ } |
} |
/* States of basic block as seen by find_many_sub_basic_blocks. */ |
@@ -302,13 +260,9 @@ make_edges (basic_block min, basic_block max, int update_p) |
{ |
rtx tmp; |
- /* Recognize exception handling placeholders. */ |
- if (GET_CODE (PATTERN (insn)) == RESX) |
- rtl_make_eh_edge (edge_cache, bb, insn); |
- |
/* Recognize a non-local goto as a branch outside the |
current function. */ |
- else if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) |
+ if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) |
; |
/* Recognize a tablejump and do the right thing. */ |
@@ -349,6 +303,15 @@ make_edges (basic_block min, basic_block max, int update_p) |
else if (returnjump_p (insn)) |
cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR, 0); |
+ /* Recognize asm goto and do the right thing. */ |
+ else if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL) |
+ { |
+ int i, n = ASM_OPERANDS_LABEL_LENGTH (tmp); |
+ for (i = 0; i < n; ++i) |
+ make_label_edge (edge_cache, bb, |
+ XEXP (ASM_OPERANDS_LABEL (tmp, i), 0), 0); |
+ } |
+ |
/* Otherwise, we have a plain conditional or unconditional jump. */ |
else |
{ |
@@ -382,12 +345,7 @@ make_edges (basic_block min, basic_block max, int update_p) |
gotos do not have their addresses taken, then only calls to |
those functions or to other nested functions that use them |
could possibly do nonlocal gotos. */ |
- |
- /* We do know that a REG_EH_REGION note with a value less |
- than 0 is guaranteed not to perform a non-local goto. */ |
- rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); |
- |
- if (!note || INTVAL (XEXP (note, 0)) >= 0) |
+ if (can_nonlocal_goto (insn)) |
for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1)) |
make_label_edge (edge_cache, bb, XEXP (x, 0), |
EDGE_ABNORMAL | EDGE_ABNORMAL_CALL); |
@@ -418,157 +376,6 @@ make_edges (basic_block min, basic_block max, int update_p) |
sbitmap_vector_free (edge_cache); |
} |
-/* Find all basic blocks of the function whose first insn is F. |
- |
- Collect and return a list of labels whose addresses are taken. This |
- will be used in make_edges for use with computed gotos. */ |
- |
-static void |
-find_basic_blocks_1 (rtx f) |
-{ |
- rtx insn, next; |
- rtx bb_note = NULL_RTX; |
- rtx head = NULL_RTX; |
- rtx end = NULL_RTX; |
- basic_block prev = ENTRY_BLOCK_PTR; |
- |
- /* We process the instructions in a slightly different way than we did |
- previously. This is so that we see a NOTE_BASIC_BLOCK after we have |
- closed out the previous block, so that it gets attached at the proper |
- place. Since this form should be equivalent to the previous, |
- count_basic_blocks continues to use the old form as a check. */ |
- |
- for (insn = f; insn; insn = next) |
- { |
- enum rtx_code code = GET_CODE (insn); |
- |
- next = NEXT_INSN (insn); |
- |
- if ((LABEL_P (insn) || BARRIER_P (insn)) |
- && head) |
- { |
- prev = create_basic_block_structure (head, end, bb_note, prev); |
- head = end = NULL_RTX; |
- bb_note = NULL_RTX; |
- } |
- |
- if (inside_basic_block_p (insn)) |
- { |
- if (head == NULL_RTX) |
- head = insn; |
- end = insn; |
- } |
- |
- if (head && control_flow_insn_p (insn)) |
- { |
- prev = create_basic_block_structure (head, end, bb_note, prev); |
- head = end = NULL_RTX; |
- bb_note = NULL_RTX; |
- } |
- |
- switch (code) |
- { |
- case NOTE: |
- /* Look for basic block notes with which to keep the |
- basic_block_info pointers stable. Unthread the note now; |
- we'll put it back at the right place in create_basic_block. |
- Or not at all if we've already found a note in this block. */ |
- if (NOTE_INSN_BASIC_BLOCK_P (insn)) |
- { |
- if (bb_note == NULL_RTX) |
- bb_note = insn; |
- else |
- next = delete_insn (insn); |
- } |
- break; |
- |
- case CODE_LABEL: |
- case JUMP_INSN: |
- case CALL_INSN: |
- case INSN: |
- case BARRIER: |
- break; |
- |
- default: |
- gcc_unreachable (); |
- } |
- } |
- |
- if (head != NULL_RTX) |
- create_basic_block_structure (head, end, bb_note, prev); |
- else if (bb_note) |
- delete_insn (bb_note); |
- |
- gcc_assert (last_basic_block == n_basic_blocks); |
- |
- clear_aux_for_blocks (); |
-} |
- |
- |
-/* Find basic blocks of the current function. |
- F is the first insn of the function. */ |
- |
-void |
-find_basic_blocks (rtx f) |
-{ |
- basic_block bb; |
- |
- timevar_push (TV_CFG); |
- |
- /* Flush out existing data. */ |
- if (basic_block_info != NULL) |
- { |
- clear_edges (); |
- |
- /* Clear bb->aux on all extant basic blocks. We'll use this as a |
- tag for reuse during create_basic_block, just in case some pass |
- copies around basic block notes improperly. */ |
- FOR_EACH_BB (bb) |
- bb->aux = NULL; |
- |
- basic_block_info = NULL; |
- } |
- |
- n_basic_blocks = count_basic_blocks (f); |
- last_basic_block = NUM_FIXED_BLOCKS; |
- ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR; |
- EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR; |
- |
- |
- /* Size the basic block table. The actual structures will be allocated |
- by find_basic_blocks_1, since we want to keep the structure pointers |
- stable across calls to find_basic_blocks. */ |
- /* ??? This whole issue would be much simpler if we called find_basic_blocks |
- exactly once, and thereafter we don't have a single long chain of |
- instructions at all until close to the end of compilation when we |
- actually lay them out. */ |
- |
- basic_block_info = VEC_alloc (basic_block, gc, n_basic_blocks); |
- VEC_safe_grow_cleared (basic_block, gc, basic_block_info, n_basic_blocks); |
- SET_BASIC_BLOCK (ENTRY_BLOCK, ENTRY_BLOCK_PTR); |
- SET_BASIC_BLOCK (EXIT_BLOCK, EXIT_BLOCK_PTR); |
- |
- find_basic_blocks_1 (f); |
- |
- profile_status = PROFILE_ABSENT; |
- |
- /* Tell make_edges to examine every block for out-going edges. */ |
- FOR_EACH_BB (bb) |
- SET_STATE (bb, BLOCK_NEW); |
- |
- /* Discover the edges of our cfg. */ |
- make_edges (ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR->prev_bb, 0); |
- |
- /* Do very simple cleanup now, for the benefit of code that runs between |
- here and cleanup_cfg, e.g. thread_prologue_and_epilogue_insns. */ |
- tidy_fallthru_edges (); |
- |
-#ifdef ENABLE_CHECKING |
- verify_flow_info (); |
-#endif |
- timevar_pop (TV_CFG); |
-} |
- |
static void |
mark_tablejump_edge (rtx label) |
{ |
@@ -646,8 +453,10 @@ find_bb_boundaries (basic_block bb) |
{ |
enum rtx_code code = GET_CODE (insn); |
- /* On code label, split current basic block. */ |
- if (code == CODE_LABEL) |
+ /* In case we've previously seen an insn that effects a control |
+ flow transfer, split the block. */ |
+ if ((flow_transfer_insn || code == CODE_LABEL) |
+ && inside_basic_block_p (insn)) |
{ |
fallthru = split_block (bb, PREV_INSN (insn)); |
if (flow_transfer_insn) |
@@ -665,27 +474,16 @@ find_bb_boundaries (basic_block bb) |
bb = fallthru->dest; |
remove_edge (fallthru); |
flow_transfer_insn = NULL_RTX; |
- if (LABEL_ALT_ENTRY_P (insn)) |
+ if (code == CODE_LABEL && LABEL_ALT_ENTRY_P (insn)) |
make_edge (ENTRY_BLOCK_PTR, bb, 0); |
} |
- |
- /* In case we've previously seen an insn that effects a control |
- flow transfer, split the block. */ |
- if (flow_transfer_insn && inside_basic_block_p (insn)) |
+ else if (code == BARRIER) |
{ |
- fallthru = split_block (bb, PREV_INSN (insn)); |
- BB_END (bb) = flow_transfer_insn; |
- |
- /* Clean up the bb field for the insns between the blocks. */ |
- for (x = NEXT_INSN (flow_transfer_insn); |
- x != BB_HEAD (fallthru->dest); |
- x = NEXT_INSN (x)) |
- if (!BARRIER_P (x)) |
- set_block_for_insn (x, NULL); |
- |
- bb = fallthru->dest; |
- remove_edge (fallthru); |
- flow_transfer_insn = NULL_RTX; |
+ /* __builtin_unreachable () may cause a barrier to be emitted in |
+ the middle of a BB. We need to split it in the same manner as |
+ if the barrier were preceded by a control_flow_insn_p insn. */ |
+ if (!flow_transfer_insn) |
+ flow_transfer_insn = prev_nonnote_insn_bb (insn); |
} |
if (control_flow_insn_p (insn)) |