1 /* "Supergraph" classes that combine CFGs and callgraph into one digraph.
2 Copyright (C) 2019-2021 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
28 /* Forward decls, using indentation to show inheritance. */
33 class callgraph_superedge
;
35 class return_superedge
;
37 class switch_cfg_superedge
;
43 /* An enum for discriminating between superedge subclasses. */
50 SUPEREDGE_INTRAPROCEDURAL_CALL
53 /* Flags for controlling the appearance of .dot dumps. */
55 enum supergraph_dot_flags
57 SUPERGRAPH_DOT_SHOW_BBS
= (1 << 0)
60 /* A traits struct describing the family of node, edge and digraph
61 classes for supergraphs. */
63 struct supergraph_traits
65 typedef supernode node_t
;
66 typedef superedge edge_t
;
67 typedef supergraph graph_t
;
70 dump_args_t (enum supergraph_dot_flags flags
,
71 const dot_annotator
*node_annotator
)
73 m_node_annotator (node_annotator
)
76 enum supergraph_dot_flags m_flags
;
77 const dot_annotator
*m_node_annotator
;
79 typedef supercluster cluster_t
;
82 /* A class to manage the setting and restoring of statement uids. */
87 void make_uid_unique (gimple
*stmt
);
88 void restore_uids () const;
91 auto_vec
<std::pair
<gimple
*, unsigned> > m_old_stmt_uids
;
94 /* A "supergraph" is a directed graph formed by joining together all CFGs,
95 linking them via interprocedural call and return edges.
97 Basic blocks are split at callsites, so that a call statement occurs
98 twice: once at the end of a supernode, and a second instance at the
99 start of the next supernode (to handle the return). */
101 class supergraph
: public digraph
<supergraph_traits
>
104 supergraph (logger
*logger
);
107 supernode
*get_node_for_function_entry (function
*fun
) const
109 return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (fun
));
112 supernode
*get_node_for_function_exit (function
*fun
) const
114 return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (fun
));
117 supernode
*get_node_for_block (basic_block bb
) const
119 return *const_cast <bb_to_node_t
&> (m_bb_to_initial_node
).get (bb
);
122 /* Get the supernode containing the second half of the gcall *
123 at an interprocedural call, within the caller. */
124 supernode
*get_caller_next_node (cgraph_edge
*edge
) const
126 return (*const_cast <cgraph_edge_to_node_t
&>
127 (m_cgraph_edge_to_caller_next_node
).get (edge
));
130 call_superedge
*get_edge_for_call (cgraph_edge
*edge
) const
132 return (*const_cast <cgraph_edge_to_call_superedge_t
&>
133 (m_cgraph_edge_to_call_superedge
).get (edge
));
136 return_superedge
*get_edge_for_return (cgraph_edge
*edge
) const
138 return (*const_cast <cgraph_edge_to_return_superedge_t
&>
139 (m_cgraph_edge_to_return_superedge
).get (edge
));
142 superedge
*get_intraprocedural_edge_for_call (cgraph_edge
*edge
) const
144 return (*const_cast <cgraph_edge_to_intraproc_superedge_t
&>
145 (m_cgraph_edge_to_intraproc_superedge
).get (edge
));
148 cfg_superedge
*get_edge_for_cfg_edge (edge e
) const
150 return (*const_cast <cfg_edge_to_cfg_superedge_t
&>
151 (m_cfg_edge_to_cfg_superedge
).get (e
));
154 supernode
*get_supernode_for_stmt (const gimple
*stmt
) const
156 return (*const_cast <stmt_to_node_t
&>(m_stmt_to_node_t
).get
157 (const_cast <gimple
*> (stmt
)));
160 void dump_dot_to_pp (pretty_printer
*pp
, const dump_args_t
&) const;
161 void dump_dot_to_file (FILE *fp
, const dump_args_t
&) const;
162 void dump_dot (const char *path
, const dump_args_t
&) const;
164 json::object
*to_json () const;
166 int num_nodes () const { return m_nodes
.length (); }
167 int num_edges () const { return m_edges
.length (); }
169 supernode
*get_node_by_index (int idx
) const
174 unsigned get_num_snodes (const function
*fun
) const
176 function_to_num_snodes_t
&map
177 = const_cast <function_to_num_snodes_t
&>(m_function_to_num_snodes
);
178 return *map
.get (fun
);
182 supernode
*add_node (function
*fun
, basic_block bb
, gcall
*returning_call
,
183 gimple_seq phi_nodes
);
184 cfg_superedge
*add_cfg_edge (supernode
*src
, supernode
*dest
, ::edge e
);
185 call_superedge
*add_call_superedge (supernode
*src
, supernode
*dest
,
187 return_superedge
*add_return_superedge (supernode
*src
, supernode
*dest
,
192 typedef ordered_hash_map
<basic_block
, supernode
*> bb_to_node_t
;
193 bb_to_node_t m_bb_to_initial_node
;
194 bb_to_node_t m_bb_to_final_node
;
196 typedef ordered_hash_map
<cgraph_edge
*, supernode
*> cgraph_edge_to_node_t
;
197 cgraph_edge_to_node_t m_cgraph_edge_to_caller_prev_node
;
198 cgraph_edge_to_node_t m_cgraph_edge_to_caller_next_node
;
200 typedef ordered_hash_map
< ::edge
, cfg_superedge
*>
201 cfg_edge_to_cfg_superedge_t
;
202 cfg_edge_to_cfg_superedge_t m_cfg_edge_to_cfg_superedge
;
204 typedef ordered_hash_map
<cgraph_edge
*, call_superedge
*>
205 cgraph_edge_to_call_superedge_t
;
206 cgraph_edge_to_call_superedge_t m_cgraph_edge_to_call_superedge
;
208 typedef ordered_hash_map
<cgraph_edge
*, return_superedge
*>
209 cgraph_edge_to_return_superedge_t
;
210 cgraph_edge_to_return_superedge_t m_cgraph_edge_to_return_superedge
;
212 typedef ordered_hash_map
<cgraph_edge
*, superedge
*>
213 cgraph_edge_to_intraproc_superedge_t
;
214 cgraph_edge_to_intraproc_superedge_t m_cgraph_edge_to_intraproc_superedge
;
216 typedef ordered_hash_map
<gimple
*, supernode
*> stmt_to_node_t
;
217 stmt_to_node_t m_stmt_to_node_t
;
219 typedef hash_map
<const function
*, unsigned> function_to_num_snodes_t
;
220 function_to_num_snodes_t m_function_to_num_snodes
;
222 saved_uids m_stmt_uids
;
225 /* A node within a supergraph. */
227 class supernode
: public dnode
<supergraph_traits
>
230 supernode (function
*fun
, basic_block bb
, gcall
*returning_call
,
231 gimple_seq phi_nodes
, int index
)
232 : m_fun (fun
), m_bb (bb
), m_returning_call (returning_call
),
233 m_phi_nodes (phi_nodes
), m_index (index
)
236 function
*get_function () const { return m_fun
; }
238 bool entry_p () const
240 return m_bb
== ENTRY_BLOCK_PTR_FOR_FN (m_fun
);
243 bool return_p () const
245 return m_bb
== EXIT_BLOCK_PTR_FOR_FN (m_fun
);
248 void dump_dot (graphviz_out
*gv
, const dump_args_t
&args
) const OVERRIDE
;
249 void dump_dot_id (pretty_printer
*pp
) const;
251 json::object
*to_json () const;
253 location_t
get_start_location () const;
254 location_t
get_end_location () const;
256 /* Returns iterator at the start of the list of phi nodes, if any. */
257 gphi_iterator
start_phis ()
259 gimple_seq
*pseq
= &m_phi_nodes
;
261 /* Adapted from gsi_start_1. */
264 i
.ptr
= gimple_seq_first (*pseq
);
266 i
.bb
= i
.ptr
? gimple_bb (i
.ptr
) : NULL
;
271 gcall
*get_returning_call () const
273 return m_returning_call
;
276 gimple
*get_last_stmt () const
278 if (m_stmts
.length () == 0)
280 return m_stmts
[m_stmts
.length () - 1];
283 gcall
*get_final_call () const
285 gimple
*stmt
= get_last_stmt ();
288 return dyn_cast
<gcall
*> (stmt
);
291 unsigned int get_stmt_index (const gimple
*stmt
) const;
293 function
* const m_fun
; // alternatively could be stored as runs of indices within the supergraph
294 const basic_block m_bb
;
295 gcall
* const m_returning_call
; // for handling the result of a returned call
296 gimple_seq m_phi_nodes
; // ptr to that of the underlying BB, for the first supernode for the BB
297 auto_vec
<gimple
*> m_stmts
;
298 const int m_index
; /* unique within the supergraph as a whole. */
301 /* An abstract base class encapsulating an edge within a supergraph.
302 Edges can be CFG edges, or calls/returns for callgraph edges. */
304 class superedge
: public dedge
<supergraph_traits
>
307 virtual ~superedge () {}
309 void dump (pretty_printer
*pp
) const;
311 void dump_dot (graphviz_out
*gv
, const dump_args_t
&args
) const;
313 virtual void dump_label_to_pp (pretty_printer
*pp
,
314 bool user_facing
) const = 0;
316 json::object
*to_json () const;
318 enum edge_kind
get_kind () const { return m_kind
; }
320 virtual cfg_superedge
*dyn_cast_cfg_superedge () { return NULL
; }
321 virtual const cfg_superedge
*dyn_cast_cfg_superedge () const { return NULL
; }
322 virtual const switch_cfg_superedge
*dyn_cast_switch_cfg_superedge () const { return NULL
; }
323 virtual callgraph_superedge
*dyn_cast_callgraph_superedge () { return NULL
; }
324 virtual const callgraph_superedge
*dyn_cast_callgraph_superedge () const { return NULL
; }
325 virtual call_superedge
*dyn_cast_call_superedge () { return NULL
; }
326 virtual const call_superedge
*dyn_cast_call_superedge () const { return NULL
; }
327 virtual return_superedge
*dyn_cast_return_superedge () { return NULL
; }
328 virtual const return_superedge
*dyn_cast_return_superedge () const { return NULL
; }
330 ::edge
get_any_cfg_edge () const;
331 cgraph_edge
*get_any_callgraph_edge () const;
333 char *get_description (bool user_facing
) const;
336 superedge (supernode
*src
, supernode
*dest
, enum edge_kind kind
)
337 : dedge
<supergraph_traits
> (src
, dest
),
342 const enum edge_kind m_kind
;
345 /* An ID representing an expression at a callsite:
346 either a parameter index, or the return value (or unknown). */
351 callsite_expr () : m_val (-1) {}
353 static callsite_expr
from_zero_based_param (int idx
)
355 return callsite_expr (idx
+ 1);
358 static callsite_expr
from_return_value ()
360 return callsite_expr (0);
363 bool param_p () const
368 bool return_value_p () const
374 callsite_expr (int val
) : m_val (val
) {}
376 int m_val
; /* 1-based parm, 0 for return value, or -1 for "unknown". */
379 /* A subclass of superedge with an associated callgraph edge (either a
380 call or a return). */
382 class callgraph_superedge
: public superedge
385 callgraph_superedge (supernode
*src
, supernode
*dst
, enum edge_kind kind
,
387 : superedge (src
, dst
, kind
),
391 void dump_label_to_pp (pretty_printer
*pp
, bool user_facing
) const
394 callgraph_superedge
*dyn_cast_callgraph_superedge () FINAL OVERRIDE
398 const callgraph_superedge
*dyn_cast_callgraph_superedge () const
404 function
*get_callee_function () const;
405 function
*get_caller_function () const;
406 tree
get_callee_decl () const;
407 tree
get_caller_decl () const;
408 gcall
*get_call_stmt () const;
409 tree
get_arg_for_parm (tree parm
, callsite_expr
*out
) const;
410 tree
get_parm_for_arg (tree arg
, callsite_expr
*out
) const;
411 tree
map_expr_from_caller_to_callee (tree caller_expr
,
412 callsite_expr
*out
) const;
413 tree
map_expr_from_callee_to_caller (tree callee_expr
,
414 callsite_expr
*out
) const;
416 cgraph_edge
*const m_cedge
;
424 is_a_helper
<const callgraph_superedge
*>::test (const superedge
*sedge
)
426 return (sedge
->get_kind () == SUPEREDGE_INTRAPROCEDURAL_CALL
427 || sedge
->get_kind () == SUPEREDGE_CALL
428 || sedge
->get_kind () == SUPEREDGE_RETURN
);
433 /* A subclass of superedge representing an interprocedural call. */
435 class call_superedge
: public callgraph_superedge
438 call_superedge (supernode
*src
, supernode
*dst
, cgraph_edge
*cedge
)
439 : callgraph_superedge (src
, dst
, SUPEREDGE_CALL
, cedge
)
442 call_superedge
*dyn_cast_call_superedge () FINAL OVERRIDE
446 const call_superedge
*dyn_cast_call_superedge () const FINAL OVERRIDE
451 return_superedge
*get_edge_for_return (const supergraph
&sg
) const
453 return sg
.get_edge_for_return (m_cedge
);
462 is_a_helper
<const call_superedge
*>::test (const superedge
*sedge
)
464 return sedge
->get_kind () == SUPEREDGE_CALL
;
469 /* A subclass of superedge represesnting an interprocedural return. */
471 class return_superedge
: public callgraph_superedge
474 return_superedge (supernode
*src
, supernode
*dst
, cgraph_edge
*cedge
)
475 : callgraph_superedge (src
, dst
, SUPEREDGE_RETURN
, cedge
)
478 return_superedge
*dyn_cast_return_superedge () FINAL OVERRIDE
{ return this; }
479 const return_superedge
*dyn_cast_return_superedge () const FINAL OVERRIDE
484 call_superedge
*get_edge_for_call (const supergraph
&sg
) const
486 return sg
.get_edge_for_call (m_cedge
);
495 is_a_helper
<const return_superedge
*>::test (const superedge
*sedge
)
497 return sedge
->get_kind () == SUPEREDGE_RETURN
;
502 /* A subclass of superedge that corresponds to a CFG edge. */
504 class cfg_superedge
: public superedge
507 cfg_superedge (supernode
*src
, supernode
*dst
, ::edge e
)
508 : superedge (src
, dst
, SUPEREDGE_CFG_EDGE
),
512 void dump_label_to_pp (pretty_printer
*pp
, bool user_facing
) const OVERRIDE
;
513 cfg_superedge
*dyn_cast_cfg_superedge () FINAL OVERRIDE
{ return this; }
514 const cfg_superedge
*dyn_cast_cfg_superedge () const FINAL OVERRIDE
{ return this; }
516 ::edge
get_cfg_edge () const { return m_cfg_edge
; }
517 int get_flags () const { return m_cfg_edge
->flags
; }
518 int true_value_p () const { return get_flags () & EDGE_TRUE_VALUE
; }
519 int false_value_p () const { return get_flags () & EDGE_FALSE_VALUE
; }
520 int back_edge_p () const { return get_flags () & EDGE_DFS_BACK
; }
522 size_t get_phi_arg_idx () const;
523 tree
get_phi_arg (const gphi
*phi
) const;
526 const ::edge m_cfg_edge
;
534 is_a_helper
<const cfg_superedge
*>::test (const superedge
*sedge
)
536 return sedge
->get_kind () == SUPEREDGE_CFG_EDGE
;
541 /* A subclass for edges from switch statements, retaining enough
542 information to identify the pertinent cases, and for adding labels
543 when rendering via graphviz. */
545 class switch_cfg_superedge
: public cfg_superedge
{
547 switch_cfg_superedge (supernode
*src
, supernode
*dst
, ::edge e
);
549 const switch_cfg_superedge
*dyn_cast_switch_cfg_superedge () const
555 void dump_label_to_pp (pretty_printer
*pp
, bool user_facing
) const
558 gswitch
*get_switch_stmt () const
560 return as_a
<gswitch
*> (m_src
->get_last_stmt ());
563 const vec
<tree
> &get_case_labels () const { return m_case_labels
; }
566 auto_vec
<tree
> m_case_labels
;
574 is_a_helper
<const switch_cfg_superedge
*>::test (const superedge
*sedge
)
576 return sedge
->dyn_cast_switch_cfg_superedge () != NULL
;
581 /* Base class for adding additional content to the .dot output
587 virtual ~dot_annotator () {}
588 virtual bool add_node_annotations (graphviz_out
*gv ATTRIBUTE_UNUSED
,
589 const supernode
&n ATTRIBUTE_UNUSED
,
590 bool within_table ATTRIBUTE_UNUSED
)
595 virtual void add_stmt_annotations (graphviz_out
*gv ATTRIBUTE_UNUSED
,
596 const gimple
*stmt ATTRIBUTE_UNUSED
,
597 bool within_row ATTRIBUTE_UNUSED
)
599 virtual bool add_after_node_annotations (graphviz_out
*gv ATTRIBUTE_UNUSED
,
600 const supernode
&n ATTRIBUTE_UNUSED
)
607 extern cgraph_edge
*supergraph_call_edge (function
*fun
, gimple
*stmt
);
611 #endif /* GCC_ANALYZER_SUPERGRAPH_H */