diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index f68c5d5cf..6f630c8a9 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -44,11 +44,18 @@ typedef struct flowvar_s { struct flowvar_s *next; ///< for ALLOC struct set_s *use; ///< set of statements that use this var struct set_s *define; ///< set of statements that define this var + struct set_s *udchains; ///< set of ud chains for this var struct operand_s *op; ///< an operand using this var int number; ///< number of variable in func's ref list int flowaddr; ///< psuedo address for local and temp vars } flowvar_t; +typedef struct udchain_s { + int var; + int usest; + int defst; +} udchain_t; + typedef struct flowloop_s { struct flowloop_s *next; unsigned head; diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index c65432026..4777d3668 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -121,6 +121,8 @@ typedef struct function_s { struct set_s *real_statements;///< actual statements for ud-chaining struct statement_s **statements; int num_statements; + int num_ud_chains; + struct udchain_s *ud_chains; int pseudo_addr;///< pseudo address space for flow analysis struct pseudoop_s *pseudo_ops;///< pseudo operands used by this function } function_t; diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index 979580d35..d79f4d9d1 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -117,6 +117,8 @@ typedef struct statement_s { operand_t *use; ///< list of auxiliary operands used operand_t *def; ///< list of auxiliary operands defined operand_t *kill; ///< list of auxiliary operands killed + int first_use; + int num_use; } statement_t; typedef struct sblock_s { diff --git a/tools/qfcc/source/dot_flow.c b/tools/qfcc/source/dot_flow.c index 0aa42f455..8440dd0d8 100644 --- a/tools/qfcc/source/dot_flow.c +++ b/tools/qfcc/source/dot_flow.c @@ -204,10 +204,10 @@ print_flow_vars (dstring_t *dstr, flowgraph_t *graph, int level) dasprintf (dstr, "%*sfv_%p [shape=none,label=<\n", indent, "", graph); dasprintf (dstr, "%*s\n", indent + 2, ""); - dasprintf (dstr, "%*s\n", + dasprintf (dstr, "%*s\n", indent + 4, ""); dasprintf (dstr, "%*s" - "\n", + "\n", indent + 4, ""); for (i = 0; i < graph->func->num_vars; i++) { var = graph->func->vars[i]; @@ -216,7 +216,25 @@ print_flow_vars (dstring_t *dstr, flowgraph_t *graph, int level) var->number, html_string(operand_string (var->op)), var->flowaddr, set_as_string (var->define)); - dasprintf (dstr, "\n", set_as_string (var->use)); + dasprintf (dstr, "", set_as_string (var->use)); + dasprintf (dstr, "", set_as_string (var->udchains)); + dasprintf (dstr, "\n"); + } + dasprintf (dstr, "%*s
flow vars
flow vars
#nameaddrdefineuse
addrdefineuseud
%s
%s%s
>];\n", indent + 2, ""); + + dasprintf (dstr, "%*sud_%p [shape=none,label=<\n", indent, "", graph); + dasprintf (dstr, "%*s\n", indent + 2, ""); + dasprintf (dstr, "%*s\n", + indent + 4, ""); + dasprintf (dstr, "%*s" + "\n", + indent + 4, ""); + for (i = 0; i < graph->func->num_ud_chains; i++) { + udchain_t ud = graph->func->ud_chains[i]; + dasprintf (dstr, "%*s" + "", + indent + 4, "", i, ud.var, ud.usest, ud.defst); } dasprintf (dstr, "%*s
ud chains
#varusedef
%d%d%d%d
>];\n", indent + 2, ""); } diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 4475fbf98..58ce1be58 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -96,6 +96,7 @@ new_flowvar (void) ALLOC (256, flowvar_t, vars, var); var->use = set_new (); var->define = set_new (); + var->udchains = set_new (); return var; } @@ -106,6 +107,7 @@ delete_flowvar (flowvar_t *var) { set_delete (var->use); set_delete (var->define); + set_delete (var->udchains); FREE (vars, var); } @@ -774,6 +776,37 @@ flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) set_delete (tmp); } +typedef struct { + set_t *gen; + set_t *kill; + set_t *stgen; + set_t *stkill; + set_t *stdef; + set_t *uninit; + flowvar_t **vars; +} reachint_t; + +static void +flow_statement_reaching (statement_t *st, reachint_t *r) +{ + set_empty (r->stgen); + set_empty (r->stkill); + + set_iter_t *var_i; + for (var_i = set_first (r->stdef); var_i; var_i = set_next (var_i)) { + flowvar_t *var = r->vars[var_i->element]; + flow_kill_aliases (r->stkill, var, r->uninit); + set_remove (r->stkill, st->number); + set_add (r->stgen, st->number); + } + + set_difference (r->gen, r->stkill); + set_union (r->gen, r->stgen); + + set_difference (r->kill, r->stgen); + set_union (r->kill, r->stkill); +} + /** Compute reaching defs */ static void @@ -783,12 +816,13 @@ flow_reaching_defs (flowgraph_t *graph) int changed; flownode_t *node; statement_t *st; - set_t *stdef = set_new (); - set_t *stgen = set_new (); - set_t *stkill = set_new (); - set_t *oldout = set_new (); - set_t *gen, *kill, *in, *out, *uninit; - set_iter_t *var_i; + reachint_t reach = { + .stgen = set_new (), + .stkill = set_new (), + .stdef = set_new (), + .vars = graph->func->vars, + }; + set_t *in, *out, *uninit; set_iter_t *pred_i; flowvar_t *var; @@ -808,10 +842,6 @@ flow_reaching_defs (flowgraph_t *graph) * * All other entry node sets are initialized to empty. */ - // kill represents the set of all statements in the function - kill = set_new (); - for (i = 0; i < graph->func->num_statements; i++) - set_add (kill, i); // uninit uninit = set_new (); for (i = 0; i < graph->func->num_vars; i++) { @@ -822,7 +852,8 @@ flow_reaching_defs (flowgraph_t *graph) * \a uninit set (which becomes the \a out set of the entry node's * reaching defs) in order to prevent them leaking into the real nodes. */ - set_difference (uninit, kill); // remove any gens from the function + // remove any gens from the function + set_difference (uninit, graph->func->real_statements); // initialize the reaching defs sets in the entry node graph->nodes[graph->num_nodes]->reaching_defs.out = uninit; graph->nodes[graph->num_nodes]->reaching_defs.in = set_new (); @@ -832,32 +863,21 @@ flow_reaching_defs (flowgraph_t *graph) // Calculate gen and kill for each block, and initialize in and out for (i = 0; i < graph->num_nodes; i++) { node = graph->nodes[i]; - gen = set_new (); - kill = set_new (); + reach.gen = set_new (); + reach.kill = set_new (); for (st = node->sblock->statements; st; st = st->next) { - flow_analyze_statement (st, 0, stdef, 0, 0); - set_empty (stgen); - set_empty (stkill); - for (var_i = set_first (stdef); var_i; var_i = set_next (var_i)) { - var = graph->func->vars[var_i->element]; - flow_kill_aliases (stkill, var, uninit); - set_remove (stkill, st->number); - set_add (stgen, st->number); - } - - set_difference (gen, stkill); - set_union (gen, stgen); - - set_difference (kill, stgen); - set_union (kill, stkill); + flow_analyze_statement (st, 0, reach.stdef, 0, 0); + flow_statement_reaching (st, &reach); } - node->reaching_defs.gen = gen; - node->reaching_defs.kill = kill; + node->reaching_defs.gen = reach.gen; + node->reaching_defs.kill = reach.kill; node->reaching_defs.in = set_new (); node->reaching_defs.out = set_new (); + reach.gen = reach.kill = 0; } changed = 1; + set_t *oldout = set_new (); while (changed) { changed = 0; // flow down the graph @@ -865,8 +885,6 @@ flow_reaching_defs (flowgraph_t *graph) node = graph->nodes[graph->depth_first[i]]; in = node->reaching_defs.in; out = node->reaching_defs.out; - gen = node->reaching_defs.gen; - kill = node->reaching_defs.kill; for (pred_i = set_first (node->predecessors); pred_i; pred_i = set_next (pred_i)) { flownode_t *pred = graph->nodes[pred_i->element]; @@ -874,16 +892,71 @@ flow_reaching_defs (flowgraph_t *graph) } set_assign (oldout, out); set_assign (out, in); - set_difference (out, kill); - set_union (out, gen); + set_difference (out, node->reaching_defs.kill); + set_union (out, node->reaching_defs.gen); if (!set_is_equivalent (out, oldout)) changed = 1; } } set_delete (oldout); - set_delete (stdef); - set_delete (stgen); - set_delete (stkill); + + reach.gen = set_new (); + reach.kill = set_new (); + set_t *use = set_new (); + set_t *tmp = set_new (); + int num_ud = 0; + for (i = 0; i < graph->num_nodes; i++) { + node = graph->nodes[i]; + set_empty (reach.kill); + set_assign (reach.gen, node->reaching_defs.in); + for (st = node->sblock->statements; st; st = st->next) { + flow_analyze_statement (st, use, reach.stdef, 0, 0); + set_empty (tmp); + for (set_iter_t *vi = set_first (use); vi; vi = set_next (vi)) { + flowvar_t *var = reach.vars[vi->element]; + set_assign (tmp, var->define); + set_intersection (tmp, reach.gen); + num_ud += set_count (tmp); + } + flow_statement_reaching (st, &reach); + } + } + graph->func->ud_chains = malloc (num_ud * sizeof (udchain_t)); + graph->func->num_ud_chains = num_ud; + num_ud = 0; + for (i = 0; i < graph->num_nodes; i++) { + node = graph->nodes[i]; + set_empty (reach.kill); + set_assign (reach.gen, node->reaching_defs.in); + for (st = node->sblock->statements; st; st = st->next) { + flow_analyze_statement (st, use, reach.stdef, 0, 0); + set_empty (tmp); + st->first_use = num_ud; + for (set_iter_t *vi = set_first (use); vi; vi = set_next (vi)) { + flowvar_t *var = reach.vars[vi->element]; + set_assign (tmp, var->define); + set_intersection (tmp, reach.gen); + for (set_iter_t *ud = set_first (tmp); ud; ud = set_next (ud)) { + set_add (var->udchains, num_ud); + udchain_t *udc = &graph->func->ud_chains[num_ud++]; + udc->var = vi->element; + udc->usest = st->number; + udc->defst = ud->element; + } + } + st->num_use = num_ud - st->first_use; + flow_statement_reaching (st, &reach); + } + } + set_delete (use); + set_delete (tmp); + set_delete (reach.gen); + set_delete (reach.kill); + reach.gen = reach.kill = 0; + + set_delete (reach.stdef); + set_delete (reach.stgen); + set_delete (reach.stkill); } /** Update the node's \a use set from the statement's \a use set @@ -1335,9 +1408,9 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, if (s->opa) { flow_add_op_var (use, s->opa, 1); } - } - if (use) { - flow_add_op_var (use, &flow_params[0].op, 1); + if (use) { + flow_add_op_var (use, &flow_params[0].op, 1); + } } } if (strcmp (s->opcode, "call") == 0) {