Add dummy nodes at the beginning and end of the graph.

The dummy nodes are for detectining uninitialized variables (entry dummy)
and making globals live at function exit (exit dummy). The reaching defs
and live vars code currently seg because neither node has had its sets
initialized.
This commit is contained in:
Bill Currie 2012-12-10 13:56:26 +09:00
parent f30741c875
commit d717a0b3f2
3 changed files with 53 additions and 18 deletions

View File

@ -96,7 +96,7 @@ typedef struct flowgraph_s {
struct flowgraph_s *next; ///< for ALLOC
struct function_s *func; ///< function to which this graph is attached
flownode_t **nodes; ///< array of nodes in the graph
int num_nodes;
int num_nodes; ///< number of real nodes in the graph
flowedge_t *edges; ///< array of all edges in the graph
int num_edges;
struct set_s *dfst; ///< edges in the depth-first search tree

View File

@ -246,6 +246,9 @@ print_flowgraph (flow_dot_t *method, flowgraph_t *graph, const char *filename)
method->print_node (dstr, graph, graph->nodes[i], 0);
}
for (i = 0; i < graph->num_edges; i++) {
if ((int) graph->edges[i].head >= graph->num_nodes
|| (int) graph->edges[i].tail >= graph->num_nodes)
continue; // dummy node
method->print_edge (dstr, graph, &graph->edges[i], 0);
}
dasprintf (dstr, "}\n");

View File

@ -854,7 +854,7 @@ flow_find_predecessors (flowgraph_t *graph)
flownode_t *node;
set_iter_t *succ;
for (i = 0; i < graph->num_nodes; i++) {
for (i = 0; i < graph->num_nodes + 2; i++) {
node = graph->nodes[i];
for (succ = set_first (node->successors); succ;
succ = set_next (succ)) {
@ -1005,6 +1005,10 @@ flow_build_dfst (flowgraph_t *graph)
set_t *visited = set_new ();
int i;
// mark the dummy nodes as visited to keep them out of the dfst
set_add (visited, graph->num_nodes);
set_add (visited, graph->num_nodes + 1);
graph->dfo = malloc (graph->num_nodes * sizeof (unsigned));
graph->dfst = set_new ();
i = graph->num_nodes;
@ -1012,6 +1016,22 @@ flow_build_dfst (flowgraph_t *graph)
set_delete (visited);
}
static flownode_t *
flow_make_node (sblock_t *sblock, int id, function_t *func)
{
flownode_t *node;
node = new_node ();
node->predecessors = set_new ();
node->successors = set_new ();
node->edges = set_new ();
node->dom = set_new ();
node->global_vars = func->global_vars;
node->id = id;
node->sblock = sblock;
return node;
}
static flowgraph_t *
flow_build_graph (function_t *func)
{
@ -1028,18 +1048,16 @@ flow_build_graph (function_t *func)
graph->func = func;
for (sb = sblock; sb; sb = sb->next)
sb->number = graph->num_nodes++;
graph->nodes = malloc (graph->num_nodes * sizeof (flownode_t *));
for (sb = sblock; sb; sb = sb->next) {
node = new_node ();
node->predecessors = set_new ();
node->successors = set_new ();
node->edges = set_new ();
node->dom = set_new ();
node->global_vars = func->global_vars;
node->id = sb->number;
node->sblock = sb;
graph->nodes[node->id] = node;
}
// + 2 for the uninitialized dummy head block and the live dummy end block
graph->nodes = malloc ((graph->num_nodes + 2) * sizeof (flownode_t *));
for (sb = sblock; sb; sb = sb->next)
graph->nodes[sb->number] = flow_make_node (sb, sb->number, func);
// Create the dummy node for detecting uninitialized variables
node = flow_make_node (0, graph->num_nodes, func);
graph->nodes[graph->num_nodes] = node;
// Create the dummy node for making global vars live at function exit
node = flow_make_node (0, graph->num_nodes + 1, func);
graph->nodes[graph->num_nodes + 1] = node;
// "convert" the basic blocks connections to flow-graph connections
for (i = 0; i < graph->num_nodes; i++) {
@ -1066,15 +1084,29 @@ flow_build_graph (function_t *func)
set_add (node->successors, statement_get_target (st)->number);
} else if (statement_is_return (st)) {
// exit from function (dead end)
// however, make the exit dummy block the node's successor
set_add (node->successors, graph->num_nodes + 1);
} else {
// there is no flow-control statement in sb, so sb's next
// must be followed
set_add (node->successors, sb->next->number);
if (sb->next) {
set_add (node->successors, sb->next->number);
} else {
bug (0, "code drops off the end of the function");
// this shouldn't happen
// however, make the exit dummy block the node's successor
set_add (node->successors, graph->num_nodes + 1);
}
}
graph->num_edges += set_size (node->successors);
}
// set the successor for the entry dummy node to the real entry node
node = graph->nodes[graph->num_nodes];
set_add (node->successors, 0);
graph->num_edges += set_size (node->successors);
graph->edges = malloc (graph->num_edges * sizeof (flowedge_t *));
for (j = 0, i = 0; i < graph->num_nodes; i++) {
for (j = 0, i = 0; i < graph->num_nodes + 2; i++) {
node = graph->nodes[i];
for (succ = set_first (node->successors); succ;
succ = set_next (succ), j++) {
@ -1098,6 +1130,8 @@ flow_data_flow (function_t *func)
flow_build_statements (func);
flow_build_vars (func);
graph = flow_build_graph (func);
if (options.block_dot.flow)
dump_dot ("flow", graph, dump_dot_flow);
func->graph = graph;
flow_reaching_defs (graph);
if (options.block_dot.reaching)
@ -1105,7 +1139,5 @@ flow_data_flow (function_t *func)
flow_live_vars (graph);
flow_uninitialized (graph);
flow_build_dags (graph);
if (options.block_dot.flow)
dump_dot ("flow", graph, dump_dot_flow);
func->sblock = flow_generate (graph);
}