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

Luca Barbieri lb at kemper.freedesktop.org
Wed Sep 8 02:42:16 UTC 2010


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

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_array_index_to_cond_assign.cpp |    2 +-
 src/glsl/ir_structure_splitting.cpp        |  149 ++++++++++++++++++++++------
 src/glsl/ir_validate.cpp                   |   23 +++--
 src/glsl/main.cpp                          |    3 +
 4 files changed, 137 insertions(+), 40 deletions(-)

diff --git a/src/glsl/ir_array_index_to_cond_assign.cpp b/src/glsl/ir_array_index_to_cond_assign.cpp
index 641168a..517c4c0 100644
--- a/src/glsl/ir_array_index_to_cond_assign.cpp
+++ b/src/glsl/ir_array_index_to_cond_assign.cpp
@@ -80,7 +80,7 @@ struct switch_generator
          test_indices = new(index) ir_constant(broadcast_index->type, &test_indices_data);
 
          ir_rvalue* condition_val = new(index) ir_expression(ir_binop_equal,
-                                                &glsl_type::bool_type[comps],
+                                                &glsl_type::bool_type[comps - 1],
                                                 broadcast_index,
                                                 test_indices);
          ir_variable* condition = new(index) ir_variable(&glsl_type::bool_type[comps], "dereference_array_condition", ir_var_temporary);
diff --git a/src/glsl/ir_structure_splitting.cpp b/src/glsl/ir_structure_splitting.cpp
index ff3ec93..1925067 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,9 @@ ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
 {
    assert(var);
 
-   if (!var->type->is_record() || var->mode == ir_var_uniform)
+   printf("stru %s\n", var->name);
+   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 +152,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 +220,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 +236,62 @@ 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
+      {
+         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: add an "undef" value to the ir and use it, or perhaps just kill base_ir directly */
+         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 +325,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,18 +405,39 @@ 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]);
       }
 
+      printf("SPLIT %s\n", entry->var->name);
       entry->var->remove();
    }
 
diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp
index b3ea566..de31ad7 100644
--- a/src/glsl/ir_validate.cpp
+++ b/src/glsl/ir_validate.cpp
@@ -283,6 +283,17 @@ ir_validate::visit_leave(ir_expression *ir)
    case ir_binop_min:
    case ir_binop_max:
    case ir_binop_pow:
+      if (ir->operands[0]->type->is_scalar())
+	 assert(ir->operands[1]->type == ir->type);
+      else if (ir->operands[1]->type->is_scalar())
+	 assert(ir->operands[0]->type == ir->type);
+      else if (ir->operands[0]->type->is_vector() &&
+	       ir->operands[1]->type->is_vector()) {
+	 assert(ir->operands[0]->type == ir->operands[1]->type);
+	 assert(ir->operands[0]->type == ir->type);
+      }
+      break;
+
    case ir_binop_less:
    case ir_binop_greater:
    case ir_binop_lequal:
@@ -293,15 +304,9 @@ ir_validate::visit_leave(ir_expression *ir)
        * IR we want to do them for vectors instead to support the
        * lessEqual() and friends builtins, and Mesa IR constructs
        */
-      if (ir->operands[0]->type->is_scalar())
-	 assert(ir->operands[1]->type == ir->type);
-      else if (ir->operands[1]->type->is_scalar())
-	 assert(ir->operands[0]->type == ir->type);
-      else if (ir->operands[0]->type->is_vector() &&
-	       ir->operands[1]->type->is_vector()) {
-	 assert(ir->operands[0]->type == ir->operands[1]->type);
-	 assert(ir->operands[0]->type == ir->type);
-      }
+      assert(ir->type->base_type == GLSL_TYPE_BOOL);
+      assert(ir->operands[0]->type == ir->operands[1]->type);
+      assert(ir->type->components() == ir->operands[0]->type->components());
       break;
 
    case ir_binop_all_equal:
diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp
index 8e73eb8..40c9781 100644
--- a/src/glsl/main.cpp
+++ b/src/glsl/main.cpp
@@ -180,6 +180,9 @@ compile_shader(struct gl_shader *shader)
 	 progress = set_loop_controls(shader->ir, ls) || progress;
 	 progress = unroll_loops(shader->ir, ls, 32) || progress;
 	 delete ls;
+
+	 progress = do_array_index_to_cond_assign(shader->ir) || progress;
+	 progress = do_structure_splitting(shader->ir) || progress;
       } while (progress);
 
       validate_ir_tree(shader->ir);




More information about the mesa-commit mailing list