* This file checks for invalid IR indicating a bug somewhere in the compiler.
*/
+/* Since this file is just a pile of asserts, don't bother compiling it if
+ * we're not building a debug build.
+ */
+#ifdef DEBUG
+
/*
* Per-register validation state.
*/
* equivalent to the uses and defs in nir_register, but built up by the
* validator. At the end, we verify that the sets have the same entries.
*/
- struct set *uses, *defs;
+ struct set *uses, *if_uses, *defs;
nir_function_impl *where_defined; /* NULL for global registers */
} reg_validate_state;
+typedef struct {
+ /*
+ * equivalent to the uses in nir_ssa_def, but built up by the validator.
+ * At the end, we verify that the sets have the same entries.
+ */
+ struct set *uses, *if_uses;
+ nir_function_impl *where_defined;
+} ssa_def_validate_state;
+
typedef struct {
/* map of register -> validation state (struct above) */
struct hash_table *regs;
{
assert(src->reg != NULL);
- struct set_entry *entry =
- _mesa_set_search(src->reg->uses, _mesa_hash_pointer(state->instr),
- state->instr);
- assert(entry && "use not in nir_register.uses");
+ struct hash_entry *entry;
+ entry = _mesa_hash_table_search(state->regs, src->reg);
+ assert(entry);
- struct hash_entry *entry2;
- entry2 = _mesa_hash_table_search(state->regs, src->reg);
+ reg_validate_state *reg_state = (reg_validate_state *) entry->data;
- assert(entry2);
+ if (state->instr) {
+ _mesa_set_add(reg_state->uses, state->instr);
- reg_validate_state *reg_state = (reg_validate_state *) entry2->data;
- _mesa_set_add(reg_state->uses, _mesa_hash_pointer(state->instr),
- state->instr);
+ assert(_mesa_set_search(src->reg->uses, state->instr));
+ } else {
+ assert(state->if_stmt);
+ _mesa_set_add(reg_state->if_uses, state->if_stmt);
+
+ assert(_mesa_set_search(src->reg->if_uses, state->if_stmt));
+ }
if (!src->reg->is_global) {
assert(reg_state->where_defined == state->impl &&
assert(entry);
- assert((nir_function_impl *) entry->data == state->impl &&
+ ssa_def_validate_state *def_state = (ssa_def_validate_state *)entry->data;
+
+ assert(def_state->where_defined == state->impl &&
"using an SSA value defined in a different function");
- struct set_entry *entry2;
+ if (state->instr) {
+ _mesa_set_add(def_state->uses, state->instr);
- entry2 = _mesa_set_search(def->uses, _mesa_hash_pointer(state->instr),
- state->instr);
+ assert(_mesa_set_search(def->uses, state->instr));
+ } else {
+ assert(state->if_stmt);
+ _mesa_set_add(def_state->if_uses, state->if_stmt);
- assert(entry2 && "SSA use missing");
+ assert(_mesa_set_search(def->if_uses, state->if_stmt));
+ }
/* TODO validate that the use is dominated by the definition */
}
{
assert(dest->reg != NULL);
- struct set_entry *entry =
- _mesa_set_search(dest->reg->defs, _mesa_hash_pointer(state->instr),
- state->instr);
+ struct set_entry *entry = _mesa_set_search(dest->reg->defs, state->instr);
assert(entry && "definition not in nir_register.defs");
struct hash_entry *entry2;
assert(entry2);
reg_validate_state *reg_state = (reg_validate_state *) entry2->data;
- _mesa_set_add(reg_state->defs, _mesa_hash_pointer(state->instr),
- state->instr);
+ _mesa_set_add(reg_state->defs, state->instr);
if (!dest->reg->is_global) {
assert(reg_state->where_defined == state->impl &&
BITSET_SET(state->ssa_defs_found, def->index);
assert(def->num_components <= 4);
- _mesa_hash_table_insert(state->ssa_defs, def, state->impl);
+
+ ssa_def_validate_state *def_state = ralloc(state->ssa_defs,
+ ssa_def_validate_state);
+ def_state->where_defined = state->impl;
+ def_state->uses = _mesa_set_create(def_state, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+ def_state->if_uses = _mesa_set_create(def_state, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+ _mesa_hash_table_insert(state->ssa_defs, def, def_state);
}
static void
* register/SSA value
*/
assert(is_packed || !(dest->write_mask & ~((1 << dest_size) - 1)));
+
+ /* validate that saturate is only ever used on instructions with
+ * destinations of type float
+ */
+ nir_alu_instr *alu = nir_instr_as_alu(state->instr);
+ assert(nir_op_infos[alu->op].output_type == nir_type_float ||
+ !dest->saturate);
+
validate_dest(&dest->dest, state);
}
for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) {
validate_alu_src(instr, i, state);
}
-
- if (instr->has_predicate)
- validate_src(&instr->predicate, state);
}
static void
{
unsigned num_srcs = nir_intrinsic_infos[instr->intrinsic].num_srcs;
for (unsigned i = 0; i < num_srcs; i++) {
+ unsigned components_read =
+ nir_intrinsic_infos[instr->intrinsic].src_components[i];
+ if (components_read == 0)
+ components_read = instr->num_components;
+
+ assert(components_read > 0);
+
+ if (instr->src[i].is_ssa) {
+ assert(components_read <= instr->src[i].ssa->num_components);
+ } else if (!instr->src[i].reg.reg->is_packed) {
+ assert(components_read <= instr->src[i].reg.reg->num_components);
+ }
+
validate_src(&instr->src[i], state);
}
if (nir_intrinsic_infos[instr->intrinsic].has_dest) {
+ unsigned components_written =
+ nir_intrinsic_infos[instr->intrinsic].dest_components;
+ if (components_written == 0)
+ components_written = instr->num_components;
+
+ assert(components_written > 0);
+
+ if (instr->dest.is_ssa) {
+ assert(components_written <= instr->dest.ssa.num_components);
+ } else if (!instr->dest.reg.reg->is_packed) {
+ assert(components_written <= instr->dest.reg.reg->num_components);
+ }
+
validate_dest(&instr->dest, state);
}
validate_deref_var(instr->variables[i], state);
}
- if (instr->has_predicate)
- validate_src(&instr->predicate, state);
+ switch (instr->intrinsic) {
+ case nir_intrinsic_load_var:
+ assert(instr->variables[0]->var->data.mode != nir_var_shader_out);
+ break;
+ case nir_intrinsic_store_var:
+ assert(instr->variables[0]->var->data.mode != nir_var_shader_in &&
+ instr->variables[0]->var->data.mode != nir_var_uniform);
+ break;
+ case nir_intrinsic_copy_var:
+ assert(instr->variables[0]->var->data.mode != nir_var_shader_in &&
+ instr->variables[0]->var->data.mode != nir_var_uniform);
+ assert(instr->variables[1]->var->data.mode != nir_var_shader_out);
+ break;
+ default:
+ break;
+ }
}
static void
{
validate_dest(&instr->dest, state);
- bool src_type_seen[nir_num_texinput_types];
- for (unsigned i = 0; i < nir_num_texinput_types; i++)
+ bool src_type_seen[nir_num_tex_src_types];
+ for (unsigned i = 0; i < nir_num_tex_src_types; i++)
src_type_seen[i] = false;
for (unsigned i = 0; i < instr->num_srcs; i++) {
- assert(!src_type_seen[instr->src_type[i]]);
- src_type_seen[instr->src_type[i]] = true;
- validate_src(&instr->src[i], state);
+ assert(!src_type_seen[instr->src[i].src_type]);
+ src_type_seen[instr->src[i].src_type] = true;
+ validate_src(&instr->src[i].src, state);
}
if (instr->sampler != NULL)
}
validate_deref_var(instr->return_deref, state);
-
- if (instr->has_predicate)
- validate_src(&instr->predicate, state);
}
static void
validate_load_const_instr(nir_load_const_instr *instr, validate_state *state)
{
- validate_dest(&instr->dest, state);
-
- if (instr->array_elems != 0) {
- assert(!instr->dest.is_ssa);
- assert(instr->dest.reg.base_offset + instr->array_elems <=
- instr->dest.reg.reg->num_array_elems);
- }
-
- if (instr->has_predicate)
- validate_src(&instr->predicate, state);
+ validate_ssa_def(&instr->def, state);
}
static void
validate_intrinsic_instr(nir_instr_as_intrinsic(instr), state);
break;
- case nir_instr_type_texture:
- validate_tex_instr(nir_instr_as_texture(instr), state);
+ case nir_instr_type_tex:
+ validate_tex_instr(nir_instr_as_tex(instr), state);
break;
case nir_instr_type_load_const:
assert(!"Invalid ALU instruction type");
break;
}
+
+ state->instr = NULL;
}
static void
{
state->instr = &instr->instr;
+ assert(instr->dest.is_ssa);
+
exec_list_validate(&instr->srcs);
- foreach_list_typed(nir_phi_src, src, node, &instr->srcs) {
+ nir_foreach_phi_src(instr, src) {
if (src->pred == pred) {
+ assert(src->src.is_ssa);
+ assert(src->src.ssa->num_components ==
+ instr->dest.ssa.num_components);
+
validate_src(&src->src, state);
+ state->instr = NULL;
return;
}
}
for (unsigned i = 0; i < 2; i++) {
if (block->successors[i] != NULL) {
struct set_entry *entry =
- _mesa_set_search(block->successors[i]->predecessors,
- _mesa_hash_pointer(block), block);
+ _mesa_set_search(block->successors[i]->predecessors, block);
assert(entry);
validate_phi_srcs(block, block->successors[i], state);
static void
validate_if(nir_if *if_stmt, validate_state *state)
{
+ state->if_stmt = if_stmt;
+
assert(!exec_node_is_head_sentinel(if_stmt->cf_node.node.prev));
nir_cf_node *prev_node = nir_cf_node_prev(&if_stmt->cf_node);
assert(prev_node->type == nir_cf_node_block);
nir_cf_node *next_node = nir_cf_node_next(&if_stmt->cf_node);
assert(next_node->type == nir_cf_node_block);
- if (!if_stmt->condition.is_ssa) {
- nir_register *reg = if_stmt->condition.reg.reg;
- struct set_entry *entry =
- _mesa_set_search(reg->if_uses, _mesa_hash_pointer(if_stmt), if_stmt);
- assert(entry);
- } else {
- nir_ssa_def *def = if_stmt->condition.ssa;
- struct set_entry *entry =
- _mesa_set_search(def->if_uses, _mesa_hash_pointer(if_stmt), if_stmt);
- assert(entry);
- }
+ validate_src(&if_stmt->condition, state);
assert(!exec_list_is_empty(&if_stmt->then_list));
assert(!exec_list_is_empty(&if_stmt->else_list));
}
state->parent_node = old_parent;
+ state->if_stmt = NULL;
}
static void
BITSET_SET(state->regs_found, reg->index);
reg_validate_state *reg_state = ralloc(state->regs, reg_validate_state);
- reg_state->uses = _mesa_set_create(reg_state, _mesa_key_pointer_equal);
- reg_state->defs = _mesa_set_create(reg_state, _mesa_key_pointer_equal);
+ reg_state->uses = _mesa_set_create(reg_state, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+ reg_state->if_uses = _mesa_set_create(reg_state, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+ reg_state->defs = _mesa_set_create(reg_state, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
reg_state->where_defined = is_global ? NULL : state->impl;
struct set_entry *entry;
set_foreach(reg->uses, entry) {
struct set_entry *entry2 =
- _mesa_set_search(reg_state->uses, _mesa_hash_pointer(entry->key),
- entry->key);
+ _mesa_set_search(reg_state->uses, entry->key);
+
+ if (entry2 == NULL) {
+ printf("%p\n", entry->key);
+ }
+ }
+
+ abort();
+ }
+
+ if (reg_state->if_uses->entries != reg->if_uses->entries) {
+ printf("extra entries in register if_uses:\n");
+ struct set_entry *entry;
+ set_foreach(reg->if_uses, entry) {
+ struct set_entry *entry2 =
+ _mesa_set_search(reg_state->if_uses, entry->key);
if (entry2 == NULL) {
printf("%p\n", entry->key);
struct set_entry *entry;
set_foreach(reg->defs, entry) {
struct set_entry *entry2 =
- _mesa_set_search(reg_state->defs, _mesa_hash_pointer(entry->key),
- entry->key);
+ _mesa_set_search(reg_state->defs, entry->key);
if (entry2 == NULL) {
printf("%p\n", entry->key);
}
}
+static bool
+postvalidate_ssa_def(nir_ssa_def *def, void *void_state)
+{
+ validate_state *state = void_state;
+
+ struct hash_entry *entry = _mesa_hash_table_search(state->ssa_defs, def);
+ ssa_def_validate_state *def_state = (ssa_def_validate_state *)entry->data;
+
+ if (def_state->uses->entries != def->uses->entries) {
+ printf("extra entries in SSA def uses:\n");
+ struct set_entry *entry;
+ set_foreach(def->uses, entry) {
+ struct set_entry *entry2 =
+ _mesa_set_search(def_state->uses, entry->key);
+
+ if (entry2 == NULL) {
+ printf("%p\n", entry->key);
+ }
+ }
+
+ abort();
+ }
+
+ if (def_state->if_uses->entries != def->if_uses->entries) {
+ printf("extra entries in SSA def uses:\n");
+ struct set_entry *entry;
+ set_foreach(def->if_uses, entry) {
+ struct set_entry *entry2 =
+ _mesa_set_search(def_state->if_uses, entry->key);
+
+ if (entry2 == NULL) {
+ printf("%p\n", entry->key);
+ }
+ }
+
+ abort();
+ }
+
+ return true;
+}
+
+static bool
+postvalidate_ssa_defs_block(nir_block *block, void *state)
+{
+ nir_foreach_instr(block, instr)
+ nir_foreach_ssa_def(instr, postvalidate_ssa_def, state);
+
+ return true;
+}
+
static void
validate_function_impl(nir_function_impl *impl, validate_state *state)
{
foreach_list_typed(nir_register, reg, node, &impl->registers) {
postvalidate_reg_decl(reg, state);
}
+
+ nir_foreach_block(impl, postvalidate_ssa_defs_block, state);
}
static void
state.shader = shader;
- struct hash_entry *entry;
- hash_table_foreach(shader->uniforms, entry) {
- validate_var_decl((nir_variable *) entry->data, true, &state);
+ exec_list_validate(&shader->uniforms);
+ foreach_list_typed(nir_variable, var, node, &shader->uniforms) {
+ validate_var_decl(var, true, &state);
}
- hash_table_foreach(shader->inputs, entry) {
- validate_var_decl((nir_variable *) entry->data, true, &state);
+ exec_list_validate(&shader->inputs);
+ foreach_list_typed(nir_variable, var, node, &shader->inputs) {
+ validate_var_decl(var, true, &state);
}
- hash_table_foreach(shader->outputs, entry) {
- validate_var_decl((nir_variable *) entry->data, true, &state);
+ exec_list_validate(&shader->outputs);
+ foreach_list_typed(nir_variable, var, node, &shader->outputs) {
+ validate_var_decl(var, true, &state);
}
exec_list_validate(&shader->globals);
destroy_validate_state(&state);
}
+
+#endif /* NDEBUG */