Mesa (shader-work): glsl: teach structure splitting to split arrays, and never split in/outs

Luca Barbieri lb at kemper.freedesktop.org
Tue Sep 14 02:30:47 UTC 2010


Module: Mesa
Branch: shader-work
Commit: 058df122e3c039f4875e9480c7f23c1123a1f630
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=058df122e3c039f4875e9480c7f23c1123a1f630

Author: Luca Barbieri <luca at luca-barbieri.com>
Date:   Wed Sep  8 03:47:58 2010 +0200

glsl: teach structure splitting to split arrays, and never split in/outs

Currently structure splitting cannot split arrays, which makes
do_array_index_to_cond_assign useless.

This commit adds that capability.

Also, it prevents it from splitting in/out/inout variables, which were
incorrectly split.

It may be possible to split them if user-defined, but that will need
further changes and some way to make sure we link stages correctly.

---

 src/glsl/ir_structure_splitting.cpp |  143 +++++++++++++++++++++++++++-------
 1 files changed, 113 insertions(+), 30 deletions(-)

diff --git a/src/glsl/ir_structure_splitting.cpp b/src/glsl/ir_structure_splitting.cpp
index ff3ec93..807d447 100644
--- a/src/glsl/ir_structure_splitting.cpp
+++ b/src/glsl/ir_structure_splitting.cpp
@@ -86,6 +86,7 @@ public:
    virtual ir_visitor_status visit(ir_variable *);
    virtual ir_visitor_status visit(ir_dereference_variable *);
    virtual ir_visitor_status visit_enter(ir_dereference_record *);
+   virtual ir_visitor_status visit_enter(ir_dereference_array *);
    virtual ir_visitor_status visit_enter(ir_assignment *);
    virtual ir_visitor_status visit_enter(ir_function_signature *);
 
@@ -102,7 +103,8 @@ ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
 {
    assert(var);
 
-   if (!var->type->is_record() || var->mode == ir_var_uniform)
+   if ((!var->type->is_record() && !var->type->is_array())
+         || (var->mode != ir_var_auto && var->mode != ir_var_temporary))
       return NULL;
 
    foreach_iter(exec_list_iterator, iter, this->variable_list) {
@@ -149,6 +151,25 @@ ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
 }
 
 ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_dereference_array *ir)
