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?= <[email protected]> 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 fcce947de388ef3d6f6d795355d6631b60ee93f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <[email protected]> Date: Mon, 31 Aug 2026 11:40:06 +0200 Subject: [PATCH 2/2] Update llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp --- llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp index 26c071fe2e18d..2924a3fd5eb9e 100644 --- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp @@ -650,7 +650,6 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType( return getOrEmitDebugTypeFunction(Ops, VoidTypeReg, ExtInstSetReg, MAI); } -// Match SPIRV-LLVM-Translator's selection logic for the Parent operand. std::optional<MCRegister> SPIRVNonSemanticDebugHandler::resolveScope( const DIScope *Scope, const DICompileUnit *FallbackCU) const { if (const auto *Ty = dyn_cast_or_null<DIType>(Scope)) _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
