LCOV - code coverage report
Current view: top level - gcc - graph.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 91.2 % 171 156
Test Date: 2026-02-28 14:20:25 Functions: 92.9 % 14 13
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Output routines for graphical representation.
       2              :    Copyright (C) 1998-2026 Free Software Foundation, Inc.
       3              :    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
       4              :    Rewritten for DOT output by Steven Bosscher, 2012.
       5              : 
       6              : This file is part of GCC.
       7              : 
       8              : GCC is free software; you can redistribute it and/or modify it under
       9              : the terms of the GNU General Public License as published by the Free
      10              : Software Foundation; either version 3, or (at your option) any later
      11              : version.
      12              : 
      13              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      14              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16              : for more details.
      17              : 
      18              : You should have received a copy of the GNU General Public License
      19              : along with GCC; see the file COPYING3.  If not see
      20              : <http://www.gnu.org/licenses/>.  */
      21              : 
      22              : #include "config.h"
      23              : #include "system.h"
      24              : #include "coretypes.h"
      25              : #include "backend.h"
      26              : #include "cfghooks.h"
      27              : #include "pretty-print.h"
      28              : #include "diagnostic-core.h" /* for fatal_error */
      29              : #include "cfganal.h"
      30              : #include "cfgloop.h"
      31              : #include "graph.h"
      32              : #include "dumpfile.h"
      33              : 
      34              : /* DOT files with the .dot extension are recognized as document templates
      35              :    by a well-known piece of word processing software out of Redmond, WA.
      36              :    Therefore some recommend using the .gv extension instead.  Obstinately
      37              :    ignore that recommendation...  */
      38              : static const char *const graph_ext = ".dot";
      39              : 
      40              : /* Open a file with MODE for dumping our graph to.
      41              :    Return the file pointer.  */
      42              : static FILE *
      43          561 : open_graph_file (const char *base, const char *mode)
      44              : {
      45          561 :   size_t namelen = strlen (base);
      46          561 :   size_t extlen = strlen (graph_ext) + 1;
      47          561 :   char *buf = XALLOCAVEC (char, namelen + extlen);
      48          561 :   FILE *fp;
      49              : 
      50          561 :   memcpy (buf, base, namelen);
      51          561 :   memcpy (buf + namelen, graph_ext, extlen);
      52              : 
      53          561 :   fp = fopen (buf, mode);
      54          561 :   if (fp == NULL)
      55            0 :     fatal_error (input_location, "cannot open %s: %m", buf);
      56              : 
      57          561 :   return fp;
      58              : }
      59              : 
      60              : /* Disable warnings about quoting issues in the pp_xxx calls below
      61              :    that (intentionally) don't follow GCC diagnostic conventions.  */
      62              : #if __GNUC__ >= 10
      63              : #  pragma GCC diagnostic push
      64              : #  pragma GCC diagnostic ignored "-Wformat-diag"
      65              : #endif
      66              : 
      67              : /* Draw a basic block BB belonging to the function with FUNCDEF_NO
      68              :    as its unique number.  */
      69              : static void
      70          913 : draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
      71              : {
      72          913 :   const char *shape;
      73          913 :   const char *fillcolor;
      74              : 
      75          913 :   if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
      76              :     {
      77              :       shape = "Mdiamond";
      78              :       fillcolor = "white";
      79              :     }
      80              :   else
      81              :     {
      82          451 :       shape = "record";
      83          355 :       fillcolor =
      84          451 :         BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
      85              :         : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
      86              :         : "lightgrey";
      87              :     }
      88              : 
      89          913 :   pp_printf (pp,
      90              :              "\tfn_%d_basic_block_%d "
      91              :              "[shape=%s,style=filled,fillcolor=%s,label=\"",
      92              :              funcdef_no, bb->index, shape, fillcolor);
      93              : 
      94          913 :   if (bb->index == ENTRY_BLOCK)
      95          231 :     pp_string (pp, "ENTRY");
      96          682 :   else if (bb->index == EXIT_BLOCK)
      97          231 :     pp_string (pp, "EXIT");
      98              :   else
      99              :     {
     100          451 :       pp_left_brace (pp);
     101          451 :       pp_write_text_to_stream (pp);
     102          451 :       dump_bb_for_graph (pp, bb);
     103          451 :       pp_right_brace (pp);
     104              :     }
     105              : 
     106          913 :   pp_string (pp, "\"];\n\n");
     107          913 :   pp_flush (pp);
     108          913 : }
     109              : 
     110              : /* Draw all successor edges of a basic block BB belonging to the function
     111              :    with FUNCDEF_NO as its unique number.  */
     112              : static void
     113          913 : draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
     114              : {
     115          913 :   edge e;
     116          913 :   edge_iterator ei;
     117         1683 :   FOR_EACH_EDGE (e, ei, bb->succs)
     118              :     {
     119          770 :       const char *style = "\"solid,bold\"";
     120          770 :       const char *color = "black";
     121          770 :       int weight = 10;
     122              : 
     123          770 :       if (e->flags & EDGE_FAKE)
     124              :         {
     125              :           style = "dotted";
     126              :           color = "green";
     127              :           weight = 0;
     128              :         }
     129          770 :       else if (e->flags & EDGE_DFS_BACK)
     130              :         {
     131              :           style = "\"dotted,bold\"";
     132              :           color = "blue";
     133              :           weight = 10;
     134              :         }
     135          766 :       else if (e->flags & EDGE_FALLTHRU)
     136              :         weight = 100;
     137          229 :       else if (e->flags & EDGE_TRUE_VALUE)
     138              :         color = "forestgreen";
     139          217 :       else if (e->flags & EDGE_FALSE_VALUE)
     140           13 :         color = "darkorange";
     141              : 
     142          770 :       if (e->flags & EDGE_ABNORMAL)
     143            0 :         color = "red";
     144              : 
     145         1540 :       pp_printf (pp,
     146              :                  "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
     147              :                  "[style=%s,color=%s,weight=%d,constraint=%s",
     148          770 :                  funcdef_no, e->src->index,
     149          770 :                  funcdef_no, e->dest->index,
     150              :                  style, color, weight,
     151          770 :                  (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true");
     152          770 :       if (e->probability.initialized_p ())
     153          626 :         pp_printf (pp, ",label=\"[%i%%]\"",
     154          626 :                    e->probability.to_reg_br_prob_base ()
     155              :                    * 100 / REG_BR_PROB_BASE);
     156          770 :       pp_printf (pp, "];\n");
     157              :     }
     158          913 :   pp_flush (pp);
     159          913 : }
     160              : 
     161              : /* Draw all the basic blocks in the CFG in case loops are not available.
     162              :    First compute a topological order of the blocks to get a good ranking of
     163              :    the nodes.  Then, if any nodes are not reachable from ENTRY, add them at
     164              :    the end.  */
     165              : 
     166              : static void
     167          105 : draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
     168              : {
     169          105 :   int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
     170          105 :   int i, n;
     171              : 
     172          105 :   auto_sbitmap visited (last_basic_block_for_fn (fun));
     173          105 :   bitmap_clear (visited);
     174              : 
     175          105 :   n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true);
     176          512 :   for (i = n_basic_blocks_for_fn (fun) - n;
     177          512 :        i < n_basic_blocks_for_fn (fun); i++)
     178              :     {
     179          407 :       basic_block bb = BASIC_BLOCK_FOR_FN (fun, rpo[i]);
     180          407 :       draw_cfg_node (pp, fun->funcdef_no, bb);
     181          407 :       bitmap_set_bit (visited, bb->index);
     182              :     }
     183          105 :   free (rpo);
     184              : 
     185          105 :   if (n != n_basic_blocks_for_fn (fun))
     186              :     {
     187              :       /* Some blocks are unreachable.  We still want to dump them.  */
     188            0 :       basic_block bb;
     189            0 :       FOR_ALL_BB_FN (bb, fun)
     190            0 :         if (! bitmap_bit_p (visited, bb->index))
     191            0 :           draw_cfg_node (pp, fun->funcdef_no, bb);
     192              :     }
     193          105 : }
     194              : 
     195              : /* Draw all the basic blocks in LOOP.  Print the blocks in breath-first
     196              :    order to get a good ranking of the nodes.  This function is recursive:
     197              :    It first prints inner loops, then the body of LOOP itself.  */
     198              : 
     199              : static void
     200          130 : draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
     201              :                          class loop *loop)
     202              : {
     203          130 :   basic_block *body;
     204          130 :   unsigned int i;
     205          130 :   const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
     206              : 
     207          130 :   if (loop->header != NULL
     208          130 :       && loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
     209            4 :     pp_printf (pp,
     210              :                "\tsubgraph cluster_%d_%d {\n"
     211              :                "\tstyle=\"filled\";\n"
     212              :                "\tcolor=\"darkgreen\";\n"
     213              :                "\tfillcolor=\"%s\";\n"
     214              :                "\tlabel=\"loop %d\";\n"
     215              :                "\tlabeljust=l;\n"
     216              :                "\tpenwidth=2;\n",
     217              :                funcdef_no, loop->num,
     218            4 :                fillcolors[(loop_depth (loop) - 1) % 3],
     219              :                loop->num);
     220              : 
     221          134 :   for (class loop *inner = loop->inner; inner; inner = inner->next)
     222            4 :     draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
     223              : 
     224          130 :   if (loop->header == NULL)
     225            0 :     return;
     226              : 
     227          130 :   if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun))
     228          126 :     body = get_loop_body (loop);
     229              :   else
     230            4 :     body = get_loop_body_in_bfs_order (loop);
     231              : 
     232          658 :   for (i = 0; i < loop->num_nodes; i++)
     233              :     {
     234          528 :       basic_block bb = body[i];
     235          528 :       if (bb->loop_father == loop)
     236          506 :         draw_cfg_node (pp, funcdef_no, bb);
     237              :     }
     238              : 
     239          130 :   free (body);
     240              : 
     241          130 :   if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
     242            4 :     pp_printf (pp, "\t}\n");
     243              : }
     244              : 
     245              : /* Draw all the basic blocks in the CFG in case the loop tree is available.
     246              :    All loop bodys are printed in clusters.  */
     247              : 
     248              : static void
     249          231 : draw_cfg_nodes (pretty_printer *pp, struct function *fun)
     250              : {
     251              :   /* ???  The loop and dominance APIs are dependent on fun == cfun.  */
     252          231 :   if (fun == cfun && loops_for_fn (fun))
     253          126 :     draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0));
     254              :   else
     255          105 :     draw_cfg_nodes_no_loops (pp, fun);
     256          231 : }
     257              : 
     258              : /* Draw all edges in the CFG.  Retreating edges are drawin as not
     259              :    constraining, this makes the layout of the graph better.  */
     260              : 
     261              : static void
     262          231 : draw_cfg_edges (pretty_printer *pp, struct function *fun)
     263              : {
     264          231 :   basic_block bb;
     265              : 
     266              :   /* Save EDGE_DFS_BACK flag to dfs_back.  */
     267          231 :   auto_bitmap dfs_back;
     268          231 :   edge e;
     269          231 :   edge_iterator ei;
     270          231 :   unsigned int idx = 0;
     271          682 :   FOR_EACH_BB_FN (bb, fun)
     272          990 :     FOR_EACH_EDGE (e, ei, bb->succs)
     273              :       {
     274          539 :         if (e->flags & EDGE_DFS_BACK)
     275            3 :           bitmap_set_bit (dfs_back, idx);
     276          539 :         idx++;
     277              :       }
     278              : 
     279          231 :   mark_dfs_back_edges (fun);
     280         1144 :   FOR_ALL_BB_FN (bb, fun)
     281          913 :     draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
     282              : 
     283              :   /* Restore EDGE_DFS_BACK flag from dfs_back.  */
     284          231 :   idx = 0;
     285          682 :   FOR_EACH_BB_FN (bb, fun)
     286          990 :     FOR_EACH_EDGE (e, ei, bb->succs)
     287              :       {
     288          539 :         if (bitmap_bit_p (dfs_back, idx))
     289            3 :           e->flags |= EDGE_DFS_BACK;
     290              :         else
     291          536 :           e->flags &= ~EDGE_DFS_BACK;
     292          539 :         idx++;
     293              :       }
     294              : 
     295              :   /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout.  */
     296          231 :   pp_printf (pp,
     297              :              "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
     298              :              "[style=\"invis\",constraint=true];\n",
     299              :              fun->funcdef_no, ENTRY_BLOCK,
     300              :              fun->funcdef_no, EXIT_BLOCK);
     301          231 :   pp_flush (pp);
     302          231 : }
     303              : 
     304              : /* Print a graphical representation of the CFG of function FUN.
     305              :    First print all basic blocks.  Draw all edges at the end to get
     306              :    subgraphs right for GraphViz, which requires nodes to be defined
     307              :    before edges to cluster nodes properly.  */
     308              : 
     309              : void DEBUG_FUNCTION
     310          231 : print_graph_cfg (FILE *fp, struct function *fun)
     311              : {
     312          231 :   pretty_printer graph_slim_pp;
     313          231 :   graph_slim_pp.set_output_stream (fp);
     314          231 :   pretty_printer *const pp = &graph_slim_pp;
     315          231 :   const char *funcname = function_name (fun);
     316          231 :   pp_printf (pp, "subgraph \"cluster_%s\" {\n"
     317              :                  "\tstyle=\"dashed\";\n"
     318              :                  "\tcolor=\"black\";\n"
     319              :                  "\tlabel=\"%s ()\";\n",
     320              :                  funcname, funcname);
     321          231 :   draw_cfg_nodes (pp, fun);
     322          231 :   draw_cfg_edges (pp, fun);
     323          231 :   pp_printf (pp, "}\n");
     324          231 :   pp_flush (pp);
     325          231 : }
     326              : 
     327              : /* Overload with additional flag argument.  */
     328              : 
     329              : void DEBUG_FUNCTION
     330            0 : print_graph_cfg (FILE *fp, struct function *fun, dump_flags_t flags)
     331              : {
     332            0 :   dump_flags_t saved_dump_flags = dump_flags;
     333            0 :   dump_flags = flags;
     334            0 :   print_graph_cfg (fp, fun);
     335            0 :   dump_flags = saved_dump_flags;
     336            0 : }
     337              : 
     338              : 
     339              : /* Print a graphical representation of the CFG of function FUN.
     340              :    First print all basic blocks.  Draw all edges at the end to get
     341              :    subgraphs right for GraphViz, which requires nodes to be defined
     342              :    before edges to cluster nodes properly.  */
     343              : 
     344              : void
     345          231 : print_graph_cfg (const char *base, struct function *fun)
     346              : {
     347          231 :   FILE *fp = open_graph_file (base, "a");
     348          231 :   print_graph_cfg (fp, fun);
     349          231 :   fclose (fp);
     350          231 : }
     351              : 
     352              : /* Start the dump of a graph.  */
     353              : static void
     354          165 : start_graph_dump (FILE *fp, const char *base)
     355              : {
     356          165 :   pretty_printer graph_slim_pp;
     357          165 :   graph_slim_pp.set_output_stream (fp);
     358          165 :   pretty_printer *const pp = &graph_slim_pp;
     359          165 :   pp_string (pp, "digraph \"");
     360          165 :   pp_write_text_to_stream (pp);
     361          165 :   pp_string (pp, base);
     362          165 :   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
     363          165 :   pp_string (pp, "\" {\n");
     364          165 :   pp_string (pp, "overlap=false;\n");
     365          165 :   pp_flush (pp);
     366          165 : }
     367              : 
     368              : /* End the dump of a graph.  */
     369              : static void
     370          165 : end_graph_dump (FILE *fp)
     371              : {
     372            0 :   fputs ("}\n", fp);
     373            0 : }
     374              : 
     375              : /* Similar as clean_dump_file, but this time for graph output files.  */
     376              : void
     377          165 : clean_graph_dump_file (const char *base)
     378              : {
     379          165 :   FILE *fp = open_graph_file (base, "w");
     380          165 :   start_graph_dump (fp, base);
     381          165 :   fclose (fp);
     382          165 : }
     383              : 
     384              : 
     385              : /* Do final work on the graph output file.  */
     386              : void
     387          165 : finish_graph_dump_file (const char *base)
     388              : {
     389          165 :   FILE *fp = open_graph_file (base, "a");
     390          165 :   end_graph_dump (fp);
     391          165 :   fclose (fp);
     392          165 : }
     393              : 
     394              : #if __GNUC__ >= 10
     395              : #  pragma GCC diagnostic pop
     396              : #endif
        

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.