From: Viktoria Maximova Date: Thu, 20 Apr 2023 21:22:52 +0000 (-0700) Subject: [PATCH 35/79] [Backport to 15][DebugInfo] Support translation of DebugFunctionDefinit... X-Git-Tag: archive/raspbian/15.0.0-6+rpi1^2~46 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=c7ff9b2004108c5221d10c14096d7639e022c3c1;p=spirv-llvm-translator-15.git [PATCH 35/79] [Backport to 15][DebugInfo] Support translation of DebugFunctionDefinition instruction (#1961) DebugFunction does not have an Function Id operand in NonSemantic.Shader debug info specification. It's been replaced by the whole new DebugFunctionDefinition instruction to avoid forward references. This instruction must appear in the entry basic block of an OpFunction. Specification: https://github.com/KhronosGroup/SPIRV-Registry/blob/main/nonsemantic/NonSemantic.Shader.DebugInfo.100.asciidoc#DebugFunctionDefinition Gbp-Pq: Name 0035-Backport-to-15-DebugInfo-Support-translation-of-Debu.patch --- diff --git a/lib/SPIRV/LLVMToSPIRVDbgTran.cpp b/lib/SPIRV/LLVMToSPIRVDbgTran.cpp index e36658b..3a71723 100644 --- a/lib/SPIRV/LLVMToSPIRVDbgTran.cpp +++ b/lib/SPIRV/LLVMToSPIRVDbgTran.cpp @@ -1133,6 +1133,7 @@ SPIRVEntry *LLVMToSPIRVDbgTran::transDbgFunction(const DISubprogram *Func) { transformToConstant(Ops, {LineIdx, ColumnIdx, FlagsIdx}); SPIRVEntry *DebugFunc = nullptr; + SPIRVValue *FuncDef = nullptr; if (!Func->isDefinition()) { DebugFunc = BM->addDebugInfo(SPIRVDebug::FunctionDeclaration, getVoidTy(), Ops); @@ -1150,9 +1151,14 @@ SPIRVEntry *LLVMToSPIRVDbgTran::transDbgFunction(const DISubprogram *Func) { SPIRVValue *SPIRVFunc = SPIRVWriter->getTranslatedValue(&F); assert(SPIRVFunc && "All function must be already translated"); Ops[FunctionIdIdx] = SPIRVFunc->getId(); + FuncDef = SPIRVFunc; break; } } + // For NonSemantic.Shader.DebugInfo we store Function Id index as a + // separate DebugFunctionDefinition instruction. + if (isNonSemanticDebugInfo()) + Ops.pop_back(); if (DISubprogram *FuncDecl = Func->getDeclaration()) Ops.push_back(transDbgEntry(FuncDecl)->getId()); @@ -1179,9 +1185,30 @@ SPIRVEntry *LLVMToSPIRVDbgTran::transDbgFunction(const DISubprogram *Func) { if (DITemplateParameterArray TPA = Func->getTemplateParams()) { DebugFunc = transDbgTemplateParams(TPA, DebugFunc); } + + if (isNonSemanticDebugInfo()) + transDbgFuncDefinition(FuncDef, DebugFunc); + return DebugFunc; } +SPIRVEntry *LLVMToSPIRVDbgTran::transDbgFuncDefinition(SPIRVValue *FuncDef, + SPIRVEntry *DbgFunc) { + if (!isNonSemanticDebugInfo() || !FuncDef) + return nullptr; + + using namespace SPIRVDebug::Operand::FunctionDefinition; + SPIRVWordVec Ops(OperandCount); + Ops[FunctionIdx] = DbgFunc->getId(); + Ops[DefinitionIdx] = FuncDef->getId(); + SPIRVFunction *F = static_cast(FuncDef); + SPIRVBasicBlock *BB = F->getNumBasicBlock() ? F->getBasicBlock(0) : nullptr; + SPIRVId ExtSetId = BM->getExtInstSetId(BM->getDebugInfoEIS()); + + return BM->addExtInst(getVoidTy(), ExtSetId, SPIRVDebug::FunctionDefinition, + Ops, BB, BB->getInst(0)); +} + // Location information SPIRVEntry *LLVMToSPIRVDbgTran::transDbgScope(const DIScope *S) { diff --git a/lib/SPIRV/LLVMToSPIRVDbgTran.h b/lib/SPIRV/LLVMToSPIRVDbgTran.h index d43040d..984de15 100644 --- a/lib/SPIRV/LLVMToSPIRVDbgTran.h +++ b/lib/SPIRV/LLVMToSPIRVDbgTran.h @@ -134,6 +134,8 @@ private: SPIRVEntry *transDbgGlobalVariable(const DIGlobalVariable *GV); SPIRVEntry *transDbgFunction(const DISubprogram *Func); + SPIRVEntry *transDbgFuncDefinition(SPIRVValue *SPVFunc, SPIRVEntry *DbgFunc); + // Location information SPIRVEntry *transDbgScope(const DIScope *S); SPIRVEntry *transDebugLoc(const DebugLoc &Loc, SPIRVBasicBlock *BB, diff --git a/lib/SPIRV/SPIRVToLLVMDbgTran.cpp b/lib/SPIRV/SPIRVToLLVMDbgTran.cpp index 2ad7b4a..42e637c 100644 --- a/lib/SPIRV/SPIRVToLLVMDbgTran.cpp +++ b/lib/SPIRV/SPIRVToLLVMDbgTran.cpp @@ -761,7 +761,11 @@ DINode *SPIRVToLLVMDbgTran::transFunction(const SPIRVExtInst *DebugInst) { // Function declaration descriptor DISubprogram *FD = nullptr; - if (Ops.size() > DeclarationIdx) { + if (isNonSemanticDebugInfo(DebugInst->getExtSetKind()) && + Ops.size() > DeclarationNonSemIdx) { + FD = transDebugInst( + BM->get(Ops[DeclarationNonSemIdx])); + } else if (Ops.size() > DeclarationIdx) { FD = transDebugInst( BM->get(Ops[DeclarationIdx])); } @@ -786,7 +790,7 @@ DINode *SPIRVToLLVMDbgTran::transFunction(const SPIRVExtInst *DebugInst) { // Create targetFuncName mostly for Fortran trampoline function if it is // the case StringRef TargetFunction; - if (Ops.size() > TargetFunctionNameIdx) { + if (Ops.size() > MinOperandCount) { TargetFunction = getString(Ops[TargetFunctionNameIdx]); } DIS = getDIBuilder(DebugInst).createFunction( @@ -796,11 +800,21 @@ DINode *SPIRVToLLVMDbgTran::transFunction(const SPIRVExtInst *DebugInst) { /*Annotations*/ nullptr, TargetFunction); } DebugInstCache[DebugInst] = DIS; - SPIRVId RealFuncId = Ops[FunctionIdIdx]; - FuncMap[RealFuncId] = DIS; - // Function. - SPIRVEntry *E = BM->getEntry(Ops[FunctionIdIdx]); + // At this point, we don't have info about the function definition for + // NonSemantic.Shader debug info. If function definition is present, it'll be + // translated later within the function scope. + // For "default" debug info we do translate function body here. + if (!isNonSemanticDebugInfo(DebugInst->getExtSetKind())) + transFunctionBody(DIS, Ops[FunctionIdIdx]); + + return DIS; +} + +void SPIRVToLLVMDbgTran::transFunctionBody(DISubprogram *DIS, SPIRVId FuncId) { + FuncMap[FuncId] = DIS; + + SPIRVEntry *E = BM->getEntry(FuncId); if (E->getOpCode() == OpFunction) { SPIRVFunction *BF = static_cast(E); llvm::Function *F = SPIRVReader->transFunction(BF); @@ -808,7 +822,18 @@ DINode *SPIRVToLLVMDbgTran::transFunction(const SPIRVExtInst *DebugInst) { if (!F->hasMetadata("dbg")) F->setMetadata("dbg", DIS); } - return DIS; +} + +DINode * +SPIRVToLLVMDbgTran::transFunctionDefinition(const SPIRVExtInst *DebugInst) { + using namespace SPIRVDebug::Operand::FunctionDefinition; + const SPIRVWordVec &Ops = DebugInst->getArguments(); + + SPIRVExtInst *Func = BM->get(Ops[FunctionIdx]); + DISubprogram *LLVMFunc = cast(DebugInstCache[Func]); + + transFunctionBody(LLVMFunc, Ops[DefinitionIdx]); + return nullptr; } DINode *SPIRVToLLVMDbgTran::transFunctionDecl(const SPIRVExtInst *DebugInst) { @@ -1203,6 +1228,9 @@ MDNode *SPIRVToLLVMDbgTran::transDebugInstImpl(const SPIRVExtInst *DebugInst) { case SPIRVDebug::FunctionDeclaration: return transFunctionDecl(DebugInst); + case SPIRVDebug::FunctionDefinition: + return transFunctionDefinition(DebugInst); + case SPIRVDebug::GlobalVariable: return transGlobalVariable(DebugInst); @@ -1272,6 +1300,7 @@ SPIRVToLLVMDbgTran::transDebugIntrinsic(const SPIRVExtInst *DebugInst, switch (DebugInst->getExtOp()) { case SPIRVDebug::Scope: case SPIRVDebug::NoScope: + case SPIRVDebug::FunctionDefinition: return nullptr; case SPIRVDebug::Declare: { using namespace SPIRVDebug::Operand::DebugDeclare; diff --git a/lib/SPIRV/SPIRVToLLVMDbgTran.h b/lib/SPIRV/SPIRVToLLVMDbgTran.h index f6b3168..b1ded37 100644 --- a/lib/SPIRV/SPIRVToLLVMDbgTran.h +++ b/lib/SPIRV/SPIRVToLLVMDbgTran.h @@ -141,6 +141,8 @@ private: DINode *transLexicalBlockDiscriminator(const SPIRVExtInst *DebugInst); DINode *transFunction(const SPIRVExtInst *DebugInst); + DINode *transFunctionDefinition(const SPIRVExtInst *DebugInst); + void transFunctionBody(DISubprogram *DIS, SPIRVId FuncId); DINode *transFunctionDecl(const SPIRVExtInst *DebugInst); diff --git a/lib/SPIRV/libSPIRV/SPIRV.debug.h b/lib/SPIRV/libSPIRV/SPIRV.debug.h index 19170e1..677f1cb 100644 --- a/lib/SPIRV/libSPIRV/SPIRV.debug.h +++ b/lib/SPIRV/libSPIRV/SPIRV.debug.h @@ -54,6 +54,7 @@ enum Instruction { Source = 35, ModuleINTEL = 36, InstCount = 37, + FunctionDefinition = 101, Module = 200, TypeSubrange = 201, TypeArrayDynamic = 202, @@ -543,12 +544,22 @@ enum { FlagsIdx = 7, ScopeLineIdx = 8, FunctionIdIdx = 9, + DeclarationNonSemIdx = 9, DeclarationIdx = 10, - TargetFunctionNameIdx = 11, + // Only for NonSemantic.Schader.DebugInfo.200 + TargetFunctionNameIdx = 10, MinOperandCount = 10 }; } +namespace FunctionDefinition { +enum { + FunctionIdx = 0, + DefinitionIdx = 1, + OperandCount = 2 +}; +} + namespace LexicalBlock { enum { SourceIdx = 0, diff --git a/lib/SPIRV/libSPIRV/SPIRVExtInst.h b/lib/SPIRV/libSPIRV/SPIRVExtInst.h index f9d5543..2fe7b09 100644 --- a/lib/SPIRV/libSPIRV/SPIRVExtInst.h +++ b/lib/SPIRV/libSPIRV/SPIRVExtInst.h @@ -260,6 +260,7 @@ template <> inline void SPIRVMap::init() { add(SPIRVDebug::Module, "DebugModule"); add(SPIRVDebug::Expression, "DebugExpression"); add(SPIRVDebug::Operation, "DebugOperation"); + add(SPIRVDebug::FunctionDefinition, "DebugFunctionDefinition"); } SPIRV_DEF_NAMEMAP(SPIRVDebugExtOpKind, SPIRVDebugExtOpMap) diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/lib/SPIRV/libSPIRV/SPIRVModule.cpp index 0916ceb..5733254 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVModule.cpp @@ -1883,7 +1883,19 @@ spv_ostream &operator<<(spv_ostream &O, SPIRVModule &M) { O << SPIRVNL() << MI.AsmTargetVec << MI.AsmVec; } - O << SPIRVNL() << MI.DebugInstVec << SPIRVNL() << MI.FuncVec; + // At this point we know that FunctionDefinition could have been included both + // into DebugInstVec and into basick block of function from FuncVec. + // By spec we should only have this instruction to be present inside the + // function body, so removing it from the DebugInstVec to avoid duplication. + MI.DebugInstVec.erase( + std::remove_if(MI.DebugInstVec.begin(), MI.DebugInstVec.end(), + [](SPIRVExtInst *I) { + return I->getExtOp() == SPIRVDebug::FunctionDefinition; + }), + MI.DebugInstVec.end()); + + O << SPIRVNL() << MI.DebugInstVec << SPIRVNL() + << MI.FuncVec; return O; } diff --git a/test/DebugInfo/NonSemantic/DebugFunction.cl b/test/DebugInfo/NonSemantic/DebugFunction.cl index da27864..74603e1 100644 --- a/test/DebugInfo/NonSemantic/DebugFunction.cl +++ b/test/DebugInfo/NonSemantic/DebugFunction.cl @@ -4,8 +4,15 @@ // - Parent operand of DebugFunction is DebugCompilationUnit, not an OpString, // even if in LLVM IR it points to a DIFile instead of DICompileUnit. -// RUN: %clang_cc1 %s -cl-std=clc++ -emit-llvm-bc -triple spir -debug-info-kind=line-tables-only -O0 -o - | llvm-spirv -o %t.spv -// RUN: llvm-spirv %t.spv --spirv-debug-info-version=nonsemantic-shader-100 -to-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV +// RUN: %clang_cc1 %s -cl-std=clc++ -emit-llvm-bc -triple spir -debug-info-kind=line-tables-only -O0 -o %t.bc +// RUN: llvm-spirv %t.bc --spirv-debug-info-version=nonsemantic-shader-100 -o %t.spv +// RUN: llvm-spirv %t.spv -to-text -o %t.spt +// RUN: FileCheck %s --input-file %t.spt --check-prefix=CHECK-SPIRV + +// RUN: llvm-spirv %t.bc --spirv-debug-info-version=nonsemantic-shader-200 -o %t.spv +// RUN: llvm-spirv %t.spv -to-text -o %t.spt +// RUN: FileCheck %s --input-file %t.spt --check-prefix=CHECK-SPIRV + // RUN: llvm-spirv -r -emit-opaque-pointers %t.spv -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-LLVM float foo(int i) { @@ -18,11 +25,17 @@ void kernel k() { // CHECK-SPIRV: String [[foo:[0-9]+]] "foo" // CHECK-SPIRV: String [[k:[0-9]+]] "k" // CHECK-SPIRV: [[CU:[0-9]+]] {{[0-9]+}} DebugCompilationUnit -// CHECK-SPIRV: DebugFunction [[foo]] {{.*}} [[CU]] {{.*}} [[foo_id:[0-9]+]] {{[0-9]+}} {{$}} -// CHECK-SPIRV: DebugFunction [[k]] {{.*}} [[CU]] {{.*}} [[k_id:[0-9]+]] {{[0-9]+}} {{$}} +// CHECK-SPIRV: [[#FuncFoo:]] [[#]] DebugFunction [[foo]] {{.*}} [[CU]] +// CHECK-SPIRV: [[#FuncK:]] [[#]] DebugFunction [[k]] {{.*}} [[CU]] +// CHECK-SPIRV-NOT: DebugFunctionDefinition + +// CHECK-SPIRV: Function {{[0-9]+}} [[#foo_id:]] +// CHECK-SPIRV: DebugFunctionDefinition [[#FuncFoo]] [[#foo_id]] +// CHECK-LLVM: define spir_func float @_Z3fooi(i32 %i) #{{[0-9]+}} !dbg ![[#foo_id:]] { -// CHECK-SPIRV: Function {{[0-9]+}} [[foo_id]] -// CHECK-LLVM: define spir_func float @_Z3fooi(i32 %i) #{{[0-9]+}} !dbg !{{[0-9]+}} { +// CHECK-SPIRV: Function {{[0-9]+}} [[#k_id:]] +// CHECK-SPIRV: DebugFunctionDefinition [[#FuncK]] [[#k_id]] +// CHECK-LLVM: define spir_kernel void @k() #{{[0-9]+}} !dbg ![[#k_id:]] -// CHECK-SPIRV: Function {{[0-9]+}} [[k_id]] -// CHECK-LLVM: define spir_kernel void @k() #{{[0-9]+}} !dbg !{{[0-9]+}} +// CHECK-LLVM: ![[#foo_id]] = distinct !DISubprogram(name: "foo" +// CHECK-LLVM: ![[#k_id]] = distinct !DISubprogram(name: "k" diff --git a/test/DebugInfo/NonSemantic/Shader200/DebugInfoTargetFunction.ll b/test/DebugInfo/NonSemantic/Shader200/DebugInfoTargetFunction.ll index 1e6e3f9..074305a 100644 --- a/test/DebugInfo/NonSemantic/Shader200/DebugInfoTargetFunction.ll +++ b/test/DebugInfo/NonSemantic/Shader200/DebugInfoTargetFunction.ll @@ -12,7 +12,7 @@ ; CHECK-SPIRV-DAG: String [[#TargetFunc:]] "_Z3foov" ; CHECK-SPIRV-DAG: ExtInst [[#]] [[#DebugNone:]] [[#]] DebugInfoNone -; CHECK-SPIRV-DAG: ExtInst [[#]] [[#]] [[#]] DebugFunction [[#Func]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#DebugNone]] [[#TargetFunc]] +; CHECK-SPIRV-DAG: ExtInst [[#]] [[#]] [[#]] DebugFunction [[#Func]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#DebugNone]] [[#TargetFunc]] ; CHECK-LLVM: define spir_func void @_Z11foo_wrapperv() {{.*}} !dbg ![[#DbgSubProg:]] { ; CHECK-LLVM: ![[#DbgSubProg]] = distinct !DISubprogram(name: "foo_wrapper", linkageName: "_Z11foo_wrapperv", scope: null, file: ![[#]], line: 3, type: ![[#]], scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], templateParams: ![[#]], retainedNodes: ![[#]], targetFuncName: "_Z3foov") diff --git a/test/DebugInfo/NonSemantic/Shader200/FortranComplex.ll b/test/DebugInfo/NonSemantic/Shader200/FortranComplex.ll index 8a1032c..daca3c4 100644 --- a/test/DebugInfo/NonSemantic/Shader200/FortranComplex.ll +++ b/test/DebugInfo/NonSemantic/Shader200/FortranComplex.ll @@ -32,10 +32,10 @@ ; CHECK-SPIRV-200-DAG: ExtInst [[#]] [[#]] [[#Import]] DebugLocalVariable [[#]] [[#Type]] ; CHECK-SPIRV-200-DAG: ExtInst [[#]] [[#]] [[#Import]] DebugLocalVariable [[#]] [[#Type]] -; CHECK-LLVM-200: ![[#]] = !DILocalVariable(name: "a", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type:]]) -; CHECK-LLVM-200: ![[#Type]] = !DIBasicType(name: "COMPLEX*8", size: 64, encoding: DW_ATE_complex_float) -; CHECK-LLVM-200: ![[#]] = !DILocalVariable(name: "b", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type]]) -; CHECK-LLVM-200: ![[#]] = !DILocalVariable(name: "c", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type]]) +; CHECK-LLVM-200-DAG: ![[#]] = !DILocalVariable(name: "a", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type:]]) +; CHECK-LLVM-200-DAG: ![[#Type]] = !DIBasicType(name: "COMPLEX*8", size: 64, encoding: DW_ATE_complex_float) +; CHECK-LLVM-200-DAG: ![[#]] = !DILocalVariable(name: "b", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type]]) +; CHECK-LLVM-200-DAG: ![[#]] = !DILocalVariable(name: "c", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type]]) ; CHECK-SPIRV-100-DAG: ExtInstImport [[#Import:]] "NonSemantic.Shader.DebugInfo.100 ; CHECK-SPIRV-100-DAG: String [[#Name:]] "COMPLEX*8" @@ -46,10 +46,10 @@ ; CHECK-SPIRV-100-DAG: ExtInst [[#]] [[#]] [[#Import]] DebugLocalVariable [[#]] [[#Type]] ; CHECK-SPIRV-100-DAG: ExtInst [[#]] [[#]] [[#Import]] DebugLocalVariable [[#]] [[#Type]] -; CHECK-LLVM-100: ![[#]] = !DILocalVariable(name: "a", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type:]]) -; CHECK-LLVM-100: ![[#Type]] = !DIBasicType(tag: DW_TAG_unspecified_type, name: "COMPLEX*8") -; CHECK-LLVM-100: ![[#]] = !DILocalVariable(name: "b", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type]]) -; CHECK-LLVM-100: ![[#]] = !DILocalVariable(name: "c", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type]]) +; CHECK-LLVM-100-DAG: ![[#]] = !DILocalVariable(name: "a", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type:]]) +; CHECK-LLVM-100-DAG: ![[#Type]] = !DIBasicType(tag: DW_TAG_unspecified_type, name: "COMPLEX*8") +; CHECK-LLVM-100-DAG: ![[#]] = !DILocalVariable(name: "b", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type]]) +; CHECK-LLVM-100-DAG: ![[#]] = !DILocalVariable(name: "c", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#Type]]) ; ModuleID = 'test.f90' source_filename = "test.f90"