[Mesa-dev] [PATCH V3 3/8] glsl: Add array specifier to ast code

Timothy Arceri t_arceri at yahoo.com.au
Wed Jan 22 03:33:02 PST 2014


Signed-off-by: Timothy Arceri <t_arceri at yahoo.com.au>
---
 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_extras.cpp |  19 ++---
 src/glsl/glsl_parser_extras.h   |   2 +
 6 files changed, 179 insertions(+), 101 deletions(-)

diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index b24052b..c15a119 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 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 8d13610..e25cba3 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 d758bfa..0dd1180 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 2e87846..996c66a 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),
@@ -788,15 +789,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();
    }
 }
 
@@ -1020,7 +1017,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);
 }
 
 
@@ -1036,7 +1033,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("= ");
@@ -1046,12 +1043,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