https://github.com/mgcarrasco updated https://github.com/llvm/llvm-project/pull/229488
>From 470bb5d238268898cf53dfcb1a2b152ae21bf9fa Mon Sep 17 00:00:00 2001 From: Manuel Carrasco <[email protected]> Date: Tue, 6 Oct 2026 11:33:02 -0500 Subject: [PATCH] [SPIRV] Emit each debug scope from getOrCreateDebugScope. Handlers return the opcode and the operands. getOrCreateDebugScope writes that instruction with a fresh id. --- .../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 348 +++++++++--------- .../SPIRV/SPIRVNonSemanticDebugHandler.h | 224 ++++++----- 2 files changed, 298 insertions(+), 274 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp index a6ab8022f8bb2..49757cbde9d01 100644 --- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp @@ -542,6 +542,7 @@ MCRegister SPIRVNonSemanticDebugHandler::emitExtInst( MCRegister VoidTypeReg, MCRegister ExtInstSetReg, ArrayRef<MCRegister> Operands, SPIRV::ModuleAnalysisInfo &MAI) { MCRegister Reg = MAI.getNextIDRegister(); + MCInst Inst; Inst.setOpcode(SPIRV::OpExtInst); Inst.addOperand(MCOperand::createReg(Reg)); @@ -761,34 +762,44 @@ MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32( // Each node emits its dependencies first. E.g. for `void f() { struct L; }`, // node L emits f, then L. For `struct S { S *p; }`, S* is a back edge, so S // is emitted without member p. -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::getOrCreateDebugScope(const DIScope *S) { +auto SPIRVNonSemanticDebugHandler::getOrCreateDebugScope(const DIScope *S) + -> EmitResult<MCRegister> { if (!S || FailedScopes.contains(S)) - return EmitResult::unsupported(); + return EmitResult<MCRegister>::unsupported(); if (auto Reg = lookupOptReg(DebugScopeRegs, S)) - return EmitResult::emitted(*Reg); + return EmitResult<MCRegister>::emitted(*Reg); // Mark the node as in progress while its dependencies are resolved/emitted. // This also prevents cycles from happening. if (!ScopesInProgress.insert(S).second) - return EmitResult::inProgress(); - EmitResult R = emitDebugScope(S); + return EmitResult<MCRegister>::inProgress(); + + EmitResult<PreparedScope> P = emitDebugScope(S); ScopesInProgress.erase(S); - assert((!R || !GlobalNSDIEnabled) && + assert((!P || !GlobalNSDIEnabled) && "debug type or scope created after module-scope NSDI emission"); - if (R) - DebugScopeRegs[S] = R.Reg; - else if (R.Status == EmitStatus::Unsupported) - FailedScopes.insert(S); - return R; + if (!P) { + if (P.Status == EmitStatus::Unsupported) + FailedScopes.insert(S); + return P.Status == EmitStatus::InProgress + ? EmitResult<MCRegister>::inProgress() + : EmitResult<MCRegister>::unsupported(); + } + + // The scope was successfully emitted. + SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI; + MCRegister Reg = + emitExtInst(P.Value->Opcode, getOrEmitOpTypeVoidReg(MAI), + MAI.getExtInstSetReg(NSSet), P.Value->Operands, MAI); + DebugScopeRegs[S] = Reg; + return EmitResult<MCRegister>::emitted(Reg); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypeBasic( - const DIBasicType *BT, MCRegister VoidTypeReg, MCRegister I32TypeReg, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { +auto SPIRVNonSemanticDebugHandler::emitDebugTypeBasic( + const DIBasicType *BT, MCRegister I32TypeReg, + SPIRV::ModuleAnalysisInfo &MAI) -> EmitResult<PreparedScope> { if (!isUInt<32>(BT->getSizeInBits())) - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); MCRegister NameReg = getCachedOpStringReg(BT->getName()); MCRegister SizeReg = emitOpConstantI32( @@ -822,13 +833,13 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeBasic( } MCRegister EncodingReg = emitOpConstantI32(Encoding, I32TypeReg, MAI); MCRegister FlagsReg = emitOpConstantI32(0, I32TypeReg, MAI); - return EmitResult::emitted(emitExtInst( - SPIRV::NonSemanticExtInst::DebugTypeBasic, VoidTypeReg, ExtInstSetReg, - {NameReg, SizeReg, EncodingReg, FlagsReg}, MAI)); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeBasic, + {NameReg, SizeReg, EncodingReg, FlagsReg}}); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugScope(const DIScope *S) { +auto SPIRVNonSemanticDebugHandler::emitDebugScope(const DIScope *S) + -> EmitResult<PreparedScope> { assert(CurrentMAI && "emitDebugScope requires CurrentMAI"); SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI; MCRegister ExtInstSetReg = MAI.getExtInstSetReg(NSSet); @@ -836,9 +847,9 @@ SPIRVNonSemanticDebugHandler::emitDebugScope(const DIScope *S) { MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI); if (const auto *BT = dyn_cast<DIBasicType>(S)) - return emitDebugTypeBasic(BT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI); + return emitDebugTypeBasic(BT, I32TypeReg, MAI); if (const auto *ST = dyn_cast<DISubroutineType>(S)) - return emitDebugTypeFunctionForSubroutineType(ST, ExtInstSetReg, MAI); + return emitDebugTypeFunctionForSubroutineType(ST, MAI); if (const auto *CT = dyn_cast<DICompositeType>(S)) return emitDebugTypeForCompositeType(CT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI); @@ -854,13 +865,13 @@ SPIRVNonSemanticDebugHandler::emitDebugScope(const DIScope *S) { return emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI); } - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypeForCompositeType( +auto SPIRVNonSemanticDebugHandler::emitDebugTypeForCompositeType( const DICompositeType *CT, MCRegister VoidTypeReg, MCRegister I32TypeReg, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { switch (CT->getTag()) { case dwarf::DW_TAG_array_type: // A vector is an array with DINode::FlagVector. A plain array is the @@ -875,49 +886,48 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeForCompositeType( // not disambiguate a matrix from a genuine array of vectors. Once the // frontend marks matrices, route them to a DebugTypeMatrix path here. if (CT->isVector()) - return emitDebugTypeVector(CT, ExtInstSetReg, MAI); - return emitDebugTypeArray(CT, ExtInstSetReg, MAI); + return emitDebugTypeVector(CT, MAI); + return emitDebugTypeArray(CT, MAI); case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_class_type: case dwarf::DW_TAG_union_type: return emitDebugTypeComposite(CT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI); default: - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); } } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypeForDerivedType( +auto SPIRVNonSemanticDebugHandler::emitDebugTypeForDerivedType( const DIDerivedType *DT, MCRegister VoidTypeReg, MCRegister I32TypeReg, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { switch (DT->getTag()) { case dwarf::DW_TAG_pointer_type: - return emitDebugTypePointer(DT, ExtInstSetReg, MAI); + return emitDebugTypePointer(DT, MAI); case dwarf::DW_TAG_typedef: return emitDebugTypedef(DT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI); case dwarf::DW_TAG_member: return emitDebugTypeMember(DT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI); default: - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); } } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypePointer( - const DIDerivedType *PT, MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI) { +auto SPIRVNonSemanticDebugHandler::emitDebugTypePointer( + const DIDerivedType *PT, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { // A DWARF address space is required to determine the SPIR-V storage class. // Skip pointer types that do not carry one. if (!PT->getDWARFAddressSpace().has_value()) - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); MCRegister BaseReg; if (const DIType *BaseTy = PT->getBaseType()) { - EmitResult Base = getOrCreateDebugScope(BaseTy); + EmitResult<MCRegister> Base = getOrCreateDebugScope(BaseTy); if (!Base) - return Base; - BaseReg = Base.Reg; + return EmitResult<PreparedScope>::failure(Base); + BaseReg = *Base.Value; } else { // No getBaseType() (typical for void*): use DebugInfoNone as Base Type, // same as SPIRV-LLVM-Translator (see issue #109287 and the DISABLED @@ -926,7 +936,6 @@ SPIRVNonSemanticDebugHandler::emitDebugTypePointer( BaseReg = CachedDebugInfoNoneReg; } - MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI); MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI); MCRegister DebugTypePointerFlagsReg = emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI); @@ -938,15 +947,14 @@ SPIRVNonSemanticDebugHandler::emitDebugTypePointer( addressSpaceToStorageClass(PT->getDWARFAddressSpace().value(), ST), I32TypeReg, MAI); - return EmitResult::emitted(emitExtInst( - SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg, ExtInstSetReg, - {BaseReg, StorageClassReg, DebugTypePointerFlagsReg}, MAI)); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugTypePointer, + {BaseReg, StorageClassReg, DebugTypePointerFlagsReg}}); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType( - const DISubroutineType *ST, MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI) { +auto SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType( + const DISubroutineType *ST, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI); MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI); MCRegister DebugTypeFunctionFlagsReg = @@ -962,22 +970,21 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType( } else { for (unsigned I = 0, E = TA.size(); I != E; ++I) { bool IsReturnType = (I == 0); - EmitResult Slot = + EmitResult<MCRegister> Slot = mapDISignatureTypeToReg(TA[I], VoidTypeReg, IsReturnType); // No emitted DebugType* id for this slot (e.g., pointer that // was skipped due missing address space, etc.). if (!Slot) - return Slot; - Ops.push_back(Slot.Reg); + return EmitResult<PreparedScope>::failure(Slot); + Ops.push_back(*Slot.Value); } } - return EmitResult::emitted( - emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeFunction, VoidTypeReg, - ExtInstSetReg, Ops, MAI)); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeFunction, Ops}); } // Match SPIRV-LLVM-Translator's selection logic for the Parent operand. -SPIRVNonSemanticDebugHandler::EmitResult +SPIRVNonSemanticDebugHandler::EmitResult<MCRegister> SPIRVNonSemanticDebugHandler::resolveScope(const DIScope *Scope, const DICompileUnit *FallbackCU) { // DebugLexicalBlockDiscriminator cannot be used as a scope, so unwrap it. @@ -989,26 +996,27 @@ SPIRVNonSemanticDebugHandler::resolveScope(const DIScope *Scope, // For a file, compile-unit, or absent scope, fall back to a compile unit. auto CUResult = [](std::optional<MCRegister> Reg) { - return Reg ? EmitResult::emitted(*Reg) : EmitResult::unsupported(); + return Reg ? EmitResult<MCRegister>::emitted(*Reg) + : EmitResult<MCRegister>::unsupported(); }; if (FallbackCU) return CUResult(lookupOptReg(DebugScopeRegs, FallbackCU)); if (CompileUnits.empty()) - return EmitResult::unsupported(); + return EmitResult<MCRegister>::unsupported(); return CUResult(lookupOptReg(DebugScopeRegs, CompileUnits[0].TheCU)); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugLexicalBlock( +auto SPIRVNonSemanticDebugHandler::emitDebugLexicalBlock( const DIScope *S, MCRegister VoidTypeReg, MCRegister I32TypeReg, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { assert((isa<DILexicalBlock, DINamespace>(S)) && "S must be a DILexicalBlock or DINamespace in emitDebugLexicalBlock"); - EmitResult Parent = resolveScope(S->getScope()); + EmitResult<MCRegister> Parent = resolveScope(S->getScope()); if (!Parent) - return Parent; + return EmitResult<PreparedScope>::failure(Parent); MCRegister FileStrReg = getCachedScopePathOpStringReg( S->getFile(), /*UseEmptyPathIfNullScope=*/true); @@ -1021,19 +1029,18 @@ SPIRVNonSemanticDebugHandler::emitDebugLexicalBlock( I32TypeReg, MAI); MCRegister ColReg = emitOpConstantI32( static_cast<uint32_t>(LB->getColumn()), I32TypeReg, MAI); - Ops = {SrcReg, LineReg, ColReg, Parent.Reg}; + Ops = {SrcReg, LineReg, ColReg, *Parent.Value}; } else { const auto *NS = cast<DINamespace>(S); // DINamespace carries no line/column info. MCRegister LineReg = emitOpConstantI32(0, I32TypeReg, MAI); MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI); MCRegister NameReg = getCachedOpStringReg(NS->getName()); - Ops = {SrcReg, LineReg, ColReg, Parent.Reg, NameReg}; + Ops = {SrcReg, LineReg, ColReg, *Parent.Value, NameReg}; } - return EmitResult::emitted( - emitExtInst(SPIRV::NonSemanticExtInst::DebugLexicalBlock, VoidTypeReg, - ExtInstSetReg, Ops, MAI)); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugLexicalBlock, Ops}); } MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugInlinedAt( @@ -1044,14 +1051,14 @@ MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugInlinedAt( if (MCRegister Cached = DebugInlinedAtRegs.lookup(IA)) return Cached; - EmitResult Scope = resolveScope(IA->getScope()); + EmitResult<MCRegister> Scope = resolveScope(IA->getScope()); if (!Scope) return MCRegister(); MCRegister LineReg = emitOpConstantI32(static_cast<uint32_t>(IA->getLine()), I32TypeReg, MAI); - SmallVector<MCRegister, 3> Ops{LineReg, Scope.Reg}; + SmallVector<MCRegister, 3> Ops{LineReg, *Scope.Value}; // Recurse before building this instruction's operands so an outer // inlined-at link is always available. if (const DILocation *Outer = IA->getInlinedAt()) { @@ -1068,22 +1075,22 @@ MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugInlinedAt( return Reg; } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration( +auto SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration( const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { assert(SP && "SP must not be null in emitDebugFunctionDeclaration"); assert(!SP->isDefinition() && "SP must not be a definition in emitDebugFunctionDeclaration"); // The IR verifier already enforces that this cannot be null. - EmitResult FnTy = getOrCreateDebugScope(SP->getType()); + EmitResult<MCRegister> FnTy = getOrCreateDebugScope(SP->getType()); if (!FnTy) - return FnTy; + return EmitResult<PreparedScope>::failure(FnTy); - EmitResult Parent = resolveScope(SP->getScope(), SP->getUnit()); + EmitResult<MCRegister> Parent = resolveScope(SP->getScope(), SP->getUnit()); if (!Parent) - return Parent; + return EmitResult<PreparedScope>::failure(Parent); MCRegister FileStrReg = getCachedScopePathOpStringReg(SP); @@ -1102,28 +1109,26 @@ SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration( FlagsVal &= ~NSDIFlagIsDefinition; MCRegister FlagsReg = emitOpConstantI32(FlagsVal, I32TypeReg, MAI); - return EmitResult::emitted( - emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDeclaration, - VoidTypeReg, ExtInstSetReg, - {NameReg, FnTy.Reg, SrcReg, LineReg, ColReg, Parent.Reg, - LinkageReg, FlagsReg}, - MAI)); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugFunctionDeclaration, + {NameReg, *FnTy.Value, SrcReg, LineReg, ColReg, + *Parent.Value, LinkageReg, FlagsReg}}); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugFunction( +auto SPIRVNonSemanticDebugHandler::emitDebugFunction( const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { assert(SP && "SP must not be null in emitDebugFunction"); assert(SP->isDefinition() && "SP must be a definition in emitDebugFunction"); - EmitResult FnTy = getOrCreateDebugScope(SP->getType()); + EmitResult<MCRegister> FnTy = getOrCreateDebugScope(SP->getType()); if (!FnTy) - return FnTy; + return EmitResult<PreparedScope>::failure(FnTy); - EmitResult Parent = resolveScope(SP->getScope(), SP->getUnit()); + EmitResult<MCRegister> Parent = resolveScope(SP->getScope(), SP->getUnit()); if (!Parent) - return Parent; + return EmitResult<PreparedScope>::failure(Parent); MCRegister NameReg = getCachedOpStringReg(SP->getName()); MCRegister LinkageReg = getCachedOpStringReg(SP->getLinkageName()); @@ -1140,31 +1145,29 @@ SPIRVNonSemanticDebugHandler::emitDebugFunction( MCRegister ScopeLineReg = emitOpConstantI32( static_cast<uint32_t>(SP->getScopeLine()), I32TypeReg, MAI); - SmallVector<MCRegister, 10> Ops = {NameReg, FnTy.Reg, SrcReg, - LineReg, ColReg, Parent.Reg, - LinkageReg, FlagsReg, ScopeLineReg}; + SmallVector<MCRegister, 10> Ops = {NameReg, *FnTy.Value, SrcReg, + LineReg, ColReg, *Parent.Value, + LinkageReg, FlagsReg, ScopeLineReg}; if (const DISubprogram *Decl = SP->getDeclaration()) { - EmitResult DeclRes = getOrCreateDebugScope(Decl); + EmitResult<MCRegister> DeclRes = getOrCreateDebugScope(Decl); if (DeclRes) - Ops.push_back(DeclRes.Reg); + Ops.push_back(*DeclRes.Value); } - return EmitResult::emitted( - emitExtInst(SPIRV::NonSemanticExtInst::DebugFunction, VoidTypeReg, - ExtInstSetReg, Ops, MAI)); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugFunction, Ops}); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(const DIType *Ty, - MCRegister VoidTypeReg, - bool ReturnType) { +auto SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg( + const DIType *Ty, MCRegister VoidTypeReg, bool ReturnType) + -> EmitResult<MCRegister> { if (!Ty) { if (ReturnType) - return EmitResult::emitted(VoidTypeReg); + return EmitResult<MCRegister>::emitted(VoidTypeReg); assert(CachedDebugInfoNoneReg.isValid() && "DebugInfoNone must be emitted before DISubroutineType operands"); - return EmitResult::emitted(CachedDebugInfoNoneReg); + return EmitResult<MCRegister>::emitted(CachedDebugInfoNoneReg); } return getOrCreateDebugScope(Ty); } @@ -1283,11 +1286,11 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable( SPIRV::ModuleAnalysisInfo &MAI) { assert(GV && "GV must not be null in emitDebugGlobalVariable"); - EmitResult Parent = resolveScope(GV->getScope()); + EmitResult<MCRegister> Parent = resolveScope(GV->getScope()); if (!Parent) return std::nullopt; - MCRegister ParentReg = Parent.Reg; + MCRegister ParentReg = *Parent.Value; // TyReg: DebugInfoNone when GV has no DI type (as done in // SPIRV-LLVM-Translator). Declarations (isDefinition: false) can have null @@ -1303,10 +1306,10 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable( std::optional<MCRegister> StaticMemberRegOpt; if (const DIDerivedType *SM = GV->getStaticDataMemberDeclaration()) { - EmitResult StaticMember = getOrCreateDebugScope(SM); + EmitResult<MCRegister> StaticMember = getOrCreateDebugScope(SM); if (!StaticMember) return std::nullopt; - StaticMemberRegOpt = StaticMember.Reg; + StaticMemberRegOpt = *StaticMember.Value; } MCRegister NameReg = getCachedOpStringReg(GV->getName()); @@ -1357,7 +1360,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugLocalVariable( MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { assert(LV && "LV must not be null in emitDebugLocalVariable"); - EmitResult Parent = resolveScope(LV->getScope()); + EmitResult<MCRegister> Parent = resolveScope(LV->getScope()); if (!Parent) return std::nullopt; @@ -1380,8 +1383,8 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugLocalVariable( MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI); MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(LV), I32TypeReg, MAI); - SmallVector<MCRegister, 8> Ops = {NameReg, TyReg, SrcReg, LineReg, - ColReg, Parent.Reg, FlagsReg}; + SmallVector<MCRegister, 8> Ops = {NameReg, TyReg, SrcReg, LineReg, + ColReg, *Parent.Value, FlagsReg}; if (unsigned Arg = LV->getArg()) Ops.push_back(emitOpConstantI32(Arg, I32TypeReg, MAI)); @@ -1389,52 +1392,47 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugLocalVariable( ExtInstSetReg, Ops, MAI); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypeVector( - const DICompositeType *VT, MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI) { +auto SPIRVNonSemanticDebugHandler::emitDebugTypeVector( + const DICompositeType *VT, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { const auto *BaseTy = dyn_cast_or_null<DIBasicType>(VT->getBaseType()); if (!BaseTy) - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); // DebugTypeVector models only 1D vectors (multi-subrange types cannot be // encoded). DINodeArray Elements = VT->getElements(); if (Elements.size() != 1) - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); const auto *SR = cast<DISubrange>(Elements[0]); const auto *CI = dyn_cast_if_present<ConstantInt *>(SR->getCount()); if (!CI) - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); - EmitResult Base = getOrCreateDebugScope(BaseTy); + EmitResult<MCRegister> Base = getOrCreateDebugScope(BaseTy); if (!Base) - return Base; + return EmitResult<PreparedScope>::failure(Base); - MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI); MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI); MCRegister CountReg = emitOpConstantI32( static_cast<uint32_t>(CI->getZExtValue()), I32TypeReg, MAI); - return EmitResult::emitted( - emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg, - ExtInstSetReg, {Base.Reg, CountReg}, MAI)); + return EmitResult<PreparedScope>::emitted(PreparedScope{ + SPIRV::NonSemanticExtInst::DebugTypeVector, {*Base.Value, CountReg}}); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypeArray( - const DICompositeType *AT, MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI) { +auto SPIRVNonSemanticDebugHandler::emitDebugTypeArray( + const DICompositeType *AT, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { // Unlike DebugTypeVector, the element may be any debug type, not only a // basic type. Create it first so this array names an id that already exists. - EmitResult Base = getOrCreateDebugScope(AT->getBaseType()); + EmitResult<MCRegister> Base = getOrCreateDebugScope(AT->getBaseType()); if (!Base) - return Base; + return EmitResult<PreparedScope>::failure(Base); - MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI); MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI); SmallVector<MCRegister> Ops; - Ops.push_back(Base.Reg); + Ops.push_back(*Base.Value); // One component count per DISubrange, in DWARF subrange order. Emit 0 for // counts that are not a compile-time constant (dynamic arrays). This matches @@ -1457,21 +1455,20 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeArray( Ops.push_back(emitOpConstantI32(Count, I32TypeReg, MAI)); } - return EmitResult::emitted( - emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeArray, VoidTypeReg, - ExtInstSetReg, Ops, MAI)); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeArray, Ops}); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypeMember( +auto SPIRVNonSemanticDebugHandler::emitDebugTypeMember( const DIDerivedType *M, MCRegister VoidTypeReg, MCRegister I32TypeReg, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { - EmitResult Ty = getOrCreateDebugScope(M->getBaseType()); + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { + EmitResult<MCRegister> Ty = getOrCreateDebugScope(M->getBaseType()); if (!Ty) - return Ty; + return EmitResult<PreparedScope>::failure(Ty); if (!isUInt<32>(M->getOffsetInBits()) || !isUInt<32>(M->getSizeInBits())) - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); MCRegister NameReg = getCachedOpStringReg(M->getName()); MCRegister FileStrReg = getCachedScopePathOpStringReg( @@ -1498,33 +1495,33 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeMember( // available but is not emitted as the optional Value operand, and under DWARF // 5 a static member is tagged DW_TAG_variable, which the caller's member loop // skips. - return EmitResult::emitted(emitExtInst( - SPIRV::NonSemanticExtInst::DebugTypeMember, VoidTypeReg, ExtInstSetReg, - {NameReg, Ty.Reg, SrcReg, LineReg, ColReg, OffsetReg, SizeReg, FlagsReg}, - MAI)); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeMember, + {NameReg, *Ty.Value, SrcReg, LineReg, ColReg, OffsetReg, + SizeReg, FlagsReg}}); } -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypeComposite( +auto SPIRVNonSemanticDebugHandler::emitDebugTypeComposite( const DICompositeType *CT, MCRegister VoidTypeReg, MCRegister I32TypeReg, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) { + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { // Parent and size before any member: a failure must stream nothing, or a // retry would emit the members again. - EmitResult Parent = resolveScope(CT->getScope()); + EmitResult<MCRegister> Parent = resolveScope(CT->getScope()); if (!Parent) - return Parent; + return EmitResult<PreparedScope>::failure(Parent); if (!isUInt<32>(CT->getSizeInBits())) - return EmitResult::unsupported(); + return EmitResult<PreparedScope>::unsupported(); SmallVector<MCRegister, 8> MemberRegs; for (const DINode *Element : CT->getElements()) { const auto *M = dyn_cast<DIDerivedType>(Element); if (!M || M->getTag() != dwarf::DW_TAG_member) continue; - EmitResult Member = getOrCreateDebugScope(M); + EmitResult<MCRegister> Member = getOrCreateDebugScope(M); if (Member) - MemberRegs.push_back(Member.Reg); + MemberRegs.push_back(*Member.Value); } MCRegister NameReg = getCachedOpStringReg(CT->getName()); @@ -1549,23 +1546,20 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeComposite( MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(CT), I32TypeReg, MAI); SmallVector<MCRegister> Ops = {NameReg, TagReg, SrcReg, - LineReg, ColReg, Parent.Reg, + LineReg, ColReg, *Parent.Value, LinkageReg, SizeReg, FlagsReg}; Ops.append(MemberRegs.begin(), MemberRegs.end()); - return EmitResult::emitted( - emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeComposite, VoidTypeReg, - ExtInstSetReg, Ops, MAI)); -} - -SPIRVNonSemanticDebugHandler::EmitResult -SPIRVNonSemanticDebugHandler::emitDebugTypedef(const DIDerivedType *TD, - MCRegister VoidTypeReg, - MCRegister I32TypeReg, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI) { - EmitResult Base = getOrCreateDebugScope(TD->getBaseType()); + return EmitResult<PreparedScope>::emitted( + PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeComposite, Ops}); +} + +auto SPIRVNonSemanticDebugHandler::emitDebugTypedef( + const DIDerivedType *TD, MCRegister VoidTypeReg, MCRegister I32TypeReg, + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) + -> EmitResult<PreparedScope> { + EmitResult<MCRegister> Base = getOrCreateDebugScope(TD->getBaseType()); if (!Base) - return Base; + return EmitResult<PreparedScope>::failure(Base); MCRegister NameReg = getCachedOpStringReg(TD->getName()); MCRegister FileStrReg = getCachedScopePathOpStringReg( @@ -1580,13 +1574,13 @@ SPIRVNonSemanticDebugHandler::emitDebugTypedef(const DIDerivedType *TD, // Parent must be a lexical scope. Valid NSDI lexical scopes are // DebugCompilationUnit, DebugFunction, DebugLexicalBlock, or // DebugTypeComposite. - EmitResult Parent = resolveScope(TD->getScope()); + EmitResult<MCRegister> Parent = resolveScope(TD->getScope()); if (!Parent) - return Parent; + return EmitResult<PreparedScope>::failure(Parent); - return EmitResult::emitted(emitExtInst( - SPIRV::NonSemanticExtInst::DebugTypedef, VoidTypeReg, ExtInstSetReg, - {NameReg, Base.Reg, SrcReg, LineReg, ColReg, Parent.Reg}, MAI)); + return EmitResult<PreparedScope>::emitted(PreparedScope{ + SPIRV::NonSemanticExtInst::DebugTypedef, + {NameReg, *Base.Value, SrcReg, LineReg, ColReg, *Parent.Value}}); } void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings( @@ -2092,11 +2086,11 @@ bool SPIRVNonSemanticDebugHandler::emitDebugScopeForInstruction( return true; } - EmitResult CurScopeRes = resolveScope(CurScope); + EmitResult<MCRegister> CurScopeRes = resolveScope(CurScope); if (!CurScopeRes) return false; - SmallVector<MCRegister, 2> Ops{CurScopeRes.Reg}; + SmallVector<MCRegister, 2> Ops{*CurScopeRes.Value}; if (CurInlinedAt) { // If the global emission did not include this inlined-at case, we skip it. MCRegister InlinedReg = DebugInlinedAtRegs.lookup(CurInlinedAt); diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h index efbabd280ea24..8e17d8cf0d39b 100644 --- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h +++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h @@ -32,6 +32,8 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCRegister.h" #include <optional> +#include <type_traits> +#include <utility> namespace llvm { @@ -81,21 +83,52 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase { InProgress, }; - struct EmitResult { - EmitStatus Status; - MCRegister Reg; + // One scope instruction, built but not yet emitted. getOrCreateDebugScope + // is the only place that emits it. + struct PreparedScope { + SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode{}; + SmallVector<MCRegister, 8> Operands; - static EmitResult emitted(MCRegister R) { return {EmitStatus::Emitted, R}; } - static EmitResult unsupported() { - return {EmitStatus::Unsupported, MCRegister()}; + PreparedScope() = default; + PreparedScope(SPIRV::NonSemanticExtInst::NonSemanticExtInst Op, + ArrayRef<MCRegister> Ops) + : Opcode(Op), Operands(Ops.begin(), Ops.end()) {} + }; + + // Status plus a payload. Value is set only when the status is Emitted, so + // InProgress and Unsupported carry no id and no PreparedScope. The payload + // is an id for a scope that already exists, and a PreparedScope for an + // instruction that getOrCreateDebugScope has not emitted yet. + template <typename T> struct EmitResult { + EmitStatus Status = EmitStatus::Unsupported; + std::optional<T> Value; + + static EmitResult emitted(T V) { + EmitResult R; + R.Status = EmitStatus::Emitted; + R.Value = std::move(V); + return R; } + static EmitResult unsupported() { return {}; } static EmitResult inProgress() { - return {EmitStatus::InProgress, MCRegister()}; + EmitResult R; + R.Status = EmitStatus::InProgress; + return R; + } + + template <typename U> + static EmitResult failure(const EmitResult<U> &Other) { + assert(!Other && "failure() requires a non-emitted result"); + EmitResult R; + R.Status = Other.Status; + return R; } explicit operator bool() const { - assert((Status != EmitStatus::Emitted || Reg.isValid()) && - "emitted EmitResult without a result id"); + assert(Value.has_value() == (Status == EmitStatus::Emitted) && + "payload is set exactly when the result is emitted"); + if constexpr (std::is_same_v<T, MCRegister>) + assert(!Value || Value->isValid()); return Status == EmitStatus::Emitted; } }; @@ -378,58 +411,54 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase { /// \c ScopesInProgress is the back edge of a cycle and is InProgress; nothing /// is emitted for that edge. An Unsupported result is recorded in /// \c FailedScopes, an InProgress one is not. - EmitResult getOrCreateDebugScope(const DIScope *S); - - /// Emit the instruction for \p S. Only \c getOrCreateDebugScope calls this - /// and records the result. - EmitResult emitDebugScope(const DIScope *S); - - /// Emit the \c DebugType* instruction for \p CT, picked by its tag. - EmitResult emitDebugTypeForCompositeType(const DICompositeType *CT, - MCRegister VoidTypeReg, - MCRegister I32TypeReg, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); - - /// Emit the \c DebugType* instruction for \p DT, picked by its tag. - EmitResult emitDebugTypeForDerivedType(const DIDerivedType *DT, - MCRegister VoidTypeReg, - MCRegister I32TypeReg, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); + EmitResult<MCRegister> getOrCreateDebugScope(const DIScope *S); + + /// Build the instruction for \p S. Only \c getOrCreateDebugScope calls this + /// and emits it. + EmitResult<PreparedScope> emitDebugScope(const DIScope *S); - /// Emit \c DebugTypeBasic for \p BT. Unsupported when the size does not fit + /// Build the \c DebugType* instruction for \p CT, picked by its tag. + EmitResult<PreparedScope> emitDebugTypeForCompositeType( + const DICompositeType *CT, MCRegister VoidTypeReg, MCRegister I32TypeReg, + MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI); + + /// Build the \c DebugType* instruction for \p DT, picked by its tag. + EmitResult<PreparedScope> + emitDebugTypeForDerivedType(const DIDerivedType *DT, MCRegister VoidTypeReg, + MCRegister I32TypeReg, MCRegister ExtInstSetReg, + SPIRV::ModuleAnalysisInfo &MAI); + + /// Build \c DebugTypeBasic for \p BT. Unsupported when the size does not fit /// in 32 bits. - EmitResult emitDebugTypeBasic(const DIBasicType *BT, MCRegister VoidTypeReg, - MCRegister I32TypeReg, MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); + EmitResult<PreparedScope> emitDebugTypeBasic(const DIBasicType *BT, + MCRegister I32TypeReg, + SPIRV::ModuleAnalysisInfo &MAI); - /// Emit \c DebugTypePointer for \p PT. Unsupported without a DWARF address + /// Build \c DebugTypePointer for \p PT. Unsupported without a DWARF address /// space, which gives the storage class. - EmitResult emitDebugTypePointer(const DIDerivedType *PT, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); + EmitResult<PreparedScope> + emitDebugTypePointer(const DIDerivedType *PT, SPIRV::ModuleAnalysisInfo &MAI); - /// Emit one DebugTypeFunction for ST when every DI operand maps to a debug - /// type id; otherwise emit nothing and return the first failing slot's + /// Build one DebugTypeFunction for ST when every DI operand maps to a debug + /// type id; otherwise build nothing and return the first failing slot's /// status. - EmitResult + EmitResult<PreparedScope> emitDebugTypeFunctionForSubroutineType(const DISubroutineType *ST, - MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI); - /// Emit \c DebugFunctionDeclaration for the non-defining subprogram \p SP. - EmitResult emitDebugFunctionDeclaration(const DISubprogram *SP, - MCRegister VoidTypeReg, - MCRegister I32TypeReg, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); - - /// Emit \c DebugFunction for the defining subprogram \p SP. - EmitResult emitDebugFunction(const DISubprogram *SP, MCRegister VoidTypeReg, + /// Build \c DebugFunctionDeclaration for the non-defining subprogram \p SP. + EmitResult<PreparedScope> + emitDebugFunctionDeclaration(const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI); + /// Build \c DebugFunction for the defining subprogram \p SP. + EmitResult<PreparedScope> emitDebugFunction(const DISubprogram *SP, + MCRegister VoidTypeReg, + MCRegister I32TypeReg, + MCRegister ExtInstSetReg, + SPIRV::ModuleAnalysisInfo &MAI); + /// Emit \c DebugLocalVariable for the source local variable \p LV: /// Name, Type, Source, Line, Column, Parent, Flags, and an optional Arg /// Number. Line, Column, Flags, and Arg Number are emitted as \c OpConstant @@ -578,67 +607,67 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase { void emitDebugBinding(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode, const MachineInstr *MI, MCRegister LocationReg); - /// Emit \c DebugTypeVector for the vector composite type \p VT. + /// Build \c DebugTypeVector for the vector composite type \p VT. /// - /// \returns Emitted with the result id on success. Unsupported, emitting + /// \returns Emitted when the operands are ready. Unsupported, building /// nothing, if \p VT has no \c DIBasicType base type, if \p VT has more than /// one \c DISubrange element, or if the component count is not a /// compile-time constant. If the base cannot be emitted, returns its status. - EmitResult emitDebugTypeVector(const DICompositeType *VT, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); + EmitResult<PreparedScope> emitDebugTypeVector(const DICompositeType *VT, + SPIRV::ModuleAnalysisInfo &MAI); - /// Emit \c DebugTypeArray for the array composite type \p AT. + /// Build \c DebugTypeArray for the array composite type \p AT. /// - /// Emits the element (base) type id followed by one Component Count per - /// \c DISubrange, in DWARF subrange order. A count that is not a - /// compile-time constant is emitted as 0, matching \c OpTypeRuntimeArray. A - /// matrix arrives here as a multi-subrange array and is emitted with one - /// count per dimension. + /// Operands are the element (base) type id followed by one Component Count + /// per \c DISubrange, in DWARF subrange order. A count that is not a + /// compile-time constant is 0, matching \c OpTypeRuntimeArray. A matrix + /// arrives here as a multi-subrange array and is built with one count per + /// dimension. /// - /// \returns Emitted with the result id on success. If \p AT's element type - /// cannot be emitted, emits nothing and returns the element's status. - EmitResult emitDebugTypeArray(const DICompositeType *AT, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); + /// \returns Emitted when the operands are ready. If \p AT's element type + /// cannot be emitted, builds nothing and returns the element's status. + EmitResult<PreparedScope> emitDebugTypeArray(const DICompositeType *AT, + SPIRV::ModuleAnalysisInfo &MAI); - /// Emit \c DebugTypeMember for the data member \p M (a \c DIDerivedType with + /// Build \c DebugTypeMember for the data member \p M (a \c DIDerivedType with /// \c DW_TAG_member). Operands: Name, Type, Source, Line, Column, Offset, /// Size, Flags. NonSemantic \c DebugTypeMember carries no Parent operand: the /// enclosing \c DebugTypeComposite references its members, not the reverse. /// - /// \returns Emitted with the result id on success. Returns the base's status - /// and emits nothing if \p M's type cannot be emitted. - EmitResult emitDebugTypeMember(const DIDerivedType *M, MCRegister VoidTypeReg, - MCRegister I32TypeReg, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); - - /// Emit \c DebugTypeComposite for the struct, class, or union \p CT, after a + /// \returns Emitted when the operands are ready. Returns the base's status + /// and builds nothing if \p M's type cannot be emitted. + EmitResult<PreparedScope> emitDebugTypeMember(const DIDerivedType *M, + MCRegister VoidTypeReg, + MCRegister I32TypeReg, + MCRegister ExtInstSetReg, + SPIRV::ModuleAnalysisInfo &MAI); + + /// Build \c DebugTypeComposite for the struct, class, or union \p CT, after a /// \c DebugTypeMember for each data member whose type can be emitted. A - /// forward declaration emits \c DebugInfoNone for Size and no members. + /// forward declaration uses \c DebugInfoNone for Size and no members. /// - /// \returns Emitted with the result id on success. Emits nothing and returns + /// \returns Emitted when the operands are ready. Builds nothing and returns /// the parent's status if the Parent scope cannot be resolved, or /// Unsupported if the size does not fit in 32 bits. Both are checked before /// any member is streamed. A member whose type fails is dropped, whatever /// the reason, and does not fail the composite. - EmitResult emitDebugTypeComposite(const DICompositeType *CT, - MCRegister VoidTypeReg, - MCRegister I32TypeReg, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); + EmitResult<PreparedScope> + emitDebugTypeComposite(const DICompositeType *CT, MCRegister VoidTypeReg, + MCRegister I32TypeReg, MCRegister ExtInstSetReg, + SPIRV::ModuleAnalysisInfo &MAI); - /// Emit \c DebugTypedef for the typedef derived type \p TD (a \c + /// Build \c DebugTypedef for the typedef derived type \p TD (a \c /// DIDerivedType with \c DW_TAG_typedef). Operands: Name, Base Type, Source, /// Line, Column, Parent. Parent is the enclosing type when \c TD->getScope() /// is an emitted \c DIType, otherwise the first module \c /// DebugCompilationUnit. /// /// \returns The base's or Parent's status if either fails. - EmitResult emitDebugTypedef(const DIDerivedType *TD, MCRegister VoidTypeReg, - MCRegister I32TypeReg, MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); + EmitResult<PreparedScope> emitDebugTypedef(const DIDerivedType *TD, + MCRegister VoidTypeReg, + MCRegister I32TypeReg, + MCRegister ExtInstSetReg, + SPIRV::ModuleAnalysisInfo &MAI); /// Map a \c DISubroutineType::getTypeArray() element to an operand register /// for @@ -652,8 +681,9 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase { /// \p Ty is null, this returns \p VoidTypeReg (\c OpTypeVoid). When /// \p ReturnType is false and \p Ty is null, this returns /// \c CachedDebugInfoNoneReg (\c DebugInfoNone). - EmitResult mapDISignatureTypeToReg(const DIType *Ty, MCRegister VoidTypeReg, - bool ReturnType); + EmitResult<MCRegister> mapDISignatureTypeToReg(const DIType *Ty, + MCRegister VoidTypeReg, + bool ReturnType); /// Map a DWARF source language code to a NonSemantic.Shader.DebugInfo.100 /// source language code. @@ -681,20 +711,20 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase { /// \c DIFile, or another scope without a dedicated debug instruction, falls /// back to \p FallbackCU or the first module \c DebugCompilationUnit recorded /// in \c DebugScopeRegs; no such compile unit is Unsupported. - EmitResult resolveScope(const DIScope *Scope, - const DICompileUnit *FallbackCU = nullptr); + EmitResult<MCRegister> + resolveScope(const DIScope *Scope, const DICompileUnit *FallbackCU = nullptr); - /// Emit \c DebugLexicalBlock for \p S, which must be a \c DILexicalBlock or + /// Build \c DebugLexicalBlock for \p S, which must be a \c DILexicalBlock or /// a \c DINamespace. A \c DILexicalBlock supplies Line/Column /// from \c getLine()/getColumn(); a \c DINamespace has neither, so both are - /// emitted as 0, and its Name is appended as an extra \c OpString operand. + /// 0, and its Name is appended as an extra \c OpString operand. /// - /// \returns Emitted with the result id on success. If \c resolveScope cannot - /// emit \c S->getScope(), emits nothing and returns that status. - EmitResult emitDebugLexicalBlock(const DIScope *S, MCRegister VoidTypeReg, - MCRegister I32TypeReg, - MCRegister ExtInstSetReg, - SPIRV::ModuleAnalysisInfo &MAI); + /// \returns Emitted when the operands are ready. If \c resolveScope cannot + /// emit \c S->getScope(), builds nothing and returns that status. + EmitResult<PreparedScope> + emitDebugLexicalBlock(const DIScope *S, MCRegister VoidTypeReg, + MCRegister I32TypeReg, MCRegister ExtInstSetReg, + SPIRV::ModuleAnalysisInfo &MAI); /// Return a cached \c DebugInlinedAt id for \p IA, or emit one (recursing /// into \c IA->getInlinedAt() first for the optional Inlined operand, so _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
