[Mesa-dev] [PATCH 4/9] glsl: Add array specifier to ast code

Timothy Arceri t_arceri at yahoo.com.au
Wed Jan 15 22:27:25 PST 2014


Signed-off-by: Timothy Arceri <t_arceri at yahoo.com.au>
---
 src/glsl/ast.h                  |  45 +++++++----
 src/glsl/ast_array_index.cpp    |  13 +++
 src/glsl/ast_to_hir.cpp         | 173 +++++++++++++++++++++++++++-------------
 src/glsl/ast_type.cpp           |   8 +-
 src/glsl/glsl_parser_extras.cpp |  30 +++----
 src/glsl/glsl_parser_extras.h   |   2 +
 6 files changed, 179 insertions(+), 92 deletions(-)

diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index 76911f0..bbae9cd 100644
--- a/src/glsl/ast.h
+++ b/src/glsl/ast.h
@@ -276,6 +276,21 @@ private:
    bool cons;
 };
 
+class ast_array_specifier : public ast_node {
+public:
+   ast_array_specifier()
+      : ast_node()
+   {
+      dimension_count = 1;
+   }
+
+   virtual void print(void) const;
+
+   unsigned dimension_count;
+   bool is_unsized_array;
+   exec_list array_dimensions;
+};
+
 /**
  * C-style aggregate initialization class
  *
@@ -325,14 +340,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;
 };
@@ -531,7 +547,6 @@ public:
 };
 
 
-
 class ast_type_specifier : public ast_node {
 public:
    /**
@@ -542,9 +557,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 */
@@ -553,7 +568,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 */
@@ -562,7 +577,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 */
@@ -580,7 +595,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;
@@ -634,7 +649,7 @@ public:
       type(NULL),
       identifier(NULL),
       is_array(false),
-      array_size(NULL),
+      array_specifier(NULL),
       formal_parameter(false),
       is_void(false)
    {
@@ -649,7 +664,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,
@@ -897,12 +912,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,
@@ -937,7 +952,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 a5f2320..f3b060e 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 4cc8eb1..c0e3443 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -1771,67 +1771,131 @@ ast_compound_statement::hir(exec_list *instructions,
    return NULL;
 }
 
+static const unsigned
+process_array_size(exec_node *node,
+                   struct _mesa_glsl_parse_state *state)
+{
+   int result = 0;
+   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) {
+      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);
+            result = 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());
+         }
+      }
+   }
+   return result;
+}
 
 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 = NULL;
+   const glsl_type *element_type = base;
+   const glsl_type *array_type_temp = element_type;
+
+   unsigned outer_dimension_count = 0;
+   unsigned dimension_count = 1;
 
    if (base == NULL)
       return glsl_type::error_type;
 
-   /* 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'"
+                          "#version 120 / GL_ARB_arrays_of_arrays "
+                          "required for defining arrays of arrays",
+                          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;
+      }
+
+      /* Settings these variables will cause
+       * any array dimensions processed with the base type to
+       * be appended onto the end of the array
+       */
+      outer_dimension_count = base->dimension_count;
+      dimension_count = base->dimension_count + 1;
+      element_type = base->element_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 (array_specifier != NULL) {
 
-      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());
-	    }
-	 }
+      exec_node *node = array_specifier->array_dimensions.tail_pred;
+      outer_dimension_count += array_specifier->dimension_count;
+
+      unsigned array_size;
+      for (/* nothing */; !node->is_head_sentinel(); node = node->prev) {
+         array_size = process_array_size(node, state);
+         array_type_temp = glsl_type::get_array_instance(array_type_temp,
+                                                         array_size,
+                                                         dimension_count);
+         dimension_count++;
+      }
+
+      if (array_specifier->is_unsized_array) {
+         array_type_temp = glsl_type::get_array_instance(array_type_temp,
+                                                         0,
+                                                         dimension_count);
+      }
+
+      if (array_type_temp == element_type) {
+         /* we found no array sizes */
+         array_type = NULL;
+      } else {
+         array_type = array_type_temp;
       }
    }
 
