mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 07:11:41 +00:00
[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:
parent
0d1fad12f0
commit
5291cfb03d
3 changed files with 33 additions and 1 deletions
|
@ -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 {
|
||||
|
|
|
@ -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,8 +855,9 @@ 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 *));
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue