Mesa (glsl2): glsl2: Add ir_assignment::write_mask and associated methods

Ian Romanick idr at kemper.freedesktop.org
Wed Aug 4 23:52:17 UTC 2010


Module: Mesa
Branch: glsl2
Commit: 5a7758efbe14dee026245a4f4f4fb3ccf7b2c23b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=5a7758efbe14dee026245a4f4f4fb3ccf7b2c23b

Author: Ian Romanick <ian.d.romanick at intel.com>
Date:   Mon Aug  2 18:48:25 2010 -0700

glsl2: Add ir_assignment::write_mask and associated methods

Replace swizzles on the LHS with additional swizzles on the RHS and a
write mask in the assignment instruction.  As part of this add
ir_assignment::set_lhs.  Ideally we'd make ir_assignment::lhs private
to prevent erroneous writes, but that would require a lot of code
butchery at this point.

Add ir_assignment constructor that takes an explicit write mask.  This
is required for ir_assignment::clone, but it can also be used in other
places.  Without this, ir_assignment clones lose their write masks,
and incorrect IR is generated in optimization passes.

Add ir_assignment::whole_variable_written method.  This method gets
the variable on the LHS if the whole variable is written or NULL
otherwise.  This is different from
ir->lhs->whole_variable_referenced() because the latter has no
knowledge of the write mask stored in the ir_assignment.

Gut all code from ir_to_mesa that handled swizzles on the LHS of
assignments.  There is probably some other refactoring that could be
done here, but that can be left for another day.

---

 src/glsl/ir.cpp                      |  113 +++++++++++++++++++++++++++++++++-
 src/glsl/ir.h                        |   44 +++++++++++++-
 src/glsl/ir_clone.cpp                |    3 +-
 src/glsl/ir_constant_variable.cpp    |    2 +-
 src/glsl/ir_copy_propagation.cpp     |    2 +-
 src/glsl/ir_dead_code_local.cpp      |    2 +-
 src/glsl/ir_print_visitor.cpp        |   14 ++++-
 src/glsl/ir_tree_grafting.cpp        |    2 +-
 src/glsl/ir_vec_index_to_swizzle.cpp |    2 +-
 src/mesa/program/ir_to_mesa.cpp      |   67 ++++++++-------------
 10 files changed, 199 insertions(+), 52 deletions(-)

diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp
index 79cbaa9..c3bade8 100644
--- a/src/glsl/ir.cpp
+++ b/src/glsl/ir.cpp
@@ -22,6 +22,7 @@
  */
 #include <string.h>
 #include "main/imports.h"
+#include "main/macros.h"
 #include "ir.h"
 #include "ir_visitor.h"
 #include "glsl_types.h"
@@ -31,13 +32,121 @@ ir_rvalue::ir_rvalue()
    this->type = glsl_type::error_type;
 }
 
