1 /* "Supergraph" classes that combine CFGs and callgraph into one digraph.
2 Copyright (C) 2019-2020 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/>. */
23 #include "coretypes.h"
27 #include "hash-table.h"
30 #include "basic-block.h"
32 #include "gimple-fold.h"
34 #include "gimple-expr.h"
38 #include "gimple-iterator.h"
39 #include "gimple-pretty-print.h"
40 #include "tree-pretty-print.h"
47 #include "analyzer/analyzer.h"
48 #include "ordered-hash-map.h"
53 #include "analyzer/supergraph.h"
54 #include "analyzer/analyzer-logging.h"
60 /* Get the function of the ultimate alias target being called at EDGE,
64 get_ultimate_function_for_cgraph_edge (cgraph_edge
*edge
)
66 cgraph_node
*ultimate_node
= edge
->callee
->ultimate_alias_target ();
69 return ultimate_node
->get_fun ();
72 /* Get the cgraph_edge, but only if there's an underlying function body. */
75 supergraph_call_edge (function
*fun
, gimple
*stmt
)
77 gcall
*call
= dyn_cast
<gcall
*> (stmt
);
80 cgraph_edge
*edge
= cgraph_node::get (fun
->decl
)->get_edge (stmt
);
84 return NULL
; /* e.g. for a function pointer. */
85 if (!get_ultimate_function_for_cgraph_edge (edge
))
90 /* supergraph's ctor. Walk the callgraph, building supernodes for each
91 CFG basic block, splitting the basic blocks at callsites. Join
92 together the supernodes with interprocedural and intraprocedural
93 superedges as appropriate. */
95 supergraph::supergraph (logger
*logger
)
97 auto_timevar
tv (TV_ANALYZER_SUPERGRAPH
);
101 /* First pass: make supernodes. */
103 /* Sort the cgraph_nodes? */
105 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
107 function
*fun
= node
->get_fun ();
109 /* Ensure that EDGE_DFS_BACK is correct for every CFG edge in
110 the supergraph (by doing it per-function). */
111 auto_cfun
sentinel (fun
);
112 mark_dfs_back_edges ();
114 const int start_idx
= m_nodes
.length ();
117 FOR_ALL_BB_FN (bb
, fun
)
119 /* The initial supernode for the BB gets the phi nodes (if any). */
120 supernode
*node_for_stmts
= add_node (fun
, bb
, NULL
, phi_nodes (bb
));
121 m_bb_to_initial_node
.put (bb
, node_for_stmts
);
122 for (gphi_iterator gpi
= gsi_start_phis (bb
); !gsi_end_p (gpi
);
125 gimple
*stmt
= gsi_stmt (gpi
);
126 m_stmt_to_node_t
.put (stmt
, node_for_stmts
);
129 /* Append statements from BB to the current supernode, splitting
130 them into a new supernode at each call site; such call statements
131 appear in both supernodes (representing call and return). */
132 gimple_stmt_iterator gsi
;
133 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
135 gimple
*stmt
= gsi_stmt (gsi
);
136 node_for_stmts
->m_stmts
.safe_push (stmt
);
137 m_stmt_to_node_t
.put (stmt
, node_for_stmts
);
138 if (cgraph_edge
*edge
= supergraph_call_edge (fun
, stmt
))
140 m_cgraph_edge_to_caller_prev_node
.put(edge
, node_for_stmts
);
141 node_for_stmts
= add_node (fun
, bb
, as_a
<gcall
*> (stmt
), NULL
);
142 m_cgraph_edge_to_caller_next_node
.put (edge
, node_for_stmts
);
146 m_bb_to_final_node
.put (bb
, node_for_stmts
);
149 const unsigned num_snodes
= m_nodes
.length () - start_idx
;
150 m_function_to_num_snodes
.put (fun
, num_snodes
);
154 const int end_idx
= m_nodes
.length () - 1;
155 logger
->log ("SN: %i...%i: function %qD",
156 start_idx
, end_idx
, fun
->decl
);
161 /* Second pass: make superedges. */
163 /* Make superedges for CFG edges. */
164 for (bb_to_node_t::iterator iter
= m_bb_to_final_node
.begin ();
165 iter
!= m_bb_to_final_node
.end ();
168 basic_block bb
= (*iter
).first
;
169 supernode
*src_supernode
= (*iter
).second
;
174 FOR_EACH_VEC_ELT (*bb
->succs
, idx
, cfg_edge
)
176 basic_block dest_cfg_block
= cfg_edge
->dest
;
177 supernode
*dest_supernode
178 = *m_bb_to_initial_node
.get (dest_cfg_block
);
179 cfg_superedge
*cfg_sedge
180 = add_cfg_edge (src_supernode
, dest_supernode
, cfg_edge
, idx
);
181 m_cfg_edge_to_cfg_superedge
.put (cfg_edge
, cfg_sedge
);
185 /* Make interprocedural superedges for calls. */
187 for (cgraph_edge_to_node_t::iterator iter
188 = m_cgraph_edge_to_caller_prev_node
.begin ();
189 iter
!= m_cgraph_edge_to_caller_prev_node
.end ();
192 cgraph_edge
*edge
= (*iter
).first
;
193 supernode
*caller_prev_supernode
= (*iter
).second
;
194 function
* callee_fn
= get_ultimate_function_for_cgraph_edge (edge
);
195 if (!callee_fn
|| !callee_fn
->cfg
)
197 basic_block callee_cfg_block
= ENTRY_BLOCK_PTR_FOR_FN (callee_fn
);
198 supernode
*callee_supernode
199 = *m_bb_to_initial_node
.get (callee_cfg_block
);
200 call_superedge
*sedge
201 = add_call_superedge (caller_prev_supernode
,
204 m_cgraph_edge_to_call_superedge
.put (edge
, sedge
);
208 /* Make interprocedural superedges for returns. */
210 for (cgraph_edge_to_node_t::iterator iter
211 = m_cgraph_edge_to_caller_next_node
.begin ();
212 iter
!= m_cgraph_edge_to_caller_next_node
.end ();
215 cgraph_edge
*edge
= (*iter
).first
;
216 supernode
*caller_next_supernode
= (*iter
).second
;
217 function
* callee_fn
= get_ultimate_function_for_cgraph_edge (edge
);
218 if (!callee_fn
|| !callee_fn
->cfg
)
220 basic_block callee_cfg_block
= EXIT_BLOCK_PTR_FOR_FN (callee_fn
);
221 supernode
*callee_supernode
222 = *m_bb_to_initial_node
.get (callee_cfg_block
);
223 return_superedge
*sedge
224 = add_return_superedge (callee_supernode
,
225 caller_next_supernode
,
227 m_cgraph_edge_to_return_superedge
.put (edge
, sedge
);
231 /* Make intraprocedural superedges linking the two halves of a call. */
233 for (cgraph_edge_to_node_t::iterator iter
234 = m_cgraph_edge_to_caller_prev_node
.begin ();
235 iter
!= m_cgraph_edge_to_caller_prev_node
.end ();
238 cgraph_edge
*edge
= (*iter
).first
;
239 supernode
*caller_prev_supernode
= (*iter
).second
;
240 supernode
*caller_next_supernode
241 = *m_cgraph_edge_to_caller_next_node
.get (edge
);
243 = new callgraph_superedge (caller_prev_supernode
,
244 caller_next_supernode
,
245 SUPEREDGE_INTRAPROCEDURAL_CALL
,
248 m_cgraph_edge_to_intraproc_superedge
.put (edge
, sedge
);
255 /* Dump this graph in .dot format to PP, using DUMP_ARGS.
256 Cluster the supernodes by function, then by BB from original CFG. */
259 supergraph::dump_dot_to_pp (pretty_printer
*pp
,
260 const dump_args_t
&dump_args
) const
262 graphviz_out
gv (pp
);
264 pp_string (pp
, "digraph \"");
265 pp_write_text_to_stream (pp
);
266 pp_string (pp
, "supergraph");
267 pp_write_text_as_dot_label_to_stream (pp
, /*for_record=*/false);
268 pp_string (pp
, "\" {\n");
271 gv
.println ("overlap=false;");
272 gv
.println ("compound=true;");
274 /* TODO: maybe (optionally) sub-subdivide by TU, for LTO; see also:
275 https://gcc-python-plugin.readthedocs.io/en/latest/_images/sample-supergraph.png
278 /* Break out the supernodes into clusters by function. */
281 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
283 function
*fun
= node
->get_fun ();
284 const char *funcname
= function_name (fun
);
285 gv
.println ("subgraph \"cluster_%s\" {",
294 /* Break out the nodes into clusters by BB from original CFG. */
297 FOR_ALL_BB_FN (bb
, fun
)
299 if (dump_args
.m_flags
& SUPERGRAPH_DOT_SHOW_BBS
)
301 gv
.println ("subgraph \"cluster_%s_bb_%i\" {",
302 funcname
, bb
->index
);
307 " label=\"bb: %i\";\n"),
311 // TODO: maybe keep an index per-function/per-bb to speed this up???
314 FOR_EACH_VEC_ELT (m_nodes
, i
, n
)
315 if (n
->m_fun
== fun
&& n
->m_bb
== bb
)
316 n
->dump_dot (&gv
, dump_args
);
318 if (dump_args
.m_flags
& SUPERGRAPH_DOT_SHOW_BBS
)
320 /* Terminate per-bb "subgraph" */
327 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
328 pp_string (pp
, "\t");
329 get_node_for_function_entry (fun
)->dump_dot_id (pp
);
330 pp_string (pp
, ":s -> ");
331 get_node_for_function_exit (fun
)->dump_dot_id (pp
);
332 pp_string (pp
, ":n [style=\"invis\",constraint=true];\n");
334 /* Terminate per-function "subgraph" */
343 FOR_EACH_VEC_ELT (m_edges
, i
, e
)
344 e
->dump_dot (&gv
, dump_args
);
346 /* Terminate "digraph" */
351 /* Dump this graph in .dot format to FP, using DUMP_ARGS. */
354 supergraph::dump_dot_to_file (FILE *fp
, const dump_args_t
&dump_args
) const
356 pretty_printer
*pp
= global_dc
->printer
->clone ();
357 pp_show_color (pp
) = 0;
358 /* %qE in logs for SSA_NAMEs should show the ssa names, rather than
359 trying to prettify things by showing the underlying var. */
360 pp_format_decoder (pp
) = default_tree_printer
;
362 pp
->buffer
->stream
= fp
;
363 dump_dot_to_pp (pp
, dump_args
);
368 /* Dump this graph in .dot format to PATH, using DUMP_ARGS. */
371 supergraph::dump_dot (const char *path
, const dump_args_t
&dump_args
) const
373 FILE *fp
= fopen (path
, "w");
374 dump_dot_to_file (fp
, dump_args
);
378 /* Return a new json::object of the form
379 {"nodes" : [objs for snodes],
380 "edges" : [objs for sedges]}. */
383 supergraph::to_json () const
385 json::object
*sgraph_obj
= new json::object ();
389 json::array
*nodes_arr
= new json::array ();
392 FOR_EACH_VEC_ELT (m_nodes
, i
, n
)
393 nodes_arr
->append (n
->to_json ());
394 sgraph_obj
->set ("nodes", nodes_arr
);
399 json::array
*edges_arr
= new json::array ();
402 FOR_EACH_VEC_ELT (m_edges
, i
, n
)
403 edges_arr
->append (n
->to_json ());
404 sgraph_obj
->set ("edges", edges_arr
);
410 /* Create a supernode for BB within FUN and add it to this supergraph.
412 If RETURNING_CALL is non-NULL, the supernode represents the resumption
413 of the basic block after returning from that call.
415 If PHI_NODES is non-NULL, this is the initial supernode for the basic
416 block, and is responsible for any handling of the phi nodes. */
419 supergraph::add_node (function
*fun
, basic_block bb
, gcall
*returning_call
,
420 gimple_seq phi_nodes
)
422 supernode
*n
= new supernode (fun
, bb
, returning_call
, phi_nodes
,
424 m_nodes
.safe_push (n
);
428 /* Create a new cfg_superedge from SRC to DEST for the underlying CFG edge E,
429 adding it to this supergraph.
431 If the edge is for a switch statement, create a switch_cfg_superedge
432 subclass using IDX (the index of E within the out-edges from SRC's
433 underlying basic block). */
436 supergraph::add_cfg_edge (supernode
*src
, supernode
*dest
, ::edge e
, int idx
)
438 /* Special-case switch edges. */
439 gimple
*stmt
= src
->get_last_stmt ();
440 cfg_superedge
*new_edge
;
441 if (stmt
&& stmt
->code
== GIMPLE_SWITCH
)
442 new_edge
= new switch_cfg_superedge (src
, dest
, e
, idx
);
444 new_edge
= new cfg_superedge (src
, dest
, e
);
449 /* Create and add a call_superedge representing an interprocedural call
450 from SRC to DEST, using CEDGE. */
453 supergraph::add_call_superedge (supernode
*src
, supernode
*dest
,
456 call_superedge
*new_edge
= new call_superedge (src
, dest
, cedge
);
461 /* Create and add a return_superedge representing returning from an
462 interprocedural call, returning from SRC to DEST, using CEDGE. */
465 supergraph::add_return_superedge (supernode
*src
, supernode
*dest
,
468 return_superedge
*new_edge
= new return_superedge (src
, dest
, cedge
);
473 /* Implementation of dnode::dump_dot vfunc for supernodes.
475 Write a cluster for the node, and within it a .dot node showing
476 the phi nodes and stmts. Call into any node annotator from ARGS to
477 potentially add other records to the cluster. */
480 supernode::dump_dot (graphviz_out
*gv
, const dump_args_t
&args
) const
482 gv
->println ("subgraph cluster_node_%i {",
486 gv
->println("style=\"solid\";");
487 gv
->println("color=\"black\";");
488 gv
->println("fillcolor=\"lightgrey\";");
489 gv
->println("label=\"sn: %i (bb: %i)\";", m_index
, m_bb
->index
);
491 pretty_printer
*pp
= gv
->get_pp ();
493 if (args
.m_node_annotator
)
494 args
.m_node_annotator
->add_node_annotations (gv
, *this, false);
499 " [shape=none,margin=0,style=filled,fillcolor=%s,label=<",
501 pp_string (pp
, "<TABLE BORDER=\"0\">");
502 pp_write_text_to_stream (pp
);
504 bool had_row
= false;
506 /* Give any annotator the chance to add its own per-node TR elements. */
507 if (args
.m_node_annotator
)
508 if (args
.m_node_annotator
->add_node_annotations (gv
, *this, true))
511 if (m_returning_call
)
514 pp_string (pp
, "returning call: ");
519 pp_gimple_stmt_1 (pp
, m_returning_call
, 0, (dump_flags_t
)0);
520 pp_write_text_as_html_like_dot_to_stream (pp
);
522 /* Give any annotator the chance to add per-stmt TD elements to
524 if (args
.m_node_annotator
)
525 args
.m_node_annotator
->add_stmt_annotations (gv
, m_returning_call
,
529 /* Give any annotator the chance to add per-stmt TR elements. */
530 if (args
.m_node_annotator
)
531 args
.m_node_annotator
->add_stmt_annotations (gv
, m_returning_call
,
540 pp_string (pp
, "<TR><TD>ENTRY</TD></TR>");
547 pp_string (pp
, "<TR><TD>EXIT</TD></TR>");
553 for (gphi_iterator gpi
= const_cast<supernode
*> (this)->start_phis ();
554 !gsi_end_p (gpi
); gsi_next (&gpi
))
556 const gimple
*stmt
= gsi_stmt (gpi
);
559 pp_gimple_stmt_1 (pp
, stmt
, 0, (dump_flags_t
)0);
560 pp_write_text_as_html_like_dot_to_stream (pp
);
562 /* Give any annotator the chance to add per-phi TD elements to
564 if (args
.m_node_annotator
)
565 args
.m_node_annotator
->add_stmt_annotations (gv
, stmt
, true);
568 /* Give any annotator the chance to add per-phi TR elements. */
569 if (args
.m_node_annotator
)
570 args
.m_node_annotator
->add_stmt_annotations (gv
, stmt
, false);
579 FOR_EACH_VEC_ELT (m_stmts
, i
, stmt
)
583 pp_gimple_stmt_1 (pp
, stmt
, 0, (dump_flags_t
)0);
584 pp_write_text_as_html_like_dot_to_stream (pp
);
586 /* Give any annotator the chance to add per-stmt TD elements to
588 if (args
.m_node_annotator
)
589 args
.m_node_annotator
->add_stmt_annotations (gv
, stmt
, true);
592 /* Give any annotator the chance to add per-stmt TR elements. */
593 if (args
.m_node_annotator
)
594 args
.m_node_annotator
->add_stmt_annotations (gv
, stmt
, false);
600 /* Give any annotator the chance to add additional per-node TR elements
601 to the end of the TABLE. */
602 if (args
.m_node_annotator
)
603 if (args
.m_node_annotator
->add_after_node_annotations (gv
, *this))
606 /* Graphviz requires a TABLE element to have at least one TR
607 (and each TR to have at least one TD). */
610 pp_string (pp
, "<TR><TD>(empty)</TD></TR>");
614 pp_string (pp
, "</TABLE>>];\n\n");
617 /* Terminate "subgraph" */
622 /* Write an ID for this node to PP, for use in .dot output. */
625 supernode::dump_dot_id (pretty_printer
*pp
) const
627 pp_printf (pp
, "node_%i", m_index
);
630 /* Return a new json::object of the form
633 "m_returning_call": optional str,
638 supernode::to_json () const
640 json::object
*snode_obj
= new json::object ();
642 snode_obj
->set ("idx", new json::integer_number (m_index
));
643 snode_obj
->set ("bb_idx", new json::integer_number (m_bb
->index
));
645 if (m_returning_call
)
648 pp_format_decoder (&pp
) = default_tree_printer
;
649 pp_gimple_stmt_1 (&pp
, m_returning_call
, 0, (dump_flags_t
)0);
650 snode_obj
->set ("returning_call",
651 new json::string (pp_formatted_text (&pp
)));
656 json::array
*phi_arr
= new json::array ();
657 for (gphi_iterator gpi
= const_cast<supernode
*> (this)->start_phis ();
658 !gsi_end_p (gpi
); gsi_next (&gpi
))
660 const gimple
*stmt
= gsi_stmt (gpi
);
662 pp_format_decoder (&pp
) = default_tree_printer
;
663 pp_gimple_stmt_1 (&pp
, stmt
, 0, (dump_flags_t
)0);
664 phi_arr
->append (new json::string (pp_formatted_text (&pp
)));
666 snode_obj
->set ("phis", phi_arr
);
671 json::array
*stmt_arr
= new json::array ();
674 FOR_EACH_VEC_ELT (m_stmts
, i
, stmt
)
677 pp_format_decoder (&pp
) = default_tree_printer
;
678 pp_gimple_stmt_1 (&pp
, stmt
, 0, (dump_flags_t
)0);
679 stmt_arr
->append (new json::string (pp_formatted_text (&pp
)));
681 snode_obj
->set ("stmts", stmt_arr
);
687 /* Get a location_t for the start of this supernode. */
690 supernode::get_start_location () const
693 && get_pure_location (m_returning_call
->location
) != UNKNOWN_LOCATION
)
694 return m_returning_call
->location
;
698 FOR_EACH_VEC_ELT (m_stmts
, i
, stmt
)
699 if (get_pure_location (stmt
->location
) != UNKNOWN_LOCATION
)
700 return stmt
->location
;
704 // TWEAK: show the decl instead; this leads to more readable output:
705 return DECL_SOURCE_LOCATION (m_fun
->decl
);
707 return m_fun
->function_start_locus
;
710 return m_fun
->function_end_locus
;
712 return UNKNOWN_LOCATION
;
715 /* Get a location_t for the end of this supernode. */
718 supernode::get_end_location () const
722 FOR_EACH_VEC_ELT_REVERSE (m_stmts
, i
, stmt
)
723 if (get_pure_location (stmt
->location
) != UNKNOWN_LOCATION
)
724 return stmt
->location
;
727 && get_pure_location (m_returning_call
->location
) != UNKNOWN_LOCATION
)
728 return m_returning_call
->location
;
731 return m_fun
->function_start_locus
;
733 return m_fun
->function_end_locus
;
735 return UNKNOWN_LOCATION
;
738 /* Given STMT within this supernode, return its index within m_stmts. */
741 supernode::get_stmt_index (const gimple
*stmt
) const
745 FOR_EACH_VEC_ELT (m_stmts
, i
, iter_stmt
)
746 if (iter_stmt
== stmt
)
751 /* Dump this superedge to PP. */
754 superedge::dump (pretty_printer
*pp
) const
756 pp_printf (pp
, "edge: SN: %i -> SN: %i", m_src
->m_index
, m_dest
->m_index
);
757 char *desc
= get_description (false);
758 if (strlen (desc
) > 0)
761 pp_string (pp
, desc
);
766 /* Dump this superedge to stderr. */
769 superedge::dump () const
772 pp_format_decoder (&pp
) = default_tree_printer
;
773 pp_show_color (&pp
) = pp_show_color (global_dc
->printer
);
774 pp
.buffer
->stream
= stderr
;
780 /* Implementation of dedge::dump_dot for superedges.
781 Write a .dot edge to GV representing this superedge. */
784 superedge::dump_dot (graphviz_out
*gv
, const dump_args_t
&) const
786 const char *style
= "\"solid,bold\"";
787 const char *color
= "black";
789 const char *constraint
= "true";
795 case SUPEREDGE_CFG_EDGE
:
800 case SUPEREDGE_RETURN
:
803 case SUPEREDGE_INTRAPROCEDURAL_CALL
:
804 style
= "\"dotted\"";
808 /* Adapted from graph.c:draw_cfg_node_succ_edges. */
809 if (::edge cfg_edge
= get_any_cfg_edge ())
811 if (cfg_edge
->flags
& EDGE_FAKE
)
817 else if (cfg_edge
->flags
& EDGE_DFS_BACK
)
819 style
= "\"dotted,bold\"";
823 else if (cfg_edge
->flags
& EDGE_FALLTHRU
)
829 if (cfg_edge
->flags
& EDGE_ABNORMAL
)
835 pretty_printer
*pp
= gv
->get_pp ();
837 m_src
->dump_dot_id (pp
);
838 pp_string (pp
, " -> ");
839 m_dest
->dump_dot_id (pp
);
841 (" [style=%s, color=%s, weight=%d, constraint=%s,"
842 " ltail=\"cluster_node_%i\", lhead=\"cluster_node_%i\""
844 style
, color
, weight
, constraint
,
845 m_src
->m_index
, m_dest
->m_index
);
847 dump_label_to_pp (pp
, false);
849 pp_printf (pp
, "\"];\n");
852 /* Return a new json::object of the form
853 {"src_idx": int, the index of the source supernode,
854 "dst_idx": int, the index of the destination supernode,
858 superedge::to_json () const
860 json::object
*sedge_obj
= new json::object ();
861 sedge_obj
->set ("src_idx", new json::integer_number (m_src
->m_index
));
862 sedge_obj
->set ("dst_idx", new json::integer_number (m_dest
->m_index
));
866 pp_format_decoder (&pp
) = default_tree_printer
;
867 dump_label_to_pp (&pp
, false);
868 sedge_obj
->set ("desc", new json::string (pp_formatted_text (&pp
)));
874 /* If this is an intraprocedural superedge, return the associated
875 CFG edge. Otherwise, return NULL. */
878 superedge::get_any_cfg_edge () const
880 if (const cfg_superedge
*sub
= dyn_cast_cfg_superedge ())
881 return sub
->get_cfg_edge ();
885 /* If this is an interprocedural superedge, return the associated
886 cgraph_edge *. Otherwise, return NULL. */
889 superedge::get_any_callgraph_edge () const
891 if (const callgraph_superedge
*sub
= dyn_cast_callgraph_superedge ())
896 /* Build a description of this superedge (e.g. "true" for the true
897 edge of a conditional, or "case 42:" for a switch case).
899 The caller is responsible for freeing the result.
901 If USER_FACING is false, the result also contains any underlying
902 CFG edge flags. e.g. " (flags FALLTHRU | DFS_BACK)". */
905 superedge::get_description (bool user_facing
) const
908 dump_label_to_pp (&pp
, user_facing
);
909 return xstrdup (pp_formatted_text (&pp
));
912 /* Implementation of superedge::dump_label_to_pp for non-switch CFG
915 For true/false edges, print "true" or "false" to PP.
917 If USER_FACING is false, also print flags on the underlying CFG edge to
921 cfg_superedge::dump_label_to_pp (pretty_printer
*pp
,
922 bool user_facing
) const
925 pp_printf (pp
, "true");
926 else if (false_value_p ())
927 pp_printf (pp
, "false");
932 /* Express edge flags as a string with " | " separator.
933 e.g. " (flags FALLTHRU | DFS_BACK)". */
936 pp_string (pp
, " (flags ");
937 bool seen_flag
= false;
938 #define DEF_EDGE_FLAG(NAME,IDX) \
940 if (get_flags () & EDGE_##NAME) \
943 pp_string (pp, " | "); \
944 pp_printf (pp, "%s", (#NAME)); \
948 #include "cfg-flags.def"
953 /* Otherwise, no label. */
956 /* Get the phi argument for PHI for this CFG edge. */
959 cfg_superedge::get_phi_arg (const gphi
*phi
) const
961 size_t index
= m_cfg_edge
->dest_idx
;
962 return gimple_phi_arg_def (phi
, index
);
965 /* Implementation of superedge::dump_label_to_pp for CFG superedges for
968 Print "case VAL:", "case LOWER ... UPPER:", or "default:" to PP. */
971 switch_cfg_superedge::dump_label_to_pp (pretty_printer
*pp
,
972 bool user_facing ATTRIBUTE_UNUSED
) const
974 tree case_label
= get_case_label ();
975 gcc_assert (TREE_CODE (case_label
) == CASE_LABEL_EXPR
);
976 tree lower_bound
= CASE_LOW (case_label
);
977 tree upper_bound
= CASE_HIGH (case_label
);
980 pp_printf (pp
, "case ");
981 dump_generic_node (pp
, lower_bound
, 0, (dump_flags_t
)0, false);
984 pp_printf (pp
, " ... ");
985 dump_generic_node (pp
, upper_bound
, 0, (dump_flags_t
)0, false);
990 pp_printf (pp
, "default:");
993 /* Get the case label for this "switch" superedge. */
996 switch_cfg_superedge::get_case_label () const
998 return gimple_switch_label (get_switch_stmt (), m_idx
);
1001 /* Implementation of superedge::dump_label_to_pp for interprocedural
1005 callgraph_superedge::dump_label_to_pp (pretty_printer
*pp
,
1006 bool user_facing ATTRIBUTE_UNUSED
) const
1011 case SUPEREDGE_CFG_EDGE
:
1014 case SUPEREDGE_CALL
:
1015 pp_printf (pp
, "call");
1018 case SUPEREDGE_RETURN
:
1019 pp_printf (pp
, "return");
1022 case SUPEREDGE_INTRAPROCEDURAL_CALL
:
1023 pp_printf (pp
, "intraproc link");
1028 /* Get the function that was called at this interprocedural call/return
1032 callgraph_superedge::get_callee_function () const
1034 return get_ultimate_function_for_cgraph_edge (m_cedge
);
1037 /* Get the calling function at this interprocedural call/return edge. */
1040 callgraph_superedge::get_caller_function () const
1042 return m_cedge
->caller
->get_fun ();
1045 /* Get the fndecl that was called at this interprocedural call/return
1049 callgraph_superedge::get_callee_decl () const
1051 return get_callee_function ()->decl
;
1054 /* Get the calling fndecl at this interprocedural call/return edge. */
1057 callgraph_superedge::get_caller_decl () const
1059 return get_caller_function ()->decl
;
1062 /* Given PARM_TO_FIND, a PARM_DECL, identify its index (writing it
1063 to *OUT if OUT is non-NULL), and return the corresponding argument
1067 callgraph_superedge::get_arg_for_parm (tree parm_to_find
,
1068 callsite_expr
*out
) const
1070 gcc_assert (TREE_CODE (parm_to_find
) == PARM_DECL
);
1072 tree callee
= get_callee_decl ();
1073 const gcall
*call_stmt
= get_call_stmt ();
1076 for (tree iter_parm
= DECL_ARGUMENTS (callee
); iter_parm
;
1077 iter_parm
= DECL_CHAIN (iter_parm
), ++i
)
1079 if (i
>= gimple_call_num_args (call_stmt
))
1081 if (iter_parm
== parm_to_find
)
1084 *out
= callsite_expr::from_zero_based_param (i
);
1085 return gimple_call_arg (call_stmt
, i
);
1093 /* Look for a use of ARG_TO_FIND as an argument at this callsite.
1094 If found, return the default SSA def of the corresponding parm within
1095 the callee, and if OUT is non-NULL, write the index to *OUT.
1096 Only the first match is handled. */
1099 callgraph_superedge::get_parm_for_arg (tree arg_to_find
,
1100 callsite_expr
*out
) const
1102 tree callee
= get_callee_decl ();
1103 const gcall
*call_stmt
= get_call_stmt ();
1106 for (tree iter_parm
= DECL_ARGUMENTS (callee
); iter_parm
;
1107 iter_parm
= DECL_CHAIN (iter_parm
), ++i
)
1109 if (i
>= gimple_call_num_args (call_stmt
))
1111 tree param
= gimple_call_arg (call_stmt
, i
);
1112 if (arg_to_find
== param
)
1115 *out
= callsite_expr::from_zero_based_param (i
);
1116 return ssa_default_def (get_callee_function (), iter_parm
);
1124 /* Map caller_expr back to an expr within the callee, or return NULL_TREE.
1125 If non-NULL is returned, populate OUT. */
1128 callgraph_superedge::map_expr_from_caller_to_callee (tree caller_expr
,
1129 callsite_expr
*out
) const
1131 /* Is it an argument (actual param)? If so, convert to
1132 parameter (formal param). */
1133 tree parm
= get_parm_for_arg (caller_expr
, out
);
1136 /* Otherwise try return value. */
1137 if (caller_expr
== gimple_call_lhs (get_call_stmt ()))
1140 *out
= callsite_expr::from_return_value ();
1141 return DECL_RESULT (get_callee_decl ());
1147 /* Map callee_expr back to an expr within the caller, or return NULL_TREE.
1148 If non-NULL is returned, populate OUT. */
1151 callgraph_superedge::map_expr_from_callee_to_caller (tree callee_expr
,
1152 callsite_expr
*out
) const
1154 if (callee_expr
== NULL_TREE
)
1157 /* If it's a parameter (formal param), get the argument (actual param). */
1158 if (TREE_CODE (callee_expr
) == PARM_DECL
)
1159 return get_arg_for_parm (callee_expr
, out
);
1161 /* Similar for the default SSA name of the PARM_DECL. */
1162 if (TREE_CODE (callee_expr
) == SSA_NAME
1163 && SSA_NAME_IS_DEFAULT_DEF (callee_expr
)
1164 && TREE_CODE (SSA_NAME_VAR (callee_expr
)) == PARM_DECL
)
1165 return get_arg_for_parm (SSA_NAME_VAR (callee_expr
), out
);
1167 /* Otherwise try return value. */
1168 if (callee_expr
== DECL_RESULT (get_callee_decl ()))
1171 *out
= callsite_expr::from_return_value ();
1172 return gimple_call_lhs (get_call_stmt ());
1180 #endif /* #if ENABLE_ANALYZER */