Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 56 additions & 4 deletions lib/SPIRV/LLVMToSPIRVDbgTran.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,23 @@ SPIRVType *LLVMToSPIRVDbgTran::getInt32Ty() {
return Int32T;
}

SPIRVEntry *LLVMToSPIRVDbgTran::getVoidDebugType() {
// Create a proper void debug type instead of DebugInfoNone
// This is needed for function return types that are void
using namespace SPIRVDebug::Operand::TypeBasic;
SPIRVWordVec Ops(OperandCountOCL);
Ops[NameIdx] = BM->getString("void")->getId();
ConstantInt *Size = getUInt(M, 0); // void has size 0
Ops[SizeIdx] = SPIRVWriter->transValue(Size, nullptr)->getId();
Ops[EncodingIdx] = SPIRVDebug::Unspecified;
if (isNonSemanticDebugInfo()) {
transformToConstant(Ops, {EncodingIdx});
// Flags value could not be generated by clang or by LLVM environment.
Ops.push_back(getDebugInfoNoneId());
}
return BM->addDebugInfo(SPIRVDebug::TypeBasic, getVoidTy(), Ops);
}

SPIRVEntry *LLVMToSPIRVDbgTran::getScope(DIScope *S) {
if (S)
return transDbgEntry(S);
Expand Down Expand Up @@ -906,10 +923,16 @@ LLVMToSPIRVDbgTran::transDbgSubroutineType(const DISubroutineType *FT) {
// First element of the TypeArray is the type of the return value,
// followed by types of the function arguments' types.
// The same order is preserved in SPIRV.
for (unsigned I = 0; I < NumElements; ++I)
Ops[ReturnTypeIdx + I] = transDbgEntry(Types[I])->getId();
for (unsigned I = 0; I < NumElements; ++I) {
if (Types[I]) {
Ops[ReturnTypeIdx + I] = transDbgEntry(Types[I])->getId();
} else {
// Handle void type - create a proper void debug type instead of DebugInfoNone
Ops[ReturnTypeIdx + I] = getVoidDebugType()->getId();
}
}
} else { // void foo();
Ops[ReturnTypeIdx] = getVoidTy()->getId();
Ops[ReturnTypeIdx] = getVoidDebugType()->getId();
}

if (isNonSemanticDebugInfo())
Expand Down Expand Up @@ -1310,7 +1333,36 @@ SPIRVEntry *LLVMToSPIRVDbgTran::transDbgFunction(const DISubprogram *Func) {
if (DISubprogram *FuncDecl = Func->getDeclaration())
Ops.push_back(transDbgEntry(FuncDecl)->getId());
else {
Ops.push_back(getDebugInfoNoneId());
// Create a DebugFunctionDeclaration for this function definition
// since the Declaration operand must be a DebugFunctionDeclaration result ID
SPIRVWordVec DeclOps(SPIRVDebug::Operand::FunctionDeclaration::OperandCount);
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::NameIdx] = BM->getString(Func->getName().str())->getId();
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::TypeIdx] = transDbgEntry(Func->getType())->getId();
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::SourceIdx] = getSource(Func)->getId();
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::LineIdx] = Func->getLine();
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::ColumnIdx] = 0; // This version of DISubprogram has no column number
Comment on lines +1339 to +1343
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we are already using namespace SPIRVDebug::Operand::Function few lines above, so it's not really needed to specify it here.

auto *Scope = Func->getScope();
if (Scope && !isa<DIFile>(Scope)) {
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::ParentIdx] = getScope(Scope)->getId();
} else {
if (auto *Unit = Func->getUnit())
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::ParentIdx] = SPIRVCUMap[Unit]->getId();
else
// it might so happen, that DISubprogram is missing Unit parameter
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::ParentIdx] = SPIRVCUMap.begin()->second->getId();
}
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::LinkageNameIdx] = BM->getString(Func->getLinkageName().str())->getId();
DeclOps[SPIRVDebug::Operand::FunctionDeclaration::FlagsIdx] = adjustAccessFlags(Scope, transDebugFlags(Func));
if (isNonSemanticDebugInfo()) {
std::vector<SPIRVWord> ConstIdxs = {SPIRVDebug::Operand::FunctionDeclaration::LineIdx,
SPIRVDebug::Operand::FunctionDeclaration::ColumnIdx,
SPIRVDebug::Operand::FunctionDeclaration::FlagsIdx};
transformToConstant(DeclOps, ConstIdxs);
}

SPIRVEntry *CreatedFuncDecl = BM->addDebugInfo(SPIRVDebug::FunctionDeclaration, getVoidTy(), DeclOps);
Ops.push_back(CreatedFuncDecl->getId());

if (BM->getDebugInfoEIS() == SPIRVEIS_NonSemantic_Shader_DebugInfo_200) {
// Translate targetFuncName mostly for Fortran trampoline function if it
// is the case
Expand Down
1 change: 1 addition & 0 deletions lib/SPIRV/LLVMToSPIRVDbgTran.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class LLVMToSPIRVDbgTran {
// Helper methods
SPIRVType *getVoidTy();
SPIRVType *getInt32Ty();
SPIRVEntry *getVoidDebugType();
SPIRVEntry *getScope(DIScope *SR);
SPIRVEntry *getGlobalVariable(const DIGlobalVariable *GV);
inline bool isNonSemanticDebugInfo();
Expand Down
21 changes: 21 additions & 0 deletions test/DebugInfo/DebugFunctionDeclarationBug.cl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Test case to verify the fix for the issue where DebugFunction uses DebugInfoNone instead of DebugFunctionDeclaration
// for the Declaration operand when there's no separate function declaration.
// This test verifies that spirv-val now passes successfully after the fix.

// RUN: %clang_cc1 %s -emit-llvm-bc -triple spir -debug-info-kind=limited -O0 -o - | llvm-spirv -o %t.spv
// RUN: spirv-val %t.spv

// This test should pass spirv-val validation after the bug fix
// We can also verify that the SPIR-V contains proper DebugFunctionDeclaration
// RUN: llvm-spirv --to-text %t.spv -o - | FileCheck %s --check-prefix=CHECK-SPIRV-TEXT

// CHECK-SPIRV-TEXT: DebugFunctionDeclaration
// CHECK-SPIRV-TEXT: DebugFunction

int test_function(int x) {
return x + 1;
}

void kernel test_kernel() {
int result = test_function(42);
}
Loading