Commit cfbe3efe by Zdenek Dvorak Committed by Zdenek Dvorak

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
parent 5bd61841
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> 2004-02-12 Chris Demetriou <cgd@broadcom.com>
* config/mips/mips.md (casesi_internal, casesi_internal_di): * config/mips/mips.md (casesi_internal, casesi_internal_di):
......
...@@ -1111,21 +1111,230 @@ simple_loop_p (struct loop *loop, struct loop_desc *desc) ...@@ -1111,21 +1111,230 @@ simple_loop_p (struct loop *loop, struct loop_desc *desc)
return any; 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 /* 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. 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 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 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 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 void
mark_irreducible_loops (struct loops *loops) 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; 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; struct loop *cloop;
/* Reset the flags. */ /* Reset the flags. */
...@@ -1136,176 +1345,74 @@ mark_irreducible_loops (struct loops *loops) ...@@ -1136,176 +1345,74 @@ mark_irreducible_loops (struct loops *loops)
e->flags &= ~EDGE_IRREDUCIBLE_LOOP; 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. */ /* Create the edge lists. */
for (i = 0; i < last_basic_block + loops->num; i++) g = new_graph (last_basic_block + loops->num);
n_edges[i] = 0;
FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb) FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
for (e = act->succ; e; e = e->succ_next) for (e = act->succ; e; e = e->succ_next)
{ {
/* Ignore edges to exit. */ /* Ignore edges to exit. */
if (e->dest == EXIT_BLOCK_PTR) if (e->dest == EXIT_BLOCK_PTR)
continue; continue;
/* And latch edges. */ /* And latch edges. */
if (e->dest->loop_father->header == e->dest if (e->dest->loop_father->header == e->dest
&& e->dest->loop_father->latch == act) && e->dest->loop_father->latch == act)
continue; continue;
/* Edges inside a single loop should be left where they are. Edges /* Edges inside a single loop should be left where they are. Edges
to subloop headers should lead to representative of the subloop, to subloop headers should lead to representative of the subloop,
but from the same place. */ but from the same place.
if (act->loop_father == e->dest->loop_father
|| act->loop_father == e->dest->loop_father->outer) Edges exiting loops should lead from representative
{
n_edges[act->index + 1]++;
continue;
}
/* Edges exiting loops remain. They should lead from representative
of the son of nearest common ancestor of the loops in that of the son of nearest common ancestor of the loops in that
act lays. */ 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++) src = BB_REPR (act);
{ dest = BB_REPR (e->dest);
edges[i] = xmalloc (n_edges[i] * sizeof (edge));
n_edges[i] = 0;
}
FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb) if (e->dest->loop_father->header == e->dest)
for (e = act->succ; e; e = e->succ_next) dest = LOOP_REPR (e->dest->loop_father);
{
if (e->dest == EXIT_BLOCK_PTR) if (!flow_bb_inside_loop_p (act->loop_father, e->dest))
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)
{ {
edges[act->index + 1][n_edges[act->index + 1]++] = e; depth = find_common_loop (act->loop_father,
continue; 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) add_edge (g, src, dest, e);
cloop = act->loop_father;
else
cloop = act->loop_father->pred[depth];
i = cloop->num + last_basic_block;
edges[i][n_edges[i]++] = e;
} }
/* Compute dfs numbering, starting from loop headers, and mark found /* Find the strongly connected components. Use the algorithm of Tarjan --
loops. */ first determine the postorder dfs numbering in reversed graph, then
tick = 0; run the dfs on the original graph in the order given by decreasing
for (i = 0; i < last_basic_block + loops->num; i++) numbers assigned by the previous pass. */
nq = 0;
FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{ {
dfs_in[i] = -1; queue1[nq++] = BB_REPR (act);
closed[i] = 0;
mr[i] = last_basic_block + loops->num;
mri[i] = -1;
} }
for (i = 1; i < (int) loops->num; i++)
stack_top = 0;
for (i = 0; i < loops->num; i++)
if (loops->parray[i]) if (loops->parray[i])
{ queue1[nq++] = LOOP_REPR (loops->parray[i]);
stack[stack_top] = loops->parray[i]->header->index + 1; dfs (g, queue1, nq, queue2, false);
estack[stack_top] = NULL; for (i = 0; i < nq; i++)
stack_top++; queue1[i] = queue2[nq - i - 1];
} dfs (g, queue1, nq, NULL, true);
while (stack_top) /* Mark the irreducible loops. */
{ for_each_edge (g, check_irred);
int idx, sidx;
idx = stack[stack_top - 1]; free_graph (g);
if (dfs_in[idx] < 0) free (queue1);
dfs_in[idx] = tick++; 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; loops->state |= LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment