SpirvShaderDebugger: Implement scope nesting

Previously nested scopes would hide their parent variables.
This is no longer the case.

Bug: b/148401179
Change-Id: Icf2771a525524b8796ab12e295e141388bb5b399
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/42368
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShaderDebugger.cpp b/src/Pipeline/SpirvShaderDebugger.cpp
index 41913d9..637dd80 100644
--- a/src/Pipeline/SpirvShaderDebugger.cpp
+++ b/src/Pipeline/SpirvShaderDebugger.cpp
@@ -377,6 +377,12 @@
 	return scope->parent ? find<T>(scope->parent) : nullptr;
 }
 
+bool hasDebuggerScope(debug::Scope *spirvScope)
+{
+	return debug::cast<debug::Function>(spirvScope) != nullptr ||
+	       debug::cast<debug::LexicalBlock>(spirvScope) != nullptr;
+}
+
 }  // namespace debug
 }  // anonymous namespace
 
@@ -421,7 +427,8 @@
 
 	void process(const SpirvShader *shader, const InsnIterator &insn, EmitState *state, Pass pass);
 
-	void setPosition(EmitState *state, const std::string &path, uint32_t line, uint32_t column);
+	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);
 
 	// exposeVariable exposes the variable with the given ID to the debugger
 	// using the specified key.
@@ -469,8 +476,6 @@
 	// use get() and add() to access this
 	std::unordered_map<debug::Object::ID, std::unique_ptr<debug::Object>> objects;
 
-	std::unordered_map<std::string, vk::dbg::File::ID> fileIDs;
-
 	// defineOrEmit() when called in Pass::Define, creates and stores a
 	// zero-initialized object into the Debugger::objects map using the
 	// object identifier held by second instruction operand.
@@ -483,6 +488,8 @@
 	// The object type is automatically inferred from the function signature.
 	template<typename F, typename T = typename std::remove_pointer<ArgTyT<F>>::type>
 	void defineOrEmit(InsnIterator insn, Pass pass, F &&emit);
+
+	std::unordered_map<std::string, std::shared_ptr<vk::dbg::File>> files;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -502,7 +509,7 @@
 	void enter(vk::dbg::Context::Lock &lock, const char *name);
 	void exit();
 	void updateActiveLaneMask(int lane, bool enabled);
-	void update(vk::dbg::File::ID file, int line, int column);
+	void updateLocation(vk::dbg::File::ID file, int line, int column);
 	void createScope(const debug::Scope *);
 	void setScope(debug::SourceScope *newScope);
 
@@ -594,7 +601,7 @@
 	rootScopes.localsByLane[lane]->put("enabled", vk::dbg::make_constant(enabled));
 }
 
-void SpirvShader::Impl::Debugger::State::update(vk::dbg::File::ID fileID, int line, int column)
+void SpirvShader::Impl::Debugger::State::updateLocation(vk::dbg::File::ID fileID, int line, int column)
 {
 	auto file = debugger->ctx->lock().get(fileID);
 	thread->update([&](vk::dbg::Frame &frame) {
@@ -645,19 +652,35 @@
 
 	ASSERT(spirvScope != nullptr);
 
-	// TODO: Deal with scope nesting.
-
 	auto lock = debugger->ctx->lock();
 	Scopes s = {};
 	s.locals = lock.createScope(spirvScope->source->dbgFile);
 	s.hovers = lock.createScope(spirvScope->source->dbgFile);
+
 	for(int i = 0; i < sw::SIMD::Width; i++)
 	{
 		auto locals = lock.createVariableContainer();
-		locals->extend(builtinsByLane[i]);
 		s.localsByLane[i] = locals;
 		s.locals->variables->put(laneNames[i], locals);
 	}
+
+	if(hasDebuggerScope(spirvScope->parent))
+	{
+		auto parent = getScopes(spirvScope->parent);
+		for(int i = 0; i < sw::SIMD::Width; i++)
+		{
+			s.localsByLane[i]->extend(parent.localsByLane[i]);
+		}
+		s.hovers->variables->extend(parent.hovers->variables);
+	}
+	else
+	{
+		for(int i = 0; i < sw::SIMD::Width; i++)
+		{
+			s.localsByLane[i]->extend(builtinsByLane[i]);
+		}
+	}
+
 	scopes.emplace(spirvScope, std::move(s));
 }
 
@@ -667,7 +690,7 @@
 	if(oldSrcScope == newSrcScope) { return; }
 	srcScope = newSrcScope;
 
-	if(debug::cast<debug::LexicalBlock>(srcScope->scope))
+	if(hasDebuggerScope(srcScope->scope))
 	{
 		auto lock = debugger->ctx->lock();
 		auto thread = lock.currentThread();
@@ -1027,7 +1050,7 @@
 
 				auto file = dbg->ctx->lock().createVirtualFile(source->file.c_str(), source->source.c_str());
 				source->dbgFile = file;
-				fileIDs.emplace(source->file.c_str(), file->id);
+				files.emplace(source->file.c_str(), file);
 			});
 			break;
 
@@ -1057,12 +1080,17 @@
 	}
 }
 
-void SpirvShader::Impl::Debugger::setPosition(EmitState *state, const std::string &path, uint32_t line, uint32_t column)
+void SpirvShader::Impl::Debugger::setLocation(EmitState *state, const std::shared_ptr<vk::dbg::File> &file, int line, int column)
 {
-	auto it = fileIDs.find(path);
-	if(it != fileIDs.end())
+	rr::Call(&State::updateLocation, state->routine->dbgState, file->id, line, column);
+}
+
+void SpirvShader::Impl::Debugger::setLocation(EmitState *state, const std::string &path, int line, int column)
+{
+	auto it = files.find(path);
+	if(it != files.end())
 	{
-		rr::Call(&State::update, state->routine->dbgState, it->second, line, column);
+		setLocation(state, it->second, line, column);
 	}
 }
 
@@ -1479,18 +1507,19 @@
 	}
 #	endif  // PRINT_EACH_EXECUTED_INSTRUCTION
 
-	if(extensionsImported.count(Extension::OpenCLDebugInfo100) == 0)
-	{
-		// We're emitting debugger logic for SPIR-V.
-		// Only single line step over statement instructions.
-		if(IsStatement(insn.opcode()))
-		{
-			auto dbg = impl.debugger;
-			if(!dbg) { return; }
+	// Only single line step over statement instructions.
 
-			auto line = dbg->spirvLineMappings.at(insn.wordPointer(0));
-			auto column = 0;
-			rr::Call(&Impl::Debugger::State::update, state->routine->dbgState, dbg->spirvFile->id, line, column);
+	if(auto dbg = impl.debugger)
+	{
+		if(extensionsImported.count(Extension::OpenCLDebugInfo100) == 0)
+		{
+			// We're emitting debugger logic for SPIR-V.
+			if(IsStatement(insn.opcode()))
+			{
+				auto line = dbg->spirvLineMappings.at(insn.wordPointer(0));
+				auto column = 0;
+				dbg->setLocation(state, dbg->spirvFile, line, column);
+			}
 		}
 	}
 }
@@ -1542,7 +1571,7 @@
 		auto path = getString(insn.word(1));
 		auto line = insn.word(2);
 		auto column = insn.word(3);
-		dbg->setPosition(state, path, line, column);
+		dbg->setLocation(state, path, line, column);
 	}
 	return EmitResult::Continue;
 }