hppa: Export main in pr104869.C on hpux
[official-gcc.git] / gcc / analyzer / supergraph.h
blob0cafbb5723427b4140bec13749b5fdbf6436d6ba
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 tree get_label () const;
302 function * const m_fun; // alternatively could be stored as runs of indices within the supergraph
303 const basic_block m_bb;
304 gcall * const m_returning_call; // for handling the result of a returned call
305 gimple_seq m_phi_nodes; // ptr to that of the underlying BB, for the first supernode for the BB
306 auto_vec<gimple *> m_stmts;
307 const int m_index; /* unique within the supergraph as a whole. */
310 /* An abstract base class encapsulating an edge within a supergraph.
311 Edges can be CFG edges, or calls/returns for callgraph edges. */
313 class superedge : public dedge<supergraph_traits>
315 public:
316 virtual ~superedge () {}
318 void dump (pretty_printer *pp) const;
319 void dump () const;
320 void dump_dot (graphviz_out *gv, const dump_args_t &args)
321 const final override;
323 virtual void dump_label_to_pp (pretty_printer *pp,
324 bool user_facing) const = 0;
326 json::object *to_json () const;
328 enum edge_kind get_kind () const { return m_kind; }
330 virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; }
331 virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; }
332 virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return NULL; }
333 virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; }
334 virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return NULL; }
335 virtual call_superedge *dyn_cast_call_superedge () { return NULL; }
336 virtual const call_superedge *dyn_cast_call_superedge () const { return NULL; }
337 virtual return_superedge *dyn_cast_return_superedge () { return NULL; }
338 virtual const return_superedge *dyn_cast_return_superedge () const { return NULL; }
340 ::edge get_any_cfg_edge () const;
341 cgraph_edge *get_any_callgraph_edge () const;
343 label_text get_description (bool user_facing) const;
345 protected:
346 superedge (supernode *src, supernode *dest, enum edge_kind kind)
347 : dedge<supergraph_traits> (src, dest),
348 m_kind (kind)
351 public:
352 const enum edge_kind m_kind;
355 /* An ID representing an expression at a callsite:
356 either a parameter index, or the return value (or unknown). */
358 class callsite_expr
360 public:
361 callsite_expr () : m_val (-1) {}
363 static callsite_expr from_zero_based_param (int idx)
365 return callsite_expr (idx + 1);
368 static callsite_expr from_return_value ()
370 return callsite_expr (0);
373 bool param_p () const
375 return m_val > 0;
378 bool return_value_p () const
380 return m_val == 0;
383 private:
384 callsite_expr (int val) : m_val (val) {}
386 int m_val; /* 1-based parm, 0 for return value, or -1 for "unknown". */
389 /* A subclass of superedge with an associated callgraph edge (either a
390 call or a return). */
392 class callgraph_superedge : public superedge
394 public:
395 callgraph_superedge (supernode *src, supernode *dst, enum edge_kind kind,
396 cgraph_edge *cedge)
397 : superedge (src, dst, kind),
398 m_cedge (cedge)
401 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
402 final override;
404 callgraph_superedge *dyn_cast_callgraph_superedge () final override
406 return this;
408 const callgraph_superedge *dyn_cast_callgraph_superedge () const
409 final override
411 return this;
414 function *get_callee_function () const;
415 function *get_caller_function () const;
416 tree get_callee_decl () const;
417 tree get_caller_decl () const;
418 gcall *get_call_stmt () const;
419 tree get_arg_for_parm (tree parm, callsite_expr *out) const;
420 tree get_parm_for_arg (tree arg, callsite_expr *out) const;
421 tree map_expr_from_caller_to_callee (tree caller_expr,
422 callsite_expr *out) const;
423 tree map_expr_from_callee_to_caller (tree callee_expr,
424 callsite_expr *out) const;
426 cgraph_edge *const m_cedge;
429 } // namespace ana
431 template <>
432 template <>
433 inline bool
434 is_a_helper <const callgraph_superedge *>::test (const superedge *sedge)
436 return (sedge->get_kind () == SUPEREDGE_INTRAPROCEDURAL_CALL
437 || sedge->get_kind () == SUPEREDGE_CALL
438 || sedge->get_kind () == SUPEREDGE_RETURN);
441 namespace ana {
443 /* A subclass of superedge representing an interprocedural call. */
445 class call_superedge : public callgraph_superedge
447 public:
448 call_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
449 : callgraph_superedge (src, dst, SUPEREDGE_CALL, cedge)
452 call_superedge *dyn_cast_call_superedge () final override
454 return this;
456 const call_superedge *dyn_cast_call_superedge () const final override
458 return this;
461 return_superedge *get_edge_for_return (const supergraph &sg) const
463 return sg.get_edge_for_return (m_cedge);
467 } // namespace ana
469 template <>
470 template <>
471 inline bool
472 is_a_helper <const call_superedge *>::test (const superedge *sedge)
474 return sedge->get_kind () == SUPEREDGE_CALL;
477 namespace ana {
479 /* A subclass of superedge represesnting an interprocedural return. */
481 class return_superedge : public callgraph_superedge
483 public:
484 return_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
485 : callgraph_superedge (src, dst, SUPEREDGE_RETURN, cedge)
488 return_superedge *dyn_cast_return_superedge () final override { return this; }
489 const return_superedge *dyn_cast_return_superedge () const final override
491 return this;
494 call_superedge *get_edge_for_call (const supergraph &sg) const
496 return sg.get_edge_for_call (m_cedge);
500 } // namespace ana
502 template <>
503 template <>
504 inline bool
505 is_a_helper <const return_superedge *>::test (const superedge *sedge)
507 return sedge->get_kind () == SUPEREDGE_RETURN;
510 namespace ana {
512 /* A subclass of superedge that corresponds to a CFG edge. */
514 class cfg_superedge : public superedge
516 public:
517 cfg_superedge (supernode *src, supernode *dst, ::edge e)
518 : superedge (src, dst, SUPEREDGE_CFG_EDGE),
519 m_cfg_edge (e)
522 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const override;
523 cfg_superedge *dyn_cast_cfg_superedge () final override { return this; }
524 const cfg_superedge *dyn_cast_cfg_superedge () const final override { return this; }
526 ::edge get_cfg_edge () const { return m_cfg_edge; }
527 int get_flags () const { return m_cfg_edge->flags; }
528 int true_value_p () const { return get_flags () & EDGE_TRUE_VALUE; }
529 int false_value_p () const { return get_flags () & EDGE_FALSE_VALUE; }
530 int back_edge_p () const { return get_flags () & EDGE_DFS_BACK; }
532 size_t get_phi_arg_idx () const;
533 tree get_phi_arg (const gphi *phi) const;
535 location_t get_goto_locus () const { return m_cfg_edge->goto_locus; }
537 private:
538 const ::edge m_cfg_edge;
541 } // namespace ana
543 template <>
544 template <>
545 inline bool
546 is_a_helper <const cfg_superedge *>::test (const superedge *sedge)
548 return sedge->get_kind () == SUPEREDGE_CFG_EDGE;
551 namespace ana {
553 /* A subclass for edges from switch statements, retaining enough
554 information to identify the pertinent cases, and for adding labels
555 when rendering via graphviz. */
557 class switch_cfg_superedge : public cfg_superedge {
558 public:
559 switch_cfg_superedge (supernode *src, supernode *dst, ::edge e);
561 const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const
562 final override
564 return this;
567 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
568 final override;
570 gswitch *get_switch_stmt () const
572 return as_a <gswitch *> (m_src->get_last_stmt ());
575 const vec<tree> &get_case_labels () const { return m_case_labels; }
577 bool implicitly_created_default_p () const;
579 private:
580 auto_vec<tree> m_case_labels;
583 } // namespace ana
585 template <>
586 template <>
587 inline bool
588 is_a_helper <const switch_cfg_superedge *>::test (const superedge *sedge)
590 return sedge->dyn_cast_switch_cfg_superedge () != NULL;
593 namespace ana {
595 /* Base class for adding additional content to the .dot output
596 for a supergraph. */
598 class dot_annotator
600 public:
601 virtual ~dot_annotator () {}
602 virtual bool add_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
603 const supernode &n ATTRIBUTE_UNUSED,
604 bool within_table ATTRIBUTE_UNUSED)
605 const
607 return false;
609 virtual void add_stmt_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
610 const gimple *stmt ATTRIBUTE_UNUSED,
611 bool within_row ATTRIBUTE_UNUSED)
612 const {}
613 virtual bool add_after_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
614 const supernode &n ATTRIBUTE_UNUSED)
615 const
617 return false;
621 extern cgraph_edge *supergraph_call_edge (function *fun, const gimple *stmt);
622 extern function *get_ultimate_function_for_cgraph_edge (cgraph_edge *edge);
624 } // namespace ana
626 #endif /* GCC_ANALYZER_SUPERGRAPH_H */