glsl: fix the type of ir_constant_data::u16
[mesa.git] / src / compiler / glsl / ir_array_refcount.cpp
index 7627fa13bd228c86f7c969877802703164777f8d..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
@@ -76,54 +75,6 @@ ir_array_refcount_entry::~ir_array_refcount_entry()
    delete [] bits;
 }
 
-
-void
-ir_array_refcount_entry::mark_array_elements_referenced(const array_deref_range *dr,
-                                                        unsigned count)
-{
-   if (count != array_depth)
-      return;
-
-   mark_array_elements_referenced(dr, count, 1, 0);
-}
-
-void
-ir_array_refcount_entry::mark_array_elements_referenced(const array_deref_range *dr,
-                                                        unsigned count,
-                                                        unsigned scale,
-                                                        unsigned linearized_index)
-{
-   /* Walk through the list of array dereferences in least- to
-    * most-significant order.  Along the way, accumulate the current
-    * linearized offset and the scale factor for each array-of-.
-    */
-   for (unsigned i = 0; i < count; i++) {
-      if (dr[i].index < dr[i].size) {
-         linearized_index += dr[i].index * scale;
-         scale *= dr[i].size;
-      } else {
-         /* For each element in the current array, update the count and
-          * offset, then recurse to process the remaining arrays.
-          *
-          * There is some inefficency here if the last element in the
-          * array_deref_range list specifies the entire array.  In that case,
-          * the loop will make recursive calls with count == 0.  In the call,
-          * all that will happen is the bit will be set.
-          */
-         for (unsigned j = 0; j < dr[i].size; j++) {
-            mark_array_elements_referenced(&dr[i + 1],
-                                           count - (i + 1),
-                                           scale * dr[i].size,
-                                           linearized_index + (j * scale));
-         }
-
-         return;
-      }
-   }
-
-   BITSET_SET(bits, linearized_index);
-}
-
 ir_array_refcount_entry *
 ir_array_refcount_visitor::get_variable_entry(ir_variable *var)
 {
@@ -159,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)