diff options
Diffstat (limited to 'gcc/cfg.c')
-rw-r--r-- | gcc/cfg.c | 221 |
1 files changed, 142 insertions, 79 deletions
@@ -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 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GCC. @@ -66,6 +66,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "ggc.h" #include "hashtab.h" #include "alloc-pool.h" +#include "df.h" #include "cfgloop.h" /* The obstack on which the flow graph components are allocated. */ @@ -163,24 +164,28 @@ void compact_blocks (void) { int i; - basic_block bb; SET_BASIC_BLOCK (ENTRY_BLOCK, ENTRY_BLOCK_PTR); SET_BASIC_BLOCK (EXIT_BLOCK, EXIT_BLOCK_PTR); - - i = NUM_FIXED_BLOCKS; - FOR_EACH_BB (bb) + + if (df) + df_compact_blocks (); + else { - SET_BASIC_BLOCK (i, bb); - bb->index = i; - i++; - } - - gcc_assert (i == n_basic_blocks); - - for (; i < last_basic_block; i++) - SET_BASIC_BLOCK (i, NULL); + basic_block bb; + + i = NUM_FIXED_BLOCKS; + FOR_EACH_BB (bb) + { + SET_BASIC_BLOCK (i, bb); + bb->index = i; + i++; + } + gcc_assert (i == n_basic_blocks); + for (; i < last_basic_block; i++) + SET_BASIC_BLOCK (i, NULL); + } last_basic_block = n_basic_blocks; } @@ -205,6 +210,7 @@ static inline void connect_src (edge e) { VEC_safe_push (edge, gc, e->src->succs, e); + df_mark_solutions_dirty (); } /* Connect E to E->dest. */ @@ -215,6 +221,7 @@ connect_dest (edge e) basic_block dest = e->dest; VEC_safe_push (edge, gc, dest->preds, e); e->dest_idx = EDGE_COUNT (dest->preds) - 1; + df_mark_solutions_dirty (); } /* Disconnect edge E from E->src. */ @@ -237,6 +244,7 @@ disconnect_src (edge e) ei_next (&ei); } + df_mark_solutions_dirty (); gcc_unreachable (); } @@ -254,6 +262,7 @@ disconnect_dest (edge e) to update dest_idx of the edge that moved into the "hole". */ if (dest_idx < EDGE_COUNT (dest->preds)) EDGE_PRED (dest, dest_idx)->dest_idx = dest_idx; + df_mark_solutions_dirty (); } /* Create an edge connecting SRC and DEST with flags FLAGS. Return newly @@ -275,7 +284,6 @@ unchecked_make_edge (basic_block src, basic_block dst, int flags) connect_dest (e); execute_on_growing_pred (e); - return e; } @@ -409,15 +417,16 @@ redirect_edge_pred (edge e, basic_block new_pred) connect_src (e); } -/* Clear all basic block flags, with the exception of partitioning. */ +/* Clear all basic block flags, with the exception of partitioning and + setjmp_target. */ void 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_DISABLE_SCHEDULE) - | (bb->flags & BB_RTL)); + bb->flags = (BB_PARTITION (bb) + | (bb->flags & (BB_DISABLE_SCHEDULE + BB_RTL + BB_NON_LOCAL_GOTO_TARGET))); } /* Check the consistency of profile information. We can't do that @@ -469,6 +478,41 @@ check_bb_profile (basic_block bb, FILE * file) } } +/* Write information about registers and basic blocks into FILE. + This is part of making a debugging dump. */ + +void +dump_regset (regset r, FILE *outf) +{ + unsigned i; + reg_set_iterator rsi; + + if (r == NULL) + { + fputs (" (nil)", outf); + return; + } + + EXECUTE_IF_SET_IN_REG_SET (r, 0, i, rsi) + { + fprintf (outf, " %d", i); + if (i < FIRST_PSEUDO_REGISTER) + fprintf (outf, " [%s]", + reg_names[i]); + } +} + +/* Print a human-readable representation of R on the standard error + stream. This function is designed to be used from within the + debugger. */ + +void +debug_regset (regset r) +{ + dump_regset (r, stderr); + putc ('\n', stderr); +} + /* Emit basic block information for BB. HEADER is true if the user wants the generic information and the predecessors, FOOTER is true if they want the successors. FLAGS is the dump flags of interest; TDF_DETAILS emit @@ -500,6 +544,14 @@ dump_bb_info (basic_block bb, bool header, bool footer, int flags, fprintf (file, "%sPredecessors: ", prefix); FOR_EACH_EDGE (e, ei, bb->preds) dump_edge_info (file, e, 0); + + if ((flags & TDF_DETAILS) + && (bb->flags & BB_RTL) + && df) + { + fprintf (file, "\n"); + df_dump_top (bb, file); + } } if (footer) @@ -507,81 +559,92 @@ dump_bb_info (basic_block bb, bool header, bool footer, int flags, fprintf (file, "\n%sSuccessors: ", prefix); FOR_EACH_EDGE (e, ei, bb->succs) dump_edge_info (file, e, 1); - } - if ((flags & TDF_DETAILS) - && (bb->flags & BB_RTL)) - { - if (bb->il.rtl->global_live_at_start && header) + if ((flags & TDF_DETAILS) + && (bb->flags & BB_RTL) + && df) { - fprintf (file, "\n%sRegisters live at start:", prefix); - dump_regset (bb->il.rtl->global_live_at_start, file); - } - - if (bb->il.rtl->global_live_at_end && footer) - { - fprintf (file, "\n%sRegisters live at end:", prefix); - dump_regset (bb->il.rtl->global_live_at_end, file); + fprintf (file, "\n"); + df_dump_bottom (bb, file); } } putc ('\n', file); } +/* Dump the register info to FILE. */ + +void +dump_reg_info (FILE *file) +{ + unsigned int i, max = max_reg_num (); + if (reload_completed) + return; + + if (reg_info_p_size < max) + max = reg_info_p_size; + + fprintf (file, "%d registers.\n", max); + for (i = FIRST_PSEUDO_REGISTER; i < max; i++) + { + enum reg_class class, 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) + fprintf (file, "; set %d time%s", REG_N_SETS (i), + (REG_N_SETS (i) == 1) ? "" : "s"); + else if (df) + 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"); + 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"); + else if (REG_N_CALLS_CROSSED (i)) + fprintf (file, "; crosses %d calls", REG_N_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); + altclass = reg_alternate_class (i); + if (class != GENERAL_REGS || altclass != ALL_REGS) + { + if (altclass == ALL_REGS || class == ALL_REGS) + fprintf (file, "; pref %s", reg_class_names[(int) class]); + else if (altclass == NO_REGS) + fprintf (file, "; %s or none", reg_class_names[(int) class]); + else + fprintf (file, "; pref %s, else %s", + reg_class_names[(int) class], + reg_class_names[(int) altclass]); + } + + if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i])) + fprintf (file, "; pointer"); + fprintf (file, ".\n"); + } +} + + void dump_flow_info (FILE *file, int flags) { basic_block bb; /* There are no pseudo registers after reload. Don't dump them. */ - if (reg_n_info && !reload_completed - && (flags & TDF_DETAILS) != 0) - { - unsigned int i, max = max_reg_num (); - fprintf (file, "%d registers.\n", max); - for (i = FIRST_PSEUDO_REGISTER; i < max; i++) - if (REG_N_REFS (i)) - { - enum reg_class prefclass, 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) - fprintf (file, " in block %d", REG_BASIC_BLOCK (i)); - if (REG_N_SETS (i)) - fprintf (file, "; set %d time%s", REG_N_SETS (i), - (REG_N_SETS (i) == 1) ? "" : "s"); - 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)); - if (REG_N_CALLS_CROSSED (i) == 1) - fprintf (file, "; crosses 1 call"); - else if (REG_N_CALLS_CROSSED (i)) - fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i)); - if (regno_reg_rtx[i] != NULL - && PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD) - fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i)); - - prefclass = reg_preferred_class (i); - altclass = reg_alternate_class (i); - if (prefclass != GENERAL_REGS || altclass != ALL_REGS) - { - if (altclass == ALL_REGS || prefclass == ALL_REGS) - fprintf (file, "; pref %s", reg_class_names[(int) prefclass]); - else if (altclass == NO_REGS) - fprintf (file, "; %s or none", reg_class_names[(int) prefclass]); - else - fprintf (file, "; pref %s, else %s", - reg_class_names[(int) prefclass], - reg_class_names[(int) altclass]); - } - - if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i])) - fprintf (file, "; pointer"); - fprintf (file, ".\n"); - } - } + if (reg_info_p_size && (flags & TDF_DETAILS) != 0) + dump_reg_info (file); fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges); FOR_EACH_BB (bb) |