[Mesa-dev] [PATCH 3/3] glsl: Always search for an exact function signature match.

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


Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:

    #version 130
    void main() {
        float f = abs(5.0);
        int i = abs(5);
    }

The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".

The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that.  Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".

Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.

Fixes piglit test builtin-overload-matching.frag.

This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments.  Plus, the changes are fairly invasive.

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

diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
index 08fdd64..880109e 100644
--- a/src/glsl/ast_function.cpp
+++ b/src/glsl/ast_function.cpp
@@ -273,41 +273,75 @@ match_function_by_name(exec_list *instructions, const char *name,
 {
    void *ctx = state;
    ir_function *f = state->symbols->get_function(name);
-   ir_function_signature *sig;
-
-   sig = f ? f->matching_signature(actual_parameters) : NULL;
+   ir_function_signature *local_sig = NULL;
+   ir_function_signature *sig = NULL;
+
+   /* Is the function hidden by a record type constructor? */
+   if (state->symbols->get_type(name))
+      goto done; /* no match */
+
+   /* Is the function hidden by a variable (impossible in 1.10)? */
+   if (state->language_version != 110 && state->symbols->get_variable(name))
+      goto done; /* no match */
+
+   if (f != NULL) {
+      /* Look for a match in the local shader.  If exact, we're done. */
+      bool is_exact = false;
+      sig = local_sig = f->matching_signature(actual_parameters, is_exact);
+      if (is_exact)
+	 goto done;
+
+      if (!state->es_shader && f->has_user_signature()) {
+	 /* In desktop GL, the presence of a user-defined signature hides any
+	  * built-in signatures, so we must ignore them.  In contrast, in ES2
+	  * user-defined signatures add new overloads, so we must proceed.
+	  */
+	 goto done;
+      }
+   }
 
-   /* FINISHME: This doesn't handle the case where shader X contains a
-    * FINISHME: matching signature but shader X + N contains an _exact_
-    * FINISHME: matching signature.
-    */
-   if (sig == NULL
-       && (f == NULL || state->es_shader || !f->has_user_signature())
-       && state->symbols->get_type(name) == NULL
-       && (state->language_version == 110
-	   || state->symbols->get_variable(name) == NULL)) {
-      /* The current shader doesn't contain a matching function or signature.
-       * Before giving up, look for the prototype in the built-in functions.
-       */
-      _mesa_glsl_initialize_functions(state);
-      for (unsigned i = 0; i < state->num_builtins_to_link; i++) {
-	 ir_function *builtin;
-	 builtin = state->builtins_to_link[i]->symbols->get_function(name);
-	 sig = builtin ? builtin->matching_signature(actual_parameters) : NULL;
-	 if (sig != NULL) {
-	    if (f == NULL) {
-	       f = new(ctx) ir_function(name);
-	       state->symbols->add_global_function(f);
-	       emit_function(state, f);
-	    }
+   /* Local shader has no exact candidates; check the built-ins. */
+   _mesa_glsl_initialize_functions(state);
+   for (unsigned i = 0; i < state->num_builtins_to_link; i++) {
+      ir_function *builtin =
+	 state->builtins_to_link[i]->symbols->get_function(name);
+      if (builtin == NULL)
+	 continue;
+
+      bool is_exact = false;
+      ir_function_signature *builtin_sig =
+	 builtin->matching_signature(actual_parameters, is_exact);
+
+      if (builtin_sig == NULL)
+	 continue;
+
+      /* If the built-in signature is exact, we can stop. */
+      if (is_exact) {
+	 sig = builtin_sig;
+	 goto done;
+      }
 
-	    f->add_signature(sig->clone_prototype(f, NULL));
-	    break;
-	 }
+      if (sig == NULL) {
+	 /* We found an inexact match, which is better than nothing.  However,
+	  * we should keep searching for an exact match.
+	  */
+	 sig = builtin_sig;
       }
    }
 
+done:
    if (sig != NULL) {
+      /* If the match is from a linked built-in shader, import the prototype. */
+      if (sig != local_sig) {
+	 if (f == NULL) {
+	    f = new(ctx) ir_function(name);
+	    state->symbols->add_global_function(f);
+	    emit_function(state, f);
+	 }
+	 f->add_signature(sig->clone_prototype(f, NULL));
+      }
+
+      /* Finally, generate a call instruction. */
       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