nir: add NIR_DEBUG=progress_validation

Fails if a shader was changed but the pass didn't report progress.

Signed-off-by: Rhys Perry <pendingchaos02@gmail.com>
Reviewed-by: Marek Olšák <maraeo@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35069>
This commit is contained in:
Rhys Perry 2025-05-16 16:23:41 +01:00 committed by Marge Bot
parent 706ba80057
commit 7538167096
3 changed files with 88 additions and 23 deletions

View file

@ -51,6 +51,8 @@ static const struct debug_named_value nir_debug_control[] = {
"Disable shader validation at each successful lowering/optimization call" },
{ "extended_validation", NIR_DEBUG_EXTENDED_VALIDATION,
"Validate even if a pass does not make progress and test that it properly preserves most types of metadata. This can be very slow" },
{ "progress_validation", NIR_DEBUG_PROGRESS_VALIDATION,
"Validate that a shader is unmodified if a pass does not report progress" },
{ "invalidate_metadata", NIR_DEBUG_INVALIDATE_METADATA,
"Invalidate metadata before passes to try to find passes which don't require metadata that they use. This overrides NIR_DEBUG=extended_validation somewhat" },
{ "tgsi", NIR_DEBUG_TGSI,

View file

@ -93,6 +93,7 @@ extern bool nir_debug_print_shader[MESA_SHADER_KERNEL + 1];
#define NIR_DEBUG_PRINT_PASS_FLAGS (1u << 22)
#define NIR_DEBUG_INVALIDATE_METADATA (1u << 23)
#define NIR_DEBUG_PRINT_STRUCT_DECLS (1u << 24)
#define NIR_DEBUG_PROGRESS_VALIDATION (1u << 25)
#define NIR_DEBUG_PRINT (NIR_DEBUG_PRINT_VS | \
NIR_DEBUG_PRINT_TCS | \
@ -4717,6 +4718,8 @@ void nir_validate_ssa_dominance(nir_shader *shader, const char *when);
void nir_metadata_set_validation_flag(nir_shader *shader);
void nir_metadata_check_validation_flag(nir_shader *shader);
void nir_metadata_require_most(nir_shader *shader);
struct blob nir_validate_progress_setup(nir_shader *shader);
void nir_validate_progress_finish(nir_shader *shader, struct blob *setup_blob, bool progress, const char *when);
static inline bool
should_skip_nir(const char *name)
@ -4773,6 +4776,19 @@ nir_metadata_require_most(nir_shader *shader)
{
(void)shader;
}
static inline struct blob
nir_validate_progress_setup(nir_shader *shader)
{
return (struct blob){};
}
static inline void
nir_validate_progress_finish(nir_shader *shader, struct blob *setup_blob, bool progress, const char *when)
{
(void)shader;
(void)setup_blob;
(void)progress;
(void)when;
}
static inline bool
should_skip_nir(UNUSED const char *pass_name)
{
@ -4812,15 +4828,20 @@ should_print_nir(UNUSED nir_shader *shader)
nir_metadata_set_validation_flag(nir); \
if (should_print_nir(nir)) \
printf("%s\n", #pass); \
static const char *when = "after " #pass " in " __FILE__ ":" NIR_STRINGIZE(__LINE__); \
struct blob blob_before = nir_validate_progress_setup(nir); \
if (pass(nir, ##__VA_ARGS__)) { \
nir_validate_shader(nir, "after " #pass " in " __FILE__ ":" NIR_STRINGIZE(__LINE__)); \
nir_validate_shader(nir, when); \
UNUSED bool _; \
progress = true; \
if (should_print_nir(nir)) \
nir_print_shader(nir, stdout); \
nir_metadata_check_validation_flag(nir); \
} else if (NIR_DEBUG(EXTENDED_VALIDATION)) { \
nir_validate_shader(nir, "after " #pass " in " __FILE__ ":" NIR_STRINGIZE(__LINE__)); \
nir_validate_progress_finish(nir, &blob_before, true, when); \
} else { \
if (NIR_DEBUG(EXTENDED_VALIDATION)) \
nir_validate_shader(nir, when); \
nir_validate_progress_finish(nir, &blob_before, false, when); \
} \
})

View file

@ -2151,15 +2151,8 @@ nir_serialize_function(struct blob *blob, const nir_function *fxn)
util_dynarray_fini(&ctx.phi_fixups);
}
/**
* Serialize NIR into a binary blob.
*
* \param strip Don't serialize information only useful for debugging,
* such as variable names, making cache hits from similar
* shaders more likely.
*/
void
nir_serialize(struct blob *blob, const nir_shader *nir, bool strip)
static void
serialize_internal(struct blob *blob, const nir_shader *nir, bool strip, bool serialize_info)
{
write_ctx ctx = { 0 };
_mesa_pointer_hash_table_init(&ctx.remap_table, NULL);
@ -2172,6 +2165,8 @@ nir_serialize(struct blob *blob, const nir_shader *nir, bool strip)
size_t idx_size_offset = blob_reserve_uint32(blob);
struct shader_info info = nir->info;
if (!serialize_info)
memset(&info, 0, sizeof(info));
enum nir_serialize_shader_flags flags = 0;
if (!strip && info.name)
@ -2220,6 +2215,19 @@ nir_serialize(struct blob *blob, const nir_shader *nir, bool strip)
util_dynarray_fini(&ctx.phi_fixups);
}
/**
* Serialize NIR into a binary blob.
*
* \param strip Don't serialize information only useful for debugging,
* such as variable names, making cache hits from similar
* shaders more likely.
*/
void
nir_serialize(struct blob *blob, const nir_shader *nir, bool strip)
{
serialize_internal(blob, nir, strip, true);
}
nir_shader *
nir_deserialize(void *mem_ctx,
const struct nir_shader_compiler_options *options,
@ -2335,3 +2343,37 @@ nir_shader_serialize_deserialize(nir_shader *shader)
nir_shader_replace(shader, copy);
ralloc_free(dead_ctx);
}
#ifndef NDEBUG
struct blob
nir_validate_progress_setup(nir_shader *shader)
{
if (!NIR_DEBUG(PROGRESS_VALIDATION))
return (struct blob){};
struct blob blob_before;
blob_init(&blob_before);
serialize_internal(&blob_before, shader, false, false);
return blob_before;
}
void
nir_validate_progress_finish(nir_shader *shader, struct blob *setup_blob, bool progress, const char *when)
{
if (!NIR_DEBUG(PROGRESS_VALIDATION))
return;
if (!progress) {
struct blob blob_after;
blob_init(&blob_after);
serialize_internal(&blob_after, shader, false, false);
if (setup_blob->size != blob_after.size ||
memcmp(setup_blob->data, blob_after.data, setup_blob->size)) {
fprintf(stderr, "NIR changed but no progress reported %s\n", when);
abort();
}
blob_finish(&blob_after);
}
blob_finish(setup_blob);
}
#endif