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") {
"SpirvShader.cpp",
"SpirvShaderArithmetic.cpp",
"SpirvShaderControlFlow.cpp",
"SpirvShaderDebugger.cpp",
"SpirvShaderEnumNames.cpp",
"SpirvShaderGLSLstd450.cpp",
"SpirvShaderGroup.cpp",
......
......@@ -18,6 +18,8 @@
#include "Vulkan/VkPipelineLayout.hpp"
#include "Vulkan/VkRenderPass.hpp"
#include "marl/defer.h"
#include <spirv/unified1/spirv.hpp>
namespace sw {
......@@ -39,6 +41,11 @@ SpirvShader::SpirvShader(
{
ASSERT(insns.size() > 0);
if(dbgctx)
{
dbgInit(dbgctx);
}
if(renderPass)
{
// capture formats of any input attachments present
......@@ -719,6 +726,13 @@ SpirvShader::SpirvShader(
{
it.second.AssignBlockFields();
}
dbgCreateFile();
}
SpirvShader::~SpirvShader()
{
dbgTerm();
}
void SpirvShader::DeclareType(InsnIterator insn)
......@@ -1452,6 +1466,7 @@ void SpirvShader::DefineResult(const InsnIterator &insn)
}
object.definition = insn;
dbgDeclareResult(insn, resultId);
}
OutOfBoundsBehavior SpirvShader::EmitState::getOutOfBoundsBehavior(spv::StorageClass storageClass) const
......@@ -1542,6 +1557,9 @@ void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLan
{
EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, robustBufferAccess, executionModel);
dbgBeginEmit(&state);
defer(dbgEndEmit(&state));
// Emit everything up to the first label
// TODO: Separate out dispatch of block from non-block instructions?
for(auto insn : *this)
......@@ -1577,6 +1595,9 @@ void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitSta
SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
{
dbgBeginEmitInstruction(insn, state);
defer(dbgEndEmitInstruction(insn, state));
auto opcode = insn.opcode();
switch(opcode)
......@@ -1624,7 +1645,6 @@ SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitStat
case spv::OpSource:
case spv::OpSourceContinued:
case spv::OpSourceExtension:
case spv::OpLine:
case spv::OpNoLine:
case spv::OpModuleProcessed:
case spv::OpString:
......@@ -1632,6 +1652,9 @@ SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitStat
// or don't require any work at all.
return EmitResult::Continue;
case spv::OpLine:
return EmitLine(insn, state);
case spv::OpLabel:
return EmitResult::Continue;
......
......@@ -497,6 +497,8 @@ public:
bool robustBufferAccess,
const std::shared_ptr<vk::dbg::Context> &dbgctx);
~SpirvShader();
struct Modes
{
bool EarlyFragmentTests : 1;
......@@ -1090,6 +1092,7 @@ private:
EmitResult EmitSelect(InsnIterator insn, EmitState *state) const;
EmitResult EmitExtendedInstruction(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 EmitAll(InsnIterator insn, EmitState *state) const;
EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
......@@ -1170,14 +1173,58 @@ private:
// Returns 0 when invalid.
static VkShaderStageFlagBits executionModelToStage(spv::ExecutionModel model);
// Impl holds private forward declaration structs that are implemented
// in the corresponding SpirvShaderXXX.cpp files.
// Debugger API functions. When ENABLE_VK_DEBUGGER is not defined, these
// 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
// littering the header with implementation details.
struct Impl
{
struct Debugger;
struct Group;
Debugger *debugger = nullptr;
};
Impl impl;
};
class SpirvRoutine
......@@ -1230,6 +1277,8 @@ public:
std::array<SIMD::Int, 3> localInvocationID;
std::array<SIMD::Int, 3> globalInvocationID;
Pointer<Byte> dbgState; // Pointer to a debugger state.
void createVariable(SpirvShader::Object::ID id, uint32_t size)
{
bool added = variables.emplace(id, Variable(size)).second;
......
......@@ -702,6 +702,7 @@ void SpirvShader::Yield(YieldResult res) const
void SpirvShader::SetActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const
{
state->activeLaneMaskValue = mask.value;
dbgUpdateActiveLaneMask(mask, state);
}
} // 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