glsl: allow AoA to be sized by initializer or constructor
authorTimothy Arceri <t_arceri@yahoo.com.au>
Thu, 15 Oct 2015 03:32:41 +0000 (14:32 +1100)
committerTimothy Arceri <t_arceri@yahoo.com.au>
Thu, 15 Oct 2015 09:35:45 +0000 (20:35 +1100)
V2: Split out unsized array validation to its own patch as
suggested by Samuel.

Reviewed-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com>
src/glsl/ast.h
src/glsl/ast_array_index.cpp
src/glsl/ast_function.cpp
src/glsl/ast_to_hir.cpp
src/glsl/glsl_parser.yy

index 67faacd0ef85105b82816578f3852afdf0974410..57d432d4b023ec18a6f41f74f421635da64a9436 100644 (file)
@@ -183,6 +183,7 @@ enum ast_operators {
    ast_post_dec,
    ast_field_selection,
    ast_array_index,
+   ast_unsized_array_dim,
 
    ast_function_call,
 
@@ -324,16 +325,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);
@@ -346,11 +338,8 @@ public:
 
    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;
 };
index 5e8f49d70b0daf0139c26a8d870142f019b36ab7..7855e0a6190b27b147298772b17385de8703b704 100644 (file)
 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("] ");
    }
 }
index b72eb3ffb9ee864a2ce9ff45da2c7cec189b7518..c5c5cae333bb858c2212f1f3d53f2e2eed6f8f65 100644 (file)
@@ -991,6 +991,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) {
@@ -1017,12 +1018,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.
@@ -1039,6 +1062,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);
 
index c04db3505c1575fb1876ce3106538c95d9aaad3f..fb2c0f7026c8e6915f8e615e589683a881f8b90b 100644 (file)
@@ -782,8 +782,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 {
@@ -1810,6 +1832,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.
@@ -2047,6 +2073,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();
 
@@ -2115,14 +2149,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;
@@ -2130,9 +2156,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;
@@ -6453,6 +6476,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
@@ -6476,7 +6502,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;
@@ -6503,9 +6529,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
index c1bcccc34f42c60562e8062f913257bb4b8a2e0b..16c91710bbb483b9883699c4fa8a2378c05f84bd 100644 (file)
@@ -1962,7 +1962,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 ']'
@@ -1973,17 +1975,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 ']'
    {