diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index f2df8f5e57d..056c350cc34 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -4916,6 +4916,30 @@ do { \ #define NIR_SKIP(name) should_skip_nir(#name) +#ifndef NDEBUG + +void _nir_assert_no_progress(bool progress, const char *when); + +/* Abort if the pass has made any progress. This can be used to assert that: + * - our minimalist pass invocation loops in drivers are sufficient and don't + * leave any unoptimized code in the shader + * - our lowering is sufficient and other passes don't add instructions that + * would cause lowering having to be repeated + */ +#define NIR_PASS_ASSERT_NO_PROGRESS(nir, pass, ...) \ + do { \ + if (!NIR_DEBUG(NOVALIDATE)) { \ + static const char *when = #pass " in " __FILE__ ":" NIR_STRINGIZE(__LINE__); \ + bool _progress = false; \ + NIR_PASS(_progress, nir, pass, ##__VA_ARGS__); \ + _nir_assert_no_progress(_progress, when); \ + } \ + } while (0) + +#else +#define NIR_ASSERT_PASS_NO_PROGRESS(nir, pass, ...) +#endif + /** An instruction filtering callback with writemask * * Returns true if the instruction should be processed with the associated diff --git a/src/compiler/nir/nir_validate.c b/src/compiler/nir/nir_validate.c index f2d5ec0f414..34ce9983e63 100644 --- a/src/compiler/nir/nir_validate.c +++ b/src/compiler/nir/nir_validate.c @@ -2355,4 +2355,23 @@ nir_validate_ssa_dominance(nir_shader *shader, const char *when) destroy_validate_state(&state); } +void +_nir_assert_no_progress(bool progress, const char *when) +{ + if (!progress) + return; + + /* Lock around dumping so that we get clean dumps in a multi-threaded + * scenario. + */ + simple_mtx_lock(&fail_dump_mutex); + + fprintf(stderr, "NIR assertion failed: Expected no progress from %s.\n", + when); + fflush(stderr); + + simple_mtx_unlock(&fail_dump_mutex); + abort(); +} + #endif /* NDEBUG */