nir/glsl: Add an explicit_alignment field to glsl_type

When creating explicit type, the alignment information is lost, thus
forcing explicit type users to recalculate the alignment using the same
size_align() function. Let's add a new field to cache this information.

Only structs, matrices, and vectors have and explicit alignment.  Arrays
alignment is implicitly set to its element alignment and matrices are
required to have an alignment that matches that of its vector columns.
the concept of alignment simply doesn't apply to other types.

We make the strategic choice to not allow explicit alignments on
scalars.  This is for a couple of reasons:

 1. There are no cases today where we use explicit types where we want
    any other alignment for scalars than natural alignment.

 2. Vectors don't have a component alignment that's separate from the
    explicit_alignment so it's impossible to get an explicitly aligned
    scalar type which is the component of the explicitly aligned vector
    type.

This choice may cause problems if we ever want to use explicitly laid
out types for things like varyings where we sometimes want vec4
alignment of scalars.  We can deal with that when the time comes.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6472>
diff --git a/src/compiler/glsl_types.cpp b/src/compiler/glsl_types.cpp
index 1aeb443..288ddcf 100644
--- a/src/compiler/glsl_types.cpp
+++ b/src/compiler/glsl_types.cpp
@@ -46,13 +46,15 @@
 glsl_type::glsl_type(GLenum gl_type,
                      glsl_base_type base_type, unsigned vector_elements,
                      unsigned matrix_columns, const char *name,
-                     unsigned explicit_stride, bool row_major) :
+                     unsigned explicit_stride, bool row_major,
+                     unsigned explicit_alignment) :
    gl_type(gl_type),
    base_type(base_type), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(row_major), packed(0),
    vector_elements(vector_elements), matrix_columns(matrix_columns),
-   length(0), explicit_stride(explicit_stride)
+   length(0), explicit_stride(explicit_stride),
+   explicit_alignment(explicit_alignment)
 {
    /* Values of these types must fit in the two bits of
     * glsl_type::sampled_type.
@@ -75,6 +77,7 @@
    /* Neither dimension is zero or both dimensions are zero.
     */
    assert((vector_elements == 0) == (matrix_columns == 0));
+   assert(util_is_power_of_two_or_zero(explicit_alignment));
    memset(& fields, 0, sizeof(fields));
 }
 
@@ -86,7 +89,7 @@
    sampler_dimensionality(dim), sampler_shadow(shadow),
    sampler_array(array), interface_packing(0),
    interface_row_major(0), packed(0),
-   length(0), explicit_stride(0)
+   length(0), explicit_stride(0), explicit_alignment(0)
 {
    this->mem_ctx = ralloc_context(NULL);
    assert(this->mem_ctx != NULL);
@@ -100,16 +103,20 @@
 }
 
 glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
-                     const char *name, bool packed) :
+                     const char *name, bool packed,
+                     unsigned explicit_alignment) :
    gl_type(0),
    base_type(GLSL_TYPE_STRUCT), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(0), packed(packed),
    vector_elements(0), matrix_columns(0),
