<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Sorry for the delay in replying to this, I've been out sick for the last couple of days.<div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Sep 5, 2017, at 1:00 PM, Reid Kleckner via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">Debug info today handles two cases reasonably well:</div><div class="">1. At -O0, dbg.declare does a good job describing variables that live at some known stack offset</div><div class="">2. With optimizations, variables promoted to SSA can be described with dbg.value</div><div class=""><br class=""></div><div class="">This leaves behind a large hole in our optimized debug info: variables that cannot be promoted, typically because they are address-taken. This is <a href="https://llvm.org/pr34136" class="">https://llvm.org/pr34136</a>, and this RFC is mostly about addressing that.</div><div class=""><br class=""></div><div class="">The status today is that instcombine removes all dbg.declares and heuristically inserts dbg.values where it can identify the value of the variable in question. This prevents us from having misleading debug info, but it throws away information about the variable’s location in memory.</div><div class=""><br class=""></div><div class="">Part of the reason that instcombine discards dbg.declares is that we can’t mix and match dbg.value with dbg.declare. If the backend sees a dbg.declare, it accepts that information as more reliable and discards all DBG_VALUE instructions associated with that variable. So, we need something we can mix. We need a way to say, the variable lives in memory *at this program point*, and it might live somewhere else later on. I propose that we introduce DW_OP_LLVM_memory for this purpose, and then we transition from dbg.declare to dbg.value+DW_OP_LLVM_memory.</div><div class=""><br class=""></div><div class="">Initially I believed that DW_OP_deref was the way to say this with existing DWARF expression opcodes, but I implemented that in <a href="https://reviews.llvm.org/D37311" class="">https://reviews.llvm.org/D37311</a> and learned more about how DWARF expressions work. When a debugger begins evaluating a DWARF expression, it assumes that the resulting value will be a pointer to the variable in memory.</div></div></div></blockquote><div><br class=""></div><div>That is an oversimplification. DWARF distinguishes at least three different kinds of locations: register locations (for when a variable is in a particular register and only there, i.e., the debugger may write to the register to modify the variable's value; think K&R C register variables), memory locations (which behave as you describe and allow the debugger to write to memory), implicit locations (DW_OP_stack_value, constants, ..., where the debugger can't write to modify). In LLVM we don't distinguish these cases as much as we should.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""> For a debugger, this makes sense, because debug builds put things in memory and even after optimization many variables must be spilled. Only the special DW_OP_regN and DW_OP_stack_value expression opcodes change the location of the value from memory to register or stack value.</div></div></div></blockquote><div><br class=""></div><div>See above.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="">LLVM SSA values obviously do not have an address that we can take and they don’t live in registers, so neither the default memory location model nor DW_OP_regN make sense for LLVM’s dbg.value. We could hypothetically repurpose DW_OP_stack_value to indicate that the SSA value passed to llvm.dbg.value *is* the variable’s value, and if the expression lacks DW_OP_stack_value, it must be a the address of the value. However, that is backwards incompatible and it seems like quite a stretch.</div></div></div></blockquote><div><br class=""></div><div>I don't think we should burden ourselves with backwards compatibility too much for this, if we have a good solution, I'm fine with having an upgrade that "looses" all incompatible dbg.value intrinsics once.</div><div>More to your point, in DWARF, DW_OP_stack_value means something different (see above) and I'd prefer to use the DWARF semantics for operators in DIEpressions and introduce custom DW_OP_LLVM_* ones where the semantics differ.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="">DW_OP_LLVM_memory would be very similar to DW_OP_stack_value, though. It would only be valid at the end of a DIExpression. The backend will always remove it because the debugger will assume the variable lives in memory unless it is told otherwise.</div><div class=""><br class=""></div><div class="">For the original problem of improving optimized debug info while avoiding inaccurate information in the presence of dead store elimination, consider this C example:</div><div class=""> int x = 42; // Can DSE</div><div class=""> dostuff(x); // Can propagate 42</div><div class=""> x = computation(); // Post-dominates `x = 42` store</div><div class=""> escape(&x);</div><div class=""><br class=""></div><div class="">We should be able to do this:</div><div class=""> int x; // eliminate `x = 42` store</div><div class=""> dbg.value(!x, 42, !DIExpression()) // mark x as the constant 42 in debug info</div><div class=""> dostuff(42); // propagate 42</div><div class=""> dbg.value(!x, &x, !DIExpression(DW_OP_LLVM_memory)) // x is in memory again</div><div class=""> x = computation();</div><div class=""> escape(&x);</div><div class=""><br class=""></div><div class="">Passes that delete stores would be responsible for checking if the store destination is part of an alloca with associated dbg.value instructions. They would emit a new dbg.value instruction for that variable with the stored value, and clone the dbg.value instruction that puts the variable back in memory before the killing store. If the store is dead because variable lifetime is ending, the second dbg.value is unnecessary.</div><div class=""><br class=""></div><div class="">This will also allow us to fix debug info for px in this example:</div><div class=""> void __attribute__((optnone, noinline)) usevar(int *x) {}</div><div class=""> int main(int argc, char **argv) {</div><div class=""> int x = 42;</div><div class=""> int *px = &x;</div><div class=""> usevar(&x);</div><div class=""> if (argc) usevar(px);</div><div class=""> }</div><div class=""><br class=""></div><div class="">Today, we emit a location for px like `DW_OP_breg7 RSP+12`, which gives it the incorrect value 42. This is because our DBG_VALUE instruction for px’s location uses a frame index, which we assume is in memory. This is not the case, px is not in memory, it’s value is a stack object pointer.</div><div class=""><br class=""></div><div class="">Please reply if you have any thoughts on this proposal. Adrian and I hashed this out over Bugzilla, IRC, and in person, so it shouldn’t be too surprising. Let me know if you want to be CC’d on the patches.</div></div></div></blockquote><div><br class=""></div><div>I'm going to read through all the other replies now, before commenting on the concrete proposal.</div><div><br class=""></div><div>thanks for writing this up,</div><div>Adrian</div><br class=""><blockquote type="cite" class=""><div class="">
_______________________________________________<br class="">LLVM Developers mailing list<br class=""><a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a><br class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev<br class=""></div></blockquote></div><br class=""></div></body></html>