[qfcc] Keep track of reachable dag nodes

In order to correctly handle swap-style code

    { t = a; a = b; b = t; }

edges need to be created for each of the assignments moving an
identifier lable, but the dag must remain acyclic (the above example
wants to create a cycle). Having the reachable nodes recorded makes
checking for potential loops a quick operation.
This commit is contained in:
Bill Currie 2021-06-29 09:41:03 +09:00
parent 0d1fad12f0
commit 5291cfb03d
3 changed files with 33 additions and 1 deletions

View file

@ -79,6 +79,9 @@ typedef struct dagnode_s {
struct set_s *edges; ///< includes nodes pointed to by \a children
//@}
struct set_s *identifiers; ///< set of identifiers attached to this node
struct set_s *reachable; ///< set of nodes reachable via edges (not
///< parents) for ensuring cycles are not
///< created
} dagnode_t;
typedef struct dag_s {

View file

@ -116,6 +116,7 @@ new_node (dag_t *dag)
node->parents = set_new ();
node->edges = set_new ();
node->identifiers = set_new ();
node->reachable = set_new ();
node->number = dag->num_nodes;
set_add (dag->roots, node->number); // nodes start out as root nodes
dag->nodes[dag->num_nodes++] = node;
@ -255,6 +256,20 @@ dag_make_leafs (dag_t *dag, statement_t *s, operand_t *operands[FLOW_OPERANDS])
}
}
static void
dagnode_set_reachable (dag_t *dag, dagnode_t *node)
{
for (set_iter_t *edge_iter = set_first (node->edges); edge_iter;
edge_iter = set_next (edge_iter)) {
dagnode_t *r = dag->nodes[edge_iter->element];
// The other node is directly reachable
set_add (node->reachable, r->number);
// All nodes reachable by the other node are indirectly reachable
// from this node.
set_union (node->reachable, r->reachable);
}
}
static void
dag_make_children (dag_t *dag, statement_t *s,
operand_t *operands[FLOW_OPERANDS],
@ -282,6 +297,10 @@ dag_make_children (dag_t *dag, statement_t *s,
// When an operand refers to a killed node, it must be
// evaluated AFTER the killing node has been evaluated.
set_add (node->edges, killer->number);
// If killer is set, then node is guaranteed to be a new node
// and thus does not have any parents, so no need to worry about
// updating the reachable sets of any parent nodes.
dagnode_set_reachable (dag, node);
}
children[i] = node;
}
@ -828,6 +847,7 @@ dag_create (flownode_t *flownode)
n->label = op;
dagnode_add_children (dag, n, operands, children);
dagnode_set_edges (dag, n);
dagnode_set_reachable (dag, n);
}
}
lx = operand_label (dag, operands[0]);
@ -835,9 +855,10 @@ dag_create (flownode_t *flownode)
lx->expr = s->expr;
dagnode_attach_label (n, lx);
}
if (n->type == st_ptrassign)
if (n->type == st_ptrassign) {
dag_kill_nodes (dag, n);
}
}
nodes = malloc (dag->num_nodes * sizeof (dagnode_t *));
memcpy (nodes, dag->nodes, dag->num_nodes * sizeof (dagnode_t *));

View file

@ -124,6 +124,14 @@ print_node (dstring_t *dstr, dag_t *dag, dagnode_t *node)
node, dag->nodes[edge_iter->element]);
}
set_delete (edges);
if (0) {
for (edge_iter = set_first (node->reachable); edge_iter;
edge_iter = set_next (edge_iter)) {
dasprintf (dstr,
" \"dagnode_%p\" -> \"dagnode_%p\" [style=dotted];\n",
node, dag->nodes[edge_iter->element]);
}
}
if (0 && !set_is_empty (node->identifiers)) {
set_iter_t *id_iter;
daglabel_t *id;