summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Ekstrand <jason@jlekstrand.net>2020-06-01 15:39:31 -0500
committerMarge Bot <eric+marge@anholt.net>2020-09-08 19:44:01 +0000
commit45bcb1084139b58378551e2d954bd6032db20330 (patch)
tree37521fecf821202c3e2e50464366919a8ae88c99
parent6cef8040672e84393e59ed6efa9953c95f5f8c92 (diff)
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>
-rw-r--r--src/compiler/nir/nir.h2
-rw-r--r--src/compiler/nir/nir_validate.c96
2 files changed, 98 insertions, 0 deletions
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
index bb3507ff862..21cc4a71053 100644
--- a/src/compiler/nir/nir.h
+++ b/src/compiler/nir/nir.h
@@ -3886,6 +3886,7 @@ void nir_shader_serialize_deserialize(nir_shader *s);
#ifndef NDEBUG
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_check_validation_flag(nir_shader *shader);
@@ -3937,6 +3938,7 @@ should_print_nir(void)
}
#else
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_check_validation_flag(nir_shader *shader) { (void) shader; }
static inline bool should_skip_nir(UNUSED const char *pass_name) { return false; }
diff --git a/src/compiler/nir/nir_validate.c b/src/compiler/nir/nir_validate.c
index 1a9732365d6..90576b0a08f 100644
--- a/src/compiler/nir/nir_validate.c
+++ b/src/compiler/nir/nir_validate.c
@@ -1206,6 +1206,60 @@ validate_var_decl(nir_variable *var, nir_variable_mode valid_modes,
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
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);
_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
@@ -1365,4 +1427,38 @@ nir_validate_shader(nir_shader *shader, const char *when)
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 */