mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-20 05:50:28 +08:00
cfgloopanal.c (mark_irreducible_loops): Rewriten.
* cfgloopanal.c (mark_irreducible_loops): Rewriten. (struct edge, struct vertex, struct graph): New. (dump_graph, new_graph, add_edge, dfs, check_irred, for_each_edge, free_graph): New functions. From-SVN: r77755
This commit is contained in:
parent
5bd61841e4
commit
cfbe3efe45
@ -1,3 +1,10 @@
|
||||
2004-02-13 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
|
||||
|
||||
* cfgloopanal.c (mark_irreducible_loops): Rewriten.
|
||||
(struct edge, struct vertex, struct graph): New.
|
||||
(dump_graph, new_graph, add_edge, dfs, check_irred, for_each_edge,
|
||||
free_graph): New functions.
|
||||
|
||||
2004-02-12 Chris Demetriou <cgd@broadcom.com>
|
||||
|
||||
* config/mips/mips.md (casesi_internal, casesi_internal_di):
|
||||
|
@ -1111,21 +1111,230 @@ simple_loop_p (struct loop *loop, struct loop_desc *desc)
|
||||
return any;
|
||||
}
|
||||
|
||||
/* Structure representing edge of a graph. */
|
||||
|
||||
struct edge
|
||||
{
|
||||
int src, dest; /* Source and destination. */
|
||||
struct edge *pred_next, *succ_next;
|
||||
/* Next edge in predecessor and successor lists. */
|
||||
void *data; /* Data attached to the edge. */
|
||||
};
|
||||
|
||||
/* Structure representing vertex of a graph. */
|
||||
|
||||
struct vertex
|
||||
{
|
||||
struct edge *pred, *succ;
|
||||
/* Lists of predecessors and successors. */
|
||||
int component; /* Number of dfs restarts before reaching the
|
||||
vertex. */
|
||||
int post; /* Postorder number. */
|
||||
};
|
||||
|
||||
/* Structure representing a graph. */
|
||||
|
||||
struct graph
|
||||
{
|
||||
int n_vertices; /* Number of vertices. */
|
||||
struct vertex *vertices;
|
||||
/* The vertices. */
|
||||
};
|
||||
|
||||
/* Dumps graph G into F. */
|
||||
|
||||
extern void dump_graph (FILE *, struct graph *);
|
||||
void dump_graph (FILE *f, struct graph *g)
|
||||
{
|
||||
int i;
|
||||
struct edge *e;
|
||||
|
||||
for (i = 0; i < g->n_vertices; i++)
|
||||
{
|
||||
if (!g->vertices[i].pred
|
||||
&& !g->vertices[i].succ)
|
||||
continue;
|
||||
|
||||
fprintf (f, "%d (%d)\t<-", i, g->vertices[i].component);
|
||||
for (e = g->vertices[i].pred; e; e = e->pred_next)
|
||||
fprintf (f, " %d", e->src);
|
||||
fprintf (f, "\n");
|
||||
|
||||
fprintf (f, "\t->");
|
||||
for (e = g->vertices[i].succ; e; e = e->succ_next)
|
||||
fprintf (f, " %d", e->dest);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Creates a new graph with N_VERTICES vertices. */
|
||||
|
||||
static struct graph *
|
||||
new_graph (int n_vertices)
|
||||
{
|
||||
struct graph *g = xmalloc (sizeof (struct graph));
|
||||
|
||||
g->n_vertices = n_vertices;
|
||||
g->vertices = xcalloc (n_vertices, sizeof (struct vertex));
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
/* Adds an edge from F to T to graph G, with DATA attached. */
|
||||
|
||||
static void
|
||||
add_edge (struct graph *g, int f, int t, void *data)
|
||||
{
|
||||
struct edge *e = xmalloc (sizeof (struct edge));
|
||||
|
||||
e->src = f;
|
||||
e->dest = t;
|
||||
e->data = data;
|
||||
|
||||
e->pred_next = g->vertices[t].pred;
|
||||
g->vertices[t].pred = e;
|
||||
|
||||
e->succ_next = g->vertices[f].succ;
|
||||
g->vertices[f].succ = e;
|
||||
}
|
||||
|
||||
/* Runs dfs search over vertices of G, from NQ vertices in queue QS.
|
||||
The vertices in postorder are stored into QT. If FORWARD is false,
|
||||
backward dfs is run. */
|
||||
|
||||
static void
|
||||
dfs (struct graph *g, int *qs, int nq, int *qt, bool forward)
|
||||
{
|
||||
int i, tick = 0, v, comp = 0, top;
|
||||
struct edge *e;
|
||||
struct edge **stack = xmalloc (sizeof (struct edge *) * g->n_vertices);
|
||||
|
||||
for (i = 0; i < g->n_vertices; i++)
|
||||
{
|
||||
g->vertices[i].component = -1;
|
||||
g->vertices[i].post = -1;
|
||||
}
|
||||
|
||||
#define FST_EDGE(V) (forward ? g->vertices[(V)].succ : g->vertices[(V)].pred)
|
||||
#define NEXT_EDGE(E) (forward ? (E)->succ_next : (E)->pred_next)
|
||||
#define EDGE_SRC(E) (forward ? (E)->src : (E)->dest)
|
||||
#define EDGE_DEST(E) (forward ? (E)->dest : (E)->src)
|
||||
|
||||
for (i = 0; i < nq; i++)
|
||||
{
|
||||
v = qs[i];
|
||||
if (g->vertices[v].post != -1)
|
||||
continue;
|
||||
|
||||
g->vertices[v].component = comp++;
|
||||
e = FST_EDGE (v);
|
||||
top = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (e && g->vertices[EDGE_DEST (e)].component != -1)
|
||||
e = NEXT_EDGE (e);
|
||||
|
||||
if (!e)
|
||||
{
|
||||
if (qt)
|
||||
qt[tick] = v;
|
||||
g->vertices[v].post = tick++;
|
||||
|
||||
if (!top)
|
||||
break;
|
||||
|
||||
e = stack[--top];
|
||||
v = EDGE_SRC (e);
|
||||
e = NEXT_EDGE (e);
|
||||
continue;
|
||||
}
|
||||
|
||||
stack[top++] = e;
|
||||
v = EDGE_DEST (e);
|
||||
e = FST_EDGE (v);
|
||||
g->vertices[v].component = comp - 1;
|
||||
}
|
||||
}
|
||||
|
||||
free (stack);
|
||||
}
|
||||
|
||||
/* Marks the edge E in graph G irreducible if it connects two vertices in the
|
||||
same scc. */
|
||||
|
||||
static void
|
||||
check_irred (struct graph *g, struct edge *e)
|
||||
{
|
||||
edge real = e->data;
|
||||
|
||||
/* All edges should lead from a component with higher number to the
|
||||
one with lower one. */
|
||||
if (g->vertices[e->src].component < g->vertices[e->dest].component)
|
||||
abort ();
|
||||
|
||||
if (g->vertices[e->src].component != g->vertices[e->dest].component)
|
||||
return;
|
||||
|
||||
real->flags |= EDGE_IRREDUCIBLE_LOOP;
|
||||
if (flow_bb_inside_loop_p (real->src->loop_father, real->dest))
|
||||
real->src->flags |= BB_IRREDUCIBLE_LOOP;
|
||||
}
|
||||
|
||||
/* Runs CALLBACK for all edges in G. */
|
||||
|
||||
static void
|
||||
for_each_edge (struct graph *g,
|
||||
void (callback) (struct graph *, struct edge *))
|
||||
{
|
||||
struct edge *e;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g->n_vertices; i++)
|
||||
for (e = g->vertices[i].succ; e; e = e->succ_next)
|
||||
callback (g, e);
|
||||
}
|
||||
|
||||
/* Releases the memory occupied by G. */
|
||||
|
||||
static void
|
||||
free_graph (struct graph *g)
|
||||
{
|
||||
struct edge *e, *n;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g->n_vertices; i++)
|
||||
for (e = g->vertices[i].succ; e; e = n)
|
||||
{
|
||||
n = e->succ_next;
|
||||
free (e);
|
||||
}
|
||||
free (g->vertices);
|
||||
free (g);
|
||||
}
|
||||
|
||||
/* Marks blocks and edges that are part of non-recognized loops; i.e. we
|
||||
throw away all latch edges and mark blocks inside any remaining cycle.
|
||||
Everything is a bit complicated due to fact we do not want to do this
|
||||
for parts of cycles that only "pass" through some loop -- i.e. for
|
||||
each cycle, we want to mark blocks that belong directly to innermost
|
||||
loop containing the whole cycle. */
|
||||
loop containing the whole cycle.
|
||||
|
||||
LOOPS is the loop tree. */
|
||||
|
||||
#define LOOP_REPR(LOOP) ((LOOP)->num + last_basic_block)
|
||||
#define BB_REPR(BB) ((BB)->index + 1)
|
||||
|
||||
void
|
||||
mark_irreducible_loops (struct loops *loops)
|
||||
{
|
||||
int *dfs_in, *closed, *mr, *mri, *n_edges, *stack;
|
||||
unsigned i;
|
||||
edge **edges, e;
|
||||
edge *estack;
|
||||
basic_block act;
|
||||
int stack_top, tick, depth;
|
||||
edge e;
|
||||
int i, src, dest;
|
||||
struct graph *g;
|
||||
int *queue1 = xmalloc ((last_basic_block + loops->num) * sizeof (int));
|
||||
int *queue2 = xmalloc ((last_basic_block + loops->num) * sizeof (int));
|
||||
int nq, depth;
|
||||
struct loop *cloop;
|
||||
|
||||
/* Reset the flags. */
|
||||
@ -1136,176 +1345,74 @@ mark_irreducible_loops (struct loops *loops)
|
||||
e->flags &= ~EDGE_IRREDUCIBLE_LOOP;
|
||||
}
|
||||
|
||||
/* The first last_basic_block + 1 entries are for real blocks (including
|
||||
entry); then we have loops->num - 1 fake blocks for loops to that we
|
||||
assign edges leading from loops (fake loop 0 is not interesting). */
|
||||
dfs_in = xmalloc ((last_basic_block + loops->num) * sizeof (int));
|
||||
closed = xmalloc ((last_basic_block + loops->num) * sizeof (int));
|
||||
mr = xmalloc ((last_basic_block + loops->num) * sizeof (int));
|
||||
mri = xmalloc ((last_basic_block + loops->num) * sizeof (int));
|
||||
n_edges = xmalloc ((last_basic_block + loops->num) * sizeof (int));
|
||||
edges = xmalloc ((last_basic_block + loops->num) * sizeof (edge *));
|
||||
stack = xmalloc ((n_basic_blocks + loops->num) * sizeof (int));
|
||||
estack = xmalloc ((n_basic_blocks + loops->num) * sizeof (edge));
|
||||
|
||||
/* Create the edge lists. */
|
||||
for (i = 0; i < last_basic_block + loops->num; i++)
|
||||
n_edges[i] = 0;
|
||||
g = new_graph (last_basic_block + loops->num);
|
||||
|
||||
FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
|
||||
for (e = act->succ; e; e = e->succ_next)
|
||||
{
|
||||
/* Ignore edges to exit. */
|
||||
if (e->dest == EXIT_BLOCK_PTR)
|
||||
continue;
|
||||
|
||||
/* And latch edges. */
|
||||
if (e->dest->loop_father->header == e->dest
|
||||
&& e->dest->loop_father->latch == act)
|
||||
continue;
|
||||
|
||||
/* Edges inside a single loop should be left where they are. Edges
|
||||
to subloop headers should lead to representative of the subloop,
|
||||
but from the same place. */
|
||||
if (act->loop_father == e->dest->loop_father
|
||||
|| act->loop_father == e->dest->loop_father->outer)
|
||||
{
|
||||
n_edges[act->index + 1]++;
|
||||
continue;
|
||||
}
|
||||
/* Edges exiting loops remain. They should lead from representative
|
||||
but from the same place.
|
||||
|
||||
Edges exiting loops should lead from representative
|
||||
of the son of nearest common ancestor of the loops in that
|
||||
act lays. */
|
||||
depth = find_common_loop (act->loop_father, e->dest->loop_father)->depth + 1;
|
||||
if (depth == act->loop_father->depth)
|
||||
cloop = act->loop_father;
|
||||
else
|
||||
cloop = act->loop_father->pred[depth];
|
||||
n_edges[cloop->num + last_basic_block]++;
|
||||
}
|
||||
|
||||
for (i = 0; i < last_basic_block + loops->num; i++)
|
||||
{
|
||||
edges[i] = xmalloc (n_edges[i] * sizeof (edge));
|
||||
n_edges[i] = 0;
|
||||
}
|
||||
src = BB_REPR (act);
|
||||
dest = BB_REPR (e->dest);
|
||||
|
||||
FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
|
||||
for (e = act->succ; e; e = e->succ_next)
|
||||
{
|
||||
if (e->dest == EXIT_BLOCK_PTR)
|
||||
continue;
|
||||
if (e->dest->loop_father->header == e->dest
|
||||
&& e->dest->loop_father->latch == act)
|
||||
continue;
|
||||
if (act->loop_father == e->dest->loop_father
|
||||
|| act->loop_father == e->dest->loop_father->outer)
|
||||
if (e->dest->loop_father->header == e->dest)
|
||||
dest = LOOP_REPR (e->dest->loop_father);
|
||||
|
||||
if (!flow_bb_inside_loop_p (act->loop_father, e->dest))
|
||||
{
|
||||
edges[act->index + 1][n_edges[act->index + 1]++] = e;
|
||||
continue;
|
||||
depth = find_common_loop (act->loop_father,
|
||||
e->dest->loop_father)->depth + 1;
|
||||
if (depth == act->loop_father->depth)
|
||||
cloop = act->loop_father;
|
||||
else
|
||||
cloop = act->loop_father->pred[depth];
|
||||
|
||||
src = LOOP_REPR (cloop);
|
||||
}
|
||||
depth = find_common_loop (act->loop_father, e->dest->loop_father)->depth + 1;
|
||||
if (depth == act->loop_father->depth)
|
||||
cloop = act->loop_father;
|
||||
else
|
||||
cloop = act->loop_father->pred[depth];
|
||||
i = cloop->num + last_basic_block;
|
||||
edges[i][n_edges[i]++] = e;
|
||||
|
||||
add_edge (g, src, dest, e);
|
||||
}
|
||||
|
||||
/* Compute dfs numbering, starting from loop headers, and mark found
|
||||
loops. */
|
||||
tick = 0;
|
||||
for (i = 0; i < last_basic_block + loops->num; i++)
|
||||
/* Find the strongly connected components. Use the algorithm of Tarjan --
|
||||
first determine the postorder dfs numbering in reversed graph, then
|
||||
run the dfs on the original graph in the order given by decreasing
|
||||
numbers assigned by the previous pass. */
|
||||
nq = 0;
|
||||
FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
|
||||
{
|
||||
dfs_in[i] = -1;
|
||||
closed[i] = 0;
|
||||
mr[i] = last_basic_block + loops->num;
|
||||
mri[i] = -1;
|
||||
queue1[nq++] = BB_REPR (act);
|
||||
}
|
||||
|
||||
stack_top = 0;
|
||||
for (i = 0; i < loops->num; i++)
|
||||
for (i = 1; i < (int) loops->num; i++)
|
||||
if (loops->parray[i])
|
||||
{
|
||||
stack[stack_top] = loops->parray[i]->header->index + 1;
|
||||
estack[stack_top] = NULL;
|
||||
stack_top++;
|
||||
}
|
||||
queue1[nq++] = LOOP_REPR (loops->parray[i]);
|
||||
dfs (g, queue1, nq, queue2, false);
|
||||
for (i = 0; i < nq; i++)
|
||||
queue1[i] = queue2[nq - i - 1];
|
||||
dfs (g, queue1, nq, NULL, true);
|
||||
|
||||
while (stack_top)
|
||||
{
|
||||
int idx, sidx;
|
||||
/* Mark the irreducible loops. */
|
||||
for_each_edge (g, check_irred);
|
||||
|
||||
idx = stack[stack_top - 1];
|
||||
if (dfs_in[idx] < 0)
|
||||
dfs_in[idx] = tick++;
|
||||
free_graph (g);
|
||||
free (queue1);
|
||||
free (queue2);
|
||||
|
||||
while (n_edges[idx])
|
||||
{
|
||||
e = edges[idx][--n_edges[idx]];
|
||||
sidx = e->dest->loop_father->header == e->dest
|
||||
? e->dest->loop_father->num + last_basic_block
|
||||
: e->dest->index + 1;
|
||||
if (closed[sidx])
|
||||
{
|
||||
if (mri[sidx] != -1 && !closed[mri[sidx]])
|
||||
{
|
||||
if (mr[sidx] < mr[idx])
|
||||
{
|
||||
mr[idx] = mr[sidx];
|
||||
mri[idx] = mri[sidx];
|
||||
}
|
||||
|
||||
if (mr[sidx] <= dfs_in[idx])
|
||||
e->flags |= EDGE_IRREDUCIBLE_LOOP;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (dfs_in[sidx] < 0)
|
||||
{
|
||||
stack[stack_top] = sidx;
|
||||
estack[stack_top] = e;
|
||||
stack_top++;
|
||||
goto next;
|
||||
}
|
||||
if (dfs_in[sidx] < mr[idx])
|
||||
{
|
||||
mr[idx] = dfs_in[sidx];
|
||||
mri[idx] = sidx;
|
||||
}
|
||||
e->flags |= EDGE_IRREDUCIBLE_LOOP;
|
||||
}
|
||||
|
||||
/* Return back. */
|
||||
closed[idx] = 1;
|
||||
e = estack[stack_top - 1];
|
||||
stack_top--;
|
||||
if (e)
|
||||
{
|
||||
/* Propagate information back. */
|
||||
sidx = stack[stack_top - 1];
|
||||
if (mr[sidx] > mr[idx])
|
||||
{
|
||||
mr[sidx] = mr[idx];
|
||||
mri[sidx] = mri[idx];
|
||||
}
|
||||
if (mr[idx] <= dfs_in[sidx])
|
||||
e->flags |= EDGE_IRREDUCIBLE_LOOP;
|
||||
}
|
||||
/* Mark the block if relevant. */
|
||||
if (idx && idx <= last_basic_block && mr[idx] <= dfs_in[idx])
|
||||
BASIC_BLOCK (idx - 1)->flags |= BB_IRREDUCIBLE_LOOP;
|
||||
next:;
|
||||
}
|
||||
|
||||
free (stack);
|
||||
free (estack);
|
||||
free (dfs_in);
|
||||
free (closed);
|
||||
free (mr);
|
||||
free (mri);
|
||||
for (i = 0; i < last_basic_block + loops->num; i++)
|
||||
free (edges[i]);
|
||||
free (edges);
|
||||
free (n_edges);
|
||||
loops->state |= LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user