-   length(num_fields), explicit_stride(0)
+   length(num_fields), explicit_stride(0),
+   explicit_alignment(explicit_alignment)
 {
    unsigned int i;
 
+   assert(util_is_power_of_two_or_zero(explicit_alignment));
+
    this->mem_ctx = ralloc_context(NULL);
    assert(this->mem_ctx != NULL);
 
@@ -136,7 +143,7 @@
    interface_packing((unsigned) packing),
    interface_row_major((unsigned) row_major), packed(0),
    vector_elements(0), matrix_columns(0),
-   length(num_fields), explicit_stride(0)
+   length(num_fields), explicit_stride(0), explicit_alignment(0)
 {
    unsigned int i;
 
@@ -161,7 +168,7 @@
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(0), matrix_columns(0),
-   length(num_params), explicit_stride(0)
+   length(num_params), explicit_stride(0), explicit_alignment(0)
 {
    unsigned int i;
 
@@ -190,7 +197,7 @@
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(1), matrix_columns(1),
-   length(0), explicit_stride(0)
+   length(0), explicit_stride(0), explicit_alignment(0)
 {
    this->mem_ctx = ralloc_context(NULL);
    assert(this->mem_ctx != NULL);
@@ -567,7 +574,8 @@
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(0), matrix_columns(0),
-   length(length), name(NULL), explicit_stride(explicit_stride)
+   length(length), name(NULL), explicit_stride(explicit_stride),
+   explicit_alignment(array->explicit_alignment)
 {
    this->fields.array = array;
    /* Inherit the gl type of the base. The GL type is used for
@@ -650,24 +658,30 @@
 
 const glsl_type *
 glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns,
-                        unsigned explicit_stride, bool row_major)
+                        unsigned explicit_stride, bool row_major,
+                        unsigned explicit_alignment)
 {
    if (base_type == GLSL_TYPE_VOID) {
-      assert(explicit_stride == 0 && !row_major);
+      assert(explicit_stride == 0 && explicit_alignment == 0 && !row_major);
       return void_type;
    }
 
-   /* Matrix and vector types with explicit strides have to be looked up in a
-    * table so they're handled separately.
+   /* Matrix and vector types with explicit strides or alignment have to be
+    * looked up in a table so they're handled separately.
     */
-   if (explicit_stride > 0) {
+   if (explicit_stride > 0 || explicit_alignment > 0) {
+      if (explicit_alignment > 0) {
+         assert(util_is_power_of_two_nonzero(explicit_alignment));
+         assert(explicit_stride % explicit_alignment == 0);
+      }
+
       const glsl_type *bare_type = get_instance(base_type, rows, columns);
 
-      assert(columns > 1 || !row_major);
+      assert(columns > 1 || (rows > 1 && !row_major));
 
       char name[128];
-      snprintf(name, sizeof(name), "%sx%uB%s", bare_type->name,
-               explicit_stride, row_major ? "RM" : "");
+      snprintf(name, sizeof(name), "%sx%ua%uB%s", bare_type->name,
+               explicit_stride, explicit_alignment, row_major ? "RM" : "");
 
       mtx_lock(&glsl_type::hash_mutex);
       assert(glsl_type_users > 0);
@@ -684,7 +698,8 @@
          const glsl_type *t = new glsl_type(bare_type->gl_type,
                                             (glsl_base_type)base_type,
                                             rows, columns, name,
-                                            explicit_stride, row_major);
+                                            explicit_stride, row_major,
+                                            explicit_alignment);
 
          entry = _mesa_hash_table_insert(explicit_matrix_types,
                                          t->name, (void *)t);
@@ -694,6 +709,7 @@
       assert(((glsl_type *) entry->data)->vector_elements == rows);
       assert(((glsl_type *) entry->data)->matrix_columns == columns);
       assert(((glsl_type *) entry->data)->explicit_stride == explicit_stride);
+      assert(((glsl_type *) entry->data)->explicit_alignment == explicit_alignment);
 
       const glsl_type *t = (const glsl_type *) entry->data;
 
@@ -1124,6 +1140,9 @@
    if (this->interface_row_major != b->interface_row_major)
       return false;
 
+   if (this->explicit_alignment != b->explicit_alignment)
+      return false;
+
    /* From the GLSL 4.20 specification (Sec 4.2):
     *
     *     "Structures must have the same name, sequence of type names, and
@@ -1251,9 +1270,9 @@
 glsl_type::get_struct_instance(const glsl_struct_field *fields,
                                unsigned num_fields,
                                const char *name,
-                               bool packed)
+                               bool packed, unsigned explicit_alignment)
 {
-   const glsl_type key(fields, num_fields, name, packed);
+   const glsl_type key(fields, num_fields, name, packed, explicit_alignment);
 
    mtx_lock(&glsl_type::hash_mutex);
    assert(glsl_type_users > 0);
@@ -1266,7 +1285,8 @@
    const struct hash_entry *entry = _mesa_hash_table_search(struct_types,
                                                             &key);
    if (entry == NULL) {
-      const glsl_type *t = new glsl_type(fields, num_fields, name, packed);
+      const glsl_type *t = new glsl_type(fields, num_fields, name, packed,
+                                         explicit_alignment);
 
       entry = _mesa_hash_table_insert(struct_types, t, (void *) t);
    }
@@ -1275,6 +1295,7 @@
    assert(((glsl_type *) entry->data)->length == num_fields);
    assert(strcmp(((glsl_type *) entry->data)->name, name) == 0);
    assert(((glsl_type *) entry->data)->packed == packed);
+   assert(((glsl_type *) entry->data)->explicit_alignment == explicit_alignment);
 
    glsl_type *t = (glsl_type *) entry->data;
 
@@ -2448,9 +2469,16 @@
 glsl_type::get_explicit_type_for_size_align(glsl_type_size_align_func type_info,
                                             unsigned *size, unsigned *alignment) const
 {
-   if (this->is_scalar() || this->is_vector()) {
+   if (this->is_scalar()) {
       type_info(this, size, alignment);
+      assert(*size == explicit_type_scalar_byte_size(this));
+      assert(*alignment == explicit_type_scalar_byte_size(this));
       return this;
+   } else if (this->is_vector()) {
+      type_info(this, size, alignment);
+      assert(*alignment % explicit_type_scalar_byte_size(this) == 0);
+      return glsl_type::get_instance(this->base_type, this->vector_elements,
+                                     1, 0, false, *alignment);
    } else if (this->is_array()) {
       unsigned elem_size, elem_align;
       const struct glsl_type *explicit_element =
@@ -2484,7 +2512,7 @@
       const glsl_type *type;
       if (this->is_struct()) {
          type = get_struct_instance(fields, this->length, this->name,
-                                    this->packed);
+                                    this->packed, *alignment);
       } else {
          assert(!this->packed);
          type = get_interface_instance(fields, this->length,
@@ -2500,9 +2528,10 @@
       unsigned stride = align(col_size, col_align);
 
       *size = this->matrix_columns * stride;
+      /* Matrix and column alignments match. See glsl_type::column_type() */
       *alignment = col_align;
       return glsl_type::get_instance(this->base_type, this->vector_elements,
-                                     this->matrix_columns, stride, false);
+                                     this->matrix_columns, stride, false, *alignment);
    } else {
       unreachable("Unhandled type.");
    }
@@ -2684,7 +2713,8 @@
       unsigned interface_row_major:1;
       unsigned vector_elements:3;
       unsigned matrix_columns:3;
-      unsigned explicit_stride:20;
+      unsigned explicit_stride:16;
+      unsigned explicit_alignment:4;
    } basic;
    struct {
       unsigned base_type:5;
@@ -2703,7 +2733,8 @@
       unsigned base_type:5;
       unsigned interface_packing_or_packed:2;
       unsigned interface_row_major:1;
-      unsigned length:24;
+      unsigned length:20;
+      unsigned explicit_alignment:4;
    } strct;
 };
 
@@ -2768,13 +2799,17 @@
       else if (type->vector_elements == 16)
          encoded.basic.vector_elements = 6;
       encoded.basic.matrix_columns = type->matrix_columns;
-      encoded.basic.explicit_stride = MIN2(type->explicit_stride, 0xfffff);
+      encoded.basic.explicit_stride = MIN2(type->explicit_stride, 0xffff);
+      encoded.basic.explicit_alignment =
+         MIN2(ffs(type->explicit_alignment), 0xf);
       blob_write_uint32(blob, encoded.u32);
       /* If we don't have enough bits for explicit_stride, store it
        * separately.
        */
-      if (encoded.basic.explicit_stride == 0xfffff)
+      if (encoded.basic.explicit_stride == 0xffff)
          blob_write_uint32(blob, type->explicit_stride);
+      if (encoded.basic.explicit_alignment == 0xf)
+         blob_write_uint32(blob, type->explicit_alignment);
       return;
    case GLSL_TYPE_SAMPLER:
       encoded.sampler.dimensionality = type->sampler_dimensionality;
@@ -2808,7 +2843,9 @@
       return;
    case GLSL_TYPE_STRUCT:
    case GLSL_TYPE_INTERFACE:
-      encoded.strct.length = MIN2(type->length, 0xffffff);
+      encoded.strct.length = MIN2(type->length, 0xfffff);
+      encoded.strct.explicit_alignment =
+         MIN2(ffs(type->explicit_alignment), 0xf);
       if (type->is_interface()) {
          encoded.strct.interface_packing_or_packed = type->interface_packing;
          encoded.strct.interface_row_major = type->interface_row_major;
@@ -2819,8 +2856,10 @@
       blob_write_string(blob, type->name);
 
       /* If we don't have enough bits for length, store it separately. */
-      if (encoded.strct.length == 0xffffff)
+      if (encoded.strct.length == 0xfffff)
          blob_write_uint32(blob, type->length);
+      if (encoded.strct.length == 0xf)
+         blob_write_uint32(blob, type->explicit_alignment);
 
       for (unsigned i = 0; i < type->length; i++)
          encode_glsl_struct_field(blob, &type->fields.structure[i]);
@@ -2863,8 +2902,13 @@
    case GLSL_TYPE_INT64:
    case GLSL_TYPE_BOOL: {
       unsigned explicit_stride = encoded.basic.explicit_stride;
-      if (explicit_stride == 0xfffff)
+      if (explicit_stride == 0xffff)
          explicit_stride = blob_read_uint32(blob);
+      unsigned explicit_alignment = encoded.basic.explicit_alignment;
+      if (explicit_alignment == 0xf)
+         explicit_alignment = blob_read_uint32(blob);
+      else if (explicit_alignment > 0)
+         explicit_alignment = 1 << (explicit_alignment - 1);
       uint32_t vector_elements = encoded.basic.vector_elements;
       if (vector_elements == 5)
          vector_elements = 8;
@@ -2873,7 +2917,8 @@
       return glsl_type::get_instance(base_type, encoded.basic.vector_elements,
                                      encoded.basic.matrix_columns,
                                      explicit_stride,
-                                     encoded.basic.interface_row_major);
+                                     encoded.basic.interface_row_major,
+                                     explicit_alignment);
    }
    case GLSL_TYPE_SAMPLER:
       return glsl_type::get_sampler_instance((enum glsl_sampler_dim)encoded.sampler.dimensionality,
@@ -2902,8 +2947,13 @@
    case GLSL_TYPE_INTERFACE: {
       char *name = blob_read_string(blob);
       unsigned num_fields = encoded.strct.length;
-      if (num_fields == 0xffffff)
+      if (num_fields == 0xfffff)
          num_fields = blob_read_uint32(blob);
+      unsigned explicit_alignment = encoded.strct.explicit_alignment;
+      if (explicit_alignment == 0xf)
+         explicit_alignment = blob_read_uint32(blob);
+      else if (explicit_alignment > 0)
+         explicit_alignment = 1 << (explicit_alignment - 1);
 
       glsl_struct_field *fields =
          (glsl_struct_field *) malloc(sizeof(glsl_struct_field) * num_fields);
@@ -2912,6 +2962,7 @@
 
       const glsl_type *t;
       if (base_type == GLSL_TYPE_INTERFACE) {
+         assert(explicit_alignment == 0);
          enum glsl_interface_packing packing =
             (glsl_interface_packing) encoded.strct.interface_packing_or_packed;
          bool row_major = encoded.strct.interface_row_major;
@@ -2919,7 +2970,8 @@
                                                row_major, name);
       } else {
          unsigned packed = encoded.strct.interface_packing_or_packed;
-         t = glsl_type::get_struct_instance(fields, num_fields, name, packed);
+         t = glsl_type::get_struct_instance(fields, num_fields, name, packed,
+                                            explicit_alignment);
       }
 
       free(fields);
diff --git a/src/compiler/glsl_types.h b/src/compiler/glsl_types.h
index 6a57c70..8058425 100644
--- a/src/compiler/glsl_types.h
+++ b/src/compiler/glsl_types.h
@@ -333,6 +333,13 @@
    unsigned explicit_stride;
 
    /**
+    * Explicit alignment. This is used to communicate explicit alignment
+    * constraints. Should be 0 if the type has no explicit alignment
+    * constraint.
+    */
+   unsigned explicit_alignment;
+
+   /**
     * Subtype of composite data types.
     */
    union {
@@ -420,7 +427,8 @@
    static const glsl_type *get_instance(unsigned base_type, unsigned rows,
                                         unsigned columns,
                                         unsigned explicit_stride = 0,
-                                        bool row_major = false);
+                                        bool row_major = false,
+                                        unsigned explicit_alignment = 0);
 
    /**
     * Get the instance of a sampler type
@@ -446,7 +454,8 @@
    static const glsl_type *get_struct_instance(const glsl_struct_field *fields,
 					       unsigned num_fields,
 					       const char *name,
-					       bool packed = false);
+					       bool packed = false,
+					       unsigned explicit_alignment = 0);
 
    /**
     * Get the instance of an interface block type
@@ -1107,10 +1116,21 @@
       if (!is_matrix())
          return error_type;
 
-      if (explicit_stride && interface_row_major)
-         return get_instance(base_type, vector_elements, 1, explicit_stride);
-      else
-         return get_instance(base_type, vector_elements, 1);
+      if (interface_row_major) {
+         /* If we're row-major, the vector element stride is the same as the
+          * matrix stride and we have no alignment (i.e. component-aligned).
+          */
+         return get_instance(base_type, vector_elements, 1,
+                             explicit_stride, false, 0);
+      } else {
+         /* Otherwise, the vector is tightly packed (stride=0).  For
+          * alignment, we treat a matrix as an array of columns make the same
+          * assumption that the alignment of the column is the same as the
+          * alignment of the whole matrix.
+          */
+         return get_instance(base_type, vector_elements, 1,
+                             0, false, explicit_alignment);
+      }
    }
 
    /**
@@ -1236,7 +1256,8 @@
    glsl_type(GLenum gl_type,
              glsl_base_type base_type, unsigned vector_elements,
              unsigned matrix_columns, const char *name,
-             unsigned explicit_stride = 0, bool row_major = false);
+             unsigned explicit_stride = 0, bool row_major = false,
+             unsigned explicit_alignment = 0);
 
    /** Constructor for sampler or image types */
    glsl_type(GLenum gl_type, glsl_base_type base_type,
@@ -1245,7 +1266,8 @@
 
    /** Constructor for record types */
    glsl_type(const glsl_struct_field *fields, unsigned num_fields,
-	     const char *name, bool packed = false);
+	     const char *name, bool packed = false,
+	     unsigned explicit_alignment = 0);
 
    /** Constructor for interface types */
    glsl_type(const glsl_struct_field *fields, unsigned num_fields,
diff --git a/src/compiler/nir_types.cpp b/src/compiler/nir_types.cpp
index 9b4f9c5..1fff15c 100644
--- a/src/compiler/nir_types.cpp
+++ b/src/compiler/nir_types.cpp
@@ -860,6 +860,12 @@
    return type->explicit_size(align_to_stride);
 }
 
+unsigned
+glsl_get_explicit_alignment(const struct glsl_type *type)
+{
+   return type->explicit_alignment;
+}
+
 bool
 glsl_type_is_packed(const struct glsl_type *type)
 {
diff --git a/src/compiler/nir_types.h b/src/compiler/nir_types.h
index 2df1e2c..14fae6a 100644
--- a/src/compiler/nir_types.h
+++ b/src/compiler/nir_types.h
@@ -122,6 +122,7 @@
                                  unsigned *size, unsigned *align);
 
 unsigned glsl_get_explicit_size(const struct glsl_type *type, bool align_to_stride);
+unsigned glsl_get_explicit_alignment(const struct glsl_type *type);
 
 static inline unsigned
 glsl_get_bit_size(const struct glsl_type *type)