Browse Source

Pix source-to-instruction offsets (#2835)

This is a direct implementation of a new API for PIX that shortcuts the large and unwieldy (and not-really-working-well) DIA equivalent to find the set of instructions that correspond to a given source location.
Jeff Noyle 5 years ago
parent
commit
35769dabe1

+ 14 - 0
include/dxc/dxcpix.h

@@ -132,6 +132,14 @@ IDxcPixDxilLiveVariables : public IUnknown
       _COM_Outptr_ IDxcPixVariable** ppVariable) = 0;
 };
 
+struct __declspec(uuid("eb71f85e-8542-44b5-87da-9d76045a1910"))
+  IDxcPixDxilInstructionOffsets : public IUnknown
+{
+  virtual STDMETHODIMP_(DWORD) GetCount() = 0;
+
+  virtual STDMETHODIMP_(DWORD) GetOffsetByIndex(_In_ DWORD Index) = 0;
+};
+
 struct __declspec(uuid("6dd5d45e-a417-4a26-b0ff-bdb7d6dcc63d"))
 IDxcPixDxilDebugInfo : public IUnknown
 {
@@ -150,6 +158,12 @@ IDxcPixDxilDebugInfo : public IUnknown
   virtual STDMETHODIMP GetStackDepth(
       _In_ DWORD InstructionOffset,
       _Out_ DWORD* StackDepth) = 0;
+
+  virtual STDMETHODIMP InstructionOffsetsFromSourceLocation(
+      _In_ const wchar_t *FileName,
+      _In_ DWORD SourceLine,
+      _In_ DWORD SourceColumn,
+      _COM_Outptr_ IDxcPixDxilInstructionOffsets** ppOffsets) = 0;
 };
 
 struct __declspec(uuid("61b16c95-8799-4ed8-bdb0-3b6c08a141b4"))

+ 95 - 1
lib/DxilDia/DxcPixDxilDebugInfo.cpp

@@ -18,6 +18,8 @@
 
 #include "DxcPixLiveVariables.h"
 #include "DxcPixDxilDebugInfo.h"
+#include "DxcPixBase.h"
+#include "dxc/DxilPixPasses/DxilPixVirtualRegisters.h"
 
 STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::GetLiveVariablesAt(
   _In_ DWORD InstructionOffset,
@@ -112,4 +114,96 @@ llvm::Instruction* dxil_debug_info::DxcPixDxilDebugInfo::FindInstruction(
   }
 
   return const_cast<llvm::Instruction *>(it->second);
-}
+}
+
+STDMETHODIMP
+dxil_debug_info::DxcPixDxilDebugInfo::InstructionOffsetsFromSourceLocation(
+    _In_ const wchar_t *FileName, _In_ DWORD SourceLine,
+    _In_ DWORD SourceColumn,
+    _COM_Outptr_ IDxcPixDxilInstructionOffsets **ppOffsets) 
+{
+  return dxil_debug_info::NewDxcPixDxilDebugInfoObjectOrThrow<
+      dxil_debug_info::DxcPixDxilInstructionOffsets>(
+      ppOffsets, m_pMalloc, m_pSession, FileName, SourceLine, SourceColumn);
+}
+
+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;
+
+  auto files = pSession->Contents()->operands();
+  for (const auto& file : files)
+  {
+    auto candidateFilename = llvm::dyn_cast<llvm::MDString>(file->getOperand(0))
+        ->getString();
+
+    if (CompareFilenames(FileName, candidateFilename.str().c_str()))
+    {
+
+      auto Fn = pSession->DxilModuleRef().GetEntryFunction();
+      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)
+            {
+              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);
+}

+ 35 - 0
lib/DxilDia/DxcPixDxilDebugInfo.h

@@ -19,6 +19,7 @@
 #include "dxc/Support/microcom.h"
 
 #include <memory>
+#include <vector>
 
 namespace dxil_dia
 {
@@ -76,6 +77,13 @@ public:
       _In_ DWORD InstructionOffset,
       _Outptr_ DWORD *StackDepth) override;
 
+
+  STDMETHODIMP InstructionOffsetsFromSourceLocation(
+      _In_ const wchar_t *FileName, 
+      _In_ DWORD SourceLine,
+      _In_ DWORD SourceColumn, 
+      _COM_Outptr_ IDxcPixDxilInstructionOffsets **ppOffsets) override;
+
   llvm::Module *GetModuleRef();
 
   IMalloc *GetMallocNoRef()
@@ -83,4 +91,31 @@ public:
     return m_pMalloc;
   }
 };
