summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/glsl/ir_structure_splitting.cpp54
1 files changed, 51 insertions, 3 deletions
diff --git a/src/glsl/ir_structure_splitting.cpp b/src/glsl/ir_structure_splitting.cpp
index 902eeadb2a4..f9931670bdf 100644
--- a/src/glsl/ir_structure_splitting.cpp
+++ b/src/glsl/ir_structure_splitting.cpp
@@ -80,7 +80,7 @@ public:
virtual ir_visitor_status visit(ir_variable *);
virtual ir_visitor_status visit(ir_dereference_variable *);
virtual ir_visitor_status visit_enter(ir_dereference_record *);
-
+ virtual ir_visitor_status visit_enter(ir_assignment *);
virtual ir_visitor_status visit_enter(ir_function_signature *);
variable_entry *get_variable_entry(ir_variable *var);
@@ -142,6 +142,19 @@ ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
}
ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
+{
+ if (ir->lhs->as_dereference_variable() &&
+ ir->rhs->as_dereference_variable() &&
+ !ir->condition) {
+ /* We'll split copies of a structure to copies of components, so don't
+ * descend to the ir_dereference_variables.
+ */
+ return visit_continue_with_parent;
+ }
+}
+
+ir_visitor_status
ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
{
/* We don't want to descend into the function parameters and
@@ -302,9 +315,44 @@ ir_structure_splitting_visitor::visit_leave(ir_dereference_record *ir)
ir_visitor_status
ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
{
- split_rvalue(&ir->rhs);
+ ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
+ ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
+ variable_entry *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
+ variable_entry *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
+ const glsl_type *type = ir->rhs->type;
+
+ if ((lhs_entry || rhs_entry) && !ir->condition) {
+ for (unsigned int i = 0; i < type->length; i++) {
+ ir_dereference *new_lhs, *new_rhs;
+ void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
+
+ if (lhs_entry) {
+ new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
+ } else {
+ new_lhs = new(mem_ctx)
+ ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
+ type->fields.structure[i].name);
+ }
+
+ if (rhs_entry) {
+ new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
+ } else {
+ new_rhs = new(mem_ctx)
+ ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
+ type->fields.structure[i].name);
+ }
+
+ ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
+ new_rhs,
+ NULL));
+ }
+ ir->remove();
+ } else {
+ split_rvalue(&ir->rhs);
+ split_deref(&ir->lhs);
+ }
+
split_rvalue(&ir->condition);
- split_deref(&ir->lhs);
return visit_continue;
}