Begin doing some data flow analysis.

In te beginning, live variables.
This commit is contained in:
Bill Currie 2012-11-06 15:30:07 +09:00
parent c00e666668
commit 4b64912793
3 changed files with 83 additions and 0 deletions

View file

@ -68,6 +68,13 @@ typedef struct flownode_s {
struct set_s *successors; ///< successors 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 *edges; ///< edges leaving this node to successor nodes
struct set_s *dom; ///< dominating nodes struct set_s *dom; ///< dominating nodes
struct {
struct set_s *use;
struct set_s *def;
struct set_s *in;
struct set_s *out;
} live_vars;
struct sblock_s *sblock; ///< original statement block
} flownode_t; } flownode_t;
typedef struct flowgraph_s { typedef struct flowgraph_s {
@ -91,6 +98,7 @@ struct sblock_s **flow_get_targetlist (struct statement_s *s);
void flow_build_vars (struct function_s *func); void flow_build_vars (struct function_s *func);
flowgraph_t *flow_build_graph (struct sblock_s *func); flowgraph_t *flow_build_graph (struct sblock_s *func);
void flow_del_graph (flowgraph_t *graph); void flow_del_graph (flowgraph_t *graph);
void flow_data_flow (struct function_s *func);
void print_flowgraph (flowgraph_t *graph, const char *filename); void print_flowgraph (flowgraph_t *graph, const char *filename);

View file

@ -249,6 +249,80 @@ flow_build_vars (function_t *func)
} }
} }
static void
live_set_use (flowvar_t *var, set_t *use, set_t *def)
{
// the variable is used before it is defined
if (var && !set_is_member (def, var->number))
set_add (use, var->number);
}
static void
live_set_def (flowvar_t *var, set_t *use, set_t *def)
{
// the variable is defined before it is used
if (var && !set_is_member (use, var->number))
set_add (def, var->number);
}
static void
flow_live_vars (function_t *func)
{
flowgraph_t *graph = func->graph;
int i, j;
flownode_t *node;
set_t *use;
set_t *def;
set_t *tmp = set_new ();
set_iter_t *succ;
operand_t *d, *u[3];
statement_t *st;
int changed = 1;
// first, calculate use and def for each block, and initialize the in and
// out sets.
for (i = 0; i < graph->num_nodes; i++) {
node = graph->nodes[i];
use = set_new ();
def = set_new ();
for (st = node->sblock->statements; st; st = st->next) {
find_operands (st, &d, &u[0], &u[1], &u[2]);
live_set_def (flow_get_var (d), use, def);
for (j = 0; j < 3; j++)
live_set_use (flow_get_var (u[j]), use, def);
}
node->live_vars.use = use;
node->live_vars.def = def;
node->live_vars.in = set_new ();
node->live_vars.out = set_new ();
}
while (changed) {
changed = 0;
// flow UP the graph because live variable analysis uses information
// from a node's successors rather than its predecessors.
for (j = graph->num_nodes - 1; j >= 0; j--) {
node = graph->nodes[graph->dfo[j]];
set_empty (tmp);
for (succ = set_first (node->successors); succ;
succ = set_next (succ))
set_union (tmp, graph->nodes[succ->member]->live_vars.in);
if (!set_is_equivalent (node->live_vars.out, tmp)) {
changed = 1;
set_assign (node->live_vars.out, tmp);
}
set_assign (node->live_vars.in, node->live_vars.out);
set_difference (node->live_vars.in, node->live_vars.def);
}
}
}
void
flow_data_flow (function_t *func)
{
flow_live_vars (func);
}
int int
flow_is_cond (statement_t *s) flow_is_cond (statement_t *s)
{ {

View file

@ -645,6 +645,7 @@ emit_function (function_t *f, expr_t *e)
f->sblock = make_statements (e); f->sblock = make_statements (e);
flow_build_vars (f); flow_build_vars (f);
f->graph = flow_build_graph (f->sblock); f->graph = flow_build_graph (f->sblock);
flow_data_flow (f);
emit_statements (f->sblock); emit_statements (f->sblock);
} }