[qfcc] Calculate ud-chains

The first use will be pointer analysis for function arguments where the
argument points to an array to mark the array as live, but I'm sure
there'll be plenty of other uses.
This commit is contained in:
Bill Currie 2023-05-20 00:59:23 +09:00
parent 4b3b6d516a
commit 9247ab91fd
5 changed files with 145 additions and 43 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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 {

View file

@ -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<table border=\"0\" cellborder=\"1\" "
"cellspacing=\"0\">\n", indent + 2, "");
dasprintf (dstr, "%*s<tr><td colspan=\"5\">flow vars</td></tr>\n",
dasprintf (dstr, "%*s<tr><td colspan=\"6\">flow vars</td></tr>\n",
indent + 4, "");
dasprintf (dstr, "%*s<tr><td>#</td><td>name</td>"
"<td>addr</td><td>define</td><td>use</td></tr>\n",
"<td>addr</td><td>define</td><td>use</td><td>ud</td></tr>\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, "<td>%s</td></tr>\n", set_as_string (var->use));
dasprintf (dstr, "<td>%s</td>", set_as_string (var->use));
dasprintf (dstr, "<td>%s</td>", set_as_string (var->udchains));
dasprintf (dstr, "</tr>\n");
}
dasprintf (dstr, "%*s</table>>];\n", indent + 2, "");
dasprintf (dstr, "%*sud_%p [shape=none,label=<\n", indent, "", graph);
dasprintf (dstr, "%*s<table border=\"0\" cellborder=\"1\" "
"cellspacing=\"0\">\n", indent + 2, "");
dasprintf (dstr, "%*s<tr><td colspan=\"4\">ud chains</td></tr>\n",
indent + 4, "");
dasprintf (dstr, "%*s<tr><td>#</td><td>var</td>"
"<td>use</td><td>def</td></tr>\n",
indent + 4, "");
for (i = 0; i < graph->func->num_ud_chains; i++) {
udchain_t ud = graph->func->ud_chains[i];
dasprintf (dstr, "%*s<tr><td>%d</td><td>%d</td>"
"<td>%d</td><td>%d</td></tr>",
indent + 4, "", i, ud.var, ud.usest, ud.defst);
}
dasprintf (dstr, "%*s</table>>];\n", indent + 2, "");
}

View file

@ -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) {