[Mesa-dev] [PATCH 2/3] glsl_to_tgsi: Use a separate visitor to handle dereferences.

Vincent Lejeune vljn at ovi.com
Sat Jan 7 14:06:01 PST 2012


---
 src/mesa/state_tracker/st_glsl_to_tgsi.cpp |  375 +++++++++++++++++++---------
 1 files changed, 262 insertions(+), 113 deletions(-)

diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 2825180..ab93a65 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -526,6 +526,205 @@ variable_store::optimise_access(void)
    reindex_rvalue();
 }
 
+/**
+ * This visitor will retrieve offset and expression of indirect addressing
+ * from any ir_dereference*
+ */
+class glsl_to_tgsi_dereference_to_address : public ir_visitor {
+public:
+   ir_constant *possible_constant;
+   unsigned offset;
+   struct {
+      unsigned stride;
+      unsigned max_index;
+      ir_rvalue *expr;
+   } indirect_address_expression[8];
+   unsigned indirect_address_expression_count;
+   variable_store &store;
+   glsl_to_tgsi_dereference_to_address(variable_store&);
+   void* mem_ctx;
+   variable_storage *entry;
+
+   void visit(class ir_dereference_variable *);
+   void visit(class ir_dereference_array *);
+   void visit(class ir_dereference_record *);
+   void visit(class ir_constant *);
+
+   void visit(ir_variable *);
+   void visit(ir_function_signature *);
+   void visit(ir_function *);
+   void visit(ir_expression *);
+   void visit(ir_texture *);
+   void visit(ir_swizzle *);
+   void visit(ir_assignment *);
+   void visit(ir_call *);
+   void visit(ir_discard *);
+   void visit(ir_if *);
+   void visit(ir_loop *);
+   void visit(ir_loop_jump *);
+   void visit(ir_return *);
+};
+
+glsl_to_tgsi_dereference_to_address::glsl_to_tgsi_dereference_to_address(variable_store &s):possible_constant(NULL), indirect_address_expression_count(0), store(s), entry(NULL)
+{
+
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_variable *ir)
+{
+   entry = store.find_variable_storage(ir->var);
+   ir_variable *var = ir->var;
+
+   if (!entry) {
+      switch (var->mode) {
+      case ir_var_uniform:
+         entry = store.push(var, PROGRAM_UNIFORM, var->location);
+         break;
+      case ir_var_in:
+      case ir_var_inout:
+         /* The linker assigns locations for varyings and attributes,
+          * including deprecated builtins (like gl_Color), user-assign
+          * generic attributes (glBindVertexLocation), and
+          * user-defined varyings.
+          *
+          * FINISHME: We would hit this path for function arguments.  Fix!
+          */
+         assert(var->location != -1);
+         entry = store.push(var, PROGRAM_INPUT, var->location);
+         break;
+      case ir_var_out:
+         entry = store.push(var, PROGRAM_OUTPUT, var->location);
+         break;
+      case ir_var_system_value:
+         entry = store.push(var, PROGRAM_SYSTEM_VALUE, var->location);
+         break;
+      case ir_var_auto:
+      case ir_var_temporary:
+         entry = store.push(var);
+         break;
+      }
+   }
+
+   if (!entry) {
+      printf("Failed to make storage for %s\n", var->name);
+      exit(1);
+   }
+
+   offset = 0;
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_constant *ir)
+{
+   possible_constant = ir;
+   offset = 0;
+   return;
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_record *ir)
+{
+   unsigned int i;
+   const glsl_type *struct_type = ir->record->type;
+   ir->record->accept(this);
+
+   for (i = 0; i < struct_type->length; i++) {
+      if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
+         break;
+      offset += type_size(struct_type->fields.structure[i].type);
+   }
+   return;
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_array *ir)
+{
+   ir_constant *index;
+   int element_size = type_size(ir->type);
+   ir->array->accept(this);
+
+   index = ir->array_index->constant_expression_value();
+
+   if (index) {
+      offset += index->value.i[0] * element_size;
+   } else {
+      indirect_address_expression[indirect_address_expression_count].expr = ir->array_index;
+      indirect_address_expression[indirect_address_expression_count].stride = element_size;
+      if (ir->array->type->is_array()) {
+         indirect_address_expression[indirect_address_expression_count].max_index = ir->array->type->length;
+      }
+      else if (ir->array->type->is_matrix()) {
+         indirect_address_expression[indirect_address_expression_count].max_index = ir->array->type->components();
+      }
+
+      indirect_address_expression_count++;
+   }
+   return;
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_function *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_if *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_variable *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_discard *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_function_signature *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_expression *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_call *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_texture *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_loop *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_return *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_loop_jump *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_assignment *)
+{
+   assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_swizzle *)
+{
+   assert(0);
+}
+
+
 class glsl_to_tgsi_visitor : public ir_visitor {
 public:
    glsl_to_tgsi_visitor();
@@ -584,6 +783,8 @@ public:
    virtual void visit(ir_if *);
    /*@}*/
 
+   void handle_dereference(ir_dereference *);
+
    st_src_reg result;
 
    /** List of variable_storage */
@@ -2084,145 +2285,93 @@ glsl_to_tgsi_visitor::visit(ir_swizzle *ir)
 }
 
 void
