[llvm-branch-commits] [llvm] [NFC][SPIRV] Converge different `resolveDebugParentScope` versions into a single one (PR #219925)
Juan Manuel Martinez CaamaƱo via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Sep 1 02:15:15 PDT 2026
https://github.com/jmmartinez updated https://github.com/llvm/llvm-project/pull/219925
>From 7d906ae5a2c3dcb05d152e1e66f48da8f275b42e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
<jmartinezcaamao at gmail.com>
Date: Mon, 31 Aug 2026 11:21:08 +0200
Subject: [PATCH 1/2] [NFC][SPIRV] Converge different resolveDebugParentScope
versions into a single one
---
.../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 111 ++++--------------
.../SPIRV/SPIRVNonSemanticDebugHandler.h | 47 ++------
2 files changed, 36 insertions(+), 122 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 96862cad99afa..26c071fe2e18d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -651,59 +651,24 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
}
// Match SPIRV-LLVM-Translator's selection logic for the Parent operand.
-std::optional<MCRegister>
-SPIRVNonSemanticDebugHandler::resolveDebugFunctionParent(
- const DISubprogram *SP) const {
- const DIScope *Scope = SP->getScope();
- if (Scope && !isa<DIFile>(Scope)) {
- // Find the DINamespace that was emitted as a lexical block.
- if (isa<DINamespace>(Scope))
- return lookupOptReg(DebugLexicalBlockRegs, Scope);
- // TODO: Complete with other lookups once other scopes are supported
- // (subclasses of DIScope).
- const DIType *Ty = dyn_cast<DIType>(Scope);
- if (!Ty)
- return std::nullopt;
- return lookupOptReg(DebugTypeRegs, Ty);
- }
-
- const DICompileUnit *ParentCU = SP->getUnit();
- if (!ParentCU && !CompileUnits.empty())
- ParentCU = CompileUnits[0].TheCU;
- if (!ParentCU)
- return std::nullopt;
- return lookupOptReg(CUToCompilationUnitDbgReg, ParentCU);
-}
-
-std::optional<MCRegister> SPIRVNonSemanticDebugHandler::resolveTypeScopeParent(
- const DIScope *Scope) const {
- // When the scope is itself a type (e.g. a struct nested in another struct),
- // the parent is that enclosing type's debug id.
+std::optional<MCRegister> SPIRVNonSemanticDebugHandler::resolveScope(
+ const DIScope *Scope, const DICompileUnit *FallbackCU) const {
if (const auto *Ty = dyn_cast_or_null<DIType>(Scope))
return lookupOptReg(DebugTypeRegs, Ty);
- // Find the DINamespace that was emitted as a lexical block.
- if (isa_and_nonnull<DINamespace>(Scope))
+ if (isa_and_nonnull<DILexicalBlock, DINamespace>(Scope))
return lookupOptReg(DebugLexicalBlockRegs, Scope);
- // For a file, compile-unit, or absent scope, the parent is the first module
- // DebugCompilationUnit.
- if (CompileUnits.empty())
- return std::nullopt;
-
- return lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
-}
-
-std::optional<MCRegister>
-SPIRVNonSemanticDebugHandler::resolveLexicalBlockParent(
- const DIScope *Scope) const {
- if (isa_and_nonnull<DILexicalBlock>(Scope) ||
- isa_and_nonnull<DINamespace>(Scope))
- return lookupOptReg(DebugLexicalBlockRegs, Scope);
if (const auto *SP = dyn_cast_or_null<DISubprogram>(Scope))
return lookupOptReg(DebugFunctionRegs, SP);
+
+ // For a file, compile-unit, or absent scope, fall back to a compile unit.
+ if (FallbackCU)
+ return lookupOptReg(CUToCompilationUnitDbgReg, FallbackCU);
+
if (CompileUnits.empty())
return std::nullopt;
+
return lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
}
@@ -712,7 +677,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugLexicalBlock(
MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
assert((isa<DILexicalBlock, DINamespace>(S)) &&
"S must be a DILexicalBlock or DINamespace in emitDebugLexicalBlock");
- auto ParentRegOpt = resolveLexicalBlockParent(S->getScope());
+ auto ParentRegOpt = resolveScope(S->getScope());
if (!ParentRegOpt)
return std::nullopt;
@@ -757,7 +722,7 @@ SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
return std::nullopt;
MCRegister FnTyReg = *FnTyRegOpt;
- auto ParentRegOpt = resolveDebugFunctionParent(SP);
+ auto ParentRegOpt = resolveScope(SP->getScope(), SP->getUnit());
if (!ParentRegOpt)
return std::nullopt;
@@ -798,7 +763,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugFunction(
if (!FnTyRegOpt)
return std::nullopt;
- auto ParentRegOpt = resolveDebugFunctionParent(SP);
+ auto ParentRegOpt = resolveScope(SP->getScope(), SP->getUnit());
if (!ParentRegOpt)
return std::nullopt;
@@ -842,30 +807,6 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
return lookupOptReg(DebugTypeRegs, Ty);
}
-MCRegister SPIRVNonSemanticDebugHandler::resolveGlobalVariableParent(
- const DIGlobalVariable *GV) const {
- // A namespace-scoped global variable's parent is the enclosing
- // DebugLexicalBlock emitted for that DINamespace.
- // TODO: When this backend emits debug instructions for subprogram,
- // compilation units, and module scopes, also return GV->getScope()'s debug
- // id for those cases.
- if (isa_and_nonnull<DINamespace>(GV->getScope())) {
- if (auto ParentRegOpt = lookupOptReg(DebugLexicalBlockRegs, GV->getScope()))
- return *ParentRegOpt;
- }
-
- // !CompileUnits.empty() was already checked before staring the emission of
- // NSDI instructions.
- assert(!CompileUnits.empty() &&
- "resolveGlobalVariableParent requires non-empty CompileUnits");
- std::optional<MCRegister> ParentRegOpt =
- lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
- assert(ParentRegOpt && "DebugCompilationUnit must be emitted before "
- "resolveGlobalVariableParent");
- // Fallback: first module compile unit (SPIRV-LLVM-Translator default).
- return *ParentRegOpt;
-}
-
// Unimplemented no-op; see emitDebugExpression declaration.
std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
const DIExpression *, MCRegister, MCRegister, SPIRV::ModuleAnalysisInfo &) {
@@ -878,7 +819,12 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
SPIRV::ModuleAnalysisInfo &MAI) {
assert(GV && "GV must not be null in emitDebugGlobalVariable");
- MCRegister ParentReg = resolveGlobalVariableParent(GV);
+ assert(!CompileUnits.empty() &&
+ "emitDebugGlobalVariable requires non-empty CompileUnits");
+ auto ParentRegOpt = resolveScope(GV->getScope());
+ assert(ParentRegOpt && "DebugCompilationUnit must be emitted before "
+ "emitDebugGlobalVariable");
+ MCRegister ParentReg = *ParentRegOpt;
// TyReg: DebugInfoNone when GV has no DI type (as done in
// SPIRV-LLVM-Translator). Declarations (isDefinition: false) can have null
@@ -1051,7 +997,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
const DICompositeType *CT, ArrayRef<MCRegister> MemberRegs,
MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
SPIRV::ModuleAnalysisInfo &MAI) {
- auto ParentRegOpt = resolveTypeScopeParent(CT->getScope());
+ auto ParentRegOpt = resolveScope(CT->getScope());
if (!ParentRegOpt)
return std::nullopt;
@@ -1105,21 +1051,10 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypedef(
// Parent must be a lexical scope. Valid NSDI lexical scopes are
// DebugCompilationUnit, DebugFunction, DebugLexicalBlock, or
// DebugTypeComposite.
- //
- // FIXME: We currently only emit DebugCompilationUnit, so the compile unit is
- // the only parent available today.
- MCRegister ParentReg;
- if (const auto *Ty = dyn_cast_or_null<DIType>(TD->getScope()))
- if (auto TyRegOpt = lookupOptReg(DebugTypeRegs, Ty))
- ParentReg = *TyRegOpt;
- if (!ParentReg.isValid()) {
- assert(!CompileUnits.empty() &&
- "emitDebugTypedef requires a compile unit for the Parent operand");
- auto CURegOpt =
- lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
- assert(CURegOpt && "DebugCompilationUnit must be emitted before typedefs");
- ParentReg = *CURegOpt;
- }
+ auto ParentRegOpt = resolveScope(TD->getScope());
+ if (!ParentRegOpt)
+ return std::nullopt;
+ MCRegister ParentReg = *ParentRegOpt;
return emitExtInst(
SPIRV::NonSemanticExtInst::DebugTypedef, VoidTypeReg, ExtInstSetReg,
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index 0b3c6fa0aa081..04faf612df920 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -334,8 +334,7 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
/// DISubroutineType type, the signature type was not emitted in \c
/// DebugTypeRegs, no path
/// \c OpString was recorded for \p SP in section 7, or
- /// \c resolveDebugFunctionParent returns no id for the \c Parent
- /// operand.
+ /// \c resolveScope returns no id for the \c Parent operand.
std::optional<MCRegister>
emitDebugFunctionDeclaration(const DISubprogram *SP, MCRegister VoidTypeReg,
MCRegister I32TypeReg, MCRegister ExtInstSetReg,
@@ -371,9 +370,6 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
SPIRV::ModuleAnalysisInfo &MAI);
- /// Resolve the \c Parent operand for \c DebugGlobalVariable.
- MCRegister resolveGlobalVariableParent(const DIGlobalVariable *GV) const;
-
/// Emit \c DebugExpression for \p Expr. Unimplemented: defined as a no-op
/// (\returns \c std::nullopt, emits nothing) so \c emitDebugGlobalVariable
/// can complete Variable-operand resolution for the opcodes we support today.
@@ -480,34 +476,18 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
MCRegister ExtInstSetReg,
SPIRV::ModuleAnalysisInfo &MAI);
- /// Resolve the \c Parent operand for \c DebugFunctionDeclaration and
- /// \c DebugFunction: an emitted debug type id when \c SP->getScope() is a
- /// \c DIType in \c DebugTypeRegs, otherwise \c DebugCompilationUnit for
- /// \c SP->getUnit() (or the first module CU when \c unit: is absent).
- /// \returns \c std::nullopt when the scope requires a parent we cannot supply
- /// (non-file scope that is not a mapped \c DIType) or the CU has no emitted
- /// id.
- std::optional<MCRegister>
- resolveDebugFunctionParent(const DISubprogram *SP) const;
-
- /// Resolve the \c Parent operand for a type instruction (\c
- /// DebugTypeComposite) from its \p Scope: an emitted debug type id when \p
- /// Scope is a \c DIType in \c DebugTypeRegs (a type nested in another type),
- /// otherwise the first module \c DebugCompilationUnit.
- /// \returns \c std::nullopt when \p Scope is a \c DIType that has not been
- /// emitted, or when there is no compile unit.
- std::optional<MCRegister> resolveTypeScopeParent(const DIScope *Scope) const;
-
- /// Resolve the \c Parent operand for \c DebugLexicalBlock, and for any other
- /// instruction whose LLVM scope may be a \c DILexicalBlock or \c
- /// DINamespace: an emitted \c DebugLexicalBlock id when \p Scope is a \c
- /// DILexicalBlock or \c DINamespace already in \c DebugLexicalBlockRegs, an
- /// emitted \c DebugFunction id when \p Scope is a defining \c DISubprogram,
- /// otherwise the first module \c DebugCompilationUnit.
- /// \returns \c std::nullopt when \p Scope requires a parent we cannot
- /// supply, or the fallback CU has no emitted id.
+ /// Map \p Scope to the NonSemantic debug id used as a \c Parent operand.
+ ///
+ /// Checks \c DebugTypeRegs, \c DebugLexicalBlockRegs, and \c
+ /// DebugFunctionRegs in order. When \p Scope is null, a \c DIFile, or
+ /// another scope without a dedicated debug instruction, falls back to \p
+ /// FallbackCU or the first module \c DebugCompilationUnit.
+ ///
+ /// \returns \c std::nullopt when \p Scope names an emitted scope that has
+ /// not been recorded yet, or when no fallback compile unit is available.
std::optional<MCRegister>
- resolveLexicalBlockParent(const DIScope *Scope) const;
+ resolveScope(const DIScope *Scope,
+ const DICompileUnit *FallbackCU = nullptr) const;
/// Emit \c DebugLexicalBlock for \p S, which must be a \c DILexicalBlock or
/// a \c DINamespace. A \c DILexicalBlock supplies Line/Column
@@ -515,8 +495,7 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
/// emitted as 0, and its Name is appended as an extra \c OpString operand.
///
/// \returns The result id register on success. Returns \c std::nullopt and
- /// emits nothing if \c resolveLexicalBlockParent returns no id for
- /// \c S->getScope().
+ /// emits nothing if \c resolveScope returns no id for \c S->getScope().
std::optional<MCRegister>
emitDebugLexicalBlock(const DIScope *S, MCRegister VoidTypeReg,
MCRegister I32TypeReg, MCRegister ExtInstSetReg,
>From 37ef9ac9226b770da31c44551981f0844e9cf2a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
<jmartinezcaamao at gmail.com>
Date: Tue, 1 Sep 2026 11:14:39 +0200
Subject: [PATCH 2/2] [Review] remove asserts
---
llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 26c071fe2e18d..2c2f9172f81c0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -819,11 +819,10 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
SPIRV::ModuleAnalysisInfo &MAI) {
assert(GV && "GV must not be null in emitDebugGlobalVariable");
- assert(!CompileUnits.empty() &&
- "emitDebugGlobalVariable requires non-empty CompileUnits");
auto ParentRegOpt = resolveScope(GV->getScope());
- assert(ParentRegOpt && "DebugCompilationUnit must be emitted before "
- "emitDebugGlobalVariable");
+ if (!ParentRegOpt)
+ return std::nullopt;
+
MCRegister ParentReg = *ParentRegOpt;
// TyReg: DebugInfoNone when GV has no DI type (as done in
More information about the llvm-branch-commits
mailing list