[Mesa-dev] [PATCH 14/14] glsl: Add support for C-style initializers.

Matt Turner mattst88 at gmail.com
Sat Jun 29 19:44:04 PDT 2013


Required by GL_ARB_shading_language_420pack.

Parts based on work done by Todd Previte and Ken Graunke, implementing
basic support for C-style initializers of arrays.
---
 src/glsl/ast.h                  |   5 ++
 src/glsl/ast_to_hir.cpp         |  14 +++-
 src/glsl/glsl_parser.yy         |  63 ++++++++++++++
 src/glsl/glsl_parser_extras.cpp | 179 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 260 insertions(+), 1 deletion(-)

diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index 5b1e7d3..2bf967c 100644
--- a/src/glsl/ast.h
+++ b/src/glsl/ast.h
@@ -903,6 +903,11 @@ _mesa_ast_array_index_to_hir(void *mem_ctx,
 			     ir_rvalue *array, ir_rvalue *idx,
 			     YYLTYPE &loc, YYLTYPE &idx_loc);
 
+extern void
+_mesa_ast_set_aggregate_type(const ast_type_specifier *type,
+                             ast_expression *expr,
+                             _mesa_glsl_parse_state *state);
+
 void
 emit_function(_mesa_glsl_parse_state *state, ir_function *f);
 
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 8d78f34..b9f8df5 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -4005,7 +4005,19 @@ ast_type_specifier::hir(exec_list *instructions,
       return NULL;
    }
 
-   if (this->structure != NULL)
+   /* _mesa_ast_set_aggregate_type() sets the <structure> field so that
+    * process_record_constructor() can do type-checking on C-style initializer
+    * expressions of structs, but ast_struct_specifier should only be translated
+    * to HIR if it is declaring the type of a structure.
+    *
+    * The ->is_declaration field is false for initializers of variables
+    * declared separately from the struct's type definition.
+    *
+    *    struct S { ... };              (is_declaration = true)
+    *    struct T { ... } t = { ... };  (is_declaration = true)
+    *    S s = { ... };                 (is_declaration = false)
+    */
+   if (this->structure != NULL && this->structure->is_declaration)
       return this->structure->hir(instructions, state);
 
    return NULL;
diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy
index 56367f8..42375bb 100644
--- a/src/glsl/glsl_parser.yy
+++ b/src/glsl/glsl_parser.yy
@@ -221,6 +221,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
 %type <declarator_list> init_declarator_list
 %type <declarator_list> single_declaration
 %type <expression> initializer
+%type <expression> initializer_list
 %type <node> declaration
 %type <node> declaration_statement
 %type <node> jump_statement
@@ -961,6 +962,13 @@ init_declarator_list:
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
 	   state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+	   if ($7->oper == ast_aggregate)
+	   {
+	      ast_aggregate_initializer *ai = (ast_aggregate_initializer*)$7;
+	      ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier);
+	      type->is_array = true;
+	      _mesa_ast_set_aggregate_type(type, ai, state);
+	   }
 	}
 	| init_declarator_list ',' any_identifier '[' constant_expression ']' '=' initializer
 	{
@@ -971,6 +979,14 @@ init_declarator_list:
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
 	   state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+	   if ($8->oper == ast_aggregate)
+	   {
+	      ast_aggregate_initializer *ai = (ast_aggregate_initializer*)$8;
+	      ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier);
+	      type->is_array = true;
+	      type->array_size = $5;
+	      _mesa_ast_set_aggregate_type(type, ai, state);
+	   }
 	}
 	| init_declarator_list ',' any_identifier '=' initializer
 	{
@@ -981,6 +997,11 @@ init_declarator_list:
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
 	   state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+	   if ($5->oper == ast_aggregate)
+	   {
+	      ast_aggregate_initializer *ai = (ast_aggregate_initializer*)$5;
+	      _mesa_ast_set_aggregate_type($1->type->specifier, ai, state);
+	   }
 	}
 	;
 
@@ -1028,6 +1049,13 @@ single_declaration:
 	   $$ = new(ctx) ast_declarator_list($1);
 	   $$->set_location(yylloc);
 	   $$->declarations.push_tail(&decl->link);