-glsl_to_tgsi_visitor::visit(ir_dereference_variable *ir)
+glsl_to_tgsi_visitor::handle_dereference(ir_dereference *ir)
 {
-   variable_storage *entry = find_variable_storage(ir->var);
-   ir_variable *var = ir->var;
+   glsl_to_tgsi_dereference_to_address secondary_visitor(store);
+   secondary_visitor.mem_ctx = mem_ctx;
+   ir->accept(&secondary_visitor);
 
-   if (!entry) {
-      switch (var->mode) {
-      case ir_var_uniform:
-         entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM,
-        				       var->location);
-         this->variables.push_tail(entry);
-         break;
-      case ir_var_in:
-      case ir_var_inout:
-         /* The linker assigns locations for varyings and attributes,
-          * including deprecated builtins (like gl_Color), user-assign
-          * generic attributes (glBindVertexLocation), and
-          * user-defined varyings.
-          *
-          * FINISHME: We would hit this path for function arguments.  Fix!
-          */
-         assert(var->location != -1);
-         entry = new(mem_ctx) variable_storage(var,
-                                               PROGRAM_INPUT,
-                                               var->location);
-         break;
-      case ir_var_out:
-         assert(var->location != -1);
-         entry = new(mem_ctx) variable_storage(var,
-                                               PROGRAM_OUTPUT,
-                                               var->location);
-         break;
-      case ir_var_system_value:
-         entry = new(mem_ctx) variable_storage(var,
-                                               PROGRAM_SYSTEM_VALUE,
-                                               var->location);
-         break;
-      case ir_var_auto:
-      case ir_var_temporary:
-         entry = new(mem_ctx) variable_storage(var, PROGRAM_TEMPORARY,
-        				       this->next_temp);
-         this->variables.push_tail(entry);
-
-         next_temp += type_size(var->type);
-         break;
-      }
+   st_src_reg result;
+   if (secondary_visitor.possible_constant) {
+      secondary_visitor.possible_constant->accept(this);
+      result = this->result;
 
-      if (!entry) {
-         printf("Failed to make storage for %s\n", var->name);
-         exit(1);
-      }
+   }
+   else {
+      variable_storage *entry = secondary_visitor.entry;
+      result = st_src_reg(entry->file, entry->index, ir->type);
    }
 
-   this->result = st_src_reg(entry->file, entry->index, var->type);
-   if (!native_integers)
-      this->result.type = GLSL_TYPE_FLOAT;
-}
-
-void
-glsl_to_tgsi_visitor::visit(ir_dereference_array *ir)
-{
-   ir_constant *index;
-   st_src_reg src;
-   int element_size = type_size(ir->type);
-
-   index = ir->array_index->constant_expression_value();
-
-   ir->array->accept(this);
-   src = this->result;
-
-   if (index) {
-      src.index += index->value.i[0] * element_size;
-   } else {
-      /* Variable index array dereference.  It eats the "vec4" of the
-       * base of the array and an index that offsets the TGSI register
-       * index.
-       */
-      ir->array_index->accept(this);
+   result.index += secondary_visitor.offset;
 
+   if (secondary_visitor.indirect_address_expression_count > 0) {
       st_src_reg index_reg;
 
-      if (element_size == 1) {
-         index_reg = this->result;
-      } else {
-         index_reg = get_temp(native_integers ?
-                              glsl_type::int_type : glsl_type::float_type);
-
-         emit(ir, TGSI_OPCODE_MUL, st_dst_reg(index_reg),
-              this->result, st_src_reg_for_type(index_reg.type, element_size));
+      if(secondary_visitor.entry)
+         secondary_visitor.entry->is_reladdressed = true;
+      else {
+         /* This is an ugly hack that should be properly handled when variable_store will also store immediates*/
+         store.retrieve_anonymous_temp(result.index)->is_reladdressed = true;
       }
 
-      /* If there was already a relative address register involved, add the
-       * new and the old together to get the new offset.
-       */
-      if (src.reladdr != NULL) {
-         st_src_reg accum_reg = get_temp(native_integers ?
-                                glsl_type::int_type : glsl_type::float_type);
+      for (unsigned i = 0; i < secondary_visitor.indirect_address_expression_count; i++) {
+         secondary_visitor.indirect_address_expression[i].expr->accept(this);
+         unsigned element_size = secondary_visitor.indirect_address_expression[i].stride;
 
-         emit(ir, TGSI_OPCODE_ADD, st_dst_reg(accum_reg),
-              index_reg, *src.reladdr);
+         if (i == 0) {
+            if (element_size == 1) {
+               index_reg = this->result;
+            } else {
+               index_reg = store.get_temp(native_integers ?
+                                    glsl_type::int_type : glsl_type::float_type);
 
-         index_reg = accum_reg;
+               emit(ir, TGSI_OPCODE_MUL, st_dst_reg(index_reg),
+                    this->result, st_src_reg_for_type(index_reg.type, element_size));
+            }
+         }
+         else {
+            if (element_size == 1) {
+               emit(ir, TGSI_OPCODE_ADD, st_dst_reg(index_reg),
+                    index_reg, this->result);
+            }
+            else {
+               emit(ir, TGSI_OPCODE_UMAD, st_dst_reg(index_reg),
+                     this->result, st_src_reg_for_type(index_reg.type, element_size), index_reg);
+            }
+         }
       }
 
-      src.reladdr = ralloc(mem_ctx, st_src_reg);
-      memcpy(src.reladdr, &index_reg, sizeof(index_reg));
+      result.reladdr = ralloc(mem_ctx, st_src_reg);
+      *(result.reladdr) = st_src_reg(index_reg);
    }
 
+   this->result = result;
    /* If the type is smaller than a vec4, replicate the last channel out. */
    if (ir->type->is_scalar() || ir->type->is_vector())
-      src.swizzle = swizzle_for_size(ir->type->vector_elements);
+      this->result.swizzle = swizzle_for_size(ir->type->vector_elements);
    else
-      src.swizzle = SWIZZLE_NOOP;
+      this->result.swizzle = SWIZZLE_NOOP;
 
-   this->result = src;
+   if (!native_integers)
+      this->result.type = GLSL_TYPE_FLOAT;
 }
 
 void
-glsl_to_tgsi_visitor::visit(ir_dereference_record *ir)
+glsl_to_tgsi_visitor::visit(ir_dereference_variable *ir)
 {
-   unsigned int i;
-   const glsl_type *struct_type = ir->record->type;
-   int offset = 0;
-
-   ir->record->accept(this);
-
-   for (i = 0; i < struct_type->length; i++) {
-      if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
-         break;
-      offset += type_size(struct_type->fields.structure[i].type);
-   }
+   handle_dereference(ir);
+}
 
-   /* If the type is smaller than a vec4, replicate the last channel out. */
-   if (ir->type->is_scalar() || ir->type->is_vector())
-      this->result.swizzle = swizzle_for_size(ir->type->vector_elements);
-   else
-      this->result.swizzle = SWIZZLE_NOOP;
+void
+glsl_to_tgsi_visitor::visit(ir_dereference_array *ir)
+{
+   handle_dereference(ir);
+}
 
-   this->result.index += offset;
+void
+glsl_to_tgsi_visitor::visit(ir_dereference_record *ir)
+{
+   handle_dereference(ir);
 }
 
 /**
-- 
1.7.7



More information about the mesa-dev mailing list