From: Alyssa Rosenzweig Date: Fri, 23 Jul 2021 15:21:29 +0000 (-0400) Subject: pan/va: Add FAU validation X-Git-Tag: upstream/22.3.5~11203 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fd1906afea59073780939810e0e46094264677d3;p=platform%2Fupstream%2Fmesa.git pan/va: Add FAU validation Signed-off-by: Alyssa Rosenzweig Part-of: --- diff --git a/src/panfrost/bifrost/meson.build b/src/panfrost/bifrost/meson.build index 914bd53..81eb621 100644 --- a/src/panfrost/bifrost/meson.build +++ b/src/panfrost/bifrost/meson.build @@ -47,6 +47,7 @@ libpanfrost_bifrost_files = files( 'bifrost_compile.c', 'valhall/va_optimize.c', 'valhall/va_pack.c', + 'valhall/va_validate.c', ) bifrost_gen_disasm_c = custom_target( @@ -161,6 +162,7 @@ if with_tests 'test/test-packing.cpp', 'test/test-scheduler-predicates.cpp', 'valhall/test/test-add-imm.cpp', + 'valhall/test/test-validate-fau.cpp', ), c_args : [c_msvc_compat_args, no_override_init_args], gnu_symbol_visibility : 'hidden', diff --git a/src/panfrost/bifrost/valhall/test/test-validate-fau.cpp b/src/panfrost/bifrost/valhall/test/test-validate-fau.cpp new file mode 100644 index 0000000..4275d03 --- /dev/null +++ b/src/panfrost/bifrost/valhall/test/test-validate-fau.cpp @@ -0,0 +1,124 @@ +/* + * 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 "va_compiler.h" +#include "bi_test.h" +#include "bi_builder.h" + +#include + +#define CASE(instr, expected) do { \ + if (va_validate_fau(instr) != expected) { \ + fprintf(stderr, "Incorrect validation for:\n"); \ + bi_print_instr(instr, stderr); \ + fprintf(stderr, "\n"); \ + ADD_FAILURE(); \ + } \ +} while(0) + +#define VALID(instr) CASE(instr, true) +#define INVALID(instr) CASE(instr, false) + +class ValidateFau : public testing::Test { +protected: + ValidateFau() { + mem_ctx = ralloc_context(NULL); + b = bit_builder(mem_ctx); + + zero = bi_fau((enum bir_fau) (BIR_FAU_IMMEDIATE | 0), false); + imm1 = bi_fau((enum bir_fau) (BIR_FAU_IMMEDIATE | 1), false); + imm2 = bi_fau((enum bir_fau) (BIR_FAU_IMMEDIATE | 2), false); + unif = bi_fau((enum bir_fau) (BIR_FAU_UNIFORM | 5), false); + unif2 = bi_fau((enum bir_fau) (BIR_FAU_UNIFORM | 6), false); + core_id = bi_fau(BIR_FAU_CORE_ID, false); + lane_id = bi_fau(BIR_FAU_LANE_ID, false); + } + + ~ValidateFau() { + ralloc_free(mem_ctx); + } + + void *mem_ctx; + bi_builder *b; + bi_index zero, imm1, imm2, unif, unif2, core_id, lane_id; +}; + +TEST_F(ValidateFau, One64BitUniformSlot) +{ + VALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), bi_register(3), + unif, BI_ROUND_NONE)); + VALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), bi_word(unif, 1), + unif, BI_ROUND_NONE)); + VALID(bi_fma_f32_to(b, bi_register(1), unif, unif, bi_word(unif, 1), + BI_ROUND_NONE)); + INVALID(bi_fma_f32_to(b, bi_register(1), unif, unif2, bi_register(1), + BI_ROUND_NONE)); + INVALID(bi_fma_f32_to(b, bi_register(1), unif, unif2, bi_word(unif, 1), + BI_ROUND_NONE)); + + /* Crafted case that appears correct at first glance and was erronously + * marked as valid in early versions of the validator. + */ + INVALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), + bi_fau((enum bir_fau) (BIR_FAU_UNIFORM | 0), false), + bi_fau((enum bir_fau) (BIR_FAU_UNIFORM | 1), true), + BI_ROUND_NONE)); +} + +TEST_F(ValidateFau, Combined64BitUniformsConstants) +{ + VALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), bi_word(unif, 1), + unif, BI_ROUND_NONE)); + VALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), zero, + unif, BI_ROUND_NONE)); + VALID(bi_fma_f32_to(b, bi_register(1), zero, imm1, imm1, BI_ROUND_NONE)); + INVALID(bi_fma_f32_to(b, bi_register(1), zero, bi_word(unif, 1), + unif, BI_ROUND_NONE)); + INVALID(bi_fma_f32_to(b, bi_register(1), zero, imm1, imm2, BI_ROUND_NONE)); +} + +TEST_F(ValidateFau, UniformsOnlyInDefaultMode) +{ + INVALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), bi_word(unif, 1), + lane_id, BI_ROUND_NONE)); + INVALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), bi_word(unif, 1), + core_id, BI_ROUND_NONE)); +} + +TEST_F(ValidateFau, SingleSpecialImmediate) +{ + VALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), bi_register(2), + lane_id, BI_ROUND_NONE)); + VALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), bi_register(2), + core_id, BI_ROUND_NONE)); + INVALID(bi_fma_f32_to(b, bi_register(1), bi_register(2), lane_id, + core_id, BI_ROUND_NONE)); +} + +TEST_F(ValidateFau, SmokeTests) +{ + VALID(bi_mov_i32_to(b, bi_register(1), bi_register(2))); + VALID(bi_mov_i32_to(b, bi_register(1), unif)); + VALID(bi_fma_f32_to(b, bi_register(1), bi_discard(bi_register(1)), + unif, bi_neg(zero), BI_ROUND_NONE)); +} diff --git a/src/panfrost/bifrost/valhall/va_compiler.h b/src/panfrost/bifrost/valhall/va_compiler.h index d7207cd..1d2a76a 100644 --- a/src/panfrost/bifrost/valhall/va_compiler.h +++ b/src/panfrost/bifrost/valhall/va_compiler.h @@ -34,6 +34,9 @@ extern "C" { #endif +bool va_validate_fau(bi_instr *I); +void va_validate(FILE *fp, bi_context *ctx); +void va_repair_fau(bi_builder *b, bi_instr *I); void va_fuse_add_imm(bi_instr *I); uint64_t va_pack_instr(const bi_instr *I, unsigned flow); diff --git a/src/panfrost/bifrost/valhall/va_validate.c b/src/panfrost/bifrost/valhall/va_validate.c new file mode 100644 index 0000000..e404d74 --- /dev/null +++ b/src/panfrost/bifrost/valhall/va_validate.c @@ -0,0 +1,170 @@ +/* + * 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 "va_compiler.h" +#include "valhall.h" +#include "bi_builder.h" + +/* Valhall has limits on access to fast-access uniforms: + * + * An instruction may access no more than a single 64-bit uniform slot. + * An instruction may access no more than 64-bits of combined uniforms and constants. + * An instruction may access no more than a single special immediate (e.g. lane_id). + * + * We validate these constraints. + * + * An instruction may only access a single page of (special or uniform) FAU. + * This constraint does not need explicit validation: since FAU slots are + * naturally aligned, they never cross page boundaries, so this condition is + * implied by only acesssing a single 64-bit slot. + */ + +struct fau_state { + signed uniform_slot; + bi_index buffer[2]; +}; + +static bool +fau_state_buffer(struct fau_state *fau, bi_index idx) +{ + for (unsigned i = 0; i < ARRAY_SIZE(fau->buffer); ++i) { + if (bi_is_word_equiv(fau->buffer[i], idx)) + return true; + else if (bi_is_null(fau->buffer[i])) { + fau->buffer[i] = idx; + return true; + } + } + + return false; +} + +static bool +fau_state_uniform(struct fau_state *fau, bi_index idx) +{ + /* Each slot is 64-bits. The low/high half is encoded as the offset of the + * bi_index, which we want to ignore. + */ + unsigned slot = (idx.value & 63); + + if (fau->uniform_slot < 0) + fau->uniform_slot = slot; + + return fau->uniform_slot == slot; +} + +static bool +fau_is_special(enum bir_fau fau) +{ + return !(fau & (BIR_FAU_UNIFORM | BIR_FAU_IMMEDIATE)); +} + +static bool +fau_state_special(struct fau_state *fau, bi_index idx) +{ + for (unsigned i = 0; i < ARRAY_SIZE(fau->buffer); ++i) { + bi_index buf = fau->buffer[i]; + bool special = !bi_is_null(buf) && fau_is_special(buf.value); + + if (special && !bi_is_equiv(buf, idx)) + return false; + } + + return true; +} + +static bool +valid_src(struct fau_state *fau, unsigned fau_page, bi_index src) +{ + if (src.type != BI_INDEX_FAU) + return true; + + bool valid = (fau_page == va_fau_page(src.value)); + valid &= fau_state_buffer(fau, src); + + if (src.value & BIR_FAU_UNIFORM) + valid &= fau_state_uniform(fau, src); + else if (fau_is_special(src.value)) + valid &= fau_state_special(fau, src); + + return valid; +} + +bool +va_validate_fau(bi_instr *I) +{ + bool valid = true; + struct fau_state fau = { .uniform_slot = -1 }; + unsigned fau_page = va_select_fau_page(I); + + bi_foreach_src(I, s) { + valid &= valid_src(&fau, fau_page, I->src[s]); + } + + return valid; +} + +void +va_repair_fau(bi_builder *b, bi_instr *I) +{ + struct fau_state fau = { .uniform_slot = -1 }; + unsigned fau_page = va_select_fau_page(I); + + bi_foreach_src(I, s) { + struct fau_state push = fau; + bi_index src = I->src[s]; + + if (!valid_src(&fau, fau_page, src)) { + bi_index copy = bi_mov_i32(b, bi_strip_index(src)); + I->src[s] = bi_replace_index(src, copy); + + /* Rollback update. Since the replacement move doesn't affect FAU + * state, there is no need to call valid_src again. + */ + fau = push; + } + } +} + +void +va_validate(FILE *fp, bi_context *ctx) +{ + bool errors = false; + + bi_foreach_instr_global(ctx, I) { + if (!va_validate_fau(I)) { + if (!errors) { + fprintf(fp, "Validation failed, this is a bug. Shader:\n\n"); + bi_print_shader(ctx, fp); + fprintf(fp, "Offending code:\n"); + } + + bi_print_instr(I, fp); + fprintf(fp, "\n"); + errors = true; + } + } + + if (errors) + exit(1); +}