From bfb48750f08223fdf1c2d7bf4db1bba5a1088a7c Mon Sep 17 00:00:00 2001 From: Timothy Arceri Date: Thu, 23 Jan 2014 23:16:41 +1100 Subject: [PATCH] glsl: Add ARB_arrays_of_arrays support to yacc definition and ast Adds array specifier object to hold array information Signed-off-by: Timothy Arceri Reviewed-by: Paul Berry --- src/glsl/ast.h | 66 +++++++++--- src/glsl/ast_array_index.cpp | 13 +++ src/glsl/ast_to_hir.cpp | 172 +++++++++++++++++++------------- src/glsl/ast_type.cpp | 8 +- src/glsl/glsl_parser.yy | 128 +++++++++++------------- src/glsl/glsl_parser_extras.cpp | 19 ++-- src/glsl/glsl_parser_extras.h | 2 + 7 files changed, 235 insertions(+), 173 deletions(-) diff --git a/src/glsl/ast.h b/src/glsl/ast.h index b24052bfd04..d462dd59763 100644 --- a/src/glsl/ast.h +++ b/src/glsl/ast.h @@ -276,6 +276,43 @@ private: bool cons; }; +class ast_array_specifier : public ast_node { +public: + /** Unsized array specifier ([]) */ + explicit ast_array_specifier(const struct YYLTYPE &locp) + : dimension_count(1), is_unsized_array(true) + { + set_location(locp); + } + + /** Sized array specifier ([dim]) */ + ast_array_specifier(const struct YYLTYPE &locp, ast_expression *dim) + : dimension_count(1), is_unsized_array(false) + { + set_location(locp); + array_dimensions.push_tail(&dim->link); + } + + void add_dimension(ast_expression *dim) + { + array_dimensions.push_tail(&dim->link); + dimension_count++; + } + + virtual void print(void) const; + + /* Count including sized and unsized dimensions */ + unsigned dimension_count; + + /* 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. + */ + exec_list array_dimensions; +}; + /** * C-style aggregate initialization class * @@ -334,14 +371,15 @@ public: class ast_declaration : public ast_node { public: - ast_declaration(const char *identifier, bool is_array, ast_expression *array_size, - ast_expression *initializer); + ast_declaration(const char *identifier, bool is_array, + ast_array_specifier *array_specifier, + ast_expression *initializer); virtual void print(void) const; const char *identifier; bool is_array; - ast_expression *array_size; + ast_array_specifier *array_specifier; ast_expression *initializer; }; @@ -551,9 +589,9 @@ public: * be modified. Zeros the inherited ast_node's fields. */ ast_type_specifier(const ast_type_specifier *that, bool is_array, - ast_expression *array_size) + ast_array_specifier *array_specifier) : ast_node(), type_name(that->type_name), structure(that->structure), - is_array(is_array), array_size(array_size), + is_array(is_array), array_specifier(array_specifier), default_precision(that->default_precision) { /* empty */ @@ -562,7 +600,7 @@ public: /** Construct a type specifier from a type name */ ast_type_specifier(const char *name) : type_name(name), structure(NULL), - is_array(false), array_size(NULL), + is_array(false), array_specifier(NULL), default_precision(ast_precision_none) { /* empty */ @@ -571,7 +609,7 @@ public: /** Construct a type specifier from a structure definition */ ast_type_specifier(ast_struct_specifier *s) : type_name(s->name), structure(s), - is_array(false), array_size(NULL), + is_array(false), array_specifier(NULL), default_precision(ast_precision_none) { /* empty */ @@ -589,7 +627,7 @@ public: ast_struct_specifier *structure; bool is_array; - ast_expression *array_size; + ast_array_specifier *array_specifier; /** For precision statements, this is the given precision; otherwise none. */ unsigned default_precision:2; @@ -643,7 +681,7 @@ public: type(NULL), identifier(NULL), is_array(false), - array_size(NULL), + array_specifier(NULL), formal_parameter(false), is_void(false) { @@ -658,7 +696,7 @@ public: ast_fully_specified_type *type; const char *identifier; bool is_array; - ast_expression *array_size; + ast_array_specifier *array_specifier; static void parameters_to_hir(exec_list *ast_parameters, bool formal, exec_list *ir_parameters, @@ -906,12 +944,12 @@ public: ast_interface_block(ast_type_qualifier layout, const char *instance_name, bool is_array, - ast_expression *array_size) + ast_array_specifier *array_specifier) : layout(layout), block_name(NULL), instance_name(instance_name), - is_array(is_array), array_size(array_size) + is_array(is_array), array_specifier(array_specifier) { if (!is_array) - assert(array_size == NULL); + assert(array_specifier == NULL); } virtual ir_rvalue *hir(exec_list *instructions, @@ -946,7 +984,7 @@ public: * If the block is not declared as an array or if the block instance array * is unsized, this field will be \c NULL. */ - ast_expression *array_size; + ast_array_specifier *array_specifier; }; diff --git a/src/glsl/ast_array_index.cpp b/src/glsl/ast_array_index.cpp index a5f23206acf..f3b060ea657 100644 --- a/src/glsl/ast_array_index.cpp +++ b/src/glsl/ast_array_index.cpp @@ -25,6 +25,19 @@ #include "glsl_types.h" #include "ir.h" +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(); + printf("] "); + } +} /** * If \c ir is a reference to an array for which we are tracking the max array diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 8d13610e426..e25cba3fa64 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -1771,64 +1771,108 @@ ast_compound_statement::hir(exec_list *instructions, return NULL; } +/** + * Evaluate the given exec_node (which should be an ast_node representing + * a single array dimension) and return its integer value. + */ +static const unsigned +process_array_size(exec_node *node, + struct _mesa_glsl_parse_state *state) +{ + exec_list dummy_instructions; + + ast_node *array_size = exec_node_data(ast_node, node, link); + ir_rvalue *const ir = array_size->hir(& dummy_instructions, + state); + YYLTYPE loc = array_size->get_location(); + + if (ir == NULL) { + _mesa_glsl_error(& loc, state, + "array size could not be resolved"); + return 0; + } + + if (!ir->type->is_integer()) { + _mesa_glsl_error(& loc, state, + "array size must be integer type"); + return 0; + } + + if (!ir->type->is_scalar()) { + _mesa_glsl_error(& loc, state, + "array size must be scalar type"); + return 0; + } + + ir_constant *const size = ir->constant_expression_value(); + if (size == NULL) { + _mesa_glsl_error(& loc, state, "array size must be a " + "constant valued expression"); + return 0; + } + + if (size->value.i[0] <= 0) { + _mesa_glsl_error(& loc, state, "array size must be > 0"); + return 0; + } + + assert(size->type == ir->type); + + /* If the array size is const (and we've verified that + * it is) then no instructions should have been emitted + * when we converted it to HIR. If they were emitted, + * then either the array size isn't const after all, or + * we are emitting unnecessary instructions. + */ + assert(dummy_instructions.is_empty()); + + return size->value.u[0]; +} static const glsl_type * -process_array_type(YYLTYPE *loc, const glsl_type *base, ast_node *array_size, - struct _mesa_glsl_parse_state *state) +process_array_type(YYLTYPE *loc, const glsl_type *base, + ast_array_specifier *array_specifier, + struct _mesa_glsl_parse_state *state) { - unsigned length = 0; + const glsl_type *array_type = base; - if (base == NULL) - return glsl_type::error_type; + if (array_specifier != NULL) { + if (base->is_array()) { - /* From page 19 (page 25) of the GLSL 1.20 spec: - * - * "Only one-dimensional arrays may be declared." - */ - if (base->is_array()) { - _mesa_glsl_error(loc, state, - "invalid array of `%s' (only one-dimensional arrays " - "may be declared)", - base->name); - return glsl_type::error_type; - } + /* From page 19 (page 25) of the GLSL 1.20 spec: + * + * "Only one-dimensional arrays may be declared." + */ + if (!state->ARB_arrays_of_arrays_enable) { + _mesa_glsl_error(loc, state, + "invalid array of `%s'" + "GL_ARB_arrays_of_arrays " + "required for defining arrays of arrays", + base->name); + return glsl_type::error_type; + } - if (array_size != NULL) { - exec_list dummy_instructions; - ir_rvalue *const ir = array_size->hir(& dummy_instructions, state); - YYLTYPE loc = array_size->get_location(); + if (base->length == 0) { + _mesa_glsl_error(loc, state, + "only the outermost array dimension can " + "be unsized", + base->name); + return glsl_type::error_type; + } + } - if (ir != NULL) { - if (!ir->type->is_integer()) { - _mesa_glsl_error(& loc, state, "array size must be integer type"); - } else if (!ir->type->is_scalar()) { - _mesa_glsl_error(& loc, state, "array size must be scalar type"); - } else { - ir_constant *const size = ir->constant_expression_value(); - - if (size == NULL) { - _mesa_glsl_error(& loc, state, "array size must be a " - "constant valued expression"); - } else if (size->value.i[0] <= 0) { - _mesa_glsl_error(& loc, state, "array size must be > 0"); - } else { - assert(size->type == ir->type); - length = size->value.u[0]; - - /* If the array size is const (and we've verified that - * it is) then no instructions should have been emitted - * when we converted it to HIR. If they were emitted, - * then either the array size isn't const after all, or - * we are emitting unnecessary instructions. - */ - assert(dummy_instructions.is_empty()); - } - } + for (exec_node *node = array_specifier->array_dimensions.tail_pred; + !node->is_head_sentinel(); node = node->prev) { + 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); } - const glsl_type *array_type = glsl_type::get_array_instance(base, length); - return array_type != NULL ? array_type : glsl_type::error_type; + return array_type; } @@ -1841,10 +1885,8 @@ ast_type_specifier::glsl_type(const char **name, type = state->symbols->get_type(this->type_name); *name = this->type_name; - if (this->is_array) { - YYLTYPE loc = this->get_location(); - type = process_array_type(&loc, type, this->array_size, state); - } + YYLTYPE loc = this->get_location(); + type = process_array_type(&loc, type, this->array_specifier, state); return type; } @@ -2831,7 +2873,7 @@ ast_declarator_list::hir(exec_list *instructions, foreach_list_typed (ast_declaration, decl, link, &this->declarations) { assert(!decl->is_array); - assert(decl->array_size == NULL); + assert(decl->array_specifier == NULL); assert(decl->initializer == NULL); ir_variable *const earlier = @@ -2966,14 +3008,8 @@ ast_declarator_list::hir(exec_list *instructions, continue; } - if (decl->is_array) { - var_type = process_array_type(&loc, decl_type, decl->array_size, - state); - if (var_type->is_error()) - continue; - } else { - var_type = decl_type; - } + var_type = process_array_type(&loc, decl_type, decl->array_specifier, + state); var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto); @@ -3530,9 +3566,7 @@ ast_parameter_declarator::hir(exec_list *instructions, /* This only handles "vec4 foo[..]". The earlier specifier->glsl_type(...) * call already handled the "vec4[..] foo" case. */ - if (this->is_array) { - type = process_array_type(&loc, type, this->array_size, state); - } + type = process_array_type(&loc, type, this->array_specifier, state); if (!type->is_error() && type->is_unsized_array()) { _mesa_glsl_error(&loc, state, "arrays passed as parameters must have " @@ -4660,10 +4694,8 @@ ast_process_structure_or_interface_block(exec_list *instructions, "members"); } - if (decl->is_array) { - field_type = process_array_type(&loc, decl_type, decl->array_size, - state); - } + field_type = process_array_type(&loc, decl_type, + decl->array_specifier, state); fields[i].type = field_type; fields[i].name = decl->identifier; fields[i].location = -1; @@ -5045,7 +5077,7 @@ ast_interface_block::hir(exec_list *instructions, * interface array size *doesn't* need to be specified is on a * geometry shader input. */ - if (this->array_size == NULL && + if (this->array_specifier->is_unsized_array && (state->stage != MESA_SHADER_GEOMETRY || !this->layout.flags.q.in)) { _mesa_glsl_error(&loc, state, "only geometry shader inputs may be unsized " @@ -5054,7 +5086,7 @@ ast_interface_block::hir(exec_list *instructions, } const glsl_type *block_array_type = - process_array_type(&loc, block_type, this->array_size, state); + process_array_type(&loc, block_type, this->array_specifier, state); var = new(state) ir_variable(block_array_type, this->instance_name, diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp index d758bfa1f2a..0dd1180c37f 100644 --- a/src/glsl/ast_type.cpp +++ b/src/glsl/ast_type.cpp @@ -33,13 +33,9 @@ ast_type_specifier::print(void) const } if (is_array) { - printf("[ "); - - if (array_size) { - array_size->print(); + if (array_specifier) { + array_specifier->print(); } - - printf("] "); } } diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy index 5451b764a77..2786e920922 100644 --- a/src/glsl/glsl_parser.yy +++ b/src/glsl/glsl_parser.yy @@ -97,6 +97,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, ast_node *node; ast_type_specifier *type_specifier; + ast_array_specifier *array_specifier; ast_fully_specified_type *fully_specified_type; ast_function *function; ast_parameter_declarator *parameter_declarator; @@ -202,6 +203,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, %type interface_qualifier %type type_specifier %type type_specifier_nonarray +%type array_specifier %type basic_type_specifier_nonarray %type fully_specified_type %type function_prototype @@ -880,7 +882,7 @@ parameter_declarator: $$->type->specifier = $1; $$->identifier = $2; } - | type_specifier any_identifier '[' constant_expression ']' + | type_specifier any_identifier array_specifier { void *ctx = state; $$ = new(ctx) ast_parameter_declarator(); @@ -889,8 +891,7 @@ parameter_declarator: $$->type->set_location(yylloc); $$->type->specifier = $1; $$->identifier = $2; - $$->is_array = true; - $$->array_size = $4; + $$->array_specifier = $3; } ; @@ -983,40 +984,20 @@ init_declarator_list: $$->declarations.push_tail(&decl->link); state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto)); } - | init_declarator_list ',' any_identifier '[' ']' + | init_declarator_list ',' any_identifier array_specifier { void *ctx = state; - ast_declaration *decl = new(ctx) ast_declaration($3, true, NULL, NULL); + ast_declaration *decl = new(ctx) ast_declaration($3, true, $4, NULL); decl->set_location(yylloc); $$ = $1; $$->declarations.push_tail(&decl->link); state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto)); } - | init_declarator_list ',' any_identifier '[' constant_expression ']' + | init_declarator_list ',' any_identifier array_specifier '=' initializer { void *ctx = state; - ast_declaration *decl = new(ctx) ast_declaration($3, true, $5, NULL); - decl->set_location(yylloc); - - $$ = $1; - $$->declarations.push_tail(&decl->link); - state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto)); - } - | init_declarator_list ',' any_identifier '[' ']' '=' initializer - { - void *ctx = state; - ast_declaration *decl = new(ctx) ast_declaration($3, true, NULL, $7); - decl->set_location(yylloc); - - $$ = $1; - $$->declarations.push_tail(&decl->link); - state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto)); - } - | init_declarator_list ',' any_identifier '[' constant_expression ']' '=' initializer - { - void *ctx = state; - ast_declaration *decl = new(ctx) ast_declaration($3, true, $5, $8); + ast_declaration *decl = new(ctx) ast_declaration($3, true, $4, $6); decl->set_location(yylloc); $$ = $1; @@ -1053,37 +1034,19 @@ single_declaration: $$->set_location(yylloc); $$->declarations.push_tail(&decl->link); } - | fully_specified_type any_identifier '[' ']' + | fully_specified_type any_identifier array_specifier { void *ctx = state; - ast_declaration *decl = new(ctx) ast_declaration($2, true, NULL, NULL); + ast_declaration *decl = new(ctx) ast_declaration($2, true, $3, NULL); $$ = new(ctx) ast_declarator_list($1); $$->set_location(yylloc); $$->declarations.push_tail(&decl->link); } - | fully_specified_type any_identifier '[' constant_expression ']' + | fully_specified_type any_identifier array_specifier '=' initializer { void *ctx = state; - ast_declaration *decl = new(ctx) ast_declaration($2, true, $4, NULL); - - $$ = new(ctx) ast_declarator_list($1); - $$->set_location(yylloc); - $$->declarations.push_tail(&decl->link); - } - | fully_specified_type any_identifier '[' ']' '=' initializer - { - void *ctx = state; - ast_declaration *decl = new(ctx) ast_declaration($2, true, NULL, $6); - - $$ = new(ctx) ast_declarator_list($1); - $$->set_location(yylloc); - $$->declarations.push_tail(&decl->link); - } - | fully_specified_type any_identifier '[' constant_expression ']' '=' initializer - { - void *ctx = state; - ast_declaration *decl = new(ctx) ast_declaration($2, true, $4, $7); + ast_declaration *decl = new(ctx) ast_declaration($2, true, $3, $5); $$ = new(ctx) ast_declarator_list($1); $$->set_location(yylloc); @@ -1584,19 +1547,51 @@ storage_qualifier: } ; -type_specifier: - type_specifier_nonarray - | type_specifier_nonarray '[' ']' +array_specifier: + '[' ']' + { + void *ctx = state; + $$ = new(ctx) ast_array_specifier(yylloc); + } + | '[' constant_expression ']' + { + void *ctx = state; + $$ = new(ctx) ast_array_specifier(yylloc, $2); + } + | array_specifier '[' ']' + { + $$ = $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"); + } + } + | array_specifier '[' constant_expression ']' { $$ = $1; - $$->is_array = true; - $$->array_size = NULL; + + if (!state->ARB_arrays_of_arrays_enable) { + _mesa_glsl_error(& @1, state, + "GL_ARB_arrays_of_arrays " + "required for defining arrays of arrays"); + } + + $$->add_dimension($3); } - | type_specifier_nonarray '[' constant_expression ']' + ; + +type_specifier: + type_specifier_nonarray + | type_specifier_nonarray array_specifier { $$ = $1; - $$->is_array = true; - $$->array_size = $3; + $$->array_specifier = $2; } ; @@ -1779,16 +1774,10 @@ struct_declarator: $$ = new(ctx) ast_declaration($1, false, NULL, NULL); $$->set_location(yylloc); } - | any_identifier '[' ']' + | any_identifier array_specifier { void *ctx = state; - $$ = new(ctx) ast_declaration($1, true, NULL, NULL); - $$->set_location(yylloc); - } - | any_identifier '[' constant_expression ']' - { - void *ctx = state; - $$ = new(ctx) ast_declaration($1, true, $3, NULL); + $$ = new(ctx) ast_declaration($1, true, $2, NULL); $$->set_location(yylloc); } ; @@ -2288,15 +2277,10 @@ instance_name_opt: $$ = new(state) ast_interface_block(*state->default_uniform_qualifier, $1, false, NULL); } - | NEW_IDENTIFIER '[' constant_expression ']' - { - $$ = new(state) ast_interface_block(*state->default_uniform_qualifier, - $1, true, $3); - } - | NEW_IDENTIFIER '[' ']' + | NEW_IDENTIFIER array_specifier { $$ = new(state) ast_interface_block(*state->default_uniform_qualifier, - $1, true, NULL); + $1, true, $2); } ; diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 345e426b75a..ceb42b61722 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -484,6 +484,7 @@ struct _mesa_glsl_extension { static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = { /* API availability */ /* name GL ES supported flag */ + EXT(ARB_arrays_of_arrays, true, false, ARB_arrays_of_arrays), EXT(ARB_conservative_depth, true, false, ARB_conservative_depth), EXT(ARB_draw_buffers, true, false, dummy_true), EXT(ARB_draw_instanced, true, false, ARB_draw_instanced), @@ -789,15 +790,11 @@ ast_node::ast_node(void) static void -ast_opt_array_size_print(bool is_array, const ast_expression *array_size) +ast_opt_array_dimensions_print(bool is_array, const ast_array_specifier *array_specifier) { if (is_array) { - printf("[ "); - - if (array_size) - array_size->print(); - - printf("] "); + if (array_specifier) + array_specifier->print(); } } @@ -1021,7 +1018,7 @@ ast_parameter_declarator::print(void) const type->print(); if (identifier) printf("%s ", identifier); - ast_opt_array_size_print(is_array, array_size); + ast_opt_array_dimensions_print(is_array, array_specifier); } @@ -1037,7 +1034,7 @@ void ast_declaration::print(void) const { printf("%s ", identifier); - ast_opt_array_size_print(is_array, array_size); + ast_opt_array_dimensions_print(is_array, array_specifier); if (initializer) { printf("= "); @@ -1047,12 +1044,12 @@ ast_declaration::print(void) const ast_declaration::ast_declaration(const char *identifier, bool is_array, - ast_expression *array_size, + ast_array_specifier *array_specifier, ast_expression *initializer) { this->identifier = identifier; this->is_array = is_array; - this->array_size = array_size; + this->array_specifier = array_specifier; this->initializer = initializer; } diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index 6f60b73b31c..8a4cbf14c91 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -294,6 +294,8 @@ struct _mesa_glsl_parse_state { * \name Enable bits for GLSL extensions */ /*@{*/ + bool ARB_arrays_of_arrays_enable; + bool ARB_arrays_of_arrays_warn; bool ARB_draw_buffers_enable; bool ARB_draw_buffers_warn; bool ARB_draw_instanced_enable; -- 2.30.2