/* Graph representation and manipulation functions. | |

Copyright (C) 2007-2022 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 "bitmap.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; | |

e->data = NULL; | |

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. If | |

SKIP_EDGE_P is not NULL, it points to a callback function. Edge E will be | |

skipped if callback function returns true. */ | |

static inline struct graph_edge * | |

foll_in_subgraph (struct graph_edge *e, bool forward, bitmap subgraph, | |

skip_edge_callback skip_edge_p) | |

{ | |

int d; | |

if (!e) | |

return e; | |

if (!subgraph && (!skip_edge_p || !skip_edge_p (e))) | |

return e; | |

while (e) | |

{ | |

d = dfs_edge_dest (e, forward); | |

/* 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))) | |

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. If SKIP_EDGE_P is not | |

NULL, it points to a callback function. Edge E will be skipped if callback | |

function returns true. */ | |

static inline struct graph_edge * | |

dfs_fst_edge (struct graph *g, int v, bool forward, bitmap subgraph, | |

skip_edge_callback skip_edge_p) | |

{ | |

struct graph_edge *e; | |

e = (forward ? g->vertices[v].succ : g->vertices[v].pred); | |

return foll_in_subgraph (e, forward, subgraph, skip_edge_p); | |

} | |

/* Helper function for graphds_dfs. Returns the next edge after 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. */ | |

static inline struct graph_edge * | |

dfs_next_edge (struct graph_edge *e, bool forward, bitmap subgraph, | |

skip_edge_callback skip_edge_p) | |

{ | |

return foll_in_subgraph (forward ? e->succ_next : e->pred_next, | |

forward, subgraph, skip_edge_p); | |

} | |

/* 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). If SKIP_EDGE_P is not | |

NULL, it points to a callback function. Edge E will be skipped if | |

callback function returns true. */ | |

int | |

graphds_dfs (struct graph *g, int *qs, int nq, vec<int> *qt, | |

bool forward, bitmap subgraph, | |

skip_edge_callback skip_edge_p) | |

{ | |

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

top = 0; | |

while (1) | |

{ | |

while (e) | |

{ | |

if (g->vertices[dfs_edge_dest (e, forward)].component | |

== -1) | |

break; | |

e = dfs_next_edge (e, forward, subgraph, skip_edge_p); | |

} | |

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

continue; | |

} | |

stack[top++] = e; | |

v = dfs_edge_dest (e, forward); | |

e = dfs_fst_edge (g, v, forward, subgraph, skip_edge_p); | |

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. If SKIP_EDGE_P is not NULL, it points to a callback function. | |

Edge E will be skipped if callback function returns true. | |

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, | |

skip_edge_callback skip_edge_p) | |

{ | |

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

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

free (queue); | |

postorder.release (); | |

return comp; | |

} | |

/* Runs CALLBACK for all edges in G. DATA is private data for CALLBACK. */ | |

void | |

for_each_edge (struct graph *g, graphds_edge_callback callback, void *data) | |

{ | |

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

} | |

/* 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; | |

} | |

} |