<p dir="ltr">Other than my nitpicking below this looks great! Thanks for working on this!<br>
On Apr 7, 2015 2:32 AM, "Kenneth Graunke" <<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>> wrote:<br>
><br>
> Jason pointed out that variable dereferences in NIR are really part of<br>
> their parent instruction, and should have the same lifetime.<br>
><br>
> Unlike in GLSL IR, they're not used very often - just for intrinsic<br>
> variables, call parameters & return, and indirect samplers for<br>
> texturing.  Also, nir_deref_var is the top-level concept, and<br>
> nir_deref_array/nir_deref_record are child nodes.<br>
><br>
> This patch attempts to allocate nir_deref_vars out of their parent<br>
> instruction, and any sub-dereferences out of their parent deref.<br>
> It enforces these restrictions in the validator as well.<br>
><br>
> This means that freeing an instruction should free its associated<br>
> dereference chain as well.  The memory sweeper pass can also happily<br>
> ignore them.<br>
><br>
> Signed-off-by: Kenneth Graunke <<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>><br>
> ---<br>
>  src/glsl/nir/glsl_to_nir.cpp        | 47 ++++++++++++++++++++-----------------<br>
>  src/glsl/nir/nir.c                  |  6 ++---<br>
>  src/glsl/nir/nir_lower_var_copies.c |  8 +++----<br>
>  src/glsl/nir/nir_split_var_copies.c |  4 ++--<br>
>  src/glsl/nir/nir_validate.c         | 13 ++++++----<br>
>  src/mesa/program/prog_to_nir.c      |  9 ++++---<br>
>  6 files changed, 45 insertions(+), 42 deletions(-)<br>
><br>
> This is still a lot of churn, but surprisingly about even on LOC.<br>
> With the validator code in place, I suspect we can get this right<br>
> going forward without too much trouble.<br>
><br>
> diff --git a/src/glsl/nir/glsl_to_nir.cpp b/src/glsl/nir/glsl_to_nir.cpp<br>
> index 80c5b3a..f61a47a 100644<br>
> --- a/src/glsl/nir/glsl_to_nir.cpp<br>
> +++ b/src/glsl/nir/glsl_to_nir.cpp<br>
> @@ -88,6 +88,8 @@ private:<br>
>     exec_list *cf_node_list;<br>
>     nir_instr *result; /* result of the expression tree last visited */<br>
><br>
> +   nir_deref_var *make_deref(void *mem_ctx, ir_instruction *ir);<br>
> +<br>
>     /* the head of the dereference chain we're creating */<br>
>     nir_deref_var *deref_head;<br>
>     /* the tail of the dereference chain we're creating */<br>
> @@ -156,6 +158,14 @@ nir_visitor::~nir_visitor()<br>
>     _mesa_hash_table_destroy(this->overload_table, NULL);<br>
>  }<br>
><br>
> +nir_deref_var *<br>
> +nir_visitor::make_deref(void *mem_ctx, ir_instruction *ir)</p>
<p dir="ltr">I'm not a huge fan of the name. Maybe evaluate_deref to match evaluate_rvalue or perhaps build_deref?  In any case, it doesn't really matter so I won't quibble.</p>
<p dir="ltr">It should, however, take a nir_instr instead of a void as its memory context.  That makes it a bit more explicit.</p>
<p dir="ltr">> +{<br>
> +   ir->accept(this);<br>
> +   ralloc_steal(mem_ctx, this->deref_head);<br>
> +   return this->deref_head;<br>
> +}<br>
> +<br>
>  static nir_constant *<br>
>  constant_copy(ir_constant *ir, void *mem_ctx)<br>
>  {<br>
> @@ -582,13 +592,11 @@ void<br>
>  nir_visitor::visit(ir_return *ir)<br>
>  {<br>
>     if (ir->value != NULL) {<br>
> -      ir->value->accept(this);<br>
>        nir_intrinsic_instr *copy =<br>
>           nir_intrinsic_instr_create(this->shader, nir_intrinsic_copy_var);<br>
><br>
> -      copy->variables[0] = nir_deref_var_create(this->shader,<br>
> -                                                this->impl->return_var);<br>
> -      copy->variables[1] = this->deref_head;<br>
> +      copy->variables[0] = nir_deref_var_create(copy, this->impl->return_var);<br>
> +      copy->variables[1] = make_deref(copy, ir->value);<br>
>     }<br>
><br>
>     nir_jump_instr *instr = nir_jump_instr_create(this->shader, nir_jump_return);<br>
> @@ -613,8 +621,7 @@ nir_visitor::visit(ir_call *ir)<br>
>        nir_intrinsic_instr *instr = nir_intrinsic_instr_create(shader, op);<br>
>        ir_dereference *param =<br>
>           (ir_dereference *) ir->actual_parameters.get_head();<br>
> -      param->accept(this);<br>
> -      instr->variables[0] = this->deref_head;<br>
> +      instr->variables[0] = make_deref(instr, param);<br>
>        nir_ssa_dest_init(&instr->instr, &instr->dest, 1, NULL);<br>
><br>
>        nir_instr_insert_after_cf_list(this->cf_node_list, &instr->instr);<br>
> @@ -623,8 +630,7 @@ nir_visitor::visit(ir_call *ir)<br>
>           nir_intrinsic_instr_create(shader, nir_intrinsic_store_var);<br>
>        store_instr->num_components = 1;<br>
><br>
> -      ir->return_deref->accept(this);<br>
> -      store_instr->variables[0] = this->deref_head;<br>
> +      store_instr->variables[0] = make_deref(store_instr, ir->return_deref);<br>
>        store_instr->src[0].is_ssa = true;<br>
>        store_instr->src[0].ssa = &instr->dest.ssa;<br>
><br>
> @@ -642,13 +648,11 @@ nir_visitor::visit(ir_call *ir)<br>
><br>
>     unsigned i = 0;<br>
>     foreach_in_list(ir_dereference, param, &ir->actual_parameters) {<br>
> -      param->accept(this);<br>
> -      instr->params[i] = this->deref_head;<br>
> +      instr->params[i] = make_deref(instr, param);<br>
>        i++;<br>
>     }<br>
><br>
> -   ir->return_deref->accept(this);<br>
> -   instr->return_deref = this->deref_head;<br>
> +   instr->return_deref = make_deref(instr, ir->return_deref);<br>
>     nir_instr_insert_after_cf_list(this->cf_node_list, &instr->instr);<br>
>  }<br>
><br>
> @@ -663,12 +667,8 @@ nir_visitor::visit(ir_assignment *ir)<br>
>        nir_intrinsic_instr *copy =<br>
>           nir_intrinsic_instr_create(this->shader, nir_intrinsic_copy_var);<br>
><br>
> -      ir->lhs->accept(this);<br>
> -      copy->variables[0] = this->deref_head;<br>
> -<br>
> -      ir->rhs->accept(this);<br>
> -      copy->variables[1] = this->deref_head;<br>
> -<br>
> +      copy->variables[0] = make_deref(copy, ir->lhs);<br>
> +      copy->variables[1] = make_deref(copy, ir->rhs);<br>
><br>
>        if (ir->condition) {<br>
>           nir_if *if_stmt = nir_if_create(this->shader);<br>
> @@ -700,6 +700,7 @@ nir_visitor::visit(ir_assignment *ir)<br>
>        load->num_components = ir->lhs->type->vector_elements;<br>
>        nir_ssa_dest_init(&load->instr, &load->dest, num_components, NULL);<br>
>        load->variables[0] = lhs_deref;<br>
> +      ralloc_steal(load, load->variables[0]);<br>
>        nir_instr_insert_after_cf_list(this->cf_node_list, &load->instr);<br>
><br>
>        nir_op vec_op;<br>
> @@ -741,7 +742,7 @@ nir_visitor::visit(ir_assignment *ir)<br>
>     nir_intrinsic_instr *store =<br>
>        nir_intrinsic_instr_create(this->shader, nir_intrinsic_store_var);<br>
>     store->num_components = ir->lhs->type->vector_elements;<br>
> -   nir_deref *store_deref = nir_copy_deref(this->shader, &lhs_deref->deref);<br>
> +   nir_deref *store_deref = nir_copy_deref(store, &lhs_deref->deref);<br>
>     store->variables[0] = nir_deref_as_var(store_deref);<br>
>     store->src[0] = src;<br>
><br>
> @@ -816,6 +817,7 @@ nir_visitor::evaluate_rvalue(ir_rvalue* ir)<br>
>           nir_intrinsic_instr_create(this->shader, nir_intrinsic_load_var);<br>
>        load_instr->num_components = ir->type->vector_elements;<br>
>        load_instr->variables[0] = this->deref_head;<br>
> +      ralloc_steal(load_instr, load_instr->variables[0]);<br>
>        add_instr(&load_instr->instr, ir->type->vector_elements);<br>
>     }<br>
><br>
> @@ -959,6 +961,7 @@ nir_visitor::visit(ir_expression *ir)<br>
>        nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(shader, op);<br>
>        intrin->num_components = deref->type->vector_elements;<br>
>        intrin->variables[0] = this->deref_head;<br>
> +      ralloc_steal(intrin, intrin->variables[0]);<br>
><br>
>        if (intrin->intrinsic == nir_intrinsic_interp_var_at_offset ||<br>
>            intrin->intrinsic == nir_intrinsic_interp_var_at_sample)<br>
> @@ -1630,8 +1633,7 @@ nir_visitor::visit(ir_texture *ir)<br>
>        unreachable("not reached");<br>
>     }<br>
><br>
> -   ir->sampler->accept(this);<br>
> -   instr->sampler = this->deref_head;<br>
> +   instr->sampler = make_deref(instr, ir->sampler);<br>
><br>
>     unsigned src_number = 0;<br>
><br>
> @@ -1756,7 +1758,7 @@ nir_visitor::visit(ir_dereference_record *ir)<br>
>     int field_index = this->deref_tail->type->field_index(ir->field);<br>
>     assert(field_index >= 0);<br>
><br>
> -   nir_deref_struct *deref = nir_deref_struct_create(this->shader, field_index);<br>
> +   nir_deref_struct *deref = nir_deref_struct_create(this->deref_tail, field_index);<br>
>     deref->deref.type = ir->type;<br>
>     this->deref_tail->child = &deref->deref;<br>
>     this->deref_tail = &deref->deref;<br>
> @@ -1780,5 +1782,6 @@ nir_visitor::visit(ir_dereference_array *ir)<br>
>     ir->array->accept(this);<br>
><br>
>     this->deref_tail->child = &deref->deref;<br>
> +   ralloc_steal(this->deref_tail, deref);<br>
>     this->deref_tail = &deref->deref;<br>
>  }<br>
> diff --git a/src/glsl/nir/nir.c b/src/glsl/nir/nir.c<br>
> index 85ff0f4..1c6b603 100644<br>
> --- a/src/glsl/nir/nir.c<br>
> +++ b/src/glsl/nir/nir.c<br>
> @@ -543,7 +543,7 @@ copy_deref_var(void *mem_ctx, nir_deref_var *deref)<br>
>     nir_deref_var *ret = nir_deref_var_create(mem_ctx, deref->var);<br>
>     ret->deref.type = deref->deref.type;<br>
>     if (deref->deref.child)<br>
> -      ret->deref.child = nir_copy_deref(mem_ctx, deref->deref.child);<br>
> +      ret->deref.child = nir_copy_deref(ret, deref->deref.child);<br>
>     return ret;<br>
>  }<br>
><br>
> @@ -558,7 +558,7 @@ copy_deref_array(void *mem_ctx, nir_deref_array *deref)<br>
>     }<br>
>     ret->deref.type = deref->deref.type;<br>
>     if (deref->deref.child)<br>
> -      ret->deref.child = nir_copy_deref(mem_ctx, deref->deref.child);<br>
> +      ret->deref.child = nir_copy_deref(ret, deref->deref.child);<br>
>     return ret;<br>
>  }<br>
><br>
> @@ -568,7 +568,7 @@ copy_deref_struct(void *mem_ctx, nir_deref_struct *deref)<br>
>     nir_deref_struct *ret = nir_deref_struct_create(mem_ctx, deref->index);<br>
>     ret->deref.type = deref->deref.type;<br>
>     if (deref->deref.child)<br>
> -      ret->deref.child = nir_copy_deref(mem_ctx, deref->deref.child);<br>
> +      ret->deref.child = nir_copy_deref(ret, deref->deref.child);<br>
>     return ret;<br>
>  }</p>
<p dir="ltr">I'd really like to make nir_copy_deref operate on deref_var's and take a nir_instr as well but that can be another patch later.</p>
<p dir="ltr">> diff --git a/src/glsl/nir/nir_lower_var_copies.c b/src/glsl/nir/nir_lower_var_copies.c<br>
> index 85ebb28..58389a7 100644<br>
> --- a/src/glsl/nir/nir_lower_var_copies.c<br>
> +++ b/src/glsl/nir/nir_lower_var_copies.c<br>
> @@ -148,13 +148,10 @@ emit_copy_load_store(nir_intrinsic_instr *copy_instr,<br>
><br>
>        unsigned num_components = glsl_get_vector_elements(src_tail->type);<br>
><br>
> -      nir_deref *src_deref = nir_copy_deref(mem_ctx, &src_head->deref);<br>
> -      nir_deref *dest_deref = nir_copy_deref(mem_ctx, &dest_head->deref);<br>
> -<br>
>        nir_intrinsic_instr *load =<br>
>           nir_intrinsic_instr_create(mem_ctx, nir_intrinsic_load_var);<br>
>        load->num_components = num_components;<br>
> -      load->variables[0] = nir_deref_as_var(src_deref);<br>
> +      load->variables[0] = nir_deref_as_var(nir_copy_deref(load, &src_head->deref));<br>
>        nir_ssa_dest_init(&load->instr, &load->dest, num_components, NULL);<br>
><br>
>        nir_instr_insert_before(&copy_instr->instr, &load->instr);<br>
> @@ -162,7 +159,8 @@ emit_copy_load_store(nir_intrinsic_instr *copy_instr,<br>
>        nir_intrinsic_instr *store =<br>
>           nir_intrinsic_instr_create(mem_ctx, nir_intrinsic_store_var);<br>
>        store->num_components = num_components;<br>
> -      store->variables[0] = nir_deref_as_var(dest_deref);<br>
> +      store->variables[0] = nir_deref_as_var(nir_copy_deref(store, &dest_head->deref));<br>
> +<br>
>        store->src[0].is_ssa = true;<br>
>        store->src[0].ssa = &load->dest.ssa;<br>
><br>
> diff --git a/src/glsl/nir/nir_split_var_copies.c b/src/glsl/nir/nir_split_var_copies.c<br>
> index 4d663b5..fc72c07 100644<br>
> --- a/src/glsl/nir/nir_split_var_copies.c<br>
> +++ b/src/glsl/nir/nir_split_var_copies.c<br>
> @@ -188,8 +188,8 @@ split_var_copy_instr(nir_intrinsic_instr *old_copy,<br>
>            * belongs to the copy instruction and b) the deref chains may<br>
>            * have some of the same links due to the way we constructed them<br>
>            */<br>
> -         nir_deref *src = nir_copy_deref(state->mem_ctx, src_head);<br>
> -         nir_deref *dest = nir_copy_deref(state->mem_ctx, dest_head);<br>
> +         nir_deref *src = nir_copy_deref(new_copy, src_head);<br>
> +         nir_deref *dest = nir_copy_deref(new_copy, dest_head);<br>
><br>
>           new_copy->variables[0] = nir_deref_as_var(dest);<br>
>           new_copy->variables[1] = nir_deref_as_var(src);<br>
> diff --git a/src/glsl/nir/nir_validate.c b/src/glsl/nir/nir_validate.c<br>
> index e8c9d7b..a7aa798 100644<br>
> --- a/src/glsl/nir/nir_validate.c<br>
> +++ b/src/glsl/nir/nir_validate.c<br>
> @@ -295,6 +295,8 @@ validate_alu_instr(nir_alu_instr *instr, validate_state *state)<br>
>  static void<br>
>  validate_deref_chain(nir_deref *deref, validate_state *state)<br>
>  {<br>
> +   assert(deref->child == NULL || ralloc_parent(deref->child) == deref);<br>
> +<br>
>     nir_deref *parent = NULL;<br>
>     while (deref != NULL) {<br>
>        switch (deref->deref_type) {<br>
> @@ -336,9 +338,10 @@ validate_var_use(nir_variable *var, validate_state *state)<br>
>  }<br>
><br>
>  static void<br>
> -validate_deref_var(nir_deref_var *deref, validate_state *state)<br>
> +validate_deref_var(void *parent_mem_ctx, nir_deref_var *deref, validate_state *state)<br>
>  {<br>
>     assert(deref != NULL);<br>
> +   assert(ralloc_parent(deref) == parent_mem_ctx);</p>
<p dir="ltr">Thanks for validating this!</p>
<p dir="ltr">>     assert(deref->deref.type == deref->var->type);<br>
><br>
>     validate_var_use(deref->var, state);<br>
> @@ -386,7 +389,7 @@ validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state)<br>
><br>
>     unsigned num_vars = nir_intrinsic_infos[instr->intrinsic].num_variables;<br>
>     for (unsigned i = 0; i < num_vars; i++) {<br>
> -      validate_deref_var(instr->variables[i], state);<br>
> +      validate_deref_var(instr, instr->variables[i], state);<br>
>     }<br>
><br>
>     switch (instr->intrinsic) {<br>
> @@ -423,7 +426,7 @@ validate_tex_instr(nir_tex_instr *instr, validate_state *state)<br>
>     }<br>
><br>
>     if (instr->sampler != NULL)<br>
> -      validate_deref_var(instr->sampler, state);<br>
> +      validate_deref_var(instr, instr->sampler, state);<br>
>  }<br>
><br>
>  static void<br>
> @@ -438,10 +441,10 @@ validate_call_instr(nir_call_instr *instr, validate_state *state)<br>
><br>
>     for (unsigned i = 0; i < instr->num_params; i++) {<br>
>        assert(instr->callee->params[i].type == instr->params[i]->deref.type);<br>
> -      validate_deref_var(instr->params[i], state);<br>
> +      validate_deref_var(instr, instr->params[i], state);<br>
>     }<br>
><br>
> -   validate_deref_var(instr->return_deref, state);<br>
> +   validate_deref_var(instr, instr->return_deref, state);<br>
>  }<br>
><br>
>  static void<br>
> diff --git a/src/mesa/program/prog_to_nir.c b/src/mesa/program/prog_to_nir.c<br>
> index 5f00a8b..b298d07 100644<br>
> --- a/src/mesa/program/prog_to_nir.c<br>
> +++ b/src/mesa/program/prog_to_nir.c<br>
> @@ -153,8 +153,7 @@ ptn_get_src(struct ptn_compile *c, const struct prog_src_register *prog_src)<br>
>        nir_intrinsic_instr *load =<br>
>           nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var);<br>
>        load->num_components = 4;<br>
> -      load->variables[0] =<br>
> -         nir_deref_var_create(b->shader, c->input_vars[prog_src->Index]);<br>
> +      load->variables[0] = nir_deref_var_create(load, c->input_vars[prog_src->Index]);<br>
><br>
>        nir_ssa_dest_init(&load->instr, &load->dest, 4, NULL);<br>
>        nir_instr_insert_after_cf_list(b->cf_node_list, &load->instr);<br>
> @@ -918,7 +917,7 @@ ptn_add_output_stores(struct ptn_compile *c)<br>
>           nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var);<br>
>        store->num_components = 4;<br>
>        store->variables[0] =<br>
> -         nir_deref_var_create(b->shader, c->output_vars[var->data.location]);<br>
> +         nir_deref_var_create(store, c->output_vars[var->data.location]);<br>
>        store->src[0].reg.reg = c->output_regs[var->data.location];<br>
>        nir_instr_insert_after_cf_list(c->build.cf_node_list, &store->instr);<br>
>     }<br>
> @@ -962,7 +961,7 @@ setup_registers_and_variables(struct ptn_compile *c)<br>
>              nir_intrinsic_instr *load_x =<br>
>                 nir_intrinsic_instr_create(shader, nir_intrinsic_load_var);<br>
>              load_x->num_components = 1;<br>
> -            load_x->variables[0] = nir_deref_var_create(shader, var);<br>
> +            load_x->variables[0] = nir_deref_var_create(load_x, var);<br>
>              nir_ssa_dest_init(&load_x->instr, &load_x->dest, 1, NULL);<br>
>              nir_instr_insert_after_cf_list(b->cf_node_list, &load_x->instr);<br>
><br>
> @@ -978,7 +977,7 @@ setup_registers_and_variables(struct ptn_compile *c)<br>
>              nir_intrinsic_instr *store =<br>
>                 nir_intrinsic_instr_create(shader, nir_intrinsic_store_var);<br>
>              store->num_components = 4;<br>
> -            store->variables[0] = nir_deref_var_create(shader, fullvar);<br>
> +            store->variables[0] = nir_deref_var_create(store, fullvar);<br>
>              store->src[0] = nir_src_for_ssa(f001);<br>
>              nir_instr_insert_after_cf_list(b->cf_node_list, &store->instr);<br>
><br>
> --<br>
> 2.3.5<br>
><br>
> _______________________________________________<br>
> mesa-dev mailing list<br>
> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</p>