| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // DxcPixCompilationInfo.cpp // |
| // Copyright (C) Microsoft Corporation. All rights reserved. // |
| // This file is distributed under the University of Illinois Open Source // |
| // License. See LICENSE.TXT for details. // |
| // // |
| // Defines all of the entrypoints for DXC's PIX interfaces for returning // |
| // compilation parameters such as target profile, entry point, etc. // |
| // // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "dxc/Support/WinIncludes.h" |
| |
| #include "dxc/dxcapi.h" |
| #include "dxc/dxcpix.h" |
| |
| #include "dxc/Support/FileIOHelper.h" |
| #include "dxc/Support/Global.h" |
| #include "dxc/Support/microcom.h" |
| #include "llvm/Support/FileSystem.h" |
| #include "llvm/Support/MSFileSystem.h" |
| |
| #include "DxcPixBase.h" |
| #include "DxcPixDxilDebugInfo.h" |
| |
| #include <functional> |
| |
| #include "dxc/Support/WinIncludes.h" |
| |
| #include "DxcPixCompilationInfo.h" |
| #include "DxcPixDxilDebugInfo.h" |
| |
| #include "dxc/Support/Global.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/IR/DebugInfo.h" |
| #include "llvm/IR/DebugInfoMetadata.h" |
| #include "llvm/IR/Dominators.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/IntrinsicInst.h" |
| #include "llvm/IR/Intrinsics.h" |
| #include "llvm/IR/Module.h" |
| |
| #include "DxilDiaSession.h" |
| |
| #include <unordered_map> |
| |
| namespace dxil_debug_info { |
| |
| struct CompilationInfo : public IDxcPixCompilationInfo { |
| private: |
| DXC_MICROCOM_TM_REF_FIELDS(); |
| |
| dxil_dia::Session *m_pSession; |
| llvm::NamedMDNode *m_contents; |
| llvm::NamedMDNode *m_defines; |
| llvm::NamedMDNode *m_mainFileName; |
| llvm::NamedMDNode *m_arguments; |
| |
| public: |
| CompilationInfo(IMalloc *pMalloc, dxil_dia::Session *pSession); |
| |
| DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL(); |
| DXC_MICROCOM_TM_ALLOC(CompilationInfo); |
| |
| HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) final { |
| return DoBasicQueryInterface<IDxcPixCompilationInfo>(this, iid, ppvObject); |
| } |
| virtual STDMETHODIMP GetSourceFile(DWORD SourceFileOrdinal, BSTR *pSourceName, |
| BSTR *pSourceContents) override; |
| virtual STDMETHODIMP GetArguments(BSTR *pArguments) override; |
| virtual STDMETHODIMP GetMacroDefinitions(BSTR *pMacroDefinitions) override; |
| virtual STDMETHODIMP GetEntryPointFile(BSTR *pEntryPointFile) override; |
| virtual STDMETHODIMP GetHlslTarget(BSTR *pHlslTarget) override; |
| virtual STDMETHODIMP GetEntryPoint(BSTR *pEntryPoint) override; |
| }; |
| |
| CompilationInfo::CompilationInfo(IMalloc *pMalloc, dxil_dia::Session *pSession) |
| : m_pMalloc(pMalloc), m_pSession(pSession) { |
| auto *Module = m_pSession->DxilModuleRef().GetModule(); |
| m_contents = |
| Module->getNamedMetadata(hlsl::DxilMDHelper::kDxilSourceContentsMDName); |
| if (!m_contents) |
| m_contents = Module->getNamedMetadata("llvm.dbg.contents"); |
| |
| m_defines = |
| Module->getNamedMetadata(hlsl::DxilMDHelper::kDxilSourceDefinesMDName); |
| if (!m_defines) |
| m_defines = Module->getNamedMetadata("llvm.dbg.defines"); |
| |
| m_mainFileName = Module->getNamedMetadata( |
| hlsl::DxilMDHelper::kDxilSourceMainFileNameMDName); |
| if (!m_mainFileName) |
| m_mainFileName = Module->getNamedMetadata("llvm.dbg.mainFileName"); |
| |
| m_arguments = |
| Module->getNamedMetadata(hlsl::DxilMDHelper::kDxilSourceArgsMDName); |
| if (!m_arguments) |
| m_arguments = Module->getNamedMetadata("llvm.dbg.args"); |
| } |
| |
| static void MDStringOperandToBSTR(llvm::MDOperand const &mdOperand, |
| BSTR *pBStr) { |
| llvm::StringRef MetadataAsStringRef = |
| llvm::dyn_cast<llvm::MDString>(mdOperand)->getString(); |
| std::string StringWithTerminator(MetadataAsStringRef.begin(), |
| MetadataAsStringRef.size()); |
| CA2W cv(StringWithTerminator.c_str(), CP_UTF8); |
| CComBSTR BStr; |
| BStr.Append(cv); |
| BStr.Append(L"\0", 1); |
| *pBStr = BStr.Detach(); |
| } |
| |
| STDMETHODIMP |
| CompilationInfo::GetSourceFile(DWORD SourceFileOrdinal, BSTR *pSourceName, |
| BSTR *pSourceContents) { |
| *pSourceName = nullptr; |
| *pSourceContents = nullptr; |
| |
| if (SourceFileOrdinal >= m_contents->getNumOperands()) { |
| return E_INVALIDARG; |
| } |
| |
| llvm::MDTuple *FileTuple = |
| llvm::cast<llvm::MDTuple>(m_contents->getOperand(SourceFileOrdinal)); |
| |
| MDStringOperandToBSTR(FileTuple->getOperand(0), pSourceName); |
| MDStringOperandToBSTR(FileTuple->getOperand(1), pSourceContents); |
| |
| return S_OK; |
| } |
| |
| STDMETHODIMP CompilationInfo::GetArguments(BSTR *pArguments) { |
| llvm::MDNode *argsNode = m_arguments->getOperand(0); |
| |
| // Don't return any arguments that denote things that are returned via |
| // other methods in this class (and that PIX isn't expecting to see |
| // in the arguments list): |
| const char *specialCases[] = { |
| "/T", "-T", "-D", "/D", "-E", "/E", |
| }; |
| |
| // Concatenate arguments into one string |
| 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++) { |
| // It's legal for users to specify, for example, /Emain or /E main: |
| 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" ", 1); |
| } |
| pBSTR.Append(L"\0", 1); |
| *pArguments = pBSTR.Detach(); |
| return S_OK; |
| } |
| |
| STDMETHODIMP CompilationInfo::GetMacroDefinitions(BSTR *pMacroDefinitions) { |
| llvm::MDNode *definesNode = m_defines->getOperand(0); |
| // Concatenate definitions into one string separated by spaces |
| 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()); |
| |
| // PIX is expecting quoted strings as the definitions. So if no quotes were |
| // given, add them now: |
| auto findEquals = str.find_first_of("="); |
| if (findEquals != std::string::npos && findEquals + 1 < str.length()) { |
| std::string definition = str.substr(findEquals + 1); |
| if (definition.front() != '\"') { |
| definition.insert(definition.begin(), '\"'); |
| } |
| if (definition.back() != '\"') { |
| definition.push_back('\"'); |
| } |
| std::string name = str.substr(0, findEquals); |
| str = name + "=" + definition; |
| } |
| |
| CA2W cv(str.c_str(), CP_UTF8); |
| pBSTR.Append(L"-D", 2); |
| pBSTR.Append(cv); |
| pBSTR.Append(L" ", 1); |
| } |
| pBSTR.Append(L"\0", 1); |
| *pMacroDefinitions = pBSTR.Detach(); |
| return S_OK; |
| } |
| |
| STDMETHODIMP |
| CompilationInfo::GetEntryPointFile(BSTR *pEntryPointFile) { |
| llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>( |
| m_mainFileName->getOperand(0)->getOperand(0)) |
| ->getString(); |
| std::string str(strRef.begin(), |
| strRef.size()); // To make sure str is null terminated |
| CA2W cv(str.c_str(), CP_UTF8); |
| CComBSTR pBSTR; |
| pBSTR.Append(cv); |
| *pEntryPointFile = pBSTR.Detach(); |
| return S_OK; |
| } |
| |
| STDMETHODIMP |
| CompilationInfo::GetHlslTarget(BSTR *pHlslTarget) { |
| CA2W cv(m_pSession->DxilModuleRef().GetShaderModel()->GetName(), CP_UTF8); |
| CComBSTR pBSTR; |
| pBSTR.Append(cv); |
| *pHlslTarget = pBSTR.Detach(); |
| return S_OK; |
| } |
| |
| STDMETHODIMP |
| CompilationInfo::GetEntryPoint(BSTR *pEntryPoint) { |
| auto name = m_pSession->DxilModuleRef().GetEntryFunctionName(); |
| CA2W cv(name.c_str(), CP_UTF8); |
| CComBSTR pBSTR; |
| pBSTR.Append(cv); |
| *pEntryPoint = pBSTR.Detach(); |
| return S_OK; |
| } |
| |
| } // namespace dxil_debug_info |
| |
| HRESULT |
| dxil_debug_info::CreateDxilCompilationInfo(IMalloc *pMalloc, |
| dxil_dia::Session *pSession, |
| IDxcPixCompilationInfo **ppResult) { |
| return NewDxcPixDxilDebugInfoObjectOrThrow<CompilationInfo>(ppResult, pMalloc, |
| pSession); |
| } |