Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PDB output to linker #6834

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions tools/clang/tools/dxclib/dxc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ int DxcContext::Link() {
IFT(pLinker->RegisterLibrary(wInputFiles.back().c_str(), pLib));
}

CComPtr<IDxcOperationResult> pLinkResult;
CComPtr<IDxcOperationResult> pLinkOperationResult;

std::vector<std::wstring> argStrings;
CopyArgsToWStrings(m_Opts.Args, CoreOption, argStrings);
Expand All @@ -967,19 +967,40 @@ int DxcContext::Link() {
IFT(pLinker->Link(StringRefWide(m_Opts.EntryPoint),
StringRefWide(m_Opts.TargetProfile), wpInputFiles.data(),
wpInputFiles.size(), args.data(), args.size(),
&pLinkResult));
&pLinkOperationResult));

HRESULT status;
IFT(pLinkResult->GetStatus(&status));
IFT(pLinkOperationResult->GetStatus(&status));
if (SUCCEEDED(status)) {
CComPtr<IDxcBlob> pContainer;
IFT(pLinkResult->GetResult(&pContainer));
IFT(pLinkOperationResult->GetResult(&pContainer));

if (pContainer.p != nullptr) {
ActOnBlob(pContainer.p);
CComPtr<IDxcResult> pLinkResult;
CComPtr<IDxcBlob> pDebugBlob;

std::wstring outputPDBPath;
Unicode::UTF8ToWideString(m_Opts.DebugFile.str().c_str(), &outputPDBPath);

if (!m_Opts.DebugFile.empty()) {
if (SUCCEEDED(pLinkOperationResult->QueryInterface(&pLinkResult))) {
if (pLinkResult->HasOutput(DXC_OUT_PDB)) {
CComPtr<IDxcBlobWide> pDebugBlobName;

IFT(pLinkResult->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pDebugBlob),
&pDebugBlobName));

if (m_Opts.DebugFileIsDirectory())
outputPDBPath += pDebugBlobName->GetStringPointer();
}
}
}