+
+class DxcPixDxilInstructionOffsets : public IDxcPixDxilInstructionOffsets
+{
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+  CComPtr<dxil_dia::Session> m_pSession;
+
+  DxcPixDxilInstructionOffsets(
+    IMalloc* pMalloc,
+    dxil_dia::Session *pSession,
+    const wchar_t *FileName,
+    DWORD SourceLine,
+    DWORD SourceColumn);
+
+  std::vector<DWORD> m_offsets;
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_ALLOC(DxcPixDxilInstructionOffsets)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcPixDxilInstructionOffsets>(this, iid, ppvObject);
+  }
+
+  virtual STDMETHODIMP_(DWORD) GetCount() override;
+  virtual STDMETHODIMP_(DWORD) GetOffsetByIndex(_In_ DWORD Index) override;
+};
 }  // namespace dxil_debug_info

+ 1 - 0
lib/DxilDia/DxcPixDxilStorage.cpp

@@ -18,6 +18,7 @@
 #include "DxcPixBase.h"
 #include "DxcPixLiveVariables.h"
 #include "DxcPixTypes.h"
+#include "DxilDiaSession.h"
 
 static HRESULT UnAliasType(
     IDxcPixType *MaybeAlias,

+ 26 - 1
lib/DxilDia/DxcPixEntrypoints.cpp

@@ -17,6 +17,7 @@
 
 #include "dxc/dxcapi.h"
 #include "dxc/dxcpix.h"
+#include "DxilDiaSession.h"
 
 #include "dxc/Support/Global.h"
 #include "dxc/Support/microcom.h"
@@ -64,6 +65,7 @@ OutParamImpl<T> OutParam(T *V)
   return OutParamImpl<T>(V);
 }
 
+
 // InParam/InParamImpl provides a mechanism that entrypoints
 // use to tag method arguments as InParams. InParams are
 // not zero-initialized.
@@ -213,7 +215,6 @@ void WrapOutParams(IMalloc *M, T, O... Others)
   WrapOutParams(M, Others...);
 }
 
-
 // DEFINE_ENTRYPOINT_WRAPPER_TRAIT is a helper macro that every entrypoint
 // should use in order to define the EntrypointWrapper traits class for
 // the interface it implements.
@@ -718,9 +719,33 @@ struct IDxcPixDxilDebugInfoEntrypoint : public Entrypoint<IDxcPixDxilDebugInfo>
   {
     return InvokeOnReal(&IInterface::GetStackDepth, InstructionOffset, CheckNotNull(OutParam(StackDepth)));
   }
+
+  STDMETHODIMP InstructionOffsetsFromSourceLocation(
+      _In_ const wchar_t* FileName,
+      _In_ DWORD SourceLine,
+      _In_ DWORD SourceColumn,
+      _COM_Outptr_ IDxcPixDxilInstructionOffsets** ppOffsets) override
+  {
+    return InvokeOnReal(&IInterface::InstructionOffsetsFromSourceLocation, CheckNotNull(InParam(FileName)), SourceLine, SourceColumn, CheckNotNull(OutParam(ppOffsets)));
+  }
 };
 DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixDxilDebugInfo);
 
+struct IDxcPixDxilInstructionOffsetsEntrypoint : public Entrypoint<IDxcPixDxilInstructionOffsets>
+{
+  DEFINE_ENTRYPOINT_BOILERPLATE(IDxcPixDxilInstructionOffsetsEntrypoint);
+
+  STDMETHODIMP_(DWORD) GetCount() override
+  {
+    return InvokeOnReal(&IInterface::GetCount);
+  }
+
+  STDMETHODIMP_(DWORD) GetOffsetByIndex(_In_ DWORD Index) override
+  {
+    return InvokeOnReal(&IInterface::GetOffsetByIndex, Index);
+  }
+};
+DEFINE_ENTRYPOINT_WRAPPER_TRAIT(IDxcPixDxilInstructionOffsets);
 
 struct IDxcPixCompilationInfoEntrypoint
     : public Entrypoint<IDxcPixCompilationInfo>

+ 1 - 0
lib/DxilDia/DxcPixLiveVariables.cpp

@@ -15,6 +15,7 @@
 #include "DxcPixDxilDebugInfo.h"
 #include "DxcPixLiveVariables.h"
 #include "DxcPixLiveVariables_FragmentIterator.h" 
+#include "DxilDiaSession.h"
 
 #include "dxc/Support/Global.h"
 #include "llvm/ADT/SmallVector.h"

+ 1 - 0
lib/DxilDia/DxcPixTypes.cpp

@@ -12,6 +12,7 @@
 
 #include "DxcPixBase.h"
 #include "DxcPixTypes.h"
+#include "DxilDiaSession.h"
 
 HRESULT dxil_debug_info::CreateDxcPixType(
     DxcPixDxilDebugInfo *pDxilDebugInfo,

+ 1 - 0
lib/DxilDia/DxcPixVariables.cpp

@@ -23,6 +23,7 @@
 #include "DxcPixDxilStorage.h"
 #include "DxcPixLiveVariables.h"
 #include "DxcPixTypes.h"
+#include "DxilDiaSession.h"
 
 #include <set>
 #include <vector>