[Mesa-dev] [PATCH 3/5] glsl: struct constructors/initializers only allow implicit conversions

Timothy Arceri timothy.arceri at collabora.com
Thu Aug 4 22:35:27 UTC 2016


On Thu, 2016-08-04 at 23:55 +0300, Andres Gomez wrote:
> When an argument for a structure constructor or initializer doesn't
> match the expected type, only Section 4.1.10 “Implicit Conversions”
> are allowed to try to match that expected type.
> 
> From page 32 (page 38 of the PDF) of the GLSL 1.20 spec:
> 
>   " The arguments to the constructor will be used to set the
> structure's
>     fields, in order, using one argument per field. Each argument
> must
>     be the same type as the field it sets, or be a type that can be
>     converted to the field's type according to Section 4.1.10
> “Implicit
>     Conversions.”"
> 
> From page 35 (page 41 of the PDF) of the GLSL 4.20 spec:
> 
>   " In all cases, the innermost initializer (i.e., not a list of
>     initializers enclosed in curly braces) applied to an object must
>     have the same type as the object being initialized or be a type
> that
>     can be converted to the object's type according to section 4.1.10
>     "Implicit Conversions". In the latter case, an implicit
> conversion
>     will be done on the initializer before the assignment is done."
> 
> v2: Remove also the now redundant constant conversion, the
>     constant_record_constructor helper and the replacement code
>     (Timothy).
> 
> Fixes GL44-CTS.shading_language_420pack.initializer_list_negative
> 
> Signed-off-by: Andres Gomez <agomez at igalia.com>
> ---
>  src/compiler/glsl/ast_function.cpp | 104 ++++++++++++++++++++-------
> ----------
>  1 file changed, 55 insertions(+), 49 deletions(-)
> 
> diff --git a/src/compiler/glsl/ast_function.cpp
> b/src/compiler/glsl/ast_function.cpp
> index e30c70c..9b1fa45 100644
> --- a/src/compiler/glsl/ast_function.cpp
> +++ b/src/compiler/glsl/ast_function.cpp
> @@ -1161,24 +1161,6 @@ process_array_constructor(exec_list
> *instructions,
>  
>  
>  /**
> - * Try to convert a record constructor to a constant expression
> - */
> -static ir_constant *
> -constant_record_constructor(const glsl_type *constructor_type,
> -			    exec_list *parameters, void *mem_ctx)
> -{
> -   foreach_in_list(ir_instruction, node, parameters) {
> -      ir_constant *constant = node->as_constant();
> -      if (constant == NULL)
> -	 return NULL;
> -      node->replace_with(constant);
> -   }
> -
> -   return new(mem_ctx) ir_constant(constructor_type, parameters);
> -}
> -
> -
> -/**
>   * Determine if a list consists of a single scalar r-value
>   */
>  bool
> @@ -1709,53 +1691,77 @@ process_record_constructor(exec_list
> *instructions,
>                             struct _mesa_glsl_parse_state *state)
>  {
>     void *ctx = state;
> +   /* From page 32 (page 38 of the PDF) of the GLSL 1.20 spec:
> +    *
> +    *    "The arguments to the constructor will be used to set the
> structure's
> +    *     fields, in order, using one argument per field. Each
> argument must
> +    *     be the same type as the field it sets, or be a type that
> can be
> +    *     converted to the field's type according to Section 4.1.10
> “Implicit
> +    *     Conversions.”"
> +    *
> +    * From page 35 (page 41 of the PDF) of the GLSL 4.20 spec:
> +    *
> +    *    "In all cases, the innermost initializer (i.e., not a list
> of
> +    *     initializers enclosed in curly braces) applied to an
> object must
> +    *     have the same type as the object being initialized or be a
> type that
> +    *     can be converted to the object's type according to section
> 4.1.10
> +    *     "Implicit Conversions". In the latter case, an implicit
> conversion
> +    *     will be done on the initializer before the assignment is
> done."
> +    */
>     exec_list actual_parameters;
>  
> -   process_parameters(instructions, &actual_parameters,
> -                      parameters, state);
> +   const unsigned parameter_count =
> +         process_parameters(instructions, &actual_parameters,
> parameters,
> +                            state);
>  
> -   exec_node *node = actual_parameters.get_head_raw();
> -   for (unsigned i = 0; i < constructor_type->length; i++) {
> -      ir_rvalue *ir = (ir_rvalue *) node;
> +   if (parameter_count != constructor_type->length) {
> +      _mesa_glsl_error(loc, state,
> +                       "%s parameters in constructor for `%s'",
> +                       parameter_count > constructor_type->length
> +                       ? "too many": "insufficient",
> +                       constructor_type->name);
> +      return ir_rvalue::error_value(ctx);
> +   }

Thanks for you patience with this series :)  The parameter check above
is a nice cleanup too thanks. Patches 2 and 3 are:

Reviewed-by: Timothy Arceri <timothy.arceri at collabora.com>


>  
> -      if (node->is_tail_sentinel()) {
> -         _mesa_glsl_error(loc, state,
> -                          "insufficient parameters to constructor
> for `%s'",
> -                          constructor_type->name);
> -         return ir_rvalue::error_value(ctx);
> -      }
> +   bool all_parameters_are_constant = true;
>  
> -      if (apply_implicit_conversion(constructor_type-
> >fields.structure[i].type,
> -                                 ir, state)) {
> -         node->replace_with(ir);
> -      } else {
> +   int i = 0;
> +   /* Type cast each parameter and, if possible, fold constants. */
> +   foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) {
> +
> +      const glsl_struct_field *struct_field =
> +         &constructor_type->fields.structure[i];
> +
> +      /* Apply implicit conversions (not the scalar constructor
> rules, see the
> +       * spec quote above!) and attempt to convert the parameter to
> a constant
> +       * valued expression. After doing so, track whether or not all
> the
> +       * parameters to the constructor are trivially constant valued
> +       * expressions.
> +       */
> +      all_parameters_are_constant &=
> +         implicitly_convert_component(ir, struct_field->type-
> >base_type,
> +                                      state);
> +
> +      if (ir->type != struct_field->type) {
>           _mesa_glsl_error(loc, state,
>                            "parameter type mismatch in constructor
> for `%s.%s' "
>                            "(%s vs %s)",
>                            constructor_type->name,
> -                          constructor_type-
> >fields.structure[i].name,
> +                          struct_field->name,
>                            ir->type->name,
> -                          constructor_type-
> >fields.structure[i].type->name);
> +                          struct_field->type->name);
>           return ir_rvalue::error_value(ctx);
>        }
>  
> -      node = node->next;
> +      i++;
>     }
>  
> -   if (!node->is_tail_sentinel()) {
> -      _mesa_glsl_error(loc, state, "too many parameters in
> constructor "
> -                                    "for `%s'", constructor_type-
> >name);
> -      return ir_rvalue::error_value(ctx);
> +   if (all_parameters_are_constant) {
> +      return new(ctx) ir_constant(constructor_type,
> &actual_parameters);
> +   } else {
> +      return emit_inline_record_constructor(constructor_type,
> instructions,
> +                                            &actual_parameters,
> state);
>     }
> -
> -   ir_rvalue *const constant =
> -      constant_record_constructor(constructor_type,
> &actual_parameters,
> -                                  state);
> -
> -   return (constant != NULL)
> -            ? constant
> -            : emit_inline_record_constructor(constructor_type,
> instructions,
> -                                             &actual_parameters,
> state);
>  }
>  
>  ir_rvalue *


More information about the mesa-dev mailing list