nir/lower_io: Add support for global scratch addressing
[mesa.git] / src / compiler / nir / nir_deref.c
index aa841223a3be9b80646a070d5580c16f16b05936..79ca329391b309b014ac497a1210d78a0e84219b 100644 (file)
@@ -657,10 +657,13 @@ rematerialize_deref_in_block(nir_deref_instr *deref,
    switch (deref->deref_type) {
    case nir_deref_type_var:
    case nir_deref_type_array_wildcard:
-   case nir_deref_type_cast:
       /* Nothing more to do */
       break;
 
+   case nir_deref_type_cast:
+      new_deref->cast.ptr_stride = deref->cast.ptr_stride;
+      break;
+
    case nir_deref_type_array:
    case nir_deref_type_ptr_as_array:
       assert(!nir_src_as_deref(deref->arr.index));
@@ -753,6 +756,42 @@ nir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl *impl)
    return state.progress;
 }
 
+static void
+nir_deref_instr_fixup_child_types(nir_deref_instr *parent)
+{
+   nir_foreach_use(use, &parent->dest.ssa) {
+      if (use->parent_instr->type != nir_instr_type_deref)
+         continue;
+
+      nir_deref_instr *child = nir_instr_as_deref(use->parent_instr);
+      switch (child->deref_type) {
+      case nir_deref_type_var:
+         unreachable("nir_deref_type_var cannot be a child");
+
+      case nir_deref_type_array:
+      case nir_deref_type_array_wildcard:
+         child->type = glsl_get_array_element(parent->type);
+         break;
+
+      case nir_deref_type_ptr_as_array:
+         child->type = parent->type;
+         break;
+
+      case nir_deref_type_struct:
+         child->type = glsl_get_struct_field(parent->type,
+                                             child->strct.index);
+         break;
+
+      case nir_deref_type_cast:
+         /* We stop the recursion here */
+         continue;
+      }
+
+      /* Recurse into children */
+      nir_deref_instr_fixup_child_types(child);
+   }
+}
+
 static bool
 is_trivial_array_deref_cast(nir_deref_instr *cast)
 {
@@ -800,6 +839,44 @@ opt_remove_cast_cast(nir_deref_instr *cast)
    return true;
 }
 
+static bool
+opt_remove_sampler_cast(nir_deref_instr *cast)
+{
+   assert(cast->deref_type == nir_deref_type_cast);
+   nir_deref_instr *parent = nir_src_as_deref(cast->parent);
+   if (parent == NULL)
+      return false;
+
+   /* Strip both types down to their non-array type and bail if there are any
+    * discrepancies in array lengths.
+    */
+   const struct glsl_type *parent_type = parent->type;
+   const struct glsl_type *cast_type = cast->type;
+   while (glsl_type_is_array(parent_type) && glsl_type_is_array(cast_type)) {
+      if (glsl_get_length(parent_type) != glsl_get_length(cast_type))
+         return false;
+      parent_type = glsl_get_array_element(parent_type);
+      cast_type = glsl_get_array_element(cast_type);
+   }
+
+   if (glsl_type_is_array(parent_type) || glsl_type_is_array(cast_type))
+      return false;
+
+   if (!glsl_type_is_sampler(parent_type) ||
+       cast_type != glsl_bare_sampler_type())
+      return false;
+
+   /* We're a cast from a more detailed sampler type to a bare sampler */
+   nir_ssa_def_rewrite_uses(&cast->dest.ssa,
+                            nir_src_for_ssa(&parent->dest.ssa));
+   nir_instr_remove(&cast->instr);
+
+   /* Recursively crawl the deref tree and clean up types */
+   nir_deref_instr_fixup_child_types(parent);
+
+   return true;
+}
+
 /**
  * Is this casting a struct to a contained struct.
  * struct a { struct b field0 };
@@ -839,6 +916,9 @@ opt_deref_cast(nir_builder *b, nir_deref_instr *cast)
    if (opt_replace_struct_wrapper_cast(b, cast))
       return true;
 
+   if (opt_remove_sampler_cast(cast))
+      return true;
+
    progress = opt_remove_cast_cast(cast);
    if (!is_trivial_deref_cast(cast))
       return progress;
@@ -863,7 +943,9 @@ opt_deref_cast(nir_builder *b, nir_deref_instr *cast)
    /* If uses would be a bit crazy */
    assert(list_is_empty(&cast->dest.ssa.if_uses));
 
-   nir_deref_instr_remove_if_unused(cast);
+   if (nir_deref_instr_remove_if_unused(cast))
+      progress = true;
+
    return progress;
 }
 
@@ -950,9 +1032,7 @@ nir_opt_deref_impl(nir_function_impl *impl)
       nir_metadata_preserve(impl, nir_metadata_block_index |
                                   nir_metadata_dominance);
    } else {
-#ifndef NDEBUG
-      impl->valid_metadata &= ~nir_metadata_not_properly_reset;
-#endif
+      nir_metadata_preserve(impl, nir_metadata_all);
    }
 
    return progress;