<div dir="ltr">[+debug info cabal & Gor for coroutines]<br><br>Might be a bit easier with a reproduction using C++ coroutines (easier for the rest of us to reproduce/etc).<br><br>At first glance (not knowing a great deal about coroutines, not having looked at the IR, etc) - it doesn't look like it's /wrong/ per se, the two variables are still there, but without locations (so it's not like LLVM lost the notion that there were those two variables in that scope). I doubt there's any fundamental limitation & likely this can be fixed/improved. Happy to dive in/point you in the right direction if you'd like to work on fixing that.<br><br>Not sure about the anon variables - where they come from/why they're there.<br><br><div class="gmail_quote"><div dir="ltr">On Wed, Jun 27, 2018 at 10:42 AM Andrew Kelley via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org">llvm-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div><div><div><div>I'm going to show the same function, first normally, and then as a coroutine, and show how gdb can see the variable when it's a normal function, but not when it's a coroutine. I'd like to understand if this can be improved.<br><br></div><div>I'm trying to debug a real world problem, but the lack of debug info on variables in coroutines is making it difficult. Should I file a bug? Is this a fundamental limitation? Is anyone else interested in this?<br></div><div><br></div>Here is a normal function source (in zig):<br><br>const Point = struct {<br> x: i32,<br> y: i32,<br>};<br><br>pub fn main() void {<br> testAsyncSeq();<br>}<br><br>fn testAsyncSeq() void {<br> var blah = Point{ .x = 12, .y = 34 };<br> var bar = blah.x + 1;<br> var baz = bar + 1;<br>}<br><br></div>when we step through `testAsyncSeq` in gdb, the `blah` variable is visible:<br><br>Breakpoint 1, testAsyncSeq () at /home/andy/downloads/zig/build/test2.zig:13<br>13 var blah = Point{ .x = 12, .y = 34 };<br>(gdb) info locals<br>blah = {<br> x = 0, <br> y = 0<br>}<br>(gdb) next<br>14 var bar = blah.x + 1;<br>(gdb) info locals<br>bar = 0<br>blah = {<br> x = 12, <br> y = 34<br>}<br>(gdb) quit<br><br><br></div>However if I take advantage of LLVM's coroutines, the debug info seems to not be correct:<br><br>const std = @import("std");<br><br>const Point = struct {<br> x: i32,<br> y: i32,<br>};<br><br>pub fn main() !void {<br> const p = try async<std.debug.global_allocator> testAsyncSeq();<br> resume p;<br> cancel p;<br>}<br><br>async fn testAsyncSeq() void {<br> var blah = Point{ .x = 12, .y = 34 };<br> suspend;<br> var bar = blah.x + 1;<br> var baz = bar + 1;<br>}<br><br></div>Now in gdb the `blah` variable is not visible:<br><br>Breakpoint 1, testAsyncSeq () at /home/andy/downloads/zig/build/test.zig:14<br>14 async fn testAsyncSeq() void {<br>(gdb) next<br>15 var blah = Point{ .x = 12, .y = 34 };<br>(gdb) <br>16 suspend;<br>(gdb) info locals<br>bar = <optimized out><br>blah = <optimized out><br>_anon = 0x0<br>_anon = 368<br>_anon = 0x23a028 <global_fixed_allocator><br>_anon = <optimized out><br>(gdb) quit<br><br></div>Here is the LLVM IR generated for the function in the coroutines case. You can see that it has full debug info and @llvm.dbg.declare just like in the "normal function" case.<br><br>; Function Attrs: nobuiltin noinline nounwind optnone<br>define internal fastcc i8* @testAsyncSeq(%StackTrace* nonnull, %Allocator*, i16*) unnamed_addr #5 !dbg !1163 {<br>Entry:<br> %3 = alloca %"[]usize", align 8<br> %4 = alloca i8*, align 8<br> %5 = alloca %"[]u8", align 8<br> %_anon = alloca %"AsyncFramePromise(void)", align 8<br> %_anon1 = alloca i8*, align 8<br> %_anon2 = alloca i64, align 8<br> %_anon3 = alloca %Allocator*, align 8<br> %blah = alloca %Point, align 4<br> %bar = alloca i32, align 4<br> %baz = alloca i32, align 4<br> %6 = bitcast %"AsyncFramePromise(void)"* %_anon to i8*, !dbg !1191<br> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %6, i8* bitcast (%"AsyncFramePromise(void)"* @57 to i8*), i64 280, i32 8, i1 false), !dbg !1191<br> call void @llvm.dbg.declare(metadata %"AsyncFramePromise(void)"* %_anon, metadata !1168, metadata !DIExpression()), !dbg !1191<br> store i8* null, i8** %_anon1, align 8, !dbg !1191<br> call void @llvm.dbg.declare(metadata i8** %_anon1, metadata !1178, metadata !DIExpression()), !dbg !1191<br> %7 = bitcast %"AsyncFramePromise(void)"* %_anon to i8*, !dbg !1191<br> %8 = call token @<a href="http://llvm.coro.id" target="_blank">llvm.coro.id</a>(i32 16, i8* %7, i8* null, i8* null), !dbg !1191<br> %9 = call i64 @llvm.coro.size.i64(), !dbg !1191<br> store i64 %9, i64* %_anon2, align 8, !dbg !1191<br> call void @llvm.dbg.declare(metadata i64* %_anon2, metadata !1179, metadata !DIExpression()), !dbg !1191<br> store %Allocator* %1, %Allocator** %_anon3, align 8, !dbg !1191<br> call void @llvm.dbg.declare(metadata %Allocator** %_anon3, metadata !1180, metadata !DIExpression()), !dbg !1191<br> %10 = getelementptr inbounds %Allocator, %Allocator* %1, i32 0, i32 0, !dbg !1191<br> %11 = load void ({ i16, %"[]u8" }*, %StackTrace*, %Allocator*, i64, i29)*, void ({ i16, %"[]u8" }*, %StackTrace*, %Allocator*, i64, i29)** %10, align 8, !dbg !1191<br> %12 = call fastcc i8* @__zig_coro_alloc_helper(void ({ i16, %"[]u8" }*, %StackTrace*, %Allocator*, i64, i29)* %11, %StackTrace* %0, %Allocator* %1, i16* %2, i64 %9), !dbg !1191<br> %13 = icmp ne i8* %12, null, !dbg !1191<br> br i1 %13, label %AllocOk, label %AllocError, !dbg !1191<br><br>AllocError: ; preds = %Entry<br> ret i8* undef, !dbg !1191<br><br>AllocOk: ; preds = %Entry<br> %14 = call i8* @llvm.coro.begin(token %8, i8* %12), !dbg !1191<br> %15 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %_anon, i32 0, i32 0, !dbg !1191<br> store i8* null, i8** %15, align 8, !dbg !1191<br> %16 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %_anon, i32 0, i32 3, !dbg !1191<br> %17 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %_anon, i32 0, i32 2, !dbg !1191<br> %18 = getelementptr inbounds %StackTrace, %StackTrace* %17, i32 0, i32 0, !dbg !1191<br> store i64 0, i64* %18, align 8, !dbg !1191<br> %19 = getelementptr inbounds %StackTrace, %StackTrace* %17, i32 0, i32 1, !dbg !1191<br> %20 = getelementptr inbounds %"[]usize", %"[]usize"* %3, i32 0, i32 0, !dbg !1191<br> %21 = getelementptr inbounds [30 x i64], [30 x i64]* %16, i64 0, i64 0, !dbg !1191<br> store i64* %21, i64** %20, align 8, !dbg !1191<br> %22 = getelementptr inbounds %"[]usize", %"[]usize"* %3, i32 0, i32 1, !dbg !1191<br> store i64 30, i64* %22, align 8, !dbg !1191<br> %23 = bitcast %"[]usize"* %3 to i8*, !dbg !1191<br> %24 = bitcast %"[]usize"* %19 to i8*, !dbg !1191<br> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %24, i8* %23, i64 16, i32 8, i1 false), !dbg !1191<br> %25 = bitcast %Point* %blah to i8*, !dbg !1192<br> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %25, i8* bitcast (%Point* @60 to i8*), i64 8, i32 4, i1 false), !dbg !1192<br> call void @llvm.dbg.declare(metadata %Point* %blah, metadata !1181, metadata !DIExpression()), !dbg !1192<br> %26 = call i8 @llvm.coro.suspend(token none, i1 false), !dbg !1193<br> switch i8 %26, label %Suspend [<br> i8 0, label %SuspendResume<br> i8 1, label %SuspendCleanup<br> ], !dbg !1193<br><br>SuspendCleanup: ; preds = %AllocOk<br> br label %FinalCleanup, !dbg !1193<br><br>SuspendResume: ; preds = %AllocOk<br> %27 = getelementptr inbounds %Point, %Point* %blah, i32 0, i32 0, !dbg !1194<br> %28 = load i32, i32* %27, align 4, !dbg !1194<br> %29 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %28, i32 1), !dbg !1195<br> %30 = extractvalue { i32, i1 } %29, 0, !dbg !1195<br> %31 = extractvalue { i32, i1 } %29, 1, !dbg !1195<br> br i1 %31, label %OverflowFail, label %OverflowOk, !dbg !1195<br><br>CoroEarlyFinal: ; preds = %OverflowOk5<br> %32 = call i8 @llvm.coro.suspend(token none, i1 true), !dbg !1191<br> switch i8 %32, label %Suspend [<br> i8 0, label %InvalidResume<br> i8 1, label %FinalCleanup<br> ], !dbg !1191<br><br>Suspend: ; preds = %Resume, %CheckFree, %CoroEarlyFinal, %AllocOk<br> %33 = call i1 @llvm.coro.end(i8* null, i1 false), !dbg !1191<br> ret i8* %14, !dbg !1191<br><br>InvalidResume: ; preds = %CoroEarlyFinal<br> tail call fastcc void @panic(%"[]u8"* @49, %StackTrace* null), !dbg !1191<br> unreachable, !dbg !1191<br><br>CoroNormalFinal: ; preds = %OverflowOk5<br> %34 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %_anon, i32 0, i32 1, !dbg !1191<br> br label %CheckFree, !dbg !1191<br><br>FinalCleanup: ; preds = %CoroEarlyFinal, %SuspendCleanup<br> br label %CheckFree, !dbg !1191<br><br>CheckFree: ; preds = %FinalCleanup, %CoroNormalFinal<br> %35 = phi i1 [ false, %FinalCleanup ], [ true, %CoroNormalFinal ], !dbg !1191<br> %36 = load %Allocator*, %Allocator** %_anon3, align 8, !dbg !1191<br> %37 = getelementptr inbounds %Allocator, %Allocator* %36, i32 0, i32 2, !dbg !1191<br> %38 = load void (%Allocator*, %"[]u8"*)*, void (%Allocator*, %"[]u8"*)** %37, align 8, !dbg !1191<br> %39 = call i8* @llvm.coro.free(token %8, i8* %14), !dbg !1191<br> store i8* %39, i8** %4, align 8, !dbg !1191<br> %40 = load i64, i64* %_anon2, align 8, !dbg !1191<br> %41 = load i8*, i8** %4, align 8, !dbg !1191<br> %42 = getelementptr inbounds %"[]u8", %"[]u8"* %5, i32 0, i32 0, !dbg !1191<br> %43 = getelementptr inbounds i8, i8* %41, i64 0, !dbg !1191<br> store i8* %43, i8** %42, align 8, !dbg !1191<br> %44 = getelementptr inbounds %"[]u8", %"[]u8"* %5, i32 0, i32 1, !dbg !1191<br> %45 = sub nsw i64 %40, 0, !dbg !1191<br> store i64 %45, i64* %44, align 8, !dbg !1191<br> call fastcc void %38(%Allocator* %36, %"[]u8"* %5), !dbg !1191<br> br i1 %35, label %Resume, label %Suspend, !dbg !1191<br><br>Resume: ; preds = %CheckFree<br> %46 = load i8*, i8** %_anon1, align 8, !dbg !1191<br> %47 = load i8*, i8** %_anon1, align 8, !dbg !1191<br> call void @llvm.coro.resume(i8* %47), !dbg !1191<br> br label %Suspend, !dbg !1191<br><br>OverflowFail: ; preds = %SuspendResume<br> tail call fastcc void @panic(%"[]u8"* @41, %StackTrace* null), !dbg !1195<br> unreachable, !dbg !1195<br><br>OverflowOk: ; preds = %SuspendResume<br> store i32 %30, i32* %bar, align 4, !dbg !1196<br> call void @llvm.dbg.declare(metadata i32* %bar, metadata !1187, metadata !DIExpression()), !dbg !1196<br> %48 = load i32, i32* %bar, align 4, !dbg !1197<br> %49 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %48, i32 1), !dbg !1198<br> %50 = extractvalue { i32, i1 } %49, 0, !dbg !1198<br> %51 = extractvalue { i32, i1 } %49, 1, !dbg !1198<br> br i1 %51, label %OverflowFail4, label %OverflowOk5, !dbg !1198<br><br>OverflowFail4: ; preds = %OverflowOk<br> tail call fastcc void @panic(%"[]u8"* @41, %StackTrace* null), !dbg !1198<br> unreachable, !dbg !1198<br><br>OverflowOk5: ; preds = %OverflowOk<br> store i32 %50, i32* %baz, align 4, !dbg !1199<br> call void @llvm.dbg.declare(metadata i32* %baz, metadata !1189, metadata !DIExpression()), !dbg !1199<br> %52 = bitcast i8** %15 to i64*, !dbg !1191<br> %53 = ptrtoint i8* %14 to i64, !dbg !1191<br> %54 = atomicrmw xchg i64* %52, i64 %53 seq_cst, !dbg !1191<br> %55 = inttoptr i64 %54 to i8*, !dbg !1191<br> store i8* %55, i8** %_anon1, align 8, !dbg !1191<br> %56 = icmp ne i8* %55, null, !dbg !1191<br> br i1 %56, label %CoroNormalFinal, label %CoroEarlyFinal, !dbg !1191<br>}<br></div></div>
_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
</blockquote></div></div>