[Mesa-dev] [PATCH] glsl: Fix handling of array dereferences of vectors in opt_dead_code_local

Ian Romanick idr at freedesktop.org
Tue Jan 29 18:52:08 PST 2013


From: Ian Romanick <ian.d.romanick at intel.com>

Three parts to the fix:

1. If the array dereference is a constant index, figure out the real
write mask.

2. If the array dereference not is a constant index, assume the
assignment may generate any component.

3. If the array dereference not is a constant index, assume the
assigment will not kill any previous component write.

Signed-off-by: Ian Romanick <ian.d.romanick at intel.com>
Cc: Chris Wolfe <cwolfe at chromium.org>
Cc: Eric Anholt <eric at anholt.net>
Cc: Kenneth Graunke <kenneth at whitecape.org>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=53256
---
 src/glsl/opt_dead_code_local.cpp | 82 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 5 deletions(-)

diff --git a/src/glsl/opt_dead_code_local.cpp b/src/glsl/opt_dead_code_local.cpp
index 8c31802..aa2911a 100644
--- a/src/glsl/opt_dead_code_local.cpp
+++ b/src/glsl/opt_dead_code_local.cpp
@@ -38,10 +38,73 @@
 #include "ir_optimization.h"
 #include "glsl_types.h"
 
-static bool debug = false;
+static bool debug = true;
 
 namespace {
 
+static bool
+is_array_deref_of_vector(ir_rvalue *ir)
+{
+   if (ir->ir_type == ir_type_dereference_array) {
+      ir_dereference_array *const d = ir->as_dereference_array();
+
+      assert(d != NULL);
+      return d->array->type->is_vector();
+   }
+
+   return false;
+}
+
+/**
+ * Get the mask that may be generated by an assignment
+ *
+ * If the LHS of the assignment is anything other than an array dereference of
+ * a vector, the \c write_mask of the assignment is returned.  If the LHS of
+ * the assignment is an array dereference, the write mask is a lie.  The
+ * actual write mask is determined by the array index.  If the array index is
+ * a constant, calculate the mask from that constant.
+ *
+ * If the index is not a constant, the function can operation in one of two
+ * modes.  In the first mode, when \c want_availability_mask is \c true, it is
+ * assumed that any field of the vector may be written.  This is used when
+ * adding an assignment to the assignment list.  In the second mode, when
+ * \c want_availability_mask is \c false, it is assumed that no fields of the
+ * vector are written.  This is used when trying to remove earlier assignments
+ * from the list.
+ */
+static int
+may_set_mask(ir_assignment *ir, bool want_availability_mask)
+{
+   int mask = ir->write_mask;
+
+   /* If the LHS is an array derefernce of a vector, try to figure out what
+    * the real write mask is.  If the index is not a constant, assume that any
+    * element may be written.
+    */
+   if (is_array_deref_of_vector(ir->lhs)) {
+      ir_dereference_array *const d = ir->lhs->as_dereference_array();
+      ir_constant *const c = d->array_index->as_constant();
+
+      if (c != NULL) {
+         const int idx = (c != NULL) ? c->get_uint_component(0) : -1;
+
+         if (idx >= 0 && idx <= 3)
+            mask = 1U << idx;
+         else
+            mask = 0;
+      } else {
+         /* Set the write-mask depending on the size of the vector.
+          */
+         if (want_availability_mask)
+            mask = (1U << d->array->type->vector_components()) - 1;
+         else
+            mask = 0;
+      }
+   }
+
+   return mask;
+}
+
 class assignment_entry : public exec_node
 {
 public:
@@ -51,7 +114,7 @@ public:
       assert(ir);
       this->lhs = lhs;
       this->ir = ir;
-      this->available = ir->write_mask;
+      this->available = may_set_mask(ir, true);
    }
 
    ir_variable *lhs;
@@ -185,7 +248,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
 	    if (entry->lhs != var)
 	       continue;
 
-	    int remove = entry->available & ir->write_mask;
+            int remove = entry->available & may_set_mask(ir, false);
 	    if (debug) {
 	       printf("%s 0x%01x - 0x%01x = 0x%01x\n",
 		      var->name,
@@ -201,13 +264,22 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
 		  printf("\n");
 	       }
 
-	       entry->ir->write_mask &= ~remove;
 	       entry->available &= ~remove;
-	       if (entry->ir->write_mask == 0) {
+               if (entry->available == 0) {
 		  /* Delete the dead assignment. */
 		  entry->ir->remove();
 		  entry->remove();
 	       } else {
+                  /* If the LHS of the assignment is an array dereference of a
+                   * vector, give up.  It's either a constant index (that will
+                   * be lowered to a regular write-mask before trying this
+                   * optimization pass again), or it's a variable index (that
+                   * can't have its write-mask reduced).
+                   */
+                  if (is_array_deref_of_vector(entry->ir->lhs))
+                     continue;
+
+                  entry->ir->write_mask &= ~remove;
 		  void *mem_ctx = ralloc_parent(entry->ir);
 		  /* Reswizzle the RHS arguments according to the new
 		   * write_mask.
-- 
1.7.11.7



More information about the mesa-dev mailing list