+/**
+ * Modify the swizzle make to move one component to another
+ *
+ * \param m    IR swizzle to be modified
+ * \param from Component in the RHS that is to be swizzled
+ * \param to   Desired swizzle location of \c from
+ */
+static void
+update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to)
+{
+   switch (to) {
+   case 0: m.x = from; break;
+   case 1: m.y = from; break;
+   case 2: m.z = from; break;
+   case 3: m.w = from; break;
+   default: assert(!"Should not get here.");
+   }
+
+   m.num_components = MAX2(m.num_components, (to + 1));
+}
+
+void
+ir_assignment::set_lhs(ir_rvalue *lhs)
+{
+   while (lhs != NULL) {
+      ir_swizzle *swiz = lhs->as_swizzle();
+
+      if (swiz == NULL)
+	 break;
+
+      unsigned write_mask = 0;
+      ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
+
+      for (unsigned i = 0; i < swiz->mask.num_components; i++) {
+	 unsigned c = 0;
+
+	 switch (i) {
+	 case 0: c = swiz->mask.x; break;
+	 case 1: c = swiz->mask.y; break;
+	 case 2: c = swiz->mask.z; break;
+	 case 3: c = swiz->mask.w; break;
+	 default: assert(!"Should not get here.");
+	 }
+
+	 write_mask |= (((this->write_mask >> i) & 1) << c);
+	 update_rhs_swizzle(rhs_swiz, i, c);
+      }
+
+      this->write_mask = write_mask;
+      lhs = swiz->val;
+
+      this->rhs = new(this) ir_swizzle(this->rhs, rhs_swiz);
+   }
+
+   assert((lhs == NULL) || lhs->as_dereference());
+
+   this->lhs = (ir_dereference *) lhs;
+}
+
+ir_variable *
+ir_assignment::whole_variable_written()
+{
+   ir_variable *v = this->lhs->whole_variable_referenced();
+
+   if (v == NULL)
+      return NULL;
+
+   if (v->type->is_scalar())
+      return v;
+
+   if (v->type->is_vector()) {
+      const unsigned mask = (1U << v->type->vector_elements) - 1;
+
+      if (mask != this->write_mask)
+	 return NULL;
+   }
+
+   /* Either all the vector components are assigned or the variable is some
+    * composite type (and the whole thing is assigned.
+    */
+   return v;
+}
+
+ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs,
+			     ir_rvalue *condition, unsigned write_mask)
+{
+   this->ir_type = ir_type_assignment;
+   this->condition = condition;
+   this->rhs = rhs;
+   this->lhs = lhs;
+   this->write_mask = write_mask;
+}
+
 ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs,
 			     ir_rvalue *condition)
 {
    this->ir_type = ir_type_assignment;
-   this->lhs = lhs;
-   this->rhs = rhs;
    this->condition = condition;
+   this->rhs = rhs;
+
+   /* If the RHS is a vector type, assume that all components of the vector
+    * type are being written to the LHS.  The write mask comes from the RHS
+    * because we can have a case where the LHS is a vec4 and the RHS is a
+    * vec3.  In that case, the assignment is:
+    *
+    *     (assign (...) (xyz) (var_ref lhs) (var_ref rhs))
+    */
+   if (rhs->type->is_vector())
+      this->write_mask = (1U << rhs->type->vector_elements) - 1;
+   else if (rhs->type->is_scalar())
+      this->write_mask = 1;
+   else
+      this->write_mask = 0;
+
+   this->set_lhs(lhs);
 }
 
 
diff --git a/src/glsl/ir.h b/src/glsl/ir.h
index f964b36..9878950 100644
--- a/src/glsl/ir.h
+++ b/src/glsl/ir.h
@@ -514,6 +514,16 @@ class ir_assignment : public ir_instruction {
 public:
    ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, ir_rvalue *condition);
 
+   /**
+    * Construct an assignment with an explicit write mask
+    *
+    * \note
+    * Since a write mask is supplied, the LHS must already be a bare
+    * \c ir_dereference.  The cannot be any swizzles in the LHS.
+    */
+   ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, ir_rvalue *condition,
+		 unsigned write_mask);
+
    virtual ir_assignment *clone(void *mem_ctx, struct hash_table *ht) const;
 
    virtual ir_constant *constant_expression_value();
@@ -531,9 +541,31 @@ public:
    }
 
    /**
+    * Get a whole variable written by an assignment
+    *
+    * If the LHS of the assignment writes a whole variable, the variable is
+    * returned.  Otherwise \c NULL is returned.  Examples of whole-variable
+    * assignment are:
+    *
+    *  - Assigning to a scalar
+    *  - Assigning to all components of a vector
+    *  - Whole array (or matrix) assignment
+    *  - Whole structure assignment
+    */
+   ir_variable *whole_variable_written();
+
+   /**
+    * Set the LHS of an assignment
+    */
+   void set_lhs(ir_rvalue *lhs);
+
+   /**
     * Left-hand side of the assignment.
+    *
+    * This should be treated as read only.  If you need to set the LHS of an
+    * assignment, use \c ir_assignment::set_lhs.
     */
-   ir_rvalue *lhs;
+   ir_dereference *lhs;
 
    /**
     * Value being assigned
@@ -544,6 +576,16 @@ public:
     * Optional condition for the assignment.
     */
    ir_rvalue *condition;
