glsl2: Handle plain variable copies in struct splitting.
authorEric Anholt <eric@anholt.net>
Mon, 9 Aug 2010 06:29:54 +0000 (23:29 -0700)
committerEric Anholt <eric@anholt.net>
Mon, 9 Aug 2010 06:45:58 +0000 (23:45 -0700)
glsl-fs-raytrace goes from 620 Mesa IR instructions out of the
compiler to 585.

src/glsl/ir_structure_splitting.cpp

index 902eeadb2a4538d5f5299640cae16b4180b9c974..f9931670bdf70bbe03dfb766319a2e2ab3573ce5 100644 (file)
@@ -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);
@@ -141,6 +141,19 @@ ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
    return visit_continue_with_parent;
 }
 
+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)
 {
@@ -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;
 }