aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@cygnus.com>1999-04-06 22:10:53 +0000
committerRichard Henderson <rth@cygnus.com>1999-04-06 22:10:53 +0000
commit23483032286e47df621fecd173706359bb03e7a1 (patch)
tree90a39e1a592c285664eb3df641380a889308f933
parent2fce2931aa7c6ea43d1fc431c4de23c590087d2d (diff)
* 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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@26226 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/flow.c239
-rw-r--r--gcc/toplev.c29
-rw-r--r--gcc/toplev.h5
4 files changed, 263 insertions, 24 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d3892b20f5c..443a62835ea 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+Tue Apr 6 22:09:40 1999 Richard Henderson <rth@cygnus.com>
+
+ * 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 <hubicka@paru.cas.cz>
+ Richard Henderson <rth@cygnus.com>
+
+ * 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 <hubicka@paru.cas.cz>
* flow.c (split_edge) update correctly flow graph, disable
diff --git a/gcc/flow.c b/gcc/flow.c
index d2d1d500825..072d2089c79 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 c5675c1c172..5da95455555 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 05a9c40315b..1f408637719 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 *, ...))