OSDN Git Service

* basic-block.h (last_basic_block): Declare.
[pf3gnuchains/gcc-fork.git] / gcc / cfg.c
index d8d8c99..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.
 
@@ -19,10 +19,11 @@ along with GCC; see the file COPYING.  If not, write to the Free
 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 02111-1307, USA.  */
 
-/* This file contains low level functions to manipulate with CFG and analyze it.
-   All other modules should not transform the datastructure directly and use
-   abstraction instead.  The file is supposed to be ordered bottom-up and should
-   not contain any code depdendent on particular intermediate language (RTL or trees)
+/* This file contains low level functions to manipulate the CFG and
+   analyze it.  All other modules should not transform the datastructure
+   directly and use abstraction instead.  The file is supposed to be
+   ordered bottom-up and should not contain any code dependent on a
+   particular intermediate language (RTL or trees).
 
    Available functionality:
      - Initialization/deallocation
@@ -33,10 +34,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
         make_edge, make_single_succ_edge, cached_make_edge, remove_edge
         - Low level edge redirection (without updating instruction chain)
             redirect_edge_succ, redirect_edge_succ_nodup, redirect_edge_pred
-     - Dumpipng and debugging
+     - Dumping and debugging
         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"
@@ -63,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;
@@ -91,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 */
@@ -109,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 */
@@ -117,8 +127,9 @@ struct basic_block_def entry_exit_blocks[2]
 };
 
 void debug_flow_info                   PARAMS ((void));
+static void free_edge                  PARAMS ((edge));
 \f
-/* Called once at intialization time.  */
+/* Called once at initialization time.  */
 
 void
 init_flow ()
@@ -142,23 +153,54 @@ init_flow ()
     }
 }
 \f
+/* Helper function for remove_edge and clear_edges.  Frees edge structure
+   without actually unlinking it from the pred/succ lists.  */
+
+static void
+free_edge (e)
+     edge e;
+{
+  n_edges--;
+  memset (e, 0, sizeof *e);
+  e->succ_next = first_deleted_edge;
+  first_deleted_edge = e;
+}
+
 /* Free the memory associated with the edge structures.  */
 
 void
 clear_edges ()
 {
-  int i;
+  basic_block bb;
+  edge e;
+
+  FOR_EACH_BB (bb)
+    {
+      edge e = bb->succ;
+
+      while (e)
+       {
+         edge next = e->succ_next;
+
+         free_edge (e);
+         e = next;
+       }
+
+      bb->succ = NULL;
+      bb->pred = NULL;
+    }
 
-  for (i = 0; i < n_basic_blocks; ++i)
+  e = ENTRY_BLOCK_PTR->succ;
+  while (e)
     {
-      basic_block bb = BASIC_BLOCK (i);
+      edge next = e->succ_next;
 
-      while (bb->succ)
-       remove_edge (bb->succ);
+      free_edge (e);
+      e = next;
     }
 
-  while (ENTRY_BLOCK_PTR->succ)
-    remove_edge (ENTRY_BLOCK_PTR->succ);
+  EXIT_BLOCK_PTR->pred = NULL;
+  ENTRY_BLOCK_PTR->succ = NULL;
 
   if (n_edges)
     abort ();
@@ -179,32 +221,67 @@ alloc_block ()
     }
   else
     {
-      bb = (basic_block) obstack_alloc (&flow_obstack, sizeof (*bb));
-      memset (bb, 0, sizeof (*bb));
+      bb = (basic_block) obstack_alloc (&flow_obstack, sizeof *bb);
+      memset (bb, 0, sizeof *bb);
     }
   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));
+  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;
 }
@@ -221,17 +298,16 @@ cached_make_edge (edge_cache, src, dst, flags)
   int use_edge_cache;
   edge e;
 
