#include "tree-dfa.h"
#include "cfganal.h"
#include "function.h"
+#include "json.h"
#include "analyzer/analyzer.h"
#include "ordered-hash-map.h"
#include "options.h"
namespace ana {
+/* Get the function of the ultimate alias target being called at EDGE,
+ if any. */
+
+static function *
+get_ultimate_function_for_cgraph_edge (cgraph_edge *edge)
+{
+ cgraph_node *ultimate_node = edge->callee->ultimate_alias_target ();
+ if (!ultimate_node)
+ return NULL;
+ return ultimate_node->get_fun ();
+}
+
/* Get the cgraph_edge, but only if there's an underlying function body. */
cgraph_edge *
return NULL;
if (!edge->callee)
return NULL; /* e.g. for a function pointer. */
- if (!edge->callee->get_fun ())
+ if (!get_ultimate_function_for_cgraph_edge (edge))
return NULL;
return edge;
}
/* supergraph's ctor. Walk the callgraph, building supernodes for each
CFG basic block, splitting the basic blocks at callsites. Join
together the supernodes with interprocedural and intraprocedural
- superedges as appropriate. */
+ superedges as appropriate.
+ Assign UIDs to the gimple stmts. */
supergraph::supergraph (logger *logger)
{
LOG_FUNC (logger);
- /* First pass: make supernodes. */
+ /* First pass: make supernodes (and assign UIDs to the gimple stmts). */
{
+ unsigned next_uid = 0;
+
/* Sort the cgraph_nodes? */
cgraph_node *node;
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
{
gimple *stmt = gsi_stmt (gpi);
m_stmt_to_node_t.put (stmt, node_for_stmts);
+ stmt->uid = next_uid++;
}
/* Append statements from BB to the current supernode, splitting
gimple *stmt = gsi_stmt (gsi);
node_for_stmts->m_stmts.safe_push (stmt);
m_stmt_to_node_t.put (stmt, node_for_stmts);
+ stmt->uid = next_uid++;
if (cgraph_edge *edge = supergraph_call_edge (fun, stmt))
{
m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts);
{
cgraph_edge *edge = (*iter).first;
supernode *caller_prev_supernode = (*iter).second;
- basic_block callee_cfg_block
- = ENTRY_BLOCK_PTR_FOR_FN (edge->callee->get_fun ());
+ function* callee_fn = get_ultimate_function_for_cgraph_edge (edge);
+ if (!callee_fn || !callee_fn->cfg)
+ continue;
+ basic_block callee_cfg_block = ENTRY_BLOCK_PTR_FOR_FN (callee_fn);
supernode *callee_supernode
= *m_bb_to_initial_node.get (callee_cfg_block);
call_superedge *sedge
{
cgraph_edge *edge = (*iter).first;
supernode *caller_next_supernode = (*iter).second;
- basic_block callee_cfg_block
- = EXIT_BLOCK_PTR_FOR_FN (edge->callee->get_fun ());
+ function* callee_fn = get_ultimate_function_for_cgraph_edge (edge);
+ if (!callee_fn || !callee_fn->cfg)
+ continue;
+ basic_block callee_cfg_block = EXIT_BLOCK_PTR_FOR_FN (callee_fn);
supernode *callee_supernode
= *m_bb_to_initial_node.get (callee_cfg_block);
return_superedge *sedge
fclose (fp);
}
+/* Return a new json::object of the form
+ {"nodes" : [objs for snodes],
+ "edges" : [objs for sedges]}. */
+
+json::object *
+supergraph::to_json () const
+{
+ json::object *sgraph_obj = new json::object ();
+
+ /* Nodes. */
+ {
+ json::array *nodes_arr = new json::array ();
+ unsigned i;
+ supernode *n;
+ FOR_EACH_VEC_ELT (m_nodes, i, n)
+ nodes_arr->append (n->to_json ());
+ sgraph_obj->set ("nodes", nodes_arr);
+ }
+
+ /* Edges. */
+ {
+ json::array *edges_arr = new json::array ();
+ unsigned i;
+ superedge *n;
+ FOR_EACH_VEC_ELT (m_edges, i, n)
+ edges_arr->append (n->to_json ());
+ sgraph_obj->set ("edges", edges_arr);
+ }
+
+ return sgraph_obj;
+}
+
/* Create a supernode for BB within FUN and add it to this supergraph.
If RETURNING_CALL is non-NULL, the supernode represents the resumption
gv->println("style=\"solid\";");
gv->println("color=\"black\";");
gv->println("fillcolor=\"lightgrey\";");
- gv->println("label=\"sn: %i\";", m_index);
+ gv->println("label=\"sn: %i (bb: %i)\";", m_index, m_bb->index);
pretty_printer *pp = gv->get_pp ();
if (args.m_node_annotator)
- args.m_node_annotator->add_node_annotations (gv, *this);
+ args.m_node_annotator->add_node_annotations (gv, *this, false);
gv->write_indent ();
dump_dot_id (pp);
bool had_row = false;
+ /* Give any annotator the chance to add its own per-node TR elements. */
+ if (args.m_node_annotator)
+ if (args.m_node_annotator->add_node_annotations (gv, *this, true))
+ had_row = true;
+
if (m_returning_call)
{
- gv->begin_tr ();
+ gv->begin_trtd ();
pp_string (pp, "returning call: ");
- gv->end_tr ();
+ gv->end_tdtr ();
gv->begin_tr ();
+ gv->begin_td ();
pp_gimple_stmt_1 (pp, m_returning_call, 0, (dump_flags_t)0);
pp_write_text_as_html_like_dot_to_stream (pp);
+ gv->end_td ();
+ /* Give any annotator the chance to add per-stmt TD elements to
+ this row. */
+ if (args.m_node_annotator)
+ args.m_node_annotator->add_stmt_annotations (gv, m_returning_call,
+ true);
gv->end_tr ();
+ /* Give any annotator the chance to add per-stmt TR elements. */
if (args.m_node_annotator)
- args.m_node_annotator->add_stmt_annotations (gv, m_returning_call);
+ args.m_node_annotator->add_stmt_annotations (gv, m_returning_call,
+ false);
pp_newline (pp);
had_row = true;
{
const gimple *stmt = gsi_stmt (gpi);
gv->begin_tr ();
+ gv->begin_td ();
pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
pp_write_text_as_html_like_dot_to_stream (pp);
+ gv->end_td ();
+ /* Give any annotator the chance to add per-phi TD elements to
+ this row. */
+ if (args.m_node_annotator)
+ args.m_node_annotator->add_stmt_annotations (gv, stmt, true);
gv->end_tr ();
+ /* Give any annotator the chance to add per-phi TR elements. */
if (args.m_node_annotator)
- args.m_node_annotator->add_stmt_annotations (gv, stmt);
+ args.m_node_annotator->add_stmt_annotations (gv, stmt, false);
pp_newline (pp);
had_row = true;
FOR_EACH_VEC_ELT (m_stmts, i, stmt)
{
gv->begin_tr ();
+ gv->begin_td ();
pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
pp_write_text_as_html_like_dot_to_stream (pp);
+ gv->end_td ();
+ /* Give any annotator the chance to add per-stmt TD elements to
+ this row. */
+ if (args.m_node_annotator)
+ args.m_node_annotator->add_stmt_annotations (gv, stmt, true);
gv->end_tr ();
+ /* Give any annotator the chance to add per-stmt TR elements. */
if (args.m_node_annotator)
- args.m_node_annotator->add_stmt_annotations (gv, stmt);
+ args.m_node_annotator->add_stmt_annotations (gv, stmt, false);
pp_newline (pp);
had_row = true;
}
+ /* Give any annotator the chance to add additional per-node TR elements
+ to the end of the TABLE. */
+ if (args.m_node_annotator)
+ if (args.m_node_annotator->add_after_node_annotations (gv, *this))
+ had_row = true;
+
/* Graphviz requires a TABLE element to have at least one TR
(and each TR to have at least one TD). */
if (!had_row)
pp_printf (pp, "node_%i", m_index);
}
+/* Return a new json::object of the form
+ {"idx": int,
+ "bb_idx": int,
+ "m_returning_call": optional str,
+ "phis": [str],
+ "stmts" : [str]}. */
+
+json::object *
+supernode::to_json () const
+{
+ json::object *snode_obj = new json::object ();
+
+ snode_obj->set ("idx", new json::integer_number (m_index));
+ snode_obj->set ("bb_idx", new json::integer_number (m_bb->index));
+
+ if (m_returning_call)
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_gimple_stmt_1 (&pp, m_returning_call, 0, (dump_flags_t)0);
+ snode_obj->set ("returning_call",
+ new json::string (pp_formatted_text (&pp)));
+ }
+
+ /* Phi nodes. */
+ {
+ json::array *phi_arr = new json::array ();
+ for (gphi_iterator gpi = const_cast<supernode *> (this)->start_phis ();
+ !gsi_end_p (gpi); gsi_next (&gpi))
+ {
+ const gimple *stmt = gsi_stmt (gpi);
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
+ phi_arr->append (new json::string (pp_formatted_text (&pp)));
+ }
+ snode_obj->set ("phis", phi_arr);
+ }
+
+ /* Statements. */
+ {
+ json::array *stmt_arr = new json::array ();
+ int i;
+ gimple *stmt;
+ FOR_EACH_VEC_ELT (m_stmts, i, stmt)
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
+ stmt_arr->append (new json::string (pp_formatted_text (&pp)));
+ }
+ snode_obj->set ("stmts", stmt_arr);
+ }
+
+ return snode_obj;
+}
+
/* Get a location_t for the start of this supernode. */
location_t
gcc_unreachable ();
}
+/* Dump this superedge to PP. */
+
+void
+superedge::dump (pretty_printer *pp) const
+{
+ pp_printf (pp, "edge: SN: %i -> SN: %i", m_src->m_index, m_dest->m_index);
+ char *desc = get_description (false);
+ if (strlen (desc) > 0)
+ {
+ pp_space (pp);
+ pp_string (pp, desc);
+ }
+ free (desc);
+}
+
+/* Dump this superedge to stderr. */
+
+DEBUG_FUNCTION void
+superedge::dump () const
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_show_color (&pp) = pp_show_color (global_dc->printer);
+ pp.buffer->stream = stderr;
+ dump (&pp);
+ pp_newline (&pp);
+ pp_flush (&pp);
+}
+
/* Implementation of dedge::dump_dot for superedges.
Write a .dot edge to GV representing this superedge. */
pp_printf (pp, "\"];\n");
}
+/* Return a new json::object of the form
+ {"src_idx": int, the index of the source supernode,
+ "dst_idx": int, the index of the destination supernode,
+ "desc" : str. */
+
+json::object *
+superedge::to_json () const
+{
+ json::object *sedge_obj = new json::object ();
+ sedge_obj->set ("src_idx", new json::integer_number (m_src->m_index));
+ sedge_obj->set ("dst_idx", new json::integer_number (m_dest->m_index));
+
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ dump_label_to_pp (&pp, false);
+ sedge_obj->set ("desc", new json::string (pp_formatted_text (&pp)));
+ }
+
+ return sedge_obj;
+}
+
/* If this is an intraprocedural superedge, return the associated
CFG edge. Otherwise, return NULL. */
function *
callgraph_superedge::get_callee_function () const
{
- return m_cedge->callee->get_fun ();
+ return get_ultimate_function_for_cgraph_edge (m_cedge);
}
/* Get the calling function at this interprocedural call/return edge. */