Require target lra in gcc.dg/pr108095.c
[official-gcc.git] / gcc / analyzer / state-purge.cc
blob3a73146d928b1ab775934e91842b102367747dd8
1 /* Classes for purging state at function_points.
2 Copyright (C) 2019-2023 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 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "timevar.h"
27 #include "tree-ssa-alias.h"
28 #include "function.h"
29 #include "basic-block.h"
30 #include "gimple.h"
31 #include "stringpool.h"
32 #include "tree-vrp.h"
33 #include "gimple-ssa.h"
34 #include "tree-ssanames.h"
35 #include "tree-phinodes.h"
36 #include "options.h"
37 #include "ssa-iterators.h"
38 #include "diagnostic-core.h"
39 #include "gimple-pretty-print.h"
40 #include "analyzer/analyzer.h"
41 #include "analyzer/call-string.h"
42 #include "analyzer/supergraph.h"
43 #include "analyzer/program-point.h"
44 #include "analyzer/analyzer-logging.h"
45 #include "analyzer/state-purge.h"
46 #include "analyzer/store.h"
47 #include "analyzer/region-model.h"
48 #include "gimple-walk.h"
49 #include "cgraph.h"
51 #if ENABLE_ANALYZER
53 /* Given NODE at an access, determine if this access is within
54 a decl that could be consider for purging, and if so, return the decl. */
56 static tree
57 get_candidate_for_purging (tree node)
59 tree iter = node;
60 while (1)
61 switch (TREE_CODE (iter))
63 default:
64 return NULL_TREE;
66 case ADDR_EXPR:
67 case MEM_REF:
68 case COMPONENT_REF:
69 iter = TREE_OPERAND (iter, 0);
70 continue;
72 case VAR_DECL:
73 if (is_global_var (iter))
74 return NULL_TREE;
75 else
76 return iter;
78 case PARM_DECL:
79 case RESULT_DECL:
80 return iter;
84 /* Class-based handler for walk_stmt_load_store_addr_ops at a particular
85 function_point, for populating the worklists within a state_purge_map. */
87 class gimple_op_visitor : public log_user
89 public:
90 gimple_op_visitor (state_purge_map *map,
91 const function_point &point,
92 function *fun)
93 : log_user (map->get_logger ()),
94 m_map (map),
95 m_point (point),
96 m_fun (fun)
99 bool on_load (gimple *stmt, tree base, tree op)
101 LOG_FUNC (get_logger ());
102 if (get_logger ())
104 pretty_printer pp;
105 pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
106 log ("on_load: %s; base: %qE, op: %qE",
107 pp_formatted_text (&pp), base, op);
109 if (tree node = get_candidate_for_purging (base))
110 add_needed (node);
111 return true;
114 bool on_store (gimple *stmt, tree base, tree op)
116 LOG_FUNC (get_logger ());
117 if (get_logger ())
119 pretty_printer pp;
120 pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
121 log ("on_store: %s; base: %qE, op: %qE",
122 pp_formatted_text (&pp), base, op);
124 return true;
127 bool on_addr (gimple *stmt, tree base, tree op)
129 LOG_FUNC (get_logger ());
130 if (get_logger ())
132 pretty_printer pp;
133 pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
134 log ("on_addr: %s; base: %qE, op: %qE",
135 pp_formatted_text (&pp), base, op);
137 if (TREE_CODE (op) != ADDR_EXPR)
138 return true;
139 if (tree node = get_candidate_for_purging (base))
141 add_needed (node);
142 add_pointed_to (node);
144 return true;
147 private:
148 void add_needed (tree decl)
150 gcc_assert (get_candidate_for_purging (decl) == decl);
151 state_purge_per_decl &data
152 = get_or_create_data_for_decl (decl);
153 data.add_needed_at (m_point);
155 /* Handle calls: if we're seeing a use at a call, then add a use at the
156 "after-supernode" point (in case of interprocedural call superedges). */
157 if (m_point.final_stmt_p ())
158 data.add_needed_at (m_point.get_next ());
161 void add_pointed_to (tree decl)
163 gcc_assert (get_candidate_for_purging (decl) == decl);
164 get_or_create_data_for_decl (decl).add_pointed_to_at (m_point);
167 state_purge_per_decl &
168 get_or_create_data_for_decl (tree decl)
170 return m_map->get_or_create_data_for_decl (m_fun, decl);
173 state_purge_map *m_map;
174 const function_point &m_point;
175 function *m_fun;
178 static bool
179 my_load_cb (gimple *stmt, tree base, tree op, void *user_data)
181 gimple_op_visitor *x = (gimple_op_visitor *)user_data;
182 return x->on_load (stmt, base, op);
185 static bool
186 my_store_cb (gimple *stmt, tree base, tree op, void *user_data)
188 gimple_op_visitor *x = (gimple_op_visitor *)user_data;
189 return x->on_store (stmt, base, op);
192 static bool
193 my_addr_cb (gimple *stmt, tree base, tree op, void *user_data)
195 gimple_op_visitor *x = (gimple_op_visitor *)user_data;
196 return x->on_addr (stmt, base, op);
199 /* state_purge_map's ctor. Walk all SSA names in all functions, building
200 a state_purge_per_ssa_name instance for each.
201 Also, walk all loads and address-taken ops of local variables, building
202 a state_purge_per_decl as appropriate. */
204 state_purge_map::state_purge_map (const supergraph &sg,
205 region_model_manager *mgr,
206 logger *logger)
207 : log_user (logger), m_sg (sg)
209 LOG_FUNC (logger);
211 auto_timevar tv (TV_ANALYZER_STATE_PURGE);
213 cgraph_node *node;
214 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
216 function *fun = node->get_fun ();
217 if (logger)
218 log ("function: %s", function_name (fun));
219 tree name;
220 unsigned int i;;
221 FOR_EACH_SSA_NAME (i, name, fun)
223 /* For now, don't bother tracking the .MEM SSA names. */
224 if (tree var = SSA_NAME_VAR (name))
225 if (TREE_CODE (var) == VAR_DECL)
226 if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
227 continue;
228 m_ssa_map.put (name, new state_purge_per_ssa_name (*this, name, fun));
232 /* Find all uses of local vars.
233 We iterate through all function points, finding loads, stores, and
234 address-taken operations on locals, building a pair of worklists. */
235 for (auto snode : sg.m_nodes)
237 if (logger)
238 log ("SN: %i", snode->m_index);
239 /* We ignore m_returning_call and phi nodes. */
240 gimple *stmt;
241 unsigned i;
242 FOR_EACH_VEC_ELT (snode->m_stmts, i, stmt)
244 function_point point (function_point::before_stmt (snode, i));
245 gimple_op_visitor v (this, point, snode->get_function ());
246 walk_stmt_load_store_addr_ops (stmt, &v,
247 my_load_cb, my_store_cb, my_addr_cb);
251 /* Now iterate through the m_decl_map, processing each pair of worklists. */
252 for (state_purge_map::decl_iterator iter = begin_decls ();
253 iter != end_decls ();
254 ++iter)
256 state_purge_per_decl *per_decl_data = (*iter).second;
257 per_decl_data->process_worklists (*this, mgr);
261 /* state_purge_map's dtor. */
263 state_purge_map::~state_purge_map ()
265 for (auto iter : m_ssa_map)
266 delete iter.second;
267 for (auto iter : m_decl_map)
268 delete iter.second;
271 /* Get the state_purge_per_decl for local DECL within FUN, creating it
272 if necessary. */
274 state_purge_per_decl &
275 state_purge_map::get_or_create_data_for_decl (function *fun, tree decl)
277 if (state_purge_per_decl **slot
278 = const_cast <decl_map_t&> (m_decl_map).get (decl))
279 return **slot;
280 state_purge_per_decl *result = new state_purge_per_decl (*this, decl, fun);
281 m_decl_map.put (decl, result);
282 return *result;
285 /* class state_purge_per_ssa_name : public state_purge_per_tree. */
287 /* state_purge_per_ssa_name's ctor.
289 Locate all uses of VAR within FUN.
290 Walk backwards from each use, marking program points, until
291 we reach the def stmt, populating m_points_needing_var.
293 We have to track program points rather than
294 just stmts since there could be empty basic blocks on the way. */
296 state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
297 tree name,
298 function *fun)
299 : state_purge_per_tree (fun), m_points_needing_name (), m_name (name)
301 LOG_FUNC (map.get_logger ());
303 if (map.get_logger ())
305 map.log ("SSA name: %qE within %qD", name, fun->decl);
307 /* Show def stmt. */
308 const gimple *def_stmt = SSA_NAME_DEF_STMT (name);
309 pretty_printer pp;
310 pp_gimple_stmt_1 (&pp, def_stmt, 0, (dump_flags_t)0);
311 map.log ("def stmt: %s", pp_formatted_text (&pp));
314 auto_vec<function_point> worklist;
316 /* Add all immediate uses of name to the worklist.
317 Compare with debug_immediate_uses. */
318 imm_use_iterator iter;
319 use_operand_p use_p;
320 FOR_EACH_IMM_USE_FAST (use_p, iter, name)
322 if (USE_STMT (use_p))
324 const gimple *use_stmt = USE_STMT (use_p);
325 if (map.get_logger ())
327 pretty_printer pp;
328 pp_gimple_stmt_1 (&pp, use_stmt, 0, (dump_flags_t)0);
329 map.log ("used by stmt: %s", pp_formatted_text (&pp));
332 const supernode *snode
333 = map.get_sg ().get_supernode_for_stmt (use_stmt);
335 /* If it's a use within a phi node, then we care about
336 which in-edge we came from. */
337 if (use_stmt->code == GIMPLE_PHI)
339 for (gphi_iterator gpi
340 = const_cast<supernode *> (snode)->start_phis ();
341 !gsi_end_p (gpi); gsi_next (&gpi))
343 gphi *phi = gpi.phi ();
344 if (phi == use_stmt)
346 /* Find arguments (and thus in-edges) which use NAME. */
347 for (unsigned arg_idx = 0;
348 arg_idx < gimple_phi_num_args (phi);
349 ++arg_idx)
351 if (name == gimple_phi_arg (phi, arg_idx)->def)
353 edge in_edge = gimple_phi_arg_edge (phi, arg_idx);
354 const superedge *in_sedge
355 = map.get_sg ().get_edge_for_cfg_edge (in_edge);
356 function_point point
357 = function_point::before_supernode
358 (snode, in_sedge);
359 add_to_worklist (point, &worklist,
360 map.get_logger ());
361 m_points_needing_name.add (point);
367 else
369 function_point point = before_use_stmt (map, use_stmt);
370 add_to_worklist (point, &worklist, map.get_logger ());
371 m_points_needing_name.add (point);
373 /* We also need to add uses for conditionals and switches,
374 where the stmt "happens" at the after_supernode, for filtering
375 the out-edges. */
376 if (use_stmt == snode->get_last_stmt ())
378 if (map.get_logger ())
379 map.log ("last stmt in BB");
380 function_point point
381 = function_point::after_supernode (snode);
382 add_to_worklist (point, &worklist, map.get_logger ());
383 m_points_needing_name.add (point);
385 else
386 if (map.get_logger ())
387 map.log ("not last stmt in BB");
392 /* Process worklist by walking backwards until we reach the def stmt. */
394 log_scope s (map.get_logger (), "processing worklist");
395 while (worklist.length () > 0)
397 function_point point = worklist.pop ();
398 process_point (point, &worklist, map);
402 if (map.get_logger ())
404 map.log ("%qE in %qD is needed to process:", name, fun->decl);
405 /* Log m_points_needing_name, sorting it to avoid churn when comparing
406 dumps. */
407 auto_vec<function_point> points;
408 for (point_set_t::iterator iter = m_points_needing_name.begin ();
409 iter != m_points_needing_name.end ();
410 ++iter)
411 points.safe_push (*iter);
412 points.qsort (function_point::cmp_ptr);
413 unsigned i;
414 function_point *point;
415 FOR_EACH_VEC_ELT (points, i, point)
417 map.start_log_line ();
418 map.get_logger ()->log_partial (" point: ");
419 point->print (map.get_logger ()->get_printer (), format (false));
420 map.end_log_line ();
425 /* Return true if the SSA name is needed at POINT. */
427 bool
428 state_purge_per_ssa_name::needed_at_point_p (const function_point &point) const
430 return const_cast <point_set_t &> (m_points_needing_name).contains (point);
433 /* Get the function_point representing immediately before USE_STMT.
434 Subroutine of ctor. */
436 function_point
437 state_purge_per_ssa_name::before_use_stmt (const state_purge_map &map,
438 const gimple *use_stmt)
440 gcc_assert (use_stmt->code != GIMPLE_PHI);
442 const supernode *supernode
443 = map.get_sg ().get_supernode_for_stmt (use_stmt);
444 unsigned int stmt_idx = supernode->get_stmt_index (use_stmt);
445 return function_point::before_stmt (supernode, stmt_idx);
448 /* Add POINT to *WORKLIST if the point has not already been seen.
449 Subroutine of ctor. */
451 void
452 state_purge_per_ssa_name::add_to_worklist (const function_point &point,
453 auto_vec<function_point> *worklist,
454 logger *logger)
456 LOG_FUNC (logger);
457 if (logger)
459 logger->start_log_line ();
460 logger->log_partial ("point: '");
461 point.print (logger->get_printer (), format (false));
462 logger->log_partial ("' for worklist for %qE", m_name);
463 logger->end_log_line ();
466 gcc_assert (point.get_function () == get_function ());
467 if (point.get_from_edge ())
468 gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
470 if (m_points_needing_name.contains (point))
472 if (logger)
473 logger->log ("already seen for %qE", m_name);
475 else
477 if (logger)
478 logger->log ("not seen; adding to worklist for %qE", m_name);
479 m_points_needing_name.add (point);
480 worklist->safe_push (point);
484 /* Return true iff NAME is used by any of the phi nodes in SNODE
485 when processing the in-edge with PHI_ARG_IDX. */
487 static bool
488 name_used_by_phis_p (tree name, const supernode *snode,
489 size_t phi_arg_idx)
491 gcc_assert (TREE_CODE (name) == SSA_NAME);
493 for (gphi_iterator gpi
494 = const_cast<supernode *> (snode)->start_phis ();
495 !gsi_end_p (gpi); gsi_next (&gpi))
497 gphi *phi = gpi.phi ();
498 if (gimple_phi_arg_def (phi, phi_arg_idx) == name)
499 return true;
501 return false;
504 /* Process POINT, popped from WORKLIST.
505 Iterate over predecessors of POINT, adding to WORKLIST. */
507 void
508 state_purge_per_ssa_name::process_point (const function_point &point,
509 auto_vec<function_point> *worklist,
510 const state_purge_map &map)
512 logger *logger = map.get_logger ();
513 LOG_FUNC (logger);
514 if (logger)
516 logger->start_log_line ();
517 logger->log_partial ("considering point: '");
518 point.print (logger->get_printer (), format (false));
519 logger->log_partial ("' for %qE", m_name);
520 logger->end_log_line ();
523 gimple *def_stmt = SSA_NAME_DEF_STMT (m_name);
525 const supernode *snode = point.get_supernode ();
527 switch (point.get_kind ())
529 default:
530 gcc_unreachable ();
532 case PK_ORIGIN:
533 break;
535 case PK_BEFORE_SUPERNODE:
537 for (gphi_iterator gpi
538 = const_cast<supernode *> (snode)->start_phis ();
539 !gsi_end_p (gpi); gsi_next (&gpi))
541 gcc_assert (point.get_from_edge ());
542 const cfg_superedge *cfg_sedge
543 = point.get_from_edge ()->dyn_cast_cfg_superedge ();
544 gcc_assert (cfg_sedge);
546 gphi *phi = gpi.phi ();
547 /* Are we at the def-stmt for m_name? */
548 if (phi == def_stmt)
550 if (name_used_by_phis_p (m_name, snode,
551 cfg_sedge->get_phi_arg_idx ()))
553 if (logger)
554 logger->log ("name in def stmt used within phis;"
555 " continuing");
557 else
559 if (logger)
560 logger->log ("name in def stmt not used within phis;"
561 " terminating");
562 return;
567 /* Add given pred to worklist. */
568 if (point.get_from_edge ())
570 gcc_assert (point.get_from_edge ()->m_src);
571 add_to_worklist
572 (function_point::after_supernode (point.get_from_edge ()->m_src),
573 worklist, logger);
575 else
577 /* Add any intraprocedually edge for a call. */
578 if (snode->m_returning_call)
580 gcall *returning_call = snode->m_returning_call;
581 cgraph_edge *cedge
582 = supergraph_call_edge (snode->m_fun,
583 returning_call);
584 if(cedge)
586 superedge *sedge
587 = map.get_sg ().get_intraprocedural_edge_for_call (cedge);
588 gcc_assert (sedge);
589 add_to_worklist
590 (function_point::after_supernode (sedge->m_src),
591 worklist, logger);
593 else
595 supernode *callernode
596 = map.get_sg ().get_supernode_for_stmt (returning_call);
598 gcc_assert (callernode);
599 add_to_worklist
600 (function_point::after_supernode (callernode),
601 worklist, logger);
606 break;
608 case PK_BEFORE_STMT:
610 if (def_stmt == point.get_stmt ())
612 if (logger)
613 logger->log ("def stmt; terminating");
614 return;
616 if (point.get_stmt_idx () > 0)
617 add_to_worklist (function_point::before_stmt
618 (snode, point.get_stmt_idx () - 1),
619 worklist, logger);
620 else
622 /* Add before_supernode to worklist. This captures the in-edge,
623 so we have to do it once per in-edge. */
624 unsigned i;
625 superedge *pred;
626 FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
627 add_to_worklist (function_point::before_supernode (snode,
628 pred),
629 worklist, logger);
632 break;
634 case PK_AFTER_SUPERNODE:
636 if (snode->m_stmts.length ())
637 add_to_worklist
638 (function_point::before_stmt (snode,
639 snode->m_stmts.length () - 1),
640 worklist, logger);
641 else
643 /* Add before_supernode to worklist. This captures the in-edge,
644 so we have to do it once per in-edge. */
645 unsigned i;
646 superedge *pred;
647 FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
648 add_to_worklist (function_point::before_supernode (snode,
649 pred),
650 worklist, logger);
651 /* If it's the initial BB, add it, to ensure that we
652 have "before supernode" for the initial ENTRY block, and don't
653 erroneously purge SSA names for initial values of parameters. */
654 if (snode->entry_p ())
656 add_to_worklist
657 (function_point::before_supernode (snode, NULL),
658 worklist, logger);
662 break;
666 /* class state_purge_per_decl : public state_purge_per_tree. */
668 /* state_purge_per_decl's ctor. */
670 state_purge_per_decl::state_purge_per_decl (const state_purge_map &map,
671 tree decl,
672 function *fun)
673 : state_purge_per_tree (fun),
674 m_decl (decl)
676 /* The RESULT_DECL is always needed at the end of its function. */
677 if (TREE_CODE (decl) == RESULT_DECL)
679 supernode *exit_snode = map.get_sg ().get_node_for_function_exit (fun);
680 add_needed_at (function_point::after_supernode (exit_snode));
684 /* Mark the value of the decl (or a subvalue within it) as being needed
685 at POINT. */
687 void
688 state_purge_per_decl::add_needed_at (const function_point &point)
690 m_points_needing_decl.add (point);
693 /* Mark that a pointer to the decl (or a region within it) is taken
694 at POINT. */
696 void
697 state_purge_per_decl::add_pointed_to_at (const function_point &point)
699 m_points_taking_address.add (point);
702 /* Process the worklists for this decl:
703 (a) walk backwards from points where we know the value of the decl
704 is needed, marking points until we get to a stmt that fully overwrites
705 the decl.
706 (b) walk forwards from points where the address of the decl is taken,
707 marking points as potentially needing the value of the decl. */
709 void
710 state_purge_per_decl::process_worklists (const state_purge_map &map,
711 region_model_manager *mgr)
713 logger *logger = map.get_logger ();
714 LOG_SCOPE (logger);
715 if (logger)
716 logger->log ("decl: %qE within %qD", m_decl, get_fndecl ());
718 /* Worklist for walking backwards from uses. */
720 auto_vec<function_point> worklist;
721 point_set_t seen;
723 /* Add all uses of the decl to the worklist. */
724 for (auto iter : m_points_needing_decl)
725 worklist.safe_push (iter);
727 region_model model (mgr);
728 model.push_frame (get_function (), NULL, NULL);
730 /* Process worklist by walking backwards until we reach a stmt
731 that fully overwrites the decl. */
733 log_scope s (logger, "processing worklist");
734 while (worklist.length () > 0)
736 function_point point = worklist.pop ();
737 process_point_backwards (point, &worklist, &seen, map, model);
742 /* Worklist for walking forwards from address-taken points. */
744 auto_vec<function_point> worklist;
745 point_set_t seen;
747 /* Add all uses of the decl to the worklist. */
748 for (auto iter : m_points_taking_address)
750 worklist.safe_push (iter);
752 /* Add to m_points_needing_decl (now that we traversed
753 it above for the backward worklist). */
754 m_points_needing_decl.add (iter);
757 /* Process worklist by walking forwards. */
759 log_scope s (logger, "processing worklist");
760 while (worklist.length () > 0)
762 function_point point = worklist.pop ();
763 process_point_forwards (point, &worklist, &seen, map);
769 /* Add POINT to *WORKLIST if the point is not already in *seen.
770 Add newly seen points to *SEEN and to m_points_needing_name. */
772 void
773 state_purge_per_decl::add_to_worklist (const function_point &point,
774 auto_vec<function_point> *worklist,
775 point_set_t *seen,
776 logger *logger)
778 LOG_FUNC (logger);
779 if (logger)
781 logger->start_log_line ();
782 logger->log_partial ("point: '");
783 point.print (logger->get_printer (), format (false));
784 logger->log_partial ("' for worklist for %qE", m_decl);
785 logger->end_log_line ();
788 gcc_assert (point.get_function () == get_function ());
789 if (point.get_from_edge ())
790 gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
792 if (seen->contains (point))
794 if (logger)
795 logger->log ("already seen for %qE", m_decl);
797 else
799 if (logger)
800 logger->log ("not seen; adding to worklist for %qE", m_decl);
801 m_points_needing_decl.add (point);
802 seen->add (point);
803 worklist->safe_push (point);
807 /* Determine if REG_A and REG_B express writing to exactly the same
808 set of bits.
809 For example, when "s.field" is the only field of "s", and there's no
810 padding, this should return true. */
812 static bool
813 same_binding_p (const region *reg_a, const region *reg_b,
814 store_manager *store_mgr)
816 if (reg_a->get_base_region () != reg_b->get_base_region ())
817 return false;
818 if (reg_a->empty_p ())
819 return false;
820 const binding_key *bind_key_a = binding_key::make (store_mgr, reg_a);
821 if (reg_b->empty_p ())
822 return false;
823 const binding_key *bind_key_b = binding_key::make (store_mgr, reg_b);
824 return bind_key_a == bind_key_b;
827 /* Return true if STMT fully overwrites DECL. */
829 static bool
830 fully_overwrites_p (const gimple *stmt, tree decl,
831 const region_model &model)
833 if (tree lhs = gimple_get_lhs (stmt))
835 /* Determine if LHS fully overwrites DECL.
836 We can't just check for equality; consider the case of
837 "s.field = EXPR;" where the stmt writes to the only field
838 of "s", and there's no padding. */
839 const region *lhs_reg = model.get_lvalue (lhs, NULL);
840 const region *decl_reg = model.get_lvalue (decl, NULL);
841 if (same_binding_p (lhs_reg, decl_reg,
842 model.get_manager ()->get_store_manager ()))
843 return true;
845 return false;
848 /* Process POINT, popped from *WORKLIST.
849 Iterate over predecessors of POINT, adding to *WORKLIST and *SEEN,
850 until we get to a stmt that fully overwrites the decl. */
852 void
853 state_purge_per_decl::
854 process_point_backwards (const function_point &point,
855 auto_vec<function_point> *worklist,
856 point_set_t *seen,
857 const state_purge_map &map,
858 const region_model &model)
860 logger *logger = map.get_logger ();
861 LOG_FUNC (logger);
862 if (logger)
864 logger->start_log_line ();
865 logger->log_partial ("considering point: '");
866 point.print (logger->get_printer (), format (false));
867 logger->log_partial ("' for %qE", m_decl);
868 logger->end_log_line ();
870 const supernode *snode = point.get_supernode ();
872 switch (point.get_kind ())
874 default:
875 gcc_unreachable ();
877 case PK_ORIGIN:
878 break;
880 case PK_BEFORE_SUPERNODE:
882 /* Add given pred to worklist. */
883 if (point.get_from_edge ())
885 gcc_assert (point.get_from_edge ()->m_src);
886 add_to_worklist
887 (function_point::after_supernode (point.get_from_edge ()->m_src),
888 worklist, seen, logger);
890 else
892 /* Add any intraprocedually edge for a call. */
893 if (snode->m_returning_call)
895 gcall *returning_call = snode->m_returning_call;
896 cgraph_edge *cedge
897 = supergraph_call_edge (snode->m_fun,
898 returning_call);
899 if(cedge)
901 superedge *sedge
902 = map.get_sg ().get_intraprocedural_edge_for_call (cedge);
903 gcc_assert (sedge);
904 add_to_worklist
905 (function_point::after_supernode (sedge->m_src),
906 worklist, seen, logger);
908 else
910 supernode *callernode
911 = map.get_sg ().get_supernode_for_stmt (returning_call);
913 gcc_assert (callernode);
914 add_to_worklist
915 (function_point::after_supernode (callernode),
916 worklist, seen, logger);
921 break;
923 case PK_BEFORE_STMT:
925 /* This is somewhat equivalent to how the SSA case handles
926 def-stmts. */
927 if (fully_overwrites_p (point.get_stmt (), m_decl, model)
928 /* ...but we mustn't be at a point that also consumes the
929 current value of the decl when it's generating the new
930 value, for cases such as
931 struct st s;
932 s = foo ();
933 s = bar (s);
934 where we want to make sure that we don't stop at the:
935 s = bar (s);
936 since otherwise we would erroneously purge the state of "s"
937 after:
938 s = foo ();
940 && !m_points_needing_decl.contains (point))
942 if (logger)
943 logger->log ("stmt fully overwrites %qE; terminating", m_decl);
944 return;
946 if (point.get_stmt_idx () > 0)
947 add_to_worklist (function_point::before_stmt
948 (snode, point.get_stmt_idx () - 1),
949 worklist, seen, logger);
950 else
952 /* Add before_supernode to worklist. This captures the in-edge,
953 so we have to do it once per in-edge. */
954 unsigned i;
955 superedge *pred;
956 FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
957 add_to_worklist (function_point::before_supernode (snode,
958 pred),
959 worklist, seen, logger);
962 break;
964 case PK_AFTER_SUPERNODE:
966 if (snode->m_stmts.length ())
967 add_to_worklist
968 (function_point::before_stmt (snode,
969 snode->m_stmts.length () - 1),
970 worklist, seen, logger);
971 else
973 /* Add before_supernode to worklist. This captures the in-edge,
974 so we have to do it once per in-edge. */
975 unsigned i;
976 superedge *pred;
977 FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
978 add_to_worklist (function_point::before_supernode (snode,
979 pred),
980 worklist, seen, logger);
983 break;
988 /* Process POINT, popped from *WORKLIST.
989 Iterate over successors of POINT, adding to *WORKLIST and *SEEN. */
991 void
992 state_purge_per_decl::
993 process_point_forwards (const function_point &point,
994 auto_vec<function_point> *worklist,
995 point_set_t *seen,
996 const state_purge_map &map)
998 logger *logger = map.get_logger ();
999 LOG_FUNC (logger);
1000 if (logger)
1002 logger->start_log_line ();
1003 logger->log_partial ("considering point: '");
1004 point.print (logger->get_printer (), format (false));
1005 logger->log_partial ("' for %qE", m_decl);
1006 logger->end_log_line ();
1008 const supernode *snode = point.get_supernode ();
1010 switch (point.get_kind ())
1012 default:
1013 case PK_ORIGIN:
1014 gcc_unreachable ();
1016 case PK_BEFORE_SUPERNODE:
1018 function_point next = point.get_next ();
1019 add_to_worklist (next, worklist, seen, logger);
1021 break;
1023 case PK_BEFORE_STMT:
1025 /* Perhaps we should stop at a clobber of the decl,
1026 but that ought to purge state for us explicitly. */
1027 function_point next = point.get_next ();
1028 add_to_worklist (next, worklist, seen, logger);
1030 break;
1032 case PK_AFTER_SUPERNODE:
1034 /* Look at interprocedural out-edges. */
1035 unsigned i;
1036 superedge *succ;
1037 FOR_EACH_VEC_ELT (snode->m_succs, i, succ)
1039 enum edge_kind kind = succ->get_kind ();
1040 if (kind == SUPEREDGE_CFG_EDGE
1041 || kind == SUPEREDGE_INTRAPROCEDURAL_CALL)
1042 add_to_worklist (function_point::before_supernode (succ->m_dest,
1043 succ),
1044 worklist, seen, logger);
1047 break;
1051 /* Return true if the decl is needed at POINT. */
1053 bool
1054 state_purge_per_decl::needed_at_point_p (const function_point &point) const
1056 return const_cast <point_set_t &> (m_points_needing_decl).contains (point);
1059 /* class state_purge_annotator : public dot_annotator. */
1061 /* Implementation of dot_annotator::add_node_annotations vfunc for
1062 state_purge_annotator.
1064 Add an additional record showing which names are purged on entry
1065 to the supernode N. */
1067 bool
1068 state_purge_annotator::add_node_annotations (graphviz_out *gv,
1069 const supernode &n,
1070 bool within_table) const
1072 if (m_map == NULL)
1073 return false;
1075 if (within_table)
1076 return false;
1078 pretty_printer *pp = gv->get_pp ();
1080 pp_printf (pp, "annotation_for_node_%i", n.m_index);
1081 pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
1082 "lightblue");
1083 pp_write_text_to_stream (pp);
1085 /* Different in-edges mean different names need purging.
1086 Determine which points to dump. */
1087 auto_vec<function_point> points;
1088 if (n.entry_p () || n.m_returning_call)
1089 points.safe_push (function_point::before_supernode (&n, NULL));
1090 else
1091 for (auto inedge : n.m_preds)
1092 points.safe_push (function_point::before_supernode (&n, inedge));
1093 points.safe_push (function_point::after_supernode (&n));
1095 for (auto & point : points)
1097 point.print (pp, format (true));
1098 pp_newline (pp);
1099 print_needed (gv, point, false);
1100 pp_newline (pp);
1103 pp_string (pp, "\"];\n\n");
1104 pp_flush (pp);
1105 return false;
1108 /* Print V to GV as a comma-separated list in braces, titling it with TITLE.
1109 If WITHIN_TABLE is true, print it within a <TR>
1111 Subroutine of state_purge_annotator::print_needed. */
1113 static void
1114 print_vec_of_names (graphviz_out *gv, const char *title,
1115 const auto_vec<tree> &v, bool within_table)
1117 pretty_printer *pp = gv->get_pp ();
1118 tree name;
1119 unsigned i;
1120 if (within_table)
1121 gv->begin_trtd ();
1122 pp_printf (pp, "%s: {", title);
1123 FOR_EACH_VEC_ELT (v, i, name)
1125 if (i > 0)
1126 pp_string (pp, ", ");
1127 pp_printf (pp, "%qE", name);
1129 pp_printf (pp, "}");
1130 if (within_table)
1132 pp_write_text_as_html_like_dot_to_stream (pp);
1133 gv->end_tdtr ();
1135 pp_newline (pp);
1138 /* Implementation of dot_annotator::add_stmt_annotations for
1139 state_purge_annotator.
1141 Add text showing which names are purged at STMT. */
1143 void
1144 state_purge_annotator::add_stmt_annotations (graphviz_out *gv,
1145 const gimple *stmt,
1146 bool within_row) const
1148 if (within_row)
1149 return;
1151 if (m_map == NULL)
1152 return;
1154 if (stmt->code == GIMPLE_PHI)
1155 return;
1157 pretty_printer *pp = gv->get_pp ();
1159 pp_newline (pp);
1161 const supernode *supernode = m_map->get_sg ().get_supernode_for_stmt (stmt);
1162 unsigned int stmt_idx = supernode->get_stmt_index (stmt);
1163 function_point before_stmt
1164 (function_point::before_stmt (supernode, stmt_idx));
1166 print_needed (gv, before_stmt, true);
1169 /* Get the decls and SSA names needed and not-needed at POINT, and
1170 print them to GV.
1171 If WITHIN_TABLE is true, print them within <TR> elements. */
1173 void
1174 state_purge_annotator::print_needed (graphviz_out *gv,
1175 const function_point &point,
1176 bool within_table) const
1178 auto_vec<tree> needed;
1179 auto_vec<tree> not_needed;
1180 for (state_purge_map::ssa_iterator iter = m_map->begin_ssas ();
1181 iter != m_map->end_ssas ();
1182 ++iter)
1184 tree name = (*iter).first;
1185 state_purge_per_ssa_name *per_name_data = (*iter).second;
1186 if (per_name_data->get_function () == point.get_function ())
1188 if (per_name_data->needed_at_point_p (point))
1189 needed.safe_push (name);
1190 else
1191 not_needed.safe_push (name);
1194 for (state_purge_map::decl_iterator iter = m_map->begin_decls ();
1195 iter != m_map->end_decls ();
1196 ++iter)
1198 tree decl = (*iter).first;
1199 state_purge_per_decl *per_decl_data = (*iter).second;
1200 if (per_decl_data->get_function () == point.get_function ())
1202 if (per_decl_data->needed_at_point_p (point))
1203 needed.safe_push (decl);
1204 else
1205 not_needed.safe_push (decl);
1209 print_vec_of_names (gv, "needed here", needed, within_table);
1210 print_vec_of_names (gv, "not needed here", not_needed, within_table);
1213 #endif /* #if ENABLE_ANALYZER */