-  /* Don't bother with edge cache for ENTRY or EXIT; there aren't that
-     many edges to them, and we didn't allocate memory for it.  */
+  /* Don't bother with edge cache for ENTRY or EXIT, if there aren't that
+     many edges to them, or we didn't allocate memory for it.  */
   use_edge_cache = (edge_cache
-                   && src != ENTRY_BLOCK_PTR
-                   && dst != EXIT_BLOCK_PTR);
+                   && src != ENTRY_BLOCK_PTR && dst != EXIT_BLOCK_PTR);
 
   /* Make sure we don't add duplicate edges.  */
   switch (use_edge_cache)
     {
     default:
-      /* Quick test for non-existance of the edge.  */
+      /* Quick test for non-existence of the edge.  */
       if (! TEST_BIT (edge_cache[src->index], dst->index))
        break;
 
@@ -257,8 +333,8 @@ cached_make_edge (edge_cache, src, dst, flags)
     }
   else
     {
-      e = (edge) obstack_alloc (&flow_obstack, sizeof (*e));
-      memset (e, 0, sizeof (*e));
+      e = (edge) obstack_alloc (&flow_obstack, sizeof *e);
+      memset (e, 0, sizeof *e);
     }
   n_edges++;
 
@@ -288,7 +364,7 @@ make_edge (src, dest, flags)
   return cached_make_edge (NULL, src, dest, flags);
 }
 
-/* Create an edge connecting SRC to DEST and set probability by knowling
+/* Create an edge connecting SRC to DEST and set probability by knowing
    that it is the single edge leaving SRC.  */
 
 edge
@@ -313,6 +389,7 @@ remove_edge (e)
   edge last_succ = NULL;
   edge tmp;
   basic_block src, dest;
+
   src = e->src;
   dest = e->dest;
   for (tmp = src->succ; tmp && tmp != e; tmp = tmp->succ_next)
@@ -335,10 +412,7 @@ remove_edge (e)
   else
     dest->pred = e->pred_next;
 
-  n_edges--;
-  memset (e, 0, sizeof (*e));
-  e->succ_next = first_deleted_edge;
-  first_deleted_edge = e;
+  free_edge (e);
 }
 
 /* Redirect an edge's successor from one block to another.  */
@@ -361,7 +435,7 @@ redirect_edge_succ (e, new_succ)
   e->dest = new_succ;
 }
 
-/* Like previous but avoid possible dupplicate edge.  */
+/* Like previous but avoid possible duplicate edge.  */
 
 edge
 redirect_edge_succ_nodup (e, new_succ)
@@ -369,10 +443,12 @@ redirect_edge_succ_nodup (e, new_succ)
      basic_block new_succ;
 {
   edge s;
+
   /* Check whether the edge is already present.  */
   for (s = e->src->succ; s; s = s->succ_next)
     if (s->dest == new_succ && s != e)
       break;
+
   if (s)
     {
       s->flags |= e->flags;
@@ -383,6 +459,7 @@ redirect_edge_succ_nodup (e, new_succ)
     }
   else
     redirect_edge_succ (e, new_succ);
+
   return e;
 }
 
@@ -398,6 +475,7 @@ redirect_edge_pred (e, new_pred)
   /* Disconnect the edge from the old predecessor block.  */
   for (pe = &e->src->succ; *pe != e; pe = &(*pe)->succ_next)
     continue;
+
   *pe = (*pe)->succ_next;
 
   /* Reconnect the edge to the new predecessor block.  */
@@ -405,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);
@@ -418,6 +506,7 @@ dump_flow_info (file)
     if (REG_N_REFS (i))
       {
        enum reg_class class, altclass;
+
        fprintf (file, "\nRegister %d used %d times across %d insns",
                 i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
        if (REG_BASIC_BLOCK (i) >= 0)
@@ -425,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));
@@ -433,8 +522,10 @@ 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);
        altclass = reg_alternate_class (i);
        if (class != GENERAL_REGS || altclass != ALL_REGS)
@@ -448,21 +539,31 @@ dump_flow_info (file)
                       reg_class_names[(int) class],
                       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;