+
+
+   /**
+    * Component mask written
+    *
+    * For non-vector types in the LHS, this field will be zero.  For vector
+    * types, a bit will be set for each component that is written.  Note that
+    * for \c vec2 and \c vec3 types only the lower bits will ever be set.
+    */
+   unsigned write_mask:4;
 };
 
 /* Update ir_expression::num_operands() and operator_strs when
diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp
index 5983183..0e20216 100644
--- a/src/glsl/ir_clone.cpp
+++ b/src/glsl/ir_clone.cpp
@@ -242,7 +242,8 @@ ir_assignment::clone(void *mem_ctx, struct hash_table *ht) const
 
    return new(mem_ctx) ir_assignment(this->lhs->clone(mem_ctx, ht),
 				     this->rhs->clone(mem_ctx, ht),
-				     new_condition);
+				     new_condition,
+				     this->write_mask);
 }
 
 ir_function *
diff --git a/src/glsl/ir_constant_variable.cpp b/src/glsl/ir_constant_variable.cpp
index 749e2cf..1fb73e7 100644
--- a/src/glsl/ir_constant_variable.cpp
+++ b/src/glsl/ir_constant_variable.cpp
@@ -110,7 +110,7 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
 	 return visit_continue;
    }
 
-   ir_variable *var = ir->lhs->whole_variable_referenced();
+   ir_variable *var = ir->whole_variable_written();
    if (!var)
       return visit_continue;
 
diff --git a/src/glsl/ir_copy_propagation.cpp b/src/glsl/ir_copy_propagation.cpp
index 5712398..26588a3 100644
--- a/src/glsl/ir_copy_propagation.cpp
+++ b/src/glsl/ir_copy_propagation.cpp
@@ -224,7 +224,7 @@ add_copy(void *ctx, ir_assignment *ir, exec_list *acp)
 	 return;
    }
 
-   ir_variable *lhs_var = ir->lhs->whole_variable_referenced();
+   ir_variable *lhs_var = ir->whole_variable_written();
    ir_variable *rhs_var = ir->rhs->whole_variable_referenced();
 
    if ((lhs_var != NULL) && (rhs_var != NULL)) {
diff --git a/src/glsl/ir_dead_code_local.cpp b/src/glsl/ir_dead_code_local.cpp
index 7a44ec8..b22cc55 100644
--- a/src/glsl/ir_dead_code_local.cpp
+++ b/src/glsl/ir_dead_code_local.cpp
@@ -137,7 +137,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
    }
 
    /* Now, check if we did a whole-variable assignment. */
-   if (always_assign && (ir->lhs->whole_variable_referenced() != NULL)) {
+   if (always_assign && (ir->whole_variable_written() != NULL)) {
       /* We did a whole-variable assignment.  So, any instruction in
        * the assignment list with the same LHS is dead.
        */
diff --git a/src/glsl/ir_print_visitor.cpp b/src/glsl/ir_print_visitor.cpp
index 73476e7..39b11bb 100644
--- a/src/glsl/ir_print_visitor.cpp
+++ b/src/glsl/ir_print_visitor.cpp
@@ -296,7 +296,19 @@ void ir_print_visitor::visit(ir_assignment *ir)
    else
       printf("(constant bool (1))");
 
-   printf(" ");
+
+   char mask[5];
+   unsigned j = 0;
+
+   for (unsigned i = 0; i < 4; i++) {
+      if ((ir->write_mask & (1 << i)) != 0) {
+	 mask[j] = "xyzw"[i];
+	 j++;
+      }
+   }
+   mask[j] = '\0';
+
+   printf(" (%s) ", mask);
 
    ir->lhs->accept(this);
 
diff --git a/src/glsl/ir_tree_grafting.cpp b/src/glsl/ir_tree_grafting.cpp
index 6f62de7..38034a6 100644
--- a/src/glsl/ir_tree_grafting.cpp
+++ b/src/glsl/ir_tree_grafting.cpp
@@ -315,7 +315,7 @@ tree_grafting_basic_block(ir_instruction *bb_first,
       if (!assign)
 	 continue;
 
-      ir_variable *lhs_var = assign->lhs->whole_variable_referenced();
+      ir_variable *lhs_var = assign->whole_variable_written();
       if (!lhs_var)
 	 continue;
 
diff --git a/src/glsl/ir_vec_index_to_swizzle.cpp b/src/glsl/ir_vec_index_to_swizzle.cpp
index 1e170cb..b3de91f 100644
--- a/src/glsl/ir_vec_index_to_swizzle.cpp
+++ b/src/glsl/ir_vec_index_to_swizzle.cpp
@@ -107,7 +107,7 @@ ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)
 ir_visitor_status
 ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir)
 {
-   ir->lhs = convert_vec_index_to_swizzle(ir->lhs);
+   ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs));
    ir->rhs = convert_vec_index_to_swizzle(ir->rhs);
 
    return visit_continue;
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index 777b4d9..1cec4aa 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -356,6 +356,7 @@ ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir,
 					ir_to_mesa_dst_reg dst,
 					ir_to_mesa_src_reg src0)
 {
+   assert(dst.writemask != 0);
    return ir_to_mesa_emit_op3(ir, op, dst,
 			      src0, ir_to_mesa_undef, ir_to_mesa_undef);
 }
