OSDN Git Service

* basic-block.h (last_basic_block): Declare.
[pf3gnuchains/gcc-fork.git] / gcc / cfg.c
index 8adcef6..313516b 100644 (file)
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -1,6 +1,6 @@
 /* Control flow graph manipulation code for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
         dump_flow_info, debug_flow_info, dump_edge_info
      - Allocation of AUX fields for basic blocks
         alloc_aux_for_blocks, free_aux_for_blocks, alloc_aux_for_block
+     - clear_bb_flags
  */
 \f
 #include "config.h"
@@ -64,6 +65,10 @@ static char *flow_firstobj;
 
 int n_basic_blocks;
 
+/* First free basic block number.  */
+
+int last_basic_block;
+
 /* Number of edges in the current function.  */
 
 int n_edges;
@@ -92,6 +97,8 @@ struct basic_block_def entry_exit_blocks[2]
     NULL,                      /* global_live_at_end */
     NULL,                      /* aux */
     ENTRY_BLOCK,               /* index */
+    NULL,                      /* prev_bb */
+    EXIT_BLOCK_PTR,            /* next_bb */
     0,                         /* loop_depth */
     0,                         /* count */
     0,                         /* frequency */
@@ -110,6 +117,8 @@ struct basic_block_def entry_exit_blocks[2]
     NULL,                      /* global_live_at_end */
     NULL,                      /* aux */
     EXIT_BLOCK,                        /* index */
+    ENTRY_BLOCK_PTR,           /* prev_bb */
+    NULL,                      /* next_bb */
     0,                         /* loop_depth */
     0,                         /* count */
     0,                         /* frequency */
@@ -162,12 +171,11 @@ free_edge (e)
 void
 clear_edges ()
 {
-  int i;
+  basic_block bb;
   edge e;
 
-  for (i = 0; i < n_basic_blocks; ++i)
+  FOR_EACH_BB (bb)
     {
-      basic_block bb = BASIC_BLOCK (i);
       edge e = bb->succ;
 
       while (e)
@@ -219,26 +227,61 @@ alloc_block ()
   return bb;
 }
 
-/* Remove block B from the basic block array and compact behind it.  */
+/* Link block B to chain after AFTER.  */
+void
+link_block (b, after)
+     basic_block b, after;
+{
+  b->next_bb = after->next_bb;
+  b->prev_bb = after;
+  after->next_bb = b;
+  b->next_bb->prev_bb = b;
+}
 
+/* Unlink block B from chain.  */
 void
-expunge_block (b)
+unlink_block (b)
      basic_block b;
 {
-  int i, n = n_basic_blocks;
+  b->next_bb->prev_bb = b->prev_bb;
+  b->prev_bb->next_bb = b->next_bb;
+}
 
-  for (i = b->index; i + 1 < n; ++i)
+/* Sequentially order blocks and compact the arrays.  */
+void
+compact_blocks ()
+{
+  int i;
+  basic_block bb;
+  i = 0;
+  FOR_EACH_BB (bb)
     {
-      basic_block x = BASIC_BLOCK (i + 1);
-      BASIC_BLOCK (i) = x;
-      x->index = i;
+      BASIC_BLOCK (i) = bb;
+      bb->index = i;
+      i++;
     }
 
+  if (i != n_basic_blocks)
+    abort ();
+
+  last_basic_block = n_basic_blocks;
+}
+
+
+/* Remove block B from the basic block array.  */
+
+void
+expunge_block (b)
+     basic_block b;
+{
+  unlink_block (b);
+  BASIC_BLOCK (b->index) = NULL;
+  n_basic_blocks--;
+
   /* Invalidate data to make bughunting easier.  */
   memset (b, 0, sizeof *b);
   b->index = -3;
-  basic_block_info->num_elements--;
-  n_basic_blocks--;
   b->succ = (edge) first_deleted_block;
   first_deleted_block = (basic_block) b;
 }
@@ -440,12 +483,22 @@ redirect_edge_pred (e, new_pred)
   new_pred->succ = e;
   e->src = new_pred;
 }
+
+void
+clear_bb_flags ()
+{
+  basic_block bb;
+
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+    bb->flags = 0;
+}
 \f
 void
 dump_flow_info (file)
      FILE *file;
 {
   int i;
+  basic_block bb;
   static const char * const reg_class_names[] = REG_CLASS_NAMES;
 
   fprintf (file, "%d registers.\n", max_regno);
@@ -461,7 +514,7 @@ dump_flow_info (file)
        if (REG_N_SETS (i))
          fprintf (file, "; set %d time%s", REG_N_SETS (i),
                   (REG_N_SETS (i) == 1) ? "" : "s");
-       if (REG_USERVAR_P (regno_reg_rtx[i]))
+       if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i]))
          fprintf (file, "; user var");
        if (REG_N_DEATHS (i) != 1)
          fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
@@ -469,7 +522,8 @@ dump_flow_info (file)
          fprintf (file, "; crosses 1 call");
        else if (REG_N_CALLS_CROSSED (i))
          fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
-       if (PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
+       if (regno_reg_rtx[i] != NULL
+           && PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
          fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
 
        class = reg_preferred_class (i);
@@ -486,22 +540,30 @@ dump_flow_info (file)
                       reg_class_names[(int) altclass]);
          }
 
-       if (REG_POINTER (regno_reg_rtx[i]))
+       if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i]))
          fprintf (file, "; pointer");
        fprintf (file, ".\n");
       }
 
   fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
