[llvm-branch-commits] [llvm] Implement support for NSDI DebugFunctionDefinition. (PR #211853)
Manuel Carrasco via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jul 24 09:46:18 PDT 2026
https://github.com/mgcarrasco created https://github.com/llvm/llvm-project/pull/211853
None
>From 4c29867c94e4d20c611829c8bff355475ffc68e0 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Fri, 24 Jul 2026 11:45:11 -0500
Subject: [PATCH] Implement support for NSDI DebugFunctionDefinition.
---
llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 17 +-
.../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 166 +++++++++++++++++-
.../SPIRV/SPIRVNonSemanticDebugHandler.h | 71 +++++---
...ug-function-definition-after-opvariable.ll | 36 ++++
.../debug-info/debug-function-definition.ll | 40 +++++
5 files changed, 300 insertions(+), 30 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-function-definition-after-opvariable.ll
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-function-definition.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 0d03ff70ffd71..8fdf979fb2de2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -322,16 +322,27 @@ void SPIRVAsmPrinter::emitInstruction(const MachineInstr *MI) {
SPIRV_MC::verifyInstructionPredicates(MI->getOpcode(),
getSubtargetInfo().getFeatureBits());
- if (!MAI->getSkipEmission(MI))
+ bool InstructionEmitted = !MAI->getSkipEmission(MI);
+ if (InstructionEmitted) {
outputInstruction(MI);
+ if (NSDebugHandler && !isHidden() && MAI)
+ NSDebugHandler->notifyMachineInstructionEmitted(MI, *MF, *MAI);
+ }
// Output OpLabel after OpFunction and OpFunctionParameter in the first MBB.
const MachineInstr *NextMI = MI->getNextNode();
- if (!LabeledMBB.contains(MI->getParent()) && isFuncOrHeaderInstr(MI, TII) &&
- (!NextMI || !isFuncOrHeaderInstr(NextMI, TII))) {
+ bool BlockHasLabel = LabeledMBB.contains(MI->getParent());
+ bool IsFunctionPreambleInstruction = isFuncOrHeaderInstr(MI, TII);
+ bool IsNextInstructionFunctionPreamble =
+ NextMI && isFuncOrHeaderInstr(NextMI, TII);
+ bool ShouldEmitEntryLabel = !BlockHasLabel && IsFunctionPreambleInstruction &&
+ !IsNextInstructionFunctionPreamble;
+ if (ShouldEmitEntryLabel) {
assert(MI->getParent()->getNumber() == MF->front().getNumber() &&
"OpFunction is not in the front MBB of MF");
emitOpLabel(*MI->getParent());
+ if (NSDebugHandler && !isHidden() && MAI)
+ NSDebugHandler->notifyEntryLabelEmitted(*MF, *MAI);
}
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index cc916eded5010..cc62553a58660 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -14,6 +14,8 @@
#include "llvm/ADT/SmallVectorExtras.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/GlobalVariable.h"
@@ -152,6 +154,35 @@ static uint32_t transDebugFlags(const DINode *DN) {
return Flags;
}
+static const MachineInstr *
+findLastEmittedFunctionOpVariable(const MachineFunction &MF,
+ SPIRV::ModuleAnalysisInfo &MAI) {
+
+ // We iterate over the instructions to find the last OpVariable instruction if
+ // any. The following SPIRV rule is used to terminate the traversal earlier:
+ // SPIR-V 2.16.1, Function Structure: "All OpVariable instructions in a
+ // function must be in the first block in the function. These instructions,
+ // together with any intermixed OpLine and OpNoLine instructions, must be the
+ // first instructions in that block."
+ const MachineInstr *LastOpVariable = nullptr;
+ bool SeenOpVariable = false;
+ for (const MachineInstr &MI : MF.front()) {
+ if (MI.getOpcode() == SPIRV::OpVariable) {
+ SeenOpVariable = true;
+ if (!MAI.getSkipEmission(&MI))
+ LastOpVariable = &MI;
+ continue;
+ }
+
+ bool CanInterleaveWithOpVariable =
+ MI.getOpcode() == SPIRV::OpLine || MI.getOpcode() == SPIRV::OpNoLine;
+ if (SeenOpVariable && !CanInterleaveWithOpVariable &&
+ !MAI.getSkipEmission(&MI))
+ break;
+ }
+ return LastOpVariable;
+}
+
} // namespace
SPIRVNonSemanticDebugHandler::SPIRVNonSemanticDebugHandler(AsmPrinter &AP)
@@ -198,6 +229,7 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
SubprogramDefinitions.clear();
GlobalVariableDebugInfoMap.clear();
DebugFunctionDeclarationRegs.clear();
+ DebugFunctionRegs.clear();
ScopeToPathOpStringReg.clear();
CUToCompilationUnitDbgReg.clear();
DebugSourceRegByFileStr.clear();
@@ -206,6 +238,9 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
I32ConstantCache.clear();
DebugTypeFunctionCache.clear();
GlobalDIEmitted = false;
+ GlobalNSDIEnabled = false;
+ CurrentMAI = nullptr;
+ CachedExtInstSetReg = MCRegister();
#ifndef NDEBUG
NonSemanticOpStringsSectionEmitted = false;
#endif
@@ -810,18 +845,128 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
#endif
}
-void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
+void SPIRVNonSemanticDebugHandler::emitDebugFunctionDefinition(
+ MCRegister DebugFunctionReg, MCRegister OpFunctionReg,
+ SPIRV::ModuleAnalysisInfo &MAI) {
+ assert(DebugFunctionReg.isValid() && OpFunctionReg.isValid() &&
+ "DebugFunctionDefinition operands must be valid");
+ MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
+ emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDefinition, VoidTypeReg,
+ CachedExtInstSetReg, {DebugFunctionReg, OpFunctionReg}, MAI);
+}
+
+void SPIRVNonSemanticDebugHandler::resetPerFunctionDebugState() {
+ CurrentMF = nullptr;
+ LastFunctionOpVariable = nullptr;
+ DebugFunctionDefinitionEmitted = false;
+}
+
+void SPIRVNonSemanticDebugHandler::preparePerFunctionDebug(
+ const MachineFunction *MF) {
+ resetPerFunctionDebugState();
+ if (!GlobalNSDIEnabled || !CurrentMAI)
+ return;
+
+ CurrentMF = MF;
+
+ if (MF->getFunction()
+ .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME)
+ .isValid())
+ return;
+
+ const DISubprogram *SP = MF->getFunction().getSubprogram();
+ if (!SP || !SP->isDefinition())
+ return;
+
+ // DebugFunctionDefinition is emitted after the last function-level
+ // OpVariable. If there are none, it is emitted after the entry OpLabel.
+ LastFunctionOpVariable = findLastEmittedFunctionOpVariable(*MF, *CurrentMAI);
+}
+
+void SPIRVNonSemanticDebugHandler::tryEmitDebugFunctionDefinition(
+ SPIRV::ModuleAnalysisInfo &MAI) {
+ if (DebugFunctionDefinitionEmitted || !GlobalNSDIEnabled)
+ return;
+
+ assert(CurrentMF && "no current MachineFunction");
+ const Function &F = CurrentMF->getFunction();
+ const DISubprogram *SP = F.getSubprogram();
+ if (!SP || !SP->isDefinition())
+ return;
+
+ auto DFIt = DebugFunctionRegs.find(SP);
+ if (DFIt == DebugFunctionRegs.end())
+ return;
+
+ MCRegister OpFunctionReg = MAI.getGlobalObjReg(&F);
+ if (!OpFunctionReg.isValid())
+ return;
+
+ emitDebugFunctionDefinition(DFIt->second, OpFunctionReg, MAI);
+ DebugFunctionDefinitionEmitted = true;
+}
+
+void SPIRVNonSemanticDebugHandler::beginFunctionImpl(
+ const MachineFunction *MF) {
+ preparePerFunctionDebug(MF);
+}
+
+void SPIRVNonSemanticDebugHandler::endFunctionImpl(const MachineFunction *MF) {
+ (void)MF;
+ resetPerFunctionDebugState();
+}
+
+void SPIRVNonSemanticDebugHandler::notifyMachineInstructionEmitted(
+ const MachineInstr *MI, const MachineFunction &MF,
SPIRV::ModuleAnalysisInfo &MAI) {
- if (GlobalDIEmitted || CompileUnits.empty())
+ if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted)
+ return;
+ assert(CurrentMF == &MF &&
+ "notification does not match the current MachineFunction");
+ if (MI->getParent() != &MF.front())
+ return;
+
+ // If this is the last function-level OpVariable, emit the
+ // DebugFunctionDefinition. Otherwise, we had already done it before right
+ // after the OpLabel.
+ if (MI == LastFunctionOpVariable)
+ tryEmitDebugFunctionDefinition(MAI);
+}
+
+void SPIRVNonSemanticDebugHandler::notifyEntryLabelEmitted(
+ const MachineFunction &MF, SPIRV::ModuleAnalysisInfo &MAI) {
+ if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted)
return;
+ assert(CurrentMF == &MF &&
+ "notification does not match the current MachineFunction");
+
+ // If there are no function-level OpVariables, emit the
+ // DebugFunctionDefinition. Otherwise, DebugFunctionDefinition is emitted
+ // after the last OpVariable.
+ if (!LastFunctionOpVariable)
+ tryEmitDebugFunctionDefinition(MAI);
+}
+
+bool SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
+ SPIRV::ModuleAnalysisInfo &MAI) {
+ if (GlobalDIEmitted)
+ return GlobalNSDIEnabled;
+
GlobalDIEmitted = true;
+ if (CompileUnits.empty()) {
+ GlobalNSDIEnabled = false;
+ return false;
+ }
+
// Retrieve the ext inst set register allocated by prepareModuleOutput().
constexpr unsigned NSSet = static_cast<unsigned>(
SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
MCRegister ExtInstSetReg = MAI.getExtInstSetReg(NSSet);
- if (!ExtInstSetReg.isValid())
- return; // Extension not available.
+ if (!ExtInstSetReg.isValid()) {
+ GlobalNSDIEnabled = false;
+ return false;
+ }
#ifndef NDEBUG
assert(NonSemanticOpStringsSectionEmitted &&
@@ -829,6 +974,9 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
"emitNonSemanticGlobalDebugInfo()");
#endif
+ CurrentMAI = &MAI;
+ CachedExtInstSetReg = ExtInstSetReg;
+
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
@@ -944,13 +1092,19 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
}
// Emit DebugFunction for DISubprogram definitions.
- for (const DISubprogram *SP : SubprogramDefinitions)
- emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
+ for (const DISubprogram *SP : SubprogramDefinitions) {
+ if (auto FnReg =
+ emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
+ DebugFunctionRegs[SP] = *FnReg;
+ }
// Emit DebugGlobalVariable for each collected DIGlobalVariable.
for (const auto &[GV, Info] : GlobalVariableDebugInfoMap)
emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
MAI);
+
+ GlobalNSDIEnabled = true;
+ return true;
}
SmallString<128>
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index 35e3a79499c14..8a6220af6e885 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -40,16 +40,15 @@ class SPIRVSubtarget;
/// the module contains debug info (llvm.dbg.cu).
///
/// Call sequence:
-/// beginModule() -- collect compile-unit metadata.
-/// prepareModuleOutput() -- add extension + ext inst set to MAI.
-/// emitNonSemanticDebugStrings() -- OpString for NSDI strings (sec. 7).
-/// emitNonSemanticGlobalDebugInfo() -- emit DebugSource,
-/// DebugCompilationUnit, DebugTypeBasic,
-/// DebugTypePointer, DebugTypeFunction,
-/// DebugFunctionDeclaration,
-/// DebugFunction.
-/// beginFunctionImpl() -- no-op (no per-function DI yet).
-/// endFunctionImpl() -- no-op.
+/// - beginModule() collects compile-unit metadata.
+/// - prepareModuleOutput() adds the extension and ext-inst set to MAI.
+/// - emitNonSemanticDebugStrings() emits NSDI OpStrings in section 7.
+/// - emitNonSemanticGlobalDebugInfo() emits module-scope NSDI and sets
+/// GlobalNSDIEnabled.
+/// - beginFunctionImpl() prepares per-function DebugFunctionDefinition state.
+/// - SPIRVAsmPrinter notifies the handler when it emits MachineInstrs and the
+/// synthesized entry OpLabel.
+/// - endFunctionImpl() resets per-function state.
class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
struct CompileUnitInfo {
const DICompileUnit *TheCU = nullptr;
@@ -92,6 +91,10 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
// (only entries where emission succeeded).
DenseMap<const DISubprogram *, MCRegister> DebugFunctionDeclarationRegs;
+ // DebugFunction result id per emitted definition DISubprogram (only entries
+ // where emission succeeded).
+ DenseMap<const DISubprogram *, MCRegister> DebugFunctionRegs;
+
// Path \c OpString result id per \c DIScope (CU, \c DIFile, declaration
// \c DISubprogram, …). Filled during \c emitNonSemanticDebugStrings() using
// \c getDebugFullPath + \c emitOpStringIfNew; section 10 uses it for
@@ -139,6 +142,20 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
// change.
bool GlobalDIEmitted = false;
+ // True when emitNonSemanticGlobalDebugInfo() completed module-scope NSDI
+ // emission for this module.
+ bool GlobalNSDIEnabled = false;
+
+ SPIRV::ModuleAnalysisInfo *CurrentMAI = nullptr;
+
+ MCRegister CachedExtInstSetReg;
+
+ const MachineFunction *CurrentMF = nullptr;
+
+ const MachineInstr *LastFunctionOpVariable = nullptr;
+
+ bool DebugFunctionDefinitionEmitted = false;
+
public:
explicit SPIRVNonSemanticDebugHandler(AsmPrinter &AP);
@@ -168,7 +185,17 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
/// SPIRVAsmPrinter::outputModuleSections() at section 10 in place of
/// outputModuleSection(MB_NonSemanticGlobalDI). Requires
/// emitNonSemanticDebugStrings() to have run first when NSDI strings apply.
- void emitNonSemanticGlobalDebugInfo(SPIRV::ModuleAnalysisInfo &MAI);
+ /// \returns true when module-scope NSDI emission ran; false when skipped.
+ bool emitNonSemanticGlobalDebugInfo(SPIRV::ModuleAnalysisInfo &MAI);
+
+ /// Called after an MI has been emitted.
+ void notifyMachineInstructionEmitted(const MachineInstr *MI,
+ const MachineFunction &MF,
+ SPIRV::ModuleAnalysisInfo &MAI);
+
+ /// Called after the synthesized entry \c OpLabel has been emitted.
+ void notifyEntryLabelEmitted(const MachineFunction &MF,
+ SPIRV::ModuleAnalysisInfo &MAI);
protected:
// All module-level output is driven by emitNonSemanticGlobalDebugInfo(),
@@ -182,21 +209,23 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
// point and MMI remains null for this handler's entire lifetime. The
// base-class beginInstruction/endInstruction dereference MMI to create temp
// symbols for label tracking and would crash. Override them as no-ops.
- // When per-function NSDI is implemented, use Asm->OutStreamer->getContext()
- // for MCContext access rather than MMI->getContext().
+ // Future local NSDI that needs MCContext must use
+ // Asm->OutStreamer->getContext() rather than MMI->getContext().
void beginInstruction(const MachineInstr *MI) override {}
void endInstruction() override {}
- // TODO: Emit DebugFunctionDefinition here once per-function NSDI emission is
- // implemented. DebugHandlerBase::beginFunction() populates LScopes and
- // DbgValues, which are needed for DebugLine emission. Do not override
- // beginFunction() until that work is in place.
- void beginFunctionImpl(const MachineFunction *MF) override {}
- // TODO: Add per-function cleanup when DebugFunctionDefinition emission is in
- // place.
- void endFunctionImpl(const MachineFunction *MF) override {}
+ void beginFunctionImpl(const MachineFunction *MF) override;
+ void endFunctionImpl(const MachineFunction *MF) override;
private:
+ void emitDebugFunctionDefinition(MCRegister DebugFunctionReg,
+ MCRegister OpFunctionReg,
+ SPIRV::ModuleAnalysisInfo &MAI);
+
+ void resetPerFunctionDebugState();
+ void preparePerFunctionDebug(const MachineFunction *MF);
+ void tryEmitDebugFunctionDefinition(SPIRV::ModuleAnalysisInfo &MAI);
+
void emitMCInst(MCInst &Inst);
MCRegister emitOpString(StringRef S, SPIRV::ModuleAnalysisInfo &MAI);
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-function-definition-after-opvariable.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-definition-after-opvariable.ll
new file mode 100644
index 0000000000000..ec3c93c5115b6
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-definition-after-opvariable.ll
@@ -0,0 +1,36 @@
+; RUN: llc --verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_non_semantic_info %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; DebugFunctionDefinition must follow function-local OpVariable instructions.
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[DF:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugFunction {{.*}}
+; CHECK: [[FOO:%[0-9]+]] = OpFunction
+; CHECK: OpVariable {{.*}} Function
+; CHECK-NEXT: OpVariable {{.*}} Function
+; CHECK-NEXT: OpExtInst [[VOID]] [[EXT]] DebugFunctionDefinition [[DF]] [[FOO]]
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func void @foo() !dbg !4 {
+entry:
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ store i32 0, ptr %x
+ store i32 1, ptr %y
+ ret void, !dbg !7
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "debug-function-definition-after-opvariable.c", directory: "/src")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+
+!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !5, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null}
+!7 = !DILocation(line: 2, column: 1, scope: !4)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-function-definition.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-definition.ll
new file mode 100644
index 0000000000000..5cacfd5c14281
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-definition.ll
@@ -0,0 +1,40 @@
+; RUN: llc --verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_non_semantic_info %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Exercise NonSemantic DebugFunctionDefinition for a defined function.
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[I32:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[PATH:%[0-9]+]] = OpString "/src/debug-function-definition.c"
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "add_one"
+; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource [[PATH]]
+; CHECK-DAG: [[CU:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugCompilationUnit {{.*}}
+; CHECK-DAG: [[TF:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugTypeFunction {{.*}}
+; CHECK-DAG: [[DF:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugFunction [[NAME]] [[TF]] [[DS]] {{.*}}
+; CHECK: [[ADD_ONE:%[0-9]+]] = OpFunction
+; CHECK: OpLabel
+; CHECK-NEXT: OpExtInst [[VOID]] [[EXT]] DebugFunctionDefinition [[DF]] [[ADD_ONE]]
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func i32 @add_one(i32 %value) !dbg !5 {
+entry:
+ %result = add i32 %value, 1
+ ret i32 %result, !dbg !8
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "debug-function-definition.c", directory: "/src")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+
+!4 = !DISubroutineType(types: !6)
+!6 = !{!7, !7}
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+
+!5 = distinct !DISubprogram(name: "add_one", linkageName: "add_one", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!8 = !DILocation(line: 3, column: 3, scope: !5)
More information about the llvm-branch-commits
mailing list