Mesa (master): nir: Add tests for dead write elimination

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Oct 16 00:35:04 UTC 2018


Module: Mesa
Branch: master
Commit: a02fd7000d4f1d6912d9916eea3d72b01aa4990f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=a02fd7000d4f1d6912d9916eea3d72b01aa4990f

Author: Caio Marcelo de Oliveira Filho <caio.oliveira at intel.com>
Date:   Wed Aug 29 16:30:09 2018 -0700

nir: Add tests for dead write elimination

Note at the moment the pass called is nir_opt_copy_prop_vars, because
dead write elimination is implemented there.

Also added tests that involve identifying dead writes in multiple
blocks (e.g. the overwrite happens in another block).  Those currently
fail as expected, so are marked to be skipped.

Reviewed-by: Jason Ekstrand <jason at jlekstrand.net>

---

 src/compiler/nir/tests/vars_tests.cpp | 241 ++++++++++++++++++++++++++++++++++
 1 file changed, 241 insertions(+)

diff --git a/src/compiler/nir/tests/vars_tests.cpp b/src/compiler/nir/tests/vars_tests.cpp
index 9b2877fcc9..0a2ff3f3d3 100644
--- a/src/compiler/nir/tests/vars_tests.cpp
+++ b/src/compiler/nir/tests/vars_tests.cpp
@@ -26,6 +26,9 @@
 #include "nir.h"
 #include "nir_builder.h"
 
+/* This optimization is done together with copy propagation. */
+#define nir_opt_dead_write_vars nir_opt_copy_prop_vars
+
 namespace {
 
 class nir_vars_test : public ::testing::Test {
@@ -132,6 +135,7 @@ nir_vars_test::find_next_intrinsic(nir_intrinsic_op intrinsic,
 
 /* Allow grouping the tests while still sharing the helpers. */
 class nir_copy_prop_vars_test : public nir_vars_test {};
+class nir_dead_write_vars_test : public nir_vars_test {};
 
 } // namespace
 
@@ -188,3 +192,240 @@ TEST_F(nir_copy_prop_vars_test, simple_store_load)
       EXPECT_EQ(store->src[1].ssa, stored_value);
    }
 }
