Ver Fonte

[spirv] Non-floating point matrix layout. (#1097)

Ehsan há 7 anos atrás
pai
commit
93ba5ed95f

+ 2 - 1
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -384,7 +384,8 @@ public:
   uint32_t getFloat32Type();
   uint32_t getFloat64Type();
   uint32_t getVecType(uint32_t elemType, uint32_t elemCount);
-  uint32_t getMatType(QualType elemType, uint32_t colType, uint32_t colCount);
+  uint32_t getMatType(QualType elemType, uint32_t colType, uint32_t colCount,
+                      Type::DecorationSet decorations = {});
   uint32_t getPointerType(uint32_t pointeeType, spv::StorageClass);
   uint32_t getStructType(llvm::ArrayRef<uint32_t> fieldTypes,
                          llvm::StringRef structName = "",

+ 3 - 2
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -881,7 +881,8 @@ uint32_t ModuleBuilder::getVecType(uint32_t elemType, uint32_t elemCount) {
 }
 
 uint32_t ModuleBuilder::getMatType(QualType elemType, uint32_t colType,
-                                   uint32_t colCount) {
+                                   uint32_t colCount,
+                                   Type::DecorationSet decorations) {
   // NOTE: According to Item "Data rules" of SPIR-V Spec 2.16.1 "Universal
   // Validation Rules":
   //   Matrix types can only be parameterized with floating-point types.
@@ -889,7 +890,7 @@ uint32_t ModuleBuilder::getMatType(QualType elemType, uint32_t colType,
   // So we need special handling of non-fp matrices. We emulate non-fp
   // matrices as an array of vectors.
   if (!elemType->isFloatingType())
-    return getArrayType(colType, getConstantUint32(colCount));
+    return getArrayType(colType, getConstantUint32(colCount), decorations);
 
   const Type *type = Type::getMatrix(theContext, colType, colCount);
   const uint32_t typeId = theContext.getResultIdForType(type);

+ 52 - 18
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -1055,6 +1055,14 @@ void SPIRVEmitter::doHLSLBufferDecl(const HLSLBufferDecl *bufferDecl) {
       for (const auto *annotation : varMember->getUnusualAnnotations())
         if (const auto *packing = dyn_cast<hlsl::ConstantPacking>(annotation))
           emitWarning("packoffset ignored since not supported", packing->Loc);
+
+      // We cannot handle external initialization of column-major matrices now.
+      if (typeTranslator.isOrContainsNonFpColMajorMatrix(varMember->getType(),
+                                                         varMember)) {
+        emitError("externally initialized non-floating-point column-major "
+                  "matrices not supported yet",
+                  varMember->getLocation());
+      }
     }
   }
   if (!validateVKAttributes(bufferDecl))
@@ -1084,6 +1092,14 @@ void SPIRVEmitter::doVarDecl(const VarDecl *decl) {
   if (!validateVKAttributes(decl))
     return;
 
+  // We cannot handle external initialization of column-major matrices now.
+  if (isExternalVar(decl) &&
+      typeTranslator.isOrContainsNonFpColMajorMatrix(decl->getType(), decl)) {
+    emitError("externally initialized non-floating-point column-major "
+              "matrices not supported yet",
+              decl->getLocation());
+  }
+
   if (decl->hasAttr<VKConstantIdAttr>()) {
     // This is a VarDecl for specialization constant.
     createSpecConstant(decl);
@@ -1724,7 +1740,6 @@ void SPIRVEmitter::doSwitchStmt(const SwitchStmt *switchStmt,
 
 SpirvEvalInfo
 SPIRVEmitter::doArraySubscriptExpr(const ArraySubscriptExpr *expr) {
-
   llvm::SmallVector<uint32_t, 4> indices;
   auto info = loadIfAliasVarRef(collectArrayStructIndices(expr, &indices));
 
@@ -4506,9 +4521,36 @@ SpirvEvalInfo SPIRVEmitter::processAssignment(const Expr *lhs,
 void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
                               const SpirvEvalInfo &rhsVal,
                               const QualType lhsValType) {
+
+  // Lambda for cases where we want to store per each array element.
+  const auto storeValueForEachArrayElement = [this, &lhsPtr,
+                                              &rhsVal](uint32_t arraySize,
+                                                       QualType arrayElemType) {
+    for (uint32_t i = 0; i < arraySize; ++i) {
+      const auto subRhsValType =
+          typeTranslator.translateType(arrayElemType, rhsVal.getLayoutRule());
+      const auto subRhsVal =
+          theBuilder.createCompositeExtract(subRhsValType, rhsVal, {i});
+      const auto subLhsPtrType = theBuilder.getPointerType(
+          typeTranslator.translateType(arrayElemType, lhsPtr.getLayoutRule()),
+          lhsPtr.getStorageClass());
+      const auto subLhsPtr = theBuilder.createAccessChain(
+          subLhsPtrType, lhsPtr, {theBuilder.getConstantUint32(i)});
+
+      storeValue(lhsPtr.substResultId(subLhsPtr),
+                 rhsVal.substResultId(subRhsVal), arrayElemType);
+    }
+  };
+
+  QualType matElemType = {};
+  uint32_t numRows = 0, numCols = 0;
+  const bool lhsIsMat =
+      typeTranslator.isMxNMatrix(lhsValType, &matElemType, &numRows, &numCols);
+  const bool lhsIsFloatMat = lhsIsMat && matElemType->isFloatingType();
+  const bool lhsIsNonFpMat = lhsIsMat && !matElemType->isFloatingType();
+
   if (typeTranslator.isScalarType(lhsValType) ||
-      typeTranslator.isVectorType(lhsValType) ||
-      typeTranslator.isMxNMatrix(lhsValType)) {
+      typeTranslator.isVectorType(lhsValType) || lhsIsFloatMat) {
     theBuilder.createStore(lhsPtr, rhsVal);
   } else if (TypeTranslator::isOpaqueType(lhsValType)) {
     // Resource types are represented using RecordType in the AST.
@@ -4545,6 +4587,12 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
     // Note: this check should happen after those setting needsLegalization.
     // TODO: is this optimization always correct?
     theBuilder.createStore(lhsPtr, rhsVal);
+  } else if (lhsIsNonFpMat) {
+    // Note: This check should happen before the RecordType check.
+    // Non-fp matrices are represented as arrays of vectors in SPIR-V.
+    // Each array element is a vector. Get the QualType for the vector.
+    const auto elemType = astContext.getExtVectorType(matElemType, numCols);
+    storeValueForEachArrayElement(numRows, elemType);
   } else if (const auto *recordType = lhsValType->getAs<RecordType>()) {
     uint32_t index = 0;
     for (const auto *field : recordType->getDecl()->fields()) {
@@ -4569,21 +4617,7 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
     // TODO: handle extra large array size?
     const auto size =
         static_cast<uint32_t>(arrayType->getSize().getZExtValue());
-
-    for (uint32_t i = 0; i < size; ++i) {
-      const auto subRhsValType =
-          typeTranslator.translateType(elemType, rhsVal.getLayoutRule());
-      const auto subRhsVal =
-          theBuilder.createCompositeExtract(subRhsValType, rhsVal, {i});
-      const auto subLhsPtrType = theBuilder.getPointerType(
-          typeTranslator.translateType(elemType, lhsPtr.getLayoutRule()),
-          lhsPtr.getStorageClass());
-      const auto subLhsPtr = theBuilder.createAccessChain(
-          subLhsPtrType, lhsPtr, {theBuilder.getConstantUint32(i)});
-
-      storeValue(lhsPtr.substResultId(subLhsPtr),
-                 rhsVal.substResultId(subRhsVal), elemType);
-    }
+    storeValueForEachArrayElement(size, elemType);
   } else {
     emitError("storing value of type %0 unimplemented", {}) << lhsValType;
   }

+ 48 - 13
tools/clang/lib/SPIRV/TypeTranslator.cpp

@@ -429,20 +429,22 @@ uint32_t TypeTranslator::translateType(QualType type, LayoutRule rule,
     QualType elemType = {};
     uint32_t rowCount = 0, colCount = 0;
     if (isMxNMatrix(type, &elemType, &rowCount, &colCount)) {
-
-      // We cannot handle external initialization of column-major matrices now.
-      if (!elemType->isFloatingType() && rule != LayoutRule::Void &&
-          !isRowMajor) {
-        emitError(
-            "externally initialized column-major matrices not supported yet");
-        return 0;
-      }
-
       // HLSL matrices are row major, while SPIR-V matrices are column major.
       // We are mapping what HLSL semantically mean a row into a column here.
       const uint32_t vecType =
           theBuilder.getVecType(translateType(elemType), colCount);
-      return theBuilder.getMatType(elemType, vecType, rowCount);
+
+      // If the matrix element type is not float, it is represented as an array
+      // of vectors, and should therefore have the ArrayStride decoration.
+      llvm::SmallVector<const Decoration *, 4> decorations;
+      if (!elemType->isFloatingType() && rule != LayoutRule::Void) {
+        uint32_t stride = 0;
+        (void)getAlignmentAndSize(type, rule, isRowMajor, &stride);
+        decorations.push_back(
+            Decoration::getArrayStride(*theBuilder.getSPIRVContext(), stride));
+      }
+
+      return theBuilder.getMatType(elemType, vecType, rowCount, decorations);
     }
   }
 
@@ -830,6 +832,35 @@ bool TypeTranslator::isMxNMatrix(QualType type, QualType *elemType,
   return true;
 }
 
+bool TypeTranslator::isOrContainsNonFpColMajorMatrix(QualType type,
+                                                     const Decl *decl) const {
+  const auto isColMajorDecl = [this](const Decl *decl) {
+    return decl->hasAttr<HLSLColumnMajorAttr>() ||
+           !decl->hasAttr<HLSLRowMajorAttr>() && !spirvOptions.defaultRowMajor;
+  };
+
+  QualType elemType = {};
+  if (isMxNMatrix(type, &elemType) && !elemType->isFloatingType()) {
+    return isColMajorDecl(decl);
+  }
+
+  if (const auto *arrayType = astContext.getAsConstantArrayType(type)) {
+    if (isMxNMatrix(arrayType->getElementType(), &elemType) &&
+        !elemType->isFloatingType())
+      return isColMajorDecl(decl);
+  }
+
+  if (const auto *structType = type->getAs<RecordType>()) {
+    const auto *decl = structType->getDecl();
+    for (const auto *field : decl->fields()) {
+      if (isOrContainsNonFpColMajorMatrix(field->getType(), field))
+        return true;
+    }
+  }
+
+  return false;
+}
+
 bool TypeTranslator::isRowMajorMatrix(QualType type, const Decl *decl) const {
   if (!isMxNMatrix(type) && !type->isArrayType())
     return false;
@@ -991,7 +1022,12 @@ TypeTranslator::getLayoutDecorations(const DeclContext *decl, LayoutRule rule) {
       // MatrixStride on the field. So skip possible arrays here.
       fieldType = arrayType->getElementType();
     }
-    if (isMxNMatrix(fieldType)) {
+
+    // Non-floating point matrices are represented as arrays of vectors, and
+    // therefore ColMajor and RowMajor decorations should not be applied to
+    // them.
+    QualType elemType = {};
+    if (isMxNMatrix(fieldType, &elemType) && elemType->isFloatingType()) {
       memberAlignment = memberSize = stride = 0;
       std::tie(memberAlignment, memberSize) =
           getAlignmentAndSize(fieldType, rule, isRowMajor, &stride);
@@ -1256,8 +1292,7 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
   //
   // 8. If the member is an array of S row-major matrices with C columns and R
   //    rows, the matrix is stored identically to a row of S X R row vectors
-  //    with C
-  //    components each, according to rule (4).
+  //    with C components each, according to rule (4).
   //
   // 9. If the member is a structure, the base alignment of the structure is N,
   //    where N is the largest base alignment value of any of its members, and

+ 7 - 2
tools/clang/lib/SPIRV/TypeTranslator.h

@@ -164,10 +164,15 @@ public:
                           uint32_t *rowCount = nullptr,
                           uint32_t *colCount = nullptr);
 
-  /// \broef returns true if type is a matrix and matrix is row major
-  /// If decl is not nullptr, is is checked for attributes specifying majorness
+  /// \brief Returns true if type is a matrix and matrix is row major
+  /// If decl is not nullptr, it is checked for attributes specifying majorness.
   bool isRowMajorMatrix(QualType type, const Decl *decl = nullptr) const;
 
+  /// \brief Returns true if the decl type is a non-floating-point matrix and
+  /// the matrix is column major, or if it is an array/struct containing such
+  /// matrices.
+  bool isOrContainsNonFpColMajorMatrix(QualType type, const Decl *decl) const;
+
   /// \brief Returns true if the two types are the same scalar or vector type,
   /// regardless of constness and literalness.
   static bool isSameScalarOrVecType(QualType type1, QualType type2);

+ 8 - 5
tools/clang/test/CodeGenSPIRV/vk.layout.asbuffer.std430.hlsl

@@ -4,6 +4,8 @@
 // CHECK: OpDecorate %_arr_v3float_uint_2 ArrayStride 16
 // CHECK: OpDecorate %_arr_mat2v3float_uint_2 ArrayStride 32
 // CHECK: OpDecorate %_arr_mat2v3float_uint_2_0 ArrayStride 24
+// CHECK: OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK: OpDecorate %_arr__arr_v3int_uint_2_uint_2 ArrayStride 32
 
 // CHECK: OpMemberDecorate %S 0 Offset 0
 // CHECK: OpMemberDecorate %S 1 Offset 16
@@ -17,13 +19,14 @@
 // CHECK: OpMemberDecorate %S 4 MatrixStride 8
 // CHECK: OpMemberDecorate %S 4 RowMajor
 // CHECK: OpMemberDecorate %S 5 Offset 208
+// CHECK: OpMemberDecorate %S 6 Offset 272
 
-// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 224
+// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 288
 
 // CHECK: OpMemberDecorate %T 0 Offset 0
-// CHECK: OpMemberDecorate %T 1 Offset 448
+// CHECK: OpMemberDecorate %T 1 Offset 576
 
-// CHECK: OpDecorate %_runtimearr_T ArrayStride 464
+// CHECK: OpDecorate %_runtimearr_T ArrayStride 592
 
 // CHECK: OpMemberDecorate %type_AppendStructuredBuffer_T 0 Offset 0
 // CHECK: OpDecorate %type_AppendStructuredBuffer_T BufferBlock
@@ -36,7 +39,8 @@ struct S {
     row_major    float2x3 c[2];
     column_major float2x3 d[2];
                  float2x3 e[2];
-                 int      f;
+    row_major    int2x3   f[2];
+                 int      g;
 };
 
 struct T {
@@ -49,4 +53,3 @@ AppendStructuredBuffer<T> buffer2;
 float main() : A {
     return 1.0;
 }
-

+ 30 - 26
tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.nested.std140.hlsl

@@ -1,39 +1,42 @@
 // Run: %dxc -T vs_6_0 -E main
 
 // Deep nested array of matrices
-// Depp nested majorness
+// Deep nested majorness
 struct R {                         // Alignment    Offset  Size                              Next
     row_major    float2x3 rf1[3];  // 16(vec4)  -> 0     + 3(array) * stride(2 * 16(vec4)) = 96
     column_major float2x3 rf2[4];  // 16(vec4)  -> 96    + 4(array) * stride(3 * 16(vec4)) = 288
                  float2x3 rf3[2];  // 16(vec4)  -> 288   + 2(array) * stride(3 * 16(vec4)) = 384
-                 int      rf4;     // 4         -> 384   + 4                               = 388
-};                                 // 16(max)                                                400 (388 round up to R alignment)
+    row_major    int2x3   rf4[2];  // 16(vec4)  -> 384   + 2(array) * stride(2 * 16(vec4)) = 448
+                 int      rf5;     // 4         -> 448   + 4                               = 452
+};                                 // 16(max)                                                464 (452 round up to R alignment)
 
 // Array of scalars, vectors, matrices, and structs
 struct S {                         // Alignment   Offset  Size                              Next
     float3       sf1[3];           // 16(vec4) -> 0     + 3(array) * 16(vec4)             = 48
     float        sf2[3];           // 4        -> 48    + 3(array) * 16(vec4)             = 96
-    R            sf3[4];           // 16       -> 96    + 4(array) * stride(400)          = 1696
-    row_major    float3x2 sf4[2];  // 16(vec4) -> 1696  + 2(array) * stride(3 * 16(vec4)) = 1792
-    column_major float3x2 sf5[3];  // 16(vec4) -> 1792  + 3(array) * stride(2 * 16(vec4)) = 1888
-                 float3x2 sf6[4];  // 16(vec4) -> 1888  + 4(array) * stride(2 * 16(vec4)) = 2016
-                 float    sf7;     // 4        -> 2016  + 4                               = 2020
-};                                 // 16(max)                                               2032 (2020 round up to S alignment)
+    R            sf3[4];           // 16       -> 96    + 4(array) * stride(464)          = 1952
+    row_major    float3x2 sf4[2];  // 16(vec4) -> 1952  + 2(array) * stride(3 * 16(vec4)) = 2048
+    column_major float3x2 sf5[3];  // 16(vec4) -> 2048  + 3(array) * stride(2 * 16(vec4)) = 2144
+                 float3x2 sf6[4];  // 16(vec4) -> 2144  + 4(array) * stride(2 * 16(vec4)) = 2272
+                 float    sf7;     // 4        -> 2272  + 4                               = 2276
+};                                 // 16(max)                                               2288 (2276 round up to S alignment)
 
 struct T {        // Alignment    Offset  Size              Next
-    R    tf1[2];  // 16        -> 0     + 2(array) * 400  = 800
-    S    tf2[3];  // 16        -> 800   + 3(array) * 2032 = 6896
-    uint tf3;     // 4         -> 6896  + 4               = 6900
-};                // 16(max)                                6912 (6900 round up to T alignment)
+    R    tf1[2];  // 16        -> 0     + 2(array) * 464  = 928
+    S    tf2[3];  // 16        -> 928   + 3(array) * 2288 = 7792
+    uint tf3;     // 4         -> 7792  + 4               = 7796
+};                // 16(max)                                7808 (7796 round up to T alignment)
 
 cbuffer MyCbuffer {  // Alignment   Offset   Size              Next
-    T    t[2];       // 16       -> 0      + 2(array) * 6912 = 13824
-    bool z;          // 4        -> 13824
+    T    t[2];       // 16       -> 0      + 2(array) * 7808 = 15616
+    bool z;          // 4        -> 15616
 };
 
 // CHECK:      OpDecorate %_arr_mat2v3float_uint_3 ArrayStride 32
 // CHECK:      OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 48
 // CHECK:      OpDecorate %_arr_mat2v3float_uint_2 ArrayStride 48
+// CHECK:      OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK:      OpDecorate %_arr__arr_v3int_uint_2_uint_2 ArrayStride 32
 
 // CHECK:      OpMemberDecorate %R 0 Offset 0
 // CHECK-NEXT: OpMemberDecorate %R 0 MatrixStride 16
@@ -45,11 +48,12 @@ cbuffer MyCbuffer {  // Alignment   Offset   Size              Next
 // CHECK-NEXT: OpMemberDecorate %R 2 MatrixStride 16
 // CHECK-NEXT: OpMemberDecorate %R 2 RowMajor
 // CHECK-NEXT: OpMemberDecorate %R 3 Offset 384
+// CHECK-NEXT: OpMemberDecorate %R 4 Offset 448
 
-// CHECK:      OpDecorate %_arr_R_uint_2 ArrayStride 400
+// CHECK:      OpDecorate %_arr_R_uint_2 ArrayStride 464
 // CHECK:      OpDecorate %_arr_v3float_uint_3 ArrayStride 16
 // CHECK:      OpDecorate %_arr_float_uint_3 ArrayStride 16
-// CHECK:      OpDecorate %_arr_R_uint_4 ArrayStride 400
+// CHECK:      OpDecorate %_arr_R_uint_4 ArrayStride 464
 
 // CHECK:      OpDecorate %_arr_mat3v2float_uint_2 ArrayStride 48
 // CHECK:      OpDecorate %_arr_mat3v2float_uint_3 ArrayStride 32
@@ -58,27 +62,27 @@ cbuffer MyCbuffer {  // Alignment   Offset   Size              Next
 // CHECK:      OpMemberDecorate %S 0 Offset 0
 // CHECK-NEXT: OpMemberDecorate %S 1 Offset 48
 // CHECK-NEXT: OpMemberDecorate %S 2 Offset 96
-// CHECK-NEXT: OpMemberDecorate %S 3 Offset 1696
+// CHECK-NEXT: OpMemberDecorate %S 3 Offset 1952
 // CHECK-NEXT: OpMemberDecorate %S 3 MatrixStride 16
 // CHECK-NEXT: OpMemberDecorate %S 3 ColMajor
-// CHECK-NEXT: OpMemberDecorate %S 4 Offset 1792
+// CHECK-NEXT: OpMemberDecorate %S 4 Offset 2048
 // CHECK-NEXT: OpMemberDecorate %S 4 MatrixStride 16
 // CHECK-NEXT: OpMemberDecorate %S 4 RowMajor
-// CHECK-NEXT: OpMemberDecorate %S 5 Offset 1888
+// CHECK-NEXT: OpMemberDecorate %S 5 Offset 2144
 // CHECK-NEXT: OpMemberDecorate %S 5 MatrixStride 16
 // CHECK-NEXT: OpMemberDecorate %S 5 RowMajor
-// CHECK-NEXT: OpMemberDecorate %S 6 Offset 2016
+// CHECK-NEXT: OpMemberDecorate %S 6 Offset 2272
 
-// CHECK:      OpDecorate %_arr_S_uint_3 ArrayStride 2032
+// CHECK-NEXT: OpDecorate %_arr_S_uint_3 ArrayStride 2288
 
 // CHECK:      OpMemberDecorate %T 0 Offset 0
-// CHECK-NEXT: OpMemberDecorate %T 1 Offset 800
-// CHECK-NEXT: OpMemberDecorate %T 2 Offset 6896
+// CHECK-NEXT: OpMemberDecorate %T 1 Offset 928
+// CHECK-NEXT: OpMemberDecorate %T 2 Offset 7792
 
-// CHECK:      OpDecorate %_arr_T_uint_2 ArrayStride 6912
+// CHECK:      OpDecorate %_arr_T_uint_2 ArrayStride 7808
 
 // CHECK-NEXT: OpMemberDecorate %type_MyCbuffer 0 Offset 0
-// CHECK-NEXT: OpMemberDecorate %type_MyCbuffer 1 Offset 13824
+// CHECK-NEXT: OpMemberDecorate %type_MyCbuffer 1 Offset 15616
 
 // CHECK:      OpDecorate %type_MyCbuffer Block
 float main() : A {

+ 14 - 11
tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.std140.hlsl

@@ -11,13 +11,14 @@ struct S {      // Alignment    Offset                                Size
     float  sf4; // 4         -> 44                                  + 4         = 48
 };              // 16(max)                                                        48(48 round up to S max alignment)
 
-struct T {           // Alignment     Offset                               Size              = Next
-    int      tf1;    // 4          -> 0                                  + 4                 = 4
-    R        tf2[3]; // 16         -> 16 (4 rounded up to R alignment)   + 3 * stride(16)    = 64
-    float3x2 tf3;    // 16(vec4)   -> 64 (64 round up to vec4 alignment) + 2 * stride(vec4)  = 96
-    S        tf4;    // 16         -> 96 (96 round up to S alignment)    + 48                = 144
-    float    tf5;    // 4          -> 144                                + 4                 = 148
-};                   // 16(max)                                                                160(148 round up to T max alignment)
+struct T {                     // Alignment     Offset                               Size              = Next
+              int      tf1;    // 4          -> 0                                  + 4                 = 4
+              R        tf2[3]; // 16         -> 16 (4 rounded up to R alignment)   + 3 * stride(16)    = 64
+              float3x2 tf3;    // 16(vec4)   -> 64 (64 round up to vec4 alignment) + 2 * stride(vec4)  = 96
+              S        tf4;    // 16         -> 96 (96 round up to S alignment)    + 48                = 144
+              float    tf5;    // 4          -> 144                                + 4                 = 148
+    row_major int3x2   tf6;    // 16(vec4)   -> 160 (148 rounded up to vec4)       + 3 * stride(vec4)  = 208
+};                             // 16(max)                                                                208(208 round up to T max alignment)
 
 cbuffer MyCBuffer {              // Alignment   Offset                                 Size                     Next
                  bool     a;     // 4        -> 0                                    +     4                  = 4
@@ -28,9 +29,9 @@ cbuffer MyCBuffer {              // Alignment   Offset
                  float2x1 f;     // 8(vec2)  -> 112 (112 round up to vec2 aligment)  + 2 * 4                  = 120
     row_major    float2x3 g[3];  // 16(vec4) -> 128 (120 round up to vec4 alignment) + 3 * 2 * stride(vec4)   = 224
     column_major float2x2 h[4];  // 16(vec4) -> 224 (224 round up to vec4 alignment) + 4 * 2 * stride(vec4)   = 352
-                 T        t;     // 16       -> 352 (352 round up to vec4 alignment) + 160                    = 512
-                 float    z;     // 4        -> 512
-
+                 T        t;     // 16       -> 352 (352 round up to vec4 alignment) + 208                    = 560
+    row_major    int2x3   y;     // 16(vec4) -> 560 (560 round up to vec4 alignment) + 2 * stride(vec4)       = 592
+                 float    z;     // 4        -> 592
 };
 
 // CHECK:      OpDecorate %_arr_mat2v3float_uint_3 ArrayStride 32
@@ -52,6 +53,7 @@ cbuffer MyCBuffer {              // Alignment   Offset
 // CHECK-NEXT: OpMemberDecorate %T 2 RowMajor
 // CHECK-NEXT: OpMemberDecorate %T 3 Offset 96
 // CHECK-NEXT: OpMemberDecorate %T 4 Offset 144
+// CHECK-NEXT: OpMemberDecorate %T 5 Offset 160
 
 // CHECK:      OpMemberDecorate %type_MyCBuffer 0 Offset 0
 // CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 1 Offset 4
@@ -70,7 +72,8 @@ cbuffer MyCBuffer {              // Alignment   Offset
 // CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 7 MatrixStride 16
 // CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 7 RowMajor
 // CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 8 Offset 352
-// CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 9 Offset 512
+// CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 9 Offset 560
+// CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 10 Offset 592
 // CHECK-NEXT: OpDecorate %type_MyCBuffer Block
 
 float main() : A {

+ 20 - 0
tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.zpc.hlsl

@@ -3,6 +3,9 @@
 // CHECK: OpDecorate %_arr_mat2v3float_uint_5 ArrayStride 32
 // CHECK: OpDecorate %_arr_mat2v3float_uint_5_0 ArrayStride 48
 
+// CHECK: OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK: OpDecorate %_arr__arr_v3int_uint_2_uint_5 ArrayStride 32
+
 // CHECK: OpMemberDecorate %type_MyCBuffer 0 ColMajor
 // CHECK: OpMemberDecorate %type_MyCBuffer 1 RowMajor
 // CHECK: OpMemberDecorate %type_MyCBuffer 2 RowMajor
@@ -12,6 +15,8 @@ cbuffer MyCBuffer {
     row_major    float2x3 matrices1[5];
     column_major float2x3 matrices2[5];
                  float2x3 matrices3[5];
+
+    row_major    int2x3   matrices4[5];
 }
 
 void main() {
@@ -22,4 +27,19 @@ void main() {
     float2x3 m1 = matrices1[1];
     float2x3 m2 = matrices2[2];
     float2x3 m3 = matrices3[3];
+
+    // Note: Since non-fp matrices are represented as arrays of vectors, and
+    // due to layout decoration on the rhs of the assignments below,
+    // a load and store is performed for each vector.
+
+// CHECK:          [[ptr_matrices4:%\d+]] = OpAccessChain %_ptr_Uniform__arr__arr_v3int_uint_2_uint_5 %MyCBuffer %int_3
+// CHECK-NEXT:   [[ptr_matrices4_1:%\d+]] = OpAccessChain %_ptr_Uniform__arr_v3int_uint_2 [[ptr_matrices4]] %int_1
+// CHECK-NEXT:       [[matrices4_1:%\d+]] = OpLoad %_arr_v3int_uint_2 [[ptr_matrices4_1]]
+// CHECK-NEXT:  [[matrices4_1_row0:%\d+]] = OpCompositeExtract %v3int [[matrices4_1]] 0
+// CHECK-NEXT:       [[ptr_m4_row0:%\d+]] = OpAccessChain %_ptr_Function_v3int %m4 %uint_0
+// CHECK-NEXT:                              OpStore [[ptr_m4_row0]] [[matrices4_1_row0]]
+// CHECK-NEXT:  [[matrices4_1_row1:%\d+]] = OpCompositeExtract %v3int [[matrices4_1]] 1
+// CHECK-NEXT:       [[ptr_m4_row1:%\d+]] = OpAccessChain %_ptr_Function_v3int %m4 %uint_1
+// CHECK-NEXT:                              OpStore [[ptr_m4_row1]] [[matrices4_1_row1]]
+    int2x3 m4 = matrices4[1];
 }

+ 31 - 0
tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.zpr.hlsl

@@ -3,6 +3,9 @@
 // CHECK: OpDecorate %_arr_mat2v3float_uint_5 ArrayStride 32
 // CHECK: OpDecorate %_arr_mat2v3float_uint_5_0 ArrayStride 48
 
+// CHECK: OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK: OpDecorate %_arr__arr_v3int_uint_2_uint_5 ArrayStride 32
+
 // CHECK: OpMemberDecorate %type_MyCBuffer 0 ColMajor
 // CHECK: OpMemberDecorate %type_MyCBuffer 1 RowMajor
 // CHECK: OpMemberDecorate %type_MyCBuffer 2 ColMajor
@@ -12,6 +15,9 @@ cbuffer MyCBuffer {
     row_major    float2x3 matrices1[5];
     column_major float2x3 matrices2[5];
                  float2x3 matrices3[5];
+
+    row_major    int2x3   matrices4[5];
+                 int2x3   matrices5[5];
 }
 
 void main() {
@@ -22,4 +28,29 @@ void main() {
     float2x3 m1 = matrices1[1];
     float2x3 m2 = matrices2[2];
     float2x3 m3 = matrices3[3];
+
+    // Note: Since non-fp matrices are represented as arrays of vectors, and
+    // due to layout decoration on the rhs of the assignments below,
+    // a load and store is performed for each vector.
+
+// CHECK:          [[ptr_matrices4:%\d+]] = OpAccessChain %_ptr_Uniform__arr__arr_v3int_uint_2_uint_5 %MyCBuffer %int_3
+// CHECK-NEXT:   [[ptr_matrices4_1:%\d+]] = OpAccessChain %_ptr_Uniform__arr_v3int_uint_2 [[ptr_matrices4]] %int_1
+// CHECK-NEXT:       [[matrices4_1:%\d+]] = OpLoad %_arr_v3int_uint_2 [[ptr_matrices4_1]]
+// CHECK-NEXT:  [[matrices4_1_row0:%\d+]] = OpCompositeExtract %v3int [[matrices4_1]] 0
+// CHECK-NEXT:       [[ptr_m4_row0:%\d+]] = OpAccessChain %_ptr_Function_v3int %m4 %uint_0
+// CHECK-NEXT:                              OpStore [[ptr_m4_row0]] [[matrices4_1_row0]]
+// CHECK-NEXT:  [[matrices4_1_row1:%\d+]] = OpCompositeExtract %v3int [[matrices4_1]] 1
+// CHECK-NEXT:       [[ptr_m4_row1:%\d+]] = OpAccessChain %_ptr_Function_v3int %m4 %uint_1
+// CHECK-NEXT:                              OpStore [[ptr_m4_row1]] [[matrices4_1_row1]]
+    int2x3 m4 = matrices4[1];
+// CHECK:          [[ptr_matrices5:%\d+]] = OpAccessChain %_ptr_Uniform__arr__arr_v3int_uint_2_uint_5 %MyCBuffer %int_4
+// CHECK-NEXT:   [[ptr_matrices5_2:%\d+]] = OpAccessChain %_ptr_Uniform__arr_v3int_uint_2 [[ptr_matrices5]] %int_2
+// CHECK-NEXT:       [[matrices5_2:%\d+]] = OpLoad %_arr_v3int_uint_2 [[ptr_matrices5_2]]
+// CHECK-NEXT: [[matrices_5_2_row0:%\d+]] = OpCompositeExtract %v3int [[matrices5_2]] 0
+// CHECK-NEXT:       [[ptr_m5_row0:%\d+]] = OpAccessChain %_ptr_Function_v3int %m5 %uint_0
+// CHECK-NEXT:                              OpStore [[ptr_m5_row0]] [[matrices_5_2_row0]]
+// CHECK-NEXT: [[matrices_5_2_row1:%\d+]] = OpCompositeExtract %v3int [[matrices5_2]] 1
+// CHECK-NEXT:       [[ptr_m5_row1:%\d+]] = OpAccessChain %_ptr_Function_v3int %m5 %uint_1
+// CHECK-NEXT:                              OpStore [[ptr_m5_row1]] [[matrices_5_2_row1]]
+    int2x3 m5 = matrices5[2];
 }

+ 8 - 4
tools/clang/test/CodeGenSPIRV/vk.layout.csbuffer.std430.hlsl

@@ -4,6 +4,8 @@
 // CHECK: OpDecorate %_arr_v3float_uint_2 ArrayStride 16
 // CHECK: OpDecorate %_arr_mat2v3float_uint_2 ArrayStride 32
 // CHECK: OpDecorate %_arr_mat2v3float_uint_2_0 ArrayStride 24
+// CHECK: OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK: OpDecorate %_arr__arr_v3int_uint_2_uint_2 ArrayStride 32
 
 // CHECK: OpMemberDecorate %S 0 Offset 0
 // CHECK: OpMemberDecorate %S 1 Offset 16
@@ -17,13 +19,14 @@
 // CHECK: OpMemberDecorate %S 4 MatrixStride 8
 // CHECK: OpMemberDecorate %S 4 RowMajor
 // CHECK: OpMemberDecorate %S 5 Offset 208
+// CHECK: OpMemberDecorate %S 6 Offset 272
 
-// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 224
+// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 288
 
 // CHECK: OpMemberDecorate %T 0 Offset 0
-// CHECK: OpMemberDecorate %T 1 Offset 448
+// CHECK: OpMemberDecorate %T 1 Offset 576
 
-// CHECK: OpDecorate %_runtimearr_T ArrayStride 464
+// CHECK: OpDecorate %_runtimearr_T ArrayStride 592
 
 // CHECK: OpMemberDecorate %type_ConsumeStructuredBuffer_T 0 Offset 0
 // CHECK: OpDecorate %type_ConsumeStructuredBuffer_T BufferBlock
@@ -36,7 +39,8 @@ struct S {
     row_major    float2x3 c[2];
     column_major float2x3 d[2];
                  float2x3 e[2];
-                 int      f;
+    row_major    int2x3   f[2];
+                 int      g;
 };
 
 struct T {

+ 20 - 0
tools/clang/test/CodeGenSPIRV/vk.layout.non-fp-matrix.error.hlsl

@@ -0,0 +1,20 @@
+// Run: %dxc -T vs_6_0 -E main
+
+cbuffer MyCBuffer {
+  struct S {
+    int2x3   matrices4[5];
+  } s;
+}
+
+struct T {
+    int2x3   t[5];
+};
+
+RWStructuredBuffer<T> rwsb;
+
+void main() {
+   int2x3 m4 = s.matrices4[1];
+}
+
+// CHECK: :6:5: error: externally initialized non-floating-point column-major matrices not supported yet
+// CHECK: :13:23: error: externally initialized non-floating-point column-major matrices not supported yet

+ 14 - 3
tools/clang/test/CodeGenSPIRV/vk.layout.push-constant.std430.hlsl

@@ -2,28 +2,39 @@
 
 // CHECK: OpDecorate %_arr_v2float_uint_3 ArrayStride 8
 // CHECK: OpDecorate %_arr_mat3v2float_uint_2 ArrayStride 32
+// CHECK: OpDecorate %_arr_v2int_uint_3 ArrayStride 8
+// CHECK: OpDecorate %_arr__arr_v2int_uint_3_uint_2 ArrayStride 24
 
 // CHECK: OpMemberDecorate %T 0 Offset 0
 // CHECK: OpMemberDecorate %T 1 Offset 32
 // CHECK: OpMemberDecorate %T 1 MatrixStride 16
 // CHECK: OpMemberDecorate %T 1 RowMajor
+// CHECK: OpMemberDecorate %T 2 Offset 96
+// CHECK: OpMemberDecorate %T 3 Offset 144
+// CHECK: OpMemberDecorate %T 3 MatrixStride 8
+// CHECK: OpMemberDecorate %T 3 ColMajor
 struct T {
                  float2   f1[3];
     column_major float3x2 f2[2];
+    row_major    int3x2   f4[2];
+    row_major    float3x2 f3[2];
 };
 
+// CHECK: OpDecorate %_arr_v3int_uint_2 ArrayStride 16
 // CHECK: OpMemberDecorate %type_PushConstant_S 0 Offset 0
 // CHECK: OpMemberDecorate %type_PushConstant_S 1 Offset 16
 // CHECK: OpMemberDecorate %type_PushConstant_S 2 Offset 32
-// CHECK: OpMemberDecorate %type_PushConstant_S 3 Offset 128
-// CHECK: OpMemberDecorate %type_PushConstant_S 3 MatrixStride 16
-// CHECK: OpMemberDecorate %type_PushConstant_S 3 ColMajor
+// CHECK: OpMemberDecorate %type_PushConstant_S 3 Offset 224
+// CHECK: OpMemberDecorate %type_PushConstant_S 4 Offset 256
+// CHECK: OpMemberDecorate %type_PushConstant_S 4 MatrixStride 16
+// CHECK: OpMemberDecorate %type_PushConstant_S 4 ColMajor
 
 // CHECK: OpDecorate %type_PushConstant_S Block
 struct S {
               float    f1;
               float3   f2;
               T        f4;
+    row_major int2x3   f5;
     row_major float2x3 f3;
 };
 

+ 34 - 26
tools/clang/test/CodeGenSPIRV/vk.layout.sbuffer.nested.std430.hlsl

@@ -6,29 +6,31 @@ struct R {                         // Alignment    Offset  Size
     row_major    float2x3 rf1[3];  // 16(vec4)  -> 0     + 3(array) * stride(2 * 16(vec4)) = 96
     column_major float2x3 rf2[4];  // 8(vec2)   -> 96    + 4(array) * stride(3 * 8(vec2))  = 192
                  float2x3 rf3[2];  // 8(vec2)   -> 192   + 2(array) * stride(3 * 8(vec2))  = 240
-                 int      rf4;     // 4         -> 240   + 4                               = 244
-};                                 // 16(max)                                                256 (244 round up to R alignment)
+    row_major    int2x3   rf4[3];  // 16(vec4)  -> 240   + 3(array) * stride(2 * 16(vec4)) = 336
+                 int      rf5;     // 4         -> 336   + 4                               = 340
+};                                 // 16(max)                                                352 (340 round up to R alignment)
 
 // Array of scalars, vectors, matrices, and structs
 struct S {                         // Alignment   Offset  Size                              Next
     float3       sf1[3];           // 16(vec4) -> 0     + 3(array) * 16(vec4)             = 48
     float        sf2[3];           // 4        -> 48    + 3(array) * 4                    = 60
-    R            sf3[4];           // 16       -> 64    + 4(array) * stride(256)          = 1088
-    row_major    float3x2 sf4[2];  // 8(vec2)  -> 1088  + 2(array) * stride(3 * 8(vec2))  = 1136
-    column_major float3x2 sf5[3];  // 16(vec4) -> 1136  + 3(array) * stride(2 * 16(vec4)) = 1232
-                 float3x2 sf6[4];  // 16(vec4) -> 1232  + 4(array) * stride(2 * 16(vec4)) = 1360
-                 float    sf7;     // 4        -> 1360  + 4                               = 1364
-};                                 // 16(max)                                               1376 (1364 round up to S alignment)
+    R            sf3[4];           // 16       -> 64    + 4(array) * stride(256)          = 1472
+    row_major    float3x2 sf4[2];  // 8(vec2)  -> 1472  + 2(array) * stride(3 * 8(vec2))  = 1520
+    column_major float3x2 sf5[3];  // 16(vec4) -> 1520  + 3(array) * stride(2 * 16(vec4)) = 1616
+                 float3x2 sf6[4];  // 16(vec4) -> 1616  + 4(array) * stride(2 * 16(vec4)) = 1744
+    row_major    int3x2   sf7[2];  // 8(vec2)  -> 1744  + 2(array) * stride(3 * 8(vec2))  = 1792
+                 float    sf8;     // 4        -> 1792  + 4                               = 1796
+};                                 // 16(max)                                               1808 (1796 round up to S alignment)
 
 struct T {        // Alignment    Offset  Size              Next
-    R    tf1[2];  // 16        -> 0     + 2(array) * 256  = 512
-    S    tf2[3];  // 16        -> 512   + 3(array) * 1376 = 4640
-    uint tf3;     // 4         -> 4640  + 4               = 4644
-};                // 16(max)                                4656 (4640 round up to T alignment)
+    R    tf1[2];  // 16        -> 0     + 2(array) * 352  = 704
+    S    tf2[3];  // 16        -> 704   + 3(array) * 1808 = 6128
+    uint tf3;     // 4         -> 6128  + 4               = 6132
+};                // 16(max)                                6144 (6132 round up to T alignment)
 
 struct SBuffer {  // Alignment   Offset   Size                 Next
-    T    t[2];       // 16       -> 0      + 2(array) * 4656 = 9312
-    bool z;          // 4        -> 9312
+    T    t[2];       // 16       -> 0      + 2(array) * 6144 = 12288
+    bool z;          // 4        -> 12288
 };
 
 RWStructuredBuffer<SBuffer> MySBuffer;
@@ -36,6 +38,8 @@ RWStructuredBuffer<SBuffer> MySBuffer;
 // CHECK:      OpDecorate %_arr_mat2v3float_uint_3 ArrayStride 32
 // CHECK:      OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 24
 // CHECK:      OpDecorate %_arr_mat2v3float_uint_2 ArrayStride 24
+// CHECK:      OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK:      OpDecorate %_arr__arr_v3int_uint_2_uint_3 ArrayStride 32
 
 // CHECK:      OpMemberDecorate %R 0 Offset 0
 // CHECK-NEXT: OpMemberDecorate %R 0 MatrixStride 16
@@ -47,42 +51,46 @@ RWStructuredBuffer<SBuffer> MySBuffer;
 // CHECK-NEXT: OpMemberDecorate %R 2 MatrixStride 8
 // CHECK-NEXT: OpMemberDecorate %R 2 RowMajor
 // CHECK-NEXT: OpMemberDecorate %R 3 Offset 240
+// CHECK-NEXT: OpMemberDecorate %R 4 Offset 336
 
-// CHECK:      OpDecorate %_arr_R_uint_2 ArrayStride 256
+// CHECK:      OpDecorate %_arr_R_uint_2 ArrayStride 352
 // CHECK:      OpDecorate %_arr_v3float_uint_3 ArrayStride 16
 // CHECK:      OpDecorate %_arr_float_uint_3 ArrayStride 4
-// CHECK:      OpDecorate %_arr_R_uint_4 ArrayStride 256
+// CHECK:      OpDecorate %_arr_R_uint_4 ArrayStride 352
 
 // CHECK:      OpDecorate %_arr_mat3v2float_uint_2 ArrayStride 24
 // CHECK:      OpDecorate %_arr_mat3v2float_uint_3 ArrayStride 32
 // CHECK:      OpDecorate %_arr_mat3v2float_uint_4 ArrayStride 32
+// CHECK:      OpDecorate %_arr_v2int_uint_3 ArrayStride 8
+// CHECK:      OpDecorate %_arr__arr_v2int_uint_3_uint_2 ArrayStride 24
 
 // CHECK:      OpMemberDecorate %S 0 Offset 0
 // CHECK-NEXT: OpMemberDecorate %S 1 Offset 48
 // CHECK-NEXT: OpMemberDecorate %S 2 Offset 64
-// CHECK-NEXT: OpMemberDecorate %S 3 Offset 1088
+// CHECK-NEXT: OpMemberDecorate %S 3 Offset 1472
 // CHECK-NEXT: OpMemberDecorate %S 3 MatrixStride 8
 // CHECK-NEXT: OpMemberDecorate %S 3 ColMajor
-// CHECK-NEXT: OpMemberDecorate %S 4 Offset 1136
+// CHECK-NEXT: OpMemberDecorate %S 4 Offset 1520
 // CHECK-NEXT: OpMemberDecorate %S 4 MatrixStride 16
 // CHECK-NEXT: OpMemberDecorate %S 4 RowMajor
-// CHECK-NEXT: OpMemberDecorate %S 5 Offset 1232
+// CHECK-NEXT: OpMemberDecorate %S 5 Offset 1616
 // CHECK-NEXT: OpMemberDecorate %S 5 MatrixStride 16
 // CHECK-NEXT: OpMemberDecorate %S 5 RowMajor
-// CHECK-NEXT: OpMemberDecorate %S 6 Offset 1360
+// CHECK-NEXT: OpMemberDecorate %S 6 Offset 1744
+// CHECK-NEXT: OpMemberDecorate %S 7 Offset 1792
 
-// CHECK:      OpDecorate %_arr_S_uint_3 ArrayStride 1376
+// CHECK:      OpDecorate %_arr_S_uint_3 ArrayStride 1808
 
 // CHECK:      OpMemberDecorate %T 0 Offset 0
-// CHECK-NEXT: OpMemberDecorate %T 1 Offset 512
-// CHECK-NEXT: OpMemberDecorate %T 2 Offset 4640
+// CHECK-NEXT: OpMemberDecorate %T 1 Offset 704
+// CHECK-NEXT: OpMemberDecorate %T 2 Offset 6128
 
-// CHECK:      OpDecorate %_arr_T_uint_2 ArrayStride 4656
+// CHECK:      OpDecorate %_arr_T_uint_2 ArrayStride 6144
 
 // CHECK-NEXT: OpMemberDecorate %SBuffer 0 Offset 0
-// CHECK-NEXT: OpMemberDecorate %SBuffer 1 Offset 9312
+// CHECK-NEXT: OpMemberDecorate %SBuffer 1 Offset 12288
 
-// CHECK:      OpDecorate %_runtimearr_SBuffer ArrayStride 9328
+// CHECK:      OpDecorate %_runtimearr_SBuffer ArrayStride 12304
 
 // CHECK:      OpMemberDecorate %type_RWStructuredBuffer_SBuffer 0 Offset 0
 // CHECK-NEXT: OpDecorate %type_RWStructuredBuffer_SBuffer BufferBlock

+ 18 - 11
tools/clang/test/CodeGenSPIRV/vk.layout.sbuffer.std430.hlsl

@@ -11,13 +11,14 @@ struct S {      // Alignment    Offset                                Size
     float  sf4; // 4         -> 28                                  + 4         = 32
 };              // 16(max)                                                        32
 
-struct T {           // Alignment     Offset                               Size              = Next
-    int      tf1;    // 4          -> 0                                  + 4                 = 4
-    R        tf2[3]; // 8          -> 8                                  + 3 * stride(8)     = 32
-    float3x2 tf3;    // 16(vec4)   -> 32 (32 round up to vec4 alignment) + 2 * stride(vec4)  = 64
-    S        tf4;    // 16         -> 64 (64 round up to S alignment)    + 32                = 96
-    float    tf5;    // 4          -> 96                                 + 4                 = 100
-};                   // 16(max)                                                                112(100 round up to T max alignment)
+struct T {                      // Alignment     Offset                               Size              = Next
+               int      tf1;    // 4          -> 0                                  + 4                 = 4
+               R        tf2[3]; // 8          -> 8                                  + 3 * stride(8)     = 32
+               float3x2 tf3;    // 16(vec4)   -> 32 (32 round up to vec4 alignment) + 2 * stride(vec4)  = 64
+  row_major    int3x2   tf4;    // 16(vec4)   -> 64 (64 round up to vec4 alignment) + 3 * stride(vec2)  = 88
+               S        tf5;    // 16         -> 96 (88 round up to S alignment)    + 32                = 128
+               float    tf6;    // 4          -> 128                                + 4                 = 132
+};                              // 16(max)                                                                144(132 round up to T max alignment)
 
 struct SBuffer {              // Alignment   Offset                                 Size                     Next
                  bool     a;     // 4        -> 0                                    +     4                  = 4
@@ -28,8 +29,9 @@ struct SBuffer {              // Alignment   Offset
                  float2x1 f;     // 8(vec2)  -> 88 (88 round up to vec2 aligment)    + 2 * 4                  = 96
     row_major    float2x3 g[3];  // 16(vec4) -> 96 (96 round up to vec4 alignment)   + 3 * 2 * stride(vec4)   = 192
     column_major float2x2 h[4];  // 16(vec4) -> 192 (192 round up to vec2 alignment) + 4 * 2 * stride(vec2)   = 256
-                 T        t;     // 16       -> 256 (352 round up to T alignment)    + 112                    = 368
-                 float    z;     // 4        -> 368
+    row_major    int2x3   i[5];  // 16(vec4) -> 256 (256 round up to vec4 alignment) + 5 * 2 * stride(vec4)   = 416
+                 T        t;     // 16       -> 416 (416 round up to T alignment)    + 144                    = 560
+                 float    z;     // 4        -> 560
 
 };
 
@@ -37,10 +39,13 @@ StructuredBuffer<SBuffer> MySBuffer;
 
 // CHECK:      OpDecorate %_arr_mat2v3float_uint_3 ArrayStride 32
 // CHECK:      OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
+// CHECK:      OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK:      OpDecorate %_arr__arr_v3int_uint_2_uint_5 ArrayStride 32
 
 // CHECK:      OpMemberDecorate %R 0 Offset 0
 
 // CHECK:      OpDecorate %_arr_R_uint_3 ArrayStride 8
+// CEHCK:      OpDecorate %_arr_v2int_uint_3 ArrayStride 8
 
 // CHECK:      OpMemberDecorate %S 0 Offset 0
 // CHECK-NEXT: OpMemberDecorate %S 1 Offset 8
@@ -54,6 +59,7 @@ StructuredBuffer<SBuffer> MySBuffer;
 // CHECK-NEXT: OpMemberDecorate %T 2 RowMajor
 // CHECK-NEXT: OpMemberDecorate %T 3 Offset 64
 // CHECK-NEXT: OpMemberDecorate %T 4 Offset 96
+// CHECK-NEXT: OpMemberDecorate %T 5 Offset 128
 
 // CHECK:      OpMemberDecorate %SBuffer 0 Offset 0
 // CHECK-NEXT: OpMemberDecorate %SBuffer 1 Offset 4
@@ -72,9 +78,10 @@ StructuredBuffer<SBuffer> MySBuffer;
 // CHECK-NEXT: OpMemberDecorate %SBuffer 7 MatrixStride 8
 // CHECK-NEXT: OpMemberDecorate %SBuffer 7 RowMajor
 // CHECK-NEXT: OpMemberDecorate %SBuffer 8 Offset 256
-// CHECK-NEXT: OpMemberDecorate %SBuffer 9 Offset 368
+// CHECK-NEXT: OpMemberDecorate %SBuffer 9 Offset 416
+// CHECK-NEXT: OpMemberDecorate %SBuffer 10 Offset 560
 
-// CHECK:      OpDecorate %_runtimearr_SBuffer ArrayStride 384
+// CHECK:      OpDecorate %_runtimearr_SBuffer ArrayStride 576
 
 // CHECK:      OpMemberDecorate %type_StructuredBuffer_SBuffer 0 Offset 0
 // CHECK-NEXT: OpMemberDecorate %type_StructuredBuffer_SBuffer 0 NonWritable

+ 7 - 3
tools/clang/test/CodeGenSPIRV/vk.layout.tbuffer.std430.hlsl

@@ -4,6 +4,8 @@
 // CHECK: OpDecorate %_arr_v3float_uint_2 ArrayStride 16
 // CHECK: OpDecorate %_arr_mat2v3float_uint_2 ArrayStride 32
 // CHECK: OpDecorate %_arr_mat2v3float_uint_2_0 ArrayStride 24
+// CHECK: OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK: OpDecorate %_arr__arr_v3int_uint_2_uint_2 ArrayStride 32
 
 // CHECK: OpMemberDecorate %S 0 Offset 0
 // CHECK: OpMemberDecorate %S 1 Offset 16
@@ -17,11 +19,12 @@
 // CHECK: OpMemberDecorate %S 4 MatrixStride 8
 // CHECK: OpMemberDecorate %S 4 RowMajor
 // CHECK: OpMemberDecorate %S 5 Offset 208
+// CHECK: OpMemberDecorate %S 6 Offset 272
 
-// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 224
+// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 288
 
 // CHECK: OpMemberDecorate %type_myTbuffer 0 Offset 0
-// CHECK: OpMemberDecorate %type_myTbuffer 1 Offset 448
+// CHECK: OpMemberDecorate %type_myTbuffer 1 Offset 576
 
 // CHECK: OpDecorate %type_myTbuffer BufferBlock
 
@@ -34,7 +37,8 @@ struct S {
     row_major    float2x3 c[2];
     column_major float2x3 d[2];
                  float2x3 e[2];
-                 int      f;
+    row_major    int2x3   f[2];
+                 int      g;
 };
 
 tbuffer myTbuffer : register(t0)

+ 7 - 3
tools/clang/test/CodeGenSPIRV/vk.layout.texture-buffer.std430.hlsl

@@ -4,6 +4,8 @@
 // CHECK: OpDecorate %_arr_v3float_uint_2 ArrayStride 16
 // CHECK: OpDecorate %_arr_mat2v3float_uint_2 ArrayStride 32
 // CHECK: OpDecorate %_arr_mat2v3float_uint_2_0 ArrayStride 24
+// CHECK: OpDecorate %_arr_v3int_uint_2 ArrayStride 16
+// CHECK: OpDecorate %_arr__arr_v3int_uint_2_uint_2 ArrayStride 32
 
 // CHECK: OpMemberDecorate %S 0 Offset 0
 // CHECK: OpMemberDecorate %S 1 Offset 16
@@ -17,11 +19,12 @@
 // CHECK: OpMemberDecorate %S 4 MatrixStride 8
 // CHECK: OpMemberDecorate %S 4 RowMajor
 // CHECK: OpMemberDecorate %S 5 Offset 208
+// CHECK: OpMemberDecorate %S 6 Offset 272
 
-// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 224
+// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 288
 
 // CHECK: OpMemberDecorate %type_TextureBuffer_T 0 Offset 0
-// CHECK: OpMemberDecorate %type_TextureBuffer_T 1 Offset 448
+// CHECK: OpMemberDecorate %type_TextureBuffer_T 1 Offset 576
 
 // CHECK: OpDecorate %type_TextureBuffer_T BufferBlock
 
@@ -34,7 +37,8 @@ struct S {
     row_major    float2x3 c[2];
     column_major float2x3 d[2];
                  float2x3 e[2];
-                 int      f;
+    row_major    int2x3   f[2];
+                 int      g;
 };
 
 struct T {

+ 4 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -1216,6 +1216,10 @@ TEST_F(FileTest, VulkanSubpassInputError) {
   runFileTest("vk.subpass-input.error.hlsl", Expect::Failure);
 }
 
+TEST_F(FileTest, NonFpColMajorError) {
+  runFileTest("vk.layout.non-fp-matrix.error.hlsl", Expect::Failure);
+}
+
 // HS: for different Patch Constant Functions
 TEST_F(FileTest, HullShaderPCFVoid) { runFileTest("hs.pcf.void.hlsl"); }
 TEST_F(FileTest, HullShaderPCFTakesInputPatch) {