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#include "nir_deref.h" 31bf215546Sopenharmony_ci#include "compiler/nir_types.h" 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci/* 34bf215546Sopenharmony_ci * Lowers all copy intrinsics to sequences of load/store intrinsics. 35bf215546Sopenharmony_ci */ 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_cistatic nir_deref_instr * 38bf215546Sopenharmony_cibuild_deref_to_next_wildcard(nir_builder *b, 39bf215546Sopenharmony_ci nir_deref_instr *parent, 40bf215546Sopenharmony_ci nir_deref_instr ***deref_arr) 41bf215546Sopenharmony_ci{ 42bf215546Sopenharmony_ci for (; **deref_arr; (*deref_arr)++) { 43bf215546Sopenharmony_ci if ((**deref_arr)->deref_type == nir_deref_type_array_wildcard) 44bf215546Sopenharmony_ci return parent; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci parent = nir_build_deref_follower(b, parent, **deref_arr); 47bf215546Sopenharmony_ci } 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci assert(**deref_arr == NULL); 50bf215546Sopenharmony_ci *deref_arr = NULL; 51bf215546Sopenharmony_ci return parent; 52bf215546Sopenharmony_ci} 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic void 55bf215546Sopenharmony_ciemit_deref_copy_load_store(nir_builder *b, 56bf215546Sopenharmony_ci nir_deref_instr *dst_deref, 57bf215546Sopenharmony_ci nir_deref_instr **dst_deref_arr, 58bf215546Sopenharmony_ci nir_deref_instr *src_deref, 59bf215546Sopenharmony_ci nir_deref_instr **src_deref_arr, 60bf215546Sopenharmony_ci enum gl_access_qualifier dst_access, 61bf215546Sopenharmony_ci enum gl_access_qualifier src_access) 62bf215546Sopenharmony_ci{ 63bf215546Sopenharmony_ci if (dst_deref_arr || src_deref_arr) { 64bf215546Sopenharmony_ci assert(dst_deref_arr && src_deref_arr); 65bf215546Sopenharmony_ci dst_deref = build_deref_to_next_wildcard(b, dst_deref, &dst_deref_arr); 66bf215546Sopenharmony_ci src_deref = build_deref_to_next_wildcard(b, src_deref, &src_deref_arr); 67bf215546Sopenharmony_ci } 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci if (dst_deref_arr || src_deref_arr) { 70bf215546Sopenharmony_ci assert(dst_deref_arr && src_deref_arr); 71bf215546Sopenharmony_ci assert((*dst_deref_arr)->deref_type == nir_deref_type_array_wildcard); 72bf215546Sopenharmony_ci assert((*src_deref_arr)->deref_type == nir_deref_type_array_wildcard); 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci unsigned length = glsl_get_length(src_deref->type); 75bf215546Sopenharmony_ci /* The wildcards should represent the same number of elements */ 76bf215546Sopenharmony_ci assert(length == glsl_get_length(dst_deref->type)); 77bf215546Sopenharmony_ci assert(length > 0); 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci for (unsigned i = 0; i < length; i++) { 80bf215546Sopenharmony_ci emit_deref_copy_load_store(b, 81bf215546Sopenharmony_ci nir_build_deref_array_imm(b, dst_deref, i), 82bf215546Sopenharmony_ci dst_deref_arr + 1, 83bf215546Sopenharmony_ci nir_build_deref_array_imm(b, src_deref, i), 84bf215546Sopenharmony_ci src_deref_arr + 1, dst_access, src_access); 85bf215546Sopenharmony_ci } 86bf215546Sopenharmony_ci } else { 87bf215546Sopenharmony_ci assert(glsl_get_bare_type(dst_deref->type) == 88bf215546Sopenharmony_ci glsl_get_bare_type(src_deref->type)); 89bf215546Sopenharmony_ci assert(glsl_type_is_vector_or_scalar(dst_deref->type)); 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci nir_store_deref_with_access(b, dst_deref, 92bf215546Sopenharmony_ci nir_load_deref_with_access(b, src_deref, src_access), 93bf215546Sopenharmony_ci ~0, src_access); 94bf215546Sopenharmony_ci } 95bf215546Sopenharmony_ci} 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_civoid 98bf215546Sopenharmony_cinir_lower_deref_copy_instr(nir_builder *b, nir_intrinsic_instr *copy) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci /* Unfortunately, there's just no good way to handle wildcards except to 101bf215546Sopenharmony_ci * flip the chain around and walk the list from variable to final pointer. 102bf215546Sopenharmony_ci */ 103bf215546Sopenharmony_ci assert(copy->src[0].is_ssa && copy->src[1].is_ssa); 104bf215546Sopenharmony_ci nir_deref_instr *dst = nir_instr_as_deref(copy->src[0].ssa->parent_instr); 105bf215546Sopenharmony_ci nir_deref_instr *src = nir_instr_as_deref(copy->src[1].ssa->parent_instr); 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_ci nir_deref_path dst_path, src_path; 108bf215546Sopenharmony_ci nir_deref_path_init(&dst_path, dst, NULL); 109bf215546Sopenharmony_ci nir_deref_path_init(&src_path, src, NULL); 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci b->cursor = nir_before_instr(©->instr); 112bf215546Sopenharmony_ci emit_deref_copy_load_store(b, dst_path.path[0], &dst_path.path[1], 113bf215546Sopenharmony_ci src_path.path[0], &src_path.path[1], 114bf215546Sopenharmony_ci nir_intrinsic_dst_access(copy), 115bf215546Sopenharmony_ci nir_intrinsic_src_access(copy)); 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci nir_deref_path_finish(&dst_path); 118bf215546Sopenharmony_ci nir_deref_path_finish(&src_path); 119bf215546Sopenharmony_ci} 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_cistatic bool 122bf215546Sopenharmony_cilower_var_copies_impl(nir_function_impl *impl) 123bf215546Sopenharmony_ci{ 124bf215546Sopenharmony_ci bool progress = false; 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci nir_builder b; 127bf215546Sopenharmony_ci nir_builder_init(&b, impl); 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci nir_foreach_block(block, impl) { 130bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 131bf215546Sopenharmony_ci if (instr->type != nir_instr_type_intrinsic) 132bf215546Sopenharmony_ci continue; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci nir_intrinsic_instr *copy = nir_instr_as_intrinsic(instr); 135bf215546Sopenharmony_ci if (copy->intrinsic != nir_intrinsic_copy_deref) 136bf215546Sopenharmony_ci continue; 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci nir_lower_deref_copy_instr(&b, copy); 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci nir_instr_remove(©->instr); 141bf215546Sopenharmony_ci nir_deref_instr_remove_if_unused(nir_src_as_deref(copy->src[0])); 142bf215546Sopenharmony_ci nir_deref_instr_remove_if_unused(nir_src_as_deref(copy->src[1])); 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ci progress = true; 145bf215546Sopenharmony_ci nir_instr_free(©->instr); 146bf215546Sopenharmony_ci } 147bf215546Sopenharmony_ci } 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci if (progress) { 150bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_block_index | 151bf215546Sopenharmony_ci nir_metadata_dominance); 152bf215546Sopenharmony_ci } else { 153bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_all); 154bf215546Sopenharmony_ci } 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci return progress; 157bf215546Sopenharmony_ci} 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci/* Lowers every copy_var instruction in the program to a sequence of 160bf215546Sopenharmony_ci * load/store instructions. 161bf215546Sopenharmony_ci */ 162bf215546Sopenharmony_cibool 163bf215546Sopenharmony_cinir_lower_var_copies(nir_shader *shader) 164bf215546Sopenharmony_ci{ 165bf215546Sopenharmony_ci bool progress = false; 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 168bf215546Sopenharmony_ci if (function->impl) 169bf215546Sopenharmony_ci progress |= lower_var_copies_impl(function->impl); 170bf215546Sopenharmony_ci } 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci return progress; 173bf215546Sopenharmony_ci} 174