return (a < b) ? a : b;
}
+static ir_rvalue *
+convert_component(ir_rvalue *src, const glsl_type *desired_type);
+
static unsigned
process_parameters(exec_list *instructions, exec_list *actual_parameters,
exec_list *parameters,
{
void *ctx = state;
- const ir_function_signature *sig =
- f->matching_signature(actual_parameters);
+ ir_function_signature *sig = f->matching_signature(actual_parameters);
/* The instructions param will be used when the FINISHMEs below are done */
(void) instructions;
}
}
+ if (formal->type->is_numeric() || formal->type->is_boolean()) {
+ ir_rvalue *converted = convert_component(actual, formal->type);
+ actual->replace_with(converted);
+ }
+
actual_iter.next();
formal_iter.next();
}
- /* FINISHME: The list of actual parameters needs to be modified to
- * FINISHME: include any necessary conversions.
+ /* Always insert the call in the instruction stream, and return a deref
+ * of its return val if it returns a value, since we don't know if
+ * the rvalue is going to be assigned to anything or not.
*/
- return new(ctx) ir_call(sig, actual_parameters);
+ ir_call *call = new(ctx) ir_call(sig, actual_parameters);
+ if (!sig->return_type->is_void()) {
+ ir_variable *var;
+ ir_dereference_variable *deref;
+
+ var = new(ctx) ir_variable(sig->return_type,
+ talloc_asprintf(ctx, "%s_retval",
+ sig->function_name()),
+ ir_var_temporary);
+ instructions->push_tail(var);
+
+ deref = new(ctx) ir_dereference_variable(var);
+ ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL);
+ instructions->push_tail(assign);
+
+ deref = new(ctx) ir_dereference_variable(var);
+ return deref;
+ } else {
+ instructions->push_tail(call);
+ return NULL;
+ }
} else {
/* FINISHME: Log a better error message here. G++ will show the types
* FINISHME: of the actual parameters and the set of candidate
/**
* Perform automatic type conversion of constructor parameters
+ *
+ * This implements the rules in the "Conversion and Scalar Constructors"
+ * section (GLSL 1.10 section 5.4.1), not the "Implicit Conversions" rules.
*/
static ir_rvalue *
convert_component(ir_rvalue *src, const glsl_type *desired_type)
assert(result != NULL);
+ /* Try constant folding; it may fold in the conversion we just added. */
ir_constant *const constant = result->constant_expression_value();
return (constant != NULL) ? (ir_rvalue *) constant : (ir_rvalue *) result;
}
-
/**
* Dereference a specific component from a scalar, vector, or matrix
*/
if (constructor_type->length == 0) {
constructor_type =
- glsl_type::get_array_instance(state,
- constructor_type->element_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);
+ bool all_parameters_are_constant = true;
- /* If the constructor for this type of array does not exist, generate the
- * prototype and add it to the symbol table.
- */
- if (f == NULL) {
- f = constructor_type->generate_constructor(state->symbols);
+ /* 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!) */
+ if (constructor_type->element_type()->is_float()) {
+ const glsl_type *desired_type =
+ glsl_type::get_instance(GLSL_TYPE_FLOAT,
+ ir->type->vector_elements,
+ ir->type->matrix_columns);
+ result = convert_component(ir, desired_type);
+ }
+
+ if (result->type != constructor_type->element_type()) {
+ _mesa_glsl_error(loc, state, "type error in array constructor: "
+ "expected: %s, found %s",
+ constructor_type->element_type()->name,
+ result->type->name);
+ }
+
+ /* 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);
}
- ir_rvalue *const r =
- process_call(instructions, f, loc, &actual_parameters, state);
+ if (all_parameters_are_constant) {
+ /* FINISHME: Add support for generating constant arrays. */
+ }
+
+ ir_variable *var = new(ctx) ir_variable(constructor_type, "array_ctor",
+ ir_var_temporary);
+ instructions->push_tail(var);
- assert(r != NULL);
- assert(r->type->is_error() || (r->type == constructor_type));
+ 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));
- return r;
+ ir_instruction *assignment = new(ctx) ir_assignment(lhs, rhs, NULL);
+ instructions->push_tail(assignment);
+
+ i++;
+ }
+
+ return new(ctx) ir_dereference_variable(var);
}
assert(!parameters->is_empty());
ir_variable *var = new(ctx) ir_variable(type,
- talloc_strdup(ctx, "vec_ctor"));
+ talloc_strdup(ctx, "vec_ctor"),
+ ir_var_temporary);
instructions->push_tail(var);
/* There are two kinds of vector constructors.
assert(!parameters->is_empty());
ir_variable *var = new(ctx) ir_variable(type,
- talloc_strdup(ctx, "mat_ctor"));
+ talloc_strdup(ctx, "mat_ctor"),
+ ir_var_temporary);
instructions->push_tail(var);
/* There are three kinds of matrix constructors.
*/
ir_variable *rhs_var =
new(ctx) ir_variable(glsl_type::vec4_type,
- talloc_strdup(ctx, "mat_ctor_vec"));
+ talloc_strdup(ctx, "mat_ctor_vec"),
+ ir_var_temporary);
instructions->push_tail(rhs_var);
ir_constant_data zero;
*/
ir_variable *const rhs_var =
new(ctx) ir_variable(first_param->type,
- talloc_strdup(ctx, "mat_ctor_mat"));
+ talloc_strdup(ctx, "mat_ctor_mat"),
+ ir_var_temporary);
instructions->push_tail(rhs_var);
ir_dereference *const rhs_var_ref =
*/
ir_variable *rhs_var =
new(ctx) ir_variable(rhs->type,
- talloc_strdup(ctx, "mat_ctor_vec"));
+ talloc_strdup(ctx, "mat_ctor_vec"),
+ ir_var_temporary);
instructions->push_tail(rhs_var);
ir_dereference *rhs_var_ref =
void *ctx = state;
/* There are three sorts of function calls.
*
- * 1. contstructors - The first subexpression is an ast_type_specifier.
+ * 1. constructors - The first subexpression is an ast_type_specifier.
* 2. methods - Only the .length() method of array types.
* 3. functions - Calls to regular old functions.
*
* correct order. These constructors follow essentially the same type
* matching rules as functions.
*/
- if (constructor_type->is_numeric() || constructor_type->is_boolean()) {
- /* Total number of components of the type being constructed.
- */
- const unsigned type_components = constructor_type->components();
-
- /* Number of components from parameters that have actually been
- * consumed. This is used to perform several kinds of error checking.
- */
- unsigned components_used = 0;
-
- unsigned matrix_parameters = 0;
- unsigned nonmatrix_parameters = 0;
- exec_list actual_parameters;
+ if (!constructor_type->is_numeric() && !constructor_type->is_boolean())
+ return ir_call::get_error_instruction(ctx);
- bool all_parameters_are_constant = true;
+ /* Total number of components of the type being constructed. */
+ const unsigned type_components = constructor_type->components();
- /* This handles invalid constructor calls such as 'vec4 v = vec4();'
- */
- if (this->expressions.is_empty()) {
- _mesa_glsl_error(& loc, state, "too few components to construct "
- "`%s'",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- foreach_list (n, &this->expressions) {
- ast_node *ast = exec_node_data(ast_node, n, link);
- ir_rvalue *result =
- ast->hir(instructions, state)->as_rvalue();
-
- /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
- *
- * "It is an error to provide extra arguments beyond this
- * last used argument."
- */
- if (components_used >= type_components) {
- _mesa_glsl_error(& loc, state, "too many parameters to `%s' "
- "constructor",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
+ /* Number of components from parameters that have actually been
+ * consumed. This is used to perform several kinds of error checking.
+ */
+ unsigned components_used = 0;
- if (!result->type->is_numeric() && !result->type->is_boolean()) {
- _mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
- "non-numeric data type",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
+ unsigned matrix_parameters = 0;
+ unsigned nonmatrix_parameters = 0;
+ exec_list actual_parameters;
- /* Count the number of matrix and nonmatrix parameters. This
- * is used below to enforce some of the constructor rules.
- */
- if (result->type->is_matrix())
- matrix_parameters++;
- else
- nonmatrix_parameters++;
-
- /* Type cast the parameter and add it to the parameter list for
- * the constructor.
- */
- const glsl_type *desired_type =
- glsl_type::get_instance(constructor_type->base_type,
- result->type->vector_elements,
- result->type->matrix_columns);
- result = convert_component(result, desired_type);
-
- /* 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;
-
- actual_parameters.push_tail(result);
- components_used += result->type->components();
- }
+ foreach_list (n, &this->expressions) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ir_rvalue *result = ast->hir(instructions, state)->as_rvalue();
- /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
+ /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
*
- * "It is an error to construct matrices from other matrices. This
- * is reserved for future use."
+ * "It is an error to provide extra arguments beyond this
+ * last used argument."
*/
- if ((state->language_version <= 110) && (matrix_parameters > 0)
- && constructor_type->is_matrix()) {
- _mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
- "matrix in GLSL 1.10",
+ if (components_used >= type_components) {
+ _mesa_glsl_error(& loc, state, "too many parameters to `%s' "
+ "constructor",
constructor_type->name);
return ir_call::get_error_instruction(ctx);
}
- /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
- *
- * "If a matrix argument is given to a matrix constructor, it is
- * an error to have any other arguments."
- */
- if ((matrix_parameters > 0)
- && ((matrix_parameters + nonmatrix_parameters) > 1)
- && constructor_type->is_matrix()) {
- _mesa_glsl_error(& loc, state, "for matrix `%s' constructor, "
- "matrix must be only parameter",
+ if (!result->type->is_numeric() && !result->type->is_boolean()) {
+ _mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
+ "non-numeric data type",
constructor_type->name);
return ir_call::get_error_instruction(ctx);
}
- /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
- *
- * "In these cases, there must be enough components provided in the
- * arguments to provide an initializer for every component in the
- * constructed value."
+ /* Count the number of matrix and nonmatrix parameters. This
+ * is used below to enforce some of the constructor rules.
*/
- if ((components_used < type_components) && (components_used != 1)) {
- _mesa_glsl_error(& loc, state, "too few components to construct "
- "`%s'",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ if (result->type->is_matrix())
+ matrix_parameters++;
+ else
+ nonmatrix_parameters++;
+
+ actual_parameters.push_tail(result);
+ components_used += result->type->components();
+ }
+
+ /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "It is an error to construct matrices from other matrices. This
+ * is reserved for future use."
+ */
+ if ((state->language_version <= 110) && (matrix_parameters > 0)
+ && constructor_type->is_matrix()) {
+ _mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
+ "matrix in GLSL 1.10",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "If a matrix argument is given to a matrix constructor, it is
+ * an error to have any other arguments."
+ */
+ if ((matrix_parameters > 0)
+ && ((matrix_parameters + nonmatrix_parameters) > 1)
+ && constructor_type->is_matrix()) {
+ _mesa_glsl_error(& loc, state, "for matrix `%s' constructor, "
+ "matrix must be only parameter",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "In these cases, there must be enough components provided in the
+ * arguments to provide an initializer for every component in the
+ * constructed value."
+ */
+ if ((components_used < type_components) && (components_used != 1)) {
+ _mesa_glsl_error(& loc, state, "too few components to construct "
+ "`%s'",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ /* Later, we cast each parameter to the same base type as the
+ * constructor. Since there are no non-floating point matrices, we
+ * need to break them up into a series of column vectors.
+ */
+ if (constructor_type->base_type != GLSL_TYPE_FLOAT) {
+ foreach_list_safe(n, &actual_parameters) {
+ ir_rvalue *matrix = (ir_rvalue *) n;
+
+ if (!matrix->type->is_matrix())
+ continue;
+
+ /* Create a temporary containing the matrix. */
+ ir_variable *var = new(ctx) ir_variable(matrix->type, "matrix_tmp",
+ ir_var_temporary);
+ instructions->push_tail(var);
+ instructions->push_tail(new(ctx) ir_assignment(new(ctx)
+ ir_dereference_variable(var), matrix, NULL));
+ var->constant_value = matrix->constant_expression_value();
+
+ /* Replace the matrix with dereferences of its columns. */
+ for (int i = 0; i < matrix->type->matrix_columns; i++) {
+ matrix->insert_before(new (ctx) ir_dereference_array(var,
+ new(ctx) ir_constant(i)));
+ }
+ matrix->remove();
}
+ }
+
+ 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;
+ const glsl_type *desired_type =
+ glsl_type::get_instance(constructor_type->base_type,
+ ir->type->vector_elements,
+ ir->type->matrix_columns);
+ ir_rvalue *result = convert_component(ir, desired_type);
- /* If all of the parameters are trivially constant, create a
- * constant representing the complete collection of parameters.
+ /* 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.
*/
- if (all_parameters_are_constant) {
- if (components_used >= type_components)
- return new(ctx) ir_constant(constructor_type,
- & actual_parameters);
-
- /* The above case must handle all scalar constructors.
- */
- assert(constructor_type->is_vector()
- || constructor_type->is_matrix());
-
- /* Constructors with exactly one component are special for
- * vectors and matrices. For vectors it causes all elements of
- * the vector to be filled with the value. For matrices it
- * causes the matrix to be filled with 0 and the diagonal to be
- * filled with the value.
- */
- ir_constant_data data;
- ir_constant *const initializer =
- (ir_constant *) actual_parameters.head;
- if (constructor_type->is_matrix())
- generate_constructor_matrix(constructor_type, initializer,
- &data);
- else
- generate_constructor_vector(constructor_type, initializer,
- &data);
-
- return new(ctx) ir_constant(constructor_type, &data);
- } else if (constructor_type->is_scalar()) {
- return dereference_component((ir_rvalue *) actual_parameters.head,
- 0);
- } else if (constructor_type->is_vector()) {
- return emit_inline_vector_constructor(constructor_type,
- instructions,
- &actual_parameters,
- ctx);
- } else {
- assert(constructor_type->is_matrix());
- return emit_inline_matrix_constructor(constructor_type,
- instructions,
- &actual_parameters,
- ctx);
+ ir_rvalue *const constant = result->constant_expression_value();
+
+ if (constant != NULL)
+ result = constant;
+ else
+ all_parameters_are_constant = false;
+
+ if (result != ir) {
+ ir->replace_with(result);
}
}
- return ir_call::get_error_instruction(ctx);
+ /* If all of the parameters are trivially constant, create a
+ * constant representing the complete collection of parameters.
+ */
+ if (all_parameters_are_constant) {
+ if (components_used >= type_components)
+ return new(ctx) ir_constant(constructor_type,
+ & actual_parameters);
+
+ /* The above case must handle all scalar constructors.
+ */
+ assert(constructor_type->is_vector()
+ || constructor_type->is_matrix());
+
+ /* Constructors with exactly one component are special for
+ * vectors and matrices. For vectors it causes all elements of
+ * the vector to be filled with the value. For matrices it
+ * causes the matrix to be filled with 0 and the diagonal to be
+ * filled with the value.
+ */
+ ir_constant_data data;
+ ir_constant *const initializer =
+ (ir_constant *) actual_parameters.head;
+ if (constructor_type->is_matrix())
+ generate_constructor_matrix(constructor_type, initializer,
+ &data);
+ else
+ generate_constructor_vector(constructor_type, initializer,
+ &data);
+
+ return new(ctx) ir_constant(constructor_type, &data);
+ } else if (constructor_type->is_scalar()) {
+ return dereference_component((ir_rvalue *) actual_parameters.head,
+ 0);
+ } else if (constructor_type->is_vector()) {
+ return emit_inline_vector_constructor(constructor_type,
+ instructions,
+ &actual_parameters,
+ ctx);
+ } else {
+ assert(constructor_type->is_matrix());
+ return emit_inline_matrix_constructor(constructor_type,
+ instructions,
+ &actual_parameters,
+ ctx);
+ }
} else {
const ast_expression *id = subexpressions[0];
YYLTYPE loc = id->get_location();