1/* 2 * Copyright © 2018 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "nir.h" 25#include "nir_builder.h" 26#include "nir_deref.h" 27#include "util/hash_table.h" 28 29void 30nir_deref_path_init(nir_deref_path *path, 31 nir_deref_instr *deref, void *mem_ctx) 32{ 33 assert(deref != NULL); 34 35 /* The length of the short path is at most ARRAY_SIZE - 1 because we need 36 * room for the NULL terminator. 37 */ 38 static const int max_short_path_len = ARRAY_SIZE(path->_short_path) - 1; 39 40 int count = 0; 41 42 nir_deref_instr **tail = &path->_short_path[max_short_path_len]; 43 nir_deref_instr **head = tail; 44 45 *tail = NULL; 46 for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) { 47 count++; 48 if (count <= max_short_path_len) 49 *(--head) = d; 50 } 51 52 if (count <= max_short_path_len) { 53 /* If we're under max_short_path_len, just use the short path. */ 54 path->path = head; 55 goto done; 56 } 57 58#ifndef NDEBUG 59 /* Just in case someone uses short_path by accident */ 60 for (unsigned i = 0; i < ARRAY_SIZE(path->_short_path); i++) 61 path->_short_path[i] = (void *)0xdeadbeef; 62#endif 63 64 path->path = ralloc_array(mem_ctx, nir_deref_instr *, count + 1); 65 head = tail = path->path + count; 66 *tail = NULL; 67 for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) 68 *(--head) = d; 69 70done: 71 assert(head == path->path); 72 assert(tail == head + count); 73 assert(*tail == NULL); 74} 75 76void 77nir_deref_path_finish(nir_deref_path *path) 78{ 79 if (path->path < &path->_short_path[0] || 80 path->path > &path->_short_path[ARRAY_SIZE(path->_short_path) - 1]) 81 ralloc_free(path->path); 82} 83 84/** 85 * Recursively removes unused deref instructions 86 */ 87bool 88nir_deref_instr_remove_if_unused(nir_deref_instr *instr) 89{ 90 bool progress = false; 91 92 for (nir_deref_instr *d = instr; d; d = nir_deref_instr_parent(d)) { 93 /* If anyone is using this deref, leave it alone */ 94 assert(d->dest.is_ssa); 95 if (!list_empty(&d->dest.ssa.uses)) 96 break; 97 98 nir_instr_remove(&d->instr); 99 progress = true; 100 } 101 102 return progress; 103} 104 105bool 106nir_deref_instr_has_indirect(nir_deref_instr *instr) 107{ 108 while (instr->deref_type != nir_deref_type_var) { 109 /* Consider casts to be indirects */ 110 if (instr->deref_type == nir_deref_type_cast) 111 return true; 112 113 if ((instr->deref_type == nir_deref_type_array || 114 instr->deref_type == nir_deref_type_ptr_as_array) && 115 !nir_src_is_const(instr->arr.index)) 116 return true; 117 118 instr = nir_deref_instr_parent(instr); 119 } 120 121 return false; 122} 123 124unsigned 125nir_deref_instr_ptr_as_array_stride(nir_deref_instr *deref) 126{ 127 switch (deref->deref_type) { 128 case nir_deref_type_array: 129 return glsl_get_explicit_stride(nir_deref_instr_parent(deref)->type); 130 case nir_deref_type_ptr_as_array: 131 return nir_deref_instr_ptr_as_array_stride(nir_deref_instr_parent(deref)); 132 case nir_deref_type_cast: 133 return deref->cast.ptr_stride; 134 default: 135 return 0; 136 } 137} 138 139static unsigned 140type_get_array_stride(const struct glsl_type *elem_type, 141 glsl_type_size_align_func size_align) 142{ 143 unsigned elem_size, elem_align; 144 size_align(elem_type, &elem_size, &elem_align); 145 return ALIGN_POT(elem_size, elem_align); 146} 147 148static unsigned 149struct_type_get_field_offset(const struct glsl_type *struct_type, 150 glsl_type_size_align_func size_align, 151 unsigned field_idx) 152{ 153 assert(glsl_type_is_struct_or_ifc(struct_type)); 154 unsigned offset = 0; 155 for (unsigned i = 0; i <= field_idx; i++) { 156 unsigned elem_size, elem_align; 157 size_align(glsl_get_struct_field(struct_type, i), &elem_size, &elem_align); 158 offset = ALIGN_POT(offset, elem_align); 159 if (i < field_idx) 160 offset += elem_size; 161 } 162 return offset; 163} 164 165unsigned 166nir_deref_instr_get_const_offset(nir_deref_instr *deref, 167 glsl_type_size_align_func size_align) 168{ 169 nir_deref_path path; 170 nir_deref_path_init(&path, deref, NULL); 171 172 assert(path.path[0]->deref_type == nir_deref_type_var); 173 174 unsigned offset = 0; 175 for (nir_deref_instr **p = &path.path[1]; *p; p++) { 176 if ((*p)->deref_type == nir_deref_type_array) { 177 offset += nir_src_as_uint((*p)->arr.index) * 178 type_get_array_stride((*p)->type, size_align); 179 } else if ((*p)->deref_type == nir_deref_type_struct) { 180 /* p starts at path[1], so this is safe */ 181 nir_deref_instr *parent = *(p - 1); 182 offset += struct_type_get_field_offset(parent->type, size_align, 183 (*p)->strct.index); 184 } else { 185 unreachable("Unsupported deref type"); 186 } 187 } 188 189 nir_deref_path_finish(&path); 190 191 return offset; 192} 193 194nir_ssa_def * 195nir_build_deref_offset(nir_builder *b, nir_deref_instr *deref, 196 glsl_type_size_align_func size_align) 197{ 198 nir_deref_path path; 199 nir_deref_path_init(&path, deref, NULL); 200 201 assert(path.path[0]->deref_type == nir_deref_type_var); 202 203 nir_ssa_def *offset = nir_imm_int(b, 0); 204 for (nir_deref_instr **p = &path.path[1]; *p; p++) { 205 if ((*p)->deref_type == nir_deref_type_array) { 206 nir_ssa_def *index = nir_ssa_for_src(b, (*p)->arr.index, 1); 207 int stride = type_get_array_stride((*p)->type, size_align); 208 offset = nir_iadd(b, offset, nir_imul_imm(b, index, stride)); 209 } else if ((*p)->deref_type == nir_deref_type_struct) { 210 /* p starts at path[1], so this is safe */ 211 nir_deref_instr *parent = *(p - 1); 212 unsigned field_offset = 213 struct_type_get_field_offset(parent->type, size_align, 214 (*p)->strct.index); 215 offset = nir_iadd_imm(b, offset, field_offset); 216 } else { 217 unreachable("Unsupported deref type"); 218 } 219 } 220 221 nir_deref_path_finish(&path); 222 223 return offset; 224} 225 226bool 227nir_remove_dead_derefs_impl(nir_function_impl *impl) 228{ 229 bool progress = false; 230 231 nir_foreach_block(block, impl) { 232 nir_foreach_instr_safe(instr, block) { 233 if (instr->type == nir_instr_type_deref && 234 nir_deref_instr_remove_if_unused(nir_instr_as_deref(instr))) 235 progress = true; 236 } 237 } 238 239 if (progress) 240 nir_metadata_preserve(impl, nir_metadata_block_index | 241 nir_metadata_dominance); 242 243 return progress; 244} 245 246bool 247nir_remove_dead_derefs(nir_shader *shader) 248{ 249 bool progress = false; 250 nir_foreach_function(function, shader) { 251 if (function->impl && nir_remove_dead_derefs_impl(function->impl)) 252 progress = true; 253 } 254 255 return progress; 256} 257 258void 259nir_fixup_deref_modes(nir_shader *shader) 260{ 261 nir_foreach_function(function, shader) { 262 if (!function->impl) 263 continue; 264 265 nir_foreach_block(block, function->impl) { 266 nir_foreach_instr(instr, block) { 267 if (instr->type != nir_instr_type_deref) 268 continue; 269 270 nir_deref_instr *deref = nir_instr_as_deref(instr); 271 if (deref->deref_type == nir_deref_type_cast) 272 continue; 273 274 nir_variable_mode parent_mode; 275 if (deref->deref_type == nir_deref_type_var) { 276 parent_mode = deref->var->data.mode; 277 } else { 278 assert(deref->parent.is_ssa); 279 nir_deref_instr *parent = 280 nir_instr_as_deref(deref->parent.ssa->parent_instr); 281 parent_mode = parent->mode; 282 } 283 284 deref->mode = parent_mode; 285 } 286 } 287 } 288} 289 290static bool 291modes_may_alias(nir_variable_mode a, nir_variable_mode b) 292{ 293 /* Generic pointers can alias with SSBOs */ 294 if ((a == nir_var_mem_ssbo || a == nir_var_mem_global) && 295 (b == nir_var_mem_ssbo || b == nir_var_mem_global)) 296 return true; 297 298 /* In the general case, pointers can only alias if they have the same mode. 299 * 300 * NOTE: In future, with things like OpenCL generic pointers, this may not 301 * be true and will have to be re-evaluated. However, with graphics only, 302 * it should be safe. 303 */ 304 return a == b; 305} 306 307static bool 308deref_path_contains_coherent_decoration(nir_deref_path *path) 309{ 310 assert(path->path[0]->deref_type == nir_deref_type_var); 311 312 if (path->path[0]->var->data.image.access & ACCESS_COHERENT) 313 return true; 314 315 for (nir_deref_instr **p = &path->path[1]; *p; p++) { 316 if ((*p)->deref_type != nir_deref_type_struct) 317 continue; 318 319 const struct glsl_type *struct_type = (*(p - 1))->type; 320 const struct glsl_struct_field *field = 321 glsl_get_struct_field_data(struct_type, (*p)->strct.index); 322 if (field->memory_coherent) 323 return true; 324 } 325 326 return false; 327} 328 329nir_deref_compare_result 330nir_compare_deref_paths(nir_deref_path *a_path, 331 nir_deref_path *b_path) 332{ 333 if (!modes_may_alias(b_path->path[0]->mode, a_path->path[0]->mode)) 334 return nir_derefs_do_not_alias; 335 336 if (a_path->path[0]->deref_type != b_path->path[0]->deref_type) 337 return nir_derefs_may_alias_bit; 338 339 if (a_path->path[0]->deref_type == nir_deref_type_var) { 340 if (a_path->path[0]->var != b_path->path[0]->var) { 341 /* Shader and function temporaries aren't backed by memory so two 342 * distinct variables never alias. 343 */ 344 static const nir_variable_mode temp_var_modes = 345 nir_var_shader_temp | nir_var_function_temp; 346 if ((a_path->path[0]->mode & temp_var_modes) || 347 (b_path->path[0]->mode & temp_var_modes)) 348 return nir_derefs_do_not_alias; 349 350 /* If they are both declared coherent or have coherent somewhere in 351 * their path (due to a member of an interface being declared 352 * coherent), we have to assume we that we could have any kind of 353 * aliasing. Otherwise, they could still alias but the client didn't 354 * tell us and that's their fault. 355 */ 356 if (deref_path_contains_coherent_decoration(a_path) && 357 deref_path_contains_coherent_decoration(b_path)) 358 return nir_derefs_may_alias_bit; 359 360 /* If we can chase the deref all the way back to the variable and 361 * they're not the same variable and at least one is not declared 362 * coherent, we know they can't possibly alias. 363 */ 364 return nir_derefs_do_not_alias; 365 } 366 } else { 367 assert(a_path->path[0]->deref_type == nir_deref_type_cast); 368 /* If they're not exactly the same cast, it's hard to compare them so we 369 * just assume they alias. Comparing casts is tricky as there are lots 370 * of things such as mode, type, etc. to make sure work out; for now, we 371 * just assume nit_opt_deref will combine them and compare the deref 372 * instructions. 373 * 374 * TODO: At some point in the future, we could be clever and understand 375 * that a float[] and int[] have the same layout and aliasing structure 376 * but double[] and vec3[] do not and we could potentially be a bit 377 * smarter here. 378 */ 379 if (a_path->path[0] != b_path->path[0]) 380 return nir_derefs_may_alias_bit; 381 } 382 383 /* Start off assuming they fully compare. We ignore equality for now. In 384 * the end, we'll determine that by containment. 385 */ 386 nir_deref_compare_result result = nir_derefs_may_alias_bit | 387 nir_derefs_a_contains_b_bit | 388 nir_derefs_b_contains_a_bit; 389 390 nir_deref_instr **a_p = &a_path->path[1]; 391 nir_deref_instr **b_p = &b_path->path[1]; 392 while (*a_p != NULL && *a_p == *b_p) { 393 a_p++; 394 b_p++; 395 } 396 397 /* We're at either the tail or the divergence point between the two deref 398 * paths. Look to see if either contains a ptr_as_array deref. It it 399 * does we don't know how to safely make any inferences. Hopefully, 400 * nir_opt_deref will clean most of these up and we can start inferring 401 * things again. 402 * 403 * In theory, we could do a bit better. For instance, we could detect the 404 * case where we have exactly one ptr_as_array deref in the chain after the 405 * divergence point and it's matched in both chains and the two chains have 406 * different constant indices. 407 */ 408 for (nir_deref_instr **t_p = a_p; *t_p; t_p++) { 409 if ((*t_p)->deref_type == nir_deref_type_ptr_as_array) 410 return nir_derefs_may_alias_bit; 411 } 412 for (nir_deref_instr **t_p = b_p; *t_p; t_p++) { 413 if ((*t_p)->deref_type == nir_deref_type_ptr_as_array) 414 return nir_derefs_may_alias_bit; 415 } 416 417 while (*a_p != NULL && *b_p != NULL) { 418 nir_deref_instr *a_tail = *(a_p++); 419 nir_deref_instr *b_tail = *(b_p++); 420 421 switch (a_tail->deref_type) { 422 case nir_deref_type_array: 423 case nir_deref_type_array_wildcard: { 424 assert(b_tail->deref_type == nir_deref_type_array || 425 b_tail->deref_type == nir_deref_type_array_wildcard); 426 427 if (a_tail->deref_type == nir_deref_type_array_wildcard) { 428 if (b_tail->deref_type != nir_deref_type_array_wildcard) 429 result &= ~nir_derefs_b_contains_a_bit; 430 } else if (b_tail->deref_type == nir_deref_type_array_wildcard) { 431 if (a_tail->deref_type != nir_deref_type_array_wildcard) 432 result &= ~nir_derefs_a_contains_b_bit; 433 } else { 434 assert(a_tail->deref_type == nir_deref_type_array && 435 b_tail->deref_type == nir_deref_type_array); 436 assert(a_tail->arr.index.is_ssa && b_tail->arr.index.is_ssa); 437 438 if (nir_src_is_const(a_tail->arr.index) && 439 nir_src_is_const(b_tail->arr.index)) { 440 /* If they're both direct and have different offsets, they 441 * don't even alias much less anything else. 442 */ 443 if (nir_src_as_uint(a_tail->arr.index) != 444 nir_src_as_uint(b_tail->arr.index)) 445 return nir_derefs_do_not_alias; 446 } else if (a_tail->arr.index.ssa == b_tail->arr.index.ssa) { 447 /* They're the same indirect, continue on */ 448 } else { 449 /* They're not the same index so we can't prove anything about 450 * containment. 451 */ 452 result &= ~(nir_derefs_a_contains_b_bit | nir_derefs_b_contains_a_bit); 453 } 454 } 455 break; 456 } 457 458 case nir_deref_type_struct: { 459 /* If they're different struct members, they don't even alias */ 460 if (a_tail->strct.index != b_tail->strct.index) 461 return nir_derefs_do_not_alias; 462 break; 463 } 464 465 default: 466 unreachable("Invalid deref type"); 467 } 468 } 469 470 /* If a is longer than b, then it can't contain b */ 471 if (*a_p != NULL) 472 result &= ~nir_derefs_a_contains_b_bit; 473 if (*b_p != NULL) 474 result &= ~nir_derefs_b_contains_a_bit; 475 476 /* If a contains b and b contains a they must be equal. */ 477 if ((result & nir_derefs_a_contains_b_bit) && (result & nir_derefs_b_contains_a_bit)) 478 result |= nir_derefs_equal_bit; 479 480 return result; 481} 482 483nir_deref_compare_result 484nir_compare_derefs(nir_deref_instr *a, nir_deref_instr *b) 485{ 486 if (a == b) { 487 return nir_derefs_equal_bit | nir_derefs_may_alias_bit | 488 nir_derefs_a_contains_b_bit | nir_derefs_b_contains_a_bit; 489 } 490 491 nir_deref_path a_path, b_path; 492 nir_deref_path_init(&a_path, a, NULL); 493 nir_deref_path_init(&b_path, b, NULL); 494 assert(a_path.path[0]->deref_type == nir_deref_type_var || 495 a_path.path[0]->deref_type == nir_deref_type_cast); 496 assert(b_path.path[0]->deref_type == nir_deref_type_var || 497 b_path.path[0]->deref_type == nir_deref_type_cast); 498 499 nir_deref_compare_result result = nir_compare_deref_paths(&a_path, &b_path); 500 501 nir_deref_path_finish(&a_path); 502 nir_deref_path_finish(&b_path); 503 504 return result; 505} 506 507struct rematerialize_deref_state { 508 bool progress; 509 nir_builder builder; 510 nir_block *block; 511 struct hash_table *cache; 512}; 513 514static nir_deref_instr * 515rematerialize_deref_in_block(nir_deref_instr *deref, 516 struct rematerialize_deref_state *state) 517{ 518 if (deref->instr.block == state->block) 519 return deref; 520 521 if (!state->cache) { 522 state->cache = _mesa_pointer_hash_table_create(NULL); 523 } 524 525 struct hash_entry *cached = _mesa_hash_table_search(state->cache, deref); 526 if (cached) 527 return cached->data; 528 529 nir_builder *b = &state->builder; 530 nir_deref_instr *new_deref = 531 nir_deref_instr_create(b->shader, deref->deref_type); 532 new_deref->mode = deref->mode; 533 new_deref->type = deref->type; 534 535 if (deref->deref_type == nir_deref_type_var) { 536 new_deref->var = deref->var; 537 } else { 538 nir_deref_instr *parent = nir_src_as_deref(deref->parent); 539 if (parent) { 540 parent = rematerialize_deref_in_block(parent, state); 541 new_deref->parent = nir_src_for_ssa(&parent->dest.ssa); 542 } else { 543 nir_src_copy(&new_deref->parent, &deref->parent, new_deref); 544 } 545 } 546 547 switch (deref->deref_type) { 548 case nir_deref_type_var: 549 case nir_deref_type_array_wildcard: 550 case nir_deref_type_cast: 551 /* Nothing more to do */ 552 break; 553 554 case nir_deref_type_array: 555 assert(!nir_src_as_deref(deref->arr.index)); 556 nir_src_copy(&new_deref->arr.index, &deref->arr.index, new_deref); 557 break; 558 559 case nir_deref_type_struct: 560 new_deref->strct.index = deref->strct.index; 561 break; 562 563 default: 564 unreachable("Invalid deref instruction type"); 565 } 566 567 nir_ssa_dest_init(&new_deref->instr, &new_deref->dest, 568 deref->dest.ssa.num_components, 569 deref->dest.ssa.bit_size, 570 deref->dest.ssa.name); 571 nir_builder_instr_insert(b, &new_deref->instr); 572 573 return new_deref; 574} 575 576static bool 577rematerialize_deref_src(nir_src *src, void *_state) 578{ 579 struct rematerialize_deref_state *state = _state; 580 581 nir_deref_instr *deref = nir_src_as_deref(*src); 582 if (!deref) 583 return true; 584 585 nir_deref_instr *block_deref = rematerialize_deref_in_block(deref, state); 586 if (block_deref != deref) { 587 nir_instr_rewrite_src(src->parent_instr, src, 588 nir_src_for_ssa(&block_deref->dest.ssa)); 589 nir_deref_instr_remove_if_unused(deref); 590 state->progress = true; 591 } 592 593 return true; 594} 595 596/** Re-materialize derefs in every block 597 * 598 * This pass re-materializes deref instructions in every block in which it is 599 * used. After this pass has been run, every use of a deref will be of a 600 * deref in the same block as the use. Also, all unused derefs will be 601 * deleted as a side-effect. 602 */ 603bool 604nir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl *impl) 605{ 606 struct rematerialize_deref_state state = { 0 }; 607 nir_builder_init(&state.builder, impl); 608 609 nir_foreach_block(block, impl) { 610 state.block = block; 611 612 /* Start each block with a fresh cache */ 613 if (state.cache) 614 _mesa_hash_table_clear(state.cache, NULL); 615 616 nir_foreach_instr_safe(instr, block) { 617 if (instr->type == nir_instr_type_deref && 618 nir_deref_instr_remove_if_unused(nir_instr_as_deref(instr))) 619 continue; 620 621 state.builder.cursor = nir_before_instr(instr); 622 nir_foreach_src(instr, rematerialize_deref_src, &state); 623 } 624 625#ifndef NDEBUG 626 nir_if *following_if = nir_block_get_following_if(block); 627 if (following_if) 628 assert(!nir_src_as_deref(following_if->condition)); 629#endif 630 } 631 632 _mesa_hash_table_destroy(state.cache, NULL); 633 634 return state.progress; 635} 636 637static bool 638is_trivial_deref_cast(nir_deref_instr *cast) 639{ 640 nir_deref_instr *parent = nir_src_as_deref(cast->parent); 641 if (!parent) 642 return false; 643 644 return cast->mode == parent->mode && 645 cast->type == parent->type && 646 cast->dest.ssa.num_components == parent->dest.ssa.num_components && 647 cast->dest.ssa.bit_size == parent->dest.ssa.bit_size; 648} 649 650static bool 651is_trivial_array_deref_cast(nir_deref_instr *cast) 652{ 653 assert(is_trivial_deref_cast(cast)); 654 655 nir_deref_instr *parent = nir_src_as_deref(cast->parent); 656 657 if (parent->deref_type == nir_deref_type_array) { 658 return cast->cast.ptr_stride == 659 glsl_get_explicit_stride(nir_deref_instr_parent(parent)->type); 660 } else if (parent->deref_type == nir_deref_type_ptr_as_array) { 661 return cast->cast.ptr_stride == 662 nir_deref_instr_ptr_as_array_stride(parent); 663 } else { 664 return false; 665 } 666} 667 668static bool 669is_deref_ptr_as_array(nir_instr *instr) 670{ 671 return instr->type == nir_instr_type_deref && 672 nir_instr_as_deref(instr)->deref_type == nir_deref_type_ptr_as_array; 673} 674 675/** 676 * Remove casts that just wrap other casts. 677 */ 678static bool 679opt_remove_cast_cast(nir_deref_instr *cast) 680{ 681 nir_deref_instr *first_cast = cast; 682 683 while (true) { 684 nir_deref_instr *parent = nir_deref_instr_parent(first_cast); 685 if (parent == NULL || parent->deref_type != nir_deref_type_cast) 686 break; 687 first_cast = parent; 688 } 689 if (cast == first_cast) 690 return false; 691 692 nir_instr_rewrite_src(&cast->instr, &cast->parent, 693 nir_src_for_ssa(first_cast->parent.ssa)); 694 return true; 695} 696 697/** 698 * Is this casting a struct to a contained struct. 699 * struct a { struct b field0 }; 700 * ssa_5 is structa; 701 * deref_cast (structb *)ssa_5 (function_temp structb); 702 * converts to 703 * deref_struct &ssa_5->field0 (function_temp structb); 704 * This allows subsequent copy propagation to work. 705 */ 706static bool 707opt_replace_struct_wrapper_cast(nir_builder *b, nir_deref_instr *cast) 708{ 709 nir_deref_instr *parent = nir_src_as_deref(cast->parent); 710 if (!parent) 711 return false; 712 713 if (!glsl_type_is_struct(parent->type)) 714 return false; 715 716 if (glsl_get_struct_field_offset(parent->type, 0) != 0) 717 return false; 718 719 if (cast->type != glsl_get_struct_field(parent->type, 0)) 720 return false; 721 722 nir_deref_instr *replace = nir_build_deref_struct(b, parent, 0); 723 nir_ssa_def_rewrite_uses(&cast->dest.ssa, nir_src_for_ssa(&replace->dest.ssa)); 724 nir_deref_instr_remove_if_unused(cast); 725 return true; 726} 727 728static bool 729opt_deref_cast(nir_builder *b, nir_deref_instr *cast) 730{ 731 bool progress; 732 733 if (opt_replace_struct_wrapper_cast(b, cast)) 734 return true; 735 736 progress = opt_remove_cast_cast(cast); 737 if (!is_trivial_deref_cast(cast)) 738 return progress; 739 740 bool trivial_array_cast = is_trivial_array_deref_cast(cast); 741 742 assert(cast->dest.is_ssa); 743 assert(cast->parent.is_ssa); 744 745 nir_foreach_use_safe(use_src, &cast->dest.ssa) { 746 /* If this isn't a trivial array cast, we can't propagate into 747 * ptr_as_array derefs. 748 */ 749 if (is_deref_ptr_as_array(use_src->parent_instr) && 750 !trivial_array_cast) 751 continue; 752 753 nir_instr_rewrite_src(use_src->parent_instr, use_src, cast->parent); 754 progress = true; 755 } 756 757 /* If uses would be a bit crazy */ 758 assert(list_empty(&cast->dest.ssa.if_uses)); 759 760 nir_deref_instr_remove_if_unused(cast); 761 return progress; 762} 763 764static bool 765opt_deref_ptr_as_array(nir_builder *b, nir_deref_instr *deref) 766{ 767 assert(deref->deref_type == nir_deref_type_ptr_as_array); 768 769 nir_deref_instr *parent = nir_deref_instr_parent(deref); 770 771 if (nir_src_is_const(deref->arr.index) && 772 nir_src_as_int(deref->arr.index) == 0) { 773 /* If it's a ptr_as_array deref with an index of 0, it does nothing 774 * and we can just replace its uses with its parent. 775 * 776 * The source of a ptr_as_array deref always has a deref_type of 777 * nir_deref_type_array or nir_deref_type_cast. If it's a cast, it 778 * may be trivial and we may be able to get rid of that too. Any 779 * trivial cast of trivial cast cases should be handled already by 780 * opt_deref_cast() above. 781 */ 782 if (parent->deref_type == nir_deref_type_cast && 783 is_trivial_deref_cast(parent)) 784 parent = nir_deref_instr_parent(parent); 785 nir_ssa_def_rewrite_uses(&deref->dest.ssa, 786 nir_src_for_ssa(&parent->dest.ssa)); 787 nir_instr_remove(&deref->instr); 788 return true; 789 } 790 791 if (parent->deref_type != nir_deref_type_array && 792 parent->deref_type != nir_deref_type_ptr_as_array) 793 return false; 794 795 assert(parent->parent.is_ssa); 796 assert(parent->arr.index.is_ssa); 797 assert(deref->arr.index.is_ssa); 798 799 nir_ssa_def *new_idx = nir_iadd(b, parent->arr.index.ssa, 800 deref->arr.index.ssa); 801 802 deref->deref_type = parent->deref_type; 803 nir_instr_rewrite_src(&deref->instr, &deref->parent, parent->parent); 804 nir_instr_rewrite_src(&deref->instr, &deref->arr.index, 805 nir_src_for_ssa(new_idx)); 806 return true; 807} 808 809bool 810nir_opt_deref_impl(nir_function_impl *impl) 811{ 812 bool progress = false; 813 814 nir_builder b; 815 nir_builder_init(&b, impl); 816 817 nir_foreach_block(block, impl) { 818 nir_foreach_instr_safe(instr, block) { 819 if (instr->type != nir_instr_type_deref) 820 continue; 821 822 b.cursor = nir_before_instr(instr); 823 824 nir_deref_instr *deref = nir_instr_as_deref(instr); 825 switch (deref->deref_type) { 826 case nir_deref_type_ptr_as_array: 827 if (opt_deref_ptr_as_array(&b, deref)) 828 progress = true; 829 break; 830 831 case nir_deref_type_cast: 832 if (opt_deref_cast(&b, deref)) 833 progress = true; 834 break; 835 836 default: 837 /* Do nothing */ 838 break; 839 } 840 } 841 } 842 843 if (progress) { 844 nir_metadata_preserve(impl, nir_metadata_block_index | 845 nir_metadata_dominance); 846 } else { 847#ifndef NDEBUG 848 impl->valid_metadata &= ~nir_metadata_not_properly_reset; 849#endif 850 } 851 852 return progress; 853} 854 855bool 856nir_opt_deref(nir_shader *shader) 857{ 858 bool progress = false; 859 860 nir_foreach_function(func, shader) { 861 if (func->impl && nir_opt_deref_impl(func->impl)) 862 progress = true; 863 } 864 865 return progress; 866} 867