libstdc++: Fix formatter for low-resolution chrono::zoned_time (LWG 4124)
[official-gcc.git] / gcc / analyzer / state-purge.cc
blob7f5a40ae4add2df6b5e0cc9b99143a72b83796c5
1 /* Classes for purging state at function_points.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #define INCLUDE_MEMORY
23 #define INCLUDE_VECTOR
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tree.h"
27 #include "timevar.h"
28 #include "tree-ssa-alias.h"
29 #include "function.h"
30 #include "basic-block.h"
31 #include "gimple.h"
32 #include "stringpool.h"
33 #include "tree-vrp.h"
34 #include "gimple-ssa.h"
35 #include "tree-ssanames.h"
36 #include "tree-phinodes.h"
37 #include "options.h"
38 #include "ssa-iterators.h"
39 #include "diagnostic-core.h"
40 #include "gimple-pretty-print.h"
41 #include "analyzer/analyzer.h"
42 #include "analyzer/call-string.h"
43 #include "analyzer/supergraph.h"
44 #include "analyzer/program-point.h"
45 #include "analyzer/analyzer-logging.h"
46 #include "analyzer/state-purge.h"
47 #include "analyzer/store.h"
48 #include "analyzer/region-model.h"
49 #include "gimple-walk.h"
50 #include "cgraph.h"
52 #if ENABLE_ANALYZER
54 /* Given NODE at an access, determine if this access is within
55 a decl that could be consider for purging, and if so, return the decl. */
57 static tree
58 get_candidate_for_purging (tree node)
60 tree iter = node;
61 while (1)
62 switch (TREE_CODE (iter))
64 default:
65 return NULL_TREE;
67 case ADDR_EXPR:
68 case MEM_REF:
69 case COMPONENT_REF:
70 iter = TREE_OPERAND (iter, 0);
71 continue;
73 case VAR_DECL:
74 if (is_global_var (iter))
75 return NULL_TREE;
76 else
77 return iter;
79 case PARM_DECL:
80 case RESULT_DECL:
81 return iter;
85 /* Class-based handler for walk_stmt_load_store_addr_ops at a particular
86 function_point, for populating the worklists within a state_purge_map. */
88 class gimple_op_visitor : public log_user
90 public:
91 gimple_op_visitor (state_purge_map *map,
92 const function_point &point,
93 const function &fun)
94 : log_user (map->get_logger ()),
95 m_map (map),
96 m_point (point),
97 m_fun (fun)
100 bool on_load (gimple *stmt, tree base, tree op)
102 LOG_FUNC (get_logger ());
103 if (get_logger ())
105 pretty_printer pp;
106 pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
107 log ("on_load: %s; base: %qE, op: %qE",
108 pp_formatted_text (&pp), base, op);
110 if (tree node = get_candidate_for_purging (base))
111 add_needed (node);
112 return true;
115 bool on_store (gimple *stmt, tree base, tree op)
117 LOG_FUNC (get_logger ());
118 if (get_logger ())
120 pretty_printer pp;
121 pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
122 log ("on_store: %s; base: %qE, op: %qE",
123 pp_formatted_text (&pp), base, op);
125 return true;
128 bool on_addr (gimple *stmt, tree base, tree op)
130 LOG_FUNC (get_logger ());
131 if (get_logger ())
133 pretty_printer pp;
134 pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
135 log ("on_addr: %s; base: %qE, op: %qE",
136 pp_formatted_text (&pp), base, op);
138 if (TREE_CODE (op) != ADDR_EXPR)
139 return true;
140 if (tree node = get_candidate_for_purging (base))
142 add_needed (node);
143 add_pointed_to (node);
145 return true;
148 private:
149 void add_needed (tree decl)
151 gcc_assert (get_candidate_for_purging (decl) == decl);
152 state_purge_per_decl &data
153 = get_or_create_data_for_decl (decl);
154 data.add_needed_at (m_point);
156 /* Handle calls: if we're seeing a use at a call, then add a use at the
157 "after-supernode" point (in case of interprocedural call superedges). */
158 if (m_point.final_stmt_p ())
159 data.add_needed_at (m_point.get_next ());
162 void add_pointed_to (tree decl)
164 gcc_assert (get_candidate_for_purging (decl) == decl);
165 get_or_create_data_for_decl (decl).add_pointed_to_at (m_point);
168 state_purge_per_decl &
169 get_or_create_data_for_decl (tree decl)
171 return m_map->get_or_create_data_for_decl (m_fun, decl);
174 state_purge_map *m_map;
175 const function_point &m_point;
176 const function &m_fun;
179 static bool
180 my_load_cb (gimple *stmt, tree base, tree op, void *user_data)
182 gimple_op_visitor *x = (gimple_op_visitor *)user_data;
183 return x->on_load (stmt, base, op);
186 static bool
187 my_store_cb (gimple *stmt, tree base, tree op, void *user_data)
189 gimple_op_visitor *x = (gimple_op_visitor *)user_data;
190 return x->on_store (stmt, base, op);
193 static bool
194 my_addr_cb (gimple *stmt, tree base, tree op, void *user_data)
196 gimple_op_visitor *x = (gimple_op_visitor *)user_data;
197 return x->on_addr (stmt, base, op);
200 /* state_purge_map's ctor. Walk all SSA names in all functions, building
201 a state_purge_per_ssa_name instance for each.
202 Also, walk all loads and address-taken ops of local variables, building
203 a state_purge_per_decl as appropriate. */
205 state_purge_map::state_purge_map (const supergraph &sg,
206 region_model_manager *mgr,
207 logger *logger)
208 : log_user (logger), m_sg (sg)
210 LOG_FUNC (logger);
212 auto_timevar tv (TV_ANALYZER_STATE_PURGE);
214 cgraph_node *node;
215 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
217 function *fun = node->get_fun ();
218 gcc_assert (fun);
219 if (logger)
220 log ("function: %s", function_name (fun));
221 tree name;
222 unsigned int i;;
223 FOR_EACH_SSA_NAME (i, name, fun)
225 /* For now, don't bother tracking the .MEM SSA names. */
226 if (tree var = SSA_NAME_VAR (name))
227 if (TREE_CODE (var) == VAR_DECL)
228 if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
229 continue;
230 m_ssa_map.put (name, new state_purge_per_ssa_name (*this, name, *fun));
234 /* Find all uses of local vars.
235 We iterate through all function points, finding loads, stores, and
236 address-taken operations on locals, building a pair of worklists. */
237 for (auto snode : sg.m_nodes)
239 if (logger)
240 log ("SN: %i", snode->m_index);
241 /* We ignore m_returning_call and phi nodes. */
242 gimple *stmt;
243 unsigned i;
244 FOR_EACH_VEC_ELT (snode->m_stmts, i, stmt)
246 function *fun = snode->get_function ();
247 gcc_assert (fun);
248 function_point point (function_point::before_stmt (snode, i));
249 gimple_op_visitor v (this, point, *fun);
250 walk_stmt_load_store_addr_ops (stmt, &v,
251 my_load_cb, my_store_cb, my_addr_cb);
255 /* Now iterate through the m_decl_map, processing each pair of worklists. */
256 for (state_purge_map::decl_iterator iter = begin_decls ();
257 iter != end_decls ();
258 ++iter)
260 state_purge_per_decl *per_decl_data = (*iter).second;
261 per_decl_data->process_worklists (*this, mgr);
265 /* state_purge_map's dtor. */
267 state_purge_map::~state_purge_map ()
269 for (auto iter : m_ssa_map)
270 delete iter.second;
271 for (auto iter : m_decl_map)
272 delete iter.second;
275 /* Get the state_purge_per_decl for local DECL within FUN, creating it
276 if necessary. */
278 state_purge_per_decl &
279 state_purge_map::get_or_create_data_for_decl (const function &fun, tree decl)
281 if (state_purge_per_decl **slot
282 = const_cast <decl_map_t&> (m_decl_map).get (decl))
283 return **slot;
284 state_purge_per_decl *result = new state_purge_per_decl (*this, decl, fun);
285 m_decl_map.put (decl, result);
286 return *result;
289 /* class state_purge_per_ssa_name : public state_purge_per_tree. */
291 /* state_purge_per_ssa_name's ctor.
293 Locate all uses of VAR within FUN.
294 Walk backwards from each use, marking program points, until
295 we reach the def stmt, populating m_points_needing_var.
297 We have to track program points rather than
298 just stmts since there could be empty basic blocks on the way. */
300 state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
301 tree name,
302 const function &fun)
303 : state_purge_per_tree (fun), m_points_needing_name (), m_name (name)
305 LOG_FUNC (map.get_logger ());
307 if (map.get_logger ())
309 map.log ("SSA name: %qE within %qD", name, fun.decl);
311 /* Show def stmt. */
312 const gimple *def_stmt = SSA_NAME_DEF_STMT (name);
313 pretty_printer pp;
314 pp_gimple_stmt_1 (&pp, def_stmt, 0, (dump_flags_t)0);
315 map.log ("def stmt: %s", pp_formatted_text (&pp));
318 auto_vec<function_point> worklist;
320 /* Add all immediate uses of name to the worklist.
321 Compare with debug_immediate_uses. */
322 imm_use_iterator iter;
323 use_operand_p use_p;
324 FOR_EACH_IMM_USE_FAST (use_p, iter, name)
326 if (USE_STMT (use_p))
328 const gimple *use_stmt = USE_STMT (use_p);
329 if (map.get_logger ())
331 pretty_printer pp;
332 pp_gimple_stmt_1 (&pp, use_stmt, 0, (dump_flags_t)0);
333 map.log ("used by stmt: %s", pp_formatted_text (&pp));
336 if (is_gimple_debug (use_stmt))
338 /* We skipped debug stmts when building the supergraph,
339 so ignore them now. */
340 if (map.get_logger ())
341 map.log ("skipping debug stmt");
342 continue;
345 const supernode *snode
346 = map.get_sg ().get_supernode_for_stmt (use_stmt);
348 /* If it's a use within a phi node, then we care about
349 which in-edge we came from. */
350 if (use_stmt->code == GIMPLE_PHI)
352 for (gphi_iterator gpi
353 = const_cast<supernode *> (snode)->start_phis ();
354 !gsi_end_p (gpi); gsi_next (&gpi))
356 gphi *phi = gpi.phi ();
357 if (phi == use_stmt)
359 /* Find arguments (and thus in-edges) which use NAME. */
360 for (unsigned arg_idx = 0;
361 arg_idx < gimple_phi_num_args (phi);
362 ++arg_idx)
364 if (name == gimple_phi_arg (phi, arg_idx)->def)
366 edge in_edge = gimple_phi_arg_edge (phi, arg_idx);
367 const superedge *in_sedge
368 = map.get_sg ().get_edge_for_cfg_edge (in_edge);
369 function_point point
370 = function_point::before_supernode
371 (snode, in_sedge);
372 add_to_worklist (point, &worklist,
373 map.get_logger ());
374 m_points_needing_name.add (point);
380 else
382 function_point point = before_use_stmt (map, use_stmt);
383 add_to_worklist (point, &worklist, map.get_logger ());
384 m_points_needing_name.add (point);
386 /* We also need to add uses for conditionals and switches,
387 where the stmt "happens" at the after_supernode, for filtering
388 the out-edges. */
389 if (use_stmt == snode->get_last_stmt ())
391 if (map.get_logger ())
392 map.log ("last stmt in BB");
393 function_point point
394 = function_point::after_supernode (snode);
395 add_to_worklist (point, &worklist, map.get_logger ());
396 m_points_needing_name.add (point);
398 else
399 if (map.get_logger ())
400 map.log ("not last stmt in BB");
405 /* Process worklist by walking backwards until we reach the def stmt. */
407 log_scope s (map.get_logger (), "processing worklist");
408 while (worklist.length () > 0)
410 function_point point = worklist.pop ();
411 process_point (point, &worklist, map);
415 if (map.get_logger ())
417 map.log ("%qE in %qD is needed to process:", name, fun.decl);
418 /* Log m_points_needing_name, sorting it to avoid churn when comparing
419 dumps. */
420 auto_vec<function_point> points;
421 for (point_set_t::iterator iter = m_points_needing_name.begin ();
422 iter != m_points_needing_name.end ();
423 ++iter)
424 points.safe_push (*iter);
425 points.qsort (function_point::cmp_ptr);
426 unsigned i;
427 function_point *point;
428 FOR_EACH_VEC_ELT (points, i, point)
430 map.start_log_line ();
431 map.get_logger ()->log_partial (" point: ");
432 point->print (map.get_logger ()->get_printer (), format (false));
433 map.end_log_line ();
438 /* Return true if the SSA name is needed at POINT. */
440 bool
441 state_purge_per_ssa_name::needed_at_point_p (const function_point &point) const
443 return const_cast <point_set_t &> (m_points_needing_name).contains (point);
446 /* Get the function_point representing immediately before USE_STMT.
447 Subroutine of ctor. */
449 function_point
450 state_purge_per_ssa_name::before_use_stmt (const state_purge_map &map,
451 const gimple *use_stmt)
453 gcc_assert (use_stmt->code != GIMPLE_PHI);
455 const supernode *supernode
456 = map.get_sg ().get_supernode_for_stmt (use_stmt);
457 unsigned int stmt_idx = supernode->get_stmt_index (use_stmt);
458 return function_point::before_stmt (supernode, stmt_idx);
461 /* Add POINT to *WORKLIST if the point has not already been seen.
462 Subroutine of ctor. */
464 void
465 state_purge_per_ssa_name::add_to_worklist (const function_point &point,
466 auto_vec<function_point> *worklist,
467 logger *logger)
469 LOG_FUNC (logger);
470 if (logger)
472 logger->start_log_line ();
473 logger->log_partial ("point: '");
474 point.print (logger->get_printer (), format (false));
475 logger->log_partial ("' for worklist for %qE", m_name);
476 logger->end_log_line ();
479 gcc_assert (point.get_function () == &get_function ());
480 if (point.get_from_edge ())
481 gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
483 if (m_points_needing_name.contains (point))
485 if (logger)
486 logger->log ("already seen for %qE", m_name);
488 else
490 if (logger)
491 logger->log ("not seen; adding to worklist for %qE", m_name);
492 m_points_needing_name.add (point);
493 worklist->safe_push (point);
497 /* Return true iff NAME is used by any of the phi nodes in SNODE
498 when processing the in-edge with PHI_ARG_IDX. */
500 static bool
501 name_used_by_phis_p (tree name, const supernode *snode,
502 size_t phi_arg_idx)
504 gcc_assert (TREE_CODE (name) == SSA_NAME);
506 for (gphi_iterator gpi
507 = const_cast<supernode *> (snode)->start_phis ();
508 !gsi_end_p (gpi); gsi_next (&gpi))
510 gphi *phi = gpi.phi ();
511 if (gimple_phi_arg_def (phi, phi_arg_idx) == name)
512 return true;
514 return false;
517 /* Process POINT, popped from WORKLIST.
518 Iterate over predecessors of POINT, adding to WORKLIST. */
520 void
521 state_purge_per_ssa_name::process_point (const function_point &point,
522 auto_vec<function_point> *worklist,
523 const state_purge_map &map)
525 logger *logger = map.get_logger ();
526 LOG_FUNC (logger);
527 if (logger)
529 logger->start_log_line ();
530 logger->log_partial ("considering point: '");
531 point.print (logger->get_printer (), format (false));
532 logger->log_partial ("' for %qE", m_name);
533 logger->end_log_line ();
536 gimple *def_stmt = SSA_NAME_DEF_STMT (m_name);
538 const supernode *snode = point.get_supernode ();
540 switch (point.get_kind ())
542 default:
543 gcc_unreachable ();
545 case PK_ORIGIN:
546 break;
548 case PK_BEFORE_SUPERNODE:
550 for (gphi_iterator gpi
551 = const_cast<supernode *> (snode)->start_phis ();
552 !gsi_end_p (gpi); gsi_next (&gpi))
554 gcc_assert (point.get_from_edge ());
555 const cfg_superedge *cfg_sedge
556 = point.get_from_edge ()->dyn_cast_cfg_superedge ();
557 gcc_assert (cfg_sedge);
559 gphi *phi = gpi.phi ();
560 /* Are we at the def-stmt for m_name? */
561 if (phi == def_stmt)
563 if (name_used_by_phis_p (m_name, snode,
564 cfg_sedge->get_phi_arg_idx ()))
566 if (logger)
567 logger->log ("name in def stmt used within phis;"
568 " continuing");
570 else
572 if (logger)
573 logger->log ("name in def stmt not used within phis;"
574 " terminating");
575 return;
580 /* Add given pred to worklist. */
581 if (point.get_from_edge ())
583 gcc_assert (point.get_from_edge ()->m_src);
584 add_to_worklist
585 (function_point::after_supernode (point.get_from_edge ()->m_src),
586 worklist, logger);
588 else
590 /* Add any intraprocedually edge for a call. */
591 if (snode->m_returning_call)
593 gcall *returning_call = snode->m_returning_call;
594 cgraph_edge *cedge
595 = supergraph_call_edge (snode->m_fun,
596 returning_call);
597 if(cedge)
599 superedge *sedge
600 = map.get_sg ().get_intraprocedural_edge_for_call (cedge);
601 gcc_assert (sedge);
602 add_to_worklist
603 (function_point::after_supernode (sedge->m_src),
604 worklist, logger);
606 else
608 supernode *callernode
609 = map.get_sg ().get_supernode_for_stmt (returning_call);
611 gcc_assert (callernode);
612 add_to_worklist
613 (function_point::after_supernode (callernode),
614 worklist, logger);
619 break;
621 case PK_BEFORE_STMT:
623 if (def_stmt == point.get_stmt ())
625 if (logger)
626 logger->log ("def stmt; terminating");
627 return;
629 if (point.get_stmt_idx () > 0)
630 add_to_worklist (function_point::before_stmt
631 (snode, point.get_stmt_idx () - 1),
632 worklist, logger);
633 else
635 /* Add before_supernode to worklist. This captures the in-edge,
636 so we have to do it once per in-edge. */
637 unsigned i;
638 superedge *pred;
639 FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
640 add_to_worklist (function_point::before_supernode (snode,
641 pred),
642 worklist, logger);
645 break;
647 case PK_AFTER_SUPERNODE:
649 if (snode->m_stmts.length ())
650 add_to_worklist
651 (function_point::before_stmt (snode,
652 snode->m_stmts.length () - 1),
653 worklist, logger);
654 else
656 /* Add before_supernode to worklist. This captures the in-edge,
657 so we have to do it once per in-edge. */
658 unsigned i;
659 superedge *pred;
660 FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
661 add_to_worklist (function_point::before_supernode (snode,
662 pred),
663 worklist, logger);
664 /* If it's the initial BB, add it, to ensure that we
665 have "before supernode" for the initial ENTRY block, and don't
666 erroneously purge SSA names for initial values of parameters. */
667 if (snode->entry_p ())
669 add_to_worklist
670 (function_point::before_supernode (snode, NULL),
671 worklist, logger);
675 break;
679 /* class state_purge_per_decl : public state_purge_per_tree. */
681 /* state_purge_per_decl's ctor. */
683 state_purge_per_decl::state_purge_per_decl (const state_purge_map &map,
684 tree decl,
685 const function &fun)
686 : state_purge_per_tree (fun),
687 m_decl (decl)
689 /* The RESULT_DECL is always needed at the end of its function. */
690 if (TREE_CODE (decl) == RESULT_DECL)
692 supernode *exit_snode = map.get_sg ().get_node_for_function_exit (fun);
693 add_needed_at (function_point::after_supernode (exit_snode));
697 /* Mark the value of the decl (or a subvalue within it) as being needed
698 at POINT. */
700 void
701 state_purge_per_decl::add_needed_at (const function_point &point)
703 m_points_needing_decl.add (point);
706 /* Mark that a pointer to the decl (or a region within it) is taken
707 at POINT. */
709 void
710 state_purge_per_decl::add_pointed_to_at (const function_point &point)
712 m_points_taking_address.add (point);
715 /* Process the worklists for this decl:
716 (a) walk backwards from points where we know the value of the decl
717 is needed, marking points until we get to a stmt that fully overwrites
718 the decl.
719 (b) walk forwards from points where the address of the decl is taken,
720 marking points as potentially needing the value of the decl. */
722 void
723 state_purge_per_decl::process_worklists (const state_purge_map &map,
724 region_model_manager *mgr)
726 logger *logger = map.get_logger ();
727 LOG_SCOPE (logger);
728 if (logger)
729 logger->log ("decl: %qE within %qD", m_decl, get_fndecl ());
731 /* Worklist for walking backwards from uses. */
733 auto_vec<function_point> worklist;
734 point_set_t seen;
736 /* Add all uses of the decl to the worklist. */
737 for (auto iter : m_points_needing_decl)
738 worklist.safe_push (iter);
740 region_model model (mgr);
741 model.push_frame (get_function (), NULL, NULL);
743 /* Process worklist by walking backwards until we reach a stmt
744 that fully overwrites the decl. */
746 log_scope s (logger, "processing worklist");
747 while (worklist.length () > 0)
749 function_point point = worklist.pop ();
750 process_point_backwards (point, &worklist, &seen, map, model);
755 /* Worklist for walking forwards from address-taken points. */
757 auto_vec<function_point> worklist;
758 point_set_t seen;
760 /* Add all uses of the decl to the worklist. */
761 for (auto iter : m_points_taking_address)
763 worklist.safe_push (iter);
765 /* Add to m_points_needing_decl (now that we traversed
766 it above for the backward worklist). */
767 m_points_needing_decl.add (iter);
770 /* Process worklist by walking forwards. */
772 log_scope s (logger, "processing worklist");
773 while (worklist.length () > 0)
775 function_point point = worklist.pop ();
776 process_point_forwards (point, &worklist, &seen, map);
782 /* Add POINT to *WORKLIST if the point is not already in *seen.
783 Add newly seen points to *SEEN and to m_points_needing_name. */
785 void
786 state_purge_per_decl::add_to_worklist (const function_point &point,
787 auto_vec<function_point> *worklist,
788 point_set_t *seen,
789 logger *logger)
791 LOG_FUNC (logger);
792 if (logger)
794 logger->start_log_line ();
795 logger->log_partial ("point: '");
796 point.print (logger->get_printer (), format (false));
797 logger->log_partial ("' for worklist for %qE", m_decl);
798 logger->end_log_line ();
801 gcc_assert (point.get_function () == &get_function ());
802 if (point.get_from_edge ())
803 gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
805 if (seen->contains (point))
807 if (logger)
808 logger->log ("already seen for %qE", m_decl);
810 else
812 if (logger)
813 logger->log ("not seen; adding to worklist for %qE", m_decl);
814 m_points_needing_decl.add (point);
815 seen->add (point);
816 worklist->safe_push (point);
820 /* Determine if REG_A and REG_B express writing to exactly the same
821 set of bits.
822 For example, when "s.field" is the only field of "s", and there's no
823 padding, this should return true. */
825 static bool
826 same_binding_p (const region *reg_a, const region *reg_b,
827 store_manager *store_mgr)
829 if (reg_a->get_base_region () != reg_b->get_base_region ())
830 return false;
831 if (reg_a->empty_p ())
832 return false;
833 const binding_key *bind_key_a = binding_key::make (store_mgr, reg_a);
834 if (reg_b->empty_p ())
835 return false;
836 const binding_key *bind_key_b = binding_key::make (store_mgr, reg_b);
837 return bind_key_a == bind_key_b;
840 /* Return true if STMT fully overwrites DECL. */
842 static bool
843 fully_overwrites_p (const gimple *stmt, tree decl,
844 const region_model &model)
846 if (tree lhs = gimple_get_lhs (stmt))
848 /* Determine if LHS fully overwrites DECL.
849 We can't just check for equality; consider the case of
850 "s.field = EXPR;" where the stmt writes to the only field
851 of "s", and there's no padding. */
852 const region *lhs_reg = model.get_lvalue (lhs, NULL);
853 const region *decl_reg = model.get_lvalue (decl, NULL);
854 if (same_binding_p (lhs_reg, decl_reg,
855 model.get_manager ()->get_store_manager ()))
856 return true;
858 return false;
861 /* Process POINT, popped from *WORKLIST.
862 Iterate over predecessors of POINT, adding to *WORKLIST and *SEEN,
863 until we get to a stmt that fully overwrites the decl. */
865 void
866 state_purge_per_decl::
867 process_point_backwards (const function_point &point,
868 auto_vec<function_point> *worklist,
869 point_set_t *seen,
870 const state_purge_map &map,
871 const region_model &model)
873 logger *logger = map.get_logger ();
874 LOG_FUNC (logger);
875 if (logger)
877 logger->start_log_line ();
878 logger->log_partial ("considering point: '");
879 point.print (logger->get_printer (), format (false));
880 logger->log_partial ("' for %qE", m_decl);
881 logger->end_log_line ();
883 const supernode *snode = point.get_supernode ();
885 switch (point.get_kind ())
887 default:
888 gcc_unreachable ();
890 case PK_ORIGIN:
891 break;
893 case PK_BEFORE_SUPERNODE:
895 /* Add given pred to worklist. */
896 if (point.get_from_edge ())
898 gcc_assert (point.get_from_edge ()->m_src);
899 add_to_worklist
900 (function_point::after_supernode (point.get_from_edge ()->m_src),
901 worklist, seen, logger);
903 else
905 /* Add any intraprocedually edge for a call. */
906 if (snode->m_returning_call)
908 gcall *returning_call = snode->m_returning_call;
909 cgraph_edge *cedge
910 = supergraph_call_edge (snode->m_fun,
911 returning_call);
912 if(cedge)
914 superedge *sedge
915 = map.get_sg ().get_intraprocedural_edge_for_call (cedge);
916 gcc_assert (sedge);
917 add_to_worklist
918 (function_point::after_supernode (sedge->m_src),
919 worklist, seen, logger);
921 else
923 supernode *callernode
924 = map.get_sg ().get_supernode_for_stmt (returning_call);
926 gcc_assert (callernode);
927 add_to_worklist
928 (function_point::after_supernode (callernode),
929 worklist, seen, logger);
934 break;
936 case PK_BEFORE_STMT:
938 /* This is somewhat equivalent to how the SSA case handles
939 def-stmts. */
940 if (fully_overwrites_p (point.get_stmt (), m_decl, model)
941 /* ...but we mustn't be at a point that also consumes the
942 current value of the decl when it's generating the new
943 value, for cases such as
944 struct st s;
945 s = foo ();
946 s = bar (s);
947 where we want to make sure that we don't stop at the:
948 s = bar (s);
949 since otherwise we would erroneously purge the state of "s"
950 after:
951 s = foo ();
953 && !m_points_needing_decl.contains (point))
955 if (logger)
956 logger->log ("stmt fully overwrites %qE; terminating", m_decl);
957 return;
959 if (point.get_stmt_idx () > 0)
960 add_to_worklist (function_point::before_stmt
961 (snode, point.get_stmt_idx () - 1),
962 worklist, seen, logger);
963 else
965 /* Add before_supernode to worklist. This captures the in-edge,
966 so we have to do it once per in-edge. */
967 unsigned i;
968 superedge *pred;
969 FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
970 add_to_worklist (function_point::before_supernode (snode,
971 pred),
972 worklist, seen, logger);
975 break;
977 case PK_AFTER_SUPERNODE:
979 if (snode->m_stmts.length ())
980 add_to_worklist
981 (function_point::before_stmt (snode,
982 snode->m_stmts.length () - 1),
983 worklist, seen, logger);
984 else
986 /* Add before_supernode to worklist. This captures the in-edge,
987 so we have to do it once per in-edge. */
988 unsigned i;
989 superedge *pred;
990 FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
991 add_to_worklist (function_point::before_supernode (snode,
992 pred),
993 worklist, seen, logger);
996 break;
1001 /* Process POINT, popped from *WORKLIST.
1002 Iterate over successors of POINT, adding to *WORKLIST and *SEEN. */
1004 void
1005 state_purge_per_decl::
1006 process_point_forwards (const function_point &point,
1007 auto_vec<function_point> *worklist,
1008 point_set_t *seen,
1009 const state_purge_map &map)
1011 logger *logger = map.get_logger ();
1012 LOG_FUNC (logger);
1013 if (logger)
1015 logger->start_log_line ();
1016 logger->log_partial ("considering point: '");
1017 point.print (logger->get_printer (), format (false));
1018 logger->log_partial ("' for %qE", m_decl);
1019 logger->end_log_line ();
1021 const supernode *snode = point.get_supernode ();
1023 switch (point.get_kind ())
1025 default:
1026 case PK_ORIGIN:
1027 gcc_unreachable ();
1029 case PK_BEFORE_SUPERNODE:
1031 function_point next = point.get_next ();
1032 add_to_worklist (next, worklist, seen, logger);
1034 break;
1036 case PK_BEFORE_STMT:
1038 /* Perhaps we should stop at a clobber of the decl,
1039 but that ought to purge state for us explicitly. */
1040 function_point next = point.get_next ();
1041 add_to_worklist (next, worklist, seen, logger);
1043 break;
1045 case PK_AFTER_SUPERNODE:
1047 /* Look at interprocedural out-edges. */
1048 unsigned i;
1049 superedge *succ;
1050 FOR_EACH_VEC_ELT (snode->m_succs, i, succ)
1052 enum edge_kind kind = succ->get_kind ();
1053 if (kind == SUPEREDGE_CFG_EDGE
1054 || kind == SUPEREDGE_INTRAPROCEDURAL_CALL)
1055 add_to_worklist (function_point::before_supernode (succ->m_dest,
1056 succ),
1057 worklist, seen, logger);
1060 break;
1064 /* Return true if the decl is needed at POINT. */
1066 bool
1067 state_purge_per_decl::needed_at_point_p (const function_point &point) const
1069 return const_cast <point_set_t &> (m_points_needing_decl).contains (point);
1072 /* class state_purge_annotator : public dot_annotator. */
1074 /* Implementation of dot_annotator::add_node_annotations vfunc for
1075 state_purge_annotator.
1077 Add an additional record showing which names are purged on entry
1078 to the supernode N. */
1080 bool
1081 state_purge_annotator::add_node_annotations (graphviz_out *gv,
1082 const supernode &n,
1083 bool within_table) const
1085 if (m_map == NULL)
1086 return false;
1088 if (within_table)
1089 return false;
1091 pretty_printer *pp = gv->get_pp ();
1093 pp_printf (pp, "annotation_for_node_%i", n.m_index);
1094 pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
1095 "lightblue");
1096 pp_write_text_to_stream (pp);
1098 /* Different in-edges mean different names need purging.
1099 Determine which points to dump. */
1100 auto_vec<function_point> points;
1101 if (n.entry_p () || n.m_returning_call)
1102 points.safe_push (function_point::before_supernode (&n, NULL));
1103 else
1104 for (auto inedge : n.m_preds)
1105 points.safe_push (function_point::before_supernode (&n, inedge));
1106 points.safe_push (function_point::after_supernode (&n));
1108 for (auto & point : points)
1110 point.print (pp, format (true));
1111 pp_newline (pp);
1112 print_needed (gv, point, false);
1113 pp_newline (pp);
1116 pp_string (pp, "\"];\n\n");
1117 pp_flush (pp);
1118 return false;
1121 /* Print V to GV as a comma-separated list in braces, titling it with TITLE.
1122 If WITHIN_TABLE is true, print it within a <TR>
1124 Subroutine of state_purge_annotator::print_needed. */
1126 static void
1127 print_vec_of_names (graphviz_out *gv, const char *title,
1128 const auto_vec<tree> &v, bool within_table)
1130 pretty_printer *pp = gv->get_pp ();
1131 tree name;
1132 unsigned i;
1133 if (within_table)
1134 gv->begin_trtd ();
1135 pp_printf (pp, "%s: {", title);
1136 FOR_EACH_VEC_ELT (v, i, name)
1138 if (i > 0)
1139 pp_string (pp, ", ");
1140 pp_printf (pp, "%qE", name);
1142 pp_printf (pp, "}");
1143 if (within_table)
1145 pp_write_text_as_html_like_dot_to_stream (pp);
1146 gv->end_tdtr ();
1148 pp_newline (pp);
1151 /* Implementation of dot_annotator::add_stmt_annotations for
1152 state_purge_annotator.
1154 Add text showing which names are purged at STMT. */
1156 void
1157 state_purge_annotator::add_stmt_annotations (graphviz_out *gv,
1158 const gimple *stmt,
1159 bool within_row) const
1161 if (within_row)
1162 return;
1164 if (m_map == NULL)
1165 return;
1167 if (stmt->code == GIMPLE_PHI)
1168 return;
1170 pretty_printer *pp = gv->get_pp ();
1172 pp_newline (pp);
1174 const supernode *supernode = m_map->get_sg ().get_supernode_for_stmt (stmt);
1175 unsigned int stmt_idx = supernode->get_stmt_index (stmt);
1176 function_point before_stmt
1177 (function_point::before_stmt (supernode, stmt_idx));
1179 print_needed (gv, before_stmt, true);
1182 /* Get the decls and SSA names needed and not-needed at POINT, and
1183 print them to GV.
1184 If WITHIN_TABLE is true, print them within <TR> elements. */
1186 void
1187 state_purge_annotator::print_needed (graphviz_out *gv,
1188 const function_point &point,
1189 bool within_table) const
1191 auto_vec<tree> needed;
1192 auto_vec<tree> not_needed;
1193 for (state_purge_map::ssa_iterator iter = m_map->begin_ssas ();
1194 iter != m_map->end_ssas ();
1195 ++iter)
1197 tree name = (*iter).first;
1198 state_purge_per_ssa_name *per_name_data = (*iter).second;
1199 if (&per_name_data->get_function () == point.get_function ())
1201 if (per_name_data->needed_at_point_p (point))
1202 needed.safe_push (name);
1203 else
1204 not_needed.safe_push (name);
1207 for (state_purge_map::decl_iterator iter = m_map->begin_decls ();
1208 iter != m_map->end_decls ();
1209 ++iter)
1211 tree decl = (*iter).first;
1212 state_purge_per_decl *per_decl_data = (*iter).second;
1213 if (&per_decl_data->get_function () == point.get_function ())
1215 if (per_decl_data->needed_at_point_p (point))
1216 needed.safe_push (decl);
1217 else
1218 not_needed.safe_push (decl);
1222 print_vec_of_names (gv, "needed here", needed, within_table);
1223 print_vec_of_names (gv, "not needed here", not_needed, within_table);
1226 #endif /* #if ENABLE_ANALYZER */