1 /* 2 * Copyright 2015 Broadcom 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 #include "util/macros.h" 25 #include "nir.h" 26 #include "nir_builder.h" 27 28 /** @file nir_lower_load_const_to_scalar.c 29 * 30 * Replaces vector nir_load_const instructions with a series of loads and a 31 * vec[234] to reconstruct the original vector (on the assumption that 32 * nir_lower_alu_to_scalar() will then be used to split it up). 33 * 34 * This gives NIR a chance to CSE more operations on a scalar shader, when the 35 * same value was used in different vector contant loads. 36 */ 37 38 static bool 39 lower_load_const_instr_scalar(nir_load_const_instr *lower) 40 { 41 if (lower->def.num_components == 1) 42 return false; 43 44 nir_builder b; 45 nir_builder_init(&b, nir_cf_node_get_function(&lower->instr.block->cf_node)); 46 b.cursor = nir_before_instr(&lower->instr); 47 48 /* Emit the individual loads. */ 49 nir_ssa_def *loads[4]; 50 for (unsigned i = 0; i < lower->def.num_components; i++) { 51 nir_load_const_instr *load_comp = 52 nir_load_const_instr_create(b.shader, 1, lower->def.bit_size); 53 if (lower->def.bit_size == 64) 54 load_comp->value.f64[0] = lower->value.f64[i]; 55 else 56 load_comp->value.u32[0] = lower->value.u32[i]; 57 assert(lower->def.bit_size == 64 || lower->def.bit_size == 32); 58 nir_builder_instr_insert(&b, &load_comp->instr); 59 loads[i] = &load_comp->def; 60 } 61 62 /* Batch things back together into a vector. */ 63 nir_ssa_def *vec = nir_vec(&b, loads, lower->def.num_components); 64 65 /* Replace the old load with a reference to our reconstructed vector. */ 66 nir_ssa_def_rewrite_uses(&lower->def, nir_src_for_ssa(vec)); 67 nir_instr_remove(&lower->instr); 68 return true; 69 } 70 71 static bool 72 nir_lower_load_const_to_scalar_impl(nir_function_impl *impl) 73 { 74 bool progress = false; 75 76 nir_foreach_block(block, impl) { 77 nir_foreach_instr_safe(instr, block) { 78 if (instr->type == nir_instr_type_load_const) 79 progress |= 80 lower_load_const_instr_scalar(nir_instr_as_load_const(instr)); 81 } 82 } 83 84 if (progress) 85 nir_metadata_preserve(impl, nir_metadata_block_index | 86 nir_metadata_dominance); 87 88 return progress; 89 } 90 91 bool 92 nir_lower_load_const_to_scalar(nir_shader *shader) 93 { 94 bool progress = false; 95 96 nir_foreach_function(function, shader) { 97 if (function->impl) 98 progress |= nir_lower_load_const_to_scalar_impl(function->impl); 99 } 100 101 return progress; 102 } 103