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