glsl: allow AoA to be sized by initializer or constructor

V2: Split out unsized array validation to its own patch as
suggested by Samuel.

Reviewed-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com>
This commit is contained in:
Timothy Arceri
2015-10-15 14:32:41 +11:00
parent 296a7ea471
commit 3129359ed7
5 changed files with 82 additions and 41 deletions
+2 -13
View File
@@ -183,6 +183,7 @@ enum ast_operators {
ast_post_dec,
ast_field_selection,
ast_array_index,
ast_unsized_array_dim,
ast_function_call,
@@ -324,16 +325,7 @@ public:
class ast_array_specifier : public ast_node {
public:
/** Unsized array specifier ([]) */
explicit ast_array_specifier(const struct YYLTYPE &locp)
: is_unsized_array(true)
{
set_location(locp);
}
/** Sized array specifier ([dim]) */
ast_array_specifier(const struct YYLTYPE &locp, ast_expression *dim)
: is_unsized_array(false)
{
set_location(locp);
array_dimensions.push_tail(&dim->link);
@@ -346,11 +338,8 @@ public:
virtual void print(void) const;
/* If true, this means that the array has an unsized outermost dimension. */
bool is_unsized_array;
/* This list contains objects of type ast_node containing the
* sized dimensions only, in outermost-to-innermost order.
* array dimensions in outermost-to-innermost order.
*/
exec_list array_dimensions;
};
+2 -5
View File
@@ -28,13 +28,10 @@
void
ast_array_specifier::print(void) const
{
if (this->is_unsized_array) {
printf("[ ] ");
}
foreach_list_typed (ast_node, array_dimension, link, &this->array_dimensions) {
printf("[ ");
array_dimension->print();
if (((ast_expression*)array_dimension)->oper != ast_unsized_array_dim)
array_dimension->print();
printf("] ");
}
}
+32 -1
View File
@@ -991,6 +991,7 @@ process_array_constructor(exec_list *instructions,
}
bool all_parameters_are_constant = true;
const glsl_type *element_type = constructor_type->fields.array;
/* Type cast each parameter and, if possible, fold constants. */
foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) {
@@ -1017,12 +1018,34 @@ process_array_constructor(exec_list *instructions,
}
}
if (result->type != constructor_type->fields.array) {
if (constructor_type->fields.array->is_unsized_array()) {
/* As the inner parameters of the constructor are created without
* knowledge of each other we need to check to make sure unsized
* parameters of unsized constructors all end up with the same size.
*
* e.g we make sure to fail for a constructor like this:
* vec4[][] a = vec4[][](vec4[](vec4(0.0), vec4(1.0)),
* vec4[](vec4(0.0), vec4(1.0), vec4(1.0)),
* vec4[](vec4(0.0), vec4(1.0)));
*/
if (element_type->is_unsized_array()) {
/* This is the first parameter so just get the type */
element_type = result->type;
} else if (element_type != result->type) {
_mesa_glsl_error(loc, state, "type error in array constructor: "
"expected: %s, found %s",
element_type->name,
result->type->name);
return ir_rvalue::error_value(ctx);
}
} else if (result->type != constructor_type->fields.array) {
_mesa_glsl_error(loc, state, "type error in array constructor: "
"expected: %s, found %s",
constructor_type->fields.array->name,
result->type->name);
return ir_rvalue::error_value(ctx);
} else {
element_type = result->type;
}
/* Attempt to convert the parameter to a constant valued expression.
@@ -1039,6 +1062,14 @@ process_array_constructor(exec_list *instructions,
ir->replace_with(result);
}
if (constructor_type->fields.array->is_unsized_array()) {
constructor_type =
glsl_type::get_array_instance(element_type,
parameter_count);
assert(constructor_type != NULL);
assert(constructor_type->length == parameter_count);
}
if (all_parameters_are_constant)
return new(ctx) ir_constant(constructor_type, &actual_parameters);
+40 -17
View File
@@ -782,8 +782,30 @@ validate_assignment(struct _mesa_glsl_parse_state *state,
* Note: Whole-array assignments are not permitted in GLSL 1.10, but this
* is handled by ir_dereference::is_lvalue.
*/
if (lhs->type->is_unsized_array() && rhs->type->is_array()
&& (lhs->type->fields.array == rhs->type->fields.array)) {
const glsl_type *lhs_t = lhs->type;
const glsl_type *rhs_t = rhs->type;
bool unsized_array = false;
while(lhs_t->is_array()) {
if (rhs_t == lhs_t)
break; /* the rest of the inner arrays match so break out early */
if (!rhs_t->is_array()) {
unsized_array = false;
break; /* number of dimensions mismatch */
}
if (lhs_t->length == rhs_t->length) {
lhs_t = lhs_t->fields.array;
rhs_t = rhs_t->fields.array;
continue;
} else if (lhs_t->is_unsized_array()) {
unsized_array = true;
} else {
unsized_array = false;
break; /* sized array mismatch */
}
lhs_t = lhs_t->fields.array;
rhs_t = rhs_t->fields.array;
}
if (unsized_array) {
if (is_initializer) {
return rhs;
} else {
@@ -1810,6 +1832,10 @@ ast_expression::do_hir(exec_list *instructions,
break;
}
case ast_unsized_array_dim:
assert(!"ast_unsized_array_dim: Should never get here.");
break;
case ast_function_call:
/* Should *NEVER* get here. ast_function_call should always be handled
* by ast_function_expression::hir.
@@ -2047,6 +2073,14 @@ process_array_size(exec_node *node,
exec_list dummy_instructions;
ast_node *array_size = exec_node_data(ast_node, node, link);
/**
* Dimensions other than the outermost dimension can by unsized if they
* are immediately sized by a constructor or initializer.
*/
if (((ast_expression*)array_size)->oper == ast_unsized_array_dim)
return 0;
ir_rvalue *const ir = array_size->hir(& dummy_instructions, state);
YYLTYPE loc = array_size->get_location();
@@ -2115,14 +2149,6 @@ process_array_type(YYLTYPE *loc, const glsl_type *base,
base->name);
return glsl_type::error_type;
}
if (base->length == 0) {
_mesa_glsl_error(loc, state,
"only the outermost array dimension can "
"be unsized",
base->name);
return glsl_type::error_type;
}
}
for (exec_node *node = array_specifier->array_dimensions.tail_pred;
@@ -2130,9 +2156,6 @@ process_array_type(YYLTYPE *loc, const glsl_type *base,
unsigned array_size = process_array_size(node, state);
array_type = glsl_type::get_array_instance(array_type, array_size);
}
if (array_specifier->is_unsized_array)
array_type = glsl_type::get_array_instance(array_type, 0);
}
return array_type;
@@ -6453,6 +6476,9 @@ ast_interface_block::hir(exec_list *instructions,
ir_variable *var;
if (this->array_specifier != NULL) {
const glsl_type *block_array_type =
process_array_type(&loc, block_type, this->array_specifier, state);
/* Section 4.3.7 (Interface Blocks) of the GLSL 1.50 spec says:
*
* For uniform blocks declared an array, each individual array
@@ -6476,7 +6502,7 @@ ast_interface_block::hir(exec_list *instructions,
* tessellation control shader output, and tessellation evaluation
* shader input.
*/
if (this->array_specifier->is_unsized_array) {
if (block_array_type->is_unsized_array()) {
bool allow_inputs = state->stage == MESA_SHADER_GEOMETRY ||
state->stage == MESA_SHADER_TESS_CTRL ||
state->stage == MESA_SHADER_TESS_EVAL;
@@ -6503,9 +6529,6 @@ ast_interface_block::hir(exec_list *instructions,
}
}
const glsl_type *block_array_type =
process_array_type(&loc, block_type, this->array_specifier, state);
/* From section 4.3.9 (Interface Blocks) of the GLSL ES 3.10 spec:
*
* * Arrays of arrays of blocks are not allowed
+6 -5
View File
@@ -1962,7 +1962,9 @@ array_specifier:
'[' ']'
{
void *ctx = state;
$$ = new(ctx) ast_array_specifier(@1);
$$ = new(ctx) ast_array_specifier(@1, new(ctx) ast_expression(
ast_unsized_array_dim, NULL,
NULL, NULL));
$$->set_location_range(@1, @2);
}
| '[' constant_expression ']'
@@ -1973,17 +1975,16 @@ array_specifier:
}
| array_specifier '[' ']'
{
void *ctx = state;
$$ = $1;
if (!state->ARB_arrays_of_arrays_enable) {
_mesa_glsl_error(& @1, state,
"GL_ARB_arrays_of_arrays "
"required for defining arrays of arrays");
} else {
_mesa_glsl_error(& @1, state,
"only the outermost array dimension can "
"be unsized");
}
$$->add_dimension(new(ctx) ast_expression(ast_unsized_array_dim, NULL,
NULL, NULL));
}
| array_specifier '[' constant_expression ']'
{