Rewrite dags to use sets.

While things are quite broken now (very incorrect code is being generated),
the dag is much easier to work with. The dag is now stored in an array of
nodes (the children pointers are still used for dagnode operands), and sets
are used for marking node parents, attached identifiers and (when done,
extra edges).
This commit is contained in:
Bill Currie 2012-11-17 21:14:42 +09:00
parent 0bb2fc1891
commit 12133bc02f
5 changed files with 241 additions and 249 deletions

View file

@ -43,11 +43,8 @@ struct dstring_s;
struct flownode_s;
typedef struct daglabel_s {
/// \name attached identifer linked list
//@{
struct daglabel_s *next;
struct daglabel_s **prev;
//@}
int number; ///< index into array of labels in dag_t
struct daglabel_s *daglabel_chain; ///< all labels created for a dag
const char *opcode; ///< not if op
struct operand_s *op; ///< not if opcode;
@ -57,29 +54,41 @@ typedef struct daglabel_s {
typedef struct dagnode_s {
struct dagnode_s *next;
int print_count; ///< used to avoid double printing nodes
int is_child; ///< true if a child node
int number; ///< index into array of nodes in dag_t
struct set_s *parents; ///< empty if root node
int cost; ///< cost of this node in temp vars
st_type_t type; ///< type of node (st_node = leaf)
daglabel_t *label; ///< ident/const if leaf node, or operator
etype_t tl;
/// \name child nodes
/// All three child nodes will be null if this node is a leaf
/// If \a a is null, both \a b and \a c must also be null. If \a is not
/// null, either \a b or \a c or even both may be non-null. Both \a b and
/// \a c being non-null is reserved for the few opcodes that take three
/// inputs (rcall2+, 3 op state, indirect move, indexed pointer assignment)
/// \a b and \a c are used to help keep track of the original statement
/// operands
/// if \a children[0] is null, the rest must be null as well. Similar for
/// \a children[1].
///
/// \a edges is the set of all nodes upon which this node depends. ie,
/// they must be evaluated before this node is evaluted. So while nodes
/// in \a edges may not be true children of this node, they are effective
/// children in the DAG. That is, \a edges is for producing a correct
/// topological sort of the DAG.
//@{
struct dagnode_s *a, *b, *c;
etype_t ta, tb, tc; ///< desired type of each operand (to alias)
struct dagnode_s *children[3];
etype_t types[3]; ///< desired type of each operand (to alias)
struct set_s *edges; ///< includes nodes pointed to by \a children
//@}
daglabel_t *identifiers; ///< list of identifiers with value of this node
struct set_s *identifiers; ///< set of identifiers attached to this node
} dagnode_t;
typedef struct dag_s {
struct dag_s *next;
dagnode_t **nodes; ///< array of all dagnodes in this dag
int num_nodes;
daglabel_t **labels; ///< array of all daglabels in this dag
int num_labels;;
struct set_s *roots; ///< set of root nodes
struct flownode_s *flownode;///< flow node this dag represents
} dag_t;
const char *daglabel_string (daglabel_t *label);
void print_dag (struct dstring_s *dstr, dagnode_t *node);
void print_dag (struct dstring_s *dstr, dag_t *dag);
/** Make a dag for a single basic block.
@ -88,9 +97,9 @@ void print_dag (struct dstring_s *dstr, dagnode_t *node);
variable information already computed.
\return The dag representing the basic block.
*/
dagnode_t *dag_create (const struct flownode_s *flownode);
dag_t *dag_create (const struct flownode_s *flownode);
void dag_generate (sblock_t *block, const struct flownode_s *flownode);
void dag_generate (dag_t *dag, sblock_t *block);
//@}

View file

@ -76,7 +76,7 @@ typedef struct flownode_s {
struct set_s *out;
} live_vars;
struct sblock_s *sblock; ///< original statement block
struct dagnode_s *dag; ///< dag for this node
struct dag_s *dag; ///< dag for this node
} flownode_t;
typedef struct flowgraph_s {

View file

@ -53,6 +53,7 @@
static daglabel_t *free_labels;
static dagnode_t *free_nodes;
static dag_t *free_dags;
static daglabel_t *daglabel_chain;
@ -80,6 +81,14 @@ flush_daglabels (void)
}
}
static dag_t *
new_dag (void)
{
dag_t *dag;
ALLOC (256, dag_t, dags, dag);
return dag;
}
static daglabel_t *
new_label (void)
{
@ -87,6 +96,7 @@ new_label (void)
ALLOC (256, daglabel_t, labels, label);
label->daglabel_chain = daglabel_chain;
daglabel_chain = label;
label->number = -1;
return label;
}
@ -95,6 +105,9 @@ new_node (void)
{
dagnode_t *node;
ALLOC (256, dagnode_t, nodes, node);
node->parents = set_new ();
node->edges = set_new ();
node->identifiers = set_new ();
return node;
}
@ -210,22 +223,19 @@ node (operand_t *op)
static int
dagnode_match (const dagnode_t *n, const daglabel_t *op,
const dagnode_t *y, const dagnode_t *z, const dagnode_t *w)
dagnode_t *operands[3])
{
int i;
if (n->label->opcode != op->opcode)
return 0;
if (n->a && y && n->a->label->op != y->label->op)
return 0;
if (n->b && z && n->b->label->op != z->label->op)
return 0;
if (n->c && w && n->c->label->op != w->label->op)
return 0;
if ((!n->a) ^ (!y))
return 0;
if ((!n->c) ^ (!z))
return 0;
if ((!n->b) ^ (!w))
return 0;
for (i = 0; i < 3; i++) {
if (n->children[i] && operands[i]
&& n->children[i]->label->op != operands[i]->label->op )
return 0;
if ((!n->children[i]) ^ (!operands[i]))
return 0;
}
return 1;
}
@ -254,165 +264,153 @@ dagnode_attach_label (dagnode_t *n, daglabel_t *l)
if (!op_is_identifer (l->op))
internal_error (0, "attempt to attach non-identifer label to dagnode "
"identifers");
if (n->identifiers)
n->identifiers->prev = &l->next;
l->next = n->identifiers;
l->prev = &n->identifiers;
if (l->dagnode)
set_remove (l->dagnode->identifiers, l->number);
l->dagnode = n;
n->identifiers = l;
set_add (n->identifiers, l->number);
}
static void
daglabel_detatch (daglabel_t *l)
{
if (l->next)
l->next->prev = l->prev;
*l->prev = l->next;
l->dagnode = 0;
}
static statement_t *
build_statement (const char *opcode, operand_t *a, operand_t *b, operand_t *c,
expr_t *expr)
{
statement_t *st = new_statement (st_none, opcode, expr);
st->opa = a;
st->opb = b;
st->opc = c;
return st;
}
dagnode_t *
dag_t *
dag_create (const flownode_t *flownode)
{
sblock_t *block = flownode->sblock;
dag_t *dag;
sblock_t *block = flownode->sblock;
statement_t *s;
dagnode_t *dagnodes = 0;
dagnode_t **dagtail = &dagnodes;
dagnode_t *d;
dagnode_t **nodes;
daglabel_t **labels;
int num_statements = 0;
int num_nodes = 0;
int num_labels = 0;
int i;
flush_daglabels ();
for (s = block->statements; s; s = s->next)
num_statements++;
// at most 4 per statement
nodes = alloca (num_statements * 4 * sizeof (dagnode_t));
// at most 3 per statement
labels = alloca (num_statements * 3 * sizeof (daglabel_t));
for (s = block->statements; s; s = s->next) {
operand_t *operands[4];
dagnode_t *n = 0, *ny, *nz, *nw;
dagnode_t *n = 0, *children[3] = {0, 0, 0};
daglabel_t *op, *lx;
int i;
flow_analyze_statement (s, 0, 0, 0, operands);
if (!(ny = node (operands[1]))) {
ny = leaf_node (operands[1], s->expr);
if (s->type == st_assign) {
*dagtail = ny;
dagtail = &ny->next;
for (i = 0; i < 3; i++) {
if (!(children[i] = node (operands[i + 1]))) {
children[i] = leaf_node (operands[i + 1], s->expr);
if (children[i]) {
children[i]->number = num_nodes;
nodes[num_nodes++] = children[i];
if (children[i]->label->number == -1) {
children[i]->label->number = num_labels;
labels[num_labels++] = children[i]->label;
}
}
}
}
if (!(nz = node (operands[2])))
nz = leaf_node (operands[2], s->expr);
if (!(nw = node (operands[3])))
nw = leaf_node (operands[3], s->expr);
op = opcode_label (s->opcode, s->expr);
op->number = num_labels;
labels[num_labels++] = op;
if (s->type == st_assign) {
n = ny;
n = children[0];
} else {
for (n = dagnodes; n; n = n->next)
if (dagnode_match (n, op, ny, nz, nw))
n = 0;
for (i = 0; i < num_nodes; i++) {
if (dagnode_match (nodes[i], op, children)) {
n = nodes[i];
break;
}
}
}
if (!n) {
n = new_node ();
n->type = s->type;
n->label = op;
n->a = ny;
n->b = nz;
n->c = nw;
if (ny) {
ny->is_child = 1;
n->ta = operands[1]->type;
n->number = num_nodes;
nodes[num_nodes++] = n;
for (i = 0; i < 3; i++) {
n->children[i] = children[i];
if (n->children[i]) {
set_add (n->children[i]->parents, n->number);
n->types[i] = operands[i + 1]->type;
}
}
if (nz) {
nz->is_child = 1;
n->tb = operands[2]->type;
}
if (nw) {
nw->is_child = 1;
n->tc = operands[3]->type;
}
*dagtail = n;
dagtail = &n->next;
}
lx = operand_label (operands[0]);
if (lx) {
if (lx->prev)
daglabel_detatch (lx);
flowvar_t *var = flow_get_var (lx->op);
lx->expr = s->expr;
dagnode_attach_label (n, lx);
if (lx->number == -1) {
lx->number = num_labels;
labels[num_labels++] = lx;
}
if (set_is_member (flownode->live_vars.out, var->number))
dagnode_attach_label (n, lx);
}
}
for (d = dagnodes; d; d = d->next) {
daglabel_t **l = &d->identifiers;
while (*l) {
if ((*l)->op->op_type == op_temp
&& !set_is_member (flownode->live_vars.out,
flow_get_var ((*l)->op)->number))
daglabel_detatch (*l);
else
l = &(*l)->next;
}
dag = new_dag ();
dag->nodes = malloc (num_nodes * sizeof (dagnode_t *));
memcpy (dag->nodes, nodes, num_nodes * sizeof (dagnode_t *));
dag->num_nodes = num_nodes;
dag->labels = malloc (num_labels * sizeof (daglabel_t *));
memcpy (dag->labels, labels, num_labels * sizeof (daglabel_t *));
dag->num_labels = num_labels;
dag->roots = set_new ();
for (i = 0; i < num_nodes; i++) {
if (set_is_empty (dag->nodes[i]->parents))
set_add (dag->roots, dag->nodes[i]->number);
}
while (dagnodes->is_child) {
dagnode_t *n = dagnodes->next;
dagnodes->next = 0;
dagnodes = n;
}
for (d = dagnodes; d && d->next; d = d->next) {
while (d->next && d->next->is_child) {
dagnode_t *n = d->next->next;
d->next->next = 0;
d->next = n;
}
}
return dagnodes;
return dag;
}
static statement_t *
build_statement (const char *opcode, operand_t **operands, expr_t *expr)
{
statement_t *st = new_statement (st_none, opcode, expr);
st->opa = operands[0];
st->opb = operands[1];
st->opc = operands[2];
return st;
}
#if 0
static void
dag_calc_node_costs (dagnode_t *dagnode)
{
if ((!dagnode->a && (dagnode->b || dagnode->c))
|| (dagnode->a && !dagnode->b && dagnode->c))
internal_error (0, "bad dag node");
int i;
if (dagnode->a)
dag_calc_node_costs (dagnode->a);
if (dagnode->b)
dag_calc_node_costs (dagnode->b);
if (dagnode->c)
dag_calc_node_costs (dagnode->c);
for (i = 0; i < 3; i++)
if (dagnode->children[i])
dag_calc_node_costs (dagnode->children[i]);
// if dagnode->a is null, then this is a leaf (as b and c are guaranted to
// be null)
if (!dagnode->a) {
if (!dagnode->children[0]) {
// Because qc vm statements don't mix source and destination operands,
// leaves never need temporary variables.
dagnode->cost = 0;
} else {
int different = 0;
// a non-leaf is guaranteed to have a valid "a"
dagnode->cost = dagnode->a->cost;
if (dagnode->b && dagnode->b->cost != dagnode->cost) {
dagnode->cost = max (dagnode->cost, dagnode->b->cost);
different = 1;
}
if (dagnode->c && (different || dagnode->c->cost != dagnode->cost)) {
dagnode->cost = max (dagnode->cost, dagnode->c->cost);
different = 1;
// a non-leaf is guaranteed to have a valid first child
dagnode->cost = dagnode->children[0]->cost;
for (i = 1; i < 3; i++) {
if (dagnode->children[i]
&& dagnode->children[i]->cost != dagnode->cost) {
dagnode->cost = max (dagnode->cost,
dagnode->children[i]->cost);
different = 1;
}
}
if (!different)
dagnode->cost += 1;
}
}
#endif
static operand_t *
fix_op_type (operand_t *op, etype_t type)
{
@ -422,93 +420,103 @@ fix_op_type (operand_t *op, etype_t type)
}
static operand_t *
generate_assignments (sblock_t *block, operand_t *src, daglabel_t *var)
generate_assignments (dag_t *dag, sblock_t *block, operand_t *src,
set_iter_t *var_iter)
{
statement_t *st;
operand_t *dst = 0;
operand_t *operands[3] = {src, 0, 0};
daglabel_t *var;
while (var) {
operand_t *vop = fix_op_type (var->op, src->type);
for ( ; var_iter; var_iter = set_next (var_iter)) {
var = dag->labels[var_iter->member];
operands[1] = fix_op_type (var->op, src->type);
if (!dst) {
dst = vop;
dst = operands[1];
while (dst->op_type == op_alias)
dst = dst->o.alias;
}
st = build_statement ("=", src, vop, 0, var->expr);
st = build_statement ("=", operands, var->expr);
sblock_add_statement (block, st);
var = var->next;
}
return dst;
}
static operand_t *dag_gencode (dag_t *dag, sblock_t *block,
const dagnode_t *dagnode);
static operand_t *
dag_gencode (sblock_t *block, const dagnode_t *dagnode)
make_operand (dag_t *dag, sblock_t *block, const dagnode_t *dagnode, int index)
{
operand_t *opa = 0, *opb = 0, *opc = 0;
operand_t *op;
op = dag_gencode (dag, block, dagnode->children[index]);
op = fix_op_type (op, dagnode->types[index]);
return op;
}
static operand_t *
dag_gencode (dag_t *dag, sblock_t *block, const dagnode_t *dagnode)
{
operand_t *operands[3] = {0, 0, 0};
operand_t *dst = 0;
statement_t *st;
daglabel_t *var;
set_iter_t *var_iter;
int i;
switch (dagnode->type) {
case st_none:
if (!dagnode->label->op)
internal_error (0, "non-leaf label in leaf node");
dst = dagnode->label->op;
if (dagnode->identifiers)
dst = generate_assignments (block, dst, dagnode->identifiers);
if ((var_iter = set_first (dagnode->identifiers)))
dst = generate_assignments (dag, block, dst, var_iter);
break;
case st_expr:
opa = fix_op_type (dag_gencode (block, dagnode->a), dagnode->ta);
if (dagnode->b)
opb = fix_op_type (dag_gencode (block, dagnode->b),
dagnode->tb);
if (!(var = dagnode->identifiers)) {
opc = temp_operand (get_type (dagnode->label->expr));
operands[0] = make_operand (dag, block, dagnode, 0);
if (dagnode->children[1])
operands[1] = make_operand (dag, block, dagnode, 1);
if (!(var_iter = set_first (dagnode->identifiers))) {
operands[2] = temp_operand (get_type (dagnode->label->expr));
} else {
opc = fix_op_type (var->op,
extract_type (dagnode->label->expr));
var = var->next;
daglabel_t *var = dag->labels[var_iter->member];
etype_t type = extract_type (dagnode->label->expr);
operands[2] = fix_op_type (var->op, type);
var_iter = set_next (var_iter);
}
dst = opc;
st = build_statement (dagnode->label->opcode, opa, opb, opc,
dst = operands[2];
st = build_statement (dagnode->label->opcode, operands,
dagnode->label->expr);
sblock_add_statement (block, st);
generate_assignments (block, opc, var);
generate_assignments (dag, block, operands[2], var_iter);
break;
case st_assign:
internal_error (0, "unexpected assignment node");
case st_ptrassign:
opa = fix_op_type (dag_gencode (block, dagnode->a), dagnode->ta);
opb = fix_op_type (dag_gencode (block, dagnode->b), dagnode->tb);
if (dagnode->c)
opc = fix_op_type (dag_gencode (block, dagnode->c),
dagnode->tc);
st = build_statement (dagnode->label->opcode, opa, opb, opc,
operands[0] = make_operand (dag, block, dagnode, 0);
operands[1] = make_operand (dag, block, dagnode, 1);
if (dagnode->children[2])
operands[2] = make_operand (dag, block, dagnode, 2);
st = build_statement (dagnode->label->opcode, operands,
dagnode->label->expr);
sblock_add_statement (block, st);
break;
case st_move:
case st_state:
case st_func:
if (dagnode->a)
opa = fix_op_type (dag_gencode (block, dagnode->a),
dagnode->ta);
if (dagnode->b)
opb = fix_op_type (dag_gencode (block, dagnode->b),
dagnode->tb);
if (dagnode->c)
opc = fix_op_type (dag_gencode (block, dagnode->c),
dagnode->tc);
st = build_statement (dagnode->label->opcode, opa, opb, opc,
for (i = 0; i < 3; i++)
if (dagnode->children[i])
operands[i] = make_operand (dag, block, dagnode, i);
st = build_statement (dagnode->label->opcode, operands,
dagnode->label->expr);
sblock_add_statement (block, st);
break;
case st_flow:
opa = fix_op_type (dag_gencode (block, dagnode->a), dagnode->ta);
if (dagnode->b)
opb = fix_op_type (dag_gencode (block, dagnode->b),
dagnode->tb);
st = build_statement (dagnode->label->opcode, opa, opb, 0,
operands[0] = make_operand (dag, block, dagnode, 0);
if (dagnode->children[1])
operands[1] = make_operand (dag, block, dagnode, 1);
st = build_statement (dagnode->label->opcode, operands,
dagnode->label->expr);
sblock_add_statement (block, st);
break;
@ -517,14 +525,11 @@ dag_gencode (sblock_t *block, const dagnode_t *dagnode)
}
void
dag_generate (sblock_t *block, const flownode_t *flownode)
dag_generate (dag_t *dag, sblock_t *block)
{
const dagnode_t *dag;
set_iter_t *node_iter;
dag_calc_node_costs (flownode->dag);
for (dag = flownode->dag; dag; dag = dag->next) {
//if (!dag->a || (strcmp (dag->label->opcode, ".=") && !dag->identifiers))
// continue;
dag_gencode (block, dag);
}
for (node_iter = set_first (dag->roots); node_iter;
node_iter = set_next (node_iter))
dag_gencode (dag, block, dag->nodes[node_iter->member]);
}

View file

@ -44,83 +44,58 @@
#include <QF/va.h>
#include "dags.h"
#include "set.h"
#include "statements.h"
#include "symtab.h"
#include "type.h"
static int print_count;
static void
print_node_def (dstring_t *dstr, dagnode_t *node, int recurse)
print_node_def (dstring_t *dstr, dagnode_t *node)
{
if (!node->a && (node->b || node->c)) {
dasprintf (dstr, " \"dagnode_%p\" [label=\"bad node\"];\n", node);
return;
}
dasprintf (dstr, " \"dagnode_%p\" [%slabel=\"%s\"];\n", node,
node->type != st_none ? "" : "shape=none,",
daglabel_string (node->label));
if (recurse) {
if (node->a)
print_node_def (dstr, node->a, 1);
if (node->b)
print_node_def (dstr, node->b, 1);
if (node->c)
print_node_def (dstr, node->c, 1);
}
}
static void
print_root_nodes (dstring_t *dstr, dagnode_t *dag)
print_root_nodes (dstring_t *dstr, dag_t *dag)
{
set_iter_t *node_iter;
dasprintf (dstr, " subgraph roots_%p {", dag);
dasprintf (dstr, " rank=same;");
for (; dag; dag = dag->next)
print_node_def (dstr, dag, 0);
for (node_iter = set_first (dag->roots); node_iter;
node_iter = set_next (node_iter))
print_node_def (dstr, dag->nodes[node_iter->member]);
dasprintf (dstr, " }\n");
}
static void
print_child_nodes (dstring_t *dstr, dagnode_t *dag)
print_child_nodes (dstring_t *dstr, dag_t *dag)
{
for (; dag; dag = dag->next) {
if (!dag->a && (dag->b || dag->c))
continue;
if (dag->a)
print_node_def (dstr, dag->a, 1);
if (dag->b)
print_node_def (dstr, dag->b, 1);
if (dag->c)
print_node_def (dstr, dag->c, 1);
int i;
dagnode_t *node;
for (i = 0; i < dag->num_nodes; i++) {
node = dag->nodes[i];
if (!set_is_empty (node->parents))
print_node_def (dstr, node);
}
}
static void
print_node (dstring_t *dstr, dagnode_t *node)
print_node (dstring_t *dstr, dag_t *dag, dagnode_t *node)
{
if (node->print_count == print_count)
return;
node->print_count = print_count;
if (node->a) {
dasprintf (dstr, " \"dagnode_%p\" -> \"dagnode_%p\" [label=a];\n",
node, node->a);
print_node (dstr, node->a);
int i;
for (i = 0; i < 3; i++) {
if (node->children[i]) {
dasprintf (dstr,
" \"dagnode_%p\" -> \"dagnode_%p\" [label=%c];\n",
node, node->children[i], i + 'a');
}
}
if (node->b) {
dasprintf (dstr, " \"dagnode_%p\" -> \"dagnode_%p\" [label=b];\n",
node, node->b);
print_node (dstr, node->b);
}
if (node->c) {
dasprintf (dstr, " \"dagnode_%p\" -> \"dagnode_%p\" [label=c];\n",
node, node->c);
print_node (dstr, node->c);
}
if (node->next)
dasprintf (dstr,
" \"dagnode_%p\" -> \"dagnode_%p\" [style=dashed];\n",
node, node->next);
if (node->identifiers) {
if (!set_is_empty (node->identifiers)) {
set_iter_t *id_iter;
daglabel_t *id;
dasprintf (dstr, " \"dagnode_%p\" -> \"dagid_%p\" "
@ -130,8 +105,11 @@ print_node (dstring_t *dstr, dagnode_t *node)
"cellspacing=\"0\">\n");
dasprintf (dstr, " <tr>\n");
dasprintf (dstr, " <td>");
for (id = node->identifiers; id; id = id->next)
dasprintf (dstr, "%s%s", daglabel_string(id), id->next ? " " : "");
for (id_iter = set_first (node->identifiers); id_iter;
id_iter = set_next (id_iter)) {
id = dag->labels[id_iter->member];
dasprintf (dstr, " %s", daglabel_string(id));
}
dasprintf (dstr, " </td>");
dasprintf (dstr, " </tr>\n");
dasprintf (dstr, " </table>>];\n");
@ -139,13 +117,13 @@ print_node (dstring_t *dstr, dagnode_t *node)
}
void
print_dag (dstring_t *dstr, dagnode_t *dag)
print_dag (dstring_t *dstr, dag_t *dag)
{
int i;
dasprintf (dstr, " subgraph cluster_dag_%p {", dag);
print_count++;
print_root_nodes (dstr, dag);
print_child_nodes (dstr, dag);
for (; dag; dag = dag->next)
print_node (dstr, dag);
for (i = 0; i < dag->num_nodes; i++)
print_node (dstr, dag, dag->nodes[i]);
dasprintf (dstr, " }\n");
}

View file

@ -433,7 +433,7 @@ flow_generate (flowgraph_t *graph)
label->dest = block;
}
// generate new statements from the dag;
dag_generate (block, node);
dag_generate (node->dag, block);
}
//dump_dot ("post", code, dump_dot_sblock);
return code;