brw: Simplify the test code for brw passes

The key change is to use a builder to write the expected shader result
and compare that.  To make this less error prone, a few helper functions
were added

- a way to allocate VGRFs from both shaders in parallel, that way the
  same brw_reg can be used in both of them;
- assertions that a pass will make progress or not, and proper output
  when the unexpected happens;
- use a common brw_shader_pass_test class so to collect some of the helpers;
- make some helpers work directly with builder.

The idea is to improve the signal in tests, so that the disasm comments
are not necessary anymore.  For example

```
TEST_F(saturate_propagation_test, basic)
{
   brw_reg dst1 = bld.vgrf(BRW_TYPE_F);
   brw_reg src0 = bld.vgrf(BRW_TYPE_F);
   brw_reg src1 = bld.vgrf(BRW_TYPE_F);
   brw_reg dst0 = bld.ADD(src0, src1);
   set_saturate(true, bld.MOV(dst1, dst0));

   /* = Before =
    *
    * 0: add(16)       dst0  src0  src1
    * 1: mov.sat(16)   dst1  dst0
    *
    * = After =
    * 0: add.sat(16)   dst0  src0  src1
    * 1: mov(16)       dst1  dst0
    */

   brw_calculate_cfg(*v);
   bblock_t *block0 = v->cfg->blocks[0];

   EXPECT_EQ(0, block0->start_ip);
   EXPECT_EQ(1, block0->end_ip);

   EXPECT_TRUE(saturate_propagation(v));
   EXPECT_EQ(0, block0->start_ip);
   EXPECT_EQ(1, block0->end_ip);
   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
   EXPECT_TRUE(instruction(block0, 0)->saturate);
   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
   EXPECT_FALSE(instruction(block0, 1)->saturate);
}
```

becomes

```
TEST_F(saturate_propagation_test, basic)
{
   brw_builder bld = make_shader(MESA_SHADER_FRAGMENT, 16);
   brw_builder exp = make_shader(MESA_SHADER_FRAGMENT, 16);

   brw_reg dst0 = vgrf(bld, exp, BRW_TYPE_F);
   brw_reg dst1 = vgrf(bld, exp, BRW_TYPE_F);
   brw_reg src0 = vgrf(bld, exp, BRW_TYPE_F);
   brw_reg src1 = vgrf(bld, exp, BRW_TYPE_F);

   bld.ADD(dst0, src0, src1);
   bld.MOV(dst1, dst0)->saturate = true;

   EXPECT_PROGRESS(brw_opt_saturate_propagation, bld);

   exp.ADD(dst0, src0, src1)->saturate = true;
   exp.MOV(dst1, dst0);

   EXPECT_SHADERS_MATCH(bld, exp);
}
```

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33936>
This commit is contained in:
Caio Oliveira
2025-03-05 16:58:32 -08:00
committed by Marge Bot
parent bdfb478be1
commit 91feef40db
8 changed files with 1260 additions and 2465 deletions
@@ -3,101 +3,41 @@
* SPDX-License-Identifier: MIT
*/
#include <gtest/gtest.h>
#include "brw_shader.h"
#include "test_helpers.h"
#include "brw_builder.h"
#include "brw_cfg.h"
struct FSCombineConstantsTest : public ::testing::Test {
FSCombineConstantsTest() {
mem_ctx = ralloc_context(NULL);
class CombineConstantsTest : public brw_shader_pass_test {};
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_COMPUTE, NULL, NULL);
shader = new brw_shader(&compiler, &params, NULL,
&prog_data.base, nir, 8, false, false);
}
~FSCombineConstantsTest() override {
delete shader;
ralloc_free(mem_ctx);
mem_ctx = NULL;
}
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;
brw_shader *shader;
bool opt_combine_constants(brw_shader *s) {
const bool print = getenv("TEST_DEBUG");
if (print) {
fprintf(stderr, "= Before =\n");
s->cfg->dump();
}
bool ret = brw_opt_combine_constants(*s);
if (print) {
fprintf(stderr, "\n= After =\n");
s->cfg->dump();
}
return ret;
}
};
TEST_F(FSCombineConstantsTest, Simple)
TEST_F(CombineConstantsTest, Simple)
{
brw_builder bld = brw_builder(shader);
brw_builder bld = make_shader(MESA_SHADER_COMPUTE);
brw_builder exp = make_shader(MESA_SHADER_COMPUTE);
brw_reg r = brw_vec8_grf(1, 0);
brw_reg imm_a = brw_imm_ud(1);
brw_reg imm_b = brw_imm_ud(2);
brw_reg imm_a = brw_imm_d(1);
brw_reg imm_b = brw_imm_d(2);
bld.SEL(r, imm_a, imm_b);
brw_calculate_cfg(*shader);
bool progress = opt_combine_constants(shader);
ASSERT_TRUE(progress);
EXPECT_PROGRESS(brw_opt_combine_constants, bld);
ASSERT_EQ(shader->cfg->num_blocks, 1);
bblock_t *block = shader->cfg->first_block();
ASSERT_NE(block, nullptr);
brw_reg tmp = component(exp.vgrf(BRW_TYPE_D), 0);
/* We can do better but for now sanity check that
* there's a MOV and a SEL.
*/
ASSERT_EQ(block->start()->opcode, BRW_OPCODE_MOV);
ASSERT_EQ(block->end()->opcode, BRW_OPCODE_SEL);
exp.group(1, 0).exec_all().MOV(tmp, imm_a);
exp .SEL(r, tmp, imm_b);
EXPECT_SHADERS_MATCH(bld, exp);
}
TEST_F(FSCombineConstantsTest, DoContainingDo)
TEST_F(CombineConstantsTest, DoContainingDo)
{
brw_builder bld = brw_builder(shader);
brw_builder bld = make_shader(MESA_SHADER_COMPUTE);
brw_builder exp = make_shader(MESA_SHADER_COMPUTE);
brw_reg r1 = brw_vec8_grf(1, 0);
brw_reg r2 = brw_vec8_grf(2, 0);
brw_reg imm_a = brw_imm_ud(1);
brw_reg imm_b = brw_imm_ud(2);
brw_reg imm_a = brw_imm_d(1);
brw_reg imm_b = brw_imm_d(2);
bld.DO();
bld.DO();
@@ -105,18 +45,19 @@ TEST_F(FSCombineConstantsTest, DoContainingDo)
bld.WHILE();
bld.WHILE();
bld.SEL(r2, imm_a, imm_b);
brw_calculate_cfg(*shader);
unsigned original_num_blocks = shader->cfg->num_blocks;
EXPECT_PROGRESS(brw_opt_combine_constants, bld);
bool progress = opt_combine_constants(shader);
ASSERT_TRUE(progress);
/* Explicit emit the expected FLOW instruction. */
exp.emit(BRW_OPCODE_DO);
brw_reg tmp = component(exp.vgrf(BRW_TYPE_D), 0);
exp.group(1, 0).exec_all().MOV(tmp, imm_a);
exp.emit(SHADER_OPCODE_FLOW);
exp.DO();
exp.SEL(r1, tmp, imm_b);
exp.WHILE();
exp.WHILE();
exp.SEL(r2, tmp, imm_b);
/* We can do better but for now sanity check there's
* enough blocks, since the original issue motivating this
* test is that the shader would be empty.
*/
ASSERT_GE(shader->cfg->num_blocks, original_num_blocks);
brw_validate(*shader);
EXPECT_SHADERS_MATCH(bld, exp);
}