#define REG_BLOCK_GLOBAL -2
#define REG_BASIC_BLOCK(N) (VARRAY_REG (reg_n_info, N)->basic_block)
-
-/* List of integers.
- These are used for storing things like predecessors, etc.
-
- This scheme isn't very space efficient, especially on 64 bit machines.
- The interface is designed so that the implementation can be replaced with
- something more efficient if desirable. */
-
-typedef struct int_list {
- struct int_list *next;
- int val;
-} int_list;
-
-typedef int_list *int_list_ptr;
-
-/* Integer list elements are allocated in blocks to reduce the frequency
- of calls to malloc and to reduce the associated space overhead. */
-
-typedef struct int_list_block {
- struct int_list_block *next;
- int nodes_left;
-#define INT_LIST_NODES_IN_BLK 500
- struct int_list nodes[INT_LIST_NODES_IN_BLK];
-} int_list_block;
-
-/* Given a pointer to the list, return pointer to first element. */
-#define INT_LIST_FIRST(il) (il)
-
-/* Given a pointer to a list element, return pointer to next element. */
-#define INT_LIST_NEXT(p) ((p)->next)
-
-/* Return non-zero if P points to the end of the list. */
-#define INT_LIST_END(p) ((p) == NULL)
-
-/* Return element pointed to by P. */
-#define INT_LIST_VAL(p) ((p)->val)
-
-#define INT_LIST_SET_VAL(p, new_val) ((p)->val = (new_val))
-
-extern void free_int_list PROTO ((int_list_block **));
\f
/* Stuff for recording basic block info. */
extern void set_block_for_insn PROTO ((rtx, basic_block));
extern void set_block_num PROTO ((rtx, int));
-extern void free_bb_mem PROTO ((void));
extern void free_basic_block_vars PROTO ((int));
extern basic_block split_edge PROTO ((edge));
int find_edge_index PROTO ((struct edge_list *,
basic_block, basic_block));
-extern void compute_preds_succs PROTO ((int_list_ptr *, int_list_ptr *,
- int *, int *));
extern void compute_flow_dominators PROTO ((sbitmap *, sbitmap *));
extern void compute_immediate_dominators PROTO ((int *, sbitmap *));
void debug_flow_info PROTO((void));
static void dump_edge_info PROTO((FILE *, edge, int));
-static int_list_ptr alloc_int_list_node PROTO ((int_list_block **));
-static int_list_ptr add_int_list_node PROTO ((int_list_block **,
- int_list **, int));
-
-static void add_pred_succ PROTO ((int, int, int_list_ptr *,
- int_list_ptr *, int *, int *));
-
static void count_reg_sets_1 PROTO ((rtx));
static void count_reg_sets PROTO ((rtx));
static void count_reg_references PROTO ((rtx));
}
}
-\f
-/* Integer list support. */
-
-/* Allocate a node from list *HEAD_PTR. */
-
-static int_list_ptr
-alloc_int_list_node (head_ptr)
- int_list_block **head_ptr;
-{
- struct int_list_block *first_blk = *head_ptr;
-
- if (first_blk == NULL || first_blk->nodes_left <= 0)
- {
- first_blk = (struct int_list_block *) xmalloc (sizeof (struct int_list_block));
- first_blk->nodes_left = INT_LIST_NODES_IN_BLK;
- first_blk->next = *head_ptr;
- *head_ptr = first_blk;
- }
-
- first_blk->nodes_left--;
- return &first_blk->nodes[first_blk->nodes_left];
-}
-
-/* Pointer to head of predecessor/successor block list. */
-static int_list_block *pred_int_list_blocks;
-
-/* Add a new node to integer list LIST with value VAL.
- LIST is a pointer to a list object to allow for different implementations.
- If *LIST is initially NULL, the list is empty.
- The caller must not care whether the element is added to the front or
- to the end of the list (to allow for different implementations). */
-
-static int_list_ptr
-add_int_list_node (blk_list, list, val)
- int_list_block **blk_list;
- int_list **list;
- int val;
-{
- int_list_ptr p = alloc_int_list_node (blk_list);
-
- p->val = val;
- p->next = *list;
- *list = p;
- return p;
-}
-
-/* Free the blocks of lists at BLK_LIST. */
-
-void
-free_int_list (blk_list)
- int_list_block **blk_list;
-{
- int_list_block *p, *next;
-
- for (p = *blk_list; p != NULL; p = next)
- {
- next = p->next;
- free (p);
- }
-
- /* Mark list as empty for the next function we compile. */
- *blk_list = NULL;
-}
-\f
-/* Predecessor/successor computation. */
-
-/* Mark PRED_BB a precessor of SUCC_BB,
- and conversely SUCC_BB a successor of PRED_BB. */
-
-static void
-add_pred_succ (pred_bb, succ_bb, s_preds, s_succs, num_preds, num_succs)
- int pred_bb;
- int succ_bb;
- int_list_ptr *s_preds;
- int_list_ptr *s_succs;
- int *num_preds;
- int *num_succs;
-{
- if (succ_bb != EXIT_BLOCK)
- {
- add_int_list_node (&pred_int_list_blocks, &s_preds[succ_bb], pred_bb);
- num_preds[succ_bb]++;
- }
- if (pred_bb != ENTRY_BLOCK)
- {
- add_int_list_node (&pred_int_list_blocks, &s_succs[pred_bb], succ_bb);
- num_succs[pred_bb]++;
- }
-}
-
-/* Convert edge lists into pred/succ lists for backward compatibility. */
-
-void
-compute_preds_succs (s_preds, s_succs, num_preds, num_succs)
- int_list_ptr *s_preds;
- int_list_ptr *s_succs;
- int *num_preds;
- int *num_succs;
-{
- int i, n = n_basic_blocks;
- edge e;
-
- memset (s_preds, 0, n_basic_blocks * sizeof (int_list_ptr));
- memset (s_succs, 0, n_basic_blocks * sizeof (int_list_ptr));
- memset (num_preds, 0, n_basic_blocks * sizeof (int));
- memset (num_succs, 0, n_basic_blocks * sizeof (int));
-
- for (i = 0; i < n; ++i)
- {
- basic_block bb = BASIC_BLOCK (i);
-
- for (e = bb->succ; e ; e = e->succ_next)
- add_pred_succ (i, e->dest->index, s_preds, s_succs,
- num_preds, num_succs);
- }
-
- for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
- add_pred_succ (ENTRY_BLOCK, e->dest->index, s_preds, s_succs,
- num_preds, num_succs);
-}
-
-/* Free basic block data storage. */
-
-void
-free_bb_mem ()
-{
- free_int_list (&pred_int_list_blocks);
-}
-
/* Compute dominator relationships using new flow graph structures. */
void
compute_flow_dominators (dominators, post_dominators)
static int is_cfg_nonregular PROTO ((void));
-static int build_control_flow PROTO ((int_list_ptr *, int_list_ptr *,
- int *, int *));
+static int build_control_flow PROTO ((struct edge_list *));
static void new_edge PROTO ((int, int));
void debug_regions PROTO ((void));
static void find_single_block_region PROTO ((void));
-static void find_rgns PROTO ((int_list_ptr *, int_list_ptr *,
- int *, int *, sbitmap *));
+static void find_rgns PROTO ((struct edge_list *, sbitmap *));
static int too_large PROTO ((int, int *, int *));
extern void debug_live PROTO ((int, int));
prevent cross block scheduling. */
static int
-build_control_flow (s_preds, s_succs, num_preds, num_succs)
- int_list_ptr *s_preds;
- int_list_ptr *s_succs;
- int *num_preds;
- int *num_succs;
+build_control_flow (edge_list)
+ struct edge_list *edge_list;
{
- int i;
- int_list_ptr succ;
- int unreachable;
+ int i, unreachable, num_edges;
- /* Count the number of edges in the cfg. */
- nr_edges = 0;
+ /* This already accounts for entry/exit edges. */
+ num_edges = NUM_EDGES (edge_list);
+
+ /* Unreachable loops with more than one basic block are detected
+ during the DFS traversal in find_rgns.
+
+ Unreachable loops with a single block are detected here. This
+ test is redundant with the one in find_rgns, but it's much
+ cheaper to go ahead and catch the trivial case here. */
unreachable = 0;
for (i = 0; i < n_basic_blocks; i++)
{
- nr_edges += num_succs[i];
-
- /* Unreachable loops with more than one basic block are detected
- during the DFS traversal in find_rgns.
+ basic_block b = BASIC_BLOCK (i);
- Unreachable loops with a single block are detected here. This
- test is redundant with the one in find_rgns, but it's much
- cheaper to go ahead and catch the trivial case here. */
- if (num_preds[i] == 0
- || (num_preds[i] == 1 && INT_LIST_VAL (s_preds[i]) == i))
+ if (b->pred == NULL
+ || (b->pred->dest == b
+ && b->pred->pred_next == NULL))
unreachable = 1;
}
- /* Account for entry/exit edges. */
- nr_edges += 2;
-
+ /* ??? We can kill these soon. */
in_edges = (int *) xcalloc (n_basic_blocks, sizeof (int));
out_edges = (int *) xcalloc (n_basic_blocks, sizeof (int));
- edge_table = (haifa_edge *) xcalloc (nr_edges, sizeof (haifa_edge));
+ edge_table = (haifa_edge *) xcalloc (num_edges, sizeof (haifa_edge));
nr_edges = 0;
- for (i = 0; i < n_basic_blocks; i++)
- for (succ = s_succs[i]; succ; succ = succ->next)
- {
- if (INT_LIST_VAL (succ) != EXIT_BLOCK)
- new_edge (i, INT_LIST_VAL (succ));
- }
+ for (i = 0; i < num_edges; i++)
+ {
+ edge e = INDEX_EDGE (edge_list, i);
+
+ if (e->dest != EXIT_BLOCK_PTR
+ && e->src != ENTRY_BLOCK_PTR)
+ new_edge (e->src->index, e->dest->index);
+ }
/* Increment by 1, since edge 0 is unused. */
nr_edges++;
of edge tables. That would simplify it somewhat. */
static void
-find_rgns (s_preds, s_succs, num_preds, num_succs, dom)
- int_list_ptr *s_preds;
- int_list_ptr *s_succs;
- int *num_preds;
- int *num_succs;
+find_rgns (edge_list, dom)
+ struct edge_list *edge_list;
sbitmap *dom;
{
int *max_hdr, *dfs_nr, *stack, *degree;
/* Note if a block is in the block queue. */
sbitmap in_stack;
+ int num_edges = NUM_EDGES (edge_list);
+
/* Perform a DFS traversal of the cfg. Identify loop headers, inner loops
and a mapping from block to its loop header (if the block is contained
in a loop, else -1).
to hold degree counts. */
degree = dfs_nr;
- /* Compute the in-degree of every block in the graph. */
- for (i = 0; i < n_basic_blocks; i++)
- degree[i] = num_preds[i];
+ for (i = 0; i < num_edges; i++)
+ {
+ edge e = INDEX_EDGE (edge_list, i);
+
+ if (e->src != ENTRY_BLOCK_PTR)
+ degree[e->src->index]++;
+ }
/* Do not perform region scheduling if there are any unreachable
blocks. */
{
if (TEST_BIT (header, i) && TEST_BIT (inner, i))
{
- int_list_ptr ps;
+ edge e;
int j;
/* Now check that the loop is reducible. We do this separate
/* Decrease degree of all I's successors for topological
ordering. */
- for (ps = s_succs[i]; ps; ps = ps->next)
- if (INT_LIST_VAL (ps) != EXIT_BLOCK
- && INT_LIST_VAL (ps) != ENTRY_BLOCK)
- --degree[INT_LIST_VAL(ps)];
+ for (e = BASIC_BLOCK (i)->succ; e; e = e->succ_next)
+ if (e->dest != EXIT_BLOCK_PTR)
+ --degree[e->dest->index];
/* Estimate # insns, and count # blocks in the region. */
num_bbs = 1;
for (j = 0; j < n_basic_blocks; j++)
/* Leaf nodes have only a single successor which must
be EXIT_BLOCK. */
- if (num_succs[j] == 1
- && INT_LIST_VAL (s_succs[j]) == EXIT_BLOCK)
+ if (BASIC_BLOCK (j)->succ
+ && BASIC_BLOCK (j)->succ->dest == EXIT_BLOCK_PTR
+ && BASIC_BLOCK (j)->succ->succ_next == NULL)
{
queue[++tail] = j;
SET_BIT (in_queue, j);
}
else
{
- int_list_ptr ps;
+ edge e;
- for (ps = s_preds[i]; ps; ps = ps->next)
+ for (e = BASIC_BLOCK (i)->pred; e; e = e->pred_next)
{
- node = INT_LIST_VAL (ps);
-
- if (node == ENTRY_BLOCK || node == EXIT_BLOCK)
+ if (e->src == ENTRY_BLOCK_PTR)
continue;
-
+
+ node = e->src->index;
+
if (max_hdr[node] == loop_head && node != i)
{
/* This is a loop latch. */
while (head < tail && !too_large_failure)
{
- int_list_ptr ps;
+ edge e;
child = queue[++head];
- for (ps = s_preds[child]; ps; ps = ps->next)
+ for (e = BASIC_BLOCK (child)->pred; e; e = e->pred_next)
{
- node = INT_LIST_VAL (ps);
+ node = e->src->index;
/* See discussion above about nodes not marked as in
this loop during the initial DFS traversal. */
- if (node == ENTRY_BLOCK || node == EXIT_BLOCK
+ if (e->src == ENTRY_BLOCK_PTR
|| max_hdr[node] != loop_head)
{
tail = -1;
the region. */
while (tail >= 0)
{
- int_list_ptr ps;
-
if (head < 0)
head = tail;
child = queue[head];
if (degree[child] == 0)
{
+ edge e;
+
degree[child] = -1;
rgn_bb_table[idx++] = child;
BLOCK_TO_BB (child) = ++count;
CONTAINING_RGN (child) = nr_regions;
queue[head] = queue[tail--];
- for (ps = s_succs[child]; ps; ps = ps->next)
- if (INT_LIST_VAL (ps) != ENTRY_BLOCK
- && INT_LIST_VAL (ps) != EXIT_BLOCK)
- --degree[INT_LIST_VAL (ps)];
+ for (e = BASIC_BLOCK (child)->succ;
+ e;
+ e = e->succ_next)
+ if (e->dest != EXIT_BLOCK_PTR)
+ --degree[e->dest->index];
}
else
--head;
}
else
{
- int_list_ptr *s_preds, *s_succs;
- int *num_preds, *num_succs;
sbitmap *dom;
+ struct edge_list *edge_list;
- s_preds = (int_list_ptr *) xmalloc (n_basic_blocks
- * sizeof (int_list_ptr));
- s_succs = (int_list_ptr *) xmalloc (n_basic_blocks
- * sizeof (int_list_ptr));
- num_preds = (int *) xmalloc (n_basic_blocks * sizeof (int));
- num_succs = (int *) xmalloc (n_basic_blocks * sizeof (int));
dom = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
/* The scheduler runs after flow; therefore, we can't blindly call
We could (should?) recompute register live information. Doing
so may even be beneficial. */
-
- compute_preds_succs (s_preds, s_succs, num_preds, num_succs);
+ edge_list = create_edge_list ();
/* Compute the dominators and post dominators. We don't
currently use post dominators, but we should for
/* build_control_flow will return nonzero if it detects unreachable
blocks or any other irregularity with the cfg which prevents
cross block scheduling. */
- if (build_control_flow (s_preds, s_succs, num_preds, num_succs) != 0)
+ if (build_control_flow (edge_list) != 0)
find_single_block_region ();
else
- find_rgns (s_preds, s_succs, num_preds, num_succs, dom);
+ find_rgns (edge_list, dom);
if (sched_verbose >= 3)
debug_regions ();
/* For now. This will move as more and more of haifa is converted
to using the cfg code in flow.c. */
- free_bb_mem ();
free (dom);
- free (s_preds);
- free (s_succs);
- free (num_preds);
- free (num_succs);
}
}