1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Connor Abbott (cwabbott0@gmail.com) 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "nir.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci/* 31bf215546Sopenharmony_ci * Implements the algorithms for computing the dominance tree and the 32bf215546Sopenharmony_ci * dominance frontier from "A Simple, Fast Dominance Algorithm" by Cooper, 33bf215546Sopenharmony_ci * Harvey, and Kennedy. 34bf215546Sopenharmony_ci */ 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_cistatic bool 37bf215546Sopenharmony_ciinit_block(nir_block *block, nir_function_impl *impl) 38bf215546Sopenharmony_ci{ 39bf215546Sopenharmony_ci if (block == nir_start_block(impl)) 40bf215546Sopenharmony_ci block->imm_dom = block; 41bf215546Sopenharmony_ci else 42bf215546Sopenharmony_ci block->imm_dom = NULL; 43bf215546Sopenharmony_ci block->num_dom_children = 0; 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci /* See nir_block_dominates */ 46bf215546Sopenharmony_ci block->dom_pre_index = UINT32_MAX; 47bf215546Sopenharmony_ci block->dom_post_index = 0; 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci _mesa_set_clear(block->dom_frontier, NULL); 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci return true; 52bf215546Sopenharmony_ci} 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic nir_block * 55bf215546Sopenharmony_ciintersect(nir_block *b1, nir_block *b2) 56bf215546Sopenharmony_ci{ 57bf215546Sopenharmony_ci while (b1 != b2) { 58bf215546Sopenharmony_ci /* 59bf215546Sopenharmony_ci * Note, the comparisons here are the opposite of what the paper says 60bf215546Sopenharmony_ci * because we index blocks from beginning -> end (i.e. reverse 61bf215546Sopenharmony_ci * post-order) instead of post-order like they assume. 62bf215546Sopenharmony_ci */ 63bf215546Sopenharmony_ci while (b1->index > b2->index) 64bf215546Sopenharmony_ci b1 = b1->imm_dom; 65bf215546Sopenharmony_ci while (b2->index > b1->index) 66bf215546Sopenharmony_ci b2 = b2->imm_dom; 67bf215546Sopenharmony_ci } 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci return b1; 70bf215546Sopenharmony_ci} 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_cistatic bool 73bf215546Sopenharmony_cicalc_dominance(nir_block *block) 74bf215546Sopenharmony_ci{ 75bf215546Sopenharmony_ci nir_block *new_idom = NULL; 76bf215546Sopenharmony_ci set_foreach(block->predecessors, entry) { 77bf215546Sopenharmony_ci nir_block *pred = (nir_block *) entry->key; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci if (pred->imm_dom) { 80bf215546Sopenharmony_ci if (new_idom) 81bf215546Sopenharmony_ci new_idom = intersect(pred, new_idom); 82bf215546Sopenharmony_ci else 83bf215546Sopenharmony_ci new_idom = pred; 84bf215546Sopenharmony_ci } 85bf215546Sopenharmony_ci } 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci if (block->imm_dom != new_idom) { 88bf215546Sopenharmony_ci block->imm_dom = new_idom; 89bf215546Sopenharmony_ci return true; 90bf215546Sopenharmony_ci } 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci return false; 93bf215546Sopenharmony_ci} 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_cistatic bool 96bf215546Sopenharmony_cicalc_dom_frontier(nir_block *block) 97bf215546Sopenharmony_ci{ 98bf215546Sopenharmony_ci if (block->predecessors->entries > 1) { 99bf215546Sopenharmony_ci set_foreach(block->predecessors, entry) { 100bf215546Sopenharmony_ci nir_block *runner = (nir_block *) entry->key; 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci /* Skip unreachable predecessors */ 103bf215546Sopenharmony_ci if (runner->imm_dom == NULL) 104bf215546Sopenharmony_ci continue; 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci while (runner != block->imm_dom) { 107bf215546Sopenharmony_ci _mesa_set_add(runner->dom_frontier, block); 108bf215546Sopenharmony_ci runner = runner->imm_dom; 109bf215546Sopenharmony_ci } 110bf215546Sopenharmony_ci } 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci return true; 114bf215546Sopenharmony_ci} 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci/* 117bf215546Sopenharmony_ci * Compute each node's children in the dominance tree from the immediate 118bf215546Sopenharmony_ci * dominator information. We do this in three stages: 119bf215546Sopenharmony_ci * 120bf215546Sopenharmony_ci * 1. Calculate the number of children each node has 121bf215546Sopenharmony_ci * 2. Allocate arrays, setting the number of children to 0 again 122bf215546Sopenharmony_ci * 3. For each node, add itself to its parent's list of children, using 123bf215546Sopenharmony_ci * num_dom_children as an index - at the end of this step, num_dom_children 124bf215546Sopenharmony_ci * for each node will be the same as it was at the end of step #1. 125bf215546Sopenharmony_ci */ 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_cistatic void 128bf215546Sopenharmony_cicalc_dom_children(nir_function_impl* impl) 129bf215546Sopenharmony_ci{ 130bf215546Sopenharmony_ci void *mem_ctx = ralloc_parent(impl); 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 133bf215546Sopenharmony_ci if (block->imm_dom) 134bf215546Sopenharmony_ci block->imm_dom->num_dom_children++; 135bf215546Sopenharmony_ci } 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 138bf215546Sopenharmony_ci block->dom_children = ralloc_array(mem_ctx, nir_block *, 139bf215546Sopenharmony_ci block->num_dom_children); 140bf215546Sopenharmony_ci block->num_dom_children = 0; 141bf215546Sopenharmony_ci } 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 144bf215546Sopenharmony_ci if (block->imm_dom) { 145bf215546Sopenharmony_ci block->imm_dom->dom_children[block->imm_dom->num_dom_children++] 146bf215546Sopenharmony_ci = block; 147bf215546Sopenharmony_ci } 148bf215546Sopenharmony_ci } 149bf215546Sopenharmony_ci} 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_cistatic void 152bf215546Sopenharmony_cicalc_dfs_indicies(nir_block *block, uint32_t *index) 153bf215546Sopenharmony_ci{ 154bf215546Sopenharmony_ci /* UINT32_MAX has special meaning. See nir_block_dominates. */ 155bf215546Sopenharmony_ci assert(*index < UINT32_MAX - 2); 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci block->dom_pre_index = (*index)++; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci for (unsigned i = 0; i < block->num_dom_children; i++) 160bf215546Sopenharmony_ci calc_dfs_indicies(block->dom_children[i], index); 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci block->dom_post_index = (*index)++; 163bf215546Sopenharmony_ci} 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_civoid 166bf215546Sopenharmony_cinir_calc_dominance_impl(nir_function_impl *impl) 167bf215546Sopenharmony_ci{ 168bf215546Sopenharmony_ci if (impl->valid_metadata & nir_metadata_dominance) 169bf215546Sopenharmony_ci return; 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci nir_metadata_require(impl, nir_metadata_block_index); 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 175bf215546Sopenharmony_ci init_block(block, impl); 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci bool progress = true; 179bf215546Sopenharmony_ci while (progress) { 180bf215546Sopenharmony_ci progress = false; 181bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 182bf215546Sopenharmony_ci if (block != nir_start_block(impl)) 183bf215546Sopenharmony_ci progress |= calc_dominance(block); 184bf215546Sopenharmony_ci } 185bf215546Sopenharmony_ci } 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 188bf215546Sopenharmony_ci calc_dom_frontier(block); 189bf215546Sopenharmony_ci } 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci nir_block *start_block = nir_start_block(impl); 192bf215546Sopenharmony_ci start_block->imm_dom = NULL; 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci calc_dom_children(impl); 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci uint32_t dfs_index = 1; 197bf215546Sopenharmony_ci calc_dfs_indicies(start_block, &dfs_index); 198bf215546Sopenharmony_ci} 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_civoid 201bf215546Sopenharmony_cinir_calc_dominance(nir_shader *shader) 202bf215546Sopenharmony_ci{ 203bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 204bf215546Sopenharmony_ci if (function->impl) 205bf215546Sopenharmony_ci nir_calc_dominance_impl(function->impl); 206bf215546Sopenharmony_ci } 207bf215546Sopenharmony_ci} 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_cistatic nir_block * 210bf215546Sopenharmony_ciblock_return_if_reachable(nir_block *b) 211bf215546Sopenharmony_ci{ 212bf215546Sopenharmony_ci return (b && nir_block_is_reachable(b)) ? b : NULL; 213bf215546Sopenharmony_ci} 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci/** 216bf215546Sopenharmony_ci * Computes the least common ancestor of two blocks. If one of the blocks 217bf215546Sopenharmony_ci * is null or unreachable, the other block is returned or NULL if it's 218bf215546Sopenharmony_ci * unreachable. 219bf215546Sopenharmony_ci */ 220bf215546Sopenharmony_cinir_block * 221bf215546Sopenharmony_cinir_dominance_lca(nir_block *b1, nir_block *b2) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci if (b1 == NULL || !nir_block_is_reachable(b1)) 224bf215546Sopenharmony_ci return block_return_if_reachable(b2); 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci if (b2 == NULL || !nir_block_is_reachable(b2)) 227bf215546Sopenharmony_ci return block_return_if_reachable(b1); 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci assert(nir_cf_node_get_function(&b1->cf_node) == 230bf215546Sopenharmony_ci nir_cf_node_get_function(&b2->cf_node)); 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci assert(nir_cf_node_get_function(&b1->cf_node)->valid_metadata & 233bf215546Sopenharmony_ci nir_metadata_dominance); 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci return intersect(b1, b2); 236bf215546Sopenharmony_ci} 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci/** 239bf215546Sopenharmony_ci * Returns true if parent dominates child according to the following 240bf215546Sopenharmony_ci * definition: 241bf215546Sopenharmony_ci * 242bf215546Sopenharmony_ci * "The block A dominates the block B if every path from the start block 243bf215546Sopenharmony_ci * to block B passes through A." 244bf215546Sopenharmony_ci * 245bf215546Sopenharmony_ci * This means, in particular, that any unreachable block is dominated by every 246bf215546Sopenharmony_ci * other block and an unreachable block does not dominate anything except 247bf215546Sopenharmony_ci * another unreachable block. 248bf215546Sopenharmony_ci */ 249bf215546Sopenharmony_cibool 250bf215546Sopenharmony_cinir_block_dominates(nir_block *parent, nir_block *child) 251bf215546Sopenharmony_ci{ 252bf215546Sopenharmony_ci assert(nir_cf_node_get_function(&parent->cf_node) == 253bf215546Sopenharmony_ci nir_cf_node_get_function(&child->cf_node)); 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci assert(nir_cf_node_get_function(&parent->cf_node)->valid_metadata & 256bf215546Sopenharmony_ci nir_metadata_dominance); 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci /* If a block is unreachable, then nir_block::dom_pre_index == UINT32_MAX 259bf215546Sopenharmony_ci * and nir_block::dom_post_index == 0. This allows us to trivially handle 260bf215546Sopenharmony_ci * unreachable blocks here with zero extra work. 261bf215546Sopenharmony_ci */ 262bf215546Sopenharmony_ci return child->dom_pre_index >= parent->dom_pre_index && 263bf215546Sopenharmony_ci child->dom_post_index <= parent->dom_post_index; 264bf215546Sopenharmony_ci} 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_cibool 267bf215546Sopenharmony_cinir_block_is_unreachable(nir_block *block) 268bf215546Sopenharmony_ci{ 269bf215546Sopenharmony_ci assert(nir_cf_node_get_function(&block->cf_node)->valid_metadata & 270bf215546Sopenharmony_ci nir_metadata_dominance); 271bf215546Sopenharmony_ci assert(nir_cf_node_get_function(&block->cf_node)->valid_metadata & 272bf215546Sopenharmony_ci nir_metadata_block_index); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci /* Unreachable blocks have no dominator. The only reachable block with no 275bf215546Sopenharmony_ci * dominator is the start block which has index 0. 276bf215546Sopenharmony_ci */ 277bf215546Sopenharmony_ci return block->index > 0 && block->imm_dom == NULL; 278bf215546Sopenharmony_ci} 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_civoid 281bf215546Sopenharmony_cinir_dump_dom_tree_impl(nir_function_impl *impl, FILE *fp) 282bf215546Sopenharmony_ci{ 283bf215546Sopenharmony_ci fprintf(fp, "digraph doms_%s {\n", impl->function->name); 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 286bf215546Sopenharmony_ci if (block->imm_dom) 287bf215546Sopenharmony_ci fprintf(fp, "\t%u -> %u\n", block->imm_dom->index, block->index); 288bf215546Sopenharmony_ci } 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci fprintf(fp, "}\n\n"); 291bf215546Sopenharmony_ci} 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_civoid 294bf215546Sopenharmony_cinir_dump_dom_tree(nir_shader *shader, FILE *fp) 295bf215546Sopenharmony_ci{ 296bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 297bf215546Sopenharmony_ci if (function->impl) 298bf215546Sopenharmony_ci nir_dump_dom_tree_impl(function->impl, fp); 299bf215546Sopenharmony_ci } 300bf215546Sopenharmony_ci} 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_civoid 303bf215546Sopenharmony_cinir_dump_dom_frontier_impl(nir_function_impl *impl, FILE *fp) 304bf215546Sopenharmony_ci{ 305bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 306bf215546Sopenharmony_ci fprintf(fp, "DF(%u) = {", block->index); 307bf215546Sopenharmony_ci set_foreach(block->dom_frontier, entry) { 308bf215546Sopenharmony_ci nir_block *df = (nir_block *) entry->key; 309bf215546Sopenharmony_ci fprintf(fp, "%u, ", df->index); 310bf215546Sopenharmony_ci } 311bf215546Sopenharmony_ci fprintf(fp, "}\n"); 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci} 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_civoid 316bf215546Sopenharmony_cinir_dump_dom_frontier(nir_shader *shader, FILE *fp) 317bf215546Sopenharmony_ci{ 318bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 319bf215546Sopenharmony_ci if (function->impl) 320bf215546Sopenharmony_ci nir_dump_dom_frontier_impl(function->impl, fp); 321bf215546Sopenharmony_ci } 322bf215546Sopenharmony_ci} 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_civoid 325bf215546Sopenharmony_cinir_dump_cfg_impl(nir_function_impl *impl, FILE *fp) 326bf215546Sopenharmony_ci{ 327bf215546Sopenharmony_ci fprintf(fp, "digraph cfg_%s {\n", impl->function->name); 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 330bf215546Sopenharmony_ci if (block->successors[0]) 331bf215546Sopenharmony_ci fprintf(fp, "\t%u -> %u\n", block->index, block->successors[0]->index); 332bf215546Sopenharmony_ci if (block->successors[1]) 333bf215546Sopenharmony_ci fprintf(fp, "\t%u -> %u\n", block->index, block->successors[1]->index); 334bf215546Sopenharmony_ci } 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci fprintf(fp, "}\n\n"); 337bf215546Sopenharmony_ci} 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_civoid 340bf215546Sopenharmony_cinir_dump_cfg(nir_shader *shader, FILE *fp) 341bf215546Sopenharmony_ci{ 342bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 343bf215546Sopenharmony_ci if (function->impl) 344bf215546Sopenharmony_ci nir_dump_cfg_impl(function->impl, fp); 345bf215546Sopenharmony_ci } 346bf215546Sopenharmony_ci} 347