From 4b649127936232c253183e24e9b236ba4973e748 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 6 Nov 2012 15:30:07 +0900 Subject: [PATCH] Begin doing some data flow analysis. In te beginning, live variables. --- tools/qfcc/include/flow.h | 8 ++++ tools/qfcc/source/flow.c | 74 ++++++++++++++++++++++++++++++++++++ tools/qfcc/source/function.c | 1 + 3 files changed, 83 insertions(+) diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index 71b29d403..9bdbfa6e3 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -68,6 +68,13 @@ typedef struct flownode_s { 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 { + 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; 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); flowgraph_t *flow_build_graph (struct sblock_s *func); void flow_del_graph (flowgraph_t *graph); +void flow_data_flow (struct function_s *func); void print_flowgraph (flowgraph_t *graph, const char *filename); diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 02193fe42..4b435a41b 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -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 flow_is_cond (statement_t *s) { diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index b6695305d..3471cbf57 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -645,6 +645,7 @@ emit_function (function_t *f, expr_t *e) f->sblock = make_statements (e); flow_build_vars (f); f->graph = flow_build_graph (f->sblock); + flow_data_flow (f); emit_statements (f->sblock); }