glsl: fix the type of ir_constant_data::u16
[mesa.git] / src / compiler / glsl / ir_array_refcount.cpp
index 1b5c43c9927f976db9d63427c24da75a2aace002..0c18c7e0ecf143c3e24e30506f779751b8208e16 100644 (file)
 #include "util/hash_table.h"
 
 ir_array_refcount_visitor::ir_array_refcount_visitor()
-   : derefs(0), num_derefs(0), derefs_size(0)
+   : last_array_deref(0), derefs(0), num_derefs(0), derefs_size(0)
 {
    this->mem_ctx = ralloc_context(NULL);
-   this->ht = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
-                                      _mesa_key_pointer_equal);
+   this->ht = _mesa_pointer_hash_table_create(NULL);
 }
 
 static void
@@ -60,6 +59,14 @@ ir_array_refcount_entry::ir_array_refcount_entry(ir_variable *var)
    num_bits = MAX2(1, var->type->arrays_of_arrays_size());
    bits = new BITSET_WORD[BITSET_WORDS(num_bits)];
    memset(bits, 0, BITSET_WORDS(num_bits) * sizeof(bits[0]));
+
+   /* Count the "depth" of the arrays-of-arrays. */
+   array_depth = 0;
+   for (const glsl_type *type = var->type;
+        type->is_array();
+        type = type->fields.array) {
+      array_depth++;
+   }
 }
 
 
@@ -68,7 +75,6 @@ ir_array_refcount_entry::~ir_array_refcount_entry()
    delete [] bits;
 }
 
-
 ir_array_refcount_entry *
 ir_array_refcount_visitor::get_variable_entry(ir_variable *var)
 {
@@ -104,6 +110,79 @@ ir_array_refcount_visitor::get_array_deref()
    return d;
 }
 
+ir_visitor_status
+ir_array_refcount_visitor::visit_enter(ir_dereference_array *ir)
+{
+   /* It could also be a vector or a matrix.  Individual elements of vectors
+    * are natrices are not tracked, so bail.
+    */
+   if (!ir->array->type->is_array())
+      return visit_continue;
+
+   /* If this array dereference is a child of an array dereference that was
+    * already visited, just continue on.  Otherwise, for an arrays-of-arrays
+    * dereference like x[1][2][3][4], we'd process the [1][2][3][4] sequence,
+    * the [1][2][3] sequence, the [1][2] sequence, and the [1] sequence.  This
+    * ensures that we only process the full sequence.
+    */
+   if (last_array_deref && last_array_deref->array == ir) {
+      last_array_deref = ir;
+      return visit_continue;
+   }
+
+   last_array_deref = ir;
+
+   num_derefs = 0;
+
+   ir_rvalue *rv = ir;
+   while (rv->ir_type == ir_type_dereference_array) {
+      ir_dereference_array *const deref = rv->as_dereference_array();
+
+      assert(deref != NULL);
+      assert(deref->array->type->is_array());
+
+      ir_rvalue *const array = deref->array;
+      const ir_constant *const idx = deref->array_index->as_constant();
+      array_deref_range *const dr = get_array_deref();
+
+      dr->size = array->type->array_size();
+
+      if (idx != NULL) {
+         dr->index = idx->get_int_component(0);
+      } else {
+         /* An unsized array can occur at the end of an SSBO.  We can't track
+          * accesses to such an array, so bail.
+          */
+         if (array->type->array_size() == 0)
+            return visit_continue;
+
+         dr->index = dr->size;
+      }
+
+      rv = array;
+   }
+
+   ir_dereference_variable *const var_deref = rv->as_dereference_variable();
+
+   /* If the array being dereferenced is not a variable, bail.  At the very
+    * least, ir_constant and ir_dereference_record are possible.
+    */
+   if (var_deref == NULL)
+      return visit_continue;
+
+   ir_array_refcount_entry *const entry =
+      this->get_variable_entry(var_deref->var);
+
+   if (entry == NULL)
+      return visit_stop;
+
+   link_util_mark_array_elements_referenced(derefs, num_derefs,
+                                            entry->array_depth,
+                                            entry->bits);
+
+   return visit_continue;
+}
+
 
 ir_visitor_status
 ir_array_refcount_visitor::visit(ir_dereference_variable *ir)