--- /dev/null
+/*
+ * Copyright © 2019 Broadcom
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "util/set.h"
+#include "util/dag.h"
+
+/**
+ * Adds a directed edge from the parent node to the child.
+ *
+ * Both nodes should have been initialized with dag_init_node(). The edge
+ * list may contain multiple edges to the same child with different data.
+ */
+void
+dag_add_edge(struct dag_node *parent, struct dag_node *child, void *data)
+{
+ util_dynarray_foreach(&parent->edges, struct dag_edge, edge) {
+ if (edge->child == child && edge->data == data)
+ return;
+ }
+ /* Remove the child as a DAG head. */
+ list_delinit(&child->link);
+
+ struct dag_edge edge = {
+ .child = child,
+ .data = data,
+ };
+
+ util_dynarray_append(&parent->edges, struct dag_edge, edge);
+ child->parent_count++;
+}
+
+/* Removes a single edge from the graph, promoting the child to a DAG head.
+ *
+ * Note that calling this other than through dag_prune_head() means that you
+ * need to be careful when iterating the edges of remaining nodes for NULL
+ * children.
+ */
+void
+dag_remove_edge(struct dag *dag, struct dag_edge *edge)
+{
+ if (!edge->child)
+ return;
+
+ struct dag_node *child = edge->child;
+ child->parent_count--;
+ if (child->parent_count == 0)
+ list_addtail(&child->link, &dag->heads);
+
+ edge->child = NULL;
+ edge->data = NULL;
+}
+
+/**
+ * Removes a DAG head from the graph, and moves any new dag heads into the
+ * heads list.
+ */
+void
+dag_prune_head(struct dag *dag, struct dag_node *node)
+{
+ assert(!node->parent_count);
+
+ list_delinit(&node->link);
+
+ util_dynarray_foreach(&node->edges, struct dag_edge, edge) {
+ dag_remove_edge(dag, edge);
+ }
+}
+
+/**
+ * Initializes DAG node (probably embedded in some other datastructure in the
+ * user).
+ */
+void
+dag_init_node(struct dag *dag, struct dag_node *node)
+{
+ util_dynarray_init(&node->edges, dag);
+ list_addtail(&node->link, &dag->heads);
+}
+
+struct dag_traverse_bottom_up_state {
+ struct set *seen;
+ void *data;
+};
+
+static void
+dag_traverse_bottom_up_node(struct dag_node *node,
+ void (*cb)(struct dag_node *node,
+ void *data),
+ struct dag_traverse_bottom_up_state *state)
+{
+ if (_mesa_set_search(state->seen, node))
+ return;
+
+ util_dynarray_foreach(&node->edges, struct dag_edge, edge) {
+ dag_traverse_bottom_up_node(edge->child, cb, state);
+ }
+
+ cb(node, state->data);
+ _mesa_set_add(state->seen, node);
+}
+
+/**
+ * Walks the DAG from leaves to the root, ensuring that each node is only seen
+ * once its children have been, and each node is only traversed once.
+ */
+void
+dag_traverse_bottom_up(struct dag *dag, void (*cb)(struct dag_node *node,
+ void *data), void *data)
+{
+ struct dag_traverse_bottom_up_state state = {
+ .seen = _mesa_pointer_set_create(NULL),
+ .data = data,
+ };
+
+ list_for_each_entry(struct dag_node, node, &dag->heads, link) {
+ dag_traverse_bottom_up_node(node, cb, &state);
+ }
+
+ ralloc_free(state.seen);
+}
+
+/**
+ * Creates an empty DAG datastructure.
+ */
+struct dag *
+dag_create(void *mem_ctx)
+{
+ struct dag *dag = rzalloc(mem_ctx, struct dag);
+
+ list_inithead(&dag->heads);
+
+ return dag;
+}
+
--- /dev/null
+/*
+ * Copyright © 2019 Broadcom
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef DAG_H
+#define DAG_H
+
+#include <stdint.h>
+#include "util/list.h"
+#include "util/u_dynarray.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dag_edge {
+ struct dag_node *child;
+ /* User-defined data associated with the edge. */
+ void *data;
+};
+
+struct dag_node {
+ /* Position in the DAG heads list (or a self-link) */
+ struct list_head link;
+ /* Array struct edge to the children. */
+ struct util_dynarray edges;
+ uint32_t parent_count;
+};
+
+struct dag {
+ struct list_head heads;
+};
+
+struct dag *dag_create(void *mem_ctx);
+void dag_init_node(struct dag *dag, struct dag_node *node);
+void dag_add_edge(struct dag_node *parent, struct dag_node *child, void *data);
+void dag_remove_edge(struct dag *dag, struct dag_edge *edge);
+void dag_traverse_bottom_up(struct dag *dag, void (*cb)(struct dag_node *node,
+ void *data), void *data);
+void dag_prune_head(struct dag *dag, struct dag_node *node);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif