[Mesa-dev] [PATCH 11/12] glsl: Generate correct ir_binop_vector_extract code for out and inout parameters

Ian Romanick idr at freedesktop.org
Mon Apr 8 15:24:42 PDT 2013


From: Ian Romanick <ian.d.romanick at intel.com>

Like with type conversions on out parameters, some extra copies need to
occur to handle these cases.  The fundamental problem is that
ir_binop_vector_extract is not an lvalue, but out and inout parameters
must be lvalues.  A previous patch delt with a similar problem in the
LHS of ir_assignment.

Signed-off-by: Ian Romanick <ian.d.romanick at intel.com>
---
 src/glsl/ast_function.cpp | 149 +++++++++++++++++++++++++++++++---------------
 1 file changed, 102 insertions(+), 47 deletions(-)

diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
index 26f72cf..0d32241 100644
--- a/src/glsl/ast_function.cpp
+++ b/src/glsl/ast_function.cpp
@@ -165,10 +165,18 @@ verify_parameter_modes(_mesa_glsl_parse_state *state,
 			     actual->variable_referenced()->name);
 	    return false;
 	 } else if (!actual->is_lvalue()) {
-	    _mesa_glsl_error(&loc, state,
-			     "function parameter '%s %s' is not an lvalue",
-			     mode, formal->name);
-	    return false;
+	    /* Even though ir_binop_vector_extract is not an l-value, let it
+	     * slop through.  generate_call will handle it correctly.
+	     */
+	    ir_expression *const expr = ((ir_rvalue *) actual)->as_expression();
+	    if (expr == NULL
+		|| expr->operation != ir_binop_vector_extract
+		|| !expr->operands[0]->is_lvalue()) {
+	       _mesa_glsl_error(&loc, state,
+				"function parameter '%s %s' is not an lvalue",
+				mode, formal->name);
+	       return false;
+	    }
 	 }
       }
 
@@ -178,6 +186,93 @@ verify_parameter_modes(_mesa_glsl_parse_state *state,
    return true;
 }
 
+static void
+fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type,
+	      exec_list *before_instructions, exec_list *after_instructions,
+	      bool parameter_is_inout)
+{
+   ir_expression *const expr = actual->as_expression();
+
+   /* If the types match exactly and the parameter is not a vector-extract,
+    * nothing needs to be done to fix the parameter.
+    */
+   if (formal_type == actual->type
+       && (expr == NULL || expr->operation != ir_binop_vector_extract))
+      return;
+
+   /* 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);
+    *
+    * If the parameter is an ir_expression of ir_binop_vector_extract,
+    * additional conversion is needed in the post-call re-write.
+    */
+   ir_variable *tmp =
+      new(mem_ctx) ir_variable(formal_type, "inout_tmp", ir_var_temporary);
+
+   before_instructions->push_tail(tmp);
+
+   /* If the parameter is an inout parameter, copy the value of the actual
+    * parameter to the new temporary.  Note that no type conversion is allowed
+    * here because inout parameters must match types exactly.
+    */
+   if (parameter_is_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);
+
+      ir_dereference_variable *const deref_tmp_1 =
+	 new(mem_ctx) ir_dereference_variable(tmp);
+      ir_assignment *const assignment =
+	 new(mem_ctx) ir_assignment(deref_tmp_1, actual);
+      before_instructions->push_tail(assignment);
+   }
+
+   /* Replace the parameter in the call with a dereference of the new
+    * temporary.
+    */
+   ir_dereference_variable *const deref_tmp_2 =
+      new(mem_ctx) ir_dereference_variable(tmp);
+   actual->replace_with(deref_tmp_2);
+
+
+   /* Copy the temporary variable to the actual parameter with optional
+    * type conversion applied.
+    */
+   ir_rvalue *rhs = new(mem_ctx) ir_dereference_variable(tmp);
+   if (actual->type != formal_type)
+      rhs = convert_component(rhs, actual->type);
+
+   ir_rvalue *lhs = actual;
+   if (expr != NULL && expr->operation == ir_binop_vector_extract) {
+      rhs = new(mem_ctx) ir_expression(ir_triop_vector_insert,
+				       expr->operands[0]->type,
+				       expr->operands[0]->clone(mem_ctx, NULL),
+				       rhs,
+				       expr->operands[1]->clone(mem_ctx, NULL));
+      lhs = expr->operands[0]->clone(mem_ctx, NULL);
+   }
+
+   ir_assignment *const assignment_2 = new(mem_ctx) ir_assignment(lhs, rhs);
+   after_instructions->push_tail(assignment_2);
+}
+
 /**
  * If a function call is generated, \c call_ir will point to it on exit.
  * Otherwise \c call_ir will be set to \c NULL.
@@ -218,50 +313,10 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
 	    break;
 	 }
 	 case ir_var_function_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_function_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);
+	    fix_parameter(ctx, actual, formal->type,
+			  instructions, &post_call_conversions,
+			  formal->mode == ir_var_function_inout);
 	    break;
 	 default:
 	    assert (!"Illegal formal parameter mode");
-- 
1.8.1.4



More information about the mesa-dev mailing list