[Mesa-dev] [PATCH V7 03/24] glsl: allow AoA to be sized by initializer or constructor
Samuel Iglesias Gonsálvez
siglesias at igalia.com
Fri Oct 9 04:33:29 PDT 2015
On 09/10/15 13:25, Timothy Arceri wrote:
> On Thu, 2015-10-08 at 11:08 +0200, Samuel Iglesias Gonsálvez wrote:
>> On 07/10/15 00:47, Timothy Arceri wrote:
>>> 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 4c31436..b43be24 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 5e8f49d..7855e0a 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 26d4c62..cf4e64a 100644
>>> --- a/src/glsl/ast_function.cpp
>>> +++ b/src/glsl/ast_function.cpp
>>> @@ -950,6 +950,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) {
>>> @@ -976,12 +977,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.
>>> @@ -998,6 +1021,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 9511440..3dfa3e6 100644
>>> --- a/src/glsl/ast_to_hir.cpp
>>> +++ b/src/glsl/ast_to_hir.cpp
>>> @@ -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 {
>>> @@ -1804,6 +1826,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.
>>> @@ -1967,6 +1993,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
>>
>> s/by/be
>>
>>> + * 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();
>>>
>>> @@ -2035,14 +2069,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;
>>> @@ -2050,9 +2076,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;
>>> @@ -2591,6 +2614,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;
>>> + }
>>> + }
>>> +}
>>> +
>>
>> It seems the changes related to of array dimensions could be in a
>> separate patch.
>
> Thanks for all the reviews :)
>
> Yes I can split the validation out into its own patch. I thin preceding
> this one.
>
OK, thanks.
>
>>
>>> static void
>>> apply_type_qualifier_to_variable(const struct ast_type_qualifier
>>> *qual,
>>> ir_variable *var,
>>> @@ -4264,6 +4306,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:
>>> @@ -5789,6 +5833,7 @@
>>> ast_process_structure_or_interface_block(exec_list *instructions,
>>>
>>> const struct glsl_type *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;
>>> @@ -6304,6 +6349,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
>>> @@ -6327,7 +6375,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()) {
>>
>>
>> I guess this is needed as interface blocks (e.g. uniform blocks) can
>> be
>> arrays of arrays?
>>
>
> No its because this patch removes the is_unsized_array field. This code
> is used by single dimension arrays also.
>
OK, thanks for the explanation.
This patch (except validation code which would be in a separate one) is:
Reviewed-by: Samuel Iglesias Gonsálvez <siglesias at igalia.com>
Sam
>> If that it's the case, it seems this hunk can be in a separate patch,
>> right?
>>
>> Sam
>>
>>> bool allow_inputs = state->stage ==
>>> MESA_SHADER_GEOMETRY ||
>>> state->stage ==
>>> MESA_SHADER_TESS_CTRL ||
>>> state->stage ==
>>> MESA_SHADER_TESS_EVAL;
>>> @@ -6354,9 +6402,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 c1bcccc..16c9171 100644
>>> --- a/src/glsl/glsl_parser.yy
>>> +++ b/src/glsl/glsl_parser.yy
>>> @@ -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 ']'
>>> {
>>>
>
More information about the mesa-dev
mailing list