1; RUN: opt < %s -O0 -enable-coroutines -S | FileCheck %s 2; RUN: opt < %s -passes='default<O0>' -enable-coroutines -S | FileCheck %s 3 4; Define a function 'f' that resembles the Clang frontend's output for the 5; following C++ coroutine: 6; 7; void foo() { 8; int i = 0; 9; ++i; 10; print(i); // Prints '1' 11; 12; co_await suspend_always(); 13; 14; int j = 0; 15; ++i; 16; print(i); // Prints '2' 17; ++j; 18; print(j); // Prints '1' 19; } 20; 21; The CHECKs verify that dbg.declare intrinsics are created for the coroutine 22; funclet 'f.resume', and that they reference the address of the variables on 23; the coroutine frame. The debug locations for the original function 'f' are 24; static (!11 and !13), whereas the coroutine funclet will have its own new 25; ones with identical line and column numbers. 26; 27; CHECK-LABEL: define void @f() { 28; CHECK: entry: 29; CHECK: [[IGEP:%.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 30; CHECK: [[JGEP:%.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 31; CHECK: init.ready: 32; CHECK: call void @llvm.dbg.declare(metadata i32* [[IGEP]], metadata ![[IVAR:[0-9]+]], metadata !DIExpression()), !dbg ![[IDBGLOC:[0-9]+]] 33; CHECK: await.ready: 34; CHECK: call void @llvm.dbg.declare(metadata i32* [[JGEP]], metadata ![[JVAR:[0-9]+]], metadata !DIExpression()), !dbg ![[JDBGLOC:[0-9]+]] 35; 36; CHECK-LABEL: define internal fastcc void @f.resume({{.*}}) { 37; CHECK: entry.resume: 38; CHECK: [[IGEP_RESUME:%.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 39; CHECK: [[JGEP_RESUME:%.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 40; CHECK: init.ready: 41; CHECK: call void @llvm.dbg.declare(metadata i32* [[IGEP_RESUME]], metadata ![[IVAR_RESUME:[0-9]+]], metadata !DIExpression()), !dbg ![[IDBGLOC_RESUME:[0-9]+]] 42; CHECK: await.ready: 43; CHECK: call void @llvm.dbg.declare(metadata i32* [[JGEP_RESUME]], metadata ![[JVAR_RESUME:[0-9]+]], metadata !DIExpression()), !dbg ![[JDBGLOC_RESUME:[0-9]+]] 44; 45; CHECK: ![[IVAR]] = !DILocalVariable(name: "i" 46; CHECK: ![[SCOPE:[0-9]+]] = distinct !DILexicalBlock(scope: !8, file: !1, line: 23, column: 12) 47; CHECK: ![[IDBGLOC]] = !DILocation(line: 24, column: 7, scope: ![[SCOPE]]) 48; CHECK: ![[JVAR]] = !DILocalVariable(name: "j" 49; CHECK: ![[JDBGLOC]] = !DILocation(line: 32, column: 7, scope: ![[SCOPE]]) 50; CHECK: ![[IVAR_RESUME]] = !DILocalVariable(name: "i" 51; CHECK: ![[RESUME_SCOPE:[0-9]+]] = distinct !DILexicalBlock(scope: !8, file: !1, line: 23, column: 12) 52; CHECK: ![[IDBGLOC_RESUME]] = !DILocation(line: 24, column: 7, scope: ![[RESUME_SCOPE]]) 53; CHECK: ![[JVAR_RESUME]] = !DILocalVariable(name: "j" 54; CHECK: ![[JDBGLOC_RESUME]] = !DILocation(line: 32, column: 7, scope: ![[RESUME_SCOPE]]) 55define void @f() { 56entry: 57 %__promise = alloca i8, align 8 58 %i = alloca i32, align 4 59 %j = alloca i32, align 4 60 %id = call token @llvm.coro.id(i32 16, i8* %__promise, i8* null, i8* null) 61 %alloc = call i1 @llvm.coro.alloc(token %id) 62 br i1 %alloc, label %coro.alloc, label %coro.init 63 64coro.alloc: ; preds = %entry 65 %size = call i64 @llvm.coro.size.i64() 66 %memory = call i8* @new(i64 %size) 67 br label %coro.init 68 69coro.init: ; preds = %coro.alloc, %entry 70 %phi.entry.alloc = phi i8* [ null, %entry ], [ %memory, %coro.alloc ] 71 %begin = call i8* @llvm.coro.begin(token %id, i8* %phi.entry.alloc) 72 %ready = call i1 @await_ready() 73 br i1 %ready, label %init.ready, label %init.suspend 74 75init.suspend: ; preds = %coro.init 76 %save = call token @llvm.coro.save(i8* null) 77 call void @await_suspend() 78 %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) 79 switch i8 %suspend, label %coro.ret [ 80 i8 0, label %init.ready 81 i8 1, label %init.cleanup 82 ] 83 84init.cleanup: ; preds = %init.suspend 85 br label %cleanup 86 87init.ready: ; preds = %init.suspend, %coro.init 88 call void @await_resume() 89 call void @llvm.dbg.declare(metadata i32* %i, metadata !6, metadata !DIExpression()), !dbg !11 90 store i32 0, i32* %i, align 4 91 %i.init.ready.load = load i32, i32* %i, align 4 92 %i.init.ready.inc = add nsw i32 %i.init.ready.load, 1 93 store i32 %i.init.ready.inc, i32* %i, align 4 94 %i.init.ready.reload = load i32, i32* %i, align 4 95 call void @print(i32 %i.init.ready.reload) 96 %ready.again = call zeroext i1 @await_ready() 97 br i1 %ready.again, label %await.ready, label %await.suspend 98 99await.suspend: ; preds = %init.ready 100 %save.again = call token @llvm.coro.save(i8* null) 101 %from.address = call i8* @from_address(i8* %begin) 102 call void @await_suspend() 103 %suspend.again = call i8 @llvm.coro.suspend(token %save.again, i1 false) 104 switch i8 %suspend.again, label %coro.ret [ 105 i8 0, label %await.ready 106 i8 1, label %await.cleanup 107 ] 108 109await.cleanup: ; preds = %await.suspend 110 br label %cleanup 111 112await.ready: ; preds = %await.suspend, %init.ready 113 call void @await_resume() 114 call void @llvm.dbg.declare(metadata i32* %j, metadata !12, metadata !DIExpression()), !dbg !13 115 store i32 0, i32* %j, align 4 116 %i.await.ready.load = load i32, i32* %i, align 4 117 %i.await.ready.inc = add nsw i32 %i.await.ready.load, 1 118 store i32 %i.await.ready.inc, i32* %i, align 4 119 %j.await.ready.load = load i32, i32* %j, align 4 120 %j.await.ready.inc = add nsw i32 %j.await.ready.load, 1 121 store i32 %j.await.ready.inc, i32* %j, align 4 122 %i.await.ready.reload = load i32, i32* %i, align 4 123 call void @print(i32 %i.await.ready.reload) 124 %j.await.ready.reload = load i32, i32* %j, align 4 125 call void @print(i32 %j.await.ready.reload) 126 call void @return_void() 127 br label %coro.final 128 129coro.final: ; preds = %await.ready 130 call void @final_suspend() 131 %coro.final.await_ready = call i1 @await_ready() 132 br i1 %coro.final.await_ready, label %final.ready, label %final.suspend 133 134final.suspend: ; preds = %coro.final 135 %final.suspend.coro.save = call token @llvm.coro.save(i8* null) 136 %final.suspend.from_address = call i8* @from_address(i8* %begin) 137 call void @await_suspend() 138 %final.suspend.coro.suspend = call i8 @llvm.coro.suspend(token %final.suspend.coro.save, i1 true) 139 switch i8 %final.suspend.coro.suspend, label %coro.ret [ 140 i8 0, label %final.ready 141 i8 1, label %final.cleanup 142 ] 143 144final.cleanup: ; preds = %final.suspend 145 br label %cleanup 146 147final.ready: ; preds = %final.suspend, %coro.final 148 call void @await_resume() 149 br label %cleanup 150 151cleanup: ; preds = %final.ready, %final.cleanup, %await.cleanup, %init.cleanup 152 %cleanup.dest.slot.0 = phi i32 [ 0, %final.ready ], [ 2, %final.cleanup ], [ 2, %await.cleanup ], [ 2, %init.cleanup ] 153 %free.memory = call i8* @llvm.coro.free(token %id, i8* %begin) 154 %free = icmp ne i8* %free.memory, null 155 br i1 %free, label %coro.free, label %after.coro.free 156 157coro.free: ; preds = %cleanup 158 call void @delete(i8* %free.memory) 159 br label %after.coro.free 160 161after.coro.free: ; preds = %coro.free, %cleanup 162 switch i32 %cleanup.dest.slot.0, label %unreachable [ 163 i32 0, label %cleanup.cont 164 i32 2, label %coro.ret 165 ] 166 167cleanup.cont: ; preds = %after.coro.free 168 br label %coro.ret 169 170coro.ret: ; preds = %cleanup.cont, %after.coro.free, %final.suspend, %await.suspend, %init.suspend 171 %end = call i1 @llvm.coro.end(i8* null, i1 false) 172 ret void 173 174unreachable: ; preds = %after.coro.free 175 unreachable 176} 177 178declare void @llvm.dbg.declare(metadata, metadata, metadata) 179declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) 180declare i1 @llvm.coro.alloc(token) 181declare i64 @llvm.coro.size.i64() 182declare token @llvm.coro.save(i8*) 183declare i8* @llvm.coro.begin(token, i8* writeonly) 184declare i8 @llvm.coro.suspend(token, i1) 185declare i8* @llvm.coro.free(token, i8* nocapture readonly) 186declare i1 @llvm.coro.end(i8*, i1) 187 188declare i8* @new(i64) 189declare void @delete(i8*) 190declare i1 @await_ready() 191declare void @await_suspend() 192declare void @await_resume() 193declare void @print(i32) 194declare i8* @from_address(i8*) 195declare void @return_void() 196declare void @final_suspend() 197 198!llvm.dbg.cu = !{!0} 199!llvm.linker.options = !{} 200!llvm.module.flags = !{!3, !4} 201!llvm.ident = !{!5} 202 203!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None) 204!1 = !DIFile(filename: "repro.cpp", directory: ".") 205!2 = !{} 206!3 = !{i32 7, !"Dwarf Version", i32 4} 207!4 = !{i32 2, !"Debug Info Version", i32 3} 208!5 = !{!"clang version 11.0.0"} 209!6 = !DILocalVariable(name: "i", scope: !7, file: !1, line: 24, type: !10) 210!7 = distinct !DILexicalBlock(scope: !8, file: !1, line: 23, column: 12) 211!8 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 23, type: !9, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) 212!9 = !DISubroutineType(types: !2) 213!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 214!11 = !DILocation(line: 24, column: 7, scope: !7) 215!12 = !DILocalVariable(name: "j", scope: !7, file: !1, line: 32, type: !10) 216!13 = !DILocation(line: 32, column: 7, scope: !7) 217