From 34487bf85731112fd68f579b0cb1c888c71ebfef Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 6 Apr 1999 15:10:53 -0700 Subject: flow.c (verify_flow_info): New function. * flow.c (verify_flow_info): New function. (find_basic_blocks): Call it if ENABLE_CHECKING. (merge_blocks): Don't merge if there are non-deletable labels. * toplev.c (fatal_insn): Allow a printf-style arg list. * toplev.h (fatal_insn): Update prototype. From-SVN: r26226 --- gcc/ChangeLog | 14 ++++ gcc/flow.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- gcc/toplev.c | 29 +++---- gcc/toplev.h | 5 +- 4 files changed, 263 insertions(+), 24 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d3892b2..443a628 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +Tue Apr 6 22:09:40 1999 Richard Henderson + + * expr.c (expand_builtin_setjmp): Put setjmp return label on + nonlocal_goto_handler_labels for flow. + +Tue Apr 6 22:05:21 1999 Jan Hubicka + Richard Henderson + + * flow.c (verify_flow_info): New function. + (find_basic_blocks): Call it if ENABLE_CHECKING. + (merge_blocks): Don't merge if there are non-deletable labels. + * toplev.c (fatal_insn): Allow a printf-style arg list. + * toplev.h (fatal_insn): Update prototype. + Tue Apr 6 16:18:58 1999 Jan Hubicka * flow.c (split_edge) update correctly flow graph, disable diff --git a/gcc/flow.c b/gcc/flow.c index d2d1d50..072d208 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -335,6 +335,7 @@ static void count_reg_sets PROTO ((rtx)); static void count_reg_references PROTO ((rtx)); static void notice_stack_pointer_modification PROTO ((rtx, rtx)); static void invalidate_mems_from_autoinc PROTO ((rtx)); +void verify_flow_info PROTO ((void)); /* Find basic blocks of the current function. F is the first insn of the function and NREGS the number of register @@ -418,6 +419,10 @@ find_basic_blocks (f, nregs, file, do_cleanup) /* Kill the data we won't maintain. */ label_value_list = 0; + +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif } /* Count the basic blocks of the function. */ @@ -1945,15 +1950,14 @@ merge_blocks (e, b, c) jump must go in a new basic block D. */ } - /* If a label still appears somewhere, we cannot delete the label, which - means we cannot merge the blocks. We have still won a tad by tidying - the interface between the two blocks. */ - if (GET_CODE (c->head) == CODE_LABEL - && ! can_delete_label_p (c->head)) - { - tidy_fallthru_edge (e, b, c); - return 0; - } + /* If a label still appears somewhere and we cannot delete the label, + then we cannot merge the blocks. The edge was tidied already. */ + { + rtx insn, stop = NEXT_INSN (c->head); + for (insn = NEXT_INSN (b->end); insn != stop; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == CODE_LABEL && !can_delete_label_p (insn)) + return 0; + } merge_blocks_nomove (b, c); return 1; @@ -5001,3 +5005,220 @@ set_block_num (insn, bb) { set_block_for_insn (insn, BASIC_BLOCK (bb)); } + +/* Verify the CFG consistency. This function check some CFG invariants and + aborts when something is wrong. Hope that this function will help to + convert many optimization passes to preserve CFG consistent. + + Currently it does following checks: + + - test head/end pointers + - overlapping of basic blocks + - edge list corectness + - headers of basic blocks (the NOTE_INSN_BASIC_BLOCK note) + - tails of basic blocks (ensure that boundary is necesary) + - scans body of the basic block for JUMP_INSN, CODE_LABEL + and NOTE_INSN_BASIC_BLOCK + - check that all insns are in the basic blocks + (except the switch handling code, barriers and notes) + + In future it can be extended check a lot of other stuff as well + (reachability of basic blocks, life information, etc. etc.). */ + +void +verify_flow_info () +{ + const int max_uid = get_max_uid (); + const rtx rtx_first = get_insns (); + basic_block *bb_info; + rtx x; + int i; + + bb_info = (basic_block *) alloca (max_uid * sizeof (basic_block)); + memset (bb_info, 0, max_uid * sizeof (basic_block)); + + /* First pass check head/end pointers and set bb_info array used by + later passes. */ + for (i = n_basic_blocks - 1; i >= 0; i--) + { + basic_block bb = BASIC_BLOCK (i); + + /* Check the head pointer and make sure that it is pointing into + insn list. */ + for (x = rtx_first; x != NULL_RTX; x = NEXT_INSN (x)) + if (x == bb->head) + break; + if (!x) + { + fatal ("verify_flow_info: Head insn %d for block %d not found in the insn stream.\n", + INSN_UID (bb->head), bb->index); + } + + /* Check the end pointer and make sure that it is pointing into + insn list. */ + for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x)) + { + if (bb_info[INSN_UID (x)] != NULL) + { + fatal ("verify_flow_info: Insn %d is in multiple basic blocks (%d and %d)", + INSN_UID (x), bb->index, bb_info[INSN_UID (x)]->index); + } + bb_info[INSN_UID (x)] = bb; + + if (x == bb->end) + break; + } + if (!x) + { + fatal ("verify_flow_info: End insn %d for block %d not found in the insn stream.\n", + INSN_UID (bb->end), bb->index); + } + } + + /* Now check the basic blocks (boundaries etc.) */ + for (i = n_basic_blocks - 1; i >= 0; i--) + { + basic_block bb = BASIC_BLOCK (i); + /* Check corectness of edge lists */ + edge e; + + e = bb->succ; + while (e) + { + if (e->src != bb) + { + fprintf (stderr, "verify_flow_info: Basic block %d succ edge is corrupted\n", + bb->index); + fprintf (stderr, "Predecessor: "); + dump_edge_info (stderr, e, 0); + fprintf (stderr, "\nSuccessor: "); + dump_edge_info (stderr, e, 1); + fflush (stderr); + abort (); + } + if (e->dest != EXIT_BLOCK_PTR) + { + edge e2 = e->dest->pred; + while (e2 && e2 != e) + e2 = e2->pred_next; + if (!e2) + { + fatal ("verify_flow_info: Basic block %i edge lists are corrupted\n", + bb->index); + } + } + e = e->succ_next; + } + + e = bb->pred; + while (e) + { + if (e->dest != bb) + { + fprintf (stderr, "verify_flow_info: Basic block %d pred edge is corrupted\n", + bb->index); + fprintf (stderr, "Predecessor: "); + dump_edge_info (stderr, e, 0); + fprintf (stderr, "\nSuccessor: "); + dump_edge_info (stderr, e, 1); + fflush (stderr); + abort (); + } + if (e->src != ENTRY_BLOCK_PTR) + { + edge e2 = e->src->succ; + while (e2 && e2 != e) + e2 = e2->succ_next; + if (!e2) + { + fatal ("verify_flow_info: Basic block %i edge lists are corrupted\n", + bb->index); + } + } + e = e->pred_next; + } + + /* OK pointers are correct. Now check the header of basic + block. It ought to contain optional CODE_LABEL followed + by NOTE_BASIC_BLOCK. */ + x = bb->head; + if (GET_CODE (x) == CODE_LABEL) + { + if (bb->end == x) + { + fatal ("verify_flow_info: Basic block contains only CODE_LABEL and no NOTE_INSN_BASIC_BLOCK note\n"); + } + x = NEXT_INSN (x); + } + if (GET_CODE (x) != NOTE + || NOTE_LINE_NUMBER (x) != NOTE_INSN_BASIC_BLOCK + || NOTE_BASIC_BLOCK (x) != bb) + { + fatal ("verify_flow_info: NOTE_INSN_BASIC_BLOCK is missing for block %d\n", + bb->index); + } + + if (bb->end == x) + { + /* Do checks for empty blocks here */ + } + else + { + x = NEXT_INSN (x); + while (x) + { + if (GET_CODE (x) == NOTE + && NOTE_LINE_NUMBER (x) == NOTE_INSN_BASIC_BLOCK) + { + fatal ("verify_flow_info: NOTE_INSN_BASIC_BLOCK %d in the middle of basic block %d\n", + INSN_UID (x), bb->index); + } + + if (x == bb->end) + break; + + if (GET_CODE (x) == JUMP_INSN + || GET_CODE (x) == CODE_LABEL + || GET_CODE (x) == BARRIER) + { + fatal_insn ("verify_flow_info: Incorrect insn in the middle of basic block %d\n", + x, bb->index); + } + + x = NEXT_INSN (x); + } + } + } + + x = rtx_first; + while (x) + { + if (!bb_info[INSN_UID (x)]) + { + switch (GET_CODE (x)) + { + case BARRIER: + case NOTE: + break; + + case CODE_LABEL: + /* An addr_vec is placed outside any block block. */ + if (NEXT_INSN (x) + && GET_CODE (NEXT_INSN (x)) == JUMP_INSN + && (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC + || GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC)) + { + x = NEXT_INSN (x); + } + + /* But in any case, non-deletable labels can appear anywhere. */ + break; + + default: + fatal_insn ("verify_flow_info: Insn outside basic block\n", x); + } + } + + x = NEXT_INSN (x); + } +} diff --git a/gcc/toplev.c b/gcc/toplev.c index c5675c1..5da9545 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1436,21 +1436,24 @@ fatal_io_error (name) just calling abort(). */ void -fatal_insn (msgid, insn) - const char *msgid; - rtx insn; +fatal_insn VPROTO((const char *msgid, rtx insn, ...)) { - error (msgid); +#ifndef ANSI_PROTOTYPES + const char *msgid; + rtx insn; +#endif + va_list ap; + + VA_START (ap, insn); + +#ifndef ANSI_PROTOTYPES + msgid = va_arg (ap, const char *); + insn = va_arg (ap, rtx); +#endif + + verror (msgid, ap); debug_rtx (insn); - if (asm_out_file) - fflush (asm_out_file); - if (aux_info_file) - fflush (aux_info_file); - if (rtl_dump_file != NULL) - fflush (rtl_dump_file); - fflush (stdout); - fflush (stderr); - abort (); + exit (FATAL_EXIT_CODE); } /* Called to give a better error message when we don't have an insn to match diff --git a/gcc/toplev.h b/gcc/toplev.h index 05a9c40..1f40863 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -43,8 +43,9 @@ extern void pfatal_with_name PROTO ((const char *)) ATTRIBUTE_NORETURN; extern void fatal_insn_not_found PROTO ((struct rtx_def *)) ATTRIBUTE_NORETURN; -extern void fatal_insn PROTO ((const char *, struct rtx_def *)) - ATTRIBUTE_NORETURN; +extern void fatal_insn PVPROTO ((const char *, + struct rtx_def *, ...)) + ATTRIBUTE_PRINTF(1, 3) ATTRIBUTE_NORETURN; extern void warning PVPROTO ((const char *, ...)) ATTRIBUTE_PRINTF_1; extern void error PVPROTO ((const char *, ...)) -- cgit v1.1