1 /* 2 * Copyright 2014 Intel Corporation 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 * Authors: 24 * Jason Ekstrand (jason (at) jlekstrand.net) 25 * 26 */ 27 28 /* 29 * This lowering pass detects when a global variable is only being used by 30 * one function and makes it local to that function 31 */ 32 33 #include "nir.h" 34 35 static bool 36 mark_global_var_uses_block(nir_block *block, nir_function_impl *impl, 37 struct hash_table *var_func_table) 38 { 39 nir_foreach_instr(instr, block) { 40 if (instr->type != nir_instr_type_intrinsic) 41 continue; 42 43 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 44 unsigned num_vars = nir_intrinsic_infos[intrin->intrinsic].num_variables; 45 46 for (unsigned i = 0; i < num_vars; i++) { 47 nir_variable *var = intrin->variables[i]->var; 48 if (var->data.mode != nir_var_global) 49 continue; 50 51 struct hash_entry *entry = 52 _mesa_hash_table_search(var_func_table, var); 53 54 if (entry) { 55 if (entry->data != impl) 56 entry->data = NULL; 57 } else { 58 _mesa_hash_table_insert(var_func_table, var, impl); 59 } 60 } 61 } 62 63 return true; 64 } 65 66 bool 67 nir_lower_global_vars_to_local(nir_shader *shader) 68 { 69 bool progress = false; 70 71 /* A hash table keyed on variable pointers that stores the unique 72 * nir_function_impl that uses the given variable. If a variable is 73 * used in multiple functions, the data for the given key will be NULL. 74 */ 75 struct hash_table *var_func_table = 76 _mesa_hash_table_create(NULL, _mesa_hash_pointer, 77 _mesa_key_pointer_equal); 78 79 nir_foreach_function(function, shader) { 80 if (function->impl) { 81 nir_foreach_block(block, function->impl) 82 mark_global_var_uses_block(block, function->impl, var_func_table); 83 } 84 } 85 86 struct hash_entry *entry; 87 hash_table_foreach(var_func_table, entry) { 88 nir_variable *var = (void *)entry->key; 89 nir_function_impl *impl = entry->data; 90 91 assert(var->data.mode == nir_var_global); 92 93 if (impl != NULL) { 94 exec_node_remove(&var->node); 95 var->data.mode = nir_var_local; 96 exec_list_push_tail(&impl->locals, &var->node); 97 nir_metadata_preserve(impl, nir_metadata_block_index | 98 nir_metadata_dominance | 99 nir_metadata_live_ssa_defs); 100 progress = true; 101 } 102 } 103 104 _mesa_hash_table_destroy(var_func_table, NULL); 105 106 return progress; 107 } 108