Przeglądaj źródła

PIX Shader debugger: Fixes for structs that contain resources or member functions (#5237)

-don't allow ancestor structs and member functions to contribute to member index, from the point of view of PIX
-account for resources-as-members
Jeff Noyle 2 lat temu
rodzic
commit
4e0ef84941

+ 7 - 0
include/dxc/dxcpix.h

@@ -84,6 +84,13 @@ IDxcPixStructType : public IDxcPixType
       _COM_Outptr_ IDxcPixStructField** ppField) = 0;
 };
 
+struct __declspec(uuid("7409f40c-dccb-41aa-bb42-1c95bbf7562f"))
+IDxcPixStructType2 : public IDxcPixStructType
+{
+  virtual STDMETHODIMP GetBaseType(
+      _COM_Outptr_ IDxcPixType **ppType) = 0;
+};
+
 struct __declspec(uuid("74d522f5-16c4-40cb-867b-4b4149e3db0e"))
 IDxcPixDxilStorage : public IUnknown
 {

+ 14 - 7
lib/DxilDia/DxcPixDxilStorage.cpp

@@ -55,7 +55,7 @@ HRESULT CreateDxcPixStorageImpl(
     IDxcPixDxilStorage** ppStorage)
 {
   CComPtr<IDxcPixArrayType> ArrayTy;
-  CComPtr<IDxcPixStructType> StructTy;
+  CComPtr<IDxcPixStructType2> StructTy;
   CComPtr<IDxcPixScalarType> ScalarTy;
 
   CComPtr<IDxcPixType> UnalisedType;
@@ -165,14 +165,21 @@ STDMETHODIMP dxil_debug_info::DxcPixDxilStructStorage::AccessField(
     _In_ LPCWSTR Name,
     _COM_Outptr_ IDxcPixDxilStorage** ppResult)
 {
-  CComPtr<IDxcPixStructField> Field;
-  IFR(m_pType->GetFieldByName(Name, &Field));
-
+  DWORD FieldOffsetInBits = 0;
   CComPtr<IDxcPixType> FieldType;
-  IFR(Field->GetType(&FieldType));
+  if (*Name != 0)
+  {
+      CComPtr<IDxcPixStructField> Field;
+      IFR(m_pType->GetFieldByName(Name, &Field));
+
+      IFR(Field->GetType(&FieldType));
 
-  DWORD FieldOffsetInBits;
-  IFR(Field->GetOffsetInBits(&FieldOffsetInBits));
+      IFR(Field->GetOffsetInBits(&FieldOffsetInBits));
+  }
+  else 
+  {
+      IFR(m_pType->GetBaseType(&FieldType));
+  }
 
   const unsigned NewOffsetInBits =
       m_OffsetFromStorageStartInBits + FieldOffsetInBits;

+ 2 - 2
lib/DxilDia/DxcPixDxilStorage.h

@@ -99,7 +99,7 @@ private:
   DXC_MICROCOM_TM_REF_FIELDS()
   CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
   CComPtr<IDxcPixType> m_pOriginalType;
-  CComPtr<IDxcPixStructType> m_pType;
+  CComPtr<IDxcPixStructType2> m_pType;
   VariableInfo const *m_pVarInfo;
   unsigned m_OffsetFromStorageStartInBits;
 
@@ -107,7 +107,7 @@ private:
       IMalloc *pMalloc,
       DxcPixDxilDebugInfo *pDxilDebugInfo,
       IDxcPixType* OriginalType,
-      IDxcPixStructType *pType,
+      IDxcPixStructType2 *pType,
       VariableInfo const *pVarInfo,
       unsigned OffsetFromStorageStartInBits)
     : m_pMalloc(pMalloc)

+ 30 - 23
lib/DxilDia/DxcPixEntrypoints.cpp

@@ -557,9 +557,9 @@ struct IDxcPixStructFieldEntrypoint : public Entrypoint<IDxcPixStructField>
 };
 DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixStructField);
 
-struct IDxcPixStructTypeEntrypoint : public Entrypoint<IDxcPixStructType>
+struct IDxcPixStructType2Entrypoint : public Entrypoint<IDxcPixStructType2>
 {
-  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixStructTypeEntrypoint);
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixStructType2Entrypoint);
 
   STDMETHODIMP GetName(
       _Outptr_result_z_ BSTR *Name) override
