18a1362adSmaya/* 28a1362adSmaya * Copyright © 2019 Broadcom 38a1362adSmaya * 48a1362adSmaya * Permission is hereby granted, free of charge, to any person obtaining a 58a1362adSmaya * copy of this software and associated documentation files (the "Software"), 68a1362adSmaya * to deal in the Software without restriction, including without limitation 78a1362adSmaya * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88a1362adSmaya * and/or sell copies of the Software, and to permit persons to whom the 98a1362adSmaya * Software is furnished to do so, subject to the following conditions: 108a1362adSmaya * 118a1362adSmaya * The above copyright notice and this permission notice (including the next 128a1362adSmaya * paragraph) shall be included in all copies or substantial portions of the 138a1362adSmaya * Software. 148a1362adSmaya * 158a1362adSmaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168a1362adSmaya * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178a1362adSmaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188a1362adSmaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 198a1362adSmaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 208a1362adSmaya * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 218a1362adSmaya * IN THE SOFTWARE. 228a1362adSmaya */ 238a1362adSmaya 248a1362adSmaya#include "util/set.h" 258a1362adSmaya#include "util/dag.h" 268a1362adSmaya 278a1362adSmaya/** 288a1362adSmaya * Adds a directed edge from the parent node to the child. 298a1362adSmaya * 308a1362adSmaya * Both nodes should have been initialized with dag_init_node(). The edge 318a1362adSmaya * list may contain multiple edges to the same child with different data. 328a1362adSmaya */ 338a1362adSmayavoid 348a1362adSmayadag_add_edge(struct dag_node *parent, struct dag_node *child, void *data) 358a1362adSmaya{ 368a1362adSmaya util_dynarray_foreach(&parent->edges, struct dag_edge, edge) { 378a1362adSmaya if (edge->child == child && edge->data == data) 388a1362adSmaya return; 398a1362adSmaya } 408a1362adSmaya /* Remove the child as a DAG head. */ 418a1362adSmaya list_delinit(&child->link); 428a1362adSmaya 438a1362adSmaya struct dag_edge edge = { 448a1362adSmaya .child = child, 458a1362adSmaya .data = data, 468a1362adSmaya }; 478a1362adSmaya 488a1362adSmaya util_dynarray_append(&parent->edges, struct dag_edge, edge); 498a1362adSmaya child->parent_count++; 508a1362adSmaya} 518a1362adSmaya 528a1362adSmaya/* Removes a single edge from the graph, promoting the child to a DAG head. 538a1362adSmaya * 548a1362adSmaya * Note that calling this other than through dag_prune_head() means that you 558a1362adSmaya * need to be careful when iterating the edges of remaining nodes for NULL 568a1362adSmaya * children. 578a1362adSmaya */ 588a1362adSmayavoid 598a1362adSmayadag_remove_edge(struct dag *dag, struct dag_edge *edge) 608a1362adSmaya{ 618a1362adSmaya if (!edge->child) 628a1362adSmaya return; 638a1362adSmaya 648a1362adSmaya struct dag_node *child = edge->child; 658a1362adSmaya child->parent_count--; 668a1362adSmaya if (child->parent_count == 0) 678a1362adSmaya list_addtail(&child->link, &dag->heads); 688a1362adSmaya 698a1362adSmaya edge->child = NULL; 708a1362adSmaya edge->data = NULL; 718a1362adSmaya} 728a1362adSmaya 738a1362adSmaya/** 748a1362adSmaya * Removes a DAG head from the graph, and moves any new dag heads into the 758a1362adSmaya * heads list. 768a1362adSmaya */ 778a1362adSmayavoid 788a1362adSmayadag_prune_head(struct dag *dag, struct dag_node *node) 798a1362adSmaya{ 808a1362adSmaya assert(!node->parent_count); 818a1362adSmaya 828a1362adSmaya list_delinit(&node->link); 838a1362adSmaya 848a1362adSmaya util_dynarray_foreach(&node->edges, struct dag_edge, edge) { 858a1362adSmaya dag_remove_edge(dag, edge); 868a1362adSmaya } 878a1362adSmaya} 888a1362adSmaya 898a1362adSmaya/** 908a1362adSmaya * Initializes DAG node (probably embedded in some other datastructure in the 918a1362adSmaya * user). 928a1362adSmaya */ 938a1362adSmayavoid 948a1362adSmayadag_init_node(struct dag *dag, struct dag_node *node) 958a1362adSmaya{ 968a1362adSmaya util_dynarray_init(&node->edges, dag); 978a1362adSmaya list_addtail(&node->link, &dag->heads); 988a1362adSmaya} 998a1362adSmaya 1008a1362adSmayastruct dag_traverse_bottom_up_state { 1018a1362adSmaya struct set *seen; 1028a1362adSmaya void *data; 1038a1362adSmaya}; 1048a1362adSmaya 1058a1362adSmayastatic void 1068a1362adSmayadag_traverse_bottom_up_node(struct dag_node *node, 1078a1362adSmaya void (*cb)(struct dag_node *node, 1088a1362adSmaya void *data), 1098a1362adSmaya struct dag_traverse_bottom_up_state *state) 1108a1362adSmaya{ 1118a1362adSmaya if (_mesa_set_search(state->seen, node)) 1128a1362adSmaya return; 1138a1362adSmaya 1147ec681f3Smrg struct util_dynarray stack; 1157ec681f3Smrg util_dynarray_init(&stack, NULL); 1167ec681f3Smrg 1177ec681f3Smrg do { 1187ec681f3Smrg assert(node); 1197ec681f3Smrg 1207ec681f3Smrg while (node->edges.size != 0) { 1217ec681f3Smrg util_dynarray_append(&stack, struct dag_node *, node); 1227ec681f3Smrg 1237ec681f3Smrg /* Push unprocessed children onto stack in reverse order. Note that 1247ec681f3Smrg * it's possible for any of the children nodes to already be on the 1257ec681f3Smrg * stack. 1267ec681f3Smrg */ 1277ec681f3Smrg util_dynarray_foreach_reverse(&node->edges, struct dag_edge, edge) { 1287ec681f3Smrg if (!_mesa_set_search(state->seen, edge->child)) { 1297ec681f3Smrg util_dynarray_append(&stack, struct dag_node *, edge->child); 1307ec681f3Smrg } 1317ec681f3Smrg } 1327ec681f3Smrg 1337ec681f3Smrg /* Get last element pushed: either left-most child or current node. 1347ec681f3Smrg * If it's the current node, that means that we've processed all its 1357ec681f3Smrg * children already. 1367ec681f3Smrg */ 1377ec681f3Smrg struct dag_node *top = util_dynarray_pop(&stack, struct dag_node *); 1387ec681f3Smrg if (top == node) 1397ec681f3Smrg break; 1407ec681f3Smrg node = top; 1417ec681f3Smrg } 1427ec681f3Smrg 1437ec681f3Smrg /* Process the node */ 1447ec681f3Smrg cb(node, state->data); 1457ec681f3Smrg _mesa_set_add(state->seen, node); 1467ec681f3Smrg 1477ec681f3Smrg /* Find the next unprocessed node in the stack */ 1487ec681f3Smrg do { 1497ec681f3Smrg node = NULL; 1507ec681f3Smrg if (stack.size == 0) 1517ec681f3Smrg break; 1527ec681f3Smrg 1537ec681f3Smrg node = util_dynarray_pop(&stack, struct dag_node *); 1547ec681f3Smrg } while (_mesa_set_search(state->seen, node)); 1557ec681f3Smrg } while (node); 1567ec681f3Smrg 1577ec681f3Smrg util_dynarray_fini(&stack); 1588a1362adSmaya} 1598a1362adSmaya 1608a1362adSmaya/** 1618a1362adSmaya * Walks the DAG from leaves to the root, ensuring that each node is only seen 1628a1362adSmaya * once its children have been, and each node is only traversed once. 1638a1362adSmaya */ 1648a1362adSmayavoid 1658a1362adSmayadag_traverse_bottom_up(struct dag *dag, void (*cb)(struct dag_node *node, 1668a1362adSmaya void *data), void *data) 1678a1362adSmaya{ 1688a1362adSmaya struct dag_traverse_bottom_up_state state = { 1698a1362adSmaya .seen = _mesa_pointer_set_create(NULL), 1708a1362adSmaya .data = data, 1718a1362adSmaya }; 1728a1362adSmaya 1738a1362adSmaya list_for_each_entry(struct dag_node, node, &dag->heads, link) { 1748a1362adSmaya dag_traverse_bottom_up_node(node, cb, &state); 1758a1362adSmaya } 1768a1362adSmaya 1778a1362adSmaya ralloc_free(state.seen); 1788a1362adSmaya} 1798a1362adSmaya 1808a1362adSmaya/** 1818a1362adSmaya * Creates an empty DAG datastructure. 1828a1362adSmaya */ 1838a1362adSmayastruct dag * 1848a1362adSmayadag_create(void *mem_ctx) 1858a1362adSmaya{ 1868a1362adSmaya struct dag *dag = rzalloc(mem_ctx, struct dag); 1878a1362adSmaya 1888a1362adSmaya list_inithead(&dag->heads); 1898a1362adSmaya 1908a1362adSmaya return dag; 1918a1362adSmaya} 1928a1362adSmaya 193