/* 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.
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"
int n_basic_blocks;
+/* First free basic block number. */
+
+int last_basic_block;
+
/* Number of edges in the current function. */
int n_edges;
NULL, /* global_live_at_end */
NULL, /* aux */
ENTRY_BLOCK, /* index */
+ NULL, /* prev_bb */
+ EXIT_BLOCK_PTR, /* next_bb */
0, /* loop_depth */
0, /* count */
0, /* frequency */
NULL, /* global_live_at_end */
NULL, /* aux */
EXIT_BLOCK, /* index */
+ ENTRY_BLOCK_PTR, /* prev_bb */
+ NULL, /* next_bb */
0, /* loop_depth */
0, /* count */
0, /* frequency */
void
clear_edges ()
{
- int i;
+ basic_block bb;
edge e;
- for (i = 0; i < n_basic_blocks; ++i)
+ FOR_EACH_BB (bb)
{
- basic_block bb = BASIC_BLOCK (i);
edge e = bb->succ;
while (e)
return bb;
}
-/* Remove block B from the basic block array and compact behind it. */
+/* Link block B to chain after AFTER. */
+void
+link_block (b, after)
+ basic_block b, after;
+{
+ b->next_bb = after->next_bb;
+ b->prev_bb = after;
+ after->next_bb = b;
+ b->next_bb->prev_bb = b;
+}
+/* Unlink block B from chain. */
void
-expunge_block (b)
+unlink_block (b)
basic_block b;
{
- int i, n = n_basic_blocks;
+ b->next_bb->prev_bb = b->prev_bb;
+ b->prev_bb->next_bb = b->next_bb;
+}
- for (i = b->index; i + 1 < n; ++i)
+/* Sequentially order blocks and compact the arrays. */
+void
+compact_blocks ()
+{
+ int i;
+ basic_block bb;
+
+ i = 0;
+ FOR_EACH_BB (bb)
{
- basic_block x = BASIC_BLOCK (i + 1);
- BASIC_BLOCK (i) = x;
- x->index = i;
+ BASIC_BLOCK (i) = bb;
+ bb->index = i;
+ i++;
}
+ if (i != n_basic_blocks)
+ abort ();
+
+ last_basic_block = n_basic_blocks;
+}
+
+
+/* Remove block B from the basic block array. */
+
+void
+expunge_block (b)
+ basic_block b;
+{
+ unlink_block (b);
+ BASIC_BLOCK (b->index) = NULL;
+ n_basic_blocks--;
+
/* 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;
}
new_pred->succ = e;
e->src = new_pred;
}
+
+void
+clear_bb_flags ()
+{
+ basic_block bb;
+
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+ bb->flags = 0;
+}
\f
void
dump_flow_info (file)
FILE *file;
{
int i;
+ basic_block bb;
static const char * const reg_class_names[] = REG_CLASS_NAMES;
fprintf (file, "%d registers.\n", max_regno);
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));
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);
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");
}
fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
- for (i = 0; i < n_basic_blocks; i++)
+ FOR_EACH_BB (bb)
{
- basic_block bb = BASIC_BLOCK (i);
edge e;
+ int sum;
+ gcov_type lsum;
fprintf (file, "\nBasic block %d: first insn %d, last %d, ",
i, INSN_UID (bb->head), INSN_UID (bb->end));
+ fprintf (file, "prev %d, next %d, ",
+ bb->prev_bb->index, bb->next_bb->index);
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, ", 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");
fprintf (file, "Predecessors: ");
for (e = bb->pred; e; e = e->pred_next)
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);
if (e->flags)
{
static const char * const bitnames[]
- = {"fallthru", "ab", "abcall", "eh", "fake", "dfs_back"};
+ = {"fallthru", "ab", "abcall", "eh", "fake", "dfs_back", "can_fallthru"};
int comma = 0;
int i, flags = e->flags;
first_block_aux_obj = (char *) obstack_alloc (&block_aux_obstack, 0);
if (size)
{
- int i;
-
- for (i = 0; i < n_basic_blocks; i++)
- alloc_aux_for_block (BASIC_BLOCK (i), size);
+ basic_block bb;
- alloc_aux_for_block (ENTRY_BLOCK_PTR, size);
- alloc_aux_for_block (EXIT_BLOCK_PTR, size);
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+ alloc_aux_for_block (bb, size);
}
}
void
clear_aux_for_blocks ()
{
- int i;
-
- for (i = 0; i < n_basic_blocks; i++)
- BASIC_BLOCK (i)->aux = NULL;
+ basic_block bb;
- ENTRY_BLOCK_PTR->aux = NULL;
- EXIT_BLOCK_PTR->aux = NULL;
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+ bb->aux = NULL;
}
/* Free data allocated in block_aux_obstack and clear AUX pointers
first_edge_aux_obj = (char *) obstack_alloc (&edge_aux_obstack, 0);
if (size)
{
- int i;
- for (i = -1; i < n_basic_blocks; i++)
+ basic_block bb;
+
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{
- basic_block bb;
edge e;
- if (i >= 0)
- bb = BASIC_BLOCK (i);
- else
- bb = ENTRY_BLOCK_PTR;
-
for (e = bb->succ; e; e = e->succ_next)
alloc_aux_for_edge (e, size);
}
void
clear_aux_for_edges ()
{
- int i;
+ basic_block bb;
+ edge e;
- for (i = -1; i < n_basic_blocks; i++)
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{
- basic_block bb;
- edge e;
-
- if (i >= 0)
- bb = BASIC_BLOCK (i);
- else
- bb = ENTRY_BLOCK_PTR;
-
for (e = bb->succ; e; e = e->succ_next)
e->aux = NULL;
}