OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / cfg.c
index c62033c..32615fb 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, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -57,7 +57,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "function.h"
 #include "except.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "tm_p.h"
 #include "obstack.h"
 #include "timevar.h"
@@ -67,6 +67,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "df.h"
 #include "cfgloop.h"
+#include "tree-flow.h"
 
 /* The obstack on which the flow graph components are allocated.  */
 
@@ -80,17 +81,21 @@ static void free_edge (edge);
 /* Called once at initialization time.  */
 
 void
-init_flow (void)
+init_flow (struct function *the_fun)
 {
-  if (!cfun->cfg)
-    cfun->cfg = GGC_CNEW (struct control_flow_graph);
-  n_edges = 0;
-  ENTRY_BLOCK_PTR = GGC_CNEW (struct basic_block_def);
-  ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
-  EXIT_BLOCK_PTR = GGC_CNEW (struct basic_block_def);
-  EXIT_BLOCK_PTR->index = EXIT_BLOCK;
-  ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR;
-  EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR;
+  if (!the_fun->cfg)
+    the_fun->cfg = ggc_alloc_cleared_control_flow_graph ();
+  n_edges_for_function (the_fun) = 0;
+  ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun)
+    = ggc_alloc_cleared_basic_block_def ();
+  ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun)->index = ENTRY_BLOCK;
+  EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun)
+    = ggc_alloc_cleared_basic_block_def ();
+  EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun)->index = EXIT_BLOCK;
+  ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun)->next_bb
+    = EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun);
+  EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun)->prev_bb
+    = ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun);
 }
 \f
 /* Helper function for remove_edge and clear_edges.  Frees edge structure
@@ -134,7 +139,7 @@ basic_block
 alloc_block (void)
 {
   basic_block bb;
-  bb = GGC_CNEW (struct basic_block_def);
+  bb = ggc_alloc_cleared_basic_block_def ();
   return bb;
 }
 
@@ -166,13 +171,13 @@ compact_blocks (void)
 
   SET_BASIC_BLOCK (ENTRY_BLOCK, ENTRY_BLOCK_PTR);
   SET_BASIC_BLOCK (EXIT_BLOCK, EXIT_BLOCK_PTR);
-  
+
   if (df)
     df_compact_blocks ();
-  else 
+  else
     {
       basic_block bb;
-      
+
       i = NUM_FIXED_BLOCKS;
       FOR_EACH_BB (bb)
        {
@@ -272,7 +277,7 @@ edge
 unchecked_make_edge (basic_block src, basic_block dst, int flags)
 {
   edge e;
-  e = GGC_CNEW (struct edge_def);
+  e = ggc_alloc_cleared_edge_def ();
   n_edges++;
 
   e->src = src;
@@ -359,6 +364,9 @@ remove_edge_raw (edge e)
   disconnect_src (e);
   disconnect_dest (e);
 
+  /* This is probably not needed, but it doesn't hurt.  */
+  redirect_edge_var_map_clear (e);
+
   free_edge (e);
 }
 
@@ -394,6 +402,7 @@ redirect_edge_succ_nodup (edge e, basic_block new_succ)
       if (s->probability > REG_BR_PROB_BASE)
        s->probability = REG_BR_PROB_BASE;
       s->count += e->count;
+      redirect_edge_var_map_dup (s, e);
       remove_edge (e);
       e = s;
     }
@@ -424,7 +433,7 @@ clear_bb_flags (void)
   basic_block bb;
 
   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
-    bb->flags = (BB_PARTITION (bb)  
+    bb->flags = (BB_PARTITION (bb)
                 | (bb->flags & (BB_DISABLE_SCHEDULE + BB_RTL + BB_NON_LOCAL_GOTO_TARGET)));
 }
 \f
@@ -505,7 +514,7 @@ dump_regset (regset r, FILE *outf)
    stream.  This function is designed to be used from within the
    debugger.  */
 
-void
+DEBUG_FUNCTION void
 debug_regset (regset r)
 {
   dump_regset (r, stderr);
@@ -534,11 +543,33 @@ dump_bb_info (basic_block bb, bool header, bool footer, int flags,
       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");
+      /* Both maybe_hot_bb_p & probably_never_executed_bb_p functions
+        crash without cfun. */
+      if (cfun && maybe_hot_bb_p (bb))
+       fputs (", maybe hot", file);
+      if (cfun && probably_never_executed_bb_p (bb))
+       fputs (", probably never executed", file);
+      if (bb->flags)
+       {
+         static const char * const bits[] = {
+           "new", "reachable", "irr_loop", "superblock", "disable_sched",
+           "hot_partition", "cold_partition", "duplicated",
+           "non_local_goto_target", "rtl", "forwarder", "nonthreadable",
+           "modified"
+         };
+         unsigned int flags;
+
+         fputs (", flags:", file);
+         for (flags = bb->flags; flags ; flags &= flags - 1)
+           {
+             unsigned i = ctz_hwi (flags);
+             if (i < ARRAY_SIZE (bits))
+               fprintf (file, " %s", bits[i]);
+             else
+               fprintf (file, " <%d>", i);
+           }
+       }
+      fputs (".\n", file);
 
       fprintf (file, "%sPredecessors: ", prefix);
       FOR_EACH_EDGE (e, ei, bb->preds)
@@ -548,7 +579,7 @@ dump_bb_info (basic_block bb, bool header, bool footer, int flags,
          && (bb->flags & BB_RTL)
          && df)
        {
-         fprintf (file, "\n");
+         putc ('\n', file);
          df_dump_top (bb, file);
        }
    }
@@ -563,7 +594,7 @@ dump_bb_info (basic_block bb, bool header, bool footer, int flags,
          && (bb->flags & BB_RTL)
          && df)
        {
-         fprintf (file, "\n");
+         putc ('\n', file);
          df_dump_bottom (bb, file);
        }
    }
