glsl2: Emit structure constructors inline
authorIan Romanick <ian.d.romanick@intel.com>
Wed, 1 Sep 2010 20:46:04 +0000 (13:46 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 2 Sep 2010 03:39:09 +0000 (20:39 -0700)
Fixes piglit test cases glsl-[fv]s-all-0[12].

src/glsl/ast_function.cpp

index 1fa2fabefb9a090711a78e00f0b32dd084d4c21f..1cd300c382d6bb214411caacf52d63c160558637 100644 (file)
@@ -429,43 +429,14 @@ process_array_constructor(exec_list *instructions,
  */
 static ir_constant *
 constant_record_constructor(const glsl_type *constructor_type,
-                           YYLTYPE *loc, exec_list *parameters,
-                           struct _mesa_glsl_parse_state *state)
+                           exec_list *parameters, void *mem_ctx)
 {
-   void *ctx = state;
-   bool all_parameters_are_constant = true;
-
-   exec_node *node = parameters->head;
-   for (unsigned i = 0; i < constructor_type->length; i++) {
-      ir_instruction *ir = (ir_instruction *) node;
-
-      if (node->is_tail_sentinel()) {
-        _mesa_glsl_error(loc, state,
-                         "insufficient parameters to constructor for `%s'",
-                         constructor_type->name);
-        return NULL;
-      }
-
-      if (ir->type != constructor_type->fields.structure[i].type) {
-        _mesa_glsl_error(loc, state,
-                         "parameter type mismatch in constructor for `%s' "
-                         " (%s vs %s)",
-                         constructor_type->name,
-                         ir->type->name,
-                         constructor_type->fields.structure[i].type->name);
+   foreach_list(node, parameters) {
+      if (((ir_instruction *) node)->as_constant() == NULL)
         return NULL;
-      }
-
-      if (ir->as_constant() == NULL)
-        all_parameters_are_constant = false;
-
-      node = node->next;
    }
 
-   if (!all_parameters_are_constant)
-      return NULL;
-
-   return new(ctx) ir_constant(constructor_type, parameters);
+   return new(mem_ctx) ir_constant(constructor_type, parameters);
 }
 
 
@@ -948,6 +919,39 @@ emit_inline_matrix_constructor(const glsl_type *type,
 }
 
 
+ir_rvalue *
+emit_inline_record_constructor(const glsl_type *type,
+                              exec_list *instructions,
+                              exec_list *parameters,
+                              void *mem_ctx)
+{
+   ir_variable *const var =
+      new(mem_ctx) ir_variable(type, "record_ctor", ir_var_temporary);
+   ir_dereference_variable *const d = new(mem_ctx) ir_dereference_variable(var);
+
+   instructions->push_tail(var);
+
+   exec_node *node = parameters->head;
+   for (unsigned i = 0; i < type->length; i++) {
+      assert(!node->is_tail_sentinel());
+
+      ir_dereference *const lhs =
+        new(mem_ctx) ir_dereference_record(d->clone(mem_ctx, NULL),
+                                           type->fields.structure[i].name);
+
+      ir_rvalue *const rhs = ((ir_instruction *) node)->as_rvalue();
+      assert(rhs != NULL);
+
+      ir_instruction *const assign = new(mem_ctx) ir_assignment(lhs, rhs, NULL);
+
+      instructions->push_tail(assign);
+      node = node->next;
+   }
+
+   return d;
+}
+
+
 ir_rvalue *
 ast_function_expression::hir(exec_list *instructions,
                             struct _mesa_glsl_parse_state *state)
@@ -989,6 +993,7 @@ ast_function_expression::hir(exec_list *instructions,
                                          & loc, &this->expressions, state);
       }
 
+
       /* There are two kinds of constructor call.  Constructors for built-in
        * language types, such as mat4 and vec2, are free form.  The only
        * requirement is that the parameters must provide enough values of the
@@ -1176,11 +1181,39 @@ ast_function_expression::hir(exec_list *instructions,
         state->symbols->get_type(id->primary_expression.identifier);
 
       if ((type != NULL) && type->is_record()) {
-        ir_constant *constant =
-           constant_record_constructor(type, &loc, &actual_parameters, state);
+        exec_node *node = actual_parameters.head;
+        for (unsigned i = 0; i < type->length; i++) {
+           ir_instruction *ir = (ir_instruction *) node;
+
+           if (node->is_tail_sentinel()) {
+              _mesa_glsl_error(&loc, state,
+                               "insufficient parameters to constructor "
+                               "for `%s'",
+                               type->name);
+              return ir_call::get_error_instruction(ctx);
+           }
 
-        if (constant != NULL)
-           return constant;
+           if (ir->type != type->fields.structure[i].type) {
+              _mesa_glsl_error(&loc, state,
+                               "parameter type mismatch in constructor "
+                               "for `%s.%s' (%s vs %s)",
+                               type->name,
+                               type->fields.structure[i].name,
+                               ir->type->name,
+                               type->fields.structure[i].type->name);
+              return ir_call::get_error_instruction(ctx);;
+           }
+
+           node = node->next;
+        }
+
+        ir_rvalue *const constant =
+           constant_record_constructor(type, &actual_parameters, state);
+
+        return (constant != NULL)
+           ? constant
+           : emit_inline_record_constructor(type, instructions,
+                                            &actual_parameters, state);
       }
 
       return match_function_by_name(instructions,