Nuke find_operands in favor of flow_analyze_statement.

flow_analyze_statement uses the statement type to quickly determin which
operands are inputs and which are outputs. It takes (optional) sets for
used variables, defined variables and killed variables (only partially
working, but I don't actually use kill sets yet). It also takes an optional
array for storing the operands: index 0 is the output, 1-3 are the inputs.
flow_analyze_statement clears any given sets on entry.

Live variable analysis now uses the sets rather than individual vars. Much
cleaner code :).

Dags are completely broken.
This commit is contained in:
Bill Currie 2012-11-16 19:33:37 +09:00
parent 001e1ac059
commit 1100efba54
5 changed files with 202 additions and 75 deletions

View file

@ -98,6 +98,9 @@ int flow_is_jumpb (struct statement_s *s);
int flow_is_return (struct statement_s *s); int flow_is_return (struct statement_s *s);
struct sblock_s *flow_get_target (struct statement_s *s); struct sblock_s *flow_get_target (struct statement_s *s);
struct sblock_s **flow_get_targetlist (struct statement_s *s); struct sblock_s **flow_get_targetlist (struct statement_s *s);
void flow_analyze_statement (struct statement_s *s, struct set_s *use,
struct set_s *def, struct set_s *kill,
struct operand_s *operands[4]);
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);

View file

@ -111,8 +111,6 @@ operand_t *temp_operand (struct type_s *type);
sblock_t *new_sblock (void); sblock_t *new_sblock (void);
statement_t *new_statement (st_type_t type, const char *opcode, statement_t *new_statement (st_type_t type, const char *opcode,
struct expr_s *expr); struct expr_s *expr);
int find_operands (statement_t *s, operand_t **x, operand_t **y, operand_t **z,
operand_t **w);
void sblock_add_statement (sblock_t *sblock, statement_t *statement); void sblock_add_statement (sblock_t *sblock, statement_t *statement);
sblock_t *make_statements (struct expr_s *expr); sblock_t *make_statements (struct expr_s *expr);
void print_statement (statement_t *s); void print_statement (statement_t *s);

View file