+	   if ($6->oper == ast_aggregate)
+	   {
+	      ast_aggregate_initializer *ai = (ast_aggregate_initializer*)$6;
+	      ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier);
+	      type->is_array = true;
+	      _mesa_ast_set_aggregate_type(type, ai, state);
+	   }
 	}
 	| fully_specified_type any_identifier '[' constant_expression ']' '=' initializer
 	{
@@ -1037,6 +1065,14 @@ single_declaration:
 	   $$ = new(ctx) ast_declarator_list($1);
 	   $$->set_location(yylloc);
 	   $$->declarations.push_tail(&decl->link);
+	   if ($7->oper == ast_aggregate)
+	   {
+	      ast_aggregate_initializer *ai = (ast_aggregate_initializer*)$7;
+	      ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier);
+	      type->is_array = true;
+	      type->array_size = $4;
+	      _mesa_ast_set_aggregate_type(type, ai, state);
+	   }
 	}
 	| fully_specified_type any_identifier '=' initializer
 	{
@@ -1046,6 +1082,10 @@ single_declaration:
 	   $$ = new(ctx) ast_declarator_list($1);
 	   $$->set_location(yylloc);
 	   $$->declarations.push_tail(&decl->link);
+	   if ($4->oper == ast_aggregate)
+	   {
+              _mesa_ast_set_aggregate_type($1->specifier, $4, state);
+	   }
 	}
 	| INVARIANT variable_identifier // Vertex only.
 	{
@@ -1503,6 +1543,7 @@ struct_specifier:
 	   $$ = new(ctx) ast_struct_specifier($2, $4);
 	   $$->set_location(yylloc);
 	   state->symbols->add_type($2, glsl_type::void_type);
+           state->symbols->add_type_ast($2, new(ctx) ast_type_specifier($$));
 	}
 	| STRUCT '{' struct_declaration_list '}'
 	{
@@ -1570,6 +1611,28 @@ struct_declarator:
 
 initializer:
 	assignment_expression
+	| '{' initializer_list '}'
+	{
+	   $$ = $2;
+	}
+	| '{' initializer_list ',' '}'
+	{
+	   $$ = $2;
+	}
+	;
+
+initializer_list:
+	initializer
+	{
+	   void *ctx = state;
+	   $$ = new(ctx) ast_aggregate_initializer();
+	   $$->set_location(yylloc);
+	   $$->expressions.push_tail(& $1->link);
+	}
+	| initializer_list ',' initializer
+	{
+	   $1->expressions.push_tail(& $3->link);
+	}
 	;
 
 declaration_statement:
diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp
index bab81fe..f4b4924 100644
--- a/src/glsl/glsl_parser_extras.cpp
+++ b/src/glsl/glsl_parser_extras.cpp
@@ -663,6 +663,185 @@ _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
    return true;
 }
 
