nir: Add a "compact array" flag and IO lowering code.
[mesa.git] / src / compiler / glsl / opt_array_splitting.cpp
index a294da56616f8a6846f008b7813a601b77b79fde..e3073b022ca6aadeab2a8c4b74c5b07dad921995 100644 (file)
@@ -93,6 +93,7 @@ public:
    {
       this->mem_ctx = ralloc_context(NULL);
       this->variable_list.make_empty();
+      this->in_whole_array_copy = false;
    }
 
    ~ir_array_reference_visitor(void)
@@ -104,6 +105,8 @@ public:
 
    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 *);
 
@@ -113,6 +116,8 @@ public:
    exec_list variable_list;
 
    void *mem_ctx;
+
+   bool in_whole_array_copy;
 };
 
 } /* namespace */
@@ -157,11 +162,34 @@ ir_array_reference_visitor::visit(ir_variable *ir)
    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 *ir)
+{
+   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
@@ -350,6 +378,33 @@ ir_array_splitting_visitor::visit_leave(ir_assignment *ir)
     */
    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();