@ -289,9 +289,9 @@ dag_create (const flownode_t *flownode)
operand_t *x = 0, *y = 0, *z = 0, *w = 0; operand_t *x = 0, *y = 0, *z = 0, *w = 0;
dagnode_t *n = 0, *ny, *nz, *nw; dagnode_t *n = 0, *ny, *nz, *nw;
daglabel_t *op, *lx; daglabel_t *op, *lx;
int simp; int simp = 0;
simp = find_operands (s, &x, &y, &z, &w); //simp = find_operands (s, &x, &y, &z, &w);
if (!(ny = node (y))) { if (!(ny = node (y))) {
ny = leaf_node (y); ny = leaf_node (y);
if (simp) { if (simp) {

View file

@ -40,9 +40,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "QF/dstring.h" #include "QF/dstring.h"
#include "QF/va.h"
#include "dags.h" #include "dags.h"
#include "def.h" #include "def.h"
#include "diagnostic.h"
#include "dot.h" #include "dot.h"
#include "flow.h" #include "flow.h"
#include "function.h" #include "function.h"
@ -58,6 +60,22 @@ static flowloop_t *free_loops;
static flownode_t *free_nodes; static flownode_t *free_nodes;
static flowgraph_t *free_graphs; static flowgraph_t *free_graphs;
static struct {
const char *name;
operand_t op;
} flow_params[] = {
{".return", {0, op_symbol}},
{".param_0", {0, op_symbol}},
{".param_1", {0, op_symbol}},
{".param_2", {0, op_symbol}},
{".param_3", {0, op_symbol}},
{".param_4", {0, op_symbol}},
{".param_5", {0, op_symbol}},
{".param_6", {0, op_symbol}},
{".param_7", {0, op_symbol}},
};
static const int num_flow_params = sizeof(flow_params)/sizeof(flow_params[0]);
static void static void
dump_dot_flow (void *data, const char *fname) dump_dot_flow (void *data, const char *fname)
{ {
@ -164,7 +182,7 @@ flow_get_var (operand_t *op)
o->o.symbol->flowvar = new_flowvar (); o->o.symbol->flowvar = new_flowvar ();
return o->o.symbol->flowvar; return o->o.symbol->flowvar;
} }
//FIXME functions? (some are variable) //FIXME functions? (some are variable) values?
return 0; return 0;
} }
@ -216,15 +234,33 @@ add_operand (function_t *func, operand_t *op)
} }
} }
static symbol_t *
param_symbol (const char *name)
{
symbol_t *sym;
sym = make_symbol (name, &type_param, pr.symtab->space, st_extern);
if (!sym->table)
symtab_addsymbol (pr.symtab, sym);
return sym;
}
void void
flow_build_vars (function_t *func) flow_build_vars (function_t *func)
{ {
sblock_t *sblock; sblock_t *sblock;
statement_t *s; statement_t *s;
int num_vars; int num_vars = 0;
int num_statements = 0; int num_statements = 0;
int i;
for (num_vars = 0, sblock = func->sblock; sblock; sblock = sblock->next) { // first, count .return and .param_[0-7] as they are always needed
for (i = 0; i < num_flow_params; i++) {
flow_params[i].op.o.symbol = param_symbol (flow_params[i].name);
num_vars += count_operand (&flow_params[i].op);
}
// then run through the statements in the function looking for accessed
// variables
for (sblock = func->sblock; sblock; sblock = sblock->next) {
for (s = sblock->statements; s; s = s->next) { for (s = sblock->statements; s; s = s->next) {
num_vars += count_operand (s->opa); num_vars += count_operand (s->opa);
num_vars += count_operand (s->opb); num_vars += count_operand (s->opb);
@ -236,6 +272,11 @@ flow_build_vars (function_t *func)
func->vars = malloc (num_vars * sizeof (daglabel_t *)); func->vars = malloc (num_vars * sizeof (daglabel_t *));
func->num_vars = 0; // incremented by add_operand func->num_vars = 0; // incremented by add_operand
// first, add .return and .param_[0-7] as they are always needed
for (i = 0; i < num_flow_params; i++)
add_operand (func, &flow_params[i].op);
// then run through the statements in the function adding accessed
// variables
for (sblock = func->sblock; sblock; sblock = sblock->next) { for (sblock = func->sblock; sblock; sblock = sblock->next) {
for (s = sblock->statements; s; s = s->next) { for (s = sblock->statements; s; s = s->next) {
add_operand (func, s->opa); add_operand (func, s->opa);
@ -255,19 +296,19 @@ flow_build_vars (function_t *func)
} }
static void static void
live_set_use (flowvar_t *var, set_t *use, set_t *def) live_set_use (set_t *stuse, set_t *use, set_t *def)
{ {
// the variable is used before it is defined // the variable is used before it is defined
if (var && !set_is_member (def, var->number)) set_difference (stuse, def);
set_add (use, var->number); set_union (use, stuse);
} }
static void static void
live_set_def (flowvar_t *var, set_t *use, set_t *def) live_set_def (set_t *stdef, set_t *use, set_t *def)
{ {
// the variable is defined before it is used // the variable is defined before it is used
if (var && !set_is_member (use, var->number)) set_difference (stdef, use);
set_add (def, var->number); set_union (def, stdef);
} }
static void static void
@ -277,9 +318,10 @@ flow_live_vars (flowgraph_t *graph)
flownode_t *node; flownode_t *node;
set_t *use; set_t *use;
set_t *def; set_t *def;
set_t *stuse = set_new ();
set_t *stdef = set_new ();
set_t *tmp = set_new (); set_t *tmp = set_new ();
set_iter_t *succ; set_iter_t *succ;
operand_t *d, *u[3];
statement_t *st; statement_t *st;
int changed = 1; int changed = 1;
@ -290,10 +332,9 @@ flow_live_vars (flowgraph_t *graph)
use = set_new (); use = set_new ();
def = set_new (); def = set_new ();
for (st = node->sblock->statements; st; st = st->next) { for (st = node->sblock->statements; st; st = st->next) {
find_operands (st, &d, &u[0], &u[1], &u[2]); flow_analyze_statement (st, stuse, stdef, 0, 0);
for (j = 0; j < 3; j++) live_set_use (stuse, use, def);
live_set_use (flow_get_var (u[j]), use, def); live_set_def (stdef, use, def);
live_set_def (flow_get_var (d), use, def);
} }
node->live_vars.use = use; node->live_vars.use = use;
node->live_vars.def = def; node->live_vars.def = def;
@ -320,6 +361,9 @@ flow_live_vars (flowgraph_t *graph)
set_union (node->live_vars.in, node->live_vars.use); set_union (node->live_vars.in, node->live_vars.use);
} }
} }
set_delete (stuse);
set_delete (stdef);
set_delete (tmp);
} }
static void static void
@ -339,23 +383,28 @@ flow_build_dags (flowgraph_t *graph)
void void
flow_data_flow (flowgraph_t *graph) flow_data_flow (flowgraph_t *graph)
{ {
int i, j; int i;
flownode_t *node; flownode_t *node;
statement_t *st; statement_t *st;
operand_t *d, *u[3];
flowvar_t *var; flowvar_t *var;
set_t *stuse = set_new ();
set_t *stdef = set_new ();
set_iter_t *var_i;
for (i = 0; i < graph->num_nodes; i++) { for (i = 0; i < graph->num_nodes; i++) {
node = graph->nodes[i]; node = graph->nodes[i];
for (st = node->sblock->statements; st; st = st->next) { for (st = node->sblock->statements; st; st = st->next) {
find_operands (st, &d, &u[0], &u[1], &u[2]); flow_analyze_statement (st, stuse, stdef, 0, 0);
if (d && (var = flow_get_var (d))) for (var_i = set_first (stdef); var_i; var_i = set_next (var_i)) {
var = graph->func->vars[var_i->member];
set_add (var->define, st->number); set_add (var->define, st->number);
for (j = 0; j < 3; j++) }
if (u[j] && (var = flow_get_var (u[j]))) for (var_i = set_first (stuse); var_i; var_i = set_next (var_i)) {
var = graph->func->vars[var_i->member];
set_add (var->use, st->number); set_add (var->use, st->number);
} }
} }
}
flow_live_vars (graph); flow_live_vars (graph);
flow_build_dags (graph); flow_build_dags (graph);
if (options.block_dot.flow) if (options.block_dot.flow)
@ -386,7 +435,7 @@ flow_generate (flowgraph_t *graph)
// generate new statements from the dag; // generate new statements from the dag;
dag_generate (block, node); dag_generate (block, node);
} }
dump_dot ("post", code, dump_dot_sblock); //dump_dot ("post", code, dump_dot_sblock);
return code; return code;
} }
@ -462,6 +511,132 @@ flow_get_targetlist (statement_t *s)
return target_list; return target_list;
} }
static void
flow_add_op_var (set_t *set, operand_t *op)
{
flowvar_t *var;
if (!set)
return;
if (!(var = flow_get_var (op)))
return;
set_add (set, var->number);
}
void
flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
operand_t *operands[4])
{
int i, start, calln;
if (use)
set_empty (use);
if (def)
set_empty (def);
if (kill)
set_empty (kill);
if (operands) {
for (i = 0; i < 4; i++)
operands[i] = 0;
}
switch (s->type) {
case st_none:
internal_error (s->expr, "not a statement");
case st_expr:
flow_add_op_var (def, s->opc);
flow_add_op_var (use, s->opa);
if (s->opb)
flow_add_op_var (use, s->opb);
if (operands) {
operands[0] = s->opc;
operands[1] = s->opa;
operands[2] = s->opb;
}
break;
case st_assign:
flow_add_op_var (def, s->opb);
flow_add_op_var (use, s->opa);
if (operands) {
operands[0] = s->opb;
operands[1] = s->opa;
}
break;
case st_ptrassign:
case st_move:
flow_add_op_var (use, s->opa);
flow_add_op_var (use, s->opb);
if (s->opc)
flow_add_op_var (use, s->opc);
if (kill) {
//FIXME set of everything
}
if (operands) {
operands[1] = s->opa;
operands[2] = s->opb;
operands[3] = s->opc;
}
break;
case st_state:
flow_add_op_var (use, s->opa);
flow_add_op_var (use, s->opb);
if (s->opc)
flow_add_op_var (use, s->opc);
//FIXME entity members
if (operands) {
operands[1] = s->opa;
operands[2] = s->opb;
operands[3] = s->opc;
}
break;
case st_func:
if (strcmp (s->opcode, "<RETURN>") == 0
|| strcmp (s->opcode, "<DONE>") == 0) {
flow_add_op_var (use, s->opa);
break;
} else if (strcmp (s->opcode, "<RETURN_V>") == 0) {
if (use)
set_add (use, 0); //FIXME assumes .return location
break;
}
if (strncmp (s->opcode, "<CALL", 5) == 0) {
start = 0;
calln = s->opcode[5] - '0';
flow_add_op_var (use, s->opa);
} else { // RCALL
start = 2;
calln = s->opcode[6] - '0';
flow_add_op_var (use, s->opa);
flow_add_op_var (use, s->opb);
if (s->opc)
flow_add_op_var (use, s->opc);
}
if (use) {
for (i = start; i < calln; i++)
set_add (use, i + 1); //FIXME assumes .param_N locations
}
if (kill)
set_add (kill, 0); //FIXME assumes .return location
if (operands) {
operands[1] = s->opa;
operands[2] = s->opb;
operands[3] = s->opc;
}
break;
case st_flow:
if (strcmp (s->opcode, "<GOTO>") != 0) {
flow_add_op_var (use, s->opa);
if (strcmp (s->opcode, "<JUMPB>") == 0)
flow_add_op_var (use, s->opb);
}
if (operands) {
operands[1] = s->opa;
operands[2] = s->opb;
}
break;
}
}
static void static void
flow_find_predecessors (flowgraph_t *graph) flow_find_predecessors (flowgraph_t *graph)
{ {

View file

@ -212,55 +212,6 @@ print_statement (statement_t *s)
printf (")\n"); printf (")\n");
} }
int
find_operands (statement_t *s, operand_t **x, operand_t **y, operand_t **z,
operand_t **w)
{
int simp = 0;
*x = *y = *z = *w = 0;
if (s->opc) {
*y = s->opa;
if (s->opb) {
// except for move, indexed pointer store, rcall2+, and state,
// all are of the form c = a op b
*z = s->opb;
if (!strncmp (s->opcode, "<MOVE", 5)
|| !strncmp (s->opcode, "<RCALL", 6)
|| !strcmp (s->opcode, "<STATE>")
|| !strcmp (s->opcode, ".=")) {
*w = s->opc;
} else {
*x = s->opc;
}
} else {
// these are all c = op a
*x = s->opc;
}
} else if (s->opb) {
*y = s->opa;
if (s->opcode[1] == 'I') {
// conditional
} else if (s->opcode[0] == '<' || s->opcode[0] == '.') {
// pointer store or branch
*z = s->opb;
} else {
// b = a
*x = s->opb;
simp = 1;
}
} else if (s->opa) {
if (s->opcode[1] == 'G') {
} else {
*y = s->opa;
if (s->opcode[1] == 'R')
simp = 1;
}
}
return simp;
}
static sblock_t *free_sblocks; static sblock_t *free_sblocks;
static statement_t *free_statements; static statement_t *free_statements;
static operand_t *free_operands; static operand_t *free_operands;