* DEALINGS IN THE SOFTWARE.
*/
-#include <cstdio>
#include "glsl_symbol_table.h"
#include "ast.h"
#include "glsl_types.h"
foreach_list (n, parameters) {
ast_node *const ast = exec_node_data(ast_node, n, link);
- ir_rvalue *const result = ast->hir(instructions, state);
+ ir_rvalue *result = ast->hir(instructions, state);
+
+ ir_constant *const constant = result->constant_expression_value();
+ if (constant != NULL)
+ result = constant;
actual_parameters->push_tail(result);
count++;
static ir_rvalue *
match_function_by_name(exec_list *instructions, const char *name,
- YYLTYPE *loc, exec_list *parameters,
+ YYLTYPE *loc, exec_list *actual_parameters,
struct _mesa_glsl_parse_state *state)
{
ir_function *f = state->symbols->get_function(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.
+ /* Once we've determined that the function being called might exist, try
+ * to find an overload of the function that matches the parameters.
*/
- return process_call(instructions, f, loc, &actual_parameters, state);
+ return process_call(instructions, f, loc, actual_parameters, state);
}
{
const unsigned a = desired_type->base_type;
const unsigned b = src->type->base_type;
+ ir_expression *result = NULL;
if (src->type->is_error())
return src;
case GLSL_TYPE_UINT:
case GLSL_TYPE_INT:
if (b == GLSL_TYPE_FLOAT)
- return new ir_expression(ir_unop_f2i, desired_type, src, NULL);
+ result = new ir_expression(ir_unop_f2i, desired_type, src, NULL);
else {
assert(b == GLSL_TYPE_BOOL);
- return new ir_expression(ir_unop_b2i, desired_type, src, NULL);
+ result = new ir_expression(ir_unop_b2i, desired_type, src, NULL);
}
break;
case GLSL_TYPE_FLOAT:
switch (b) {
case GLSL_TYPE_UINT:
- return new ir_expression(ir_unop_u2f, desired_type, src, NULL);
+ result = new ir_expression(ir_unop_u2f, desired_type, src, NULL);
+ break;
case GLSL_TYPE_INT:
- return new ir_expression(ir_unop_i2f, desired_type, src, NULL);
+ result = new ir_expression(ir_unop_i2f, desired_type, src, NULL);
+ break;
case GLSL_TYPE_BOOL:
- return new ir_expression(ir_unop_b2f, desired_type, src, NULL);
+ result = new ir_expression(ir_unop_b2f, desired_type, src, NULL);
+ break;
}
break;
case GLSL_TYPE_BOOL: {
- int z = 0;
- ir_constant *const zero = new ir_constant(src->type, &z);
+ ir_constant *zero = NULL;
+
+ switch (b) {
+ case GLSL_TYPE_UINT: zero = new ir_constant(unsigned(0)); break;
+ case GLSL_TYPE_INT: zero = new ir_constant(int(0)); break;
+ case GLSL_TYPE_FLOAT: zero = new ir_constant(0.0f); break;
+ }
- return new ir_expression(ir_binop_nequal, desired_type, src, zero);
+ result = new ir_expression(ir_binop_nequal, desired_type, src, zero);
}
}
- assert(!"Should not get here.");
- return NULL;
+ assert(result != NULL);
+
+ ir_constant *const constant = result->constant_expression_value();
+ return (constant != NULL) ? (ir_rvalue *) constant : (ir_rvalue *) result;
}
*/
const int c = component / src->type->column_type()->vector_elements;
const int r = component % src->type->column_type()->vector_elements;
- ir_constant *const col_index = new ir_constant(glsl_type::int_type, &c);
+ ir_constant *const col_index = new ir_constant(c);
ir_dereference *const col = new ir_dereference_array(src, col_index);
col->type = src->type->column_type();
}
+/**
+ * Try to convert a record constructor to a constant expression
+ */
+static ir_constant *
+constant_record_constructor(const glsl_type *constructor_type,
+ YYLTYPE *loc, exec_list *parameters,
+ struct _mesa_glsl_parse_state *state)
+{
+ bool all_parameters_are_constant = true;
+
+ exec_node *node = parameters->head;
+ for (unsigned i = 0; i < constructor_type->length; i++) {
+ ir_instruction *ir = (ir_instruction *) node;
+
+ if (node->is_tail_sentinal()) {
+ _mesa_glsl_error(loc, state,
+ "insufficient parameters to constructor for `%s'",
+ constructor_type->name);
+ return NULL;
+ }
+
+ if (ir->type != constructor_type->fields.structure[i].type) {
+ _mesa_glsl_error(loc, state,
+ "parameter type mismatch in constructor for `%s' "
+ " (%s vs %s)",
+ constructor_type->name,
+ ir->type->name,
+ constructor_type->fields.structure[i].type->name);
+ return NULL;
+ }
+
+ if (ir->as_constant() == NULL)
+ all_parameters_are_constant = false;
+
+ node = node->next;
+ }
+
+ if (!all_parameters_are_constant)
+ return NULL;
+
+ return new ir_constant(constructor_type, parameters);
+}
+
+
+/**
+ * Generate data for a constant matrix constructor w/a single scalar parameter
+ *
+ * Matrix constructors in GLSL can be passed a single scalar of the
+ * approriate type. In these cases, the resulting matrix is the identity
+ * matrix multipled by the specified scalar. This function generates data for
+ * that matrix.
+ *
+ * \param type Type of the desired matrix.
+ * \param initializer Scalar value used to initialize the matrix diagonal.
+ * \param data Location to store the resulting matrix.
+ */
+void
+generate_constructor_matrix(const glsl_type *type, ir_constant *initializer,
+ ir_constant_data *data)
+{
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ for (unsigned i = 0; i < type->components(); i++)
+ data->u[i] = 0;
+
+ for (unsigned i = 0; i < type->matrix_columns; i++) {
+ /* The array offset of the ith row and column of the matrix.
+ */
+ const unsigned idx = (i * type->vector_elements) + i;
+
+ data->u[idx] = initializer->value.u[0];
+ }
+ break;
+
+ case GLSL_TYPE_FLOAT:
+ for (unsigned i = 0; i < type->components(); i++)
+ data->f[i] = 0;
+
+ for (unsigned i = 0; i < type->matrix_columns; i++) {
+ /* The array offset of the ith row and column of the matrix.
+ */
+ const unsigned idx = (i * type->vector_elements) + i;
+
+ data->f[idx] = initializer->value.f[0];
+ }
+
+ break;
+
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+}
+
+
+/**
+ * Generate data for a constant vector constructor w/a single scalar parameter
+ *
+ * Vector constructors in GLSL can be passed a single scalar of the
+ * approriate type. In these cases, the resulting vector contains the specified
+ * value in all components. This function generates data for that vector.
+ *
+ * \param type Type of the desired vector.
+ * \param initializer Scalar value used to initialize the vector.
+ * \param data Location to store the resulting vector data.
+ */
+void
+generate_constructor_vector(const glsl_type *type, ir_constant *initializer,
+ ir_constant_data *data)
+{
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ for (unsigned i = 0; i < type->components(); i++)
+ data->u[i] = initializer->value.u[0];
+
+ break;
+
+ case GLSL_TYPE_FLOAT:
+ for (unsigned i = 0; i < type->components(); i++)
+ data->f[i] = initializer->value.f[0];
+
+ break;
+
+ case GLSL_TYPE_BOOL:
+ for (unsigned i = 0; i < type->components(); i++)
+ data->b[i] = initializer->value.b[0];
+
+ break;
+
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+}
+
+
ir_rvalue *
ast_function_expression::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
bool all_parameters_are_constant = true;
- assert(!this->expressions.is_empty());
+ /* 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();
+ }
foreach_list (n, &this->expressions) {
ast_node *ast = exec_node_data(ast_node, n, link);
ir_rvalue *result =
ast->hir(instructions, state)->as_rvalue();
+ ir_variable *result_var = NULL;
/* Attempt to convert the parameter to a constant valued expression.
* After doing so, track whether or not all the parameters to the
else
nonmatrix_parameters++;
+ /* We can't use the same instruction node in the multiple
+ * swizzle dereferences that happen, so assign it to a
+ * variable and deref that. Plus it saves computation for
+ * complicated expressions and handles
+ * glsl-vs-constructor-call.shader_test.
+ */
+ if (result->type->components() >= 1 && !result->as_constant()) {
+ result_var = new ir_variable(result->type, "constructor_tmp");
+ ir_dereference_variable *lhs;
+
+ lhs = new ir_dereference_variable(result_var);
+ instructions->push_tail(new ir_assignment(lhs, result, NULL));
+ }
/* Process each of the components of the parameter. Dereference
* each component individually, perform any type conversions, and
if (components_used >= type_components)
break;
- ir_rvalue *const component =
- convert_component(dereference_component(result, i),
- base_type);
+ ir_rvalue *component;
+
+ if (result_var) {
+ ir_dereference *d = new ir_dereference_variable(result_var);
+ component = dereference_component(d, i);
+ } else {
+ component = dereference_component(result, i);
+ }
+ component = convert_component(component, base_type);
/* All cases that could result in component->type being the
* error type should have already been caught above.
/* If all of the parameters are trivially constant, create a
* constant representing the complete collection of parameters.
*/
- if (all_parameters_are_constant
- && (sig->return_type->is_scalar()
- || sig->return_type->is_vector()
- || sig->return_type->is_matrix())
- && (components_used >= type_components))
- return new ir_constant(sig->return_type, & actual_parameters);
- else
+ if (all_parameters_are_constant) {
+ if (components_used >= type_components)
+ return new ir_constant(sig->return_type, & actual_parameters);
+
+ assert(sig->return_type->is_vector()
+ || sig->return_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 (sig->return_type->is_matrix())
+ generate_constructor_matrix(sig->return_type, initializer,
+ &data);
+ else
+ generate_constructor_vector(sig->return_type, initializer,
+ &data);
+
+ return new ir_constant(sig->return_type, &data);
+ } else
return new ir_call(sig, & actual_parameters);
} else {
/* FINISHME: Log a better error message here. G++ will show the
} else {
const ast_expression *id = subexpressions[0];
YYLTYPE loc = id->get_location();
+ exec_list actual_parameters;
+
+ process_parameters(instructions, &actual_parameters, &this->expressions,
+ state);
+
+ const glsl_type *const type =
+ state->symbols->get_type(id->primary_expression.identifier);
+
+ if ((type != NULL) && type->is_record()) {
+ ir_constant *constant =
+ constant_record_constructor(type, &loc, &actual_parameters, state);
+
+ if (constant != NULL)
+ return constant;
+ }
return match_function_by_name(instructions,
id->primary_expression.identifier, & loc,
- &this->expressions, state);
+ &actual_parameters, state);
}
return ir_call::get_error_instruction();