Hi Brian, Thanks for working on coroutines, the debugging experience, and in particular thanks for the comprehensive write-up!,
On Thu, Feb 6, 2020 at 1:19 PM Brian Gesiak via llvm-dev <llvm-...@lists.llvm.org> wrote: > Specifically, I’m trying to improve lldb’s behavior when showing > variables in the current stack frame, when that frame corresponds to a > coroutine function. [...] Everything in the IR appears correct to my eyes, although I know next to nothing about coroutines and might have missed something. The simplest explanation of why the variable location goes missing can be seen in the disassembly: > ``` > 0x401885 <+373>: movq -0x8(%rbp), %rax > 0x401889 <+377>: movl $0x0, 0x40(%rax) > 0x401890 <+384>: X movl 0x28(%rax), %edx > 0x401893 <+387>: X addl $0x1, %edx > 0x401896 <+390>: X movl %edx, 0x28(%rax) > 0x401899 <+393>: X movl 0x40(%rax), %edx > 0x40189c <+396>: addl $0x1, %edx > 0x40189f <+399>: movl %edx, 0x40(%rax) > -> 0x4018a2 <+402>: movl 0x28(%rax), %esi > ``` Where I've marked with 'X' before the mnemonic the instructions that the variable location list covers. The location of "i" is correctly given as edx from its load to its store, and ends when edx is overwritten with the value of "j". In all the rest of the code, the variables value is in memory, and the DWARF data doesn't record this. Ideally debug info would track variables when they're stored to memory -- however we don't automatically know whether any subsequent store to memory will overwrite that variable, and so we don't track locations into memory. PR40628 [0] is an example of what can go wrong, where we described a variable as being in memory, but didn't know when that location was overwritten. If whatever's producing the coroutine IR has guarantees about where and when variables are loaded/stored from/to memory, it should be possible to put more information into the IR, so that the rest of LLVM doesn't have to guess. For example, this portion of IR: %15 = load i32, i32* %i.reload.addr62, align 4, !dbg !670 call void @llvm.dbg.value(metadata i32 %15, metadata !659, metadata !DIExpression()), !dbg !661 %inc19 = add nsw i32 %15, 1, !dbg !670 call void @llvm.dbg.value(metadata i32 %inc19, metadata !659, metadata !DIExpression()), !dbg !661 store i32 %inc19, i32* %i.reload.addr62, align 4, !dbg !670 Could have a call to llvm.dbg.addr(metadata i32 *%i.reload.addr66, ...) inserted after the store, indicating that the variable is located in memory. This should work (TM) so long as that memory is never overwritten with something that isn't the current value of "i" on every path after the call to llvm.dbg.addr; and on every path after the call to llvm.dbg.addr, when the variable is loaded form memory, there's a call to llvm.dbg.value to indicate that the variable is located somewhere other than memory now. Providing that extra information should improve the location coverage for your example, certainly when unoptimised. However, I believe (80%) this method isn't safe against optimisation, because (for example) dead stores can be deleted by LLVM passes without deleting the call to llvm.dbg.addr, pointing the variable location at a stale value in memory. Unfortunately I'm not aware of a facility or technique that protects against this right now. (CC Reid who I think ran into this last?). Note that there's some support for tracking variables through stack spills in post-isel debug data passes, however those loads and stores operate in well defined ways, and general loads and stores might not. [0] https://bugs.llvm.org/show_bug.cgi?id=40628 -- Thanks, Jeremy _______________________________________________ lldb-dev mailing list lldb-dev@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev