diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c index 6dd117c7718..5ed9594f7d6 100644 --- a/src/compiler/nir/nir.c +++ b/src/compiler/nir/nir.c @@ -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, diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 8635291d5b1..396bceb3061 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -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) { @@ -4808,20 +4824,25 @@ should_print_nir(UNUSED nir_shader *shader) #define NIR_STRINGIZE_INNER(x) #x #define NIR_STRINGIZE(x) NIR_STRINGIZE_INNER(x) -#define NIR_PASS(progress, nir, pass, ...) _PASS(pass, nir, { \ - nir_metadata_set_validation_flag(nir); \ - if (should_print_nir(nir)) \ - printf("%s\n", #pass); \ - if (pass(nir, ##__VA_ARGS__)) { \ - nir_validate_shader(nir, "after " #pass " in " __FILE__ ":" NIR_STRINGIZE(__LINE__)); \ - 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__)); \ - } \ +#define NIR_PASS(progress, nir, pass, ...) _PASS(pass, nir, { \ + 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, when); \ + UNUSED bool _; \ + progress = true; \ + if (should_print_nir(nir)) \ + nir_print_shader(nir, stdout); \ + 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, ...) \ diff --git a/src/compiler/nir/nir_serialize.c b/src/compiler/nir/nir_serialize.c index 98c020201d9..af5bf913f66 100644 --- a/src/compiler/nir/nir_serialize.c +++ b/src/compiler/nir/nir_serialize.c @@ -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