nir: Make nir_deref_path_init skip trivial casts
authorCaio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Wed, 15 Jan 2020 19:51:58 +0000 (11:51 -0800)
committerMarge Bot <eric+marge@anholt.net>
Wed, 29 Jan 2020 18:25:36 +0000 (18:25 +0000)
In a NIR generated using SPIR-V initializers to variables, copy
propagation can end up transforming

    vec1 32 ssa_33 = deref_var &@1 (shared mat2x4)
    vec1 32 ssa_35 = mov ssa_33
    vec1 32 ssa_7 = deref_cast (mat2x4 *)ssa_35 (shared mat2x4)  /* ptr_stride=0 */

into

    vec1 32 ssa_33 = deref_var &@1 (shared mat2x4)
    vec1 32 ssa_7 = deref_cast (mat2x4 *)ssa_33 (shared mat2x4)  /* ptr_stride=0 */

Before the optimization, the "head" of a path of deref that uses ssa_7
will be the cast.  After, it will be the variable in ssa_33.  Since
the types are the same, this is a trivial cast that would be picked up
by nir_opt_deref.

If we need to compare such deref-chain after optimization with another
deref-chain for the same variable, the compare function will get
confused by the cast in the middle.

One alternative would be to add nir_opt_deref to places that compare
derefs, but that might not scale well, so skip the trivial casts when
generating the paths instead.

Motivated by the discussion in
https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3047#note_383660.

Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3420>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3420>

src/compiler/nir/nir_deref.c

index 02f77d622bd6b8d7779f215e38d32c8de9b4bd5d..aa841223a3be9b80646a070d5580c16f16b05936 100644 (file)
 #include "nir_deref.h"
 #include "util/hash_table.h"
 
+static bool
+is_trivial_deref_cast(nir_deref_instr *cast)
+{
+   nir_deref_instr *parent = nir_src_as_deref(cast->parent);
+   if (!parent)
+      return false;
+
+   return cast->mode == parent->mode &&
+          cast->type == parent->type &&
+          cast->dest.ssa.num_components == parent->dest.ssa.num_components &&
+          cast->dest.ssa.bit_size == parent->dest.ssa.bit_size;
+}
+
 void
 nir_deref_path_init(nir_deref_path *path,
                     nir_deref_instr *deref, void *mem_ctx)
@@ -44,6 +57,8 @@ nir_deref_path_init(nir_deref_path *path,
 
    *tail = NULL;
    for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
+      if (d->deref_type == nir_deref_type_cast && is_trivial_deref_cast(d))
+         continue;
       count++;
       if (count <= max_short_path_len)
          *(--head) = d;
@@ -64,8 +79,11 @@ nir_deref_path_init(nir_deref_path *path,
    path->path = ralloc_array(mem_ctx, nir_deref_instr *, count + 1);
    head = tail = path->path + count;
    *tail = NULL;
-   for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d))
+   for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
+      if (d->deref_type == nir_deref_type_cast && is_trivial_deref_cast(d))
+         continue;
       *(--head) = d;
+   }
 
 done:
    assert(head == path->path);
@@ -735,19 +753,6 @@ nir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl *impl)
    return state.progress;
 }
 
-static bool
-is_trivial_deref_cast(nir_deref_instr *cast)
-{
-   nir_deref_instr *parent = nir_src_as_deref(cast->parent);
-   if (!parent)
-      return false;
-
-   return cast->mode == parent->mode &&
-          cast->type == parent->type &&
-          cast->dest.ssa.num_components == parent->dest.ssa.num_components &&
-          cast->dest.ssa.bit_size == parent->dest.ssa.bit_size;
-}
-
 static bool
 is_trivial_array_deref_cast(nir_deref_instr *cast)
 {