[Mesa-dev] [PATCH 2/3] glsl: Split code to generate an ir_call out from match_function_by_name.

Kenneth Graunke kenneth at whitecape.org
Fri Nov 11 02:56:15 PST 2011


match_function_by_name performs two fairly separate tasks:
1. Hunt down the appropriate ir_function_signature for the callee.
2. Generate the actual ir_call (assuming we found the callee).

Both of these are complicated.  The first has to handle exact/inexact
matches, lazy importing of built-in prototypes, different scoping rules
for 1.10, 1.20+, and ES.  Not to mention printing a user-friendly error
message with pretty-printed "maybe you meant this" candidate signatures.

The second has to deal with void/non-void functions, pre-call implicit
conversions for "in" parmeters, and post-call "out" call conversions.

Trying to do both in one function is just too unwieldy.  Time to split.

This patch purely moves the code to generate an ir_call into a separate
function and reindents it.  Otherwise, the code is identical.

Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
---
 src/glsl/ast_function.cpp |  338 +++++++++++++++++++++++----------------------
 1 files changed, 173 insertions(+), 165 deletions(-)

diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
index fc0d749..08fdd64 100644
--- a/src/glsl/ast_function.cpp
+++ b/src/glsl/ast_function.cpp
@@ -93,6 +93,178 @@ prototype_string(const glsl_type *return_type, const char *name,
    return str;
 }
 
