#include "glsl_types.h"
#include "ir.h"
-static ir_rvalue *
-match_function_by_name(exec_list *instructions, const char *name,
- YYLTYPE *loc, simple_node *parameters,
- struct _mesa_glsl_parse_state *state)
+static unsigned
+process_parameters(exec_list *instructions, exec_list *actual_parameters,
+ simple_node *parameters,
+ struct _mesa_glsl_parse_state *state)
{
- ir_function *f = state->symbols->get_function(name);
-
- if (f == NULL) {
- _mesa_glsl_error(loc, state, "function `%s' undeclared", name);
- return ir_call::get_error_instruction();
- }
-
- /* Once we've determined that the function being called might exist,
- * process the parameters.
- */
- exec_list actual_parameters;
simple_node *const first = parameters;
+ unsigned count = 0;
+
if (first != NULL) {
simple_node *ptr = first;
do {
((ast_node *) ptr)->hir(instructions, state);
ptr = ptr->next;
- actual_parameters.push_tail(result);
+ actual_parameters->push_tail(result);
+ count++;
} while (ptr != first);
}
- /* After processing the function's actual parameters, try to find an
- * overload of the function that matches.
- */
+ return count;
+}
+
+
+static ir_rvalue *
+process_call(exec_list *instructions, ir_function *f,
+ YYLTYPE *loc, exec_list *actual_parameters,
+ struct _mesa_glsl_parse_state *state)
+{
const ir_function_signature *sig =
- f->matching_signature(& actual_parameters);
+ f->matching_signature(actual_parameters);
+
+ /* The instructions param will be used when the FINISHMEs below are done */
+ (void) instructions;
+
if (sig != NULL) {
+ /* Verify that 'out' and 'inout' actual parameters are lvalues. This
+ * isn't done in ir_function::matching_signature because that function
+ * cannot generate the necessary diagnostics.
+ */
+ exec_list_iterator actual_iter = actual_parameters->iterator();
+ exec_list_iterator formal_iter = sig->parameters.iterator();
+
+ while (actual_iter.has_next()) {
+ ir_rvalue *actual =
+ ((ir_instruction *) actual_iter.get())->as_rvalue();
+ ir_variable *formal =
+ ((ir_instruction *) formal_iter.get())->as_variable();
+
+ assert(actual != NULL);
+ assert(formal != NULL);
+
+ if ((formal->mode == ir_var_out)
+ || (formal->mode == ir_var_inout)) {
+ if (! actual->is_lvalue()) {
+ /* FINISHME: Log a better diagnostic here. There is no way
+ * FINISHME: to tell the user which parameter is invalid.
+ */
+ _mesa_glsl_error(loc, state, "`%s' parameter is not lvalue",
+ (formal->mode == ir_var_out) ? "out" : "inout");
+ }
+ }
+
+ actual_iter.next();
+ formal_iter.next();
+ }
+
/* FINISHME: The list of actual parameters needs to be modified to
* FINISHME: include any necessary conversions.
*/
- return new ir_call(sig, & actual_parameters);
+ return new ir_call(sig, actual_parameters);
} else {
/* FINISHME: Log a better error message here. G++ will show the types
* FINISHME: of the actual parameters and the set of candidate
* FINISHME: multiple functions match.
*/
_mesa_glsl_error(loc, state, "no matching function for call to `%s'",
- name);
+ f->name);
return ir_call::get_error_instruction();
}
}
+static ir_rvalue *
+match_function_by_name(exec_list *instructions, const char *name,
+ YYLTYPE *loc, simple_node *parameters,
+ struct _mesa_glsl_parse_state *state)
+{
+ ir_function *f = state->symbols->get_function(name);
+
+ if (f == NULL) {
+ _mesa_glsl_error(loc, state, "function `%s' undeclared", name);
+ return ir_call::get_error_instruction();
+ }
+
+ /* Once we've determined that the function being called might exist,
+ * process the parameters.
+ */
+ exec_list actual_parameters;
+ process_parameters(instructions, &actual_parameters, parameters, state);
+
+ /* After processing the function's actual parameters, try to find an
+ * overload of the function that matches.
+ */
+ return process_call(instructions, f, loc, &actual_parameters, state);
+}
+
+
/**
* Perform automatic type conversion of constructor parameters
*/
return new ir_expression(ir_unop_f2i, desired_type, src, NULL);
else {
assert(b == GLSL_TYPE_BOOL);
- assert(!"FINISHME: Convert bool to int / uint.");
+ return new ir_expression(ir_unop_f2b, desired_type, src, NULL);
}
case GLSL_TYPE_FLOAT:
switch (b) {
case GLSL_TYPE_INT:
return new ir_expression(ir_unop_i2f, desired_type, src, NULL);
case GLSL_TYPE_BOOL:
- assert(!"FINISHME: Convert bool to float.");
+ return new ir_expression(ir_unop_b2f, desired_type, src, NULL);
}
break;
case GLSL_TYPE_BOOL: {
}
+static ir_rvalue *
+process_array_constructor(exec_list *instructions,
+ const glsl_type *constructor_type,
+ YYLTYPE *loc, simple_node *parameters,
+ struct _mesa_glsl_parse_state *state)
+{
+ /* Array constructors come in two forms: sized and unsized. Sized array
+ * constructors look like 'vec4[2](a, b)', where 'a' and 'b' are vec4
+ * variables. In this case the number of parameters must exactly match the
+ * specified size of the array.
+ *
+ * Unsized array constructors look like 'vec4[](a, b)', where 'a' and 'b'
+ * are vec4 variables. In this case the size of the array being constructed
+ * is determined by the number of parameters.
+ *
+ * From page 52 (page 58 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "There must be exactly the same number of arguments as the size of
+ * the array being constructed. If no size is present in the
+ * constructor, then the array is explicitly sized to the number of
+ * arguments provided. The arguments are assigned in order, starting at
+ * element 0, to the elements of the constructed array. Each argument
+ * must be the same type as the element type of the array, or be a type
+ * that can be converted to the element type of the array according to
+ * Section 4.1.10 "Implicit Conversions.""
+ */
+ exec_list actual_parameters;
+ const unsigned parameter_count =
+ process_parameters(instructions, &actual_parameters, parameters, state);
+
+ 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;
+
+ _mesa_glsl_error(loc, state, "array constructor must have %s %u "
+ "parameter%s",
+ (constructor_type->length != 0) ? "at least" : "exactly",
+ min_param, (min_param <= 1) ? "" : "s");
+ return ir_call::get_error_instruction();
+ }
+
+ if (constructor_type->length == 0) {
+ constructor_type =
+ glsl_type::get_array_instance(constructor_type->element_type(),
+ parameter_count);
+ assert(constructor_type != NULL);
+ assert(constructor_type->length == parameter_count);
+ }
+
+ ir_function *f = state->symbols->get_function(constructor_type->name);
+
+ /* If the constructor for this type of array does not exist, generate the
+ * prototype and add it to the symbol table. The code will be generated
+ * later.
+ */
+ if (f == NULL) {
+ f = constructor_type->generate_constructor_prototype(state->symbols);
+ }
+
+ ir_rvalue *const r =
+ process_call(instructions, f, loc, &actual_parameters, state);
+
+ assert(r != NULL);
+ assert(r->type->is_error() || (r->type == constructor_type));
+
+ return r;
+}
+
+
ir_rvalue *
ast_function_expression::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
if (is_constructor()) {
const ast_type_specifier *type = (ast_type_specifier *) subexpressions[0];
YYLTYPE loc = type->get_location();
+ const char *name;
- const glsl_type *const constructor_type =
- state->symbols->get_type(type->type_name);
+ const glsl_type *const constructor_type = type->glsl_type(& name, state);
/* Constructors for samplers are illegal.
return ir_call::get_error_instruction();
}
+ if (constructor_type->is_array()) {
+ if (state->language_version <= 110) {
+ _mesa_glsl_error(& loc, state,
+ "array constructors forbidden in GLSL 1.10");
+ return ir_call::get_error_instruction();
+ }
+
+ return process_array_constructor(instructions, constructor_type,
+ & loc, subexpressions[1], state);
+ }
/* There are two kinds of constructor call. Constructors for built-in
* language types, such as mat4 and vec2, are free form. The only
* arguments to provide an initializer for every component in the
* constructed value."
*/
- if (components_used < type_components) {
+ if ((components_used < type_components) && (components_used != 1)) {
_mesa_glsl_error(& loc, state, "too few components to construct "
"`%s'",
constructor_type->name);