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

Author: Caio Oliveira <caio.olive...@intel.com>
Date:   Fri Nov  3 22:41:59 2023 -0700

intel/compiler: Add a few tests to opt_predicated_break

v2 (idr): Fix expectations BottomBreakWithContinue. opt_predicated_break
will remove the IF and make the CONTINUE predicated.

v3 (idr): Temporarily disable the one test that fails.

v4 (idr): Free strings allocated by open_memstream. Fixes gitlab CI
failures in debian-testing-asan.

Reviewed-by: Ian Romanick <ian.d.roman...@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25216>

---

 src/intel/compiler/meson.build               |   1 +
 src/intel/compiler/test_predicated_break.cpp | 339 +++++++++++++++++++++++++++
 2 files changed, 340 insertions(+)

diff --git a/src/intel/compiler/meson.build b/src/intel/compiler/meson.build
index e936bacc3dd..200cc9859fa 100644
--- a/src/intel/compiler/meson.build
+++ b/src/intel/compiler/meson.build
@@ -194,6 +194,7 @@ if with_tests
     executable(
       'intel_compiler_tests',
       files(
+        'test_predicated_break.cpp',
         'test_eu_compact.cpp',
         'test_eu_validate.cpp',
         'test_fs_cmod_propagation.cpp',
diff --git a/src/intel/compiler/test_predicated_break.cpp 
b/src/intel/compiler/test_predicated_break.cpp
new file mode 100644
index 00000000000..3c9433c7589
--- /dev/null
+++ b/src/intel/compiler/test_predicated_break.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2023 Intel Corporation
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <gtest/gtest.h>
+#include "brw_fs.h"
+#include "brw_cfg.h"
+
+using namespace brw;
+
+class PredicatedBreakTest : public ::testing::Test {
+   virtual void SetUp();
+   virtual void TearDown();
+
+public:
+   bool debug;
+   void *mem_ctx;
+   brw_compiler compiler;
+   brw_compile_params params;
+   intel_device_info devinfo;
+   struct brw_wm_prog_data prog_data;
+   struct gl_shader_program *shader_prog;
+
+   fs_visitor *shader_a;
+   fs_visitor *shader_b;
+
+   bool opt_predicated_break(fs_visitor *s);
+};
+
+void
+PredicatedBreakTest::SetUp()
+{
+   debug = getenv("TEST_DEBUG");
+
+   mem_ctx = ralloc_context(NULL);
+
+   devinfo = {};
+   devinfo.ver = 9;
+   devinfo.verx10 = 90;
+
+   compiler = {};
+   compiler.devinfo = &devinfo;
+   brw_init_isa_info(&compiler.isa, &devinfo);
+
+   params = {};
+   params.mem_ctx = mem_ctx;
+
+   prog_data = {};
+   nir_shader *nir =
+      nir_shader_create(mem_ctx, MESA_SHADER_FRAGMENT, NULL, NULL);
+
+   shader_a = new fs_visitor(&compiler, &params, NULL,
+                             &prog_data.base, nir, 8, false, false);
+
+   shader_b = new fs_visitor(&compiler, &params, NULL,
+                             &prog_data.base, nir, 8, false, false);
+}
+
+void
+PredicatedBreakTest::TearDown()
+{
+   delete shader_a;
+   delete shader_b;
+   ralloc_free(mem_ctx);
+   mem_ctx = NULL;
+}
+
+bool
+PredicatedBreakTest::opt_predicated_break(fs_visitor *s)
+{
+   const bool print = getenv("TEST_DEBUG");
+
+   if (print) {
+      fprintf(stderr, "= Before =\n");
+      s->cfg->dump();
+   }
+
+   bool ret = ::opt_predicated_break(s);
+
+   if (print) {
+      fprintf(stderr, "\n= After =\n");
+      s->cfg->dump();
+   }
+
+   return ret;
+}
+
+static fs_builder
+make_builder(fs_visitor *s)
+{
+   return fs_builder(s, s->dispatch_width).at_end();
+}
+
+static testing::AssertionResult
+shaders_match(const char *a_expr, const char *b_expr,
+              fs_visitor *a, fs_visitor *b)
+{
+   /* Using the CFG string dump for this.  Not ideal but it is
+    * convenient that covers some CFG information, helping to
+    * check if the optimization is keeping the CFG valid.
+    */
+
+   char *a_str = NULL;
+   size_t a_size = 0;
+   FILE *a_file = open_memstream(&a_str, &a_size);
+   a->cfg->dump(a_file);
+   fclose(a_file);
+
+   char *b_str = NULL;
+   size_t b_size = 0;
+   FILE *b_file = open_memstream(&b_str, &b_size);
+   b->cfg->dump(b_file);
+   fclose(b_file);
+
+   if (a_size != b_size || strcmp(a_str, b_str) != 0) {
+      std::stringstream result;
+
+      result << "Shaders don't match.\n\n"
+             << a_expr << " is:\n\n" << a_str
+             << "\n---\n"
+             << b_expr << " is:\n\n" << b_str
+             << "\n";
+
+      free(a_str);
+      free(b_str);
+      return testing::AssertionFailure() << result.str();
+   }
+
+   free(a_str);
+   free(b_str);
+   return testing::AssertionSuccess();
+}
+
+#define ASSERT_SHADERS_MATCH(a, b)  ASSERT_PRED_FORMAT2(shaders_match, a, b)
+
+TEST_F(PredicatedBreakTest, TopBreakWithoutContinue)
+{
+   fs_builder a = make_builder(shader_a);
+   fs_builder b = make_builder(shader_b);
+
+   fs_reg r1 = brw_vec8_grf(1, 0);
+   fs_reg r2 = brw_vec8_grf(2, 0);
+   fs_reg r3 = brw_vec8_grf(3, 0);
+
+   a.DO();
+   a.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   a.IF(BRW_PREDICATE_NORMAL);
+   a.BREAK();
+   a.ENDIF();
+   a.ADD(r1, r2, r3);
+   a.WHILE();
+   a.NOP();  /* There's always going to be something after a WHILE. */
+   shader_a->calculate_cfg();
+
+   /* The IF/ENDIF around the BREAK is expected to be removed. */
+   bool progress = opt_predicated_break(shader_a);
+   EXPECT_TRUE(progress);
+
+   b.DO();
+   b.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   b.BREAK()->predicate = BRW_PREDICATE_NORMAL;
+   b.ADD(r1, r2, r3);
+   b.WHILE();
+   b.NOP();
+   shader_b->calculate_cfg();
+
+   ASSERT_SHADERS_MATCH(shader_a, shader_b);
+}
+
+TEST_F(PredicatedBreakTest, TopBreakWithContinue)
+{
+   fs_builder a = make_builder(shader_a);
+   fs_builder b = make_builder(shader_b);
+
+   fs_reg r1 = brw_vec8_grf(1, 0);
+   fs_reg r2 = brw_vec8_grf(2, 0);
+   fs_reg r3 = brw_vec8_grf(3, 0);
+
+   a.DO();
+   a.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   a.IF(BRW_PREDICATE_NORMAL);
+   a.BREAK();
+   a.ENDIF();
+   a.ADD(r1, r2, r3);
+   a.CMP(r1, r2, r3, BRW_CONDITIONAL_GE);
+   a.IF(BRW_PREDICATE_NORMAL);
+   a.CONTINUE();
+   a.ENDIF();
+   a.MUL(r1, r2, r3);
+   a.WHILE();
+   a.NOP();  /* There's always going to be something after a WHILE. */
+   shader_a->calculate_cfg();
+
+   /* The IF/ENDIF around the BREAK and the CONTINUE are expected to be
+    * removed.
+    */
+   bool progress = opt_predicated_break(shader_a);
+   EXPECT_TRUE(progress);
+
+   b.DO();
+   b.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   b.BREAK()->predicate = BRW_PREDICATE_NORMAL;
+   b.ADD(r1, r2, r3);
+   b.CMP(r1, r2, r3, BRW_CONDITIONAL_GE);
+   b.CONTINUE()->predicate = BRW_PREDICATE_NORMAL;
+   b.MUL(r1, r2, r3);
+   b.WHILE();
+   b.NOP();
+   shader_b->calculate_cfg();
+
+   ASSERT_SHADERS_MATCH(shader_a, shader_b);
+}
+
+TEST_F(PredicatedBreakTest, DISABLED_BottomBreakWithoutContinue)
+{
+   fs_builder a = make_builder(shader_a);
+   fs_builder b = make_builder(shader_b);
+
+   fs_reg r1 = brw_vec8_grf(1, 0);
+   fs_reg r2 = brw_vec8_grf(2, 0);
+   fs_reg r3 = brw_vec8_grf(3, 0);
+
+   a.DO();
+   a.ADD(r1, r2, r3);
+   a.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   a.IF(BRW_PREDICATE_NORMAL);
+   a.BREAK();
+   a.ENDIF();
+   a.WHILE();
+   a.NOP();  /* There's always going to be something after a WHILE. */
+   shader_a->calculate_cfg();
+
+   /* BREAK is the only way to exit the loop, so expect to remove the
+    * IF/BREAK/ENDIF and add a predicate to WHILE.
+    */
+   bool progress = opt_predicated_break(shader_a);
+   EXPECT_TRUE(progress);
+
+   b.DO();
+   b.ADD(r1, r2, r3);
+   b.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   auto w = b.WHILE();
+   w->predicate = BRW_PREDICATE_NORMAL;
+   w->predicate_inverse = true;
+   b.NOP();
+   shader_b->calculate_cfg();
+
+   ASSERT_SHADERS_MATCH(shader_a, shader_b);
+}
+
+
+TEST_F(PredicatedBreakTest, BottomBreakWithContinue)
+{
+   fs_builder a = make_builder(shader_a);
+   fs_builder b = make_builder(shader_b);
+
+   fs_reg r1 = brw_vec8_grf(1, 0);
+   fs_reg r2 = brw_vec8_grf(2, 0);
+   fs_reg r3 = brw_vec8_grf(3, 0);
+
+   a.DO();
+   a.ADD(r1, r2, r3);
+   a.CMP(r1, r2, r3, BRW_CONDITIONAL_GE);
+   a.IF(BRW_PREDICATE_NORMAL);
+   a.CONTINUE();
+   a.ENDIF();
+   a.MUL(r1, r2, r3);
+   a.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   a.IF(BRW_PREDICATE_NORMAL);
+   a.BREAK();
+   a.ENDIF();
+   a.WHILE();
+   a.NOP();  /* There's always going to be something after a WHILE. */
+   shader_a->calculate_cfg();
+
+   /* With a CONTINUE, the BREAK can't be removed, but still remove the
+    * IF/ENDIF around both of them.
+    */
+   bool progress = opt_predicated_break(shader_a);
+   EXPECT_TRUE(progress);
+
+   b.DO();
+   b.ADD(r1, r2, r3);
+   b.CMP(r1, r2, r3, BRW_CONDITIONAL_GE);
+   b.CONTINUE()->predicate = BRW_PREDICATE_NORMAL;
+   b.MUL(r1, r2, r3);
+   b.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   b.BREAK()->predicate = BRW_PREDICATE_NORMAL;
+   b.WHILE();
+   b.NOP();
+   shader_b->calculate_cfg();
+
+   ASSERT_SHADERS_MATCH(shader_a, shader_b);
+}
+
+TEST_F(PredicatedBreakTest, TwoBreaks)
+{
+   fs_builder a = make_builder(shader_a);
+   fs_builder b = make_builder(shader_b);
+
+   fs_reg r1 = brw_vec8_grf(1, 0);
+   fs_reg r2 = brw_vec8_grf(2, 0);
+   fs_reg r3 = brw_vec8_grf(3, 0);
+
+   a.DO();
+   a.ADD(r1, r2, r3);
+   a.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   a.IF(BRW_PREDICATE_NORMAL);
+   a.BREAK();
+   a.ENDIF();
+   a.MUL(r1, r2, r3);
+   a.CMP(r1, r2, r3, BRW_CONDITIONAL_GE);
+   a.IF(BRW_PREDICATE_NORMAL);
+   a.BREAK();
+   a.ENDIF();
+   a.AND(r1, r2, r3);
+   a.WHILE();
+   a.NOP();  /* There's always going to be something after a WHILE. */
+   shader_a->calculate_cfg();
+
+   /* The IF/ENDIF around the breaks are expected to be removed. */
+   bool progress = opt_predicated_break(shader_a);
+   EXPECT_TRUE(progress);
+
+   b.DO();
+   b.ADD(r1, r2, r3);
+   b.CMP(r1, r2, r3, BRW_CONDITIONAL_NZ);
+   b.BREAK()->predicate = BRW_PREDICATE_NORMAL;
+   b.MUL(r1, r2, r3);
+   b.CMP(r1, r2, r3, BRW_CONDITIONAL_GE);
+   b.BREAK()->predicate = BRW_PREDICATE_NORMAL;
+   b.AND(r1, r2, r3);
+   b.WHILE();
+   b.NOP();  /* There's always going to be something after a WHILE. */
+   shader_b->calculate_cfg();
+
+   ASSERT_SHADERS_MATCH(shader_a, shader_b);
+}

Reply via email to