-
-      fprintf (file, "\nBasic block %d: first insn %d, last %d, loop_depth %d, count ",
-              i, INSN_UID (bb->head), INSN_UID (bb->end), bb->loop_depth);
-      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
-      fprintf (file, ", freq %i.\n", bb->frequency);
+      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", 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)
@@ -479,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);
@@ -511,19 +643,17 @@ dump_edge_info (file, e, do_succ)
   if (e->count)
     {
       fprintf (file, " count:");
-      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) e->count);
+      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, e->count);
     }
 
   if (e->flags)
     {
-      static const char * const bitnames[] = {
-       "fallthru", "ab", "abcall", "eh", "fake", "dfs_back"
-      };
+      static const char * const bitnames[]
+       = {"fallthru", "ab", "abcall", "eh", "fake", "dfs_back", "can_fallthru"};
       int comma = 0;
       int i, flags = e->flags;
 
-      fputc (' ', file);
-      fputc ('(', file);
+      fputs (" (", file);
       for (i = 0; flags; i++)
        if (flags & (1 << i))
          {
@@ -537,11 +667,13 @@ dump_edge_info (file, e, do_succ)
              fprintf (file, "%d", i);
            comma = 1;
          }
+
       fputc (')', file);
     }
 }
 \f
-/* Simple routies to easilly allocate AUX fields of basic blocks.  */
+/* Simple routines to easily allocate AUX fields of basic blocks.  */
+
 static struct obstack block_aux_obstack;
 static void *first_block_aux_obj = 0;
 static struct obstack edge_aux_obstack;
@@ -576,36 +708,43 @@ alloc_aux_for_blocks (size)
       gcc_obstack_init (&block_aux_obstack);
       initialized = 1;
     }
+
   /* Check whether AUX data are still allocated.  */
   else if (first_block_aux_obj)
     abort ();
   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);
-      alloc_aux_for_block (ENTRY_BLOCK_PTR, size);
-      alloc_aux_for_block (EXIT_BLOCK_PTR, size);
+      basic_block bb;
+
+      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+       alloc_aux_for_block (bb, size);
     }
 }
 
+/* Clear AUX pointers of all blocks.  */
+
+void
+clear_aux_for_blocks ()
+{
+  basic_block bb;
+
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+    bb->aux = NULL;
+}
+
 /* Free data allocated in block_aux_obstack and clear AUX pointers
    of all blocks.  */
 
 void
 free_aux_for_blocks ()
 {
-  int i;
-
   if (!first_block_aux_obj)
     abort ();
   obstack_free (&block_aux_obstack, first_block_aux_obj);
-  for (i = 0; i < n_basic_blocks; i++)
-    BASIC_BLOCK (i)->aux = NULL;
-  ENTRY_BLOCK_PTR->aux = NULL;
-  EXIT_BLOCK_PTR->aux = NULL;
   first_block_aux_obj = NULL;
+
+  clear_aux_for_blocks ();
 }
 
 /* Allocate an memory edge of SIZE as BB->aux.  The obstack must
@@ -637,50 +776,51 @@ alloc_aux_for_edges (size)
       gcc_obstack_init (&edge_aux_obstack);
       initialized = 1;
     }
+
   /* Check whether AUX data are still allocated.  */
   else if (first_edge_aux_obj)
     abort ();
+
   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);
        }
     }
 }
 
+/* Clear AUX pointers of all edges.  */
+
+void
+clear_aux_for_edges ()
+{
+  basic_block bb;
+  edge e;
+
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
+    {
+      for (e = bb->succ; e; e = e->succ_next)
+       e->aux = NULL;
+    }
+}
+
 /* Free data allocated in edge_aux_obstack and clear AUX pointers
    of all edges.  */
 
 void
 free_aux_for_edges ()
 {
-  int i;
-
   if (!first_edge_aux_obj)
     abort ();
   obstack_free (&edge_aux_obstack, first_edge_aux_obj);
-  for (i = -1; i < n_basic_blocks; i++)
-    {
-      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;
-    }
   first_edge_aux_obj = NULL;
+
+  clear_aux_for_edges ();
 }