diff --git a/src/asahi/compiler/meson.build b/src/asahi/compiler/meson.build index 3a8f2729b30..bd336277034 100644 --- a/src/asahi/compiler/meson.build +++ b/src/asahi/compiler/meson.build @@ -76,3 +76,22 @@ libasahi_compiler = static_library( gnu_symbol_visibility : 'hidden', build_by_default : false, ) + +if with_tests + test( + 'agx_tests', + executable( + 'agx_tests', + files( + 'test/test-optimizer.cpp', + ), + c_args : [c_msvc_compat_args, no_override_init_args], + gnu_symbol_visibility : 'hidden', + include_directories : [inc_include, inc_src, inc_mesa], + dependencies: [idep_gtest, idep_nir, idep_agx_opcodes_h, idep_agx_builder_h], + link_with : [libasahi_compiler], + ), + suite : ['asahi'], + protocol : gtest_test_protocol, + ) +endif diff --git a/src/asahi/compiler/test/agx_test.h b/src/asahi/compiler/test/agx_test.h new file mode 100644 index 00000000000..94c81e13688 --- /dev/null +++ b/src/asahi/compiler/test/agx_test.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2020-2021 Collabora Ltd. + * + * 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 MERCHANTAAGXLITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIAAGXLITY, 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. + * + * Authors (Collabora): + * Alyssa Rosenzweig + */ + +#ifndef __AGX_TEST_H +#define __AGX_TEST_H + +#include +#include +#include "agx_compiler.h" +#include "agx_builder.h" + +/* Helper to generate a agx_builder suitable for creating test instructions */ +static inline agx_builder * +agx_test_builder(void *memctx) +{ + agx_context *ctx = rzalloc(memctx, agx_context); + list_inithead(&ctx->blocks); + + agx_block *blk = rzalloc(ctx, agx_block); + + blk->predecessors = _mesa_set_create(blk, + _mesa_hash_pointer, + _mesa_key_pointer_equal); + + list_addtail(&blk->link, &ctx->blocks); + list_inithead(&blk->instructions); + + agx_builder *b = rzalloc(memctx, agx_builder); + b->shader = ctx; + b->cursor = agx_after_block(blk); + + return b; +} + +/* Helper to compare for logical equality of instructions. Need to skip over + * the link, guaranteed to be first. After that we can compare raw data. */ +static inline bool +agx_instr_equal(agx_instr *A, agx_instr *B) +{ + return memcmp((uint8_t *) A + sizeof(struct list_head), + (uint8_t *) B + sizeof(struct list_head), + sizeof(agx_instr) - sizeof(struct list_head)) == 0; +} + +static inline bool +agx_block_equal(agx_block *A, agx_block *B) +{ + if (list_length(&A->instructions) != list_length(&B->instructions)) + return false; + + list_pair_for_each_entry(agx_instr, insA, insB, + &A->instructions, &B->instructions, link) { + if (!agx_instr_equal(insA, insB)) + return false; + } + + return true; +} + +static inline bool +agx_shader_equal(agx_context *A, agx_context *B) +{ + if (list_length(&A->blocks) != list_length(&B->blocks)) + return false; + + list_pair_for_each_entry(agx_block, blockA, blockB, + &A->blocks, &B->blocks, link) { + if (!agx_block_equal(blockA, blockB)) + return false; + } + + return true; +} + +#define ASSERT_SHADER_EQUAL(A, B) \ + if (!agx_shader_equal(A, B)) { \ + ADD_FAILURE(); \ + fprintf(stderr, "Pass produced unexpected results"); \ + fprintf(stderr, " Actual:\n"); \ + agx_print_shader(A, stderr); \ + fprintf(stderr, " Expected:\n"); \ + agx_print_shader(B, stderr); \ + fprintf(stderr, "\n"); \ + } \ + +#define INSTRUCTION_CASE(instr, expected, pass) do { \ + agx_builder *A = agx_test_builder(mem_ctx); \ + agx_builder *B = agx_test_builder(mem_ctx); \ + { \ + agx_builder *b = A; \ + instr; \ + } \ + { \ + agx_builder *b = B; \ + expected; \ + } \ + pass(A->shader); \ + ASSERT_SHADER_EQUAL(A->shader, B->shader); \ +} while(0) + +#endif diff --git a/src/asahi/compiler/test/test-optimizer.cpp b/src/asahi/compiler/test/test-optimizer.cpp new file mode 100644 index 00000000000..2591c3158fb --- /dev/null +++ b/src/asahi/compiler/test/test-optimizer.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Collabora, Ltd. + * + * 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 "agx_test.h" + +#include + +static void +agx_optimize_and_dce(agx_context *ctx) +{ + agx_optimizer(ctx); + agx_dce(ctx); +} + +#define CASE(instr, expected) INSTRUCTION_CASE(instr, expected, agx_optimize_and_dce) +#define NEGCASE(instr) CASE(instr, instr) + +static inline agx_index +agx_fmov(agx_builder *b, agx_index s0) +{ + agx_index tmp = agx_temp(b->shader, s0.size); + agx_fmov_to(b, tmp, s0); + return tmp; +} + +class Optimizer : public testing::Test { +protected: + Optimizer() { + mem_ctx = ralloc_context(NULL); + + wx = agx_register(0, AGX_SIZE_32); + wy = agx_register(2, AGX_SIZE_32); + wz = agx_register(4, AGX_SIZE_32); + + hx = agx_register(0, AGX_SIZE_16); + } + + ~Optimizer() { + ralloc_free(mem_ctx); + } + + void *mem_ctx; + + agx_index wx, wy, wz, hx; +}; + +TEST_F(Optimizer, FusedFABSNEG) +{ + CASE(agx_fadd_to(b, wz, agx_fmov(b, agx_abs(wx)), wy), + agx_fadd_to(b, wz, agx_abs(wx), wy)); + + CASE(agx_fmul_to(b, wz, wx, agx_fmov(b, agx_neg(agx_abs(wx)))), + agx_fmul_to(b, wz, wx, agx_neg(agx_abs(wx)))); +}