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" }, "Disable shader validation at each successful lowering/optimization call" },
{ "extended_validation", NIR_DEBUG_EXTENDED_VALIDATION, { "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" }, "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", 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" }, "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, { "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_PRINT_PASS_FLAGS (1u << 22)
#define NIR_DEBUG_INVALIDATE_METADATA (1u << 23) #define NIR_DEBUG_INVALIDATE_METADATA (1u << 23)
#define NIR_DEBUG_PRINT_STRUCT_DECLS (1u << 24) #define NIR_DEBUG_PRINT_STRUCT_DECLS (1u << 24)
#define NIR_DEBUG_PROGRESS_VALIDATION (1u << 25)
#define NIR_DEBUG_PRINT (NIR_DEBUG_PRINT_VS | \ #define NIR_DEBUG_PRINT (NIR_DEBUG_PRINT_VS | \
NIR_DEBUG_PRINT_TCS | \ 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_set_validation_flag(nir_shader *shader);
void nir_metadata_check_validation_flag(nir_shader *shader); void nir_metadata_check_validation_flag(nir_shader *shader);
void nir_metadata_require_most(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 static inline bool
should_skip_nir(const char *name) should_skip_nir(const char *name)
@ -4773,6 +4776,19 @@ nir_metadata_require_most(nir_shader *shader)
{ {
(void)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 static inline bool
should_skip_nir(UNUSED const char *pass_name) should_skip_nir(UNUSED const char *pass_name)
{ {
@ -4808,20 +4824,25 @@ should_print_nir(UNUSED nir_shader *shader)
#define NIR_STRINGIZE_INNER(x) #x #define NIR_STRINGIZE_INNER(x) #x
#define NIR_STRINGIZE(x) NIR_STRINGIZE_INNER(x) #define NIR_STRINGIZE(x) NIR_STRINGIZE_INNER(x)
#define NIR_PASS(progress, nir, pass, ...) _PASS(pass, nir, { \ #define NIR_PASS(progress, nir, pass, ...) _PASS(pass, nir, { \
nir_metadata_set_validation_flag(nir); \ nir_metadata_set_validation_flag(nir); \
if (should_print_nir(nir)) \ if (should_print_nir(nir)) \
printf("%s\n", #pass); \ printf("%s\n", #pass); \
if (pass(nir, ##__VA_ARGS__)) { \ static const char *when = "after " #pass " in " __FILE__ ":" NIR_STRINGIZE(__LINE__); \
nir_validate_shader(nir, "after " #pass " in " __FILE__ ":" NIR_STRINGIZE(__LINE__)); \ struct blob blob_before = nir_validate_progress_setup(nir); \
UNUSED bool _; \ if (pass(nir, ##__VA_ARGS__)) { \
progress = true; \ nir_validate_shader(nir, when); \
if (should_print_nir(nir)) \ UNUSED bool _; \
nir_print_shader(nir, stdout); \ progress = true; \
nir_metadata_check_validation_flag(nir); \ if (should_print_nir(nir)) \
} else if (NIR_DEBUG(EXTENDED_VALIDATION)) { \ nir_print_shader(nir, stdout); \
nir_validate_shader(nir, "after " #pass " in " __FILE__ ":" NIR_STRINGIZE(__LINE__)); \ nir_metadata_check_validation_flag(nir); \
} \ 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); \
} \
}) })
#define _NIR_LOOP_PASS(progress, idempotent, skip, nir, pass, ...) \ #define _NIR_LOOP_PASS(progress, idempotent, skip, nir, pass, ...) \

View file

@ -2151,15 +2151,8 @@ nir_serialize_function(struct blob *blob, const nir_function *fxn)
util_dynarray_fini(&ctx.phi_fixups); util_dynarray_fini(&ctx.phi_fixups);
} }
/** static void
* Serialize NIR into a binary blob. serialize_internal(struct blob *blob, const nir_shader *nir, bool strip, bool serialize_info)
*
* \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)
{ {
write_ctx ctx = { 0 }; write_ctx ctx = { 0 };
_mesa_pointer_hash_table_init(&ctx.remap_table, NULL); _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); size_t idx_size_offset = blob_reserve_uint32(blob);
struct shader_info info = nir->info; struct shader_info info = nir->info;
if (!serialize_info)
memset(&info, 0, sizeof(info));
enum nir_serialize_shader_flags flags = 0; enum nir_serialize_shader_flags flags = 0;
if (!strip && info.name) 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); 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_shader *
nir_deserialize(void *mem_ctx, nir_deserialize(void *mem_ctx,
const struct nir_shader_compiler_options *options, const struct nir_shader_compiler_options *options,
@ -2335,3 +2343,37 @@ nir_shader_serialize_deserialize(nir_shader *shader)
nir_shader_replace(shader, copy); nir_shader_replace(shader, copy);
ralloc_free(dead_ctx); 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