OSDN Git Service

* config/s390/s390.c (s390_emit_epilogue): Always restore registers
[pf3gnuchains/gcc-fork.git] / gcc / cfg.c
index 37c994f..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.
 
@@ -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"
@@ -152,7 +153,7 @@ free_edge (e)
      edge e;
 {
   n_edges--;
-  memset (e, 0, sizeof (*e));
+  memset (e, 0, sizeof *e);
   e->succ_next = first_deleted_edge;
   first_deleted_edge = e;
 }
@@ -177,6 +178,7 @@ clear_edges ()
          free_edge (e);
          e = next;
        }
+
       bb->succ = NULL;
       bb->pred = NULL;
     }
@@ -189,6 +191,7 @@ clear_edges ()
       free_edge (e);
       e = next;
     }
+
   EXIT_BLOCK_PTR->pred = NULL;
   ENTRY_BLOCK_PTR->succ = NULL;
 
@@ -211,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;
 }
@@ -220,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;
 {
@@ -232,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
@@ -253,11 +264,10 @@ 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)
@@ -289,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++;
 
@@ -345,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)
@@ -398,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;
@@ -412,6 +425,7 @@ redirect_edge_succ_nodup (e, new_succ)
     }
   else
     redirect_edge_succ (e, new_succ);
+
   return e;
 }
 
@@ -427,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.  */
@@ -434,6 +449,16 @@ 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)
@@ -447,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)
@@ -454,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));
@@ -462,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)
@@ -477,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");
       }
@@ -487,10 +516,13 @@ dump_flow_info (file)
     {
       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: ");
@@ -508,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);
@@ -540,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))
          {
@@ -566,11 +627,13 @@ dump_edge_info (file, e, do_succ)
              fprintf (file, "%d", i);
            comma = 1;
          }
+
       fputc (')', file);
     }
 }
 \f
 /* 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;
@@ -605,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 ();
@@ -612,8 +676,10 @@ 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);
     }
@@ -628,6 +694,7 @@ clear_aux_for_blocks ()
 
   for (i = 0; i < n_basic_blocks; i++)
     BASIC_BLOCK (i)->aux = NULL;
+
   ENTRY_BLOCK_PTR->aux = NULL;
   EXIT_BLOCK_PTR->aux = NULL;
 }
@@ -675,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)
     {
@@ -691,6 +760,7 @@ 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);
        }
@@ -713,6 +783,7 @@ clear_aux_for_edges ()
        bb = BASIC_BLOCK (i);
       else
        bb = ENTRY_BLOCK_PTR;
+
       for (e = bb->succ; e; e = e->succ_next)
        e->aux = NULL;
     }