glsl: Update deref types when resizing implicitly sized arrays.
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 2 Nov 2016 20:35:30 +0000 (13:35 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 3 Nov 2016 08:42:37 +0000 (01:42 -0700)
At link time, we resolve the size of implicitly sized arrays.
When doing so, we update the type of the ir_variables.  However,
we neglected to update the type of ir_dereference nodes which
reference those variables.

It turns out array_resize_visitor (for GS/TCS/TES interface array
handling) already did 2/3 of the cases for this, so we can simply
refactor the code and reuse it.

This fixes:
GL45-CTS.shader_storage_buffer_object.basic-syntax
GL45-CTS.shader_storage_buffer_object.basic-syntaxSSO

which have an SSBO containing an implicitly sized array, followed
by some other members.  setup_buffer_access uses the dereference
types to compute offsets to fields, and it had a stale type where
the implicitly sized array's length was still 0 instead of the
actual length.

While we're here, we can also fix update_array_sizes to properly
update deref types as well, fixing a FINISHME from 2010.

Cc: mesa-stable@lists.freedesktop.org
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Timothy Arceri <timothy.arceri@collabora.com>
src/compiler/glsl/linker.cpp

index 463c1f6c21f029da01677845ef2356962cc7c9ae..aceea8d520e547607a26462018dede65edebff42 100644 (file)
@@ -181,7 +181,43 @@ private:
 };
 
 
-class array_resize_visitor : public ir_hierarchical_visitor {
+/**
+ * A visitor helper that provides methods for updating the types of
+ * ir_dereferences.  Classes that update variable types (say, updating
+ * array sizes) will want to use this so that dereference types stay in sync.
+ */
+class deref_type_updater : public ir_hierarchical_visitor {
+public:
+   virtual ir_visitor_status visit(ir_dereference_variable *ir)
+   {
+      ir->type = ir->var->type;
+      return visit_continue;
+   }
+
+   virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
+   {
+      const glsl_type *const vt = ir->array->type;
+      if (vt->is_array())
+         ir->type = vt->fields.array;
+      return visit_continue;
+   }
+
+   virtual ir_visitor_status visit_leave(ir_dereference_record *ir)
+   {
+      for (unsigned i = 0; i < ir->record->type->length; i++) {
+         const struct glsl_struct_field *field =
+            &ir->record->type->fields.structure[i];
+         if (strcmp(field->name, ir->field) == 0) {
+            ir->type = field->type;
+            break;
+         }
+      }
+      return visit_continue;
+   }
+};
+
+
+class array_resize_visitor : public deref_type_updater {
 public:
    unsigned num_vertices;
    gl_shader_program *prog;
@@ -240,24 +276,6 @@ public:
 
       return visit_continue;
    }
-
-   /* Dereferences of input variables need to be updated so that their type
-    * matches the newly assigned type of the variable they are accessing. */
-   virtual ir_visitor_status visit(ir_dereference_variable *ir)
-   {
-      ir->type = ir->var->type;
-      return visit_continue;
-   }
-
-   /* Dereferences of 2D input arrays need to be updated so that their type
-    * matches the newly assigned type of the array they are accessing. */
-   virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
-   {
-      const glsl_type *const vt = ir->array->type;
-      if (vt->is_array())
-         ir->type = vt->fields.array;
-      return visit_continue;
-   }
 };
 
 /**
@@ -1361,7 +1379,7 @@ move_non_declarations(exec_list *instructions, exec_node *last,
  * it inside that function leads to compiler warnings with some versions of
  * gcc.
  */
-class array_sizing_visitor : public ir_hierarchical_visitor {
+class array_sizing_visitor : public deref_type_updater {
 public:
    array_sizing_visitor()
       : mem_ctx(ralloc_context(NULL)),
@@ -2283,6 +2301,8 @@ update_array_sizes(struct gl_shader_program *prog)
          if (prog->_LinkedShaders[i] == NULL)
             continue;
 
+      bool types_were_updated = false;
+
       foreach_in_list(ir_instruction, node, prog->_LinkedShaders[i]->ir) {
          ir_variable *const var = node->as_variable();
 
@@ -2338,11 +2358,15 @@ update_array_sizes(struct gl_shader_program *prog)
 
             var->type = glsl_type::get_array_instance(var->type->fields.array,
                                                       size + 1);
-            /* FINISHME: We should update the types of array
-             * dereferences of this variable now.
-             */
+            types_were_updated = true;
          }
       }
+
+      /* Update the types of dereferences in case we changed any. */
+      if (types_were_updated) {
+         deref_type_updater v;
+         v.run(prog->_LinkedShaders[i]->ir);
+      }
    }
 }