xref: /llvm-project/llvm/test/Transforms/Coroutines/coro-debug-spill-dbg.declare.ll (revision 094572701dce4aaf36f4521d6cf750420d39f206)
1; Test spilling a temp generates dbg.declare in resume/destroy/cleanup functions.
2;
3; RUN: opt < %s -passes='cgscc(coro-split)' -S | FileCheck %s
4; RUN: opt --try-experimental-debuginfo-iterators < %s -passes='cgscc(coro-split)' -S | FileCheck %s
5;
6; The test case simulates a coroutine method in a class.
7;
8; class Container {
9;  public:
10;    Container() : field(12) {}
11;    Task foo() {
12;      co_await std::suspend_always{};
13;      auto *copy = this;
14;      co_return;
15;    }
16;    int field;
17; };
18;
19; We want to make sure that the "this" pointer is accessable in debugger before and after the suspension point.
20;
21; CHECK: define internal fastcc void @foo.resume(ptr noundef nonnull align 8 dereferenceable(32) %[[HDL:.*]])
22; CHECK-NEXT: entry.resume:
23; CHECK-NEXT:   %[[HDL]].debug = alloca ptr, align 8
24; CHECK-NEXT:   #dbg_declare(ptr %[[HDL]].debug, ![[THIS_RESUME:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 24),
25;
26; CHECK: define internal fastcc void @foo.destroy(ptr noundef nonnull align 8 dereferenceable(32) %[[HDL]])
27; CHECK-NEXT: entry.destroy:
28; CHECK-NEXT:   %[[HDL]].debug = alloca ptr, align 8
29; CHECK-NEXT:   #dbg_declare(ptr %[[HDL]].debug, ![[THIS_DESTROY:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 24),
30;
31; CHECK: define internal fastcc void @foo.cleanup(ptr noundef nonnull align 8 dereferenceable(32) %[[HDL]])
32; CHECK-NEXT: entry.cleanup:
33; CHECK-NEXT:   %[[HDL]].debug = alloca ptr, align 8
34; CHECK-NEXT:   #dbg_declare(ptr %[[HDL]].debug, ![[THIS_CLEANUP:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 24),
35;
36; CHECK: ![[THIS_RESUME]] = !DILocalVariable(name: "this"
37; CHECK: ![[THIS_DESTROY]] = !DILocalVariable(name: "this"
38; CHECK: ![[THIS_CLEANUP]] = !DILocalVariable(name: "this"
39
40; Function Attrs: presplitcoroutine
41define ptr @foo(ptr noundef nonnull align 1 dereferenceable(1) %this) #0 !dbg !11 {
42entry:
43  %this.addr = alloca ptr, align 8
44  %__promise = alloca i8, align 1
45  store ptr %this, ptr %this.addr, align 8
46  call void @llvm.dbg.declare(metadata ptr %this.addr, metadata !20, metadata !DIExpression()), !dbg !22
47  %this1 = load ptr, ptr %this.addr, align 8
48  %0 = bitcast ptr %__promise to ptr
49  %id = call token @llvm.coro.id(i32 16, ptr %0, ptr null, ptr null)
50  %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
51  br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
52
53dyn.alloc:                                        ; preds = %entry
54  %size = call i32 @llvm.coro.size.i32()
55  %alloc = call ptr @malloc(i32 %size)
56  br label %coro.begin
57
58coro.begin:                                       ; preds = %dyn.alloc, %entry
59  %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
60  %hdl = call ptr @llvm.coro.begin(token %id, ptr %phi)
61  call void @llvm.dbg.declare(metadata ptr %__promise, metadata !23, metadata !DIExpression()), !dbg !22
62  %1 = call i8 @llvm.coro.suspend(token none, i1 false)
63  switch i8 %1, label %suspend [
64    i8 0, label %resume
65    i8 1, label %cleanup
66  ]
67
68resume:                                           ; preds = %coro.begin
69  call void @bar(ptr %this1)
70  br label %cleanup
71
72cleanup:                                          ; preds = %resume, %coro.begin
73  %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
74  call void @free(ptr %mem)
75  br label %suspend
76
77suspend:                                          ; preds = %cleanup, %coro.begin
78  %2 = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
79  ret ptr %hdl
80}
81
82; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
83declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
84
85; Function Attrs: nounwind memory(argmem: read)
86declare ptr @llvm.coro.free(token, ptr nocapture readonly) #2
87
88; Function Attrs: nounwind memory(none)
89declare i32 @llvm.coro.size.i32() #3
90
91; Function Attrs: nounwind
92declare i8 @llvm.coro.suspend(token, i1) #4
93
94declare void @llvm.coro.resume(ptr)
95
96declare void @llvm.coro.destroy(ptr)
97
98; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
99declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) #5
100
101; Function Attrs: nounwind
102declare i1 @llvm.coro.alloc(token) #4
103
104; Function Attrs: nounwind
105declare ptr @llvm.coro.begin(token, ptr writeonly) #4
106
107; Function Attrs: nounwind
108declare i1 @llvm.coro.end(ptr, i1, token) #4
109
110declare noalias ptr @malloc(i32)
111
112declare void @free(ptr)
113
114declare void @bar(ptr)
115
116attributes #0 = { presplitcoroutine }
117attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
118attributes #2 = { nounwind memory(argmem: read) }
119attributes #3 = { nounwind memory(none) }
120attributes #4 = { nounwind }
121attributes #5 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
122
123!llvm.dbg.cu = !{!0}
124!llvm.linker.options = !{}
125!llvm.module.flags = !{!3, !4, !5, !6, !7, !8, !9}
126!llvm.ident = !{!10}
127
128!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 17.0.20210610", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None)
129!1 = !DIFile(filename: "test.cpp", directory: ".")
130!2 = !{}
131!3 = !{i32 7, !"Dwarf Version", i32 5}
132!4 = !{i32 2, !"Debug Info Version", i32 3}
133!5 = !{i32 1, !"wchar_size", i32 4}
134!6 = !{i32 8, !"PIC Level", i32 2}
135!7 = !{i32 7, !"PIE Level", i32 2}
136!8 = !{i32 7, !"uwtable", i32 2}
137!9 = !{i32 7, !"frame-pointer", i32 2}
138!10 = !{!"clang version 17.0.20210610"}
139!11 = distinct !DISubprogram(name: "foo", linkageName: "_ZN9Container3fooEv", scope: !1, file: !1, line: 20, type: !12, scopeLine: 20, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !13, retainedNodes: !2)
140!12 = !DISubroutineType(types: !2)
141!13 = !DISubprogram(name: "foo", linkageName: "_ZN9Container3fooEv", scope: !14, file: !1, line: 20, type: !12, scopeLine: 20, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0)
142!14 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Container", file: !1, line: 17, size: 8, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !15, identifier: "_ZTS9Container")
143!15 = !{!16, !13}
144!16 = !DISubprogram(name: "Container", scope: !14, file: !1, line: 19, type: !17, scopeLine: 19, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0)
145!17 = !DISubroutineType(types: !18)
146!18 = !{null, !19}
147!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
148!20 = !DILocalVariable(name: "this", arg: 1, scope: !11, type: !21, flags: DIFlagArtificial | DIFlagObjectPointer)
149!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
150!22 = !DILocation(line: 0, scope: !11)
151!23 = !DILocalVariable(name: "__promise", scope: !11, type: !24, flags: DIFlagArtificial)
152!24 = !DIDerivedType(tag: DW_TAG_typedef, name: "promise_type", scope: !11, file: !1, line: 40, baseType: !25)
153!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "promise_type", scope: !11, file: !1, line: 6, size: 8, flags: DIFlagTypePassByValue, elements: !2, identifier: "_ZTSN4Task12promise_typeE")
154