@@ -598,8 +598,14 @@ struct IDxcPixStructTypeEntrypoint : public Entrypoint<IDxcPixStructType>
   {
     return InvokeOnReal(&IInterface::GetFieldByName, CheckNotNull(InParam(lpName)), CheckNotNull(OutParam(ppField)));
   }
+
+  STDMETHODIMP GetBaseType(
+      _Outptr_result_z_ IDxcPixType** ppType) override
+  {
+    return InvokeOnReal(&IInterface::GetBaseType, CheckNotNull(OutParam(ppType)));
+  }
 };
-DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixStructType);
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixStructType2);
 
 struct IDxcPixDxilStorageEntrypoint : public Entrypoint<IDxcPixDxilStorage>
 {
@@ -833,28 +839,29 @@ HRESULT CreateEntrypointWrapper(
     REFIID riid,
     void** ppvObject)
 {
-#define HANDLE_INTERFACE(IInterface)                                         \
-    if (__uuidof(IInterface) == riid)                                        \
-    {                                                                        \
-        return NewDxcPixDxilDebugInfoObjectOrThrow<IInterface##Entrypoint>(  \
-            (IInterface **) ppvObject,                                       \
-            pMalloc,                                                         \
-            (IInterface *) pReal);                                           \
+#define HANDLE_INTERFACE(IInterface, ImplInterface)                             \
+    if (__uuidof(IInterface) == riid)                                           \
+    {                                                                           \
+        return NewDxcPixDxilDebugInfoObjectOrThrow<ImplInterface##Entrypoint>(  \
+            (IInterface **) ppvObject,                                          \
+            pMalloc,                                                            \
+            (ImplInterface *)pReal);                                            \
     } (void)0
 
-  HANDLE_INTERFACE(IUnknown);
-  HANDLE_INTERFACE(IDxcPixType);
-  HANDLE_INTERFACE(IDxcPixConstType);
-  HANDLE_INTERFACE(IDxcPixTypedefType);
-  HANDLE_INTERFACE(IDxcPixScalarType);
-  HANDLE_INTERFACE(IDxcPixArrayType);
-  HANDLE_INTERFACE(IDxcPixStructField);
-  HANDLE_INTERFACE(IDxcPixStructType);
-  HANDLE_INTERFACE(IDxcPixDxilStorage);
-  HANDLE_INTERFACE(IDxcPixVariable);
-  HANDLE_INTERFACE(IDxcPixDxilLiveVariables);
-  HANDLE_INTERFACE(IDxcPixDxilDebugInfo);
-  HANDLE_INTERFACE(IDxcPixCompilationInfo);
+  HANDLE_INTERFACE(IUnknown, IUnknown);
+  HANDLE_INTERFACE(IDxcPixType, IDxcPixType);
+  HANDLE_INTERFACE(IDxcPixConstType, IDxcPixConstType);
+  HANDLE_INTERFACE(IDxcPixTypedefType, IDxcPixTypedefType);
+  HANDLE_INTERFACE(IDxcPixScalarType, IDxcPixScalarType);
+  HANDLE_INTERFACE(IDxcPixArrayType, IDxcPixArrayType);
+  HANDLE_INTERFACE(IDxcPixStructField, IDxcPixStructField);
+  HANDLE_INTERFACE(IDxcPixStructType, IDxcPixStructType2);
+  HANDLE_INTERFACE(IDxcPixStructType2, IDxcPixStructType2);
+  HANDLE_INTERFACE(IDxcPixDxilStorage, IDxcPixDxilStorage);
+  HANDLE_INTERFACE(IDxcPixVariable, IDxcPixVariable);
+  HANDLE_INTERFACE(IDxcPixDxilLiveVariables, IDxcPixDxilLiveVariables);
+  HANDLE_INTERFACE(IDxcPixDxilDebugInfo, IDxcPixDxilDebugInfo);
+  HANDLE_INTERFACE(IDxcPixCompilationInfo, IDxcPixCompilationInfo);
 
   return E_FAIL;
 }

+ 76 - 22
lib/DxilDia/DxcPixTypes.cpp

