[Mesa-dev] [PATCH 07/24] glsl: allow AoA to be sized by initializer or constructor
Timothy Arceri
t_arceri at yahoo.com.au
Thu Sep 17 00:02:51 PDT 2015
>From Section 4.1.9 of the GLSL ES 3.10 spec:
"Arrays are sized either at compile-time or at run-time.
To size an array at compile-time, either the size
must be specified within the brackets as above or
must be inferred from the type of the initializer."
---
src/glsl/ast.h | 15 ++-------
src/glsl/ast_array_index.cpp | 7 ++--
src/glsl/ast_function.cpp | 33 +++++++++++++++++-
src/glsl/ast_to_hir.cpp | 79 ++++++++++++++++++++++++++++++++++----------
src/glsl/glsl_parser.yy | 11 +++---
5 files changed, 104 insertions(+), 41 deletions(-)
diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index d8c6cea..230b602 100644
--- a/src/glsl/ast.h
+++ b/src/glsl/ast.h
@@ -181,6 +181,7 @@ enum ast_operators {
ast_post_dec,
ast_field_selection,
ast_array_index,
+ ast_unsized_array_dim,
ast_function_call,
@@ -318,16 +319,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);
@@ -340,11 +332,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;
};
diff --git a/src/glsl/ast_array_index.cpp b/src/glsl/ast_array_index.cpp
index ae399f0..a91258f 100644
--- a/src/glsl/ast_array_index.cpp
+++ b/src/glsl/ast_array_index.cpp
@@ -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("] ");
}
}
diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
index 803edf5..d003655 100644
--- a/src/glsl/ast_function.cpp
+++ b/src/glsl/ast_function.cpp
@@ -908,6 +908,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) {
@@ -934,12 +935,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.
@@ -956,6 +979,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);
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index f4c7240..1d91029 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -726,8 +726,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 {
@@ -1739,6 +1761,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.
@@ -1902,6 +1928,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();
@@ -1970,14 +2004,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;
@@ -1985,9 +2011,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;
@@ -2526,6 +2549,25 @@ is_conflicting_fragcoord_redeclaration(struct _mesa_glsl_parse_state *state,
return false;
}
+static inline void
+validate_array_dimensions(const glsl_type *t,
+ struct _mesa_glsl_parse_state *state,
+ YYLTYPE *loc) {
+ if (t->is_array()) {
+ t = t->fields.array;
+ while (t->is_array()) {
+ if (t->is_unsized_array()) {
+ _mesa_glsl_error(loc, state,
+ "only the outermost array dimension can "
+ "be unsized",
+ t->name);
+ break;
+ }
+ t = t->fields.array;
+ }
+ }
+}
+
static void
apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
ir_variable *var,
@@ -4197,6 +4239,8 @@ ast_declarator_list::hir(exec_list *instructions,
result = process_initializer((earlier == NULL) ? var : earlier,
decl, this->type,
&initializer_instructions, state);
+ } else {
+ validate_array_dimensions(var_type, state, &loc);
}
/* From page 23 (page 29 of the PDF) of the GLSL 1.10 spec:
@@ -5708,6 +5752,7 @@ ast_process_structure_or_interface_block(exec_list *instructions,
field_type = process_array_type(&loc, decl_type,
decl->array_specifier, state);
+ validate_array_dimensions(field_type, state, &loc);
fields[i].type = field_type;
fields[i].name = decl->identifier;
fields[i].location = -1;
@@ -6161,6 +6206,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
@@ -6184,7 +6232,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;
@@ -6211,9 +6259,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
diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy
index 59e4527..bdd4dea 100644
--- a/src/glsl/glsl_parser.yy
+++ b/src/glsl/glsl_parser.yy
@@ -1958,7 +1958,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 ']'
@@ -1969,17 +1971,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 ']'
{
--
2.4.3
More information about the mesa-dev
mailing list