Mesa (staging/22.1): nir/deref: Handle SSBO array bindings specially

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jun 16 21:43:16 UTC 2022


Module: Mesa
Branch: staging/22.1
Commit: c1c7c02aa47a833c289a3419105f353bb1f9dc91
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=c1c7c02aa47a833c289a3419105f353bb1f9dc91

Author: Jason Ekstrand <jason.ekstrand at collabora.com>
Date:   Mon Jun  6 12:13:02 2022 -0500

nir/deref: Handle SSBO array bindings specially

Instead of just checking for the variables to match, check that the
entire deref up to the interface type matches.

Tested-by: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Reviewed-by: M Henning <drawoc at darkrefraction.com>
Reviewed-by: Rhys Perry <pendingchaos02 at gmail.com>
Cc: mesa-stable at lists.freedesktop.org
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16894>
(cherry picked from commit 8492e78f9d14c187596c13725f6974816d02a0e9)

---

 .pick_status.json                     |   2 +-
 src/compiler/nir/nir_deref.c          |  34 ++++-
 src/compiler/nir/tests/vars_tests.cpp | 228 ++++++++++++++++++++++++++++++++++
 3 files changed, 262 insertions(+), 2 deletions(-)

diff --git a/.pick_status.json b/.pick_status.json
index d003a63bf65..568f24a7164 100644
--- a/.pick_status.json
+++ b/.pick_status.json
@@ -3982,7 +3982,7 @@
         "description": "nir/deref: Handle SSBO array bindings specially",
         "nominated": true,
         "nomination_type": 0,
-        "resolution": 0,
+        "resolution": 1,
         "main_sha": null,
         "because_sha": null
     },
diff --git a/src/compiler/nir/nir_deref.c b/src/compiler/nir/nir_deref.c
index f40e7b71500..7864ae3198f 100644
--- a/src/compiler/nir/nir_deref.c
+++ b/src/compiler/nir/nir_deref.c
@@ -562,6 +562,17 @@ compare_deref_paths(nir_deref_path *a_path, nir_deref_path *b_path,
    return result;
 }
 
+static bool
+is_interface_struct_deref(const nir_deref_instr *deref)
+{
+   if (deref->deref_type == nir_deref_type_struct) {
+      assert(glsl_type_is_struct_or_ifc(nir_deref_instr_parent(deref)->type));
+      return true;
+   } else {
+      return false;
+   }
+}
+
 nir_deref_compare_result
 nir_compare_deref_paths(nir_deref_path *a_path,
                         nir_deref_path *b_path)
