#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
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)
{
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)