blob: 28a265f2d7c96ceca525ce7910a3fd8a95f6146d [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// 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 <functional>
#include <type_traits>
#include <comdef.h>
#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
#include "dxc/Support/Unicode.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.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/MathExtras.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<N>(M, Node), m_dwTypeID(dwTypeID), m_pType(Type) {}
STDMETHODIMP get_type(
/* [retval][out] */ IDiaSymbol **ppRetVal) override {
if (ppRetVal == nullptr) {
return E_INVALIDARG;
}
*ppRetVal = nullptr;
if (m_pType == nullptr) {
return S_FALSE;
}
Symbol *ret;
IFR(this->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;
};
namespace symbol_factory {
class GlobalScope final : public SymbolManager::SymbolFactory {
public:
GlobalScope(DWORD ID, DWORD ParentID)
: SymbolManager::SymbolFactory(ID, ParentID) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
return hlsl_symbols::GlobalScopeSymbol::Create(pMalloc, pSession, ppRet);
}
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class Compiland final : public SymbolManager::SymbolFactory {
public:
Compiland(DWORD ID, DWORD ParentID, llvm::DICompileUnit *CU)
: SymbolManager::SymbolFactory(ID, ParentID), m_CU(CU) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(hlsl_symbols::CompilandSymbol::Create(pMalloc, pSession, m_CU, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
return S_OK;
}
private:
llvm::DICompileUnit *m_CU;
};
} // namespace symbol_factory
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
};
namespace symbol_factory {
class CompilandDetails final : public SymbolManager::SymbolFactory {
public:
CompilandDetails(DWORD ID, DWORD ParentID)
: SymbolManager::SymbolFactory(ID, ParentID) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(hlsl_symbols::CompilandDetailsSymbol::Create(pMalloc, pSession, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
return S_OK;
}
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
using CompilandEnvCreateFn = HRESULT(IMalloc *, Session *, Symbol **);
template <CompilandEnvCreateFn C>
class CompilandEnv final : public SymbolManager::SymbolFactory {
public:
CompilandEnv(DWORD ID, DWORD ParentID)
: SymbolManager::SymbolFactory(ID, ParentID) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(C(pMalloc, pSession, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
return S_OK;
}
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class Function final : public SymbolManager::SymbolFactory {
public:
Function(DWORD ID, DWORD ParentID, llvm::DISubprogram *Node, DWORD TypeID)
: SymbolManager::SymbolFactory(ID, ParentID), m_Node(Node),
m_TypeID(TypeID) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(FunctionSymbol::Create(pMalloc, pSession, m_ID, m_Node, m_TypeID,
m_Node->getType(), ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
(*ppRet)->SetName(CA2W(m_Node->getName().str().c_str(), CP_UTF8));
return S_OK;
}
private:
llvm::DISubprogram *m_Node;
DWORD m_TypeID;
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class FunctionBlock final : public SymbolManager::SymbolFactory {
public:
FunctionBlock(DWORD ID, DWORD ParentID)
: SymbolManager::SymbolFactory(ID, ParentID) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(FunctionBlockSymbol::Create(pMalloc, pSession, m_ID, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
return S_OK;
}
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class Type final : public SymbolManager::SymbolFactory {
public:
Type(DWORD ID, DWORD ParentID, DWORD st, llvm::DIType *Node,
TypeSymbol::LazySymbolName LazySymbolName)
: SymbolManager::SymbolFactory(ID, ParentID), m_st(st), m_Node(Node),
m_LazySymbolName(LazySymbolName) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(TypeSymbol::Create(pMalloc, pSession, m_ParentID, m_ID, m_st, m_Node,
m_LazySymbolName, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
return S_OK;
}
private:
DWORD m_st;
llvm::DIType *m_Node;
TypeSymbol::LazySymbolName m_LazySymbolName;
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class TypedefType final : public SymbolManager::SymbolFactory {
public:
TypedefType(DWORD ID, DWORD ParentID, llvm::DIType *Node, DWORD BaseTypeID)
: SymbolManager::SymbolFactory(ID, ParentID), m_Node(Node),
m_BaseTypeID(BaseTypeID) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(TypedefTypeSymbol::Create(pMalloc, pSession, m_ParentID, m_ID, m_Node,
m_BaseTypeID, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
(*ppRet)->SetName(CA2W(m_Node->getName().str().c_str(), CP_UTF8));
return S_OK;
}
private:
llvm::DIType *m_Node;
DWORD m_BaseTypeID;
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class VectorType final : public SymbolManager::SymbolFactory {
public:
VectorType(DWORD ID, DWORD ParentID, llvm::DIType *Node, DWORD ElemTyID,
std::uint32_t NumElts)
: SymbolManager::SymbolFactory(ID, ParentID), m_Node(Node),
m_ElemTyID(ElemTyID), m_NumElts(NumElts) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(VectorTypeSymbol::Create(pMalloc, pSession, m_ParentID, m_ID, m_Node,
m_ElemTyID, m_NumElts, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
(*ppRet)->SetName(CA2W(m_Node->getName().str().c_str(), CP_UTF8));
return S_OK;
}
private:
llvm::DIType *m_Node;
DWORD m_ElemTyID;
std::uint32_t m_NumElts;
};
} // namespace symbol_factory
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);
};
namespace symbol_factory {
class UDT final : public SymbolManager::SymbolFactory {
public:
UDT(DWORD ID, DWORD ParentID, llvm::DICompositeType *Node,
TypeSymbol::LazySymbolName LazySymbolName)
: SymbolManager::SymbolFactory(ID, ParentID), m_Node(Node),
m_LazySymbolName(LazySymbolName) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(UDTSymbol::Create(pMalloc, pSession, m_ParentID, m_ID, m_Node,
m_LazySymbolName, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
return S_OK;
}
private:
llvm::DICompositeType *m_Node;
TypeSymbol::LazySymbolName m_LazySymbolName;
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class GlobalVariable final : public SymbolManager::SymbolFactory {
public:
GlobalVariable(DWORD ID, DWORD ParentID, llvm::DIGlobalVariable *GV,
DWORD TypeID, llvm::DIType *Type)
: SymbolManager::SymbolFactory(ID, ParentID), m_GV(GV), m_TypeID(TypeID),
m_Type(Type) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(GlobalVariableSymbol::Create(pMalloc, pSession, m_ID, m_GV, m_TypeID,
m_Type, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
(*ppRet)->SetName(CA2W(m_GV->getName().str().c_str(), CP_UTF8));
(*ppRet)->SetIsHLSLData(true);
return S_OK;
}
private:
llvm::DIGlobalVariable *m_GV;
DWORD m_TypeID;
llvm::DIType *m_Type;
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class LocalVarInfo {
public:
LocalVarInfo() = default;
LocalVarInfo(const LocalVarInfo &) = delete;
LocalVarInfo(LocalVarInfo &&) = 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;
};
class LocalVariable final : public SymbolManager::SymbolFactory {
public:
LocalVariable(DWORD ID, DWORD ParentID, llvm::DIVariable *Node, DWORD TypeID,
llvm::DIType *Type, std::shared_ptr<LocalVarInfo> VI)
: SymbolManager::SymbolFactory(ID, ParentID), m_Node(Node),
m_TypeID(TypeID), m_Type(Type), m_VI(VI) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(LocalVariableSymbol::Create(pMalloc, pSession, m_ID, m_Node, m_TypeID,
m_Type, m_VI->GetOffsetInUDT(),
m_VI->GetDxilRegister(), ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
(*ppRet)->SetName(CA2W(m_Node->getName().str().c_str(), CP_UTF8));
(*ppRet)->SetDataKind(m_Node->getTag() == llvm::dwarf::DW_TAG_arg_variable
? DataIsParam
: DataIsLocal);
return S_OK;
}
private:
llvm::DIVariable *m_Node;
DWORD m_TypeID;
llvm::DIType *m_Type;
std::shared_ptr<LocalVarInfo> m_VI;
};
} // namespace symbol_factory
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;
};
namespace symbol_factory {
class UDTField final : public SymbolManager::SymbolFactory {
public:
UDTField(DWORD ID, DWORD ParentID, llvm::DIDerivedType *Node, DWORD TypeID,
llvm::DIType *Type)
: SymbolManager::SymbolFactory(ID, ParentID), m_Node(Node),
m_TypeID(TypeID), m_Type(Type) {}
virtual HRESULT Create(Session *pSession, Symbol **ppRet) override {
IMalloc *pMalloc = pSession->GetMallocNoRef();
IFR(UDTFieldSymbol::Create(pMalloc, pSession, m_ID, m_Node, m_TypeID,
m_Type, ppRet));
(*ppRet)->SetLexicalParent(m_ParentID);
(*ppRet)->SetName(CA2W(m_Node->getName().str().c_str(), CP_UTF8));
(*ppRet)->SetDataKind(m_Node->isStaticMember() ? DataIsStaticLocal
: DataIsMember);
return S_OK;
}
private:
llvm::DIDerivedType *m_Node;
DWORD m_TypeID;
llvm::DIType *m_Type;
};
} // namespace symbol_factory
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;
TypeInfo(DWORD dwTypeID, uint64_t alignInBits)
: m_dwTypeID(dwTypeID), m_alignInBytes(alignInBits / 8) {}
DWORD GetTypeID() const { return m_dwTypeID; }
DWORD GetCurrentSizeInBytes() const { return m_dwCurrentSizeInBytes; }
uint64_t GetAlignmentInBytes() const { return m_alignInBytes; }
const std::vector<llvm::DIType *> &GetLayout() const { return m_Layout; }
void Embed(const TypeInfo &TI);
void AddBasicType(llvm::DIBasicType *BT);
void AppendSize(uint64_t baseSize);
private:
DWORD m_dwTypeID;
std::vector<llvm::DIType *> m_Layout;
DWORD m_dwCurrentSizeInBytes = 0;
uint64_t m_alignInBytes;
};
using TypeToInfoMap =
llvm::DenseMap<llvm::DIType *, std::unique_ptr<TypeInfo>>;
// Because of the way the VarToID map is constructed, the
// vector<LocalVarInfo> may need to grow. The Symbol Constructor for local
// variable captures the LocalVarInfo 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<symbol_factory::LocalVarInfo>>>;
using UDTFieldToIDMap = llvm::DenseMap<llvm::DIDerivedType *, DWORD>;
SymbolManagerInit(
Session *pSession,
std::vector<std::unique_ptr<SymbolManager::SymbolFactory>> *pSymCtors,
SymbolManager::ScopeToIDMap *pScopeToSym,
SymbolManager::IDToLiveRangeMap *pSymToLR);
template <typename Factory, typename... Args>
HRESULT AddSymbol(DWORD dwParentID, DWORD *pNewSymID, Args &&...args) {
if (dwParentID > m_SymCtors.size()) {
return E_FAIL;
}
const DWORD dwNewSymID = m_SymCtors.size() + 1;
m_SymCtors.emplace_back(std::unique_ptr<Factory>(
new Factory(dwNewSymID, dwParentID, std::forward<Args>(args)...)));
*pNewSymID = dwNewSymID;
IFR(AddParent(dwParentID));
return S_OK;
}
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,
dxil_dia::Session::RVA *pLowestUserRVA,
dxil_dia::Session::RVA *pHighestUserRVA);
HRESULT GetDxilAllocaRegister(llvm::Instruction *I, DWORD *pRegNum,
DWORD *pRegSize);
HRESULT PopulateParentToChildrenIDMap(
SymbolManager::ParentToChildrenMap *pParentToChildren);
private:
HRESULT GetTypeInfo(llvm::DIType *T, TypeInfo **TI);
template <typename Factory, typename... Args>
HRESULT AddType(DWORD dwParentID, llvm::DIType *T, DWORD *pNewSymID,
uint64_t alignment, Args &&...args) {
IFR(AddSymbol<Factory>(dwParentID, pNewSymID, std::forward<Args>(args)...));
if (!m_TypeToInfo
.insert(std::make_pair(
T, llvm::make_unique<TypeInfo>(*pNewSymID, alignment)))
.second) {
return E_FAIL;
}
return S_OK;
}
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<std::unique_ptr<SymbolManager::SymbolFactory>> &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)) {
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::UTF8ToWideStringOrThrow(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");
const char *specialCases[] = {
"/T", "-T", "-D", "/D", "-E", "/E",
};
llvm::MDNode *argsNode = pSession->Arguments()->getOperand(0);
// Construct a double null terminated string for defines with L"\0" as a
// delimiter
CComBSTR pBSTR;
for (llvm::MDNode::op_iterator it = argsNode->op_begin();
it != argsNode->op_end(); ++it) {
llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(*it)->getString();
bool skip = false;
bool skipTwice = false;
for (unsigned i = 0; i < _countof(specialCases); i++) {
if (strRef == specialCases[i]) {
skipTwice = true;
skip = true;
break;
} else if (strRef.startswith(specialCases[i])) {
skip = true;
break;
}
}
if (skip) {
if (skipTwice)
++it;
continue;
}
std::string str(strRef.begin(), strRef.size());
CA2W cv(str.c_str(), CP_UTF8);
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::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(), CP_UTF8);
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(), CP_UTF8));
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 = nullptr;
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;
}
// 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<std::unique_ptr<SymbolManager::SymbolFactory>> *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);
}
uint64_t alignmentInBytes = TI.GetAlignmentInBytes();
if (alignmentInBytes != 0) {
m_dwCurrentSizeInBytes =
llvm::RoundUpToAlignment(m_dwCurrentSizeInBytes, alignmentInBytes);
}
m_dwCurrentSizeInBytes += TI.m_dwCurrentSizeInBytes;
}
void dxil_dia::hlsl_symbols::SymbolManagerInit::TypeInfo::AppendSize(
uint64_t baseSize) {
static constexpr DWORD kNumBitsPerByte = 8;
m_dwCurrentSizeInBytes += baseSize / kNumBitsPerByte;
}
void dxil_dia::hlsl_symbols::SymbolManagerInit::TypeInfo::AddBasicType(
llvm::DIBasicType *BT) {
m_Layout.emplace_back(BT);
static constexpr DWORD kNumBitsPerByte = 8;
uint64_t alignmentInBytes = BT->getAlignInBits() / kNumBitsPerByte;
if (alignmentInBytes != 0) {
m_dwCurrentSizeInBytes =
llvm::RoundUpToAlignment(m_dwCurrentSizeInBytes, alignmentInBytes);
}
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.get();
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();
} else if (auto *BlockFile = llvm::dyn_cast<llvm::DILexicalBlockFile>(LS)) {
ParentLS = BlockFile->getScope();
}
if (ParentLS == nullptr) {
return E_FAIL;
}
DWORD dwParentID;
IFR(CreateFunctionBlockForLocalScope(ParentLS, &dwParentID));
IFR(AddSymbol<symbol_factory::FunctionBlock>(dwParentID, pNewSymID));
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) {
bool FoundFunctions = false;
for (llvm::DISubprogram *SubProgram : CU->getSubprograms()) {
DWORD dwNewFunID;
const DWORD dwParentID =
SubProgram->isLocalToUnit() ? HlslCompilandId : HlslProgramId;
DWORD dwSubprogramTypeID;
IFR(CreateType(SubProgram->getType(), &dwSubprogramTypeID));
IFR(AddSymbol<symbol_factory::Function>(dwParentID, &dwNewFunID, SubProgram,
dwSubprogramTypeID));
m_ScopeToSym.insert(std::make_pair(SubProgram, dwNewFunID));
}
for (llvm::DISubprogram *SubProgram : CU->getSubprograms()) {
if (llvm::Function *F = SubProgram->getFunction()) {
IFR(CreateFunctionBlocksForFunction(F));
FoundFunctions = true;
}
}
if (!FoundFunctions) {
// This works around an old bug in dxcompiler whose effects are still
// sometimes present in PIX users' traces. (The bug was that the
// subprogram(s) weren't pointing to their contained function.)
llvm::Module *M = &m_Session.ModuleRef();
auto &DM = M->GetDxilModule();
llvm::Function *EntryPoint = DM.GetEntryFunction();
IFR(CreateFunctionBlocksForFunction(EntryPoint));
}
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<symbol_factory::GlobalVariable>(
dwParentID, &dwUnusedNewGVID, GlobalVariable, dwGVTypeID, GVType));
}
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, CP_UTF8);
}
}
if (first) {
OS << "(";
}
firstArg = first;
first = false;
}
OS << ")";
return S_OK;
};
}
IFR(AddType<symbol_factory::Type>(dwParentID, ST, pNewTypeID, 0 /*alignment*/,
SymTagFunctionType, ST, LazyName));
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<symbol_factory::Type>(dwParentID, BT, pNewTypeID,
BT->getAlignInBits(), SymTagBaseType, BT,
LazyName));
TypeInfo *TI;
IFR(GetTypeInfo(BT, &TI));
TI->AddBasicType(BT);
return S_OK;
}
static uint64_t getBaseClassSize(llvm::DIType *Ty) {
uint64_t sizeInBits = Ty->getSizeInBits();
auto *DerivedTy = llvm::dyn_cast<llvm::DIDerivedType>(Ty);
if (DerivedTy != nullptr) {
// Working around a bug where byte size is stored instead of bit size
if (sizeInBits == 4 && Ty->getSizeInBits() == 32) {
sizeInBits = 32;
}
if (sizeInBits == 0) {
const llvm::DITypeIdentifierMap EmptyMap;
switch (DerivedTy->getTag()) {
case llvm::dwarf::DW_TAG_restrict_type:
case llvm::dwarf::DW_TAG_reference_type:
case llvm::dwarf::DW_TAG_const_type:
case llvm::dwarf::DW_TAG_typedef: {
llvm::DIType *baseType = DerivedTy->getBaseType().resolve(EmptyMap);
if (baseType != nullptr) {
return getBaseClassSize(baseType);
}
}
}
}
}
return sizeInBits;
}
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, CP_UTF8);
}
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<symbol_factory::Type>(dwParentID, CT, pNewTypeID,
BaseType->getAlignInBits(),
SymTagArrayType, CT, LazyName));
TypeInfo *ctTI;
IFR(GetTypeInfo(CT, &ctTI));
TypeInfo *baseTI;
IFR(GetTypeInfo(BaseType, &baseTI));
int64_t embedCount = 1;
for (llvm::DINode *N : CT->getElements()) {
if (N != nullptr) {
if (auto *SubRange = llvm::dyn_cast<llvm::DISubrange>(N)) {
embedCount *= SubRange->getCount();
} else {
return E_FAIL;
}
}
}
for (int64_t i = 0; i < embedCount; ++i) {
ctTI->Embed(*baseTI);
}
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<symbol_factory::UDT>(dwParentID, CT, pNewTypeID,
CT->getAlignInBits(), CT, LazyName));
TypeInfo *udtTI;
IFR(GetTypeInfo(CT, &udtTI));
auto udtScope = BeginUDTScope(udtTI);
if (CT->getElements().size() == 0) {
// "Resources" (textures, samplers, etc.) are composite types without any
// elements, but they do have a size.
udtTI->AppendSize(CT->getSizeInBits());
} else {
for (llvm::DINode *N : CT->getElements()) {
if (auto *Field = llvm::dyn_cast<llvm::DIType>(N)) {
std::unique_ptr<UDTScope> UDTScopeOverride;
if (Field->isStaticMember()) {
// Static members do not contribute to sizes or offsets.
UDTScopeOverride.reset(new UDTScope(&m_pCurUDT, nullptr));
}
DWORD dwUnusedFieldID;
IFR(CreateType(Field, &dwUnusedFieldID));
if (Field->getTag() == llvm::dwarf::DW_TAG_inheritance) {
// The base class is a type of its own, so will have contributed to
// its own TypeInfo. But we still need to remember the size that it
// contributed to this type:
auto *DerivedType = llvm::cast<llvm::DIDerivedType>(Field);
const llvm::DITypeIdentifierMap EmptyMap;
llvm::DIType *BaseType = DerivedType->getBaseType().resolve(EmptyMap);
udtTI->AppendSize(getBaseClassSize(BaseType));
}
}
}
}
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<symbol_factory::VectorType>(dwParentID, T, pNewTypeID,
T->getAlignInBits(), T, dwElemTyID,
ElemCnt->getLimitedValue()));
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, CP_UTF8);
}
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<symbol_factory::TypedefType>(dwParentID, DT, pNewTypeID,
BaseTy->getAlignInBits(), DT,
dwBaseTypeID));
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<symbol_factory::Type>(dwParentID, DT, pNewTypeID,
DT->getAlignInBits(), st, DT, LazyName));
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));
DWORD dwNewLVID;
newVars.emplace_back(std::make_shared<symbol_factory::LocalVarInfo>());
std::shared_ptr<symbol_factory::LocalVarInfo> VI = newVars.back();
IFR(AddSymbol<symbol_factory::LocalVariable>(dwParentID, &dwNewLVID, LV,
dwLVTypeID, LVTy, VI));
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) {
TypeInfo *lvTI;
IFR(GetTypeInfo(FieldTy, &lvTI));
#ifndef NDEBUG
const DWORD dwOffsetInBytes =
(lvTI->GetAlignmentInBytes() == 0)
? CurrentUDTInfo().GetCurrentSizeInBytes()
: llvm::RoundUpToAlignment(CurrentUDTInfo().GetCurrentSizeInBytes(),
lvTI->GetAlignmentInBytes());
DXASSERT_ARGS(dwOffsetInBytes == (unsigned)(Field->getOffsetInBits() / 8),
"%d vs %d", dwOffsetInBytes,
(unsigned)(Field->getOffsetInBits() / 8));
#endif
CurrentUDTInfo().Embed(*lvTI);
}
DWORD dwNewLVID;
IFR(AddSymbol<symbol_factory::UDTField>(dwParentID, &dwNewLVID, Field,
dwLVTypeID, FieldTy));
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()->getInlinedAtScope());
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;
if (FAILED(CreateLocalVariable(dwParentID, LV))) {
continue;
}
}
}
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[FirstUseRVA,
// 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.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;
Session::RVA FirstUseRVA;
Session::RVA LastUseRVA;
HRESULT hr = IsDbgDeclareCall(M, I, &Reg, &RegSize, &LV, &StartOffset,
&EndOffset, &FirstUseRVA, &LastUseRVA);
if (hr != S_OK) {
continue;
}
endOfScopeRVA = std::max<Session::RVA>(endOfScopeRVA, LastUseRVA);
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>(FirstUseRVA),
endOfScopeRVA - static_cast<uint32_t>(FirstUseRVA)};
}
}
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,
dxil_dia::Session::RVA *pLowestUserRVA,
dxil_dia::Session::RVA *pHighestUserRVA) {
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;
*pLowestUserRVA = 0;
*pHighestUserRVA = 0;
std::vector<dxil_dia::Session::RVA> usesRVAs;
bool HasRegister = false;
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;
}
HasRegister = true;
llvm::iterator_range<llvm::Value::user_iterator> users = Reg->users();
for (llvm::User *user : users) {
auto *inst = llvm::dyn_cast<llvm::Instruction>(user);
if (inst != nullptr) {
auto rva = m_Session.RvaMapRef().find(inst);
usesRVAs.push_back(rva->second);
}
}
}
}
}
if (!HasRegister) {
return E_FAIL;
}
if (!usesRVAs.empty()) {
*pLowestUserRVA = *std::min_element(usesRVAs.begin(), usesRVAs.end());
*pHighestUserRVA = *std::max_element(usesRVAs.begin(), usesRVAs.end());
}
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;
}
static constexpr uint64_t kNumBytesPerDword = 4;
if (Fields->isBitPiece()) {
const uint64_t BitPieceOffset = Fields->getBitPieceOffset();
const uint64_t BitPieceSize = 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.
if (*pRegSize * kNumBytesPerDword == BitPieceSize) {
// Size is bytes.
*pStartOffset = BitPieceOffset;
*pEndOffset = *pStartOffset + BitPieceSize;
} else {
// Size is (should be) bits; pStartOffset/pEndOffset should be bytes.
// We don't expect to encounter bit pieces more granular than bytes.
static constexpr uint64_t kNumBitsPerByte = 8;
(void)kNumBitsPerByte;
assert(BitPieceOffset % kNumBitsPerByte == 0);
assert(BitPieceSize % kNumBitsPerByte == 0);
*pStartOffset = BitPieceOffset / kNumBitsPerByte;
*pEndOffset = *pStartOffset + (BitPieceSize / kNumBitsPerByte);
}
} else {
*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]->Create(&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::SymbolFactory::SymbolFactory(DWORD ID, DWORD ParentID)
: m_ID(ID), m_ParentID(ParentID) {}
dxil_dia::SymbolManager::SymbolFactory::~SymbolFactory() = default;
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<hlsl_symbols::symbol_factory::GlobalScope>(
kNullSymbolID, &dwHlslProgramID));
DXASSERT_ARGS(dwHlslProgramID == HlslProgramId, "%d vs %d", dwHlslProgramID,
HlslProgramId);
DWORD dwHlslCompilandID;
IFT(SMI.AddSymbol<hlsl_symbols::symbol_factory::Compiland>(
dwHlslProgramID, &dwHlslCompilandID, ShaderCU));
m_scopeToID.insert(std::make_pair(ShaderCU, dwHlslCompilandID));
DXASSERT_ARGS(dwHlslCompilandID == HlslCompilandId, "%d vs %d",
dwHlslCompilandID, HlslCompilandId);
DWORD dwHlslCompilandDetailsId;
IFT(SMI.AddSymbol<hlsl_symbols::symbol_factory::CompilandDetails>(
dwHlslCompilandID, &dwHlslCompilandDetailsId));
DXASSERT_ARGS(dwHlslCompilandDetailsId == HlslCompilandDetailsId, "%d vs %d",
dwHlslCompilandDetailsId, HlslCompilandDetailsId);
DWORD dwHlslCompilandEnvFlagsID;
IFT(SMI.AddSymbol<hlsl_symbols::symbol_factory::CompilandEnv<
hlsl_symbols::CompilandEnvSymbol::CreateFlags>>(
dwHlslCompilandID, &dwHlslCompilandEnvFlagsID));
DXASSERT_ARGS(dwHlslCompilandEnvFlagsID == HlslCompilandEnvFlagsId,
"%d vs %d", dwHlslCompilandEnvFlagsID, HlslCompilandEnvFlagsId);
DWORD dwHlslCompilandEnvTargetID;
IFT(SMI.AddSymbol<hlsl_symbols::symbol_factory::CompilandEnv<
hlsl_symbols::CompilandEnvSymbol::CreateTarget>>(
dwHlslCompilandID, &dwHlslCompilandEnvTargetID));
DXASSERT_ARGS(dwHlslCompilandEnvTargetID == HlslCompilandEnvTargetId,
"%d vs %d", dwHlslCompilandEnvTargetID,
HlslCompilandEnvTargetId);
DWORD dwHlslCompilandEnvEntryID;
IFT(SMI.AddSymbol<hlsl_symbols::symbol_factory::CompilandEnv<
hlsl_symbols::CompilandEnvSymbol::CreateEntry>>(
dwHlslCompilandID, &dwHlslCompilandEnvEntryID));
DXASSERT_ARGS(dwHlslCompilandEnvEntryID == HlslCompilandEnvEntryId,
"%d vs %d", dwHlslCompilandEnvEntryID, HlslCompilandEnvEntryId);
DWORD dwHlslCompilandEnvDefinesID;
IFT(SMI.AddSymbol<hlsl_symbols::symbol_factory::CompilandEnv<
hlsl_symbols::CompilandEnvSymbol::CreateDefines>>(
dwHlslCompilandID, &dwHlslCompilandEnvDefinesID));
DXASSERT_ARGS(dwHlslCompilandEnvDefinesID == HlslCompilandEnvDefinesId,
"%d vs %d", dwHlslCompilandEnvDefinesID,
HlslCompilandEnvDefinesId);
DWORD dwHlslCompilandEnvArgumentsID;
IFT(SMI.AddSymbol<hlsl_symbols::symbol_factory::CompilandEnv<
hlsl_symbols::CompilandEnvSymbol::CreateArguments>>(
dwHlslCompilandID, &dwHlslCompilandEnvArgumentsID));
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]->Create(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;
}