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: 2024-12-21 13:15:12 Functions: 85.7 % 14 12
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Output routines for graphical representation.
       2                 :             :    Copyright (C) 1998-2024 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                 :         540 : open_graph_file (const char *base, const char *mode)
      44                 :             : {
      45                 :         540 :   size_t namelen = strlen (base);
      46                 :         540 :   size_t extlen = strlen (graph_ext) + 1;
      47                 :         540 :   char *buf = XALLOCAVEC (char, namelen + extlen);
      48                 :         540 :   FILE *fp;
      49                 :             : 
      50                 :         540 :   memcpy (buf, base, namelen);
      51                 :         540 :   memcpy (buf + namelen, graph_ext, extlen);
      52                 :             : 
      53                 :         540 :   fp = fopen (buf, mode);
      54                 :         540 :   if (fp == NULL)
      55                 :           0 :     fatal_error (input_location, "cannot open %s: %m", buf);
      56                 :             : 
      57                 :         540 :   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                 :         879 : draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
      71                 :             : {
      72                 :         879 :   const char *shape;
      73                 :         879 :   const char *fillcolor;
      74                 :             : 
      75                 :         879 :   if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
      76                 :             :     {
      77                 :             :       shape = "Mdiamond";
      78                 :             :       fillcolor = "white";
      79                 :             :     }
      80                 :             :   else
      81                 :             :     {
      82                 :         435 :       shape = "record";
      83                 :         345 :       fillcolor =
      84                 :         435 :         BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
      85                 :             :         : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
      86                 :             :         : "lightgrey";
      87                 :             :     }
      88                 :             : 
      89                 :         879 :   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                 :         879 :   if (bb->index == ENTRY_BLOCK)
      95                 :         222 :     pp_string (pp, "ENTRY");
      96                 :         657 :   else if (bb->index == EXIT_BLOCK)
      97                 :         222 :     pp_string (pp, "EXIT");
      98                 :             :   else
      99                 :             :     {
     100                 :         435 :       pp_left_brace (pp);
     101                 :         435 :       pp_write_text_to_stream (pp);
     102                 :         435 :       dump_bb_for_graph (pp, bb);
     103                 :         435 :       pp_right_brace (pp);
     104                 :             :     }
     105                 :             : 
     106                 :         879 :   pp_string (pp, "\"];\n\n");
     107                 :         879 :   pp_flush (pp);
     108                 :         879 : }
     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                 :         879 : draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
     114                 :             : {
     115                 :         879 :   edge e;
     116                 :         879 :   edge_iterator ei;
     117                 :        1621 :   FOR_EACH_EDGE (e, ei, bb->succs)
     118                 :             :     {
     119                 :         742 :       const char *style = "\"solid,bold\"";
     120                 :         742 :       const char *color = "black";
     121                 :         742 :       int weight = 10;
     122                 :             : 
     123                 :         742 :       if (e->flags & EDGE_FAKE)
     124                 :             :         {
     125                 :             :           style = "dotted";
     126                 :             :           color = "green";
     127                 :             :           weight = 0;
     128                 :             :         }
     129                 :         742 :       else if (e->flags & EDGE_DFS_BACK)
     130                 :             :         {
     131                 :             :           style = "\"dotted,bold\"";
     132                 :             :           color = "blue";
     133                 :             :           weight = 10;
     134                 :             :         }
     135                 :         738 :       else if (e->flags & EDGE_FALLTHRU)
     136                 :             :         weight = 100;
     137                 :         221 :       else if (e->flags & EDGE_TRUE_VALUE)
     138                 :             :         color = "forestgreen";
     139                 :         209 :       else if (e->flags & EDGE_FALSE_VALUE)
     140                 :          13 :         color = "darkorange";
     141                 :             : 
     142                 :         742 :       if (e->flags & EDGE_ABNORMAL)
     143                 :           0 :         color = "red";
     144                 :             : 
     145                 :        1484 :       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                 :         742 :                  funcdef_no, e->src->index,
     149                 :         742 :                  funcdef_no, e->dest->index,
     150                 :             :                  style, color, weight,
     151                 :         742 :                  (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true");
     152                 :         742 :       if (e->probability.initialized_p ())
     153                 :         605 :         pp_printf (pp, ",label=\"[%i%%]\"",
     154                 :         605 :                    e->probability.to_reg_br_prob_base ()
     155                 :             :                    * 100 / REG_BR_PROB_BASE);
     156                 :         742 :       pp_printf (pp, "];\n");
     157                 :             :     }
     158                 :         879 :   pp_flush (pp);
     159                 :         879 : }
     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                 :          99 : draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
     168                 :             : {
     169                 :          99 :   int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
     170                 :          99 :   int i, n;
     171                 :             : 
     172                 :          99 :   auto_sbitmap visited (last_basic_block_for_fn (fun));
     173                 :          99 :   bitmap_clear (visited);
     174                 :             : 
     175                 :          99 :   n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true);
     176                 :         482 :   for (i = n_basic_blocks_for_fn (fun) - n;
     177                 :         482 :        i < n_basic_blocks_for_fn (fun); i++)
     178                 :             :     {
     179                 :         383 :       basic_block bb = BASIC_BLOCK_FOR_FN (fun, rpo[i]);
     180                 :         383 :       draw_cfg_node (pp, fun->funcdef_no, bb);
     181                 :         383 :       bitmap_set_bit (visited, bb->index);
     182                 :             :     }
     183                 :          99 :   free (rpo);
     184                 :             : 
     185                 :          99 :   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                 :          99 : }
     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                 :         127 : draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
     201                 :             :                          class loop *loop)
     202                 :             : {
     203                 :         127 :   basic_block *body;
     204                 :         127 :   unsigned int i;
     205                 :         127 :   const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
     206                 :             : 
     207                 :         127 :   if (loop->header != NULL
     208                 :         127 :       && 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                 :         131 :   for (class loop *inner = loop->inner; inner; inner = inner->next)
     222                 :           4 :     draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
     223                 :             : 
     224                 :         127 :   if (loop->header == NULL)
     225                 :           0 :     return;
     226                 :             : 
     227                 :         127 :   if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun))
     228                 :         123 :     body = get_loop_body (loop);
     229                 :             :   else
     230                 :           4 :     body = get_loop_body_in_bfs_order (loop);
     231                 :             : 
     232                 :         645 :   for (i = 0; i < loop->num_nodes; i++)
     233                 :             :     {
     234                 :         518 :       basic_block bb = body[i];
     235                 :         518 :       if (bb->loop_father == loop)
     236                 :         496 :         draw_cfg_node (pp, funcdef_no, bb);
     237                 :             :     }
     238                 :             : 
     239                 :         127 :   free (body);
     240                 :             : 
     241                 :         127 :   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                 :         222 : draw_cfg_nodes (pretty_printer *pp, struct function *fun)
     250                 :             : {
     251                 :             :   /* ???  The loop and dominance APIs are dependent on fun == cfun.  */
     252                 :         222 :   if (fun == cfun && loops_for_fn (fun))
     253                 :         123 :     draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0));
     254                 :             :   else
     255                 :          99 :     draw_cfg_nodes_no_loops (pp, fun);
     256                 :         222 : }
     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                 :         222 : draw_cfg_edges (pretty_printer *pp, struct function *fun)
     263                 :             : {
     264                 :         222 :   basic_block bb;
     265                 :             : 
     266                 :             :   /* Save EDGE_DFS_BACK flag to dfs_back.  */
     267                 :         222 :   auto_bitmap dfs_back;
     268                 :         222 :   edge e;
     269                 :         222 :   edge_iterator ei;
     270                 :         222 :   unsigned int idx = 0;
     271                 :         657 :   FOR_EACH_BB_FN (bb, fun)
     272                 :         955 :     FOR_EACH_EDGE (e, ei, bb->succs)
     273                 :             :       {
     274                 :         520 :         if (e->flags & EDGE_DFS_BACK)
     275                 :           3 :           bitmap_set_bit (dfs_back, idx);
     276                 :         520 :         idx++;
     277                 :             :       }
     278                 :             : 
     279                 :         222 :   mark_dfs_back_edges (fun);
     280                 :        1101 :   FOR_ALL_BB_FN (bb, fun)
     281                 :         879 :     draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
     282                 :             : 
     283                 :             :   /* Restore EDGE_DFS_BACK flag from dfs_back.  */
     284                 :         222 :   idx = 0;
     285                 :         657 :   FOR_EACH_BB_FN (bb, fun)
     286                 :         955 :     FOR_EACH_EDGE (e, ei, bb->succs)
     287                 :             :       {
     288                 :         520 :         if (bitmap_bit_p (dfs_back, idx))
     289                 :           3 :           e->flags |= EDGE_DFS_BACK;
     290                 :             :         else
     291                 :         517 :           e->flags &= ~EDGE_DFS_BACK;
     292                 :         520 :         idx++;
     293                 :             :       }
     294                 :             : 
     295                 :             :   /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout.  */
     296                 :         222 :   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                 :         222 :   pp_flush (pp);
     302                 :         222 : }
     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                 :         222 : print_graph_cfg (FILE *fp, struct function *fun)
     311                 :             : {
     312                 :         222 :   pretty_printer graph_slim_pp;
     313                 :         222 :   graph_slim_pp.set_output_stream (fp);
     314                 :         222 :   pretty_printer *const pp = &graph_slim_pp;
     315                 :         222 :   const char *funcname = function_name (fun);
     316                 :         222 :   pp_printf (pp, "subgraph \"cluster_%s\" {\n"
     317                 :             :                  "\tstyle=\"dashed\";\n"
     318                 :             :                  "\tcolor=\"black\";\n"
     319                 :             :                  "\tlabel=\"%s ()\";\n",
     320                 :             :                  funcname, funcname);
     321                 :         222 :   draw_cfg_nodes (pp, fun);
     322                 :         222 :   draw_cfg_edges (pp, fun);
     323                 :         222 :   pp_printf (pp, "}\n");
     324                 :         222 :   pp_flush (pp);
     325                 :         222 : }
     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                 :         222 : print_graph_cfg (const char *base, struct function *fun)
     346                 :             : {
     347                 :         222 :   FILE *fp = open_graph_file (base, "a");
     348                 :         222 :   print_graph_cfg (fp, fun);
     349                 :         222 :   fclose (fp);
     350                 :         222 : }
     351                 :             : 
     352                 :             : /* Start the dump of a graph.  */
     353                 :             : static void
     354                 :         159 : start_graph_dump (FILE *fp, const char *base)
     355                 :             : {
     356                 :         159 :   pretty_printer graph_slim_pp;
     357                 :         159 :   graph_slim_pp.set_output_stream (fp);
     358                 :         159 :   pretty_printer *const pp = &graph_slim_pp;
     359                 :         159 :   pp_string (pp, "digraph \"");
     360                 :         159 :   pp_write_text_to_stream (pp);
     361                 :         159 :   pp_string (pp, base);
     362                 :         159 :   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
     363                 :         159 :   pp_string (pp, "\" {\n");
     364                 :         159 :   pp_string (pp, "overlap=false;\n");
     365                 :         159 :   pp_flush (pp);
     366                 :         159 : }
     367                 :             : 
     368                 :             : /* End the dump of a graph.  */
     369                 :             : static void
     370                 :         159 : 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                 :         159 : clean_graph_dump_file (const char *base)
     378                 :             : {
     379                 :         159 :   FILE *fp = open_graph_file (base, "w");
     380                 :         159 :   start_graph_dump (fp, base);
     381                 :         159 :   fclose (fp);
     382                 :         159 : }
     383                 :             : 
     384                 :             : 
     385                 :             : /* Do final work on the graph output file.  */
     386                 :             : void
     387                 :         159 : finish_graph_dump_file (const char *base)
     388                 :             : {
     389                 :         159 :   FILE *fp = open_graph_file (base, "a");
     390                 :         159 :   end_graph_dump (fp);
     391                 :         159 :   fclose (fp);
     392                 :         159 : }
     393                 :             : 
     394                 :             : #if __GNUC__ >= 10
     395                 :             : #  pragma GCC diagnostic pop
     396                 :             : #endif
        

Generated by: LCOV version 2.1-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.