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