[Mesa-dev] [PATCH 3/3] glsl: Perform implicit type conversions on function call out parameters.

Ian Romanick idr at freedesktop.org
Tue Aug 2 18:27:46 PDT 2011


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/02/2011 05:38 PM, Paul Berry wrote:
> When an out parameter undergoes an implicit type conversion, we need
> to store it in a temporary, and then after the call completes, convert
> the resulting value.  In other words, we convert code like the
> following:
> 
> void f(out int x);
> float value;
> f(value);
> 
> Into IR that's equivalent to this:
> 
> void f(out int x);
> float value;
> int x_converted;
> f(x_converted);
> value = float(x_converted);
> 
> This transformation needs to happen during ast-to-IR convertion (as
> opposed to, say, a lowering pass), because it is invalid IR for formal
> and actual parameters to have types that don't match.

I want to digest this code a bit more, but I have a couple minor
comments below.

> Fixes piglit tests spec/glsl-1.20/compiler/qualifiers/out-03.vert and
> spec/glsl-1.20/execution/qualifiers/vs-out-{01,02,03}.shader_test, and
> bug 39651.
> 
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=39651
> ---
>  src/glsl/ast_function.cpp |   64 +++++++++++++++++++++++++++++++++++++++++---
>  1 files changed, 59 insertions(+), 5 deletions(-)
> 
> diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
> index 8bcf48d..f945a94 100644
> --- a/src/glsl/ast_function.cpp
> +++ b/src/glsl/ast_function.cpp
> @@ -134,6 +134,8 @@ match_function_by_name(exec_list *instructions, const char *name,
>        }
>     }
>  
> +   exec_list post_call_conversions;
> +
>     if (sig != NULL) {
>        /* Verify that 'out' and 'inout' actual parameters are lvalues.  This
>         * isn't done in ir_function::matching_signature because that function
> @@ -141,6 +143,13 @@ match_function_by_name(exec_list *instructions, const char *name,
>         *
>         * Also, validate that 'const_in' formal parameters (an extension of our
>         * IR) correspond to ir_constant actual parameters.
> +       *
> +       * Also, perform implicit conversion of arguments.  Note: to
> +       * implicitly convert out parameters, we need to place them in a
> +       * temporary variable, and do the conversion after the call
> +       * takes place.  Since we haven't emitted the call yet, we'll
> +       * place the post-call conversions in a temporary exec_list, and
> +       * emit them later.

It looks like this comment (and the others below) are wrapped to much
less than 80 columns.

>         */
>        exec_list_iterator actual_iter = actual_parameters->iterator();
>        exec_list_iterator formal_iter = sig->parameters.iterator();
> @@ -185,8 +194,50 @@ match_function_by_name(exec_list *instructions, const char *name,
>  	 }
>  
>  	 if (formal->type->is_numeric() || formal->type->is_boolean()) {
> -	    ir_rvalue *converted = convert_component(actual, formal->type);
> -	    actual->replace_with(converted);
> +            switch (formal->mode) {
> +            case ir_var_in:
> +               {

The { should be on the same line as the case, and emacs got the
indentation wonkey because it's not.

> +                  ir_rvalue *converted
> +                     = convert_component(actual, formal->type);
> +                  actual->replace_with(converted);
> +               }
> +               break;
> +            case ir_var_out:
> +               if (actual->type != formal->type)
> +               {

The { should be on the same line as the if.

> +                  /* Create a temporary variable to hold the out
> +                   * parameter.  Don't pass a hashtable to clone()
> +                   * because we don't want this temporary variable to
> +                   * be in scope.
> +                   */
> +                  ir_variable *tmp = formal->clone(ctx, NULL);
> +                  tmp->mode = ir_var_auto;

ir_var_auto is only used for user-defined variables, and
ir_var_temporary is used for compiler-generated variables.  We'd also
usually do something like:

    ir_variable *tmp =
        new(mem_ctx) ir_variable(formal->type,
                                 "out_parameter_conversion",
                                 ir_var_temporary);

Giving it a name like that makes the origin of the variable clear in
shader dumps.  This has proven to be an invaluable debugging tool.

> +                  instructions->push_tail(tmp);
> +                  ir_dereference_variable *deref_tmp_1
> +                     = new(ctx) ir_dereference_variable(tmp);
> +                  ir_dereference_variable *deref_tmp_2
> +                     = new(ctx) ir_dereference_variable(tmp);
> +                  ir_rvalue *converted_tmp
> +                     = convert_component(deref_tmp_1, actual->type);
> +                  ir_assignment *assignment
> +                     = new(ctx) ir_assignment(actual, converted_tmp);
> +                  post_call_conversions.push_tail(assignment);
> +                  actual->replace_with(deref_tmp_2);
> +               }
> +               break;
> +            case ir_var_inout:
> +               /* Inout parameters should never require conversion,
> +                * since that would require an implicit conversion to
> +                * exist both to and from the formal parameter type,
> +                * and there are no bidirectional implicit
> +                * conversions.
> +                */
> +               assert (actual->type == formal->type);
> +               break;
> +            default:
> +               assert (!"Illegal formal parameter mode");
> +               break;
> +            }
>  	 }
>  
>  	 actual_iter.next();
> @@ -196,11 +247,13 @@ match_function_by_name(exec_list *instructions, const char *name,
>        /* Always insert the call in the instruction stream, and return a deref
>         * of its return val if it returns a value, since we don't know if
>         * the rvalue is going to be assigned to anything or not.
> +       *
> +       * Also insert any out parameter conversions after the call.
>         */
>        ir_call *call = new(ctx) ir_call(sig, actual_parameters);
> +      ir_dereference_variable *deref;
>        if (!sig->return_type->is_void()) {
>  	 ir_variable *var;
> -	 ir_dereference_variable *deref;
>  
>  	 var = new(ctx) ir_variable(sig->return_type,
>  				    ralloc_asprintf(ctx, "%s_retval",
> @@ -215,11 +268,12 @@ match_function_by_name(exec_list *instructions, const char *name,
>  	    var->constant_value = call->constant_expression_value();
>  
>  	 deref = new(ctx) ir_dereference_variable(var);
> -	 return deref;
>        } else {
>  	 instructions->push_tail(call);
> -	 return NULL;
> +	 deref = NULL;
>        }
> +      instructions->append_list(&post_call_conversions);
> +      return deref;
>     } else {
>        char *str = prototype_string(NULL, name, actual_parameters);
>  

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAk44pBIACgkQX1gOwKyEAw+8cQCdEHeiCWoywUnYtcr+DYuknNNQ
D30An1q/wyBD1Y7nRiCjw7RmYHTpGZjE
=Vh6j
-----END PGP SIGNATURE-----


More information about the mesa-dev mailing list