@@ -573,7 +604,7 @@ dump_bb_info (basic_block bb, bool header, bool footer, int flags,
 
 /* Dump the register info to FILE.  */
 
-void 
+void
 dump_reg_info (FILE *file)
 {
   unsigned int i, max = max_reg_num ();
@@ -586,15 +617,15 @@ dump_reg_info (FILE *file)
   fprintf (file, "%d registers.\n", max);
   for (i = FIRST_PSEUDO_REGISTER; i < max; i++)
     {
-      enum reg_class class, altclass;
-      
+      enum reg_class rclass, altclass;
+
       if (regstat_n_sets_and_refs)
        fprintf (file, "\nRegister %d used %d times across %d insns",
                 i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
       else if (df)
        fprintf (file, "\nRegister %d used %d times across %d insns",
                 i, DF_REG_USE_COUNT (i) + DF_REG_DEF_COUNT (i), REG_LIVE_LENGTH (i));
-      
+
       if (REG_BASIC_BLOCK (i) >= NUM_FIXED_BLOCKS)
        fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
       if (regstat_n_sets_and_refs)
@@ -604,34 +635,36 @@ dump_reg_info (FILE *file)
        fprintf (file, "; set %d time%s", DF_REG_DEF_COUNT (i),
                 (DF_REG_DEF_COUNT (i) == 1) ? "" : "s");
       if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i]))
-       fprintf (file, "; user var");
+       fputs ("; user var", file);
       if (REG_N_DEATHS (i) != 1)
        fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
       if (REG_N_CALLS_CROSSED (i) == 1)
-       fprintf (file, "; crosses 1 call");
+       fputs ("; crosses 1 call", file);
       else if (REG_N_CALLS_CROSSED (i))
        fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
+      if (REG_FREQ_CALLS_CROSSED (i))
+       fprintf (file, "; crosses call with %d frequency", REG_FREQ_CALLS_CROSSED (i));
       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);
+
+      rclass = reg_preferred_class (i);
       altclass = reg_alternate_class (i);
-      if (class != GENERAL_REGS || altclass != ALL_REGS)
+      if (rclass != GENERAL_REGS || altclass != ALL_REGS)
        {
-         if (altclass == ALL_REGS || class == ALL_REGS)
-           fprintf (file, "; pref %s", reg_class_names[(int) class]);
+         if (altclass == ALL_REGS || rclass == ALL_REGS)
+           fprintf (file, "; pref %s", reg_class_names[(int) rclass]);
          else if (altclass == NO_REGS)
-           fprintf (file, "; %s or none", reg_class_names[(int) class]);
+           fprintf (file, "; %s or none", reg_class_names[(int) rclass]);
          else
            fprintf (file, "; pref %s, else %s",
-                    reg_class_names[(int) class],
+                    reg_class_names[(int) rclass],
                     reg_class_names[(int) altclass]);
        }
-      
+
       if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i]))
-       fprintf (file, "; pointer");
-      fprintf (file, ".\n");
+       fputs ("; pointer", file);
+      fputs (".\n", file);
     }
 }
 
@@ -646,7 +679,7 @@ dump_flow_info (FILE *file, int flags)
     dump_reg_info (file);
 
   fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
-  FOR_EACH_BB (bb)
+  FOR_ALL_BB (bb)
     {
       dump_bb_info (bb, true, true, flags, "", file);
       check_bb_profile (bb, file);
@@ -655,7 +688,7 @@ dump_flow_info (FILE *file, int flags)
   putc ('\n', file);
 }
 
