nir: Add a dominance validation pass

We don't do full dominance validation of SSA values in nir_validate
because it requires generating valid dominance information and, while
that's not extremely expensive, it's probably more than we want to do on
every pass.  Also, dominance information is generated through the
metadata system so if we ran it by default in nir_validate, we would get
different beavior of the metadata system based on whether or not you
have a debug build and metadata bugs would be very hard to find.

However, having a pass for it that can be run occasionally, should help
detect and expose bugs.  For ease of use, we add a NIR_VALIDATE_SSA_DOMINANCE
environment variable which can be set to manually enable dominance
validation as a standard part of nir_validate.

Reviewed-by: Daniel Schürmann <daniel@schuermann.dev>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5288>
This commit is contained in:
Jason Ekstrand
2020-06-01 15:39:31 -05:00
committed by Marge Bot
parent 6cef804067
commit 45bcb10841
2 changed files with 98 additions and 0 deletions

View File

@@ -3886,6 +3886,7 @@ void nir_shader_serialize_deserialize(nir_shader *s);
#ifndef NDEBUG #ifndef NDEBUG
void nir_validate_shader(nir_shader *shader, const char *when); void nir_validate_shader(nir_shader *shader, const char *when);
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);
@@ -3937,6 +3938,7 @@ should_print_nir(void)
} }
#else #else
static inline void nir_validate_shader(nir_shader *shader, const char *when) { (void) shader; (void)when; } static inline void nir_validate_shader(nir_shader *shader, const char *when) { (void) shader; (void)when; }
static inline void nir_validate_ssa_dominance(nir_shader *shader, const char *when) { (void) shader; (void)when; }
static inline void nir_metadata_set_validation_flag(nir_shader *shader) { (void) shader; } static inline void nir_metadata_set_validation_flag(nir_shader *shader) { (void) shader; }
static inline void nir_metadata_check_validation_flag(nir_shader *shader) { (void) shader; } static inline void nir_metadata_check_validation_flag(nir_shader *shader) { (void) shader; }
static inline bool should_skip_nir(UNUSED const char *pass_name) { return false; } static inline bool should_skip_nir(UNUSED const char *pass_name) { return false; }

View File

@@ -1206,6 +1206,60 @@ validate_var_decl(nir_variable *var, nir_variable_mode valid_modes,
state->var = NULL; state->var = NULL;
} }
static bool
validate_ssa_def_dominance(nir_ssa_def *def, void *_state)
{
validate_state *state = _state;
validate_assert(state, def->index < state->impl->ssa_alloc);
validate_assert(state, !BITSET_TEST(state->ssa_defs_found, def->index));
BITSET_SET(state->ssa_defs_found, def->index);
return true;
}
static bool
validate_src_dominance(nir_src *src, void *_state)
{
validate_state *state = _state;
if (!src->is_ssa)
return true;
if (src->ssa->parent_instr->block == src->parent_instr->block) {
validate_assert(state, src->ssa->index < state->impl->ssa_alloc);
validate_assert(state, BITSET_TEST(state->ssa_defs_found,
src->ssa->index));
} else {
validate_assert(state, nir_block_dominates(src->ssa->parent_instr->block,
src->parent_instr->block));
}
return true;
}
static void
validate_ssa_dominance(nir_function_impl *impl, validate_state *state)
{
nir_metadata_require(impl, nir_metadata_dominance);
nir_foreach_block(block, impl) {
state->block = block;
nir_foreach_instr(instr, block) {
state->instr = instr;
if (instr->type == nir_instr_type_phi) {
nir_phi_instr *phi = nir_instr_as_phi(instr);
nir_foreach_phi_src(src, phi) {
validate_assert(state,
nir_block_dominates(src->src.ssa->parent_instr->block,
src->pred));
}
} else {
nir_foreach_src(instr, validate_src_dominance, state);
}
nir_foreach_ssa_def(instr, validate_ssa_def_dominance, state);
}
}
}
static void static void
validate_function_impl(nir_function_impl *impl, validate_state *state) validate_function_impl(nir_function_impl *impl, validate_state *state)
{ {
@@ -1257,6 +1311,14 @@ validate_function_impl(nir_function_impl *impl, validate_state *state)
validate_assert(state, state->ssa_srcs->entries == 0); validate_assert(state, state->ssa_srcs->entries == 0);
_mesa_set_clear(state->ssa_srcs, NULL); _mesa_set_clear(state->ssa_srcs, NULL);
static int validate_dominance = -1;
if (validate_dominance < 0) {
validate_dominance =
env_var_as_boolean("NIR_VALIDATE_SSA_DOMINANCE", false);
}
if (validate_dominance)
validate_ssa_dominance(impl, state);
} }
static void static void
@@ -1365,4 +1427,38 @@ nir_validate_shader(nir_shader *shader, const char *when)
destroy_validate_state(&state); destroy_validate_state(&state);
} }
void
nir_validate_ssa_dominance(nir_shader *shader, const char *when)
{
static int should_validate = -1;
if (should_validate < 0)
should_validate = env_var_as_boolean("NIR_VALIDATE", true);
if (!should_validate)
return;
validate_state state;
init_validate_state(&state);
state.shader = shader;
nir_foreach_function(func, shader) {
if (func->impl == NULL)
continue;
state.ssa_defs_found = reralloc(state.mem_ctx, state.ssa_defs_found,
BITSET_WORD,
BITSET_WORDS(func->impl->ssa_alloc));
memset(state.ssa_defs_found, 0, BITSET_WORDS(func->impl->ssa_alloc) *
sizeof(BITSET_WORD));
state.impl = func->impl;
validate_ssa_dominance(func->impl, &state);
}
if (_mesa_hash_table_num_entries(state.errors) > 0)
dump_errors(&state, when);
destroy_validate_state(&state);
}
#endif /* NDEBUG */ #endif /* NDEBUG */