+
+/**
+ * Returns the name of the type of a column of a matrix. E.g.,
+ *
+ *    "mat3"   -> "vec3"
+ *    "mat4x2" -> "vec2"
+ */
+static const char *
+_mesa_ast_get_matrix_column_type_name(const char *matrix_type_name)
+{
+   static const char *vec_name[] = { "vec2", "vec3", "vec4" };
+   long rows;
+
+   if (strlen(matrix_type_name) == strlen("mat4")) {
+      rows = strtol(matrix_type_name + 3, NULL, 10);
+   } else {
+      assert(strlen(matrix_type_name) == strlen("mat4x2"));
+
+      rows = strtol(matrix_type_name + 5, NULL, 10);
+   }
+   return vec_name[rows - 2];
+}
+
+/**
+ * Recurses through <type> and <expr> if <expr> is an aggregate initializer
+ * and sets <expr>'s <constructor_type> field to <type>. Gives later functions
+ * (process_array_constructor, et al) sufficient information to do type
+ * checking.
+ *
+ * Operates on assignments involving an aggregate initializer. E.g.,
+ *
+ * vec4 pos = {1.0, -1.0, 0.0, 1.0};
+ *
+ * or more ridiculously,
+ *
+ * struct S {
+ *     vec4 v[2];
+ * };
+ *
+ * struct {
+ *     S a[2], b;
+ *     int c;
+ * } aggregate = {
+ *     {
+ *         {
+ *             {
+ *                 {1.0, 2.0, 3.0, 4.0}, // a[0].v[0]
+ *                 {5.0, 6.0, 7.0, 8.0}  // a[0].v[1]
+ *             } // a[0].v
+ *         }, // a[0]
+ *         {
+ *             {
+ *                 {1.0, 2.0, 3.0, 4.0}, // a[1].v[0]
+ *                 {5.0, 6.0, 7.0, 8.0}  // a[1].v[1]
+ *             } // a[1].v
+ *         } // a[1]
+ *     }, // a
+ *     {
+ *         {
+ *             {1.0, 2.0, 3.0, 4.0}, // b.v[0]
+ *             {5.0, 6.0, 7.0, 8.0}  // b.v[1]
+ *         } // b.v
+ *     }, // b
+ *     4 // c
+ * };
+ *
+ * This pass is necessary because the right-hand side of <type> e = { ... }
+ * doesn't contain sufficient information to determine if the types match.
+ */
+void
+_mesa_ast_set_aggregate_type(const ast_type_specifier *type,
+                             ast_expression *expr,
+                             _mesa_glsl_parse_state *state)
+{
+   void *ctx = state;
+   ast_aggregate_initializer *ai = (ast_aggregate_initializer *)expr;
+   ai->constructor_type = (ast_type_specifier *)type;
+
+   bool is_declaration = ai->constructor_type->structure != NULL;
+   if (!is_declaration) {
+      /* Look up <type> name in the symbol table to see if it's a struct. */
+      const ast_type_specifier *struct_type =
+         state->symbols->get_type_ast(type->type_name);
+      ai->constructor_type->structure =
+         struct_type ? new(ctx) ast_struct_specifier(struct_type->structure)
+                     : NULL;
+   }
+
+   /* If the aggregate is an array, recursively set its elements' types. */
+   if (type->is_array) {
+      /* We want to set the element type which is not an array itself, so make
+       * a copy of the array type and set its is_array field to false.
+       *
+       * E.g., if <type> if struct S[2] we want to set each element's type to
+       * struct S.
+       *
+       * XXX: Update when ARB_array_of_arrays is supported.
+       */
+      ast_type_specifier *non_array_type = new(ctx) ast_type_specifier(type);
+      non_array_type->is_array = false;
+      non_array_type->array_size = NULL;
+
+      for (exec_node *expr_node = ai->expressions.head;
+           !expr_node->is_tail_sentinel();
+           expr_node = expr_node->next) {
+         ast_expression *expr = exec_node_data(ast_expression, expr_node,
+                                               link);
+
+         if (expr->oper == ast_aggregate)
+            _mesa_ast_set_aggregate_type(non_array_type, expr, state);
+      }
+
+   /* If the aggregate is a struct, recursively set its fields' types. */
+   } else if (ai->constructor_type->structure) {
+      ai->constructor_type->structure->is_declaration = is_declaration;
+      exec_node *expr_node = ai->expressions.head;
+
+      /* Iterate through the struct's fields' declarations. E.g., iterate from
+       * "float a, b" to "int c" in the struct below.
+       *
+       *     struct {
+       *         float a, b;
+       *         int c;
+       *     } s;
+       */
+      for (exec_node *decl_list_node =
+              ai->constructor_type->structure->declarations.head;
+           !decl_list_node->is_tail_sentinel();
+           decl_list_node = decl_list_node->next) {
+         ast_declarator_list *decl_list = exec_node_data(ast_declarator_list,
+                                                         decl_list_node, link);
+
+         for (exec_node *decl_node = decl_list->declarations.head;
+              !decl_node->is_tail_sentinel() && !expr_node->is_tail_sentinel();
+              decl_node = decl_node->next, expr_node = expr_node->next) {
+            ast_declaration *decl = exec_node_data(ast_declaration, decl_node,
+                                                   link);
+            ast_expression *expr = exec_node_data(ast_expression, expr_node,
+                                                  link);
+
+            /* Declaration shadows the <type> parameter. */
+            ast_type_specifier *type =
+               new(ctx) ast_type_specifier(decl_list->type->specifier);
+            if (!type->is_array) {
+               /* XXX: Update when ARB_array_of_arrays is supported. */
+               type->is_array = decl->is_array;
+               type->array_size = decl->array_size;
+            }
+
+            if (expr->oper == ast_aggregate)
+               _mesa_ast_set_aggregate_type(type, expr, state);
+         }
+      }
+   } else {
+      /* If the aggregate is a matrix, set its columns' types. */
+      const char *name;
+      const glsl_type *const constructor_type =
+         ai->constructor_type->glsl_type(&name, state);
+
+      if (constructor_type->is_matrix()) {
+         for (exec_node *expr_node = ai->expressions.head;
+              !expr_node->is_tail_sentinel();
+              expr_node = expr_node->next) {
+            ast_expression *expr = exec_node_data(ast_expression, expr_node,
+                                                  link);
+
+            /* Declaration shadows the <type> parameter. */
+            ast_type_specifier *type =
+               new(ctx) ast_type_specifier(ai->constructor_type);
+            type->type_name = _mesa_ast_get_matrix_column_type_name(name);
+
+            if (expr->oper == ast_aggregate)
+               _mesa_ast_set_aggregate_type(type, expr, state);
+         }
+      }
+   }
+}
+
+
 void
 _mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
 {
-- 
1.8.1.5



More information about the mesa-dev mailing list