Commit b0ca2a89 by Ben Clayton

Pipeline: Implement the SpirvShader debugger.

Generate a synthetic file containing the spirv disassembly, and allow the debugger to single line step over these instructions, along with inspection of the SSA values. All of this is no-op unless ENABLE_VK_DEBUGGER is defined at compile time, and the VK_DEBUG_PORT env var is set at run time. Bug: b/145351270 Change-Id: Iba71717d78f7213ba586a1632b44f5fe08addf08 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38915 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com> Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com>
parent 5fd905ca
...@@ -41,6 +41,7 @@ swiftshader_source_set("Pipeline") { ...@@ -41,6 +41,7 @@ swiftshader_source_set("Pipeline") {
"SpirvShader.cpp", "SpirvShader.cpp",
"SpirvShaderArithmetic.cpp", "SpirvShaderArithmetic.cpp",
"SpirvShaderControlFlow.cpp", "SpirvShaderControlFlow.cpp",
"SpirvShaderDebugger.cpp",
"SpirvShaderEnumNames.cpp", "SpirvShaderEnumNames.cpp",
"SpirvShaderGLSLstd450.cpp", "SpirvShaderGLSLstd450.cpp",
"SpirvShaderGroup.cpp", "SpirvShaderGroup.cpp",
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "Vulkan/VkPipelineLayout.hpp" #include "Vulkan/VkPipelineLayout.hpp"
#include "Vulkan/VkRenderPass.hpp" #include "Vulkan/VkRenderPass.hpp"
#include "marl/defer.h"
#include <spirv/unified1/spirv.hpp> #include <spirv/unified1/spirv.hpp>
namespace sw { namespace sw {
...@@ -39,6 +41,11 @@ SpirvShader::SpirvShader( ...@@ -39,6 +41,11 @@ SpirvShader::SpirvShader(
{ {
ASSERT(insns.size() > 0); ASSERT(insns.size() > 0);
if(dbgctx)
{
dbgInit(dbgctx);
}
if(renderPass) if(renderPass)
{ {
// capture formats of any input attachments present // capture formats of any input attachments present
...@@ -719,6 +726,13 @@ SpirvShader::SpirvShader( ...@@ -719,6 +726,13 @@ SpirvShader::SpirvShader(
{ {
it.second.AssignBlockFields(); it.second.AssignBlockFields();
} }
dbgCreateFile();
}
SpirvShader::~SpirvShader()
{
dbgTerm();
} }
void SpirvShader::DeclareType(InsnIterator insn) void SpirvShader::DeclareType(InsnIterator insn)
...@@ -1452,6 +1466,7 @@ void SpirvShader::DefineResult(const InsnIterator &insn) ...@@ -1452,6 +1466,7 @@ void SpirvShader::DefineResult(const InsnIterator &insn)
} }
object.definition = insn; object.definition = insn;
dbgDeclareResult(insn, resultId);
} }
OutOfBoundsBehavior SpirvShader::EmitState::getOutOfBoundsBehavior(spv::StorageClass storageClass) const OutOfBoundsBehavior SpirvShader::EmitState::getOutOfBoundsBehavior(spv::StorageClass storageClass) const
...@@ -1542,6 +1557,9 @@ void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLan ...@@ -1542,6 +1557,9 @@ void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLan
{ {
EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, robustBufferAccess, executionModel); EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, robustBufferAccess, executionModel);
dbgBeginEmit(&state);
defer(dbgEndEmit(&state));
// Emit everything up to the first label // Emit everything up to the first label
// TODO: Separate out dispatch of block from non-block instructions? // TODO: Separate out dispatch of block from non-block instructions?
for(auto insn : *this) for(auto insn : *this)
...@@ -1577,6 +1595,9 @@ void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitSta ...@@ -1577,6 +1595,9 @@ void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitSta
SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
{ {
dbgBeginEmitInstruction(insn, state);
defer(dbgEndEmitInstruction(insn, state));
auto opcode = insn.opcode(); auto opcode = insn.opcode();
switch(opcode) switch(opcode)
...@@ -1624,7 +1645,6 @@ SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitStat ...@@ -1624,7 +1645,6 @@ SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitStat
case spv::OpSource: case spv::OpSource:
case spv::OpSourceContinued: case spv::OpSourceContinued:
case spv::OpSourceExtension: case spv::OpSourceExtension:
case spv::OpLine:
case spv::OpNoLine: case spv::OpNoLine:
case spv::OpModuleProcessed: case spv::OpModuleProcessed:
case spv::OpString: case spv::OpString:
...@@ -1632,6 +1652,9 @@ SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitStat ...@@ -1632,6 +1652,9 @@ SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitStat
// or don't require any work at all. // or don't require any work at all.
return EmitResult::Continue; return EmitResult::Continue;
case spv::OpLine:
return EmitLine(insn, state);
case spv::OpLabel: case spv::OpLabel:
return EmitResult::Continue; return EmitResult::Continue;
......
...@@ -497,6 +497,8 @@ public: ...@@ -497,6 +497,8 @@ public:
bool robustBufferAccess, bool robustBufferAccess,
const std::shared_ptr<vk::dbg::Context> &dbgctx); const std::shared_ptr<vk::dbg::Context> &dbgctx);
~SpirvShader();
struct Modes struct Modes
{ {
bool EarlyFragmentTests : 1; bool EarlyFragmentTests : 1;
...@@ -1090,6 +1092,7 @@ private: ...@@ -1090,6 +1092,7 @@ private:
EmitResult EmitSelect(InsnIterator insn, EmitState *state) const; EmitResult EmitSelect(InsnIterator insn, EmitState *state) const;
EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const; EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const;
EmitResult EmitExtGLSLstd450(InsnIterator insn, EmitState *state) const; EmitResult EmitExtGLSLstd450(InsnIterator insn, EmitState *state) const;
EmitResult EmitLine(InsnIterator insn, EmitState *state) const;
EmitResult EmitAny(InsnIterator insn, EmitState *state) const; EmitResult EmitAny(InsnIterator insn, EmitState *state) const;
EmitResult EmitAll(InsnIterator insn, EmitState *state) const; EmitResult EmitAll(InsnIterator insn, EmitState *state) const;
EmitResult EmitBranch(InsnIterator insn, EmitState *state) const; EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
...@@ -1170,14 +1173,58 @@ private: ...@@ -1170,14 +1173,58 @@ private:
// Returns 0 when invalid. // Returns 0 when invalid.
static VkShaderStageFlagBits executionModelToStage(spv::ExecutionModel model); static VkShaderStageFlagBits executionModelToStage(spv::ExecutionModel model);
// Impl holds private forward declaration structs that are implemented // Debugger API functions. When ENABLE_VK_DEBUGGER is not defined, these
// in the corresponding SpirvShaderXXX.cpp files. // are all no-ops.
// dbgInit() initializes the debugger code generation.
// All other dbgXXX() functions are no-op until this is called.
void dbgInit(const std::shared_ptr<vk::dbg::Context> &dbgctx);
// dbgTerm() terminates the debugger code generation.
void dbgTerm();
// dbgCreateFile() generates a synthetic file containing the disassembly
// of the SPIR-V shader. This is the file displayed in the debug
// session.
void dbgCreateFile();
// dbgBeginEmit() sets up the debugging state for the shader.
void dbgBeginEmit(EmitState *state) const;
// dbgEndEmit() tears down the debugging state for the shader.
void dbgEndEmit(EmitState *state) const;
// dbgBeginEmitInstruction() updates the current debugger location for
// the given instruction.
void dbgBeginEmitInstruction(InsnIterator insn, EmitState *state) const;
// dbgEndEmitInstruction() creates any new debugger variables for the
// instruction that just completed.
void dbgEndEmitInstruction(InsnIterator insn, EmitState *state) const;
// dbgExposeIntermediate() exposes the intermediate with the given ID to
// the debugger.
void dbgExposeIntermediate(Object::ID id, EmitState *state) const;
// dbgUpdateActiveLaneMask() updates the active lane masks to the
// debugger.
void dbgUpdateActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const;
// dbgDeclareResult() associates resultId as the result of the given
// instruction.
void dbgDeclareResult(const InsnIterator &insn, Object::ID resultId) const;
// Impl holds forward declaration structs and pointers to state for the
// private implementations in the corresponding SpirvShaderXXX.cpp files.
// This allows access to the private members of the SpirvShader, without // This allows access to the private members of the SpirvShader, without
// littering the header with implementation details. // littering the header with implementation details.
struct Impl struct Impl
{ {
struct Debugger;
struct Group; struct Group;
Debugger *debugger = nullptr;
}; };
Impl impl;
}; };
class SpirvRoutine class SpirvRoutine
...@@ -1230,6 +1277,8 @@ public: ...@@ -1230,6 +1277,8 @@ public:
std::array<SIMD::Int, 3> localInvocationID; std::array<SIMD::Int, 3> localInvocationID;
std::array<SIMD::Int, 3> globalInvocationID; std::array<SIMD::Int, 3> globalInvocationID;
Pointer<Byte> dbgState; // Pointer to a debugger state.
void createVariable(SpirvShader::Object::ID id, uint32_t size) void createVariable(SpirvShader::Object::ID id, uint32_t size)
{ {
bool added = variables.emplace(id, Variable(size)).second; bool added = variables.emplace(id, Variable(size)).second;
......
...@@ -702,6 +702,7 @@ void SpirvShader::Yield(YieldResult res) const ...@@ -702,6 +702,7 @@ void SpirvShader::Yield(YieldResult res) const
void SpirvShader::SetActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const void SpirvShader::SetActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const
{ {
state->activeLaneMaskValue = mask.value; state->activeLaneMaskValue = mask.value;
dbgUpdateActiveLaneMask(mask, state);
} }
} // namespace sw } // namespace sw
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment