Kaynağa Gözat

Implements DIA Interfaces for HLSL variable-value mapping. (#2050)

John Porto 6 yıl önce
ebeveyn
işleme
d432a02f77

+ 1 - 0
lib/DxilPIXPasses/DxilPIXVirtualRegisters.h → include/dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h

@@ -43,6 +43,7 @@ static constexpr char MDName[] = "pix-alloca-reg";
 static constexpr uint32_t ID = 1;
 
 void AddMD(llvm::LLVMContext &Ctx, llvm::AllocaInst *pAlloca, std::uint32_t RegNum, std::uint32_t Count);
+bool FromInst(llvm::AllocaInst *pAlloca, std::uint32_t *pRegBase, std::uint32_t *pRegSize);
 }  // namespace PixAllocaReg
 
 namespace PixAllocaRegWrite {

+ 1 - 1
lib/CMakeLists.txt

@@ -24,9 +24,9 @@ add_subdirectory(DxcSupport) # HLSL Change
 add_subdirectory(HLSL) # HLSL Change
 add_subdirectory(DXIL) # HLSL Change
 add_subdirectory(DxilContainer) # HLSL Change
+add_subdirectory(DxilPIXPasses) # HLSL Change
 if(WIN32) # HLSL Change
   add_subdirectory(DxilDia) # HLSL Change
 endif(WIN32) # HLSL Change
-add_subdirectory(DxilPIXPasses) # HLSL Change
 add_subdirectory(DxilRootSignature) # HLSL Change
 add_subdirectory(DxrFallback) # HLSL Change

+ 3 - 0
lib/DxilDia/CMakeLists.txt

@@ -10,6 +10,7 @@ add_llvm_library(LLVMDxilDia
   DxilDiaDataSource.cpp
   DxilDiaEnumTables.cpp
   DxilDiaSession.cpp
+  DxilDiaSymbolManager.cpp
   DxilDiaTable.cpp
   DxilDiaTableFrameData.cpp
   DxilDiaTableInjectedSources.cpp
@@ -28,3 +29,5 @@ if (WIN32)
   target_link_libraries(LLVMDxilDia PRIVATE ${LIBRARIES} ${DIASDK_LIBRARIES})
   include_directories(AFTER ${LLVM_INCLUDE_DIR}/dxc/Tracing ${DIASDK_INCLUDE_DIRS})
 endif (WIN32)
+
+add_dependencies(LLVMDxilDia LLVMDxilPIXPasses intrinsics_gen)

+ 202 - 19
lib/DxilDia/DxilDiaSession.cpp

@@ -11,18 +11,24 @@
 
 #include "DxilDiaSession.h"
 
+#include "dxc/DxilPIXPasses/DxilPIXPasses.h"
+#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/InstIterator.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/PassRegistry.h"
 
 #include "DxilDia.h"
 #include "DxilDiaEnumTables.h"
 #include "DxilDiaTable.h"
 #include "DxilDiaTableInjectedSources.h"
 #include "DxilDiaTableLineNumbers.h"
+#include "DxilDiaTableSourceFiles.h"
+#include "DxilDiaTableSymbols.h"
 
 void dxil_dia::Session::Init(
     std::shared_ptr<llvm::LLVMContext> context,
@@ -34,6 +40,11 @@ void dxil_dia::Session::Init(
   m_finder = finder;
   m_dxilModule = std::make_unique<hlsl::DxilModule>(module.get());
 
+  llvm::legacy::PassManager PM;
+  llvm::initializeDxilAnnotateWithVirtualRegisterPass(*llvm::PassRegistry::getPassRegistry());
+  PM.add(llvm::createDxilAnnotateWithVirtualRegisterPass());
+  PM.run(*m_module);
+
   // Extract HLSL metadata.
   m_dxilModule->LoadDxilMetadata();
 
@@ -59,30 +70,35 @@ void dxil_dia::Session::Init(
     m_arguments = m_module->getNamedMetadata("llvm.dbg.args");
 
   // Build up a linear list of instructions. The index will be used as the
-  // RVA. Debug instructions are ommitted from this enumeration.
-  for (const llvm::Function &fn : m_module->functions()) {
-    for (llvm::const_inst_iterator it = inst_begin(fn), end = inst_end(fn); it != end; ++it) {
-      const llvm::Instruction &i = *it;
-      if (const auto *call = llvm::dyn_cast<const llvm::CallInst>(&i)) {
-        const llvm::Function *pFn = call->getCalledFunction();
-        if (pFn && pFn->getName().startswith("llvm.dbg.")) {
-          continue;
-        }
+  // RVA.
+  for (llvm::Function &fn : m_module->functions()) {
+    for (llvm::inst_iterator it = inst_begin(fn), end = inst_end(fn); it != end; ++it) {
+      llvm::Instruction &i = *it;
+      RVA rva;
+      if (!pix_dxil::PixDxilInstNum::FromInst(&i, &rva)) {
+        continue;
       }
-
-      m_rvaMap.insert({ &i, static_cast<RVA>(m_instructions.size()) });
-      m_instructions.push_back(&i);
-      if (i.getDebugLoc()) {
+      m_rvaMap.insert({ &i, rva });
+      m_instructions.insert({ rva, &i});
+      if (llvm::DebugLoc DL = i.getDebugLoc()) {
+        auto result = m_lineToInfoMap.emplace(DL.getLine(), LineInfo(DL.getCol(), rva, rva + 1));
+        if (!result.second) {
+          result.first->second.StartCol = std::min(result.first->second.StartCol, DL.getCol());
+          result.first->second.Last = rva + 1;
+        }
         m_instructionLines.push_back(&i);
       }
     }
   }
 
   // Sanity check to make sure rva map is same as instruction index.
-  for (size_t i = 0, e = m_instructions.size(); i < e; ++i) {
-    DXASSERT(m_rvaMap.find(m_instructions[i]) != m_rvaMap.end(), "instruction not mapped to rva");
-    DXASSERT(m_rvaMap[m_instructions[i]] == i, "instruction mapped to wrong rva");
+  for (auto It = m_instructions.begin(); It != m_instructions.end(); ++It) {
+    DXASSERT(m_rvaMap.find(It->second) != m_rvaMap.end(), "instruction not mapped to rva");
+    DXASSERT(m_rvaMap[It->second] == It->first, "instruction mapped to wrong rva");
   }
+
+  // Initialize symbols
+  m_symsMgr.Init(this);
 }
 
 HRESULT dxil_dia::Session::getSourceFileIdByName(
@@ -109,6 +125,21 @@ STDMETHODIMP dxil_dia::Session::get_loadAddress(
   return S_OK;
 }
 
+STDMETHODIMP dxil_dia::Session::get_globalScope(
+  /* [retval][out] */ IDiaSymbol **pRetVal) {
+  DxcThreadMalloc TM(m_pMalloc);
+
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = nullptr;
+
+  Symbol *ret;
+  IFR(m_symsMgr.GetGlobalScope(&ret));
+  *pRetVal = ret;
+  return S_OK;
+}
+
 STDMETHODIMP dxil_dia::Session::getEnumTables(
     /* [out] */ _COM_Outptr_ IDiaEnumTables **ppEnumTables) {
   if (!m_pEnumTables) {
@@ -136,6 +167,57 @@ STDMETHODIMP dxil_dia::Session::findFileById(
   return pElt->QueryInterface(ppResult);
 }
 
+STDMETHODIMP dxil_dia::Session::findFile(
+    /* [in] */ IDiaSymbol *pCompiland,
+    /* [in] */ LPCOLESTR name,
+    /* [in] */ DWORD compareFlags,
+    /* [out] */ IDiaEnumSourceFiles **ppResult) {
+    if (!m_pEnumTables) {
+        return E_INVALIDARG;
+    }
+    
+    // TODO: properly support compareFlags.
+    auto namecmp = &_wcsicmp;
+    if (compareFlags & nsCaseSensitive) {
+        namecmp = &wcscmp;
+    }
+
+    DxcThreadMalloc TM(m_pMalloc);
+    CComPtr<IDiaTable> pTable;
+    VARIANT vtIndex;
+    vtIndex.vt = VT_UI4;
+    vtIndex.uintVal = (int)Table::Kind::SourceFiles;
+    IFR(m_pEnumTables->Item(vtIndex, &pTable));
+
+    CComPtr<IDiaEnumSourceFiles> pSourceTable;
+    IFR(pTable->QueryInterface(&pSourceTable));
+    HRESULT hr;
+    CComPtr<IDiaSourceFile> src;
+    ULONG cnt;
+    std::vector<CComPtr<IDiaSourceFile>> sources;
+
+    pSourceTable->Reset();
+    while (SUCCEEDED(hr = pSourceTable->Next(1, &src, &cnt)) && hr == S_OK && cnt == 1) {
+        CComBSTR currName;
+        IFR(src->get_fileName(&currName));
+        if (namecmp(name, currName) == 0) {
+            sources.emplace_back(src);
+        }
+        src.Release();
+    }
+
+    *ppResult = CreateOnMalloc<SourceFilesTable>(
+        GetMallocNoRef(),
+        this,
+        std::move(sources));
+
+    if (*ppResult == nullptr) {
+        return E_OUTOFMEMORY;
+    }
+    (*ppResult)->AddRef();
+    return S_OK;
+}
+
 namespace dxil_dia {
 static HRESULT DxcDiaFindLineNumbersByRVA(
   Session *pSession,
@@ -147,15 +229,16 @@ static HRESULT DxcDiaFindLineNumbersByRVA(
     return E_POINTER;
 
   std::vector<const llvm::Instruction*> instructions;
-  const std::vector<const llvm::Instruction*> &allInstructions = pSession->InstructionsRef();
+  auto &allInstructions = pSession->InstructionsRef();
 
   // Gather the list of insructions that map to the given rva range.
   for (DWORD i = rva; i < rva + length; ++i) {
-    if (i >= allInstructions.size())
+    auto It = allInstructions.find(i);
+    if (It == allInstructions.end())
       return E_INVALIDARG;
 
     // Only include the instruction if it has debug info for line mappings.
-    const llvm::Instruction *inst = allInstructions[i];
+    const llvm::Instruction *inst = It->second;
     if (inst->getDebugLoc())
       instructions.push_back(inst);
   }
@@ -187,6 +270,80 @@ STDMETHODIMP dxil_dia::Session::findLinesByRVA(
   return DxcDiaFindLineNumbersByRVA(this, rva, length, ppResult);
 }
 
+STDMETHODIMP dxil_dia::Session::findInlineeLinesByAddr(
+  /* [in] */ IDiaSymbol *parent,
+  /* [in] */ DWORD isect,
+  /* [in] */ DWORD offset,
+  /* [in] */ DWORD length,
+  /* [out] */ IDiaEnumLineNumbers **ppResult) {
+  DxcThreadMalloc TM(m_pMalloc);
+  return DxcDiaFindLineNumbersByRVA(this, offset, length, ppResult);
+}
+
+STDMETHODIMP dxil_dia::Session::findLinesByLinenum(
+  /* [in] */ IDiaSymbol *compiland,
+  /* [in] */ IDiaSourceFile *file,
+  /* [in] */ DWORD linenum,
+  /* [in] */ DWORD column,
+  /* [out] */ IDiaEnumLineNumbers **ppResult) {
+    if (!m_pEnumTables) {
+        return E_INVALIDARG;
+    }
+    *ppResult = nullptr;
+
+    DxcThreadMalloc TM(m_pMalloc);
+    CComPtr<IDiaTable> pTable;
+    VARIANT vtIndex;
+    vtIndex.vt = VT_UI4;
+    vtIndex.uintVal = (int)Table::Kind::LineNumbers;
+    IFR(m_pEnumTables->Item(vtIndex, &pTable));
+
+    CComPtr<IDiaEnumLineNumbers> pLineTable;
+    IFR(pTable->QueryInterface(&pLineTable));
+    HRESULT hr;
+    CComPtr<IDiaLineNumber> line;
+    ULONG cnt;
+    std::vector<const llvm::Instruction *> lines;
+
+    std::function<bool(DWORD, DWORD)>column_matches = [column](DWORD colStart, DWORD colEnd) -> bool {
+        return true;
+    };
+
+    if (column != 0) {
+        column_matches = [column](DWORD colStart, DWORD colEnd) -> bool {
+            return colStart < column && column < colEnd;
+        };
+    }
+
+    pLineTable->Reset();
+    while (SUCCEEDED(hr = pLineTable->Next(1, &line, &cnt)) && hr == S_OK && cnt == 1) {
+        CComPtr<IDiaSourceFile> f;
+        DWORD ln, lnEnd, cn, cnEnd;
+        IFR(line->get_lineNumber(&ln));
+        IFR(line->get_lineNumberEnd(&lnEnd));
+        IFR(line->get_columnNumber(&cn));
+        IFR(line->get_columnNumberEnd(&cnEnd));
+        IFR(line->get_sourceFile(&f));
+        
+        if (file == f && (ln <= linenum && linenum <= lnEnd) && column_matches(cn, cnEnd)) {
+            lines.emplace_back(reinterpret_cast<LineNumber*>(line.p)->Inst());
+        }
+        line.Release();
+    }
+
+    HRESULT result = lines.empty() ? S_FALSE : S_OK;
+    *ppResult = CreateOnMalloc<LineNumbersTable>(
+        GetMallocNoRef(),
+        this,
+        std::move(lines));
+
+    if (*ppResult == nullptr) {
+        return E_OUTOFMEMORY;
+    }
+    (*ppResult)->AddRef();
+    return result;
+}
+
 STDMETHODIMP dxil_dia::Session::findInjectedSource(
   /* [in] */ LPCOLESTR srcFile,
   /* [out] */ IDiaEnumInjectedSources **ppResult) {
@@ -203,3 +360,29 @@ STDMETHODIMP dxil_dia::Session::findInjectedSource(
   }
   return S_FALSE;
 }
+
+static constexpr DWORD kD3DCodeSection = 1;
+STDMETHODIMP dxil_dia::Session::findInlineFramesByAddr(
+  /* [in] */ IDiaSymbol *parent,
+  /* [in] */ DWORD isect,
+  /* [in] */ DWORD offset,
+  /* [out] */ IDiaEnumSymbols **ppResult) {
+  if (parent != nullptr || isect != kD3DCodeSection || ppResult == nullptr) {
+    return E_INVALIDARG;
+  }
+  *ppResult = nullptr;
+
+  DxcThreadMalloc TM(m_pMalloc);
+  auto &allInstructions = InstructionsRef();
+  auto It = allInstructions.find(offset);
+  if (It == allInstructions.end()) {
+    return E_INVALIDARG;
+  }
+
+  HRESULT hr;
+  SymbolChildrenEnumerator *ChildrenEnum;
+  IFR(hr = m_symsMgr.DbgScopeOf(It->second, &ChildrenEnum));
+
+  *ppResult = ChildrenEnum;
+  return hr;
+}

+ 34 - 16
lib/DxilDia/DxilDiaSession.h

@@ -13,6 +13,7 @@
 
 #include "dxc/Support/WinIncludes.h"
 
+#include <map>
 #include <memory>
 #include <unordered_map>
 #include <vector>
@@ -25,12 +26,25 @@
 #include "dxc/Support/microcom.h"
 
 #include "DxilDia.h"
+#include "DxilDiaSymbolManager.h"
 
 namespace dxil_dia {
-
 class Session : public IDiaSession {
 public:
   using RVA = unsigned;
+  using RVAMap = std::map<RVA, const llvm::Instruction *>;
+
+  struct LineInfo {
+    LineInfo(std::uint32_t start_col, RVA first, RVA last)
+      : StartCol(start_col),
+        First(first),
+        Last(last) {}
+
+    std::uint32_t StartCol = 0;
+    RVA First = 0;
+    RVA Last = 0;
+  };
+  using LineToInfoMap = std::unordered_map<std::uint32_t, LineInfo>;
 
   DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
   DXC_MICROCOM_TM_CTOR(Session)
@@ -48,9 +62,11 @@ public:
   hlsl::DxilModule &DxilModuleRef() { return *m_dxilModule.get(); }
   llvm::Module &ModuleRef() { return *m_module.get(); }
   llvm::DebugInfoFinder &InfoRef() { return *m_finder.get(); }
-  std::vector<const llvm::Instruction *> &InstructionsRef() { return m_instructions; }
-  std::vector<const llvm::Instruction *> &InstructionLinesRef() { return m_instructionLines; }
-  std::unordered_map<const llvm::Instruction *, RVA> &RvaMapRef() { return m_rvaMap; }
+  const SymbolManager &SymMgr() const { return m_symsMgr; }
+  const RVAMap &InstructionsRef() const { return m_instructions; }
+  const std::vector<const llvm::Instruction *> &InstructionLinesRef() const { return m_instructionLines; }
+  const std::unordered_map<const llvm::Instruction *, RVA> &RvaMapRef() const { return m_rvaMap; }
+  const LineToInfoMap &LineToColumnStartMapRef() const { return m_lineToInfoMap; }
 
   HRESULT getSourceFileIdByName(llvm::StringRef fileName, DWORD *pRetVal);
 
@@ -65,7 +81,7 @@ public:
     /* [in] */ ULONGLONG NewVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_globalScope(
-    /* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ IDiaSymbol **pRetVal) override;
 
   STDMETHODIMP getEnumTables(
     _COM_Outptr_ IDiaEnumTables **ppEnumTables) override;
@@ -75,21 +91,21 @@ public:
 
   STDMETHODIMP findChildren(
     /* [in] */ IDiaSymbol *parent,
-  /* [in] */ enum SymTagEnum symtag,
+    /* [in] */ enum SymTagEnum symtag,
     /* [in] */ LPCOLESTR name,
     /* [in] */ DWORD compareFlags,
     /* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
 
   STDMETHODIMP findChildrenEx(
     /* [in] */ IDiaSymbol *parent,
-  /* [in] */ enum SymTagEnum symtag,
+    /* [in] */ enum SymTagEnum symtag,
     /* [in] */ LPCOLESTR name,
     /* [in] */ DWORD compareFlags,
     /* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
 
   STDMETHODIMP findChildrenExByAddr(
     /* [in] */ IDiaSymbol *parent,
-  /* [in] */ enum SymTagEnum symtag,
+    /* [in] */ enum SymTagEnum symtag,
     /* [in] */ LPCOLESTR name,
     /* [in] */ DWORD compareFlags,
     /* [in] */ DWORD isect,
@@ -98,7 +114,7 @@ public:
 
   STDMETHODIMP findChildrenExByVA(
     /* [in] */ IDiaSymbol *parent,
-  /* [in] */ enum SymTagEnum symtag,
+    /* [in] */ enum SymTagEnum symtag,
     /* [in] */ LPCOLESTR name,
     /* [in] */ DWORD compareFlags,
     /* [in] */ ULONGLONG va,
@@ -106,7 +122,7 @@ public:
 
   STDMETHODIMP findChildrenExByRVA(
     /* [in] */ IDiaSymbol *parent,
-  /* [in] */ enum SymTagEnum symtag,
+    /* [in] */ enum SymTagEnum symtag,
     /* [in] */ LPCOLESTR name,
     /* [in] */ DWORD compareFlags,
     /* [in] */ DWORD rva,
@@ -115,7 +131,7 @@ public:
   STDMETHODIMP findSymbolByAddr(
     /* [in] */ DWORD isect,
     /* [in] */ DWORD offset,
-  /* [in] */ enum SymTagEnum symtag,
+    /* [in] */ enum SymTagEnum symtag,
     /* [out] */ IDiaSymbol **ppSymbol) override { return ENotImpl(); }
 
   STDMETHODIMP findSymbolByRVA(
@@ -157,7 +173,7 @@ public:
     /* [in] */ IDiaSymbol *pCompiland,
     /* [in] */ LPCOLESTR name,
     /* [in] */ DWORD compareFlags,
-    /* [out] */ IDiaEnumSourceFiles **ppResult) override { return ENotImpl(); }
+    /* [out] */ IDiaEnumSourceFiles **ppResult) override;
 
   STDMETHODIMP findFileById(
     /* [in] */ DWORD uniqueId,
@@ -189,7 +205,7 @@ public:
     /* [in] */ IDiaSourceFile *file,
     /* [in] */ DWORD linenum,
     /* [in] */ DWORD column,
-    /* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
+    /* [out] */ IDiaEnumLineNumbers **ppResult) override;
 
   STDMETHODIMP findInjectedSource(
       /* [in] */ LPCOLESTR srcFile,
@@ -202,7 +218,7 @@ public:
     /* [in] */ IDiaSymbol *parent,
     /* [in] */ DWORD isect,
     /* [in] */ DWORD offset,
-    /* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
+    /* [out] */ IDiaEnumSymbols **ppResult) override;
 
   STDMETHODIMP findInlineFramesByRVA(
     /* [in] */ IDiaSymbol *parent,
@@ -223,7 +239,7 @@ public:
     /* [in] */ DWORD isect,
     /* [in] */ DWORD offset,
     /* [in] */ DWORD length,
-    /* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
+    /* [out] */ IDiaEnumLineNumbers **ppResult) override;
 
   STDMETHODIMP findInlineeLinesByRVA(
     /* [in] */ IDiaSymbol *parent,
@@ -369,9 +385,11 @@ private:
   llvm::NamedMDNode *m_defines;
   llvm::NamedMDNode *m_mainFileName;
   llvm::NamedMDNode *m_arguments;
-  std::vector<const llvm::Instruction *> m_instructions;
+  RVAMap m_instructions;
   std::vector<const llvm::Instruction *> m_instructionLines; // Instructions with line info.
   std::unordered_map<const llvm::Instruction *, RVA> m_rvaMap; // Map instruction to its RVA.
+  LineToInfoMap m_lineToInfoMap;
+  SymbolManager m_symsMgr;
 
 private:
   CComPtr<IDiaEnumTables> m_pEnumTables;

+ 1987 - 0
lib/DxilDia/DxilDiaSymbolManager.cpp

@@ -0,0 +1,1987 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilDiaSymbolsManager.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.                                     //
+//                                                                           //
+// DIA API implementation for DXIL modules.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+#include "DxilDiaSymbolManager.h"
+
+#include <cctype>
+#include <type_traits>
+
+#include <comdef.h>
+
+#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
+#include "dxc/Support/Unicode.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "DxilDiaSession.h"
+#include "DxilDiaTableSymbols.h"
+
+static constexpr std::uint32_t kNullSymbolID = 0;
+
+namespace dxil_dia {
+namespace hlsl_symbols {
+
+// HLSL Symbol Hierarchy
+// ---- ------ ---------
+// 
+//                                  +---------------+
+//                                  | Program (EXE) |                                   Global Scope
+//                                  +------+--------+
+//                                         |
+//                                +--------^-----------+
+//                                | Compiland (Shader) |                                Compilation Unit
+//                                +--------+-----------+
+//                                         |
+//      +------------+------------+--------+-------+------------+--------------+
+//      |            |            |        |       |            |              |        
+// +----^----+   +---^---+   +----^---+    |   +---^---+   +----^----+   +-----^-----+
+// | Details |   | Flags |   | Target |    |   | Entry |   | Defines |   | Arguments |  Synthetic Symbols
+// +---------+   +-------+   +--------+    |   +-------+   +---------+   +-----------+
+//                                         |
+//                                         |
+//       +---------------+------------+----+-----+-------------+-----------+
+//       |               |            |          |             |           | 
+// +-----^-----+   +-----^-----+   +--^--+   +---^--+      +---^--+     +--^--+
+// | Function0 |   | Function1 |   | ... |   | UDT0 |      | UDT1 |     | ... |         Source Symbols
+// +-----+-----+   +-----+-----+   +-----+   +---+--+      +---+--+     +-----+
+//       |               |                       |             |
+//  +----^----+     +----^----+             +----^----+   +----^----+
+//  | Locals0 |     | Locals1 |             | Fields0 |   | Fields1 |
+//  +---------+     +---------+             +---------+   +---------+
+
+static const std::string & DxilEntryName(Session *pSession);
+
+template <typename S, typename... C, typename = typename std::enable_if<!std::is_same<Symbol, S>::value>::type>
+HRESULT AllocAndInit(
+  IMalloc *pMalloc,
+  Session *pSession,
+  DWORD dwIndex,
+  DWORD dwSymTag,
+  S **ppSymbol,
+  C... ctorArgs) {
+  *ppSymbol = S::Alloc(pMalloc, ctorArgs...);
+  if (*ppSymbol == nullptr) {
+    return E_OUTOFMEMORY;
+  }
+  (*ppSymbol)->AddRef();
+  (*ppSymbol)->Init(pSession, dwIndex, dwSymTag);
+  return S_OK;
+}
+
+template <typename T, typename R>
+T *dyn_cast_to_ditype(R ref) {
+  return llvm::dyn_cast<T>((llvm::Metadata *) ref);
+}
+
+template <typename T, typename R>
+T *dyn_cast_to_ditype_or_null(R ref) {
+  return llvm::dyn_cast_or_null<T>((llvm::Metadata *) ref);
+}
+
+template <typename N>
+struct DISymbol : public Symbol {
+  DISymbol(IMalloc *M, N Node) : Symbol(M), m_pNode(Node) {}
+
+  N m_pNode;
+};
+
+template <typename N>
+struct TypedSymbol : public DISymbol<N> {
+  TypedSymbol(IMalloc *M, N Node, DWORD dwTypeID, llvm::DIType *Type) : DISymbol(M, Node), m_dwTypeID(dwTypeID), m_pType(Type) {}
+
+  STDMETHODIMP get_type(
+    /* [retval][out] */ IDiaSymbol **ppRetVal) override {
+    if (ppRetVal == nullptr) {
+      return E_INVALIDARG;
+    }
+    *ppRetVal = false;
+
+    if (m_pType == nullptr) {
+      return S_FALSE;
+    }
+
+    Symbol *ret;
+    IFR(m_pSession->SymMgr().GetSymbolByID(m_dwTypeID, &ret));
+
+    *ppRetVal = ret;
+    return S_OK;
+  }
+
+  const DWORD m_dwTypeID;
+  llvm::DIType *m_pType;
+};
+
+struct GlobalScopeSymbol : public Symbol {
+  DXC_MICROCOM_TM_ALLOC(GlobalScopeSymbol)
+  explicit GlobalScopeSymbol(IMalloc *M) : Symbol(M) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, Symbol **ppSym);
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+};
+
+struct CompilandSymbol : public DISymbol<llvm::DICompileUnit *> {
+  DXC_MICROCOM_TM_ALLOC(CompilandSymbol)
+  explicit CompilandSymbol(IMalloc *M, llvm::DICompileUnit *CU) : DISymbol<llvm::DICompileUnit *>(M, CU) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, llvm::DICompileUnit *CU, Symbol **ppSym);
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+};
+
+struct CompilandDetailsSymbol : public Symbol {
+  DXC_MICROCOM_TM_ALLOC(CompilandDetailsSymbol)
+  explicit CompilandDetailsSymbol(IMalloc *M) : Symbol(M) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, Symbol **ppSym);
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+
+#pragma region IDiaSymbol implementation
+// DEFINE_SIMPLE_GETTER is used to generate the boilerplate needed for the
+// property getters needed by this symbol. name is the property name (as
+// defined in IDiaSymbol::get_<name>. There should be a static (non-const OK)
+// function defined in this class as
+//
+//    <RetTy> <name>(CompilandDetailsSymbol * <this>)
+//
+// <RetTy> **must** match the property type in IDiaSymbol::get_<name>'s
+// parameter; <this> is literally the this pointer. The function needs to
+// be static (thus requiring the explicit <this> parameter) so that
+// DEFINE_SIMPLE_GETTER can use decltype(name(nullptr)) in order to
+// define the property parameter type.
+#define DEFINE_SIMPLE_GETTER(name)                                        \
+    STDMETHODIMP get_ ## name(decltype(name(nullptr)) *pValue) override { \
+      if (pValue == nullptr) {                                            \
+        return E_INVALIDARG;                                              \
+      }                                                                   \
+      *pValue = name(this);                                               \
+      return S_OK;                                                        \
+    }
+
+  static constexpr DWORD platform(CompilandDetailsSymbol *) { return 256; }
+  static constexpr DWORD language(CompilandDetailsSymbol *) { return 16; }
+  static constexpr BOOL hasDebugInfo(CompilandDetailsSymbol *) { return true; }
+  static BSTR compilerName(CompilandDetailsSymbol *) {
+    CComBSTR retval;
+    retval.Append("dxcompiler");
+    return retval.Detach();
+  }
+  static DWORD frontEndMajor(CompilandDetailsSymbol *self) {
+    return self->m_pSession->DxilModuleRef().GetShaderModel()->GetMajor();
+  }
+  static DWORD frontEndMinor(CompilandDetailsSymbol *self) {
+    return self->m_pSession->DxilModuleRef().GetShaderModel()->GetMinor();
+  }
+
+  DEFINE_SIMPLE_GETTER(platform);
+  DEFINE_SIMPLE_GETTER(language);
+  DEFINE_SIMPLE_GETTER(frontEndMajor);
+  DEFINE_SIMPLE_GETTER(frontEndMinor);
+  DEFINE_SIMPLE_GETTER(hasDebugInfo);
+  DEFINE_SIMPLE_GETTER(compilerName);
+#undef DEFINE_SIMPLE_GETTER
+#pragma endregion
+};
+
+struct CompilandEnvSymbol : public Symbol {
+  DXC_MICROCOM_TM_ALLOC(CompilandEnvSymbol)
+  explicit CompilandEnvSymbol(IMalloc *M) : Symbol(M) {}
+  static HRESULT CreateFlags(IMalloc *pMalloc, Session *pSession, Symbol **ppSym);
+  static HRESULT CreateTarget(IMalloc *pMalloc, Session *pSession, Symbol **ppSym);
+  static HRESULT CreateEntry(IMalloc *pMalloc, Session *pSession, Symbol **ppSym);
+  static HRESULT CreateDefines(IMalloc *pMalloc, Session *pSession, Symbol **pSym);
+  static HRESULT CreateArguments(IMalloc *pMalloc, Session *pSession, Symbol **ppSym);
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+};
+
+struct FunctionSymbol : public TypedSymbol<llvm::DISubprogram *> {
+  DXC_MICROCOM_TM_ALLOC(FunctionSymbol)
+  FunctionSymbol(IMalloc *M, llvm::DISubprogram *Node, DWORD dwTypeID, llvm::DIType *Type) : TypedSymbol<llvm::DISubprogram *>(M, Node, dwTypeID, Type) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, llvm::DISubprogram *Node, DWORD dwTypeID, llvm::DIType *Type, Symbol **ppSym);
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+};
+
+struct FunctionBlockSymbol : public Symbol {
+  DXC_MICROCOM_TM_ALLOC(FunctionBlockSymbol)
+  explicit FunctionBlockSymbol(IMalloc *M) : Symbol(M) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, Symbol **ppSym);
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+};
+
+struct TypeSymbol : public DISymbol<llvm::DIType *> {
+  using LazySymbolName = std::function<HRESULT(Session *, std::string *)>;
+  DXC_MICROCOM_TM_ALLOC(TypeSymbol)
+  TypeSymbol(IMalloc *M, llvm::DIType *Node, LazySymbolName LazySymbolName) : DISymbol<llvm::DIType *>(M, Node), m_lazySymbolName(LazySymbolName) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwParentID, DWORD dwID, DWORD st, llvm::DIType *Node, LazySymbolName LazySymbolName, Symbol **ppSym);
+  STDMETHODIMP get_name(
+    /* [retval][out] */ BSTR *pRetVal) override;
+  STDMETHODIMP get_baseType(
+    /* [retval][out] */ DWORD *pRetVal) override;
+  STDMETHODIMP get_length(
+    /* [retval][out] */ ULONGLONG *pRetVal) override;
+
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+
+  LazySymbolName m_lazySymbolName;
+};
+
+struct TypedefTypeSymbol : public TypeSymbol {
+  DXC_MICROCOM_TM_ALLOC(TypedefTypeSymbol)
+  TypedefTypeSymbol(IMalloc *M, llvm::DIType *Node, DWORD dwBaseTypeID) : TypeSymbol(M, Node, nullptr), m_dwBaseTypeID(dwBaseTypeID) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwParentID, DWORD dwID,llvm::DIType *Node, DWORD dwBaseTypeID, Symbol **ppSym);
+
+  STDMETHODIMP get_type(
+    /* [retval][out] */ IDiaSymbol **ppRetVal) override;
+
+  const DWORD m_dwBaseTypeID;
+};
+
+struct VectorTypeSymbol : public TypeSymbol {
+  DXC_MICROCOM_TM_ALLOC(VectorTypeSymbol)
+  VectorTypeSymbol(IMalloc *M, llvm::DIType *Node, DWORD dwElemTyID, std::uint32_t NumElts) : TypeSymbol(M, Node, nullptr), m_ElemTyID(dwElemTyID), m_NumElts(NumElts) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwParentID, DWORD dwID,llvm::DIType *Node, DWORD dwElemTyID, std::uint32_t NumElts, Symbol **ppSym);
+
+  STDMETHODIMP get_count(
+    /* [retval][out] */ DWORD *pRetVal) override;
+  STDMETHODIMP get_type(
+    /* [retval][out] */ IDiaSymbol **ppRetVal) override;
+
+  std::uint32_t m_ElemTyID;
+  std::uint32_t m_NumElts;
+};
+
+struct UDTSymbol : public TypeSymbol {
+  DXC_MICROCOM_TM_ALLOC(UDTSymbol)
+  UDTSymbol(IMalloc *M, llvm::DICompositeType *Node, LazySymbolName LazyName) : TypeSymbol(M, Node, LazyName) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwParentID, DWORD dwID, llvm::DICompositeType *Node, LazySymbolName LazySymbolName, Symbol **ppSym);
+};
+
+struct GlobalVariableSymbol : public TypedSymbol<llvm::DIGlobalVariable *> {
+  DXC_MICROCOM_TM_ALLOC(GlobalVariableSymbol)
+  GlobalVariableSymbol(IMalloc *M, llvm::DIGlobalVariable *GV, DWORD dwTypeID, llvm::DIType *Type) : TypedSymbol<llvm::DIGlobalVariable *>(M, GV, dwTypeID, Type) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, llvm::DIGlobalVariable *GV, DWORD dwTypeID, llvm::DIType *Type, Symbol **ppSym);
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+};
+
+struct LocalVariableSymbol : public TypedSymbol<llvm::DIVariable *> {
+  DXC_MICROCOM_TM_ALLOC(LocalVariableSymbol)
+  LocalVariableSymbol(IMalloc *M, llvm::DIVariable *Node, DWORD dwTypeID, llvm::DIType *Type, DWORD dwOffsetInUDT, DWORD dwDxilRegNum) : TypedSymbol<llvm::DIVariable *>(M, Node, dwTypeID, Type), m_dwOffsetInUDT(dwOffsetInUDT), m_dwDxilRegNum(dwDxilRegNum) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, llvm::DIVariable *Node, DWORD dwTypeID, llvm::DIType *Type, DWORD dwOffsetInUDT, DWORD m_dwDxilRegNum, Symbol **ppSym);
+  STDMETHODIMP get_locationType(
+    /* [retval][out] */ DWORD *pRetVal) override;
+  STDMETHODIMP get_isAggregated(
+    /* [retval][out] */ BOOL *pRetVal) override;
+  STDMETHODIMP get_registerType(
+    /* [retval][out] */ DWORD *pRetVal) override;
+  STDMETHODIMP get_offsetInUdt(
+    /* [retval][out] */ DWORD *pRetVal) override;
+  STDMETHODIMP get_sizeInUdt(
+    /* [retval][out] */ DWORD *pRetVal) override;
+  STDMETHODIMP get_numberOfRegisterIndices(
+    /* [retval][out] */ DWORD *pRetVal) override;
+  STDMETHODIMP get_numericProperties(
+    /* [in] */ DWORD cnt,
+    /* [out] */ DWORD *pcnt,
+    /* [size_is][out] */ DWORD *pProperties) override;
+
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+
+  const DWORD m_dwOffsetInUDT;
+  const DWORD m_dwDxilRegNum;
+};
+
+struct UDTFieldSymbol : public TypedSymbol<llvm::DIDerivedType *> {
+  DXC_MICROCOM_TM_ALLOC(UDTFieldSymbol)
+  UDTFieldSymbol(IMalloc *M, llvm::DIDerivedType *Node, DWORD dwTypeID, llvm::DIType *Type) : TypedSymbol<llvm::DIDerivedType *>(M, Node, dwTypeID, Type) {}
+  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, llvm::DIDerivedType *Node, DWORD dwTypeID, llvm::DIType *Type, Symbol **ppSym);
+  STDMETHODIMP get_offset(
+    /* [retval][out] */ LONG *pRetVal) override;
+
+  HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) override;
+};
+
+class SymbolManagerInit {
+public:
+  using SymbolCtor = std::function<HRESULT(Session *pSession, DWORD ID, Symbol **ppSym)>;
+
+  using LazySymbolName = TypeSymbol::LazySymbolName;
+
+  class TypeInfo {
+  public:
+    TypeInfo() = delete;
+    TypeInfo(const TypeInfo &) = delete;
+    TypeInfo(TypeInfo &&) = default;
+
+    explicit TypeInfo(DWORD dwTypeID) : m_dwTypeID(dwTypeID) {}
+
+    DWORD GetTypeID() const { return m_dwTypeID; }
+    DWORD GetCurrentSizeInBytes() const { return m_dwCurrentSizeInBytes; }
+    const std::vector<llvm::DIType *> &GetLayout() const { return m_Layout; }
+
+    void Embed(const TypeInfo &TI);
+
+    void AddBasicType(llvm::DIBasicType *BT);
+
+  private:
+    DWORD m_dwTypeID;
+    std::vector<llvm::DIType *> m_Layout;
+    DWORD m_dwCurrentSizeInBytes = 0;
+  };
+  using TypeToInfoMap = llvm::DenseMap<llvm::DIType *, TypeInfo>;
+
+  class VarInfo {
+  public:
+    VarInfo() = default;
+    VarInfo(const VarInfo &) = delete;
+    VarInfo(VarInfo &&) = default;
+
+    DWORD GetVarID() const { return m_dwVarID; }
+    DWORD GetOffsetInUDT() const { return m_dwOffsetInUDT; }
+    DWORD GetDxilRegister() const { return m_dwDxilRegister; }
+
+    void SetVarID(DWORD dwVarID) { m_dwVarID = dwVarID; }
+    void SetOffsetInUDT(DWORD dwOffsetInUDT) { m_dwOffsetInUDT = dwOffsetInUDT; }
+    void SetDxilRegister(DWORD dwDxilReg) { m_dwDxilRegister = dwDxilReg; }
+
+  private:
+    DWORD m_dwVarID = 0;
+    DWORD m_dwOffsetInUDT = 0;
+    DWORD m_dwDxilRegister = 0;
+  };
+
+  // Because of the way the VarToID map is constructed, the vector<VarInfo>
+  // may need to grow. The Symbol Constructor for local variable captures
+  // the VarInfo for the local variable it creates, and it needs access to
+  // the information on this map (thus a by-value capture is not enough).
+  // We heap-allocate the VarInfos, and the local variables symbol
+  // constructors capture the pointer - meaning everything should be fine
+  // even if the vector is moved around.
+  using LocalVarToIDMap = llvm::DenseMap<llvm::DILocalVariable *, std::vector<std::shared_ptr<VarInfo>>>;
+
+  using UDTFieldToIDMap = llvm::DenseMap<llvm::DIDerivedType *, DWORD>;
+
+  SymbolManagerInit(
+    Session *pSession,
+    std::vector<SymbolManager::CreateSymbolFn> *pSymCtors,
+    SymbolManager::ScopeToIDMap *pScopeToSym,
+    SymbolManager::IDToLiveRangeMap *pSymToLR);
+
+  HRESULT AddSymbol(DWORD dwParentID, DWORD *pNewSymID, SymbolCtor symCtor);
+  HRESULT CreateFunctionsForAllCUs();
+  HRESULT CreateGlobalVariablesForAllCUs();
+  HRESULT CreateLocalVariables();
+  HRESULT CreateLiveRanges();
+  HRESULT IsDbgDeclareCall(llvm::Module *M, const llvm::Instruction *I, DWORD *pReg, DWORD *pRegSize, llvm::DILocalVariable **LV, uint64_t *pStartOffset, uint64_t *pEndOffset);
+  HRESULT GetDxilAllocaRegister(llvm::Instruction *I, DWORD *pRegNum, DWORD *pRegSize);
+  HRESULT PopulateParentToChildrenIDMap(SymbolManager::ParentToChildrenMap *pParentToChildren);
+
+private:
+  HRESULT GetTypeInfo(llvm::DIType *T, TypeInfo **TI);
+  HRESULT AddType(DWORD dwParentID, llvm::DIType *T, DWORD *pNewSymID, SymbolCtor symCtor);
+  HRESULT AddParent(DWORD dwParentIndex);
+  HRESULT CreateFunctionBlockForLocalScope(llvm::DILocalScope *LS, DWORD *pNewSymID);
+  HRESULT CreateFunctionBlockForInstruction(llvm::Instruction *I);
+  HRESULT CreateFunctionBlocksForFunction(llvm::Function *F);
+  HRESULT CreateFunctionsForCU(llvm::DICompileUnit *CU);
+  HRESULT CreateGlobalVariablesForCU(llvm::DICompileUnit *CU);
+  HRESULT GetScopeID(llvm::DIScope *S, DWORD *pScopeID);
+  HRESULT CreateType(llvm::DIType *T, DWORD *pNewTypeID);
+  HRESULT CreateSubroutineType(DWORD dwParentID, llvm::DISubroutineType *ST, DWORD *pNewTypeID);
+  HRESULT CreateBasicType(DWORD dwParentID, llvm::DIBasicType *VT, DWORD *pNewTypeID);
+  HRESULT CreateCompositeType(DWORD dwParentID, llvm::DICompositeType *CT, DWORD *pNewTypeID);
+  HRESULT CreateHLSLType(llvm::DICompositeType *T, DWORD *pNewTypeID);
+  HRESULT IsHLSLVectorType(llvm::DICompositeType *T, DWORD *pEltTyID, std::uint32_t *pElemCnt);
+  HRESULT CreateHLSLVectorType(llvm::DICompositeType *T, DWORD pEltTyID, std::uint32_t pElemCnt, DWORD *pNewTypeID);
+  HRESULT HandleDerivedType(DWORD dwParentID, llvm::DIDerivedType *DT, DWORD *pNewTypeID);
+  HRESULT CreateLocalVariable(DWORD dwParentID, llvm::DILocalVariable *LV);
+  HRESULT GetTypeLayout(llvm::DIType *Ty, std::vector<DWORD> *pRet);
+  HRESULT CreateUDTField(DWORD dwParentID, llvm::DIDerivedType *Field);
+
+  Session &m_Session;
+  std::vector<SymbolManager::CreateSymbolFn> &m_SymCtors;
+  SymbolManager::ScopeToIDMap &m_ScopeToSym;
+  SymbolManager::IDToLiveRangeMap &m_SymToLR;
+
+  // vector of parents, i.e., for each i in parents[i], parents[i] is the
+  // parent of m_symbol[i].
+  std::vector<std::uint32_t> m_Parent;
+
+  LocalVarToIDMap m_VarToID;
+
+  UDTFieldToIDMap m_FieldToID;
+
+  TypeToInfoMap m_TypeToInfo;
+
+  TypeInfo &CurrentUDTInfo() { return *m_pCurUDT; }
+  TypeInfo *m_pCurUDT = nullptr;
+
+  struct UDTScope {
+    UDTScope() = delete;
+    UDTScope(const UDTScope &) = delete;
+    UDTScope(UDTScope &&) = default;
+
+    UDTScope(TypeInfo **pCur, TypeInfo *pNext) : m_pCur(pCur), m_pPrev(*pCur) {
+      *pCur = pNext;
+    }
+    ~UDTScope() { *m_pCur = m_pPrev; }
+
+    TypeInfo **m_pCur;
+    TypeInfo *m_pPrev;
+  };
+
+  UDTScope BeginUDTScope(TypeInfo *pNext) {
+    return UDTScope(&m_pCurUDT, pNext);
+  }
+
+};
+
+}  // namespace hlsl_symbols
+}  // namespace dxil_dia
+
+STDMETHODIMP dxil_dia::hlsl_symbols::TypeSymbol::get_baseType(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = btNoType;
+
+  if (auto *BT = llvm::dyn_cast<llvm::DIBasicType>(m_pNode)) {
+    const DWORD SizeInBits = BT->getSizeInBits();
+    switch (BT->getEncoding()) {
+    case llvm::dwarf::DW_ATE_boolean:
+      *pRetVal = btBool; break;
+    case llvm::dwarf::DW_ATE_unsigned:
+      *pRetVal = btUInt; break;
+    case llvm::dwarf::DW_ATE_signed:
+      *pRetVal = btInt; break;
+    case llvm::dwarf::DW_ATE_float:
+      *pRetVal = btFloat; break;
+    }
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::TypeSymbol::get_length(
+  /* [retval][out] */ ULONGLONG *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = 0;
+
+  if (auto *BT = llvm::dyn_cast<llvm::DIBasicType>(m_pNode)) {
+    static constexpr DWORD kNumBitsPerByte = 8;
+    const DWORD SizeInBits = BT->getSizeInBits();
+    *pRetVal = SizeInBits / kNumBitsPerByte;
+  }
+
+  return S_OK;
+}
+
+static const std::string &dxil_dia::hlsl_symbols::DxilEntryName(Session *pSession) {
+  return pSession->DxilModuleRef().GetEntryFunctionName();
+}
+
+HRESULT dxil_dia::hlsl_symbols::GlobalScopeSymbol::Create(IMalloc *pMalloc, Session *pSession, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, HlslProgramId, SymTagExe, (GlobalScopeSymbol**)ppSym));
+  (*ppSym)->SetName(L"HLSL");
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::GlobalScopeSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  return m_pSession->SymMgr().ChildrenOf(this, children);
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandSymbol::Create(IMalloc *pMalloc, Session *pSession, llvm::DICompileUnit *CU, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, HlslCompilandId, SymTagCompiland, (CompilandSymbol**)ppSym, CU));
+  (*ppSym)->SetName(L"main");
+  if (pSession->MainFileName()) {
+    llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(pSession->MainFileName()->getOperand(0)->getOperand(0))->getString();
+    std::string str(strRef.begin(), strRef.size()); // To make sure str is null terminated
+    (*ppSym)->SetSourceFileName(_bstr_t(Unicode::UTF8ToUTF16StringOrThrow(str.data()).c_str()));
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  return m_pSession->SymMgr().ChildrenOf(this, children);
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandDetailsSymbol::Create(IMalloc *pMalloc, Session *pSession, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, HlslCompilandDetailsId, SymTagCompilandDetails, (CompilandDetailsSymbol**)ppSym));
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandDetailsSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  children->clear();
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandEnvSymbol::CreateFlags(IMalloc *pMalloc, Session *pSession, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, HlslCompilandEnvFlagsId, SymTagCompilandEnv, (CompilandEnvSymbol**)ppSym));
+  (*ppSym)->SetName(L"hlslFlags");
+  (*ppSym)->SetValue(pSession->DxilModuleRef().GetGlobalFlags());
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandEnvSymbol::CreateTarget(IMalloc *pMalloc, Session *pSession, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, HlslCompilandEnvTargetId, SymTagCompilandEnv, (CompilandEnvSymbol**)ppSym));
+  (*ppSym)->SetName(L"hlslTarget");
+  (*ppSym)->SetValue(pSession->DxilModuleRef().GetShaderModel()->GetName());
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandEnvSymbol::CreateEntry(IMalloc *pMalloc, Session *pSession, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, HlslCompilandEnvEntryId, SymTagCompilandEnv, (CompilandEnvSymbol**)ppSym));
+  (*ppSym)->SetName(L"hlslEntry");
+  (*ppSym)->SetValue(DxilEntryName(pSession).c_str());
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandEnvSymbol::CreateDefines(IMalloc *pMalloc, Session *pSession, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, HlslCompilandEnvDefinesId, SymTagCompilandEnv, (CompilandEnvSymbol**)ppSym));
+  (*ppSym)->SetName(L"hlslDefines");
+  llvm::MDNode *definesNode = pSession->Defines()->getOperand(0);
+  // Construct a double null terminated string for defines with L"\0" as a delimiter
+  CComBSTR pBSTR;
+  for (llvm::MDNode::op_iterator it = definesNode->op_begin(); it != definesNode->op_end(); ++it) {
+    llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(*it)->getString();
+    std::string str(strRef.begin(), strRef.size());
+    CA2W cv(str.c_str());
+    pBSTR.Append(cv);
+    pBSTR.Append(L"\0", 1);
+  }
+  pBSTR.Append(L"\0", 1);
+  VARIANT Variant;
+  Variant.bstrVal = pBSTR;
+  Variant.vt = VARENUM::VT_BSTR;
+  (*ppSym)->SetValue(&Variant);
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandEnvSymbol::CreateArguments(IMalloc *pMalloc, Session *pSession, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, HlslCompilandEnvArgumentsId, SymTagCompilandEnv, (CompilandEnvSymbol**)ppSym));
+  (*ppSym)->SetName(L"hlslArguments");
+  auto Arguments = pSession->Arguments()->getOperand(0);
+  auto NumArguments = Arguments->getNumOperands();
+  std::string args;
+  for (unsigned i = 0; i < NumArguments; ++i) {
+    llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(Arguments->getOperand(i))->getString();
+    if (!args.empty())
+      args.push_back(' ');
+    args = args + strRef.str();
+  }
+  (*ppSym)->SetValue(args.c_str());
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::CompilandEnvSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  children->clear();
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::FunctionSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, llvm::DISubprogram *Node, DWORD dwTypeID, llvm::DIType *Type, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, SymTagFunction, (FunctionSymbol**)ppSym, Node, dwTypeID, Type));
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::FunctionSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  return m_pSession->SymMgr().ChildrenOf(this, children);
+}
+
+HRESULT dxil_dia::hlsl_symbols::FunctionBlockSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, SymTagBlock, (FunctionBlockSymbol**)ppSym));
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::FunctionBlockSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  return m_pSession->SymMgr().ChildrenOf(this, children);
+}
+
+HRESULT dxil_dia::hlsl_symbols::TypeSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwParentID, DWORD dwID, DWORD st, llvm::DIType *Node, LazySymbolName LazySymbolName, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, st, (TypeSymbol**)ppSym, Node, LazySymbolName));
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::TypeSymbol::get_name(
+  /* [retval][out] */ BSTR *pRetVal) {
+  DxcThreadMalloc TM(m_pSession->GetMallocNoRef());
+  if (m_lazySymbolName != nullptr) {
+    DXASSERT(!this->HasName(), "Setting type name multiple times.");
+    std::string Name;
+    IFR(m_lazySymbolName(m_pSession, &Name));
+    this->SetName(CA2W(Name.c_str()));
+    m_lazySymbolName = nullptr;
+  }
+  return Symbol::get_name(pRetVal);
+}
+
+HRESULT dxil_dia::hlsl_symbols::TypeSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  return m_pSession->SymMgr().ChildrenOf(this, children);
+}
+
+HRESULT dxil_dia::hlsl_symbols::VectorTypeSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwParentID, DWORD dwID, llvm::DIType *Node, DWORD dwElemTyID, std::uint32_t NumElts, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, SymTagVectorType, (VectorTypeSymbol**)ppSym, Node, dwElemTyID, NumElts));
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::VectorTypeSymbol::get_count(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = m_NumElts;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::VectorTypeSymbol::get_type(
+  /* [retval][out] */ IDiaSymbol **ppRetVal) {
+  if (ppRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *ppRetVal = false;
+
+  Symbol *ret;
+  IFR(m_pSession->SymMgr().GetSymbolByID(m_ElemTyID, &ret));
+
+  *ppRetVal = ret;
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::UDTSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwParentID, DWORD dwID, llvm::DICompositeType *Node, LazySymbolName LazySymbolName, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, SymTagUDT, (UDTSymbol**)ppSym, Node, LazySymbolName));
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::TypedefTypeSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwParentID, DWORD dwID, llvm::DIType *Node, DWORD dwBaseTypeID, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, SymTagTypedef, (TypedefTypeSymbol**)ppSym, Node, dwBaseTypeID));
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::TypedefTypeSymbol::get_type(
+  /* [retval][out] */ IDiaSymbol **ppRetVal) {
+  if (ppRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *ppRetVal = nullptr;
+
+  Symbol *ret = nullptr;
+  IFR(m_pSession->SymMgr().GetSymbolByID(m_dwBaseTypeID, &ret));
+  *ppRetVal = ret;
+
+  return S_FALSE;
+}
+
+HRESULT dxil_dia::hlsl_symbols::GlobalVariableSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, llvm::DIGlobalVariable *GV, DWORD dwTypeID, llvm::DIType *Type, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, SymTagData, (GlobalVariableSymbol**)ppSym, GV, dwTypeID, Type));
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::GlobalVariableSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  children->clear();
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::LocalVariableSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, llvm::DIVariable *Node, DWORD dwTypeID, llvm::DIType *Type, DWORD dwOffsetInUDT, DWORD dwDxilRegNum, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, SymTagData, (LocalVariableSymbol**)ppSym, Node, dwTypeID, Type, dwOffsetInUDT, dwDxilRegNum));
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::LocalVariableSymbol::get_locationType(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = LocIsEnregistered;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::LocalVariableSymbol::get_isAggregated(
+  /* [retval][out] */ BOOL *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = m_pType->getTag() == llvm::dwarf::DW_TAG_member;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::LocalVariableSymbol::get_registerType(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  static constexpr DWORD kPixTraceVirtualRegister = 0xfe;
+  *pRetVal = kPixTraceVirtualRegister;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::LocalVariableSymbol::get_offsetInUdt(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = m_dwOffsetInUDT;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::LocalVariableSymbol::get_sizeInUdt(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  static constexpr DWORD kBitsPerByte = 8;
+  //auto *DT = llvm::cast<llvm::DIDerivedType>(m_pType);
+  *pRetVal = 4; //DT->getSizeInBits() / kBitsPerByte;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::LocalVariableSymbol::get_numberOfRegisterIndices(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = 1;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::LocalVariableSymbol::get_numericProperties(
+  /* [in] */ DWORD cnt,
+  /* [out] */ DWORD *pcnt,
+  /* [size_is][out] */ DWORD *pProperties) {
+  if (pcnt == nullptr || pProperties == nullptr || cnt != 1) {
+    return E_INVALIDARG;
+  }
+
+  pProperties[0] = m_dwDxilRegNum;
+  *pcnt = 1;
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::LocalVariableSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  children->clear();
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::UDTFieldSymbol::Create(IMalloc *pMalloc, Session *pSession, DWORD dwID, llvm::DIDerivedType *Node, DWORD dwTypeID, llvm::DIType *Type, Symbol **ppSym) {
+  IFR(AllocAndInit(pMalloc, pSession, dwID, SymTagData, (UDTFieldSymbol**)ppSym, Node, dwTypeID, Type));
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::hlsl_symbols::UDTFieldSymbol::get_offset(
+  /* [retval][out] */ LONG *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  static constexpr DWORD kBitsPerByte = 8;
+  *pRetVal = m_pNode->getOffsetInBits() / kBitsPerByte;
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::UDTFieldSymbol::GetChildren(std::vector<CComPtr<Symbol>> *children) {
+  children->clear();
+  return S_OK;
+}
+
+dxil_dia::hlsl_symbols::SymbolManagerInit::SymbolManagerInit(
+    Session *pSession,
+    std::vector<SymbolManager::CreateSymbolFn> *pSymCtors,
+    SymbolManager::ScopeToIDMap *pScopeToSym,
+    SymbolManager::IDToLiveRangeMap *pSymToLR)
+  : m_Session(*pSession),
+    m_SymCtors(*pSymCtors),
+    m_ScopeToSym(*pScopeToSym),
+    m_SymToLR(*pSymToLR) {
+  DXASSERT_ARGS(m_Parent.size() == m_SymCtors.size(),
+                "parent and symbol array size mismatch: %d vs %d",
+                m_Parent.size(),
+                m_SymCtors.size());
+}
+
+void dxil_dia::hlsl_symbols::SymbolManagerInit::TypeInfo::Embed(const TypeInfo &TI) {
+  for (const auto &E : TI.GetLayout()) {
+    m_Layout.emplace_back(E);
+  }
+  m_dwCurrentSizeInBytes += TI.m_dwCurrentSizeInBytes;
+}
+
+void dxil_dia::hlsl_symbols::SymbolManagerInit::TypeInfo::AddBasicType(llvm::DIBasicType *BT) {
+  m_Layout.emplace_back(BT);
+
+  static constexpr DWORD kNumBitsPerByte = 8;
+  m_dwCurrentSizeInBytes += BT->getSizeInBits() / kNumBitsPerByte;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::GetTypeInfo(llvm::DIType *T, TypeInfo **TI) {
+  auto tyInfoIt = m_TypeToInfo.find(T);
+  if (tyInfoIt == m_TypeToInfo.end()) {
+    return E_FAIL;
+  }
+
+  *TI = &tyInfoIt->second;
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::AddType(DWORD dwParentID, llvm::DIType *T, DWORD *pNewSymID, SymbolCtor symCtor) {
+  IFR(AddSymbol(dwParentID, pNewSymID, symCtor));
+  if (!m_TypeToInfo.insert(std::make_pair(T, TypeInfo(*pNewSymID))).second) {
+    return E_FAIL;
+  }
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::AddSymbol(DWORD dwParentID, DWORD *pNewSymID, SymbolCtor symCtor) {
+  if (dwParentID > m_SymCtors.size()) {
+    return E_FAIL;
+  }
+
+  const DWORD dwNewSymID = m_SymCtors.size() + 1;
+  m_SymCtors.emplace_back(std::bind(symCtor, std::placeholders::_1, dwNewSymID, std::placeholders::_2));
+  *pNewSymID = dwNewSymID;
+  IFR(AddParent(dwParentID));
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::AddParent(DWORD dwParentIndex) {
+  m_Parent.emplace_back(dwParentIndex);
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateFunctionBlockForLocalScope(llvm::DILocalScope *LS, DWORD *pNewSymID) {
+  if (LS == nullptr) {
+    return E_FAIL;
+  }
+
+  auto lsIT = m_ScopeToSym.find(LS);
+  if (lsIT != m_ScopeToSym.end()) {
+    *pNewSymID = lsIT->second;
+    return S_OK;
+  }
+
+  llvm::DILocalScope *ParentLS = nullptr;
+  if (auto *Location = llvm::dyn_cast<llvm::DILocation>(LS)) {
+    ParentLS = Location->getInlinedAtScope();
+    if (ParentLS == nullptr) {
+      ParentLS = Location->getScope();
+    }
+  } else if (auto *Block = llvm::dyn_cast<llvm::DILexicalBlock>(LS)) {
+    ParentLS = Block->getScope();
+  }
+
+  if (ParentLS == nullptr) {
+    return E_FAIL;
+  }
+
+  DWORD dwParentID;
+  IFR(CreateFunctionBlockForLocalScope(ParentLS, &dwParentID));
+
+  IFR(AddSymbol(dwParentID, pNewSymID, [dwParentID](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(FunctionBlockSymbol::Create(pMalloc, pSession, ID, ppSym));
+    (*ppSym)->SetLexicalParent(dwParentID);
+    return S_OK;
+  }));
+  m_ScopeToSym.insert(std::make_pair(LS, *pNewSymID));
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateFunctionBlockForInstruction(llvm::Instruction *I) {
+  const llvm::DebugLoc &DL = I->getDebugLoc();
+  if (!DL) {
+    return S_OK;
+  }
+
+  llvm::MDNode *LocalScope = DL.getInlinedAtScope();
+  if (LocalScope == nullptr) {
+    LocalScope = DL.getScope();
+  }
+  if (LocalScope == nullptr) {
+    return S_OK;
+  }
+  auto *LS = llvm::dyn_cast<llvm::DILocalScope>(LocalScope);
+  if (LS == nullptr) {
+    return E_FAIL;
+  }
+
+  auto localScopeIt = m_ScopeToSym.find(LS);
+  if (localScopeIt == m_ScopeToSym.end()) {
+    DWORD dwUnusedNewSymID;
+    IFR(CreateFunctionBlockForLocalScope(LS, &dwUnusedNewSymID));
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateFunctionBlocksForFunction(llvm::Function *F) {
+  for (llvm::BasicBlock &BB : *F) {
+    for (llvm::Instruction &I : BB) {
+      IFR(CreateFunctionBlockForInstruction(&I));
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateFunctionsForCU(llvm::DICompileUnit *CU) {
+  for (llvm::DISubprogram *SubProgram : CU->getSubprograms()) {
+    DWORD dwNewFunID;
+    const DWORD dwParentID = SubProgram->isLocalToUnit() ? HlslCompilandId : HlslProgramId;
+    DWORD dwSubprogramTypeID;
+    IFR(CreateType(SubProgram->getType(), &dwSubprogramTypeID));
+    IFR(AddSymbol(dwParentID, &dwNewFunID, [SubProgram, dwParentID, dwSubprogramTypeID](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+      IMalloc *pMalloc = pSession->GetMallocNoRef();
+      IFR(FunctionSymbol::Create(pMalloc, pSession, ID, SubProgram, dwSubprogramTypeID, SubProgram->getType(), ppSym));
+      (*ppSym)->SetLexicalParent(dwParentID);
+      (*ppSym)->SetName(CA2W(SubProgram->getName().str().c_str()));
+      return S_OK;
+    }));
+    m_ScopeToSym.insert(std::make_pair(SubProgram, dwNewFunID));
+
+    if (llvm::Function *F = SubProgram->getFunction()) {
+      IFR(CreateFunctionBlocksForFunction(F));
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateFunctionsForAllCUs() {
+  for (llvm::DICompileUnit *pCU : m_Session.InfoRef().compile_units()) {
+    IFR(CreateFunctionsForCU(pCU));
+  }
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateGlobalVariablesForCU(llvm::DICompileUnit *CU) {
+  for (llvm::DIGlobalVariable *GlobalVariable : CU->getGlobalVariables()) {
+    DWORD dwUnusedNewGVID;
+    const DWORD dwParentID = GlobalVariable->isLocalToUnit() ? HlslCompilandId : HlslProgramId;
+    auto *GVType = dyn_cast_to_ditype<llvm::DIType>(GlobalVariable->getType());
+    DWORD dwGVTypeID;
+    IFR(CreateType(GVType, &dwGVTypeID));
+    IFR(AddSymbol(dwParentID, &dwUnusedNewGVID, [GlobalVariable, dwParentID, dwGVTypeID, GVType](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+      IMalloc *pMalloc = pSession->GetMallocNoRef();
+      IFR(GlobalVariableSymbol::Create(pMalloc, pSession, ID, GlobalVariable, dwGVTypeID, GVType, ppSym));
+      (*ppSym)->SetLexicalParent(dwParentID);
+      (*ppSym)->SetName(CA2W(GlobalVariable->getName().str().c_str()));
+      (*ppSym)->SetIsHLSLData(true);
+      return S_OK;
+    }));
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateGlobalVariablesForAllCUs() {
+  for (llvm::DICompileUnit *pCU : m_Session.InfoRef().compile_units()) {
+    IFR(CreateGlobalVariablesForCU(pCU));
+  }
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::GetScopeID(llvm::DIScope *S, DWORD *pScopeID) {
+  auto ParentScopeIt = m_ScopeToSym.find(S);
+  if (ParentScopeIt != m_ScopeToSym.end()) {
+    *pScopeID = ParentScopeIt->second;
+  } else {
+    auto *ParentScopeTy = llvm::dyn_cast<llvm::DIType>(S);
+    if (!ParentScopeTy) {
+      // Any non-existing scope must be a type.
+      return E_FAIL;
+    }
+    IFR(CreateType(ParentScopeTy, pScopeID));
+  }
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateType(llvm::DIType *Type, DWORD *pNewTypeID) {
+  if (Type == nullptr) {
+    return E_FAIL;
+  }
+
+  auto lsIT = m_TypeToInfo.find(Type);
+  if (lsIT != m_TypeToInfo.end()) {
+    *pNewTypeID = lsIT->second.GetTypeID();
+    return S_OK;
+  }
+
+  if (auto *ST = llvm::dyn_cast<llvm::DISubroutineType>(Type)) {
+    IFR(CreateSubroutineType(HlslProgramId, ST, pNewTypeID));
+    return S_OK;
+  } else if (auto *BT = llvm::dyn_cast<llvm::DIBasicType>(Type)) {
+    IFR(CreateBasicType(HlslProgramId, BT, pNewTypeID));
+    return S_OK;
+  } else if (auto *CT = llvm::dyn_cast<llvm::DICompositeType>(Type)) {
+    DWORD dwParentID = HlslProgramId;
+    if (auto *ParentScope = dyn_cast_to_ditype_or_null<llvm::DIScope>(CT->getScope())) {
+      IFR(GetScopeID(ParentScope, &dwParentID));
+    }
+    IFR(CreateCompositeType(dwParentID, CT, pNewTypeID));
+    return S_OK;
+  } else if (auto *DT = llvm::dyn_cast<llvm::DIDerivedType>(Type)) {
+    DWORD dwParentID = HlslProgramId;
+    if (auto *ParentScope = dyn_cast_to_ditype_or_null<llvm::DIScope>(DT->getScope())) {
+      IFR(GetScopeID(ParentScope, &dwParentID));
+    }
+    IFR(HandleDerivedType(dwParentID, DT, pNewTypeID));
+    return S_OK;
+  }
+
+  return E_FAIL;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateSubroutineType(DWORD dwParentID, llvm::DISubroutineType *ST, DWORD *pNewTypeID) {
+  LazySymbolName LazyName;
+
+  llvm::DITypeRefArray Types = ST->getTypeArray();
+  if (Types.size() > 0) {
+    std::vector<DWORD> TypeIDs;
+    TypeIDs.reserve(Types.size());
+
+    for (llvm::Metadata *M : Types) {
+      auto *Ty = dyn_cast_to_ditype_or_null<llvm::DIType>(M);
+      if (Ty == nullptr) {
+        TypeIDs.emplace_back(kNullSymbolID);
+      } else {
+        DWORD dwTyID;
+        IFR(CreateType(Ty, &dwTyID));
+        TypeIDs.emplace_back(dwTyID);
+      }
+    }
+
+    LazyName = [TypeIDs](Session *pSession, std::string *Name) -> HRESULT {
+      Name->clear();
+      llvm::raw_string_ostream OS(*Name);
+      OS.SetUnbuffered();
+
+      bool first = true;
+      bool firstArg = true;
+      auto &SM = pSession->SymMgr();
+      for (DWORD ID : TypeIDs) {
+        if (!first && !firstArg) {
+          OS << ", ";
+        }
+        if (ID == kNullSymbolID) {
+          OS << "void";
+        } else {
+          CComPtr<Symbol> SymTy;
+          IFR(SM.GetSymbolByID(ID, &SymTy));
+          CComBSTR name;
+          IFR(SymTy->get_name(&name));
+          if (!name) {
+            OS << "???";
+          } else {
+            OS << CW2A((BSTR)name);
+          }
+        }
+        if (first) {
+          OS << "(";
+        }
+        firstArg = first;
+        first = false;
+      }
+      OS << ")";
+      return S_OK;
+    };
+  }
+
+  IFR(AddType(dwParentID, ST, pNewTypeID, [ST, dwParentID, LazyName](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(TypeSymbol::Create(pMalloc, pSession, dwParentID, ID, SymTagFunctionType, ST, LazyName, ppSym));
+    (*ppSym)->SetLexicalParent(dwParentID);
+    return S_OK;
+  }));
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateBasicType(DWORD dwParentID, llvm::DIBasicType *BT, DWORD *pNewTypeID) {
+  DXASSERT_ARGS(dwParentID == HlslProgramId,
+                "%d vs %d",
+                dwParentID,
+                HlslProgramId);
+
+  LazySymbolName LazyName = [BT](Session *pSession, std::string *Name) -> HRESULT {
+    *Name = BT->getName();
+    return S_OK;
+  };
+
+  IFR(AddType(dwParentID, BT, pNewTypeID, [BT, dwParentID, LazyName](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(TypeSymbol::Create(pMalloc, pSession, dwParentID, ID, SymTagBaseType, BT, LazyName, ppSym));
+    (*ppSym)->SetLexicalParent(dwParentID);
+    return S_OK;
+  }));
+
+  TypeInfo *TI;
+  IFR(GetTypeInfo(BT, &TI));
+  TI->AddBasicType(BT);
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateCompositeType(DWORD dwParentID, llvm::DICompositeType *CT, DWORD *pNewTypeID) {
+  switch (CT->getTag()) {
+  case llvm::dwarf::DW_TAG_array_type: {
+    auto *BaseType = dyn_cast_to_ditype_or_null<llvm::DIType>(CT->getBaseType());
+    if (BaseType == nullptr) {
+      return E_FAIL;
+    }
+
+    DWORD dwBaseTypeID = kNullSymbolID;
+    IFR(CreateType(BaseType, &dwBaseTypeID));
+
+    auto LazyName = [CT, dwBaseTypeID](Session *pSession, std::string *Name) -> HRESULT {
+      auto &SM = pSession->SymMgr();
+      Name->clear();
+      llvm::raw_string_ostream OS(*Name);
+      OS.SetUnbuffered();
+
+      auto *BaseTy = llvm::dyn_cast<llvm::DIType>(CT->getBaseType());
+      if (BaseTy == nullptr) {
+        return E_FAIL;
+      }
+      CComPtr<Symbol> SymTy;
+      IFR(SM.GetSymbolByID(dwBaseTypeID, &SymTy));
+      CComBSTR name;
+      IFR(SymTy->get_name(&name));
+      if (!name) {
+        OS << "???";
+      } else {
+        OS << CW2A((BSTR)name);
+      }
+
+      OS << "[";
+      bool first = true;
+      for (llvm::DINode *N : CT->getElements()) {
+        if (!first) {
+          OS << "][";
+        }
+        first = false;
+        if (N != nullptr) {
+          if (auto *SubRange = llvm::dyn_cast<llvm::DISubrange>(N)) {
+            OS << SubRange->getCount();
+          } else {
+            OS << "???";
+          }
+        }
+      }
+      OS << "]";
+      return S_OK;
+    };
+
+    IFR(AddType(dwParentID, CT, pNewTypeID, [CT, dwParentID, LazyName](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+      IMalloc *pMalloc = pSession->GetMallocNoRef();
+      IFR(TypeSymbol::Create(pMalloc, pSession, dwParentID, ID, SymTagArrayType, CT, LazyName, ppSym));
+      (*ppSym)->SetLexicalParent(dwParentID);
+      return S_OK;
+    }));
+
+    return S_OK;
+  }
+  case llvm::dwarf::DW_TAG_class_type: {
+    HRESULT hr;
+    IFR(hr = CreateHLSLType(CT, pNewTypeID));
+    if (hr == S_OK) {
+      return S_OK;
+    }
+    break;
+  }
+  }
+
+  auto LazyName = [CT](Session *pSession, std::string *Name) -> HRESULT {
+    *Name = CT->getName();
+    return S_OK;
+  };
+
+  IFR(AddType(dwParentID, CT, pNewTypeID, [CT, dwParentID, LazyName](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(UDTSymbol::Create(pMalloc, pSession, dwParentID, ID, CT, LazyName, ppSym));
+    (*ppSym)->SetLexicalParent(dwParentID);
+    return S_OK;
+  }));
+
+  TypeInfo *udtTI;
+  IFR(GetTypeInfo(CT, &udtTI));
+  auto udtScope = BeginUDTScope(udtTI);
+  for (llvm::DINode *N : CT->getElements()) {
+    if (auto *Field = llvm::dyn_cast<llvm::DIType>(N)) {
+      DWORD dwUnusedFieldID;
+      IFR(CreateType(Field, &dwUnusedFieldID));
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateHLSLType(llvm::DICompositeType *T, DWORD *pNewTypeID) {
+  DWORD dwEltTyID;
+  std::uint32_t ElemCnt;
+  HRESULT hr;
+  IFR(hr = IsHLSLVectorType(T, &dwEltTyID, &ElemCnt));
+  if (hr == S_OK) {
+    // e.g. float4, int2 etc
+    return CreateHLSLVectorType(T, dwEltTyID, ElemCnt, pNewTypeID);
+  }
+  return S_FALSE;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::IsHLSLVectorType(llvm::DICompositeType *T, DWORD *pEltTyID, std::uint32_t *pElemCnt) {
+  llvm::StringRef Name = T->getName();
+  if (!Name.startswith("vector<")) {
+    return S_FALSE;
+  }
+
+  llvm::DITemplateParameterArray Args = T->getTemplateParams();
+  if (Args.size() != 2) {
+    return E_FAIL;
+  }
+
+  auto *ElemTyParam = llvm::dyn_cast<llvm::DITemplateTypeParameter>(Args[0]);
+  if (ElemTyParam == nullptr) {
+    return E_FAIL;
+  }
+  auto *ElemTy = dyn_cast_to_ditype<llvm::DIType>(ElemTyParam->getType());
+  if (ElemTy == nullptr) {
+    return E_FAIL;
+  }
+
+  DWORD dwEltTyID;
+  IFR(CreateType(ElemTy, &dwEltTyID));
+
+  auto *ElemCntParam = llvm::dyn_cast<llvm::DITemplateValueParameter>(Args[1]);
+  if (ElemCntParam == nullptr) {
+    return E_FAIL;
+  }
+  auto *ElemCntMD = llvm::dyn_cast<llvm::ConstantAsMetadata>(ElemCntParam->getValue());
+  auto *ElemCnt = llvm::dyn_cast_or_null<llvm::ConstantInt>(ElemCntMD->getValue());
+  if (ElemCnt == nullptr) {
+    return E_FAIL;
+  }
+  if (ElemCnt->getLimitedValue() > 4) {
+    return E_FAIL;
+  }
+
+  *pEltTyID = dwEltTyID;
+  *pElemCnt = ElemCnt->getLimitedValue();
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateHLSLVectorType(llvm::DICompositeType *T, DWORD pEltTyID, std::uint32_t pElemCnt, DWORD *pNewTypeID) {
+  llvm::DITemplateParameterArray Args = T->getTemplateParams();
+  if (Args.size() != 2) {
+    return E_FAIL;
+  }
+
+  auto *ElemTyParam = llvm::dyn_cast<llvm::DITemplateTypeParameter>(Args[0]);
+  if (ElemTyParam == nullptr) {
+    return E_FAIL;
+  }
+  auto *ElemTy = dyn_cast_to_ditype<llvm::DIType>(ElemTyParam->getType());
+  if (ElemTy == nullptr) {
+    return E_FAIL;
+  }
+
+  DWORD dwElemTyID;
+  IFT(CreateType(ElemTy, &dwElemTyID));
+
+  auto *ElemCntParam = llvm::dyn_cast<llvm::DITemplateValueParameter>(Args[1]);
+  if (ElemCntParam == nullptr) {
+    return E_FAIL;
+  }
+  auto *ElemCntMD = llvm::dyn_cast<llvm::ConstantAsMetadata>(ElemCntParam->getValue());
+  auto *ElemCnt = llvm::dyn_cast_or_null<llvm::ConstantInt>(ElemCntMD->getValue());
+  if (ElemCnt == nullptr) {
+    return E_FAIL;
+  }
+  if (ElemCnt->getLimitedValue() > 4) {
+    return E_FAIL;
+  }
+
+  const DWORD dwParentID = HlslProgramId;
+  IFR(AddType(dwParentID, T, pNewTypeID, [T, dwParentID, dwElemTyID, ElemCnt](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(VectorTypeSymbol::Create(pMalloc, pSession, dwParentID, ID, T, dwElemTyID, ElemCnt->getLimitedValue(), ppSym));
+    (*ppSym)->SetLexicalParent(dwParentID);
+    (*ppSym)->SetName(CA2W(T->getName().str().c_str()));
+    return S_OK;
+  }));
+
+  TypeInfo *vecTI;
+  IFR(GetTypeInfo(T, &vecTI));
+  TypeInfo *elemTI;
+  IFR(GetTypeInfo(ElemTy, &elemTI));
+  for (std::uint64_t i = 0; i < ElemCnt->getLimitedValue(); ++i) {
+    vecTI->Embed(*elemTI);
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::HandleDerivedType(DWORD dwParentID, llvm::DIDerivedType *DT, DWORD *pNewTypeID) {
+  DWORD st;
+  LazySymbolName LazyName;
+
+  DWORD dwBaseTypeID = kNullSymbolID;
+  auto *BaseTy = llvm::dyn_cast_or_null<llvm::DIType>(DT->getBaseType());
+  if (BaseTy != nullptr) {
+    IFR(CreateType(BaseTy, &dwBaseTypeID));
+  }
+
+  auto LazyNameWithQualifier = [dwBaseTypeID, DT](Session *pSession, std::string *Name, const char *Qualifier) -> HRESULT {
+    auto &SM = pSession->SymMgr();
+    Name->clear();
+    llvm::raw_string_ostream OS(*Name);
+    OS.SetUnbuffered();
+
+    auto *BaseTy = llvm::dyn_cast<llvm::DIType>(DT->getBaseType());
+    if (BaseTy == nullptr) {
+      return E_FAIL;
+    }
+    CComPtr<Symbol> SymTy;
+    IFR(SM.GetSymbolByID(dwBaseTypeID, &SymTy));
+    CComBSTR name;
+    IFR(SymTy->get_name(&name));
+    if (!name) {
+      OS << "???";
+    } else {
+      OS << CW2A((BSTR)name);
+    }
+    OS << Qualifier;
+    return S_OK;
+  };
+
+  switch (DT->getTag()) {
+  case llvm::dwarf::DW_TAG_member: {
+    // Type is not really a type, but rather a struct member.
+    IFR(CreateUDTField(dwParentID, DT));
+    return S_OK;
+  }
+  default:
+    st = SymTagBlock;
+    LazyName = [](Session *pSession, std::string *Name) -> HRESULT {
+      Name->clear();
+      return S_OK;
+    };
+    break;
+  case llvm::dwarf::DW_TAG_typedef: {
+    if (dwBaseTypeID == kNullSymbolID) {
+      return E_FAIL;
+    }
+
+    IFR(AddType(dwParentID, DT, pNewTypeID, [dwParentID, DT, dwBaseTypeID](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+      IMalloc *pMalloc = pSession->GetMallocNoRef();
+      IFR(TypedefTypeSymbol::Create(pMalloc, pSession, dwParentID, ID, DT, dwBaseTypeID, ppSym));
+      (*ppSym)->SetLexicalParent(dwParentID);
+      (*ppSym)->SetName(CA2W(DT->getName().str().c_str()));
+      return S_OK;
+    }));
+
+    TypeInfo *dtTI;
+    IFR(GetTypeInfo(DT, &dtTI));
+    TypeInfo *baseTI;
+    IFR(GetTypeInfo(BaseTy, &baseTI));
+    dtTI->Embed(*baseTI);
+
+    return S_OK;
+  }
+  case llvm::dwarf::DW_TAG_const_type: {
+    if (dwBaseTypeID == kNullSymbolID) {
+      return E_FAIL;
+    }
+
+    st = SymTagCustomType;
+    LazyName = std::bind(LazyNameWithQualifier, std::placeholders::_1, std::placeholders::_2, " const");
+    break;
+  }
+  case llvm::dwarf::DW_TAG_pointer_type: {
+    if (dwBaseTypeID == kNullSymbolID) {
+      return E_FAIL;
+    }
+
+    st = SymTagPointerType;
+    LazyName = std::bind(LazyNameWithQualifier, std::placeholders::_1, std::placeholders::_2, " *");
+    break;
+  }
+  case llvm::dwarf::DW_TAG_reference_type: {
+    if (dwBaseTypeID == kNullSymbolID) {
+      return E_FAIL;
+    }
+
+    st = SymTagCustomType;
+    LazyName = std::bind(LazyNameWithQualifier, std::placeholders::_1, std::placeholders::_2, " &");
+    break;
+  }
+  }
+
+  IFR(AddType(dwParentID, DT, pNewTypeID, [DT, dwParentID, st, LazyName](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(TypeSymbol::Create(pMalloc, pSession, dwParentID, ID, st, DT, LazyName, ppSym));
+    (*ppSym)->SetLexicalParent(dwParentID);
+    return S_OK;
+  }));
+
+  if (DT->getTag() == llvm::dwarf::DW_TAG_const_type) {
+    TypeInfo *dtTI;
+    IFR(GetTypeInfo(DT, &dtTI));
+    TypeInfo *baseTI;
+    IFR(GetTypeInfo(BaseTy, &baseTI));
+    dtTI->Embed(*baseTI);
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateLocalVariable(DWORD dwParentID, llvm::DILocalVariable *LV) {
+  auto *LVTy = dyn_cast_to_ditype<llvm::DIType>(LV->getType());
+  if (LVTy == nullptr) {
+    return E_FAIL;
+  }
+
+  if (m_VarToID.count(LV) != 0) {
+    return S_OK;
+  }
+
+  DWORD dwLVTypeID;
+  IFR(CreateType(LVTy, &dwLVTypeID));
+  TypeInfo *varTI;
+  IFR(GetTypeInfo(LVTy, &varTI));
+
+  DWORD dwOffsetInUDT = 0;
+  auto &newVars = m_VarToID[LV];
+  std::vector<llvm::DIType *> Tys = varTI->GetLayout();
+  for (llvm::DIType *Ty : Tys) {
+    TypeInfo *TI;
+    IFR(GetTypeInfo(Ty, &TI));
+    const DWORD dwTypeID = TI->GetTypeID();
+    DWORD dwNewLVID;
+    newVars.emplace_back(std::make_shared<VarInfo>());
+    std::shared_ptr<VarInfo> VI = newVars.back();
+    IFR(AddSymbol(dwParentID, &dwNewLVID, [dwParentID, LV, dwTypeID, dwLVTypeID, LVTy, VI](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+      IMalloc *pMalloc = pSession->GetMallocNoRef();
+      IFR(LocalVariableSymbol::Create(pMalloc, pSession, ID, LV, dwLVTypeID, LVTy, VI->GetOffsetInUDT(), VI->GetDxilRegister(), ppSym));
+      (*ppSym)->SetLexicalParent(dwParentID);
+      (*ppSym)->SetName(CA2W(LV->getName().str().c_str()));
+      (*ppSym)->SetDataKind(LV->getTag() == llvm::dwarf::DW_TAG_arg_variable ? DataIsParam : DataIsLocal);
+      return S_OK;
+    }));
+    VI->SetVarID(dwNewLVID);
+    VI->SetOffsetInUDT(dwOffsetInUDT);
+
+    static constexpr DWORD kNumBitsPerByte = 8;
+    dwOffsetInUDT += Ty->getSizeInBits() / kNumBitsPerByte;
+  }
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::GetTypeLayout(llvm::DIType *Ty, std::vector<DWORD> *pRet) {
+  pRet->clear();
+
+  TypeInfo *TI;
+  IFR(GetTypeInfo(Ty, &TI));
+  for (llvm::DIType * T : TI->GetLayout()) {
+    TypeInfo *eTI;
+    IFR(GetTypeInfo(T, &eTI));
+    pRet->emplace_back(eTI->GetTypeID());
+  }
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateUDTField(DWORD dwParentID, llvm::DIDerivedType *Field) {
+  auto *FieldTy = dyn_cast_to_ditype<llvm::DIType>(Field->getBaseType());
+  if (FieldTy == nullptr) {
+    return E_FAIL;
+  }
+
+  if (m_FieldToID.count(Field) != 0) {
+    return S_OK;
+  }
+
+  DWORD dwLVTypeID;
+  IFR(CreateType(FieldTy, &dwLVTypeID));
+  if (m_pCurUDT != nullptr) {
+    const DWORD dwOffsetInBytes = CurrentUDTInfo().GetCurrentSizeInBytes();
+    DXASSERT_ARGS(dwOffsetInBytes == Field->getOffsetInBits() / 8,
+      "%d vs %d",
+      dwOffsetInBytes,
+      Field->getOffsetInBits() / 8);
+    TypeInfo *lvTI;
+    IFR(GetTypeInfo(FieldTy, &lvTI));
+    CurrentUDTInfo().Embed(*lvTI);
+  }
+
+  DWORD dwNewLVID;
+  IFR(AddSymbol(dwParentID, &dwNewLVID, [dwParentID, Field, dwLVTypeID, FieldTy](Session *pSession, DWORD ID, Symbol **ppSym) -> HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(UDTFieldSymbol::Create(pMalloc, pSession, ID, Field, dwLVTypeID, FieldTy, ppSym));
+    (*ppSym)->SetLexicalParent(dwParentID);
+    (*ppSym)->SetName(CA2W(Field->getName().str().c_str()));
+    (*ppSym)->SetDataKind(Field->isStaticMember() ? DataIsStaticLocal : DataIsMember);
+    return S_OK;
+  }));
+  m_FieldToID.insert(std::make_pair(Field, dwNewLVID));
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateLocalVariables() {
+  llvm::Module *M = &m_Session.ModuleRef();
+
+  llvm::Function *DbgDeclare = llvm::Intrinsic::getDeclaration(M, llvm::Intrinsic::dbg_declare);
+  for (llvm::Value *U : DbgDeclare->users()) {
+    auto *CI = llvm::dyn_cast<llvm::CallInst>(U);
+    auto *LS = llvm::dyn_cast_or_null<llvm::DILocalScope>(CI->getDebugLoc()->getScope());
+    auto SymIt = m_ScopeToSym.find(LS);
+    if (SymIt == m_ScopeToSym.end()) {
+      continue;
+    }
+
+    auto *LocalNameMetadata = llvm::dyn_cast<llvm::MetadataAsValue>(CI->getArgOperand(1));
+    if (auto *LV = llvm::dyn_cast<llvm::DILocalVariable>(LocalNameMetadata->getMetadata())) {
+      const DWORD dwParentID = SymIt->second;
+      IFR(CreateLocalVariable(dwParentID, LV));
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::CreateLiveRanges() {
+  // Simple algorithm:
+  //   live_range = map from SymbolID to SymbolManager.LiveRange
+  //   end_of_scope = map from Scope to RVA
+  //   for each I in reverse(pSession.InstructionsRef):
+  //     scope = I.scope
+  //     if scope not in end_of_scope:
+  //       end_of_scope[scope] = rva(I)
+  //     if I is dbg.declare:
+  //       live_range[symbol of I] = SymbolManager.LiveRange[RVA(I), end_of_scope[scope]]
+  llvm::Module *M = &m_Session.ModuleRef();
+  m_SymToLR.clear();
+  const auto &Instrs = m_Session.InstructionsRef();
+  llvm::DenseMap<llvm::DILocalScope *, Session::RVA> EndOfScope;
+  for (auto It = Instrs.rbegin(); It != Instrs.rend(); ++It) {
+    const Session::RVA RVA = It->first;
+    const auto *I = It->second;
+    const llvm::DebugLoc &DL = I->getDebugLoc();
+    if (!DL) {
+      continue;
+    }
+    llvm::MDNode *LocalScope = DL.getInlinedAtScope();
+    if (LocalScope == nullptr) {
+      LocalScope = DL.getScope();
+    }
+    if (LocalScope == nullptr) {
+      continue;
+    }
+    auto *LS = llvm::dyn_cast<llvm::DILocalScope>(LocalScope);
+    if (LS == nullptr) {
+      return E_FAIL;
+    }
+
+    if (EndOfScope.count(LS) == 0) {
+      EndOfScope.insert(std::make_pair(LS, RVA + 1));
+    }
+    auto endOfScopeRVA = EndOfScope.find(LS)->second;
+
+    DWORD Reg;
+    DWORD RegSize;
+    llvm::DILocalVariable *LV;
+    uint64_t StartOffset;
+    uint64_t EndOffset;
+    HRESULT hr;
+    IFR(hr = IsDbgDeclareCall(M, I, &Reg, &RegSize, &LV, &StartOffset, &EndOffset));
+    if (hr != S_OK) {
+      continue;
+    }
+
+    auto varIt = m_VarToID.find(LV);
+    if (varIt == m_VarToID.end()) {
+      // All variables should already have been seen and created.
+      return E_FAIL;
+    }
+
+    for (auto &Var : varIt->second) {
+      const DWORD dwOffsetInUDT = Var->GetOffsetInUDT();
+      if (dwOffsetInUDT < StartOffset || dwOffsetInUDT >= EndOffset) {
+        continue;
+      }
+      DXASSERT_ARGS((dwOffsetInUDT - StartOffset) % 4 == 0,
+                    "Invalid byte offset %d into variable",
+                    (dwOffsetInUDT - StartOffset));
+      const DWORD dwRegIndex = (dwOffsetInUDT - StartOffset) / 4;
+      if (dwRegIndex >= RegSize) {
+        continue;
+      }
+      Var->SetDxilRegister(Reg + dwRegIndex);
+      m_SymToLR[Var->GetVarID()] = SymbolManager::LiveRange{
+        static_cast<uint32_t>(RVA),
+        endOfScopeRVA - static_cast<uint32_t>(RVA)
+      };
+    }
+
+  }
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::IsDbgDeclareCall(llvm::Module *M, const llvm::Instruction *I, DWORD *pReg, DWORD *pRegSize, llvm::DILocalVariable **LV, uint64_t *pStartOffset, uint64_t *pEndOffset) {
+  auto *CI = llvm::dyn_cast<llvm::CallInst>(I);
+  if (CI == nullptr) {
+    return S_FALSE;
+  }
+
+  llvm::Function *DbgDeclare = llvm::Intrinsic::getDeclaration(M, llvm::Intrinsic::dbg_declare);
+  if (CI->getCalledFunction() != DbgDeclare) {
+    return S_FALSE;
+  }
+
+  *LV = nullptr;
+  *pReg = *pRegSize = 0;
+  *pStartOffset = *pEndOffset = 0;
+
+  if (auto *RegMV = llvm::dyn_cast<llvm::MetadataAsValue>(CI->getArgOperand(0))) {
+    if (auto *RegVM = llvm::dyn_cast<llvm::ValueAsMetadata>(RegMV->getMetadata())) {
+      if (auto *Reg = llvm::dyn_cast<llvm::Instruction>(RegVM->getValue())) {
+        HRESULT hr;
+        IFR(hr = GetDxilAllocaRegister(Reg, pReg, pRegSize));
+        if (hr != S_OK) {
+          return hr;
+        }
+      }
+    }
+  }
+
+  if (auto *LVMV = llvm::dyn_cast<llvm::MetadataAsValue>(CI->getArgOperand(1))) {
+    *LV = llvm::dyn_cast<llvm::DILocalVariable>(LVMV->getMetadata());
+    if (LV == nullptr) {
+      return E_FAIL;
+    }
+  }
+
+  if (auto *FieldsMV = llvm::dyn_cast<llvm::MetadataAsValue>(CI->getArgOperand(2))) {
+    auto *Fields = llvm::dyn_cast<llvm::DIExpression>(FieldsMV->getMetadata());
+    if (Fields == nullptr) {
+      return E_FAIL;
+    }
+
+    if (Fields->isBitPiece()) {
+      const uint64_t Offset = Fields->getBitPieceOffset();
+      const uint64_t Size = Fields->getBitPieceSize();
+
+      // dxcompiler had a bug (fixed in
+      // 4870297404a37269e24ddce7db3bd94a8110fff8) where the BitPieceSize
+      // was defined in bytes, not bits. We use the register size in bits to
+      // verify if Size is bits or bytes.
+      static constexpr uint64_t kNumBytesPerDword = 4;
+      if (*pRegSize * kNumBytesPerDword == Size) {
+          // Size is bytes.
+          *pStartOffset = Offset;
+          *pEndOffset = *pStartOffset + Size;
+      } else {
+          // Size is (should be) bits; pStartOffset/pEndOffset should be bytes.
+          static constexpr uint64_t kNumBitsPerByte = 8;
+          (void)kNumBitsPerByte;
+          assert(*pRegSize * kNumBytesPerDword * kNumBitsPerByte == Size);
+          *pStartOffset = Offset / kNumBitsPerByte;
+          *pEndOffset = *pStartOffset + (Size / kNumBitsPerByte);
+      }
+    } else {
+      static constexpr uint64_t kNumBytesPerDword = 4;
+      *pStartOffset = 0;
+      *pEndOffset = *pRegSize * kNumBytesPerDword;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::GetDxilAllocaRegister(llvm::Instruction *I, DWORD *pRegNum, DWORD *pRegSize) {
+  auto *Alloca = llvm::dyn_cast<llvm::AllocaInst>(I);
+  if (Alloca == nullptr) {
+    return S_FALSE;
+  }
+
+  std::uint32_t uRegNum;
+  std::uint32_t uRegSize;
+  if (!pix_dxil::PixAllocaReg::FromInst(Alloca, &uRegNum, &uRegSize)) {
+    return S_FALSE;
+  }
+
+  *pRegNum = uRegNum;
+  *pRegSize = uRegSize;
+  return S_OK;
+}
+
+HRESULT dxil_dia::hlsl_symbols::SymbolManagerInit::PopulateParentToChildrenIDMap(SymbolManager::ParentToChildrenMap *pParentToChildren) {
+  DXASSERT_ARGS(m_SymCtors.size() == m_Parent.size(),
+                "parents vector must be the same size of symbols ctor vector: %d vs %d",
+                m_SymCtors.size(),
+                m_Parent.size());
+
+  for (size_t i = 0; i < m_Parent.size(); ++i) {
+#ifndef NDEBUG
+    {
+      CComPtr<Symbol> S;
+      IFT(m_SymCtors[i](&m_Session, &S));
+      DXASSERT_ARGS(S->GetID() == i + 1,
+                    "Invalid symbol index %d for %d",
+                    S->GetID(),
+                   i + 1);
+    }
+#endif  // !NDEBUG
+
+    DXASSERT_ARGS(m_Parent[i] != kNullSymbolID || (i + 1) == HlslProgramId,
+                  "Parentless symbol %d", i + 1);
+    if (m_Parent[i] != kNullSymbolID) {
+      pParentToChildren->emplace(m_Parent[i], i + 1);
+    }
+  }
+
+  return S_OK;
+}
+
+dxil_dia::SymbolManager::SymbolManager() = default;
+
+dxil_dia::SymbolManager::~SymbolManager() {
+  m_pSession = nullptr;
+}
+
+void dxil_dia::SymbolManager::Init(Session *pSes) {
+  DXASSERT(m_pSession == nullptr, "SymbolManager already initialized");
+  m_pSession = pSes;
+  m_symbolCtors.clear();
+  m_parentToChildren.clear();
+
+  llvm::DebugInfoFinder &DIFinder = pSes->InfoRef();
+  if (DIFinder.compile_unit_count() != 1) {
+    throw hlsl::Exception(E_FAIL);
+  }
+  llvm::DICompileUnit *ShaderCU = *DIFinder.compile_units().begin();
+
+  hlsl_symbols::SymbolManagerInit SMI(pSes, &m_symbolCtors, &m_scopeToID, &m_symbolToLiveRange);
+
+  DWORD dwHlslProgramID;
+  IFT(SMI.AddSymbol(kNullSymbolID, &dwHlslProgramID, [](Session *pSession, DWORD, Symbol **ppSym) -> HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    return hlsl_symbols::GlobalScopeSymbol::Create(pMalloc, pSession, ppSym);
+  }));
+  DXASSERT_ARGS(dwHlslProgramID == HlslProgramId,
+                "%d vs %d",
+                dwHlslProgramID,
+                HlslProgramId);
+
+
+  DWORD dwHlslCompilandID;
+  IFT(SMI.AddSymbol(dwHlslProgramID, &dwHlslCompilandID, [dwHlslProgramID, ShaderCU](Session *pSession, DWORD, Symbol **ppSym) ->HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(hlsl_symbols::CompilandSymbol::Create(pMalloc, pSession, ShaderCU, ppSym));
+    (*ppSym)->SetLexicalParent(dwHlslProgramID);
+    return S_OK;
+  }));
+  m_scopeToID.insert(std::make_pair(ShaderCU, dwHlslCompilandID));
+  DXASSERT_ARGS(dwHlslCompilandID == HlslCompilandId,
+                "%d vs %d",
+                dwHlslCompilandID,
+                HlslCompilandId);
+
+
+  DWORD dwHlslCompilandDetailsId;
+  IFT(SMI.AddSymbol(dwHlslCompilandID, &dwHlslCompilandDetailsId, [dwHlslCompilandID](Session *pSession, DWORD, Symbol **ppSym) ->HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(hlsl_symbols::CompilandDetailsSymbol::Create(pMalloc, pSession, ppSym));
+    (*ppSym)->SetLexicalParent(dwHlslCompilandID);
+    return S_OK;
+  }));
+  DXASSERT_ARGS(dwHlslCompilandDetailsId == HlslCompilandDetailsId,
+                "%d vs %d",
+                dwHlslCompilandDetailsId,
+                HlslCompilandDetailsId);
+
+
+  DWORD dwHlslCompilandEnvFlagsID;
+  IFT(SMI.AddSymbol(dwHlslCompilandID, &dwHlslCompilandEnvFlagsID,[dwHlslCompilandID](Session *pSession, DWORD, Symbol **ppSym) ->HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(hlsl_symbols::CompilandEnvSymbol::CreateFlags(pMalloc, pSession, ppSym));
+    (*ppSym)->SetLexicalParent(dwHlslCompilandID);
+    return S_OK;
+  }));
+  DXASSERT_ARGS(dwHlslCompilandEnvFlagsID == HlslCompilandEnvFlagsId,
+                "%d vs %d",
+                dwHlslCompilandEnvFlagsID,
+                HlslCompilandEnvFlagsId);
+
+
+  DWORD dwHlslCompilandEnvTargetID;
+  IFT(SMI.AddSymbol(dwHlslCompilandID, &dwHlslCompilandEnvTargetID, [dwHlslCompilandID](Session *pSession, DWORD, Symbol **ppSym) ->HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(hlsl_symbols::CompilandEnvSymbol::CreateTarget(pMalloc, pSession, ppSym));
+    (*ppSym)->SetLexicalParent(dwHlslCompilandID);
+    return S_OK;
+  }));
+  DXASSERT_ARGS(dwHlslCompilandEnvTargetID == HlslCompilandEnvTargetId,
+                "%d vs %d",
+                dwHlslCompilandEnvTargetID,
+                HlslCompilandEnvTargetId);
+
+
+  DWORD dwHlslCompilandEnvEntryID;
+  IFT(SMI.AddSymbol(dwHlslCompilandID, &dwHlslCompilandEnvEntryID, [dwHlslCompilandID](Session *pSession, DWORD, Symbol **ppSym) ->HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(hlsl_symbols::CompilandEnvSymbol::CreateEntry(pMalloc, pSession, ppSym));
+    (*ppSym)->SetLexicalParent(dwHlslCompilandID);
+    return S_OK;
+  }));
+  DXASSERT_ARGS(dwHlslCompilandEnvEntryID == HlslCompilandEnvEntryId,
+                "%d vs %d",
+                dwHlslCompilandEnvEntryID,
+                HlslCompilandEnvEntryId);
+
+
+  DWORD dwHlslCompilandEnvDefinesID;
+  IFT(SMI.AddSymbol(dwHlslCompilandID, &dwHlslCompilandEnvDefinesID, [dwHlslCompilandID](Session *pSession, DWORD, Symbol **ppSym) ->HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFR(hlsl_symbols::CompilandEnvSymbol::CreateDefines(pMalloc, pSession, ppSym));
+    (*ppSym)->SetLexicalParent(dwHlslCompilandID);
+    return S_OK;
+  }));
+  DXASSERT_ARGS(dwHlslCompilandEnvDefinesID == HlslCompilandEnvDefinesId,
+                "%d vs %d",
+                dwHlslCompilandEnvDefinesID,
+                HlslCompilandEnvDefinesId);
+
+
+  DWORD dwHlslCompilandEnvArgumentsID;
+  IFT(SMI.AddSymbol(dwHlslCompilandID, &dwHlslCompilandEnvArgumentsID, [dwHlslCompilandID](Session *pSession, DWORD, Symbol **ppSym) ->HRESULT {
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    IFT(hlsl_symbols::CompilandEnvSymbol::CreateArguments(pMalloc, pSession, ppSym));
+    (*ppSym)->SetLexicalParent(dwHlslCompilandID);
+    return S_OK;
+  }));
+  DXASSERT_ARGS(dwHlslCompilandEnvArgumentsID == HlslCompilandEnvArgumentsId,
+                "%d vs %d",
+                dwHlslCompilandEnvArgumentsID,
+                HlslCompilandEnvArgumentsId);
+
+
+  IFT(SMI.CreateFunctionsForAllCUs());
+  IFT(SMI.CreateGlobalVariablesForAllCUs());
+  IFT(SMI.CreateLocalVariables());
+  IFT(SMI.CreateLiveRanges());
+  IFT(SMI.PopulateParentToChildrenIDMap(&m_parentToChildren));
+}
+
+HRESULT dxil_dia::SymbolManager::GetSymbolByID(size_t id, Symbol **ppSym) const {
+  if (ppSym == nullptr) {
+    return E_INVALIDARG;
+  }
+  *ppSym = nullptr;
+
+  if (m_pSession == nullptr) {
+    return E_FAIL;
+  }
+
+  if (id <= 0) {
+    return E_INVALIDARG;
+  }
+  if (id > m_symbolCtors.size()) {
+    return S_FALSE;
+  }
+
+  DxcThreadMalloc TM(m_pSession->GetMallocNoRef());
+  IFR(m_symbolCtors[id - 1](m_pSession, ppSym));
+  return S_OK;
+}
+
+HRESULT dxil_dia::SymbolManager::GetLiveRangeOf(Symbol *pSym, LiveRange *LR) const {
+  const DWORD dwSymID = pSym->GetID();
+  if (dwSymID <= 0 || dwSymID > m_symbolCtors.size()) {
+    return E_INVALIDARG;
+  }
+
+  auto symIt = m_symbolToLiveRange.find(dwSymID);
+  if (symIt == m_symbolToLiveRange.end()) {
+    return S_FALSE;
+  }
+  *LR = symIt->second;
+  return S_OK;
+}
+
+HRESULT dxil_dia::SymbolManager::GetGlobalScope(Symbol **ppSym) const {
+  return GetSymbolByID(HlslProgramId, ppSym);
+}
+
+HRESULT dxil_dia::SymbolManager::ChildrenOf(DWORD ID, std::vector<CComPtr<Symbol>> *pChildren) const {
+  pChildren->clear();
+  auto childrenList = m_parentToChildren.equal_range(ID);
+  for (auto it = childrenList.first; it != childrenList.second; ++it) {
+    CComPtr<Symbol> Child;
+    IFR(GetSymbolByID(it->second, &Child));
+    pChildren->emplace_back(Child);
+  }
+  return S_OK;
+}
+
+HRESULT dxil_dia::SymbolManager::ChildrenOf(Symbol *pSym, std::vector<CComPtr<Symbol>> *pChildren) const {
+  const std::uint32_t pSymID = pSym->GetID();
+  IFR(ChildrenOf(pSymID, pChildren));
+  return S_OK;
+}
+
+HRESULT dxil_dia::SymbolManager::DbgScopeOf(const llvm::Instruction *instr, SymbolChildrenEnumerator **ppRet) const {
+  *ppRet = nullptr;
+
+  const llvm::DebugLoc &DL = instr->getDebugLoc();
+  if (!DL) {
+    return S_FALSE;
+  }
+
+  llvm::MDNode *LocalScope = DL.getInlinedAtScope();
+  if (LocalScope == nullptr) {
+    LocalScope = DL.getScope();
+  }
+  if (LocalScope == nullptr) {
+    return S_FALSE;
+  }
+  auto *LS = llvm::dyn_cast<llvm::DILocalScope>(LocalScope);
+  if (LS == nullptr) {
+    // This is a failure as instructions should always live in a DILocalScope
+    return E_FAIL;
+  }
+
+  auto scopeIt = m_scopeToID.find(LS);
+  if (scopeIt == m_scopeToID.end()) {
+    // This is a failure because all scopes should already exist in the symbol manager.
+    return E_FAIL;
+  }
+
+  CComPtr<SymbolChildrenEnumerator> ret = SymbolChildrenEnumerator::Alloc(m_pSession->GetMallocNoRef());
+  if (!ret) {
+    return E_OUTOFMEMORY;
+  }
+
+  CComPtr<Symbol> s;
+  IFR(GetSymbolByID(scopeIt->second, &s));
+  std::vector<CComPtr<Symbol>> children{s};
+  ret->Init(std::move(children));
+
+  *ppRet = ret.Detach();
+  return S_OK;
+}

+ 84 - 0
lib/DxilDia/DxilDiaSymbolManager.h

@@ -0,0 +1,84 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilDiaSymbolsManager.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.                                     //
+//                                                                           //
+// DIA API implementation for DXIL modules.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+#pragma once
+
+#include "dxc/Support/WinIncludes.h"
+
+#include <cstdint>
+#include <functional>
+#include <unordered_map>
+#include <vector>
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/ADT/PointerUnion.h"
+
+namespace llvm {
+class DIDerivedType;
+class DILocalVariable;
+class DIScope;
+class DITemplateTypeParameter;
+class DIType;
+class Instruction;
+}  // namespace llvm
+
+namespace dxil_dia {
+class Session;
+class Symbol;
+class SymbolChildrenEnumerator;
+
+class SymbolManager {
+public:
+  struct LiveRange {
+    unsigned Start;
+    unsigned Length;
+  };
+
+  using CreateSymbolFn = std::function<HRESULT(Session *pSession, Symbol **)>;
+  using ScopeToIDMap = llvm::DenseMap<llvm::DIScope *, DWORD>;
+  using IDToLiveRangeMap = std::unordered_map<DWORD, LiveRange>;
+  using ParentToChildrenMap = std::unordered_multimap<DWORD, DWORD>;
+
+
+  SymbolManager();
+  ~SymbolManager();
+
+  void Init(Session *pSes);
+
+  size_t NumSymbols() const { return m_symbolCtors.size(); }
+  HRESULT GetSymbolByID(size_t id, Symbol **ppSym) const;
+  HRESULT GetLiveRangeOf(Symbol *pSym, LiveRange *LR) const;
+  HRESULT GetGlobalScope(Symbol **ppSym) const;
+  HRESULT ChildrenOf(Symbol *pSym, std::vector<CComPtr<Symbol>> *pChildren) const;
+  HRESULT DbgScopeOf(const llvm::Instruction *instr, SymbolChildrenEnumerator **ppRet) const;
+
+private:
+  HRESULT ChildrenOf(DWORD ID, std::vector<CComPtr<Symbol>> *pChildren) const;
+
+  // Not a CComPtr, and not AddRef'd - m_pSession is the owner of this.
+  Session *m_pSession = nullptr;
+
+  // Vector of all symbols in the DXIL module.
+  std::vector<CreateSymbolFn> m_symbolCtors;
+
+  // Mapping from scope to its ID.
+  ScopeToIDMap m_scopeToID;
+
+  // Mapping from symbol ID to live range. Globals are live [0, end),
+  // locals, [first dbg.declare, end of scope)
+  // TODO: the live range information assumes structured dxil - which should hold
+  // for non-optimized code - so we need something more robust. For now, this is
+  // good enough.
+  IDToLiveRangeMap m_symbolToLiveRange;
+
+  ParentToChildrenMap m_parentToChildren;
+};
+}  // namespace dxil_dia

+ 19 - 18
lib/DxilDia/DxilDiaTable.cpp

@@ -25,22 +25,23 @@ HRESULT dxil_dia::Table::Create(
     /* [in] */ Session *pSession,
     /* [in] */ Table::Kind kind,
     /* [out] */ IDiaTable **ppTable) {
-  *ppTable = nullptr;
-  IMalloc *pMalloc = pSession->GetMallocNoRef();
-  switch (kind) {
-  case Table::Kind::Symbols: *ppTable = CreateOnMalloc<SymbolsTable>(pMalloc, pSession); break;
-  case Table::Kind::SourceFiles: *ppTable = CreateOnMalloc<SourceFilesTable>(pMalloc, pSession); break;
-  case Table::Kind::LineNumbers: *ppTable = CreateOnMalloc<LineNumbersTable>(pMalloc, pSession); break;
-  case Table::Kind::Sections: *ppTable = CreateOnMalloc<SectionsTable>(pMalloc, pSession); break;
-  case Table::Kind::SegmentMap: *ppTable = CreateOnMalloc<SegmentMapTable>(pMalloc, pSession); break;
-  case Table::Kind::InjectedSource: *ppTable = CreateOnMalloc<InjectedSourcesTable>(pMalloc, pSession); break;
-  case Table::Kind::FrameData: *ppTable = CreateOnMalloc<FrameDataTable>(pMalloc, pSession); break;
-  case Table::Kind::InputAssemblyFile: *ppTable = CreateOnMalloc<InputAssemblyFilesTable>(pMalloc, pSession); break;
-  default: return E_FAIL;
-  }
-  if (*ppTable == nullptr)
-    return E_OUTOFMEMORY;
-  (*ppTable)->AddRef();
-  return S_OK;
-  return E_NOTIMPL;
+  try {
+    *ppTable = nullptr;
+    IMalloc *pMalloc = pSession->GetMallocNoRef();
+    switch (kind) {
+    case Table::Kind::Symbols: *ppTable = CreateOnMalloc<SymbolsTable>(pMalloc, pSession); break;
+    case Table::Kind::SourceFiles: *ppTable = CreateOnMalloc<SourceFilesTable>(pMalloc, pSession); break;
+    case Table::Kind::LineNumbers: *ppTable = CreateOnMalloc<LineNumbersTable>(pMalloc, pSession); break;
+    case Table::Kind::Sections: *ppTable = CreateOnMalloc<SectionsTable>(pMalloc, pSession); break;
+    case Table::Kind::SegmentMap: *ppTable = CreateOnMalloc<SegmentMapTable>(pMalloc, pSession); break;
+    case Table::Kind::InjectedSource: *ppTable = CreateOnMalloc<InjectedSourcesTable>(pMalloc, pSession); break;
+    case Table::Kind::FrameData: *ppTable = CreateOnMalloc<FrameDataTable>(pMalloc, pSession); break;
+    case Table::Kind::InputAssemblyFile: *ppTable = CreateOnMalloc<InputAssemblyFilesTable>(pMalloc, pSession); break;
+    default: return E_FAIL;
+    }
+    if (*ppTable == nullptr)
+      return E_OUTOFMEMORY;
+    (*ppTable)->AddRef();
+    return S_OK;
+  } CATCH_CPP_RETURN_HRESULT();
 }

+ 15 - 0
lib/DxilDia/DxilDiaTable.h

@@ -15,6 +15,7 @@
 
 #include "dia2.h"
 
+#include "dxc/Support/Global.h"
 #include "dxc/Support/microcom.h"
 
 #include "DxilDia.h"
@@ -47,6 +48,19 @@ namespace impl {
 
 template<typename T, typename TItem>
 class TableBase : public IDiaTable, public T {
+public:
+  // COM Interfaces do not have virtual destructors; they instead rely on
+  // AddRef/Release matching calls for managing object lifetimes. This
+  // template is inherited by the implementing table types (which is fine),
+  // and it also provides the base implementation of the COM's memory
+  // management callbacks (which is not fine: once a table goes out of scope
+  // a method in this class will invoke the object's destructor -- which, being
+  // non-virtual, will be this class' instead of the derived table's.) Therefore,
+  // we introduce a virtual destructor.
+  virtual ~TableBase() {
+    DXASSERT(m_dwRef == 0, "deleting COM table with active references");
+  }
+
 protected:
   static constexpr LPCWSTR TableNames[] = {
     L"Symbols",
@@ -64,6 +78,7 @@ protected:
   unsigned m_next;
   unsigned m_count;
   Table::Kind m_kind;
+
 public:
   DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
 

+ 53 - 1
lib/DxilDia/DxilDiaTableLineNumbers.cpp

@@ -64,9 +64,61 @@ STDMETHODIMP dxil_dia::LineNumber::get_columnNumberEnd(
   return S_OK;
 }
 
+STDMETHODIMP dxil_dia::LineNumber::get_addressOffset(
+  /* [retval][out] */ DWORD *pRetVal) {
+  return get_relativeVirtualAddress(pRetVal);
+}
+
 STDMETHODIMP dxil_dia::LineNumber::get_relativeVirtualAddress(
   /* [retval][out] */ DWORD *pRetVal) {
-  *pRetVal = m_pSession->RvaMapRef()[m_inst];
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = 0;
+
+  const auto &rvaMap = m_pSession->RvaMapRef();
+  auto it = rvaMap.find(m_inst);
+  if (it == rvaMap.end()) {
+    return E_FAIL;
+  }
+
+  *pRetVal = it->second;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::LineNumber::get_length(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = 1;
+
+  if (llvm::DebugLoc DL = m_inst->getDebugLoc()) {
+    const auto &LineToColumn = m_pSession->LineToColumnStartMapRef();
+    auto it = LineToColumn.find(DL.getLine());
+    if (it != LineToColumn.end()) {
+      *pRetVal = it->second.Last - it->second.First;
+    }
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::LineNumber::get_statement(
+  /* [retval][out] */ BOOL *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = FALSE;
+
+  if (llvm::DebugLoc DL = m_inst->getDebugLoc()) {
+    const auto &LineToColumn = m_pSession->LineToColumnStartMapRef();
+    auto it = LineToColumn.find(DL.getLine());
+    if (it != LineToColumn.end()) {
+      *pRetVal = it->second.StartCol == DL.getCol();
+    }
+  }
+
   return S_OK;
 }
 

+ 5 - 3
lib/DxilDia/DxilDiaTableLineNumbers.h

@@ -48,6 +48,8 @@ public:
 
   const llvm::DebugLoc &DL() const;
 
+  const llvm::Instruction *Inst() const { return m_inst; }
+
   STDMETHODIMP get_compiland(
     /* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
 
@@ -70,7 +72,7 @@ public:
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_addressOffset(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_relativeVirtualAddress(
     /* [retval][out] */ DWORD *pRetVal) override;
@@ -79,13 +81,13 @@ public:
     /* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_length(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_sourceFileId(
     /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_statement(
-    /* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ BOOL *pRetVal) override;
 
   STDMETHODIMP get_compilandId(
     /* [retval][out] */ DWORD *pRetVal) override;

+ 19 - 10
lib/DxilDia/DxilDiaTableSourceFiles.cpp

@@ -44,14 +44,23 @@ dxil_dia::SourceFilesTable::SourceFilesTable(
     m_items.assign(m_count, nullptr);
   }
 
-  HRESULT dxil_dia::SourceFilesTable::GetItem(DWORD index, IDiaSourceFile **ppItem) {
-    if (!m_items[index]) {
-      m_items[index] = CreateOnMalloc<SourceFile>(m_pMalloc, m_pSession, index);
-      if (m_items[index] == nullptr)
-        return E_OUTOFMEMORY;
-    }
-    m_items[index].p->AddRef();
-    *ppItem = m_items[index];
-    (*ppItem)->AddRef();
-    return S_OK;
+dxil_dia::SourceFilesTable::SourceFilesTable(
+    IMalloc *pMalloc,
+    Session *pSession,
+    std::vector<CComPtr<IDiaSourceFile>> &&items)
+    : impl::TableBase<IDiaEnumSourceFiles, IDiaSourceFile>(pMalloc, pSession, Table::Kind::SourceFiles),
+      m_items(std::move(items)) {
+    m_count = m_items.size();
+}
+
+HRESULT dxil_dia::SourceFilesTable::GetItem(DWORD index, IDiaSourceFile **ppItem) {
+  if (!m_items[index]) {
+    m_items[index] = CreateOnMalloc<SourceFile>(m_pMalloc, m_pSession, index);
+    if (m_items[index] == nullptr)
+      return E_OUTOFMEMORY;
   }
+  m_items[index].p->AddRef();
+  *ppItem = m_items[index];
+  (*ppItem)->AddRef();
+  return S_OK;
+}

+ 2 - 0
lib/DxilDia/DxilDiaTableSourceFiles.h

@@ -69,6 +69,8 @@ public:
 class SourceFilesTable : public impl::TableBase<IDiaEnumSourceFiles, IDiaSourceFile> {
 public:
   SourceFilesTable(IMalloc *pMalloc, Session *pSession);
+  SourceFilesTable(IMalloc *pMalloc, Session *pSession,
+                   std::vector<CComPtr<IDiaSourceFile>> &&items);
 
   HRESULT GetItem(DWORD index, IDiaSourceFile **ppItem) override;
 

+ 353 - 93
lib/DxilDia/DxilDiaTableSymbols.cpp

@@ -14,28 +14,30 @@
 #include <comdef.h>
 
 #include "dxc/Support/Unicode.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_os_ostream.h"
 
 #include "DxilDiaSession.h"
 
-HRESULT dxil_dia::Symbol::Create(IMalloc *pMalloc, Session *pSession, DWORD index, DWORD symTag, Symbol **pSymbol) {
-  *pSymbol = Alloc(pMalloc);
-  if (*pSymbol == nullptr) return E_OUTOFMEMORY;
-  (*pSymbol)->AddRef();
-  (*pSymbol)->Init(pSession, index, symTag);
-  return S_OK;
-}
+dxil_dia::Symbol::~Symbol() = default;
 
-void dxil_dia::Symbol::Init(Session *pSession, DWORD index, DWORD symTag) {
+void dxil_dia::Symbol::Init(Session *pSession, DWORD ID, DWORD symTag) {
+  DXASSERT_ARGS(m_pSession == nullptr, "Double init on symbol %d", ID);
   m_pSession = pSession;
-  m_index = index;
+  m_ID = ID;
   m_symTag = symTag;
 }
 
 STDMETHODIMP dxil_dia::Symbol::get_symIndexId(
   /* [retval][out] */ DWORD *pRetVal) {
-  *pRetVal = m_index;
+  *pRetVal = m_ID;
   return S_OK;
 }
 
@@ -47,119 +49,377 @@ STDMETHODIMP dxil_dia::Symbol::get_symTag(
 
 STDMETHODIMP dxil_dia::Symbol::get_name(
   /* [retval][out] */ BSTR *pRetVal) {
+  DxcThreadMalloc TM(m_pSession->GetMallocNoRef());
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = nullptr;
+  if (!m_hasName) {
+    return S_FALSE;
+  }
   return m_name.CopyTo(pRetVal);
 }
 
+STDMETHODIMP dxil_dia::Symbol::get_lexicalParent(
+  /* [retval][out] */ IDiaSymbol **pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = nullptr;
+
+  DWORD dwParentID = this->m_lexicalParent;
+  if (dwParentID == 0) {
+    return S_FALSE;
+  }
+
+  Symbol *pParent;
+  IFR(m_pSession->SymMgr().GetSymbolByID(dwParentID, &pParent));
+
+  *pRetVal = pParent;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_type(
+  /* [retval][out] */ IDiaSymbol **pRetVal) {
+  return S_FALSE;
+}
+
 STDMETHODIMP dxil_dia::Symbol::get_dataKind(
   /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = 0;
+  if (!m_hasDataKind) {
+    return S_FALSE;
+  }
   *pRetVal = m_dataKind;
   return m_dataKind ? S_OK : S_FALSE;
 }
 
+STDMETHODIMP dxil_dia::Symbol::get_locationType(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = LocIsNull;
+  return S_FALSE;
+}
+
 STDMETHODIMP dxil_dia::Symbol::get_sourceFileName(
   /* [retval][out] */ BSTR *pRetVal) {
   if (pRetVal == nullptr) {
     return E_INVALIDARG;
   }
+  *pRetVal = nullptr;
+  if (!m_hasSourceFileName) {
+    return S_FALSE;
+  }
   *pRetVal = m_sourceFileName.Copy();
   return S_OK;
 }
 
 STDMETHODIMP dxil_dia::Symbol::get_value(
   /* [retval][out] */ VARIANT *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  ZeroMemory(pRetVal, sizeof(*pRetVal));
+  if (!m_hasValue) {
+    return S_FALSE;
+  }
   return VariantCopy(pRetVal, &m_value);
 }
 
-dxil_dia::SymbolsTable::SymbolsTable(IMalloc *pMalloc, Session *pSession)
-  : impl::TableBase<IDiaEnumSymbols, IDiaSymbol>(pMalloc, pSession, Table::Kind::Symbols) {
-    // The count is as follows:
-    // One symbol for the program.
-    // One Compiland per compilation unit.
-    // One CompilandDetails per compilation unit.
-    // Three CompilandEnv per Compliands: hlslFlags, hlslTarget, hlslEntry, hlslDefines, hlslArguments.
-    // One Function/Data for each global.
-    // One symbol for each type.
-  const size_t SymbolsPerCU = 1 + 1 + 5;
-  m_count = 1 + pSession->InfoRef().compile_unit_count() * SymbolsPerCU;
+STDMETHODIMP dxil_dia::Symbol::get_baseType(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal != nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = btNoType;
+  return S_FALSE;
 }
 
-HRESULT dxil_dia::SymbolsTable::GetItem(DWORD index, IDiaSymbol **ppItem) {
+STDMETHODIMP dxil_dia::Symbol::get_count(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_offset(
+  /* [retval][out] */ LONG *pRetVal) {
+  if (pRetVal != nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_length(
+  /* [retval][out] */ ULONGLONG *pRetVal) {
+  if (pRetVal != nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_lexicalParentId(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = 0;
+  if (!m_hasLexicalParent) {
+    return S_FALSE;
+  }
+  *pRetVal = m_lexicalParent;
+  return S_OK;
+}
+
+void dxil_dia::SymbolChildrenEnumerator::Init(std::vector<CComPtr<Symbol>> &&syms) {
+  std::swap(syms, m_symbols);
+  m_pos = m_symbols.begin();
+}
+
+HRESULT STDMETHODCALLTYPE dxil_dia::SymbolChildrenEnumerator::get_Count(
+  /* [retval][out] */ LONG *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = m_symbols.size();
+  return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE dxil_dia::SymbolChildrenEnumerator::Item(
+  /* [in] */ DWORD index,
+  /* [retval][out] */ IDiaSymbol **symbol) {
+  if (symbol == nullptr) {
+    return E_INVALIDARG;
+  }
+  *symbol = nullptr;
+
+  if (index < 0 || index > m_symbols.size()) {
+    return E_INVALIDARG;
+  }
+
+  *symbol = m_symbols[index];
+  (*symbol)->AddRef();
+  return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE dxil_dia::SymbolChildrenEnumerator::Reset(void) {
+  m_pos = m_symbols.begin();
+  return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE dxil_dia::SymbolChildrenEnumerator::Next(
+  /* [in] */ ULONG celt,
+  /* [out] */ IDiaSymbol **rgelt,
+  /* [out] */ ULONG *pceltFetched) {
   DxcThreadMalloc TM(m_pMalloc);
+  if (rgelt == nullptr || pceltFetched == nullptr) {
+    return E_INVALIDARG;
+  }
 
-  // Ids are one-based, so adjust the index.
-  ++index;
-
-  // Program symbol.
-  CComPtr<Symbol> item;
-  if (index == HlslProgramId) {
-    IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagExe, &item));
-    item->SetName(L"HLSL");
-  } else if (index == HlslCompilandId) {
-    IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompiland, &item));
-    item->SetName(L"main");
-    item->SetLexicalParent(HlslProgramId);
-    if (m_pSession->MainFileName()) {
-      llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(m_pSession->MainFileName()->getOperand(0)->getOperand(0))->getString();
-      std::string str(strRef.begin(), strRef.size()); // To make sure str is null terminated
-      item->SetSourceFileName(_bstr_t(Unicode::UTF8ToUTF16StringOrThrow(str.data()).c_str()));
-    }
-  } else if (index == HlslCompilandDetailsId) {
-    IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandDetails, &item));
-    item->SetLexicalParent(HlslCompilandId);
-    // TODO: complete the rest of the compiland details
-    // platform: 256, language: 16, frontEndMajor: 6, frontEndMinor: 3, value: 0, hasDebugInfo: 1, compilerName: comiler string goes here
-  } else if (index == HlslCompilandEnvFlagsId) {
-    IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
-    item->SetLexicalParent(HlslCompilandId);
-    item->SetName(L"hlslFlags");
-    item->SetValue(m_pSession->DxilModuleRef().GetGlobalFlags());
-  } else if (index == HlslCompilandEnvTargetId) {
-    IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
-    item->SetLexicalParent(HlslCompilandId);
-    item->SetName(L"hlslTarget");
-    item->SetValue(m_pSession->DxilModuleRef().GetShaderModel()->GetName());
-  } else if (index == HlslCompilandEnvEntryId) {
-    IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
-    item->SetLexicalParent(HlslCompilandId);
-    item->SetName(L"hlslEntry");
-    item->SetValue(m_pSession->DxilModuleRef().GetEntryFunctionName().c_str());
-  } else if (index == HlslCompilandEnvDefinesId) {
-    IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
-    item->SetLexicalParent(HlslCompilandId);
-    item->SetName(L"hlslDefines");
-    llvm::MDNode *definesNode = m_pSession->Defines()->getOperand(0);
-    // Construct a double null terminated string for defines with L"\0" as a delimiter
-    CComBSTR pBSTR;
-    for (llvm::MDNode::op_iterator it = definesNode->op_begin(); it != definesNode->op_end(); ++it) {
-      llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(*it)->getString();
-      std::string str(strRef.begin(), strRef.size());
-      CA2W cv(str.c_str());
-      pBSTR.Append(cv);
-      pBSTR.Append(L"\0", 1);
+  *pceltFetched = 0;
+  ZeroMemory(rgelt, sizeof(*rgelt) * celt);
+
+  for (; *pceltFetched < celt && m_pos != m_symbols.end(); ++m_pos, ++rgelt, ++(*pceltFetched)) {
+    *rgelt = *m_pos;
+    (*rgelt)->AddRef();
+  }
+
+  return (*pceltFetched == celt) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::findChildren(
+  /* [in] */ enum SymTagEnum symtag,
+  /* [in] */ LPCOLESTR name,
+  /* [in] */ DWORD compareFlags,
+  /* [out] */ IDiaEnumSymbols **ppResult) {
+  return findChildrenEx(symtag, name, compareFlags, ppResult);;
+}
+
+STDMETHODIMP dxil_dia::Symbol::findChildrenEx(
+  /* [in] */ enum SymTagEnum symtag,
+  /* [in] */ LPCOLESTR name,
+  /* [in] */ DWORD compareFlags,
+  /* [out] */ IDiaEnumSymbols **ppResult)  {
+  DxcThreadMalloc TM(m_pMalloc);
+  if (ppResult == nullptr) {
+    return E_INVALIDARG;
+  }
+  *ppResult = nullptr;
+
+  CComPtr<SymbolChildrenEnumerator> ret = SymbolChildrenEnumerator::Alloc(m_pMalloc);
+  if (!ret) {
+    return E_OUTOFMEMORY;
+  }
+
+  std::vector<CComPtr<Symbol>> children;
+  IFR(GetChildren(&children));
+
+  if (symtag != nsNone) {
+    std::vector<CComPtr<Symbol>> tmp;
+    tmp.reserve(children.size());
+    for (const auto & c : children) {
+      if (c->m_symTag == symtag) {
+        tmp.emplace_back(c);
+      }
     }
-    pBSTR.Append(L"\0", 1);
-    VARIANT Variant;
-    Variant.bstrVal = pBSTR;
-    Variant.vt = VARENUM::VT_BSTR;
-    item->SetValue(&Variant);
-  } else if (index == HlslCompilandEnvArgumentsId) {
-    IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
-    item->SetLexicalParent(HlslCompilandId);
-    item->SetName(L"hlslArguments");
-    auto Arguments = m_pSession->Arguments()->getOperand(0);
-    auto NumArguments = Arguments->getNumOperands();
-    std::string args;
-    for (unsigned i = 0; i < NumArguments; ++i) {
-      llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(Arguments->getOperand(i))->getString();
-      if (!args.empty())
-        args.push_back(' ');
-      args = args + strRef.str();
+    std::swap(tmp, children);
+  }
+
+  if (name != nullptr && compareFlags != nsNone) {
+    std::vector<CComPtr<Symbol>> tmp;
+    tmp.reserve(children.size());
+    for (const auto & c : children) {
+      CComBSTR cName;
+      IFR(c->get_name(&cName));
+      if (compareFlags == nsfCaseInsensitive && StrCmpW(cName, name) != 0) {
+        continue;
+      } else if (compareFlags == nsfCaseSensitive && StrCmpIW(cName, name) != 0) {
+        continue;
+      }
+
+      if (c->m_symTag == symtag) {
+        tmp.emplace_back(c);
+      }
     }
-    item->SetValue(args.c_str());
+    std::swap(tmp, children);
   }
 
-  // TODO: add support for global data and functions as well as types.
+  ret->Init(std::move(children));
 
-  *ppItem = item.Detach();
-  return (*ppItem == nullptr) ? E_FAIL : S_OK;
+  *ppResult = ret.Detach();
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_isAggregated(
+  /* [retval][out] */ BOOL *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = false;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_registerType(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_sizeInUdt(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_liveRangeStartAddressOffset(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = 0;
+
+  SymbolManager::LiveRange LR;
+  IFR(m_pSession->SymMgr().GetLiveRangeOf(this, &LR));
+  *pRetVal = LR.Start;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_liveRangeLength(
+  /* [retval][out] */ ULONGLONG *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = 0;
+
+  SymbolManager::LiveRange LR;
+  IFR(m_pSession->SymMgr().GetLiveRangeOf(this, &LR));
+  *pRetVal = LR.Length;
+  return S_OK;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_offsetInUdt(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_numericProperties(
+  /* [in] */ DWORD cnt,
+  /* [out] */ DWORD *pcnt,
+  /* [size_is][out] */ DWORD *pProperties) {
+  if (pcnt == nullptr || pProperties == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  ZeroMemory(pProperties, sizeof(*pProperties) * cnt);
+  *pcnt = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_numberOfRegisterIndices(
+  /* [retval][out] */ DWORD *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+
+  *pRetVal = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP dxil_dia::Symbol::get_isHLSLData(
+  /* [retval][out] */ BOOL *pRetVal) {
+  if (pRetVal == nullptr) {
+    return E_INVALIDARG;
+  }
+  *pRetVal = false;
+  if (!m_hasIsHLSLData) {
+    return S_FALSE;
+  }
+  *pRetVal = m_isHLSLData;
+  return S_OK;
+}
+
+dxil_dia::SymbolsTable::SymbolsTable(IMalloc *pMalloc, Session *pSession)
+  : impl::TableBase<IDiaEnumSymbols, IDiaSymbol>(pMalloc, pSession, Table::Kind::Symbols) {
+  m_count = pSession->SymMgr().NumSymbols();
+}
+
+HRESULT dxil_dia::SymbolsTable::GetItem(DWORD index, IDiaSymbol **ppItem) {
+  if (ppItem == nullptr) {
+    return E_INVALIDARG;
+  }
+  *ppItem = nullptr;
+
+  Symbol *ret = nullptr;
+  const DWORD dwSymID = index + 1;
+  IFR(m_pSession->SymMgr().GetSymbolByID(dwSymID, &ret));
+
+  *ppItem = ret;
+  return S_OK;
 }

+ 93 - 32
lib/DxilDia/DxilDiaTableSymbols.h

@@ -13,6 +13,8 @@
 
 #include "dxc/Support/WinIncludes.h"
 
+#include <vector>
+
 #include "dia2.h"
 
 #include "dxc/Support/Global.h"
@@ -26,32 +28,50 @@ class Session;
 
 class Symbol : public IDiaSymbol {
   DXC_MICROCOM_TM_REF_FIELDS()
+
+protected:
+  DXC_MICROCOM_TM_CTOR_ONLY(Symbol)
+
     CComPtr<Session> m_pSession;
-  DWORD m_index;
+
+private:
+  DWORD m_ID;
   DWORD m_symTag;
+  bool m_hasLexicalParent = false;
   DWORD m_lexicalParent = 0;
+  bool m_hasIsHLSLData = false;
+  bool m_isHLSLData = false;
+  bool m_hasDataKind = false;
   DWORD m_dataKind = 0;
+  bool m_hasSourceFileName = false;
   CComBSTR m_sourceFileName;
+  bool m_hasName = false;
   CComBSTR m_name;
+  bool m_hasValue = false;
   CComVariant m_value;
+
 public:
+  virtual ~Symbol();
   DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
-    DXC_MICROCOM_TM_CTOR(Symbol)
-    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) final {
     return DoBasicQueryInterface<IDiaSymbol>(this, iid, ppvObject);
   }
 
-  static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD index, DWORD symTag, Symbol **pSymbol);
-
   void Init(Session *pSession, DWORD index, DWORD symTag);
 
-  void SetDataKind(DWORD value) { m_dataKind = value; }
-  void SetLexicalParent(DWORD value) { m_lexicalParent = value; }
-  void SetName(LPCWSTR value) { m_name = value; }
-  void SetValue(LPCSTR value) { m_value = value; }
-  void SetValue(VARIANT *pValue) { m_value.Copy(pValue); }
-  void SetValue(unsigned value) { m_value = value; }
-  void SetSourceFileName(BSTR value) { m_sourceFileName = value; }
+  DWORD GetID() const { return m_ID; }
+
+  void SetDataKind(DWORD value) { m_hasDataKind = true; m_dataKind = value; }
+  void SetLexicalParent(DWORD value) { m_hasLexicalParent = true; m_lexicalParent = value; }
+  bool HasName() const { return m_hasName; }
+  void SetName(LPCWSTR value) { m_hasName = true; m_name = value; }
+  void SetValue(LPCSTR value) { m_hasValue = true; m_value = value; }
+  void SetValue(VARIANT *pValue) { m_hasValue = true; m_value.Copy(pValue); }
+  void SetValue(unsigned value) { m_hasValue = true; m_value = value; }
+  void SetSourceFileName(BSTR value) { m_hasSourceFileName = true; m_sourceFileName = value; }
+  void SetIsHLSLData(bool value) { m_hasIsHLSLData = true; m_isHLSLData = value; }
+
+  virtual HRESULT GetChildren(std::vector<CComPtr<Symbol>> *children) = 0;
 
 #pragma region IDiaSymbol implementation.
   STDMETHODIMP get_symIndexId(
@@ -64,19 +84,19 @@ public:
     /* [retval][out] */ BSTR *pRetVal) override;
 
   STDMETHODIMP get_lexicalParent(
-    /* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ IDiaSymbol **pRetVal) override;
 
   STDMETHODIMP get_classParent(
     /* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_type(
-    /* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ IDiaSymbol **pRetVal) override;
 
   STDMETHODIMP get_dataKind(
     /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_locationType(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_addressSection(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -94,10 +114,10 @@ public:
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_offset(
-    /* [retval][out] */ LONG *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ LONG *pRetVal) override;
 
   STDMETHODIMP get_length(
-    /* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ ULONGLONG *pRetVal) override;
 
   STDMETHODIMP get_slot(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -175,7 +195,7 @@ public:
     /* [retval][out] */ VARIANT *pRetVal) override;
 
   STDMETHODIMP get_baseType(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_token(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -193,7 +213,7 @@ public:
     /* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_count(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_bitPosition(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -238,7 +258,7 @@ public:
     /* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_lexicalParentId(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_classParentId(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -306,13 +326,13 @@ public:
     /* [in] */ enum SymTagEnum symtag,
     /* [in] */ LPCOLESTR name,
     /* [in] */ DWORD compareFlags,
-    /* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
+    /* [out] */ IDiaEnumSymbols **ppResult) override;
 
   STDMETHODIMP findChildrenEx(
     /* [in] */ enum SymTagEnum symtag,
     /* [in] */ LPCOLESTR name,
     /* [in] */ DWORD compareFlags,
-    /* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
+    /* [out] */ IDiaEnumSymbols **ppResult) override;
 
   STDMETHODIMP findChildrenExByAddr(
     /* [in] */ enum SymTagEnum symtag,
@@ -441,7 +461,7 @@ public:
     /* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_isAggregated(
-    /* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ BOOL *pRetVal) override;
 
   STDMETHODIMP get_isSplitted(
     /* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
@@ -522,7 +542,7 @@ public:
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_liveRangeStartAddressOffset(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_liveRangeStartRelativeVirtualAddress(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -531,10 +551,10 @@ public:
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_liveRangeLength(
-    /* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ ULONGLONG *pRetVal) override;
 
   STDMETHODIMP get_offsetInUdt(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_paramBasePointerRegisterId(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -560,7 +580,7 @@ public:
   STDMETHODIMP get_numericProperties(
     /* [in] */ DWORD cnt,
     /* [out] */ DWORD *pcnt,
-    /* [size_is][out] */ DWORD *pProperties) override { return ENotImpl(); }
+    /* [size_is][out] */ DWORD *pProperties) override;
 
   STDMETHODIMP get_modifierValues(
     /* [in] */ DWORD cnt,
@@ -577,7 +597,7 @@ public:
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_registerType(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_baseDataSlot(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -595,7 +615,7 @@ public:
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_sizeInUdt(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_memorySpaceKind(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
@@ -613,10 +633,10 @@ public:
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
 
   STDMETHODIMP get_numberOfRegisterIndices(
-    /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ DWORD *pRetVal) override;
 
   STDMETHODIMP get_isHLSLData(
-    /* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
+    /* [retval][out] */ BOOL *pRetVal) override;
 
   STDMETHODIMP get_isPointerToDataMember(
     /* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
@@ -808,7 +828,48 @@ public:
   STDMETHODIMP get_bindSlot(
     /* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
 
-#pragma endregion IDiaSymbol implementation.
+#pragma endregion
+};
+
+class SymbolChildrenEnumerator : public IDiaEnumSymbols {
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_CTOR(SymbolChildrenEnumerator)
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDiaEnumSymbols>(this, iid, ppvObject);
+  }
+
+  void Init(std::vector<CComPtr<Symbol>> &&syms);
+
+#pragma region IDiaEnumSymbols implementation
+  /* [id][helpstring][propget] */ HRESULT STDMETHODCALLTYPE get__NewEnum(
+    /* [retval][out] */ IUnknown **pRetVal) override { return ENotImpl(); }
+
+  /* [id][helpstring][propget] */ HRESULT STDMETHODCALLTYPE get_Count(
+    /* [retval][out] */ LONG *pRetVal) override;
+
+  /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Item(
+    /* [in] */ DWORD index,
+    /* [retval][out] */ IDiaSymbol **symbol) override;
+
+  HRESULT STDMETHODCALLTYPE Next(
+    /* [in] */ ULONG celt,
+    /* [out] */ IDiaSymbol **rgelt,
+    /* [out] */ ULONG *pceltFetched) override;
+
+  HRESULT STDMETHODCALLTYPE Skip(
+    /* [in] */ ULONG celt) override { return ENotImpl(); }
+
+  HRESULT STDMETHODCALLTYPE Reset(void) override;
+
+  HRESULT STDMETHODCALLTYPE Clone(
+    /* [out] */ IDiaEnumSymbols **ppenum) override { return ENotImpl(); }
+#pragma endregion
+
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  std::vector<CComPtr<Symbol>> m_symbols;
+  std::vector<CComPtr<Symbol>>::iterator m_pos;
 };
 
 class SymbolsTable : public impl::TableBase<IDiaEnumSymbols, IDiaSymbol> {

+ 1 - 1
lib/DxilDia/LLVMBuild.txt

@@ -13,4 +13,4 @@
 type = Library
 name = DxilDia
 parent = Libraries
-required_libraries = Core DxcSupport Support
+required_libraries = Core DxilPIXPasses DxcSupport Support

+ 22 - 7
lib/DxilPIXPasses/DxilAnnotateWithVirtualRegister.cpp

@@ -10,11 +10,11 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-#include "dxc/DxilPIXPasses/DxilPIXPasses.h"
-
 #include <memory>
 
 #include "dxc/DXIL/DxilModule.h"
+#include "dxc/DxilPIXPasses/DxilPIXPasses.h"
+#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
 #include "dxc/Support/Global.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
@@ -30,8 +30,6 @@
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
 
-#include "DxilPIXVirtualRegisters.h"
-
 #define DEBUG_TYPE "dxil-annotate-with-virtual-regs"
 
 namespace {
@@ -70,12 +68,26 @@ bool DxilAnnotateWithVirtualRegister::runOnModule(llvm::Module &M) {
   }
 
   if (OSOverride != nullptr) {
-    *OSOverride << "\nBegin - dxil values to virtual register mapping\n";
+    *OSOverride << "\nBegin - instruction ID to line\n";
   }
 
   std::uint32_t InstNum = 0;
   for (llvm::Instruction &I : llvm::inst_range(m_DM->GetEntryFunction())) {
-    pix_dxil::PixDxilInstNum::AddMD(M.getContext(), &I, ++InstNum);
+    if (OSOverride != nullptr) {
+      *OSOverride << InstNum << ' ';
+      I.print(*OSOverride);
+      *OSOverride << "\n";
+    }
+    pix_dxil::PixDxilInstNum::AddMD(M.getContext(), &I, InstNum++);
+  }
+
+  if (OSOverride != nullptr) {
+    *OSOverride << "\nEnd - instruction ID to line\n";
+  }
+
+
+  if (OSOverride != nullptr) {
+    *OSOverride << "\nBegin - dxil values to virtual register mapping\n";
   }
 
   for (llvm::Instruction &I : llvm::inst_range(m_DM->GetEntryFunction())) {
@@ -165,7 +177,10 @@ bool DxilAnnotateWithVirtualRegister::IsAllocaRegisterWrite(llvm::Value *V, llvm
 
 void DxilAnnotateWithVirtualRegister::AnnotateAlloca(llvm::AllocaInst *pAlloca) {
   llvm::Type *pAllocaTy = pAlloca->getType()->getElementType();
-  if (pAllocaTy->isFloatTy() || pAllocaTy->isIntegerTy()) {
+  if (pAllocaTy->isFloatTy() ||
+      pAllocaTy->isIntegerTy() ||
+      pAllocaTy->isHalfTy() ||
+      pAllocaTy->isIntegerTy(16)) {
     AssignNewAllocaRegister(pAlloca, 1);
   } else if (auto *AT = llvm::dyn_cast<llvm::ArrayType>(pAllocaTy)) {
     AssignNewAllocaRegister(pAlloca, AT->getNumElements());

+ 1 - 2
lib/DxilPIXPasses/DxilDebugInstrumentation.cpp

@@ -13,6 +13,7 @@
 #include "dxc/DXIL/DxilModule.h"
 #include "dxc/DXIL/DxilOperations.h"
 #include "dxc/DxilPIXPasses/DxilPIXPasses.h"
+#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
 #include "dxc/DXIL/DxilUtil.h"
 
 #include "llvm/IR/Module.h"
@@ -21,8 +22,6 @@
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/ADT/STLExtras.h"
 
-#include "DxilPIXVirtualRegisters.h"
-
 using namespace llvm;
 using namespace hlsl;
 

+ 13 - 1
lib/DxilPIXPasses/DxilPIXVirtualRegisters.cpp

@@ -10,7 +10,7 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-#include "DxilPIXVirtualRegisters.h"
+#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
 
 #include "dxc/Support/Global.h"
 #include "llvm/IR/Constant.h"
@@ -123,6 +123,18 @@ void pix_dxil::PixAllocaReg::AddMD(llvm::LLVMContext &Ctx, llvm::AllocaInst *pAl
                                llvm::ConstantAsMetadata::get(B.getInt32(Count)) }));
 }
 
+bool pix_dxil::PixAllocaReg::FromInst(llvm::AllocaInst *pAlloca, std::uint32_t *pRegBase, std::uint32_t *pRegSize) {
+  *pRegBase = 0;
+  *pRegSize = 0;
+
+  auto *mdNodes = pAlloca->getMetadata(MDName);
+  if (mdNodes == nullptr) {
+    return false;
+  }
+
+  return ParsePixAllocaReg(mdNodes, pRegBase, pRegSize);
+}
+
 namespace pix_dxil {
 namespace PixAllocaRegWrite {
 static constexpr uint32_t IndexIsConst = 1;

+ 24 - 12
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -981,7 +981,7 @@ TEST_F(CompilerTest, CompileWhenDebugThenDIPresent) {
   //WEX::Logging::Log::Comment(GetDebugInfoAsText(pDiaSource).c_str());
 
   // Very basic tests - we have basic symbols, line numbers, and files with sources.
-  VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"symIndexId: 5, CompilandEnv, name: hlslTarget, value: ps_6_0"));
+  VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"symIndexId: 5, CompilandEnv, name: hlslTarget, lexicalParent: id=2, value: ps_6_0"));
   VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"lineNumber: 2"));
   VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"length: 99, filename: source.hlsl"));
   std::wstring diaFileContent = GetDebugFileContent(pDiaSource).c_str();
@@ -1013,28 +1013,40 @@ TEST_F(CompilerTest, CompileDebugLines) {
     "  return z;\r\n"
     "}", &pDiaSource));
     
-  const int numExpectedRVAs = 6;
+  static constexpr uint32_t numExpectedRVAs = 10;
 
   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[0].line, 1);
-    // 1: abs
+    // 1: dbg.value
     VERIFY_ARE_EQUAL(lines[1].rva,  1);
-    VERIFY_ARE_EQUAL(lines[1].line, 2);
-    // 2: sin
+    VERIFY_ARE_EQUAL(lines[1].line, 1);
+    // 2: abs
     VERIFY_ARE_EQUAL(lines[2].rva,  2);
-    VERIFY_ARE_EQUAL(lines[2].line, 3);
-    // 3: add
+    VERIFY_ARE_EQUAL(lines[2].line, 2);
+    // 3: dbg.value
     VERIFY_ARE_EQUAL(lines[3].rva,  3);
-    VERIFY_ARE_EQUAL(lines[3].line, 4);
-    // 4: storeOutput
+    VERIFY_ARE_EQUAL(lines[3].line, 2);
+    // 4: sin
     VERIFY_ARE_EQUAL(lines[4].rva,  4);
-    VERIFY_ARE_EQUAL(lines[4].line, 5);
-    // 5: ret
+    VERIFY_ARE_EQUAL(lines[4].line, 3);
+    // 5: dbg.value
     VERIFY_ARE_EQUAL(lines[5].rva,  5);
-    VERIFY_ARE_EQUAL(lines[5].line, 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);
   };
   
   CComPtr<IDiaSession> pSession;