New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pass-by-reference arg shows incorrect debuginfo value within loop after LICM #37030
Comments
I don't think it's feasible to assert that the debugger show updated values for 'total' within this loop, because it amounts to a demand that LICM never happen. As applied to this loop, the whole point of LICM is to sink the store.
I think this would be misleading. Inspecting "total" should show the user the value pointed-to by the "total" pointer. This is the only way print a correct value when "total" is aliased.
This might create scenarios where the variable is never presented as available, even though the debugger is perfectly able to inspect it, because hoisting/sinking occurs frequently. I also think this would be misleading, because users expect any inspection of "total" to show the value pointed-to by the "total" pointer. |
That seems eminently reasonable so I think we'll have to resolve this as it is, but it still leaves me uneasy. Putting myself in the shoes of some user who has written this loop and is trying to debug it, but doesn't know/care anything about compiler optimizations, the debugger is just plain wrong. This is an unfortunate case where we're comparing pretty unfavourably with the Microsoft compiler in terms of quality of the optimized debugging experience. Looking into it more closely it seems the reason that they do so well is because they have a store inside the loop (tested with VS2017 at /Ox). It's a shame that there's no way in DWARF (... I assume ... paging Paul ;) ) to represent this sort of situation where we know where the value according to the semantics of the user code being stepped through, but that it has not yet been stored to the location of the pointer. Feature request for a future standard? I'll put this in the bucket of things to assess the impact of disabling for -Og mode. For reference, GCC 5.4.0 has the same -O2 behaviour as clang here, but the value of total is visible on every iteration with -Og. |
Drive-by comment without having read the context: DWARF has DW_OP_implicit_pointer:
|
That's not really stating the situation accurately. 'total' is a reference, The value of the pointed-to variable is being computed in the loop, and As Adrian points out, in DWARF v5 we could describe this more accurately. FTR, I am sympathetic to the idea that '-Og' should avoid code-motion |
Right. I'm trying to come at this problem by putting aside all of my knowledge of compiler internals and just think about the experience of the average user who doesn't care to drop down to stepping through disassembly and just expects source level stepping to work. In this case, from the user point of view I can happily step through the loop and see some of my variables being updated, but not this one in particular. With my other compiler for my other platform I can see all my variables being updated on each iteration. Therefore I prefer to debug on that other platform. I guess my question at this stage is whether: |
It would obviously improve the debugging experience in this kind of situation, |
I've been thinking about this recently, and the more I think about it, the more I'm not sure that I agree with this entirely. My concern comes down to that fact that regardless of the underlying compiler implementation it's a reference, not a pointer: "It is neither a pointer to the object, nor a copy of the object. It is the object." - https://isocpp.org/wiki/faq/references#overview-refs So, from a pure user perspective, I still think that there's an argument to be made that for a few instructions within the loop the location of 'total' (and any aliases of it) is a register, not an address. If total had come into the function as int* I'd agree entirely with the above points (but still arguing in favour of a way to represent 'pending' values to the debugger). It may well be that we have to accept this as a limitation of the LLVM representation, but I'm leaning towards disagreeing with the assessment that it would be incorrect behaviour to temporarily bind the debug location of total to the register, as opposed to reasonable behaviour that may be not feasible to properly model. |
Hmmm. If 'total' was a global 'int' variable instead of an 'int&' parameter, So, I'm becoming more convinced that Greg has a point, and the problem |
Extended Description
Versions:
Repro case:
Trace output from DExTer ( http://llvm.org/devmtg/2018-04/slides/Bedwell-Measuring_the_User_Debugging_Experience.pdf ) with -opt-bisect-limit=31. Each line represents stepping once in the debugger. The values in the {} are the results of evaluating those expressions in the debugger while paused at that step.
We can see that variable total which is a function argument that has been passed by reference lives in the memory pointed at by $rdx, so the values match. Ignore $r10 for now.
Trace output from DExTer with -opt-bisect-limit=32 (BISECT: running pass (32) Loop Invariant Code Motion on loop).
Within the loop, variable 'total' now lives in $r10 and is only stored back to the address in $rdx after the loop terminates. The debug info for total still appears to be pointing at address of $rdx throughout though, so we get an incorrect value of 0.
Even though "total" comes in as a reference I think it would be fair to set the location of total to the register throughout the loop. At the very least I'd expect to see a "variable not visible due to optimization" type message.
The text was updated successfully, but these errors were encountered: