1/* "Supergraph" classes that combine CFGs and callgraph into one digraph.
2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#ifndef GCC_ANALYZER_SUPERGRAPH_H
22#define GCC_ANALYZER_SUPERGRAPH_H
23
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"
30#include "except.h"
31
32using namespace ana;
33
34namespace ana {
35
36/* Forward decls, using indentation to show inheritance. */
37
38class supergraph;
39class supernode;
40class superedge;
41 class callgraph_superedge;
42 class call_superedge;
43 class return_superedge;
44 class cfg_superedge;
45 class switch_cfg_superedge;
46 class eh_dispatch_cfg_superedge;
47 class eh_dispatch_try_cfg_superedge;
48 class eh_dispatch_allowed_cfg_superedge;
49class supercluster;
50class dot_annotator;
51
52class logger;
53
54/* An enum for discriminating between superedge subclasses. */
55
56enum edge_kind
57{
58 SUPEREDGE_CFG_EDGE,
59 SUPEREDGE_CALL,
60 SUPEREDGE_RETURN,
61 SUPEREDGE_INTRAPROCEDURAL_CALL
62};
63
64/* Flags for controlling the appearance of .dot dumps. */
65
66enum supergraph_dot_flags
67{
68 SUPERGRAPH_DOT_SHOW_BBS = (1 << 0)
69};
70
71/* A traits struct describing the family of node, edge and digraph
72 classes for supergraphs. */
73
74struct supergraph_traits
75{
76 typedef supernode node_t;
77 typedef superedge edge_t;
78 typedef supergraph graph_t;
79 struct dump_args_t
80 {
81 dump_args_t (enum supergraph_dot_flags flags,
82 const dot_annotator *node_annotator)
83 : m_flags (flags),
84 m_node_annotator (node_annotator)
85 {}
86
87 enum supergraph_dot_flags m_flags;
88 const dot_annotator *m_node_annotator;
89 };
90 typedef supercluster cluster_t;
91};
92
93/* A class to manage the setting and restoring of statement uids. */
94
95class saved_uids
96{
97public:
98 void make_uid_unique (gimple *stmt);
99 void restore_uids () const;
100
101private:
102 auto_vec<std::pair<gimple *, unsigned> > m_old_stmt_uids;
103};
104
105/* A "supergraph" is a directed graph formed by joining together all CFGs,
106 linking them via interprocedural call and return edges.
107
108 Basic blocks are split at callsites, so that a call statement occurs
109 twice: once at the end of a supernode, and a second instance at the
110 start of the next supernode (to handle the return). */
111
112class supergraph : public digraph<supergraph_traits>
113{
114public:
115 supergraph (logger *logger);
116 ~supergraph ();
117
118 supernode *get_node_for_function_entry (const function &fun) const
119 {
120 return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (&fun));
121 }
122
123 supernode *get_node_for_function_exit (const function &fun) const
124 {
125 return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (&fun));
126 }
127
128 supernode *get_node_for_block (basic_block bb) const
129 {
130 return *const_cast <bb_to_node_t &> (m_bb_to_initial_node).get (k: bb);
131 }
132
133 /* Get the supernode containing the second half of the gcall &
134 at an interprocedural call, within the caller. */
135 supernode *get_caller_next_node (cgraph_edge *edge) const
136 {
137 return (*const_cast <cgraph_edge_to_node_t &>
138 (m_cgraph_edge_to_caller_next_node).get (k: edge));
139 }
140
141 call_superedge *get_edge_for_call (cgraph_edge *edge) const
142 {
143 return (*const_cast <cgraph_edge_to_call_superedge_t &>
144 (m_cgraph_edge_to_call_superedge).get (k: edge));
145 }
146
147 return_superedge *get_edge_for_return (cgraph_edge *edge) const
148 {
149 return (*const_cast <cgraph_edge_to_return_superedge_t &>
150 (m_cgraph_edge_to_return_superedge).get (k: edge));
151 }
152
153 superedge *get_intraprocedural_edge_for_call (cgraph_edge *edge) const
154 {
155 return (*const_cast <cgraph_edge_to_intraproc_superedge_t &>
156 (m_cgraph_edge_to_intraproc_superedge).get (k: edge));
157 }
158
159 cfg_superedge *get_edge_for_cfg_edge (edge e) const
160 {
161 return (*const_cast <cfg_edge_to_cfg_superedge_t &>
162 (m_cfg_edge_to_cfg_superedge).get (k: e));
163 }
164
165 supernode *get_supernode_for_stmt (const gimple *stmt) const
166 {
167 return (*const_cast <stmt_to_node_t &>(m_stmt_to_node_t).get
168 (k: const_cast <gimple *> (stmt)));
169 }
170
171 void dump_dot_to_pp (pretty_printer *pp, const dump_args_t &) const;
172 void dump_dot_to_file (FILE *fp, const dump_args_t &) const;
173 void dump_dot (const char *path, const dump_args_t &) const;
174
175 std::unique_ptr<json::object> to_json () const;
176
177 int num_nodes () const { return m_nodes.length (); }
178 int num_edges () const { return m_edges.length (); }
179
180 supernode *get_node_by_index (int idx) const
181 {
182 return m_nodes[idx];
183 }
184
185 unsigned get_num_snodes (const function *fun) const
186 {
187 function_to_num_snodes_t &map
188 = const_cast <function_to_num_snodes_t &>(m_function_to_num_snodes);
189 return *map.get (k: fun);
190 }
191
192private:
193 supernode *add_node (function *fun, basic_block bb, gcall *returning_call,
194 gimple_seq phi_nodes);
195 cfg_superedge *add_cfg_edge (supernode *src, supernode *dest, ::edge e);
196 call_superedge *add_call_superedge (supernode *src, supernode *dest,
197 cgraph_edge *cedge);
198 return_superedge *add_return_superedge (supernode *src, supernode *dest,
199 cgraph_edge *cedge);
200
201 /* Data. */
202
203 typedef ordered_hash_map<basic_block, supernode *> bb_to_node_t;
204 bb_to_node_t m_bb_to_initial_node;
205 bb_to_node_t m_bb_to_final_node;
206
207 typedef ordered_hash_map<cgraph_edge *, supernode *> cgraph_edge_to_node_t;
208 cgraph_edge_to_node_t m_cgraph_edge_to_caller_prev_node;
209 cgraph_edge_to_node_t m_cgraph_edge_to_caller_next_node;
210
211 typedef ordered_hash_map< ::edge, cfg_superedge *>
212 cfg_edge_to_cfg_superedge_t;
213 cfg_edge_to_cfg_superedge_t m_cfg_edge_to_cfg_superedge;
214
215 typedef ordered_hash_map<cgraph_edge *, call_superedge *>
216 cgraph_edge_to_call_superedge_t;
217 cgraph_edge_to_call_superedge_t m_cgraph_edge_to_call_superedge;
218
219 typedef ordered_hash_map<cgraph_edge *, return_superedge *>
220 cgraph_edge_to_return_superedge_t;
221 cgraph_edge_to_return_superedge_t m_cgraph_edge_to_return_superedge;
222
223 typedef ordered_hash_map<cgraph_edge *, superedge *>
224 cgraph_edge_to_intraproc_superedge_t;
225 cgraph_edge_to_intraproc_superedge_t m_cgraph_edge_to_intraproc_superedge;
226
227 typedef ordered_hash_map<gimple *, supernode *> stmt_to_node_t;
228 stmt_to_node_t m_stmt_to_node_t;
229
230 typedef hash_map<const function *, unsigned> function_to_num_snodes_t;
231 function_to_num_snodes_t m_function_to_num_snodes;
232
233 saved_uids m_stmt_uids;
234};
235
236/* A node within a supergraph. */
237
238class supernode : public dnode<supergraph_traits>
239{
240 public:
241 supernode (function *fun, basic_block bb, gcall *returning_call,
242 gimple_seq phi_nodes, int index)
243 : m_fun (fun), m_bb (bb), m_returning_call (returning_call),
244 m_phi_nodes (phi_nodes), m_index (index)
245 {}
246
247 function *get_function () const { return m_fun; }
248
249 bool entry_p () const
250 {
251 return m_bb == ENTRY_BLOCK_PTR_FOR_FN (m_fun);
252 }
253
254 bool return_p () const
255 {
256 return m_bb == EXIT_BLOCK_PTR_FOR_FN (m_fun);
257 }
258
259 void dump_dot (graphviz_out *gv, const dump_args_t &args) const override;
260 void dump_dot_id (pretty_printer *pp) const;
261
262 std::unique_ptr<json::object> to_json () const;
263
264 location_t get_start_location () const;
265 location_t get_end_location () const;
266
267 /* Returns iterator at the start of the list of phi nodes, if any. */
268 gphi_iterator start_phis ()
269 {
270 gimple_seq *pseq = &m_phi_nodes;
271
272 /* Adapted from gsi_start_1. */
273 gphi_iterator i;
274
275 i.ptr = gimple_seq_first (s: *pseq);
276 i.seq = pseq;
277 i.bb = i.ptr ? gimple_bb (g: i.ptr) : NULL;
278
279 return i;
280 }
281
282 gcall *get_returning_call () const
283 {
284 return m_returning_call;
285 }
286
287 gimple *get_last_stmt () const
288 {
289 if (m_stmts.length () == 0)
290 return NULL;
291 return m_stmts[m_stmts.length () - 1];
292 }
293
294 gcall *get_final_call () const
295 {
296 gimple *stmt = get_last_stmt ();
297 if (stmt == NULL)
298 return NULL;
299 return dyn_cast<gcall *> (p: stmt);
300 }
301
302 unsigned int get_stmt_index (const gimple *stmt) const;
303
304 tree get_label () const;
305
306 function * const m_fun; // alternatively could be stored as runs of indices within the supergraph
307 const basic_block m_bb;
308 gcall * const m_returning_call; // for handling the result of a returned call
309 gimple_seq m_phi_nodes; // ptr to that of the underlying BB, for the first supernode for the BB
310 auto_vec<gimple *> m_stmts;
311 const int m_index; /* unique within the supergraph as a whole. */
312};
313
314/* An abstract base class encapsulating an edge within a supergraph.
315 Edges can be CFG edges, or calls/returns for callgraph edges. */
316
317class superedge : public dedge<supergraph_traits>
318{
319 public:
320 virtual ~superedge () {}
321
322 void dump (pretty_printer *pp) const;
323 void dump () const;
324 void dump_dot (graphviz_out *gv, const dump_args_t &args)
325 const final override;
326
327 virtual void dump_label_to_pp (pretty_printer *pp,
328 bool user_facing) const = 0;
329
330 std::unique_ptr<json::object> to_json () const;
331
332 enum edge_kind get_kind () const { return m_kind; }
333
334 virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; }
335 virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; }
336 virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return NULL; }
337 virtual const eh_dispatch_cfg_superedge *dyn_cast_eh_dispatch_cfg_superedge () const { return nullptr; }
338 virtual const eh_dispatch_try_cfg_superedge *dyn_cast_eh_dispatch_try_cfg_superedge () const { return nullptr; }
339 virtual const eh_dispatch_allowed_cfg_superedge *dyn_cast_eh_dispatch_allowed_cfg_superedge () const { return nullptr; }
340 virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; }
341 virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return NULL; }
342 virtual call_superedge *dyn_cast_call_superedge () { return NULL; }
343 virtual const call_superedge *dyn_cast_call_superedge () const { return NULL; }
344 virtual return_superedge *dyn_cast_return_superedge () { return NULL; }
345 virtual const return_superedge *dyn_cast_return_superedge () const { return NULL; }
346
347 ::edge get_any_cfg_edge () const;
348 cgraph_edge *get_any_callgraph_edge () const;
349
350 label_text get_description (bool user_facing) const;
351
352 protected:
353 superedge (supernode *src, supernode *dest, enum edge_kind kind)
354 : dedge<supergraph_traits> (src, dest),
355 m_kind (kind)
356 {}
357
358 public:
359 const enum edge_kind m_kind;
360};
361
362/* An ID representing an expression at a callsite:
363 either a parameter index, or the return value (or unknown). */
364
365class callsite_expr
366{
367 public:
368 callsite_expr () : m_val (-1) {}
369
370 static callsite_expr from_zero_based_param (int idx)
371 {
372 return callsite_expr (idx + 1);
373 }
374
375 static callsite_expr from_return_value ()
376 {
377 return callsite_expr (0);
378 }
379
380 bool param_p () const
381 {
382 return m_val > 0;
383 }
384
385 bool return_value_p () const
386 {
387 return m_val == 0;
388 }
389
390 private:
391 callsite_expr (int val) : m_val (val) {}
392
393 int m_val; /* 1-based parm, 0 for return value, or -1 for "unknown". */
394};
395
396/* A subclass of superedge with an associated callgraph edge (either a
397 call or a return). */
398
399class callgraph_superedge : public superedge
400{
401 public:
402 callgraph_superedge (supernode *src, supernode *dst, enum edge_kind kind,
403 cgraph_edge *cedge)
404 : superedge (src, dst, kind),
405 m_cedge (cedge)
406 {}
407
408 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
409 final override;
410
411 callgraph_superedge *dyn_cast_callgraph_superedge () final override
412 {
413 return this;
414 }
415 const callgraph_superedge *dyn_cast_callgraph_superedge () const
416 final override
417 {
418 return this;
419 }
420
421 function *get_callee_function () const;
422 function *get_caller_function () const;
423 tree get_callee_decl () const;
424 tree get_caller_decl () const;
425 const gcall &get_call_stmt () const;
426 tree get_arg_for_parm (tree parm, callsite_expr *out) const;
427 tree get_parm_for_arg (tree arg, callsite_expr *out) const;
428 tree map_expr_from_caller_to_callee (tree caller_expr,
429 callsite_expr *out) const;
430 tree map_expr_from_callee_to_caller (tree callee_expr,
431 callsite_expr *out) const;
432
433 cgraph_edge *const m_cedge;
434};
435
436} // namespace ana
437
438template <>
439template <>
440inline bool
441is_a_helper <const callgraph_superedge *>::test (const superedge *sedge)
442{
443 return (sedge->get_kind () == SUPEREDGE_INTRAPROCEDURAL_CALL
444 || sedge->get_kind () == SUPEREDGE_CALL
445 || sedge->get_kind () == SUPEREDGE_RETURN);
446}
447
448namespace ana {
449
450/* A subclass of superedge representing an interprocedural call. */
451
452class call_superedge : public callgraph_superedge
453{
454 public:
455 call_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
456 : callgraph_superedge (src, dst, SUPEREDGE_CALL, cedge)
457 {}
458
459 call_superedge *dyn_cast_call_superedge () final override
460 {
461 return this;
462 }
463 const call_superedge *dyn_cast_call_superedge () const final override
464 {
465 return this;
466 }
467
468 return_superedge *get_edge_for_return (const supergraph &sg) const
469 {
470 return sg.get_edge_for_return (edge: m_cedge);
471 }
472};
473
474} // namespace ana
475
476template <>
477template <>
478inline bool
479is_a_helper <const call_superedge *>::test (const superedge *sedge)
480{
481 return sedge->get_kind () == SUPEREDGE_CALL;
482}
483
484namespace ana {
485
486/* A subclass of superedge represesnting an interprocedural return. */
487
488class return_superedge : public callgraph_superedge
489{
490 public:
491 return_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
492 : callgraph_superedge (src, dst, SUPEREDGE_RETURN, cedge)
493 {}
494
495 return_superedge *dyn_cast_return_superedge () final override { return this; }
496 const return_superedge *dyn_cast_return_superedge () const final override
497 {
498 return this;
499 }
500
501 call_superedge *get_edge_for_call (const supergraph &sg) const
502 {
503 return sg.get_edge_for_call (edge: m_cedge);
504 }
505};
506
507} // namespace ana
508
509template <>
510template <>
511inline bool
512is_a_helper <const return_superedge *>::test (const superedge *sedge)
513{
514 return sedge->get_kind () == SUPEREDGE_RETURN;
515}
516
517namespace ana {
518
519/* A subclass of superedge that corresponds to a CFG edge. */
520
521class cfg_superedge : public superedge
522{
523 public:
524 cfg_superedge (supernode *src, supernode *dst, ::edge e)
525 : superedge (src, dst, SUPEREDGE_CFG_EDGE),
526 m_cfg_edge (e)
527 {}
528
529 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const override;
530 cfg_superedge *dyn_cast_cfg_superedge () final override { return this; }
531 const cfg_superedge *dyn_cast_cfg_superedge () const final override { return this; }
532
533 ::edge get_cfg_edge () const { return m_cfg_edge; }
534 int get_flags () const { return m_cfg_edge->flags; }
535 int true_value_p () const { return get_flags () & EDGE_TRUE_VALUE; }
536 int false_value_p () const { return get_flags () & EDGE_FALSE_VALUE; }
537 int back_edge_p () const { return get_flags () & EDGE_DFS_BACK; }
538
539 size_t get_phi_arg_idx () const;
540 tree get_phi_arg (const gphi *phi) const;
541
542 location_t get_goto_locus () const { return m_cfg_edge->goto_locus; }
543
544 private:
545 const ::edge m_cfg_edge;
546};
547
548} // namespace ana
549
550template <>
551template <>
552inline bool
553is_a_helper <const cfg_superedge *>::test (const superedge *sedge)
554{
555 return sedge->get_kind () == SUPEREDGE_CFG_EDGE;
556}
557
558namespace ana {
559
560/* A subclass for edges from switch statements, retaining enough
561 information to identify the pertinent cases, and for adding labels
562 when rendering via graphviz. */
563
564class switch_cfg_superedge : public cfg_superedge {
565 public:
566 switch_cfg_superedge (supernode *src, supernode *dst, ::edge e);
567
568 const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const
569 final override
570 {
571 return this;
572 }
573
574 void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
575 final override;
576
577 gswitch *get_switch_stmt () const
578 {
579 return as_a <gswitch *> (p: m_src->get_last_stmt ());
580 }
581
582 const vec<tree> &get_case_labels () const { return m_case_labels; }
583
584 bool implicitly_created_default_p () const;
585
586private:
587 auto_vec<tree> m_case_labels;
588};
589
590} // namespace ana
591
592template <>
593template <>
594inline bool
595is_a_helper <const switch_cfg_superedge *>::test (const superedge *sedge)
596{
597 return sedge->dyn_cast_switch_cfg_superedge () != NULL;
598}
599
600namespace ana {
601
602/* A subclass for edges from eh_dispatch statements, retaining enough
603 information to identify the various types being caught, vs the
604 "unhandled type" case, and for adding labels when rendering
605 via graphviz.
606 This is abstract; there are concrete subclasses based on the type
607 of the eh_region. */
608
609class eh_dispatch_cfg_superedge : public cfg_superedge
610{
611 public:
612 static std::unique_ptr<eh_dispatch_cfg_superedge>
613 make (supernode *src,
614 supernode *dest,
615 ::edge e,
616 const geh_dispatch *eh_dispatch_stmt);
617
618 const eh_dispatch_cfg_superedge *dyn_cast_eh_dispatch_cfg_superedge () const
619 final override
620 {
621 return this;
622 }
623
624 const geh_dispatch *
625 get_eh_dispatch_stmt () const
626 {
627 return m_eh_dispatch_stmt;
628 }
629
630 const eh_status &get_eh_status () const;
631 eh_region get_eh_region () const { return m_eh_region; }
632
633 virtual bool
634 apply_constraints (region_model *model,
635 region_model_context *ctxt,
636 tree exception_type,
637 std::unique_ptr<rejected_constraint> *out) const = 0;
638
639protected:
640 eh_dispatch_cfg_superedge (supernode *src, supernode *dst, ::edge e,
641 const geh_dispatch *eh_dispatch_stmt,
642 eh_region eh_reg);
643
644private:
645 const geh_dispatch *m_eh_dispatch_stmt;
646 eh_region m_eh_region;
647};
648
649} // namespace ana
650
651template <>
652template <>
653inline bool
654is_a_helper <const eh_dispatch_cfg_superedge *>::test (const superedge *sedge)
655{
656 return sedge->dyn_cast_eh_dispatch_cfg_superedge () != NULL;
657}
658
659namespace ana {
660
661/* A concrete subclass for edges from an eh_dispatch statements
662 for ERT_TRY regions. */
663
664class eh_dispatch_try_cfg_superedge : public eh_dispatch_cfg_superedge
665{
666 public:
667 eh_dispatch_try_cfg_superedge (supernode *src, supernode *dst, ::edge e,
668 const geh_dispatch *eh_dispatch_stmt,
669 eh_region eh_reg,
670 eh_catch ehc)
671 : eh_dispatch_cfg_superedge (src, dst, e, eh_dispatch_stmt, eh_reg),
672 m_eh_catch (ehc)
673 {
674 gcc_assert (eh_reg->type == ERT_TRY);
675 }
676
677 const eh_dispatch_try_cfg_superedge *
678 dyn_cast_eh_dispatch_try_cfg_superedge () const final override
679 {
680 return this;
681 }
682
683 void dump_label_to_pp (pretty_printer *pp,
684 bool user_facing) const final override;
685
686 eh_catch get_eh_catch () const { return m_eh_catch; }
687
688 bool
689 apply_constraints (region_model *model,
690 region_model_context *ctxt,
691 tree exception_type,
692 std::unique_ptr<rejected_constraint> *out)
693 const final override;
694
695private:
696 eh_catch m_eh_catch;
697};
698
699} // namespace ana
700
701template <>
702template <>
703inline bool
704is_a_helper <const eh_dispatch_try_cfg_superedge *>::test (const superedge *sedge)
705{
706 return sedge->dyn_cast_eh_dispatch_try_cfg_superedge () != NULL;
707}
708
709namespace ana {
710
711/* A concrete subclass for edges from an eh_dispatch statements
712 for ERT_ALLOWED_EXCEPTIONS regions. */
713
714class eh_dispatch_allowed_cfg_superedge : public eh_dispatch_cfg_superedge
715{
716 public:
717 enum eh_kind
718 {
719 expected,
720 unexpected
721 };
722
723 eh_dispatch_allowed_cfg_superedge (supernode *src, supernode *dst, ::edge e,
724 const geh_dispatch *eh_dispatch_stmt,
725 eh_region eh_reg);
726
727 const eh_dispatch_allowed_cfg_superedge *
728 dyn_cast_eh_dispatch_allowed_cfg_superedge () const final override
729 {
730 return this;
731 }
732
733 void dump_label_to_pp (pretty_printer *pp,
734 bool user_facing) const final override;
735
736 bool
737 apply_constraints (region_model *model,
738 region_model_context *ctxt,
739 tree exception_type,
740 std::unique_ptr<rejected_constraint> *out)
741 const final override;
742
743 enum eh_kind get_eh_kind () const { return m_kind; }
744
745private:
746 enum eh_kind m_kind;
747};
748
749} // namespace ana
750
751template <>
752template <>
753inline bool
754is_a_helper <const eh_dispatch_allowed_cfg_superedge *>::test (const superedge *sedge)
755{
756 return sedge->dyn_cast_eh_dispatch_allowed_cfg_superedge () != NULL;
757}
758
759namespace ana {
760/* Base class for adding additional content to the .dot output
761 for a supergraph. */
762
763class dot_annotator
764{
765 public:
766 virtual ~dot_annotator () {}
767 virtual bool add_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
768 const supernode &n ATTRIBUTE_UNUSED,
769 bool within_table ATTRIBUTE_UNUSED)
770 const
771 {
772 return false;
773 }
774 virtual void add_stmt_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
775 const gimple *stmt ATTRIBUTE_UNUSED,
776 bool within_row ATTRIBUTE_UNUSED)
777 const {}
778 virtual bool add_after_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
779 const supernode &n ATTRIBUTE_UNUSED)
780 const
781 {
782 return false;
783 }
784};
785
786extern cgraph_edge *supergraph_call_edge (function *fun, const gimple *stmt);
787extern function *get_ultimate_function_for_cgraph_edge (cgraph_edge *edge);
788
789} // namespace ana
790
791#endif /* GCC_ANALYZER_SUPERGRAPH_H */
792

source code of gcc/analyzer/supergraph.h