blob: 94ab29ae1c18836d531acae2b4c6ac0ab2073f90 [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// DxcPixDxilDebugInfo.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 the main class for dxcompiler's API for PIX support. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "dxc/DXIL/DxilOperations.h"
#include "dxc/Support/WinIncludes.h"
#include "dxc/Support/exception.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "DxcPixBase.h"
#include "DxcPixDxilDebugInfo.h"
#include "DxcPixLiveVariables.h"
#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::GetLiveVariablesAt(
DWORD InstructionOffset, IDxcPixDxilLiveVariables **ppLiveVariables) {
return m_LiveVars->GetLiveVariablesAtInstruction(
FindInstruction(InstructionOffset), ppLiveVariables);
}
STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::IsVariableInRegister(
DWORD InstructionOffset, const wchar_t *VariableName) {
return S_OK;
}
STDMETHODIMP
dxil_debug_info::DxcPixDxilDebugInfo::GetFunctionName(DWORD InstructionOffset,
BSTR *ppFunctionName) {
llvm::Instruction *IP = FindInstruction(InstructionOffset);
const llvm::DITypeIdentifierMap EmptyMap;
if (const llvm::DebugLoc &DL = IP->getDebugLoc()) {
auto *S = llvm::dyn_cast<llvm::DIScope>(DL.getScope());
while (S != nullptr && !llvm::isa<llvm::DICompileUnit>(S)) {
if (auto *SS = llvm::dyn_cast<llvm::DISubprogram>(S)) {
*ppFunctionName = CComBSTR(CA2W(SS->getName().data())).Detach();
return S_OK;
}
S = S->getScope().resolve(EmptyMap);
}
}
*ppFunctionName = CComBSTR(L"<\?\?\?>").Detach();
return S_FALSE;
}
STDMETHODIMP
dxil_debug_info::DxcPixDxilDebugInfo::GetStackDepth(DWORD InstructionOffset,
DWORD *StackDepth) {
llvm::Instruction *IP = FindInstruction(InstructionOffset);
DWORD Depth = 0;
llvm::DebugLoc DL = IP->getDebugLoc();
while (DL && DL.getInlinedAtScope() != nullptr) {
DL = DL.getInlinedAt();
++Depth;
}
*StackDepth = Depth;
return S_OK;
}
#include "DxilDiaSession.h"
dxil_debug_info::DxcPixDxilDebugInfo::DxcPixDxilDebugInfo(
IMalloc *pMalloc, dxil_dia::Session *pSession)
: m_pMalloc(pMalloc), m_pSession(pSession),
m_LiveVars(new LiveVariables()) {
m_LiveVars->Init(this);
}
dxil_debug_info::DxcPixDxilDebugInfo::~DxcPixDxilDebugInfo() = default;
llvm::Module *dxil_debug_info::DxcPixDxilDebugInfo::GetModuleRef() {
return &m_pSession->ModuleRef();
}
llvm::Instruction *dxil_debug_info::DxcPixDxilDebugInfo::FindInstruction(
DWORD InstructionOffset) const {
const auto &Instructions = m_pSession->InstructionsRef();
auto it = Instructions.find(InstructionOffset);
if (it == Instructions.end()) {
throw hlsl::Exception(E_BOUNDS, "Out-of-bounds: Instruction offset");
}
return const_cast<llvm::Instruction *>(it->second);
}
STDMETHODIMP
dxil_debug_info::DxcPixDxilDebugInfo::InstructionOffsetsFromSourceLocation(
const wchar_t *FileName, DWORD SourceLine, DWORD SourceColumn,
IDxcPixDxilInstructionOffsets **ppOffsets) {
return dxil_debug_info::NewDxcPixDxilDebugInfoObjectOrThrow<
dxil_debug_info::DxcPixDxilInstructionOffsets>(
ppOffsets, m_pMalloc, m_pSession, FileName, SourceLine, SourceColumn);
}
STDMETHODIMP
dxil_debug_info::DxcPixDxilDebugInfo::SourceLocationsFromInstructionOffset(
DWORD InstructionOffset, IDxcPixDxilSourceLocations **ppSourceLocations) {
llvm::Instruction *IP = FindInstruction(InstructionOffset);
return dxil_debug_info::NewDxcPixDxilDebugInfoObjectOrThrow<
dxil_debug_info::DxcPixDxilSourceLocations>(ppSourceLocations, m_pMalloc,
m_pSession, IP);
}
static bool CompareFilenames(const wchar_t *l, const char *r) {
while (*l && *r) {
bool theSame = false;
if (*l == L'/' && *r == '\\') {
theSame = true;
}
if (*l == L'\\' && *r == '/') {
theSame = true;
}
if (!theSame) {
if (::tolower(*l) != ::tolower(*r)) {
return false;
}
}
l++;
r++;
}
if (*l || *r) {
return false;
}
return true;
}
dxil_debug_info::DxcPixDxilInstructionOffsets::DxcPixDxilInstructionOffsets(
IMalloc *pMalloc, dxil_dia::Session *pSession, const wchar_t *FileName,
DWORD SourceLine, DWORD SourceColumn) {
assert(SourceColumn == 0);
(void)SourceColumn;
for (llvm::Function &Fn :
pSession->DxilModuleRef().GetModule()->functions()) {
if (Fn.isDeclaration() || Fn.isIntrinsic() || hlsl::OP::IsDxilOpFunc(&Fn))
continue;
auto &Blocks = Fn.getBasicBlockList();
for (auto &CurrentBlock : Blocks) {
auto &Is = CurrentBlock.getInstList();
for (auto &Inst : Is) {
auto &debugLoc = Inst.getDebugLoc();
if (debugLoc) {
unsigned line = debugLoc.getLine();
if (line == SourceLine) {
auto file = debugLoc.get()->getFilename();
if (CompareFilenames(FileName, file.str().c_str())) {
std::uint32_t InstructionNumber;
if (pix_dxil::PixDxilInstNum::FromInst(&Inst,
&InstructionNumber)) {
m_offsets.push_back(InstructionNumber);
}
}
}
}
}
}
}
}
DWORD dxil_debug_info::DxcPixDxilInstructionOffsets::GetCount() {
return static_cast<DWORD>(m_offsets.size());
}
DWORD dxil_debug_info::DxcPixDxilInstructionOffsets::GetOffsetByIndex(
DWORD Index) {
if (Index < static_cast<DWORD>(m_offsets.size())) {
return m_offsets[Index];
}
return static_cast<DWORD>(-1);
}
dxil_debug_info::DxcPixDxilSourceLocations::DxcPixDxilSourceLocations(
IMalloc *pMalloc, dxil_dia::Session *pSession, llvm::Instruction *IP) {
const llvm::DITypeIdentifierMap EmptyMap;
if (const llvm::DebugLoc &DL = IP->getDebugLoc()) {
auto *S = llvm::dyn_cast<llvm::DIScope>(DL.getScope());
while (S != nullptr && !llvm::isa<llvm::DIFile>(S)) {
if (auto Namespace = llvm::dyn_cast<llvm::DINamespace>(S)) {
// DINamespace has a getScope member (that hides DIScope's)
// that returns a DIScope directly, but if that namespace
// is at file-level scope, it will return nullptr.
if (auto *ContainingScope = Namespace->getScope())
S = ContainingScope;
else
S = S->getFile();
} else if (auto Subprogram = llvm::dyn_cast<llvm::DISubprogram>(S)) {
S = Subprogram->getFile();
} else
S = S->getScope().resolve(EmptyMap);
}
if (S != nullptr) {
Location loc;
loc.Line = DL->getLine();
loc.Column = DL->getColumn();
loc.Filename = CA2W(S->getFilename().data());
m_locations.emplace_back(std::move(loc));
}
}
}
STDMETHODIMP_(DWORD) dxil_debug_info::DxcPixDxilSourceLocations::GetCount() {
return static_cast<DWORD>(m_locations.size());
}
STDMETHODIMP
dxil_debug_info::DxcPixDxilSourceLocations::GetFileNameByIndex(DWORD Index,
BSTR *Name) {
if (Index >= static_cast<DWORD>(m_locations.size())) {
return E_BOUNDS;
}
*Name = m_locations[Index].Filename.Copy();
return S_OK;
}
STDMETHODIMP_(DWORD)
dxil_debug_info::DxcPixDxilSourceLocations::GetColumnByIndex(DWORD Index) {
if (Index >= static_cast<DWORD>(m_locations.size())) {
return E_BOUNDS;
}
return m_locations[Index].Column;
}
STDMETHODIMP_(DWORD)
dxil_debug_info::DxcPixDxilSourceLocations::GetLineNumberByIndex(DWORD Index) {
if (Index >= static_cast<DWORD>(m_locations.size())) {
return E_BOUNDS;
}
return m_locations[Index].Line;
}