[PATCH 35/79] [Backport to 15][DebugInfo] Support translation of DebugFunctionDefinit...
authorViktoria Maximova <viktoria.maksimova@intel.com>
Thu, 20 Apr 2023 21:22:52 +0000 (14:22 -0700)
committerAndreas Beckmann <anbe@debian.org>
Thu, 14 Mar 2024 19:01:08 +0000 (20:01 +0100)
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

lib/SPIRV/LLVMToSPIRVDbgTran.cpp
lib/SPIRV/LLVMToSPIRVDbgTran.h
lib/SPIRV/SPIRVToLLVMDbgTran.cpp
lib/SPIRV/SPIRVToLLVMDbgTran.h
lib/SPIRV/libSPIRV/SPIRV.debug.h
lib/SPIRV/libSPIRV/SPIRVExtInst.h
lib/SPIRV/libSPIRV/SPIRVModule.cpp
test/DebugInfo/NonSemantic/DebugFunction.cl
test/DebugInfo/NonSemantic/Shader200/DebugInfoTargetFunction.ll
test/DebugInfo/NonSemantic/Shader200/FortranComplex.ll

index e36658b48a9e924d147fd9cedf32d43ca73e2a98..3a71723295d61547a3c0ca88f2c5814c358cfece 100644 (file)
@@ -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<SPIRVFunction *>(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) {
index d43040d7ad9579a7a1dab6429350dd1e44a13447..984de156e18909932ec6b111834925711aa81355 100644 (file)
@@ -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,
index 2ad7b4a9d99d6629bb00bbca156f07e3e9aa9a05..42e637ca76ec1fbf496d3d340ecaaff699401041 100644 (file)
@@ -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<DISubprogram>(
+        BM->get<SPIRVExtInst>(Ops[DeclarationNonSemIdx]));
+  } else if (Ops.size() > DeclarationIdx) {
     FD = transDebugInst<DISubprogram>(
         BM->get<SPIRVExtInst>(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<SPIRVFunction *>(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<SPIRVExtInst>(Ops[FunctionIdx]);
+  DISubprogram *LLVMFunc = cast<DISubprogram>(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;
index f6b3168691b6bffdb1649ca68dffc91528a950c2..b1ded375f66faccc4e36b3ea685ff220f8f0500f 100644 (file)
@@ -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);
 
index 19170e1dbb511a5e75e5595827b83895d78453dc..677f1cbaee9122f2a6afd7e276379eebe71341c4 100644 (file)
@@ -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,
index f9d55433cb41a0725bfd56ef0f0e4f9f494cf5f0..2fe7b096f336a9bc325c4bd7546066ab31f433cc 100644 (file)
@@ -260,6 +260,7 @@ template <> inline void SPIRVMap<SPIRVDebugExtOpKind, std::string>::init() {
   add(SPIRVDebug::Module, "DebugModule");
   add(SPIRVDebug::Expression, "DebugExpression");
   add(SPIRVDebug::Operation, "DebugOperation");
+  add(SPIRVDebug::FunctionDefinition, "DebugFunctionDefinition");
 }
 SPIRV_DEF_NAMEMAP(SPIRVDebugExtOpKind, SPIRVDebugExtOpMap)
 
index 0916cebc2e3ac27db33673a3e781095cc93c1cb2..5733254ef288546aece4f6e2f2fb660f65d916e8 100644 (file)
@@ -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;
 }
 
index da27864f27ad74f522f93e04e5cc7af2836cc5bb..74603e177529e4642c3471fb7d922480d06cb697 100644 (file)
@@ -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"
index 1e6e3f9f57dce1e5ffbd5a6ef6a127ff1de87fac..074305afbee84df5b58fdb8db29966f740c58329 100644 (file)
@@ -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")
index 8a1032c36f60afd9a6163de31740f4f0718eeade..daca3c4af7a5f6fd2a079b44b906f7026b3e77ac 100644 (file)
 ; 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"
 ; 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"