ActOnBlob(pContainer.p, pDebugBlob.p, outputPDBPath.c_str());
}
} else {
CComPtr<IDxcBlobEncoding> pErrors;
IFT(pLinkResult->GetErrorBuffer(&pErrors));
IFT(pLinkOperationResult->GetErrorBuffer(&pErrors));
if (pErrors != nullptr) {
printf("Link failed:\n%s",
static_cast<char *>(pErrors->GetBufferPointer()));
Expand Down
118 changes: 114 additions & 4 deletions tools/clang/tools/dxcompiler/dxclinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,27 @@
#include "llvm/ADT/SmallVector.h"
#include <algorithm>

#include "dxc/DXIL/DxilPDB.h"
#include "dxc/HLSL/DxilLinker.h"
#include "dxc/HLSL/DxilValidation.h"
#include "dxc/Support/HLSLOptions.h"
#include "dxc/Support/Unicode.h"
#include "dxc/Support/microcom.h"
#include "dxc/dxcapi.internal.h"
#include "dxcutil.h"
#include "dxcversion.inc"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/Cloning.h"

#ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
#include "clang/Basic/Version.h"
#endif // SUPPORT_QUERY_GIT_COMMIT_INFO

using namespace hlsl;
using namespace llvm;
Expand Down Expand Up @@ -86,7 +93,15 @@ struct DeserializedDxilCompilerVersion {
}
};

class DxcLinker : public IDxcLinker, public IDxcContainerEvent {
class DxcLinker : public IDxcLinker,
public IDxcContainerEvent,
public IDxcVersionInfo3,
#ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
public IDxcVersionInfo2
#else
public IDxcVersionInfo
#endif // SUPPORT_QUERY_GIT_COMMIT_INFO
{
public:
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
DXC_MICROCOM_TM_CTOR(DxcLinker)
Expand Down Expand Up @@ -128,7 +143,11 @@ class DxcLinker : public IDxcLinker, public IDxcContainerEvent {

HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
void **ppvObject) override {
return DoBasicQueryInterface<IDxcLinker>(this, riid, ppvObject);
return DoBasicQueryInterface<IDxcLinker, IDxcVersionInfo,
#ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
IDxcVersionInfo2,
#endif // SUPPORT_QUERY_GIT_COMMIT_INFO
IDxcVersionInfo3>(this, riid, ppvObject);
}

void Initialize() {
Expand Down Expand Up @@ -162,6 +181,57 @@ class DxcLinker : public IDxcLinker, public IDxcContainerEvent {
return true;
}

// IDxcVersionInfo
HRESULT STDMETHODCALLTYPE GetVersion(UINT32 *pMajor,
UINT32 *pMinor) override {
if (pMajor == nullptr || pMinor == nullptr)
return E_INVALIDARG;
*pMajor = DXIL::kDxilMajor;
*pMinor = DXIL::kDxilMinor;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetCustomVersionString(
char **pVersionString // Custom version string for compiler. (Must be
// CoTaskMemFree()'d!)
) override {
size_t size = strlen(RC_FILE_VERSION);
char *const result = (char *)CoTaskMemAlloc(size + 1);
if (result == nullptr)
return E_OUTOFMEMORY;
std::strcpy(result, RC_FILE_VERSION);
*pVersionString = result;
return S_OK;
}

#ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
HRESULT STDMETHODCALLTYPE GetCommitInfo(UINT32 *pCommitCount,
char **pCommitHash) override {
if (pCommitCount == nullptr || pCommitHash == nullptr)
return E_INVALIDARG;

char *const hash = (char *)CoTaskMemAlloc(
8 + 1); // 8 is guaranteed by utils/GetCommitInfo.py
if (hash == nullptr)
return E_OUTOFMEMORY;
std::strcpy(hash, clang::getGitCommitHash());

*pCommitHash = hash;
*pCommitCount = clang::getGitCommitCount();

return S_OK;
}
#endif // SUPPORT_QUERY_GIT_COMMIT_INFO

HRESULT STDMETHODCALLTYPE GetFlags(UINT32 *pFlags) override {
if (pFlags == nullptr)
return E_INVALIDARG;
*pFlags = DxcVersionInfoFlags_None;
#ifndef NDEBUG
*pFlags |= DxcVersionInfoFlags_Debug;
#endif
return S_OK;
}

~DxcLinker() {
// Make sure DxilLinker is released before LLVMContext.
m_pLinker.reset();
Expand Down Expand Up @@ -409,11 +479,16 @@ HRESULT STDMETHODCALLTYPE DxcLinker::Link(
SerializeFlags |= SerializeDxilFlags::IncludeDebugInfoPart;
}

std::unique_ptr<llvm::Module> debugModule;
if (opts.GenerateFullDebugInfo()) {
debugModule.reset(llvm::CloneModule(pM.get()));
}

// Validation.
HRESULT valHR = S_OK;
dxcutil::AssembleInputs inputs(
std::move(pM), pOutputBlob, DxcGetThreadMallocNoRef(),
SerializeFlags, pOutputStream, opts.DebugFile, &Diag,
SerializeFlags, pOutputStream, opts.GetPDBName(), &Diag,
&ShaderHashContent, pReflectionStream, pRootSigStream, nullptr,
nullptr);
if (needsValidation) {
Expand All @@ -431,7 +506,42 @@ HRESULT STDMETHODCALLTYPE DxcLinker::Link(
std::swap(pOutputBlob, pTargetBlob);
}
}
// TODO: DFCC_ShaderDebugName

// DXC_OUT_PDB
if (pOutputBlob && opts.GenerateFullDebugInfo() &&
(SerializeFlags & SerializeDxilFlags::IncludeDebugNamePart) !=
0) {
// Resolve PDB name
{
const DxilContainerHeader *pContainer =
reinterpret_cast<DxilContainerHeader *>(
pOutputBlob->GetBufferPointer());
DXASSERT(IsValidDxilContainer(pContainer,
pOutputBlob->GetBufferSize()),
"else invalid container generated");

auto it = std::find_if(begin(pContainer), end(pContainer),
DxilPartIsType(DFCC_ShaderDebugName));
if (it != end(pContainer)) {
const char *pDebugName;
if (GetDxilShaderDebugName(*it, &pDebugName, nullptr) &&
pDebugName && *pDebugName) {
IFT(pResult->SetOutputName(DXC_OUT_PDB, pDebugName));
}
}
}

// Generate PDB contents
{
CComPtr<IDxcBlob> pPdbBlob;
IFT(dxcutil::CreatePDBContainerFromModule(
m_pMalloc, opts, debugModule.get(), pOutputBlob,
pReflectionStream, this, nullptr, ShaderHashContent.Digest,
&pPdbBlob));

IFT(pResult->SetOutputObject(DXC_OUT_PDB, pPdbBlob));
}
}

// DXC_OUT_REFLECTION
if (pReflectionStream && pReflectionStream->GetPtrSize()) {
Expand Down
Loading
Loading