X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fnir%2Fnir_validate.c;h=9938c0ef8b19ebd5debf587b6b7a72d01d45dad3;hb=e16531fbe3a79bc27cf00701616a260b452597ef;hp=13010ae21d29d39532a6acaf407a9de10eb77eaf;hpb=34952b56716a0f97812d68cd69540ab6bcc54c82;p=mesa.git diff --git a/src/glsl/nir/nir_validate.c b/src/glsl/nir/nir_validate.c index 13010ae21d2..9938c0ef8b1 100644 --- a/src/glsl/nir/nir_validate.c +++ b/src/glsl/nir/nir_validate.c @@ -50,6 +50,15 @@ typedef struct { 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; @@ -66,6 +75,9 @@ typedef struct { /* the current if statement being validated */ nir_if *if_stmt; + /* the current loop being visited */ + nir_loop *loop; + /* the parent of the current cf node being visited */ nir_cf_node *parent_node; @@ -88,77 +100,77 @@ typedef struct { static void validate_src(nir_src *src, validate_state *state); static void -validate_reg_src(nir_reg_src *src, validate_state *state) +validate_reg_src(nir_src *src, validate_state *state) { - assert(src->reg != NULL); + assert(src->reg.reg != NULL); struct hash_entry *entry; - entry = _mesa_hash_table_search(state->regs, src->reg); + entry = _mesa_hash_table_search(state->regs, src->reg.reg); assert(entry); reg_validate_state *reg_state = (reg_validate_state *) entry->data; if (state->instr) { - _mesa_set_add(reg_state->uses, state->instr); - - assert(_mesa_set_search(src->reg->uses, state->instr)); + _mesa_set_add(reg_state->uses, src); } 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)); + _mesa_set_add(reg_state->if_uses, src); } - if (!src->reg->is_global) { + if (!src->reg.reg->is_global) { assert(reg_state->where_defined == state->impl && "using a register declared in a different function"); } - assert((src->reg->num_array_elems == 0 || - src->base_offset < src->reg->num_array_elems) && + assert((src->reg.reg->num_array_elems == 0 || + src->reg.base_offset < src->reg.reg->num_array_elems) && "definitely out-of-bounds array access"); - if (src->indirect) { - assert(src->reg->num_array_elems != 0); - assert((src->indirect->is_ssa || src->indirect->reg.indirect == NULL) && + if (src->reg.indirect) { + assert(src->reg.reg->num_array_elems != 0); + assert((src->reg.indirect->is_ssa || + src->reg.indirect->reg.indirect == NULL) && "only one level of indirection allowed"); - validate_src(src->indirect, state); + validate_src(src->reg.indirect, state); } } static void -validate_ssa_src(nir_ssa_def *def, validate_state *state) +validate_ssa_src(nir_src *src, validate_state *state) { - assert(def != NULL); + assert(src->ssa != NULL); - struct hash_entry *entry = _mesa_hash_table_search(state->ssa_defs, def); + struct hash_entry *entry = _mesa_hash_table_search(state->ssa_defs, src->ssa); assert(entry); - assert((nir_function_impl *) entry->data == state->impl && - "using an SSA value defined in a different function"); + ssa_def_validate_state *def_state = (ssa_def_validate_state *)entry->data; - struct set_entry *entry2; + assert(def_state->where_defined == state->impl && + "using an SSA value defined in a different function"); if (state->instr) { - entry2 = _mesa_set_search(def->uses, state->instr); + _mesa_set_add(def_state->uses, src); } else { assert(state->if_stmt); - entry2 = _mesa_set_search(def->if_uses, state->if_stmt); + _mesa_set_add(def_state->if_uses, src); } - assert(entry2 && "SSA use missing"); - /* TODO validate that the use is dominated by the definition */ } static void validate_src(nir_src *src, validate_state *state) { + if (state->instr) + assert(src->parent_instr == state->instr); + else + assert(src->parent_if == state->if_stmt); + if (src->is_ssa) - validate_ssa_src(src->ssa, state); + validate_ssa_src(src, state); else - validate_reg_src(&src->reg, state); + validate_reg_src(src, state); } static void @@ -190,8 +202,7 @@ validate_reg_dest(nir_reg_dest *dest, validate_state *state) { assert(dest->reg != NULL); - struct set_entry *entry = _mesa_set_search(dest->reg->defs, state->instr); - assert(entry && "definition not in nir_register.defs"); + assert(dest->parent_instr == state->instr); struct hash_entry *entry2; entry2 = _mesa_hash_table_search(state->regs, dest->reg); @@ -199,7 +210,7 @@ validate_reg_dest(nir_reg_dest *dest, validate_state *state) assert(entry2); reg_validate_state *reg_state = (reg_validate_state *) entry2->data; - _mesa_set_add(reg_state->defs, state->instr); + _mesa_set_add(reg_state->defs, dest); if (!dest->reg->is_global) { assert(reg_state->where_defined == state->impl && @@ -225,8 +236,21 @@ validate_ssa_def(nir_ssa_def *def, validate_state *state) assert(!BITSET_TEST(state->ssa_defs_found, def->index)); BITSET_SET(state->ssa_defs_found, def->index); + assert(def->parent_instr == state->instr); + assert(def->num_components <= 4); - _mesa_hash_table_insert(state->ssa_defs, def, state->impl); + + list_validate(&def->uses); + list_validate(&def->if_uses); + + 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 @@ -276,6 +300,8 @@ validate_alu_instr(nir_alu_instr *instr, validate_state *state) static void validate_deref_chain(nir_deref *deref, validate_state *state) { + assert(deref->child == NULL || ralloc_parent(deref->child) == deref); + nir_deref *parent = NULL; while (deref != NULL) { switch (deref->deref_type) { @@ -317,9 +343,10 @@ validate_var_use(nir_variable *var, validate_state *state) } static void -validate_deref_var(nir_deref_var *deref, validate_state *state) +validate_deref_var(void *parent_mem_ctx, nir_deref_var *deref, validate_state *state) { assert(deref != NULL); + assert(ralloc_parent(deref) == parent_mem_ctx); assert(deref->deref.type == deref->var->type); validate_var_use(deref->var, state); @@ -367,7 +394,7 @@ validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state) unsigned num_vars = nir_intrinsic_infos[instr->intrinsic].num_variables; for (unsigned i = 0; i < num_vars; i++) { - validate_deref_var(instr->variables[i], state); + validate_deref_var(instr, instr->variables[i], state); } switch (instr->intrinsic) { @@ -376,11 +403,13 @@ validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state) 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); + instr->variables[0]->var->data.mode != nir_var_uniform && + instr->variables[0]->var->data.mode != nir_var_shader_storage); 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); + instr->variables[0]->var->data.mode != nir_var_uniform && + instr->variables[0]->var->data.mode != nir_var_shader_storage); assert(instr->variables[1]->var->data.mode != nir_var_shader_out); break; default: @@ -404,7 +433,7 @@ validate_tex_instr(nir_tex_instr *instr, validate_state *state) } if (instr->sampler != NULL) - validate_deref_var(instr->sampler, state); + validate_deref_var(instr, instr->sampler, state); } static void @@ -419,10 +448,10 @@ validate_call_instr(nir_call_instr *instr, validate_state *state) for (unsigned i = 0; i < instr->num_params; i++) { assert(instr->callee->params[i].type == instr->params[i]->deref.type); - validate_deref_var(instr->params[i], state); + validate_deref_var(instr, instr->params[i], state); } - validate_deref_var(instr->return_deref, state); + validate_deref_var(instr, instr->return_deref, state); } static void @@ -568,9 +597,85 @@ validate_block(nir_block *block, validate_state *state) } } + struct set_entry *entry; + set_foreach(block->predecessors, entry) { + const nir_block *pred = entry->key; + assert(pred->successors[0] == block || + pred->successors[1] == block); + } + if (!exec_list_is_empty(&block->instr_list) && - nir_block_last_instr(block)->type == nir_instr_type_jump) + nir_block_last_instr(block)->type == nir_instr_type_jump) { assert(block->successors[1] == NULL); + nir_jump_instr *jump = nir_instr_as_jump(nir_block_last_instr(block)); + switch (jump->type) { + case nir_jump_break: { + nir_block *after = + nir_cf_node_as_block(nir_cf_node_next(&state->loop->cf_node)); + assert(block->successors[0] == after); + break; + } + + case nir_jump_continue: { + nir_block *first = + nir_cf_node_as_block(nir_loop_first_cf_node(state->loop)); + assert(block->successors[0] == first); + break; + } + + case nir_jump_return: + assert(block->successors[0] == state->impl->end_block); + break; + + default: + unreachable("bad jump type"); + } + } else { + nir_cf_node *next = nir_cf_node_next(&block->cf_node); + if (next == NULL) { + switch (state->parent_node->type) { + case nir_cf_node_loop: { + nir_block *first = + nir_cf_node_as_block(nir_loop_first_cf_node(state->loop)); + assert(block->successors[0] == first); + /* due to the hack for infinite loops, block->successors[1] may + * point to the block after the loop. + */ + break; + } + + case nir_cf_node_if: { + nir_block *after = + nir_cf_node_as_block(nir_cf_node_next(state->parent_node)); + assert(block->successors[0] == after); + assert(block->successors[1] == NULL); + break; + } + + case nir_cf_node_function: + assert(block->successors[0] == state->impl->end_block); + assert(block->successors[1] == NULL); + break; + + default: + unreachable("unknown control flow node type"); + } + } else { + if (next->type == nir_cf_node_if) { + nir_if *if_stmt = nir_cf_node_as_if(next); + assert(&block->successors[0]->cf_node == + nir_if_first_then_node(if_stmt)); + assert(&block->successors[1]->cf_node == + nir_if_first_else_node(if_stmt)); + } else { + assert(next->type == nir_cf_node_loop); + nir_loop *loop = nir_cf_node_as_loop(next); + assert(&block->successors[0]->cf_node == + nir_loop_first_cf_node(loop)); + assert(block->successors[1] == NULL); + } + } + } } static void @@ -582,12 +687,6 @@ validate_if(nir_if *if_stmt, validate_state *state) nir_cf_node *prev_node = nir_cf_node_prev(&if_stmt->cf_node); assert(prev_node->type == nir_cf_node_block); - nir_block *prev_block = nir_cf_node_as_block(prev_node); - assert(&prev_block->successors[0]->cf_node == - nir_if_first_then_node(if_stmt)); - assert(&prev_block->successors[1]->cf_node == - nir_if_first_else_node(if_stmt)); - assert(!exec_node_is_tail_sentinel(if_stmt->cf_node.node.next)); nir_cf_node *next_node = nir_cf_node_next(&if_stmt->cf_node); assert(next_node->type == nir_cf_node_block); @@ -621,10 +720,6 @@ validate_loop(nir_loop *loop, validate_state *state) nir_cf_node *prev_node = nir_cf_node_prev(&loop->cf_node); assert(prev_node->type == nir_cf_node_block); - nir_block *prev_block = nir_cf_node_as_block(prev_node); - assert(&prev_block->successors[0]->cf_node == nir_loop_first_cf_node(loop)); - assert(prev_block->successors[1] == NULL); - assert(!exec_node_is_tail_sentinel(loop->cf_node.node.next)); nir_cf_node *next_node = nir_cf_node_next(&loop->cf_node); assert(next_node->type == nir_cf_node_block); @@ -633,6 +728,8 @@ validate_loop(nir_loop *loop, validate_state *state) nir_cf_node *old_parent = state->parent_node; state->parent_node = &loop->cf_node; + nir_loop *old_loop = state->loop; + state->loop = loop; exec_list_validate(&loop->body); foreach_list_typed(nir_cf_node, cf_node, node, &loop->body) { @@ -640,6 +737,7 @@ validate_loop(nir_loop *loop, validate_state *state) } state->parent_node = old_parent; + state->loop = old_loop; } static void @@ -661,8 +759,7 @@ validate_cf_node(nir_cf_node *node, validate_state *state) break; default: - assert(!"Invalid ALU instruction type"); - break; + unreachable("Invalid CF node type"); } } @@ -678,6 +775,10 @@ prevalidate_reg_decl(nir_register *reg, bool is_global, validate_state *state) assert(!BITSET_TEST(state->regs_found, reg->index)); BITSET_SET(state->regs_found, reg->index); + list_validate(®->uses); + list_validate(®->defs); + list_validate(®->if_uses); + reg_validate_state *reg_state = ralloc(state->regs, reg_validate_state); reg_state->uses = _mesa_set_create(reg_state, _mesa_hash_pointer, _mesa_key_pointer_equal); @@ -698,47 +799,47 @@ postvalidate_reg_decl(nir_register *reg, validate_state *state) reg_validate_state *reg_state = (reg_validate_state *) entry->data; - if (reg_state->uses->entries != reg->uses->entries) { + nir_foreach_use(reg, src) { + struct set_entry *entry = _mesa_set_search(reg_state->uses, src); + assert(entry); + _mesa_set_remove(reg_state->uses, entry); + } + + if (reg_state->uses->entries != 0) { printf("extra entries in register uses:\n"); struct set_entry *entry; - set_foreach(reg->uses, entry) { - struct set_entry *entry2 = - _mesa_set_search(reg_state->uses, entry->key); - - if (entry2 == NULL) { - printf("%p\n", entry->key); - } - } + set_foreach(reg_state->uses, entry) + printf("%p\n", entry->key); abort(); } - if (reg_state->if_uses->entries != reg->if_uses->entries) { + nir_foreach_if_use(reg, src) { + struct set_entry *entry = _mesa_set_search(reg_state->if_uses, src); + assert(entry); + _mesa_set_remove(reg_state->if_uses, entry); + } + + if (reg_state->if_uses->entries != 0) { 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); - } - } + set_foreach(reg_state->if_uses, entry) + printf("%p\n", entry->key); abort(); } - if (reg_state->defs->entries != reg->defs->entries) { + nir_foreach_def(reg, src) { + struct set_entry *entry = _mesa_set_search(reg_state->defs, src); + assert(entry); + _mesa_set_remove(reg_state->defs, entry); + } + + if (reg_state->defs->entries != 0) { printf("extra entries in register defs:\n"); struct set_entry *entry; - set_foreach(reg->defs, entry) { - struct set_entry *entry2 = - _mesa_set_search(reg_state->defs, entry->key); - - if (entry2 == NULL) { - printf("%p\n", entry->key); - } - } + set_foreach(reg_state->defs, entry) + printf("%p\n", entry->key); abort(); } @@ -759,6 +860,56 @@ validate_var_decl(nir_variable *var, bool is_global, validate_state *state) } } +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; + + nir_foreach_use(def, src) { + struct set_entry *entry = _mesa_set_search(def_state->uses, src); + assert(entry); + _mesa_set_remove(def_state->uses, entry); + } + + if (def_state->uses->entries != 0) { + printf("extra entries in register uses:\n"); + struct set_entry *entry; + set_foreach(def_state->uses, entry) + printf("%p\n", entry->key); + + abort(); + } + + nir_foreach_if_use(def, src) { + struct set_entry *entry = _mesa_set_search(def_state->if_uses, src); + assert(entry); + _mesa_set_remove(def_state->if_uses, entry); + } + + if (def_state->if_uses->entries != 0) { + printf("extra entries in register uses:\n"); + struct set_entry *entry; + set_foreach(def_state->if_uses, entry) + 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) { @@ -809,6 +960,8 @@ 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 @@ -840,6 +993,7 @@ init_validate_state(validate_state *state) state->regs_found = NULL; state->var_defs = _mesa_hash_table_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); + state->loop = NULL; } static void @@ -860,17 +1014,19 @@ nir_validate_shader(nir_shader *shader) 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);