mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-24 17:30:12 +01:00
pan/va: Add FAU validation
Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15223>
This commit is contained in:
parent
676d9c9441
commit
fd1906afea
4 changed files with 299 additions and 0 deletions
|
|
@ -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',
|
||||
|
|
|
|||
124
src/panfrost/bifrost/valhall/test/test-validate-fau.cpp
Normal file
124
src/panfrost/bifrost/valhall/test/test-validate-fau.cpp
Normal file
|
|
@ -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 <gtest/gtest.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
170
src/panfrost/bifrost/valhall/va_validate.c
Normal file
170
src/panfrost/bifrost/valhall/va_validate.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue