[llvm-branch-commits] [llvm] [SPIRV] Emit each debug scope from getOrCreateDebugScope. (PR #229488)
Manuel Carrasco via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Oct 8 03:31:56 PDT 2026
https://github.com/mgcarrasco updated https://github.com/llvm/llvm-project/pull/229488
>From e862efc7984190feed9062da6c4cb7867b1735b5 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
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 | 344 +++++++++---------
.../SPIRV/SPIRVNonSemanticDebugHandler.h | 224 +++++++-----
2 files changed, 296 insertions(+), 272 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 3ed9eefd6d34a..ad5871e10a619 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,9 +1145,9 @@ 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};
// TODO: Create on demand once beginModule collects missing getDeclaration()
// cases.
@@ -1151,21 +1156,19 @@ SPIRVNonSemanticDebugHandler::emitDebugFunction(
Ops.push_back(*DeclRegOpt);
}
- 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);
}
@@ -1284,11 +1287,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
@@ -1304,10 +1307,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());
@@ -1358,7 +1361,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;
@@ -1381,8 +1384,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));
@@ -1390,52 +1393,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
@@ -1458,21 +1456,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(
@@ -1499,33 +1496,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());
@@ -1550,23 +1547,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(
@@ -1581,13 +1575,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(
@@ -2093,11 +2087,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
More information about the llvm-branch-commits
mailing list