+{
+   ir->array_index->accept(this);
+   if(!ir->array_index->as_constant())
+   {
+      /* FINISHME: could produce and make use of information
+       * about possible values of the index
+       */
+      ir_variable *const var = ir->array->variable_referenced();
+      variable_entry2 *entry = this->get_variable_entry2(var);
+
+      if (entry)
+         entry->whole_structure_access++;
+   }
+
+   /* Don't descend into the ir_dereference_variable below. */
+   return visit_continue_with_parent;
+}
+ir_visitor_status
 ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
 {
    if (ir->lhs->as_dereference_variable() &&
@@ -198,7 +219,7 @@ ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
 {
    assert(var);
 
-   if (!var->type->is_record())
+   if (!var->type->is_record() && !var->type->is_array())
       return NULL;
 
    foreach_iter(exec_list_iterator, iter, *this->variable_list) {
@@ -214,27 +235,61 @@ ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
 void
 ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
 {
-   if ((*deref)->ir_type != ir_type_dereference_record)
-      return;
-
-   ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
-   ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
-   if (!deref_var)
-      return;
-
-   variable_entry2 *entry = get_splitting_entry(deref_var->var);
-   if (!entry)
-      return;
+   if ((*deref)->ir_type == ir_type_dereference_record)
+   {
+      ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
+      ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
+      if (!deref_var)
+         return;
+
+      variable_entry2 *entry = get_splitting_entry(deref_var->var);
+      if (!entry)
+         return;
+
+      unsigned int i;
+      for (i = 0; i < entry->var->type->length; i++) {
+         if (strcmp(deref_record->field,
+                    entry->var->type->fields.structure[i].name) == 0)
+            break;
+      }
+      assert(i != entry->var->type->length);
 
-   unsigned int i;
-   for (i = 0; i < entry->var->type->length; i++) {
-      if (strcmp(deref_record->field,
-		 entry->var->type->fields.structure[i].name) == 0)
-	 break;
+      *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
+   }
+   else if ((*deref)->ir_type == ir_type_dereference_array)
+   {
+      ir_dereference_array *deref_array = (ir_dereference_array*)*deref;
+      ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable();
+      if (!deref_var)
+         return;
+
+      variable_entry2 *entry = get_splitting_entry(deref_var->var);
+      if (!entry)
+         return;
+
+      ir_constant* index = deref_array->array_index->as_constant();
+      assert(index);
+      assert(index->type->is_scalar());
+      assert(index->type->base_type == GLSL_TYPE_INT || index->type->base_type == GLSL_TYPE_UINT);
+
+      unsigned i = index->value.u[0];
+      if(i < (unsigned)deref_var->var->type->length)
+      {
+         *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
+      } else {
+         /* FINISHME: is it ok to use a never-assigned variable this way? ... */
+         ir_variable* undef = new(entry->mem_ctx) ir_variable((*deref)->type, "undef", ir_var_temporary);
+         base_ir->insert_before(undef);
+         *deref = new(entry->mem_ctx) ir_dereference_variable(undef);
+#if 0
+         /* FINISHME: ... or should we do this? */
+         if(type->is_numeric() || type->is_boolean())
+            *deref = ir_constant::zero(entry->mem_ctx, (*deref)->type);
+         else
+            *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[0]);
+#endif
+      }
    }
-   assert(i != entry->var->type->length);
-
-   *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
 }
 
 void
@@ -268,19 +323,30 @@ ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
 
 	 if (lhs_entry) {
 	    new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
-	 } else {
+	 } else if(type->is_record()) {
 	    new_lhs = new(mem_ctx)
 	       ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
 				     type->fields.structure[i].name);
-	 }
+	 } else if(type->is_array()) {
+	    new_lhs = new(mem_ctx)
+               ir_dereference_array(ir->lhs->clone(mem_ctx, NULL),
+	                            new(mem_ctx) ir_constant((int)i));
+	 } else
+	    assert(0);
 
 	 if (rhs_entry) {
 	    new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
-	 } else {
+	 } else if(type->is_record()){
 	    new_rhs = new(mem_ctx)
 	       ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
 				     type->fields.structure[i].name);
-	 }
+         } else if(type->is_array()) {
+            new_rhs = new(mem_ctx)
+               ir_dereference_array(ir->rhs->clone(mem_ctx, NULL),
+                                    new(mem_ctx) ir_constant((int)i));
+         } else
+            assert(0);
+
 
 	 ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
 						      new_rhs,
@@ -337,15 +403,32 @@ do_structure_splitting(exec_list *instructions)
 				       ir_variable *,
 				       type->length);
 
+      /* FINISHME: create these on demand */
       for (unsigned int i = 0; i < entry->var->type->length; i++) {
-	 const char *name = talloc_asprintf(mem_ctx, "%s_%s",
+	 const char *name;
+
+	 if(type->is_record()) {
+	    name = talloc_asprintf(mem_ctx, "%s_%s",
 					    entry->var->name,
 					    type->fields.structure[i].name);
 
-	 entry->components[i] =
-	    new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
-					    name,
-					    ir_var_temporary);
+	    entry->components[i] =
+	          new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
+	                name,
+	                ir_var_temporary);
+	 } else if(type->is_array()) {
+	    name = talloc_asprintf(mem_ctx, "%s_%i",
+	                                                entry->var->name,
+	                                                i);
+
+	    entry->components[i] =
+	          new(entry->mem_ctx) ir_variable(type->fields.array,
+	                name,
+	                ir_var_temporary);
+	 }
+	 else
+	    assert(0);
+
 	 entry->var->insert_before(entry->components[i]);
       }
 




More information about the mesa-commit mailing list