| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // 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; |
| } |