Vulkan/Debug: Don't step for column updates
OpLine is produced for any line / column change.
Column information may be useful for stack frame information (say two function calls on the same line), diagnosing a crash in a complex expression, or some other tooling. However, it's not so useful for IDE debugger stepping, unless you have a location for the span end (which we don't).
Bug: b/155390706
Bug: b/148401179
Change-Id: Ic416c6e3c47044d707bfa36112e1153588669424
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/44549
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShaderDebugger.cpp b/src/Pipeline/SpirvShaderDebugger.cpp
index e936a4d..7011cb8 100644
--- a/src/Pipeline/SpirvShaderDebugger.cpp
+++ b/src/Pipeline/SpirvShaderDebugger.cpp
@@ -451,6 +451,7 @@
void process(const SpirvShader *shader, const InsnIterator &insn, EmitState *state, Pass pass);
+ void setNextSetLocationIsStep();
void setLocation(EmitState *state, const std::shared_ptr<vk::dbg::File> &, int line, int column);
void setLocation(EmitState *state, const std::string &path, int line, int column);
@@ -514,6 +515,8 @@
void defineOrEmit(InsnIterator insn, Pass pass, F &&emit);
std::unordered_map<std::string, std::shared_ptr<vk::dbg::File>> files;
+ bool nextSetLocationIsStep = true;
+ int lastSetLocationLine = 0;
};
////////////////////////////////////////////////////////////////////////////////
@@ -533,7 +536,7 @@
void enter(vk::dbg::Context::Lock &lock, const char *name);
void exit();
void updateActiveLaneMask(int lane, bool enabled);
- void updateLocation(vk::dbg::File::ID file, int line, int column);
+ void updateLocation(bool isStep, vk::dbg::File::ID file, int line, int column);
void createScope(const debug::Scope *);
void setScope(debug::SourceScope *newScope);
@@ -595,7 +598,7 @@
builtinsByLane[i] = lock.createVariableContainer();
}
- thread->update([&](vk::dbg::Frame &frame) {
+ thread->update(true, [&](vk::dbg::Frame &frame) {
rootScopes.locals = frame.locals;
rootScopes.hovers = frame.hovers;
for(int i = 0; i < sw::SIMD::Width; i++)
@@ -631,10 +634,10 @@
rootScopes.localsByLane[lane]->put("enabled", vk::dbg::make_constant(enabled));
}
-void SpirvShader::Impl::Debugger::State::updateLocation(vk::dbg::File::ID fileID, int line, int column)
+void SpirvShader::Impl::Debugger::State::updateLocation(bool isStep, vk::dbg::File::ID fileID, int line, int column)
{
auto file = debugger->ctx->lock().get(fileID);
- thread->update([&](vk::dbg::Frame &frame) {
+ thread->update(isStep, [&](vk::dbg::Frame &frame) {
frame.location = { file, line, column };
});
}
@@ -735,7 +738,7 @@
}
auto dbgScope = getScopes(srcScope->scope);
- thread->update([&](vk::dbg::Frame &frame) {
+ thread->update(true, [&](vk::dbg::Frame &frame) {
frame.locals = dbgScope.locals;
frame.hovers = dbgScope.hovers;
});
@@ -1137,9 +1140,21 @@
}
}
+void SpirvShader::Impl::Debugger::setNextSetLocationIsStep()
+{
+ nextSetLocationIsStep = true;
+}
+
void SpirvShader::Impl::Debugger::setLocation(EmitState *state, const std::shared_ptr<vk::dbg::File> &file, int line, int column)
{
- rr::Call(&State::updateLocation, state->routine->dbgState, file->id, line, column);
+ if(line != lastSetLocationLine)
+ {
+ // If the line number has changed, then this is always a step.
+ nextSetLocationIsStep = true;
+ lastSetLocationLine = line;
+ }
+ rr::Call(&State::updateLocation, state->routine->dbgState, nextSetLocationIsStep, file->id, line, column);
+ nextSetLocationIsStep = false;
}
void SpirvShader::Impl::Debugger::setLocation(EmitState *state, const std::string &path, int line, int column)
@@ -1579,6 +1594,16 @@
if(auto dbg = impl.debugger)
{
+ if(insn.opcode() == spv::OpLabel)
+ {
+ // Whenever we hit a label, force the next OpLine to be steppable.
+ // This handles the case where we have control flow on the same line
+ // For example:
+ // while(true) { foo(); }
+ // foo() should be repeatedly steppable.
+ dbg->setNextSetLocationIsStep();
+ }
+
if(extensionsImported.count(Extension::OpenCLDebugInfo100) == 0)
{
// We're emitting debugger logic for SPIR-V.
diff --git a/src/Vulkan/Debug/Thread.cpp b/src/Vulkan/Debug/Thread.cpp
index 5c819f7..8228465 100644
--- a/src/Vulkan/Debug/Thread.cpp
+++ b/src/Vulkan/Debug/Thread.cpp
@@ -96,15 +96,22 @@
frames.pop_back();
}
-void Thread::update(std::function<void(Frame &)> f)
+void Thread::update(bool isStep, std::function<void(Frame &)> f)
{
marl::lock lock(mutex);
auto &frame = *frames.back();
- auto oldLocation = frame.location;
- f(frame);
- if(frame.location != oldLocation)
+ if(isStep)
{
- onLocationUpdate(lock);
+ auto oldLocation = frame.location;
+ f(frame);
+ if(frame.location != oldLocation)
+ {
+ onLocationUpdate(lock);
+ }
+ }
+ else
+ {
+ f(frame);
}
}
diff --git a/src/Vulkan/Debug/Thread.hpp b/src/Vulkan/Debug/Thread.hpp
index cf946a9..690fb37 100644
--- a/src/Vulkan/Debug/Thread.hpp
+++ b/src/Vulkan/Debug/Thread.hpp
@@ -143,9 +143,14 @@
State state() const;
// update() calls f to modify the top most frame of the stack.
- // If the frame's location is changed, update() potentially blocks until the
- // thread is resumed with one of the methods below.
- void update(std::function<void(Frame &)> f);
+ // If the frame's location is changed and isStep is true, update()
+ // potentially blocks until the thread is resumed with one of the methods
+ // below.
+ // isStep is used to distinguish same-statement column position updates
+ // from full line updates. Note that we cannot simply examine line position
+ // changes as single-line loops such as `while(true) { foo(); }` would not
+ // be correctly steppable.
+ void update(bool isStep, std::function<void(Frame &)> f);
// resume() resumes execution of the thread by unblocking a call to
// update() and setting the thread's state to State::Running.
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index d46620d..f6075b0 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -1805,7 +1805,7 @@
#ifdef ENABLE_VK_DEBUGGER
if(debuggerThread)
{
- debuggerThread->update([&](vk::dbg::Frame &frame) {
+ debuggerThread->update(true, [&](vk::dbg::Frame &frame) {
frame.location = { debuggerFile, line++, 0 };
});
}