mesa/src/intel/compiler/test_helpers.cpp

258 lines
6.2 KiB
C++
Raw Normal View History

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>
2025-03-05 16:58:32 -08:00
/*
* Copyright © 2025 Intel Corporation
* SPDX-License-Identifier: MIT
*/
#include "test_helpers.h"
#include "brw_builder.h"
std::string
brw_shader_to_string(brw_shader *s)
{
if (!s->cfg)
brw_calculate_cfg(*s);
char *str = NULL;
size_t size = 0;
FILE *f = open_memstream(&str, &size);
brw_print_instructions(*s, f);
fclose(f);
std::string result(str);
free(str);
return result;
}
void
brw_reindex_vgrfs(brw_shader *s)
{
struct Entry {
int new_nr;
int size;
bool valid;
};
unsigned next_nr = 0;
Entry *map = rzalloc_array(NULL, Entry, s->alloc.count);
/* Build map and update references to VGRFs instructions as
* they are seen. First destination then sources.
*/
foreach_block_and_inst(block, brw_inst, inst, s->cfg) {
if (inst->dst.file == VGRF) {
Entry &entry = map[inst->dst.nr];
if (!entry.valid) {
entry.new_nr = next_nr++;
entry.size = s->alloc.sizes[inst->dst.nr];
entry.valid = true;
}
inst->dst.nr = entry.new_nr;
}
for (int i = 0; i < inst->sources; i++) {
if (inst->src[i].file == VGRF) {
Entry &entry = map[inst->src[i].nr];
if (!entry.valid) {
entry.new_nr = next_nr++;
entry.size = s->alloc.sizes[inst->src[i].nr];
entry.valid = true;
}
inst->src[i].nr = entry.new_nr;
}
}
}
/* Move unused entries to the end. */
for (unsigned i = 0; i < s->alloc.count; i++) {
Entry &entry = map[i];
if (!entry.valid) {
entry.new_nr = next_nr++;
entry.size = s->alloc.sizes[i];
entry.valid = true;
}
}
assert(next_nr == s->alloc.count);
/* Update sizes. */
for (unsigned i = 0; i < s->alloc.count; i++)
s->alloc.sizes[map[i].new_nr] = map[i].size;
ralloc_free(map);
s->invalidate_analysis(BRW_DEPENDENCY_VARIABLES);
}
void
EXPECT_SHADERS_MATCH(brw_shader *a, brw_shader *b)
{
if (!a->cfg)
brw_calculate_cfg(*a);
if (!b->cfg)
brw_calculate_cfg(*b);
brw_validate(*a);
brw_validate(*b);
brw_reindex_vgrfs(a);
brw_reindex_vgrfs(b);
std::string sa = brw_shader_to_string(a);
std::string sb = brw_shader_to_string(b);
EXPECT_EQ(sa, sb);
}
class TestHelpers : public brw_shader_pass_test {};
TEST_F(TestHelpers, ReindexVGRFsDestinations)
{
brw_builder bld = make_shader();
brw_reg d = bld.vgrf(BRW_TYPE_UD);
brw_reg c = bld.vgrf(BRW_TYPE_UD);
brw_reg b = bld.vgrf(BRW_TYPE_UD);
brw_reg a = bld.vgrf(BRW_TYPE_UD);
brw_inst *mov_a = bld.MOV(a, brw_vec8_grf(0, 0));
brw_inst *mov_b = bld.MOV(b, a);
brw_inst *mov_c = bld.MOV(c, b);
brw_inst *add_d = bld.ADD(d, a, b);
EXPECT_EQ(mov_a->dst.nr, 3);
EXPECT_EQ(mov_b->dst.nr, 2);
EXPECT_EQ(mov_c->dst.nr, 1);
EXPECT_EQ(add_d->dst.nr, 0);
brw_calculate_cfg(*bld.shader);
brw_reindex_vgrfs(bld.shader);
EXPECT_EQ(mov_a->dst.nr, 0);
EXPECT_EQ(mov_b->dst.nr, 1);
EXPECT_EQ(mov_c->dst.nr, 2);
EXPECT_EQ(add_d->dst.nr, 3);
}
TEST_F(TestHelpers, ReindexVGRFsSources)
{
brw_builder bld = make_shader();
brw_reg d = bld.vgrf(BRW_TYPE_UD);
brw_reg c = bld.vgrf(BRW_TYPE_UD);
brw_reg b = bld.vgrf(BRW_TYPE_UD);
brw_reg a = bld.vgrf(BRW_TYPE_UD);
brw_inst *mov_a = bld.MOV(brw_vec8_grf(0, 0), a);
brw_inst *mov_b = bld.MOV(brw_vec8_grf(7, 0), b);
brw_inst *add_cd = bld.ADD(brw_vec8_grf(14, 0), c, d);
EXPECT_EQ(mov_a->src[0].nr, 3);
EXPECT_EQ(mov_b->src[0].nr, 2);
EXPECT_EQ(add_cd->src[0].nr, 1);
EXPECT_EQ(add_cd->src[1].nr, 0);
brw_calculate_cfg(*bld.shader);
brw_reindex_vgrfs(bld.shader);
EXPECT_EQ(mov_a->src[0].nr, 0);
EXPECT_EQ(mov_b->src[0].nr, 1);
EXPECT_EQ(add_cd->src[0].nr, 2);
EXPECT_EQ(add_cd->src[1].nr, 3);
}
TEST_F(TestHelpers, ReindexVGRFsIncludesSizes)
{
brw_builder bld = make_shader();
brw_reg d = bld.vgrf(BRW_TYPE_UD, 1);
brw_reg c = bld.vgrf(BRW_TYPE_UD, 6);
brw_reg b = bld.vgrf(BRW_TYPE_UD, 8);
brw_reg a = bld.vgrf(BRW_TYPE_UD, 2);
brw_inst *mov_a = bld.MOV(a, brw_imm_d(2222));
brw_inst *mov_b = bld.MOV(b, brw_imm_d(8888));
brw_inst *mov_c = bld.MOV(c, brw_imm_d(6666));
brw_inst *mov_d = bld.MOV(d, brw_imm_d(1111));
EXPECT_EQ(mov_a->dst.nr, 3);
EXPECT_EQ(mov_b->dst.nr, 2);
EXPECT_EQ(mov_c->dst.nr, 1);
EXPECT_EQ(mov_d->dst.nr, 0);
brw_calculate_cfg(*bld.shader);
brw_reindex_vgrfs(bld.shader);
EXPECT_EQ(mov_a->dst.nr, 0);
EXPECT_EQ(mov_b->dst.nr, 1);
EXPECT_EQ(mov_c->dst.nr, 2);
EXPECT_EQ(mov_d->dst.nr, 3);
brw_shader *s = bld.shader;
EXPECT_EQ(s->alloc.count, 4);
EXPECT_EQ(s->alloc.sizes[0], 2);
EXPECT_EQ(s->alloc.sizes[1], 8);
EXPECT_EQ(s->alloc.sizes[2], 6);
EXPECT_EQ(s->alloc.sizes[3], 1);
}
TEST_F(TestHelpers, ReindexVGRFsUnusedAreMovedToTheEnd)
{
brw_builder bld = make_shader();
brw_reg a = bld.vgrf(BRW_TYPE_UD, 4);
UNUSED brw_reg b = bld.vgrf(BRW_TYPE_UD, 6);
brw_reg c = bld.vgrf(BRW_TYPE_UD, 8);
brw_inst *add = bld.ADD(a, a, c);
brw_calculate_cfg(*bld.shader);
brw_reindex_vgrfs(bld.shader);
EXPECT_EQ(add->src[0].nr, 0);
EXPECT_EQ(add->src[1].nr, 1);
brw_shader *s = bld.shader;
EXPECT_EQ(s->alloc.count, 3);
EXPECT_EQ(s->alloc.sizes[0], 4);
EXPECT_EQ(s->alloc.sizes[1], 8);
EXPECT_EQ(s->alloc.sizes[2], 6);
}
TEST_F(TestHelpers, MatchShadersSameStructureDifferentNumbers)
{
brw_builder a = make_shader();
brw_builder b = make_shader();
int nr_from_a;
int nr_from_b;
/* Build using the builder automatic allocations. */
{
brw_inst *add = NULL;
brw_reg src0 = a.MOV(brw_ud8_grf(1, 0));
brw_reg src1 = a.MOV(brw_ud8_grf(7, 0));
a.ADD(src0, src1, &add);
EXPECT_EQ(add->dst.file, VGRF);
nr_from_a = add->dst.nr;
}
/* Build using explicitly created VGRFs. */
{
brw_reg dst = b.vgrf(BRW_TYPE_UD);
brw_reg src0 = b.vgrf(BRW_TYPE_UD);
brw_reg src1 = b.vgrf(BRW_TYPE_UD);
b.MOV(src0, brw_ud8_grf(1, 0));
b.MOV(src1, brw_ud8_grf(7, 0));
b.ADD(dst, src0, src1);
nr_from_b = dst.nr;
}
EXPECT_NE(nr_from_a, nr_from_b);
EXPECT_SHADERS_MATCH(a, b);
}