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