1 /* "Supergraph" classes that combine CFGs and callgraph into one digraph.
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)
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"
26 #include "basic-block.h"
28 #include "gimple-iterator.h"
35 /* Forward decls, using indentation to show inheritance. */
40 class callgraph_superedge
;
42 class return_superedge
;
44 class switch_cfg_superedge
;
50 /* An enum for discriminating between superedge subclasses. */
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
;
77 dump_args_t (enum supergraph_dot_flags flags
,
78 const dot_annotator
*node_annotator
)
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. */
94 void make_uid_unique (gimple
*stmt
);
95 void restore_uids () const;
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
>
111 supergraph (logger
*logger
);
114 supernode
*get_node_for_function_entry (const function
&fun
) const
116 return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (&fun
));
119 supernode
*get_node_for_function_exit (const 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 std::unique_ptr
<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
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
);
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
,
194 return_superedge
*add_return_superedge (supernode
*src
, supernode
*dest
,
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
>
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 std::unique_ptr
<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. */
271 i
.ptr
= gimple_seq_first (*pseq
);
273 i
.bb
= i
.ptr
? gimple_bb (i
.ptr
) : NULL
;
278 gcall
*get_returning_call () const
280 return m_returning_call
;
283 gimple
*get_last_stmt () const
285 if (m_stmts
.length () == 0)
287 return m_stmts
[m_stmts
.length () - 1];
290 gcall
*get_final_call () const
292 gimple
*stmt
= get_last_stmt ();
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
>
316 virtual ~superedge () {}
318 void dump (pretty_printer
*pp
) 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 std::unique_ptr
<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;
346 superedge (supernode
*src
, supernode
*dest
, enum edge_kind kind
)
347 : dedge
<supergraph_traits
> (src
, dest
),
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). */
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
378 bool return_value_p () const
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
395 callgraph_superedge (supernode
*src
, supernode
*dst
, enum edge_kind kind
,
397 : superedge (src
, dst
, kind
),
401 void dump_label_to_pp (pretty_printer
*pp
, bool user_facing
) const
404 callgraph_superedge
*dyn_cast_callgraph_superedge () final override
408 const callgraph_superedge
*dyn_cast_callgraph_superedge () const
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
;
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
);
443 /* A subclass of superedge representing an interprocedural call. */
445 class call_superedge
: public callgraph_superedge
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
456 const call_superedge
*dyn_cast_call_superedge () const final override
461 return_superedge
*get_edge_for_return (const supergraph
&sg
) const
463 return sg
.get_edge_for_return (m_cedge
);
472 is_a_helper
<const call_superedge
*>::test (const superedge
*sedge
)
474 return sedge
->get_kind () == SUPEREDGE_CALL
;
479 /* A subclass of superedge represesnting an interprocedural return. */
481 class return_superedge
: public callgraph_superedge
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
494 call_superedge
*get_edge_for_call (const supergraph
&sg
) const
496 return sg
.get_edge_for_call (m_cedge
);
505 is_a_helper
<const return_superedge
*>::test (const superedge
*sedge
)
507 return sedge
->get_kind () == SUPEREDGE_RETURN
;
512 /* A subclass of superedge that corresponds to a CFG edge. */
514 class cfg_superedge
: public superedge
517 cfg_superedge (supernode
*src
, supernode
*dst
, ::edge e
)
518 : superedge (src
, dst
, SUPEREDGE_CFG_EDGE
),
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
; }
538 const ::edge m_cfg_edge
;
546 is_a_helper
<const cfg_superedge
*>::test (const superedge
*sedge
)
548 return sedge
->get_kind () == SUPEREDGE_CFG_EDGE
;
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
{
559 switch_cfg_superedge (supernode
*src
, supernode
*dst
, ::edge e
);
561 const switch_cfg_superedge
*dyn_cast_switch_cfg_superedge () const
567 void dump_label_to_pp (pretty_printer
*pp
, bool user_facing
) const
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;
580 auto_vec
<tree
> m_case_labels
;
588 is_a_helper
<const switch_cfg_superedge
*>::test (const superedge
*sedge
)
590 return sedge
->dyn_cast_switch_cfg_superedge () != NULL
;
595 /* Base class for adding additional content to the .dot output
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
)
609 virtual void add_stmt_annotations (graphviz_out
*gv ATTRIBUTE_UNUSED
,
610 const gimple
*stmt ATTRIBUTE_UNUSED
,
611 bool within_row ATTRIBUTE_UNUSED
)
613 virtual bool add_after_node_annotations (graphviz_out
*gv ATTRIBUTE_UNUSED
,
614 const supernode
&n ATTRIBUTE_UNUSED
)
621 extern cgraph_edge
*supergraph_call_edge (function
*fun
, const gimple
*stmt
);
622 extern function
*get_ultimate_function_for_cgraph_edge (cgraph_edge
*edge
);
626 #endif /* GCC_ANALYZER_SUPERGRAPH_H */