diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index a660ac321..e7412eacd 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -45,6 +45,7 @@ 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 flow_calc_dominators (struct function_s *func); //@} diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index 260ae820a..64e76f328 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -81,6 +81,7 @@ typedef struct sblock_s { int number; ///< number of this block in flow graph statement_t *statements; statement_t **tail; + struct set_s *dom; ///< set of nodes that dominate this node } sblock_t; struct expr_s; diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index c0c1d5e1e..bc64b35f2 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -44,6 +44,7 @@ #include "dags.h" #include "flow.h" #include "function.h" +#include "set.h" #include "statements.h" #include "symtab.h" @@ -226,3 +227,42 @@ flow_build_graph (function_t *func) } } } + +void +flow_calc_dominators (function_t *func) +{ + set_t *work; + sblock_t **pred; + int i; + int changed; + + if (!func->num_nodes) + return; + + // First, create a base set for the initial state of the non-initial nodes + work = set_new (); + for (i = 0; i < func->num_nodes; i++) + set_add (work, i); + + func->graph[0]->dom = set_new (); + set_add (func->graph[0]->dom, 0); + + // initialize dom for the non-initial nodes + for (i = 1; i < func->num_nodes; i++) { + func->graph[i]->dom = set_new (); + set_assign (func->graph[i]->dom, work); + } + + do { + changed = 0; + for (i = 1; i < func->num_nodes; i++) { + set_assign (work, func->graph[i]->pred[0]->dom); + for (pred = func->graph[i]->pred + 1; *pred; pred++) + set_intersection (work, (*pred)->dom); + set_add (work, i); + if (!set_is_equivalent (work, func->graph[i]->dom)) + changed = 1; + set_assign (func->graph[i]->dom, work); + } + } while (changed); +} diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 790844bb4..f39d28454 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); flow_build_graph (f); + flow_calc_dominators (f); if (options.block_dot.flow) print_flow (f->sblock, nva ("%s.%s.%s.dot", GETSTR (pr.source_file), f->name, "flow"));