1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014 Connor Abbott 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#include "nir_control_flow.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci/* 32bf215546Sopenharmony_ci * This file implements an optimization that deletes statically 33bf215546Sopenharmony_ci * unreachable/dead code. In NIR, one way this can happen is when an if 34bf215546Sopenharmony_ci * statement has a constant condition: 35bf215546Sopenharmony_ci * 36bf215546Sopenharmony_ci * if (true) { 37bf215546Sopenharmony_ci * ... 38bf215546Sopenharmony_ci * } 39bf215546Sopenharmony_ci * 40bf215546Sopenharmony_ci * We delete the if statement and paste the contents of the always-executed 41bf215546Sopenharmony_ci * branch into the surrounding control flow, possibly removing more code if 42bf215546Sopenharmony_ci * the branch had a jump at the end. 43bf215546Sopenharmony_ci * 44bf215546Sopenharmony_ci * Another way is that control flow can end in a jump so that code after it 45bf215546Sopenharmony_ci * never gets executed. In particular, this can happen after optimizing 46bf215546Sopenharmony_ci * something like: 47bf215546Sopenharmony_ci * 48bf215546Sopenharmony_ci * if (true) { 49bf215546Sopenharmony_ci * ... 50bf215546Sopenharmony_ci * break; 51bf215546Sopenharmony_ci * } 52bf215546Sopenharmony_ci * ... 53bf215546Sopenharmony_ci * 54bf215546Sopenharmony_ci * We also consider the case where both branches of an if end in a jump, e.g.: 55bf215546Sopenharmony_ci * 56bf215546Sopenharmony_ci * if (...) { 57bf215546Sopenharmony_ci * break; 58bf215546Sopenharmony_ci * } else { 59bf215546Sopenharmony_ci * continue; 60bf215546Sopenharmony_ci * } 61bf215546Sopenharmony_ci * ... 62bf215546Sopenharmony_ci * 63bf215546Sopenharmony_ci * Finally, we also handle removing useless loops and ifs, i.e. loops and ifs 64bf215546Sopenharmony_ci * with no side effects and without any definitions that are used 65bf215546Sopenharmony_ci * elsewhere. This case is a little different from the first two in that the 66bf215546Sopenharmony_ci * code is actually run (it just never does anything), but there are similar 67bf215546Sopenharmony_ci * issues with needing to be careful with restarting after deleting the 68bf215546Sopenharmony_ci * cf_node (see dead_cf_list()) so this is a convenient place to remove them. 69bf215546Sopenharmony_ci */ 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cistatic void 72bf215546Sopenharmony_ciremove_after_cf_node(nir_cf_node *node) 73bf215546Sopenharmony_ci{ 74bf215546Sopenharmony_ci nir_cf_node *end = node; 75bf215546Sopenharmony_ci while (!nir_cf_node_is_last(end)) 76bf215546Sopenharmony_ci end = nir_cf_node_next(end); 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci nir_cf_list list; 79bf215546Sopenharmony_ci nir_cf_extract(&list, nir_after_cf_node(node), nir_after_cf_node(end)); 80bf215546Sopenharmony_ci nir_cf_delete(&list); 81bf215546Sopenharmony_ci} 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_cistatic void 84bf215546Sopenharmony_ciopt_constant_if(nir_if *if_stmt, bool condition) 85bf215546Sopenharmony_ci{ 86bf215546Sopenharmony_ci /* First, we need to remove any phi nodes after the if by rewriting uses to 87bf215546Sopenharmony_ci * point to the correct source. 88bf215546Sopenharmony_ci */ 89bf215546Sopenharmony_ci nir_block *after = nir_cf_node_as_block(nir_cf_node_next(&if_stmt->cf_node)); 90bf215546Sopenharmony_ci nir_block *last_block = condition ? nir_if_last_then_block(if_stmt) 91bf215546Sopenharmony_ci : nir_if_last_else_block(if_stmt); 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, after) { 94bf215546Sopenharmony_ci if (instr->type != nir_instr_type_phi) 95bf215546Sopenharmony_ci break; 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci nir_phi_instr *phi = nir_instr_as_phi(instr); 98bf215546Sopenharmony_ci nir_ssa_def *def = NULL; 99bf215546Sopenharmony_ci nir_foreach_phi_src(phi_src, phi) { 100bf215546Sopenharmony_ci if (phi_src->pred != last_block) 101bf215546Sopenharmony_ci continue; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci assert(phi_src->src.is_ssa); 104bf215546Sopenharmony_ci def = phi_src->src.ssa; 105bf215546Sopenharmony_ci } 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_ci assert(def); 108bf215546Sopenharmony_ci assert(phi->dest.is_ssa); 109bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(&phi->dest.ssa, def); 110bf215546Sopenharmony_ci nir_instr_remove(instr); 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci /* The control flow list we're about to paste in may include a jump at the 114bf215546Sopenharmony_ci * end, and in that case we have to delete the rest of the control flow 115bf215546Sopenharmony_ci * list after the if since it's unreachable and the validator will balk if 116bf215546Sopenharmony_ci * we don't. 117bf215546Sopenharmony_ci */ 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci if (!exec_list_is_empty(&last_block->instr_list)) { 120bf215546Sopenharmony_ci nir_instr *last_instr = nir_block_last_instr(last_block); 121bf215546Sopenharmony_ci if (last_instr->type == nir_instr_type_jump) 122bf215546Sopenharmony_ci remove_after_cf_node(&if_stmt->cf_node); 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci /* Finally, actually paste in the then or else branch and delete the if. */ 126bf215546Sopenharmony_ci struct exec_list *cf_list = condition ? &if_stmt->then_list 127bf215546Sopenharmony_ci : &if_stmt->else_list; 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci nir_cf_list list; 130bf215546Sopenharmony_ci nir_cf_list_extract(&list, cf_list); 131bf215546Sopenharmony_ci nir_cf_reinsert(&list, nir_after_cf_node(&if_stmt->cf_node)); 132bf215546Sopenharmony_ci nir_cf_node_remove(&if_stmt->cf_node); 133bf215546Sopenharmony_ci} 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_cistatic bool 136bf215546Sopenharmony_cidef_only_used_in_cf_node(nir_ssa_def *def, void *_node) 137bf215546Sopenharmony_ci{ 138bf215546Sopenharmony_ci nir_cf_node *node = _node; 139bf215546Sopenharmony_ci assert(node->type == nir_cf_node_loop || node->type == nir_cf_node_if); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci nir_block *before = nir_cf_node_as_block(nir_cf_node_prev(node)); 142bf215546Sopenharmony_ci nir_block *after = nir_cf_node_as_block(nir_cf_node_next(node)); 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ci nir_foreach_use(use, def) { 145bf215546Sopenharmony_ci /* Because NIR is structured, we can easily determine whether or not a 146bf215546Sopenharmony_ci * value escapes a CF node by looking at the block indices of its uses 147bf215546Sopenharmony_ci * to see if they lie outside the bounds of the CF node. 148bf215546Sopenharmony_ci * 149bf215546Sopenharmony_ci * Note: Normally, the uses of a phi instruction are considered to be 150bf215546Sopenharmony_ci * used in the block that is the predecessor of the phi corresponding to 151bf215546Sopenharmony_ci * that use. If we were computing liveness or something similar, that 152bf215546Sopenharmony_ci * would mean a special case here for phis. However, we're trying here 153bf215546Sopenharmony_ci * to determine if the SSA def ever escapes the loop. If it's used by a 154bf215546Sopenharmony_ci * phi that lives outside the loop then it doesn't matter if the 155bf215546Sopenharmony_ci * corresponding predecessor is inside the loop or not because the value 156bf215546Sopenharmony_ci * can go through the phi into the outside world and escape the loop. 157bf215546Sopenharmony_ci */ 158bf215546Sopenharmony_ci if (use->parent_instr->block->index <= before->index || 159bf215546Sopenharmony_ci use->parent_instr->block->index >= after->index) 160bf215546Sopenharmony_ci return false; 161bf215546Sopenharmony_ci } 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci /* Same check for if-condition uses */ 164bf215546Sopenharmony_ci nir_foreach_if_use(use, def) { 165bf215546Sopenharmony_ci nir_block *use_block = 166bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_prev(&use->parent_if->cf_node)); 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci if (use_block->index <= before->index || 169bf215546Sopenharmony_ci use_block->index >= after->index) 170bf215546Sopenharmony_ci return false; 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci return true; 174bf215546Sopenharmony_ci} 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci/* 177bf215546Sopenharmony_ci * Test if a loop or if node is dead. Such nodes are dead if: 178bf215546Sopenharmony_ci * 179bf215546Sopenharmony_ci * 1) It has no side effects (i.e. intrinsics which could possibly affect the 180bf215546Sopenharmony_ci * state of the program aside from producing an SSA value, indicated by a lack 181bf215546Sopenharmony_ci * of NIR_INTRINSIC_CAN_ELIMINATE). 182bf215546Sopenharmony_ci * 183bf215546Sopenharmony_ci * 2) It has no phi instructions after it, since those indicate values inside 184bf215546Sopenharmony_ci * the node being used after the node. 185bf215546Sopenharmony_ci * 186bf215546Sopenharmony_ci * 3) None of the values defined inside the node is used outside the node, 187bf215546Sopenharmony_ci * i.e. none of the definitions that dominate the node exit are used outside. 188bf215546Sopenharmony_ci * 189bf215546Sopenharmony_ci * If those conditions hold, then the node is dead and can be deleted. 190bf215546Sopenharmony_ci */ 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_cistatic bool 193bf215546Sopenharmony_cinode_is_dead(nir_cf_node *node) 194bf215546Sopenharmony_ci{ 195bf215546Sopenharmony_ci assert(node->type == nir_cf_node_loop || node->type == nir_cf_node_if); 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci nir_block *after = nir_cf_node_as_block(nir_cf_node_next(node)); 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci /* Quick check if there are any phis that follow this CF node. If there 200bf215546Sopenharmony_ci * are, then we automatically know it isn't dead. 201bf215546Sopenharmony_ci */ 202bf215546Sopenharmony_ci if (!exec_list_is_empty(&after->instr_list) && 203bf215546Sopenharmony_ci nir_block_first_instr(after)->type == nir_instr_type_phi) 204bf215546Sopenharmony_ci return false; 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci nir_function_impl *impl = nir_cf_node_get_function(node); 207bf215546Sopenharmony_ci nir_metadata_require(impl, nir_metadata_block_index); 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci nir_foreach_block_in_cf_node(block, node) { 210bf215546Sopenharmony_ci bool inside_loop = node->type == nir_cf_node_loop; 211bf215546Sopenharmony_ci for (nir_cf_node *n = &block->cf_node; 212bf215546Sopenharmony_ci !inside_loop && n != node; n = n->parent) { 213bf215546Sopenharmony_ci if (n->type == nir_cf_node_loop) 214bf215546Sopenharmony_ci inside_loop = true; 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci nir_foreach_instr(instr, block) { 218bf215546Sopenharmony_ci if (instr->type == nir_instr_type_call) 219bf215546Sopenharmony_ci return false; 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_ci /* Return and halt instructions can cause us to skip over other 222bf215546Sopenharmony_ci * side-effecting instructions after the loop, so consider them to 223bf215546Sopenharmony_ci * have side effects here. 224bf215546Sopenharmony_ci * 225bf215546Sopenharmony_ci * When the block is not inside a loop, break and continue might also 226bf215546Sopenharmony_ci * cause a skip. 227bf215546Sopenharmony_ci */ 228bf215546Sopenharmony_ci if (instr->type == nir_instr_type_jump && 229bf215546Sopenharmony_ci (!inside_loop || 230bf215546Sopenharmony_ci nir_instr_as_jump(instr)->type == nir_jump_return || 231bf215546Sopenharmony_ci nir_instr_as_jump(instr)->type == nir_jump_halt)) 232bf215546Sopenharmony_ci return false; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci if (instr->type == nir_instr_type_intrinsic) { 235bf215546Sopenharmony_ci nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 236bf215546Sopenharmony_ci if (!(nir_intrinsic_infos[intrin->intrinsic].flags & 237bf215546Sopenharmony_ci NIR_INTRINSIC_CAN_ELIMINATE)) 238bf215546Sopenharmony_ci return false; 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci switch (intrin->intrinsic) { 241bf215546Sopenharmony_ci case nir_intrinsic_load_deref: 242bf215546Sopenharmony_ci case nir_intrinsic_load_ssbo: 243bf215546Sopenharmony_ci case nir_intrinsic_load_global: 244bf215546Sopenharmony_ci /* If there's a memory barrier after the loop, a load might be 245bf215546Sopenharmony_ci * required to happen before some other instruction after the 246bf215546Sopenharmony_ci * barrier, so it is not valid to eliminate it -- unless we 247bf215546Sopenharmony_ci * know we can reorder it. 248bf215546Sopenharmony_ci * 249bf215546Sopenharmony_ci * Consider only loads that the result can be affected by other 250bf215546Sopenharmony_ci * invocations. 251bf215546Sopenharmony_ci */ 252bf215546Sopenharmony_ci if (intrin->intrinsic == nir_intrinsic_load_deref) { 253bf215546Sopenharmony_ci nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); 254bf215546Sopenharmony_ci if (!nir_deref_mode_may_be(deref, nir_var_mem_ssbo | 255bf215546Sopenharmony_ci nir_var_mem_shared | 256bf215546Sopenharmony_ci nir_var_mem_global | 257bf215546Sopenharmony_ci nir_var_shader_out)) 258bf215546Sopenharmony_ci break; 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci if (nir_intrinsic_access(intrin) & ACCESS_CAN_REORDER) 261bf215546Sopenharmony_ci break; 262bf215546Sopenharmony_ci return false; 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci case nir_intrinsic_load_shared: 265bf215546Sopenharmony_ci case nir_intrinsic_load_shared2_amd: 266bf215546Sopenharmony_ci case nir_intrinsic_load_output: 267bf215546Sopenharmony_ci case nir_intrinsic_load_per_vertex_output: 268bf215546Sopenharmony_ci /* Same as above loads. */ 269bf215546Sopenharmony_ci return false; 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci default: 272bf215546Sopenharmony_ci /* Do nothing. */ 273bf215546Sopenharmony_ci break; 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci if (!nir_foreach_ssa_def(instr, def_only_used_in_cf_node, node)) 278bf215546Sopenharmony_ci return false; 279bf215546Sopenharmony_ci } 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci return true; 283bf215546Sopenharmony_ci} 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_cistatic bool 286bf215546Sopenharmony_cidead_cf_block(nir_block *block) 287bf215546Sopenharmony_ci{ 288bf215546Sopenharmony_ci nir_if *following_if = nir_block_get_following_if(block); 289bf215546Sopenharmony_ci if (following_if) { 290bf215546Sopenharmony_ci if (nir_src_is_const(following_if->condition)) { 291bf215546Sopenharmony_ci opt_constant_if(following_if, nir_src_as_bool(following_if->condition)); 292bf215546Sopenharmony_ci return true; 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci if (node_is_dead(&following_if->cf_node)) { 296bf215546Sopenharmony_ci nir_cf_node_remove(&following_if->cf_node); 297bf215546Sopenharmony_ci return true; 298bf215546Sopenharmony_ci } 299bf215546Sopenharmony_ci } 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci nir_loop *following_loop = nir_block_get_following_loop(block); 302bf215546Sopenharmony_ci if (!following_loop) 303bf215546Sopenharmony_ci return false; 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci if (!node_is_dead(&following_loop->cf_node)) 306bf215546Sopenharmony_ci return false; 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci nir_cf_node_remove(&following_loop->cf_node); 309bf215546Sopenharmony_ci return true; 310bf215546Sopenharmony_ci} 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_cistatic bool 313bf215546Sopenharmony_cidead_cf_list(struct exec_list *list, bool *list_ends_in_jump) 314bf215546Sopenharmony_ci{ 315bf215546Sopenharmony_ci bool progress = false; 316bf215546Sopenharmony_ci *list_ends_in_jump = false; 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci nir_cf_node *prev = NULL; 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, cur, node, list) { 321bf215546Sopenharmony_ci switch (cur->type) { 322bf215546Sopenharmony_ci case nir_cf_node_block: { 323bf215546Sopenharmony_ci nir_block *block = nir_cf_node_as_block(cur); 324bf215546Sopenharmony_ci if (dead_cf_block(block)) { 325bf215546Sopenharmony_ci /* We just deleted the if or loop after this block, so we may have 326bf215546Sopenharmony_ci * deleted the block before or after it -- which one is an 327bf215546Sopenharmony_ci * implementation detail. Therefore, to recover the place we were 328bf215546Sopenharmony_ci * at, we have to use the previous cf_node. 329bf215546Sopenharmony_ci */ 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci if (prev) { 332bf215546Sopenharmony_ci cur = nir_cf_node_next(prev); 333bf215546Sopenharmony_ci } else { 334bf215546Sopenharmony_ci cur = exec_node_data(nir_cf_node, exec_list_get_head(list), 335bf215546Sopenharmony_ci node); 336bf215546Sopenharmony_ci } 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci block = nir_cf_node_as_block(cur); 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci progress = true; 341bf215546Sopenharmony_ci } 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_ci if (nir_block_ends_in_jump(block)) { 344bf215546Sopenharmony_ci *list_ends_in_jump = true; 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci if (!exec_node_is_tail_sentinel(cur->node.next)) { 347bf215546Sopenharmony_ci remove_after_cf_node(cur); 348bf215546Sopenharmony_ci return true; 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci } 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_ci break; 353bf215546Sopenharmony_ci } 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci case nir_cf_node_if: { 356bf215546Sopenharmony_ci nir_if *if_stmt = nir_cf_node_as_if(cur); 357bf215546Sopenharmony_ci bool then_ends_in_jump, else_ends_in_jump; 358bf215546Sopenharmony_ci progress |= dead_cf_list(&if_stmt->then_list, &then_ends_in_jump); 359bf215546Sopenharmony_ci progress |= dead_cf_list(&if_stmt->else_list, &else_ends_in_jump); 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci if (then_ends_in_jump && else_ends_in_jump) { 362bf215546Sopenharmony_ci *list_ends_in_jump = true; 363bf215546Sopenharmony_ci nir_block *next = nir_cf_node_as_block(nir_cf_node_next(cur)); 364bf215546Sopenharmony_ci if (!exec_list_is_empty(&next->instr_list) || 365bf215546Sopenharmony_ci !exec_node_is_tail_sentinel(next->cf_node.node.next)) { 366bf215546Sopenharmony_ci remove_after_cf_node(cur); 367bf215546Sopenharmony_ci return true; 368bf215546Sopenharmony_ci } 369bf215546Sopenharmony_ci } 370bf215546Sopenharmony_ci 371bf215546Sopenharmony_ci break; 372bf215546Sopenharmony_ci } 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ci case nir_cf_node_loop: { 375bf215546Sopenharmony_ci nir_loop *loop = nir_cf_node_as_loop(cur); 376bf215546Sopenharmony_ci bool dummy; 377bf215546Sopenharmony_ci progress |= dead_cf_list(&loop->body, &dummy); 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_ci nir_block *next = nir_cf_node_as_block(nir_cf_node_next(cur)); 380bf215546Sopenharmony_ci if (next->predecessors->entries == 0 && 381bf215546Sopenharmony_ci (!exec_list_is_empty(&next->instr_list) || 382bf215546Sopenharmony_ci !exec_node_is_tail_sentinel(next->cf_node.node.next))) { 383bf215546Sopenharmony_ci remove_after_cf_node(cur); 384bf215546Sopenharmony_ci return true; 385bf215546Sopenharmony_ci } 386bf215546Sopenharmony_ci break; 387bf215546Sopenharmony_ci } 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci default: 390bf215546Sopenharmony_ci unreachable("unknown cf node type"); 391bf215546Sopenharmony_ci } 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci prev = cur; 394bf215546Sopenharmony_ci } 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci return progress; 397bf215546Sopenharmony_ci} 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_cistatic bool 400bf215546Sopenharmony_ciopt_dead_cf_impl(nir_function_impl *impl) 401bf215546Sopenharmony_ci{ 402bf215546Sopenharmony_ci bool dummy; 403bf215546Sopenharmony_ci bool progress = dead_cf_list(&impl->body, &dummy); 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_ci if (progress) { 406bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_none); 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci /* The CF manipulation code called by this pass is smart enough to keep 409bf215546Sopenharmony_ci * from breaking any SSA use/def chains by replacing any uses of removed 410bf215546Sopenharmony_ci * instructions with SSA undefs. However, it's not quite smart enough 411bf215546Sopenharmony_ci * to always preserve the dominance properties. In particular, if you 412bf215546Sopenharmony_ci * remove the one break from a loop, stuff in the loop may still be used 413bf215546Sopenharmony_ci * outside the loop even though there's no path between the two. We can 414bf215546Sopenharmony_ci * easily fix these issues by calling nir_repair_ssa which will ensure 415bf215546Sopenharmony_ci * that the dominance properties hold. 416bf215546Sopenharmony_ci */ 417bf215546Sopenharmony_ci nir_repair_ssa_impl(impl); 418bf215546Sopenharmony_ci } else { 419bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_all); 420bf215546Sopenharmony_ci } 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_ci return progress; 423bf215546Sopenharmony_ci} 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_cibool 426bf215546Sopenharmony_cinir_opt_dead_cf(nir_shader *shader) 427bf215546Sopenharmony_ci{ 428bf215546Sopenharmony_ci bool progress = false; 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_ci nir_foreach_function(function, shader) 431bf215546Sopenharmony_ci if (function->impl) 432bf215546Sopenharmony_ci progress |= opt_dead_cf_impl(function->impl); 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_ci return progress; 435bf215546Sopenharmony_ci} 436