LCOV - code coverage report
Current view: top level - gcc - graph.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 155 170 91.2 %
Date: 2020-04-04 11:58:09 Functions: 12 14 85.7 %
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-2020 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                 :        495 : open_graph_file (const char *base, const char *mode)
      44                 :            : {
      45                 :        495 :   size_t namelen = strlen (base);
      46                 :        495 :   size_t extlen = strlen (graph_ext) + 1;
      47                 :        495 :   char *buf = XALLOCAVEC (char, namelen + extlen);
      48                 :        495 :   FILE *fp;
      49                 :            : 
      50                 :        495 :   memcpy (buf, base, namelen);
      51                 :        495 :   memcpy (buf + namelen, graph_ext, extlen);
      52                 :            : 
      53                 :        495 :   fp = fopen (buf, mode);
      54                 :        495 :   if (fp == NULL)
      55                 :          0 :     fatal_error (input_location, "cannot open %s: %m", buf);
      56                 :            : 
      57                 :        495 :   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                 :        814 : draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
      71                 :            : {
      72                 :        814 :   const char *shape;
      73                 :        814 :   const char *fillcolor;
      74                 :            : 
      75                 :        814 :   if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
      76                 :            :     {
      77                 :            :       shape = "Mdiamond";
      78                 :            :       fillcolor = "white";
      79                 :            :     }
      80                 :            :   else
      81                 :            :     {
      82                 :        408 :       shape = "record";
      83                 :        327 :       fillcolor =
      84                 :        408 :         BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
      85                 :            :         : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
      86                 :            :         : "lightgrey";
      87                 :            :     }
      88                 :            : 
      89                 :        814 :   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                 :        814 :   if (bb->index == ENTRY_BLOCK)
      95                 :        203 :     pp_string (pp, "ENTRY");
      96                 :        611 :   else if (bb->index == EXIT_BLOCK)
      97                 :        203 :     pp_string (pp, "EXIT");
      98                 :            :   else
      99                 :            :     {
     100                 :        408 :       pp_left_brace (pp);
     101                 :        408 :       pp_write_text_to_stream (pp);
     102                 :        408 :       dump_bb_for_graph (pp, bb);
     103                 :        408 :       pp_right_brace (pp);
     104                 :            :     }
     105                 :            : 
     106                 :        814 :   pp_string (pp, "\"];\n\n");
     107                 :        814 :   pp_flush (pp);
     108                 :        814 : }
     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                 :        814 : draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
     114                 :            : {
     115                 :        814 :   edge e;
     116                 :        814 :   edge_iterator ei;
     117                 :       1511 :   FOR_EACH_EDGE (e, ei, bb->succs)
     118                 :            :     {
     119                 :        697 :       const char *style = "\"solid,bold\"";
     120                 :        697 :       const char *color = "black";
     121                 :        697 :       int weight = 10;
     122                 :            : 
     123                 :        697 :       if (e->flags & EDGE_FAKE)
     124                 :            :         {
     125                 :            :           style = "dotted";
     126                 :            :           color = "green";
     127                 :            :           weight = 0;
     128                 :            :         }
     129                 :        697 :       else if (e->flags & EDGE_DFS_BACK)
     130                 :            :         {
     131                 :            :           style = "\"dotted,bold\"";
     132                 :            :           color = "blue";
     133                 :            :           weight = 10;
     134                 :            :         }
     135                 :        692 :       else if (e->flags & EDGE_FALLTHRU)
     136                 :            :         {
     137                 :        476 :           color = "blue";
     138                 :        476 :           weight = 100;
     139                 :            :         }
     140                 :            : 
     141                 :        697 :       if (e->flags & EDGE_ABNORMAL)
     142                 :          0 :         color = "red";
     143                 :            : 
     144                 :       1394 :       pp_printf (pp,
     145                 :            :                  "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
     146                 :            :                  "[style=%s,color=%s,weight=%d,constraint=%s",
     147                 :        697 :                  funcdef_no, e->src->index,
     148                 :        697 :                  funcdef_no, e->dest->index,
     149                 :            :                  style, color, weight,
     150                 :        697 :                  (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true");
     151                 :        697 :       if (e->probability.initialized_p ())
     152                 :        579 :         pp_printf (pp, ",label=\"[%i%%]\"",
     153                 :        579 :                    e->probability.to_reg_br_prob_base ()
     154                 :            :                    * 100 / REG_BR_PROB_BASE);
     155                 :        697 :       pp_printf (pp, "];\n");
     156                 :            :     }
     157                 :        814 :   pp_flush (pp);
     158                 :        814 : }
     159                 :            : 
     160                 :            : /* Draw all the basic blocks in the CFG in case loops are not available.
     161                 :            :    First compute a topological order of the blocks to get a good ranking of
     162                 :            :    the nodes.  Then, if any nodes are not reachable from ENTRY, add them at
     163                 :            :    the end.  */
     164                 :            : 
     165                 :            : static void
     166                 :         88 : draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
     167                 :            : {
     168                 :         88 :   int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
     169                 :         88 :   int i, n;
     170                 :            : 
     171                 :         88 :   auto_sbitmap visited (last_basic_block_for_fn (cfun));
     172                 :         88 :   bitmap_clear (visited);
     173                 :            : 
     174                 :         88 :   n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true);
     175                 :         88 :   for (i = n_basic_blocks_for_fn (fun) - n;
     176                 :        428 :        i < n_basic_blocks_for_fn (fun); i++)
     177                 :            :     {
     178                 :        340 :       basic_block bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]);
     179                 :        340 :       draw_cfg_node (pp, fun->funcdef_no, bb);
     180                 :        340 :       bitmap_set_bit (visited, bb->index);
     181                 :            :     }
     182                 :         88 :   free (rpo);
     183                 :            : 
     184                 :         88 :   if (n != n_basic_blocks_for_fn (fun))
     185                 :            :     {
     186                 :            :       /* Some blocks are unreachable.  We still want to dump them.  */
     187                 :          0 :       basic_block bb;
     188                 :          0 :       FOR_ALL_BB_FN (bb, fun)
     189                 :          0 :         if (! bitmap_bit_p (visited, bb->index))
     190                 :          0 :           draw_cfg_node (pp, fun->funcdef_no, bb);
     191                 :            :     }
     192                 :         88 : }
     193                 :            : 
     194                 :            : /* Draw all the basic blocks in LOOP.  Print the blocks in breath-first
     195                 :            :    order to get a good ranking of the nodes.  This function is recursive:
     196                 :            :    It first prints inner loops, then the body of LOOP itself.  */
     197                 :            : 
     198                 :            : static void
     199                 :        120 : draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
     200                 :            :                          class loop *loop)
     201                 :            : {
     202                 :        120 :   basic_block *body;
     203                 :        120 :   unsigned int i;
     204                 :        120 :   const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
     205                 :            : 
     206                 :        120 :   if (loop->header != NULL
     207                 :        120 :       && loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
     208                 :         10 :     pp_printf (pp,
     209                 :            :                "\tsubgraph cluster_%d_%d {\n"
     210                 :            :                "\tstyle=\"filled\";\n"
     211                 :            :                "\tcolor=\"darkgreen\";\n"
     212                 :            :                "\tfillcolor=\"%s\";\n"
     213                 :            :                "\tlabel=\"loop %d\";\n"
     214                 :            :                "\tlabeljust=l;\n"
     215                 :            :                "\tpenwidth=2;\n",
     216                 :            :                funcdef_no, loop->num,
     217                 :         10 :                fillcolors[(loop_depth (loop) - 1) % 3],
     218                 :            :                loop->num);
     219                 :            : 
     220                 :        125 :   for (class loop *inner = loop->inner; inner; inner = inner->next)
     221                 :          5 :     draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
     222                 :            : 
     223                 :        120 :   if (loop->header == NULL)
     224                 :          0 :     return;
     225                 :            : 
     226                 :        120 :   if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun))
     227                 :        115 :     body = get_loop_body (loop);
     228                 :            :   else
     229                 :          5 :     body = get_loop_body_in_bfs_order (loop);
     230                 :            : 
     231                 :        615 :   for (i = 0; i < loop->num_nodes; i++)
     232                 :            :     {
     233                 :        495 :       basic_block bb = body[i];
     234                 :        495 :       if (bb->loop_father == loop)
     235                 :        474 :         draw_cfg_node (pp, funcdef_no, bb);
     236                 :            :     }
     237                 :            : 
     238                 :        120 :   free (body);
     239                 :            : 
     240                 :        120 :   if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
     241                 :          5 :     pp_printf (pp, "\t}\n");
     242                 :            : }
     243                 :            : 
     244                 :            : /* Draw all the basic blocks in the CFG in case the loop tree is available.
     245                 :            :    All loop bodys are printed in clusters.  */
     246                 :            : 
     247                 :            : static void
     248                 :        203 : draw_cfg_nodes (pretty_printer *pp, struct function *fun)
     249                 :            : {
     250                 :        203 :   if (loops_for_fn (fun))
     251                 :        115 :     draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0));
     252                 :            :   else
     253                 :         88 :     draw_cfg_nodes_no_loops (pp, fun);
     254                 :        203 : }
     255                 :            : 
     256                 :            : /* Draw all edges in the CFG.  Retreating edges are drawin as not
     257                 :            :    constraining, this makes the layout of the graph better.  */
     258                 :            : 
     259                 :            : static void
     260                 :        203 : draw_cfg_edges (pretty_printer *pp, struct function *fun)
     261                 :            : {
     262                 :        203 :   basic_block bb;
     263                 :            : 
     264                 :            :   /* Save EDGE_DFS_BACK flag to dfs_back.  */
     265                 :        203 :   auto_bitmap dfs_back;
     266                 :        203 :   edge e;
     267                 :        203 :   edge_iterator ei;
     268                 :        203 :   unsigned int idx = 0;
     269                 :        611 :   FOR_EACH_BB_FN (bb, cfun)
     270                 :        902 :     FOR_EACH_EDGE (e, ei, bb->succs)
     271                 :            :       {
     272                 :        494 :         if (e->flags & EDGE_DFS_BACK)
     273                 :          2 :           bitmap_set_bit (dfs_back, idx);
     274                 :        494 :         idx++;
     275                 :            :       }
     276                 :            : 
     277                 :        203 :   mark_dfs_back_edges ();
     278                 :       1017 :   FOR_ALL_BB_FN (bb, cfun)
     279                 :        814 :     draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
     280                 :            : 
     281                 :            :   /* Restore EDGE_DFS_BACK flag from dfs_back.  */
     282                 :        203 :   idx = 0;
     283                 :        611 :   FOR_EACH_BB_FN (bb, cfun)
     284                 :        902 :     FOR_EACH_EDGE (e, ei, bb->succs)
     285                 :            :       {
     286                 :        494 :         if (bitmap_bit_p (dfs_back, idx))
     287                 :          2 :           e->flags |= EDGE_DFS_BACK;
     288                 :            :         else
     289                 :        492 :           e->flags &= ~EDGE_DFS_BACK;
     290                 :        494 :         idx++;
     291                 :            :       }
     292                 :            : 
     293                 :            :   /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout.  */
     294                 :        203 :   pp_printf (pp,
     295                 :            :              "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
     296                 :            :              "[style=\"invis\",constraint=true];\n",
     297                 :            :              fun->funcdef_no, ENTRY_BLOCK,
     298                 :            :              fun->funcdef_no, EXIT_BLOCK);
     299                 :        203 :   pp_flush (pp);
     300                 :        203 : }
     301                 :            : 
     302                 :            : /* Print a graphical representation of the CFG of function FUN.
     303                 :            :    First print all basic blocks.  Draw all edges at the end to get
     304                 :            :    subgraphs right for GraphViz, which requires nodes to be defined
     305                 :            :    before edges to cluster nodes properly.  */
     306                 :            : 
     307                 :            : void DEBUG_FUNCTION
     308                 :        203 : print_graph_cfg (FILE *fp, struct function *fun)
     309                 :            : {
     310                 :        406 :   pretty_printer graph_slim_pp;
     311                 :        203 :   graph_slim_pp.buffer->stream = fp;
     312                 :        203 :   pretty_printer *const pp = &graph_slim_pp;
     313                 :        203 :   const char *funcname = function_name (fun);
     314                 :        203 :   pp_printf (pp, "subgraph \"cluster_%s\" {\n"
     315                 :            :                  "\tstyle=\"dashed\";\n"
     316                 :            :                  "\tcolor=\"black\";\n"
     317                 :            :                  "\tlabel=\"%s ()\";\n",
     318                 :            :                  funcname, funcname);
     319                 :        203 :   draw_cfg_nodes (pp, fun);
     320                 :        203 :   draw_cfg_edges (pp, fun);
     321                 :        203 :   pp_printf (pp, "}\n");
     322                 :        203 :   pp_flush (pp);
     323                 :        203 : }
     324                 :            : 
     325                 :            : /* Overload with additional flag argument.  */
     326                 :            : 
     327                 :            : void DEBUG_FUNCTION
     328                 :          0 : print_graph_cfg (FILE *fp, struct function *fun, dump_flags_t flags)
     329                 :            : {
     330                 :          0 :   dump_flags_t saved_dump_flags = dump_flags;
     331                 :          0 :   dump_flags = flags;
     332                 :          0 :   print_graph_cfg (fp, fun);
     333                 :          0 :   dump_flags = saved_dump_flags;
     334                 :          0 : }
     335                 :            : 
     336                 :            : 
     337                 :            : /* Print a graphical representation of the CFG of function FUN.
     338                 :            :    First print all basic blocks.  Draw all edges at the end to get
     339                 :            :    subgraphs right for GraphViz, which requires nodes to be defined
     340                 :            :    before edges to cluster nodes properly.  */
     341                 :            : 
     342                 :            : void
     343                 :        203 : print_graph_cfg (const char *base, struct function *fun)
     344                 :            : {
     345                 :        203 :   FILE *fp = open_graph_file (base, "a");
     346                 :        203 :   print_graph_cfg (fp, fun);
     347                 :        203 :   fclose (fp);
     348                 :        203 : }
     349                 :            : 
     350                 :            : /* Start the dump of a graph.  */
     351                 :            : static void
     352                 :        146 : start_graph_dump (FILE *fp, const char *base)
     353                 :            : {
     354                 :        292 :   pretty_printer graph_slim_pp;
     355                 :        146 :   graph_slim_pp.buffer->stream = fp;
     356                 :        146 :   pretty_printer *const pp = &graph_slim_pp;
     357                 :        146 :   pp_string (pp, "digraph \"");
     358                 :        146 :   pp_write_text_to_stream (pp);
     359                 :        146 :   pp_string (pp, base);
     360                 :        146 :   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
     361                 :        146 :   pp_string (pp, "\" {\n");
     362                 :        146 :   pp_string (pp, "overlap=false;\n");
     363                 :        146 :   pp_flush (pp);
     364                 :        146 : }
     365                 :            : 
     366                 :            : /* End the dump of a graph.  */
     367                 :            : static void
     368                 :        146 : end_graph_dump (FILE *fp)
     369                 :            : {
     370                 :          0 :   fputs ("}\n", fp);
     371                 :          0 : }
     372                 :            : 
     373                 :            : /* Similar as clean_dump_file, but this time for graph output files.  */
     374                 :            : void
     375                 :        146 : clean_graph_dump_file (const char *base)
     376                 :            : {
     377                 :        146 :   FILE *fp = open_graph_file (base, "w");
     378                 :        146 :   start_graph_dump (fp, base);
     379                 :        146 :   fclose (fp);
     380                 :        146 : }
     381                 :            : 
     382                 :            : 
     383                 :            : /* Do final work on the graph output file.  */
     384                 :            : void
     385                 :        146 : finish_graph_dump_file (const char *base)
     386                 :            : {
     387                 :        146 :   FILE *fp = open_graph_file (base, "a");
     388                 :        146 :   end_graph_dump (fp);
     389                 :        146 :   fclose (fp);
     390                 :        146 : }
     391                 :            : 
     392                 :            : #if __GNUC__ >= 10
     393                 :            : #  pragma GCC diagnostic pop
     394                 :            : #endif

Generated by: LCOV version 1.0

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 --enable-host-shared. GCC test suite is run with the built compiler.