-  for (i = 0; i < n_basic_blocks; i++)
+  FOR_EACH_BB (bb)
     {
-      basic_block bb = BASIC_BLOCK (i);
       edge e;
+      int sum;
+      gcov_type lsum;
 
       fprintf (file, "\nBasic block %d: first insn %d, last %d, ",
               i, INSN_UID (bb->head), INSN_UID (bb->end));
+      fprintf (file, "prev %d, next %d, ",
+              bb->prev_bb->index, bb->next_bb->index);
       fprintf (file, "loop_depth %d, count ", bb->loop_depth);
       fprintf (file, HOST_WIDEST_INT_PRINT_DEC, bb->count);
-      fprintf (file, ", freq %i.\n", bb->frequency);
+      fprintf (file, ", freq %i", bb->frequency);
+      if (maybe_hot_bb_p (bb))
+       fprintf (file, ", maybe hot");
+      if (probably_never_executed_bb_p (bb))
+       fprintf (file, ", probably never executed");
+      fprintf (file, ".\n");
 
       fprintf (file, "Predecessors: ");
       for (e = bb->pred; e; e = e->pred_next)
@@ -518,6 +580,37 @@ dump_flow_info (file)
       dump_regset (bb->global_live_at_end, file);
 
       putc ('\n', file);
+
+      /* Check the consistency of profile information.  We can't do that
+        in verify_flow_info, as the counts may get invalid for incompletely
+        solved graphs, later elliminating of conditionals or roundoff errors.
+        It is still practical to have them reported for debugging of simple
+        testcases.  */
+      sum = 0;
+      for (e = bb->succ; e; e = e->succ_next)
+       sum += e->probability;
+      if (bb->succ && abs (sum - REG_BR_PROB_BASE) > 100)
+       fprintf (file, "Invalid sum of outgoing probabilities %.1f%%\n",
+                sum * 100.0 / REG_BR_PROB_BASE);
+      sum = 0;
+      for (e = bb->pred; e; e = e->pred_next)
+       sum += EDGE_FREQUENCY (e);
+      if (abs (sum - bb->frequency) > 100)
+       fprintf (file,
+                "Invalid sum of incomming frequencies %i, should be %i\n",
+                sum, bb->frequency);
+      lsum = 0;
+      for (e = bb->pred; e; e = e->pred_next)
+       lsum += e->count;
+      if (lsum - bb->count > 100 || lsum - bb->count < -100)
+       fprintf (file, "Invalid sum of incomming counts %i, should be %i\n",
+                (int)lsum, (int)bb->count);
+      lsum = 0;
+      for (e = bb->succ; e; e = e->succ_next)
+       lsum += e->count;
+      if (bb->succ && (lsum - bb->count > 100 || lsum - bb->count < -100))
+       fprintf (file, "Invalid sum of incomming counts %i, should be %i\n",
+                (int)lsum, (int)bb->count);
     }
 
   putc ('\n', file);
@@ -556,7 +649,7 @@ dump_edge_info (file, e, do_succ)
   if (e->flags)
     {
       static const char * const bitnames[]
-       = {"fallthru", "ab", "abcall", "eh", "fake", "dfs_back"};
+       = {"fallthru", "ab", "abcall", "eh", "fake", "dfs_back", "can_fallthru"};
       int comma = 0;
       int i, flags = e->flags;
 
@@ -622,13 +715,10 @@ alloc_aux_for_blocks (size)
   first_block_aux_obj = (char *) obstack_alloc (&block_aux_obstack, 0);
   if (size)
     {
-      int i;
-
-      for (i = 0; i < n_basic_blocks; i++)
-       alloc_aux_for_block (BASIC_BLOCK (i), size);
+      basic_block bb;
 
-      alloc_aux_for_block (ENTRY_BLOCK_PTR, size);
-      alloc_aux_for_block (EXIT_BLOCK_PTR, size);
+      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+       alloc_aux_for_block (bb, size);
     }
 }
 
@@ -637,13 +727,10 @@ alloc_aux_for_blocks (size)
 void
 clear_aux_for_blocks ()
 {
-  int i;
-
-  for (i = 0; i < n_basic_blocks; i++)
-    BASIC_BLOCK (i)->aux = NULL;
+  basic_block bb;
 
-  ENTRY_BLOCK_PTR->aux = NULL;
-  EXIT_BLOCK_PTR->aux = NULL;
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+    bb->aux = NULL;
 }
 
 /* Free data allocated in block_aux_obstack and clear AUX pointers
@@ -697,17 +784,12 @@ alloc_aux_for_edges (size)
   first_edge_aux_obj = (char *) obstack_alloc (&edge_aux_obstack, 0);
   if (size)
     {
-      int i;
-      for (i = -1; i < n_basic_blocks; i++)
+      basic_block bb;
+
+      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
        {
-         basic_block bb;
          edge e;
 
-         if (i >= 0)
-           bb = BASIC_BLOCK (i);
-         else
-           bb = ENTRY_BLOCK_PTR;
-
          for (e = bb->succ; e; e = e->succ_next)
            alloc_aux_for_edge (e, size);
        }
@@ -719,18 +801,11 @@ alloc_aux_for_edges (size)
 void
 clear_aux_for_edges ()
 {
-  int i;
+  basic_block bb;
+  edge e;
 
-  for (i = -1; i < n_basic_blocks; i++)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
     {
-      basic_block bb;
-      edge e;
-
-      if (i >= 0)
-       bb = BASIC_BLOCK (i);
-      else
-       bb = ENTRY_BLOCK_PTR;
-
       for (e = bb->succ; e; e = e->succ_next)
        e->aux = NULL;
     }