]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/analyzer/supergraph.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / analyzer / supergraph.cc
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>.
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>. */
20
21 #include "config.h"
22 #define INCLUDE_MEMORY
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "tm.h"
27 #include "toplev.h"
28 #include "hash-table.h"
29 #include "vec.h"
30 #include "ggc.h"
31 #include "basic-block.h"
32 #include "function.h"
33 #include "gimple.h"
34 #include "gimple-iterator.h"
35 #include "gimple-fold.h"
36 #include "tree-eh.h"
37 #include "gimple-expr.h"
38 #include "is-a.h"
39 #include "timevar.h"
40 #include "gimple-pretty-print.h"
41 #include "tree-pretty-print.h"
42 #include "graphviz.h"
43 #include "cgraph.h"
44 #include "tree-dfa.h"
45 #include "bitmap.h"
46 #include "cfganal.h"
47 #include "function.h"
48 #include "analyzer/analyzer.h"
49 #include "ordered-hash-map.h"
50 #include "options.h"
51 #include "cgraph.h"
52 #include "cfg.h"
53 #include "digraph.h"
54 #include "tree-cfg.h"
55 #include "analyzer/supergraph.h"
56 #include "analyzer/analyzer-logging.h"
57
58 #if ENABLE_ANALYZER
59
60 namespace ana {
61
62 /* Get the function of the ultimate alias target being called at EDGE,
63 if any. */
64
65 function *
66 get_ultimate_function_for_cgraph_edge (cgraph_edge *edge)
67 {
68 cgraph_node *ultimate_node = edge->callee->ultimate_alias_target ();
69 if (!ultimate_node)
70 return NULL;
71 return ultimate_node->get_fun ();
72 }
73
74 /* Get the cgraph_edge, but only if there's an underlying function body. */
75
76 cgraph_edge *
77 supergraph_call_edge (function *fun, const gimple *stmt)
78 {
79 const gcall *call = dyn_cast<const gcall *> (stmt);
80 if (!call)
81 return NULL;
82 cgraph_edge *edge
83 = cgraph_node::get (fun->decl)->get_edge (const_cast <gimple *> (stmt));
84 if (!edge)
85 return NULL;
86 if (!edge->callee)
87 return NULL; /* e.g. for a function pointer. */
88 if (!get_ultimate_function_for_cgraph_edge (edge))
89 return NULL;
90 return edge;
91 }
92
93 /* class saved_uids.
94
95 In order to ensure consistent results without relying on the ordering
96 of pointer values we assign a uid to each gimple stmt, globally unique
97 across all functions.
98
99 Normally, the stmt uids are a scratch space that each pass can freely
100 assign its own values to. However, in the case of LTO, the uids are
101 used to associate call stmts with callgraph edges between the WPA phase
102 (where the analyzer runs in LTO mode) and the LTRANS phase; if the
103 analyzer changes them in the WPA phase, it leads to errors when
104 streaming the code back in at LTRANS.
105 lto_prepare_function_for_streaming has code to renumber the stmt UIDs
106 when the code is streamed back out, but for some reason this isn't
107 called for clones.
108
109 Hence, as a workaround, this class has responsibility for tracking
110 the original uids and restoring them once the pass is complete
111 (in the supergraph dtor). */
112
113 /* Give STMT a globally unique uid, storing its original uid so it can
114 later be restored. */
115
116 void
117 saved_uids::make_uid_unique (gimple *stmt)
118 {
119 unsigned next_uid = m_old_stmt_uids.length ();
120 unsigned old_stmt_uid = stmt->uid;
121 stmt->uid = next_uid;
122 m_old_stmt_uids.safe_push
123 (std::pair<gimple *, unsigned> (stmt, old_stmt_uid));
124 }
125
126 /* Restore the saved uids of all stmts. */
127
128 void
129 saved_uids::restore_uids () const
130 {
131 unsigned i;
132 std::pair<gimple *, unsigned> *pair;
133 FOR_EACH_VEC_ELT (m_old_stmt_uids, i, pair)
134 pair->first->uid = pair->second;
135 }
136
137 /* supergraph's ctor. Walk the callgraph, building supernodes for each
138 CFG basic block, splitting the basic blocks at callsites. Join
139 together the supernodes with interprocedural and intraprocedural
140 superedges as appropriate.
141 Assign UIDs to the gimple stmts. */
142
143 supergraph::supergraph (logger *logger)
144 {
145 auto_timevar tv (TV_ANALYZER_SUPERGRAPH);
146
147 LOG_FUNC (logger);
148
149 /* First pass: make supernodes (and assign UIDs to the gimple stmts). */
150 {
151 /* Sort the cgraph_nodes? */
152 cgraph_node *node;
153 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
154 {
155 function *fun = node->get_fun ();
156
157 /* Ensure that EDGE_DFS_BACK is correct for every CFG edge in
158 the supergraph (by doing it per-function). */
159 auto_cfun sentinel (fun);
160 mark_dfs_back_edges ();
161
162 const int start_idx = m_nodes.length ();
163
164 basic_block bb;
165 FOR_ALL_BB_FN (bb, fun)
166 {
167 /* The initial supernode for the BB gets the phi nodes (if any). */
168 supernode *node_for_stmts = add_node (fun, bb, NULL, phi_nodes (bb));
169 m_bb_to_initial_node.put (bb, node_for_stmts);
170 for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi);
171 gsi_next (&gpi))
172 {
173 gimple *stmt = gsi_stmt (gpi);
174 m_stmt_to_node_t.put (stmt, node_for_stmts);
175 m_stmt_uids.make_uid_unique (stmt);
176 }
177
178 /* Append statements from BB to the current supernode, splitting
179 them into a new supernode at each call site; such call statements
180 appear in both supernodes (representing call and return). */
181 gimple_stmt_iterator gsi;
182 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
183 {
184 gimple *stmt = gsi_stmt (gsi);
185 node_for_stmts->m_stmts.safe_push (stmt);
186 m_stmt_to_node_t.put (stmt, node_for_stmts);
187 m_stmt_uids.make_uid_unique (stmt);
188 if (cgraph_edge *edge = supergraph_call_edge (fun, stmt))
189 {
190 m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts);
191 node_for_stmts = add_node (fun, bb, as_a <gcall *> (stmt),
192 NULL);
193 m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts);
194 }
195 else
196 {
197 // maybe call is via a function pointer
198 if (gcall *call = dyn_cast<gcall *> (stmt))
199 {
200 cgraph_edge *edge
201 = cgraph_node::get (fun->decl)->get_edge (stmt);
202 if (!edge || !edge->callee)
203 {
204 supernode *old_node_for_stmts = node_for_stmts;
205 node_for_stmts = add_node (fun, bb, call, NULL);
206
207 superedge *sedge
208 = new callgraph_superedge (old_node_for_stmts,
209 node_for_stmts,
210 SUPEREDGE_INTRAPROCEDURAL_CALL,
211 NULL);
212 add_edge (sedge);
213 }
214 }
215 }
216 }
217
218 m_bb_to_final_node.put (bb, node_for_stmts);
219 }
220
221 const unsigned num_snodes = m_nodes.length () - start_idx;
222 m_function_to_num_snodes.put (fun, num_snodes);
223
224 if (logger)
225 {
226 const int end_idx = m_nodes.length () - 1;
227 logger->log ("SN: %i...%i: function %qD",
228 start_idx, end_idx, fun->decl);
229 }
230 }
231 }
232
233 /* Second pass: make superedges. */
234 {
235 /* Make superedges for CFG edges. */
236 for (bb_to_node_t::iterator iter = m_bb_to_final_node.begin ();
237 iter != m_bb_to_final_node.end ();
238 ++iter)
239 {
240 basic_block bb = (*iter).first;
241 supernode *src_supernode = (*iter).second;
242
243 ::edge cfg_edge;
244 int idx;
245 if (bb->succs)
246 FOR_EACH_VEC_ELT (*bb->succs, idx, cfg_edge)
247 {
248 basic_block dest_cfg_block = cfg_edge->dest;
249 supernode *dest_supernode
250 = *m_bb_to_initial_node.get (dest_cfg_block);
251 cfg_superedge *cfg_sedge
252 = add_cfg_edge (src_supernode, dest_supernode, cfg_edge);
253 m_cfg_edge_to_cfg_superedge.put (cfg_edge, cfg_sedge);
254 }
255 }
256
257 /* Make interprocedural superedges for calls. */
258 {
259 for (cgraph_edge_to_node_t::iterator iter
260 = m_cgraph_edge_to_caller_prev_node.begin ();
261 iter != m_cgraph_edge_to_caller_prev_node.end ();
262 ++iter)
263 {
264 cgraph_edge *edge = (*iter).first;
265 supernode *caller_prev_supernode = (*iter).second;
266 function* callee_fn = get_ultimate_function_for_cgraph_edge (edge);
267 if (!callee_fn || !callee_fn->cfg)
268 continue;
269 basic_block callee_cfg_block = ENTRY_BLOCK_PTR_FOR_FN (callee_fn);
270 supernode *callee_supernode
271 = *m_bb_to_initial_node.get (callee_cfg_block);
272 call_superedge *sedge
273 = add_call_superedge (caller_prev_supernode,
274 callee_supernode,
275 edge);
276 m_cgraph_edge_to_call_superedge.put (edge, sedge);
277 }
278 }
279
280 /* Make interprocedural superedges for returns. */
281 {
282 for (cgraph_edge_to_node_t::iterator iter
283 = m_cgraph_edge_to_caller_next_node.begin ();
284 iter != m_cgraph_edge_to_caller_next_node.end ();
285 ++iter)
286 {
287 cgraph_edge *edge = (*iter).first;
288 supernode *caller_next_supernode = (*iter).second;
289 function* callee_fn = get_ultimate_function_for_cgraph_edge (edge);
290 if (!callee_fn || !callee_fn->cfg)
291 continue;
292 basic_block callee_cfg_block = EXIT_BLOCK_PTR_FOR_FN (callee_fn);
293 supernode *callee_supernode
294 = *m_bb_to_initial_node.get (callee_cfg_block);
295 return_superedge *sedge
296 = add_return_superedge (callee_supernode,
297 caller_next_supernode,
298 edge);
299 m_cgraph_edge_to_return_superedge.put (edge, sedge);
300 }
301 }
302
303 /* Make intraprocedural superedges linking the two halves of a call. */
304 {
305 for (cgraph_edge_to_node_t::iterator iter
306 = m_cgraph_edge_to_caller_prev_node.begin ();
307 iter != m_cgraph_edge_to_caller_prev_node.end ();
308 ++iter)
309 {
310 cgraph_edge *edge = (*iter).first;
311 supernode *caller_prev_supernode = (*iter).second;
312 supernode *caller_next_supernode
313 = *m_cgraph_edge_to_caller_next_node.get (edge);
314 superedge *sedge
315 = new callgraph_superedge (caller_prev_supernode,
316 caller_next_supernode,
317 SUPEREDGE_INTRAPROCEDURAL_CALL,
318 edge);
319 add_edge (sedge);
320 m_cgraph_edge_to_intraproc_superedge.put (edge, sedge);
321 }
322
323 }
324 }
325 }
326
327 /* supergraph's dtor. Reset stmt uids. */
328
329 supergraph::~supergraph ()
330 {
331 m_stmt_uids.restore_uids ();
332 }
333
334 /* Dump this graph in .dot format to PP, using DUMP_ARGS.
335 Cluster the supernodes by function, then by BB from original CFG. */
336
337 void
338 supergraph::dump_dot_to_pp (pretty_printer *pp,
339 const dump_args_t &dump_args) const
340 {
341 graphviz_out gv (pp);
342
343 pp_string (pp, "digraph \"");
344 pp_write_text_to_stream (pp);
345 pp_string (pp, "supergraph");
346 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
347 pp_string (pp, "\" {\n");
348 gv.indent ();
349
350 gv.println ("overlap=false;");
351 gv.println ("compound=true;");
352
353 /* TODO: maybe (optionally) sub-subdivide by TU, for LTO; see also:
354 https://gcc-python-plugin.readthedocs.io/en/latest/_images/sample-supergraph.png
355 */
356
357 /* Break out the supernodes into clusters by function. */
358 {
359 cgraph_node *node;
360 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
361 {
362 function *fun = node->get_fun ();
363 const char *funcname = function_name (fun);
364 gv.println ("subgraph \"cluster_%s\" {",
365 funcname);
366 gv.indent ();
367 pp_printf (pp,
368 ("style=\"dashed\";"
369 " color=\"black\";"
370 " label=\"%s\";\n"),
371 funcname);
372
373 /* Break out the nodes into clusters by BB from original CFG. */
374 {
375 basic_block bb;
376 FOR_ALL_BB_FN (bb, fun)
377 {
378 if (dump_args.m_flags & SUPERGRAPH_DOT_SHOW_BBS)
379 {
380 gv.println ("subgraph \"cluster_%s_bb_%i\" {",
381 funcname, bb->index);
382 gv.indent ();
383 pp_printf (pp,
384 ("style=\"dashed\";"
385 " color=\"black\";"
386 " label=\"bb: %i\";\n"),
387 bb->index);
388 }
389
390 // TODO: maybe keep an index per-function/per-bb to speed this up???
391 int i;
392 supernode *n;
393 FOR_EACH_VEC_ELT (m_nodes, i, n)
394 if (n->m_fun == fun && n->m_bb == bb)
395 n->dump_dot (&gv, dump_args);
396
397 if (dump_args.m_flags & SUPERGRAPH_DOT_SHOW_BBS)
398 {
399 /* Terminate per-bb "subgraph" */
400 gv.outdent ();
401 gv.println ("}");
402 }
403 }
404 }
405
406 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
407 pp_string (pp, "\t");
408 get_node_for_function_entry (fun)->dump_dot_id (pp);
409 pp_string (pp, ":s -> ");
410 get_node_for_function_exit (fun)->dump_dot_id (pp);
411 pp_string (pp, ":n [style=\"invis\",constraint=true];\n");
412
413 /* Terminate per-function "subgraph" */
414 gv.outdent ();
415 gv.println ("}");
416 }
417 }
418
419 /* Superedges. */
420 int i;
421 superedge *e;
422 FOR_EACH_VEC_ELT (m_edges, i, e)
423 e->dump_dot (&gv, dump_args);
424
425 /* Terminate "digraph" */
426 gv.outdent ();
427 gv.println ("}");
428 }
429
430 /* Dump this graph in .dot format to FP, using DUMP_ARGS. */
431
432 void
433 supergraph::dump_dot_to_file (FILE *fp, const dump_args_t &dump_args) const
434 {
435 pretty_printer *pp = global_dc->printer->clone ();
436 pp_show_color (pp) = 0;
437 /* %qE in logs for SSA_NAMEs should show the ssa names, rather than
438 trying to prettify things by showing the underlying var. */
439 pp_format_decoder (pp) = default_tree_printer;
440
441 pp->buffer->stream = fp;
442 dump_dot_to_pp (pp, dump_args);
443 pp_flush (pp);
444 delete pp;
445 }
446
447 /* Dump this graph in .dot format to PATH, using DUMP_ARGS. */
448
449 void
450 supergraph::dump_dot (const char *path, const dump_args_t &dump_args) const
451 {
452 FILE *fp = fopen (path, "w");
453 dump_dot_to_file (fp, dump_args);
454 fclose (fp);
455 }
456
457 /* Return a new json::object of the form
458 {"nodes" : [objs for snodes],
459 "edges" : [objs for sedges]}. */
460
461 json::object *
462 supergraph::to_json () const
463 {
464 json::object *sgraph_obj = new json::object ();
465
466 /* Nodes. */
467 {
468 json::array *nodes_arr = new json::array ();
469 unsigned i;
470 supernode *n;
471 FOR_EACH_VEC_ELT (m_nodes, i, n)
472 nodes_arr->append (n->to_json ());
473 sgraph_obj->set ("nodes", nodes_arr);
474 }
475
476 /* Edges. */
477 {
478 json::array *edges_arr = new json::array ();
479 unsigned i;
480 superedge *n;
481 FOR_EACH_VEC_ELT (m_edges, i, n)
482 edges_arr->append (n->to_json ());
483 sgraph_obj->set ("edges", edges_arr);
484 }
485
486 return sgraph_obj;
487 }
488
489 /* Create a supernode for BB within FUN and add it to this supergraph.
490
491 If RETURNING_CALL is non-NULL, the supernode represents the resumption
492 of the basic block after returning from that call.
493
494 If PHI_NODES is non-NULL, this is the initial supernode for the basic
495 block, and is responsible for any handling of the phi nodes. */
496
497 supernode *
498 supergraph::add_node (function *fun, basic_block bb, gcall *returning_call,
499 gimple_seq phi_nodes)
500 {
501 supernode *n = new supernode (fun, bb, returning_call, phi_nodes,
502 m_nodes.length ());
503 m_nodes.safe_push (n);
504 return n;
505 }
506
507 /* Create a new cfg_superedge from SRC to DEST for the underlying CFG edge E,
508 adding it to this supergraph.
509
510 If the edge is for a switch statement, create a switch_cfg_superedge
511 subclass. */
512
513 cfg_superedge *
514 supergraph::add_cfg_edge (supernode *src, supernode *dest, ::edge e)
515 {
516 /* Special-case switch edges. */
517 gimple *stmt = src->get_last_stmt ();
518 cfg_superedge *new_edge;
519 if (stmt && stmt->code == GIMPLE_SWITCH)
520 new_edge = new switch_cfg_superedge (src, dest, e);
521 else
522 new_edge = new cfg_superedge (src, dest, e);
523 add_edge (new_edge);
524 return new_edge;
525 }
526
527 /* Create and add a call_superedge representing an interprocedural call
528 from SRC to DEST, using CEDGE. */
529
530 call_superedge *
531 supergraph::add_call_superedge (supernode *src, supernode *dest,
532 cgraph_edge *cedge)
533 {
534 call_superedge *new_edge = new call_superedge (src, dest, cedge);
535 add_edge (new_edge);
536 return new_edge;
537 }
538
539 /* Create and add a return_superedge representing returning from an
540 interprocedural call, returning from SRC to DEST, using CEDGE. */
541
542 return_superedge *
543 supergraph::add_return_superedge (supernode *src, supernode *dest,
544 cgraph_edge *cedge)
545 {
546 return_superedge *new_edge = new return_superedge (src, dest, cedge);
547 add_edge (new_edge);
548 return new_edge;
549 }
550
551 /* Implementation of dnode::dump_dot vfunc for supernodes.
552
553 Write a cluster for the node, and within it a .dot node showing
554 the phi nodes and stmts. Call into any node annotator from ARGS to
555 potentially add other records to the cluster. */
556
557 void
558 supernode::dump_dot (graphviz_out *gv, const dump_args_t &args) const
559 {
560 gv->println ("subgraph cluster_node_%i {",
561 m_index);
562 gv->indent ();
563
564 gv->println("style=\"solid\";");
565 gv->println("color=\"black\";");
566 gv->println("fillcolor=\"lightgrey\";");
567 gv->println("label=\"sn: %i (bb: %i)\";", m_index, m_bb->index);
568
569 pretty_printer *pp = gv->get_pp ();
570
571 if (args.m_node_annotator)
572 args.m_node_annotator->add_node_annotations (gv, *this, false);
573
574 gv->write_indent ();
575 dump_dot_id (pp);
576 pp_printf (pp,
577 " [shape=none,margin=0,style=filled,fillcolor=%s,label=<",
578 "lightgrey");
579 pp_string (pp, "<TABLE BORDER=\"0\">");
580 pp_write_text_to_stream (pp);
581
582 bool had_row = false;
583
584 /* Give any annotator the chance to add its own per-node TR elements. */
585 if (args.m_node_annotator)
586 if (args.m_node_annotator->add_node_annotations (gv, *this, true))
587 had_row = true;
588
589 if (m_returning_call)
590 {
591 gv->begin_trtd ();
592 pp_string (pp, "returning call: ");
593 gv->end_tdtr ();
594
595 gv->begin_tr ();
596 gv->begin_td ();
597 pp_gimple_stmt_1 (pp, m_returning_call, 0, (dump_flags_t)0);
598 pp_write_text_as_html_like_dot_to_stream (pp);
599 gv->end_td ();
600 /* Give any annotator the chance to add per-stmt TD elements to
601 this row. */
602 if (args.m_node_annotator)
603 args.m_node_annotator->add_stmt_annotations (gv, m_returning_call,
604 true);
605 gv->end_tr ();
606
607 /* Give any annotator the chance to add per-stmt TR elements. */
608 if (args.m_node_annotator)
609 args.m_node_annotator->add_stmt_annotations (gv, m_returning_call,
610 false);
611 pp_newline (pp);
612
613 had_row = true;
614 }
615
616 if (entry_p ())
617 {
618 pp_string (pp, "<TR><TD>ENTRY</TD></TR>");
619 pp_newline (pp);
620 had_row = true;
621 }
622
623 if (return_p ())
624 {
625 pp_string (pp, "<TR><TD>EXIT</TD></TR>");
626 pp_newline (pp);
627 had_row = true;
628 }
629
630 /* Phi nodes. */
631 for (gphi_iterator gpi = const_cast<supernode *> (this)->start_phis ();
632 !gsi_end_p (gpi); gsi_next (&gpi))
633 {
634 const gimple *stmt = gsi_stmt (gpi);
635 gv->begin_tr ();
636 gv->begin_td ();
637 pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
638 pp_write_text_as_html_like_dot_to_stream (pp);
639 gv->end_td ();
640 /* Give any annotator the chance to add per-phi TD elements to
641 this row. */
642 if (args.m_node_annotator)
643 args.m_node_annotator->add_stmt_annotations (gv, stmt, true);
644 gv->end_tr ();
645
646 /* Give any annotator the chance to add per-phi TR elements. */
647 if (args.m_node_annotator)
648 args.m_node_annotator->add_stmt_annotations (gv, stmt, false);
649
650 pp_newline (pp);
651 had_row = true;
652 }
653
654 /* Statements. */
655 int i;
656 gimple *stmt;
657 FOR_EACH_VEC_ELT (m_stmts, i, stmt)
658 {
659 gv->begin_tr ();
660 gv->begin_td ();
661 pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
662 pp_write_text_as_html_like_dot_to_stream (pp);
663 gv->end_td ();
664 /* Give any annotator the chance to add per-stmt TD elements to
665 this row. */
666 if (args.m_node_annotator)
667 args.m_node_annotator->add_stmt_annotations (gv, stmt, true);
668 gv->end_tr ();
669
670 /* Give any annotator the chance to add per-stmt TR elements. */
671 if (args.m_node_annotator)
672 args.m_node_annotator->add_stmt_annotations (gv, stmt, false);
673
674 pp_newline (pp);
675 had_row = true;
676 }
677
678 /* Give any annotator the chance to add additional per-node TR elements
679 to the end of the TABLE. */
680 if (args.m_node_annotator)
681 if (args.m_node_annotator->add_after_node_annotations (gv, *this))
682 had_row = true;
683
684 /* Graphviz requires a TABLE element to have at least one TR
685 (and each TR to have at least one TD). */
686 if (!had_row)
687 {
688 pp_string (pp, "<TR><TD>(empty)</TD></TR>");
689 pp_newline (pp);
690 }
691
692 pp_string (pp, "</TABLE>>];\n\n");
693 pp_flush (pp);
694
695 /* Terminate "subgraph" */
696 gv->outdent ();
697 gv->println ("}");
698 }
699
700 /* Write an ID for this node to PP, for use in .dot output. */
701
702 void
703 supernode::dump_dot_id (pretty_printer *pp) const
704 {
705 pp_printf (pp, "node_%i", m_index);
706 }
707
708 /* Return a new json::object of the form
709 {"idx": int,
710 "fun": optional str
711 "bb_idx": int,
712 "returning_call": optional str,
713 "phis": [str],
714 "stmts" : [str]}. */
715
716 json::object *
717 supernode::to_json () const
718 {
719 json::object *snode_obj = new json::object ();
720
721 snode_obj->set ("idx", new json::integer_number (m_index));
722 snode_obj->set ("bb_idx", new json::integer_number (m_bb->index));
723 if (function *fun = get_function ())
724 snode_obj->set ("fun", new json::string (function_name (fun)));
725
726 if (m_returning_call)
727 {
728 pretty_printer pp;
729 pp_format_decoder (&pp) = default_tree_printer;
730 pp_gimple_stmt_1 (&pp, m_returning_call, 0, (dump_flags_t)0);
731 snode_obj->set ("returning_call",
732 new json::string (pp_formatted_text (&pp)));
733 }
734
735 /* Phi nodes. */
736 {
737 json::array *phi_arr = new json::array ();
738 for (gphi_iterator gpi = const_cast<supernode *> (this)->start_phis ();
739 !gsi_end_p (gpi); gsi_next (&gpi))
740 {
741 const gimple *stmt = gsi_stmt (gpi);
742 pretty_printer pp;
743 pp_format_decoder (&pp) = default_tree_printer;
744 pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
745 phi_arr->append (new json::string (pp_formatted_text (&pp)));
746 }
747 snode_obj->set ("phis", phi_arr);
748 }
749
750 /* Statements. */
751 {
752 json::array *stmt_arr = new json::array ();
753 int i;
754 gimple *stmt;
755 FOR_EACH_VEC_ELT (m_stmts, i, stmt)
756 {
757 pretty_printer pp;
758 pp_format_decoder (&pp) = default_tree_printer;
759 pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
760 stmt_arr->append (new json::string (pp_formatted_text (&pp)));
761 }
762 snode_obj->set ("stmts", stmt_arr);
763 }
764
765 return snode_obj;
766 }
767
768 /* Get a location_t for the start of this supernode. */
769
770 location_t
771 supernode::get_start_location () const
772 {
773 if (m_returning_call
774 && get_pure_location (m_returning_call->location) != UNKNOWN_LOCATION)
775 return m_returning_call->location;
776
777 int i;
778 gimple *stmt;
779 FOR_EACH_VEC_ELT (m_stmts, i, stmt)
780 if (get_pure_location (stmt->location) != UNKNOWN_LOCATION)
781 return stmt->location;
782
783 if (entry_p ())
784 {
785 // TWEAK: show the decl instead; this leads to more readable output:
786 return DECL_SOURCE_LOCATION (m_fun->decl);
787
788 return m_fun->function_start_locus;
789 }
790 if (return_p ())
791 return m_fun->function_end_locus;
792
793 return UNKNOWN_LOCATION;
794 }
795
796 /* Get a location_t for the end of this supernode. */
797
798 location_t
799 supernode::get_end_location () const
800 {
801 int i;
802 gimple *stmt;
803 FOR_EACH_VEC_ELT_REVERSE (m_stmts, i, stmt)
804 if (get_pure_location (stmt->location) != UNKNOWN_LOCATION)
805 return stmt->location;
806
807 if (m_returning_call
808 && get_pure_location (m_returning_call->location) != UNKNOWN_LOCATION)
809 return m_returning_call->location;
810
811 if (entry_p ())
812 return m_fun->function_start_locus;
813 if (return_p ())
814 return m_fun->function_end_locus;
815
816 return UNKNOWN_LOCATION;
817 }
818
819 /* Given STMT within this supernode, return its index within m_stmts. */
820
821 unsigned int
822 supernode::get_stmt_index (const gimple *stmt) const
823 {
824 unsigned i;
825 gimple *iter_stmt;
826 FOR_EACH_VEC_ELT (m_stmts, i, iter_stmt)
827 if (iter_stmt == stmt)
828 return i;
829 gcc_unreachable ();
830 }
831
832 /* Get a string for PK. */
833
834 static const char *
835 edge_kind_to_string (enum edge_kind kind)
836 {
837 switch (kind)
838 {
839 default:
840 gcc_unreachable ();
841 case SUPEREDGE_CFG_EDGE:
842 return "SUPEREDGE_CFG_EDGE";
843 case SUPEREDGE_CALL:
844 return "SUPEREDGE_CALL";
845 case SUPEREDGE_RETURN:
846 return "SUPEREDGE_RETURN";
847 case SUPEREDGE_INTRAPROCEDURAL_CALL:
848 return "SUPEREDGE_INTRAPROCEDURAL_CALL";
849 }
850 };
851
852 /* Dump this superedge to PP. */
853
854 void
855 superedge::dump (pretty_printer *pp) const
856 {
857 pp_printf (pp, "edge: SN: %i -> SN: %i", m_src->m_index, m_dest->m_index);
858 label_text desc (get_description (false));
859 if (strlen (desc.get ()) > 0)
860 {
861 pp_space (pp);
862 pp_string (pp, desc.get ());
863 }
864 }
865
866 /* Dump this superedge to stderr. */
867
868 DEBUG_FUNCTION void
869 superedge::dump () const
870 {
871 pretty_printer pp;
872 pp_format_decoder (&pp) = default_tree_printer;
873 pp_show_color (&pp) = pp_show_color (global_dc->printer);
874 pp.buffer->stream = stderr;
875 dump (&pp);
876 pp_newline (&pp);
877 pp_flush (&pp);
878 }
879
880 /* Implementation of dedge::dump_dot for superedges.
881 Write a .dot edge to GV representing this superedge. */
882
883 void
884 superedge::dump_dot (graphviz_out *gv, const dump_args_t &) const
885 {
886 const char *style = "\"solid,bold\"";
887 const char *color = "black";
888 int weight = 10;
889 const char *constraint = "true";
890
891 switch (m_kind)
892 {
893 default:
894 gcc_unreachable ();
895 case SUPEREDGE_CFG_EDGE:
896 break;
897 case SUPEREDGE_CALL:
898 color = "red";
899 break;
900 case SUPEREDGE_RETURN:
901 color = "green";
902 break;
903 case SUPEREDGE_INTRAPROCEDURAL_CALL:
904 style = "\"dotted\"";
905 break;
906 }
907
908 /* Adapted from graph.cc:draw_cfg_node_succ_edges. */
909 if (::edge cfg_edge = get_any_cfg_edge ())
910 {
911 if (cfg_edge->flags & EDGE_FAKE)
912 {
913 style = "dotted";
914 color = "green";
915 weight = 0;
916 }
917 else if (cfg_edge->flags & EDGE_DFS_BACK)
918 {
919 style = "\"dotted,bold\"";
920 color = "blue";
921 weight = 10;
922 }
923 else if (cfg_edge->flags & EDGE_FALLTHRU)
924 {
925 color = "blue";
926 weight = 100;
927 }
928
929 if (cfg_edge->flags & EDGE_ABNORMAL)
930 color = "red";
931 }
932
933 gv->write_indent ();
934
935 pretty_printer *pp = gv->get_pp ();
936
937 m_src->dump_dot_id (pp);
938 pp_string (pp, " -> ");
939 m_dest->dump_dot_id (pp);
940 pp_printf (pp,
941 (" [style=%s, color=%s, weight=%d, constraint=%s,"
942 " ltail=\"cluster_node_%i\", lhead=\"cluster_node_%i\""
943 " headlabel=\""),
944 style, color, weight, constraint,
945 m_src->m_index, m_dest->m_index);
946
947 dump_label_to_pp (pp, false);
948
949 pp_printf (pp, "\"];\n");
950 }
951
952 /* Return a new json::object of the form
953 {"kind" : str,
954 "src_idx": int, the index of the source supernode,
955 "dst_idx": int, the index of the destination supernode,
956 "desc" : str. */
957
958 json::object *
959 superedge::to_json () const
960 {
961 json::object *sedge_obj = new json::object ();
962 sedge_obj->set ("kind", new json::string (edge_kind_to_string (m_kind)));
963 sedge_obj->set ("src_idx", new json::integer_number (m_src->m_index));
964 sedge_obj->set ("dst_idx", new json::integer_number (m_dest->m_index));
965
966 {
967 pretty_printer pp;
968 pp_format_decoder (&pp) = default_tree_printer;
969 dump_label_to_pp (&pp, false);
970 sedge_obj->set ("desc", new json::string (pp_formatted_text (&pp)));
971 }
972
973 return sedge_obj;
974 }
975
976 /* If this is an intraprocedural superedge, return the associated
977 CFG edge. Otherwise, return NULL. */
978
979 ::edge
980 superedge::get_any_cfg_edge () const
981 {
982 if (const cfg_superedge *sub = dyn_cast_cfg_superedge ())
983 return sub->get_cfg_edge ();
984 return NULL;
985 }
986
987 /* If this is an interprocedural superedge, return the associated
988 cgraph_edge *. Otherwise, return NULL. */
989
990 cgraph_edge *
991 superedge::get_any_callgraph_edge () const
992 {
993 if (const callgraph_superedge *sub = dyn_cast_callgraph_superedge ())
994 return sub->m_cedge;
995 return NULL;
996 }
997
998 /* Build a description of this superedge (e.g. "true" for the true
999 edge of a conditional, or "case 42:" for a switch case).
1000
1001 If USER_FACING is false, the result also contains any underlying
1002 CFG edge flags. e.g. " (flags FALLTHRU | DFS_BACK)". */
1003
1004 label_text
1005 superedge::get_description (bool user_facing) const
1006 {
1007 pretty_printer pp;
1008 dump_label_to_pp (&pp, user_facing);
1009 return label_text::take (xstrdup (pp_formatted_text (&pp)));
1010 }
1011
1012 /* Implementation of superedge::dump_label_to_pp for non-switch CFG
1013 superedges.
1014
1015 For true/false edges, print "true" or "false" to PP.
1016
1017 If USER_FACING is false, also print flags on the underlying CFG edge to
1018 PP. */
1019
1020 void
1021 cfg_superedge::dump_label_to_pp (pretty_printer *pp,
1022 bool user_facing) const
1023 {
1024 if (true_value_p ())
1025 pp_printf (pp, "true");
1026 else if (false_value_p ())
1027 pp_printf (pp, "false");
1028
1029 if (user_facing)
1030 return;
1031
1032 /* Express edge flags as a string with " | " separator.
1033 e.g. " (flags FALLTHRU | DFS_BACK)". */
1034 if (get_flags ())
1035 {
1036 pp_string (pp, " (flags ");
1037 bool seen_flag = false;
1038 #define DEF_EDGE_FLAG(NAME,IDX) \
1039 do { \
1040 if (get_flags () & EDGE_##NAME) \
1041 { \
1042 if (seen_flag) \
1043 pp_string (pp, " | "); \
1044 pp_printf (pp, "%s", (#NAME)); \
1045 seen_flag = true; \
1046 } \
1047 } while (0);
1048 #include "cfg-flags.def"
1049 #undef DEF_EDGE_FLAG
1050 pp_string (pp, ")");
1051 }
1052
1053 /* Otherwise, no label. */
1054 }
1055
1056 /* Get the index number for this edge for use in phi stmts
1057 in its destination. */
1058
1059 size_t
1060 cfg_superedge::get_phi_arg_idx () const
1061 {
1062 return m_cfg_edge->dest_idx;
1063 }
1064
1065 /* Get the phi argument for PHI for this CFG edge. */
1066
1067 tree
1068 cfg_superedge::get_phi_arg (const gphi *phi) const
1069 {
1070 size_t index = get_phi_arg_idx ();
1071 return gimple_phi_arg_def (phi, index);
1072 }
1073
1074 switch_cfg_superedge::switch_cfg_superedge (supernode *src,
1075 supernode *dst,
1076 ::edge e)
1077 : cfg_superedge (src, dst, e)
1078 {
1079 /* Populate m_case_labels with all cases which go to DST. */
1080 const gswitch *gswitch = get_switch_stmt ();
1081 for (unsigned i = 0; i < gimple_switch_num_labels (gswitch); i++)
1082 {
1083 tree case_ = gimple_switch_label (gswitch, i);
1084 basic_block bb = label_to_block (src->get_function (),
1085 CASE_LABEL (case_));
1086 if (bb == dst->m_bb)
1087 m_case_labels.safe_push (case_);
1088 }
1089 }
1090
1091 /* Implementation of superedge::dump_label_to_pp for CFG superedges for
1092 "switch" statements.
1093
1094 Print "case VAL:", "case LOWER ... UPPER:", or "default:" to PP. */
1095
1096 void
1097 switch_cfg_superedge::dump_label_to_pp (pretty_printer *pp,
1098 bool user_facing ATTRIBUTE_UNUSED) const
1099 {
1100 if (user_facing)
1101 {
1102 for (unsigned i = 0; i < m_case_labels.length (); ++i)
1103 {
1104 if (i > 0)
1105 pp_string (pp, ", ");
1106 tree case_label = m_case_labels[i];
1107 gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1108 tree lower_bound = CASE_LOW (case_label);
1109 tree upper_bound = CASE_HIGH (case_label);
1110 if (lower_bound)
1111 {
1112 pp_printf (pp, "case ");
1113 dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
1114 if (upper_bound)
1115 {
1116 pp_printf (pp, " ... ");
1117 dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
1118 false);
1119 }
1120 pp_printf (pp, ":");
1121 }
1122 else
1123 pp_printf (pp, "default:");
1124 }
1125 }
1126 else
1127 {
1128 pp_character (pp, '{');
1129 for (unsigned i = 0; i < m_case_labels.length (); ++i)
1130 {
1131 if (i > 0)
1132 pp_string (pp, ", ");
1133 tree case_label = m_case_labels[i];
1134 gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1135 tree lower_bound = CASE_LOW (case_label);
1136 tree upper_bound = CASE_HIGH (case_label);
1137 if (lower_bound)
1138 {
1139 if (upper_bound)
1140 {
1141 pp_character (pp, '[');
1142 dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0,
1143 false);
1144 pp_string (pp, ", ");
1145 dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
1146 false);
1147 pp_character (pp, ']');
1148 }
1149 else
1150 dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
1151 }
1152 else
1153 pp_printf (pp, "default");
1154 }
1155 pp_character (pp, '}');
1156 if (implicitly_created_default_p ())
1157 {
1158 pp_string (pp, " IMPLICITLY CREATED");
1159 }
1160 }
1161 }
1162
1163 /* Return true iff this edge is purely for an implicitly-created "default". */
1164
1165 bool
1166 switch_cfg_superedge::implicitly_created_default_p () const
1167 {
1168 if (m_case_labels.length () != 1)
1169 return false;
1170
1171 tree case_label = m_case_labels[0];
1172 gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1173 if (CASE_LOW (case_label))
1174 return false;
1175
1176 /* We have a single "default" case.
1177 Assume that it was implicitly created if it has UNKNOWN_LOCATION. */
1178 return EXPR_LOCATION (case_label) == UNKNOWN_LOCATION;
1179 }
1180
1181 /* Implementation of superedge::dump_label_to_pp for interprocedural
1182 superedges. */
1183
1184 void
1185 callgraph_superedge::dump_label_to_pp (pretty_printer *pp,
1186 bool user_facing ATTRIBUTE_UNUSED) const
1187 {
1188 switch (m_kind)
1189 {
1190 default:
1191 case SUPEREDGE_CFG_EDGE:
1192 gcc_unreachable ();
1193
1194 case SUPEREDGE_CALL:
1195 pp_printf (pp, "call");
1196 break;
1197
1198 case SUPEREDGE_RETURN:
1199 pp_printf (pp, "return");
1200 break;
1201
1202 case SUPEREDGE_INTRAPROCEDURAL_CALL:
1203 pp_printf (pp, "intraproc link");
1204 break;
1205 }
1206 }
1207
1208 /* Get the function that was called at this interprocedural call/return
1209 edge. */
1210
1211 function *
1212 callgraph_superedge::get_callee_function () const
1213 {
1214 return get_ultimate_function_for_cgraph_edge (m_cedge);
1215 }
1216
1217 /* Get the calling function at this interprocedural call/return edge. */
1218
1219 function *
1220 callgraph_superedge::get_caller_function () const
1221 {
1222 return m_cedge->caller->get_fun ();
1223 }
1224
1225 /* Get the fndecl that was called at this interprocedural call/return
1226 edge. */
1227
1228 tree
1229 callgraph_superedge::get_callee_decl () const
1230 {
1231 return get_callee_function ()->decl;
1232 }
1233
1234 /* Get the gcall * of this interprocedural call/return edge. */
1235
1236 gcall *
1237 callgraph_superedge::get_call_stmt () const
1238 {
1239 if (m_cedge)
1240 return m_cedge->call_stmt;
1241
1242 return m_src->get_final_call ();
1243 }
1244
1245 /* Get the calling fndecl at this interprocedural call/return edge. */
1246
1247 tree
1248 callgraph_superedge::get_caller_decl () const
1249 {
1250 return get_caller_function ()->decl;
1251 }
1252
1253 /* Given PARM_TO_FIND, a PARM_DECL, identify its index (writing it
1254 to *OUT if OUT is non-NULL), and return the corresponding argument
1255 at the callsite. */
1256
1257 tree
1258 callgraph_superedge::get_arg_for_parm (tree parm_to_find,
1259 callsite_expr *out) const
1260 {
1261 gcc_assert (TREE_CODE (parm_to_find) == PARM_DECL);
1262
1263 tree callee = get_callee_decl ();
1264 const gcall *call_stmt = get_call_stmt ();
1265
1266 unsigned i = 0;
1267 for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm;
1268 iter_parm = DECL_CHAIN (iter_parm), ++i)
1269 {
1270 if (i >= gimple_call_num_args (call_stmt))
1271 return NULL_TREE;
1272 if (iter_parm == parm_to_find)
1273 {
1274 if (out)
1275 *out = callsite_expr::from_zero_based_param (i);
1276 return gimple_call_arg (call_stmt, i);
1277 }
1278 }
1279
1280 /* Not found. */
1281 return NULL_TREE;
1282 }
1283
1284 /* Look for a use of ARG_TO_FIND as an argument at this callsite.
1285 If found, return the default SSA def of the corresponding parm within
1286 the callee, and if OUT is non-NULL, write the index to *OUT.
1287 Only the first match is handled. */
1288
1289 tree
1290 callgraph_superedge::get_parm_for_arg (tree arg_to_find,
1291 callsite_expr *out) const
1292 {
1293 tree callee = get_callee_decl ();
1294 const gcall *call_stmt = get_call_stmt ();
1295
1296 unsigned i = 0;
1297 for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm;
1298 iter_parm = DECL_CHAIN (iter_parm), ++i)
1299 {
1300 if (i >= gimple_call_num_args (call_stmt))
1301 return NULL_TREE;
1302 tree param = gimple_call_arg (call_stmt, i);
1303 if (arg_to_find == param)
1304 {
1305 if (out)
1306 *out = callsite_expr::from_zero_based_param (i);
1307 return ssa_default_def (get_callee_function (), iter_parm);
1308 }
1309 }
1310
1311 /* Not found. */
1312 return NULL_TREE;
1313 }
1314
1315 /* Map caller_expr back to an expr within the callee, or return NULL_TREE.
1316 If non-NULL is returned, populate OUT. */
1317
1318 tree
1319 callgraph_superedge::map_expr_from_caller_to_callee (tree caller_expr,
1320 callsite_expr *out) const
1321 {
1322 /* Is it an argument (actual param)? If so, convert to
1323 parameter (formal param). */
1324 tree parm = get_parm_for_arg (caller_expr, out);
1325 if (parm)
1326 return parm;
1327 /* Otherwise try return value. */
1328 if (caller_expr == gimple_call_lhs (get_call_stmt ()))
1329 {
1330 if (out)
1331 *out = callsite_expr::from_return_value ();
1332 return DECL_RESULT (get_callee_decl ());
1333 }
1334
1335 return NULL_TREE;
1336 }
1337
1338 /* Map callee_expr back to an expr within the caller, or return NULL_TREE.
1339 If non-NULL is returned, populate OUT. */
1340
1341 tree
1342 callgraph_superedge::map_expr_from_callee_to_caller (tree callee_expr,
1343 callsite_expr *out) const
1344 {
1345 if (callee_expr == NULL_TREE)
1346 return NULL_TREE;
1347
1348 /* If it's a parameter (formal param), get the argument (actual param). */
1349 if (TREE_CODE (callee_expr) == PARM_DECL)
1350 return get_arg_for_parm (callee_expr, out);
1351
1352 /* Similar for the default SSA name of the PARM_DECL. */
1353 if (TREE_CODE (callee_expr) == SSA_NAME
1354 && SSA_NAME_IS_DEFAULT_DEF (callee_expr)
1355 && TREE_CODE (SSA_NAME_VAR (callee_expr)) == PARM_DECL)
1356 return get_arg_for_parm (SSA_NAME_VAR (callee_expr), out);
1357
1358 /* Otherwise try return value. */
1359 if (callee_expr == DECL_RESULT (get_callee_decl ()))
1360 {
1361 if (out)
1362 *out = callsite_expr::from_return_value ();
1363 return gimple_call_lhs (get_call_stmt ());
1364 }
1365
1366 return NULL_TREE;
1367 }
1368
1369 } // namespace ana
1370
1371 #endif /* #if ENABLE_ANALYZER */