Quellcode durchsuchen

Fix reflection of ConstantBuffer/StructuredBuffer arrays, nested arrays

Bugs for arrays:
- Size incorrect for ConstantBuffer type
  (should not be divided by array size)
- Size incorrect for StructuredBuffer element
  (was calculated with array dimensions multiplied in)
- Nested arrays would assert (ConstantBuffer) or
  fail to count/unwrap all resource dims (StructuredBuffer)

Match fxc weirdness:
- ConstantBuffer array has Elements == 1 for inner element type
  instead of 0, which would be consistent with everything else.
- StructuredBuffer array has "[0]" appended to the Name
  for each array dimension of the buffer...
Tex Riddell vor 6 Jahren
Ursprung
Commit
2165224f0e

+ 6 - 5
lib/HLSL/DxilCondenseResources.cpp

@@ -1636,10 +1636,13 @@ void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res,
   Constant *Symbol = Res.GetGlobalSymbol();
   Type *ElemTy = Symbol->getType()->getPointerElementType();
   bool IsResourceArray = Res.GetRangeSize() != 1;
+  std::vector<unsigned> arrayDims;
   if (IsResourceArray) {
     // Support Array of ConstantBuffer.
-    if (ElemTy->isArrayTy())
+    while (ElemTy->isArrayTy()) {
+      arrayDims.push_back((unsigned)ElemTy->getArrayNumElements());
       ElemTy = ElemTy->getArrayElementType();
+    }
   }
   StructType *ST = cast<StructType>(ElemTy);
   if (ST->isOpaque()) {
@@ -1651,12 +1654,10 @@ void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res,
   Type *UpdatedST =
       UpdateStructTypeForLegacyLayout(ST, TypeSys, M);
   if (ST != UpdatedST) {
-    Type *Ty = Symbol->getType()->getPointerElementType();
     if (IsResourceArray) {
       // Support Array of ConstantBuffer.
-      if (Ty->isArrayTy()) {
-        UpdatedST = ArrayType::get(UpdatedST, Ty->getArrayNumElements());
-      }
+      for (auto it = arrayDims.rbegin(), E = arrayDims.rend(); it != E; ++it)
+        UpdatedST = ArrayType::get(UpdatedST, *it);
     }
     GlobalVariable *NewGV = cast<GlobalVariable>(
         M.getOrInsertGlobal(Symbol->getName().str() + "_legacy", UpdatedST));

+ 32 - 7
lib/HLSL/DxilContainerReflection.cpp

@@ -357,6 +357,7 @@ class CShaderReflection;
 struct D3D11_INTERNALSHADER_RESOURCE_DEF;
 class CShaderReflectionType : public ID3D12ShaderReflectionType
 {
+  friend class CShaderReflectionConstantBuffer;
 protected:
   D3D12_SHADER_TYPE_DESC              m_Desc;
   UINT                                m_SizeInCBuffer;
@@ -429,6 +430,8 @@ class CShaderReflectionConstantBuffer : public ID3D12ShaderReflectionConstantBuf
 protected:
   D3D12_SHADER_BUFFER_DESC                m_Desc;
   std::vector<CShaderReflectionVariable>  m_Variables;
+  // For StructuredBuffer arrays, Name will have [0] appended for each dimension to match fxc behavior.
+  std::string m_ReflectionName;
 
 public:
   CShaderReflectionConstantBuffer() = default;
@@ -1101,15 +1104,18 @@ void CShaderReflectionConstantBuffer::Initialize(
   std::vector<std::unique_ptr<CShaderReflectionType>>& allTypes) {
   ZeroMemory(&m_Desc, sizeof(m_Desc));
   m_Desc.Name = CB.GetGlobalName().c_str();
-  m_Desc.Size = CB.GetSize() / CB.GetRangeSize();
+  m_Desc.Size = CB.GetSize();
   m_Desc.Size = (m_Desc.Size + 0x0f) & ~(0x0f); // Round up to 16 bytes for reflection.
   m_Desc.Type = D3D_CT_CBUFFER;
   m_Desc.uFlags = 0;
   Type *Ty = CB.GetGlobalSymbol()->getType()->getPointerElementType();
   // For ConstantBuffer<> buf[2], the array size is in Resource binding count
   // part.
-  if (Ty->isArrayTy())
+  unsigned resArrayDims = 0;
+  while (Ty->isArrayTy()) {
     Ty = Ty->getArrayElementType();
+    resArrayDims += 1;
+  }
 
   DxilTypeSystem &typeSys = M.GetTypeSystem();
   StructType *ST = cast<StructType>(Ty);
@@ -1121,6 +1127,10 @@ void CShaderReflectionConstantBuffer::Initialize(
 
   m_Desc.Variables = ST->getNumContainedTypes();
 
+  if (resArrayDims) {
+    DXASSERT(m_Desc.Variables == 1, "otherwise, assumption is wrong");
+  }
+
   for (unsigned i = 0; i < ST->getNumContainedTypes(); ++i) {
     DxilFieldAnnotation &fieldAnnotation = annotation->GetFieldAnnotation(i);
 
@@ -1133,6 +1143,12 @@ void CShaderReflectionConstantBuffer::Initialize(
     allTypes.push_back(std::unique_ptr<CShaderReflectionType>(pVarType));
     pVarType->Initialize(M, ST->getContainedType(i), fieldAnnotation, fieldAnnotation.GetCBufferOffset(), allTypes, true);
 
+    // Replicate fxc bug, where Elements == 1 for inner struct of CB array, instead of 0.
+    if (resArrayDims) {
+      DXASSERT(pVarType->m_Desc.Elements == 0, "otherwise, assumption is wrong");
+      pVarType->m_Desc.Elements = 1;
+    }
+
     BYTE *pDefaultValue = nullptr;
 
     VarDesc.Name = fieldAnnotation.GetFieldName().c_str();
@@ -1175,6 +1191,10 @@ static unsigned CalcTypeSize(Type *Ty) {
 static unsigned CalcResTypeSize(DxilModule &M, DxilResource &R) {
   UNREFERENCED_PARAMETER(M);
   Type *Ty = R.GetGlobalSymbol()->getType()->getPointerElementType();
+  if (R.IsStructuredBuffer()) {
+    while (Ty->isArrayTy())
+      Ty = Ty->getArrayElementType();
+  }
   return CalcTypeSize(Ty);
 }
 
@@ -1183,8 +1203,7 @@ void CShaderReflectionConstantBuffer::InitializeStructuredBuffer(
   DxilResource &R,
   std::vector<std::unique_ptr<CShaderReflectionType>>& allTypes) {
   ZeroMemory(&m_Desc, sizeof(m_Desc));
-  m_Desc.Name = R.GetGlobalName().c_str();
-  //m_Desc.Size = R.GetSize();
+  m_ReflectionName = R.GetGlobalName();
   m_Desc.Type = D3D11_CT_RESOURCE_BIND_INFO;
   m_Desc.uFlags = 0;
   m_Desc.Variables = 1;
@@ -1192,7 +1211,7 @@ void CShaderReflectionConstantBuffer::InitializeStructuredBuffer(
   D3D12_SHADER_VARIABLE_DESC VarDesc;
   ZeroMemory(&VarDesc, sizeof(VarDesc));
   VarDesc.Name = "$Element";
-  VarDesc.Size = CalcResTypeSize(M, R); // aligned bytes
+  VarDesc.Size = CalcResTypeSize(M, R);
   VarDesc.StartTexture = UINT_MAX;
   VarDesc.StartSampler = UINT_MAX;
   VarDesc.uFlags |= D3D_SVF_USED; // TODO: not necessarily true
@@ -1203,8 +1222,14 @@ void CShaderReflectionConstantBuffer::InitializeStructuredBuffer(
 
   // Extract the `struct` that wraps element type of the buffer resource
   Type *Ty = R.GetGlobalSymbol()->getType()->getPointerElementType();
-  if(Ty->isArrayTy())
-      Ty = Ty->getArrayElementType();
+  unsigned resArrayDims = 0;
+  while (Ty->isArrayTy()) {
+    Ty = Ty->getArrayElementType();
+    resArrayDims += 1;
+    // Replicate fxc bug, where Name gets [0] appended for each resource array dimension.
+    m_ReflectionName += "[0]";
+  }
+  m_Desc.Name = m_ReflectionName.c_str();
   StructType *ST = cast<StructType>(Ty);
 
   // Look up struct type annotation on the element type

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/structured_buffer_getdim_stride.hlsl

@@ -27,4 +27,4 @@ uint UseBuf(int2 idx) {
 // CHECK:         BindPoint: 0
 // CHECK:         ReturnType: D3D_RETURN_TYPE_MIXED
 // CHECK:         Dimension: D3D_SRV_DIMENSION_BUFFER
-// CHECK:         NumSamples (or stride): 40
+// CHECK:         NumSamples (or stride): 20

+ 319 - 2
tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/structured_buffer_layout.hlsl

@@ -4,7 +4,7 @@
 // even when structure is shared with a ConstantBuffer.
 
 #if 0
-// CHECK:       Constant Buffers:
+//      CHECK:  Constant Buffers:
 // CHECK-NEXT:    ID3D12ShaderReflectionConstantBuffer:
 // CHECK-NEXT:      D3D12_SHADER_BUFFER_DESC: Name: CB
 // CHECK-NEXT:        Type: D3D_CT_CBUFFER
@@ -360,6 +360,135 @@
 // CHECK-NEXT:          CBuffer: CB1
 // CHECK-NEXT:      }
 // CHECK-NEXT:    ID3D12ShaderReflectionConstantBuffer:
+// CHECK-NEXT:      D3D12_SHADER_BUFFER_DESC: Name: CBArray
+// CHECK-NEXT:        Type: D3D_CT_CBUFFER
+// CHECK-NEXT:        Size: 256
+// CHECK-NEXT:        uFlags: 0
+// CHECK-NEXT:        Num Variables: 1
+// CHECK-NEXT:      {
+// CHECK-NEXT:        ID3D12ShaderReflectionVariable:
+// CHECK-NEXT:          D3D12_SHADER_VARIABLE_DESC: Name: CBArray
+// CHECK-NEXT:            Size: 244
+// CHECK-NEXT:            StartOffset: 0
+// CHECK-NEXT:            uFlags: 0x2
+// CHECK-NEXT:            DefaultValue: <nullptr>
+// CHECK-NEXT:          ID3D12ShaderReflectionType:
+// CHECK-NEXT:            D3D12_SHADER_TYPE_DESC: Name: SA
+// CHECK-NEXT:              Class: D3D_SVC_STRUCT
+// CHECK-NEXT:              Type: D3D_SVT_VOID
+// CHECK-NEXT:              Elements: 1
+// CHECK-NEXT:              Rows: 1
+// CHECK-NEXT:              Columns: 32
+// CHECK-NEXT:              Members: 1
+// CHECK-NEXT:              Offset: 0
+// CHECK-NEXT:            {
+// CHECK-NEXT:              ID3D12ShaderReflectionType:
+// CHECK-NEXT:                D3D12_SHADER_TYPE_DESC: Name: S1
+// CHECK-NEXT:                  Class: D3D_SVC_STRUCT
+// CHECK-NEXT:                  Type: D3D_SVT_VOID
+// CHECK-NEXT:                  Elements: 2
+// CHECK-NEXT:                  Rows: 1
+// CHECK-NEXT:                  Columns: 16
+// CHECK-NEXT:                  Members: 8
+// CHECK-NEXT:                  Offset: 0
+// CHECK-NEXT:                {
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: int
+// CHECK-NEXT:                      Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                      Type: D3D_SVT_INT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 1
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 0
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: S0
+// CHECK-NEXT:                      Class: D3D_SVC_STRUCT
+// CHECK-NEXT:                      Type: D3D_SVT_VOID
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 3
+// CHECK-NEXT:                      Members: 2
+// CHECK-NEXT:                      Offset: 16
+// CHECK-NEXT:                    {
+// CHECK-NEXT:                      ID3D12ShaderReflectionType:
+// CHECK-NEXT:                        D3D12_SHADER_TYPE_DESC: Name: int2
+// CHECK-NEXT:                          Class: D3D_SVC_VECTOR
+// CHECK-NEXT:                          Type: D3D_SVT_INT
+// CHECK-NEXT:                          Elements: 0
+// CHECK-NEXT:                          Rows: 1
+// CHECK-NEXT:                          Columns: 2
+// CHECK-NEXT:                          Members: 0
+// CHECK-NEXT:                          Offset: 0
+// CHECK-NEXT:                      ID3D12ShaderReflectionType:
+// CHECK-NEXT:                        D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK-NEXT:                          Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                          Type: D3D_SVT_FLOAT
+// CHECK-NEXT:                          Elements: 0
+// CHECK-NEXT:                          Rows: 1
+// CHECK-NEXT:                          Columns: 1
+// CHECK-NEXT:                          Members: 0
+// CHECK-NEXT:                          Offset: 8
+// CHECK-NEXT:                    }
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: int2
+// CHECK-NEXT:                      Class: D3D_SVC_VECTOR
+// CHECK-NEXT:                      Type: D3D_SVT_INT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 2
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 32
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: float3
+// CHECK-NEXT:                      Class: D3D_SVC_VECTOR
+// CHECK-NEXT:                      Type: D3D_SVT_FLOAT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 3
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 48
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: int2
+// CHECK-NEXT:                      Class: D3D_SVC_VECTOR
+// CHECK-NEXT:                      Type: D3D_SVT_INT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 2
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 64
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: float2x1
+// CHECK-NEXT:                      Class: D3D_SVC_MATRIX_COLUMNS
+// CHECK-NEXT:                      Type: D3D_SVT_FLOAT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 2
+// CHECK-NEXT:                      Columns: 1
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 72
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: int
+// CHECK-NEXT:                      Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                      Type: D3D_SVT_INT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 1
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 80
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: float1x2
+// CHECK-NEXT:                      Class: D3D_SVC_MATRIX_COLUMNS
+// CHECK-NEXT:                      Type: D3D_SVT_FLOAT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 2
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 96
+// CHECK-NEXT:                }
+// CHECK-NEXT:            }
+// CHECK-NEXT:          CBuffer: CBArray
+// CHECK-NEXT:      }
+// CHECK-NEXT:    ID3D12ShaderReflectionConstantBuffer:
 // CHECK-NEXT:      D3D12_SHADER_BUFFER_DESC: Name: SB
 // CHECK-NEXT:        Type: D3D_CT_RESOURCE_BIND_INFO
 // CHECK-NEXT:        Size: 64
@@ -477,6 +606,186 @@
 // CHECK-NEXT:            }
 // CHECK-NEXT:          CBuffer: SB
 // CHECK-NEXT:      }
+// CHECK-NEXT:    ID3D12ShaderReflectionConstantBuffer:
+// CHECK-NEXT:      D3D12_SHADER_BUFFER_DESC: Name: SBArray
+// CHECK-NEXT:        Type: D3D_CT_RESOURCE_BIND_INFO
+// CHECK-NEXT:        Size: 128
+// CHECK-NEXT:        uFlags: 0
+// CHECK-NEXT:        Num Variables: 1
+// CHECK-NEXT:      {
+// CHECK-NEXT:        ID3D12ShaderReflectionVariable:
+// CHECK-NEXT:          D3D12_SHADER_VARIABLE_DESC: Name: $Element
+// CHECK-NEXT:            Size: 128
+// CHECK-NEXT:            StartOffset: 0
+// CHECK-NEXT:            uFlags: 0x2
+// CHECK-NEXT:            DefaultValue: <nullptr>
+// CHECK-NEXT:          ID3D12ShaderReflectionType:
+// CHECK-NEXT:            D3D12_SHADER_TYPE_DESC: Name: SA
+// CHECK-NEXT:              Class: D3D_SVC_STRUCT
+// CHECK-NEXT:              Type: D3D_SVT_VOID
+// CHECK-NEXT:              Elements: 0
+// CHECK-NEXT:              Rows: 1
+// CHECK-NEXT:              Columns: 32
+// CHECK-NEXT:              Members: 1
+// CHECK-NEXT:              Offset: 0
+// CHECK-NEXT:            {
+// CHECK-NEXT:              ID3D12ShaderReflectionType:
+// CHECK-NEXT:                D3D12_SHADER_TYPE_DESC: Name: S1
+// CHECK-NEXT:                  Class: D3D_SVC_STRUCT
+// CHECK-NEXT:                  Type: D3D_SVT_VOID
+// CHECK-NEXT:                  Elements: 2
+// CHECK-NEXT:                  Rows: 1
+// CHECK-NEXT:                  Columns: 16
+// CHECK-NEXT:                  Members: 8
+// CHECK-NEXT:                  Offset: 0
+// CHECK-NEXT:                {
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: int
+// CHECK-NEXT:                      Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                      Type: D3D_SVT_INT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 1
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 0
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: S0
+// CHECK-NEXT:                      Class: D3D_SVC_STRUCT
+// CHECK-NEXT:                      Type: D3D_SVT_VOID
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 3
+// CHECK-NEXT:                      Members: 2
+// CHECK-NEXT:                      Offset: 4
+// CHECK-NEXT:                    {
+// CHECK-NEXT:                      ID3D12ShaderReflectionType:
+// CHECK-NEXT:                        D3D12_SHADER_TYPE_DESC: Name: int2
+// CHECK-NEXT:                          Class: D3D_SVC_VECTOR
+// CHECK-NEXT:                          Type: D3D_SVT_INT
+// CHECK-NEXT:                          Elements: 0
+// CHECK-NEXT:                          Rows: 1
+// CHECK-NEXT:                          Columns: 2
+// CHECK-NEXT:                          Members: 0
+// CHECK-NEXT:                          Offset: 0
+// CHECK-NEXT:                      ID3D12ShaderReflectionType:
+// CHECK-NEXT:                        D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK-NEXT:                          Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                          Type: D3D_SVT_FLOAT
+// CHECK-NEXT:                          Elements: 0
+// CHECK-NEXT:                          Rows: 1
+// CHECK-NEXT:                          Columns: 1
+// CHECK-NEXT:                          Members: 0
+// CHECK-NEXT:                          Offset: 8
+// CHECK-NEXT:                    }
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: int2
+// CHECK-NEXT:                      Class: D3D_SVC_VECTOR
+// CHECK-NEXT:                      Type: D3D_SVT_INT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 2
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 16
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: float3
+// CHECK-NEXT:                      Class: D3D_SVC_VECTOR
+// CHECK-NEXT:                      Type: D3D_SVT_FLOAT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 3
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 24
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: int2
+// CHECK-NEXT:                      Class: D3D_SVC_VECTOR
+// CHECK-NEXT:                      Type: D3D_SVT_INT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 2
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 36
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: float2x1
+// CHECK-NEXT:                      Class: D3D_SVC_MATRIX_COLUMNS
+// CHECK-NEXT:                      Type: D3D_SVT_FLOAT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 2
+// CHECK-NEXT:                      Columns: 1
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 44
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: int
+// CHECK-NEXT:                      Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                      Type: D3D_SVT_INT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 1
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 52
+// CHECK-NEXT:                  ID3D12ShaderReflectionType:
+// CHECK-NEXT:                    D3D12_SHADER_TYPE_DESC: Name: float1x2
+// CHECK-NEXT:                      Class: D3D_SVC_MATRIX_COLUMNS
+// CHECK-NEXT:                      Type: D3D_SVT_FLOAT
+// CHECK-NEXT:                      Elements: 0
+// CHECK-NEXT:                      Rows: 1
+// CHECK-NEXT:                      Columns: 2
+// CHECK-NEXT:                      Members: 0
+// CHECK-NEXT:                      Offset: 56
+// CHECK-NEXT:                }
+// CHECK-NEXT:            }
+// CHECK-NEXT:          CBuffer: SBArray
+// CHECK-NEXT:      }
+// CHECK-NEXT:  Bound Resources:
+// CHECK-NEXT:    D3D12_SHADER_BUFFER_DESC: Name: CB
+// CHECK-NEXT:      Type: D3D_SIT_CBUFFER
+// CHECK-NEXT:      uID: 0
+// CHECK-NEXT:      BindCount: 1
+// CHECK-NEXT:      BindPoint: 0
+// CHECK-NEXT:      Space: 0
+// CHECK-NEXT:      ReturnType: <unknown: 0>
+// CHECK-NEXT:      Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK-NEXT:      NumSamples (or stride): 0
+// CHECK-NEXT:      uFlags: 0
+// CHECK-NEXT:    D3D12_SHADER_BUFFER_DESC: Name: CB1
+// CHECK-NEXT:      Type: D3D_SIT_CBUFFER
+// CHECK-NEXT:      uID: 1
+// CHECK-NEXT:      BindCount: 1
+// CHECK-NEXT:      BindPoint: 1
+// CHECK-NEXT:      Space: 0
+// CHECK-NEXT:      ReturnType: <unknown: 0>
+// CHECK-NEXT:      Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK-NEXT:      NumSamples (or stride): 0
+// CHECK-NEXT:      uFlags: 0
+// CHECK-NEXT:    D3D12_SHADER_BUFFER_DESC: Name: CBArray
+// CHECK-NEXT:      Type: D3D_SIT_CBUFFER
+// CHECK-NEXT:      uID: 2
+// CHECK-NEXT:      BindCount: 6
+// CHECK-NEXT:      BindPoint: 2
+// CHECK-NEXT:      Space: 0
+// CHECK-NEXT:      ReturnType: <unknown: 0>
+// CHECK-NEXT:      Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK-NEXT:      NumSamples (or stride): 0
+// CHECK-NEXT:      uFlags: 0
+// CHECK-NEXT:    D3D12_SHADER_BUFFER_DESC: Name: SB
+// CHECK-NEXT:      Type: D3D_SIT_STRUCTURED
+// CHECK-NEXT:      uID: 0
+// CHECK-NEXT:      BindCount: 1
+// CHECK-NEXT:      BindPoint: 0
+// CHECK-NEXT:      Space: 0
+// CHECK-NEXT:      ReturnType: D3D_RETURN_TYPE_MIXED
+// CHECK-NEXT:      Dimension: D3D_SRV_DIMENSION_BUFFER
+// CHECK-NEXT:      NumSamples (or stride): 64
+// CHECK-NEXT:      uFlags: 0
+// CHECK-NEXT:    D3D12_SHADER_BUFFER_DESC: Name: SBArray
+// CHECK-NEXT:      Type: D3D_SIT_STRUCTURED
+// CHECK-NEXT:      uID: 1
+// CHECK-NEXT:      BindCount: 6
+// CHECK-NEXT:      BindPoint: 1
+// CHECK-NEXT:      Space: 0
+// CHECK-NEXT:      ReturnType: D3D_RETURN_TYPE_MIXED
+// CHECK-NEXT:      Dimension: D3D_SRV_DIMENSION_BUFFER
+// CHECK-NEXT:      NumSamples (or stride): 128
+// CHECK-NEXT:      uFlags: 0
 
 #endif
 
@@ -513,6 +822,14 @@ cbuffer CB1 {
   float1x2 f1x2;  // CB: 176 (new rows for multi-row matrix in col_major)
 }
 
+struct SA {
+  S1 s1[2];
+};
+
+StructuredBuffer<SA> SBArray[2][3];
+ConstantBuffer<SA> CBArray[2][3];
+
 float3 main() : OUT {
-  return SB[CB.s0.i2.x + s3.i].c;
+  return SB[CB.s0.i2.x + s3.i].c
+         + SBArray[1][2][CBArray[1][2].s1[1].s0.i2.x + s3.i].s1[1].c;
 }