DWARF line number programs have the concept of “is_stmt”. According to the spec, is_stmt is: “A boolean indicating that the current instruction is a recommended breakpoint location. A recommended breakpoint location is intended to “represent” a line, a statement and/or a semantically distinct subpart of a statement.”
This is causing problems for us in rustc. We identify variables that are constant and emit IR for them early. When singlestepping the debugger seems to jump around out of place because every line that contains a constant is visited when the constant is (early) initialized. While it may be possible to defer the IR until closer to use (I’m not familiar with the history that led to the current behavior and what if anything motivated that) it would be much easier to simply mark the relevant DILocations as is_stmt=false. Is there a reason not to add API to do this and not rely solely on LLVM inferring is_stmt? Has it been proposed before?
is_stmt placement in LLVM in general could use improvements, especially with optimisations enabled.
Does the situation you’re talking about involve any optimisations?
Is there a reason not to add API to do this and not rely solely on LLVM inferring is_stmt? Has it been proposed before?
We (Sony) are currently investigating improvements to LLVM’s is_stmt placement and hope to share more details soon. The short story is that we add some metadata to instructions that perform user-visible changes (assignments, control flow, calls), then at DWARF emission we apply some heuristics to choose is_stmt locations on that set of instructions only. This is mainly aimed at improving the situation for optimized code but works at O0 too.
There’s some overlap with what you’re proposing. I can imagine a world where a front end tells LLVM that, for example, these constant inits are not meant to be “user visisble” (/not meant to be stepped on). Then our implementation uses that info.
Adding an API for explicitally disabling is_stmt for a DILocation is something we briefly explored, but the general wins don’t seem to be as great. However, it does sound like it would solve your problem, and I don’t think there’s a fundemental reason why it can’t be done. The trade off is sticking extra bits in DILocation (*).
There’s potentially a bit of a tension between the solutions as our upcoming work would add more bits to DILocation too.
I think the path forward depends a little on whether you’d be happy to wait (some months) for a general solution, or whether a stopgap solution is necessary. I don’t think the solutions are necessarily mutually exclusive and giving it some more time could result in a better integration of the two approaches.
(*) There is already a bit in DILocation used to tell LLVM that a location is attached to compiler generated code, DILocation::set/isImplicitCode, however this currently only used by the insert-gcov-profiling pass to skip those locations; it’s not currently used in determining is_stmt placement. Piggy-backing on that bit tangles profiling and stepping considerations (maybe that’s ok - requires some discussion).
Yes-ish. The optimization here is in the rustc front end, not in LLVM. The details are a bit hairy but rustc has a set of optimizations it performs (by default) even in debug builds because they can be performed before monomorphization (roughly equivalent to template instantiation in C++). Optimizing at that level simplifies the emitted LLVM-IR for every instantiation producing both compile time and binary size wins. The intent is that the set of optimizations that rustc runs (by default) in debug builds are 1) selected based on their ability to improve compilation performance and 2) should not hurt the debug-ability of programs. The latter is not always easy to achieve. Having no control over the placement of is_stmt is rather limiting in that regard.
I’m quite keen to learn more
An immediate solution isn’t really necessary (these issues have existed in rustc for at least 18 months). I think I can mitigate the worst effects of this for the time being by reordering the LLVM-IR we emit.
Yes-ish. The optimization here is in the rustc front end, not in LLVM…
Ah that’s interesting, thanks for the info.
I’m quite keen to learn more
I’ll share more details in an RFC (aiming between 1-3 weeks, but don’t hold me to that). The work is based off the ideas in the papers “Key Instructions: Solving the Code Location Problem for Optimized Code” (C. Tice, 2000) and “Debugging Optimized Code: Concepts and Implementation on DIGITAL Alpha Systems” (R. F. Brender et al).
There’s a question with our work with where the new metadata should get applied to instructions. Front ends, or in an llvm pass using an unsmart heuristic for which instructions are “key”. The latter is easiest (“works” for all front ends without additional effort) but the former gives front ends more control. That might be desirable in your case, especially given some optimisation takes place there. This might all be a bit opaque at the moment, sorry. I’ll keep the use-case in mind and raise it in the RFC.
An immediate solution isn’t really necessary (these issues have existed in rustc for at least 18 months). I think I can mitigate the worst effects of this for the time being by reordering the LLVM-IR we emit.