/* 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.
#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. */
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;
}
connect_src (edge e)
{
VEC_safe_push (edge, gc, e->src->succs, e);
+ df_mark_solutions_dirty ();
}
/* Connect E to E->dest. */
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. */
ei_next (&ei);
}
+ df_mark_solutions_dirty ();
gcc_unreachable ();
}
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
connect_dest (e);
execute_on_growing_pred (e);
-
return e;
}
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)));
}
\f
/* Check the consistency of profile information. We can't do that
}
}
\f
+/* 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
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)
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)