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