| 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))
|
|
|