Selaa lähdekoodia

Adds the DxcPixDxilDebugInfo interface and friends. (#2715)

* Adds the DxcPixDxilDebugInfo interface and friends.

* Modifies the entrypoints to require InParam/OutParam for pointers, as well as CheckNotNull them

* Removes S_FALSE for happier Jeff

* Fixes broken test

* returns E_POINTER for nullptrs

* Returns S_FALSE from UnAlias for non-aliasing types.

* fails GetName for arrays

* Addresses CR comments
John Porto 5 vuotta sitten
vanhempi
commit
63a3b45067

+ 177 - 0
include/dxc/dxcpix.h

@@ -0,0 +1,177 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dxcpix.h                                                                 //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Provides declarations for the DirectX Compiler API with pix debugging.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __DXC_PIX__
+#define __DXC_PIX__
+
+#include "objidl.h"
+#include "dxc/dxcapi.h"
+
+struct __declspec(uuid("199d8c13-d312-4197-a2c1-07a532999727"))
+IDxcPixType : public IUnknown
+{
+  virtual STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) = 0;
+
+  virtual STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *GetSizeInBits) = 0;
+
+  virtual STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType** ppBaseType) = 0;
+};
+
+struct __declspec(uuid("d9df2c8b-2773-466d-9bc2-d848d8496bf6"))
+IDxcPixConstType: public IDxcPixType
+{
+};
+
+struct __declspec(uuid("7bfca9c0-1ed0-429c-9dc2-c75597d821d2"))
+IDxcPixTypedefType: public IDxcPixType
+{
+};
+
+struct __declspec(uuid("246e1652-ed2a-4ffc-a949-43bf63750ee5"))
+IDxcPixScalarType : public IDxcPixType
+{
+};
+
+struct __declspec(uuid("9ba0d9d3-457b-426f-8019-9f3849982aa2"))
+IDxcPixArrayType : public IDxcPixType
+{
+  virtual STDMETHODIMP GetNumElements(
+      _Outptr_result_z_ DWORD* ppNumElements) = 0;
+
+  virtual STDMETHODIMP GetIndexedType(
+      _Outptr_result_z_ IDxcPixType **ppElementType) = 0;
+
+  virtual STDMETHODIMP GetElementType(
+      _Outptr_result_z_ IDxcPixType** ppElementType) = 0;
+};
+
+struct __declspec(uuid("6c707d08-7995-4a84-bae5-e6d8291f3b78"))
+IDxcPixStructField : public IUnknown
+{
+  virtual STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) = 0;
+
+  virtual STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType** ppType) = 0;
+
+  virtual STDMETHODIMP GetOffsetInBits(
+      _Outptr_result_z_ DWORD *pOffsetInBits) = 0;
+};
+
+struct __declspec(uuid("24c08c44-684b-4b1c-b41b-f8772383d074"))
+IDxcPixStructType : public IDxcPixType
+{
+  virtual STDMETHODIMP GetNumFields(
+      _Outptr_result_z_ DWORD* ppNumFields) = 0;
+
+  virtual STDMETHODIMP GetFieldByIndex(
+      DWORD dwIndex,
+      _Outptr_result_z_ IDxcPixStructField **ppField) = 0;
+
+  virtual STDMETHODIMP GetFieldByName(
+      _In_ LPCWSTR lpName,
+      _Outptr_result_z_ IDxcPixStructField** ppField) = 0;
+};
+
+struct __declspec(uuid("74d522f5-16c4-40cb-867b-4b4149e3db0e"))
+IDxcPixDxilStorage : public IUnknown
+{
+  virtual STDMETHODIMP AccessField(
+      _In_ LPCWSTR Name,
+      _COM_Outptr_ IDxcPixDxilStorage** ppResult) = 0;
+
+  virtual STDMETHODIMP Index(
+      _In_ DWORD Index,
+      _COM_Outptr_ IDxcPixDxilStorage** ppResult) = 0;
+
+  virtual STDMETHODIMP GetRegisterNumber(
+      _Outptr_result_z_ DWORD *pRegNum) = 0;
+
+  virtual STDMETHODIMP GetIsAlive() = 0;
+
+  virtual STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType** ppType) = 0;
+};
+
+struct __declspec(uuid("2f954b30-61a7-4348-95b1-2db356a75cde"))
+IDxcPixVariable : public IUnknown
+{
+  virtual STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) = 0;
+
+  virtual STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType **ppType) = 0;
+
+  virtual STDMETHODIMP GetStorage(
+      _COM_Outptr_ IDxcPixDxilStorage **ppStorage) = 0;
+};
+
+struct __declspec(uuid("c59d302f-34a2-4fe5-9646-32ce7a52d03f"))
+IDxcPixDxilLiveVariables : public IUnknown
+{
+  virtual STDMETHODIMP GetCount(
+      _Outptr_ DWORD *dwSize) = 0;
+
+  virtual STDMETHODIMP GetVariableByIndex(
+      _In_ DWORD Index,
+      _Outptr_result_z_ IDxcPixVariable ** ppVariable) = 0;
+
+  virtual STDMETHODIMP GetVariableByName(
+      _In_ LPCWSTR Name,
+      _Outptr_result_z_ IDxcPixVariable** ppVariable) = 0;
+};
+
+struct __declspec(uuid("6dd5d45e-a417-4a26-b0ff-bdb7d6dcc63d"))
+IDxcPixDxilDebugInfo : public IUnknown
+{
+  virtual STDMETHODIMP GetLiveVariablesAt(
+      _In_ DWORD InstructionOffset,
+      _COM_Outptr_ IDxcPixDxilLiveVariables **ppLiveVariables) = 0;
+
+  virtual STDMETHODIMP IsVariableInRegister(
+      _In_ DWORD InstructionOffset,
+      _In_ const wchar_t *VariableName) = 0;
+
+  virtual STDMETHODIMP GetFunctionName(
+      _In_ DWORD InstructionOffset,
+      _Outptr_result_z_ BSTR *ppFunctionName) = 0;
+
+  virtual STDMETHODIMP GetStackDepth(
+      _In_ DWORD InstructionOffset,
+      _Outptr_ DWORD *StackDepth) = 0;
+};
+
+struct __declspec(uuid("9c2a040d-8068-44ec-8c68-8bfef1b43789"))
+IDxcPixDxilDebugInfoFactory : public IUnknown
+{
+  virtual STDMETHODIMP NewDxcPixDxilDebugInfo(
+      _COM_Outptr_ IDxcPixDxilDebugInfo **ppDxilDebugInfo) = 0;
+};
+
+#ifndef CLSID_SCOPE
+#ifdef _MSC_VER
+#define CLSID_SCOPE __declspec(selectany) extern
+#else
+#define CLSID_SCOPE
+#endif
+#endif  // !CLSID_SCOPE
+
+CLSID_SCOPE const CLSID
+  CLSID_DxcPixDxilDebugger = {/* a712b622-5af7-4c77-a965-c83ac1a5d8bc */
+      0xa712b622,
+      0x5af7,
+      0x4c77,
+      {0xa9, 0x65, 0xc8, 0x3a, 0xc1, 0xa5, 0xd8, 0xbc}};
+
+#endif

+ 7 - 0
lib/DxilDia/CMakeLists.txt

