graphds.c 11.5 KB
Newer Older
1
/* Graph representation and manipulation functions.
2
   Copyright (C) 2007-2019 Free Software Foundation, Inc.
3 4 5 6 7

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
8
Software Foundation; either version 3, or (at your option) any later
9 10 11 12 13 14 15 16
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
17 18
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
19 20 21 22 23 24 25 26 27 28 29 30 31

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "bitmap.h"
#include "graphds.h"

/* Dumps graph G into F.  */

void
dump_graph (FILE *f, struct graph *g)
{
  int i;
32
  struct graph_edge *e;
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

  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);

59
  gcc_obstack_init (&g->ob);
60
  g->n_vertices = n_vertices;
61 62
  g->vertices = XOBNEWVEC (&g->ob, struct vertex, n_vertices);
  memset (g->vertices, 0, sizeof (struct vertex) * n_vertices);
63 64 65 66 67 68

  return g;
}

/* Adds an edge from F to T to graph G.  The new edge is returned.  */

69
struct graph_edge *
70 71
add_edge (struct graph *g, int f, int t)
{
72
  struct graph_edge *e = XOBNEW (&g->ob, struct graph_edge);
73 74 75 76 77 78 79 80 81 82 83
  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;

84
  e->data = NULL;
85 86 87 88 89 90 91 92 93 94
  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];
95
  struct graph_edge *e, *next;
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

  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
