Skip to content

Commit f111514

Browse files
committed
[SYCL] Correctly handle debug information in global offset pass
Make sure that cloned functions do not use debug information that points to the original function.
1 parent 90f7820 commit f111514

8 files changed

+446
-56
lines changed

llvm/include/llvm/SYCLLowerIR/GlobalOffset.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,24 @@ class GlobalOffsetPass : public PassInfoMixin<GlobalOffsetPass> {
3131
static StringRef getPassName() { return "Add implicit SYCL global offset"; }
3232

3333
private:
34+
/// In order to correctly update the debug info (if present) we have to
35+
/// populate the global value-to-value map with all original-to-cloned
36+
/// function. To achieve that traverse the call stack and create all the
37+
/// clones (without providing the body).
38+
///
39+
/// \param KCache Kernel bookkeeping helper.
40+
/// \param ImplicitOffsetIntrinsic Implicit offset intrinsic, provides a
41+
/// starting point in search for all the functions that need to be clone.
42+
void createClonesAndPopulateVMap(TargetHelpers::KernelCache &KCache,
43+
Function *ImplicitOffsetIntrinsic);
44+
3445
/// After the execution of this function, the module to which the kernel
3546
/// `Func` belongs, contains both the original function and its clone with the
3647
/// signature extended with the implicit offset parameter and `_with_offset`
3748
/// appended to the name.
3849
///
3950
/// \param Func Kernel to be processed.
51+
/// \param KCache Kernel bookkeeping helper.
4052
void processKernelEntryPoint(Function *Func,
4153
TargetHelpers::KernelCache &KCache);
4254

@@ -61,6 +73,7 @@ class GlobalOffsetPass : public PassInfoMixin<GlobalOffsetPass> {
6173
/// `nullptr`) - this is used to know whether calls to it inside clones need
6274
/// to have the implicit parameter added to it or be replaced with the
6375
/// implicit parameter.
76+
/// \param KCache Kernel bookkeeping helper.
6477
void addImplicitParameterToCallers(Module &M, Value *Callee,
6578
Function *CalleeWithImplicitParam,
6679
TargetHelpers::KernelCache &KCache);
@@ -99,6 +112,9 @@ class GlobalOffsetPass : public PassInfoMixin<GlobalOffsetPass> {
99112
llvm::Type *KernelImplicitArgumentType = nullptr;
100113
/// A type used for the alloca holding the values of global offsets.
101114
llvm::Type *ImplicitOffsetPtrType = nullptr;
115+
/// Track newly created DISUbprograms (that are attached to cloned
116+
/// functions), for ease of mapping, use the old function's name as the key.
117+
llvm::DenseMap<StringRef, DISubprogram *> DISubprogramMap;
102118

103119
unsigned TargetAS = 0;
104120
};

llvm/lib/SYCLLowerIR/GlobalOffset.cpp

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/SYCLLowerIR/GlobalOffset.h"
10-
#include "llvm/ADT/SmallSet.h"
10+
#include "llvm/IR/DIBuilder.h"
1111
#include "llvm/IR/IRBuilder.h"
1212
#include "llvm/IR/Instructions.h"
1313
#include "llvm/IR/Intrinsics.h"
@@ -18,6 +18,7 @@
1818
#include "llvm/Target/TargetIntrinsicInfo.h"
1919
#include "llvm/TargetParser/Triple.h"
2020
#include "llvm/Transforms/Utils/Cloning.h"
21+
#include <deque>
2122

2223
using namespace llvm;
2324

@@ -91,6 +92,70 @@ static void validateKernels(Module &M, TargetHelpers::KernelCache &KCache) {
9192
}
9293
}
9394

95+
void GlobalOffsetPass::createClonesAndPopulateVMap(
96+
TargetHelpers::KernelCache &KCache, Function *ImplicitOffsetIntrinsic) {
97+
std::deque<User *> WorkList;
98+
for (auto *U : ImplicitOffsetIntrinsic->users())
99+
WorkList.emplace_back(U);
100+
101+
while (!WorkList.empty()) {
102+
auto *WI = WorkList.front();
103+
WorkList.pop_front();
104+
auto *Call = dyn_cast<CallInst>(WI);
105+
if (!Call)
106+
continue; // Not interesting.
107+
108+
auto *Func = Call->getFunction();
109+
if (0 != GlobalVMap.count(Func))
110+
continue; // Already processed.
111+
112+
const bool IsKernel = KCache.isKernel(*Func);
113+
FunctionType *FuncTy = Func->getFunctionType();
114+
Type *ImplicitArgumentType =
115+
IsKernel ? KernelImplicitArgumentType->getPointerTo()
116+
: ImplicitOffsetPtrType;
117+
118+
// Construct an argument list containing all of the previous arguments.
119+
SmallVector<Type *, 8> Arguments;
120+
for (const auto &A : Func->args())
121+
Arguments.push_back(A.getType());
122+
123+
// Add the offset argument. Must be the same type as returned by
124+
// `llvm.{amdgcn|nvvm}.implicit.offset`.
125+
Arguments.push_back(ImplicitArgumentType);
126+
127+
// Build the new function.
128+
assert(!FuncTy->isVarArg() && "Variadic arguments prohibited in SYCL");
129+
FunctionType *NewFuncTy = FunctionType::get(FuncTy->getReturnType(),
130+
Arguments, FuncTy->isVarArg());
131+
Function *NewFunc = Function::Create(NewFuncTy, Func->getLinkage(),
132+
Func->getAddressSpace());
133+
NewFunc->setName(Func->getName() + "_with_offset");
134+
// Remove the subprogram, if exists, as it will be pointing to an incorrect
135+
// data.
136+
if (Func->getSubprogram())
137+
NewFunc->setSubprogram(nullptr);
138+
139+
// Keep original function ordering, clone goes right after the original.
140+
Func->getParent()->getFunctionList().insertAfter(Func->getIterator(),
141+
NewFunc);
142+
143+
// Populate the global value to value map with function arguments as well
144+
// as the cloned function itself.
145+
for (Function::arg_iterator FuncArg = Func->arg_begin(),
146+
FuncEnd = Func->arg_end(),
147+
NewFuncArg = NewFunc->arg_begin();
148+
FuncArg != FuncEnd; ++FuncArg, ++NewFuncArg) {
149+
GlobalVMap[FuncArg] = NewFuncArg;
150+
}
151+
GlobalVMap[Func] = NewFunc;
152+
153+
// Extend the work list with the users of the function.
154+
for (auto *U : Func->users())
155+
WorkList.emplace_back(U);
156+
}
157+
}
158+
94159
// New PM implementation.
95160
PreservedAnalyses GlobalOffsetPass::run(Module &M, ModuleAnalysisManager &) {
96161
// Only run this pass on SYCL device code
@@ -128,6 +193,8 @@ PreservedAnalyses GlobalOffsetPass::run(Module &M, ModuleAnalysisManager &) {
128193
// Validate kernels
129194
validateKernels(M, KCache);
130195

196+
createClonesAndPopulateVMap(KCache, ImplicitOffsetIntrinsic);
197+
131198
// Add implicit parameters to all direct and indirect users of the offset
132199
addImplicitParameterToCallers(M, ImplicitOffsetIntrinsic, nullptr, KCache);
133200
}
@@ -163,6 +230,7 @@ PreservedAnalyses GlobalOffsetPass::run(Module &M, ModuleAnalysisManager &) {
163230
assert(ImplicitOffsetIntrinsic->use_empty() &&
164231
"Not all uses of intrinsic removed");
165232
ImplicitOffsetIntrinsic->eraseFromParent();
233+
166234
return PreservedAnalyses::none();
167235
}
168236

@@ -226,10 +294,10 @@ void GlobalOffsetPass::addImplicitParameterToCallers(
226294
if (AlreadyProcessed) {
227295
NewFunc = Caller;
228296
} else {
229-
std::tie(NewFunc, ImplicitOffset) =
230-
addOffsetArgumentToFunction(M, Caller,
231-
/*KernelImplicitArgumentType*/ nullptr,
232-
/*KeepOriginal=*/true);
297+
std::tie(NewFunc, ImplicitOffset) = addOffsetArgumentToFunction(
298+
M, Caller,
299+
/*KernelImplicitArgumentType*/ nullptr,
300+
/*KeepOriginal=*/true, /*IsKernel=*/false);
233301
}
234302
CallToOld = cast<CallInst>(GlobalVMap[CallToOld]);
235303
if (!CalleeWithImplicitParam) {
@@ -296,32 +364,17 @@ std::pair<Function *, Value *> GlobalOffsetPass::addOffsetArgumentToFunction(
296364
AttributeList NAttrs =
297365
AttributeList::get(Func->getContext(), FuncAttrs.getFnAttrs(),
298366
FuncAttrs.getRetAttrs(), ArgumentAttributes);
299-
assert(!FuncTy->isVarArg() && "Variadic arguments prohibited in SYCL");
300-
FunctionType *NewFuncTy =
301-
FunctionType::get(FuncTy->getReturnType(), Arguments, FuncTy->isVarArg());
302-
303-
Function *NewFunc =
304-
Function::Create(NewFuncTy, Func->getLinkage(), Func->getAddressSpace());
305-
306-
// Keep original function ordering.
307-
M.getFunctionList().insertAfter(Func->getIterator(), NewFunc);
367+
assert(GlobalVMap.count(Func) != 0 &&
368+
"All relevant functions must be prepared ahead of time.");
369+
Function *NewFunc = dyn_cast<Function>(GlobalVMap[Func]);
308370

309371
Value *ImplicitOffset = nullptr;
310372
bool ImplicitOffsetAllocaInserted = false;
311373
if (KeepOriginal) {
312-
// TODO: Are there better naming alternatives that allow for unmangling?
313-
NewFunc->setName(Func->getName() + "_with_offset");
314-
315-
for (Function::arg_iterator FuncArg = Func->arg_begin(),
316-
FuncEnd = Func->arg_end(),
317-
NewFuncArg = NewFunc->arg_begin();
318-
FuncArg != FuncEnd; ++FuncArg, ++NewFuncArg) {
319-
GlobalVMap[FuncArg] = NewFuncArg;
320-
}
321-
322374
SmallVector<ReturnInst *, 8> Returns;
323375
CloneFunctionInto(NewFunc, Func, GlobalVMap,
324376
CloneFunctionChangeType::GlobalChanges, Returns);
377+
325378
// In order to keep the signatures of functions called by the kernel
326379
// unified, the pass has to copy global offset to an array allocated in
327380
// addrspace(3). This is done as kernels can't allocate and fill the

llvm/test/CodeGen/AMDGPU/global-offset-dbg.ll

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,33 +37,33 @@ entry:
3737
!14 = distinct !DISubprogram(name: "example_kernel", scope: !1, file: !1, line: 10, type: !12, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
3838
!15 = !DILocation(line: 1, column: 2, scope: !14)
3939
; CHECK-LABEL: define i64 @_ZTS14other_function(
40-
; CHECK-SAME: ) !dbg [[DBG5:![0-9]+]] {
40+
; CHECK-SAME: ) !dbg [[DBG6:![0-9]+]] {
4141
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 0 to i64
4242
; CHECK-NEXT: ret i64 [[TMP1]]
4343
;
4444
;
4545
; CHECK-LABEL: define i64 @_ZTS14other_function_with_offset(
46-
; CHECK-SAME: ptr addrspace(5) [[TMP0:%.*]]) !dbg [[DBG8:![0-9]+]] {
46+
; CHECK-SAME: ptr addrspace(5) [[TMP0:%.*]]) !dbg [[DBG9:![0-9]+]] {
4747
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, ptr addrspace(5) [[TMP0]], i64 2
4848
; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr addrspace(5) [[TMP2]], align 4
4949
; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
5050
; CHECK-NEXT: ret i64 [[TMP4]]
5151
;
5252
;
5353
; CHECK-LABEL: define amdgpu_kernel void @_ZTS14example_kernel(
54-
; CHECK-SAME: ) !dbg [[DBG9:![0-9]+]] {
54+
; CHECK-SAME: ) !dbg [[DBG10:![0-9]+]] {
5555
; CHECK-NEXT: [[ENTRY:.*:]]
56-
; CHECK-NEXT: [[TMP0:%.*]] = call i64 @_ZTS14other_function(), !dbg [[DBG10:![0-9]+]]
56+
; CHECK-NEXT: [[TMP0:%.*]] = call i64 @_ZTS14other_function(), !dbg [[DBG11:![0-9]+]]
5757
; CHECK-NEXT: ret void
5858
;
5959
;
6060
; CHECK-LABEL: define amdgpu_kernel void @_ZTS14example_kernel_with_offset(
61-
; CHECK-SAME: ptr byref([3 x i32]) [[TMP0:%.*]]) !dbg [[DBG11:![0-9]+]] {
61+
; CHECK-SAME: ptr byref([3 x i32]) [[TMP0:%.*]]) !dbg [[DBG12:![0-9]+]] {
6262
; CHECK-NEXT: [[ENTRY:.*:]]
63-
; CHECK-NEXT: [[TMP1:%.*]] = alloca [3 x i32], align 4, addrspace(5), !dbg [[DBG12:![0-9]+]]
64-
; CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr [[TMP0]] to ptr addrspace(4), !dbg [[DBG12]]
65-
; CHECK-NEXT: call void @llvm.memcpy.p5.p4.i64(ptr addrspace(5) align 4 [[TMP1]], ptr addrspace(4) align 1 [[TMP2]], i64 12, i1 false), !dbg [[DBG12]]
66-
; CHECK-NEXT: [[TMP3:%.*]] = call i64 @_ZTS14other_function_with_offset(ptr addrspace(5) [[TMP1]]), !dbg [[DBG12]]
63+
; CHECK-NEXT: [[TMP1:%.*]] = alloca [3 x i32], align 4, addrspace(5), !dbg [[DBG13:![0-9]+]]
64+
; CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr [[TMP0]] to ptr addrspace(4), !dbg [[DBG13]]
65+
; CHECK-NEXT: call void @llvm.memcpy.p5.p4.i64(ptr addrspace(5) align 4 [[TMP1]], ptr addrspace(4) align 1 [[TMP2]], i64 12, i1 false), !dbg [[DBG13]]
66+
; CHECK-NEXT: [[TMP3:%.*]] = call i64 @_ZTS14other_function_with_offset(ptr addrspace(5) [[TMP1]]), !dbg [[DBG13]]
6767
; CHECK-NEXT: ret void
6868
;
6969
;.
@@ -74,12 +74,13 @@ entry:
7474
; CHECK: [[META2]] = !{}
7575
; CHECK: [[META3:![0-9]+]] = !{i32 2, !"Dwarf Version", i32 4}
7676
; CHECK: [[META4:![0-9]+]] = !{i32 2, !"Debug Info Version", i32 3}
77-
; CHECK: [[DBG5]] = distinct !DISubprogram(name: "other_function", scope: [[META1]], file: [[META1]], line: 3, type: [[META6:![0-9]+]], scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META2]])
78-
; CHECK: [[META6]] = !DISubroutineType(types: [[META7:![0-9]+]])
79-
; CHECK: [[META7]] = !{null}
80-
; CHECK: [[DBG8]] = distinct !DISubprogram(name: "other_function", scope: [[META1]], file: [[META1]], line: 3, type: [[META6]], scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META2]])
81-
; CHECK: [[DBG9]] = distinct !DISubprogram(name: "example_kernel", scope: [[META1]], file: [[META1]], line: 10, type: [[META6]], scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META2]])
82-
; CHECK: [[DBG10]] = !DILocation(line: 1, column: 2, scope: [[DBG9]])
83-
; CHECK: [[DBG11]] = distinct !DISubprogram(name: "example_kernel", scope: [[META1]], file: [[META1]], line: 10, type: [[META6]], scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META2]])
84-
; CHECK: [[DBG12]] = !DILocation(line: 1, column: 2, scope: [[DBG11]])
77+
; CHECK: [[META5:![0-9]+]] = !{i32 1, !"sycl-device", i32 1}
78+
; CHECK: [[DBG6]] = distinct !DISubprogram(name: "other_function", scope: [[META1]], file: [[META1]], line: 3, type: [[META7:![0-9]+]], scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META2]])
79+
; CHECK: [[META7]] = !DISubroutineType(types: [[META8:![0-9]+]])
80+
; CHECK: [[META8]] = !{null}
81+
; CHECK: [[DBG9]] = distinct !DISubprogram(name: "other_function", scope: [[META1]], file: [[META1]], line: 3, type: [[META7]], scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META2]])
82+
; CHECK: [[DBG10]] = distinct !DISubprogram(name: "example_kernel", scope: [[META1]], file: [[META1]], line: 10, type: [[META7]], scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META2]])
83+
; CHECK: [[DBG11]] = !DILocation(line: 1, column: 2, scope: [[DBG10]])
84+
; CHECK: [[DBG12]] = distinct !DISubprogram(name: "example_kernel", scope: [[META1]], file: [[META1]], line: 10, type: [[META7]], scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META2]])
85+
; CHECK: [[DBG13]] = !DILocation(line: 1, column: 2, scope: [[DBG12]])
8586
;.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5
2+
; RUN: opt -bugpoint-enable-legacy-pm -globaloffset %s -S -o - | FileCheck %s
3+
4+
; Make sure that the debug nodes inside a function are correctly updated in a
5+
; cloned function, such that they point to the clone, not to the original
6+
; function. Notice, how DBG11 references DBG10 (and not DBG5, which is the
7+
; original function).
8+
9+
target datalayout = "e-i64:64-i128:128-v16:16-v32:32-n16:32:64"
10+
target triple = "nvptx64-nvidia-cuda"
11+
12+
define i64 @_ZN7__spirv21getGlobalInvocationIdILi1EEEmv() !dbg !5 {
13+
entry:
14+
%0 = call i32 @llvm.nvvm.read.ptx.sreg.ctaid.y(), !dbg !9
15+
%1 = call ptr @llvm.nvvm.implicit.offset()
16+
ret i64 0
17+
}
18+
19+
; Function Attrs: nounwind speculatable memory(none)
20+
declare ptr @llvm.nvvm.implicit.offset() #0
21+
22+
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
23+
declare noundef i32 @llvm.nvvm.read.ptx.sreg.ctaid.y() #1
24+
25+
attributes #0 = { nounwind speculatable memory(none) }
26+
attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
27+
28+
!llvm.dbg.cu = !{!0}
29+
!llvm.module.flags = !{!3, !4}
30+
31+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 0.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2, splitDebugInlining: false, nameTableKind: None)
32+
!1 = !DIFile(filename: "test.cpp", directory: "/")
33+
!2 = !{}
34+
!3 = !{i32 2, !"Debug Info Version", i32 3}
35+
!4 = !{i32 1, !"sycl-device", i32 1}
36+
!5 = distinct !DISubprogram(name: "getGlobalInvocationId<1>", linkageName: "_ZN7__spirv21getGlobalInvocationIdILi1EEEmv", scope: !7, file: !6, line: 201, type: !8, scopeLine: 201, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, templateParams: !2)
37+
!6 = !DIFile(filename: "header.hpp", directory: "/")
38+
!7 = !DINamespace(name: "__spirv", scope: null)
39+
!8 = distinct !DISubroutineType(types: !2)
40+
!9 = !DILocation(line: 201, column: 1, scope: !5)
41+
; CHECK-LABEL: define i64 @_ZN7__spirv21getGlobalInvocationIdILi1EEEmv(
42+
; CHECK-SAME: ) !dbg [[DBG5:![0-9]+]] {
43+
; CHECK-NEXT: [[ENTRY:.*:]]
44+
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.nvvm.read.ptx.sreg.ctaid.y(), !dbg [[DBG9:![0-9]+]]
45+
; CHECK-NEXT: ret i64 0
46+
;
47+
;
48+
; CHECK-LABEL: define i64 @_ZN7__spirv21getGlobalInvocationIdILi1EEEmv_with_offset(
49+
; CHECK-SAME: ptr [[TMP0:%.*]]) !dbg [[DBG10:![0-9]+]] {
50+
; CHECK-NEXT: [[ENTRY:.*:]]
51+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.nvvm.read.ptx.sreg.ctaid.y(), !dbg [[DBG11:![0-9]+]]
52+
; CHECK-NEXT: ret i64 0
53+
;
54+
;.
55+
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
56+
;.
57+
; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: [[META1:![0-9]+]], producer: "{{.*}}clang version {{.*}}", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: [[META2:![0-9]+]], retainedTypes: [[META2]], globals: [[META2]], imports: [[META2]], splitDebugInlining: false, nameTableKind: None)
58+
; CHECK: [[META1]] = !DIFile(filename: "test.cpp", directory: {{.*}})
59+
; CHECK: [[META2]] = !{}
60+
; CHECK: [[META3:![0-9]+]] = !{i32 2, !"Debug Info Version", i32 3}
61+
; CHECK: [[META4:![0-9]+]] = !{i32 1, !"sycl-device", i32 1}
62+
; CHECK: [[DBG5]] = distinct !DISubprogram(name: "getGlobalInvocationId<1>", linkageName: "_ZN7__spirv21getGlobalInvocationIdILi1EEEmv", scope: [[META7:![0-9]+]], file: [[META6:![0-9]+]], line: 201, type: [[META8:![0-9]+]], scopeLine: 201, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], templateParams: [[META2]])
63+
; CHECK: [[META6]] = !DIFile(filename: "header.hpp", directory: {{.*}})
64+
; CHECK: [[META7]] = !DINamespace(name: "__spirv", scope: null)
65+
; CHECK: [[META8]] = distinct !DISubroutineType(types: [[META2]])
66+
; CHECK: [[DBG9]] = !DILocation(line: 201, column: 1, scope: [[DBG5]])
67+
; CHECK: [[DBG10]] = distinct !DISubprogram(name: "getGlobalInvocationId<1>", linkageName: "_ZN7__spirv21getGlobalInvocationIdILi1EEEmv", scope: [[META7]], file: [[META6]], line: 201, type: [[META8]], scopeLine: 201, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], templateParams: [[META2]])
68+
; CHECK: [[DBG11]] = !DILocation(line: 201, column: 1, scope: [[DBG10]])
69+
;.

0 commit comments

Comments
 (0)