@@ -247,7 +247,16 @@ STDMETHODIMP dxil_debug_info::DxcPixStructType::UnAlias(
 STDMETHODIMP dxil_debug_info::DxcPixStructType::GetNumFields(
     _Outptr_result_z_ DWORD *ppNumFields)
 {
-  *ppNumFields = m_pStruct->getElements()->getNumOperands();
+  *ppNumFields = 0;
+  // DWARF lists the ancestor class, if any, and member fns
+  // as a member element. Don't count those as data members:
+  for (auto *Node : m_pStruct->getElements())
+  {
+    if (Node->getTag() != llvm::dwarf::DW_TAG_inheritance &&
+        Node->getTag() != llvm::dwarf::DW_TAG_subprogram) {
+      (*ppNumFields)++;
+    }
+  }
   return S_OK;
 }
 
@@ -255,23 +264,34 @@ STDMETHODIMP dxil_debug_info::DxcPixStructType::GetFieldByIndex(
     DWORD dwIndex,
     _Outptr_result_z_ IDxcPixStructField **ppField)
 {
-  if (dwIndex >= m_pStruct->getElements().size())
-  {
-    return E_BOUNDS;
-  }
+  *ppField = nullptr;
+
+  // DWARF lists the ancestor class, if any, and member fns
+  // as a member element. Skip such fields when enumerating
+  // by index.
 
-  auto* pDIField = llvm::dyn_cast<llvm::DIDerivedType>(
-      m_pStruct->getElements()[dwIndex]);
-  if (pDIField == nullptr)
+  DWORD ElementIndex = 0;
+  DWORD ElementSkipCount = 0;
+  for (auto *Node : m_pStruct->getElements())
   {
-    return E_FAIL;
+    if (Node->getTag() == llvm::dwarf::DW_TAG_inheritance ||
+        Node->getTag() == llvm::dwarf::DW_TAG_subprogram) {
+      ElementSkipCount++;
+    } else {
+      if (dwIndex + ElementSkipCount == ElementIndex) {
+        auto *pDIField = llvm::dyn_cast<llvm::DIDerivedType>(
+            m_pStruct->getElements()[ElementIndex]);
+        if (pDIField == nullptr) {
+          return E_FAIL;
+        }
+
+        return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixStructField>(
+            ppField, m_pMalloc, m_pDxilDebugInfo, pDIField);
+      }
+    }
+    ElementIndex++;
   }
-
-  return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixStructField>(
-      ppField,
-      m_pMalloc,
-      m_pDxilDebugInfo,
-      pDIField);
+  return E_BOUNDS;
 }
 
 STDMETHODIMP dxil_debug_info::DxcPixStructType::GetFieldByName(
@@ -286,20 +306,54 @@ STDMETHODIMP dxil_debug_info::DxcPixStructType::GetFieldByName(
     {
       return E_FAIL;
     }
-
-    if (pDIField->getName() == name)
+    if (pDIField->getTag() == llvm::dwarf::DW_TAG_inheritance) 
+    {
+      continue;
+    }
+    else
     {
-      return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixStructField>(
-          ppField,
-          m_pMalloc,
-          m_pDxilDebugInfo,
-          pDIField);
+      if (name == pDIField->getName()) 
+      {
+        return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixStructField>(
+            ppField,
+            m_pMalloc,
+            m_pDxilDebugInfo,
+            pDIField);
+      }
     }
   }
 
   return E_BOUNDS;
 }
 
+STDMETHODIMP dxil_debug_info::DxcPixStructType::GetBaseType(
+    _Outptr_result_z_ IDxcPixType **ppType)
+{
+  for (auto *Node : m_pStruct->getElements())
+  {
+    auto* pDIField = llvm::dyn_cast<llvm::DIDerivedType>(Node);
+    if (pDIField != nullptr)
+    {
+      if (pDIField->getTag() == llvm::dwarf::DW_TAG_inheritance)
+      {
+        const llvm::DITypeIdentifierMap EmptyMap;
+        auto baseType = pDIField->getBaseType().resolve(EmptyMap);
+        if (auto *CompositeType = llvm::dyn_cast<llvm::DICompositeType>(baseType))
+        {
+          return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixStructType>(
+              ppType, m_pMalloc, m_pDxilDebugInfo, CompositeType);
+        } 
+        else 
+        {
+          return E_NOINTERFACE;
+        }
+      }
+    }
+  }
+
+  return E_NOINTERFACE;
+}
+
 STDMETHODIMP dxil_debug_info::DxcPixStructField::GetName(
     _Outptr_result_z_ BSTR *Name) 
 {

+ 5 - 2
lib/DxilDia/DxcPixTypes.h

@@ -200,7 +200,7 @@ public:
       _Outptr_result_z_ IDxcPixType **ppElementType) override;
 };
 
