/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
This file is part of GCC.
#include "tree.h"
#include "rtl.h"
#include "hard-reg-set.h"
-#include "basic-block.h"
#include "regs.h"
#include "flags.h"
#include "output.h"
#include "toplev.h"
#include "tm_p.h"
#include "obstack.h"
-#include "alloc-pool.h"
#include "timevar.h"
#include "ggc.h"
/* The obstack on which the flow graph components are allocated. */
-struct obstack flow_obstack;
-static char *flow_firstobj;
-
-/* Number of basic blocks in the current function. */
-
-int n_basic_blocks;
-
-/* First free basic block number. */
-
-int last_basic_block;
-
-/* Number of edges in the current function. */
-
-int n_edges;
-
-/* The basic block array. */
-
-varray_type basic_block_info;
-
-/* The special entry and exit blocks. */
-basic_block ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR;
-
-/* Memory alloc pool for bb member rbi. */
-alloc_pool rbi_pool;
+struct bitmap_obstack reg_obstack;
void debug_flow_info (void);
static void free_edge (edge);
-
-/* Indicate the presence of the profile. */
-enum profile_status profile_status;
\f
+#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
+
/* Called once at initialization time. */
void
init_flow (void)
{
- static int initialized;
-
- n_edges = 0;
-
- if (!initialized)
- {
- gcc_obstack_init (&flow_obstack);
- flow_firstobj = obstack_alloc (&flow_obstack, 0);
- initialized = 1;
- }
- else
- {
- obstack_free (&flow_obstack, flow_firstobj);
- flow_firstobj = obstack_alloc (&flow_obstack, 0);
- }
- ENTRY_BLOCK_PTR = ggc_alloc_cleared (sizeof (*ENTRY_BLOCK_PTR));
+ ENTRY_BLOCK_PTR = ggc_alloc_cleared (sizeof (struct basic_block_def));
ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
- EXIT_BLOCK_PTR = ggc_alloc_cleared (sizeof (*EXIT_BLOCK_PTR));
+ EXIT_BLOCK_PTR = ggc_alloc_cleared (sizeof (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;
{
basic_block bb;
edge e;
+ edge_iterator ei;
FOR_EACH_BB (bb)
{
- edge e = bb->succ;
-
- while (e)
- {
- edge next = e->succ_next;
-
- free_edge (e);
- e = next;
- }
-
- bb->succ = NULL;
- bb->pred = NULL;
- }
-
- e = ENTRY_BLOCK_PTR->succ;
- while (e)
- {
- edge next = e->succ_next;
-
- free_edge (e);
- e = next;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ free_edge (e);
+ VEC_truncate (edge, bb->succs, 0);
+ VEC_truncate (edge, bb->preds, 0);
}
- EXIT_BLOCK_PTR->pred = NULL;
- ENTRY_BLOCK_PTR->succ = NULL;
+ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+ free_edge (e);
+ VEC_truncate (edge, EXIT_BLOCK_PTR->preds, 0);
+ VEC_truncate (edge, ENTRY_BLOCK_PTR->succs, 0);
gcc_assert (!n_edges);
}
return bb;
}
-/* Create memory pool for rbi_pool. */
-
-void
-alloc_rbi_pool (void)
-{
- rbi_pool = create_alloc_pool ("rbi pool",
- sizeof (struct reorder_block_def),
- n_basic_blocks + 2);
-}
-
-/* Free rbi_pool. */
-
-void
-free_rbi_pool (void)
-{
- free_alloc_pool (rbi_pool);
-}
-
/* Initialize rbi (the structure containing data used by basic block
duplication and reordering) for the given basic block. */
initialize_bb_rbi (basic_block bb)
{
gcc_assert (!bb->rbi);
- bb->rbi = pool_alloc (rbi_pool);
- memset (bb->rbi, 0, sizeof (struct reorder_block_def));
+ bb->rbi = ggc_alloc_cleared (sizeof (struct reorder_block_def));
}
/* Link block B to chain after AFTER. */
clear out BB pointer of dead statements consistently. */
}
\f
+/* Connect E to E->src. */
+
+static inline void
+connect_src (edge e)
+{
+ VEC_safe_push (edge, gc, e->src->succs, e);
+}
+
+/* Connect E to E->dest. */
+
+static inline void
+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;
+}
+
+/* Disconnect edge E from E->src. */
+
+static inline void
+disconnect_src (edge e)
+{
+ basic_block src = e->src;
+ edge_iterator ei;
+ edge tmp;
+
+ for (ei = ei_start (src->succs); (tmp = ei_safe_edge (ei)); )
+ {
+ if (tmp == e)
+ {
+ VEC_unordered_remove (edge, src->succs, ei.index);
+ return;
+ }
+ else
+ ei_next (&ei);
+ }
+
+ gcc_unreachable ();
+}
+
+/* Disconnect edge E from E->dest. */
+
+static inline void
+disconnect_dest (edge e)
+{
+ basic_block dest = e->dest;
+ unsigned int dest_idx = e->dest_idx;
+
+ VEC_unordered_remove (edge, dest->preds, dest_idx);
+
+ /* If we removed an edge in the middle of the edge vector, we need
+ 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;
+}
+
/* Create an edge connecting SRC and DEST with flags FLAGS. Return newly
created edge. Use this only if you are sure that this edge can't
possibly already exist. */
e = ggc_alloc_cleared (sizeof (*e));
n_edges++;
- e->succ_next = src->succ;
- e->pred_next = dst->pred;
e->src = src;
e->dest = dst;
e->flags = flags;
- src->succ = e;
- dst->pred = e;
+ connect_src (e);
+ connect_dest (e);
+
+ execute_on_growing_pred (e);
return e;
}
edge cache CACHE. Return the new edge, NULL if already exist. */
edge
-cached_make_edge (sbitmap *edge_cache, basic_block src, basic_block dst, int flags)
+cached_make_edge (sbitmap edge_cache, basic_block src, basic_block dst, int flags)
{
- int use_edge_cache;
- edge e;
+ if (edge_cache == NULL
+ || src == ENTRY_BLOCK_PTR
+ || dst == EXIT_BLOCK_PTR)
+ return make_edge (src, dst, flags);
- /* Don't bother with edge cache for ENTRY or EXIT, if there aren't that
- many edges to them, or we didn't allocate memory for it. */
- use_edge_cache = (edge_cache
- && src != ENTRY_BLOCK_PTR && dst != EXIT_BLOCK_PTR);
-
- /* Make sure we don't add duplicate edges. */
- switch (use_edge_cache)
+ /* Does the requested edge already exist? */
+ if (! TEST_BIT (edge_cache, dst->index))
{
- default:
- /* Quick test for non-existence of the edge. */
- if (! TEST_BIT (edge_cache[src->index], dst->index))
- break;
-
- /* The edge exists; early exit if no work to do. */
- if (flags == 0)
- return NULL;
-
- /* Fall through. */
- case 0:
- for (e = src->succ; e; e = e->succ_next)
- if (e->dest == dst)
- {
- e->flags |= flags;
- return NULL;
- }
- break;
+ /* The edge does not exist. Create one and update the
+ cache. */
+ SET_BIT (edge_cache, dst->index);
+ return unchecked_make_edge (src, dst, flags);
}
- e = unchecked_make_edge (src, dst, flags);
-
- if (use_edge_cache)
- SET_BIT (edge_cache[src->index], dst->index);
+ /* At this point, we know that the requested edge exists. Adjust
+ flags if necessary. */
+ if (flags)
+ {
+ edge e = find_edge (src, dst);
+ e->flags |= flags;
+ }
- return e;
+ return NULL;
}
/* Create an edge connecting SRC and DEST with flags FLAGS. Return newly
edge
make_edge (basic_block src, basic_block dest, int flags)
{
- return cached_make_edge (NULL, src, dest, flags);
+ edge e = find_edge (src, dest);
+
+ /* Make sure we don't add duplicate edges. */
+ if (e)
+ {
+ e->flags |= flags;
+ return NULL;
+ }
+
+ return unchecked_make_edge (src, dest, flags);
}
/* Create an edge connecting SRC to DEST and set probability by knowing
void
remove_edge (edge e)
{
- edge last_pred = NULL;
- edge last_succ = NULL;
- edge tmp;
- basic_block src, dest;
+ execute_on_shrinking_pred (e);
- src = e->src;
- dest = e->dest;
- for (tmp = src->succ; tmp && tmp != e; tmp = tmp->succ_next)
- last_succ = tmp;
-
- gcc_assert (tmp);
- if (last_succ)
- last_succ->succ_next = e->succ_next;
- else
- src->succ = e->succ_next;
-
- for (tmp = dest->pred; tmp && tmp != e; tmp = tmp->pred_next)
- last_pred = tmp;
-
- gcc_assert (tmp);
- if (last_pred)
- last_pred->pred_next = e->pred_next;
- else
- dest->pred = e->pred_next;
+ disconnect_src (e);
+ disconnect_dest (e);
free_edge (e);
}
void
redirect_edge_succ (edge e, basic_block new_succ)
{
- edge *pe;
+ execute_on_shrinking_pred (e);
- /* Disconnect the edge from the old successor block. */
- for (pe = &e->dest->pred; *pe != e; pe = &(*pe)->pred_next)
- continue;
- *pe = (*pe)->pred_next;
+ disconnect_dest (e);
- /* Reconnect the edge to the new successor block. */
- e->pred_next = new_succ->pred;
- new_succ->pred = e;
e->dest = new_succ;
+
+ /* Reconnect the edge to the new successor block. */
+ connect_dest (e);
+
+ execute_on_growing_pred (e);
}
/* Like previous but avoid possible duplicate edge. */
{
edge s;
- /* Check whether the edge is already present. */
- for (s = e->src->succ; s; s = s->succ_next)
- if (s->dest == new_succ && s != e)
- break;
-
- if (s)
+ s = find_edge (e->src, new_succ);
+ if (s && s != e)
{
s->flags |= e->flags;
s->probability += e->probability;
void
redirect_edge_pred (edge e, basic_block new_pred)
{
- edge *pe;
+ disconnect_src (e);
- /* Disconnect the edge from the old predecessor block. */
- for (pe = &e->src->succ; *pe != e; pe = &(*pe)->succ_next)
- continue;
-
- *pe = (*pe)->succ_next;
+ e->src = new_pred;
/* Reconnect the edge to the new predecessor block. */
- e->succ_next = new_pred->succ;
- new_pred->succ = e;
- e->src = new_pred;
+ connect_src (e);
}
/* Clear all basic block flags, with the exception of partitioning. */
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);
}
\f
/* Check the consistency of profile information. We can't do that
edge e;
int sum = 0;
gcov_type lsum;
+ edge_iterator ei;
if (profile_status == PROFILE_ABSENT)
return;
if (bb != EXIT_BLOCK_PTR)
{
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
sum += e->probability;
- if (bb->succ && abs (sum - REG_BR_PROB_BASE) > 100)
+ if (EDGE_COUNT (bb->succs) && abs (sum - REG_BR_PROB_BASE) > 100)
fprintf (file, "Invalid sum of outgoing probabilities %.1f%%\n",
sum * 100.0 / REG_BR_PROB_BASE);
lsum = 0;
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
lsum += e->count;
- if (bb->succ && (lsum - bb->count > 100 || lsum - bb->count < -100))
+ if (EDGE_COUNT (bb->succs)
+ && (lsum - bb->count > 100 || lsum - bb->count < -100))
fprintf (file, "Invalid sum of outgoing counts %i, should be %i\n",
(int) lsum, (int) bb->count);
}
if (bb != ENTRY_BLOCK_PTR)
{
sum = 0;
- for (e = bb->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, bb->preds)
sum += EDGE_FREQUENCY (e);
if (abs (sum - bb->frequency) > 100)
fprintf (file,
"Invalid sum of incoming frequencies %i, should be %i\n",
sum, bb->frequency);
lsum = 0;
- for (e = bb->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, bb->preds)
lsum += e->count;
if (lsum - bb->count > 100 || lsum - bb->count < -100)
fprintf (file, "Invalid sum of incoming counts %i, should be %i\n",
{
int i;
basic_block bb;
- static const char * const reg_class_names[] = REG_CLASS_NAMES;
- if (reg_n_info)
+ /* There are no pseudo registers after reload. Don't dump them. */
+ if (reg_n_info && !reload_completed)
{
- int max_regno = max_reg_num ();
fprintf (file, "%d registers.\n", max_regno);
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
if (REG_N_REFS (i))
FOR_EACH_BB (bb)
{
edge e;
+ edge_iterator ei;
fprintf (file, "\nBasic block %d ", bb->index);
fprintf (file, "prev %d, next %d, ",
fprintf (file, ".\n");
fprintf (file, "Predecessors: ");
- for (e = bb->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, bb->preds)
dump_edge_info (file, e, 0);
fprintf (file, "\nSuccessors: ");
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
dump_edge_info (file, e, 1);
- fprintf (file, "\nRegisters live at start:");
- dump_regset (bb->global_live_at_start, file);
-
- fprintf (file, "\nRegisters live at end:");
- dump_regset (bb->global_live_at_end, file);
-
- putc ('\n', file);
-
if (bb->global_live_at_start)
{
fprintf (file, "\nRegisters live at start:");
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{
edge e;
+ edge_iterator ei;
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
alloc_aux_for_edge (e, size);
}
}
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{
- for (e = bb->succ; e; e = e->succ_next)
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, bb->succs)
e->aux = NULL;
}
}
dump_cfg_bb_info (FILE *file, basic_block bb)
{
unsigned i;
+ edge_iterator ei;
bool first = true;
static const char * const bb_bitnames[] =
{
fprintf (file, "\n");
fprintf (file, "Predecessors: ");
- for (e = bb->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, bb->preds)
dump_edge_info (file, e, 0);
fprintf (file, "\nSuccessors: ");
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
dump_edge_info (file, e, 1);
fprintf (file, "\n\n");
}
{
edge c;
int prob;
+ edge_iterator ei;
bb->count -= count;
if (bb->count < 0)
fprintf (dump_file, "Edge frequencies of bb %i has been reset, "
"frequency of block should end up being 0, it is %i\n",
bb->index, bb->frequency);
- bb->succ->probability = REG_BR_PROB_BASE;
- for (c = bb->succ->succ_next; c; c = c->succ_next)
+ EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE;
+ ei = ei_start (bb->succs);
+ ei_next (&ei);
+ for (; (c = ei_safe_edge (ei)); ei_next (&ei))
c->probability = 0;
}
- else
- for (c = bb->succ; c; c = c->succ_next)
- c->probability = ((c->probability * REG_BR_PROB_BASE) / (double) prob);
+ else if (prob != REG_BR_PROB_BASE)
+ {
+ int scale = 65536 * REG_BR_PROB_BASE / prob;
- if (bb != taken_edge->src)
- abort ();
+ FOR_EACH_EDGE (c, ei, bb->succs)
+ c->probability *= scale / 65536;
+ }
+
+ gcc_assert (bb == taken_edge->src);
taken_edge->count -= count;
if (taken_edge->count < 0)
taken_edge->count = 0;
}
+
+/* Multiply all frequencies of basic blocks in array BBS of length NBBS
+ by NUM/DEN, in int arithmetic. May lose some accuracy. */
+void
+scale_bbs_frequencies_int (basic_block *bbs, int nbbs, int num, int den)
+{
+ int i;
+ edge e;
+ for (i = 0; i < nbbs; i++)
+ {
+ edge_iterator ei;
+ bbs[i]->frequency = (bbs[i]->frequency * num) / den;
+ bbs[i]->count = RDIV (bbs[i]->count * num, den);
+ FOR_EACH_EDGE (e, ei, bbs[i]->succs)
+ e->count = (e->count * num) /den;
+ }
+}
+
+/* Multiply all frequencies of basic blocks in array BBS of length NBBS
+ by NUM/DEN, in gcov_type arithmetic. More accurate than previous
+ function but considerably slower. */
+void
+scale_bbs_frequencies_gcov_type (basic_block *bbs, int nbbs, gcov_type num,
+ gcov_type den)
+{
+ int i;
+ edge e;
+
+ for (i = 0; i < nbbs; i++)
+ {
+ edge_iterator ei;
+ bbs[i]->frequency = (bbs[i]->frequency * num) / den;
+ bbs[i]->count = RDIV (bbs[i]->count * num, den);
+ FOR_EACH_EDGE (e, ei, bbs[i]->succs)
+ e->count = (e->count * num) /den;
+ }
+}