On 05/06/2013 11:35 AM, Paul Berry wrote:
On 3 May 2013 16:07, Ian Romanick <i...@freedesktop.org
<mailto:i...@freedesktop.org>> wrote:

    From: Ian Romanick <ian.d.roman...@intel.com
    <mailto:ian.d.roman...@intel.com>>

    Right now the lower_clip_distance_visitor lowers variable indexing into
    gl_ClipDistance into variable indexing into both the array
    gl_ClipDistanceMESA and the vectors of that array.  For example,

         gl_ClipDistance[i] = f;

    becomes

         gl_ClipDistanceMESA[i/4][i%4] = f;


Technically it becomes gl_ClipDistanceMESA[i>>2][i&3].  Granted it's
equivalent, but you might want to change your commit message to be more
in line with what the lowering pass actually does.


    However, variable indexing into vectors using ir_dereference_array is
    being removed.  Instead, ir_expression with ir_triop_vector_insert will
    be used.  The above code will become

         gl_ClipDistanceMESA[i/4] = vector_insert(gl_ClipDistanceMESA[i/4],
                                                  i % 4,
                                                  f);

    In order to do this, an ir_rvalue_visitor will need to be used.  This
    commit is really just a refactor to get ready for that.


This commit is actually more than just a refactor.  It also modifies how
the lowering pass treats statements of the form:

    foo = gl_ClipDistance;

so that instead of being transformed to:

    foo[0] = gl_ClipDistance[0][0];
    foo[1] = gl_ClipDistance[0][1];
    ...

they are transformed to:

    foo[0] = gl_ClipDistance[0].x;
    foo[1] = gl_ClipDistance[0].y;

I don't really understand why this is necessary (since a later
optimization pass would make this transformation anyhow), and I believe
that it introduces a bug (see below).  I'd prefer to see this
modification either dropped or split into its own patch, with an
explanation of why it is necessary.

The whole point of this entire series is getting rid of all instances of array indexing of vectors. Previously in the series, everything that could generate array indexing of a vector was modified to use the new IR. The last patch in the series updates ir_validate to throw an error if array indexing of a vector is encountered.

