LCOV - code coverage report
Current view: top level - gcc/analyzer - state-purge.cc (source / functions) Hit Total Coverage
Test: gcc.info Lines: 201 235 85.5 %
Date: 2020-03-28 11:57:23 Functions: 10 10 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* Classes for purging state at function_points.
       2                 :            :    Copyright (C) 2019-2020 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                 :            : #include "config.h"
      22                 :            : #include "system.h"
      23                 :            : #include "coretypes.h"
      24                 :            : #include "tree.h"
      25                 :            : #include "timevar.h"
      26                 :            : #include "tree-ssa-alias.h"
      27                 :            : #include "function.h"
      28                 :            : #include "basic-block.h"
      29                 :            : #include "gimple.h"
      30                 :            : #include "stringpool.h"
      31                 :            : #include "tree-vrp.h"
      32                 :            : #include "gimple-ssa.h"
      33                 :            : #include "tree-ssanames.h"
      34                 :            : #include "tree-phinodes.h"
      35                 :            : #include "options.h"
      36                 :            : #include "ssa-iterators.h"
      37                 :            : #include "diagnostic-core.h"
      38                 :            : #include "gimple-pretty-print.h"
      39                 :            : #include "function.h"
      40                 :            : #include "analyzer/analyzer.h"
      41                 :            : #include "analyzer/call-string.h"
      42                 :            : #include "digraph.h"
      43                 :            : #include "ordered-hash-map.h"
      44                 :            : #include "cfg.h"
      45                 :            : #include "gimple-iterator.h"
      46                 :            : #include "cgraph.h"
      47                 :            : #include "analyzer/supergraph.h"
      48                 :            : #include "analyzer/program-point.h"
      49                 :            : #include "analyzer/analyzer-logging.h"
      50                 :            : #include "analyzer/state-purge.h"
      51                 :            : 
      52                 :            : #if ENABLE_ANALYZER
      53                 :            : 
      54                 :            : /* state_purge_map's ctor.  Walk all SSA names in all functions, building
      55                 :            :    a state_purge_per_ssa_name instance for each.  */
      56                 :            : 
      57                 :        373 : state_purge_map::state_purge_map (const supergraph &sg,
      58                 :        373 :                                   logger *logger)
      59                 :        373 : : log_user (logger), m_sg (sg)
      60                 :            : {
      61                 :        373 :   LOG_FUNC (logger);
      62                 :            : 
      63                 :        746 :   auto_timevar tv (TV_ANALYZER_STATE_PURGE);
      64                 :            : 
      65                 :        373 :   cgraph_node *node;
      66                 :       1745 :   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
      67                 :            :   {
      68                 :        999 :     function *fun = node->get_fun ();
      69                 :        999 :     if (logger)
      70                 :          0 :       log ("function: %s", function_name (fun));
      71                 :            :     tree name;
      72                 :            :     unsigned int i;;
      73                 :       9479 :     FOR_EACH_SSA_NAME (i, name, fun)
      74                 :            :       {
      75                 :            :         /* For now, don't bother tracking the .MEM SSA names.  */
      76                 :       8465 :         if (tree var = SSA_NAME_VAR (name))
      77                 :       5651 :           if (TREE_CODE (var) == VAR_DECL)
      78                 :       4854 :             if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
      79                 :       4083 :               continue;
      80                 :       4382 :         m_map.put (name, new state_purge_per_ssa_name (*this, name, fun));
      81                 :            :       }
      82                 :            :   }
      83                 :        373 : }
      84                 :            : 
      85                 :            : /* state_purge_map's dtor.  */
      86                 :            : 
      87                 :        373 : state_purge_map::~state_purge_map ()
      88                 :            : {
      89                 :      13839 :   for (iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
      90                 :       8764 :     delete (*iter).second;
      91                 :        373 : }
      92                 :            : 
      93                 :            : /* state_purge_per_ssa_name's ctor.
      94                 :            : 
      95                 :            :    Locate all uses of VAR within FUN.
      96                 :            :    Walk backwards from each use, marking program points, until
      97                 :            :    we reach the def stmt, populating m_points_needing_var.
      98                 :            : 
      99                 :            :    We have to track program points rather than
     100                 :            :    just stmts since there could be empty basic blocks on the way.  */
     101                 :            : 
     102                 :       4382 : state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
     103                 :            :                                                     tree name,
     104                 :       4382 :                                                     function *fun)
     105                 :       4382 : : m_points_needing_name (), m_name (name), m_fun (fun)
     106                 :            : {
     107                 :       4382 :   LOG_FUNC (map.get_logger ());
     108                 :            : 
     109                 :       4382 :   if (map.get_logger ())
     110                 :            :     {
     111                 :          0 :       map.log ("SSA name: %qE within %qD", name, fun->decl);
     112                 :            : 
     113                 :            :       /* Show def stmt.  */
     114                 :          0 :       const gimple *def_stmt = SSA_NAME_DEF_STMT (name);
     115                 :          0 :       pretty_printer pp;
     116                 :          0 :       pp_gimple_stmt_1 (&pp, def_stmt, 0, (dump_flags_t)0);
     117                 :          0 :       map.log ("def stmt: %s", pp_formatted_text (&pp));
     118                 :            :     }
     119                 :            : 
     120                 :       8764 :   auto_vec<function_point> worklist;
     121                 :            : 
     122                 :            :   /* Add all immediate uses of name to the worklist.
     123                 :            :      Compare with debug_immediate_uses.  */
     124                 :       4382 :   imm_use_iterator iter;
     125                 :       4382 :   use_operand_p use_p;
     126                 :      10178 :   FOR_EACH_IMM_USE_FAST (use_p, iter, name)
     127                 :            :     {
     128                 :       5796 :       if (USE_STMT (use_p))
     129                 :            :         {
     130                 :       5796 :           const gimple *use_stmt = USE_STMT (use_p);
     131                 :       5796 :           if (map.get_logger ())
     132                 :            :             {
     133                 :          0 :               pretty_printer pp;
     134                 :          0 :               pp_gimple_stmt_1 (&pp, use_stmt, 0, (dump_flags_t)0);
     135                 :          0 :               map.log ("used by stmt: %s", pp_formatted_text (&pp));
     136                 :            :             }
     137                 :            : 
     138                 :       5796 :           const supernode *snode
     139                 :       5796 :             = map.get_sg ().get_supernode_for_stmt (use_stmt);
     140                 :            : 
     141                 :            :           /* If it's a use within a phi node, then we care about
     142                 :            :              which in-edge we came from.  */
     143                 :       5796 :           if (use_stmt->code == GIMPLE_PHI)
     144                 :            :             {
     145                 :        495 :               for (gphi_iterator gpi
     146                 :       1910 :                      = const_cast<supernode *> (snode)->start_phis ();
     147                 :       1910 :                    !gsi_end_p (gpi); gsi_next (&gpi))
     148                 :            :                 {
     149                 :       1415 :                   gphi *phi = gpi.phi ();
     150                 :       1415 :                   if (phi == use_stmt)
     151                 :            :                     {
     152                 :            :                       /* Find arguments (and thus in-edges) which use NAME.  */
     153                 :       1512 :                       for (unsigned arg_idx = 0;
     154                 :       2007 :                            arg_idx < gimple_phi_num_args (phi);
     155                 :            :                            ++arg_idx)
     156                 :            :                         {
     157                 :       1512 :                           if (name == gimple_phi_arg (phi, arg_idx)->def)
     158                 :            :                             {
     159                 :        681 :                               edge in_edge = gimple_phi_arg_edge (phi, arg_idx);
     160                 :        681 :                               const superedge *in_sedge
     161                 :        681 :                                 = map.get_sg ().get_edge_for_cfg_edge (in_edge);
     162                 :        681 :                               function_point point
     163                 :            :                                 = function_point::before_supernode
     164                 :        681 :                                 (snode, in_sedge);
     165                 :        681 :                               add_to_worklist (point, &worklist,
     166                 :            :                                                map.get_logger ());
     167                 :        681 :                               m_points_needing_name.add (point);
     168                 :            :                             }
     169                 :            :                         }
     170                 :            :                     }
     171                 :            :                 }
     172                 :            :             }
     173                 :            :           else
     174                 :            :             {
     175                 :       5301 :               function_point point = before_use_stmt (map, use_stmt);
     176                 :       5301 :               add_to_worklist (point, &worklist, map.get_logger ());
     177                 :       5301 :               m_points_needing_name.add (point);
     178                 :            : 
     179                 :            :               /* We also need to add uses for conditionals and switches,
     180                 :            :                  where the stmt "happens" at the after_supernode, for filtering
     181                 :            :                  the out-edges.  */
     182                 :      10602 :               if (use_stmt == snode->get_last_stmt ())
     183                 :            :                 {
     184                 :       1585 :                   if (map.get_logger ())
     185                 :          0 :                     map.log ("last stmt in BB");
     186                 :       1585 :                   function_point point
     187                 :       1585 :                     = function_point::after_supernode (snode);
     188                 :       1585 :                   add_to_worklist (point, &worklist, map.get_logger ());
     189                 :       1585 :                   m_points_needing_name.add (point);
     190                 :            :                 }
     191                 :            :               else
     192                 :       3716 :                 if (map.get_logger ())
     193                 :          0 :                   map.log ("not last stmt in BB");
     194                 :            :             }
     195                 :            :         }
     196                 :            :     }
     197                 :            : 
     198                 :            :   /* Process worklist by walking backwards until we reach the def stmt.  */
     199                 :       4382 :   {
     200                 :       8764 :     log_scope s (map.get_logger (), "processing worklist");
     201                 :      33637 :     while (worklist.length () > 0)
     202                 :            :       {
     203                 :      29255 :         function_point point = worklist.pop ();
     204                 :      29255 :         process_point (point, &worklist, map);
     205                 :            :     }
     206                 :            :   }
     207                 :            : 
     208                 :       4382 :   if (map.get_logger ())
     209                 :            :     {
     210                 :          0 :       map.log ("%qE in %qD is needed to process:", name, fun->decl);
     211                 :          0 :       for (point_set_t::iterator iter = m_points_needing_name.begin ();
     212                 :       4382 :            iter != m_points_needing_name.end ();
     213                 :          0 :            ++iter)
     214                 :            :         {
     215                 :          0 :           map.start_log_line ();
     216                 :          0 :           map.get_logger ()->log_partial ("  point: ");
     217                 :          0 :           (*iter).print (map.get_logger ()->get_printer (), format (false));
     218                 :          0 :           map.end_log_line ();
     219                 :            :         }
     220                 :            :     }
     221                 :       4382 : }
     222                 :            : 
     223                 :            : /* Return true if the SSA name is needed at POINT.  */
     224                 :            : 
     225                 :            : bool
     226                 :      85119 : state_purge_per_ssa_name::needed_at_point_p (const function_point &point) const
     227                 :            : {
     228                 :      85119 :   return const_cast <point_set_t &> (m_points_needing_name).contains (point);
     229                 :            : }
     230                 :            : 
     231                 :            : /* Get the function_point representing immediately before USE_STMT.
     232                 :            :    Subroutine of ctor.  */
     233                 :            : 
     234                 :            : function_point
     235                 :       5301 : state_purge_per_ssa_name::before_use_stmt (const state_purge_map &map,
     236                 :            :                                            const gimple *use_stmt)
     237                 :            : {
     238                 :       5301 :   gcc_assert (use_stmt->code != GIMPLE_PHI);
     239                 :            : 
     240                 :       5301 :   const supernode *supernode
     241                 :       5301 :     = map.get_sg ().get_supernode_for_stmt (use_stmt);
     242                 :       5301 :   unsigned int stmt_idx = supernode->get_stmt_index (use_stmt);
     243                 :       5301 :   return function_point::before_stmt (supernode, stmt_idx);
     244                 :            : }
     245                 :            : 
     246                 :            : /* Add POINT to *WORKLIST if the point has not already been seen.
     247                 :            :    Subroutine of ctor.  */
     248                 :            : 
     249                 :            : void
     250                 :      33882 : state_purge_per_ssa_name::add_to_worklist (const function_point &point,
     251                 :            :                                            auto_vec<function_point> *worklist,
     252                 :            :                                            logger *logger)
     253                 :            : {
     254                 :      67764 :   LOG_FUNC (logger);
     255                 :      33882 :   if (logger)
     256                 :            :     {
     257                 :          0 :       logger->start_log_line ();
     258                 :          0 :       logger->log_partial ("point: '");
     259                 :          0 :       point.print (logger->get_printer (), format (false));
     260                 :          0 :       logger->log_partial ("' for worklist for %qE", m_name);
     261                 :          0 :       logger->end_log_line ();
     262                 :            :     }
     263                 :            : 
     264                 :      67764 :   gcc_assert (point.get_function () == m_fun);
     265                 :      33882 :   if (point.get_from_edge ())
     266                 :       5595 :     gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
     267                 :            : 
     268                 :      33882 :   if (m_points_needing_name.contains (point))
     269                 :            :     {
     270                 :       4627 :       if (logger)
     271                 :          0 :         logger->log ("already seen for %qE", m_name);
     272                 :            :     }
     273                 :            :   else
     274                 :            :     {
     275                 :      29255 :       if (logger)
     276                 :          0 :         logger->log ("not seen; adding to worklist for %qE", m_name);
     277                 :      29255 :       m_points_needing_name.add (point);
     278                 :      29255 :       worklist->safe_push (point);
     279                 :            :     }
     280                 :      33882 : }
     281                 :            : 
     282                 :            : /* Process POINT, popped from WORKLIST.
     283                 :            :    Iterate over predecessors of POINT, adding to WORKLIST.  */
     284                 :            : 
     285                 :            : void
     286                 :      29255 : state_purge_per_ssa_name::process_point (const function_point &point,
     287                 :            :                                          auto_vec<function_point> *worklist,
     288                 :            :                                          const state_purge_map &map)
     289                 :            : {
     290                 :      29255 :   logger *logger = map.get_logger ();
     291                 :      29255 :   LOG_FUNC (logger);
     292                 :      29255 :   if (logger)
     293                 :            :     {
     294                 :          0 :       logger->start_log_line ();
     295                 :          0 :       logger->log_partial ("considering point: '");
     296                 :          0 :       point.print (logger->get_printer (), format (false));
     297                 :          0 :       logger->log_partial ("' for %qE", m_name);
     298                 :          0 :       logger->end_log_line ();
     299                 :            :     }
     300                 :            : 
     301                 :      29255 :   gimple *def_stmt = SSA_NAME_DEF_STMT (m_name);
     302                 :            : 
     303                 :      29255 :   const supernode *snode = point.get_supernode ();
     304                 :            : 
     305                 :      29255 :   switch (point.get_kind ())
     306                 :            :     {
     307                 :          0 :     default:
     308                 :          0 :       gcc_unreachable ();
     309                 :            : 
     310                 :            :     case PK_ORIGIN:
     311                 :            :       break;
     312                 :            : 
     313                 :       6379 :     case PK_BEFORE_SUPERNODE:
     314                 :       6379 :       {
     315                 :       6379 :         for (gphi_iterator gpi
     316                 :      11284 :                = const_cast<supernode *> (snode)->start_phis ();
     317                 :      11284 :              !gsi_end_p (gpi); gsi_next (&gpi))
     318                 :            :           {
     319                 :       5475 :             gphi *phi = gpi.phi ();
     320                 :       5475 :             if (phi == def_stmt)
     321                 :            :               {
     322                 :        570 :                 if (logger)
     323                 :          0 :                   logger->log ("def stmt within phis; terminating");
     324                 :        570 :                 return;
     325                 :            :               }
     326                 :            :           }
     327                 :            : 
     328                 :            :         /* Add given pred to worklist.  */
     329                 :       5809 :         if (point.get_from_edge ())
     330                 :            :           {
     331                 :       4806 :             gcc_assert (point.get_from_edge ()->m_src);
     332                 :       4806 :             add_to_worklist
     333                 :       4806 :               (function_point::after_supernode (point.get_from_edge ()->m_src),
     334                 :            :                worklist, logger);
     335                 :            :           }
     336                 :            :         else
     337                 :            :           {
     338                 :            :             /* Add any intraprocedually edge for a call.  */
     339                 :       1003 :             if (snode->m_returning_call)
     340                 :            :               {
     341                 :        228 :                 cgraph_edge *cedge
     342                 :        228 :                   = supergraph_call_edge (snode->m_fun,
     343                 :            :                                           snode->m_returning_call);
     344                 :        228 :                 gcc_assert (cedge);
     345                 :        228 :                 superedge *sedge
     346                 :        228 :                   = map.get_sg ().get_intraprocedural_edge_for_call (cedge);
     347                 :        228 :                 gcc_assert (sedge);
     348                 :        228 :                 add_to_worklist
     349                 :        228 :                   (function_point::after_supernode (sedge->m_src),
     350                 :            :                    worklist, logger);
     351                 :            :               }
     352                 :            :           }
     353                 :            :       }
     354                 :            :       break;
     355                 :            : 
     356                 :      17488 :     case PK_BEFORE_STMT:
     357                 :      17488 :       {
     358                 :      17488 :         if (def_stmt == point.get_stmt ())
     359                 :            :           {
     360                 :       3286 :             if (logger)
     361                 :          0 :               logger->log ("def stmt; terminating");
     362                 :       3286 :             return;
     363                 :            :           }
     364                 :      14202 :         if (point.get_stmt_idx () > 0)
     365                 :      10452 :           add_to_worklist (function_point::before_stmt
     366                 :      10452 :                              (snode, point.get_stmt_idx () - 1),
     367                 :            :                            worklist, logger);
     368                 :            :         else
     369                 :            :         {
     370                 :            :           /* Add before_supernode to worklist.  This captures the in-edge,
     371                 :            :              so we have to do it once per in-edge.  */
     372                 :            :           unsigned i;
     373                 :            :           superedge *pred;
     374                 :      34217 :           FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
     375                 :       5068 :             add_to_worklist (function_point::before_supernode (snode,
     376                 :      10136 :                                                                pred),
     377                 :            :                              worklist, logger);
     378                 :            :         }
     379                 :            :       }
     380                 :            :       break;
     381                 :            : 
     382                 :       5388 :     case PK_AFTER_SUPERNODE:
     383                 :       5388 :       {
     384                 :       5388 :         if (snode->m_stmts.length ())
     385                 :       4365 :           add_to_worklist
     386                 :       4365 :             (function_point::before_stmt (snode,
     387                 :       4365 :                                           snode->m_stmts.length () - 1),
     388                 :            :              worklist, logger);
     389                 :            :         else
     390                 :            :           {
     391                 :            :             /* Add before_supernode to worklist.  This captures the in-edge,
     392                 :            :                so we have to do it once per in-edge.  */
     393                 :            :             unsigned i;
     394                 :            :             superedge *pred;
     395                 :       1644 :             FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
     396                 :        621 :               add_to_worklist (function_point::before_supernode (snode,
     397                 :       1242 :                                                                  pred),
     398                 :            :                                worklist, logger);
     399                 :            :             /* If it's the initial BB, add it, to ensure that we
     400                 :            :                have "before supernode" for the initial ENTRY block, and don't
     401                 :            :                erroneously purge SSA names for initial values of parameters.  */
     402                 :       1023 :             if (snode->entry_p ())
     403                 :            :               {
     404                 :        775 :                 add_to_worklist
     405                 :        775 :                   (function_point::before_supernode (snode, NULL),
     406                 :            :                    worklist, logger);
     407                 :            :               }
     408                 :            :           }
     409                 :            :       }
     410                 :            :       break;
     411                 :            :     }
     412                 :            : }
     413                 :            : 
     414                 :            : /* class state_purge_annotator : public dot_annotator.  */
     415                 :            : 
     416                 :            : /* Implementation of dot_annotator::add_node_annotations vfunc for
     417                 :            :    state_purge_annotator.
     418                 :            : 
     419                 :            :    Add an additional record showing which names are purged on entry
     420                 :            :    to the supernode N.  */
     421                 :            : 
     422                 :            : bool
     423                 :         38 : state_purge_annotator::add_node_annotations (graphviz_out *gv,
     424                 :            :                                              const supernode &n,
     425                 :            :                                              bool within_table) const
     426                 :            : {
     427                 :         38 :   if (m_map == NULL)
     428                 :            :     return false;
     429                 :            : 
     430                 :         38 :   if (within_table)
     431                 :            :     return false;
     432                 :            : 
     433                 :         19 :   pretty_printer *pp = gv->get_pp ();
     434                 :            : 
     435                 :         19 :    pp_printf (pp, "annotation_for_node_%i", n.m_index);
     436                 :         19 :    pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
     437                 :            :               "lightblue");
     438                 :         19 :    pp_write_text_to_stream (pp);
     439                 :            : 
     440                 :            :    // FIXME: passing in a NULL in-edge means we get no hits
     441                 :         19 :    function_point before_supernode
     442                 :         19 :      (function_point::before_supernode (&n, NULL));
     443                 :            : 
     444                 :         19 :    for (state_purge_map::iterator iter = m_map->begin ();
     445                 :        456 :         iter != m_map->end ();
     446                 :        456 :         ++iter)
     447                 :            :      {
     448                 :        437 :        tree name = (*iter).first;
     449                 :        437 :        state_purge_per_ssa_name *per_name_data = (*iter).second;
     450                 :        437 :        if (per_name_data->get_function () == n.m_fun)
     451                 :            :          {
     452                 :        174 :            if (per_name_data->needed_at_point_p (before_supernode))
     453                 :          7 :              pp_printf (pp, "%qE needed here", name);
     454                 :            :            else
     455                 :        167 :              pp_printf (pp, "%qE not needed here", name);
     456                 :            :          }
     457                 :        437 :        pp_newline (pp);
     458                 :            :      }
     459                 :            : 
     460                 :         19 :    pp_string (pp, "\"];\n\n");
     461                 :         19 :    pp_flush (pp);
     462                 :         19 :    return false;
     463                 :            : }
     464                 :            : 
     465                 :            : /* Print V to GV as a comma-separated list in braces within a <TR>,
     466                 :            :    titling it with TITLE.
     467                 :            : 
     468                 :            :    Subroutine of state_purge_annotator::add_stmt_annotations.  */
     469                 :            : 
     470                 :            : static void
     471                 :         60 : print_vec_of_names (graphviz_out *gv, const char *title,
     472                 :            :                     const auto_vec<tree> &v)
     473                 :            : {
     474                 :         60 :   pretty_printer *pp = gv->get_pp ();
     475                 :         60 :   tree name;
     476                 :         60 :   unsigned i;
     477                 :         60 :   gv->begin_trtd ();
     478                 :         60 :   pp_printf (pp, "%s: {", title);
     479                 :        477 :   FOR_EACH_VEC_ELT (v, i, name)
     480                 :            :     {
     481                 :        417 :       if (i > 0)
     482                 :        359 :         pp_string (pp, ", ");
     483                 :        417 :       pp_printf (pp, "%qE", name);
     484                 :            :     }
     485                 :         60 :   pp_printf (pp, "}");
     486                 :         60 :   pp_write_text_as_html_like_dot_to_stream (pp);
     487                 :         60 :   gv->end_tdtr ();
     488                 :         60 :   pp_newline (pp);
     489                 :         60 : }
     490                 :            : 
     491                 :            : /* Implementation of dot_annotator::add_stmt_annotations for
     492                 :            :    state_purge_annotator.
     493                 :            : 
     494                 :            :    Add text showing which names are purged at STMT.  */
     495                 :            : 
     496                 :            : void
     497                 :         66 : state_purge_annotator::add_stmt_annotations (graphviz_out *gv,
     498                 :            :                                              const gimple *stmt,
     499                 :            :                                              bool within_row) const
     500                 :            : {
     501                 :         66 :   if (within_row)
     502                 :         36 :     return;
     503                 :            : 
     504                 :         33 :   if (m_map == NULL)
     505                 :            :     return;
     506                 :            : 
     507                 :         33 :   if (stmt->code == GIMPLE_PHI)
     508                 :            :     return;
     509                 :            : 
     510                 :         30 :   pretty_printer *pp = gv->get_pp ();
     511                 :            : 
     512                 :         30 :   pp_newline (pp);
     513                 :            : 
     514                 :         30 :   const supernode *supernode = m_map->get_sg ().get_supernode_for_stmt (stmt);
     515                 :         30 :   unsigned int stmt_idx = supernode->get_stmt_index (stmt);
     516                 :         30 :   function_point before_stmt
     517                 :         30 :     (function_point::before_stmt (supernode, stmt_idx));
     518                 :            : 
     519                 :         60 :   auto_vec<tree> needed;
     520                 :         30 :   auto_vec<tree> not_needed;
     521                 :        720 :   for (state_purge_map::iterator iter = m_map->begin ();
     522                 :        720 :        iter != m_map->end ();
     523                 :        720 :        ++iter)
     524                 :            :     {
     525                 :        690 :       tree name = (*iter).first;
     526                 :        690 :       state_purge_per_ssa_name *per_name_data = (*iter).second;
     527                 :        690 :       if (per_name_data->get_function () == supernode->m_fun)
     528                 :            :         {
     529                 :        417 :           if (per_name_data->needed_at_point_p (before_stmt))
     530                 :        121 :             needed.safe_push (name);
     531                 :            :           else
     532                 :        296 :             not_needed.safe_push (name);
     533                 :            :         }
     534                 :            :     }
     535                 :            : 
     536                 :         30 :   print_vec_of_names (gv, "needed here", needed);
     537                 :         30 :   print_vec_of_names (gv, "not needed here", not_needed);
     538                 :            : }
     539                 :            : 
     540                 :            : #endif /* #if ENABLE_ANALYZER */

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.