-void
+DEBUG_FUNCTION void
 debug_flow_info (void)
 {
   dump_flow_info (stderr, TDF_DETAILS);
@@ -665,10 +698,10 @@ void
 dump_edge_info (FILE *file, edge e, int do_succ)
 {
   basic_block side = (do_succ ? e->dest : e->src);
-
-  if (side == ENTRY_BLOCK_PTR)
+  /* both ENTRY_BLOCK_PTR & EXIT_BLOCK_PTR depend upon cfun. */
+  if (cfun && side == ENTRY_BLOCK_PTR)
     fputs (" ENTRY", file);
-  else if (side == EXIT_BLOCK_PTR)
+  else if (cfun && side == EXIT_BLOCK_PTR)
     fputs (" EXIT", file);
   else
     fprintf (file, " %d", side->index);
@@ -678,7 +711,7 @@ dump_edge_info (FILE *file, edge e, int do_succ)
 
   if (e->count)
     {
-      fprintf (file, " count:");
+      fputs (" count:", file);
       fprintf (file, HOST_WIDEST_INT_PRINT_DEC, e->count);
     }
 
@@ -687,7 +720,7 @@ dump_edge_info (FILE *file, edge e, int do_succ)
       static const char * const bitnames[] = {
        "fallthru", "ab", "abcall", "eh", "fake", "dfs_back",
        "can_fallthru", "irreducible", "sibcall", "loop_exit",
-       "true", "false", "exec"
+       "true", "false", "exec", "crossing", "preserve"
       };
       int comma = 0;
       int i, flags = e->flags;
@@ -721,7 +754,7 @@ static void *first_edge_aux_obj = 0;
 /* Allocate a memory block of SIZE as BB->aux.  The obstack must
    be first initialized by alloc_aux_for_blocks.  */
 
-inline void
+static void
 alloc_aux_for_block (basic_block bb, int size)
 {
   /* Verify that aux field is clear.  */
@@ -752,7 +785,7 @@ alloc_aux_for_blocks (int size)
     {
       basic_block bb;
 
-      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+      FOR_ALL_BB (bb)
        alloc_aux_for_block (bb, size);
     }
 }
@@ -764,7 +797,7 @@ clear_aux_for_blocks (void)
 {
   basic_block bb;
 
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_ALL_BB (bb)
     bb->aux = NULL;
 }
 
@@ -781,10 +814,10 @@ free_aux_for_blocks (void)
   clear_aux_for_blocks ();
 }
 
-/* Allocate a memory edge of SIZE as BB->aux.  The obstack must
+/* Allocate a memory edge of SIZE as E->aux.  The obstack must
    be first initialized by alloc_aux_for_edges.  */
 
-inline void
+void
 alloc_aux_for_edge (edge e, int size)
 {
   /* Verify that aux field is clear.  */
@@ -855,13 +888,13 @@ free_aux_for_edges (void)
   clear_aux_for_edges ();
 }
 
-void
+DEBUG_FUNCTION void
 debug_bb (basic_block bb)
 {
   dump_bb (bb, stderr, 0);
 }
 
-basic_block
+DEBUG_FUNCTION basic_block
 debug_bb_n (int n)
 {
   basic_block bb = BASIC_BLOCK (n);
@@ -879,7 +912,9 @@ dump_cfg_bb_info (FILE *file, basic_block bb)
   bool first = true;
   static const char * const bb_bitnames[] =
     {
-      "dirty", "new", "reachable", "visited", "irreducible_loop", "superblock"
+      "new", "reachable", "irreducible_loop", "superblock",
+      "nosched", "hot", "cold", "dup", "xlabel", "rtl",
+      "fwdr", "nothrd"
     };
   const unsigned n_bitnames = sizeof (bb_bitnames) / sizeof (char *);
   edge e;
@@ -889,24 +924,24 @@ dump_cfg_bb_info (FILE *file, basic_block bb)
     if (bb->flags & (1 << i))
       {
        if (first)
-         fprintf (file, " (");
+         fputs (" (", file);
        else
-         fprintf (file, ", ");
+         fputs (", ", file);
        first = false;
-       fprintf (file, bb_bitnames[i]);
+       fputs (bb_bitnames[i], file);
       }
   if (!first)
-    fprintf (file, ")");
-  fprintf (file, "\n");
+    putc (')', file);
+  putc ('\n', file);
 
-  fprintf (file, "Predecessors: ");
+  fputs ("Predecessors: ", file);
   FOR_EACH_EDGE (e, ei, bb->preds)
     dump_edge_info (file, e, 0);
 
   fprintf (file, "\nSuccessors: ");
   FOR_EACH_EDGE (e, ei, bb->succs)
     dump_edge_info (file, e, 1);
-  fprintf (file, "\n\n");
+  fputs ("\n\n", file);
 }
 
 /* Dumps a brief description of cfg to FILE.  */
@@ -986,9 +1021,15 @@ update_bb_profile_for_threading (basic_block bb, int edge_frequency,
 
       FOR_EACH_EDGE (c, ei, bb->succs)
        {
-         c->probability = RDIV (c->probability * scale, 65536);
-         if (c->probability > REG_BR_PROB_BASE)
+         /* Protect from overflow due to additional scaling.  */
+         if (c->probability > prob)
            c->probability = REG_BR_PROB_BASE;
+         else
+           {
+             c->probability = RDIV (c->probability * scale, 65536);
+             if (c->probability > REG_BR_PROB_BASE)
+               c->probability = REG_BR_PROB_BASE;
+           }
        }
     }