SpirvShaderDebugger: Make Function extend Scope
Reading between the lines of the spec, Functions are also scopes.
Move common scope fields into the base Scope class.
Fix `scope` fields requiring a `LexicalBlock` to take the more general `Scope`.
Bug: b/148401179
Change-Id: Iac7b4fd4440a701905e2dbcdf71b91146ea8ff7d
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/42248
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: 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 3ede3ac..d744859 100644
--- a/src/Pipeline/SpirvShaderDebugger.cpp
+++ b/src/Pipeline/SpirvShaderDebugger.cpp
@@ -205,10 +205,12 @@
static constexpr bool kindof(Kind kind)
{
return kind == Kind::CompilationUnit ||
+ kind == Kind::Function ||
kind == Kind::LexicalBlock;
}
struct Source *source = nullptr;
+ Scope *parent = nullptr;
};
struct Type : public Object
@@ -290,14 +292,12 @@
uint32_t flags = 0; // OR'd from OpenCLDebugInfo100DebugInfoFlags
};
-struct Function : ObjectImpl<Function, Object, Object::Kind::Function>
+struct Function : ObjectImpl<Function, Scope, Object::Kind::Function>
{
std::string name;
FunctionType *type = nullptr;
- Source *source = nullptr;
uint32_t line = 0;
uint32_t column = 0;
- struct LexicalBlock *parent = nullptr;
std::string linkage;
uint32_t flags = 0; // OR'd from OpenCLDebugInfo100DebugInfoFlags
uint32_t scopeLine = 0;
@@ -308,9 +308,7 @@
{
uint32_t line = 0;
uint32_t column = 0;
- Scope *parent = nullptr;
std::string name;
- Function *function = nullptr;
};
struct InlinedAt : ObjectImpl<InlinedAt, Object, Object::Kind::InlinedAt>
@@ -322,7 +320,7 @@
struct SourceScope : ObjectImpl<SourceScope, Object, Object::Kind::SourceScope>
{
- LexicalBlock *scope = nullptr;
+ Scope *scope = nullptr;
InlinedAt *inlinedAt = nullptr;
};
@@ -367,6 +365,16 @@
const Scope Scope::Root = CompilationUnit{};
+// find<T>() searches the nested scopes, returning for the first scope that is
+// castable to type T. If no scope can be found of type T, then nullptr is
+// returned.
+template<typename T>
+T *find(Scope *scope)
+{
+ if(auto out = cast<T>(scope)) { return out; }
+ return scope->parent ? find<T>(scope->parent) : nullptr;
+}
+
} // namespace debug
} // anonymous namespace
@@ -629,6 +637,10 @@
void SpirvShader::Impl::Debugger::State::createScope(const debug::Scope *spirvScope)
{
+ // TODO(b/151338669): We're creating scopes per-shader invocation.
+ // This is all really static information, and should only be created
+ // once *per program*.
+
ASSERT(spirvScope != nullptr);
// TODO: Deal with scope nesting.
@@ -653,23 +665,26 @@
if(oldSrcScope == newSrcScope) { return; }
srcScope = newSrcScope;
- auto lock = debugger->ctx->lock();
- auto thread = lock.currentThread();
-
- debug::Function *oldFunction = oldSrcScope ? oldSrcScope->scope->function : nullptr;
- debug::Function *newFunction = newSrcScope ? newSrcScope->scope->function : nullptr;
-
- if(oldFunction != newFunction)
+ if(debug::cast<debug::LexicalBlock>(srcScope->scope))
{
- if(oldFunction) { thread->exit(); }
- if(newFunction) { thread->enter(lock, newFunction->source->dbgFile, newFunction->name); }
- }
+ auto lock = debugger->ctx->lock();
+ auto thread = lock.currentThread();
- auto dbgScope = getScopes(srcScope->scope);
- thread->update([&](vk::dbg::Frame &frame) {
- frame.locals = dbgScope.locals;
- frame.hovers = dbgScope.hovers;
- });
+ debug::Function *oldFunction = oldSrcScope ? debug::find<debug::Function>(oldSrcScope->scope) : nullptr;
+ debug::Function *newFunction = newSrcScope ? debug::find<debug::Function>(newSrcScope->scope) : nullptr;
+
+ if(oldFunction != newFunction)
+ {
+ if(oldFunction) { thread->exit(); }
+ if(newFunction) { thread->enter(lock, newFunction->source->dbgFile, newFunction->name); }
+ }
+
+ auto dbgScope = getScopes(srcScope->scope);
+ thread->update([&](vk::dbg::Frame &frame) {
+ frame.locals = dbgScope.locals;
+ frame.hovers = dbgScope.hovers;
+ });
+ }
}
const SpirvShader::Impl::Debugger::State::Scopes &SpirvShader::Impl::Debugger::State::getScopes(const debug::Scope *scope)
@@ -680,7 +695,9 @@
}
auto dbgScopeIt = scopes.find(scope);
- ASSERT_MSG(dbgScopeIt != scopes.end(), "createScope() not called for debug::Scope %p", scope);
+ ASSERT_MSG(dbgScopeIt != scopes.end(),
+ "createScope() not called for debug::Scope %s %p",
+ cstr(scope->kind), scope);
return dbgScopeIt->second;
}
@@ -904,14 +921,14 @@
func->source = get(debug::Source::ID(insn.word(7)));
func->line = insn.word(8);
func->column = insn.word(9);
- func->parent = get(debug::LexicalBlock::ID(insn.word(10)));
+ func->parent = get(debug::Scope::ID(insn.word(10)));
func->linkage = shader->getString(insn.word(11));
func->flags = insn.word(12);
func->scopeLine = insn.word(13);
func->function = Function::ID(insn.word(14));
// declaration: word(13)
- func->parent->function = func;
+ rr::Call(&State::createScope, state->routine->dbgState, func);
});
break;
case OpenCLDebugInfo100DebugLexicalBlock:
@@ -925,15 +942,12 @@
scope->name = shader->getString(insn.word(9));
}
- // TODO: We're creating scopes per-shader invocation.
- // This is all really static information, and should only be created
- // once *per program*.
rr::Call(&State::createScope, state->routine->dbgState, scope);
});
break;
case OpenCLDebugInfo100DebugScope:
defineOrEmit(insn, pass, [&](debug::SourceScope *ss) {
- ss->scope = get(debug::LexicalBlock::ID(insn.word(5)));
+ ss->scope = get(debug::Scope::ID(insn.word(5)));
if(insn.wordCount() > 6)
{
ss->inlinedAt = get(debug::InlinedAt::ID(insn.word(6)));
@@ -947,7 +961,7 @@
case OpenCLDebugInfo100DebugInlinedAt:
defineOrEmit(insn, pass, [&](debug::InlinedAt *ia) {
ia->line = insn.word(5);
- ia->scope = get(debug::LexicalBlock::ID(insn.word(6)));
+ ia->scope = get(debug::Scope::ID(insn.word(6)));
if(insn.wordCount() > 7)
{
ia->inlined = get(debug::InlinedAt::ID(insn.word(7)));