122
dfs_edge_src (struct graph_edge *e, bool forward)
123 124 125 126 127 128 129 130
{
  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
131
dfs_edge_dest (struct graph_edge *e, bool forward)
132 133 134 135 136
{
  return forward ? e->dest : e->src;
}

/* Helper function for graphds_dfs.  Returns the first edge after E (including
137 138 139
   E), in the graph direction given by FORWARD, that belongs to SUBGRAPH.  If
   SKIP_EDGE_P is not NULL, it points to a callback function.  Edge E will be
   skipped if callback function returns true.  */
140

141
static inline struct graph_edge *
142 143
foll_in_subgraph (struct graph_edge *e, bool forward, bitmap subgraph,
		  skip_edge_callback skip_edge_p)
144 145 146
{
  int d;

147 148 149 150
  if (!e)
    return e;

  if (!subgraph && (!skip_edge_p || !skip_edge_p (e)))
151 152 153 154 155
    return e;

  while (e)
    {
      d = dfs_edge_dest (e, forward);
156 157 158
      /* Return edge if it belongs to subgraph and shouldn't be skipped.  */
      if ((!subgraph || bitmap_bit_p (subgraph, d))
	  && (!skip_edge_p || !skip_edge_p (e)))
159 160 161 162 163 164 165 166 167
	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
168 169 170
   direction given by FORWARD, that belongs to SUBGRAPH.  If SKIP_EDGE_P is not
   NULL, it points to a callback function.  Edge E will be skipped if callback
   function returns true.  */
171

172
static inline struct graph_edge *
173 174
dfs_fst_edge (struct graph *g, int v, bool forward, bitmap subgraph,
	      skip_edge_callback skip_edge_p)
175
{
176
  struct graph_edge *e;
177 178

  e = (forward ? g->vertices[v].succ : g->vertices[v].pred);
179
  return foll_in_subgraph (e, forward, subgraph, skip_edge_p);
180 181 182
}

/* Helper function for graphds_dfs.  Returns the next edge after E, in the
183 184 185
   graph direction given by FORWARD, that belongs to SUBGRAPH.  If SKIP_EDGE_P
   is not NULL, it points to a callback function.  Edge E will be skipped if
   callback function returns true.  */
186

187
static inline struct graph_edge *
188 189
dfs_next_edge (struct graph_edge *e, bool forward, bitmap subgraph,
	       skip_edge_callback skip_edge_p)
190 191
{
  return foll_in_subgraph (forward ? e->succ_next : e->pred_next,
192
			   forward, subgraph, skip_edge_p);
193 194 195 196 197 198
}

/* 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
199 200 201
   of the graph (number of the restarts of DFS).  If SKIP_EDGE_P is not
   NULL, it points to a callback function.  Edge E will be skipped if
   callback function returns true.  */
202 203

int
204
graphds_dfs (struct graph *g, int *qs, int nq, vec<int> *qt,
205 206
	     bool forward, bitmap subgraph,
	     skip_edge_callback skip_edge_p)
207 208
{
  int i, tick = 0, v, comp = 0, top;
209 210
  struct graph_edge *e;
  struct graph_edge **stack = XNEWVEC (struct graph_edge *, g->n_vertices);
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
  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++;
238
      e = dfs_fst_edge (g, v, forward, subgraph, skip_edge_p);
239 240 241 242 243 244 245 246 247
      top = 0;

      while (1)
	{
	  while (e)
	    {
	      if (g->vertices[dfs_edge_dest (e, forward)].component
		  == -1)
		break;
248
	      e = dfs_next_edge (e, forward, subgraph, skip_edge_p);
249 250 251 252 253
	    }

	  if (!e)
	    {
	      if (qt)
254
		qt->safe_push (v);
255 256 257 258 259 260 261
	      g->vertices[v].post = tick++;

	      if (!top)
		break;

	      e = stack[--top];
	      v = dfs_edge_src (e, forward);
262
	      e = dfs_next_edge (e, forward, subgraph, skip_edge_p);
263 264 265 266 267
	      continue;
	    }

	  stack[top++] = e;
	  v = dfs_edge_dest (e, forward);
268
	  e = dfs_fst_edge (g, v, forward, subgraph, skip_edge_p);
269 270 271 272 273 274 275 276 277 278 279 280 281 282
	  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
283 284
   to determine.  If SKIP_EDGE_P is not NULL, it points to a callback function.
   Edge E will be skipped if callback function returns true.
H.J. Lu committed
285

286 287 288 289 290
   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
291 292
graphds_scc (struct graph *g, bitmap subgraph,
	     skip_edge_callback skip_edge_p)
293 294
{
  int *queue = XNEWVEC (int, g->n_vertices);
295
  vec<int> postorder = vNULL;
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
  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;
    }

315
  graphds_dfs (g, queue, nq, &postorder, false, subgraph, skip_edge_p);
316
  gcc_assert (postorder.length () == (unsigned) nq);
317 318

  for (i = 0; i < nq; i++)
319
    queue[i] = postorder[nq - i - 1];
320
  comp = graphds_dfs (g, queue, nq, NULL, true, subgraph, skip_edge_p);
321 322

  free (queue);
323
  postorder.release ();
324 325 326 327

  return comp;
}

328
/* Runs CALLBACK for all edges in G.  DATA is private data for CALLBACK.  */
329 330

void
331
for_each_edge (struct graph *g, graphds_edge_callback callback, void *data)
332
{
333
  struct graph_edge *e;
334 335 336 337
  int i;

  for (i = 0; i < g->n_vertices; i++)
    for (e = g->vertices[i].succ; e; e = e->succ_next)
338
      callback (g, e, data);
339 340 341 342 343 344 345
}

/* Releases the memory occupied by G.  */

void
free_graph (struct graph *g)
{
346
  obstack_free (&g->ob, NULL);
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
  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)
{
408
  vec<int> postorder = vNULL;
409 410 411
  int *marks = XCNEWVEC (int, g->n_vertices);
  int mark = 1, i, v, idom;
  bool changed = true;
412
  struct graph_edge *e;
413 414 415

  /* We use a slight modification of the standard iterative algorithm, as
     described in
H.J. Lu committed
416

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
     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);
439 440
  gcc_assert (postorder.length () == (unsigned) g->n_vertices);
  gcc_assert (postorder[g->n_vertices - 1] == entry);
441 442 443 444 445 446 447

  while (changed)
    {
      changed = false;

      for (i = g->n_vertices - 2; i >= 0; i--)
	{
448
	  v = postorder[i];
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
	  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);
468
  postorder.release ();
469 470 471 472 473 474 475 476

  for (i = 0; i < g->n_vertices; i++)
    if (parent[i] != -1)
      {
	brother[i] = son[parent[i]];
	son[parent[i]] = i;
      }
}