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