ada: Fix wrong resolution for hidden discriminant in predicate
[official-gcc.git] / gcc / analyzer / supergraph.h
blobf8b36d789dc93990f9951ab58e7df3c9a996c8eb
1 /* "Supergraph" classes that combine CFGs and callgraph into one digraph.
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 #ifndef GCC_ANALYZER_SUPERGRAPH_H
22 #define GCC_ANALYZER_SUPERGRAPH_H
24 #include "ordered-hash-map.h"
25 #include "cfg.h"
26 #include "basic-block.h"
27 #include "gimple.h"
28 #include "gimple-iterator.h"
29 #include "digraph.h"
31 using namespace ana;
33 namespace ana {
35 /* Forward decls, using indentation to show inheritance. */
37 class supergraph;
38 class supernode;
39 class superedge;
40 class callgraph_superedge;
41 class call_superedge;
42 class return_superedge;
43 class cfg_superedge;
44 class switch_cfg_superedge;
45 class supercluster;
46 class dot_annotator;
48 class logger;
50 /* An enum for discriminating between superedge subclasses. */
52 enum edge_kind
54 SUPEREDGE_CFG_EDGE,
55 SUPEREDGE_CALL,
56 SUPEREDGE_RETURN,
57 SUPEREDGE_INTRAPROCEDURAL_CALL
60 /* Flags for controlling the appearance of .dot dumps. */
62 enum supergraph_dot_flags
64 SUPERGRAPH_DOT_SHOW_BBS = (1 << 0)
67 /* A traits struct describing the family of node, edge and digraph
68 classes for supergraphs. */
70 struct supergraph_traits
72 typedef supernode node_t;
73 typedef superedge edge_t;
74 typedef supergraph graph_t;
75 struct dump_args_t
77 dump_args_t (enum supergraph_dot_flags flags,
78 const dot_annotator *node_annotator)
79 : m_flags (flags),
80 m_node_annotator (node_annotator)
83 enum supergraph_dot_flags m_flags;
84 const dot_annotator *m_node_annotator;
86 typedef supercluster cluster_t;
89 /* A class to manage the setting and restoring of statement uids. */
91 class saved_uids
93 public:
94 void make_uid_unique (gimple *stmt);
95 void restore_uids () const;
97 private:
98 auto_vec<std::pair<gimple *, unsigned> > m_old_stmt_uids;
101 /* A "supergraph" is a directed graph formed by joining together all CFGs,
102 linking them via interprocedural call and return edges.
104 Basic blocks are split at callsites, so that a call statement occurs
105 twice: once at the end of a supernode, and a second instance at the
106 start of the next supernode (to handle the return). */
108 class supergraph : public digraph<supergraph_traits>
110 public:
111 supergraph (logger *logger);
112 ~supergraph ();
114 supernode *get_node_for_function_entry (function *fun) const
116 return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (fun));
119 supernode *get_node_for_function_exit (function *fun) const
121 return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (fun));
124 supernode *get_node_for_block (basic_block bb) const
126 return *const_cast <bb_to_node_t &> (m_bb_to_initial_node).get (bb);
129 /* Get the supernode containing the second half of the gcall *
130 at an interprocedural call, within the caller. */
131 supernode *get_caller_next_node (cgraph_edge *edge) const
133 return (*const_cast <cgraph_edge_to_node_t &>
134 (m_cgraph_edge_to_caller_next_node).get (edge));
137 call_superedge *get_edge_for_call (cgraph_edge *edge) const
139 return (*const_cast <cgraph_edge_to_call_superedge_t &>
140 (m_cgraph_edge_to_call_superedge).get (edge));
143 return_superedge *get_edge_for_return (cgraph_edge *edge) const
145 return (*const_cast <cgraph_edge_to_return_superedge_t &>
146 (m_cgraph_edge_to_return_superedge).get (edge));
149 superedge *get_intraprocedural_edge_for_call (cgraph_edge *edge) const
151 return (*const_cast <cgraph_edge_to_intraproc_superedge_t &>
152 (m_cgraph_edge_to_intraproc_superedge).get (edge));
155 cfg_superedge *get_edge_for_cfg_edge (edge e) const
157 return (*const_cast <cfg_edge_to_cfg_superedge_t &>
158 (m_cfg_edge_to_cfg_superedge).get (e));
161 supernode *get_supernode_for_stmt (const gimple *stmt) const
163 return (*const_cast <stmt_to_node_t &>(m_stmt_to_node_t).get
164 (const_cast <gimple *> (stmt)));
167 void dump_dot_to_pp (pretty_printer *pp, const dump_args_t &) const;
168 void dump_dot_to_file (FILE *fp, const dump_args_t &) const;
169 void dump_dot (const char *path, const dump_args_t &) const;
171 json::object *to_json () const;
173 int num_nodes () const { return m_nodes.length (); }
174 int num_edges () const { return m_edges.length (); }
176 supernode *get_node_by_index (int idx) const
178 return m_nodes[idx];
181 unsigned get_num_snodes (const function *fun) const
183 function_to_num_snodes_t &map
184 = const_cast <function_to_num_snodes_t &>(m_function_to_num_snodes);
185 return *map.get (fun);
188 private:
189 supernode *add_node (function *fun, basic_block bb, gcall *returning_call,
190 gimple_seq phi_nodes);
191 cfg_superedge *add_cfg_edge (supernode *src, supernode *dest, ::edge e);
192 call_superedge *add_call_superedge (supernode *src, supernode *dest,
193 cgraph_edge *cedge);
194 return_superedge *add_return_superedge (supernode *src, supernode *dest,
195 cgraph_edge *cedge);
197 /* Data. */
199 typedef ordered_hash_map<basic_block, supernode *> bb_to_node_t;
200 bb_to_node_t m_bb_to_initial_node;
201 bb_to_node_t m_bb_to_final_node;
203 typedef ordered_hash_map<cgraph_edge *, supernode *> cgraph_edge_to_node_t;
204 cgraph_edge_to_node_t m_cgraph_edge_to_caller_prev_node;
205 cgraph_edge_to_node_t m_cgraph_edge_to_caller_next_node;
207 typedef ordered_hash_map< ::edge, cfg_superedge *>
208 cfg_edge_to_cfg_superedge_t;
209 cfg_edge_to_cfg_superedge_t m_cfg_edge_to_cfg_superedge;
211 typedef ordered_hash_map<cgraph_edge *, call_superedge *>
212 cgraph_edge_to_call_superedge_t;
213 cgraph_edge_to_call_superedge_t m_cgraph_edge_to_call_superedge;
215 typedef ordered_hash_map<cgraph_edge *, return_superedge *>
216 cgraph_edge_to_return_superedge_t;
217 cgraph_edge_to_return_superedge_t m_cgraph_edge_to_return_superedge;
219 typedef ordered_hash_map<cgraph_edge *, superedge *>
220 cgraph_edge_to_intraproc_superedge_t;
221 cgraph_edge_to_intraproc_superedge_t m_cgraph_edge_to_intraproc_superedge;
223 typedef ordered_hash_map<gimple *, supernode *> stmt_to_node_t;
224 stmt_to_node_t m_stmt_to_node_t;
226 typedef hash_map<const function *, unsigned> function_to_num_snodes_t;
227 function_to_num_snodes_t m_function_to_num_snodes;
229 saved_uids m_stmt_uids;
232 /* A node within a supergraph. */
234 class supernode : public dnode<supergraph_traits>
236 public:
237 supernode (function *fun, basic_block bb, gcall *returning_call,
238 gimple_seq phi_nodes, int index)
239 : m_fun (fun), m_bb (bb), m_returning_call (returning_call),
240 m_phi_nodes (phi_nodes), m_index (index)
243 function *get_function () const { return m_fun; }
245 bool entry_p () const
247 return m_bb == ENTRY_BLOCK_PTR_FOR_FN (m_fun);
250 bool return_p () const
252 return m_bb == EXIT_BLOCK_PTR_FOR_FN (m_fun);
255 void dump_dot (graphviz_out *gv, const dump_args_t &args) const override;
256 void dump_dot_id (pretty_printer *pp) const;
258 json::object *to_json () const;
260 location_t get_start_location () const;
261 location_t get_end_location () const;
263 /* Returns iterator at the start of the list of phi nodes, if any. */
264 gphi_iterator start_phis ()
266 gimple_seq *pseq = &m_phi_nodes;
268 /* Adapted from gsi_start_1. */
269 gphi_iterator i;
271 i.ptr = gimple_seq_first (*pseq);
272 i.seq = pseq;
273 i.bb = i.ptr ? gimple_bb (i.ptr) : NULL;
275 return i;
278 gcall *get_returning_call () const
280 return m_returning_call;
283 gimple *get_last_stmt () const
285 if (m_stmts.length () == 0)
286 return NULL;
287 return m_stmts[m_stmts.length () - 1];
290 gcall *get_final_call () const
292 gimple *stmt = get_last_stmt ();
293 if (stmt == NULL)
294 return NULL;
295 return dyn_cast<gcall *> (stmt);
298 unsigned int get_stmt_index (const gimple *stmt) const;
300 function * const m_fun; // alternatively could be stored as runs of indices within the supergraph
301 const basic_block m_bb;
302 gcall * const m_returning_call; // for handling the result of a returned call
303 gimple_seq m_phi_nodes; // ptr to that of the underlying BB, for the first supernode for the BB
304 auto_vec<gimple *> m_stmts;
305 const int m_index; /* unique within the supergraph as a whole. */
308 /* An abstract base class encapsulating an edge within a supergraph.
309 Edges can be CFG edges, or calls/returns for callgraph edges. */
311 class superedge : public dedge<supergraph_traits>
313 public:
314 virtual ~superedge () {}
316 void dump (pretty_printer *pp) const;
317 void dump () const;
318 void dump_dot (graphviz_out *gv, const dump_args_t &args)
319 const final override;
321 virtual void dump_label_to_pp (pretty_printer *pp,
322 bool user_facing) const = 0;
324 json::object *to_json () const;
326 enum edge_kind get_kind () const { return m_kind; }
328 virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; }
329 virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; }
330 virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return NULL; }
331 virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; }
332 virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return NULL; }
333 virtual call_superedge *dyn_cast_call_superedge () { return NULL; }
334 virtual const call_superedge *dyn_cast_call_superedge () const { return NULL; }
335 virtual return_superedge *dyn_cast_return_superedge () { return NULL; }
336 virtual const return_superedge *dyn_cast_return_superedge () const { return NULL; }
338 ::edge get_any_cfg_edge () const;
339 cgraph_edge *get_any_callgraph_edge () const;
341 label_text get_description (bool user_facing) const;
343 protected:
344 superedge (supernode *src, supernode *dest, enum edge_kind kind)
345 : dedge<supergraph_traits> (src, dest),
346 m_kind (kind)
349 public:
350 const enum edge_kind m_kind;
353 /* An ID representing an expression at a callsite:
354 either a parameter index, or the return value (or unknown). */
356 class callsite_expr
358 public:
359 callsite_expr () : m_val (-1) {}
361 static callsite_expr from_zero_based_param (int idx)
363 return callsite_expr (idx + 1);
366 static callsite_expr from_return_value ()
368 return callsite_expr (0);
371 bool param_p () const
373 return m_val > 0;
376 bool return_value_p () const
378 return m_val == 0;
381 private:
382 callsite_expr (int val) : m_val (val) {}
384 int m_val; /* 1-based parm, 0 for return value, or -1 for "unknown". */
387 /* A subclass of superedge with an associated callgraph edge (either a
388 call or a return). */
390 class callgraph_superedge : public superedge
392 public:
393 callgraph_superedge (supernode *src, supernode *dst, enum edge_kind kind,
394 cgraph_edge *cedge)
395 : superedge (src, dst, kind),
396 m_cedge (cedge)
399 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
400 final override;
402 callgraph_superedge *dyn_cast_callgraph_superedge () final override
404 return this;
406 const callgraph_superedge *dyn_cast_callgraph_superedge () const
407 final override
409 return this;
412 function *get_callee_function () const;
413 function *get_caller_function () const;
414 tree get_callee_decl () const;
415 tree get_caller_decl () const;
416 gcall *get_call_stmt () const;
417 tree get_arg_for_parm (tree parm, callsite_expr *out) const;
418 tree get_parm_for_arg (tree arg, callsite_expr *out) const;
419 tree map_expr_from_caller_to_callee (tree caller_expr,
420 callsite_expr *out) const;
421 tree map_expr_from_callee_to_caller (tree callee_expr,
422 callsite_expr *out) const;
424 cgraph_edge *const m_cedge;
427 } // namespace ana
429 template <>
430 template <>
431 inline bool
432 is_a_helper <const callgraph_superedge *>::test (const superedge *sedge)
434 return (sedge->get_kind () == SUPEREDGE_INTRAPROCEDURAL_CALL
435 || sedge->get_kind () == SUPEREDGE_CALL
436 || sedge->get_kind () == SUPEREDGE_RETURN);
439 namespace ana {
441 /* A subclass of superedge representing an interprocedural call. */
443 class call_superedge : public callgraph_superedge
445 public:
446 call_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
447 : callgraph_superedge (src, dst, SUPEREDGE_CALL, cedge)
450 call_superedge *dyn_cast_call_superedge () final override
452 return this;
454 const call_superedge *dyn_cast_call_superedge () const final override
456 return this;
459 return_superedge *get_edge_for_return (const supergraph &sg) const
461 return sg.get_edge_for_return (m_cedge);
465 } // namespace ana
467 template <>
468 template <>
469 inline bool
470 is_a_helper <const call_superedge *>::test (const superedge *sedge)
472 return sedge->get_kind () == SUPEREDGE_CALL;
475 namespace ana {
477 /* A subclass of superedge represesnting an interprocedural return. */
479 class return_superedge : public callgraph_superedge
481 public:
482 return_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
483 : callgraph_superedge (src, dst, SUPEREDGE_RETURN, cedge)
486 return_superedge *dyn_cast_return_superedge () final override { return this; }
487 const return_superedge *dyn_cast_return_superedge () const final override
489 return this;
492 call_superedge *get_edge_for_call (const supergraph &sg) const
494 return sg.get_edge_for_call (m_cedge);
498 } // namespace ana
500 template <>
501 template <>
502 inline bool
503 is_a_helper <const return_superedge *>::test (const superedge *sedge)
505 return sedge->get_kind () == SUPEREDGE_RETURN;
508 namespace ana {
510 /* A subclass of superedge that corresponds to a CFG edge. */
512 class cfg_superedge : public superedge
514 public:
515 cfg_superedge (supernode *src, supernode *dst, ::edge e)
516 : superedge (src, dst, SUPEREDGE_CFG_EDGE),
517 m_cfg_edge (e)
520 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const override;
521 cfg_superedge *dyn_cast_cfg_superedge () final override { return this; }
522 const cfg_superedge *dyn_cast_cfg_superedge () const final override { return this; }
524 ::edge get_cfg_edge () const { return m_cfg_edge; }
525 int get_flags () const { return m_cfg_edge->flags; }
526 int true_value_p () const { return get_flags () & EDGE_TRUE_VALUE; }
527 int false_value_p () const { return get_flags () & EDGE_FALSE_VALUE; }
528 int back_edge_p () const { return get_flags () & EDGE_DFS_BACK; }
530 size_t get_phi_arg_idx () const;
531 tree get_phi_arg (const gphi *phi) const;
533 private:
534 const ::edge m_cfg_edge;
537 } // namespace ana
539 template <>
540 template <>
541 inline bool
542 is_a_helper <const cfg_superedge *>::test (const superedge *sedge)
544 return sedge->get_kind () == SUPEREDGE_CFG_EDGE;
547 namespace ana {
549 /* A subclass for edges from switch statements, retaining enough
550 information to identify the pertinent cases, and for adding labels
551 when rendering via graphviz. */
553 class switch_cfg_superedge : public cfg_superedge {
554 public:
555 switch_cfg_superedge (supernode *src, supernode *dst, ::edge e);
557 const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const
558 final override
560 return this;
563 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
564 final override;
566 gswitch *get_switch_stmt () const
568 return as_a <gswitch *> (m_src->get_last_stmt ());
571 const vec<tree> &get_case_labels () const { return m_case_labels; }
573 bool implicitly_created_default_p () const;
575 private:
576 auto_vec<tree> m_case_labels;
579 } // namespace ana
581 template <>
582 template <>
583 inline bool
584 is_a_helper <const switch_cfg_superedge *>::test (const superedge *sedge)
586 return sedge->dyn_cast_switch_cfg_superedge () != NULL;
589 namespace ana {
591 /* Base class for adding additional content to the .dot output
592 for a supergraph. */
594 class dot_annotator
596 public:
597 virtual ~dot_annotator () {}
598 virtual bool add_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
599 const supernode &n ATTRIBUTE_UNUSED,
600 bool within_table ATTRIBUTE_UNUSED)
601 const
603 return false;
605 virtual void add_stmt_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
606 const gimple *stmt ATTRIBUTE_UNUSED,
607 bool within_row ATTRIBUTE_UNUSED)
608 const {}
609 virtual bool add_after_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
610 const supernode &n ATTRIBUTE_UNUSED)
611 const
613 return false;
617 extern cgraph_edge *supergraph_call_edge (function *fun, const gimple *stmt);
618 extern function *get_ultimate_function_for_cgraph_edge (cgraph_edge *edge);
620 } // namespace ana
622 #endif /* GCC_ANALYZER_SUPERGRAPH_H */