}
/**
- * 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
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;
}
/* 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) {
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.
_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));
}
}
}
+static ir_rvalue *
+process_vec_mat_constructor(exec_list *instructions,
+ const glsl_type *constructor_type,
+ YYLTYPE *loc, exec_list *parameters,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ /* The ARB_shading_language_420pack spec says:
+ *
+ * "If an initializer is a list of initializers enclosed in curly braces,
+ * the variable being declared must be a vector, a matrix, an array, or a
+ * structure.
+ *
+ * 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, "
+ "matrices, arrays, and structs");
+ return ir_rvalue::error_value(ctx);
+ }
+
+ exec_list actual_parameters;
+ const unsigned parameter_count =
+ process_parameters(instructions, &actual_parameters, parameters, state);
+
+ if (parameter_count == 0
+ || (constructor_type->is_vector() &&
+ constructor_type->vector_elements != parameter_count)
+ || (constructor_type->is_matrix() &&
+ constructor_type->matrix_columns != parameter_count)) {
+ _mesa_glsl_error(loc, state, "%s constructor must have %u parameters",
+ constructor_type->is_vector() ? "vector" : "matrix",
+ constructor_type->vector_elements);
+ return ir_rvalue::error_value(ctx);
+ }
+
+ bool all_parameters_are_constant = true;
+
+ /* Type cast each parameter and, if possible, fold constants. */
+ foreach_list_safe(n, &actual_parameters) {
+ ir_rvalue *ir = (ir_rvalue *) n;
+ ir_rvalue *result = ir;
+
+ /* Apply implicit conversions (not the scalar constructor rules!). See
+ * the spec quote above. */
+ if (constructor_type->is_float()) {
+ const glsl_type *desired_type =
+ glsl_type::get_instance(GLSL_TYPE_FLOAT,
+ ir->type->vector_elements,
+ ir->type->matrix_columns);
+ if (result->type->can_implicitly_convert_to(desired_type)) {
+ /* Even though convert_component() implements the constructor
+ * conversion rules (not the implicit conversion rules), its safe
+ * to use it here because we already checked that the implicit
+ * conversion is legal.
+ */
+ result = convert_component(ir, desired_type);
+ }
+ }
+
+ if (constructor_type->is_matrix()) {
+ if (result->type != constructor_type->column_type()) {
+ _mesa_glsl_error(loc, state, "type error in matrix constructor: "
+ "expected: %s, found %s",
+ constructor_type->column_type()->name,
+ result->type->name);
+ return ir_rvalue::error_value(ctx);
+ }
+ } else if (result->type != constructor_type->get_scalar_type()) {
+ _mesa_glsl_error(loc, state, "type error in vector constructor: "
+ "expected: %s, found %s",
+ constructor_type->get_scalar_type()->name,
+ result->type->name);
+ return ir_rvalue::error_value(ctx);
+ }
+
+ /* Attempt to convert the parameter to a constant valued expression.
+ * After doing so, track whether or not all the parameters to the
+ * constructor are trivially constant valued expressions.
+ */
+ ir_rvalue *const constant = result->constant_expression_value();
+
+ if (constant != NULL)
+ result = constant;
+ else
+ all_parameters_are_constant = false;
+
+ ir->replace_with(result);
+ }
+
+ if (all_parameters_are_constant)
+ return new(ctx) ir_constant(constructor_type, &actual_parameters);
+
+ ir_variable *var = new(ctx) ir_variable(constructor_type, "vec_mat_ctor",
+ ir_var_temporary);
+ instructions->push_tail(var);
+
+ int i = 0;
+ foreach_list(node, &actual_parameters) {
+ ir_rvalue *rhs = (ir_rvalue *) node;
+ ir_rvalue *lhs = new(ctx) ir_dereference_array(var,
+ new(ctx) ir_constant(i));
+
+ ir_instruction *assignment = new(ctx) ir_assignment(lhs, rhs, NULL);
+ instructions->push_tail(assignment);
+
+ i++;
+ }
+
+ return new(ctx) ir_dereference_variable(var);
+}
+
+
static ir_rvalue *
process_array_constructor(exec_list *instructions,
const glsl_type *constructor_type,
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);
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);
/* 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;
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);
+}