@@ -572,6 +583,7 @@ nir_compare_deref_paths(nir_deref_path *a_path,
    if (a_path->path[0]->deref_type != b_path->path[0]->deref_type)
       return nir_derefs_may_alias_bit;
 
+   unsigned path_idx = 1;
    if (a_path->path[0]->deref_type == nir_deref_type_var) {
       const nir_variable *a_var = a_path->path[0]->var;
       const nir_variable *b_var = b_path->path[0]->var;
@@ -585,6 +597,27 @@ nir_compare_deref_paths(nir_deref_path *a_path,
       assert(a_var->data.mode == b_var->data.mode);
 
       switch (a_var->data.mode) {
+      case nir_var_mem_ssbo: {
+         nir_deref_compare_result binding_compare;
+         if (a_var == b_var) {
+            binding_compare = compare_deref_paths(a_path, b_path, &path_idx,
+                                                  is_interface_struct_deref);
+         } else {
+            binding_compare = nir_derefs_do_not_alias;
+         }
+
+         if (binding_compare & nir_derefs_equal_bit)
+            break;
+
+         /* If the binding derefs can't alias and at least one is RESTRICT,
+          * then we know they can't alias.
+          */
+         if (!(binding_compare & nir_derefs_may_alias_bit))
+            return nir_derefs_do_not_alias;
+
+         return nir_derefs_may_alias_bit;
+      }
+
       case nir_var_mem_shared:
          if (a_var == b_var)
             break;
@@ -629,7 +662,6 @@ nir_compare_deref_paths(nir_deref_path *a_path,
          return nir_derefs_may_alias_bit;
    }
 
-   unsigned path_idx = 1;
    return compare_deref_paths(a_path, b_path, &path_idx, NULL);
 }
 
diff --git a/src/compiler/nir/tests/vars_tests.cpp b/src/compiler/nir/tests/vars_tests.cpp
index eb7e7547ba9..bdd19ffb9c6 100644
--- a/src/compiler/nir/tests/vars_tests.cpp
+++ b/src/compiler/nir/tests/vars_tests.cpp
@@ -1327,6 +1327,234 @@ TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref)
    EXPECT_EQ(first->src[1].ssa, second->src[1].ssa);
 }
 
+TEST_F(nir_copy_prop_vars_test, restrict_ssbo_bindings)
+{
+   glsl_struct_field field = glsl_struct_field();
+   field.type = glsl_int_type();
+   field.name = "x";
+   const glsl_type *ifc_type =
+      glsl_type::get_interface_instance(&field, 1,
+                                        GLSL_INTERFACE_PACKING_STD430,
+                                        false /* row_major */, "b");
+   nir_variable *ssbo0 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo0");
+   nir_variable *ssbo1 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo1");
+   ssbo0->data.access = ssbo1->data.access = ACCESS_RESTRICT;
+   nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
+   out->data.access = ACCESS_RESTRICT;
+
+   nir_deref_instr *ssbo0_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, ssbo0), 0);
+   nir_store_deref(b, ssbo0_x, nir_imm_int(b, 20), 1);
+
+   nir_deref_instr *ssbo1_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, ssbo1), 0);
+   nir_store_deref(b, ssbo1_x, nir_imm_int(b, 30), 1);
+
+   /* Load ssbo0.x and store it in out.x.  This load should be dropped */
+   nir_deref_instr *out_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
+   nir_store_deref(b, out_x, nir_load_deref(b, ssbo0_x), 1);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+
+   bool progress = nir_opt_copy_prop_vars(b->shader);
+   EXPECT_TRUE(progress);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+
+   /* Store to b0.x propagated to out. */
+   nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
+   nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2);
+   ASSERT_TRUE(first->src[1].is_ssa);
+   ASSERT_TRUE(third->src[1].is_ssa);
+   EXPECT_EQ(first->src[1].ssa, third->src[1].ssa);
+}
+
+TEST_F(nir_copy_prop_vars_test, aliasing_ssbo_bindings)
+{
+   glsl_struct_field field = glsl_struct_field();
+   field.type = glsl_int_type();
+   field.name = "x";
+   const glsl_type *ifc_type =
+      glsl_type::get_interface_instance(&field, 1,
+                                        GLSL_INTERFACE_PACKING_STD430,
+                                        false /* row_major */, "b");
+   nir_variable *ssbo0 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo0");
+   nir_variable *ssbo1 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo1");
+   nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
+   out->data.access = ACCESS_RESTRICT;
+
+   nir_deref_instr *ssbo0_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, ssbo0), 0);
+   nir_store_deref(b, ssbo0_x, nir_imm_int(b, 20), 1);
+
+   nir_deref_instr *ssbo1_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, ssbo1), 0);
+   nir_store_deref(b, ssbo1_x, nir_imm_int(b, 30), 1);
+
+   /* Load ssbo0.x and store it in out.x.  This load should not be dropped */
+   nir_deref_instr *out_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
+   nir_store_deref(b, out_x, nir_load_deref(b, ssbo0_x), 1);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+
+   bool progress = nir_opt_copy_prop_vars(b->shader);
+   EXPECT_FALSE(progress);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+}
+
+TEST_F(nir_copy_prop_vars_test, ssbo_array_binding_indirect)
+{
+   glsl_struct_field field = glsl_struct_field();
+   field.type = glsl_int_type();
+   field.name = "x";
+   const glsl_type *ifc_type =
+      glsl_type::get_interface_instance(&field, 1,
+                                        GLSL_INTERFACE_PACKING_STD430,
+                                        false /* row_major */, "b");
+   const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2);
+   nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type,
+                                       "ssbo_arr");
+   ssbo_arr->data.access = ACCESS_RESTRICT;
+   nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
+   out->data.access = ACCESS_RESTRICT;
+
+   nir_ssa_def *i = nir_load_local_invocation_index(b);
+
+   nir_deref_instr *ssbo_0 =
+      nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0);
+   nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0);
+   nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1);
+
+   nir_deref_instr *ssbo_i =
+      nir_build_deref_array(b, nir_build_deref_var(b, ssbo_arr),
+                               nir_load_local_invocation_index(b));
+   nir_deref_instr *ssbo_i_x = nir_build_deref_struct(b, ssbo_i, 0);
+   nir_store_deref(b, ssbo_i_x, nir_imm_int(b, 30), 1);
+
+   /* Load ssbo_arr[0].x and store it in out.x.  This load should not be dropped */
+   nir_deref_instr *out_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
+   nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+
+   bool progress = nir_opt_copy_prop_vars(b->shader);
+   EXPECT_FALSE(progress);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+}
+
+TEST_F(nir_copy_prop_vars_test, restrict_ssbo_array_binding)
+{
+   glsl_struct_field field = glsl_struct_field();
+   field.type = glsl_int_type();
+   field.name = "x";
+   const glsl_type *ifc_type =
+      glsl_type::get_interface_instance(&field, 1,
+                                        GLSL_INTERFACE_PACKING_STD430,
+                                        false /* row_major */, "b");
+   const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2);
+   nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type,
+                                       "ssbo_arr");
+   ssbo_arr->data.access = ACCESS_RESTRICT;
+   nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
+   out->data.access = ACCESS_RESTRICT;
+
+   nir_ssa_def *i = nir_load_local_invocation_index(b);
+
+   nir_deref_instr *ssbo_0 =
+      nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0);
+   nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0);
+   nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1);
+
+   nir_deref_instr *ssbo_1 =
+      nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 1);
+   nir_deref_instr *ssbo_1_x = nir_build_deref_struct(b, ssbo_1, 0);
+   nir_store_deref(b, ssbo_1_x, nir_imm_int(b, 30), 1);
+
+   /* Load ssbo_arr[0].x and store it in out.x.  This load should be dropped */
+   nir_deref_instr *out_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
+   nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+
+   bool progress = nir_opt_copy_prop_vars(b->shader);
+   EXPECT_TRUE(progress);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+
+   /* Store to b0.x propagated to out. */
+   nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
+   nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2);
+   ASSERT_TRUE(first->src[1].is_ssa);
+   ASSERT_TRUE(third->src[1].is_ssa);
+   EXPECT_EQ(first->src[1].ssa, third->src[1].ssa);
+}
+
+TEST_F(nir_copy_prop_vars_test, aliasing_ssbo_array_binding)
+{
+   glsl_struct_field field = glsl_struct_field();
+   field.type = glsl_int_type();
+   field.name = "x";
+   const glsl_type *ifc_type =
+      glsl_type::get_interface_instance(&field, 1,
+                                        GLSL_INTERFACE_PACKING_STD430,
+                                        false /* row_major */, "b");
+   const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2);
+   nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type,
+                                       "ssbo_arr");
+   nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
+   out->data.access = ACCESS_RESTRICT;
+
+   nir_ssa_def *i = nir_load_local_invocation_index(b);
+
+   nir_deref_instr *ssbo_0 =
+      nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0);
+   nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0);
+   nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1);
+
+   nir_deref_instr *ssbo_1 =
+      nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 1);
+   nir_deref_instr *ssbo_1_x = nir_build_deref_struct(b, ssbo_1, 0);
+   nir_store_deref(b, ssbo_1_x, nir_imm_int(b, 30), 1);
+
+   /* Load ssbo_arr[0].x and store it in out.x.  This load should not be dropped */
+   nir_deref_instr *out_x =
+      nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
+   nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+
+   bool progress = nir_opt_copy_prop_vars(b->shader);
+   EXPECT_FALSE(progress);
+
+   nir_validate_shader(b->shader, NULL);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
+   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
+}
+
 TEST_F(nir_dead_write_vars_test, no_dead_writes_in_block)
 {
    nir_variable **v = create_many_int(nir_var_mem_global, "v", 2);



More information about the mesa-commit mailing list