{
this->mem_ctx = ralloc_context(NULL);
this->variable_list.make_empty();
+ this->in_whole_array_copy = false;
}
~ir_array_reference_visitor(void)
virtual ir_visitor_status visit(ir_variable *);
virtual ir_visitor_status visit(ir_dereference_variable *);
+ virtual ir_visitor_status visit_enter(ir_assignment *);
+ virtual ir_visitor_status visit_leave(ir_assignment *);
virtual ir_visitor_status visit_enter(ir_dereference_array *);
virtual ir_visitor_status visit_enter(ir_function_signature *);
exec_list variable_list;
void *mem_ctx;
+
+ bool in_whole_array_copy;
};
} /* namespace */
if (var->type->is_unsized_array())
return NULL;
+ /* FIXME: arrays of arrays are not handled correctly by this pass so we
+ * skip it for now. While the pass will create functioning code it actually
+ * produces worse code.
+ *
+ * For example the array:
+ *
+ * int[3][2] a;
+ *
+ * ends up being split up into:
+ *
+ * int[3][2] a_0;
+ * int[3][2] a_1;
+ * int[3][2] a_2;
+ *
+ * And we end up referencing each of these new arrays for example:
+ *
+ * a[0][1] will be turned into a_0[0][1]
+ * a[1][0] will be turned into a_1[1][0]
+ * a[2][0] will be turned into a_2[2][0]
+ */
+ if (var->type->is_array() && var->type->fields.array->is_array())
+ return NULL;
+
foreach_in_list(variable_entry, entry, &this->variable_list) {
if (entry->var == var)
return entry;
return visit_continue;
}
+ir_visitor_status
+ir_array_reference_visitor::visit_enter(ir_assignment *ir)
+{
+ in_whole_array_copy =
+ ir->lhs->type->is_array() && ir->whole_variable_written();
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_array_reference_visitor::visit_leave(ir_assignment *)
+{
+ in_whole_array_copy = false;
+
+ return visit_continue;
+}
+
ir_visitor_status
ir_array_reference_visitor::visit(ir_dereference_variable *ir)
{
variable_entry *entry = this->get_variable_entry(ir->var);
+ /* Allow whole-array assignments on the LHS. We can split those
+ * by "unrolling" the assignment into component-wise assignments.
+ */
+ if (in_assignee && in_whole_array_copy)
+ return visit_continue;
+
/* If we made it to here without seeing an ir_dereference_array,
* then the dereference of this array didn't have a constant index
* (see the visit_continue_with_parent below), so we can't split
*/
ir_rvalue *lhs = ir->lhs;
+ /* "Unroll" any whole array assignments, creating assignments for
+ * each array element. Then, do splitting on each new assignment.
+ */
+ if (lhs->type->is_array() && ir->whole_variable_written() &&
+ get_splitting_entry(ir->whole_variable_written())) {
+ void *mem_ctx = ralloc_parent(ir);
+
+ for (unsigned i = 0; i < lhs->type->length; i++) {
+ ir_rvalue *lhs_i =
+ new(mem_ctx) ir_dereference_array(ir->lhs->clone(mem_ctx, NULL),
+ new(mem_ctx) ir_constant(i));
+ ir_rvalue *rhs_i =
+ new(mem_ctx) ir_dereference_array(ir->rhs->clone(mem_ctx, NULL),
+ new(mem_ctx) ir_constant(i));
+ ir_rvalue *condition_i =
+ ir->condition ? ir->condition->clone(mem_ctx, NULL) : NULL;
+
+ ir_assignment *assign_i =
+ new(mem_ctx) ir_assignment(lhs_i, rhs_i, condition_i);
+
+ ir->insert_before(assign_i);
+ assign_i->accept(this);
+ }
+ ir->remove();
+ return visit_continue;
+ }
+
handle_rvalue(&lhs);
ir->lhs = lhs->as_dereference();
for (unsigned int i = 0; i < entry->size; i++) {
const char *name = ralloc_asprintf(mem_ctx, "%s_%d",
entry->var->name, i);
-
- entry->components[i] =
+ ir_variable *new_var =
new(entry->mem_ctx) ir_variable(subtype, name, ir_var_temporary);
+
+ /* Do not lose memory/format qualifiers when arrays of images are
+ * split.
+ */
+ new_var->data.memory_read_only = entry->var->data.memory_read_only;
+ new_var->data.memory_write_only = entry->var->data.memory_write_only;
+ new_var->data.memory_coherent = entry->var->data.memory_coherent;
+ new_var->data.memory_volatile = entry->var->data.memory_volatile;
+ new_var->data.memory_restrict = entry->var->data.memory_restrict;
+ new_var->data.image_format = entry->var->data.image_format;
+
+ entry->components[i] = new_var;
entry->var->insert_before(entry->components[i]);
}