]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
flow.c (verify_flow_info): New function.
authorRichard Henderson <rth@gcc.gnu.org>
Tue, 6 Apr 1999 22:10:53 +0000 (15:10 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Tue, 6 Apr 1999 22:10:53 +0000 (15:10 -0700)
        * 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
gcc/flow.c
gcc/toplev.c
gcc/toplev.h

index d3892b20f5cb4b26b187e3c0d31f292187136284..443a62835eaca1e4d8b5cb2045c2bef1845111c8 100644 (file)
@@ -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
index d2d1d50082505c7c1c493961a211bb71cafb8c6f..072d2089c79b32342b9eba6cb78dac75f3801919 100644 (file)
@@ -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));
 \f
 /* 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));
 }
+\f
+/* 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);
+    }
+}
index c5675c1c172c76f1c42df3e2ef846b68b0533dab..5da95455555bc2b159cce0459f3fcdac35ec66df 100644 (file)
@@ -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
index 05a9c40315bf556c907b2554db6ab94510c9b4e7..1f4086377197ded23fcb386540c93311f7490382 100644 (file)
@@ -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 *, ...))