X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcfg.c;h=ca04c94770e71f2c789e60aa85ffc7ca2e31271e;hb=140b44efbc2f0035cbfd23e43d97ae9ffc00c122;hp=c62033c8201cbb019157b9c4497ea5c915ba6a25;hpb=8c4c00c181e6df4f0a9afc76e4c9edbbc1c2fd41;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cfg.c b/gcc/cfg.c index c62033c8201..ca04c94770e 100644 --- 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); } /* 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))); } @@ -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; } @@ -784,7 +817,7 @@ free_aux_for_blocks (void) /* Allocate a memory edge of SIZE as BB->aux. The obstack must be first initialized by alloc_aux_for_edges. */ -inline void +static 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; + } } }