1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2018 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 24bf215546Sopenharmony_ci#include "nir.h" 25bf215546Sopenharmony_ci#include "nir_builder.h" 26bf215546Sopenharmony_ci#include "nir_deref.h" 27bf215546Sopenharmony_ci#include "util/hash_table.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_cistatic bool 30bf215546Sopenharmony_ciis_trivial_deref_cast(nir_deref_instr *cast) 31bf215546Sopenharmony_ci{ 32bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(cast->parent); 33bf215546Sopenharmony_ci if (!parent) 34bf215546Sopenharmony_ci return false; 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci return cast->modes == parent->modes && 37bf215546Sopenharmony_ci cast->type == parent->type && 38bf215546Sopenharmony_ci cast->dest.ssa.num_components == parent->dest.ssa.num_components && 39bf215546Sopenharmony_ci cast->dest.ssa.bit_size == parent->dest.ssa.bit_size; 40bf215546Sopenharmony_ci} 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_civoid 43bf215546Sopenharmony_cinir_deref_path_init(nir_deref_path *path, 44bf215546Sopenharmony_ci nir_deref_instr *deref, void *mem_ctx) 45bf215546Sopenharmony_ci{ 46bf215546Sopenharmony_ci assert(deref != NULL); 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci /* The length of the short path is at most ARRAY_SIZE - 1 because we need 49bf215546Sopenharmony_ci * room for the NULL terminator. 50bf215546Sopenharmony_ci */ 51bf215546Sopenharmony_ci static const int max_short_path_len = ARRAY_SIZE(path->_short_path) - 1; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci int count = 0; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci nir_deref_instr **tail = &path->_short_path[max_short_path_len]; 56bf215546Sopenharmony_ci nir_deref_instr **head = tail; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci *tail = NULL; 59bf215546Sopenharmony_ci for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) { 60bf215546Sopenharmony_ci if (d->deref_type == nir_deref_type_cast && is_trivial_deref_cast(d)) 61bf215546Sopenharmony_ci continue; 62bf215546Sopenharmony_ci count++; 63bf215546Sopenharmony_ci if (count <= max_short_path_len) 64bf215546Sopenharmony_ci *(--head) = d; 65bf215546Sopenharmony_ci } 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci if (count <= max_short_path_len) { 68bf215546Sopenharmony_ci /* If we're under max_short_path_len, just use the short path. */ 69bf215546Sopenharmony_ci path->path = head; 70bf215546Sopenharmony_ci goto done; 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci#ifndef NDEBUG 74bf215546Sopenharmony_ci /* Just in case someone uses short_path by accident */ 75bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(path->_short_path); i++) 76bf215546Sopenharmony_ci path->_short_path[i] = (void *)(uintptr_t)0xdeadbeef; 77bf215546Sopenharmony_ci#endif 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci path->path = ralloc_array(mem_ctx, nir_deref_instr *, count + 1); 80bf215546Sopenharmony_ci head = tail = path->path + count; 81bf215546Sopenharmony_ci *tail = NULL; 82bf215546Sopenharmony_ci for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) { 83bf215546Sopenharmony_ci if (d->deref_type == nir_deref_type_cast && is_trivial_deref_cast(d)) 84bf215546Sopenharmony_ci continue; 85bf215546Sopenharmony_ci *(--head) = d; 86bf215546Sopenharmony_ci } 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_cidone: 89bf215546Sopenharmony_ci assert(head == path->path); 90bf215546Sopenharmony_ci assert(tail == head + count); 91bf215546Sopenharmony_ci assert(*tail == NULL); 92bf215546Sopenharmony_ci} 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_civoid 95bf215546Sopenharmony_cinir_deref_path_finish(nir_deref_path *path) 96bf215546Sopenharmony_ci{ 97bf215546Sopenharmony_ci if (path->path < &path->_short_path[0] || 98bf215546Sopenharmony_ci path->path > &path->_short_path[ARRAY_SIZE(path->_short_path) - 1]) 99bf215546Sopenharmony_ci ralloc_free(path->path); 100bf215546Sopenharmony_ci} 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci/** 103bf215546Sopenharmony_ci * Recursively removes unused deref instructions 104bf215546Sopenharmony_ci */ 105bf215546Sopenharmony_cibool 106bf215546Sopenharmony_cinir_deref_instr_remove_if_unused(nir_deref_instr *instr) 107bf215546Sopenharmony_ci{ 108bf215546Sopenharmony_ci bool progress = false; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci for (nir_deref_instr *d = instr; d; d = nir_deref_instr_parent(d)) { 111bf215546Sopenharmony_ci /* If anyone is using this deref, leave it alone */ 112bf215546Sopenharmony_ci assert(d->dest.is_ssa); 113bf215546Sopenharmony_ci if (!nir_ssa_def_is_unused(&d->dest.ssa)) 114bf215546Sopenharmony_ci break; 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci nir_instr_remove(&d->instr); 117bf215546Sopenharmony_ci progress = true; 118bf215546Sopenharmony_ci } 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci return progress; 121bf215546Sopenharmony_ci} 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_cibool 124bf215546Sopenharmony_cinir_deref_instr_has_indirect(nir_deref_instr *instr) 125bf215546Sopenharmony_ci{ 126bf215546Sopenharmony_ci while (instr->deref_type != nir_deref_type_var) { 127bf215546Sopenharmony_ci /* Consider casts to be indirects */ 128bf215546Sopenharmony_ci if (instr->deref_type == nir_deref_type_cast) 129bf215546Sopenharmony_ci return true; 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci if ((instr->deref_type == nir_deref_type_array || 132bf215546Sopenharmony_ci instr->deref_type == nir_deref_type_ptr_as_array) && 133bf215546Sopenharmony_ci !nir_src_is_const(instr->arr.index)) 134bf215546Sopenharmony_ci return true; 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci instr = nir_deref_instr_parent(instr); 137bf215546Sopenharmony_ci } 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci return false; 140bf215546Sopenharmony_ci} 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_cibool 143bf215546Sopenharmony_cinir_deref_instr_is_known_out_of_bounds(nir_deref_instr *instr) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci for (; instr; instr = nir_deref_instr_parent(instr)) { 146bf215546Sopenharmony_ci if (instr->deref_type == nir_deref_type_array && 147bf215546Sopenharmony_ci nir_src_is_const(instr->arr.index) && 148bf215546Sopenharmony_ci nir_src_as_uint(instr->arr.index) >= 149bf215546Sopenharmony_ci glsl_get_length(nir_deref_instr_parent(instr)->type)) 150bf215546Sopenharmony_ci return true; 151bf215546Sopenharmony_ci } 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci return false; 154bf215546Sopenharmony_ci} 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_cibool 157bf215546Sopenharmony_cinir_deref_instr_has_complex_use(nir_deref_instr *deref, 158bf215546Sopenharmony_ci nir_deref_instr_has_complex_use_options opts) 159bf215546Sopenharmony_ci{ 160bf215546Sopenharmony_ci nir_foreach_use(use_src, &deref->dest.ssa) { 161bf215546Sopenharmony_ci nir_instr *use_instr = use_src->parent_instr; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci switch (use_instr->type) { 164bf215546Sopenharmony_ci case nir_instr_type_deref: { 165bf215546Sopenharmony_ci nir_deref_instr *use_deref = nir_instr_as_deref(use_instr); 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci /* A var deref has no sources */ 168bf215546Sopenharmony_ci assert(use_deref->deref_type != nir_deref_type_var); 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci /* If a deref shows up in an array index or something like that, it's 171bf215546Sopenharmony_ci * a complex use. 172bf215546Sopenharmony_ci */ 173bf215546Sopenharmony_ci if (use_src != &use_deref->parent) 174bf215546Sopenharmony_ci return true; 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci /* Anything that isn't a basic struct or array deref is considered to 177bf215546Sopenharmony_ci * be a "complex" use. In particular, we don't allow ptr_as_array 178bf215546Sopenharmony_ci * because we assume that opt_deref will turn any non-complex 179bf215546Sopenharmony_ci * ptr_as_array derefs into regular array derefs eventually so passes 180bf215546Sopenharmony_ci * which only want to handle simple derefs will pick them up in a 181bf215546Sopenharmony_ci * later pass. 182bf215546Sopenharmony_ci */ 183bf215546Sopenharmony_ci if (use_deref->deref_type != nir_deref_type_struct && 184bf215546Sopenharmony_ci use_deref->deref_type != nir_deref_type_array_wildcard && 185bf215546Sopenharmony_ci use_deref->deref_type != nir_deref_type_array) 186bf215546Sopenharmony_ci return true; 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci if (nir_deref_instr_has_complex_use(use_deref, opts)) 189bf215546Sopenharmony_ci return true; 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci continue; 192bf215546Sopenharmony_ci } 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci case nir_instr_type_intrinsic: { 195bf215546Sopenharmony_ci nir_intrinsic_instr *use_intrin = nir_instr_as_intrinsic(use_instr); 196bf215546Sopenharmony_ci switch (use_intrin->intrinsic) { 197bf215546Sopenharmony_ci case nir_intrinsic_load_deref: 198bf215546Sopenharmony_ci assert(use_src == &use_intrin->src[0]); 199bf215546Sopenharmony_ci continue; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci case nir_intrinsic_copy_deref: 202bf215546Sopenharmony_ci assert(use_src == &use_intrin->src[0] || 203bf215546Sopenharmony_ci use_src == &use_intrin->src[1]); 204bf215546Sopenharmony_ci continue; 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci case nir_intrinsic_store_deref: 207bf215546Sopenharmony_ci /* A use in src[1] of a store means we're taking that pointer and 208bf215546Sopenharmony_ci * writing it to a variable. Because we have no idea who will 209bf215546Sopenharmony_ci * read that variable and what they will do with the pointer, it's 210bf215546Sopenharmony_ci * considered a "complex" use. A use in src[0], on the other 211bf215546Sopenharmony_ci * hand, is a simple use because we're just going to dereference 212bf215546Sopenharmony_ci * it and write a value there. 213bf215546Sopenharmony_ci */ 214bf215546Sopenharmony_ci if (use_src == &use_intrin->src[0]) 215bf215546Sopenharmony_ci continue; 216bf215546Sopenharmony_ci return true; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci case nir_intrinsic_memcpy_deref: 219bf215546Sopenharmony_ci if (use_src == &use_intrin->src[0] && 220bf215546Sopenharmony_ci (opts & nir_deref_instr_has_complex_use_allow_memcpy_dst)) 221bf215546Sopenharmony_ci continue; 222bf215546Sopenharmony_ci if (use_src == &use_intrin->src[1] && 223bf215546Sopenharmony_ci (opts & nir_deref_instr_has_complex_use_allow_memcpy_src)) 224bf215546Sopenharmony_ci continue; 225bf215546Sopenharmony_ci return true; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci default: 228bf215546Sopenharmony_ci return true; 229bf215546Sopenharmony_ci } 230bf215546Sopenharmony_ci unreachable("Switch default failed"); 231bf215546Sopenharmony_ci } 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci default: 234bf215546Sopenharmony_ci return true; 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci nir_foreach_if_use(use, &deref->dest.ssa) 239bf215546Sopenharmony_ci return true; 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci return false; 242bf215546Sopenharmony_ci} 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_cistatic unsigned 245bf215546Sopenharmony_citype_scalar_size_bytes(const struct glsl_type *type) 246bf215546Sopenharmony_ci{ 247bf215546Sopenharmony_ci assert(glsl_type_is_vector_or_scalar(type) || 248bf215546Sopenharmony_ci glsl_type_is_matrix(type)); 249bf215546Sopenharmony_ci return glsl_type_is_boolean(type) ? 4 : glsl_get_bit_size(type) / 8; 250bf215546Sopenharmony_ci} 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ciunsigned 253bf215546Sopenharmony_cinir_deref_instr_array_stride(nir_deref_instr *deref) 254bf215546Sopenharmony_ci{ 255bf215546Sopenharmony_ci switch (deref->deref_type) { 256bf215546Sopenharmony_ci case nir_deref_type_array: 257bf215546Sopenharmony_ci case nir_deref_type_array_wildcard: { 258bf215546Sopenharmony_ci const struct glsl_type *arr_type = nir_deref_instr_parent(deref)->type; 259bf215546Sopenharmony_ci unsigned stride = glsl_get_explicit_stride(arr_type); 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci if ((glsl_type_is_matrix(arr_type) && 262bf215546Sopenharmony_ci glsl_matrix_type_is_row_major(arr_type)) || 263bf215546Sopenharmony_ci (glsl_type_is_vector(arr_type) && stride == 0)) 264bf215546Sopenharmony_ci stride = type_scalar_size_bytes(arr_type); 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci return stride; 267bf215546Sopenharmony_ci } 268bf215546Sopenharmony_ci case nir_deref_type_ptr_as_array: 269bf215546Sopenharmony_ci return nir_deref_instr_array_stride(nir_deref_instr_parent(deref)); 270bf215546Sopenharmony_ci case nir_deref_type_cast: 271bf215546Sopenharmony_ci return deref->cast.ptr_stride; 272bf215546Sopenharmony_ci default: 273bf215546Sopenharmony_ci return 0; 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci} 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_cistatic unsigned 278bf215546Sopenharmony_citype_get_array_stride(const struct glsl_type *elem_type, 279bf215546Sopenharmony_ci glsl_type_size_align_func size_align) 280bf215546Sopenharmony_ci{ 281bf215546Sopenharmony_ci unsigned elem_size, elem_align; 282bf215546Sopenharmony_ci size_align(elem_type, &elem_size, &elem_align); 283bf215546Sopenharmony_ci return ALIGN_POT(elem_size, elem_align); 284bf215546Sopenharmony_ci} 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_cistatic unsigned 287bf215546Sopenharmony_cistruct_type_get_field_offset(const struct glsl_type *struct_type, 288bf215546Sopenharmony_ci glsl_type_size_align_func size_align, 289bf215546Sopenharmony_ci unsigned field_idx) 290bf215546Sopenharmony_ci{ 291bf215546Sopenharmony_ci assert(glsl_type_is_struct_or_ifc(struct_type)); 292bf215546Sopenharmony_ci unsigned offset = 0; 293bf215546Sopenharmony_ci for (unsigned i = 0; i <= field_idx; i++) { 294bf215546Sopenharmony_ci unsigned elem_size, elem_align; 295bf215546Sopenharmony_ci size_align(glsl_get_struct_field(struct_type, i), &elem_size, &elem_align); 296bf215546Sopenharmony_ci offset = ALIGN_POT(offset, elem_align); 297bf215546Sopenharmony_ci if (i < field_idx) 298bf215546Sopenharmony_ci offset += elem_size; 299bf215546Sopenharmony_ci } 300bf215546Sopenharmony_ci return offset; 301bf215546Sopenharmony_ci} 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ciunsigned 304bf215546Sopenharmony_cinir_deref_instr_get_const_offset(nir_deref_instr *deref, 305bf215546Sopenharmony_ci glsl_type_size_align_func size_align) 306bf215546Sopenharmony_ci{ 307bf215546Sopenharmony_ci nir_deref_path path; 308bf215546Sopenharmony_ci nir_deref_path_init(&path, deref, NULL); 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci unsigned offset = 0; 311bf215546Sopenharmony_ci for (nir_deref_instr **p = &path.path[1]; *p; p++) { 312bf215546Sopenharmony_ci switch ((*p)->deref_type) { 313bf215546Sopenharmony_ci case nir_deref_type_array: 314bf215546Sopenharmony_ci offset += nir_src_as_uint((*p)->arr.index) * 315bf215546Sopenharmony_ci type_get_array_stride((*p)->type, size_align); 316bf215546Sopenharmony_ci break; 317bf215546Sopenharmony_ci case nir_deref_type_struct: { 318bf215546Sopenharmony_ci /* p starts at path[1], so this is safe */ 319bf215546Sopenharmony_ci nir_deref_instr *parent = *(p - 1); 320bf215546Sopenharmony_ci offset += struct_type_get_field_offset(parent->type, size_align, 321bf215546Sopenharmony_ci (*p)->strct.index); 322bf215546Sopenharmony_ci break; 323bf215546Sopenharmony_ci } 324bf215546Sopenharmony_ci case nir_deref_type_cast: 325bf215546Sopenharmony_ci /* A cast doesn't contribute to the offset */ 326bf215546Sopenharmony_ci break; 327bf215546Sopenharmony_ci default: 328bf215546Sopenharmony_ci unreachable("Unsupported deref type"); 329bf215546Sopenharmony_ci } 330bf215546Sopenharmony_ci } 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci nir_deref_path_finish(&path); 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_ci return offset; 335bf215546Sopenharmony_ci} 336bf215546Sopenharmony_ci 337bf215546Sopenharmony_cinir_ssa_def * 338bf215546Sopenharmony_cinir_build_deref_offset(nir_builder *b, nir_deref_instr *deref, 339bf215546Sopenharmony_ci glsl_type_size_align_func size_align) 340bf215546Sopenharmony_ci{ 341bf215546Sopenharmony_ci nir_deref_path path; 342bf215546Sopenharmony_ci nir_deref_path_init(&path, deref, NULL); 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci nir_ssa_def *offset = nir_imm_intN_t(b, 0, deref->dest.ssa.bit_size); 345bf215546Sopenharmony_ci for (nir_deref_instr **p = &path.path[1]; *p; p++) { 346bf215546Sopenharmony_ci switch ((*p)->deref_type) { 347bf215546Sopenharmony_ci case nir_deref_type_array: 348bf215546Sopenharmony_ci case nir_deref_type_ptr_as_array: { 349bf215546Sopenharmony_ci nir_ssa_def *index = nir_ssa_for_src(b, (*p)->arr.index, 1); 350bf215546Sopenharmony_ci int stride = type_get_array_stride((*p)->type, size_align); 351bf215546Sopenharmony_ci offset = nir_iadd(b, offset, nir_amul_imm(b, index, stride)); 352bf215546Sopenharmony_ci break; 353bf215546Sopenharmony_ci } 354bf215546Sopenharmony_ci case nir_deref_type_struct: { 355bf215546Sopenharmony_ci /* p starts at path[1], so this is safe */ 356bf215546Sopenharmony_ci nir_deref_instr *parent = *(p - 1); 357bf215546Sopenharmony_ci unsigned field_offset = 358bf215546Sopenharmony_ci struct_type_get_field_offset(parent->type, size_align, 359bf215546Sopenharmony_ci (*p)->strct.index); 360bf215546Sopenharmony_ci offset = nir_iadd_imm(b, offset, field_offset); 361bf215546Sopenharmony_ci break; 362bf215546Sopenharmony_ci } 363bf215546Sopenharmony_ci case nir_deref_type_cast: 364bf215546Sopenharmony_ci /* A cast doesn't contribute to the offset */ 365bf215546Sopenharmony_ci break; 366bf215546Sopenharmony_ci default: 367bf215546Sopenharmony_ci unreachable("Unsupported deref type"); 368bf215546Sopenharmony_ci } 369bf215546Sopenharmony_ci } 370bf215546Sopenharmony_ci 371bf215546Sopenharmony_ci nir_deref_path_finish(&path); 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci return offset; 374bf215546Sopenharmony_ci} 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_cibool 377bf215546Sopenharmony_cinir_remove_dead_derefs_impl(nir_function_impl *impl) 378bf215546Sopenharmony_ci{ 379bf215546Sopenharmony_ci bool progress = false; 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_ci nir_foreach_block(block, impl) { 382bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 383bf215546Sopenharmony_ci if (instr->type == nir_instr_type_deref && 384bf215546Sopenharmony_ci nir_deref_instr_remove_if_unused(nir_instr_as_deref(instr))) 385bf215546Sopenharmony_ci progress = true; 386bf215546Sopenharmony_ci } 387bf215546Sopenharmony_ci } 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci if (progress) { 390bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_block_index | 391bf215546Sopenharmony_ci nir_metadata_dominance); 392bf215546Sopenharmony_ci } else { 393bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_all); 394bf215546Sopenharmony_ci } 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci return progress; 397bf215546Sopenharmony_ci} 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_cibool 400bf215546Sopenharmony_cinir_remove_dead_derefs(nir_shader *shader) 401bf215546Sopenharmony_ci{ 402bf215546Sopenharmony_ci bool progress = false; 403bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 404bf215546Sopenharmony_ci if (function->impl && nir_remove_dead_derefs_impl(function->impl)) 405bf215546Sopenharmony_ci progress = true; 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci return progress; 409bf215546Sopenharmony_ci} 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_civoid 412bf215546Sopenharmony_cinir_fixup_deref_modes(nir_shader *shader) 413bf215546Sopenharmony_ci{ 414bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 415bf215546Sopenharmony_ci if (!function->impl) 416bf215546Sopenharmony_ci continue; 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_ci nir_foreach_block(block, function->impl) { 419bf215546Sopenharmony_ci nir_foreach_instr(instr, block) { 420bf215546Sopenharmony_ci if (instr->type != nir_instr_type_deref) 421bf215546Sopenharmony_ci continue; 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci nir_deref_instr *deref = nir_instr_as_deref(instr); 424bf215546Sopenharmony_ci if (deref->deref_type == nir_deref_type_cast) 425bf215546Sopenharmony_ci continue; 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci nir_variable_mode parent_modes; 428bf215546Sopenharmony_ci if (deref->deref_type == nir_deref_type_var) { 429bf215546Sopenharmony_ci parent_modes = deref->var->data.mode; 430bf215546Sopenharmony_ci } else { 431bf215546Sopenharmony_ci assert(deref->parent.is_ssa); 432bf215546Sopenharmony_ci nir_deref_instr *parent = 433bf215546Sopenharmony_ci nir_instr_as_deref(deref->parent.ssa->parent_instr); 434bf215546Sopenharmony_ci parent_modes = parent->modes; 435bf215546Sopenharmony_ci } 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci deref->modes = parent_modes; 438bf215546Sopenharmony_ci } 439bf215546Sopenharmony_ci } 440bf215546Sopenharmony_ci } 441bf215546Sopenharmony_ci} 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_cistatic bool 444bf215546Sopenharmony_cimodes_may_alias(nir_variable_mode a, nir_variable_mode b) 445bf215546Sopenharmony_ci{ 446bf215546Sopenharmony_ci /* Generic pointers can alias with SSBOs */ 447bf215546Sopenharmony_ci if ((a & (nir_var_mem_ssbo | nir_var_mem_global)) && 448bf215546Sopenharmony_ci (b & (nir_var_mem_ssbo | nir_var_mem_global))) 449bf215546Sopenharmony_ci return true; 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci /* Pointers can only alias if they share a mode. */ 452bf215546Sopenharmony_ci return a & b; 453bf215546Sopenharmony_ci} 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ciALWAYS_INLINE static nir_deref_compare_result 456bf215546Sopenharmony_cicompare_deref_paths(nir_deref_path *a_path, nir_deref_path *b_path, 457bf215546Sopenharmony_ci unsigned *i, bool (*stop_fn)(const nir_deref_instr *)) 458bf215546Sopenharmony_ci{ 459bf215546Sopenharmony_ci /* Start off assuming they fully compare. We ignore equality for now. In 460bf215546Sopenharmony_ci * the end, we'll determine that by containment. 461bf215546Sopenharmony_ci */ 462bf215546Sopenharmony_ci nir_deref_compare_result result = nir_derefs_may_alias_bit | 463bf215546Sopenharmony_ci nir_derefs_a_contains_b_bit | 464bf215546Sopenharmony_ci nir_derefs_b_contains_a_bit; 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci nir_deref_instr **a = a_path->path; 467bf215546Sopenharmony_ci nir_deref_instr **b = b_path->path; 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci for (; a[*i] != NULL; (*i)++) { 470bf215546Sopenharmony_ci if (a[*i] != b[*i]) 471bf215546Sopenharmony_ci break; 472bf215546Sopenharmony_ci 473bf215546Sopenharmony_ci if (stop_fn && stop_fn(a[*i])) 474bf215546Sopenharmony_ci break; 475bf215546Sopenharmony_ci } 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ci /* We're at either the tail or the divergence point between the two deref 478bf215546Sopenharmony_ci * paths. Look to see if either contains cast or a ptr_as_array deref. If 479bf215546Sopenharmony_ci * it does we don't know how to safely make any inferences. Hopefully, 480bf215546Sopenharmony_ci * nir_opt_deref will clean most of these up and we can start inferring 481bf215546Sopenharmony_ci * things again. 482bf215546Sopenharmony_ci * 483bf215546Sopenharmony_ci * In theory, we could do a bit better. For instance, we could detect the 484bf215546Sopenharmony_ci * case where we have exactly one ptr_as_array deref in the chain after the 485bf215546Sopenharmony_ci * divergence point and it's matched in both chains and the two chains have 486bf215546Sopenharmony_ci * different constant indices. 487bf215546Sopenharmony_ci */ 488bf215546Sopenharmony_ci for (unsigned j = *i; a[j] != NULL; j++) { 489bf215546Sopenharmony_ci if (stop_fn && stop_fn(a[j])) 490bf215546Sopenharmony_ci break; 491bf215546Sopenharmony_ci 492bf215546Sopenharmony_ci if (a[j]->deref_type == nir_deref_type_cast || 493bf215546Sopenharmony_ci a[j]->deref_type == nir_deref_type_ptr_as_array) 494bf215546Sopenharmony_ci return nir_derefs_may_alias_bit; 495bf215546Sopenharmony_ci } 496bf215546Sopenharmony_ci for (unsigned j = *i; b[j] != NULL; j++) { 497bf215546Sopenharmony_ci if (stop_fn && stop_fn(b[j])) 498bf215546Sopenharmony_ci break; 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_ci if (b[j]->deref_type == nir_deref_type_cast || 501bf215546Sopenharmony_ci b[j]->deref_type == nir_deref_type_ptr_as_array) 502bf215546Sopenharmony_ci return nir_derefs_may_alias_bit; 503bf215546Sopenharmony_ci } 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_ci for (; a[*i] != NULL && b[*i] != NULL; (*i)++) { 506bf215546Sopenharmony_ci if (stop_fn && (stop_fn(a[*i]) || stop_fn(b[*i]))) 507bf215546Sopenharmony_ci break; 508bf215546Sopenharmony_ci 509bf215546Sopenharmony_ci switch (a[*i]->deref_type) { 510bf215546Sopenharmony_ci case nir_deref_type_array: 511bf215546Sopenharmony_ci case nir_deref_type_array_wildcard: { 512bf215546Sopenharmony_ci assert(b[*i]->deref_type == nir_deref_type_array || 513bf215546Sopenharmony_ci b[*i]->deref_type == nir_deref_type_array_wildcard); 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci if (a[*i]->deref_type == nir_deref_type_array_wildcard) { 516bf215546Sopenharmony_ci if (b[*i]->deref_type != nir_deref_type_array_wildcard) 517bf215546Sopenharmony_ci result &= ~nir_derefs_b_contains_a_bit; 518bf215546Sopenharmony_ci } else if (b[*i]->deref_type == nir_deref_type_array_wildcard) { 519bf215546Sopenharmony_ci if (a[*i]->deref_type != nir_deref_type_array_wildcard) 520bf215546Sopenharmony_ci result &= ~nir_derefs_a_contains_b_bit; 521bf215546Sopenharmony_ci } else { 522bf215546Sopenharmony_ci assert(a[*i]->deref_type == nir_deref_type_array && 523bf215546Sopenharmony_ci b[*i]->deref_type == nir_deref_type_array); 524bf215546Sopenharmony_ci assert(a[*i]->arr.index.is_ssa && b[*i]->arr.index.is_ssa); 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci if (nir_src_is_const(a[*i]->arr.index) && 527bf215546Sopenharmony_ci nir_src_is_const(b[*i]->arr.index)) { 528bf215546Sopenharmony_ci /* If they're both direct and have different offsets, they 529bf215546Sopenharmony_ci * don't even alias much less anything else. 530bf215546Sopenharmony_ci */ 531bf215546Sopenharmony_ci if (nir_src_as_uint(a[*i]->arr.index) != 532bf215546Sopenharmony_ci nir_src_as_uint(b[*i]->arr.index)) 533bf215546Sopenharmony_ci return nir_derefs_do_not_alias; 534bf215546Sopenharmony_ci } else if (a[*i]->arr.index.ssa == b[*i]->arr.index.ssa) { 535bf215546Sopenharmony_ci /* They're the same indirect, continue on */ 536bf215546Sopenharmony_ci } else { 537bf215546Sopenharmony_ci /* They're not the same index so we can't prove anything about 538bf215546Sopenharmony_ci * containment. 539bf215546Sopenharmony_ci */ 540bf215546Sopenharmony_ci result &= ~(nir_derefs_a_contains_b_bit | nir_derefs_b_contains_a_bit); 541bf215546Sopenharmony_ci } 542bf215546Sopenharmony_ci } 543bf215546Sopenharmony_ci break; 544bf215546Sopenharmony_ci } 545bf215546Sopenharmony_ci 546bf215546Sopenharmony_ci case nir_deref_type_struct: { 547bf215546Sopenharmony_ci /* If they're different struct members, they don't even alias */ 548bf215546Sopenharmony_ci if (a[*i]->strct.index != b[*i]->strct.index) 549bf215546Sopenharmony_ci return nir_derefs_do_not_alias; 550bf215546Sopenharmony_ci break; 551bf215546Sopenharmony_ci } 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci default: 554bf215546Sopenharmony_ci unreachable("Invalid deref type"); 555bf215546Sopenharmony_ci } 556bf215546Sopenharmony_ci } 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci /* If a is longer than b, then it can't contain b. If neither a[i] nor 559bf215546Sopenharmony_ci * b[i] are NULL then we aren't at the end of the chain and we know nothing 560bf215546Sopenharmony_ci * about containment. 561bf215546Sopenharmony_ci */ 562bf215546Sopenharmony_ci if (a[*i] != NULL) 563bf215546Sopenharmony_ci result &= ~nir_derefs_a_contains_b_bit; 564bf215546Sopenharmony_ci if (b[*i] != NULL) 565bf215546Sopenharmony_ci result &= ~nir_derefs_b_contains_a_bit; 566bf215546Sopenharmony_ci 567bf215546Sopenharmony_ci /* If a contains b and b contains a they must be equal. */ 568bf215546Sopenharmony_ci if ((result & nir_derefs_a_contains_b_bit) && 569bf215546Sopenharmony_ci (result & nir_derefs_b_contains_a_bit)) 570bf215546Sopenharmony_ci result |= nir_derefs_equal_bit; 571bf215546Sopenharmony_ci 572bf215546Sopenharmony_ci return result; 573bf215546Sopenharmony_ci} 574bf215546Sopenharmony_ci 575bf215546Sopenharmony_cistatic bool 576bf215546Sopenharmony_ciis_interface_struct_deref(const nir_deref_instr *deref) 577bf215546Sopenharmony_ci{ 578bf215546Sopenharmony_ci if (deref->deref_type == nir_deref_type_struct) { 579bf215546Sopenharmony_ci assert(glsl_type_is_struct_or_ifc(nir_deref_instr_parent(deref)->type)); 580bf215546Sopenharmony_ci return true; 581bf215546Sopenharmony_ci } else { 582bf215546Sopenharmony_ci return false; 583bf215546Sopenharmony_ci } 584bf215546Sopenharmony_ci} 585bf215546Sopenharmony_ci 586bf215546Sopenharmony_cinir_deref_compare_result 587bf215546Sopenharmony_cinir_compare_deref_paths(nir_deref_path *a_path, 588bf215546Sopenharmony_ci nir_deref_path *b_path) 589bf215546Sopenharmony_ci{ 590bf215546Sopenharmony_ci if (!modes_may_alias(b_path->path[0]->modes, a_path->path[0]->modes)) 591bf215546Sopenharmony_ci return nir_derefs_do_not_alias; 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_ci if (a_path->path[0]->deref_type != b_path->path[0]->deref_type) 594bf215546Sopenharmony_ci return nir_derefs_may_alias_bit; 595bf215546Sopenharmony_ci 596bf215546Sopenharmony_ci unsigned path_idx = 1; 597bf215546Sopenharmony_ci if (a_path->path[0]->deref_type == nir_deref_type_var) { 598bf215546Sopenharmony_ci const nir_variable *a_var = a_path->path[0]->var; 599bf215546Sopenharmony_ci const nir_variable *b_var = b_path->path[0]->var; 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_ci /* If we got here, the two variables must have the same mode. The 602bf215546Sopenharmony_ci * only way modes_may_alias() can return true for two different modes 603bf215546Sopenharmony_ci * is if one is global and the other ssbo. However, Global variables 604bf215546Sopenharmony_ci * only exist in OpenCL and SSBOs don't exist there. No API allows 605bf215546Sopenharmony_ci * both for variables. 606bf215546Sopenharmony_ci */ 607bf215546Sopenharmony_ci assert(a_var->data.mode == b_var->data.mode); 608bf215546Sopenharmony_ci 609bf215546Sopenharmony_ci switch (a_var->data.mode) { 610bf215546Sopenharmony_ci case nir_var_mem_ssbo: { 611bf215546Sopenharmony_ci nir_deref_compare_result binding_compare; 612bf215546Sopenharmony_ci if (a_var == b_var) { 613bf215546Sopenharmony_ci binding_compare = compare_deref_paths(a_path, b_path, &path_idx, 614bf215546Sopenharmony_ci is_interface_struct_deref); 615bf215546Sopenharmony_ci } else { 616bf215546Sopenharmony_ci binding_compare = nir_derefs_do_not_alias; 617bf215546Sopenharmony_ci } 618bf215546Sopenharmony_ci 619bf215546Sopenharmony_ci if (binding_compare & nir_derefs_equal_bit) 620bf215546Sopenharmony_ci break; 621bf215546Sopenharmony_ci 622bf215546Sopenharmony_ci /* If the binding derefs can't alias and at least one is RESTRICT, 623bf215546Sopenharmony_ci * then we know they can't alias. 624bf215546Sopenharmony_ci */ 625bf215546Sopenharmony_ci if (!(binding_compare & nir_derefs_may_alias_bit) && 626bf215546Sopenharmony_ci ((a_var->data.access & ACCESS_RESTRICT) || 627bf215546Sopenharmony_ci (b_var->data.access & ACCESS_RESTRICT))) 628bf215546Sopenharmony_ci return nir_derefs_do_not_alias; 629bf215546Sopenharmony_ci 630bf215546Sopenharmony_ci return nir_derefs_may_alias_bit; 631bf215546Sopenharmony_ci } 632bf215546Sopenharmony_ci 633bf215546Sopenharmony_ci case nir_var_mem_shared: 634bf215546Sopenharmony_ci if (a_var == b_var) 635bf215546Sopenharmony_ci break; 636bf215546Sopenharmony_ci 637bf215546Sopenharmony_ci /* Per SPV_KHR_workgroup_memory_explicit_layout and 638bf215546Sopenharmony_ci * GL_EXT_shared_memory_block, shared blocks alias each other. 639bf215546Sopenharmony_ci * We will have either all blocks or all non-blocks. 640bf215546Sopenharmony_ci */ 641bf215546Sopenharmony_ci if (glsl_type_is_interface(a_var->type) || 642bf215546Sopenharmony_ci glsl_type_is_interface(b_var->type)) { 643bf215546Sopenharmony_ci assert(glsl_type_is_interface(a_var->type) && 644bf215546Sopenharmony_ci glsl_type_is_interface(b_var->type)); 645bf215546Sopenharmony_ci return nir_derefs_may_alias_bit; 646bf215546Sopenharmony_ci } 647bf215546Sopenharmony_ci 648bf215546Sopenharmony_ci /* Otherwise, distinct shared vars don't alias */ 649bf215546Sopenharmony_ci return nir_derefs_do_not_alias; 650bf215546Sopenharmony_ci 651bf215546Sopenharmony_ci default: 652bf215546Sopenharmony_ci /* For any other variable types, if we can chase them back to the 653bf215546Sopenharmony_ci * variable, and the variables are different, they don't alias. 654bf215546Sopenharmony_ci */ 655bf215546Sopenharmony_ci if (a_var == b_var) 656bf215546Sopenharmony_ci break; 657bf215546Sopenharmony_ci 658bf215546Sopenharmony_ci return nir_derefs_do_not_alias; 659bf215546Sopenharmony_ci } 660bf215546Sopenharmony_ci } else { 661bf215546Sopenharmony_ci assert(a_path->path[0]->deref_type == nir_deref_type_cast); 662bf215546Sopenharmony_ci /* If they're not exactly the same cast, it's hard to compare them so we 663bf215546Sopenharmony_ci * just assume they alias. Comparing casts is tricky as there are lots 664bf215546Sopenharmony_ci * of things such as mode, type, etc. to make sure work out; for now, we 665bf215546Sopenharmony_ci * just assume nit_opt_deref will combine them and compare the deref 666bf215546Sopenharmony_ci * instructions. 667bf215546Sopenharmony_ci * 668bf215546Sopenharmony_ci * TODO: At some point in the future, we could be clever and understand 669bf215546Sopenharmony_ci * that a float[] and int[] have the same layout and aliasing structure 670bf215546Sopenharmony_ci * but double[] and vec3[] do not and we could potentially be a bit 671bf215546Sopenharmony_ci * smarter here. 672bf215546Sopenharmony_ci */ 673bf215546Sopenharmony_ci if (a_path->path[0] != b_path->path[0]) 674bf215546Sopenharmony_ci return nir_derefs_may_alias_bit; 675bf215546Sopenharmony_ci } 676bf215546Sopenharmony_ci 677bf215546Sopenharmony_ci return compare_deref_paths(a_path, b_path, &path_idx, NULL); 678bf215546Sopenharmony_ci} 679bf215546Sopenharmony_ci 680bf215546Sopenharmony_cinir_deref_compare_result 681bf215546Sopenharmony_cinir_compare_derefs(nir_deref_instr *a, nir_deref_instr *b) 682bf215546Sopenharmony_ci{ 683bf215546Sopenharmony_ci if (a == b) { 684bf215546Sopenharmony_ci return nir_derefs_equal_bit | nir_derefs_may_alias_bit | 685bf215546Sopenharmony_ci nir_derefs_a_contains_b_bit | nir_derefs_b_contains_a_bit; 686bf215546Sopenharmony_ci } 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_ci nir_deref_path a_path, b_path; 689bf215546Sopenharmony_ci nir_deref_path_init(&a_path, a, NULL); 690bf215546Sopenharmony_ci nir_deref_path_init(&b_path, b, NULL); 691bf215546Sopenharmony_ci assert(a_path.path[0]->deref_type == nir_deref_type_var || 692bf215546Sopenharmony_ci a_path.path[0]->deref_type == nir_deref_type_cast); 693bf215546Sopenharmony_ci assert(b_path.path[0]->deref_type == nir_deref_type_var || 694bf215546Sopenharmony_ci b_path.path[0]->deref_type == nir_deref_type_cast); 695bf215546Sopenharmony_ci 696bf215546Sopenharmony_ci nir_deref_compare_result result = nir_compare_deref_paths(&a_path, &b_path); 697bf215546Sopenharmony_ci 698bf215546Sopenharmony_ci nir_deref_path_finish(&a_path); 699bf215546Sopenharmony_ci nir_deref_path_finish(&b_path); 700bf215546Sopenharmony_ci 701bf215546Sopenharmony_ci return result; 702bf215546Sopenharmony_ci} 703bf215546Sopenharmony_ci 704bf215546Sopenharmony_cinir_deref_path *nir_get_deref_path(void *mem_ctx, nir_deref_and_path *deref) 705bf215546Sopenharmony_ci{ 706bf215546Sopenharmony_ci if (!deref->_path) { 707bf215546Sopenharmony_ci deref->_path = ralloc(mem_ctx, nir_deref_path); 708bf215546Sopenharmony_ci nir_deref_path_init(deref->_path, deref->instr, mem_ctx); 709bf215546Sopenharmony_ci } 710bf215546Sopenharmony_ci return deref->_path; 711bf215546Sopenharmony_ci} 712bf215546Sopenharmony_ci 713bf215546Sopenharmony_cinir_deref_compare_result nir_compare_derefs_and_paths(void *mem_ctx, 714bf215546Sopenharmony_ci nir_deref_and_path *a, 715bf215546Sopenharmony_ci nir_deref_and_path *b) 716bf215546Sopenharmony_ci{ 717bf215546Sopenharmony_ci if (a->instr == b->instr) /* nir_compare_derefs has a fast path if a == b */ 718bf215546Sopenharmony_ci return nir_compare_derefs(a->instr, b->instr); 719bf215546Sopenharmony_ci 720bf215546Sopenharmony_ci return nir_compare_deref_paths(nir_get_deref_path(mem_ctx, a), 721bf215546Sopenharmony_ci nir_get_deref_path(mem_ctx, b)); 722bf215546Sopenharmony_ci} 723bf215546Sopenharmony_ci 724bf215546Sopenharmony_cistruct rematerialize_deref_state { 725bf215546Sopenharmony_ci bool progress; 726bf215546Sopenharmony_ci nir_builder builder; 727bf215546Sopenharmony_ci nir_block *block; 728bf215546Sopenharmony_ci struct hash_table *cache; 729bf215546Sopenharmony_ci}; 730bf215546Sopenharmony_ci 731bf215546Sopenharmony_cistatic nir_deref_instr * 732bf215546Sopenharmony_cirematerialize_deref_in_block(nir_deref_instr *deref, 733bf215546Sopenharmony_ci struct rematerialize_deref_state *state) 734bf215546Sopenharmony_ci{ 735bf215546Sopenharmony_ci if (deref->instr.block == state->block) 736bf215546Sopenharmony_ci return deref; 737bf215546Sopenharmony_ci 738bf215546Sopenharmony_ci if (!state->cache) { 739bf215546Sopenharmony_ci state->cache = _mesa_pointer_hash_table_create(NULL); 740bf215546Sopenharmony_ci } 741bf215546Sopenharmony_ci 742bf215546Sopenharmony_ci struct hash_entry *cached = _mesa_hash_table_search(state->cache, deref); 743bf215546Sopenharmony_ci if (cached) 744bf215546Sopenharmony_ci return cached->data; 745bf215546Sopenharmony_ci 746bf215546Sopenharmony_ci nir_builder *b = &state->builder; 747bf215546Sopenharmony_ci nir_deref_instr *new_deref = 748bf215546Sopenharmony_ci nir_deref_instr_create(b->shader, deref->deref_type); 749bf215546Sopenharmony_ci new_deref->modes = deref->modes; 750bf215546Sopenharmony_ci new_deref->type = deref->type; 751bf215546Sopenharmony_ci 752bf215546Sopenharmony_ci if (deref->deref_type == nir_deref_type_var) { 753bf215546Sopenharmony_ci new_deref->var = deref->var; 754bf215546Sopenharmony_ci } else { 755bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(deref->parent); 756bf215546Sopenharmony_ci if (parent) { 757bf215546Sopenharmony_ci parent = rematerialize_deref_in_block(parent, state); 758bf215546Sopenharmony_ci new_deref->parent = nir_src_for_ssa(&parent->dest.ssa); 759bf215546Sopenharmony_ci } else { 760bf215546Sopenharmony_ci nir_src_copy(&new_deref->parent, &deref->parent); 761bf215546Sopenharmony_ci } 762bf215546Sopenharmony_ci } 763bf215546Sopenharmony_ci 764bf215546Sopenharmony_ci switch (deref->deref_type) { 765bf215546Sopenharmony_ci case nir_deref_type_var: 766bf215546Sopenharmony_ci case nir_deref_type_array_wildcard: 767bf215546Sopenharmony_ci /* Nothing more to do */ 768bf215546Sopenharmony_ci break; 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci case nir_deref_type_cast: 771bf215546Sopenharmony_ci new_deref->cast.ptr_stride = deref->cast.ptr_stride; 772bf215546Sopenharmony_ci break; 773bf215546Sopenharmony_ci 774bf215546Sopenharmony_ci case nir_deref_type_array: 775bf215546Sopenharmony_ci case nir_deref_type_ptr_as_array: 776bf215546Sopenharmony_ci assert(!nir_src_as_deref(deref->arr.index)); 777bf215546Sopenharmony_ci nir_src_copy(&new_deref->arr.index, &deref->arr.index); 778bf215546Sopenharmony_ci break; 779bf215546Sopenharmony_ci 780bf215546Sopenharmony_ci case nir_deref_type_struct: 781bf215546Sopenharmony_ci new_deref->strct.index = deref->strct.index; 782bf215546Sopenharmony_ci break; 783bf215546Sopenharmony_ci 784bf215546Sopenharmony_ci default: 785bf215546Sopenharmony_ci unreachable("Invalid deref instruction type"); 786bf215546Sopenharmony_ci } 787bf215546Sopenharmony_ci 788bf215546Sopenharmony_ci nir_ssa_dest_init(&new_deref->instr, &new_deref->dest, 789bf215546Sopenharmony_ci deref->dest.ssa.num_components, 790bf215546Sopenharmony_ci deref->dest.ssa.bit_size, 791bf215546Sopenharmony_ci NULL); 792bf215546Sopenharmony_ci nir_builder_instr_insert(b, &new_deref->instr); 793bf215546Sopenharmony_ci 794bf215546Sopenharmony_ci return new_deref; 795bf215546Sopenharmony_ci} 796bf215546Sopenharmony_ci 797bf215546Sopenharmony_cistatic bool 798bf215546Sopenharmony_cirematerialize_deref_src(nir_src *src, void *_state) 799bf215546Sopenharmony_ci{ 800bf215546Sopenharmony_ci struct rematerialize_deref_state *state = _state; 801bf215546Sopenharmony_ci 802bf215546Sopenharmony_ci nir_deref_instr *deref = nir_src_as_deref(*src); 803bf215546Sopenharmony_ci if (!deref) 804bf215546Sopenharmony_ci return true; 805bf215546Sopenharmony_ci 806bf215546Sopenharmony_ci nir_deref_instr *block_deref = rematerialize_deref_in_block(deref, state); 807bf215546Sopenharmony_ci if (block_deref != deref) { 808bf215546Sopenharmony_ci nir_instr_rewrite_src(src->parent_instr, src, 809bf215546Sopenharmony_ci nir_src_for_ssa(&block_deref->dest.ssa)); 810bf215546Sopenharmony_ci nir_deref_instr_remove_if_unused(deref); 811bf215546Sopenharmony_ci state->progress = true; 812bf215546Sopenharmony_ci } 813bf215546Sopenharmony_ci 814bf215546Sopenharmony_ci return true; 815bf215546Sopenharmony_ci} 816bf215546Sopenharmony_ci 817bf215546Sopenharmony_ci/** Re-materialize derefs in every block 818bf215546Sopenharmony_ci * 819bf215546Sopenharmony_ci * This pass re-materializes deref instructions in every block in which it is 820bf215546Sopenharmony_ci * used. After this pass has been run, every use of a deref will be of a 821bf215546Sopenharmony_ci * deref in the same block as the use. Also, all unused derefs will be 822bf215546Sopenharmony_ci * deleted as a side-effect. 823bf215546Sopenharmony_ci * 824bf215546Sopenharmony_ci * Derefs used as sources of phi instructions are not rematerialized. 825bf215546Sopenharmony_ci */ 826bf215546Sopenharmony_cibool 827bf215546Sopenharmony_cinir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl *impl) 828bf215546Sopenharmony_ci{ 829bf215546Sopenharmony_ci struct rematerialize_deref_state state = { 0 }; 830bf215546Sopenharmony_ci nir_builder_init(&state.builder, impl); 831bf215546Sopenharmony_ci 832bf215546Sopenharmony_ci nir_foreach_block_unstructured(block, impl) { 833bf215546Sopenharmony_ci state.block = block; 834bf215546Sopenharmony_ci 835bf215546Sopenharmony_ci /* Start each block with a fresh cache */ 836bf215546Sopenharmony_ci if (state.cache) 837bf215546Sopenharmony_ci _mesa_hash_table_clear(state.cache, NULL); 838bf215546Sopenharmony_ci 839bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 840bf215546Sopenharmony_ci if (instr->type == nir_instr_type_deref && 841bf215546Sopenharmony_ci nir_deref_instr_remove_if_unused(nir_instr_as_deref(instr))) 842bf215546Sopenharmony_ci continue; 843bf215546Sopenharmony_ci 844bf215546Sopenharmony_ci /* If a deref is used in a phi, we can't rematerialize it, as the new 845bf215546Sopenharmony_ci * derefs would appear before the phi, which is not valid. 846bf215546Sopenharmony_ci */ 847bf215546Sopenharmony_ci if (instr->type == nir_instr_type_phi) 848bf215546Sopenharmony_ci continue; 849bf215546Sopenharmony_ci 850bf215546Sopenharmony_ci state.builder.cursor = nir_before_instr(instr); 851bf215546Sopenharmony_ci nir_foreach_src(instr, rematerialize_deref_src, &state); 852bf215546Sopenharmony_ci } 853bf215546Sopenharmony_ci 854bf215546Sopenharmony_ci#ifndef NDEBUG 855bf215546Sopenharmony_ci nir_if *following_if = nir_block_get_following_if(block); 856bf215546Sopenharmony_ci if (following_if) 857bf215546Sopenharmony_ci assert(!nir_src_as_deref(following_if->condition)); 858bf215546Sopenharmony_ci#endif 859bf215546Sopenharmony_ci } 860bf215546Sopenharmony_ci 861bf215546Sopenharmony_ci _mesa_hash_table_destroy(state.cache, NULL); 862bf215546Sopenharmony_ci 863bf215546Sopenharmony_ci return state.progress; 864bf215546Sopenharmony_ci} 865bf215546Sopenharmony_ci 866bf215546Sopenharmony_cistatic void 867bf215546Sopenharmony_cinir_deref_instr_fixup_child_types(nir_deref_instr *parent) 868bf215546Sopenharmony_ci{ 869bf215546Sopenharmony_ci nir_foreach_use(use, &parent->dest.ssa) { 870bf215546Sopenharmony_ci if (use->parent_instr->type != nir_instr_type_deref) 871bf215546Sopenharmony_ci continue; 872bf215546Sopenharmony_ci 873bf215546Sopenharmony_ci nir_deref_instr *child = nir_instr_as_deref(use->parent_instr); 874bf215546Sopenharmony_ci switch (child->deref_type) { 875bf215546Sopenharmony_ci case nir_deref_type_var: 876bf215546Sopenharmony_ci unreachable("nir_deref_type_var cannot be a child"); 877bf215546Sopenharmony_ci 878bf215546Sopenharmony_ci case nir_deref_type_array: 879bf215546Sopenharmony_ci case nir_deref_type_array_wildcard: 880bf215546Sopenharmony_ci child->type = glsl_get_array_element(parent->type); 881bf215546Sopenharmony_ci break; 882bf215546Sopenharmony_ci 883bf215546Sopenharmony_ci case nir_deref_type_ptr_as_array: 884bf215546Sopenharmony_ci child->type = parent->type; 885bf215546Sopenharmony_ci break; 886bf215546Sopenharmony_ci 887bf215546Sopenharmony_ci case nir_deref_type_struct: 888bf215546Sopenharmony_ci child->type = glsl_get_struct_field(parent->type, 889bf215546Sopenharmony_ci child->strct.index); 890bf215546Sopenharmony_ci break; 891bf215546Sopenharmony_ci 892bf215546Sopenharmony_ci case nir_deref_type_cast: 893bf215546Sopenharmony_ci /* We stop the recursion here */ 894bf215546Sopenharmony_ci continue; 895bf215546Sopenharmony_ci } 896bf215546Sopenharmony_ci 897bf215546Sopenharmony_ci /* Recurse into children */ 898bf215546Sopenharmony_ci nir_deref_instr_fixup_child_types(child); 899bf215546Sopenharmony_ci } 900bf215546Sopenharmony_ci} 901bf215546Sopenharmony_ci 902bf215546Sopenharmony_cistatic bool 903bf215546Sopenharmony_ciopt_alu_of_cast(nir_alu_instr *alu) 904bf215546Sopenharmony_ci{ 905bf215546Sopenharmony_ci bool progress = false; 906bf215546Sopenharmony_ci 907bf215546Sopenharmony_ci for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) { 908bf215546Sopenharmony_ci assert(alu->src[i].src.is_ssa); 909bf215546Sopenharmony_ci nir_instr *src_instr = alu->src[i].src.ssa->parent_instr; 910bf215546Sopenharmony_ci if (src_instr->type != nir_instr_type_deref) 911bf215546Sopenharmony_ci continue; 912bf215546Sopenharmony_ci 913bf215546Sopenharmony_ci nir_deref_instr *src_deref = nir_instr_as_deref(src_instr); 914bf215546Sopenharmony_ci if (src_deref->deref_type != nir_deref_type_cast) 915bf215546Sopenharmony_ci continue; 916bf215546Sopenharmony_ci 917bf215546Sopenharmony_ci assert(src_deref->parent.is_ssa); 918bf215546Sopenharmony_ci nir_instr_rewrite_src_ssa(&alu->instr, &alu->src[i].src, 919bf215546Sopenharmony_ci src_deref->parent.ssa); 920bf215546Sopenharmony_ci progress = true; 921bf215546Sopenharmony_ci } 922bf215546Sopenharmony_ci 923bf215546Sopenharmony_ci return progress; 924bf215546Sopenharmony_ci} 925bf215546Sopenharmony_ci 926bf215546Sopenharmony_cistatic bool 927bf215546Sopenharmony_ciis_trivial_array_deref_cast(nir_deref_instr *cast) 928bf215546Sopenharmony_ci{ 929bf215546Sopenharmony_ci assert(is_trivial_deref_cast(cast)); 930bf215546Sopenharmony_ci 931bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(cast->parent); 932bf215546Sopenharmony_ci 933bf215546Sopenharmony_ci if (parent->deref_type == nir_deref_type_array) { 934bf215546Sopenharmony_ci return cast->cast.ptr_stride == 935bf215546Sopenharmony_ci glsl_get_explicit_stride(nir_deref_instr_parent(parent)->type); 936bf215546Sopenharmony_ci } else if (parent->deref_type == nir_deref_type_ptr_as_array) { 937bf215546Sopenharmony_ci return cast->cast.ptr_stride == 938bf215546Sopenharmony_ci nir_deref_instr_array_stride(parent); 939bf215546Sopenharmony_ci } else { 940bf215546Sopenharmony_ci return false; 941bf215546Sopenharmony_ci } 942bf215546Sopenharmony_ci} 943bf215546Sopenharmony_ci 944bf215546Sopenharmony_cistatic bool 945bf215546Sopenharmony_ciis_deref_ptr_as_array(nir_instr *instr) 946bf215546Sopenharmony_ci{ 947bf215546Sopenharmony_ci return instr->type == nir_instr_type_deref && 948bf215546Sopenharmony_ci nir_instr_as_deref(instr)->deref_type == nir_deref_type_ptr_as_array; 949bf215546Sopenharmony_ci} 950bf215546Sopenharmony_ci 951bf215546Sopenharmony_cistatic bool 952bf215546Sopenharmony_ciopt_remove_restricting_cast_alignments(nir_deref_instr *cast) 953bf215546Sopenharmony_ci{ 954bf215546Sopenharmony_ci assert(cast->deref_type == nir_deref_type_cast); 955bf215546Sopenharmony_ci if (cast->cast.align_mul == 0) 956bf215546Sopenharmony_ci return false; 957bf215546Sopenharmony_ci 958bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(cast->parent); 959bf215546Sopenharmony_ci if (parent == NULL) 960bf215546Sopenharmony_ci return false; 961bf215546Sopenharmony_ci 962bf215546Sopenharmony_ci /* Don't use any default alignment for this check. We don't want to fall 963bf215546Sopenharmony_ci * back to type alignment too early in case we find out later that we're 964bf215546Sopenharmony_ci * somehow a child of a packed struct. 965bf215546Sopenharmony_ci */ 966bf215546Sopenharmony_ci uint32_t parent_mul, parent_offset; 967bf215546Sopenharmony_ci if (!nir_get_explicit_deref_align(parent, false /* default_to_type_align */, 968bf215546Sopenharmony_ci &parent_mul, &parent_offset)) 969bf215546Sopenharmony_ci return false; 970bf215546Sopenharmony_ci 971bf215546Sopenharmony_ci /* If this cast increases the alignment, we want to keep it. 972bf215546Sopenharmony_ci * 973bf215546Sopenharmony_ci * There is a possibility that the larger alignment provided by this cast 974bf215546Sopenharmony_ci * somehow disagrees with the smaller alignment further up the deref chain. 975bf215546Sopenharmony_ci * In that case, we choose to favor the alignment closer to the actual 976bf215546Sopenharmony_ci * memory operation which, in this case, is the cast and not its parent so 977bf215546Sopenharmony_ci * keeping the cast alignment is the right thing to do. 978bf215546Sopenharmony_ci */ 979bf215546Sopenharmony_ci if (parent_mul < cast->cast.align_mul) 980bf215546Sopenharmony_ci return false; 981bf215546Sopenharmony_ci 982bf215546Sopenharmony_ci /* If we've gotten here, we have a parent deref with an align_mul at least 983bf215546Sopenharmony_ci * as large as ours so we can potentially throw away the alignment 984bf215546Sopenharmony_ci * information on this deref. There are two cases to consider here: 985bf215546Sopenharmony_ci * 986bf215546Sopenharmony_ci * 1. We can chase the deref all the way back to the variable. In this 987bf215546Sopenharmony_ci * case, we have "perfect" knowledge, modulo indirect array derefs. 988bf215546Sopenharmony_ci * Unless we've done something wrong in our indirect/wildcard stride 989bf215546Sopenharmony_ci * calculations, our knowledge from the deref walk is better than the 990bf215546Sopenharmony_ci * client's. 991bf215546Sopenharmony_ci * 992bf215546Sopenharmony_ci * 2. We can't chase it all the way back to the variable. In this case, 993bf215546Sopenharmony_ci * because our call to nir_get_explicit_deref_align(parent, ...) above 994bf215546Sopenharmony_ci * above passes default_to_type_align=false, the only way we can even 995bf215546Sopenharmony_ci * get here is if something further up the deref chain has a cast with 996bf215546Sopenharmony_ci * an alignment which can only happen if we get an alignment from the 997bf215546Sopenharmony_ci * client (most likely a decoration in the SPIR-V). If the client has 998bf215546Sopenharmony_ci * provided us with two conflicting alignments in the deref chain, 999bf215546Sopenharmony_ci * that's their fault and we can do whatever we want. 1000bf215546Sopenharmony_ci * 1001bf215546Sopenharmony_ci * In either case, we should be without our rights, at this point, to throw 1002bf215546Sopenharmony_ci * away the alignment information on this deref. However, to be "nice" to 1003bf215546Sopenharmony_ci * weird clients, we do one more check. It really shouldn't happen but 1004bf215546Sopenharmony_ci * it's possible that the parent's alignment offset disagrees with the 1005bf215546Sopenharmony_ci * cast's alignment offset. In this case, we consider the cast as 1006bf215546Sopenharmony_ci * providing more information (or at least more valid information) and keep 1007bf215546Sopenharmony_ci * it even if the align_mul from the parent is larger. 1008bf215546Sopenharmony_ci */ 1009bf215546Sopenharmony_ci assert(cast->cast.align_mul <= parent_mul); 1010bf215546Sopenharmony_ci if (parent_offset % cast->cast.align_mul != cast->cast.align_offset) 1011bf215546Sopenharmony_ci return false; 1012bf215546Sopenharmony_ci 1013bf215546Sopenharmony_ci /* If we got here, the parent has better alignment information than the 1014bf215546Sopenharmony_ci * child and we can get rid of the child alignment information. 1015bf215546Sopenharmony_ci */ 1016bf215546Sopenharmony_ci cast->cast.align_mul = 0; 1017bf215546Sopenharmony_ci cast->cast.align_offset = 0; 1018bf215546Sopenharmony_ci return true; 1019bf215546Sopenharmony_ci} 1020bf215546Sopenharmony_ci 1021bf215546Sopenharmony_ci/** 1022bf215546Sopenharmony_ci * Remove casts that just wrap other casts. 1023bf215546Sopenharmony_ci */ 1024bf215546Sopenharmony_cistatic bool 1025bf215546Sopenharmony_ciopt_remove_cast_cast(nir_deref_instr *cast) 1026bf215546Sopenharmony_ci{ 1027bf215546Sopenharmony_ci nir_deref_instr *first_cast = cast; 1028bf215546Sopenharmony_ci 1029bf215546Sopenharmony_ci while (true) { 1030bf215546Sopenharmony_ci nir_deref_instr *parent = nir_deref_instr_parent(first_cast); 1031bf215546Sopenharmony_ci if (parent == NULL || parent->deref_type != nir_deref_type_cast) 1032bf215546Sopenharmony_ci break; 1033bf215546Sopenharmony_ci first_cast = parent; 1034bf215546Sopenharmony_ci } 1035bf215546Sopenharmony_ci if (cast == first_cast) 1036bf215546Sopenharmony_ci return false; 1037bf215546Sopenharmony_ci 1038bf215546Sopenharmony_ci nir_instr_rewrite_src(&cast->instr, &cast->parent, 1039bf215546Sopenharmony_ci nir_src_for_ssa(first_cast->parent.ssa)); 1040bf215546Sopenharmony_ci return true; 1041bf215546Sopenharmony_ci} 1042bf215546Sopenharmony_ci 1043bf215546Sopenharmony_ci/* Restrict variable modes in casts. 1044bf215546Sopenharmony_ci * 1045bf215546Sopenharmony_ci * If we know from something higher up the deref chain that the deref has a 1046bf215546Sopenharmony_ci * specific mode, we can cast to more general and back but we can never cast 1047bf215546Sopenharmony_ci * across modes. For non-cast derefs, we should only ever do anything here if 1048bf215546Sopenharmony_ci * the parent eventually comes from a cast that we restricted earlier. 1049bf215546Sopenharmony_ci */ 1050bf215546Sopenharmony_cistatic bool 1051bf215546Sopenharmony_ciopt_restrict_deref_modes(nir_deref_instr *deref) 1052bf215546Sopenharmony_ci{ 1053bf215546Sopenharmony_ci if (deref->deref_type == nir_deref_type_var) { 1054bf215546Sopenharmony_ci assert(deref->modes == deref->var->data.mode); 1055bf215546Sopenharmony_ci return false; 1056bf215546Sopenharmony_ci } 1057bf215546Sopenharmony_ci 1058bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(deref->parent); 1059bf215546Sopenharmony_ci if (parent == NULL || parent->modes == deref->modes) 1060bf215546Sopenharmony_ci return false; 1061bf215546Sopenharmony_ci 1062bf215546Sopenharmony_ci assert(parent->modes & deref->modes); 1063bf215546Sopenharmony_ci deref->modes &= parent->modes; 1064bf215546Sopenharmony_ci return true; 1065bf215546Sopenharmony_ci} 1066bf215546Sopenharmony_ci 1067bf215546Sopenharmony_cistatic bool 1068bf215546Sopenharmony_ciopt_remove_sampler_cast(nir_deref_instr *cast) 1069bf215546Sopenharmony_ci{ 1070bf215546Sopenharmony_ci assert(cast->deref_type == nir_deref_type_cast); 1071bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(cast->parent); 1072bf215546Sopenharmony_ci if (parent == NULL) 1073bf215546Sopenharmony_ci return false; 1074bf215546Sopenharmony_ci 1075bf215546Sopenharmony_ci /* Strip both types down to their non-array type and bail if there are any 1076bf215546Sopenharmony_ci * discrepancies in array lengths. 1077bf215546Sopenharmony_ci */ 1078bf215546Sopenharmony_ci const struct glsl_type *parent_type = parent->type; 1079bf215546Sopenharmony_ci const struct glsl_type *cast_type = cast->type; 1080bf215546Sopenharmony_ci while (glsl_type_is_array(parent_type) && glsl_type_is_array(cast_type)) { 1081bf215546Sopenharmony_ci if (glsl_get_length(parent_type) != glsl_get_length(cast_type)) 1082bf215546Sopenharmony_ci return false; 1083bf215546Sopenharmony_ci parent_type = glsl_get_array_element(parent_type); 1084bf215546Sopenharmony_ci cast_type = glsl_get_array_element(cast_type); 1085bf215546Sopenharmony_ci } 1086bf215546Sopenharmony_ci 1087bf215546Sopenharmony_ci if (!glsl_type_is_sampler(parent_type)) 1088bf215546Sopenharmony_ci return false; 1089bf215546Sopenharmony_ci 1090bf215546Sopenharmony_ci if (cast_type != glsl_bare_sampler_type() && 1091bf215546Sopenharmony_ci (glsl_type_is_bare_sampler(parent_type) || 1092bf215546Sopenharmony_ci cast_type != glsl_sampler_type_to_texture(parent_type))) 1093bf215546Sopenharmony_ci return false; 1094bf215546Sopenharmony_ci 1095bf215546Sopenharmony_ci /* We're a cast from a more detailed sampler type to a bare sampler or a 1096bf215546Sopenharmony_ci * texture type with the same dimensionality. 1097bf215546Sopenharmony_ci */ 1098bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(&cast->dest.ssa, 1099bf215546Sopenharmony_ci &parent->dest.ssa); 1100bf215546Sopenharmony_ci nir_instr_remove(&cast->instr); 1101bf215546Sopenharmony_ci 1102bf215546Sopenharmony_ci /* Recursively crawl the deref tree and clean up types */ 1103bf215546Sopenharmony_ci nir_deref_instr_fixup_child_types(parent); 1104bf215546Sopenharmony_ci 1105bf215546Sopenharmony_ci return true; 1106bf215546Sopenharmony_ci} 1107bf215546Sopenharmony_ci 1108bf215546Sopenharmony_ci/** 1109bf215546Sopenharmony_ci * Is this casting a struct to a contained struct. 1110bf215546Sopenharmony_ci * struct a { struct b field0 }; 1111bf215546Sopenharmony_ci * ssa_5 is structa; 1112bf215546Sopenharmony_ci * deref_cast (structb *)ssa_5 (function_temp structb); 1113bf215546Sopenharmony_ci * converts to 1114bf215546Sopenharmony_ci * deref_struct &ssa_5->field0 (function_temp structb); 1115bf215546Sopenharmony_ci * This allows subsequent copy propagation to work. 1116bf215546Sopenharmony_ci */ 1117bf215546Sopenharmony_cistatic bool 1118bf215546Sopenharmony_ciopt_replace_struct_wrapper_cast(nir_builder *b, nir_deref_instr *cast) 1119bf215546Sopenharmony_ci{ 1120bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(cast->parent); 1121bf215546Sopenharmony_ci if (!parent) 1122bf215546Sopenharmony_ci return false; 1123bf215546Sopenharmony_ci 1124bf215546Sopenharmony_ci if (cast->cast.align_mul > 0) 1125bf215546Sopenharmony_ci return false; 1126bf215546Sopenharmony_ci 1127bf215546Sopenharmony_ci if (!glsl_type_is_struct(parent->type)) 1128bf215546Sopenharmony_ci return false; 1129bf215546Sopenharmony_ci 1130bf215546Sopenharmony_ci /* Empty struct */ 1131bf215546Sopenharmony_ci if (glsl_get_length(parent->type) < 1) 1132bf215546Sopenharmony_ci return false; 1133bf215546Sopenharmony_ci 1134bf215546Sopenharmony_ci if (glsl_get_struct_field_offset(parent->type, 0) != 0) 1135bf215546Sopenharmony_ci return false; 1136bf215546Sopenharmony_ci 1137bf215546Sopenharmony_ci if (cast->type != glsl_get_struct_field(parent->type, 0)) 1138bf215546Sopenharmony_ci return false; 1139bf215546Sopenharmony_ci 1140bf215546Sopenharmony_ci nir_deref_instr *replace = nir_build_deref_struct(b, parent, 0); 1141bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(&cast->dest.ssa, &replace->dest.ssa); 1142bf215546Sopenharmony_ci nir_deref_instr_remove_if_unused(cast); 1143bf215546Sopenharmony_ci return true; 1144bf215546Sopenharmony_ci} 1145bf215546Sopenharmony_ci 1146bf215546Sopenharmony_cistatic bool 1147bf215546Sopenharmony_ciopt_deref_cast(nir_builder *b, nir_deref_instr *cast) 1148bf215546Sopenharmony_ci{ 1149bf215546Sopenharmony_ci bool progress = false; 1150bf215546Sopenharmony_ci 1151bf215546Sopenharmony_ci progress |= opt_remove_restricting_cast_alignments(cast); 1152bf215546Sopenharmony_ci 1153bf215546Sopenharmony_ci if (opt_replace_struct_wrapper_cast(b, cast)) 1154bf215546Sopenharmony_ci return true; 1155bf215546Sopenharmony_ci 1156bf215546Sopenharmony_ci if (opt_remove_sampler_cast(cast)) 1157bf215546Sopenharmony_ci return true; 1158bf215546Sopenharmony_ci 1159bf215546Sopenharmony_ci progress |= opt_remove_cast_cast(cast); 1160bf215546Sopenharmony_ci if (!is_trivial_deref_cast(cast)) 1161bf215546Sopenharmony_ci return progress; 1162bf215546Sopenharmony_ci 1163bf215546Sopenharmony_ci /* If this deref still contains useful alignment information, we don't want 1164bf215546Sopenharmony_ci * to delete it. 1165bf215546Sopenharmony_ci */ 1166bf215546Sopenharmony_ci if (cast->cast.align_mul > 0) 1167bf215546Sopenharmony_ci return progress; 1168bf215546Sopenharmony_ci 1169bf215546Sopenharmony_ci bool trivial_array_cast = is_trivial_array_deref_cast(cast); 1170bf215546Sopenharmony_ci 1171bf215546Sopenharmony_ci assert(cast->dest.is_ssa); 1172bf215546Sopenharmony_ci assert(cast->parent.is_ssa); 1173bf215546Sopenharmony_ci 1174bf215546Sopenharmony_ci nir_foreach_use_safe(use_src, &cast->dest.ssa) { 1175bf215546Sopenharmony_ci /* If this isn't a trivial array cast, we can't propagate into 1176bf215546Sopenharmony_ci * ptr_as_array derefs. 1177bf215546Sopenharmony_ci */ 1178bf215546Sopenharmony_ci if (is_deref_ptr_as_array(use_src->parent_instr) && 1179bf215546Sopenharmony_ci !trivial_array_cast) 1180bf215546Sopenharmony_ci continue; 1181bf215546Sopenharmony_ci 1182bf215546Sopenharmony_ci nir_instr_rewrite_src(use_src->parent_instr, use_src, cast->parent); 1183bf215546Sopenharmony_ci progress = true; 1184bf215546Sopenharmony_ci } 1185bf215546Sopenharmony_ci 1186bf215546Sopenharmony_ci /* If uses would be a bit crazy */ 1187bf215546Sopenharmony_ci assert(list_is_empty(&cast->dest.ssa.if_uses)); 1188bf215546Sopenharmony_ci 1189bf215546Sopenharmony_ci if (nir_deref_instr_remove_if_unused(cast)) 1190bf215546Sopenharmony_ci progress = true; 1191bf215546Sopenharmony_ci 1192bf215546Sopenharmony_ci return progress; 1193bf215546Sopenharmony_ci} 1194bf215546Sopenharmony_ci 1195bf215546Sopenharmony_cistatic bool 1196bf215546Sopenharmony_ciopt_deref_ptr_as_array(nir_builder *b, nir_deref_instr *deref) 1197bf215546Sopenharmony_ci{ 1198bf215546Sopenharmony_ci assert(deref->deref_type == nir_deref_type_ptr_as_array); 1199bf215546Sopenharmony_ci 1200bf215546Sopenharmony_ci nir_deref_instr *parent = nir_deref_instr_parent(deref); 1201bf215546Sopenharmony_ci 1202bf215546Sopenharmony_ci if (nir_src_is_const(deref->arr.index) && 1203bf215546Sopenharmony_ci nir_src_as_int(deref->arr.index) == 0) { 1204bf215546Sopenharmony_ci /* If it's a ptr_as_array deref with an index of 0, it does nothing 1205bf215546Sopenharmony_ci * and we can just replace its uses with its parent, unless it has 1206bf215546Sopenharmony_ci * alignment information. 1207bf215546Sopenharmony_ci * 1208bf215546Sopenharmony_ci * The source of a ptr_as_array deref always has a deref_type of 1209bf215546Sopenharmony_ci * nir_deref_type_array or nir_deref_type_cast. If it's a cast, it 1210bf215546Sopenharmony_ci * may be trivial and we may be able to get rid of that too. Any 1211bf215546Sopenharmony_ci * trivial cast of trivial cast cases should be handled already by 1212bf215546Sopenharmony_ci * opt_deref_cast() above. 1213bf215546Sopenharmony_ci */ 1214bf215546Sopenharmony_ci if (parent->deref_type == nir_deref_type_cast && 1215bf215546Sopenharmony_ci parent->cast.align_mul == 0 && 1216bf215546Sopenharmony_ci is_trivial_deref_cast(parent)) 1217bf215546Sopenharmony_ci parent = nir_deref_instr_parent(parent); 1218bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(&deref->dest.ssa, 1219bf215546Sopenharmony_ci &parent->dest.ssa); 1220bf215546Sopenharmony_ci nir_instr_remove(&deref->instr); 1221bf215546Sopenharmony_ci return true; 1222bf215546Sopenharmony_ci } 1223bf215546Sopenharmony_ci 1224bf215546Sopenharmony_ci if (parent->deref_type != nir_deref_type_array && 1225bf215546Sopenharmony_ci parent->deref_type != nir_deref_type_ptr_as_array) 1226bf215546Sopenharmony_ci return false; 1227bf215546Sopenharmony_ci 1228bf215546Sopenharmony_ci assert(parent->parent.is_ssa); 1229bf215546Sopenharmony_ci assert(parent->arr.index.is_ssa); 1230bf215546Sopenharmony_ci assert(deref->arr.index.is_ssa); 1231bf215546Sopenharmony_ci 1232bf215546Sopenharmony_ci deref->arr.in_bounds &= parent->arr.in_bounds; 1233bf215546Sopenharmony_ci 1234bf215546Sopenharmony_ci nir_ssa_def *new_idx = nir_iadd(b, parent->arr.index.ssa, 1235bf215546Sopenharmony_ci deref->arr.index.ssa); 1236bf215546Sopenharmony_ci 1237bf215546Sopenharmony_ci deref->deref_type = parent->deref_type; 1238bf215546Sopenharmony_ci nir_instr_rewrite_src(&deref->instr, &deref->parent, parent->parent); 1239bf215546Sopenharmony_ci nir_instr_rewrite_src(&deref->instr, &deref->arr.index, 1240bf215546Sopenharmony_ci nir_src_for_ssa(new_idx)); 1241bf215546Sopenharmony_ci return true; 1242bf215546Sopenharmony_ci} 1243bf215546Sopenharmony_ci 1244bf215546Sopenharmony_cistatic bool 1245bf215546Sopenharmony_ciis_vector_bitcast_deref(nir_deref_instr *cast, 1246bf215546Sopenharmony_ci nir_component_mask_t mask, 1247bf215546Sopenharmony_ci bool is_write) 1248bf215546Sopenharmony_ci{ 1249bf215546Sopenharmony_ci if (cast->deref_type != nir_deref_type_cast) 1250bf215546Sopenharmony_ci return false; 1251bf215546Sopenharmony_ci 1252bf215546Sopenharmony_ci /* Don't throw away useful alignment information */ 1253bf215546Sopenharmony_ci if (cast->cast.align_mul > 0) 1254bf215546Sopenharmony_ci return false; 1255bf215546Sopenharmony_ci 1256bf215546Sopenharmony_ci /* It has to be a cast of another deref */ 1257bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(cast->parent); 1258bf215546Sopenharmony_ci if (parent == NULL) 1259bf215546Sopenharmony_ci return false; 1260bf215546Sopenharmony_ci 1261bf215546Sopenharmony_ci /* The parent has to be a vector or scalar */ 1262bf215546Sopenharmony_ci if (!glsl_type_is_vector_or_scalar(parent->type)) 1263bf215546Sopenharmony_ci return false; 1264bf215546Sopenharmony_ci 1265bf215546Sopenharmony_ci /* Don't bother with 1-bit types */ 1266bf215546Sopenharmony_ci unsigned cast_bit_size = glsl_get_bit_size(cast->type); 1267bf215546Sopenharmony_ci unsigned parent_bit_size = glsl_get_bit_size(parent->type); 1268bf215546Sopenharmony_ci if (cast_bit_size == 1 || parent_bit_size == 1) 1269bf215546Sopenharmony_ci return false; 1270bf215546Sopenharmony_ci 1271bf215546Sopenharmony_ci /* A strided vector type means it's not tightly packed */ 1272bf215546Sopenharmony_ci if (glsl_get_explicit_stride(cast->type) || 1273bf215546Sopenharmony_ci glsl_get_explicit_stride(parent->type)) 1274bf215546Sopenharmony_ci return false; 1275bf215546Sopenharmony_ci 1276bf215546Sopenharmony_ci assert(cast_bit_size > 0 && cast_bit_size % 8 == 0); 1277bf215546Sopenharmony_ci assert(parent_bit_size > 0 && parent_bit_size % 8 == 0); 1278bf215546Sopenharmony_ci unsigned bytes_used = util_last_bit(mask) * (cast_bit_size / 8); 1279bf215546Sopenharmony_ci unsigned parent_bytes = glsl_get_vector_elements(parent->type) * 1280bf215546Sopenharmony_ci (parent_bit_size / 8); 1281bf215546Sopenharmony_ci if (bytes_used > parent_bytes) 1282bf215546Sopenharmony_ci return false; 1283bf215546Sopenharmony_ci 1284bf215546Sopenharmony_ci if (is_write && !nir_component_mask_can_reinterpret(mask, cast_bit_size, 1285bf215546Sopenharmony_ci parent_bit_size)) 1286bf215546Sopenharmony_ci return false; 1287bf215546Sopenharmony_ci 1288bf215546Sopenharmony_ci return true; 1289bf215546Sopenharmony_ci} 1290bf215546Sopenharmony_ci 1291bf215546Sopenharmony_cistatic nir_ssa_def * 1292bf215546Sopenharmony_ciresize_vector(nir_builder *b, nir_ssa_def *data, unsigned num_components) 1293bf215546Sopenharmony_ci{ 1294bf215546Sopenharmony_ci if (num_components == data->num_components) 1295bf215546Sopenharmony_ci return data; 1296bf215546Sopenharmony_ci 1297bf215546Sopenharmony_ci unsigned swiz[NIR_MAX_VEC_COMPONENTS] = { 0, }; 1298bf215546Sopenharmony_ci for (unsigned i = 0; i < MIN2(num_components, data->num_components); i++) 1299bf215546Sopenharmony_ci swiz[i] = i; 1300bf215546Sopenharmony_ci 1301bf215546Sopenharmony_ci return nir_swizzle(b, data, swiz, num_components); 1302bf215546Sopenharmony_ci} 1303bf215546Sopenharmony_ci 1304bf215546Sopenharmony_cistatic bool 1305bf215546Sopenharmony_ciopt_load_vec_deref(nir_builder *b, nir_intrinsic_instr *load) 1306bf215546Sopenharmony_ci{ 1307bf215546Sopenharmony_ci nir_deref_instr *deref = nir_src_as_deref(load->src[0]); 1308bf215546Sopenharmony_ci nir_component_mask_t read_mask = 1309bf215546Sopenharmony_ci nir_ssa_def_components_read(&load->dest.ssa); 1310bf215546Sopenharmony_ci 1311bf215546Sopenharmony_ci /* LLVM loves take advantage of the fact that vec3s in OpenCL are 1312bf215546Sopenharmony_ci * vec4-aligned and so it can just read/write them as vec4s. This 1313bf215546Sopenharmony_ci * results in a LOT of vec4->vec3 casts on loads and stores. 1314bf215546Sopenharmony_ci */ 1315bf215546Sopenharmony_ci if (is_vector_bitcast_deref(deref, read_mask, false)) { 1316bf215546Sopenharmony_ci const unsigned old_num_comps = load->dest.ssa.num_components; 1317bf215546Sopenharmony_ci const unsigned old_bit_size = load->dest.ssa.bit_size; 1318bf215546Sopenharmony_ci 1319bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(deref->parent); 1320bf215546Sopenharmony_ci const unsigned new_num_comps = glsl_get_vector_elements(parent->type); 1321bf215546Sopenharmony_ci const unsigned new_bit_size = glsl_get_bit_size(parent->type); 1322bf215546Sopenharmony_ci 1323bf215546Sopenharmony_ci /* Stomp it to reference the parent */ 1324bf215546Sopenharmony_ci nir_instr_rewrite_src(&load->instr, &load->src[0], 1325bf215546Sopenharmony_ci nir_src_for_ssa(&parent->dest.ssa)); 1326bf215546Sopenharmony_ci assert(load->dest.is_ssa); 1327bf215546Sopenharmony_ci load->dest.ssa.bit_size = new_bit_size; 1328bf215546Sopenharmony_ci load->dest.ssa.num_components = new_num_comps; 1329bf215546Sopenharmony_ci load->num_components = new_num_comps; 1330bf215546Sopenharmony_ci 1331bf215546Sopenharmony_ci b->cursor = nir_after_instr(&load->instr); 1332bf215546Sopenharmony_ci nir_ssa_def *data = &load->dest.ssa; 1333bf215546Sopenharmony_ci if (old_bit_size != new_bit_size) 1334bf215546Sopenharmony_ci data = nir_bitcast_vector(b, &load->dest.ssa, old_bit_size); 1335bf215546Sopenharmony_ci data = resize_vector(b, data, old_num_comps); 1336bf215546Sopenharmony_ci 1337bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses_after(&load->dest.ssa, data, 1338bf215546Sopenharmony_ci data->parent_instr); 1339bf215546Sopenharmony_ci return true; 1340bf215546Sopenharmony_ci } 1341bf215546Sopenharmony_ci 1342bf215546Sopenharmony_ci return false; 1343bf215546Sopenharmony_ci} 1344bf215546Sopenharmony_ci 1345bf215546Sopenharmony_cistatic bool 1346bf215546Sopenharmony_ciopt_store_vec_deref(nir_builder *b, nir_intrinsic_instr *store) 1347bf215546Sopenharmony_ci{ 1348bf215546Sopenharmony_ci nir_deref_instr *deref = nir_src_as_deref(store->src[0]); 1349bf215546Sopenharmony_ci nir_component_mask_t write_mask = nir_intrinsic_write_mask(store); 1350bf215546Sopenharmony_ci 1351bf215546Sopenharmony_ci /* LLVM loves take advantage of the fact that vec3s in OpenCL are 1352bf215546Sopenharmony_ci * vec4-aligned and so it can just read/write them as vec4s. This 1353bf215546Sopenharmony_ci * results in a LOT of vec4->vec3 casts on loads and stores. 1354bf215546Sopenharmony_ci */ 1355bf215546Sopenharmony_ci if (is_vector_bitcast_deref(deref, write_mask, true)) { 1356bf215546Sopenharmony_ci assert(store->src[1].is_ssa); 1357bf215546Sopenharmony_ci nir_ssa_def *data = store->src[1].ssa; 1358bf215546Sopenharmony_ci 1359bf215546Sopenharmony_ci const unsigned old_bit_size = data->bit_size; 1360bf215546Sopenharmony_ci 1361bf215546Sopenharmony_ci nir_deref_instr *parent = nir_src_as_deref(deref->parent); 1362bf215546Sopenharmony_ci const unsigned new_num_comps = glsl_get_vector_elements(parent->type); 1363bf215546Sopenharmony_ci const unsigned new_bit_size = glsl_get_bit_size(parent->type); 1364bf215546Sopenharmony_ci 1365bf215546Sopenharmony_ci nir_instr_rewrite_src(&store->instr, &store->src[0], 1366bf215546Sopenharmony_ci nir_src_for_ssa(&parent->dest.ssa)); 1367bf215546Sopenharmony_ci 1368bf215546Sopenharmony_ci /* Restrict things down as needed so the bitcast doesn't fail */ 1369bf215546Sopenharmony_ci data = nir_channels(b, data, (1 << util_last_bit(write_mask)) - 1); 1370bf215546Sopenharmony_ci if (old_bit_size != new_bit_size) 1371bf215546Sopenharmony_ci data = nir_bitcast_vector(b, data, new_bit_size); 1372bf215546Sopenharmony_ci data = resize_vector(b, data, new_num_comps); 1373bf215546Sopenharmony_ci nir_instr_rewrite_src(&store->instr, &store->src[1], 1374bf215546Sopenharmony_ci nir_src_for_ssa(data)); 1375bf215546Sopenharmony_ci store->num_components = new_num_comps; 1376bf215546Sopenharmony_ci 1377bf215546Sopenharmony_ci /* Adjust the write mask */ 1378bf215546Sopenharmony_ci write_mask = nir_component_mask_reinterpret(write_mask, old_bit_size, 1379bf215546Sopenharmony_ci new_bit_size); 1380bf215546Sopenharmony_ci nir_intrinsic_set_write_mask(store, write_mask); 1381bf215546Sopenharmony_ci return true; 1382bf215546Sopenharmony_ci } 1383bf215546Sopenharmony_ci 1384bf215546Sopenharmony_ci return false; 1385bf215546Sopenharmony_ci} 1386bf215546Sopenharmony_ci 1387bf215546Sopenharmony_cistatic bool 1388bf215546Sopenharmony_ciopt_known_deref_mode_is(nir_builder *b, nir_intrinsic_instr *intrin) 1389bf215546Sopenharmony_ci{ 1390bf215546Sopenharmony_ci nir_variable_mode modes = nir_intrinsic_memory_modes(intrin); 1391bf215546Sopenharmony_ci nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); 1392bf215546Sopenharmony_ci if (deref == NULL) 1393bf215546Sopenharmony_ci return false; 1394bf215546Sopenharmony_ci 1395bf215546Sopenharmony_ci nir_ssa_def *deref_is = NULL; 1396bf215546Sopenharmony_ci 1397bf215546Sopenharmony_ci if (nir_deref_mode_must_be(deref, modes)) 1398bf215546Sopenharmony_ci deref_is = nir_imm_true(b); 1399bf215546Sopenharmony_ci 1400bf215546Sopenharmony_ci if (!nir_deref_mode_may_be(deref, modes)) 1401bf215546Sopenharmony_ci deref_is = nir_imm_false(b); 1402bf215546Sopenharmony_ci 1403bf215546Sopenharmony_ci if (deref_is == NULL) 1404bf215546Sopenharmony_ci return false; 1405bf215546Sopenharmony_ci 1406bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(&intrin->dest.ssa, deref_is); 1407bf215546Sopenharmony_ci nir_instr_remove(&intrin->instr); 1408bf215546Sopenharmony_ci return true; 1409bf215546Sopenharmony_ci} 1410bf215546Sopenharmony_ci 1411bf215546Sopenharmony_cibool 1412bf215546Sopenharmony_cinir_opt_deref_impl(nir_function_impl *impl) 1413bf215546Sopenharmony_ci{ 1414bf215546Sopenharmony_ci bool progress = false; 1415bf215546Sopenharmony_ci 1416bf215546Sopenharmony_ci nir_builder b; 1417bf215546Sopenharmony_ci nir_builder_init(&b, impl); 1418bf215546Sopenharmony_ci 1419bf215546Sopenharmony_ci nir_foreach_block(block, impl) { 1420bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 1421bf215546Sopenharmony_ci b.cursor = nir_before_instr(instr); 1422bf215546Sopenharmony_ci 1423bf215546Sopenharmony_ci switch (instr->type) { 1424bf215546Sopenharmony_ci case nir_instr_type_alu: { 1425bf215546Sopenharmony_ci nir_alu_instr *alu = nir_instr_as_alu(instr); 1426bf215546Sopenharmony_ci if (opt_alu_of_cast(alu)) 1427bf215546Sopenharmony_ci progress = true; 1428bf215546Sopenharmony_ci break; 1429bf215546Sopenharmony_ci } 1430bf215546Sopenharmony_ci 1431bf215546Sopenharmony_ci case nir_instr_type_deref: { 1432bf215546Sopenharmony_ci nir_deref_instr *deref = nir_instr_as_deref(instr); 1433bf215546Sopenharmony_ci 1434bf215546Sopenharmony_ci if (opt_restrict_deref_modes(deref)) 1435bf215546Sopenharmony_ci progress = true; 1436bf215546Sopenharmony_ci 1437bf215546Sopenharmony_ci switch (deref->deref_type) { 1438bf215546Sopenharmony_ci case nir_deref_type_ptr_as_array: 1439bf215546Sopenharmony_ci if (opt_deref_ptr_as_array(&b, deref)) 1440bf215546Sopenharmony_ci progress = true; 1441bf215546Sopenharmony_ci break; 1442bf215546Sopenharmony_ci 1443bf215546Sopenharmony_ci case nir_deref_type_cast: 1444bf215546Sopenharmony_ci if (opt_deref_cast(&b, deref)) 1445bf215546Sopenharmony_ci progress = true; 1446bf215546Sopenharmony_ci break; 1447bf215546Sopenharmony_ci 1448bf215546Sopenharmony_ci default: 1449bf215546Sopenharmony_ci /* Do nothing */ 1450bf215546Sopenharmony_ci break; 1451bf215546Sopenharmony_ci } 1452bf215546Sopenharmony_ci break; 1453bf215546Sopenharmony_ci } 1454bf215546Sopenharmony_ci 1455bf215546Sopenharmony_ci case nir_instr_type_intrinsic: { 1456bf215546Sopenharmony_ci nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 1457bf215546Sopenharmony_ci switch (intrin->intrinsic) { 1458bf215546Sopenharmony_ci case nir_intrinsic_load_deref: 1459bf215546Sopenharmony_ci if (opt_load_vec_deref(&b, intrin)) 1460bf215546Sopenharmony_ci progress = true; 1461bf215546Sopenharmony_ci break; 1462bf215546Sopenharmony_ci 1463bf215546Sopenharmony_ci case nir_intrinsic_store_deref: 1464bf215546Sopenharmony_ci if (opt_store_vec_deref(&b, intrin)) 1465bf215546Sopenharmony_ci progress = true; 1466bf215546Sopenharmony_ci break; 1467bf215546Sopenharmony_ci 1468bf215546Sopenharmony_ci case nir_intrinsic_deref_mode_is: 1469bf215546Sopenharmony_ci if (opt_known_deref_mode_is(&b, intrin)) 1470bf215546Sopenharmony_ci progress = true; 1471bf215546Sopenharmony_ci break; 1472bf215546Sopenharmony_ci 1473bf215546Sopenharmony_ci default: 1474bf215546Sopenharmony_ci /* Do nothing */ 1475bf215546Sopenharmony_ci break; 1476bf215546Sopenharmony_ci } 1477bf215546Sopenharmony_ci break; 1478bf215546Sopenharmony_ci } 1479bf215546Sopenharmony_ci 1480bf215546Sopenharmony_ci default: 1481bf215546Sopenharmony_ci /* Do nothing */ 1482bf215546Sopenharmony_ci break; 1483bf215546Sopenharmony_ci } 1484bf215546Sopenharmony_ci } 1485bf215546Sopenharmony_ci } 1486bf215546Sopenharmony_ci 1487bf215546Sopenharmony_ci if (progress) { 1488bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_block_index | 1489bf215546Sopenharmony_ci nir_metadata_dominance); 1490bf215546Sopenharmony_ci } else { 1491bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_all); 1492bf215546Sopenharmony_ci } 1493bf215546Sopenharmony_ci 1494bf215546Sopenharmony_ci return progress; 1495bf215546Sopenharmony_ci} 1496bf215546Sopenharmony_ci 1497bf215546Sopenharmony_cibool 1498bf215546Sopenharmony_cinir_opt_deref(nir_shader *shader) 1499bf215546Sopenharmony_ci{ 1500bf215546Sopenharmony_ci bool progress = false; 1501bf215546Sopenharmony_ci 1502bf215546Sopenharmony_ci nir_foreach_function(func, shader) { 1503bf215546Sopenharmony_ci if (func->impl && nir_opt_deref_impl(func->impl)) 1504bf215546Sopenharmony_ci progress = true; 1505bf215546Sopenharmony_ci } 1506bf215546Sopenharmony_ci 1507bf215546Sopenharmony_ci return progress; 1508bf215546Sopenharmony_ci} 1509