LCOV - code coverage report
Current view: top level - gcc/diagnostics - digraphs-to-dot-from-cfg.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 82.3 % 147 121
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 8 8
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Presentation tweaks for generating .dot from digraphs for GCC CFGs.
       2              :    Copyright (C) 2025 Free Software Foundation, Inc.
       3              :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it
       8              : under the terms of the GNU General Public License as published by
       9              : the Free Software Foundation; either version 3, or (at your option)
      10              : any later version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but
      13              : WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              : General Public License for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : #define INCLUDE_ALGORITHM
      22              : #define INCLUDE_MAP
      23              : #define INCLUDE_SET
      24              : #define INCLUDE_STRING
      25              : #define INCLUDE_VECTOR
      26              : #include "config.h"
      27              : #include "system.h"
      28              : #include "coretypes.h"
      29              : 
      30              : #include "graphviz.h"
      31              : #include "xml.h"
      32              : #include "xml-printer.h"
      33              : #include "diagnostics/digraphs.h"
      34              : #include "diagnostics/digraphs-to-dot.h"
      35              : #include "diagnostics/sarif-sink.h"
      36              : #include "custom-sarif-properties/cfg.h"
      37              : 
      38              : #include "selftest.h"
      39              : 
      40              : namespace diagnostics {
      41              : namespace digraphs {
      42              : namespace to_dot {
      43              : 
      44              : namespace {
      45              :   namespace node_properties = custom_sarif_properties::cfg::node;
      46              :   namespace edge_properties = custom_sarif_properties::cfg::edge;
      47              : }
      48              : 
      49            0 : class converter_from_cfg : public converter
      50              : {
      51              : public:
      52              :   std::unique_ptr<dot::graph>
      53           45 :   make_dot_graph_from_diagnostic_graph (const digraph &dg) final override
      54              :   {
      55           45 :     auto dot_graph
      56           45 :       = converter::make_dot_graph_from_diagnostic_graph (dg);
      57              : 
      58              :     /* Add an invisible edge from ENTRY to EXIT, to improve the
      59              :        graph layout.  */
      60           45 :     if (const digraphs::node *entry_node = get_entry_node (dg))
      61           45 :       if (const digraphs::node *exit_node = get_exit_node (dg))
      62              :         {
      63           45 :           auto extra_edge_stmt
      64              :             = std::make_unique<dot::edge_stmt>
      65           90 :             (get_node_id_for_node (*entry_node, "s"),
      66          135 :              get_node_id_for_node (*exit_node, "n"));
      67           45 :           extra_edge_stmt->set_attr (dot::id ("style"), dot::id ("invis"));
      68           45 :           extra_edge_stmt->set_attr (dot::id ("constraint"), dot::id ("true"));
      69           45 :           dot_graph->m_stmt_list.add_stmt (std::move (extra_edge_stmt));
      70           45 :         }
      71              : 
      72           45 :     return dot_graph;
      73              :   }
      74              : 
      75              :   void
      76           45 :   add_any_subgraph_attrs (const digraph_node &input_node,
      77              :                           dot::subgraph &output_subgraph) final override
      78              :   {
      79           45 :     if (const char *kind = input_node.get_property (node_properties::kind))
      80              :       {
      81           45 :         if (strcmp (kind, "function") == 0)
      82              :           {
      83              :           }
      84            0 :         else if (strcmp (kind, "loop") == 0)
      85              :           {
      86            0 :             namespace loop_property_names
      87              :               = custom_sarif_properties::cfg::loop;
      88            0 :             long num;
      89            0 :             if (input_node.maybe_get_property (loop_property_names::num, num))
      90              :               {
      91            0 :                 pretty_printer pp;
      92            0 :                 pp_printf (&pp, "loop %li", num);
      93            0 :                 output_subgraph.add_attr (dot::id ("label"),
      94            0 :                                           dot::id (pp_formatted_text (&pp)));
      95            0 :               }
      96            0 :             long depth;
      97            0 :             if (input_node.maybe_get_property (loop_property_names::depth,
      98              :                                                depth))
      99              :               {
     100            0 :                 const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
     101            0 :                 output_subgraph.add_attr
     102            0 :                   (dot::id ("fillcolor"),
     103            0 :                    dot::id (fillcolors[(depth - 1) % 3]));
     104              :               }
     105            0 :             output_subgraph.add_attr (dot::id ("style"), dot::id ("filled"));
     106            0 :             output_subgraph.add_attr (dot::id ("color"), dot::id ("darkgreen"));
     107            0 :             output_subgraph.add_attr (dot::id ("labeljust"), dot::id ("l"));
     108            0 :             output_subgraph.add_attr (dot::id ("penwidth"), dot::id ("2"));
     109              :           }
     110              :       }
     111           45 :   }
     112              : 
     113              :   void
     114          270 :   add_any_node_attrs (const digraph_node &input_node,
     115              :                       dot::node_stmt &output_node) final override
     116              :   {
     117          270 :     if (const char *node_kind = input_node.get_property (node_properties::kind))
     118          270 :       if (strcmp (node_kind, "basic_block") == 0)
     119              :         {
     120          270 :           namespace bb_property_names
     121              :             = custom_sarif_properties::cfg::basic_block;
     122          270 :           const char *shape = nullptr;
     123          270 :           const char *fillcolor = "lightgrey";
     124          270 :           const char *label = nullptr;
     125          540 :           if (const char *bb_kind
     126          270 :                 = input_node.get_property (bb_property_names::kind))
     127              :             {
     128           90 :               if (strcmp (bb_kind, "entry") == 0)
     129              :                 {
     130              :                   shape = "Mdiamond";
     131              :                   fillcolor = "white";
     132              :                   label = "ENTRY";
     133              :                 }
     134           45 :               else if (strcmp (bb_kind, "exit") == 0)
     135              :                 {
     136              :                   shape = "Mdiamond";
     137              :                   fillcolor = "white";
     138              :                   label = "EXIT";
     139              :                 }
     140            0 :               else if (strcmp (bb_kind, "hot") == 0)
     141              :                 fillcolor = "lightpink";
     142            0 :               else if (strcmp (bb_kind, "cold") == 0)
     143              :                 fillcolor = "lightblue";
     144              :             }
     145              : 
     146              :           if (shape)
     147           90 :             output_node.set_attr (dot::id ("shape"), dot::id (shape));
     148              :           else
     149              :             {
     150          180 :               output_node.set_attr (dot::id ("shape"), dot::id ("none"));
     151          180 :               output_node.set_attr (dot::id ("margin"), dot::id ("0"));
     152              :             }
     153          270 :           output_node.set_attr (dot::id ("fillcolor"), dot::id (fillcolor));
     154          270 :           if (label)
     155           90 :             output_node.set_label (dot::id (label));
     156              :           else
     157              :             {
     158              :               // Create node with table
     159          180 :               xml::element table ("table", false);
     160          180 :               xml::printer xp (table);
     161          180 :               xp.set_attr ("border", "0");
     162          180 :               xp.set_attr ("cellborder", "1");
     163          180 :               xp.set_attr ("cellspacing", "0");
     164              : 
     165          180 :               long bb_index;
     166          180 :               if (input_node.maybe_get_property (bb_property_names::index,
     167              :                                                  bb_index))
     168              :                 {
     169           80 :                   xp.push_tag ("tr", true);
     170           80 :                   xp.push_tag ("td", true);
     171           80 :                   xp.set_attr ("align", "left");
     172           80 :                   pretty_printer pp;
     173           80 :                   pp_printf (&pp, "<bb %li>:", bb_index);
     174           80 :                   xp.add_text_from_pp (pp);
     175           80 :                   xp.pop_tag ("td");
     176           80 :                   xp.pop_tag ("tr");
     177           80 :                 }
     178              : 
     179          360 :               if (json::array *arr
     180          180 :                   = input_node.get_property (bb_property_names::gimple::phis))
     181           80 :                 print_rows_for_strings (*arr, xp);
     182              : 
     183          360 :               if (json::array *arr
     184              :                     = input_node.get_property
     185          180 :                         (bb_property_names::gimple::stmts))
     186           80 :                 print_rows_for_strings (*arr, xp);
     187              : 
     188          360 :               if (json::array *arr
     189          180 :                     = input_node.get_property (bb_property_names::rtl::insns))
     190          100 :                 print_rows_for_strings (*arr, xp);
     191              : 
     192              :               // xml must be done by now
     193              : 
     194          180 :               output_node.m_attrs.add (dot::id ("label"),
     195          360 :                                        dot::id (table));
     196          180 :             }
     197              :         }
     198          270 :   }
     199              : 
     200              :   virtual void
     201          270 :   add_any_edge_attrs (const digraph_edge &input_edge,
     202              :                       dot::edge_stmt &output_edge) final override
     203              :   {
     204          270 :     namespace edge_properties = custom_sarif_properties::cfg::edge;
     205              : 
     206          270 :     const char *style = "solid,bold";
     207          270 :     const char *color = "black";
     208          270 :     int weight = 10;
     209              : 
     210          270 :     if (edge_has_flag (input_edge, "FAKE"))
     211              :       {
     212            0 :         style = "dotted";
     213            0 :         color = "green";
     214            0 :         weight = 0;
     215              :       }
     216          270 :     if (edge_has_flag (input_edge, "DFS_BACK"))
     217              :       {
     218              :         style = "dotted,bold";
     219              :         color = "blue";
     220              :         weight = 10;
     221              :       }
     222          270 :     else if (edge_has_flag (input_edge, "FALLTHRU"))
     223              :       weight = 100;
     224          120 :     else if (edge_has_flag (input_edge, "TRUE_VALUE"))
     225              :       color = "forestgreen";
     226          100 :     else if (edge_has_flag (input_edge, "FALSE_VALUE"))
     227           20 :       color = "darkorange";
     228              : 
     229          270 :     if (edge_has_flag (input_edge, "ABNORMAL"))
     230            0 :       color = "red";
     231              : 
     232          270 :     output_edge.set_attr (dot::id ("style"), dot::id (style));
     233          270 :     output_edge.set_attr (dot::id ("color"), dot::id (color));
     234          270 :     output_edge.set_attr (dot::id ("weight"),
     235          540 :                           dot::id (std::to_string (weight)));
     236          540 :     output_edge.set_attr (dot::id ("constraint"),
     237          270 :                           dot::id ((edge_has_flag (input_edge, "FAKE")
     238          270 :                                     || edge_has_flag (input_edge, "DFS_BACK"))
     239          540 :                                    ? "false" : "true"));
     240              : 
     241          270 :     long probability_pc;
     242          270 :     if (input_edge.maybe_get_property (edge_properties::probability_pc,
     243              :                                        probability_pc))
     244              :       {
     245           48 :         pretty_printer pp;
     246           48 :         pp_printf (&pp, "[%li%%]", probability_pc);
     247           48 :         output_edge.set_label (dot::id (pp_formatted_text (&pp)));
     248           48 :       }
     249          270 :   }
     250              : 
     251              :   private:
     252              :     bool
     253         1840 :     edge_has_flag (const digraph_edge &input_edge,
     254              :                    const char *flag_name) const
     255              :     {
     256         1840 :       auto flags = input_edge.get_property (edge_properties::flags);
     257         5250 :       for (auto iter : *flags)
     258         1200 :         if (auto str = iter->dyn_cast_string ())
     259         1200 :           if (!strcmp (flag_name, str->get_string ()))
     260              :             return true;
     261              :       return false;
     262              :     }
     263              : 
     264              :     void
     265          260 :     print_rows_for_strings (json::array &arr,
     266              :                             xml::printer &xp)
     267              :     {
     268         1433 :       for (auto iter : arr)
     269          779 :         if (auto js_str = iter->dyn_cast_string ())
     270              :           {
     271          779 :             xp.push_tag ("tr", true);
     272          779 :             xp.push_tag ("td", true);
     273          779 :             xp.set_attr ("align", "left");
     274          779 :             xp.add_text (js_str->get_string ());
     275          779 :             xp.pop_tag ("td");
     276          779 :             xp.pop_tag ("tr");
     277              :           }
     278          260 :     }
     279              : 
     280              :   const node *
     281           90 :   get_bb_node_by_kind (const digraph &dg, const char *kind) const
     282              :   {
     283          135 :     for (auto &iter : dg.get_all_nodes ())
     284              :       {
     285          135 :         const node &input_node = *iter.second;
     286          135 :         if (const char *node_kind = input_node.get_property (node_properties::kind))
     287          135 :           if (strcmp (node_kind, "basic_block") == 0)
     288              :             {
     289          135 :               namespace bb_property_names
     290              :                 = custom_sarif_properties::cfg::basic_block;
     291          270 :               if (const char *bb_kind
     292          135 :                   = input_node.get_property (bb_property_names::kind))
     293              :                 {
     294          135 :                   if (strcmp (bb_kind, kind) == 0)
     295           90 :                     return &input_node;
     296              :                 }
     297              :             }
     298              :       }
     299              :     return nullptr;
     300              :   }
     301              : 
     302              :   const node *
     303           45 :   get_entry_node (const digraph &dg) const
     304              :   {
     305           45 :     return get_bb_node_by_kind (dg, "entry");
     306              :   }
     307              : 
     308              :   const node *
     309           45 :   get_exit_node (const digraph &dg) const
     310              :   {
     311           45 :     return get_bb_node_by_kind (dg, "exit");
     312              :   }
     313              : };
     314              : 
     315              : std::unique_ptr<converter>
     316           45 : make_converter_from_cfg ()
     317              : {
     318           45 :   return std::make_unique<converter_from_cfg> ();
     319              : }
     320              : 
     321              : } // namespace to_dot
     322              : } // namespace digraphs
     323              : } // namespace diagnostics
        

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.