nir/opt_load_store_vectorize: check for restrict at the variable
authorRhys Perry <pendingchaos02@gmail.com>
Fri, 23 Oct 2020 14:31:28 +0000 (15:31 +0100)
committerMarge Bot <eric+marge@anholt.net>
Thu, 10 Jun 2021 13:17:22 +0000 (13:17 +0000)
SPIR-V -> NIR doesn't set ACCESS_RESTRICT at the intrinsic.

fossil-db (GFX10.3):
Totals from 3 (0.00% of 139391) affected shaders:
CodeSize: 12364 -> 12356 (-0.06%)
Instrs: 2493 -> 2494 (+0.04%); split: -0.04%, +0.08%
Cycles: 15279372 -> 15295756 (+0.11%); split: -0.11%, +0.21%

Signed-off-by: Rhys Perry <pendingchaos02@gmail.com>
Reviewed-by: Daniel Schürmann <daniel@schuermann.dev>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7295>

src/compiler/nir/nir_opt_load_store_vectorize.c

index 070da47..fc924d9 100644 (file)
@@ -186,6 +186,7 @@ struct entry {
 };
 
 struct vectorize_ctx {
+   nir_shader *shader;
    const nir_load_store_vectorize_options *options;
    struct list_head entries[nir_num_variable_modes];
    struct hash_table *loads[nir_num_variable_modes];
@@ -893,30 +894,47 @@ vectorize_stores(nir_builder *b, struct vectorize_ctx *ctx,
    nir_instr_remove(first->instr);
 }
 
-/* Returns true if it can prove that "a" and "b" point to different bindings. */
+/* Returns true if it can prove that "a" and "b" point to different bindings
+ * and both use ACCESS_RESTRICT. */
 static bool
-bindings_different(nir_ssa_def *a, nir_ssa_def *b)
+bindings_different_restrict(nir_shader *shader, struct entry *a, struct entry *b)
 {
-   if (!a || !b)
-      return false;
+   bool different_bindings = false;
+   nir_variable *a_var = NULL, *b_var = NULL;
+   if (a->key->resource && b->key->resource) {
+      nir_binding a_res = nir_chase_binding(nir_src_for_ssa(a->key->resource));
+      nir_binding b_res = nir_chase_binding(nir_src_for_ssa(b->key->resource));
+      if (!a_res.success || !b_res.success)
+         return false;
 
-   nir_binding a_res = nir_chase_binding(nir_src_for_ssa(a));
-   nir_binding b_res = nir_chase_binding(nir_src_for_ssa(b));
-   if (!a_res.success || !b_res.success)
-      return false;
+      if (a_res.num_indices != b_res.num_indices ||
+          a_res.desc_set != b_res.desc_set ||
+          a_res.binding != b_res.binding)
+            different_bindings = true;
 
-   if (a_res.num_indices != b_res.num_indices ||
-       a_res.desc_set != b_res.desc_set ||
-       a_res.binding != b_res.binding)
-      return true;
+      for (unsigned i = 0; i < a_res.num_indices; i++) {
+         if (nir_src_is_const(a_res.indices[i]) && nir_src_is_const(b_res.indices[i]) &&
+             nir_src_as_uint(a_res.indices[i]) != nir_src_as_uint(b_res.indices[i]))
+               different_bindings = true;
+      }
 
-   for (unsigned i = 0; i < a_res.num_indices; i++) {
-      if (nir_src_is_const(a_res.indices[i]) && nir_src_is_const(b_res.indices[i]) &&
-          nir_src_as_uint(a_res.indices[i]) != nir_src_as_uint(b_res.indices[i]))
-         return true;
+      if (different_bindings) {
+         a_var = nir_get_binding_variable(shader, a_res);
+         b_var = nir_get_binding_variable(shader, b_res);
+      }
+   } else if (a->key->var && b->key->var) {
+      a_var = a->key->var;
+      b_var = b->key->var;
+      different_bindings = a_var != b_var;
+   } else {
+      return false;
    }
 
-   return false;
+   unsigned a_access = a->access | (a_var ? a_var->data.access : 0);
+   unsigned b_access = b->access | (b_var ? b_var->data.access : 0);
+
+   return different_bindings &&
+          ((a_access & b_access) & ACCESS_RESTRICT);
 }
 
 static int64_t
@@ -928,7 +946,7 @@ compare_entries(struct entry *a, struct entry *b)
 }
 
 static bool
-may_alias(struct entry *a, struct entry *b)
+may_alias(nir_shader *shader, struct entry *a, struct entry *b)
 {
    assert(mode_to_index(get_variable_mode(a)) ==
           mode_to_index(get_variable_mode(b)));
@@ -938,9 +956,7 @@ may_alias(struct entry *a, struct entry *b)
 
    /* if the resources/variables are definitively different and both have
     * ACCESS_RESTRICT, we can assume they do not alias. */
-   bool res_different = a->key->var != b->key->var ||
-                        bindings_different(a->key->resource, b->key->resource);
-   if (res_different && (a->access & ACCESS_RESTRICT) && (b->access & ACCESS_RESTRICT))
+   if (bindings_different_restrict(shader, a, b))
       return false;
 
    /* we can't compare offsets if the resources/variables might be different */
@@ -979,7 +995,7 @@ check_for_aliasing(struct vectorize_ctx *ctx, struct entry *first, struct entry
             continue;
          if (next == second)
             return false;
-         if (may_alias(first, next))
+         if (may_alias(ctx->shader, first, next))
             return true;
       }
    } else {
@@ -989,7 +1005,7 @@ check_for_aliasing(struct vectorize_ctx *ctx, struct entry *first, struct entry
             continue;
          if (prev == first)
             return false;
-         if (prev->is_store && may_alias(second, prev))
+         if (prev->is_store && may_alias(ctx->shader, second, prev))
             return true;
       }
    }
@@ -1381,6 +1397,7 @@ nir_opt_load_store_vectorize(nir_shader *shader, const nir_load_store_vectorize_
    bool progress = false;
 
    struct vectorize_ctx *ctx = rzalloc(NULL, struct vectorize_ctx);
+   ctx->shader = shader;
    ctx->options = options;
 
    nir_shader_index_vars(shader, options->modes);