The lowering pass for gl_ClipDistance is the last thing in the compiler that generates this sort of IR.

    v2: Convert tabs to spaces.  Suggested by Eric.

    Signed-off-by: Ian Romanick <ian.d.roman...@intel.com
    <mailto:ian.d.roman...@intel.com>>
    Cc: Paul Berry <stereotype...@gmail.com
    <mailto:stereotype...@gmail.com>>
    ---
      src/glsl/lower_clip_distance.cpp | 136
    +++++++++++++++++++++++++--------------
      1 file changed, 86 insertions(+), 50 deletions(-)

    diff --git a/src/glsl/lower_clip_distance.cpp
    b/src/glsl/lower_clip_distance.cpp
    index 643807d..19068fb 100644
    --- a/src/glsl/lower_clip_distance.cpp
    +++ b/src/glsl/lower_clip_distance.cpp
    @@ -46,10 +46,10 @@
       */

      #include "glsl_symbol_table.h"
    -#include "ir_hierarchical_visitor.h"
    +#include "ir_rvalue_visitor.h"
      #include "ir.h"

    -class lower_clip_distance_visitor : public ir_hierarchical_visitor {
    +class lower_clip_distance_visitor : public ir_rvalue_visitor {
      public:
         lower_clip_distance_visitor()
            : progress(false), old_clip_distance_var(NULL),
    @@ -59,11 +59,12 @@ public:

         virtual ir_visitor_status visit(ir_variable *);
         void create_indices(ir_rvalue*, ir_rvalue *&, ir_rvalue *&);
    -   virtual ir_visitor_status visit_leave(ir_dereference_array *);
         virtual ir_visitor_status visit_leave(ir_assignment *);
         void visit_new_assignment(ir_assignment *ir);
         virtual ir_visitor_status visit_leave(ir_call *);

    +   virtual void handle_rvalue(ir_rvalue **rvalue);
    +
         bool progress;

         /**
    @@ -173,33 +174,35 @@
    lower_clip_distance_visitor::create_indices(ir_rvalue *old_index,
      }


    -/**
    - * Replace any expression that indexes into the gl_ClipDistance
    array with an
    - * expression that indexes into one of the vec4's in
    gl_ClipDistanceMESA and
    - * accesses the appropriate component.
    - */

    -ir_visitor_status
    -lower_clip_distance_visitor::visit_leave(ir_dereference_array *ir)
    +void
    +lower_clip_distance_visitor::handle_rvalue(ir_rvalue **rv)
      {
         /* If the gl_ClipDistance var hasn't been declared yet, then
          * there's no way this deref can refer to it.
          */
    -   if (!this->old_clip_distance_var)
    -      return visit_continue;
    -
    -   ir_dereference_variable *old_var_ref =
    ir->array->as_dereference_variable();
    -   if (old_var_ref && old_var_ref->var ==
    this->old_clip_distance_var) {
    -      this->progress = true;
    -      ir_rvalue *array_index;
    -      ir_rvalue *swizzle_index;
    -      this->create_indices(ir->array_index, array_index,
    swizzle_index);
    -      void *mem_ctx = ralloc_parent(ir);
    -      ir->array = new(mem_ctx) ir_dereference_array(
    -         this->new_clip_distance_var, array_index);
    -      ir->array_index = swizzle_index;
    +   if (!this->old_clip_distance_var || *rv == NULL)
    +      return;

    +
    +   ir_dereference_array *const array = (*rv)->as_dereference_array();


Can we rename this var to "array_deref"?  It's confusing to see the
"array->array" below.

Okay.

    +   if (array != NULL) {
    +      /* Replace any expression that indexes into the
    gl_ClipDistance array
    +       * with an expression that indexes into one of the vec4's in
    +       * gl_ClipDistanceMESA and accesses the appropriate component.
    +       */
    +      ir_dereference_variable *old_var_ref =
    +         array->array->as_dereference_variable();
    +      if (old_var_ref && old_var_ref->var ==
    this->old_clip_distance_var) {
    +         this->progress = true;
    +         ir_rvalue *array_index;
    +         ir_rvalue *swizzle_index;
    +         this->create_indices(array->array_index, array_index,
    swizzle_index);
    +         void *mem_ctx = ralloc_parent(array);
    +         array->array =
    +            new(mem_ctx)
    ir_dereference_array(this->new_clip_distance_var,
    +                                              array_index);
    +         array->array_index = swizzle_index;
    +      }
         }
    -
    -   return visit_continue;
      }


    @@ -214,38 +217,71 @@
    lower_clip_distance_visitor::visit_leave(ir_assignment *ir)
      {
         ir_dereference_variable *lhs_var =
    ir->lhs->as_dereference_variable();
         ir_dereference_variable *rhs_var =
    ir->rhs->as_dereference_variable();
    -   if ((lhs_var && lhs_var->var == this->old_clip_distance_var)
    -       || (rhs_var && rhs_var->var == this->old_clip_distance_var)) {
    -      /* LHS or RHS of the assignment is the entire gl_ClipDistance
    array.
    -       * Since we are reshaping gl_ClipDistance from an array of
    floats to an
    -       * array of vec4's, this isn't going to work as a bulk assignment
    -       * anymore, so unroll it to element-by-element assignments
    and lower
    -       * each of them.
    -       *
    -       * Note: to unroll into element-by-element assignments, we
    need to make
    -       * clones of the LHS and RHS.  This is only safe if the LHS
    and RHS are
    -       * side-effect free.  Fortunately, we know that they are,
    because the
    -       * only kind of rvalue that can have side effects is an
    ir_call, and
    -       * ir_calls only appear (a) as a statement on their own, or
    (b) as the
    -       * RHS of an assignment that stores the result of the call in a
    -       * temporary variable.
    -       */
    -      void *ctx = ralloc_parent(ir);
    +   void *ctx = ralloc_parent(ir);
    +
    +   /* LHS or RHS of the assignment is the entire gl_ClipDistance array.
    +    * Since we are reshaping gl_ClipDistance from an array of
    floats to an
    +    * array of vec4's, this isn't going to work as a bulk assignment
    +    * anymore, so unroll it to element-by-element assignments and lower
    +    * each of them.
    +    *
    +    * Note: to unroll into element-by-element assignments, we need
    to make
    +    * clones of the LHS and RHS.  This is only safe if the LHS and
    RHS are
    +    * side-effect free.  Fortunately, we know that they are,
    because the
    +    * only kind of rvalue that can have side effects is an ir_call, and
    +    * ir_calls only appear (a) as a statement on their own, or (b)
    as the
    +    * RHS of an assignment that stores the result of the call in a
    +    * temporary variable.
    +    */


The last two sentences of this comment are out of date, since a long
time ago we modified ir_call to be a statement rather than an
expression.  If you're going to move this comment, please change the
last two sentences to something like "This is safe because expressions
are side-effect free".

Okay.

    +   if (lhs_var && lhs_var->var == this->old_clip_distance_var) {
            int array_size =
    this->old_clip_distance_var->type->array_size();
            for (int i = 0; i < array_size; ++i) {
    -         ir_dereference_array *new_lhs = new(ctx) ir_dereference_array(
    -            ir->lhs->clone(ctx, NULL), new(ctx) ir_constant(i));
    -         new_lhs->accept(this);
    +         ir_dereference_variable *const new_deref =
    +            new(ctx) ir_dereference_variable(new_clip_distance_var);
    +
    +         ir_dereference_array *const new_lhs =
    +            new(ctx) ir_dereference_array(new_deref,
    +                                          new(ctx) ir_constant(i / 4));
    +
               ir_dereference_array *new_rhs = new(ctx)
    ir_dereference_array(
                  ir->rhs->clone(ctx, NULL), new(ctx) ir_constant(i));
    -         new_rhs->accept(this);
    -         this->base_ir->insert_before(
    -            new(ctx) ir_assignment(new_lhs, new_rhs));
    +
    +         const int mask = 1 << (i % 4);
    +
    +         ir_assignment *const assign =
    +            new(ctx) ir_assignment(new_lhs, new_rhs, NULL, mask);
    +
    +         this->base_ir->insert_before(assign);
            }
            ir->remove();
    +
    +      return visit_continue;
    +   } else if (rhs_var && rhs_var->var == this->old_clip_distance_var) {
    +      int array_size = this->old_clip_distance_var->type->array_size();
    +      for (int i = 0; i < array_size; ++i) {
    +         ir_dereference_array *new_lhs = new(ctx) ir_dereference_array(
    +            ir->lhs->clone(ctx, NULL), new(ctx) ir_constant(i));
    +
    +         ir_dereference_variable *const new_deref =
    +            new(ctx) ir_dereference_variable(new_clip_distance_var);
    +
    +         ir_rvalue *const new_rhs =
    +            new(ctx) ir_swizzle(new(ctx)
    ir_dereference_array(new_deref,
    +
      new(ctx) ir_constant(i / 4)),
    +                                i % 4, 0, 0, 0, 1);
    +
    +         ir_assignment *const assign =
    +            new(ctx) ir_assignment(new_lhs, new_rhs);
    +
    +         this->base_ir->insert_before(assign);
    +      }
    +      ir->remove();
    +
    +      return visit_continue;
         }


As I alluded to above, it's not clear to me why splitting this code into
two separate cases (one for LHS, one for RHS) is necessary/beneficial.

Because there are two kinds of IR that replace array indexing of vectors: ir_binop_vector_extract and ir_triop_vector_insert. The next patch makes this code use those.

Also, I suspect that we now have a bug if the shader contains the
(admittedly silly) statement:

     gl_ClipDistance = gl_ClipDistance;

I don't think so. Since this is an array assignment, it will already be broken down into a sequence of

    gl_ClipDistance[0] = gl_ClipDistance[0];
    ...
    gl_ClipDistance[7] = gl_ClipDistance[7];

Right? Each of those should get handled correctly. I was also pretty sure that you added a test case for this when you originally wrote this lowering pass. Am I misremembering?

    -   return visit_continue;
    +   handle_rvalue((ir_rvalue **)&ir->lhs);
    +   return rvalue_visit(ir);


I could have really used a comment explaining why the call to
handle_rvalue() is necessary here.  Something like:
"rvalue_visit(ir_assignment*) only visits the RHS of the assignment, but
we need references to gl_ClipDistance in the LHS to be lowered also."

Okay.

      }


    @@ -330,7 +366,7 @@ lower_clip_distance_visitor::visit_leave(ir_call
    *ir)
            }
         }

    -   return visit_continue;
    +   return rvalue_visit(ir);
      }


    --
    1.8.1.4



_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to