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@jlekstrand.net) 25 * 26 */ 27 28#include "nir.h" 29#include "nir_builder.h" 30 31/* 32 * Implements "copy splitting" which is similar to structure splitting only 33 * it works on copy operations rather than the datatypes themselves. The 34 * GLSL language allows you to copy one variable to another an entire 35 * structure (which may contain arrays or other structures) at a time. 36 * Normally, in a language such as C this would be handled by a "structure 37 * splitting" pass that breaks up the structures. Unfortunately for us, 38 * structures used in inputs or outputs can't be split. Therefore, 39 * regardlesss of what we do, we have to be able to copy to/from 40 * structures. 41 * 42 * The primary purpose of structure splitting is to allow you to better 43 * optimize variable access and lower things to registers where you can. 44 * The primary issue here is that, if you lower the copy to a bunch of 45 * loads and stores, you loose a lot of information about the copy 46 * operation that you would like to keep around. To solve this problem, we 47 * have a "copy splitting" pass that, instead of splitting the structures 48 * or lowering the copy into loads and storres, splits the copy operation 49 * into a bunch of copy operations one for each leaf of the structure tree. 50 * If an intermediate array is encountered, it is referenced with a 51 * wildcard reference to indicate that the entire array is to be copied. 52 * 53 * As things become direct, array copies may be able to be losslessly 54 * lowered to having fewer and fewer wildcards. However, until that 55 * happens we want to keep the information about the arrays intact. 56 * 57 * Prior to the copy splitting pass, there are no wildcard references but 58 * there may be incomplete references where the tail of the deref chain is 59 * an array or a structure and not a specific element. After the copy 60 * splitting pass has completed, every variable deref will be a full-length 61 * dereference pointing to a single leaf in the structure type tree with 62 * possibly a few wildcard array dereferences. 63 */ 64 65static void 66split_deref_copy_instr(nir_builder *b, 67 nir_deref_instr *dst, nir_deref_instr *src, 68 enum gl_access_qualifier dst_access, 69 enum gl_access_qualifier src_access) 70{ 71 assert(glsl_get_bare_type(dst->type) == 72 glsl_get_bare_type(src->type)); 73 if (glsl_type_is_vector_or_scalar(src->type)) { 74 nir_copy_deref_with_access(b, dst, src, dst_access, src_access); 75 } else if (glsl_type_is_struct_or_ifc(src->type)) { 76 for (unsigned i = 0; i < glsl_get_length(src->type); i++) { 77 split_deref_copy_instr(b, nir_build_deref_struct(b, dst, i), 78 nir_build_deref_struct(b, src, i), 79 dst_access, src_access); 80 } 81 } else { 82 assert(glsl_type_is_matrix(src->type) || glsl_type_is_array(src->type)); 83 split_deref_copy_instr(b, nir_build_deref_array_wildcard(b, dst), 84 nir_build_deref_array_wildcard(b, src), 85 dst_access, src_access); 86 } 87} 88 89static bool 90split_var_copies_impl(nir_function_impl *impl) 91{ 92 bool progress = false; 93 94 nir_builder b; 95 nir_builder_init(&b, impl); 96 97 nir_foreach_block(block, impl) { 98 nir_foreach_instr_safe(instr, block) { 99 if (instr->type != nir_instr_type_intrinsic) 100 continue; 101 102 nir_intrinsic_instr *copy = nir_instr_as_intrinsic(instr); 103 if (copy->intrinsic != nir_intrinsic_copy_deref) 104 continue; 105 106 b.cursor = nir_instr_remove(©->instr); 107 108 nir_deref_instr *dst = 109 nir_instr_as_deref(copy->src[0].ssa->parent_instr); 110 nir_deref_instr *src = 111 nir_instr_as_deref(copy->src[1].ssa->parent_instr); 112 split_deref_copy_instr(&b, dst, src, 113 nir_intrinsic_dst_access(copy), 114 nir_intrinsic_src_access(copy)); 115 116 progress = true; 117 } 118 } 119 120 if (progress) { 121 nir_metadata_preserve(impl, nir_metadata_block_index | 122 nir_metadata_dominance); 123 } else { 124 nir_metadata_preserve(impl, nir_metadata_all); 125 } 126 127 return progress; 128} 129 130bool 131nir_split_var_copies(nir_shader *shader) 132{ 133 bool progress = false; 134 135 nir_foreach_function(function, shader) { 136 if (function->impl) 137 progress = split_var_copies_impl(function->impl) || progress; 138 } 139 140 return progress; 141} 142