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