+static ir_rvalue *
+generate_call(exec_list *instructions, ir_function_signature *sig,
+	      YYLTYPE *loc, exec_list *actual_parameters,
+	      struct _mesa_glsl_parse_state *state)
+{
+   void *ctx = state;
+   exec_list post_call_conversions;
+
+   /* Verify that 'out' and 'inout' actual parameters are lvalues.  This
+    * isn't done in ir_function::matching_signature because that function
+    * cannot generate the necessary diagnostics.
+    *
+    * 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.
+    */
+   exec_list_iterator actual_iter = actual_parameters->iterator();
+   exec_list_iterator formal_iter = sig->parameters.iterator();
+
+   while (actual_iter.has_next()) {
+      ir_rvalue *actual = (ir_rvalue *) actual_iter.get();
+      ir_variable *formal = (ir_variable *) formal_iter.get();
+
+      assert(actual != NULL);
+      assert(formal != NULL);
+
+      if (formal->mode == ir_var_const_in && !actual->as_constant()) {
+	 _mesa_glsl_error(loc, state,
+			  "parameter `%s' must be a constant expression",
+			  formal->name);
+	 return ir_call::get_error_instruction(ctx);
+      }
+
+      if ((formal->mode == ir_var_out)
+	  || (formal->mode == ir_var_inout)) {
+	 const char *mode = NULL;
+	 switch (formal->mode) {
+	 case ir_var_out:   mode = "out";   break;
+	 case ir_var_inout: mode = "inout"; break;
+	 default:           assert(false);  break;
+	 }
+	 /* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always
+	  * FIXME: 0:0(0).
+	  */
+	 if (actual->variable_referenced()
+	     && actual->variable_referenced()->read_only) {
+	    _mesa_glsl_error(loc, state,
+			     "function parameter '%s %s' references the "
+			     "read-only variable '%s'",
+			     mode, formal->name,
+			     actual->variable_referenced()->name);
+
+	 } else if (!actual->is_lvalue()) {
+	    _mesa_glsl_error(loc, state,
+			     "function parameter '%s %s' is not an lvalue",
+			     mode, formal->name);
+	 }
+      }
+
+      if (formal->type->is_numeric() || formal->type->is_boolean()) {
+	 switch (formal->mode) {
+	 case ir_var_const_in:
+	 case ir_var_in: {
+	    ir_rvalue *converted
+	       = convert_component(actual, formal->type);
+	    actual->replace_with(converted);
+	    break;
+	 }
+	 case ir_var_out:
+	    if (actual->type != formal->type) {
+	       /* To convert an out parameter, we need to create a
+		* temporary variable to hold the value before conversion,
+		* and then perform the conversion after the function call
+		* returns.
+		*
+		* This has the effect of transforming code like this:
+		*
+		*   void f(out int x);
+		*   float value;
+		*   f(value);
+		*
+		* Into IR that's equivalent to this:
+		*
+		*   void f(out int x);
+		*   float value;
+		*   int out_parameter_conversion;
+		*   f(out_parameter_conversion);
+		*   value = float(out_parameter_conversion);
+		*/
+	       ir_variable *tmp =
+		  new(ctx) ir_variable(formal->type,
+				       "out_parameter_conversion",
+				       ir_var_temporary);
+	       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();
+      formal_iter.next();
+   }
+
+   /* 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()) {
+      /* If the function call is a constant expression, don't
+       * generate the instructions to call it; just generate an
+       * ir_constant representing the constant value.
+       *
+       * Function calls can only be constant expressions starting
+       * in GLSL 1.20.
+       */
+      if (state->language_version >= 120) {
+	 ir_constant *const_val = call->constant_expression_value();
+	 if (const_val) {
+	    return const_val;
+	 }
+      }
+
+      ir_variable *var;
+
+      var = new(ctx) ir_variable(sig->return_type,
+				 ralloc_asprintf(ctx, "%s_retval",
+						 sig->function_name()),
+				 ir_var_temporary);
+      instructions->push_tail(var);
+
+      deref = new(ctx) ir_dereference_variable(var);
+      ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL);
+      instructions->push_tail(assign);
+
+      deref = new(ctx) ir_dereference_variable(var);
+   } else {
+      instructions->push_tail(call);
+      deref = NULL;
+   }
+   instructions->append_list(&post_call_conversions);
+   return deref;
+}
 
 static ir_rvalue *
 match_function_by_name(exec_list *instructions, const char *name,
@@ -135,172 +307,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
-       * cannot generate the necessary diagnostics.
-       *
-       * 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.
-       */
-      exec_list_iterator actual_iter = actual_parameters->iterator();
-      exec_list_iterator formal_iter = sig->parameters.iterator();
-
-      while (actual_iter.has_next()) {
-	 ir_rvalue *actual = (ir_rvalue *) actual_iter.get();
-	 ir_variable *formal = (ir_variable *) formal_iter.get();
-
-	 assert(actual != NULL);
-	 assert(formal != NULL);
-
-	 if (formal->mode == ir_var_const_in && !actual->as_constant()) {
-	    _mesa_glsl_error(loc, state,
-			     "parameter `%s' must be a constant expression",
-			     formal->name);
-	    return ir_call::get_error_instruction(ctx);
-	 }
-
-	 if ((formal->mode == ir_var_out)
-	     || (formal->mode == ir_var_inout)) {
-	    const char *mode = NULL;
-	    switch (formal->mode) {
-	    case ir_var_out:   mode = "out";   break;
-	    case ir_var_inout: mode = "inout"; break;
-	    default:           assert(false);  break;
-	    }
-            /* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always
-             * FIXME: 0:0(0).
-             */
-	    if (actual->variable_referenced()
-	        && actual->variable_referenced()->read_only) {
-	       _mesa_glsl_error(loc, state,
-	                        "function parameter '%s %s' references the "
-	                        "read-only variable '%s'",
-	                        mode, formal->name,
-	                        actual->variable_referenced()->name);
-
-	    } else if (!actual->is_lvalue()) {
-               _mesa_glsl_error(loc, state,
-                                "function parameter '%s %s' is not an lvalue",
-                                mode, formal->name);
-	    }
-	 }
-
-	 if (formal->type->is_numeric() || formal->type->is_boolean()) {
-            switch (formal->mode) {
-            case ir_var_const_in:
-            case ir_var_in: {
-               ir_rvalue *converted
-                  = convert_component(actual, formal->type);
-               actual->replace_with(converted);
-               break;
-            }
-            case ir_var_out:
-               if (actual->type != formal->type) {
-                  /* To convert an out parameter, we need to create a
-                   * temporary variable to hold the value before conversion,
-                   * and then perform the conversion after the function call
-                   * returns.
-                   *
-                   * This has the effect of transforming code like this:
-                   *
-                   *   void f(out int x);
-                   *   float value;
-                   *   f(value);
-                   *
-                   * Into IR that's equivalent to this:
-                   *
-                   *   void f(out int x);
-                   *   float value;
-                   *   int out_parameter_conversion;
-                   *   f(out_parameter_conversion);
-                   *   value = float(out_parameter_conversion);
-                   */
-                  ir_variable *tmp =
-                     new(ctx) ir_variable(formal->type,
-                                          "out_parameter_conversion",
-                                          ir_var_temporary);
-                  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();
-	 formal_iter.next();
-      }
-
-      /* 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()) {
-         /* If the function call is a constant expression, don't
-          * generate the instructions to call it; just generate an
-          * ir_constant representing the constant value.
-          *
-          * Function calls can only be constant expressions starting
-          * in GLSL 1.20.
-          */
-         if (state->language_version >= 120) {
-            ir_constant *const_val = call->constant_expression_value();
-            if (const_val) {
-               return const_val;
-            }
-         }
-
-	 ir_variable *var;
-
-	 var = new(ctx) ir_variable(sig->return_type,
-				    ralloc_asprintf(ctx, "%s_retval",
-						    sig->function_name()),
-				    ir_var_temporary);
-	 instructions->push_tail(var);
-
-	 deref = new(ctx) ir_dereference_variable(var);
-	 ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL);
-	 instructions->push_tail(assign);
-
-	 deref = new(ctx) ir_dereference_variable(var);
-      } else {
-	 instructions->push_tail(call);
-	 deref = NULL;
-      }
-      instructions->append_list(&post_call_conversions);
-      return deref;
+      return generate_call(instructions, sig, loc, actual_parameters, state);
    } else {
       char *str = prototype_string(NULL, name, actual_parameters);
 
-- 
1.7.7.2



More information about the mesa-dev mailing list