@@ -6,6 +6,13 @@ if (WIN32)
 endif (WIN32)
 
 add_llvm_library(LLVMDxilDia
+  DxcPixDxilDebugInfo.cpp
+  DxcPixDxilStorage.cpp
+  DxcPixEntrypoints.cpp
+  DxcPixLiveVariables.cpp
+  DxcPixLiveVariables_FragmentIterator.cpp
+  DxcPixTypes.cpp
+  DxcPixVariables.cpp
   DxilDia.cpp
   DxilDiaDataSource.cpp
   DxilDiaEnumTables.cpp

+ 27 - 0
lib/DxilDia/DxcPixBase.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include "dxc/Support/WinIncludes.h"
+
+namespace dxil_debug_info
+{
+template <typename T>
+T *Initialize(T *Obj)
+{
+  if (Obj != nullptr)
+  {
+    Obj->AddRef();
+  }
+  return Obj;
+}
+
+template <typename T, typename O, typename... A>
+HRESULT NewDxcPixDxilDebugInfoObjectOrThrow(O **pOut, A... args)
+{
+  if ((*pOut = Initialize(T::Alloc(args...))) == nullptr)
+  {
+    throw std::bad_alloc();
+  }
+
+  return S_OK;
+}
+}  // namespace dxil_debug_info

+ 115 - 0
lib/DxilDia/DxcPixDxilDebugInfo.cpp

@@ -0,0 +1,115 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixDxilDebugInfo.cpp                                                   //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Defines the main class for dxcompiler's API for PIX support.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/WinIncludes.h"
+
+#include "dxc/Support/exception.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+
+#include "DxcPixLiveVariables.h"
+#include "DxcPixDxilDebugInfo.h"
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::GetLiveVariablesAt(
+  _In_ DWORD InstructionOffset,
+  _COM_Outptr_ IDxcPixDxilLiveVariables **ppLiveVariables)
+{
+  return m_LiveVars->GetLiveVariablesAtInstruction(
+      FindInstruction(InstructionOffset),
+      ppLiveVariables);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::IsVariableInRegister(
+    _In_ DWORD InstructionOffset,
+    _In_ const wchar_t *VariableName)
+{
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::GetFunctionName(
+    _In_ DWORD InstructionOffset,
+    _Outptr_result_z_ BSTR *ppFunctionName)
+{
+  llvm::Instruction *IP = FindInstruction(InstructionOffset);
+
+  const llvm::DITypeIdentifierMap EmptyMap;
+
+  if (const llvm::DebugLoc &DL = IP->getDebugLoc())
+  {
+    auto *S = llvm::dyn_cast<llvm::DIScope>(DL.getScope());
+    while(S != nullptr && !llvm::isa<llvm::DICompileUnit>(S))
+    {
+      if (auto *SS = llvm::dyn_cast<llvm::DISubprogram>(S))
+      {
+        *ppFunctionName = CComBSTR(CA2W(SS->getName().data())).Detach();
+        return S_OK;
+      }
+
+      S = S->getScope().resolve(EmptyMap);
+    }
+  }
+
+  *ppFunctionName = CComBSTR(L"<???>").Detach();
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::GetStackDepth(
+    _In_ DWORD InstructionOffset,
+    _Outptr_ DWORD *StackDepth
+)
+{
+  llvm::Instruction *IP = FindInstruction(InstructionOffset);
+
+  DWORD Depth = 0;
+  llvm::DebugLoc DL = IP->getDebugLoc();
+  while (DL && DL.getInlinedAtScope() != nullptr)
+  {
+    DL = DL.getInlinedAt();
+    ++Depth;
+  }
+
+  *StackDepth = Depth;
+  return S_OK;
+}
+
+#include "DxilDiaSession.h"
+
+dxil_debug_info::DxcPixDxilDebugInfo::DxcPixDxilDebugInfo(
+    IMalloc *pMalloc,
+    dxil_dia::Session *pSession)
+    : m_pMalloc(pMalloc)
+    , m_pSession(pSession)
+    , m_LiveVars(new LiveVariables())
+{
+  m_LiveVars->Init(this);
+}
+
+dxil_debug_info::DxcPixDxilDebugInfo::~DxcPixDxilDebugInfo() = default;
+
+llvm::Module* dxil_debug_info::DxcPixDxilDebugInfo::GetModuleRef()
+{
+  return &m_pSession->ModuleRef();
+}
+
+llvm::Instruction* dxil_debug_info::DxcPixDxilDebugInfo::FindInstruction(
+    DWORD InstructionOffset
+) const
+{
+  const auto Instructions = m_pSession->InstructionsRef();
+  auto it = Instructions.find(InstructionOffset);
+  if (it == Instructions.end())
+  {
+    throw hlsl::Exception(E_BOUNDS, "Out-of-bounds: Instruction offset");
+  }
+
+  return const_cast<llvm::Instruction *>(it->second);
+}

+ 86 - 0
lib/DxilDia/DxcPixDxilDebugInfo.h

@@ -0,0 +1,86 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixDxilDebugInfo.h                                                     //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Declares the main class for dxcompiler's API for PIX support.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "dxc/Support/WinIncludes.h"
+#include "dxc/dxcapi.h"
+#include "dxc/dxcpix.h"
+
+#include "dxc/Support/Global.h"
+#include "dxc/Support/microcom.h"
+
+#include <memory>
+
+namespace dxil_dia
+{
+class Session;
+}  // namespace dxil_dia
+
+namespace llvm
+{
+class Instruction;
+class Module;
+}  // namespace llvm
+
+namespace dxil_debug_info
+{
+class LiveVariables;
+
+class DxcPixDxilDebugInfo : public IDxcPixDxilDebugInfo
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<dxil_dia::Session> m_pSession;
+  std::unique_ptr<LiveVariables> m_LiveVars;
+
+  DxcPixDxilDebugInfo(
+      IMalloc *pMalloc,
+      dxil_dia::Session *pSession);
+
+  llvm::Instruction* FindInstruction(
+      DWORD InstructionOffset
+  ) const;
+
+public:
+  ~DxcPixDxilDebugInfo();
+
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixDxilDebugInfo)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixDxilDebugInfo>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP GetLiveVariablesAt(
+      _In_ DWORD InstructionOffset,
+      _COM_Outptr_ IDxcPixDxilLiveVariables **ppLiveVariables) override;
+
+  STDMETHODIMP IsVariableInRegister(
+      _In_ DWORD InstructionOffset,
+      _In_ const wchar_t *VariableName) override;
+
+  STDMETHODIMP GetFunctionName(
+      _In_ DWORD InstructionOffset,
+      _Outptr_result_z_ BSTR *ppFunctionName) override;
+
+  STDMETHODIMP GetStackDepth(
+      _In_ DWORD InstructionOffset,
+      _Outptr_ DWORD *StackDepth) override;
+
+  llvm::Module *GetModuleRef();
+
+  IMalloc *GetMallocNoRef()
+  {
+    return m_pMalloc;
+  }
+};
+}  // namespace dxil_debug_info

+ 298 - 0
lib/DxilDia/DxcPixDxilStorage.cpp

@@ -0,0 +1,298 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixDxilStorage.cpp                                                     //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Defines the DxcPixDxilStorage API.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "DxcPixDxilStorage.h"
+
+#include "dxc/Support/WinIncludes.h"
+#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
+#include "llvm/IR/Instructions.h"
+
+#include "DxcPixBase.h"
+#include "DxcPixLiveVariables.h"
+#include "DxcPixTypes.h"
+
+static HRESULT UnAliasType(
+    IDxcPixType *MaybeAlias,
+    IDxcPixType **OriginalType
+)
+{
+  CComPtr<IDxcPixType> Tmp(MaybeAlias);
+  HRESULT hr = E_FAIL;
+
+  *OriginalType = nullptr;
+  do
+  {
+    CComPtr<IDxcPixType> Other;
+    
+    hr = Tmp->UnAlias(&Other);
+    IFR(hr);
+    if (hr == S_FALSE)
+    {
+      break;
+    }
+
+    Tmp = Other;
+  } while (true);
+
+  *OriginalType = Tmp.Detach();
+  return S_OK;
+}
+
+HRESULT CreateDxcPixStorageImpl(
+    dxil_debug_info::DxcPixDxilDebugInfo *pDxilDebugInfo,
+    IDxcPixType* OriginalType,
+    const dxil_debug_info::VariableInfo* VarInfo,
+    unsigned CurrentOffsetInBits,
+    IDxcPixDxilStorage** ppStorage)
+{
+  CComPtr<IDxcPixArrayType> ArrayTy;
+  CComPtr<IDxcPixStructType> StructTy;
+  CComPtr<IDxcPixScalarType> ScalarTy;
+
+  CComPtr<IDxcPixType> UnalisedType;
+  IFR(UnAliasType(OriginalType, &UnalisedType));
+
+  if (UnalisedType->QueryInterface(&ArrayTy) == S_OK)
+  {
+    return dxil_debug_info::NewDxcPixDxilDebugInfoObjectOrThrow<dxil_debug_info::DxcPixDxilArrayStorage>(
+        ppStorage,
+        pDxilDebugInfo->GetMallocNoRef(),
+        pDxilDebugInfo,
+        OriginalType,
+        ArrayTy,
+        VarInfo,
+        CurrentOffsetInBits);
+  }
+  else if (UnalisedType->QueryInterface(&StructTy) == S_OK)
+  {
+    return dxil_debug_info::NewDxcPixDxilDebugInfoObjectOrThrow<dxil_debug_info::DxcPixDxilStructStorage>(
+        ppStorage,
+        pDxilDebugInfo->GetMallocNoRef(),
+        pDxilDebugInfo,
+        OriginalType,
+        StructTy,
+        VarInfo,
+        CurrentOffsetInBits);
+  }
+  else if (UnalisedType->QueryInterface(&ScalarTy) == S_OK)
+  {
+    return dxil_debug_info::NewDxcPixDxilDebugInfoObjectOrThrow<dxil_debug_info::DxcPixDxilScalarStorage>(
+        ppStorage,
+        pDxilDebugInfo->GetMallocNoRef(),
+        pDxilDebugInfo,
+        OriginalType,
+        ScalarTy,
+        VarInfo,
+        CurrentOffsetInBits);
+  }
+
+  return E_UNEXPECTED;
+}
+
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilArrayStorage::AccessField(
+    _In_ LPCWSTR Name,
+    _COM_Outptr_ IDxcPixDxilStorage** ppResult)
+{
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilArrayStorage::Index(
+    _In_ DWORD Index,
+    _COM_Outptr_ IDxcPixDxilStorage** ppResult)
+{
+  CComPtr<IDxcPixType> IndexedType;
+  IFR(m_pType->GetIndexedType(&IndexedType));
+
+  DWORD NumElements;
+  IFR(m_pType->GetNumElements(&NumElements));
+
+  if (Index >= NumElements)
+  {
+    return E_BOUNDS;
+  }
+
+  DWORD IndexedTypeSizeInBits;
+  IFR(m_pType->GetSizeInBits(&IndexedTypeSizeInBits));
+
+  const unsigned NewOffsetInBits =
+      m_OffsetFromStorageStartInBits + Index * IndexedTypeSizeInBits;
+
+  return CreateDxcPixStorageImpl(
+      m_pDxilDebugInfo,
+      IndexedType,
+      m_pVarInfo,
+      NewOffsetInBits,
+      ppResult);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilArrayStorage::GetRegisterNumber(
+    _Outptr_result_z_ DWORD* pRegisterNumber)
+{
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilArrayStorage::GetIsAlive()
+{
+  for (auto OffsetAndRegister : m_pVarInfo->m_ValueLocationMap)
+  {
+    if (OffsetAndRegister.second.m_V != nullptr)
+    {
+      return S_OK;
+    }
+  }
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilArrayStorage::GetType(
+    _Outptr_result_z_ IDxcPixType** ppType)
+{
+  *ppType = m_pOriginalType;
+  (*ppType)->AddRef();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilStructStorage::AccessField(
+    _In_ LPCWSTR Name,
+    _COM_Outptr_ IDxcPixDxilStorage** ppResult)
+{
+  CComPtr<IDxcPixStructField> Field;
+  IFR(m_pType->GetFieldByName(Name, &Field));
+
+  CComPtr<IDxcPixType> FieldType;
+  IFR(Field->GetType(&FieldType));
+
+  DWORD FieldOffsetInBits;
+  IFR(Field->GetOffsetInBits(&FieldOffsetInBits));
+
+  const unsigned NewOffsetInBits =
+      m_OffsetFromStorageStartInBits + FieldOffsetInBits;
+
+  return CreateDxcPixStorageImpl(
+      m_pDxilDebugInfo,
+      FieldType,
+      m_pVarInfo,
+      NewOffsetInBits,
+      ppResult);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilStructStorage::Index(
+    _In_ DWORD Index,
+    _COM_Outptr_ IDxcPixDxilStorage** ppResult)
+{
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilStructStorage::GetRegisterNumber(
+    _Outptr_result_z_ DWORD* pRegisterNumber)
+{
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilStructStorage::GetIsAlive()
+{
+  for (auto OffsetAndRegister : m_pVarInfo->m_ValueLocationMap)
+  {
+    if (OffsetAndRegister.second.m_V != nullptr)
+    {
+      return S_OK;
+    }
+  }
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilStructStorage::GetType(
+    _Outptr_result_z_ IDxcPixType** ppType)
+{
+  *ppType = m_pOriginalType;
+  (*ppType)->AddRef();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilScalarStorage::AccessField(
+    _In_ LPCWSTR Name,
+    _COM_Outptr_ IDxcPixDxilStorage** ppResult)
+{
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilScalarStorage::Index(
+    _In_ DWORD Index,
+    _COM_Outptr_ IDxcPixDxilStorage** ppResult)
+{
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilScalarStorage::GetRegisterNumber(
+    _Outptr_result_z_ DWORD* pRegisterNumber)
+{
+  const auto &ValueLocationMap = m_pVarInfo->m_ValueLocationMap;
+  auto RegIt = ValueLocationMap.find(
+      m_OffsetFromStorageStartInBits);
+
+  if (RegIt == ValueLocationMap.end())
+  {
+    return E_FAIL;
+  }
+
+  if (auto *AllocaReg = llvm::dyn_cast<llvm::AllocaInst>(RegIt->second.m_V))
+  {
+    uint32_t RegNum;
+    uint32_t RegSize;
+    if (!pix_dxil::PixAllocaReg::FromInst(AllocaReg, &RegNum, &RegSize))
+    {
+      return E_FAIL;
+    }
+
+    *pRegisterNumber = RegNum + RegIt->second.m_FragmentIndex;
+  }
+  else
+  {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilScalarStorage::GetIsAlive()
+{
+  const auto &ValueLocationMap = m_pVarInfo->m_ValueLocationMap;
+  auto RegIt = ValueLocationMap.find(
+      m_OffsetFromStorageStartInBits);
+
+  return RegIt == ValueLocationMap.end() ? E_FAIL : S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilScalarStorage::GetType(
+    _Outptr_result_z_ IDxcPixType **ppType)
+{
+  *ppType = m_pOriginalType;
+  (*ppType)->AddRef();
+  return S_OK;
+}
+
+HRESULT dxil_debug_info::CreateDxcPixStorage(
+    DxcPixDxilDebugInfo *pDxilDebugInfo,
+    llvm::DIType *diType,
+    const VariableInfo *VarInfo,
+    unsigned CurrentOffsetInBits,
+    IDxcPixDxilStorage **ppStorage)
+{
+  CComPtr<IDxcPixType> OriginalType;
+  IFR(dxil_debug_info::CreateDxcPixType(pDxilDebugInfo, diType, &OriginalType));
+
+  return CreateDxcPixStorageImpl(
+      pDxilDebugInfo,
+      OriginalType,
+      VarInfo,
+      CurrentOffsetInBits,
+      ppStorage);
+}

+ 198 - 0
lib/DxilDia/DxcPixDxilStorage.h

@@ -0,0 +1,198 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixDxilStorage.h                                                       //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Declares the DxcPixDxilStorage API. This is the API that allows PIX to    //
+// find which register holds the value for a particular member of a          //
+// variable.                                                                 //
+//                                                                           //
+// For DxcPixDxilStorage, a member is a DIBasicType (i.e., float, int, etc.) //
+// This library provides Storage classes for inspecting structs, arrays, and //
+// basic types. This is what's minimally necessary for enable HLSL debugging //
+// in PIX.                                                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "dxc/Support/WinIncludes.h"
+#include "dxc/dxcapi.h"
+#include "dxc/dxcpix.h"
+
+#include "dxc/Support/microcom.h"
+
+#include "DxcPixDxilDebugInfo.h"
+
+namespace llvm
+{
+class DIType;
+}  // namespace llvm
+
+namespace dxil_debug_info
+{
+struct VariableInfo;
+
+HRESULT CreateDxcPixStorage(
+    DxcPixDxilDebugInfo *pDxilDebugInfo,
+    llvm::DIType *diType,
+    const VariableInfo *VarInfo,
+    unsigned CurrentOffsetInBits,
+    IDxcPixDxilStorage **ppStorage);
+
+class DxcPixDxilArrayStorage : public IDxcPixDxilStorage
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  CComPtr<IDxcPixType> m_pOriginalType;
+  CComPtr<IDxcPixArrayType> m_pType;
+  VariableInfo const *m_pVarInfo;
+  unsigned m_OffsetFromStorageStartInBits;
+
+  DxcPixDxilArrayStorage(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      IDxcPixType* OriginalType,
+      IDxcPixArrayType *pType,
+      const VariableInfo* pVarInfo,
+      unsigned OffsetFromStorageStartInBits)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_pOriginalType(OriginalType)
+    , m_pType(pType)
+    , m_pVarInfo(pVarInfo)
+    , m_OffsetFromStorageStartInBits(OffsetFromStorageStartInBits)
+  {
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixDxilArrayStorage)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixDxilStorage>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP AccessField(
+      _In_ LPCWSTR Name,
+      _COM_Outptr_ IDxcPixDxilStorage **ppResult) override;
+
+  STDMETHODIMP Index(
+      _In_ DWORD Index,
+      _COM_Outptr_ IDxcPixDxilStorage **ppResult) override;
+
+  STDMETHODIMP GetRegisterNumber(
+      _Outptr_result_z_ DWORD *pRegisterNumber) override;
+
+  STDMETHODIMP GetIsAlive() override;
+
+  STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType **ppType) override;
+};
+
+class DxcPixDxilStructStorage : public IDxcPixDxilStorage
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  CComPtr<IDxcPixType> m_pOriginalType;
+  CComPtr<IDxcPixStructType> m_pType;
+  VariableInfo const *m_pVarInfo;
+  unsigned m_OffsetFromStorageStartInBits;
+
+  DxcPixDxilStructStorage(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      IDxcPixType* OriginalType,
+      IDxcPixStructType *pType,
+      VariableInfo const *pVarInfo,
+      unsigned OffsetFromStorageStartInBits)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_pOriginalType(OriginalType)
+    , m_pType(pType)
+    , m_pVarInfo(pVarInfo)
+    , m_OffsetFromStorageStartInBits(OffsetFromStorageStartInBits)
+  {
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixDxilStructStorage)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixDxilStorage>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP AccessField(
+      _In_ LPCWSTR Name,
+      _COM_Outptr_ IDxcPixDxilStorage **ppResult) override;
+
+  STDMETHODIMP Index(
+      _In_ DWORD Index,
+      _COM_Outptr_ IDxcPixDxilStorage **ppResult) override;
+
+  STDMETHODIMP GetRegisterNumber(
+      _Outptr_result_z_ DWORD *pRegisterNumber) override;
+
+  STDMETHODIMP GetIsAlive() override;
+
+  STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType **ppType) override;
+};
+
+class DxcPixDxilScalarStorage : public IDxcPixDxilStorage
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  CComPtr<IDxcPixType> m_pOriginalType;
+  CComPtr<IDxcPixScalarType> m_pType;
+  VariableInfo const *m_pVarInfo;
+  unsigned m_OffsetFromStorageStartInBits;
+
+  DxcPixDxilScalarStorage(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      IDxcPixType *OriginalType,
+      IDxcPixScalarType *pType,
+      VariableInfo const *pVarInfo,
+      unsigned OffsetFromStorageStartInBits)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_pOriginalType(OriginalType)
+    , m_pType(pType)
+    , m_pVarInfo(pVarInfo)
+    , m_OffsetFromStorageStartInBits(OffsetFromStorageStartInBits)
+  {
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixDxilScalarStorage)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixDxilStorage>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP AccessField(
+      _In_ LPCWSTR Name,
+      _COM_Outptr_ IDxcPixDxilStorage **ppResult) override;
+
+  STDMETHODIMP Index(
+      _In_ DWORD Index,
+      _COM_Outptr_ IDxcPixDxilStorage **ppResult) override;
+
+  STDMETHODIMP GetRegisterNumber(
+      _Outptr_result_z_ DWORD *pRegisterNumber) override;
+
+  STDMETHODIMP GetIsAlive() override;
+
+  STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType **ppType) override;
+};
+
+}  // namespace dxil_debug_info

+ 781 - 0
lib/DxilDia/DxcPixEntrypoints.cpp

@@ -0,0 +1,781 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixEntrypoints.cpp                                                     //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Defines all of the entrypoints for DXC's PIX interfaces for dealing with  //
+// debug info. These entrypoints are responsible for setting up a common,    //
+// sane environment -- e.g., exceptions are caught and returned as an        //
+// HRESULT -- deferring to the real implementations defined elsewhere in     //
+// this library.                                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/WinIncludes.h"
+
+#include "dxc/dxcapi.h"
+#include "dxc/dxcpix.h"
+
+#include "dxc/Support/Global.h"
+#include "dxc/Support/microcom.h"
+#include "dxc/Support/FileIOHelper.h"
+#include "llvm/Support/MSFileSystem.h"
+#include "llvm/Support/FileSystem.h"
+
+#include "DxcPixBase.h"
+#include "DxcPixDxilDebugInfo.h"
+
+#include <functional>
+
+namespace dxil_debug_info
+{
+namespace entrypoints
+{
+// OutParam/OutParamImpl provides a mechanism that entrypoints
+// use to tag method arguments as OutParams. OutParams are
+// automatically zero-initialized.
+template <typename T>
+class OutParamImpl
+{
+public:
+  OutParamImpl(T *V) : m_V(V)
+  {
+    if (m_V != nullptr)
+    {
+      *m_V = T();
+    }
+  }
+
+  operator T *() const
+  {
+    return m_V;
+  }
+
+private:
+  T *m_V;
+};
+
+template <typename T>
+OutParamImpl<T> OutParam(T *V)
+{
+  return OutParamImpl<T>(V);
+}
+
+// InParam/InParamImpl provides a mechanism that entrypoints
+// use to tag method arguments as InParams. InParams are
+// not zero-initialized.
+template <typename T>
+struct InParamImpl
+{
+public:
+  InParamImpl(const T *V) : m_V(V)
+  {
+  }
+
+  operator const T *() const
+  {
+    return m_V;
+  }
+
+private:
+  const T *m_V;
+};
+
+template <typename T>
+InParamImpl<T> InParam(T *V)
+{
+  return InParamImpl<T>(V);
+}
+
+
+// ThisPtr/ThisPtrImpl provides a mechanism that entrypoints
+// use to tag method arguments as c++'s this. This values
+// are not checked/initialized.
+template <typename T>
+struct ThisPtrImpl
+{
+public:
+  ThisPtrImpl(T *V) : m_V(V)
+  {
+  }
+
+  operator T *() const
+  {
+    return m_V;
+  }
+
+private:
+  T *m_V;
+};
+
+template <typename T>
+ThisPtrImpl<T> ThisPtr(T *V)
+{
+  return ThisPtrImpl<T>(V);
+}
+
+
+// CheckNotNull/CheckNotNullImpl provide a mechanism that entrypoints
+// can use for automatic parameter validation. They will throw an
+// exception if the given parameter is null.
+template <typename T>
+class CheckNotNullImpl;
+
+template <typename T>
+class CheckNotNullImpl<OutParamImpl<T>>
+{
+public:
+  explicit CheckNotNullImpl(OutParamImpl<T> V) : m_V(V)
+  {
+  }
+
+  operator T *() const
+  {
+    if (m_V == nullptr)
+    {
+      throw hlsl::Exception(E_POINTER);
+    }
+    return m_V;
+  }
+
+private:
+  T *m_V;
+};
+
+template <typename T>
+class CheckNotNullImpl<InParamImpl<T>>
+{
+public:
+  explicit CheckNotNullImpl(InParamImpl<T> V) : m_V(V)
+  {
+  }
+
+  operator T *() const
+  {
+    if (m_V == nullptr)
+    {
+      throw hlsl::Exception(E_POINTER);
+    }
+    return m_V;
+  }
+
+private:
+  T *m_V;
+};
+
+template <typename T>
+CheckNotNullImpl<T> CheckNotNull(T V)
+{
+  return CheckNotNullImpl<T>(V);
+}
+
+// WrapOutParams will wrap any OutParams<T> that the
+// entrypoints provide to SetupAndRun -- which is essentially
+// the method that runs the actual methods.
+void WrapOutParams(IMalloc *)
+{
+}
+
+template <typename T> struct EntrypointWrapper;
+
+// WrapOutParams' specialization that detects OutParams that
+// inherit from IUnknown. Any OutParams inheriting from IUnknown
+// should be wrapped by one of the classes in this file so that
+// user calls will be safely run.
+template <
+    typename T,
+    typename =
+        typename std::enable_if<std::is_base_of<IUnknown, T>::value>::type,
+    typename... O>
+void WrapOutParams(
+    IMalloc* M,
+    CheckNotNullImpl<OutParamImpl<T *>> ppOut,
+    O... Others
+)
+{
+  if (*ppOut)
+  {
+    NewDxcPixDxilDebugInfoObjectOrThrow<typename EntrypointWrapper<T*>::type>(
+        (T**)ppOut,
+        M,
+        *ppOut);
+  }
+
+  WrapOutParams(M, Others...);
+}
+
+template <typename T, typename... O>
+void WrapOutParams(IMalloc *M, T, O... Others)
+{
+  WrapOutParams(M, Others...);
+}
+
+
+// DEFINE_ENTRYPOINT_WRAPPER_TRAIT is a helper macro that every entrypoint
+// should use in order to define the EntrypointWrapper traits class for
+// the interface it implements.
+#define DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IInterface)                         \
+template <> struct EntrypointWrapper<IInterface *>                          \
+{                                                                           \
+ using type = IInterface ## Entrypoint;                                     \
+};
+
+// IsValidArgType exposes a static method named check(), which returns
+// true if <T> is a valid type for a method argument, and false otherwise.
+// This is trying to ensure all pointers are checked, and all out params
+// are default-initialized.
+template <typename T>
+struct IsValidArgType
+{
+    static void check() {}
+};
+
+template <typename T>
+struct IsValidArgType<T *>
+{
+    static void check()
+    {
+        static_assert(
+            false,
+            "Pointer arguments should be checked and wrapped"
+            " with InParam/OutParam, or marked with ThisPtr()");
+    }
+};
+
+
+template <typename T>
+struct IsValidArgType<InParamImpl<T>>
+{
+    static void check()
+    {
+        static_assert(
+            false,
+            "InParams should be checked for nullptrs");
+    }
+};
+
+template <typename T>
+struct IsValidArgType<OutParamImpl<T>>
+{
+    static void check()
+    {
+        static_assert(
+            false,
+            "InParams should be checked for nullptrs");
+    }
+};
+
+void EnsureAllPointersAreChecked()
+{
+}
+
+template <typename T, typename... O>
+void EnsureAllPointersAreChecked(T, O... o)
+{
+  IsValidArgType<T>::check();
+  EnsureAllPointersAreChecked(o...);
+}
+
+// SetupAndRun is the function that sets up the environment
+// in which all of the user requests to the DxcPix library
+// run under.
+template<typename H, typename... A>
+HRESULT SetupAndRun(
+    IMalloc* M,
+    H Handler,
+    A... Args
+)
+{
+  DxcThreadMalloc TM(M);
+
+  HRESULT hr = E_FAIL;
+  try
+  {
+    ::llvm::sys::fs::MSFileSystem* msfPtr;
+    IFT(CreateMSFileSystemForDisk(&msfPtr));
+    std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
+
+    ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
+    IFTLLVM(pts.error_code());
+
+    EnsureAllPointersAreChecked(Args...);
+    hr = Handler(Args...);
+    WrapOutParams(M, Args...);
+  }
+  catch (const hlsl::Exception &e)
+  {
+      hr = e.hr;
+  }
+  catch (const std::bad_alloc &)
+  {
+      hr = E_OUTOFMEMORY;
+  }
+  catch (const std::exception &)
+  {
+      hr = E_FAIL;
+  }
+
+  return hr;
+}
+
+HRESULT CreateEntrypointWrapper(
+    IMalloc *pMalloc,
+    IUnknown *pReal,
+    REFIID iid,
+    void **ppvObject);
+
+// Entrypoint is the base class for all entrypoints, providing
+// the default QueryInterface implementation, as well as a
+// more convenient way of calling SetupAndRun.
+template <typename I>
+class Entrypoint : public I
+{
+protected:
+  using IInterface = I;
+
+  Entrypoint(
+      IMalloc *pMalloc,
+      IInterface *pI
+  ) : m_pMalloc(pMalloc)
+    , m_pReal(pI)
+  {
+  }
+
+  DXC_MICROCOM_TM_REF_FIELDS();
+  CComPtr<IInterface> m_pReal;
+
+  template <typename F, typename... A>
+  HRESULT InvokeOnReal(F pFn, A... Args)
+  {
+    return ::SetupAndRun(m_pMalloc, std::mem_fn(pFn), m_pReal, Args...);
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL();
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject) override final
+  {
+    return ::SetupAndRun(
+        m_pMalloc,
+        std::mem_fn(&Entrypoint<IInterface>::QueryInterfaceImpl),
+        ThisPtr(this),
+        iid,
+        CheckNotNull(OutParam(ppvObject)));
+  }
+
+  HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID iid, void** ppvObject)
+  {
+    // Special-casing so we don't need to create a new wrapper.
+    if (iid == __uuidof(IInterface) ||
+        iid == __uuidof(IUnknown)   ||
+        iid == __uuidof(INoMarshal))
+    {
+      this->AddRef();
+      *ppvObject = this;
+      return S_OK;
+    }
+
+    CComPtr<IUnknown> RealQI;
+    IFR(m_pReal->QueryInterface(iid, (void**)&RealQI));
+    return CreateEntrypointWrapper(m_pMalloc, RealQI, iid, ppvObject);
+  }
+};
+
+#define DEFINE_ENTRYPOINT_BOILERPLATE(Name)                                  \
+    Name(IMalloc *M, IInterface *pI) : Entrypoint<IInterface>(M, pI){}       \
+    DXC_MICROCOM_TM_ALLOC(Name)
+
+struct IUnknownEntrypoint : public Entrypoint<IUnknown>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IUnknownEntrypoint);
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IUnknown);
+
+struct IDxcPixTypeEntrypoint : public Entrypoint<IDxcPixType>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixTypeEntrypoint);
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override
+  {
+    return InvokeOnReal(&IInterface::GetName, CheckNotNull(OutParam(Name)));
+  }
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *SizeInBits) override
+  {
+    return InvokeOnReal(&IInterface::GetSizeInBits, CheckNotNull(OutParam(SizeInBits)));
+  }
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType** ppBaseType) override
+  {
+    return InvokeOnReal(&IInterface::UnAlias, CheckNotNull(OutParam(ppBaseType)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixType);
+
+struct IDxcPixConstTypeEntrypoint : public Entrypoint<IDxcPixConstType>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixConstTypeEntrypoint);
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override
+  {
+    return InvokeOnReal(&IInterface::GetName, CheckNotNull(OutParam(Name)));
+  }
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *SizeInBits) override
+  {
+    return InvokeOnReal(&IInterface::GetSizeInBits, CheckNotNull(OutParam(SizeInBits)));
+  }
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType** ppBaseType) override
+  {
+    return InvokeOnReal(&IInterface::UnAlias, CheckNotNull(OutParam(ppBaseType)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixConstType);
+
+struct IDxcPixTypedefTypeEntrypoint : public Entrypoint<IDxcPixTypedefType>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixTypedefTypeEntrypoint);
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override
+  {
+    return InvokeOnReal(&IInterface::GetName, CheckNotNull(OutParam(Name)));
+  }
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *SizeInBits) override
+  {
+    return InvokeOnReal(&IInterface::GetSizeInBits, CheckNotNull(OutParam(SizeInBits)));
+  }
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType** ppBaseType) override
+  {
+    return InvokeOnReal(&IInterface::UnAlias, CheckNotNull(OutParam(ppBaseType)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixTypedefType);
+
+struct IDxcPixScalarTypeEntrypoint : public Entrypoint<IDxcPixScalarType>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixScalarTypeEntrypoint);
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override
+  {
+    return InvokeOnReal(&IInterface::GetName, CheckNotNull(OutParam(Name)));
+  }
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *SizeInBits) override
+  {
+    return InvokeOnReal(&IInterface::GetSizeInBits, CheckNotNull(OutParam(SizeInBits)));
+  }
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType** ppBaseType) override
+  {
+    return InvokeOnReal(&IInterface::UnAlias, CheckNotNull(OutParam(ppBaseType)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixScalarType);
+
+struct IDxcPixArrayTypeEntrypoint : public Entrypoint<IDxcPixArrayType>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixArrayTypeEntrypoint);
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override
+  {
+    return InvokeOnReal(&IInterface::GetName, CheckNotNull(OutParam(Name)));
+  }
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *SizeInBits) override
+  {
+    return InvokeOnReal(&IInterface::GetSizeInBits, CheckNotNull(OutParam(SizeInBits)));
+  }
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType** ppBaseType) override
+  {
+    return InvokeOnReal(&IInterface::UnAlias, CheckNotNull(OutParam(ppBaseType)));
+  }
+
+  STDMETHODIMP GetNumElements(
+      _Outptr_result_z_ DWORD *ppNumElements) override
+  {
+    return InvokeOnReal(&IInterface::GetNumElements, CheckNotNull(OutParam(ppNumElements)));
+  }
+
+  STDMETHODIMP GetIndexedType(
+      _Outptr_result_z_ IDxcPixType **ppElementType) override
+  {
+    return InvokeOnReal(&IInterface::GetIndexedType, CheckNotNull(OutParam(ppElementType)));
+  }
+
+  STDMETHODIMP GetElementType(
+      _Outptr_result_z_ IDxcPixType** ppElementType) override
+  {
+    return InvokeOnReal(&IInterface::GetElementType, CheckNotNull(OutParam(ppElementType)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixArrayType);
+
+struct IDxcPixStructFieldEntrypoint : public Entrypoint<IDxcPixStructField>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixStructFieldEntrypoint);
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override
+  {
+    return InvokeOnReal(&IInterface::GetName, CheckNotNull(OutParam(Name)));
+  }
+
+  STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType** ppType) override
+  {
+    return InvokeOnReal(&IInterface::GetType, CheckNotNull(OutParam(ppType)));
+  }
+
+  STDMETHODIMP GetOffsetInBits(
+      _Outptr_result_z_ DWORD *pOffsetInBits) override
+  {
+    return InvokeOnReal(&IInterface::GetOffsetInBits, CheckNotNull(OutParam(pOffsetInBits)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixStructField);
+
+struct IDxcPixStructTypeEntrypoint : public Entrypoint<IDxcPixStructType>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixStructTypeEntrypoint);
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override
+  {
+    return InvokeOnReal(&IInterface::GetName, CheckNotNull(OutParam(Name)));
+  }
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *SizeInBits) override
+  {
+    return InvokeOnReal(&IInterface::GetSizeInBits, CheckNotNull(OutParam(SizeInBits)));
+  }
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType** ppBaseType) override
+  {
+    return InvokeOnReal(&IInterface::UnAlias, CheckNotNull(OutParam(ppBaseType)));
+  }
+
+  STDMETHODIMP GetNumFields(
+      _Outptr_result_z_ DWORD* ppNumFields) override
+  {
+      return InvokeOnReal(&IInterface::GetNumFields, CheckNotNull(OutParam(ppNumFields)));
+  }
+
+  STDMETHODIMP GetFieldByIndex(
+      DWORD dwIndex,
+      _Outptr_result_z_ IDxcPixStructField **ppField) override
+  {
+    return InvokeOnReal(&IInterface::GetFieldByIndex, dwIndex, CheckNotNull(OutParam(ppField)));
+  }
+
+  STDMETHODIMP GetFieldByName(
+      _In_ LPCWSTR lpName,
+      _Outptr_result_z_ IDxcPixStructField** ppField) override
+  {
+    return InvokeOnReal(&IInterface::GetFieldByName, CheckNotNull(InParam(lpName)), CheckNotNull(OutParam(ppField)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixStructType);
+
+struct IDxcPixDxilStorageEntrypoint : public Entrypoint<IDxcPixDxilStorage>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixDxilStorageEntrypoint);
+
+  STDMETHODIMP AccessField(
+      _In_ LPCWSTR Name,
+      _COM_Outptr_ IDxcPixDxilStorage** ppResult) override
+  {
+    return InvokeOnReal(&IInterface::AccessField, CheckNotNull(InParam(Name)), CheckNotNull(OutParam(ppResult)));
+  }
+
+  STDMETHODIMP Index(
+      _In_ DWORD Index,
+      _COM_Outptr_ IDxcPixDxilStorage** ppResult) override
+  {
+    return InvokeOnReal(&IInterface::Index, Index, CheckNotNull(OutParam(ppResult)));
+  }
+
+  STDMETHODIMP GetRegisterNumber(
+      _Outptr_result_z_ DWORD *pRegNum) override
+  {
+    return InvokeOnReal(&IInterface::GetRegisterNumber, CheckNotNull(OutParam(pRegNum)));
+  }
+
+  STDMETHODIMP GetIsAlive() override
+  {
+    return InvokeOnReal(&IInterface::GetIsAlive);
+  }
+
+  STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType** ppType) override
+  {
+    return InvokeOnReal(&IInterface::GetType, CheckNotNull(OutParam(ppType)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixDxilStorage);
+
+struct IDxcPixVariableEntrypoint : public Entrypoint<IDxcPixVariable>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixVariableEntrypoint);
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override
+  {
+    return InvokeOnReal(&IInterface::GetName, CheckNotNull(OutParam(Name)));
+  }
+
+  STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType **ppType) override
+  {
+    return InvokeOnReal(&IInterface::GetType, CheckNotNull(OutParam(ppType)));
+  }
+
+  STDMETHODIMP GetStorage(
+      _COM_Outptr_ IDxcPixDxilStorage **ppStorage) override
+  {
+      return InvokeOnReal(&IInterface::GetStorage, CheckNotNull(OutParam(ppStorage)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixVariable);
+
+struct IDxcPixDxilLiveVariablesEntrypoint : public Entrypoint<IDxcPixDxilLiveVariables>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixDxilLiveVariablesEntrypoint);
+
+  STDMETHODIMP GetCount(
+      _Outptr_ DWORD *dwSize) override
+  {
+    return InvokeOnReal(&IInterface::GetCount, CheckNotNull(OutParam(dwSize)));
+  }
+
+  STDMETHODIMP GetVariableByIndex(
+      _In_ DWORD Index,
+      _Outptr_result_z_ IDxcPixVariable ** ppVariable) override
+  {
+    return InvokeOnReal(&IInterface::GetVariableByIndex, Index, CheckNotNull(OutParam(ppVariable)));
+  }
+
+  STDMETHODIMP GetVariableByName(
+      _In_ LPCWSTR Name,
+      _Outptr_result_z_ IDxcPixVariable** ppVariable) override
+  {
+    return InvokeOnReal(&IInterface::GetVariableByName, CheckNotNull(InParam(Name)), CheckNotNull(OutParam(ppVariable)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixDxilLiveVariables);
+
+struct IDxcPixDxilDebugInfoEntrypoint : public Entrypoint<IDxcPixDxilDebugInfo>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixDxilDebugInfoEntrypoint);
+
+  STDMETHODIMP GetLiveVariablesAt(
+      _In_ DWORD InstructionOffset,
+      _COM_Outptr_ IDxcPixDxilLiveVariables **ppLiveVariables) override
+  {
+    return InvokeOnReal(&IInterface::GetLiveVariablesAt, InstructionOffset, CheckNotNull(OutParam(ppLiveVariables)));
+  }
+
+  STDMETHODIMP IsVariableInRegister(
+      _In_ DWORD InstructionOffset,
+      _In_ const wchar_t *VariableName) override
+  {
+    return InvokeOnReal(&IInterface::IsVariableInRegister, InstructionOffset, CheckNotNull(InParam(VariableName)));
+  }
+
+  STDMETHODIMP GetFunctionName(
+      _In_ DWORD InstructionOffset,
+      _Outptr_result_z_ BSTR *ppFunctionName) override
+  {
+    return InvokeOnReal(&IInterface::GetFunctionName, InstructionOffset, CheckNotNull(OutParam(ppFunctionName)));
+  }
+
+  STDMETHODIMP GetStackDepth(
+      _In_ DWORD InstructionOffset,
+      _Outptr_ DWORD *StackDepth) override
+  {
+    return InvokeOnReal(&IInterface::GetStackDepth, InstructionOffset, CheckNotNull(OutParam(StackDepth)));
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixDxilDebugInfo);
+
+HRESULT CreateEntrypointWrapper(
+    IMalloc* pMalloc,
+    IUnknown* pReal,
+    REFIID riid,
+    void** ppvObject)
+{
+#define HANDLE_INTERFACE(IInterface)                                         \
+    if (__uuidof(IInterface) == riid)                                        \
+    {                                                                        \
+        return NewDxcPixDxilDebugInfoObjectOrThrow<IInterface##Entrypoint>(  \
+            (IInterface **) ppvObject,                                       \
+            pMalloc,                                                         \
+            (IInterface *) 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);
+
+  return E_FAIL;
+}
+
+}  // namespace entrypoints
+}  // namespace dxil_debug_info
+
+#include "DxilDiaSession.h"
+
+using namespace dxil_debug_info::entrypoints;
+static STDMETHODIMP NewDxcPixDxilDebugInfoImpl(
+    IMalloc *pMalloc,
+    dxil_dia::Session *pSession,
+    IDxcPixDxilDebugInfo** ppDxilDebugInfo
+)
+{
+  return dxil_debug_info::NewDxcPixDxilDebugInfoObjectOrThrow<dxil_debug_info::DxcPixDxilDebugInfo>(
+      ppDxilDebugInfo,
+      pMalloc,
+      pSession);
+}
+
+STDMETHODIMP dxil_dia::Session::NewDxcPixDxilDebugInfo(
+    _COM_Outptr_ IDxcPixDxilDebugInfo** ppDxilDebugInfo)
+{
+  return SetupAndRun(
+      m_pMalloc,
+      &NewDxcPixDxilDebugInfoImpl,
+      m_pMalloc,
+      ThisPtr(this),
+      CheckNotNull(OutParam(ppDxilDebugInfo)));
+}

+ 268 - 0
lib/DxilDia/DxcPixLiveVariables.cpp

@@ -0,0 +1,268 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixLiveVariables.cpp                                                   //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Defines the mapping between instructions and the set of live variables    //
+// for it.                                                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/WinIncludes.h"
+
+#include "DxcPixDxilDebugInfo.h"
+#include "DxcPixLiveVariables.h"
+#include "DxcPixLiveVariables_FragmentIterator.h" 
+
+#include "dxc/Support/Global.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+
+#include <unordered_map>
+
+// ValidateDbgDeclare ensures that all of the bits in
+// [FragmentSizeInBits, FragmentOffsetInBits) are currently
+// not assigned to a dxil alloca register -- i.e., it
+// tries to find overlapping alloca registers -- which should
+// never happen -- to report the issue.
+void ValidateDbgDeclare(
+    dxil_debug_info::VariableInfo *VarInfo,
+    unsigned FragmentSizeInBits,
+    unsigned FragmentOffsetInBits
+)
+{
+#ifndef NDEBUG
+  for (unsigned i = 0; i < FragmentSizeInBits; ++i)
+  {
+    const unsigned BitNum = FragmentOffsetInBits + i;
+
+    VarInfo->m_DbgDeclareValidation.resize(
+        std::max<unsigned>(VarInfo->m_DbgDeclareValidation.size(),
+                           BitNum + 1));
+    assert(!VarInfo->m_DbgDeclareValidation[BitNum]);
+    VarInfo->m_DbgDeclareValidation[BitNum] = true;
+  }
+#endif  // !NDEBUG
+}
+
+struct dxil_debug_info::LiveVariables::Impl
+{
+  using VariableInfoMap = std::unordered_map<
+      llvm::DIVariable *,
+      std::unique_ptr<VariableInfo>>;
+
+  using LiveVarsMap =
+      std::unordered_map<llvm::DIScope*, VariableInfoMap>;
+
+  IMalloc *m_pMalloc;
+  DxcPixDxilDebugInfo *m_pDxilDebugInfo;
+  llvm::Module *m_pModule;
+  LiveVarsMap m_LiveVarsDbgDeclare;
+
+  void Init(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      llvm::Module *pModule);
+
+  void Init_DbgDeclare(llvm::DbgDeclareInst *DbgDeclare);
+
+  VariableInfo *AssignValueToOffset(
+      VariableInfoMap *VarInfoMap,
+      llvm::DIVariable *Var,
+      llvm::Value *Address,
+      unsigned FragmentIndex,
+      unsigned FragmentOffsetInBits);
+};
+
+void dxil_debug_info::LiveVariables::Impl::Init(
+    IMalloc *pMalloc,
+    DxcPixDxilDebugInfo *pDxilDebugInfo,
+    llvm::Module *pModule)
+{
+  m_pMalloc = pMalloc;
+  m_pDxilDebugInfo = pDxilDebugInfo;
+  m_pModule = pModule;
+
+  llvm::Function* DbgDeclareFn = llvm::Intrinsic::getDeclaration(
+      m_pModule,
+      llvm::Intrinsic::dbg_declare);
+
+  for (llvm::User* U : DbgDeclareFn->users())
+  {
+    if (auto* DbgDeclare = llvm::dyn_cast<llvm::DbgDeclareInst>(U))
+    {
+      Init_DbgDeclare(DbgDeclare);
+    }
+  }
+}
+
+void dxil_debug_info::LiveVariables::Impl::Init_DbgDeclare(
+    llvm::DbgDeclareInst *DbgDeclare
+)
+{
+  llvm::Value *Address = DbgDeclare->getAddress();
+  auto *Variable = DbgDeclare->getVariable();
+  auto *Expression = DbgDeclare->getExpression();
+
+  if (Address == nullptr || Variable == nullptr || Expression == nullptr)
+  {
+    return;
+  }
+
+  auto* AddressAsAlloca = llvm::dyn_cast<llvm::AllocaInst>(Address);
+  if (AddressAsAlloca == nullptr)
+  {
+      return;
+  }
+
+  auto *S = Variable->getScope();
+  if (S == nullptr)
+  {
+    return;
+  }
+
+  std::unique_ptr<FragmentIterator> Iter = FragmentIterator::Create(
+      DbgDeclare,
+      m_pModule->getDataLayout(),
+      AddressAsAlloca,
+      Expression);
+
+  if (!Iter)
+  {
+    // FragmentIterator creation failure, this skip this var.
+    return;
+  }
+
+  const unsigned FragmentSizeInBits = Iter->FragmentSizeInBits();
+
+  unsigned FragmentIndex;
+  while (Iter->Next(&FragmentIndex))
+  {
+    const unsigned FragmentOffsetInBits =
+        Iter->CurrOffsetInBits();
+
+    VariableInfo* VarInfo = AssignValueToOffset(
+        &m_LiveVarsDbgDeclare[S],
+        Variable,
+        Address,
+        FragmentIndex,
+        FragmentOffsetInBits);
+
+    ValidateDbgDeclare(
+        VarInfo,
+        FragmentSizeInBits,
+        FragmentOffsetInBits);
+  }
+}
+
+dxil_debug_info::VariableInfo* dxil_debug_info::LiveVariables::Impl::AssignValueToOffset(
+    VariableInfoMap *VarInfoMap,
+    llvm::DIVariable *Variable,
+    llvm::Value *Address,
+    unsigned FragmentIndex,
+    unsigned FragmentOffsetInBits
+)
+{
+  // FragmentIndex is the index within the alloca'd value
+  // FragmentOffsetInBits is the offset within the HLSL variable
+  // that maps to Address[FragmentIndex]
+  auto it = VarInfoMap->find(Variable);
+  if (it == VarInfoMap->end())
+  {
+    auto InsertIt = VarInfoMap->emplace(
+        Variable,
+        std::make_unique<VariableInfo>(Variable));
+    assert(InsertIt.second);
+    it = InsertIt.first;
+  }
+  auto *VarInfo = it->second.get();
+  auto &FragmentLocation =
+      VarInfo->m_ValueLocationMap[FragmentOffsetInBits];
+  FragmentLocation.m_V = Address;
+  FragmentLocation.m_FragmentIndex = FragmentIndex;
+
+  return VarInfo;
+}
+
+dxil_debug_info::LiveVariables::LiveVariables() = default;
+
+dxil_debug_info::LiveVariables::~LiveVariables() = default;
+
+HRESULT dxil_debug_info::LiveVariables::Init(DxcPixDxilDebugInfo *pDxilDebugInfo) {
+  Clear();
+  m_pImpl->Init(pDxilDebugInfo->GetMallocNoRef(), pDxilDebugInfo, pDxilDebugInfo->GetModuleRef());
+  return S_OK;
+}
+
+void dxil_debug_info::LiveVariables::Clear() {
+  m_pImpl.reset(new dxil_debug_info::LiveVariables::Impl());
+}
+
+HRESULT dxil_debug_info::LiveVariables::GetLiveVariablesAtInstruction(
+  llvm::Instruction *IP,
+  IDxcPixDxilLiveVariables **ppResult) const {
+  DXASSERT(IP != nullptr, "else IP should not be nullptr");
+  DXASSERT(ppResult != nullptr, "else Result should not be nullptr");
+
+  std::vector<const VariableInfo *> LiveVars;
+  std::set<std::string> LiveVarsName;
+
+  const llvm::DebugLoc &DL = IP->getDebugLoc();
+
+  if (!DL)
+  {
+    return E_FAIL;
+  }
+
+  llvm::DIScope *S = DL->getScope();
+  if (S == nullptr)
+  {
+    return E_FAIL;
+  }
+
+  const llvm::DITypeIdentifierMap EmptyMap;
+  while (S != nullptr)
+  {
+    auto it = m_pImpl->m_LiveVarsDbgDeclare.find(S);
+    if (it != m_pImpl->m_LiveVarsDbgDeclare.end())
+    {
+      for (const auto &VarAndInfo :  it->second)
+      {
+        auto *Var = VarAndInfo.first;
+        llvm::StringRef VarName = Var->getName();
+        if (Var->getLine() > DL.getLine())
+        {
+          // Defined later in the HLSL source.
+          continue;
+        }
+        if (VarName.empty())
+        {
+          // No name?...
+          continue;
+        }
+        if (!LiveVarsName.insert(VarName).second)
+        {
+          // There's a variable with the same name; use the
+          // previous one instead.
+          continue;
+        }
+
+        LiveVars.emplace_back(VarAndInfo.second.get());
+      }
+    }
+    S = S->getScope().resolve(EmptyMap);
+  }
+
+  return CreateDxilLiveVariables(
+      m_pImpl->m_pDxilDebugInfo,
+      std::move(LiveVars),
+      ppResult);
+}

+ 83 - 0
lib/DxilDia/DxcPixLiveVariables.h

@@ -0,0 +1,83 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixLiveVariables.h                                                     //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Implements a mapping from the instructions in the Module to the set of    //
+// live variables available in that instruction.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+#include "dxc/Support/WinIncludes.h"
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "DxcPixDxilDebugInfo.h"
+
+namespace llvm
+{
+class DIVariable;
+class Instruction;
+class Module;
+class Value;
+}  // namespace llvm
+
+namespace dxil_debug_info
+{
+
+// VariableInfo is the bag with the information about a particular
+// DIVariable in the Module.
+struct VariableInfo
+{
+  using OffsetInBits = unsigned;
+
+  // Location is the dxil alloca register where this variable lives.
+  struct Location
+  {
+    llvm::Value *m_V = nullptr;
+    unsigned m_FragmentIndex = 0;
+  };
+
+  explicit VariableInfo(
+      llvm::DIVariable *Variable
+  ) : m_Variable(Variable)
+  {
+  }
+
+  llvm::DIVariable *m_Variable;
+
+  std::map<OffsetInBits, Location> m_ValueLocationMap;
+
+#ifndef NDEBUG
+  std::vector<bool> m_DbgDeclareValidation;
+#endif // !NDEBUG
+};
+
+class LiveVariables {
+public:
+  LiveVariables();
+  ~LiveVariables();
+
+  HRESULT Init(DxcPixDxilDebugInfo *pDxilDebugInfo);
+  void Clear();
+
+  HRESULT GetLiveVariablesAtInstruction(
+    llvm::Instruction *Instr,
+    IDxcPixDxilLiveVariables **Result) const;
+
+private:
+    struct Impl;
+    std::unique_ptr<Impl> m_pImpl;
+};
+
+HRESULT CreateDxilLiveVariables(
+    DxcPixDxilDebugInfo *pDxilDebugInfo,
+    std::vector<const VariableInfo *> &&LiveVariables,
+    IDxcPixDxilLiveVariables **ppResult);
+
+}  // namespace dxil_debug_info

+ 258 - 0
lib/DxilDia/DxcPixLiveVariables_FragmentIterator.cpp

@@ -0,0 +1,258 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixLiveVariables_FragmentIterator.cpp                                  //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Implements the FragmentIterator.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/WinIncludes.h"
+
+#include "DxcPixLiveVariables_FragmentIterator.h"
+
+#include "dxc/DXIL/DxilMetadataHelper.h"
+#include "dxc/Support/exception.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+
+#include <vector>
+
+namespace dxil_debug_info
+{
+class DILayoutFragmentIterator : public FragmentIterator
+{
+public:
+  DILayoutFragmentIterator(
+      const llvm::DataLayout &DataLayout,
+      llvm::AllocaInst *Alloca,
+      llvm::DIExpression *Expression);
+
+  unsigned CurrOffsetInBits() override;
+};
+
+class DebugLayoutFragmentIterator : public FragmentIterator
+{
+public:
+  DebugLayoutFragmentIterator(
+      const llvm::DataLayout& DataLayout,
+      llvm::AllocaInst* Alloca,
+      unsigned InitialOffsetInBits,
+      const std::vector<hlsl::DxilDIArrayDim> &ArrayDims);
+
+  unsigned CurrOffsetInBits() override;
+
+private:
+  std::vector<hlsl::DxilDIArrayDim> m_ArrayDims;
+};
+}  // namespace dxil_debug_info
+
+dxil_debug_info::FragmentIterator::FragmentIterator(
+    unsigned NumFragments,
+    unsigned FragmentSizeInBits,
+    unsigned InitialOffsetInBits
+) : m_NumFragments(NumFragments)
+  , m_FragmentSizeInBits(FragmentSizeInBits)
+  , m_InitialOffsetInBits(InitialOffsetInBits)
+{
+}
+
+unsigned dxil_debug_info::FragmentIterator::FragmentSizeInBits() const
+{
+  return m_FragmentSizeInBits;
+}
+
+bool dxil_debug_info::FragmentIterator::Next(
+    unsigned* FragmentIndex
+)
+{
+  if (m_CurrFragment >= m_NumFragments)
+  {
+    return false;
+  }
+
+  *FragmentIndex = m_CurrFragment++;
+  return true;
+}
+
+static unsigned NumAllocaElements(llvm::AllocaInst *Alloca)
+{
+  llvm::Type* FragmentTy = Alloca->getAllocatedType();
+  if (auto* ArrayTy = llvm::dyn_cast<llvm::ArrayType>(FragmentTy))
+  {
+    return ArrayTy->getNumElements();
+  }
+
+  const unsigned NumElements = 1;
+  return NumElements;
+}
+
+static unsigned FragmentSizeInBitsFromAlloca(
+    const llvm::DataLayout &DataLayout,
+    llvm::AllocaInst *Alloca
+)
+{
+  llvm::Type *FragmentTy = Alloca->getAllocatedType();
+  if (auto *ArrayTy = llvm::dyn_cast<llvm::ArrayType>(FragmentTy))
+  {
+    FragmentTy = ArrayTy->getElementType();
+  }
+
+  const unsigned FragmentSizeInBits =
+      DataLayout.getTypeAllocSizeInBits(FragmentTy);
+
+  return FragmentSizeInBits;
+}
+
+static unsigned InitialOffsetInBitsFromDIExpression(
+    const llvm::DataLayout &DataLayout,
+    llvm::AllocaInst *Alloca,
+    llvm::DIExpression *Expression
+)
+{
+  unsigned FragmentOffsetInBits = 0;
+  if (Expression->getNumElements() > 0)
+  {
+    if (!Expression->isBitPiece())
+    {
+      assert(!"Unhandled DIExpression");
+      throw hlsl::Exception(E_FAIL, "Unhandled DIExpression");
+    }
+
+    FragmentOffsetInBits = Expression->getBitPieceOffset();
+    assert(Expression->getBitPieceSize() ==
+           DataLayout.getTypeAllocSizeInBits(
+              Alloca->getAllocatedType()));
+  }
+
+  return FragmentOffsetInBits;
+}
+
+dxil_debug_info::DILayoutFragmentIterator::DILayoutFragmentIterator(
+    const llvm::DataLayout& DataLayout,
+    llvm::AllocaInst* Alloca,
+    llvm::DIExpression* Expression)
+  : FragmentIterator(NumAllocaElements(Alloca),
+                     FragmentSizeInBitsFromAlloca(DataLayout, Alloca),
+                     InitialOffsetInBitsFromDIExpression(DataLayout,
+                                                         Alloca,
+                                                         Expression))
+{
+}
+
+unsigned dxil_debug_info::DILayoutFragmentIterator::CurrOffsetInBits()
+{
+  return
+      m_InitialOffsetInBits + (m_CurrFragment - 1) * m_FragmentSizeInBits;
+}
+
+static unsigned NumFragmentsFromArrayDims(
+    const std::vector<hlsl::DxilDIArrayDim>& ArrayDims
+)
+{
+  unsigned TotalNumFragments = 1;
+  for (const hlsl::DxilDIArrayDim& ArrayDim : ArrayDims) {
+    TotalNumFragments *= ArrayDim.NumElements;
+  }
+  return TotalNumFragments;
+}
+
+static unsigned FragmentSizeInBitsFrom(
+    const llvm::DataLayout& DataLayout,
+    llvm::AllocaInst *Alloca,
+    unsigned TotalNumFragments
+)
+{
+  const unsigned TotalSizeInBits =
+      DataLayout.getTypeAllocSizeInBits(
+          Alloca->getAllocatedType());
+
+  if (TotalNumFragments == 0 || TotalSizeInBits % TotalNumFragments != 0) {
+    assert(!"Malformed variable debug layout metadata.");
+    throw hlsl::Exception(
+        E_FAIL,
+        "Malformed variable debug layout metadata.");
+  }
+
+  const unsigned FragmentSizeInBits = TotalSizeInBits / TotalNumFragments;
+  return FragmentSizeInBits;
+}
+
+dxil_debug_info::DebugLayoutFragmentIterator::DebugLayoutFragmentIterator(
+    const llvm::DataLayout& DataLayout,
+    llvm::AllocaInst* Alloca,
+    unsigned InitialOffsetInBits,
+    const std::vector<hlsl::DxilDIArrayDim>& ArrayDims)
+  : FragmentIterator(NumFragmentsFromArrayDims(ArrayDims),
+                     FragmentSizeInBitsFrom(DataLayout,
+                                            Alloca, 
+                                            NumFragmentsFromArrayDims(ArrayDims)),
+                     InitialOffsetInBits)
+  , m_ArrayDims(ArrayDims)
+{
+}
+
+unsigned dxil_debug_info::DebugLayoutFragmentIterator::CurrOffsetInBits()
+{
+  // Figure out the offset of this fragment in the original
+  unsigned FragmentOffsetInBits = m_InitialOffsetInBits;
+  unsigned RemainingIndex = m_CurrFragment - 1;
+  for (const hlsl::DxilDIArrayDim& ArrayDim : m_ArrayDims) {
+      FragmentOffsetInBits += (RemainingIndex % ArrayDim.NumElements) * ArrayDim.StrideInBits;
+      RemainingIndex /= ArrayDim.NumElements;
+  }
+  assert(RemainingIndex == 0);
+  return FragmentOffsetInBits;
+}
+
+
+std::unique_ptr<dxil_debug_info::FragmentIterator>
+dxil_debug_info::FragmentIterator::Create
+(
+    llvm::DbgDeclareInst *DbgDeclare,
+    const llvm::DataLayout& DataLayout,
+    llvm::AllocaInst* Alloca,
+    llvm::DIExpression* Expression
+)
+{
+  bool HasVariableDebugLayout = false;
+  unsigned FirstFragmentOffsetInBits;
+  std::vector<hlsl::DxilDIArrayDim> ArrayDims;
+
+  std::unique_ptr<dxil_debug_info::FragmentIterator> Iter;
+
+  try
+  {
+    HasVariableDebugLayout = 
+        hlsl::DxilMDHelper::GetVariableDebugLayout(
+            DbgDeclare,
+            FirstFragmentOffsetInBits,
+            ArrayDims);
+
+    if (HasVariableDebugLayout)
+    {
+      Iter.reset(new DebugLayoutFragmentIterator(
+          DataLayout,
+          Alloca,
+          FirstFragmentOffsetInBits,
+          ArrayDims));
+    }
+    else
+    {
+      Iter.reset(new DILayoutFragmentIterator(
+          DataLayout,
+          Alloca,
+          Expression));
+    }
+  }
+  catch (const hlsl::Exception &)
+  {
+    return nullptr;
+  }
+
+  return Iter;
+}

+ 57 - 0
lib/DxilDia/DxcPixLiveVariables_FragmentIterator.h

@@ -0,0 +1,57 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixLiveVariables_FragmentIterator.h                                    //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Declares the FragmentIterator API. This API is used to traverse           //
+// DIVariables and assign alloca registers to DIBasicTypes.                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include <memory>
+
+namespace llvm
+{
+class AllocaInst;
+class DataLayout;
+class DbgDeclareInst;
+class DIExpression;
+}  // namespace llvm
+
+namespace dxil_debug_info
+{
+class FragmentIterator
+{
+public:
+  virtual ~FragmentIterator() = default;
+
+  unsigned FragmentSizeInBits() const;
+
+  virtual unsigned CurrOffsetInBits() = 0;
+
+  bool Next(unsigned *FragmentIndex);
+
+  static std::unique_ptr<FragmentIterator> Create
+  (
+      llvm::DbgDeclareInst *DbgDeclare,
+      const llvm::DataLayout &DataLayout,
+      llvm::AllocaInst *Alloca,
+      llvm::DIExpression *Expression
+  );
+
+protected:
+  FragmentIterator(
+      unsigned NumFragments,
+      unsigned FragmentSizeInBits,
+      unsigned InitialOffsetInBits);
+
+  unsigned m_CurrFragment = 0;
+  unsigned m_NumFragments = 0;
+  unsigned m_FragmentSizeInBits = 0;
+  unsigned m_InitialOffsetInBits = 0;
+};
+}  // namespace dxil_debug_info

+ 307 - 0
lib/DxilDia/DxcPixTypes.cpp

@@ -0,0 +1,307 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixTypes.cpp                                                           //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Defines the implementation for the DxcPixType -- and its subinterfaces.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+
+#include "DxcPixBase.h"
+#include "DxcPixTypes.h"
+
+HRESULT dxil_debug_info::CreateDxcPixType(
+    DxcPixDxilDebugInfo *pDxilDebugInfo,
+    llvm::DIType *diType,
+    IDxcPixType **ppResult)
+{
+  if (auto *BT = llvm::dyn_cast<llvm::DIBasicType>(diType))
+  {
+    return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixScalarType>(
+        ppResult,
+        pDxilDebugInfo->GetMallocNoRef(),
+        pDxilDebugInfo,
+        BT);
+  }
+  else if (auto *CT = llvm::dyn_cast<llvm::DICompositeType>(diType))
+  {
+    switch (CT->getTag())
+    {
+    default:
+      break;
+
+    case llvm::dwarf::DW_TAG_array_type:
+    {
+      const unsigned FirstDim = 0;
+      return NewDxcPixDxilDebugInfoObjectOrThrow< DxcPixArrayType>(
+          ppResult,
+          pDxilDebugInfo->GetMallocNoRef(),
+          pDxilDebugInfo,
+          CT,
+          FirstDim);
+    }
+
+    case llvm::dwarf::DW_TAG_class_type:
+    case llvm::dwarf::DW_TAG_structure_type:
+      return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixStructType>(
+          ppResult,
+          pDxilDebugInfo->GetMallocNoRef(),
+          pDxilDebugInfo,
+          CT);
+    }
+  }
+  else if (auto* DT = llvm::dyn_cast<llvm::DIDerivedType>(diType))
+  {
+    switch (DT->getTag())
+    {
+    default:
+      break;
+
+    case llvm::dwarf::DW_TAG_const_type:
+      return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixConstType>(
+          ppResult,
+          pDxilDebugInfo->GetMallocNoRef(),
+          pDxilDebugInfo,
+          DT);
+
+    case llvm::dwarf::DW_TAG_typedef:
+      return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixTypedefType>(
+          ppResult,
+          pDxilDebugInfo->GetMallocNoRef(),
+          pDxilDebugInfo,
+          DT);
+    }
+  }
+
+  return E_UNEXPECTED;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixConstType::GetName(
+    _Outptr_result_z_ BSTR *Name)
+{
+  CComPtr<IDxcPixType> BaseType;
+  IFR(UnAlias(&BaseType));
+
+  CComBSTR BaseName;
+  IFR(BaseType->GetName(&BaseName));
+
+  *Name = CComBSTR((L"const " + std::wstring(BaseName)).c_str()).Detach();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixConstType::GetSizeInBits(
+    _Outptr_result_z_ DWORD *pSize)
+{
+  CComPtr<IDxcPixType> BaseType;
+  IFR(UnAlias(&BaseType));
+
+  return BaseType->GetSizeInBits(pSize);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixConstType::UnAlias(
+    _Outptr_result_z_ IDxcPixType **ppType)
+{
+  return CreateDxcPixType(m_pDxilDebugInfo, m_pBaseType, ppType);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixTypedefType::GetName(
+    _Outptr_result_z_ BSTR *Name)
+{
+  *Name = CComBSTR(CA2W(m_pType->getName().data())).Detach();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixTypedefType::GetSizeInBits(
+    _Outptr_result_z_ DWORD *pSize)
+{
+  CComPtr<IDxcPixType> BaseType;
+  IFR(UnAlias(&BaseType));
+
+  return BaseType->GetSizeInBits(pSize);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixTypedefType::UnAlias(
+    _Outptr_result_z_ IDxcPixType **ppType)
+{
+  return CreateDxcPixType(m_pDxilDebugInfo, m_pBaseType, ppType);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixScalarType::GetName(
+    _Outptr_result_z_ BSTR *Name)
+{
+  *Name = CComBSTR(CA2W(m_pType->getName().data())).Detach();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixScalarType::GetSizeInBits(
+    _Outptr_result_z_ DWORD *pSizeInBits)
+{
+  *pSizeInBits = m_pType->getSizeInBits();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixScalarType::UnAlias(
+    _Outptr_result_z_ IDxcPixType **ppType)
+{
+  *ppType = this;
+  this->AddRef();
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixArrayType::GetName(
+    _Outptr_result_z_ BSTR *Name)
+{
+  return E_FAIL;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixArrayType::GetSizeInBits(
+    _Outptr_result_z_ DWORD *pSizeInBits)
+{
+  *pSizeInBits = m_pArray->getSizeInBits();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixArrayType::UnAlias(
+    _Outptr_result_z_ IDxcPixType **ppType)
+{
+  *ppType = this;
+  this->AddRef();
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixArrayType::GetNumElements(
+    _Outptr_result_z_ DWORD *ppNumElements) 
+{
+  auto* SR = llvm::dyn_cast<llvm::DISubrange>(m_pArray->getElements()[m_DimNum]);
+  if (SR == nullptr)
+  {
+    return E_FAIL;
+  }
+
+  *ppNumElements = SR->getCount();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixArrayType::GetIndexedType(
+    _Outptr_result_z_ IDxcPixType **ppIndexedElement)
+{
+  assert(1 + m_DimNum <= m_pArray->getElements().size());
+  if (1 + m_DimNum == m_pArray->getElements().size())
+  {
+    return CreateDxcPixType(m_pDxilDebugInfo, m_pBaseType, ppIndexedElement);
+  }
+
+  return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixArrayType>(
+      ppIndexedElement,
+      m_pMalloc,
+      m_pDxilDebugInfo,
+      m_pArray,
+      1 + m_DimNum);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixArrayType::GetElementType(
+    _Outptr_result_z_ IDxcPixType **ppElementType)
+{
+  return CreateDxcPixType(m_pDxilDebugInfo, m_pBaseType, ppElementType);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructType::GetName(
+    _Outptr_result_z_ BSTR *Name)
+{
+  *Name = CComBSTR(CA2W(m_pStruct->getName().data())).Detach();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructType::GetSizeInBits(
+    _Outptr_result_z_ DWORD *pSizeInBits)
+{
+  *pSizeInBits = m_pStruct->getSizeInBits();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructType::UnAlias(
+    _Outptr_result_z_ IDxcPixType **ppType)
+{
+  *ppType = this;
+  this->AddRef();
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructType::GetNumFields(
+    _Outptr_result_z_ DWORD *ppNumFields)
+{
+  *ppNumFields = m_pStruct->getElements()->getNumOperands();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructType::GetFieldByIndex(
+    DWORD dwIndex,
+    _Outptr_result_z_ IDxcPixStructField **ppField)
+{
+  if (dwIndex >= m_pStruct->getElements().size())
+  {
+    return E_BOUNDS;
+  }
+
+  auto* pDIField = llvm::dyn_cast<llvm::DIDerivedType>(
+      m_pStruct->getElements()[dwIndex]);
+  if (pDIField == nullptr)
+  {
+    return E_FAIL;
+  }
+
+  return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixStructField>(
+      ppField,
+      m_pMalloc,
+      m_pDxilDebugInfo,
+      pDIField);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructType::GetFieldByName(
+    _In_ LPCWSTR lpName,
+    _Outptr_result_z_ IDxcPixStructField **ppField)
+{
+  std::string name = CW2A(lpName);
+  for (auto *Node : m_pStruct->getElements())
+  {
+    auto* pDIField = llvm::dyn_cast<llvm::DIDerivedType>(Node);
+    if (pDIField == nullptr)
+    {
+      return E_FAIL;
+    }
+
+    if (pDIField->getName() == name)
+    {
+      return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixStructField>(
+          ppField,
+          m_pMalloc,
+          m_pDxilDebugInfo,
+          pDIField);
+    }
+  }
+
+  return E_BOUNDS;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructField::GetName(
+    _Outptr_result_z_ BSTR *Name) 
+{
+  *Name = CComBSTR(CA2W(m_pField->getName().data())).Detach();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructField::GetType(
+    _Outptr_result_z_ IDxcPixType **ppType)
+{
+  return CreateDxcPixType(m_pDxilDebugInfo, m_pType, ppType);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixStructField::GetOffsetInBits(
+    _Outptr_result_z_ DWORD *pOffsetInBits)
+{
+  *pOffsetInBits = m_pField->getOffsetInBits();
+  return S_OK;
+}

+ 292 - 0
lib/DxilDia/DxcPixTypes.h

@@ -0,0 +1,292 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixTypes.h                                                             //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Declares the classes implementing DxcPixType and its subinterfaces. These //
+// classes are used to interpret llvm::DITypes from the debug metadata.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "dxc/Support/WinIncludes.h"
+
+#include "DxcPixTypes.h"
+#include "DxcPixDxilDebugInfo.h"
+
+#include "dxc/Support/Global.h"
+#include "dxc/Support/microcom.h"
+
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+
+namespace dxil_debug_info
+{
+HRESULT CreateDxcPixType(
+    DxcPixDxilDebugInfo *ppDxilDebugInfo,
+    llvm::DIType *diType,
+    IDxcPixType **ppResult);
+
+class DxcPixConstType : public IDxcPixConstType
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  llvm::DIDerivedType *m_pType;
+  llvm::DIType *m_pBaseType;
+
+  DxcPixConstType(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      llvm::DIDerivedType *pType)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_pType(pType)
+  {
+    const llvm::DITypeIdentifierMap EmptyMap;
+    m_pBaseType = m_pType->getBaseType().resolve(EmptyMap);
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixConstType)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixConstType, IDxcPixType>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override;
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD * pSizeInBits) override;
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType **ppType) override;
+};
+
+class DxcPixTypedefType : public IDxcPixTypedefType
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  llvm::DIDerivedType *m_pType;
+  llvm::DIType *m_pBaseType;
+
+  DxcPixTypedefType(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      llvm::DIDerivedType *pType)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_pType(pType)
+  {
+    const llvm::DITypeIdentifierMap EmptyMap;
+    m_pBaseType = m_pType->getBaseType().resolve(EmptyMap);
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixTypedefType)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixTypedefType, IDxcPixType>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override;
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *pSizeInBits) override;
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType **ppBaseType) override;
+};
+
+class DxcPixScalarType : public IDxcPixScalarType
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  llvm::DIBasicType *m_pType;
+
+  DxcPixScalarType(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      llvm::DIBasicType *pType)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_pType(pType)
+  {
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixScalarType)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixScalarType, IDxcPixType>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override;
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *pSizeInBits) override;
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType **ppBaseType) override;
+};
+
+class DxcPixArrayType : public IDxcPixArrayType
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  llvm::DICompositeType *m_pArray;
+  llvm::DIType *m_pBaseType;
+  unsigned m_DimNum;
+
+  DxcPixArrayType(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      llvm::DICompositeType *pArray,
+      unsigned DimNum)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_pArray(pArray)
+    , m_DimNum(DimNum)
+  {
+    const llvm::DITypeIdentifierMap EmptyMap;
+    m_pBaseType = m_pArray->getBaseType().resolve(EmptyMap);
+
+#ifndef NDEBUG
+    assert(m_DimNum < m_pArray->getElements().size());
+
+    for (auto *Dims : m_pArray->getElements())
+    {
+      assert(llvm::isa<llvm::DISubrange>(Dims));
+    }
+#endif  // !NDEBUG
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixArrayType)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixArrayType, IDxcPixType>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override;
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *pSizeInBits) override;
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType **ppBaseType) override;
+
+  STDMETHODIMP GetNumElements(
+      _Outptr_result_z_ DWORD *ppNumElements) override;
+
+  STDMETHODIMP GetIndexedType(
+      _Outptr_result_z_ IDxcPixType **ppElementType) override;
+
+  STDMETHODIMP GetElementType(
+      _Outptr_result_z_ IDxcPixType **ppElementType) override;
+};
+
+class DxcPixStructType : public IDxcPixStructType
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  llvm::DICompositeType *m_pStruct;
+
+  DxcPixStructType(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      llvm::DICompositeType *pStruct
+  ) : m_pMalloc(pMalloc)
+      , m_pDxilDebugInfo(pDxilDebugInfo)
+      , m_pStruct(pStruct)
+  {
+#ifndef NDEBUG
+    for (auto *Node : m_pStruct->getElements())
+    {
+      assert(llvm::isa<llvm::DIDerivedType>(Node));
+    }
+#endif  // !NDEBUG
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixStructType)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixStructType, IDxcPixType>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override;
+
+  STDMETHODIMP GetSizeInBits(
+      _Outptr_result_z_ DWORD *pSizeInBits) override;
+
+  STDMETHODIMP UnAlias(
+      _Outptr_result_z_ IDxcPixType **ppBaseType) override;
+
+  STDMETHODIMP GetNumFields(
+      _Outptr_result_z_ DWORD* ppNumFields) override;
+
+  STDMETHODIMP GetFieldByIndex(
+      DWORD dwIndex,
+      _Outptr_result_z_ IDxcPixStructField **ppField) override;
+
+  STDMETHODIMP GetFieldByName(
+      _In_ LPCWSTR lpName,
+      _Outptr_result_z_ IDxcPixStructField **ppField) override;
+};
+
+class DxcPixStructField : public IDxcPixStructField
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  llvm::DIDerivedType *m_pField;
+  llvm::DIType *m_pType;
+
+  DxcPixStructField(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      llvm::DIDerivedType *pField)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_pField(pField)
+  {
+    const llvm::DITypeIdentifierMap EmptyMap;
+    m_pType = m_pField->getBaseType().resolve(EmptyMap);
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixStructField)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixStructField>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override;
+
+  STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType **ppType) override;
+
+  STDMETHODIMP GetOffsetInBits(
+      _Outptr_result_z_ DWORD *pOffsetInBits) override;
+};
+}  // namespace dxil_debug_info

+ 234 - 0
lib/DxilDia/DxcPixVariables.cpp

@@ -0,0 +1,234 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxcPixVariables.cpp                                                       //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Defines DXC's PIX api for exposing llvm::DIVariables.                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+
+#include "dxc/Support/WinIncludes.h"
+
+#include "dxc/dxcpix.h"
+#include "dxc/Support/microcom.h"
+#include "dxc/Support/Global.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+
+#include "DxcPixBase.h"
+#include "DxcPixDxilDebugInfo.h"
+#include "DxcPixDxilStorage.h"
+#include "DxcPixLiveVariables.h"
+#include "DxcPixTypes.h"
+
+#include <set>
+#include <vector>
+
+namespace dxil_debug_info
+{
+template <typename T>
+class DxcPixVariable : public IDxcPixVariable
+{
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  T *m_pVariable;
+  VariableInfo const *m_pVarInfo;
+  llvm::DIType *m_pType;
+
+  DxcPixVariable(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *DxilDebugInfo,
+      T *pVariable,
+      VariableInfo const *pVarInfo)
+    : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(DxilDebugInfo)
+    , m_pVariable(pVariable)
+    , m_pVarInfo(pVarInfo)
+  {
+    const llvm::DITypeIdentifierMap EmptyMap;
+    m_pType = m_pVariable->getType().resolve(EmptyMap);
+  }
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixVariable)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixVariable>(this, iid, ppvObject);
+  }
+
+public:
+  STDMETHODIMP GetName(
+      _Outptr_result_z_ BSTR *Name) override;
+
+  STDMETHODIMP GetType(
+      _Outptr_result_z_ IDxcPixType** ppType) override;
+
+  STDMETHODIMP GetStorage(
+      _COM_Outptr_ IDxcPixDxilStorage** ppStorage) override;
+};
+
+}  // namespace dxil_debug_info
+
+template <typename T>
+STDMETHODIMP dxil_debug_info::DxcPixVariable<T>::GetName(
+    _Outptr_result_z_ BSTR* Name)
+{
+  *Name = CComBSTR(CA2W(m_pVariable->getName().data())).Detach();
+  return S_OK;
+}
+
+template <typename T>
+STDMETHODIMP dxil_debug_info::DxcPixVariable<T>::GetType(
+    _Outptr_result_z_ IDxcPixType **ppType
+)
+{
+  return dxil_debug_info::CreateDxcPixType(
+      m_pDxilDebugInfo,
+      m_pType,
+      ppType);
+}
+
+template <typename T>
+STDMETHODIMP dxil_debug_info::DxcPixVariable<T>::GetStorage(
+    _COM_Outptr_ IDxcPixDxilStorage **ppStorage
+)
+{
+  const unsigned InitialOffsetInBits = 0;
+  return CreateDxcPixStorage(
+      m_pDxilDebugInfo,
+      m_pType,
+      m_pVarInfo,
+      InitialOffsetInBits,
+      ppStorage);
+}
+
+namespace dxil_debug_info
+{
+class DxcPixDxilLiveVariables : public IDxcPixDxilLiveVariables
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS();
+  CComPtr<DxcPixDxilDebugInfo> m_pDxilDebugInfo;
+  std::vector<const VariableInfo *> m_LiveVars;
+
+  DxcPixDxilLiveVariables(
+      IMalloc *pMalloc,
+      DxcPixDxilDebugInfo *pDxilDebugInfo,
+      std::vector<const VariableInfo *> LiveVars
+  ) : m_pMalloc(pMalloc)
+    , m_pDxilDebugInfo(pDxilDebugInfo)
+    , m_LiveVars(std::move(LiveVars))
+  {
+#ifndef NDEBUG
+    for (auto VarAndInfo : m_LiveVars)
+    {
+        assert(llvm::isa<llvm::DIGlobalVariable>(VarAndInfo->m_Variable) ||
+               llvm::isa<llvm::DILocalVariable>(VarAndInfo->m_Variable));
+    }
+#endif  // !NDEBUG
+  }
+
+  STDMETHODIMP CreateDxcPixVariable(
+      IDxcPixVariable** ppVariable,
+      VariableInfo const *VarInfo) const;
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL();
+  DXC_MICROCOM_TM_ALLOC(DxcPixDxilLiveVariables);
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) final {
+    return DoBasicQueryInterface<IDxcPixDxilLiveVariables>(this, iid, ppvObject);
+  }
+
+  STDMETHODIMP GetCount(
+      _Outptr_ DWORD *dwSize) override;
+
+  STDMETHODIMP GetVariableByIndex(
+      _In_ DWORD Index,
+      _Outptr_result_z_ IDxcPixVariable** ppVariable) override;
+
+  STDMETHODIMP GetVariableByName(
+      _In_ LPCWSTR Name,
+      _Outptr_result_z_ IDxcPixVariable** ppVariable) override;
+};
+
+}  // namespace dxil_debug_info
+STDMETHODIMP dxil_debug_info::DxcPixDxilLiveVariables::GetCount(
+    _Outptr_ DWORD *dwSize) {
+  *dwSize = m_LiveVars.size();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilLiveVariables::CreateDxcPixVariable(
+    IDxcPixVariable** ppVariable,
+    VariableInfo const* VarInfo) const
+{
+  auto *Var = VarInfo->m_Variable;
+  if (auto *DILV = llvm::dyn_cast<llvm::DILocalVariable>(Var))
+  {
+    return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixVariable<llvm::DILocalVariable>>(
+        ppVariable,
+        m_pMalloc,
+        m_pDxilDebugInfo,
+        DILV,
+        VarInfo);
+  }
+  else if (auto *DIGV = llvm::dyn_cast<llvm::DIGlobalVariable>(Var))
+  {
+    return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixVariable<llvm::DIGlobalVariable>>(
+        ppVariable,
+        m_pMalloc,
+        m_pDxilDebugInfo,
+        DIGV,
+        VarInfo);
+  }
+
+  return E_UNEXPECTED;
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilLiveVariables::GetVariableByIndex(
+    _In_ DWORD Index,
+    _Outptr_result_z_ IDxcPixVariable **ppVariable)
+{
+  if (Index >= m_LiveVars.size())
+  {
+    return E_BOUNDS;
+  }
+
+  auto* VarInfo = m_LiveVars[Index];
+  return CreateDxcPixVariable(ppVariable, VarInfo);
+}
+
+STDMETHODIMP dxil_debug_info::DxcPixDxilLiveVariables::GetVariableByName(
+    _In_ LPCWSTR Name,
+    _Outptr_result_z_ IDxcPixVariable **ppVariable)
+{
+  std::string name = CW2A(Name);
+
+  for (auto *VarInfo : m_LiveVars)
+  {
+    auto *Var = VarInfo->m_Variable;
+    if (Var->getName() == name)
+    {
+      return CreateDxcPixVariable(ppVariable, VarInfo);
+    }
+  }
+
+  return E_BOUNDS;
+}
+
+HRESULT dxil_debug_info::CreateDxilLiveVariables(
+    DxcPixDxilDebugInfo *pDxilDebugInfo,
+    std::vector<const VariableInfo *> &&LiveVariables,
+    IDxcPixDxilLiveVariables **ppResult)
+{
+  return NewDxcPixDxilDebugInfoObjectOrThrow<DxcPixDxilLiveVariables>(
+      ppResult,
+      pDxilDebugInfo->GetMallocNoRef(),
+      pDxilDebugInfo,
+      std::move(LiveVariables));
+}

+ 3 - 1
lib/DxilDia/DxilDiaSession.cpp

@@ -42,7 +42,9 @@ void dxil_dia::Session::Init(
   m_dxilModule = llvm::make_unique<hlsl::DxilModule>(module.get());
 
   llvm::legacy::PassManager PM;
+  llvm::initializeDxilDbgValueToDbgDeclarePass(*llvm::PassRegistry::getPassRegistry());
   llvm::initializeDxilAnnotateWithVirtualRegisterPass(*llvm::PassRegistry::getPassRegistry());
+  PM.add(llvm::createDxilDbgValueToDbgDeclarePass());
   PM.add(llvm::createDxilAnnotateWithVirtualRegisterPass());
   PM.run(*m_module);
 
@@ -390,4 +392,4 @@ STDMETHODIMP dxil_dia::Session::findInlineFramesByAddr(
 
   *ppResult = ChildrenEnum;
   return hr;
-}
+}

+ 6 - 2
lib/DxilDia/DxilDiaSession.h

@@ -20,6 +20,7 @@
 
 #include "dia2.h"
 
+#include "dxc/dxcpix.h"
 #include "dxc/DXIL/DxilModule.h"
 
 #include "dxc/Support/Global.h"
@@ -29,7 +30,7 @@
 #include "DxilDiaSymbolManager.h"
 
 namespace dxil_dia {
-class Session : public IDiaSession {
+class Session : public IDiaSession, public IDxcPixDxilDebugInfoFactory {
 public:
   using RVA = unsigned;
   using RVAMap = std::map<RVA, const llvm::Instruction *>;
@@ -71,7 +72,7 @@ public:
   HRESULT getSourceFileIdByName(llvm::StringRef fileName, DWORD *pRetVal);
 
   HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
-    return DoBasicQueryInterface<IDiaSession>(this, iid, ppvObject);
+    return DoBasicQueryInterface<IDiaSession, IDxcPixDxilDebugInfoFactory>(this, iid, ppvObject);
   }
 
   STDMETHODIMP get_loadAddress(
@@ -375,6 +376,9 @@ public:
     /* [in] */ IDiaSymbol *pSymbol,
     /* [out] */ IDiaInputAssemblyFile **ppResult) override { return ENotImpl(); }
 
+  STDMETHODIMP NewDxcPixDxilDebugInfo(
+      _COM_Outptr_ IDxcPixDxilDebugInfo** ppDxilDebugInfo) override;
+
 private:
   DXC_MICROCOM_TM_REF_FIELDS()
   std::shared_ptr<llvm::LLVMContext> m_context;

+ 2 - 0
lib/DxilDia/DxilDiaSymbolManager.cpp

@@ -1248,7 +1248,9 @@ HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateFunctionsForCU(llvm::DI
     IFR(CreateType(SubProgram->getType(), &dwSubprogramTypeID));
     IFR(AddSymbol<symbol_factory::Function>(dwParentID, &dwNewFunID, SubProgram, dwSubprogramTypeID));
     m_ScopeToSym.insert(std::make_pair(SubProgram, dwNewFunID));
+  }
 
+  for (llvm::DISubprogram* SubProgram : CU->getSubprograms()) {
     if (llvm::Function *F = SubProgram->getFunction()) {
       IFR(CreateFunctionBlocksForFunction(F));
       FoundFunctions = true;

+ 5 - 1
lib/DxilPIXPasses/DxilAnnotateWithVirtualRegister.cpp

@@ -22,6 +22,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstIterator.h"
+#include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Module.h"
@@ -74,7 +75,10 @@ bool DxilAnnotateWithVirtualRegister::runOnModule(llvm::Module &M) {
 
   std::uint32_t InstNum = 0;
   for (llvm::Instruction &I : llvm::inst_range(m_DM->GetEntryFunction())) {
-    pix_dxil::PixDxilInstNum::AddMD(M.getContext(), &I, InstNum++);
+    if (!llvm::isa<llvm::DbgDeclareInst>(&I))
+    {
+      pix_dxil::PixDxilInstNum::AddMD(M.getContext(), &I, InstNum++);
+    }
   }
 
   if (OSOverride != nullptr) {

+ 2 - 3
lib/DxilPIXPasses/DxilDbgValueToDbgDeclare.cpp

@@ -557,13 +557,12 @@ void VariableRegisters::PopulateAllocaMap_BasicType(
       return;
   }
 
-  auto* Loc = GetVariableLocation();
   const OffsetInBits AlignedOffset = m_Offsets.Add(Ty);
 
   llvm::Type *AllocaTy = llvm::ArrayType::get(AllocaElementTy, 1);
   llvm::AllocaInst *&Alloca = m_AlignedOffsetToAlloca[AlignedOffset];
   Alloca = m_B.CreateAlloca(AllocaTy, m_B.getInt32(0));
-  Alloca->setDebugLoc(Loc);
+  Alloca->setDebugLoc(llvm::DebugLoc());
 
   auto *Storage = GetMetadataAsValue(llvm::ValueAsMetadata::get(Alloca));
   auto *Variable = GetMetadataAsValue(m_Variable);
@@ -571,7 +570,7 @@ void VariableRegisters::PopulateAllocaMap_BasicType(
   auto *DbgDeclare = m_B.CreateCall(
       m_DbgDeclareFn,
       {Storage, Variable, Expression});
-  DbgDeclare->setDebugLoc(Loc);
+  DbgDeclare->setDebugLoc(GetVariableLocation());
 }
 
 static unsigned NumArrayElements(

+ 1 - 0
lib/DxilPIXPasses/DxilPIXPasses.cpp

@@ -31,6 +31,7 @@ HRESULT SetupRegistryPassForPIX() {
     // INIT-PASSES:BEGIN
     initializeDxilAddPixelHitInstrumentationPass(Registry);
     initializeDxilAnnotateWithVirtualRegisterPass(Registry);
+    initializeDxilDbgValueToDbgDeclarePass(Registry);
     initializeDxilDebugInstrumentationPass(Registry);
     initializeDxilForceEarlyZPass(Registry);
     initializeDxilOutputColorBecomesConstantPass(Registry);

+ 29 - 34
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -1130,40 +1130,35 @@ TEST_F(CompilerTest, CompileDebugLines) {
     "  return z;\r\n"
     "}", &pDiaSource));
     
-  static constexpr uint32_t numExpectedRVAs = 10;
+  const uint32_t numExpectedVAs = 18;
+  const uint32_t numExpectedLineEntries = 6;
 
   auto verifyLines = [=](const std::vector<LineNumber> lines) {
-    VERIFY_ARE_EQUAL(lines.size(), numExpectedRVAs);
-    // 0: loadInput
-    VERIFY_ARE_EQUAL(lines[0].rva,  0);
+    VERIFY_ARE_EQUAL(lines.size(), numExpectedLineEntries);
+
+    // loadInput
     VERIFY_ARE_EQUAL(lines[0].line, 1);
-    // 1: dbg.value
-    VERIFY_ARE_EQUAL(lines[1].rva,  1);
-    VERIFY_ARE_EQUAL(lines[1].line, 1);
-    // 2: abs
-    VERIFY_ARE_EQUAL(lines[2].rva,  2);
-    VERIFY_ARE_EQUAL(lines[2].line, 2);
-    // 3: dbg.value
-    VERIFY_ARE_EQUAL(lines[3].rva,  3);
-    VERIFY_ARE_EQUAL(lines[3].line, 2);
-    // 4: sin
-    VERIFY_ARE_EQUAL(lines[4].rva,  4);
-    VERIFY_ARE_EQUAL(lines[4].line, 3);
-    // 5: dbg.value
-    VERIFY_ARE_EQUAL(lines[5].rva,  5);
-    VERIFY_ARE_EQUAL(lines[5].line, 3);
-    // 6: fadd
-    VERIFY_ARE_EQUAL(lines[6].rva,  6);
-    VERIFY_ARE_EQUAL(lines[6].line, 4);
-    // 7: dbg.value
-    VERIFY_ARE_EQUAL(lines[7].rva,  7);
-    VERIFY_ARE_EQUAL(lines[7].line, 4);
-    // 8: storeOutput
-    VERIFY_ARE_EQUAL(lines[8].rva,  8);
-    VERIFY_ARE_EQUAL(lines[8].line, 5);
-    // 9: ret
-    VERIFY_ARE_EQUAL(lines[9].rva,  9);
-    VERIFY_ARE_EQUAL(lines[9].line, 5);
+    VERIFY_ARE_EQUAL(lines[0].rva,  4);
+
+    // abs
+    VERIFY_ARE_EQUAL(lines[1].line, 2);
+    VERIFY_ARE_EQUAL(lines[1].rva, 7);
+
+    // sin
+    VERIFY_ARE_EQUAL(lines[2].line, 3);
+    VERIFY_ARE_EQUAL(lines[2].rva, 10);
+
+    // fadd
+    VERIFY_ARE_EQUAL(lines[3].line, 4);
+    VERIFY_ARE_EQUAL(lines[3].rva, 13);
+
+    // storeOutput
+    VERIFY_ARE_EQUAL(lines[4].line, 5);
+    VERIFY_ARE_EQUAL(lines[4].rva, 16);
+
+    // ret
+    VERIFY_ARE_EQUAL(lines[5].line, 5);
+    VERIFY_ARE_EQUAL(lines[5].rva, 17);
   };
   
   CComPtr<IDiaSession> pSession;
@@ -1172,7 +1167,7 @@ TEST_F(CompilerTest, CompileDebugLines) {
   // Verify lines are ok when getting one RVA at a time.
   std::vector<LineNumber> linesOneByOne;
   VERIFY_SUCCEEDED(pDiaSource->openSession(&pSession));
-  for (int i = 0; i < numExpectedRVAs; ++i) {
+  for (int i = 0; i < numExpectedVAs; ++i) {
     VERIFY_SUCCEEDED(pSession->findLinesByRVA(i, 1, &pEnumLineNumbers));
     std::vector<LineNumber> lines = ReadLineNumbers(pEnumLineNumbers);
     std::copy(lines.begin(), lines.end(), std::back_inserter(linesOneByOne));
@@ -1183,7 +1178,7 @@ TEST_F(CompilerTest, CompileDebugLines) {
   // Verify lines are ok when getting all RVAs at once.
   std::vector<LineNumber> linesAllAtOnce;
   pEnumLineNumbers.Release();
-  VERIFY_SUCCEEDED(pSession->findLinesByRVA(0, numExpectedRVAs, &pEnumLineNumbers));
+  VERIFY_SUCCEEDED(pSession->findLinesByRVA(0, numExpectedVAs, &pEnumLineNumbers));
   linesAllAtOnce = ReadLineNumbers(pEnumLineNumbers);
   verifyLines(linesAllAtOnce);
 
@@ -1207,7 +1202,7 @@ TEST_F(CompilerTest, CompileDebugLines) {
   // Verify lines are ok when getting by address.
   std::vector<LineNumber> linesByAddr;
   pEnumLineNumbers.Release();
-  VERIFY_SUCCEEDED(pSession->findLinesByAddr(0, 0, numExpectedRVAs, &pEnumLineNumbers));
+  VERIFY_SUCCEEDED(pSession->findLinesByAddr(0, 0, numExpectedVAs, &pEnumLineNumbers));
   linesByAddr = ReadLineNumbers(pEnumLineNumbers);
   verifyLines(linesByAddr);
 

+ 1 - 0
utils/hct/hctdb.py

@@ -1954,6 +1954,7 @@ class db_dxil(object):
             {'n':'parameter1','t':'int','c':1},
             {'n':'parameter2','t':'int','c':1}])
         add_pass('dxil-annotate-with-virtual-regs', 'DxilAnnotateWithVirtualRegister', 'Annotates each instruction in the DXIL module with a virtual register number', [])
+        add_pass('dxil-dbg-value-to-dbg-declare', 'DxilDbgValueToDbgDeclare', 'Converts llvm.dbg.value uses to llvm.dbg.declare.', [])
         add_pass('hlsl-dxil-reduce-msaa-to-single', 'DxilReduceMSAAToSingleSample', 'HLSL DXIL Reduce all MSAA reads to single-sample reads', [])
 
         category_lib="dxil_gen"