-   const glsl_type *array_type = glsl_type::get_array_instance(base, length);
+   /* make sure the ast count and the current count match */
+   assert(dimension_count == outer_dimension_count);
+
    return array_type != NULL ? array_type : glsl_type::error_type;
 }
 
-
 const glsl_type *
 ast_type_specifier::glsl_type(const char **name,
 			      struct _mesa_glsl_parse_state *state) const
@@ -1843,7 +1907,7 @@ ast_type_specifier::glsl_type(const char **name,
 
    if (this->is_array) {
       YYLTYPE loc = this->get_location();
-      type = process_array_type(&loc, type, this->array_size, state);
+      type = process_array_type(&loc, type, this->array_specifier, state);
    }
 
    return type;
@@ -2824,7 +2888,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 =
@@ -2960,7 +3024,7 @@ ast_declarator_list::hir(exec_list *instructions,
       }
 
       if (decl->is_array) {
-	 var_type = process_array_type(&loc, decl_type, decl->array_size,
+	 var_type = process_array_type(&loc, decl_type, decl->array_specifier,
 				       state);
 	 if (var_type->is_error())
 	    continue;
@@ -3524,7 +3588,7 @@ ast_parameter_declarator::hir(exec_list *instructions,
     * 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()) {
@@ -4654,8 +4718,8 @@ ast_process_structure_or_interface_block(exec_list *instructions,
          }
 
 	 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;
@@ -5019,6 +5083,10 @@ ast_interface_block::hir(exec_list *instructions,
       ir_variable *var;
 
       if (this->is_array) {
+
+         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
@@ -5038,7 +5106,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 (block_array_type->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 "
@@ -5046,9 +5114,6 @@ ast_interface_block::hir(exec_list *instructions,
 
          }
 
-         const glsl_type *block_array_type =
-            process_array_type(&loc, block_type, this->array_size, state);
-
          var = new(state) ir_variable(block_array_type,
                                       this->instance_name,
                                       var_mode);
diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp
index d758bfa..ac48597 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_extras.cpp b/src/glsl/glsl_parser_extras.cpp
index 21dc3ab..92076b5 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),
@@ -769,7 +770,7 @@ _mesa_ast_set_aggregate_type(const ast_type_specifier *type,
                                                   link);
 
             bool is_array = decl_list->type->specifier->is_array;
-            ast_expression *array_size = decl_list->type->specifier->array_size;
+            ast_array_specifier *array_specifier = decl_list->type->specifier->array_specifier;
 
             /* Recognize variable declarations with the bracketed size attached
              * to the type rather than the variable name as arrays. E.g.,
@@ -777,19 +778,18 @@ _mesa_ast_set_aggregate_type(const ast_type_specifier *type,
              *     float a[2];
              *     float[2] b;
              *
-             * are both arrays, but <a>'s array_size is decl->array_size, while
-             * <b>'s array_size is decl_list->type->specifier->array_size.
+             * are both arrays, but <a>'s array_specifier is decl->array_specifier, while
+             * <b>'s array_specifier is decl_list->type->specifier->array_specifier.
              */
             if (!is_array) {
-               /* FINISHME: Update when ARB_array_of_arrays is supported. */
                is_array = decl->is_array;
-               array_size = decl->array_size;
+               array_specifier = decl->array_specifier;
             }
 
             /* Declaration shadows the <type> parameter. */
             ast_type_specifier *type =
                new(ctx) ast_type_specifier(decl_list->type->specifier,
-                                           is_array, array_size);
+                                           is_array, array_specifier);
 
             if (expr->oper == ast_aggregate)
                _mesa_ast_set_aggregate_type(type, expr, state);
@@ -876,15 +876,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();
    }
 }
 
@@ -1108,7 +1104,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);
 }
 
 
@@ -1124,7 +1120,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("= ");
@@ -1134,12 +1130,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 2444a96..1478f00 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;
-- 
1.8.3.1



More information about the mesa-dev mailing list