1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2015 Thomas Helland 3bf215546Sopenharmony_ci * Copyright © 2019 Valve Corporation 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci * Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22bf215546Sopenharmony_ci * IN THE SOFTWARE. 23bf215546Sopenharmony_ci */ 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci/* 26bf215546Sopenharmony_ci * This pass converts the ssa-graph into "Loop Closed SSA form". This is 27bf215546Sopenharmony_ci * done by placing phi nodes at the exits of the loop for all values 28bf215546Sopenharmony_ci * that are used outside the loop. The result is it transforms: 29bf215546Sopenharmony_ci * 30bf215546Sopenharmony_ci * loop { -> loop { 31bf215546Sopenharmony_ci * ssa2 = .... -> ssa2 = ... 32bf215546Sopenharmony_ci * if (cond) -> if (cond) 33bf215546Sopenharmony_ci * break; -> break; 34bf215546Sopenharmony_ci * ssa3 = ssa2 * ssa4 -> ssa3 = ssa2 * ssa4 35bf215546Sopenharmony_ci * } -> } 36bf215546Sopenharmony_ci * ssa6 = ssa2 + 4 -> ssa5 = phi(ssa2) 37bf215546Sopenharmony_ci * ssa6 = ssa5 + 4 38bf215546Sopenharmony_ci */ 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "nir.h" 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_citypedef struct { 43bf215546Sopenharmony_ci /* The nir_shader we are transforming */ 44bf215546Sopenharmony_ci nir_shader *shader; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci /* The loop we store information for */ 47bf215546Sopenharmony_ci nir_loop *loop; 48bf215546Sopenharmony_ci nir_block *block_after_loop; 49bf215546Sopenharmony_ci nir_block **exit_blocks; 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci /* Whether to skip loop invariant variables */ 52bf215546Sopenharmony_ci bool skip_invariants; 53bf215546Sopenharmony_ci bool skip_bool_invariants; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci bool progress; 56bf215546Sopenharmony_ci} lcssa_state; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_cistatic bool 59bf215546Sopenharmony_ciis_if_use_inside_loop(nir_src *use, nir_loop *loop) 60bf215546Sopenharmony_ci{ 61bf215546Sopenharmony_ci nir_block *block_before_loop = 62bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node)); 63bf215546Sopenharmony_ci nir_block *block_after_loop = 64bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node)); 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci nir_block *prev_block = 67bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_prev(&use->parent_if->cf_node)); 68bf215546Sopenharmony_ci if (prev_block->index <= block_before_loop->index || 69bf215546Sopenharmony_ci prev_block->index >= block_after_loop->index) { 70bf215546Sopenharmony_ci return false; 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci return true; 74bf215546Sopenharmony_ci} 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_cistatic bool 77bf215546Sopenharmony_ciis_use_inside_loop(nir_src *use, nir_loop *loop) 78bf215546Sopenharmony_ci{ 79bf215546Sopenharmony_ci nir_block *block_before_loop = 80bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node)); 81bf215546Sopenharmony_ci nir_block *block_after_loop = 82bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node)); 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci if (use->parent_instr->block->index <= block_before_loop->index || 85bf215546Sopenharmony_ci use->parent_instr->block->index >= block_after_loop->index) { 86bf215546Sopenharmony_ci return false; 87bf215546Sopenharmony_ci } 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci return true; 90bf215546Sopenharmony_ci} 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_cistatic bool 93bf215546Sopenharmony_ciis_defined_before_loop(nir_ssa_def *def, nir_loop *loop) 94bf215546Sopenharmony_ci{ 95bf215546Sopenharmony_ci nir_instr *instr = def->parent_instr; 96bf215546Sopenharmony_ci nir_block *block_before_loop = 97bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node)); 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci return instr->block->index <= block_before_loop->index; 100bf215546Sopenharmony_ci} 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_citypedef enum instr_invariance { 103bf215546Sopenharmony_ci undefined = 0, 104bf215546Sopenharmony_ci invariant, 105bf215546Sopenharmony_ci not_invariant, 106bf215546Sopenharmony_ci} instr_invariance; 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_cistatic instr_invariance 109bf215546Sopenharmony_ciinstr_is_invariant(nir_instr *instr, nir_loop *loop); 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_cistatic bool 112bf215546Sopenharmony_cidef_is_invariant(nir_ssa_def *def, nir_loop *loop) 113bf215546Sopenharmony_ci{ 114bf215546Sopenharmony_ci if (is_defined_before_loop(def, loop)) 115bf215546Sopenharmony_ci return invariant; 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci if (def->parent_instr->pass_flags == undefined) 118bf215546Sopenharmony_ci def->parent_instr->pass_flags = instr_is_invariant(def->parent_instr, loop); 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci return def->parent_instr->pass_flags == invariant; 121bf215546Sopenharmony_ci} 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_cistatic bool 124bf215546Sopenharmony_cisrc_is_invariant(nir_src *src, void *state) 125bf215546Sopenharmony_ci{ 126bf215546Sopenharmony_ci assert(src->is_ssa); 127bf215546Sopenharmony_ci return def_is_invariant(src->ssa, (nir_loop *)state); 128bf215546Sopenharmony_ci} 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_cistatic instr_invariance 131bf215546Sopenharmony_ciphi_is_invariant(nir_phi_instr *instr, nir_loop *loop) 132bf215546Sopenharmony_ci{ 133bf215546Sopenharmony_ci /* Base case: it's a phi at the loop header 134bf215546Sopenharmony_ci * Loop-header phis are updated in each loop iteration with 135bf215546Sopenharmony_ci * the loop-carried value, and thus control-flow dependent 136bf215546Sopenharmony_ci * on the loop itself. 137bf215546Sopenharmony_ci */ 138bf215546Sopenharmony_ci if (instr->instr.block == nir_loop_first_block(loop)) 139bf215546Sopenharmony_ci return not_invariant; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci nir_foreach_phi_src(src, instr) { 142bf215546Sopenharmony_ci if (!src_is_invariant(&src->src, loop)) 143bf215546Sopenharmony_ci return not_invariant; 144bf215546Sopenharmony_ci } 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci /* All loop header- and LCSSA-phis should be handled by this point. */ 147bf215546Sopenharmony_ci nir_cf_node *prev = nir_cf_node_prev(&instr->instr.block->cf_node); 148bf215546Sopenharmony_ci assert(prev && prev->type == nir_cf_node_if); 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci /* Invariance of phis after if-nodes also depends on the invariance 151bf215546Sopenharmony_ci * of the branch condition. 152bf215546Sopenharmony_ci */ 153bf215546Sopenharmony_ci nir_if *if_node = nir_cf_node_as_if(prev); 154bf215546Sopenharmony_ci if (!def_is_invariant(if_node->condition.ssa, loop)) 155bf215546Sopenharmony_ci return not_invariant; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci return invariant; 158bf215546Sopenharmony_ci} 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci/* An instruction is said to be loop-invariant if it 162bf215546Sopenharmony_ci * - has no sideeffects and 163bf215546Sopenharmony_ci * - solely depends on variables defined outside of the loop or 164bf215546Sopenharmony_ci * by other invariant instructions 165bf215546Sopenharmony_ci */ 166bf215546Sopenharmony_cistatic instr_invariance 167bf215546Sopenharmony_ciinstr_is_invariant(nir_instr *instr, nir_loop *loop) 168bf215546Sopenharmony_ci{ 169bf215546Sopenharmony_ci assert(instr->pass_flags == undefined); 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci switch (instr->type) { 172bf215546Sopenharmony_ci case nir_instr_type_load_const: 173bf215546Sopenharmony_ci case nir_instr_type_ssa_undef: 174bf215546Sopenharmony_ci return invariant; 175bf215546Sopenharmony_ci case nir_instr_type_call: 176bf215546Sopenharmony_ci return not_invariant; 177bf215546Sopenharmony_ci case nir_instr_type_phi: 178bf215546Sopenharmony_ci return phi_is_invariant(nir_instr_as_phi(instr), loop); 179bf215546Sopenharmony_ci case nir_instr_type_intrinsic: { 180bf215546Sopenharmony_ci nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr); 181bf215546Sopenharmony_ci if (!(nir_intrinsic_infos[intrinsic->intrinsic].flags & NIR_INTRINSIC_CAN_REORDER)) 182bf215546Sopenharmony_ci return not_invariant; 183bf215546Sopenharmony_ci } 184bf215546Sopenharmony_ci FALLTHROUGH; 185bf215546Sopenharmony_ci default: 186bf215546Sopenharmony_ci return nir_foreach_src(instr, src_is_invariant, loop) ? invariant : not_invariant; 187bf215546Sopenharmony_ci } 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci return invariant; 190bf215546Sopenharmony_ci} 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_cistatic bool 193bf215546Sopenharmony_ciconvert_loop_exit_for_ssa(nir_ssa_def *def, void *void_state) 194bf215546Sopenharmony_ci{ 195bf215546Sopenharmony_ci lcssa_state *state = void_state; 196bf215546Sopenharmony_ci bool all_uses_inside_loop = true; 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci /* Don't create LCSSA-Phis for loop-invariant variables */ 199bf215546Sopenharmony_ci if (state->skip_invariants && 200bf215546Sopenharmony_ci (def->bit_size != 1 || state->skip_bool_invariants)) { 201bf215546Sopenharmony_ci assert(def->parent_instr->pass_flags != undefined); 202bf215546Sopenharmony_ci if (def->parent_instr->pass_flags == invariant) 203bf215546Sopenharmony_ci return true; 204bf215546Sopenharmony_ci } 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci nir_foreach_use(use, def) { 207bf215546Sopenharmony_ci if (use->parent_instr->type == nir_instr_type_phi && 208bf215546Sopenharmony_ci use->parent_instr->block == state->block_after_loop) { 209bf215546Sopenharmony_ci continue; 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci if (!is_use_inside_loop(use, state->loop)) { 213bf215546Sopenharmony_ci all_uses_inside_loop = false; 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci nir_foreach_if_use(use, def) { 218bf215546Sopenharmony_ci if (!is_if_use_inside_loop(use, state->loop)) { 219bf215546Sopenharmony_ci all_uses_inside_loop = false; 220bf215546Sopenharmony_ci } 221bf215546Sopenharmony_ci } 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /* There where no sources that had defs outside the loop */ 224bf215546Sopenharmony_ci if (all_uses_inside_loop) 225bf215546Sopenharmony_ci return true; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci /* Initialize a phi-instruction */ 228bf215546Sopenharmony_ci nir_phi_instr *phi = nir_phi_instr_create(state->shader); 229bf215546Sopenharmony_ci nir_ssa_dest_init(&phi->instr, &phi->dest, 230bf215546Sopenharmony_ci def->num_components, def->bit_size, "LCSSA-phi"); 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci /* Create a phi node with as many sources pointing to the same ssa_def as 233bf215546Sopenharmony_ci * the block has predecessors. 234bf215546Sopenharmony_ci */ 235bf215546Sopenharmony_ci uint32_t num_exits = state->block_after_loop->predecessors->entries; 236bf215546Sopenharmony_ci for (uint32_t i = 0; i < num_exits; i++) { 237bf215546Sopenharmony_ci nir_phi_instr_add_src(phi, state->exit_blocks[i], nir_src_for_ssa(def)); 238bf215546Sopenharmony_ci } 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci nir_instr_insert_before_block(state->block_after_loop, &phi->instr); 241bf215546Sopenharmony_ci nir_ssa_def *dest = &phi->dest.ssa; 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci /* deref instructions need a cast after the phi */ 244bf215546Sopenharmony_ci if (def->parent_instr->type == nir_instr_type_deref) { 245bf215546Sopenharmony_ci nir_deref_instr *cast = 246bf215546Sopenharmony_ci nir_deref_instr_create(state->shader, nir_deref_type_cast); 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci nir_deref_instr *instr = nir_instr_as_deref(def->parent_instr); 249bf215546Sopenharmony_ci cast->modes = instr->modes; 250bf215546Sopenharmony_ci cast->type = instr->type; 251bf215546Sopenharmony_ci cast->parent = nir_src_for_ssa(&phi->dest.ssa); 252bf215546Sopenharmony_ci cast->cast.ptr_stride = nir_deref_instr_array_stride(instr); 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci nir_ssa_dest_init(&cast->instr, &cast->dest, 255bf215546Sopenharmony_ci phi->dest.ssa.num_components, 256bf215546Sopenharmony_ci phi->dest.ssa.bit_size, NULL); 257bf215546Sopenharmony_ci nir_instr_insert(nir_after_phis(state->block_after_loop), &cast->instr); 258bf215546Sopenharmony_ci dest = &cast->dest.ssa; 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci /* Run through all uses and rewrite those outside the loop to point to 262bf215546Sopenharmony_ci * the phi instead of pointing to the ssa-def. 263bf215546Sopenharmony_ci */ 264bf215546Sopenharmony_ci nir_foreach_use_safe(use, def) { 265bf215546Sopenharmony_ci if (use->parent_instr->type == nir_instr_type_phi && 266bf215546Sopenharmony_ci state->block_after_loop == use->parent_instr->block) { 267bf215546Sopenharmony_ci continue; 268bf215546Sopenharmony_ci } 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_ci if (!is_use_inside_loop(use, state->loop)) { 271bf215546Sopenharmony_ci nir_instr_rewrite_src(use->parent_instr, use, nir_src_for_ssa(dest)); 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci } 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci nir_foreach_if_use_safe(use, def) { 276bf215546Sopenharmony_ci if (!is_if_use_inside_loop(use, state->loop)) { 277bf215546Sopenharmony_ci nir_if_rewrite_condition(use->parent_if, nir_src_for_ssa(dest)); 278bf215546Sopenharmony_ci } 279bf215546Sopenharmony_ci } 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci state->progress = true; 282bf215546Sopenharmony_ci return true; 283bf215546Sopenharmony_ci} 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_cistatic void 286bf215546Sopenharmony_cisetup_loop_state(lcssa_state *state, nir_loop *loop) 287bf215546Sopenharmony_ci{ 288bf215546Sopenharmony_ci state->loop = loop; 289bf215546Sopenharmony_ci state->block_after_loop = 290bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node)); 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci ralloc_free(state->exit_blocks); 293bf215546Sopenharmony_ci state->exit_blocks = nir_block_get_predecessors_sorted(state->block_after_loop, state); 294bf215546Sopenharmony_ci} 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_cistatic void 297bf215546Sopenharmony_ciconvert_to_lcssa(nir_cf_node *cf_node, lcssa_state *state) 298bf215546Sopenharmony_ci{ 299bf215546Sopenharmony_ci switch (cf_node->type) { 300bf215546Sopenharmony_ci case nir_cf_node_block: 301bf215546Sopenharmony_ci return; 302bf215546Sopenharmony_ci case nir_cf_node_if: { 303bf215546Sopenharmony_ci nir_if *if_stmt = nir_cf_node_as_if(cf_node); 304bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, nested_node, node, &if_stmt->then_list) 305bf215546Sopenharmony_ci convert_to_lcssa(nested_node, state); 306bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, nested_node, node, &if_stmt->else_list) 307bf215546Sopenharmony_ci convert_to_lcssa(nested_node, state); 308bf215546Sopenharmony_ci return; 309bf215546Sopenharmony_ci } 310bf215546Sopenharmony_ci case nir_cf_node_loop: { 311bf215546Sopenharmony_ci if (state->skip_invariants) { 312bf215546Sopenharmony_ci nir_foreach_block_in_cf_node(block, cf_node) { 313bf215546Sopenharmony_ci nir_foreach_instr(instr, block) 314bf215546Sopenharmony_ci instr->pass_flags = undefined; 315bf215546Sopenharmony_ci } 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci /* first, convert inner loops */ 319bf215546Sopenharmony_ci nir_loop *loop = nir_cf_node_as_loop(cf_node); 320bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, nested_node, node, &loop->body) 321bf215546Sopenharmony_ci convert_to_lcssa(nested_node, state); 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci setup_loop_state(state, loop); 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_ci /* mark loop-invariant instructions */ 326bf215546Sopenharmony_ci if (state->skip_invariants) { 327bf215546Sopenharmony_ci /* Without a loop all instructions are invariant. 328bf215546Sopenharmony_ci * For outer loops, multiple breaks can still create phis. 329bf215546Sopenharmony_ci * The variance then depends on all (nested) break conditions. 330bf215546Sopenharmony_ci * We don't consider this, but assume all not_invariant. 331bf215546Sopenharmony_ci */ 332bf215546Sopenharmony_ci if (nir_loop_first_block(loop)->predecessors->entries == 1) 333bf215546Sopenharmony_ci goto end; 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci nir_foreach_block_in_cf_node(block, cf_node) { 336bf215546Sopenharmony_ci nir_foreach_instr(instr, block) { 337bf215546Sopenharmony_ci if (instr->pass_flags == undefined) 338bf215546Sopenharmony_ci instr->pass_flags = instr_is_invariant(instr, nir_cf_node_as_loop(cf_node)); 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci } 341bf215546Sopenharmony_ci } 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_ci nir_foreach_block_in_cf_node(block, cf_node) { 344bf215546Sopenharmony_ci nir_foreach_instr(instr, block) { 345bf215546Sopenharmony_ci nir_foreach_ssa_def(instr, convert_loop_exit_for_ssa, state); 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci /* for outer loops, invariant instructions can be variant */ 348bf215546Sopenharmony_ci if (state->skip_invariants && instr->pass_flags == invariant) 349bf215546Sopenharmony_ci instr->pass_flags = undefined; 350bf215546Sopenharmony_ci } 351bf215546Sopenharmony_ci } 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ciend: 354bf215546Sopenharmony_ci /* For outer loops, the LCSSA-phi should be considered not invariant */ 355bf215546Sopenharmony_ci if (state->skip_invariants) { 356bf215546Sopenharmony_ci nir_foreach_instr(instr, state->block_after_loop) { 357bf215546Sopenharmony_ci if (instr->type == nir_instr_type_phi) 358bf215546Sopenharmony_ci instr->pass_flags = not_invariant; 359bf215546Sopenharmony_ci else 360bf215546Sopenharmony_ci break; 361bf215546Sopenharmony_ci } 362bf215546Sopenharmony_ci } 363bf215546Sopenharmony_ci return; 364bf215546Sopenharmony_ci } 365bf215546Sopenharmony_ci default: 366bf215546Sopenharmony_ci unreachable("unknown cf node type"); 367bf215546Sopenharmony_ci } 368bf215546Sopenharmony_ci} 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_civoid 371bf215546Sopenharmony_cinir_convert_loop_to_lcssa(nir_loop *loop) 372bf215546Sopenharmony_ci{ 373bf215546Sopenharmony_ci nir_function_impl *impl = nir_cf_node_get_function(&loop->cf_node); 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci nir_metadata_require(impl, nir_metadata_block_index); 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci lcssa_state *state = rzalloc(NULL, lcssa_state); 378bf215546Sopenharmony_ci setup_loop_state(state, loop); 379bf215546Sopenharmony_ci state->shader = impl->function->shader; 380bf215546Sopenharmony_ci state->skip_invariants = false; 381bf215546Sopenharmony_ci state->skip_bool_invariants = false; 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci nir_foreach_block_in_cf_node (block, &loop->cf_node) { 384bf215546Sopenharmony_ci nir_foreach_instr(instr, block) 385bf215546Sopenharmony_ci nir_foreach_ssa_def(instr, convert_loop_exit_for_ssa, state); 386bf215546Sopenharmony_ci } 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci ralloc_free(state); 389bf215546Sopenharmony_ci} 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_cibool 392bf215546Sopenharmony_cinir_convert_to_lcssa(nir_shader *shader, bool skip_invariants, bool skip_bool_invariants) 393bf215546Sopenharmony_ci{ 394bf215546Sopenharmony_ci bool progress = false; 395bf215546Sopenharmony_ci lcssa_state *state = rzalloc(NULL, lcssa_state); 396bf215546Sopenharmony_ci state->shader = shader; 397bf215546Sopenharmony_ci state->skip_invariants = skip_invariants; 398bf215546Sopenharmony_ci state->skip_bool_invariants = skip_bool_invariants; 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 401bf215546Sopenharmony_ci if (function->impl == NULL) 402bf215546Sopenharmony_ci continue; 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci state->progress = false; 405bf215546Sopenharmony_ci nir_metadata_require(function->impl, nir_metadata_block_index); 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, node, node, &function->impl->body) 408bf215546Sopenharmony_ci convert_to_lcssa(node, state); 409bf215546Sopenharmony_ci 410bf215546Sopenharmony_ci if (state->progress) { 411bf215546Sopenharmony_ci progress = true; 412bf215546Sopenharmony_ci nir_metadata_preserve(function->impl, nir_metadata_block_index | 413bf215546Sopenharmony_ci nir_metadata_dominance); 414bf215546Sopenharmony_ci } else { 415bf215546Sopenharmony_ci nir_metadata_preserve(function->impl, nir_metadata_all); 416bf215546Sopenharmony_ci } 417bf215546Sopenharmony_ci } 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci ralloc_free(state); 420bf215546Sopenharmony_ci return progress; 421bf215546Sopenharmony_ci} 422bf215546Sopenharmony_ci 423