mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-17 01:11:45 +00:00
Rewrite the flow graph code.
The flow graph nodes are now properly separated from the graph, and edge information is stored in the graph struct. This actually made for much cleaner code (partly thanks to the use of sets and set iterators). Flow graph reduction has been (temporarily) ripped out as the entire approach was wrong. There was also a bug in that I didn't really understand the dragon book about selecting nodes and thus messed things up. The depth-first search tree "fixed" the problem, but was really the wrong solution (sledge hammer :P). Also, now that I understand that dot's directed graphs must be acyclic, I now have much better control over the graphs (back edges need to be flipped).
This commit is contained in:
parent
b9599a7119
commit
d7177a78e9
5 changed files with 214 additions and 311 deletions
|
@ -46,56 +46,43 @@ typedef struct flowloop_s {
|
|||
} flowloop_t;
|
||||
|
||||
typedef struct flowedge_s {
|
||||
unsigned tail; //< node index
|
||||
unsigned head; //< successor index
|
||||
unsigned tail;
|
||||
unsigned head;
|
||||
} flowedge_t;
|
||||
|
||||
/** Represent a node in a flow graph.
|
||||
|
||||
With the \a siblings and \a num_siblings fields, the entire graph can be
|
||||
accessed via any node within that graph.
|
||||
*/
|
||||
typedef struct flownode_s {
|
||||
struct flownode_s *next;
|
||||
unsigned id;
|
||||
int num_pred;
|
||||
unsigned *predecessors; //< indices into siblings
|
||||
int num_succ;
|
||||
unsigned *successors; //< indices into siblings
|
||||
unsigned num_nodes; //< number of nodes or sblocks
|
||||
unsigned region; //< the region of which this node is a member
|
||||
unsigned *depth_first; //< indices into siblings in depth-first order
|
||||
/// \name Node pointers.
|
||||
/// Only one of \a sblocks or \a nodes will be non-null. If \a sblocks is
|
||||
/// non-null, then this is an innermost flow-node, otherwise \a nodes
|
||||
/// will be non-null and this is a higher level flow-node representing a
|
||||
/// region.
|
||||
///
|
||||
/// \a sblocks points to the array of all sblocks in the function
|
||||
/// (it is a copy of function_t's graph member). \a id acts as an index
|
||||
/// into \a sblocks to identify the sblock associated with this node.
|
||||
///
|
||||
/// \a nodes is an array of all flow-nodes nested within the region
|
||||
/// represented by this node.
|
||||
///
|
||||
/// \a siblings is an array of all flow-nodes contained within the same
|
||||
/// region as this node.
|
||||
//@{
|
||||
struct sblock_s **sblocks;
|
||||
struct flownode_s **nodes;
|
||||
struct flownode_s **siblings;
|
||||
unsigned num_siblings;
|
||||
//@}
|
||||
struct set_s *dom;
|
||||
struct flownode_s *next; //< for ALLOC
|
||||
unsigned id; //< index of this node in the flow graph
|
||||
unsigned dfn; //< depth-first ordering of this node
|
||||
struct set_s *predecessors; //< predecessors of this node
|
||||
struct set_s *successors; //< successors of this node
|
||||
struct set_s *edges; //< edges leaving this node, to successor nodes
|
||||
struct set_s *dom; //< dominating nodes
|
||||
struct sblock_s *sblock; //< original statement block
|
||||
} flownode_t;
|
||||
|
||||
typedef struct flowgraph_s {
|
||||
struct flowgraph_s *next; //< for ALLOC
|
||||
flownode_t **nodes; //< array of nodes in the graph
|
||||
int num_nodes;
|
||||
flowedge_t *edges; //< array of all edges in the graph
|
||||
int num_edges;
|
||||
struct set_s *dfst; //< edges in the depth-first search tree
|
||||
unsigned *dfo; //< depth-first order of nodes
|
||||
flowloop_t *loops; //< linked list of natural loops
|
||||
} flowgraph_t;
|
||||
|
||||
int flow_is_cond (struct statement_s *s);
|
||||
int flow_is_goto (struct statement_s *s);
|
||||
int flow_is_return (struct statement_s *s);
|
||||
struct sblock_s *flow_get_target (struct statement_s *s);
|
||||
void flow_build_vars (struct function_s *func);
|
||||
void flow_build_graph (struct function_s *func);
|
||||
void print_flowgraph (flownode_t *flow, const char *filename);
|
||||
flowgraph_t *flow_build_graph (struct sblock_s *func);
|
||||
void flow_del_graph (flowgraph_t *graph);
|
||||
|
||||
void print_flowgraph (flowgraph_t *graph, const char *filename);
|
||||
|
||||
//@}
|
||||
|
||||
|
|
|
@ -79,14 +79,8 @@ typedef struct function_s {
|
|||
struct reloc_s *refs; ///< relocation targets for this function
|
||||
struct expr_s *var_init;
|
||||
const char *name; ///< nice name for __PRETTY_FUNCTION__
|
||||
struct sblock_s *sblock; ///< initial node of function's flow graph
|
||||
/** Array of pointers to all nodes in the function's flow graph.
|
||||
|
||||
This permits ready mapping of node number to node in the flow
|
||||
analyzer.
|
||||
*/
|
||||
struct sblock_s **graph;
|
||||
int num_nodes; ///< number of nodes in the graph
|
||||
struct sblock_s *sblock; ///< initial node of function's code
|
||||
struct flowgraph_s *graph; ///< the function's flow graph
|
||||
/** Array of pointers to all variables referenced by the function's code.
|
||||
|
||||
This permits ready mapping of (function specific) variable number to
|
||||
|
@ -95,7 +89,6 @@ typedef struct function_s {
|
|||
struct daglabel_s **vars;
|
||||
int num_vars; ///< total number of variables referenced
|
||||
struct flowloop_s *loops; ///< linked list of loops in the function
|
||||
struct flownode_s *flow; ///< flow graph
|
||||
} function_t;
|
||||
|
||||
extern function_t *current_func;
|
||||
|
|
|
@ -46,57 +46,65 @@
|
|||
#include "dags.h"
|
||||
#include "flow.h"
|
||||
#include "expr.h"
|
||||
#include "set.h"
|
||||
#include "strpool.h"
|
||||
|
||||
static void
|
||||
print_flow_node (dstring_t *dstr, flownode_t *node, int level)
|
||||
{
|
||||
int indent = level * 2 + 2;
|
||||
unsigned j;
|
||||
|
||||
if (node->nodes) {
|
||||
dasprintf (dstr, "%*ssubgraph \"cluster_%p\" {\n", indent, "", node);
|
||||
//dasprintf (dstr, "%*srankdir=TB;\n", indent + 2, "");
|
||||
dasprintf (dstr, "%*slabel=\"%d\";\n", indent + 2, "", node->id);
|
||||
for (j = 0; j < node->num_nodes; j++)
|
||||
print_flow_node (dstr, node->nodes[j], level + 1);
|
||||
dasprintf (dstr, "%*s}\n", indent, "");
|
||||
}
|
||||
dasprintf (dstr, "%*s\"fn_%p\" [label=\"%d\"];\n", indent, "", node,
|
||||
node->id);
|
||||
}
|
||||
|
||||
static void
|
||||
print_flow_edges (dstring_t *dstr, flownode_t *node, int level)
|
||||
print_flow_edges (dstring_t *dstr, flowgraph_t *graph, int level)
|
||||
{
|
||||
int indent = level * 2 + 2;
|
||||
int i;
|
||||
unsigned j;
|
||||
flowedge_t *edge;
|
||||
flownode_t *t, *h;
|
||||
const char *style;
|
||||
int weight;
|
||||
|
||||
if (node->nodes) {
|
||||
for (j = 0; j < node->num_nodes; j++)
|
||||
print_flow_edges (dstr, node->nodes[j], level + 1);
|
||||
for (i = 0; i < graph->num_edges; i++) {
|
||||
edge = &graph->edges[i];
|
||||
t = graph->nodes[edge->tail];
|
||||
h = graph->nodes[edge->head];
|
||||
if (t->dfn < h->dfn) {
|
||||
style = "solid";
|
||||
weight = 0;
|
||||
if (set_is_member (graph->dfst, i)) {
|
||||
style = "bold";
|
||||
weight = 10;
|
||||
}
|
||||
dasprintf (dstr,
|
||||
"%*s\"fn_%p\" -> \"fn_%p\" [style=%s,weight=%d];\n",
|
||||
indent, "", t, h, style, weight);
|
||||
} else {
|
||||
dasprintf (dstr,
|
||||
"%*s\"fn_%p\" -> \"fn_%p\" [dir=back, style=dashed];\n",
|
||||
indent, "", h, t);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < node->num_succ; i++)
|
||||
dasprintf (dstr, "%*s\"fn_%p\" -> \"fn_%p\";\n", indent, "", node,
|
||||
node->siblings[node->successors[i]]);
|
||||
}
|
||||
|
||||
void
|
||||
print_flowgraph (flownode_t *flow, const char *filename)
|
||||
print_flowgraph (flowgraph_t *graph, const char *filename)
|
||||
{
|
||||
unsigned i;
|
||||
int i;
|
||||
dstring_t *dstr = dstring_newstr();
|
||||
|
||||
dasprintf (dstr, "digraph flow_%p {\n", flow->siblings);
|
||||
dasprintf (dstr, "digraph flowgraph_%p {\n", graph);
|
||||
dasprintf (dstr, " layout=dot;\n");
|
||||
dasprintf (dstr, " clusterrank=local;\n");
|
||||
//dasprintf (dstr, " rankdir=TB;\n");
|
||||
dasprintf (dstr, " rankdir=TB;\n");
|
||||
dasprintf (dstr, " compound=true;\n");
|
||||
for (i = 0; i < flow->num_siblings; i++) {
|
||||
print_flow_node (dstr, flow->siblings[i], 0);
|
||||
print_flow_edges (dstr, flow->siblings[i], 0);
|
||||
for (i = 0; i < graph->num_nodes; i++) {
|
||||
print_flow_node (dstr, graph->nodes[i], 0);
|
||||
}
|
||||
print_flow_edges (dstr, graph, 0);
|
||||
dasprintf (dstr, "}\n");
|
||||
|
||||
if (filename) {
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
|
||||
static flowloop_t *free_loops;
|
||||
static flownode_t *free_nodes;
|
||||
static flowgraph_t *free_graphs;
|
||||
|
||||
static flowloop_t *
|
||||
new_loop (void)
|
||||
|
@ -76,20 +77,50 @@ new_node (void)
|
|||
ALLOC (256, flownode_t, nodes, node);
|
||||
return node;
|
||||
}
|
||||
#if 0
|
||||
|
||||
static void
|
||||
delete_node (flownode_t *node)
|
||||
{
|
||||
if (node->nodes)
|
||||
free (node->nodes);
|
||||
if (node->predecessors)
|
||||
free (node->predecessors);
|
||||
set_delete (node->predecessors);
|
||||
if (node->successors)
|
||||
free (node->successors);
|
||||
set_delete (node->successors);
|
||||
if (node->edges)
|
||||
set_delete (node->edges);
|
||||
if (node->dom)
|
||||
set_delete (node->dom);
|
||||
node->next = free_nodes;
|
||||
free_nodes = node;
|
||||
}
|
||||
#endif
|
||||
|
||||
static flowgraph_t *
|
||||
new_graph (void)
|
||||
{
|
||||
flowgraph_t *graph;
|
||||
ALLOC (256, flowgraph_t, graphs, graph);
|
||||
return graph;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_graph (flowgraph_t *graph)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (graph->nodes) {
|
||||
for (i = 0; i < graph->num_nodes; i++)
|
||||
delete_node (graph->nodes[i]);
|
||||
free (graph->nodes);
|
||||
}
|
||||
if (graph->edges)
|
||||
free (graph->edges);
|
||||
if (graph->dfst)
|
||||
set_delete (graph->dfst);
|
||||
if (graph->dfo)
|
||||
free (graph->dfo);
|
||||
graph->next = free_graphs;
|
||||
free_graphs = graph;
|
||||
}
|
||||
|
||||
static int
|
||||
is_variable (daglabel_t *var)
|
||||
{
|
||||
|
@ -167,6 +198,9 @@ flow_build_vars (function_t *func)
|
|||
num_vars += count_operand (s->opc);
|
||||
}
|
||||
}
|
||||
if (!num_vars)
|
||||
return;
|
||||
|
||||
func->vars = malloc (num_vars * sizeof (daglabel_t *));
|
||||
|
||||
func->num_vars = 0; // incremented by add_operand
|
||||
|
@ -214,83 +248,61 @@ flow_get_target (statement_t *s)
|
|||
}
|
||||
|
||||
static void
|
||||
flow_find_predecessors (flownode_t **node_list, unsigned num_nodes)
|
||||
flow_find_predecessors (flowgraph_t *graph)
|
||||
{
|
||||
unsigned i, j, k;
|
||||
int i;
|
||||
flownode_t *node;
|
||||
set_iter_t *succ;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
node = node_list[i];
|
||||
for (j = 0; j < num_nodes; j++) {
|
||||
unsigned *succ;
|
||||
flownode_t *n;
|
||||
|
||||
n = node_list[j];
|
||||
for (succ = n->successors; succ - n->successors < n->num_succ;
|
||||
succ++) {
|
||||
if (*succ == i) {
|
||||
node->num_pred++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
node->predecessors = malloc (node->num_pred * sizeof (flownode_t *));
|
||||
for (k = j = 0; j < num_nodes; j++) {
|
||||
unsigned *succ;
|
||||
flownode_t *n;
|
||||
|
||||
n = node_list[j];
|
||||
for (succ = n->successors; succ - n->successors < n->num_succ;
|
||||
succ++) {
|
||||
if (*succ == i) {
|
||||
node->predecessors[k++] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < graph->num_nodes; i++) {
|
||||
node = graph->nodes[i];
|
||||
for (succ = set_first (node->successors); succ;
|
||||
succ = set_next (succ)) {
|
||||
set_add (graph->nodes[succ->member]->predecessors, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
flow_calc_dominators (flownode_t **node_list, unsigned num_nodes)
|
||||
flow_find_dominators (flowgraph_t *graph)
|
||||
{
|
||||
set_t *work;
|
||||
flownode_t *node;
|
||||
unsigned i;
|
||||
unsigned *pred;
|
||||
int i;
|
||||
set_iter_t *pred;
|
||||
int changed;
|
||||
|
||||
if (!num_nodes)
|
||||
if (!graph->num_nodes)
|
||||
return;
|
||||
|
||||
// First, create a base set for the initial state of the non-initial nodes
|
||||
work = set_new ();
|
||||
for (i = 0; i < num_nodes; i++)
|
||||
for (i = 0; i < graph->num_nodes; i++)
|
||||
set_add (work, i);
|
||||
|
||||
node_list[0]->dom = set_new ();
|
||||
set_add (node_list[0]->dom, 0);
|
||||
set_add (graph->nodes[0]->dom, 0);
|
||||
|
||||
// initialize dom for the non-initial nodes
|
||||
for (i = 1; i < num_nodes; i++) {
|
||||
node_list[i]->dom = set_new ();
|
||||
set_assign (node_list[i]->dom, work);
|
||||
for (i = 1; i < graph->num_nodes; i++) {
|
||||
set_assign (graph->nodes[i]->dom, work);
|
||||
}
|
||||
|
||||
do {
|
||||
changed = 0;
|
||||
for (i = 1; i < num_nodes; i++) {
|
||||
node = node_list[i];
|
||||
pred = node->predecessors;
|
||||
set_assign (work, node_list[*pred]->dom);
|
||||
for (pred++; pred - node->predecessors < node->num_pred; pred++)
|
||||
set_intersection (work, node_list[*pred]->dom);
|
||||
for (i = 1; i < graph->num_nodes; i++) {
|
||||
node = graph->nodes[i];
|
||||
pred = set_first (node->predecessors);
|
||||
if (pred)
|
||||
set_assign (work, graph->nodes[pred->member]->dom);
|
||||
for (pred = set_next (pred); pred; pred = set_next (pred))
|
||||
set_intersection (work, graph->nodes[pred->member]->dom);
|
||||
set_add (work, i);
|
||||
if (!set_is_equivalent (work, node->dom))
|
||||
changed = 1;
|
||||
set_assign (node->dom, work);
|
||||
}
|
||||
} while (changed);
|
||||
set_delete (work);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -303,12 +315,12 @@ insert_loop_node (flowloop_t *loop, unsigned n, set_t *stack)
|
|||
}
|
||||
|
||||
static flowloop_t *
|
||||
make_loop (flownode_t **node_list, unsigned num_nodes, unsigned n, unsigned d)
|
||||
make_loop (flowgraph_t *graph, unsigned n, unsigned d)
|
||||
{
|
||||
flowloop_t *loop = new_loop ();
|
||||
flownode_t *node;
|
||||
set_t *stack = set_new ();
|
||||
unsigned *pred;
|
||||
set_iter_t *pred;
|
||||
|
||||
loop->head = d;
|
||||
set_add (loop->nodes, d);
|
||||
|
@ -318,30 +330,30 @@ make_loop (flownode_t **node_list, unsigned num_nodes, unsigned n, unsigned d)
|
|||
unsigned m = ss->member;
|
||||
set_del_iter (ss);
|
||||
set_remove (stack, m);
|
||||
node = node_list[m];
|
||||
for (pred = node->predecessors;
|
||||
pred - node->predecessors < node->num_pred; pred++)
|
||||
insert_loop_node (loop, *pred, stack);
|
||||
node = graph->nodes[m];
|
||||
for (pred = set_first (node->predecessors); pred;
|
||||
pred = set_next (pred))
|
||||
insert_loop_node (loop, pred->member, stack);
|
||||
}
|
||||
set_delete (stack);
|
||||
return loop;
|
||||
}
|
||||
|
||||
static flowloop_t *
|
||||
flow_find_loops (flownode_t **node_list, unsigned num_nodes)
|
||||
static void
|
||||
flow_find_loops (flowgraph_t *graph)
|
||||
{
|
||||
flownode_t *node;
|
||||
unsigned *succ;
|
||||
set_iter_t *succ;
|
||||
flowloop_t *loop, *l;
|
||||
flowloop_t *loop_list = 0;
|
||||
unsigned i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
node = node_list[i];
|
||||
for (succ = node->successors; succ - node->successors < node->num_succ;
|
||||
succ++) {
|
||||
if (set_is_member (node->dom, *succ)) {
|
||||
loop = make_loop (node_list, num_nodes, node->id, *succ);
|
||||
for (i = 0; i < graph->num_nodes; i++) {
|
||||
node = graph->nodes[i];
|
||||
for (succ = set_first (node->successors); succ;
|
||||
succ = set_next (succ)) {
|
||||
if (set_is_member (node->dom, succ->member)) {
|
||||
loop = make_loop (graph, node->id, succ->member);
|
||||
for (l = loop_list; l; l = l->next) {
|
||||
if (l->head == loop->head
|
||||
&& !set_is_subset (l->nodes, loop->nodes)
|
||||
|
@ -359,210 +371,113 @@ flow_find_loops (flownode_t **node_list, unsigned num_nodes)
|
|||
}
|
||||
}
|
||||
}
|
||||
return loop_list;
|
||||
graph->loops = loop_list;
|
||||
}
|
||||
|
||||
static void
|
||||
df_search (flownode_t *graph, set_t *visited, unsigned *i, unsigned n)
|
||||
df_search (flowgraph_t *graph, set_t *visited, int *i, int n)
|
||||
{
|
||||
int j;
|
||||
flownode_t *node;
|
||||
set_iter_t *edge;
|
||||
int succ;
|
||||
|
||||
set_add (visited, n);
|
||||
node = graph->siblings[n];
|
||||
for (j = 0; j < node->num_succ; j++) {
|
||||
if (!set_is_member (visited, node->successors[j])) {
|
||||
df_search (graph, visited, i, node->successors[j]);
|
||||
node = graph->nodes[n];
|
||||
for (edge = set_first (node->edges); edge; edge = set_next (edge)) {
|
||||
succ = graph->edges[edge->member].head;
|
||||
if (!set_is_member (visited, succ)) {
|
||||
set_add (graph->dfst, edge->member);
|
||||
df_search (graph, visited, i, succ);
|
||||
}
|
||||
}
|
||||
graph->depth_first[--*i] = n;
|
||||
node->dfn = --*i;
|
||||
graph->dfo[node->dfn] = n;
|
||||
}
|
||||
|
||||
static void
|
||||
flow_depth_first (flownode_t *graph)
|
||||
flow_build_dfst (flowgraph_t *graph)
|
||||
{
|
||||
unsigned i = graph->num_siblings;
|
||||
set_t *visited = set_new ();
|
||||
|
||||
graph->depth_first = malloc (graph->num_siblings * sizeof (unsigned));
|
||||
df_search (graph, visited, &i, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
is_predecessor (unsigned m, set_t *I, flownode_t *graph)
|
||||
{
|
||||
flownode_t *node = graph->siblings[m];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < node->num_pred; i++)
|
||||
if (!set_is_member (I, node->predecessors[i]))
|
||||
return 0;
|
||||
return 1;
|
||||
graph->dfo = malloc (graph->num_nodes * sizeof (unsigned));
|
||||
graph->dfst = set_new ();
|
||||
i = graph->num_nodes;
|
||||
df_search (graph, visited, &i, 0);
|
||||
set_delete (visited);
|
||||
}
|
||||
|
||||
static set_t *
|
||||
select_nodes (flownode_t *graph, set_t *G, unsigned n)
|
||||
flowgraph_t *
|
||||
flow_build_graph (sblock_t *sblock)
|
||||
{
|
||||
set_t *I;
|
||||
set_iter_t *m;
|
||||
|
||||
I = set_new ();
|
||||
set_add (I, n);
|
||||
set_remove (G, n);
|
||||
for (m = set_first (G); m; m = set_next (m)) {
|
||||
if (m->member == n || !is_predecessor (m->member, I, graph))
|
||||
continue;
|
||||
set_remove (G, m->member);
|
||||
set_add (I, m->member);
|
||||
}
|
||||
return I;
|
||||
}
|
||||
|
||||
static flownode_t *
|
||||
flow_reduce (flownode_t *graph)
|
||||
{
|
||||
set_t *G;
|
||||
set_t **I;
|
||||
unsigned i, j, count = 0;
|
||||
int k;
|
||||
flownode_t **node_list = 0;
|
||||
flowgraph_t *graph;
|
||||
flownode_t *node;
|
||||
set_iter_t *m;
|
||||
|
||||
if (graph->num_siblings < 2)
|
||||
return 0;
|
||||
|
||||
G = set_new ();
|
||||
// Initialize G to be the set of all nodes in graph
|
||||
for (i = 0; i < graph->num_siblings; i++)
|
||||
set_add (G, i);
|
||||
|
||||
// allocate space for the interval sets. There will never be more intervals
|
||||
// than nodes in graph.
|
||||
I = malloc (graph->num_siblings * sizeof (set_t *));
|
||||
|
||||
for (i = 0; i < graph->num_siblings; i++) {
|
||||
unsigned m = graph->depth_first[i];
|
||||
if (!set_is_member (G, m))
|
||||
continue;
|
||||
I[count++] = select_nodes (graph, G, m);
|
||||
}
|
||||
|
||||
if (count == graph->num_siblings)
|
||||
goto irreducible;
|
||||
|
||||
node_list = malloc (count * sizeof (flownode_t *));
|
||||
for (i = 0; i < count; i++) {
|
||||
node = new_node ();
|
||||
node->siblings = node_list;
|
||||
node->num_siblings = count;
|
||||
node->id = i;
|
||||
|
||||
node->num_nodes = set_size (I[i]);
|
||||
node->nodes = malloc (node->num_nodes * sizeof (flownode_t *));
|
||||
for (j = 0, m = set_first (I[i]); m; m = set_next (m), j++) {
|
||||
node->nodes[j] = graph->siblings[m->member];
|
||||
node->nodes[j]->region = i;
|
||||
}
|
||||
|
||||
node_list[node->id] = node;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
node = node_list[i];
|
||||
set_empty (G); // G now represents the set of successors of node
|
||||
for (j = 0; j < node->num_nodes; j++) {
|
||||
flownode_t *n = node->nodes[j];
|
||||
for (k = 0; k < n->num_succ; k++) {
|
||||
flownode_t *m = n->siblings[n->successors[k]];
|
||||
if (m->region != i && !set_is_member (G, m->region))
|
||||
set_add (G, m->region);
|
||||
}
|
||||
}
|
||||
node->num_succ = set_size (G);
|
||||
node->successors = malloc (node->num_succ * sizeof (unsigned));
|
||||
for (j = 0, m = set_first (G); m; j++, m = set_next (m))
|
||||
node->successors[j] = m->member;
|
||||
}
|
||||
flow_find_predecessors (node_list, count);
|
||||
flow_depth_first (node_list[0]);
|
||||
irreducible:
|
||||
for (i = 0; i < count; i++)
|
||||
set_delete (I[i]);
|
||||
free (I);
|
||||
set_delete (G);
|
||||
if (node_list)
|
||||
return node_list[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
flow_build_graph (function_t *func)
|
||||
{
|
||||
sblock_t *sblock;
|
||||
sblock_t *sb;
|
||||
statement_t *st;
|
||||
flownode_t *node;
|
||||
flownode_t **node_list;
|
||||
unsigned num_blocks = 0;
|
||||
unsigned i;
|
||||
|
||||
for (sblock = func->sblock; sblock; sblock = sblock->next)
|
||||
sblock->number = num_blocks++;
|
||||
func->graph = malloc (num_blocks * sizeof (sblock_t *));
|
||||
func->num_nodes = num_blocks;
|
||||
node_list = malloc (func->num_nodes * sizeof (flownode_t *));
|
||||
for (sblock = func->sblock; sblock; sblock = sblock->next) {
|
||||
func->graph[sblock->number] = sblock;
|
||||
set_iter_t *succ;
|
||||
int i, j;
|
||||
|
||||
graph = new_graph ();
|
||||
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->sblocks = func->graph;
|
||||
node->siblings = node_list;
|
||||
node->num_siblings = num_blocks;
|
||||
node->id = sblock->number;
|
||||
node->num_nodes = func->num_nodes;
|
||||
|
||||
node_list[node->id] = node;
|
||||
node->predecessors = set_new ();
|
||||
node->successors = set_new ();
|
||||
node->edges = set_new ();
|
||||
node->dom = set_new ();
|
||||
node->id = sb->number;
|
||||
node->sblock = sb;
|
||||
graph->nodes[node->id] = node;
|
||||
}
|
||||
|
||||
// "convert" the basic blocks connections to flow-graph connections
|
||||
for (i = 0; i < num_blocks; i++) {
|
||||
node = node_list[i];
|
||||
sblock = node->sblocks[node->id];
|
||||
for (i = 0; i < graph->num_nodes; i++) {
|
||||
node = graph->nodes[i];
|
||||
sb = node->sblock;
|
||||
st = 0;
|
||||
if (sblock->statements)
|
||||
st = (statement_t *) sblock->tail;
|
||||
//FIXME jump/jumpb
|
||||
if (sb->statements)
|
||||
st = (statement_t *) sb->tail;
|
||||
//NOTE: if st is null (the sblock has no statements), flow_is_* will
|
||||
//return false
|
||||
//FIXME jump/jumpb
|
||||
if (flow_is_goto (st)) {
|
||||
// sblock's next is never followed.
|
||||
node->num_succ = 1;
|
||||
node->successors = calloc (1, sizeof (unsigned));
|
||||
node->successors[0] = flow_get_target (st)->number;
|
||||
// sb's next is never followed.
|
||||
set_add (node->successors, flow_get_target (st)->number);
|
||||
} else if (flow_is_cond (st)) {
|
||||
// branch: either sblock's next or the conditional statment's
|
||||
// branch: either sb's next or the conditional statment's
|
||||
// target will be followed.
|
||||
node->num_succ = 2;
|
||||
node->successors = calloc (2, sizeof (unsigned));
|
||||
node->successors[0] = sblock->next->number;
|
||||
node->successors[1] = flow_get_target (st)->number;
|
||||
set_add (node->successors, sb->next->number);
|
||||
set_add (node->successors, flow_get_target (st)->number);
|
||||
} else if (flow_is_return (st)) {
|
||||
// exit from function (dead end)
|
||||
node->num_succ = 0;
|
||||
} else {
|
||||
// there is no flow-control statement in sblock, so sblock's next
|
||||
// there is no flow-control statement in sb, so sb's next
|
||||
// must be followed
|
||||
node->num_succ = 1;
|
||||
node->successors = calloc (1, sizeof (unsigned));
|
||||
node->successors[0] = sblock->next->number;
|
||||
set_add (node->successors, sb->next->number);
|
||||
}
|
||||
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++) {
|
||||
node = graph->nodes[i];
|
||||
for (succ = set_first (node->successors); succ;
|
||||
succ = set_next (succ), j++) {
|
||||
set_add (node->edges, j);
|
||||
graph->edges[j].tail = i;
|
||||
graph->edges[j].head = succ->member;
|
||||
}
|
||||
}
|
||||
flow_find_predecessors (node_list, num_blocks);
|
||||
flow_depth_first (node_list[0]);
|
||||
|
||||
flow_calc_dominators (node_list, num_blocks);
|
||||
func->loops = flow_find_loops (node_list, num_blocks);
|
||||
func->flow = node_list[0];
|
||||
while ((node = flow_reduce (func->flow)))
|
||||
func->flow = node;
|
||||
flow_build_dfst (graph);
|
||||
flow_find_predecessors (graph);
|
||||
flow_find_dominators (graph);
|
||||
flow_find_loops (graph);
|
||||
return graph;
|
||||
}
|
||||
|
||||
void
|
||||
flow_del_graph (flowgraph_t *graph)
|
||||
{
|
||||
delete_graph (graph);
|
||||
}
|
||||
|
|
|
@ -644,16 +644,16 @@ emit_function (function_t *f, expr_t *e)
|
|||
lineno_base = f->def->line;
|
||||
f->sblock = make_statements (e);
|
||||
flow_build_vars (f);
|
||||
flow_build_graph (f);
|
||||
f->graph = flow_build_graph (f->sblock);
|
||||
if (options.block_dot.flow)
|
||||
print_flowgraph (f->flow, nva ("%s.%s.%s.dot", GETSTR (pr.source_file),
|
||||
f->name, "flow"));
|
||||
print_flowgraph (f->graph, nva ("%s.%s.%s.dot", GETSTR (pr.source_file),
|
||||
f->name, "flow"));
|
||||
{
|
||||
flowloop_t *l;
|
||||
int n = 0;
|
||||
for (l = f->loops; l; l = l->next)
|
||||
n++;
|
||||
printf ("%s %d %d %d\n", f->name, f->num_nodes, f->num_vars, n);
|
||||
printf ("%s %d %d %d\n", f->name, f->graph->num_nodes, f->num_vars, n);
|
||||
}
|
||||
emit_statements (f->sblock);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue