diff options
author | Kenneth Graunke <[email protected]> | 2011-11-11 00:43:06 -0800 |
---|---|---|
committer | Kenneth Graunke <[email protected]> | 2011-11-14 17:18:12 -0800 |
commit | f1a677cefbe91a5c1a72dbeda94d2f13a9369e54 (patch) | |
tree | e30489d625296580d9664d8061d805e38bfa5473 | |
parent | cdc94082664c329e6c55cf6053893360946275bf (diff) |
glsl: Always search for an exact function signature match.
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 <[email protected]>
-rw-r--r-- | 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 08fdd64be56..126b610d193 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); |