+
+TEST_F(nir_dead_write_vars_test, no_dead_writes_in_block)
+{
+   nir_variable **v = create_many_int(nir_var_shader_storage, "v", 2);
+
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_FALSE(progress);
+}
+
+TEST_F(nir_dead_write_vars_test, no_dead_writes_different_components_in_block)
+{
+   nir_variable **v = create_many_ivec2(nir_var_shader_storage, "v", 3);
+
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
+   nir_store_var(b, v[0], nir_load_var(b, v[2]), 1 << 1);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_FALSE(progress);
+}
+
+TEST_F(nir_dead_write_vars_test, no_dead_writes_in_if_statement)
+{
+   nir_variable **v = create_many_int(nir_var_shader_storage, "v", 6);
+
+   nir_store_var(b, v[2], nir_load_var(b, v[0]), 1);
+   nir_store_var(b, v[3], nir_load_var(b, v[1]), 1);
+
+   /* Each arm of the if statement will overwrite one store. */
+   nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
+   nir_store_var(b, v[2], nir_load_var(b, v[4]), 1);
+
+   nir_push_else(b, if_stmt);
+   nir_store_var(b, v[3], nir_load_var(b, v[5]), 1);
+
+   nir_pop_if(b, if_stmt);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_FALSE(progress);
+}
+
+TEST_F(nir_dead_write_vars_test, no_dead_writes_in_loop_statement)
+{
+   nir_variable **v = create_many_int(nir_var_shader_storage, "v", 3);
+
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
+
+   /* Loop will write other value.  Since it might not be executed, it doesn't
+    * kill the first write.
+    */
+   nir_loop *loop = nir_push_loop(b);
+
+   nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
+   nir_jump(b, nir_jump_break);
+   nir_pop_if(b, if_stmt);
+
+   nir_store_var(b, v[0], nir_load_var(b, v[2]), 1);
+   nir_pop_loop(b, loop);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_FALSE(progress);
+}
+
+TEST_F(nir_dead_write_vars_test, dead_write_in_block)
+{
+   nir_variable **v = create_many_int(nir_var_shader_storage, "v", 3);
+
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
+   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
+   nir_store_var(b, v[0], load_v2, 1);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_TRUE(progress);
+
+   EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
+
+   nir_intrinsic_instr *store = find_next_intrinsic(nir_intrinsic_store_deref, NULL);
+   ASSERT_TRUE(store->src[1].is_ssa);
+   EXPECT_EQ(store->src[1].ssa, load_v2);
+}
+
+TEST_F(nir_dead_write_vars_test, dead_write_components_in_block)
+{
+   nir_variable **v = create_many_ivec2(nir_var_shader_storage, "v", 3);
+
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
+   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
+   nir_store_var(b, v[0], load_v2, 1 << 0);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_TRUE(progress);
+
+   EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
+
+   nir_intrinsic_instr *store = find_next_intrinsic(nir_intrinsic_store_deref, NULL);
+   ASSERT_TRUE(store->src[1].is_ssa);
+   EXPECT_EQ(store->src[1].ssa, load_v2);
+}
+
+
+/* TODO: The DISABLED tests below depend on the dead write removal be able to
+ * identify dead writes between multiple blocks.  This is still not
+ * implemented.
+ */
+
+TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_in_two_blocks)
+{
+   nir_variable **v = create_many_int(nir_var_shader_storage, "v", 3);
+
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
+   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
+
+   /* Causes the stores to be in different blocks. */
+   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
+
+   nir_store_var(b, v[0], load_v2, 1);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_TRUE(progress);
+
+   EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
+
+   nir_intrinsic_instr *store = find_next_intrinsic(nir_intrinsic_store_deref, NULL);
+   ASSERT_TRUE(store->src[1].is_ssa);
+   EXPECT_EQ(store->src[1].ssa, load_v2);
+}
+
+TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_components_in_two_blocks)
+{
+   nir_variable **v = create_many_ivec2(nir_var_shader_storage, "v", 3);
+
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
+
+   /* Causes the stores to be in different blocks. */
+   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
+
+   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
+   nir_store_var(b, v[0], load_v2, 1 << 0);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_TRUE(progress);
+
+   EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
+
+   nir_intrinsic_instr *store = find_next_intrinsic(nir_intrinsic_store_deref, NULL);
+   ASSERT_TRUE(store->src[1].is_ssa);
+   EXPECT_EQ(store->src[1].ssa, load_v2);
+}
+
+TEST_F(nir_dead_write_vars_test, DISABLED_dead_writes_in_if_statement)
+{
+   nir_variable **v = create_many_int(nir_var_shader_storage, "v", 4);
+
+   /* Both branches will overwrite, making the previous store dead. */
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
+
+   nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
+   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
+   nir_store_var(b, v[0], load_v2, 1);
+
+   nir_push_else(b, if_stmt);
+   nir_ssa_def *load_v3 = nir_load_var(b, v[3]);
+   nir_store_var(b, v[0], load_v3, 1);
+
+   nir_pop_if(b, if_stmt);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_TRUE(progress);
+   EXPECT_EQ(2, count_intrinsics(nir_intrinsic_store_deref));
+
+   nir_intrinsic_instr *store = NULL;
+   store = find_next_intrinsic(nir_intrinsic_store_deref, store);
+   ASSERT_TRUE(store->src[1].is_ssa);
+   EXPECT_EQ(store->src[1].ssa, load_v2);
+
+   store = find_next_intrinsic(nir_intrinsic_store_deref, store);
+   ASSERT_TRUE(store->src[1].is_ssa);
+   EXPECT_EQ(store->src[1].ssa, load_v3);
+}
+
+TEST_F(nir_dead_write_vars_test, DISABLED_memory_barrier_in_two_blocks)
+{
+   nir_variable **v = create_many_int(nir_var_shader_storage, "v", 2);
+
+   nir_store_var(b, v[0], nir_imm_int(b, 1), 1);
+   nir_store_var(b, v[1], nir_imm_int(b, 2), 1);
+
+   /* Split into many blocks. */
+   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
+
+   /* Because it is before the barrier, this will kill the previous store to that target. */
+   nir_store_var(b, v[0], nir_imm_int(b, 3), 1);
+
+   nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_memory_barrier)->instr);
+
+   nir_store_var(b, v[1], nir_imm_int(b, 4), 1);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_TRUE(progress);
+
+   EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref));
+}
+
+TEST_F(nir_dead_write_vars_test, DISABLED_unrelated_barrier_in_two_blocks)
+{
+   nir_variable **v = create_many_int(nir_var_shader_storage, "v", 3);
+   nir_variable *out = create_int(nir_var_shader_out, "out");
+
+   nir_store_var(b, out, nir_load_var(b, v[1]), 1);
+   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
+
+   /* Split into many blocks. */
+   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
+
+   /* Emit vertex will ensure writes to output variables are considered used,
+    * but should not affect other types of variables. */
+
+   nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_emit_vertex)->instr);
+
+   nir_store_var(b, out, nir_load_var(b, v[2]), 1);
+   nir_store_var(b, v[0], nir_load_var(b, v[2]), 1);
+
+   bool progress = nir_opt_dead_write_vars(b->shader);
+   ASSERT_TRUE(progress);
+
+   /* Verify the first write to v[0] was removed. */
+   EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref));
+
+   nir_intrinsic_instr *store = NULL;
+   store = find_next_intrinsic(nir_intrinsic_store_deref, store);
+   EXPECT_EQ(nir_intrinsic_get_var(store, 0), out);
+   store = find_next_intrinsic(nir_intrinsic_store_deref, store);
+   EXPECT_EQ(nir_intrinsic_get_var(store, 0), out);
+   store = find_next_intrinsic(nir_intrinsic_store_deref, store);
+   EXPECT_EQ(nir_intrinsic_get_var(store, 0), v[0]);
+}




More information about the mesa-commit mailing list