123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- /* Graph representation and manipulation functions.
- Copyright (C) 2007-2015 Free Software Foundation, Inc.
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "obstack.h"
- #include "bitmap.h"
- #include "vec.h"
- #include "graphds.h"
- /* Dumps graph G into F. */
- void
- dump_graph (FILE *f, struct graph *g)
- {
- int i;
- struct graph_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. */
- struct graph *
- new_graph (int n_vertices)
- {
- struct graph *g = XNEW (struct graph);
- gcc_obstack_init (&g->ob);
- g->n_vertices = n_vertices;
- g->vertices = XOBNEWVEC (&g->ob, struct vertex, n_vertices);
- memset (g->vertices, 0, sizeof (struct vertex) * n_vertices);
- return g;
- }
- /* Adds an edge from F to T to graph G. The new edge is returned. */
- struct graph_edge *
- add_edge (struct graph *g, int f, int t)
- {
- struct graph_edge *e = XOBNEW (&g->ob, struct graph_edge);
- struct vertex *vf = &g->vertices[f], *vt = &g->vertices[t];
- e->src = f;
- e->dest = t;
- e->pred_next = vt->pred;
- vt->pred = e;
- e->succ_next = vf->succ;
- vf->succ = e;
- return e;
- }
- /* Moves all the edges incident with U to V. */
- void
- identify_vertices (struct graph *g, int v, int u)
- {
- struct vertex *vv = &g->vertices[v];
- struct vertex *uu = &g->vertices[u];
- struct graph_edge *e, *next;
- for (e = uu->succ; e; e = next)
- {
- next = e->succ_next;
- e->src = v;
- e->succ_next = vv->succ;
- vv->succ = e;
- }
- uu->succ = NULL;
- for (e = uu->pred; e; e = next)
- {
- next = e->pred_next;
- e->dest = v;
- e->pred_next = vv->pred;
- vv->pred = e;
- }
- uu->pred = NULL;
- }
- /* Helper function for graphds_dfs. Returns the source vertex of E, in the
- direction given by FORWARD. */
- static inline int
- dfs_edge_src (struct graph_edge *e, bool forward)
- {
- return forward ? e->src : e->dest;
- }
- /* Helper function for graphds_dfs. Returns the destination vertex of E, in
- the direction given by FORWARD. */
- static inline int
- dfs_edge_dest (struct graph_edge *e, bool forward)
- {
- return forward ? e->dest : e->src;
- }
- /* Helper function for graphds_dfs. Returns the first edge after E (including
- E), in the graph direction given by FORWARD, that belongs to SUBGRAPH. */
- static inline struct graph_edge *
- foll_in_subgraph (struct graph_edge *e, bool forward, bitmap subgraph)
- {
- int d;
- if (!subgraph)
- return e;
- while (e)
- {
- d = dfs_edge_dest (e, forward);
- if (bitmap_bit_p (subgraph, d))
- return e;
- e = forward ? e->succ_next : e->pred_next;
- }
- return e;
- }
- /* Helper function for graphds_dfs. Select the first edge from V in G, in the
- direction given by FORWARD, that belongs to SUBGRAPH. */
- static inline struct graph_edge *
- dfs_fst_edge (struct graph *g, int v, bool forward, bitmap subgraph)
- {
- struct graph_edge *e;
- e = (forward ? g->vertices[v].succ : g->vertices[v].pred);
- return foll_in_subgraph (e, forward, subgraph);
- }
- /* Helper function for graphds_dfs. Returns the next edge after E, in the
- graph direction given by FORWARD, that belongs to SUBGRAPH. */
- static inline struct graph_edge *
- dfs_next_edge (struct graph_edge *e, bool forward, bitmap subgraph)
- {
- return foll_in_subgraph (forward ? e->succ_next : e->pred_next,
- forward, subgraph);
- }
- /* 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. If SUBGRAPH is not NULL, it specifies the
- subgraph of G to run DFS on. Returns the number of the components
- of the graph (number of the restarts of DFS). */
- int
- graphds_dfs (struct graph *g, int *qs, int nq, vec<int> *qt,
- bool forward, bitmap subgraph)
- {
- int i, tick = 0, v, comp = 0, top;
- struct graph_edge *e;
- struct graph_edge **stack = XNEWVEC (struct graph_edge *, g->n_vertices);
- bitmap_iterator bi;
- unsigned av;
- if (subgraph)
- {
- EXECUTE_IF_SET_IN_BITMAP (subgraph, 0, av, bi)
- {
- g->vertices[av].component = -1;
- g->vertices[av].post = -1;
- }
- }
- else
- {
- for (i = 0; i < g->n_vertices; i++)
- {
- g->vertices[i].component = -1;
- g->vertices[i].post = -1;
- }
- }
- for (i = 0; i < nq; i++)
- {
- v = qs[i];
- if (g->vertices[v].post != -1)
- continue;
- g->vertices[v].component = comp++;
- e = dfs_fst_edge (g, v, forward, subgraph);
- top = 0;
- while (1)
- {
- while (e)
- {
- if (g->vertices[dfs_edge_dest (e, forward)].component
- == -1)
- break;
- e = dfs_next_edge (e, forward, subgraph);
- }
- if (!e)
- {
- if (qt)
- qt->safe_push (v);
- g->vertices[v].post = tick++;
- if (!top)
- break;
- e = stack[--top];
- v = dfs_edge_src (e, forward);
- e = dfs_next_edge (e, forward, subgraph);
- continue;
- }
- stack[top++] = e;
- v = dfs_edge_dest (e, forward);
- e = dfs_fst_edge (g, v, forward, subgraph);
- g->vertices[v].component = comp - 1;
- }
- }
- free (stack);
- return comp;
- }
- /* Determines the strongly connected components of G, using 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. If SUBGRAPH is not NULL, it
- specifies the subgraph of G whose strongly connected components we want
- to determine.
- After running this function, v->component is the number of the strongly
- connected component for each vertex of G. Returns the number of the
- sccs of G. */
- int
- graphds_scc (struct graph *g, bitmap subgraph)
- {
- int *queue = XNEWVEC (int, g->n_vertices);
- vec<int> postorder = vNULL;
- int nq, i, comp;
- unsigned v;
- bitmap_iterator bi;
- if (subgraph)
- {
- nq = 0;
- EXECUTE_IF_SET_IN_BITMAP (subgraph, 0, v, bi)
- {
- queue[nq++] = v;
- }
- }
- else
- {
- for (i = 0; i < g->n_vertices; i++)
- queue[i] = i;
- nq = g->n_vertices;
- }
- graphds_dfs (g, queue, nq, &postorder, false, subgraph);
- gcc_assert (postorder.length () == (unsigned) nq);
- for (i = 0; i < nq; i++)
- queue[i] = postorder[nq - i - 1];
- comp = graphds_dfs (g, queue, nq, NULL, true, subgraph);
- free (queue);
- postorder.release ();
- return comp;
- }
- /* Runs CALLBACK for all edges in G. */
- void
- for_each_edge (struct graph *g, graphds_edge_callback callback)
- {
- struct graph_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. */
- void
- free_graph (struct graph *g)
- {
- obstack_free (&g->ob, NULL);
- free (g);
- }
- /* Returns the nearest common ancestor of X and Y in tree whose parent
- links are given by PARENT. MARKS is the array used to mark the
- vertices of the tree, and MARK is the number currently used as a mark. */
- static int
- tree_nca (int x, int y, int *parent, int *marks, int mark)
- {
- if (x == -1 || x == y)
- return y;
- /* We climb with X and Y up the tree, marking the visited nodes. When
- we first arrive to a marked node, it is the common ancestor. */
- marks[x] = mark;
- marks[y] = mark;
- while (1)
- {
- x = parent[x];
- if (x == -1)
- break;
- if (marks[x] == mark)
- return x;
- marks[x] = mark;
- y = parent[y];
- if (y == -1)
- break;
- if (marks[y] == mark)
- return y;
- marks[y] = mark;
- }
- /* If we reached the root with one of the vertices, continue
- with the other one till we reach the marked part of the
- tree. */
- if (x == -1)
- {
- for (y = parent[y]; marks[y] != mark; y = parent[y])
- continue;
- return y;
- }
- else
- {
- for (x = parent[x]; marks[x] != mark; x = parent[x])
- continue;
- return x;
- }
- }
- /* Determines the dominance tree of G (stored in the PARENT, SON and BROTHER
- arrays), where the entry node is ENTRY. */
- void
- graphds_domtree (struct graph *g, int entry,
- int *parent, int *son, int *brother)
- {
- vec<int> postorder = vNULL;
- int *marks = XCNEWVEC (int, g->n_vertices);
- int mark = 1, i, v, idom;
- bool changed = true;
- struct graph_edge *e;
- /* We use a slight modification of the standard iterative algorithm, as
- described in
- K. D. Cooper, T. J. Harvey and K. Kennedy: A Simple, Fast Dominance
- Algorithm
- sort vertices in reverse postorder
- foreach v
- dom(v) = everything
- dom(entry) = entry;
- while (anything changes)
- foreach v
- dom(v) = {v} union (intersection of dom(p) over all predecessors of v)
- The sets dom(v) are represented by the parent links in the current version
- of the dominance tree. */
- for (i = 0; i < g->n_vertices; i++)
- {
- parent[i] = -1;
- son[i] = -1;
- brother[i] = -1;
- }
- graphds_dfs (g, &entry, 1, &postorder, true, NULL);
- gcc_assert (postorder.length () == (unsigned) g->n_vertices);
- gcc_assert (postorder[g->n_vertices - 1] == entry);
- while (changed)
- {
- changed = false;
- for (i = g->n_vertices - 2; i >= 0; i--)
- {
- v = postorder[i];
- idom = -1;
- for (e = g->vertices[v].pred; e; e = e->pred_next)
- {
- if (e->src != entry
- && parent[e->src] == -1)
- continue;
- idom = tree_nca (idom, e->src, parent, marks, mark++);
- }
- if (idom != parent[v])
- {
- parent[v] = idom;
- changed = true;
- }
- }
- }
- free (marks);
- postorder.release ();
- for (i = 0; i < g->n_vertices; i++)
- if (parent[i] != -1)
- {
- brother[i] = son[parent[i]];
- son[parent[i]] = i;
- }
- }
|