OSDN Git Service

* config/s390/s390.c (s390_emit_epilogue): Always restore registers
[pf3gnuchains/gcc-fork.git] / gcc / cfg.c
index f8badd3..766c1b8 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"
@@ -117,8 +119,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 +145,55 @@ 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;
+  edge e;
 
   for (i = 0; i < n_basic_blocks; ++i)
     {
       basic_block bb = BASIC_BLOCK (i);
+      edge e = bb->succ;
+
+      while (e)
+       {
+         edge next = e->succ_next;
 
-      while (bb->succ)
-       remove_edge (bb->succ);
+         free_edge (e);
+         e = next;
+       }
+
+      bb->succ = NULL;
+      bb->pred = NULL;
     }
 
-  while (ENTRY_BLOCK_PTR->succ)
-    remove_edge (ENTRY_BLOCK_PTR->succ);
+  e = ENTRY_BLOCK_PTR->succ;
+  while (e)
+    {
+      edge next = e->succ_next;
+
+      free_edge (e);
+      e = next;
+    }
+
+  EXIT_BLOCK_PTR->pred = NULL;
+  ENTRY_BLOCK_PTR->succ = NULL;
 
   if (n_edges)
     abort ();
@@ -179,8 +214,8 @@ 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;
 }
@@ -188,6 +223,17 @@ alloc_block ()
 /* Remove block B from the basic block array and compact behind it.  */
 
 void
+expunge_block_nocompact (b)
+     basic_block b;
+{
+  /* Invalidate data to make bughunting easier.  */
+  memset (b, 0, sizeof *b);
+  b->index = -3;
+  b->succ = (edge) first_deleted_block;
+  first_deleted_block = (basic_block) b;
+}
+
+void
 expunge_block (b)
      basic_block b;
 {
@@ -200,13 +246,10 @@ expunge_block (b)
       x->index = i;
     }
 
-  /* 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;
+  basic_block_info->num_elements--;
+
+  expunge_block_nocompact (b);
 }
 \f
 /* Create an edge connecting SRC and DST with FLAGS optionally using
@@ -221,17 +264,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 +299,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 +330,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 +355,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 +378,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 +401,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 +409,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 +425,7 @@ redirect_edge_succ_nodup (e, new_succ)
     }
   else
     redirect_edge_succ (e, new_succ);
+
   return e;
 }
 
@@ -398,6 +441,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 +449,22 @@ redirect_edge_pred (e, new_pred)
   new_pred->succ = e;
   e->src = new_pred;
 }
+
+void
+clear_bb_flags ()
+{
+  int i;
+  ENTRY_BLOCK_PTR->flags = 0;
+  EXIT_BLOCK_PTR->flags = 0;
+  for (i = 0; i < n_basic_blocks; i++)
+    BASIC_BLOCK (i)->flags = 0;
+}
 \f
 void
 dump_flow_info (file)
      FILE *file;
 {
-  register int i;
+  int i;
   static const char * const reg_class_names[] = REG_CLASS_NAMES;
 
   fprintf (file, "%d registers.\n", max_regno);
@@ -418,6 +472,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 +480,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 +488,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,7 +505,8 @@ 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");
       }
@@ -456,12 +514,15 @@ dump_flow_info (file)
   fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
   for (i = 0; i < n_basic_blocks; i++)
     {
-      register basic_block bb = BASIC_BLOCK (i);
-      register edge e;
+      basic_block bb = BASIC_BLOCK (i);
+      edge e;
+      int sum;
+      gcov_type lsum;
 
-      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, "\nBasic block %d: first insn %d, last %d, ",
+              i, INSN_UID (bb->head), INSN_UID (bb->end));
+      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, "Predecessors: ");
@@ -479,6 +540,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 +603,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"};
       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 +627,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,6 +668,7 @@ 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 ();
@@ -583,29 +676,41 @@ alloc_aux_for_blocks (size)
   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);
     }
 }
 
-/* Free data allocated in block_aux_obstack and clear AUX pointers
-   of all blocks.  */
+/* Clear AUX pointers of all blocks.  */
 
 void
-free_aux_for_blocks ()
+clear_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;
+}
+
+/* Free data allocated in block_aux_obstack and clear AUX pointers
+   of all blocks.  */
+
+void
+free_aux_for_blocks ()
+{
+  if (!first_block_aux_obj)
+    abort ();
+  obstack_free (&block_aux_obstack, first_block_aux_obj);
   first_block_aux_obj = NULL;
+
+  clear_aux_for_blocks ();
 }
 
 /* Allocate an memory edge of SIZE as BB->aux.  The obstack must
@@ -637,9 +742,11 @@ 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)
     {
@@ -653,23 +760,20 @@ alloc_aux_for_edges (size)
            bb = BASIC_BLOCK (i);
          else
            bb = ENTRY_BLOCK_PTR;
+
          for (e = bb->succ; e; e = e->succ_next)
            alloc_aux_for_edge (e, size);
        }
     }
 }
 
-/* Free data allocated in edge_aux_obstack and clear AUX pointers
-   of all edges.  */
+/* Clear AUX pointers of all edges.  */
 
 void
-free_aux_for_edges ()
+clear_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;
@@ -679,8 +783,22 @@ free_aux_for_edges ()
        bb = BASIC_BLOCK (i);
       else
        bb = ENTRY_BLOCK_PTR;
+
       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 ()
+{
+  if (!first_edge_aux_obj)
+    abort ();
+  obstack_free (&edge_aux_obstack, first_edge_aux_obj);
   first_edge_aux_obj = NULL;
+
+  clear_aux_for_edges ();
 }