From c3b30963dd7fbca6bbc849f9f89bc0dec4b3fc1e Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 12 Jun 2020 14:08:23 -0700 Subject: [PATCH] freedreno/ir3: add test for delay slot calculation Signed-off-by: Rob Clark Part-of: --- src/freedreno/ir3/meson.build | 11 +++ src/freedreno/ir3/tests/delay.c | 167 ++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/freedreno/ir3/tests/delay.c diff --git a/src/freedreno/ir3/meson.build b/src/freedreno/ir3/meson.build index c5be77f6e4f..39531e99827 100644 --- a/src/freedreno/ir3/meson.build +++ b/src/freedreno/ir3/meson.build @@ -121,3 +121,14 @@ test('ir3_disasm', ), suite: ['freedreno'], ) + +test('ir3_delay_test', + executable( + 'ir3_delay_test', + 'tests/delay.c', + link_with: libfreedreno_ir3, + dependencies: [idep_mesautil, idep_nir_headers], + include_directories: [inc_freedreno, inc_include, inc_src, inc_mesa, inc_gallium], + ), + suite: ['freedreno'], +) diff --git a/src/freedreno/ir3/tests/delay.c b/src/freedreno/ir3/tests/delay.c new file mode 100644 index 00000000000..562bdf474d6 --- /dev/null +++ b/src/freedreno/ir3/tests/delay.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2020 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "ir3.h" +#include "ir3_compiler.h" +#include "ir3_parser.h" + +/* + * A test for delay-slot calculation. Each test specifies ir3 assembly + * for one or more instructions and the last instruction that consumes + * the previously produced values. And the expected number of delay + * slots that would be needed before that last instruction. Any source + * registers in the last instruction which are not written in a previous + * instruction are not counted. + */ + +#define TEST(n, ...) { # __VA_ARGS__, n } + +static const struct test { + const char *asmstr; + unsigned expected_delay; +} tests[] = { + TEST(6, + add.f r0.x, r2.x, r2.y + rsq r0.x, r0.x + ), + TEST(3, + mov.f32f32 r0.x, c0.x + mov.f32f32 r0.y, c0.y + add.f r0.x, r0.x, r0.y + ), + TEST(2, + mov.f32f32 r0.x, c0.x + mov.f32f32 r0.y, c0.y + mov.f32f32 r0.z, c0.z + mad.f32 r0.x, r0.x, r0.y, r0.z + ), +}; + +static struct ir3 * +parse_asm(struct ir3_compiler *c, const char *asmstr) +{ + struct ir3_shader shader = { + .type = MESA_SHADER_COMPUTE, + .compiler = c, + }; + struct ir3_shader_variant v = { + .type = shader.type, + .shader = &shader, + }; + struct ir3_kernel_info info = {}; + FILE *in = fmemopen((void *)asmstr, strlen(asmstr), "r"); + + struct ir3 *ir = ir3_parse(&v, &info, in); + + fclose(in); + + return ir; +} + +static unsigned +regn(struct ir3_register *reg) +{ + unsigned regn = reg->num; + if (reg->flags & IR3_REG_HALF) + regn += MAX_REG; + return regn; +} + +/** + * Super-cheezy into-ssa pass, doesn't handle flow control or anything + * hard. Just enough to figure out the SSA srcs of the last instruction. + * + * Note that this is not clever enough to know how many src/dst there are + * for various tex/mem instructions. But the rules for tex consuming alu + * are the same as sfu consuming alu. + */ +static void +regs_to_ssa(struct ir3 *ir) +{ + struct ir3_instruction *regfile[2 * MAX_REG] = {}; + struct ir3_block *block = + list_first_entry(&ir->block_list, struct ir3_block, node); + + foreach_instr (instr, &block->instr_list) { + foreach_src (reg, instr) { + if (reg->flags & (IR3_REG_CONST | IR3_REG_IMMED)) + continue; + + struct ir3_instruction *src = regfile[regn(reg)]; + + if (!src) + continue; + + reg->instr = src; + reg->flags |= IR3_REG_SSA; + } + + regfile[regn(instr->regs[0])] = instr; + } +} + + +int +main(int argc, char **argv) +{ + struct ir3_compiler *c; + int result = 0; + + c = ir3_compiler_create(NULL, 630); + + for (int i = 0; i < ARRAY_SIZE(tests); i++) { + const struct test *test = &tests[i]; + struct ir3 *ir = parse_asm(c, test->asmstr); + + ir3_debug_print(ir, "AFTER PARSING"); + + regs_to_ssa(ir); + + ir3_debug_print(ir, "AFTER REGS->SSA"); + + struct ir3_block *block = + list_first_entry(&ir->block_list, struct ir3_block, node); + struct ir3_instruction *last = + list_last_entry(&block->instr_list, struct ir3_instruction, node); + + /* The delay calc is expecting the instr to not yet be added to the + * block, so remove it from the block so that it doesn't get counted + * in the distance from assigner: + */ + list_delinit(&last->node); + + unsigned n = ir3_delay_calc(block, last, false, false); + + if (n != test->expected_delay) { + printf("%d: FAIL: Expected delay %u, but got %u, for:\n%s\n", + i, test->expected_delay, n, test->asmstr); + result = -1; + } else { + printf("%d: PASS\n", i); + } + } + + return result; +}