1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Jason Ekstrand (jason@jlekstrand.net) 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "nir.h" 29bf215546Sopenharmony_ci#include "nir_builder.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci/* 32bf215546Sopenharmony_ci * Implements "copy splitting" which is similar to structure splitting only 33bf215546Sopenharmony_ci * it works on copy operations rather than the datatypes themselves. The 34bf215546Sopenharmony_ci * GLSL language allows you to copy one variable to another an entire 35bf215546Sopenharmony_ci * structure (which may contain arrays or other structures) at a time. 36bf215546Sopenharmony_ci * Normally, in a language such as C this would be handled by a "structure 37bf215546Sopenharmony_ci * splitting" pass that breaks up the structures. Unfortunately for us, 38bf215546Sopenharmony_ci * structures used in inputs or outputs can't be split. Therefore, 39bf215546Sopenharmony_ci * regardlesss of what we do, we have to be able to copy to/from 40bf215546Sopenharmony_ci * structures. 41bf215546Sopenharmony_ci * 42bf215546Sopenharmony_ci * The primary purpose of structure splitting is to allow you to better 43bf215546Sopenharmony_ci * optimize variable access and lower things to registers where you can. 44bf215546Sopenharmony_ci * The primary issue here is that, if you lower the copy to a bunch of 45bf215546Sopenharmony_ci * loads and stores, you loose a lot of information about the copy 46bf215546Sopenharmony_ci * operation that you would like to keep around. To solve this problem, we 47bf215546Sopenharmony_ci * have a "copy splitting" pass that, instead of splitting the structures 48bf215546Sopenharmony_ci * or lowering the copy into loads and storres, splits the copy operation 49bf215546Sopenharmony_ci * into a bunch of copy operations one for each leaf of the structure tree. 50bf215546Sopenharmony_ci * If an intermediate array is encountered, it is referenced with a 51bf215546Sopenharmony_ci * wildcard reference to indicate that the entire array is to be copied. 52bf215546Sopenharmony_ci * 53bf215546Sopenharmony_ci * As things become direct, array copies may be able to be losslessly 54bf215546Sopenharmony_ci * lowered to having fewer and fewer wildcards. However, until that 55bf215546Sopenharmony_ci * happens we want to keep the information about the arrays intact. 56bf215546Sopenharmony_ci * 57bf215546Sopenharmony_ci * Prior to the copy splitting pass, there are no wildcard references but 58bf215546Sopenharmony_ci * there may be incomplete references where the tail of the deref chain is 59bf215546Sopenharmony_ci * an array or a structure and not a specific element. After the copy 60bf215546Sopenharmony_ci * splitting pass has completed, every variable deref will be a full-length 61bf215546Sopenharmony_ci * dereference pointing to a single leaf in the structure type tree with 62bf215546Sopenharmony_ci * possibly a few wildcard array dereferences. 63bf215546Sopenharmony_ci */ 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_cistatic void 66bf215546Sopenharmony_cisplit_deref_copy_instr(nir_builder *b, 67bf215546Sopenharmony_ci nir_deref_instr *dst, nir_deref_instr *src, 68bf215546Sopenharmony_ci enum gl_access_qualifier dst_access, 69bf215546Sopenharmony_ci enum gl_access_qualifier src_access) 70bf215546Sopenharmony_ci{ 71bf215546Sopenharmony_ci assert(glsl_get_bare_type(dst->type) == 72bf215546Sopenharmony_ci glsl_get_bare_type(src->type)); 73bf215546Sopenharmony_ci if (glsl_type_is_vector_or_scalar(src->type)) { 74bf215546Sopenharmony_ci nir_copy_deref_with_access(b, dst, src, dst_access, src_access); 75bf215546Sopenharmony_ci } else if (glsl_type_is_struct_or_ifc(src->type)) { 76bf215546Sopenharmony_ci for (unsigned i = 0; i < glsl_get_length(src->type); i++) { 77bf215546Sopenharmony_ci split_deref_copy_instr(b, nir_build_deref_struct(b, dst, i), 78bf215546Sopenharmony_ci nir_build_deref_struct(b, src, i), 79bf215546Sopenharmony_ci dst_access, src_access); 80bf215546Sopenharmony_ci } 81bf215546Sopenharmony_ci } else { 82bf215546Sopenharmony_ci assert(glsl_type_is_matrix(src->type) || glsl_type_is_array(src->type)); 83bf215546Sopenharmony_ci split_deref_copy_instr(b, nir_build_deref_array_wildcard(b, dst), 84bf215546Sopenharmony_ci nir_build_deref_array_wildcard(b, src), 85bf215546Sopenharmony_ci dst_access, src_access); 86bf215546Sopenharmony_ci } 87bf215546Sopenharmony_ci} 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_cistatic bool 90bf215546Sopenharmony_cisplit_var_copies_impl(nir_function_impl *impl) 91bf215546Sopenharmony_ci{ 92bf215546Sopenharmony_ci bool progress = false; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci nir_builder b; 95bf215546Sopenharmony_ci nir_builder_init(&b, impl); 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci nir_foreach_block(block, impl) { 98bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 99bf215546Sopenharmony_ci if (instr->type != nir_instr_type_intrinsic) 100bf215546Sopenharmony_ci continue; 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci nir_intrinsic_instr *copy = nir_instr_as_intrinsic(instr); 103bf215546Sopenharmony_ci if (copy->intrinsic != nir_intrinsic_copy_deref) 104bf215546Sopenharmony_ci continue; 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci b.cursor = nir_instr_remove(©->instr); 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci nir_deref_instr *dst = 109bf215546Sopenharmony_ci nir_instr_as_deref(copy->src[0].ssa->parent_instr); 110bf215546Sopenharmony_ci nir_deref_instr *src = 111bf215546Sopenharmony_ci nir_instr_as_deref(copy->src[1].ssa->parent_instr); 112bf215546Sopenharmony_ci split_deref_copy_instr(&b, dst, src, 113bf215546Sopenharmony_ci nir_intrinsic_dst_access(copy), 114bf215546Sopenharmony_ci nir_intrinsic_src_access(copy)); 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci progress = true; 117bf215546Sopenharmony_ci } 118bf215546Sopenharmony_ci } 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci if (progress) { 121bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_block_index | 122bf215546Sopenharmony_ci nir_metadata_dominance); 123bf215546Sopenharmony_ci } else { 124bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_all); 125bf215546Sopenharmony_ci } 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci return progress; 128bf215546Sopenharmony_ci} 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_cibool 131bf215546Sopenharmony_cinir_split_var_copies(nir_shader *shader) 132bf215546Sopenharmony_ci{ 133bf215546Sopenharmony_ci bool progress = false; 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 136bf215546Sopenharmony_ci if (function->impl) 137bf215546Sopenharmony_ci progress = split_var_copies_impl(function->impl) || progress; 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci return progress; 141bf215546Sopenharmony_ci} 142