LCOV - code coverage report
Current view: top level - gcc - graphds.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.1 % 189 176
Test Date: 2026-04-20 14:57:17 Functions: 91.7 % 12 11
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Graph representation and manipulation functions.
       2              :    Copyright (C) 2007-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it under
       7              : 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              : version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14              : for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : #include "config.h"
      21              : #include "system.h"
      22              : #include "coretypes.h"
      23              : #include "bitmap.h"
      24              : #include "graphds.h"
      25              : 
      26              : /* Dumps graph G into F.  */
      27              : 
      28              : void
      29            0 : dump_graph (FILE *f, struct graph *g)
      30              : {
      31            0 :   int i;
      32            0 :   struct graph_edge *e;
      33              : 
      34            0 :   fprintf (f, "digraph {\n");
      35            0 :   for (i = 0; i < g->n_vertices; i++)
      36              :     {
      37            0 :       fprintf (f, "\"%d\" [label=\"%d (%d): %p\"];\n",
      38            0 :                i, i, g->vertices[i].component, g->vertices[i].data);
      39            0 :       for (e = g->vertices[i].pred; e; e = e->pred_next)
      40            0 :         fprintf (f, "\"%d\" -> \"%d\" [label=\"%p\"];\n", e->src, e->dest, e->data);
      41            0 :       for (e = g->vertices[i].succ; e; e = e->succ_next)
      42            0 :         fprintf (f, "\"%d\" -> \"%d\";\n", e->src, e->dest);
      43              :     }
      44            0 :   fprintf (f, "}\n");
      45            0 : }
      46              : 
      47              : /* Creates a new graph with N_VERTICES vertices.  */
      48              : 
      49              : struct graph *
      50     63402846 : new_graph (int n_vertices)
      51              : {
      52     63402846 :   struct graph *g = XNEW (struct graph);
      53              : 
      54     63402846 :   gcc_obstack_init (&g->ob);
      55     63402846 :   g->n_vertices = n_vertices;
      56     63402846 :   g->vertices = XOBNEWVEC (&g->ob, struct vertex, n_vertices);
      57     63402846 :   memset (g->vertices, 0, sizeof (struct vertex) * n_vertices);
      58              : 
      59     63402846 :   return g;
      60              : }
      61              : 
      62              : /* Adds an edge from F to T to graph G.  The new edge is returned.  */
      63              : 
      64              : struct graph_edge *
      65    888810661 : add_edge (struct graph *g, int f, int t)
      66              : {
      67    888810661 :   struct graph_edge *e = XOBNEW (&g->ob, struct graph_edge);
      68    888810661 :   struct vertex *vf = &g->vertices[f], *vt = &g->vertices[t];
      69              : 
      70    888810661 :   e->src = f;
      71    888810661 :   e->dest = t;
      72              : 
      73    888810661 :   e->pred_next = vt->pred;
      74    888810661 :   vt->pred = e;
      75              : 
      76    888810661 :   e->succ_next = vf->succ;
      77    888810661 :   vf->succ = e;
      78              : 
      79    888810661 :   e->data = NULL;
      80    888810661 :   return e;
      81              : }
      82              : 
      83              : /* Moves all the edges incident with U to V.  */
      84              : 
      85              : void
      86      1262886 : identify_vertices (struct graph *g, int v, int u)
      87              : {
      88      1262886 :   struct vertex *vv = &g->vertices[v];
      89      1262886 :   struct vertex *uu = &g->vertices[u];
      90      1262886 :   struct graph_edge *e, *next;
      91              : 
      92      3324102 :   for (e = uu->succ; e; e = next)
      93              :     {
      94      2061216 :       next = e->succ_next;
      95              : 
      96      2061216 :       e->src = v;
      97      2061216 :       e->succ_next = vv->succ;
      98      2061216 :       vv->succ = e;
      99              :     }
     100      1262886 :   uu->succ = NULL;
     101              : 
     102      4315826 :   for (e = uu->pred; e; e = next)
     103              :     {
     104      3052940 :       next = e->pred_next;
     105              : 
     106      3052940 :       e->dest = v;
     107      3052940 :       e->pred_next = vv->pred;
     108      3052940 :       vv->pred = e;
     109              :     }
     110      1262886 :   uu->pred = NULL;
     111      1262886 : }
     112              : 
     113              : /* Helper function for graphds_dfs.  Returns the source vertex of E, in the
     114              :    direction given by FORWARD.  */
     115              : 
     116              : static inline int
     117    158994585 : dfs_edge_src (struct graph_edge *e, bool forward)
     118              : {
     119    158994585 :   return forward ? e->src : e->dest;
     120              : }
     121              : 
     122              : /* Helper function for graphds_dfs.  Returns the destination vertex of E, in
     123              :    the direction given by FORWARD.  */
     124              : 
     125              : static inline int
     126   1775521021 : dfs_edge_dest (struct graph_edge *e, bool forward)
     127              : {
     128   1775521021 :   return forward ? e->dest : e->src;
     129              : }
     130              : 
     131              : /* Helper function for graphds_dfs.  Returns the first edge after E (including
     132              :    E), in the graph direction given by FORWARD, that belongs to SUBGRAPH.  If
     133              :    SKIP_EDGE_P is not NULL, it points to a callback function.  Edge E will be
     134              :    skipped if callback function returns true.  */
     135              : 
     136              : static inline struct graph_edge *
     137   3692002274 : foll_in_subgraph (struct graph_edge *e, bool forward, bitmap subgraph,
     138              :                   skip_edge_callback skip_edge_p)
     139              : {
     140   3692002274 :   int d;
     141              : 
     142   3692002274 :   if (!e)
     143              :     return e;
     144              : 
     145   1772447516 :   if (!subgraph && (!skip_edge_p || !skip_edge_p (e)))
     146   1769355383 :     return e;
     147              : 
     148      4382779 :   while (e)
     149              :     {
     150      3728142 :       d = dfs_edge_dest (e, forward);
     151              :       /* Return edge if it belongs to subgraph and shouldn't be skipped.  */
     152      3646331 :       if ((!subgraph || bitmap_bit_p (subgraph, d))
     153      6159688 :           && (!skip_edge_p || !skip_edge_p (e)))
     154      2437496 :         return e;
     155              : 
     156      1290646 :       e = forward ? e->succ_next : e->pred_next;
     157              :     }
     158              : 
     159              :   return e;
     160              : }
     161              : 
     162              : /* Helper function for graphds_dfs.  Select the first edge from V in G, in the
     163              :    direction given by FORWARD, that belongs to SUBGRAPH.  If SKIP_EDGE_P is not
     164              :    NULL, it points to a callback function.  Edge E will be skipped if callback
     165              :    function returns true.  */
     166              : 
     167              : static inline struct graph_edge *
     168   1920209395 : dfs_fst_edge (struct graph *g, int v, bool forward, bitmap subgraph,
     169              :               skip_edge_callback skip_edge_p)
     170              : {
     171   1920209395 :   struct graph_edge *e;
     172              : 
     173   1920209395 :   e = (forward ? g->vertices[v].succ : g->vertices[v].pred);
     174   1920209395 :   return foll_in_subgraph (e, forward, subgraph, skip_edge_p);
     175              : }
     176              : 
     177              : /* Helper function for graphds_dfs.  Returns the next edge after E, in the
     178              :    graph direction given by FORWARD, that belongs to SUBGRAPH.  If SKIP_EDGE_P
     179              :    is not NULL, it points to a callback function.  Edge E will be skipped if
     180              :    callback function returns true.  */
     181              : 
     182              : static inline struct graph_edge *
     183   1771792879 : dfs_next_edge (struct graph_edge *e, bool forward, bitmap subgraph,
     184              :                skip_edge_callback skip_edge_p)
     185              : {
     186   1771792879 :   return foll_in_subgraph (forward ? e->succ_next : e->pred_next,
     187              :                            forward, subgraph, skip_edge_p);
     188              : }
     189              : 
     190              : /* Runs dfs search over vertices of G, from NQ vertices in queue QS.
     191              :    The vertices in postorder are stored into QT.  If FORWARD is false,
     192              :    backward dfs is run.  If SUBGRAPH is not NULL, it specifies the
     193              :    subgraph of G to run DFS on.  Returns the number of the components
     194              :    of the graph (number of the restarts of DFS).  If SKIP_EDGE_P is not
     195              :    NULL, it points to a callback function.  Edge E will be skipped if
     196              :    callback function returns true.  */
     197              : 
     198              : int
     199    126637858 : graphds_dfs (struct graph *g, int *qs, int nq, vec<int> *qt,
     200              :              bool forward, bitmap subgraph,
     201              :              skip_edge_callback skip_edge_p)
     202              : {
     203    126637858 :   int i, tick = 0, v, comp = 0, top;
     204    126637858 :   struct graph_edge *e;
     205    126637858 :   struct graph_edge **stack = XNEWVEC (struct graph_edge *, g->n_vertices);
     206    126637858 :   bitmap_iterator bi;
     207    126637858 :   unsigned av;
     208              : 
     209    126637858 :   if (subgraph)
     210              :     {
     211      3373088 :       EXECUTE_IF_SET_IN_BITMAP (subgraph, 0, av, bi)
     212              :         {
     213      2285298 :           g->vertices[av].component = -1;
     214      2285298 :           g->vertices[av].post = -1;
     215              :         }
     216              :     }
     217              :   else
     218              :     {
     219   2051175455 :       for (i = 0; i < g->n_vertices; i++)
     220              :         {
     221   1925625387 :           g->vertices[i].component = -1;
     222   1925625387 :           g->vertices[i].post = -1;
     223              :         }
     224              :     }
     225              : 
     226   2040348278 :   for (i = 0; i < nq; i++)
     227              :     {
     228   1913710420 :       v = qs[i];
     229   1913710420 :       if (g->vertices[v].post != -1)
     230    152495610 :         continue;
     231              : 
     232   1761214810 :       g->vertices[v].component = comp++;
     233   1761214810 :       e = dfs_fst_edge (g, v, forward, subgraph, skip_edge_p);
     234   1761214810 :       top = 0;
     235              : 
     236              :       while (1)
     237              :         {
     238   3692002274 :           while (e)
     239              :             {
     240   3543585758 :               if (g->vertices[dfs_edge_dest (e, forward)].component
     241              :                   == -1)
     242              :                 break;
     243   3225596588 :               e = dfs_next_edge (e, forward, subgraph, skip_edge_p);
     244              :             }
     245              : 
     246   2238198565 :           if (!e)
     247              :             {
     248   1920209395 :               if (qt)
     249    969425879 :                 qt->safe_push (v);
     250   1920209395 :               g->vertices[v].post = tick++;
     251              : 
     252   1920209395 :               if (!top)
     253              :                 break;
     254              : 
     255    158994585 :               e = stack[--top];
     256    158994585 :               v = dfs_edge_src (e, forward);
     257    158994585 :               e = dfs_next_edge (e, forward, subgraph, skip_edge_p);
     258    158994585 :               continue;
     259              :             }
     260              : 
     261    158994585 :           stack[top++] = e;
     262    158994585 :           v = dfs_edge_dest (e, forward);
     263    158994585 :           e = dfs_fst_edge (g, v, forward, subgraph, skip_edge_p);
     264    158994585 :           g->vertices[v].component = comp - 1;
     265              :         }
     266              :     }
     267              : 
     268    126637858 :   free (stack);
     269              : 
     270    126637858 :   return comp;
     271              : }
     272              : 
     273              : /* Determines the strongly connected components of G, using the algorithm of
     274              :    Kosaraju -- first determine the postorder dfs numbering in reversed graph,
     275              :    then run the dfs on the original graph in the order given by decreasing
     276              :    numbers assigned by the previous pass.  If SUBGRAPH is not NULL, it
     277              :    specifies the subgraph of G whose strongly connected components we want
     278              :    to determine.  If SKIP_EDGE_P is not NULL, it points to a callback function.
     279              :    Edge E will be skipped if callback function returns true.  If SCC_GROUPING
     280              :    is not null, the nodes will be added to it in the following order:
     281              : 
     282              :    - If SCC A is a direct or indirect predecessor of SCC B in the SCC dag,
     283              :      A's nodes come before B's nodes.
     284              : 
     285              :    - All of an SCC's nodes are listed consecutively, although the order
     286              :      of the nodes within an SCC is not really meaningful.
     287              : 
     288              :    After running this function, v->component is the number of the strongly
     289              :    connected component for each vertex of G.  Returns the number of the
     290              :    sccs of G.  */
     291              : 
     292              : int
     293     62593037 : graphds_scc (struct graph *g, bitmap subgraph,
     294              :              skip_edge_callback skip_edge_p, vec<int> *scc_grouping)
     295              : {
     296     62593037 :   int *queue = XNEWVEC (int, g->n_vertices);
     297     62593037 :   vec<int> postorder = vNULL;
     298     62593037 :   int nq, i, comp;
     299     62593037 :   unsigned v;
     300     62593037 :   bitmap_iterator bi;
     301              : 
     302     62593037 :   if (subgraph)
     303              :     {
     304       543895 :       nq = 0;
     305      1686544 :       EXECUTE_IF_SET_IN_BITMAP (subgraph, 0, v, bi)
     306              :         {
     307      1142649 :           queue[nq++] = v;
     308              :         }
     309              :     }
     310              :   else
     311              :     {
     312   1016218153 :       for (i = 0; i < g->n_vertices; i++)
     313    954169011 :         queue[i] = i;
     314              :       nq = g->n_vertices;
     315              :     }
     316              : 
     317     62593037 :   graphds_dfs (g, queue, nq, &postorder, false, subgraph, skip_edge_p);
     318    125186074 :   gcc_assert (postorder.length () == (unsigned) nq);
     319              : 
     320   1017904697 :   for (i = 0; i < nq; i++)
     321    955311660 :     queue[i] = postorder[nq - i - 1];
     322     62593037 :   comp = graphds_dfs (g, queue, nq, scc_grouping, true, subgraph, skip_edge_p);
     323              : 
     324     62593037 :   free (queue);
     325     62593037 :   postorder.release ();
     326              : 
     327     62593037 :   return comp;
     328              : }
     329              : 
     330              : /* Runs CALLBACK for all edges in G.  DATA is private data for CALLBACK.  */
     331              : 
     332              : void
     333        12570 : for_each_edge (struct graph *g, graphds_edge_callback callback, void *data)
     334              : {
     335        12570 :   struct graph_edge *e;
     336        12570 :   int i;
     337              : 
     338        70168 :   for (i = 0; i < g->n_vertices; i++)
     339       471449 :     for (e = g->vertices[i].succ; e; e = e->succ_next)
     340       413851 :       callback (g, e, data);
     341        12570 : }
     342              : 
     343              : /* Releases the memory occupied by G.  */
     344              : 
     345              : void
     346     63402558 : free_graph (struct graph *g)
     347              : {
     348     63402558 :   obstack_free (&g->ob, NULL);
     349     63402558 :   free (g);
     350     63402558 : }
     351              : 
     352              : /* Returns the nearest common ancestor of X and Y in tree whose parent
     353              :    links are given by PARENT.  MARKS is the array used to mark the
     354              :    vertices of the tree, and MARK is the number currently used as a mark.  */
     355              : 
     356              : static int
     357      3760115 : tree_nca (int x, int y, int *parent, int *marks, int mark)
     358              : {
     359      3760115 :   if (x == -1 || x == y)
     360              :     return y;
     361              : 
     362              :   /* We climb with X and Y up the tree, marking the visited nodes.  When
     363              :      we first arrive to a marked node, it is the common ancestor.  */
     364      1228266 :   marks[x] = mark;
     365      1228266 :   marks[y] = mark;
     366              : 
     367      1337258 :   while (1)
     368              :     {
     369      1282762 :       x = parent[x];
     370      1282762 :       if (x == -1)
     371              :         break;
     372       196219 :       if (marks[x] == mark)
     373              :         return x;
     374       138303 :       marks[x] = mark;
     375              : 
     376       138303 :       y = parent[y];
     377       138303 :       if (y == -1)
     378              :         break;
     379       131821 :       if (marks[y] == mark)
     380              :         return y;
     381        54496 :       marks[y] = mark;
     382              :     }
     383              : 
     384              :   /* If we reached the root with one of the vertices, continue
     385              :      with the other one till we reach the marked part of the
     386              :      tree.  */
     387      1093025 :   if (x == -1)
     388              :     {
     389      1109201 :       for (y = parent[y]; marks[y] != mark; y = parent[y])
     390        22658 :         continue;
     391              : 
     392              :       return y;
     393              :     }
     394              :   else
     395              :     {
     396         6915 :       for (x = parent[x]; marks[x] != mark; x = parent[x])
     397          433 :         continue;
     398              : 
     399              :       return x;
     400              :     }
     401              : }
     402              : 
     403              : /* Determines the dominance tree of G (stored in the PARENT, SON and BROTHER
     404              :    arrays), where the entry node is ENTRY.  */
     405              : 
     406              : void
     407       583287 : graphds_domtree (struct graph *g, int entry,
     408              :                  int *parent, int *son, int *brother)
     409              : {
     410       583287 :   vec<int> postorder = vNULL;
     411       583287 :   int *marks = XCNEWVEC (int, g->n_vertices);
     412       583287 :   int mark = 1, i, v, idom;
     413       583287 :   bool changed = true;
     414       583287 :   struct graph_edge *e;
     415              : 
     416              :   /* We use a slight modification of the standard iterative algorithm, as
     417              :      described in
     418              : 
     419              :      K. D. Cooper, T. J. Harvey and K. Kennedy: A Simple, Fast Dominance
     420              :         Algorithm
     421              : 
     422              :      sort vertices in reverse postorder
     423              :      foreach v
     424              :        dom(v) = everything
     425              :      dom(entry) = entry;
     426              : 
     427              :      while (anything changes)
     428              :        foreach v
     429              :          dom(v) = {v} union (intersection of dom(p) over all predecessors of v)
     430              : 
     431              :      The sets dom(v) are represented by the parent links in the current version
     432              :      of the dominance tree.  */
     433              : 
     434      3012747 :   for (i = 0; i < g->n_vertices; i++)
     435              :     {
     436      1846173 :       parent[i] = -1;
     437      1846173 :       son[i] = -1;
     438      1846173 :       brother[i] = -1;
     439              :     }
     440       583287 :   graphds_dfs (g, &entry, 1, &postorder, true, NULL);
     441      1166574 :   gcc_assert (postorder.length () == (unsigned) g->n_vertices);
     442       583287 :   gcc_assert (postorder[g->n_vertices - 1] == entry);
     443              : 
     444      1750029 :   while (changed)
     445              :     {
     446      1166742 :       changed = false;
     447              : 
     448      3693652 :       for (i = g->n_vertices - 2; i >= 0; i--)
     449              :         {
     450      2526910 :           v = postorder[i];
     451      2526910 :           idom = -1;
     452      6310311 :           for (e = g->vertices[v].pred; e; e = e->pred_next)
     453              :             {
     454      3783401 :               if (e->src != entry
     455      1497848 :                   && parent[e->src] == -1)
     456        23286 :                 continue;
     457              : 
     458      3760115 :               idom = tree_nca (idom, e->src, parent, marks, mark++);
     459              :             }
     460              : 
     461      2526910 :           if (idom != parent[v])
     462              :             {
     463      1263154 :               parent[v] = idom;
     464      1263154 :               changed = true;
     465              :             }
     466              :         }
     467              :     }
     468              : 
     469       583287 :   free (marks);
     470       583287 :   postorder.release ();
     471              : 
     472      3012747 :   for (i = 0; i < g->n_vertices; i++)
     473      1846173 :     if (parent[i] != -1)
     474              :       {
     475      1262886 :         brother[i] = son[parent[i]];
     476      1262886 :         son[parent[i]] = i;
     477              :       }
     478       583287 : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.