glsl: Split up function matching and call generation a bit more.
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 28 Mar 2012 22:57:50 +0000 (15:57 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Mon, 2 Apr 2012 21:15:29 +0000 (14:15 -0700)
We used to have one big function, match_signature_by_name, which found
a matching signature, performed out-parameter conversions, and generated
the ir_call.  As the code for matching against built-in functions became
more complicated, I split it internally, creating generate_call().

However, I left the same awkward interface.  This patch splits it into
three functions:
1. match_signature_by_name()

   This now takes a name, a list of parameters, the symbol table, and
   returns an ir_function_signature.  Simple and one purpose: matching.

2. no_matching_function_error()

   Generate the "no matching function" error and list of prototypes.
   This was complex enough that I felt it deserved its own function.

3. generate_call()

   Do the out-parameter conversion and generate the ir_call.  This
   could probably use more splitting.

The caller now has a more natural workflow: find a matching signature,
then either generate an error or a call.

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/glsl/ast_function.cpp

index 1c2e8613cb24a9c07a8242a7beeec1f528d06a48..2ad8fba1f7e90cdd7ceb8676c633e2c16fd0b1f0 100644 (file)
@@ -275,10 +275,12 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
    return deref;
 }
 
-static ir_rvalue *
-match_function_by_name(exec_list *instructions, const char *name,
-                      YYLTYPE *loc, exec_list *actual_parameters,
-                      ir_call **call_ir,
+/**
+ * Given a function name and parameter list, find the matching signature.
+ */
+static ir_function_signature *
+match_function_by_name(const char *name,
+                      exec_list *actual_parameters,
                       struct _mesa_glsl_parse_state *state)
 {
    void *ctx = state;
@@ -350,43 +352,45 @@ done:
         }
         f->add_signature(sig->clone_prototype(f, NULL));
       }
+   }
+   return sig;
+}
 
-      /* Finally, generate a call instruction. */
-      return generate_call(instructions, sig, loc, actual_parameters,
-                          call_ir, state);
-   } else {
-      char *str = prototype_string(NULL, name, actual_parameters);
-
-      _mesa_glsl_error(loc, state, "no matching function for call to `%s'",
-                      str);
-      ralloc_free(str);
-
-      const char *prefix = "candidates are: ";
+/**
+ * Raise a "no matching function" error, listing all possible overloads the
+ * compiler considered so developers can figure out what went wrong.
+ */
+static void
+no_matching_function_error(const char *name,
+                          YYLTYPE *loc,
+                          exec_list *actual_parameters,
+                          _mesa_glsl_parse_state *state)
+{
+   char *str = prototype_string(NULL, name, actual_parameters);
+   _mesa_glsl_error(loc, state, "no matching function for call to `%s'", str);
+   ralloc_free(str);
 
-      for (int i = -1; i < (int) state->num_builtins_to_link; i++) {
-        glsl_symbol_table *syms = i >= 0 ? state->builtins_to_link[i]->symbols
-                                         : state->symbols;
-        f = syms->get_function(name);
-        if (f == NULL)
-           continue;
+   const char *prefix = "candidates are: ";
 
-        foreach_list (node, &f->signatures) {
-           ir_function_signature *sig = (ir_function_signature *) node;
+   for (int i = -1; i < (int) state->num_builtins_to_link; i++) {
+      glsl_symbol_table *syms = i >= 0 ? state->builtins_to_link[i]->symbols
+                                      : state->symbols;
+      ir_function *f = syms->get_function(name);
+      if (f == NULL)
+        continue;
 
-           str = prototype_string(sig->return_type, f->name, &sig->parameters);
-           _mesa_glsl_error(loc, state, "%s%s", prefix, str);
-           ralloc_free(str);
+      foreach_list (node, &f->signatures) {
+        ir_function_signature *sig = (ir_function_signature *) node;
 
-           prefix = "                ";
-        }
+        str = prototype_string(sig->return_type, f->name, &sig->parameters);
+        _mesa_glsl_error(loc, state, "%s%s", prefix, str);
+        ralloc_free(str);
 
+        prefix = "                ";
       }
-
-      return ir_call::get_error_instruction(ctx);
    }
 }
 
-
 /**
  * Perform automatic type conversion of constructor parameters
  *
@@ -1447,17 +1451,25 @@ ast_function_expression::hir(exec_list *instructions,
       }
    } else {
       const ast_expression *id = subexpressions[0];
+      const char *func_name = id->primary_expression.identifier;
       YYLTYPE loc = id->get_location();
       exec_list actual_parameters;
 
       process_parameters(instructions, &actual_parameters, &this->expressions,
                         state);
 
+      ir_function_signature *sig =
+        match_function_by_name(func_name, &actual_parameters, state);
+
       ir_call *call = NULL;
-      ir_rvalue *const value =
-        match_function_by_name(instructions,
-                               id->primary_expression.identifier,
-                               &loc, &actual_parameters, &call, state);
+      ir_rvalue *value = NULL;
+      if (sig == NULL) {
+        no_matching_function_error(func_name, &loc, &actual_parameters, state);
+        value = ir_call::get_error_instruction(ctx);
+      } else {
+        value = generate_call(instructions, sig, &loc, &actual_parameters,
+                              &call, state);
+      }
 
       if (call != NULL) {
         /* If a function was found, make sure that none of the 'out' or 'inout'