[Mesa-dev] [PATCH 3/8] glsl: Rework lowering of non-constant array indexing

Eric Anholt eric at anholt.net
Wed Jul 20 17:01:01 PDT 2011


On Mon, 18 Jul 2011 14:15:22 -0700, "Ian Romanick" <idr at freedesktop.org> wrote:
> From: Ian Romanick <ian.d.romanick at intel.com>
> 
> The previous implementation could easily get tricked if the LHS of an
> assignment included a non-constant index that was "inside" another
> dereference.  For example:
> 
>     mat4 m[2];
>     m[0][i] = vec4(0.0);
> 
> Due to the way it tracked whether the array was being assigned, it
> would think that the non-constant index was in an r-value.  The new
> code fixes that by tracking l-values and r-values differently.  The
> index is also replaced by cloning the IR and replacing the index
> variable instead of the odd way it was done before.
> 
> Fixes i965 piglit fs-temp-array-mat[234]-index-wr and
> vs-varying-array-mat[234]-index-wr.

I think I see one little simplification, and other than that I think
I've made sense of it.

>  struct assignment_generator
>  {
>     ir_instruction* base_ir;
> -   ir_rvalue* array;
> +   ir_rvalue *rvalue;

I think this rvalue could be an ir_dereference *

> +   ir_variable *old_index;
>     bool is_write;
>     unsigned int write_mask;
>     ir_variable* var;
> @@ -61,14 +136,25 @@ struct assignment_generator
>         * underlying variable.
>         */
>        void *mem_ctx = ralloc_parent(base_ir);
> -      ir_dereference *element =
> -	 new(mem_ctx) ir_dereference_array(this->array->clone(mem_ctx, NULL),
> -					   new(mem_ctx) ir_constant(i));
> -      ir_rvalue *variable = new(mem_ctx) ir_dereference_variable(this->var);
>  
> +      /* Clone the old r-value in its entirety.  Then replace any occurances of
> +       * the old variable index with the new constant index.
> +       */
> +      ir_rvalue *element = this->rvalue->clone(mem_ctx, NULL);

Making this an ir_dereference *

> +      ir_constant *const index = new(mem_ctx) ir_constant(i);
> +      deref_replacer r(this->old_index, index);
> +      element->accept(&r);
> +      assert(r.progress);
> +
> +      /* Generate a conditional assignment to (or from) the constant indexed
> +       * array dereference.
> +       */
> +      ir_rvalue *variable = new(mem_ctx) ir_dereference_variable(this->var);
>        ir_assignment *assignment;
>        if (is_write) {
> -	 assignment = new(mem_ctx) ir_assignment(element, variable, condition,
> +	 ir_dereference *d = element->as_dereference();
> +	 assert(d != NULL);
> +	 assignment = new(mem_ctx) ir_assignment(d, variable, condition,
>  						 write_mask);

And avoiding this cast/assert...

>     ir_variable *convert_dereference_array(ir_dereference_array *orig_deref,
> -					  ir_assignment* orig_assign)
> +					  ir_assignment* orig_assign,
> +					  ir_rvalue *orig_base)
>     {
>        assert(is_array_or_matrix(orig_deref->array));
>  
> @@ -320,9 +407,12 @@ public:
>  	 new(mem_ctx) ir_assignment(lhs, orig_deref->array_index, NULL);
>        base_ir->insert_before(assign);
>  
> +      orig_deref->array_index = lhs->clone(mem_ctx, NULL);
> +
>        assignment_generator ag;
> -      ag.array = orig_deref->array;
> +      ag.rvalue = orig_base;
>        ag.base_ir = base_ir;
> +      ag.old_index = index;
>        ag.var = var;
>        if (orig_assign) {
>  	 ag.is_write = true;
> @@ -342,12 +432,16 @@ public:
>  
>     virtual void handle_rvalue(ir_rvalue **pir)
>     {
> +      if (this->in_assignee)
> +	 return;
> +
>        if (!*pir)
>           return;
>  
>        ir_dereference_array* orig_deref = (*pir)->as_dereference_array();
>        if (needs_lowering(orig_deref)) {
> -         ir_variable* var = convert_dereference_array(orig_deref, 0);
> +         ir_variable *var =
> +	    convert_dereference_array(orig_deref, NULL, orig_deref);
>           assert(var);
>           *pir = new(ralloc_parent(base_ir)) ir_dereference_variable(var);
>           this->progress = true;
> @@ -359,10 +453,11 @@ public:
>     {
>        ir_rvalue_visitor::visit_leave(ir);
>  
> -      ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
> +      find_variable_index f;
> +      ir->lhs->accept(&f);
>  
> -      if (needs_lowering(orig_deref)) {
> -         convert_dereference_array(orig_deref, ir);
> +      if ((f.deref != NULL) && storage_type_needs_lowering(f.deref)) {
> +         convert_dereference_array(f.deref, ir, ir->lhs);
>           ir->remove();
>           this->progress = true;
>        }

Because the orig_base of both convert_dereference_array() calls is a
deref.

I think it's nice to note that this is a dereference because it means
that clone()ing should be safer than, say, cloning some expression tree.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20110720/18b79779/attachment-0001.pgp>


More information about the mesa-dev mailing list