-class DxcPixStructType : public IDxcPixStructType
+class DxcPixStructType : public IDxcPixStructType2
 {
 private:
   DXC_MICROCOM_TM_REF_FIELDS()
@@ -228,7 +228,7 @@ public:
   DXC_MICROCOM_TM_ALLOC(DxcPixStructType)
 
   HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
-    return DoBasicQueryInterface<IDxcPixStructType, IDxcPixType>(this, iid, ppvObject);
+    return DoBasicQueryInterface<IDxcPixStructType2, IDxcPixStructType, IDxcPixType>(this, iid, ppvObject);
   }
 
   STDMETHODIMP GetName(
@@ -250,6 +250,9 @@ public:
   STDMETHODIMP GetFieldByName(
       _In_ LPCWSTR lpName,
       _Outptr_result_z_ IDxcPixStructField **ppField) override;
+
+  STDMETHODIMP GetBaseType(
+    _COM_Outptr_ IDxcPixType **ppType) override;
 };
 
 class DxcPixStructField : public IDxcPixStructField

+ 290 - 7
tools/clang/unittests/HLSL/PixTest.cpp

@@ -233,6 +233,10 @@ public:
   TEST_METHOD(DxcPixDxilDebugInfo_GlobalBackedGlobalStaticEmbeddedArrays_NoDbgValue)
   TEST_METHOD(DxcPixDxilDebugInfo_GlobalBackedGlobalStaticEmbeddedArrays_WithDbgValue)
   TEST_METHOD(DxcPixDxilDebugInfo_GlobalBackedGlobalStaticEmbeddedArrays_ArrayInValues)
+  TEST_METHOD(DxcPixDxilDebugInfo_StructInheritance)
+  TEST_METHOD(DxcPixDxilDebugInfo_StructContainedResource)
+  TEST_METHOD(DxcPixDxilDebugInfo_StructStaticInit)
+  TEST_METHOD(DxcPixDxilDebugInfo_StructMemberFnFirst)
 
   TEST_METHOD(VirtualRegisters_InstructionCounts)
   TEST_METHOD(VirtualRegisters_AlignedOffsets)
@@ -1186,8 +1190,12 @@ static std::string ToString(std::wstring from)
   void TestGlobalStaticCase(
       const char *hlsl, const wchar_t * profile, const char *lineAtWhichToExamineVariables,
       std::vector<VariableComponentInfo> const &ExpectedVariables);
-
-
+  CComPtr<IDxcPixDxilDebugInfo>
+  CompileAndCreateDxcDebug(const char *hlsl, const wchar_t *profile);
+  CComPtr<IDxcPixDxilLiveVariables>
+  GetLiveVariablesAt(const char *hlsl,
+                     const char *lineAtWhichToExamineVariables,
+                     IDxcPixDxilDebugInfo *dxilDebugger);
 private:
   CComPtr<IDxcBlob> WrapInNewContainer(IDxcBlob * part);
 };
@@ -2438,7 +2446,7 @@ static bool AddStorageComponents(
 
   CComPtr<IDxcPixArrayType> ArrayType;
   CComPtr<IDxcPixScalarType> ScalarType;
-  CComPtr<IDxcPixStructType> StructType;
+  CComPtr<IDxcPixStructType2> StructType;
 
   if (!FAILED(UnAliasedType->QueryInterface(&ScalarType))) {
     CComBSTR TypeName;
@@ -2499,6 +2507,17 @@ static bool AddStorageComponents(
         return false;
       }
     }
+
+    CComPtr<IDxcPixType> BaseType;
+    if (SUCCEEDED(StructType->GetBaseType(&BaseType))) {
+      CComPtr<IDxcPixDxilStorage> BaseStorage;
+      if (FAILED(pStorage->AccessField(L"", &BaseStorage))) {
+        return false;
+      }
+      if (!AddStorageComponents(BaseStorage, Name, VariableComponents)) {
+        return false;
+      }
+    }
   }
 
   return true;