@@ -1615,21 +1616,17 @@ ir_to_mesa_visitor::visit(ir_dereference_record *ir)
  * We want to be careful in assignment setup to hit the actual storage
  * instead of potentially using a temporary like we might with the
  * ir_dereference handler.
- *
- * Thanks to ir_swizzle_swizzle, and ir_vec_index_to_swizzle, we
- * should only see potentially one variable array index of a vector,
- * and one swizzle, before getting to actual vec4 storage.  So handle
- * those, then go use ir_dereference to handle the rest.
  */
 static struct ir_to_mesa_dst_reg
-get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v,
+get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v,
 		   ir_to_mesa_src_reg *r)
 {
-   struct ir_to_mesa_dst_reg dst_reg;
-   ir_swizzle *swiz;
-
+   /* The LHS must be a dereference.  If the LHS is a variable indexed array
+    * access of a vector, it must be separated into a series conditional moves
+    * before reaching this point (see ir_vec_index_to_cond_assign).
+    */
+   assert(ir->as_dereference());
    ir_dereference_array *deref_array = ir->as_dereference_array();
-   /* This should have been handled by ir_vec_index_to_cond_assign */
    if (deref_array) {
       assert(!deref_array->array->type->is_vector());
    }
@@ -1638,38 +1635,7 @@ get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v,
     * swizzles in it and write swizzles using writemask, though.
     */
    ir->accept(v);
-   dst_reg = ir_to_mesa_dst_reg_from_src(v->result);
-
-   if ((swiz = ir->as_swizzle())) {
-      int swizzles[4] = {
-	 swiz->mask.x,
-	 swiz->mask.y,
-	 swiz->mask.z,
-	 swiz->mask.w
-      };
-      int new_r_swizzle[4];
-      int orig_r_swizzle = r->swizzle;
-      int i;
-
-      for (i = 0; i < 4; i++) {
-	 new_r_swizzle[i] = GET_SWZ(orig_r_swizzle, 0);
-      }
-
-      dst_reg.writemask = 0;
-      for (i = 0; i < 4; i++) {
-	 if (i < swiz->mask.num_components) {
-	    dst_reg.writemask |= 1 << swizzles[i];
-	    new_r_swizzle[swizzles[i]] = GET_SWZ(orig_r_swizzle, i);
-	 }
-      }
-
-      r->swizzle = MAKE_SWIZZLE4(new_r_swizzle[0],
-				 new_r_swizzle[1],
-				 new_r_swizzle[2],
-				 new_r_swizzle[3]);
-   }
-
-   return dst_reg;
+   return ir_to_mesa_dst_reg_from_src(v->result);
 }
 
 void
@@ -1684,6 +1650,23 @@ ir_to_mesa_visitor::visit(ir_assignment *ir)
 
    l = get_assignment_lhs(ir->lhs, this, &r);
 
+   /* FINISHME: This should really set to the correct maximal writemask for each
+    * FINISHME: component written (in the loops below).  This case can only
+    * FINISHME: occur for matrices, arrays, and structures.
+    */
+   if (ir->write_mask == 0) {
+      assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector());
+      l.writemask = WRITEMASK_XYZW;
+   } else if (ir->lhs->type->is_scalar()) {
+      /* FINISHME: This hack makes writing to gl_FragData, which lives in the
+       * FINISHME: W component of fragment shader output zero, work correctly.
+       */
+      l.writemask = WRITEMASK_XYZW;
+   } else {
+      assert(ir->lhs->type->is_vector());
+      l.writemask = ir->write_mask;
+   }
+
    assert(l.file != PROGRAM_UNDEFINED);
    assert(r.file != PROGRAM_UNDEFINED);
 




More information about the mesa-commit mailing list