1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2016 Intel Corporation 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21b8e80941Smrg * DEALINGS IN THE SOFTWARE. 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg#include "nir.h" 25b8e80941Smrg 26b8e80941Smrgstatic void 27b8e80941Smrgadd_src(nir_src *src, struct set *invariants) 28b8e80941Smrg{ 29b8e80941Smrg if (src->is_ssa) { 30b8e80941Smrg _mesa_set_add(invariants, src->ssa); 31b8e80941Smrg } else { 32b8e80941Smrg _mesa_set_add(invariants, src->reg.reg); 33b8e80941Smrg } 34b8e80941Smrg} 35b8e80941Smrg 36b8e80941Smrgstatic bool 37b8e80941Smrgadd_src_cb(nir_src *src, void *state) 38b8e80941Smrg{ 39b8e80941Smrg add_src(src, state); 40b8e80941Smrg return true; 41b8e80941Smrg} 42b8e80941Smrg 43b8e80941Smrgstatic bool 44b8e80941Smrgdest_is_invariant(nir_dest *dest, struct set *invariants) 45b8e80941Smrg{ 46b8e80941Smrg if (dest->is_ssa) { 47b8e80941Smrg return _mesa_set_search(invariants, &dest->ssa); 48b8e80941Smrg } else { 49b8e80941Smrg return _mesa_set_search(invariants, dest->reg.reg); 50b8e80941Smrg } 51b8e80941Smrg} 52b8e80941Smrg 53b8e80941Smrgstatic void 54b8e80941Smrgadd_cf_node(nir_cf_node *cf, struct set *invariants) 55b8e80941Smrg{ 56b8e80941Smrg if (cf->type == nir_cf_node_if) { 57b8e80941Smrg nir_if *if_stmt = nir_cf_node_as_if(cf); 58b8e80941Smrg add_src(&if_stmt->condition, invariants); 59b8e80941Smrg } 60b8e80941Smrg 61b8e80941Smrg if (cf->parent) 62b8e80941Smrg add_cf_node(cf->parent, invariants); 63b8e80941Smrg} 64b8e80941Smrg 65b8e80941Smrgstatic void 66b8e80941Smrgadd_var(nir_variable *var, struct set *invariants) 67b8e80941Smrg{ 68b8e80941Smrg /* Because we pass the result of nir_intrinsic_get_var directly to this 69b8e80941Smrg * function, it's possible for var to be NULL if, for instance, there's a 70b8e80941Smrg * cast somewhere in the chain. 71b8e80941Smrg */ 72b8e80941Smrg if (var != NULL) 73b8e80941Smrg _mesa_set_add(invariants, var); 74b8e80941Smrg} 75b8e80941Smrg 76b8e80941Smrgstatic bool 77b8e80941Smrgvar_is_invariant(nir_variable *var, struct set * invariants) 78b8e80941Smrg{ 79b8e80941Smrg /* Because we pass the result of nir_intrinsic_get_var directly to this 80b8e80941Smrg * function, it's possible for var to be NULL if, for instance, there's a 81b8e80941Smrg * cast somewhere in the chain. 82b8e80941Smrg */ 83b8e80941Smrg return var && (var->data.invariant || _mesa_set_search(invariants, var)); 84b8e80941Smrg} 85b8e80941Smrg 86b8e80941Smrgstatic void 87b8e80941Smrgpropagate_invariant_instr(nir_instr *instr, struct set *invariants) 88b8e80941Smrg{ 89b8e80941Smrg switch (instr->type) { 90b8e80941Smrg case nir_instr_type_alu: { 91b8e80941Smrg nir_alu_instr *alu = nir_instr_as_alu(instr); 92b8e80941Smrg if (!dest_is_invariant(&alu->dest.dest, invariants)) 93b8e80941Smrg break; 94b8e80941Smrg 95b8e80941Smrg alu->exact = true; 96b8e80941Smrg nir_foreach_src(instr, add_src_cb, invariants); 97b8e80941Smrg break; 98b8e80941Smrg } 99b8e80941Smrg 100b8e80941Smrg case nir_instr_type_tex: { 101b8e80941Smrg nir_tex_instr *tex = nir_instr_as_tex(instr); 102b8e80941Smrg if (dest_is_invariant(&tex->dest, invariants)) 103b8e80941Smrg nir_foreach_src(instr, add_src_cb, invariants); 104b8e80941Smrg break; 105b8e80941Smrg } 106b8e80941Smrg 107b8e80941Smrg case nir_instr_type_intrinsic: { 108b8e80941Smrg nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 109b8e80941Smrg switch (intrin->intrinsic) { 110b8e80941Smrg case nir_intrinsic_copy_deref: 111b8e80941Smrg /* If the destination is invariant then so is the source */ 112b8e80941Smrg if (var_is_invariant(nir_intrinsic_get_var(intrin, 0), invariants)) 113b8e80941Smrg add_var(nir_intrinsic_get_var(intrin, 1), invariants); 114b8e80941Smrg break; 115b8e80941Smrg 116b8e80941Smrg case nir_intrinsic_load_deref: 117b8e80941Smrg if (dest_is_invariant(&intrin->dest, invariants)) 118b8e80941Smrg add_var(nir_intrinsic_get_var(intrin, 0), invariants); 119b8e80941Smrg break; 120b8e80941Smrg 121b8e80941Smrg case nir_intrinsic_store_deref: 122b8e80941Smrg if (var_is_invariant(nir_intrinsic_get_var(intrin, 0), invariants)) 123b8e80941Smrg add_src(&intrin->src[1], invariants); 124b8e80941Smrg break; 125b8e80941Smrg 126b8e80941Smrg default: 127b8e80941Smrg /* Nothing to do */ 128b8e80941Smrg break; 129b8e80941Smrg } 130b8e80941Smrg } 131b8e80941Smrg 132b8e80941Smrg case nir_instr_type_deref: 133b8e80941Smrg case nir_instr_type_jump: 134b8e80941Smrg case nir_instr_type_ssa_undef: 135b8e80941Smrg case nir_instr_type_load_const: 136b8e80941Smrg break; /* Nothing to do */ 137b8e80941Smrg 138b8e80941Smrg case nir_instr_type_phi: { 139b8e80941Smrg nir_phi_instr *phi = nir_instr_as_phi(instr); 140b8e80941Smrg if (!dest_is_invariant(&phi->dest, invariants)) 141b8e80941Smrg break; 142b8e80941Smrg 143b8e80941Smrg nir_foreach_phi_src(src, phi) { 144b8e80941Smrg add_src(&src->src, invariants); 145b8e80941Smrg add_cf_node(&src->pred->cf_node, invariants); 146b8e80941Smrg } 147b8e80941Smrg break; 148b8e80941Smrg } 149b8e80941Smrg 150b8e80941Smrg case nir_instr_type_call: 151b8e80941Smrg unreachable("This pass must be run after function inlining"); 152b8e80941Smrg 153b8e80941Smrg case nir_instr_type_parallel_copy: 154b8e80941Smrg default: 155b8e80941Smrg unreachable("Cannot have this instruction type"); 156b8e80941Smrg } 157b8e80941Smrg} 158b8e80941Smrg 159b8e80941Smrgstatic bool 160b8e80941Smrgpropagate_invariant_impl(nir_function_impl *impl, struct set *invariants) 161b8e80941Smrg{ 162b8e80941Smrg bool progress = false; 163b8e80941Smrg 164b8e80941Smrg while (true) { 165b8e80941Smrg uint32_t prev_entries = invariants->entries; 166b8e80941Smrg 167b8e80941Smrg nir_foreach_block_reverse(block, impl) { 168b8e80941Smrg nir_foreach_instr_reverse(instr, block) 169b8e80941Smrg propagate_invariant_instr(instr, invariants); 170b8e80941Smrg } 171b8e80941Smrg 172b8e80941Smrg /* Keep running until we make no more progress. */ 173b8e80941Smrg if (invariants->entries > prev_entries) { 174b8e80941Smrg progress = true; 175b8e80941Smrg continue; 176b8e80941Smrg } else { 177b8e80941Smrg break; 178b8e80941Smrg } 179b8e80941Smrg } 180b8e80941Smrg 181b8e80941Smrg if (progress) { 182b8e80941Smrg nir_metadata_preserve(impl, nir_metadata_block_index | 183b8e80941Smrg nir_metadata_dominance | 184b8e80941Smrg nir_metadata_live_ssa_defs); 185b8e80941Smrg } 186b8e80941Smrg 187b8e80941Smrg return progress; 188b8e80941Smrg} 189b8e80941Smrg 190b8e80941Smrgbool 191b8e80941Smrgnir_propagate_invariant(nir_shader *shader) 192b8e80941Smrg{ 193b8e80941Smrg /* Hash set of invariant things */ 194b8e80941Smrg struct set *invariants = _mesa_pointer_set_create(NULL); 195b8e80941Smrg 196b8e80941Smrg bool progress = false; 197b8e80941Smrg nir_foreach_function(function, shader) { 198b8e80941Smrg if (function->impl && propagate_invariant_impl(function->impl, invariants)) 199b8e80941Smrg progress = true; 200b8e80941Smrg } 201b8e80941Smrg 202b8e80941Smrg _mesa_set_destroy(invariants, NULL); 203b8e80941Smrg 204b8e80941Smrg return progress; 205b8e80941Smrg} 206