@@ -2521,10 +2540,8 @@ static bool ContainedBy(std::vector<PixTest::VariableComponentInfo> const &v1,
   return true;
 }
 
-void PixTest::TestGlobalStaticCase(const char *hlsl,
-  const wchar_t * profile,
-  const char *lineAtWhichToExamineVariables,
-  std::vector<VariableComponentInfo> const &ExpectedVariables) {
+CComPtr<IDxcPixDxilDebugInfo> PixTest::CompileAndCreateDxcDebug(const char* hlsl, const wchar_t* profile) {
+
   CComPtr<IDiaDataSource> pDiaDataSource;
   CompileAndRunAnnotationAndLoadDiaSource(m_dllSupport, hlsl, profile,
                                           &pDiaDataSource, {L"-Od"});
@@ -2537,6 +2554,13 @@ void PixTest::TestGlobalStaticCase(const char *hlsl,
 
   CComPtr<IDxcPixDxilDebugInfo> dxilDebugger;
   VERIFY_SUCCEEDED(Factory->NewDxcPixDxilDebugInfo(&dxilDebugger));
+  return dxilDebugger;
+}
+
+CComPtr<IDxcPixDxilLiveVariables>
+PixTest::GetLiveVariablesAt(const char *hlsl,
+                            const char *lineAtWhichToExamineVariables,
+                            IDxcPixDxilDebugInfo *dxilDebugger) {
 
   auto lines = SplitAndPreserveEmptyLines(std::string(hlsl), '\n');
   auto FindInterestingLine = std::find_if(
@@ -2564,6 +2588,20 @@ void PixTest::TestGlobalStaticCase(const char *hlsl,
   }
   VERIFY_IS_TRUE(liveVariables != nullptr);
 
+  return liveVariables;
+}
+
+void PixTest::TestGlobalStaticCase(
+          const char *hlsl,
+  const wchar_t * profile,
+  const char *lineAtWhichToExamineVariables,
+  std::vector<VariableComponentInfo> const &ExpectedVariables) {
+
+  auto dxilDebugger = CompileAndCreateDxcDebug(hlsl, profile);
+
+  auto liveVariables =
+      GetLiveVariablesAt(hlsl, lineAtWhichToExamineVariables, dxilDebugger);
+
   DWORD count;
   VERIFY_SUCCEEDED(liveVariables->GetCount(&count));
   bool FoundGlobal = false;
@@ -2751,6 +2789,251 @@ void main()
   TestGlobalStaticCase(hlsl, L"lib_6_6", "float Accumulator", Expected);
 }
 
+TEST_F(PixTest,
+    DxcPixDxilDebugInfo_StructInheritance) {
+  if (m_ver.SkipDxilVersion(1, 5))
+    return;
+
+  const char *hlsl = R"(
+RWStructuredBuffer<float> floatRWUAV: register(u0);
+
+struct AStruct
+{
+    float f;
+    int i[2];
+};
+
+struct ADerivedStruct : AStruct
+{
+  bool b[2];
+};
+
+int AFunction(ADerivedStruct theStruct)
+{
+  return theStruct.i[0] + theStruct.i[1] + theStruct.f + (theStruct.b[0] ? 1 : 0) + (theStruct.b[1] ? 2 : 3); // InterestingLine
+}
+
+[numthreads(1, 1, 1)]
+void main()
+{
+  ADerivedStruct aStruct;
+  aStruct.f = floatRWUAV[1];
+  aStruct.i[0] = floatRWUAV[2];
+  aStruct.i[1] = floatRWUAV[3];
+  aStruct.b[0] = floatRWUAV[4] != 0.0;
+  aStruct.b[1] = floatRWUAV[5] != 0.0;
+  floatRWUAV[0] = AFunction(aStruct);
+}
+
+)";
+  auto dxilDebugger = CompileAndCreateDxcDebug(hlsl, L"cs_6_6");
+
+  auto liveVariables =
+      GetLiveVariablesAt(hlsl, "InterestingLine", dxilDebugger);
+
+  DWORD count;
+  VERIFY_SUCCEEDED(liveVariables->GetCount(&count));
+  bool FoundTheStruct = false;
+  for (DWORD i = 0; i < count; ++i) {
+    CComPtr<IDxcPixVariable> variable;
+    VERIFY_SUCCEEDED(liveVariables->GetVariableByIndex(i, &variable));
+    CComBSTR name;
+    variable->GetName(&name);
+    if (0 == wcscmp(name, L"theStruct")) {
+      FoundTheStruct = true;
+      CComPtr<IDxcPixDxilStorage> storage;
+      VERIFY_SUCCEEDED(variable->GetStorage(&storage));
+      std::vector<VariableComponentInfo> ActualVariableComponents;
+      VERIFY_IS_TRUE(AddStorageComponents(storage, L"theStruct",
+                                          ActualVariableComponents));
+      std::vector<VariableComponentInfo> Expected;
+      Expected.push_back({L"theStruct.b[0]", L"bool"});
+      Expected.push_back({L"theStruct.b[1]", L"bool"});
+      Expected.push_back({L"theStruct.f", L"float"});
+      Expected.push_back({L"theStruct.i[0]", L"int"});
+      Expected.push_back({L"theStruct.i[1]", L"int"});
+      VERIFY_IS_TRUE(ContainedBy(ActualVariableComponents, Expected));
+      break;
+    }
+  }
+  VERIFY_IS_TRUE(FoundTheStruct);
+}
+
+TEST_F(PixTest, DxcPixDxilDebugInfo_StructContainedResource) {
+  if (m_ver.SkipDxilVersion(1, 5))
+    return;
+
+  const char *hlsl = R"(
+RWStructuredBuffer<float> floatRWUAV: register(u0);
+Texture2D srv2DTexture : register(t0, space1);
+struct AStruct
+{
+    float f;
+    Texture2D tex;
+};
+
+float4 AFunction(AStruct theStruct)
+{
+  return theStruct.tex.Load(int3(0, 0, 0)) + theStruct.f.xxxx; // InterestingLine
+}
+
+[numthreads(1, 1, 1)]
+void main()
+{
+  AStruct aStruct;
+  aStruct.f = floatRWUAV[1];
+  aStruct.tex = srv2DTexture;
+  floatRWUAV[0] = AFunction(aStruct).x;
+}
+
+)";
+  auto dxilDebugger = CompileAndCreateDxcDebug(hlsl, L"cs_6_6");
+
+  auto liveVariables =
+      GetLiveVariablesAt(hlsl, "InterestingLine", dxilDebugger);
+
+  DWORD count;
+  VERIFY_SUCCEEDED(liveVariables->GetCount(&count));
+  bool FoundTheStruct = false;
+  for (DWORD i = 0; i < count; ++i) {
+    CComPtr<IDxcPixVariable> variable;
+    VERIFY_SUCCEEDED(liveVariables->GetVariableByIndex(i, &variable));
+    CComBSTR name;
+    variable->GetName(&name);
+    if (0 == wcscmp(name, L"theStruct")) {
+      FoundTheStruct = true;
+      CComPtr<IDxcPixDxilStorage> storage;
+      VERIFY_SUCCEEDED(variable->GetStorage(&storage));
+      std::vector<VariableComponentInfo> ActualVariableComponents;
+      VERIFY_IS_TRUE(AddStorageComponents(storage, L"theStruct",
+                                          ActualVariableComponents));
+      std::vector<VariableComponentInfo> Expected;
+      Expected.push_back({L"theStruct.f", L"float"});
+      VERIFY_IS_TRUE(ContainedBy(ActualVariableComponents, Expected));
+      break;
+    }
+  }
+  VERIFY_IS_TRUE(FoundTheStruct);
+}
+
+TEST_F(PixTest, DxcPixDxilDebugInfo_StructStaticInit) {
+  if (m_ver.SkipDxilVersion(1, 5))
+    return;
+
+  const char *hlsl = R"(
+RWStructuredBuffer<float> floatRWUAV: register(u0);
+struct AStruct
+{
+    float f;
+    static AStruct Init(float fi)
+    {
+        AStruct ret;
+        ret.f = fi;
+        for(int i =0; i < 4; ++i)
+        {
+          ret.f += floatRWUAV[i+2];
+        }
+        return ret;
+    }
+};
+
+[numthreads(1, 1, 1)]
+void main()
+{
+  AStruct aStruct = AStruct::Init(floatRWUAV[1]);
+  floatRWUAV[0] = aStruct.f; // InterestingLine
+}
+
+)";
+  auto dxilDebugger = CompileAndCreateDxcDebug(hlsl, L"cs_6_6");
+
+  auto liveVariables =
+      GetLiveVariablesAt(hlsl, "InterestingLine", dxilDebugger);
+
+  DWORD count;
+  VERIFY_SUCCEEDED(liveVariables->GetCount(&count));
+  bool FoundTheStruct = false;
+  for (DWORD i = 0; i < count; ++i) {
+    CComPtr<IDxcPixVariable> variable;
+    VERIFY_SUCCEEDED(liveVariables->GetVariableByIndex(i, &variable));
+    CComBSTR name;
+    variable->GetName(&name);
+    if (0 == wcscmp(name, L"aStruct")) {
+      FoundTheStruct = true;
+      CComPtr<IDxcPixDxilStorage> storage;
+      VERIFY_SUCCEEDED(variable->GetStorage(&storage));
+      std::vector<VariableComponentInfo> ActualVariableComponents;
+      VERIFY_IS_TRUE(AddStorageComponents(storage, L"aStruct",
+                                          ActualVariableComponents));
+      std::vector<VariableComponentInfo> Expected;
+      Expected.push_back({L"aStruct.f", L"float"});
+      VERIFY_IS_TRUE(ContainedBy(ActualVariableComponents, Expected));
+      break;
+    }
+  }
+  VERIFY_IS_TRUE(FoundTheStruct);
+}
+
+TEST_F(PixTest, DxcPixDxilDebugInfo_StructMemberFnFirst) {
+  if (m_ver.SkipDxilVersion(1, 5))
+    return;
+
+  const char *hlsl = R"(
+RWStructuredBuffer<float> floatRWUAV: register(u0);
+struct AStruct
+{
+    void Init(float fi);
+    float f;
+};
+
+void AStruct::Init(float fi)
+{
+    AStruct ret;
+    f = fi;
+    for(int i =0; i < 4; ++i)
+    {
+      f += floatRWUAV[i+2];
+    }
+}
+  
+[numthreads(1, 1, 1)]
+void main()
+{
+  AStruct aStruct;
+  aStruct.Init(floatRWUAV[1]);
+  floatRWUAV[0] = aStruct.f; // InterestingLine
+}
+
+)";
+  auto dxilDebugger = CompileAndCreateDxcDebug(hlsl, L"cs_6_6");
+
+  auto liveVariables =
+      GetLiveVariablesAt(hlsl, "InterestingLine", dxilDebugger);
+
+  DWORD count;
+  VERIFY_SUCCEEDED(liveVariables->GetCount(&count));
+  bool FoundTheStruct = false;
+  for (DWORD i = 0; i < count; ++i) {
+    CComPtr<IDxcPixVariable> variable;
+    VERIFY_SUCCEEDED(liveVariables->GetVariableByIndex(i, &variable));
+    CComBSTR name;
+    variable->GetName(&name);
+    if (0 == wcscmp(name, L"aStruct")) {
+      FoundTheStruct = true;
+      CComPtr<IDxcPixDxilStorage> storage;
+      VERIFY_SUCCEEDED(variable->GetStorage(&storage));
+      std::vector<VariableComponentInfo> ActualVariableComponents;
+      VERIFY_IS_TRUE(AddStorageComponents(storage, L"aStruct",
+                                          ActualVariableComponents));
+      std::vector<VariableComponentInfo> Expected;
+      Expected.push_back({L"aStruct.f", L"float"});
+      VERIFY_IS_TRUE(ContainedBy(ActualVariableComponents, Expected));
+      break;
+    }
+  }
+  VERIFY_IS_TRUE(FoundTheStruct);
+}
+
 CComPtr<IDxcBlob> PixTest::RunShaderAccessTrackingPass(IDxcBlob *blob) {
   CComPtr<IDxcOptimizer> pOptimizer;
   VERIFY_SUCCEEDED(