glsl: Fix handling of function calls inside nested loops.
[mesa.git] / src / glsl / ast_function.cpp
index 459a17a3dca72e5cc488783b8df994897ee5150f..64237594e13e19baf021c101501d00f754aedbc9 100644 (file)
@@ -274,20 +274,20 @@ fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type,
 }
 
 /**
- * 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.
+ * Generate a function call.
+ *
+ * For non-void functions, this returns a dereference of the temporary variable
+ * which stores the return value for the call.  For void functions, this returns
+ * NULL.
  */
 static ir_rvalue *
 generate_call(exec_list *instructions, ir_function_signature *sig,
              exec_list *actual_parameters,
-             ir_call **call_ir,
              struct _mesa_glsl_parse_state *state)
 {
    void *ctx = state;
    exec_list post_call_conversions;
 
-   *call_ir = NULL;
-
    /* Perform implicit conversion of arguments.  For out parameters, we need
     * to place them in a temporary variable and do the conversion after the
     * call takes place.  Since we haven't emitted the call yet, we'll place
@@ -388,7 +388,8 @@ match_function_by_name(const char *name,
    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);
+      sig = local_sig = f->matching_signature(state, actual_parameters,
+                                              &is_exact);
       if (is_exact)
         goto done;
 
@@ -402,33 +403,8 @@ match_function_by_name(const char *name,
    }
 
    /* 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;
-      }
-   }
+   _mesa_glsl_initialize_builtin_functions();
+   sig = _mesa_glsl_find_builtin_function(state, name, actual_parameters);
 
 done:
    if (sig != NULL) {
@@ -445,6 +421,25 @@ done:
    return sig;
 }
 
+static void
+print_function_prototypes(_mesa_glsl_parse_state *state, YYLTYPE *loc,
+                          ir_function *f)
+{
+   if (f == NULL)
+      return;
+
+   foreach_list (node, &f->signatures) {
+      ir_function_signature *sig = (ir_function_signature *) node;
+
+      if (sig->is_builtin() && !sig->is_builtin_available(state))
+         continue;
+
+      char *str = prototype_string(sig->return_type, f->name, &sig->parameters);
+      _mesa_glsl_error(loc, state, "   %s", str);
+      ralloc_free(str);
+   }
+}
+
 /**
  * Raise a "no matching function" error, listing all possible overloads the
  * compiler considered so developers can figure out what went wrong.
@@ -456,27 +451,16 @@ no_matching_function_error(const char *name,
                           _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);
+   _mesa_glsl_error(loc, state,
+                    "no matching function for call to `%s'; candidates are:",
+                    str);
    ralloc_free(str);
 
-   const char *prefix = "candidates are: ";
-
-   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;
-
-      foreach_list (node, &f->signatures) {
-        ir_function_signature *sig = (ir_function_signature *) node;
+   print_function_prototypes(state, loc, state->symbols->get_function(name));
 
-        str = prototype_string(sig->return_type, f->name, &sig->parameters);
-        _mesa_glsl_error(loc, state, "%s%s", prefix, str);
-        ralloc_free(str);
-
-        prefix = "                ";
-      }
+   if (state->uses_builtin_functions) {
+      gl_shader *sh = _mesa_glsl_get_builtin_function_shader();
+      print_function_prototypes(state, loc, sh->symbols->get_function(name));
    }
 }
 
@@ -626,7 +610,7 @@ process_vec_mat_constructor(exec_list *instructions,
     *      int i = { 1 }; // illegal, i is not an aggregate"
     */
    if (constructor_type->vector_elements <= 1) {
-      _mesa_glsl_error(loc, state, "Aggregates can only initialize vectors, "
+      _mesa_glsl_error(loc, state, "aggregates can only initialize vectors, "
                        "matrices, arrays, and structs");
       return ir_rvalue::error_value(ctx);
    }
@@ -753,21 +737,21 @@ process_array_constructor(exec_list *instructions,
    exec_list actual_parameters;
    const unsigned parameter_count =
       process_parameters(instructions, &actual_parameters, parameters, state);
+   bool is_unsized_array = constructor_type->is_unsized_array();
 
-   if ((parameter_count == 0)
-       || ((constructor_type->length != 0)
-          && (constructor_type->length != parameter_count))) {
-      const unsigned min_param = (constructor_type->length == 0)
-        ? 1 : constructor_type->length;
+   if ((parameter_count == 0) ||
+       (!is_unsized_array && (constructor_type->length != parameter_count))) {
+      const unsigned min_param = is_unsized_array
+         ? 1 : constructor_type->length;
 
       _mesa_glsl_error(loc, state, "array constructor must have %s %u "
                       "parameter%s",
-                      (constructor_type->length == 0) ? "at least" : "exactly",
+                      is_unsized_array ? "at least" : "exactly",
                       min_param, (min_param <= 1) ? "" : "s");
       return ir_rvalue::error_value(ctx);
    }
 
-   if (constructor_type->length == 0) {
+   if (is_unsized_array) {
       constructor_type =
         glsl_type::get_array_instance(constructor_type->element_type(),
                                       parameter_count);
@@ -1681,7 +1665,6 @@ ast_function_expression::hir(exec_list *instructions,
       ir_function_signature *sig =
         match_function_by_name(func_name, &actual_parameters, state);
 
-      ir_call *call = NULL;
       ir_rvalue *value = NULL;
       if (sig == NULL) {
         no_matching_function_error(func_name, &loc, &actual_parameters, state);
@@ -1690,8 +1673,7 @@ ast_function_expression::hir(exec_list *instructions,
         /* an error has already been emitted */
         value = ir_rvalue::error_value(ctx);
       } else {
-        value = generate_call(instructions, sig, &actual_parameters,
-                              &call, state);
+        value = generate_call(instructions, sig, &actual_parameters, state);
       }
 
       return value;
@@ -1699,3 +1681,38 @@ ast_function_expression::hir(exec_list *instructions,
 
    return ir_rvalue::error_value(ctx);
 }
+
+ir_rvalue *
+ast_aggregate_initializer::hir(exec_list *instructions,
+                               struct _mesa_glsl_parse_state *state)
+{
+   void *ctx = state;
+   YYLTYPE loc = this->get_location();
+   const char *name;
+
+   if (!this->constructor_type) {
+      _mesa_glsl_error(&loc, state, "type of C-style initializer unknown");
+      return ir_rvalue::error_value(ctx);
+   }
+   const glsl_type *const constructor_type =
+      this->constructor_type->glsl_type(&name, state);
+
+   if (!state->ARB_shading_language_420pack_enable) {
+      _mesa_glsl_error(&loc, state, "C-style initialization requires the "
+                       "GL_ARB_shading_language_420pack extension");
+      return ir_rvalue::error_value(ctx);
+   }
+
+   if (this->constructor_type->is_array) {
+      return process_array_constructor(instructions, constructor_type, &loc,
+                                       &this->expressions, state);
+   }
+
+   if (this->constructor_type->structure) {
+      return process_record_constructor(instructions, constructor_type, &loc,
+                                        &this->expressions, state);
+   }
+
+   return process_vec_mat_constructor(instructions, constructor_type, &loc,
+                                      &this->expressions, state);
+}