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 | 21 +++--------- 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, 106 insertions(+), 45 deletions(-)
diff --git a/src/glsl/ast.h b/src/glsl/ast.h index ab94cb2..464ae4e 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,19 +332,14 @@ public: bool is_single_dimension() { - return (this->is_unsized_array && this->array_dimensions.is_empty()) || - (!this->is_unsized_array && - this->array_dimensions.tail_pred->prev != NULL && - this->array_dimensions.tail_pred->prev->is_head_sentinel()); + return this->array_dimensions.tail_pred->prev != NULL && + this->array_dimensions.tail_pred->prev->is_head_sentinel(); } 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 27e84d1..567fa7b 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 54569a8..af69ffd 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; @@ -2493,6 +2516,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, @@ -4164,6 +4206,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: @@ -5673,6 +5717,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; @@ -6127,6 +6172,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 @@ -6150,7 +6198,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; @@ -6177,9 +6225,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 7a4b55c..72606d2 100644 --- a/src/glsl/glsl_parser.yy +++ b/src/glsl/glsl_parser.yy @@ -1949,7 +1949,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 ']' @@ -1960,17 +1962,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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev