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 <kenneth@whitecape.org>
This commit is contained in:
Kenneth Graunke 2011-11-11 00:43:06 -08:00
parent cdc9408266
commit f1a677cefb
1 changed files with 62 additions and 28 deletions

View File

@ -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;
ir_function_signature *local_sig = NULL;
ir_function_signature *sig = NULL;
sig = f ? f->matching_signature(actual_parameters) : NULL;
/* Is the function hidden by a record type constructor? */
if (state->symbols->get_type(name))
goto done; /* no match */
/* 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);
}
/* 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 */
f->add_signature(sig->clone_prototype(f, NULL));
break;
}
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;
}
}
/* 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;
}
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);