]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/supergraph.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / analyzer / supergraph.cc
CommitLineData
757bf1df 1/* "Supergraph" classes that combine CFGs and callgraph into one digraph.
a945c346 2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
757bf1df
DM
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#include "config.h"
accece8c 22#define INCLUDE_MEMORY
757bf1df
DM
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"
ba206889
RB
33#include "gimple.h"
34#include "gimple-iterator.h"
757bf1df
DM
35#include "gimple-fold.h"
36#include "tree-eh.h"
37#include "gimple-expr.h"
38#include "is-a.h"
39#include "timevar.h"
757bf1df
DM
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"
a11afa7a 45#include "bitmap.h"
757bf1df
DM
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"
8ca7fa84 54#include "tree-cfg.h"
757bf1df
DM
55#include "analyzer/supergraph.h"
56#include "analyzer/analyzer-logging.h"
57
58#if ENABLE_ANALYZER
59
75038aa6
DM
60namespace ana {
61
91f993b7
DM
62/* Get the function of the ultimate alias target being called at EDGE,
63 if any. */
64
bfca9505 65function *
91f993b7
DM
66get_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
757bf1df
DM
74/* Get the cgraph_edge, but only if there's an underlying function body. */
75
76cgraph_edge *
bfca9505 77supergraph_call_edge (function *fun, const gimple *stmt)
757bf1df 78{
bfca9505 79 const gcall *call = dyn_cast<const gcall *> (stmt);
757bf1df
DM
80 if (!call)
81 return NULL;
bfca9505
DM
82 cgraph_edge *edge
83 = cgraph_node::get (fun->decl)->get_edge (const_cast <gimple *> (stmt));
757bf1df
DM
84 if (!edge)
85 return NULL;
86 if (!edge->callee)
87 return NULL; /* e.g. for a function pointer. */
91f993b7 88 if (!get_ultimate_function_for_cgraph_edge (edge))
757bf1df
DM
89 return NULL;
90 return edge;
91}
92
17f3c2b8
DM
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
116void
117saved_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
128void
129saved_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
757bf1df
DM
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
b0702ac5
DM
140 superedges as appropriate.
141 Assign UIDs to the gimple stmts. */
757bf1df
DM
142
143supergraph::supergraph (logger *logger)
144{
145 auto_timevar tv (TV_ANALYZER_SUPERGRAPH);
146
147 LOG_FUNC (logger);
148
b0702ac5 149 /* First pass: make supernodes (and assign UIDs to the gimple stmts). */
757bf1df
DM
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);
17f3c2b8 175 m_stmt_uids.make_uid_unique (stmt);
757bf1df
DM
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);
17f3c2b8 187 m_stmt_uids.make_uid_unique (stmt);
757bf1df 188 if (cgraph_edge *edge = supergraph_call_edge (fun, stmt))
aef703cf
AS
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 }
757bf1df
DM
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
8ca7fa84 252 = add_cfg_edge (src_supernode, dest_supernode, cfg_edge);
757bf1df
DM
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;
91f993b7
DM
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);
757bf1df
DM
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;
91f993b7
DM
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);
757bf1df
DM
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
17f3c2b8
DM
327/* supergraph's dtor. Reset stmt uids. */
328
329supergraph::~supergraph ()
330{
331 m_stmt_uids.restore_uids ();
332}
333
757bf1df
DM
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
337void
338supergraph::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
432void
433supergraph::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
449void
450supergraph::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
809192e7
DM
457/* Return a new json::object of the form
458 {"nodes" : [objs for snodes],
459 "edges" : [objs for sedges]}. */
460
461json::object *
462supergraph::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
757bf1df
DM
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
497supernode *
498supergraph::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
8ca7fa84 511 subclass. */
757bf1df
DM
512
513cfg_superedge *
8ca7fa84 514supergraph::add_cfg_edge (supernode *src, supernode *dest, ::edge e)
757bf1df
DM
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)
8ca7fa84 520 new_edge = new switch_cfg_superedge (src, dest, e);
757bf1df
DM
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
530call_superedge *
531supergraph::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
542return_superedge *
543supergraph::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
557void
558supernode::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\";");
73f38658 567 gv->println("label=\"sn: %i (bb: %i)\";", m_index, m_bb->index);
757bf1df
DM
568
569 pretty_printer *pp = gv->get_pp ();
570
571 if (args.m_node_annotator)
42c63313 572 args.m_node_annotator->add_node_annotations (gv, *this, false);
757bf1df
DM
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
718930c0
DM
582 bool had_row = false;
583
42c63313
DM
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
757bf1df
DM
589 if (m_returning_call)
590 {
42c63313 591 gv->begin_trtd ();
757bf1df 592 pp_string (pp, "returning call: ");
42c63313 593 gv->end_tdtr ();
757bf1df
DM
594
595 gv->begin_tr ();
42c63313 596 gv->begin_td ();
757bf1df
DM
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);
42c63313
DM
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);
757bf1df
DM
605 gv->end_tr ();
606
42c63313 607 /* Give any annotator the chance to add per-stmt TR elements. */
757bf1df 608 if (args.m_node_annotator)
42c63313
DM
609 args.m_node_annotator->add_stmt_annotations (gv, m_returning_call,
610 false);
757bf1df 611 pp_newline (pp);
718930c0
DM
612
613 had_row = true;
757bf1df
DM
614 }
615
616 if (entry_p ())
617 {
618 pp_string (pp, "<TR><TD>ENTRY</TD></TR>");
619 pp_newline (pp);
718930c0 620 had_row = true;
757bf1df
DM
621 }
622
623 if (return_p ())
624 {
625 pp_string (pp, "<TR><TD>EXIT</TD></TR>");
626 pp_newline (pp);
718930c0 627 had_row = true;
757bf1df
DM
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 ();
42c63313 636 gv->begin_td ();
757bf1df
DM
637 pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
638 pp_write_text_as_html_like_dot_to_stream (pp);
42c63313
DM
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);
757bf1df
DM
644 gv->end_tr ();
645
42c63313 646 /* Give any annotator the chance to add per-phi TR elements. */
757bf1df 647 if (args.m_node_annotator)
42c63313 648 args.m_node_annotator->add_stmt_annotations (gv, stmt, false);
757bf1df
DM
649
650 pp_newline (pp);
718930c0 651 had_row = true;
757bf1df
DM
652 }
653
654 /* Statements. */
655 int i;
656 gimple *stmt;
657 FOR_EACH_VEC_ELT (m_stmts, i, stmt)
658 {
659 gv->begin_tr ();
42c63313 660 gv->begin_td ();
757bf1df
DM
661 pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
662 pp_write_text_as_html_like_dot_to_stream (pp);
42c63313
DM
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);
757bf1df
DM
668 gv->end_tr ();
669
42c63313 670 /* Give any annotator the chance to add per-stmt TR elements. */
757bf1df 671 if (args.m_node_annotator)
42c63313 672 args.m_node_annotator->add_stmt_annotations (gv, stmt, false);
757bf1df
DM
673
674 pp_newline (pp);
718930c0
DM
675 had_row = true;
676 }
677
42c63313
DM
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
718930c0
DM
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);
757bf1df
DM
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
702void
703supernode::dump_dot_id (pretty_printer *pp) const
704{
705 pp_printf (pp, "node_%i", m_index);
706}
707
809192e7
DM
708/* Return a new json::object of the form
709 {"idx": int,
dea4a32b 710 "fun": optional str
809192e7 711 "bb_idx": int,
dea4a32b 712 "returning_call": optional str,
809192e7
DM
713 "phis": [str],
714 "stmts" : [str]}. */
715
716json::object *
717supernode::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));
dea4a32b
DM
723 if (function *fun = get_function ())
724 snode_obj->set ("fun", new json::string (function_name (fun)));
809192e7
DM
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
757bf1df
DM
768/* Get a location_t for the start of this supernode. */
769
770location_t
771supernode::get_start_location () const
772{
8397af8e
DM
773 if (m_returning_call
774 && get_pure_location (m_returning_call->location) != UNKNOWN_LOCATION)
757bf1df
DM
775 return m_returning_call->location;
776
777 int i;
778 gimple *stmt;
779 FOR_EACH_VEC_ELT (m_stmts, i, stmt)
8397af8e 780 if (get_pure_location (stmt->location) != UNKNOWN_LOCATION)
757bf1df
DM
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
841008d3
DM
793 /* We have no locations for stmts. If we have a single out-edge that's
794 a CFG edge, the goto_locus of that edge is a better location for this
795 than UNKNOWN_LOCATION. */
796 if (m_succs.length () == 1)
797 if (const cfg_superedge *cfg_sedge = m_succs[0]->dyn_cast_cfg_superedge ())
798 return cfg_sedge->get_goto_locus ();
799
757bf1df
DM
800 return UNKNOWN_LOCATION;
801}
802
803/* Get a location_t for the end of this supernode. */
804
805location_t
806supernode::get_end_location () const
807{
808 int i;
809 gimple *stmt;
810 FOR_EACH_VEC_ELT_REVERSE (m_stmts, i, stmt)
8397af8e 811 if (get_pure_location (stmt->location) != UNKNOWN_LOCATION)
757bf1df
DM
812 return stmt->location;
813
8397af8e
DM
814 if (m_returning_call
815 && get_pure_location (m_returning_call->location) != UNKNOWN_LOCATION)
757bf1df
DM
816 return m_returning_call->location;
817
818 if (entry_p ())
819 return m_fun->function_start_locus;
820 if (return_p ())
821 return m_fun->function_end_locus;
822
841008d3
DM
823 /* If we have a single out-edge that's a CFG edge, use the goto_locus of
824 that edge. */
825 if (m_succs.length () == 1)
826 if (const cfg_superedge *cfg_sedge = m_succs[0]->dyn_cast_cfg_superedge ())
827 return cfg_sedge->get_goto_locus ();
828
757bf1df
DM
829 return UNKNOWN_LOCATION;
830}
831
832/* Given STMT within this supernode, return its index within m_stmts. */
833
834unsigned int
835supernode::get_stmt_index (const gimple *stmt) const
836{
837 unsigned i;
838 gimple *iter_stmt;
839 FOR_EACH_VEC_ELT (m_stmts, i, iter_stmt)
840 if (iter_stmt == stmt)
841 return i;
842 gcc_unreachable ();
843}
844
1b761fed
DM
845/* Get any label_decl for this supernode, or NULL_TREE if there isn't one. */
846
847tree
848supernode::get_label () const
849{
850 if (m_stmts.length () == 0)
851 return NULL_TREE;
852 const glabel *label_stmt = dyn_cast<const glabel *> (m_stmts[0]);
853 if (!label_stmt)
854 return NULL_TREE;
855 return gimple_label_label (label_stmt);
856}
857
dea4a32b
DM
858/* Get a string for PK. */
859
860static const char *
861edge_kind_to_string (enum edge_kind kind)
862{
863 switch (kind)
864 {
865 default:
866 gcc_unreachable ();
867 case SUPEREDGE_CFG_EDGE:
868 return "SUPEREDGE_CFG_EDGE";
869 case SUPEREDGE_CALL:
870 return "SUPEREDGE_CALL";
871 case SUPEREDGE_RETURN:
872 return "SUPEREDGE_RETURN";
873 case SUPEREDGE_INTRAPROCEDURAL_CALL:
874 return "SUPEREDGE_INTRAPROCEDURAL_CALL";
875 }
876};
877
67fa274c
DM
878/* Dump this superedge to PP. */
879
880void
881superedge::dump (pretty_printer *pp) const
882{
883 pp_printf (pp, "edge: SN: %i -> SN: %i", m_src->m_index, m_dest->m_index);
52f538fa 884 label_text desc (get_description (false));
f858fe7a 885 if (strlen (desc.get ()) > 0)
4d661bb7
DM
886 {
887 pp_space (pp);
f858fe7a 888 pp_string (pp, desc.get ());
4d661bb7 889 }
67fa274c
DM
890}
891
892/* Dump this superedge to stderr. */
893
894DEBUG_FUNCTION void
895superedge::dump () const
896{
897 pretty_printer pp;
898 pp_format_decoder (&pp) = default_tree_printer;
899 pp_show_color (&pp) = pp_show_color (global_dc->printer);
900 pp.buffer->stream = stderr;
901 dump (&pp);
4d661bb7 902 pp_newline (&pp);
67fa274c
DM
903 pp_flush (&pp);
904}
905
757bf1df
DM
906/* Implementation of dedge::dump_dot for superedges.
907 Write a .dot edge to GV representing this superedge. */
908
909void
910superedge::dump_dot (graphviz_out *gv, const dump_args_t &) const
911{
912 const char *style = "\"solid,bold\"";
913 const char *color = "black";
914 int weight = 10;
915 const char *constraint = "true";
916
917 switch (m_kind)
918 {
919 default:
920 gcc_unreachable ();
921 case SUPEREDGE_CFG_EDGE:
922 break;
923 case SUPEREDGE_CALL:
924 color = "red";
925 break;
926 case SUPEREDGE_RETURN:
927 color = "green";
928 break;
929 case SUPEREDGE_INTRAPROCEDURAL_CALL:
930 style = "\"dotted\"";
931 break;
932 }
933
e53b6e56 934 /* Adapted from graph.cc:draw_cfg_node_succ_edges. */
757bf1df
DM
935 if (::edge cfg_edge = get_any_cfg_edge ())
936 {
937 if (cfg_edge->flags & EDGE_FAKE)
938 {
939 style = "dotted";
940 color = "green";
941 weight = 0;
942 }
943 else if (cfg_edge->flags & EDGE_DFS_BACK)
944 {
945 style = "\"dotted,bold\"";
946 color = "blue";
947 weight = 10;
948 }
949 else if (cfg_edge->flags & EDGE_FALLTHRU)
950 {
951 color = "blue";
952 weight = 100;
953 }
954
955 if (cfg_edge->flags & EDGE_ABNORMAL)
956 color = "red";
957 }
958
959 gv->write_indent ();
960
961 pretty_printer *pp = gv->get_pp ();
962
963 m_src->dump_dot_id (pp);
964 pp_string (pp, " -> ");
965 m_dest->dump_dot_id (pp);
966 pp_printf (pp,
967 (" [style=%s, color=%s, weight=%d, constraint=%s,"
968 " ltail=\"cluster_node_%i\", lhead=\"cluster_node_%i\""
969 " headlabel=\""),
970 style, color, weight, constraint,
971 m_src->m_index, m_dest->m_index);
972
973 dump_label_to_pp (pp, false);
974
975 pp_printf (pp, "\"];\n");
976}
977
809192e7 978/* Return a new json::object of the form
dea4a32b
DM
979 {"kind" : str,
980 "src_idx": int, the index of the source supernode,
809192e7
DM
981 "dst_idx": int, the index of the destination supernode,
982 "desc" : str. */
983
984json::object *
985superedge::to_json () const
986{
987 json::object *sedge_obj = new json::object ();
dea4a32b 988 sedge_obj->set ("kind", new json::string (edge_kind_to_string (m_kind)));
809192e7
DM
989 sedge_obj->set ("src_idx", new json::integer_number (m_src->m_index));
990 sedge_obj->set ("dst_idx", new json::integer_number (m_dest->m_index));
991
992 {
993 pretty_printer pp;
994 pp_format_decoder (&pp) = default_tree_printer;
995 dump_label_to_pp (&pp, false);
996 sedge_obj->set ("desc", new json::string (pp_formatted_text (&pp)));
997 }
998
999 return sedge_obj;
1000}
1001
757bf1df
DM
1002/* If this is an intraprocedural superedge, return the associated
1003 CFG edge. Otherwise, return NULL. */
1004
1005::edge
1006superedge::get_any_cfg_edge () const
1007{
1008 if (const cfg_superedge *sub = dyn_cast_cfg_superedge ())
1009 return sub->get_cfg_edge ();
1010 return NULL;
1011}
1012
1013/* If this is an interprocedural superedge, return the associated
1014 cgraph_edge *. Otherwise, return NULL. */
1015
1016cgraph_edge *
1017superedge::get_any_callgraph_edge () const
1018{
1019 if (const callgraph_superedge *sub = dyn_cast_callgraph_superedge ())
1020 return sub->m_cedge;
1021 return NULL;
1022}
1023
1024/* Build a description of this superedge (e.g. "true" for the true
1025 edge of a conditional, or "case 42:" for a switch case).
1026
757bf1df
DM
1027 If USER_FACING is false, the result also contains any underlying
1028 CFG edge flags. e.g. " (flags FALLTHRU | DFS_BACK)". */
1029
52f538fa 1030label_text
757bf1df
DM
1031superedge::get_description (bool user_facing) const
1032{
1033 pretty_printer pp;
1034 dump_label_to_pp (&pp, user_facing);
52f538fa 1035 return label_text::take (xstrdup (pp_formatted_text (&pp)));
757bf1df
DM
1036}
1037
1038/* Implementation of superedge::dump_label_to_pp for non-switch CFG
1039 superedges.
1040
1041 For true/false edges, print "true" or "false" to PP.
1042
1043 If USER_FACING is false, also print flags on the underlying CFG edge to
1044 PP. */
1045
1046void
1047cfg_superedge::dump_label_to_pp (pretty_printer *pp,
1048 bool user_facing) const
1049{
1050 if (true_value_p ())
1051 pp_printf (pp, "true");
1052 else if (false_value_p ())
1053 pp_printf (pp, "false");
1054
1055 if (user_facing)
1056 return;
1057
1058 /* Express edge flags as a string with " | " separator.
1059 e.g. " (flags FALLTHRU | DFS_BACK)". */
1060 if (get_flags ())
1061 {
1062 pp_string (pp, " (flags ");
1063 bool seen_flag = false;
1064#define DEF_EDGE_FLAG(NAME,IDX) \
1065 do { \
1066 if (get_flags () & EDGE_##NAME) \
1067 { \
1068 if (seen_flag) \
1069 pp_string (pp, " | "); \
1070 pp_printf (pp, "%s", (#NAME)); \
1071 seen_flag = true; \
1072 } \
1073 } while (0);
1074#include "cfg-flags.def"
1075#undef DEF_EDGE_FLAG
1076 pp_string (pp, ")");
1077 }
1078
841008d3
DM
1079 if (m_cfg_edge->goto_locus > BUILTINS_LOCATION)
1080 pp_string (pp, " (has goto_locus)");
1081
757bf1df
DM
1082 /* Otherwise, no label. */
1083}
1084
e0a7a675
DM
1085/* Get the index number for this edge for use in phi stmts
1086 in its destination. */
1087
1088size_t
1089cfg_superedge::get_phi_arg_idx () const
1090{
1091 return m_cfg_edge->dest_idx;
1092}
1093
757bf1df
DM
1094/* Get the phi argument for PHI for this CFG edge. */
1095
1096tree
1097cfg_superedge::get_phi_arg (const gphi *phi) const
1098{
e0a7a675 1099 size_t index = get_phi_arg_idx ();
757bf1df
DM
1100 return gimple_phi_arg_def (phi, index);
1101}
1102
8ca7fa84
DM
1103switch_cfg_superedge::switch_cfg_superedge (supernode *src,
1104 supernode *dst,
1105 ::edge e)
1106: cfg_superedge (src, dst, e)
1107{
1108 /* Populate m_case_labels with all cases which go to DST. */
1109 const gswitch *gswitch = get_switch_stmt ();
1110 for (unsigned i = 0; i < gimple_switch_num_labels (gswitch); i++)
1111 {
1112 tree case_ = gimple_switch_label (gswitch, i);
1113 basic_block bb = label_to_block (src->get_function (),
1114 CASE_LABEL (case_));
1115 if (bb == dst->m_bb)
1116 m_case_labels.safe_push (case_);
1117 }
1118}
1119
757bf1df
DM
1120/* Implementation of superedge::dump_label_to_pp for CFG superedges for
1121 "switch" statements.
1122
1123 Print "case VAL:", "case LOWER ... UPPER:", or "default:" to PP. */
1124
1125void
1126switch_cfg_superedge::dump_label_to_pp (pretty_printer *pp,
1127 bool user_facing ATTRIBUTE_UNUSED) const
1128{
8ca7fa84 1129 if (user_facing)
757bf1df 1130 {
8ca7fa84 1131 for (unsigned i = 0; i < m_case_labels.length (); ++i)
757bf1df 1132 {
8ca7fa84
DM
1133 if (i > 0)
1134 pp_string (pp, ", ");
1135 tree case_label = m_case_labels[i];
1136 gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1137 tree lower_bound = CASE_LOW (case_label);
1138 tree upper_bound = CASE_HIGH (case_label);
1139 if (lower_bound)
1140 {
1141 pp_printf (pp, "case ");
1142 dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
1143 if (upper_bound)
1144 {
1145 pp_printf (pp, " ... ");
1146 dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
1147 false);
1148 }
1149 pp_printf (pp, ":");
1150 }
1151 else
1152 pp_printf (pp, "default:");
757bf1df 1153 }
757bf1df
DM
1154 }
1155 else
8ca7fa84
DM
1156 {
1157 pp_character (pp, '{');
1158 for (unsigned i = 0; i < m_case_labels.length (); ++i)
1159 {
1160 if (i > 0)
1161 pp_string (pp, ", ");
1162 tree case_label = m_case_labels[i];
1163 gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1164 tree lower_bound = CASE_LOW (case_label);
1165 tree upper_bound = CASE_HIGH (case_label);
1166 if (lower_bound)
1167 {
1168 if (upper_bound)
1169 {
1170 pp_character (pp, '[');
1171 dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0,
1172 false);
1173 pp_string (pp, ", ");
1174 dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
1175 false);
1176 pp_character (pp, ']');
1177 }
1178 else
1179 dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
1180 }
1181 else
1182 pp_printf (pp, "default");
1183 }
1184 pp_character (pp, '}');
ccd4df81
DM
1185 if (implicitly_created_default_p ())
1186 {
1187 pp_string (pp, " IMPLICITLY CREATED");
1188 }
8ca7fa84 1189 }
757bf1df
DM
1190}
1191
ccd4df81
DM
1192/* Return true iff this edge is purely for an implicitly-created "default". */
1193
1194bool
1195switch_cfg_superedge::implicitly_created_default_p () const
1196{
1197 if (m_case_labels.length () != 1)
1198 return false;
1199
1200 tree case_label = m_case_labels[0];
1201 gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1202 if (CASE_LOW (case_label))
1203 return false;
1204
1205 /* We have a single "default" case.
1206 Assume that it was implicitly created if it has UNKNOWN_LOCATION. */
1207 return EXPR_LOCATION (case_label) == UNKNOWN_LOCATION;
1208}
1209
757bf1df
DM
1210/* Implementation of superedge::dump_label_to_pp for interprocedural
1211 superedges. */
1212
1213void
1214callgraph_superedge::dump_label_to_pp (pretty_printer *pp,
1215 bool user_facing ATTRIBUTE_UNUSED) const
1216{
1217 switch (m_kind)
1218 {
1219 default:
1220 case SUPEREDGE_CFG_EDGE:
1221 gcc_unreachable ();
1222
1223 case SUPEREDGE_CALL:
1224 pp_printf (pp, "call");
1225 break;
1226
1227 case SUPEREDGE_RETURN:
1228 pp_printf (pp, "return");
1229 break;
1230
1231 case SUPEREDGE_INTRAPROCEDURAL_CALL:
1232 pp_printf (pp, "intraproc link");
1233 break;
1234 }
1235}
1236
1237/* Get the function that was called at this interprocedural call/return
1238 edge. */
1239
1240function *
1241callgraph_superedge::get_callee_function () const
1242{
91f993b7 1243 return get_ultimate_function_for_cgraph_edge (m_cedge);
757bf1df
DM
1244}
1245
1246/* Get the calling function at this interprocedural call/return edge. */
1247
1248function *
1249callgraph_superedge::get_caller_function () const
1250{
1251 return m_cedge->caller->get_fun ();
1252}
1253
1254/* Get the fndecl that was called at this interprocedural call/return
1255 edge. */
1256
1257tree
1258callgraph_superedge::get_callee_decl () const
1259{
1260 return get_callee_function ()->decl;
1261}
1262
aef703cf
AS
1263/* Get the gcall * of this interprocedural call/return edge. */
1264
1265gcall *
1266callgraph_superedge::get_call_stmt () const
1267{
1268 if (m_cedge)
1269 return m_cedge->call_stmt;
1270
1271 return m_src->get_final_call ();
1272}
1273
757bf1df
DM
1274/* Get the calling fndecl at this interprocedural call/return edge. */
1275
1276tree
1277callgraph_superedge::get_caller_decl () const
1278{
1279 return get_caller_function ()->decl;
1280}
1281
1282/* Given PARM_TO_FIND, a PARM_DECL, identify its index (writing it
1283 to *OUT if OUT is non-NULL), and return the corresponding argument
1284 at the callsite. */
1285
1286tree
1287callgraph_superedge::get_arg_for_parm (tree parm_to_find,
1288 callsite_expr *out) const
1289{
1290 gcc_assert (TREE_CODE (parm_to_find) == PARM_DECL);
1291
1292 tree callee = get_callee_decl ();
648796da 1293 const gcall *call_stmt = get_call_stmt ();
757bf1df 1294
648796da 1295 unsigned i = 0;
757bf1df
DM
1296 for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm;
1297 iter_parm = DECL_CHAIN (iter_parm), ++i)
1298 {
648796da
DM
1299 if (i >= gimple_call_num_args (call_stmt))
1300 return NULL_TREE;
757bf1df
DM
1301 if (iter_parm == parm_to_find)
1302 {
1303 if (out)
1304 *out = callsite_expr::from_zero_based_param (i);
648796da 1305 return gimple_call_arg (call_stmt, i);
757bf1df
DM
1306 }
1307 }
1308
1309 /* Not found. */
1310 return NULL_TREE;
1311}
1312
1313/* Look for a use of ARG_TO_FIND as an argument at this callsite.
1314 If found, return the default SSA def of the corresponding parm within
1315 the callee, and if OUT is non-NULL, write the index to *OUT.
1316 Only the first match is handled. */
1317
1318tree
1319callgraph_superedge::get_parm_for_arg (tree arg_to_find,
1320 callsite_expr *out) const
1321{
1322 tree callee = get_callee_decl ();
648796da 1323 const gcall *call_stmt = get_call_stmt ();
757bf1df 1324
648796da 1325 unsigned i = 0;
757bf1df
DM
1326 for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm;
1327 iter_parm = DECL_CHAIN (iter_parm), ++i)
1328 {
648796da
DM
1329 if (i >= gimple_call_num_args (call_stmt))
1330 return NULL_TREE;
1331 tree param = gimple_call_arg (call_stmt, i);
757bf1df
DM
1332 if (arg_to_find == param)
1333 {
1334 if (out)
1335 *out = callsite_expr::from_zero_based_param (i);
1336 return ssa_default_def (get_callee_function (), iter_parm);
1337 }
1338 }
1339
1340 /* Not found. */
1341 return NULL_TREE;
1342}
1343
1344/* Map caller_expr back to an expr within the callee, or return NULL_TREE.
1345 If non-NULL is returned, populate OUT. */
1346
1347tree
1348callgraph_superedge::map_expr_from_caller_to_callee (tree caller_expr,
1349 callsite_expr *out) const
1350{
1351 /* Is it an argument (actual param)? If so, convert to
1352 parameter (formal param). */
1353 tree parm = get_parm_for_arg (caller_expr, out);
1354 if (parm)
1355 return parm;
1356 /* Otherwise try return value. */
1357 if (caller_expr == gimple_call_lhs (get_call_stmt ()))
1358 {
1359 if (out)
1360 *out = callsite_expr::from_return_value ();
1361 return DECL_RESULT (get_callee_decl ());
1362 }
1363
1364 return NULL_TREE;
1365}
1366
1367/* Map callee_expr back to an expr within the caller, or return NULL_TREE.
1368 If non-NULL is returned, populate OUT. */
1369
1370tree
1371callgraph_superedge::map_expr_from_callee_to_caller (tree callee_expr,
1372 callsite_expr *out) const
1373{
1374 if (callee_expr == NULL_TREE)
1375 return NULL_TREE;
1376
1377 /* If it's a parameter (formal param), get the argument (actual param). */
1378 if (TREE_CODE (callee_expr) == PARM_DECL)
1379 return get_arg_for_parm (callee_expr, out);
1380
1381 /* Similar for the default SSA name of the PARM_DECL. */
1382 if (TREE_CODE (callee_expr) == SSA_NAME
1383 && SSA_NAME_IS_DEFAULT_DEF (callee_expr)
1384 && TREE_CODE (SSA_NAME_VAR (callee_expr)) == PARM_DECL)
1385 return get_arg_for_parm (SSA_NAME_VAR (callee_expr), out);
1386
1387 /* Otherwise try return value. */
1388 if (callee_expr == DECL_RESULT (get_callee_decl ()))
1389 {
1390 if (out)
1391 *out = callsite_expr::from_return_value ();
1392 return gimple_call_lhs (get_call_stmt ());
1393 }
1394
1395 return NULL_TREE;
1396}
1397
75038aa6
DM
1398} // namespace ana
1399
757bf1df 1400#endif /* #if ENABLE_ANALYZER */