Skip to content
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

[DebugInfo@O2][Dexter]Stale debug variable value in optimised code #38101

Closed
jmorse opened this issue Aug 29, 2018 · 15 comments
Closed

[DebugInfo@O2][Dexter]Stale debug variable value in optimised code #38101

jmorse opened this issue Aug 29, 2018 · 15 comments
Labels
bugzilla Issues migrated from bugzilla wrong-debug

Comments

@jmorse
Copy link
Member

jmorse commented Aug 29, 2018

Bugzilla Link 38753
Resolution FIXED
Resolved on Feb 24, 2020 10:04
Version trunk
OS Linux
Blocks #38116
CC @adrian-prantl,@bjope,@dstenb,@dwblaikie,@gregbedwell,@CarlosAlbertoEnciso,@JDevlieghere,@pogo59
Fixed by commit(s) https://reviews.llvm.org/rG453dc4d7ec5a3c3d8f54fc358bc5673834516d48

Extended Description

With the (contrived) test below, the "cheese" variable has a stale value reported inside the "if" block. Using an up-to-date toolchain (r340912), and compiling with "clang++ test.cpp -g -O2 -o a.out" for x86_64, on the marked line gdb and lldb report the value of "cheese" to be four, wheras if compiled -O0 the correct value of eight is seen.

The likely cause is SimplifyCFG's tryCSEWithPredecessor replacing the duplicate "read1 + read2" expression, however the debug value for "cheese" is either lost or not updated, causing debuggers to report a state the program isn't in.

It should be possible to get this right or mark "cheese" optimised out, the true-if-block isn't merged with anything else.

Found using DExTer ( https://github.com/SNSystems/dexter ).

-------->8--------
int
main()
{
volatile int foo = 4;
int read1 = foo;
int read2 = foo;

int cheese = foo;
int a = read1 + read2;
a += cheese;

if (foo == 4) {
cheese = read1 + read2;
a -= cheese - 12;
a *= 20; // <------ stale value seen
a /= 3;
} else {
a = 0;
}

return a;
}
--------8<--------

@CarlosAlbertoEnciso
Copy link
Member

When stopping in the debugger at line:

'if (foo == 4) {',

the value reported for the variable 'a' is 16. The correct value should be 12.

@jmorse
Copy link
Member Author

jmorse commented Nov 5, 2018

bug 38754 appears to be related, in that the change from the second comment fixes this ticket. This could be marked duplicate, but I'll keep it open in case the solution to 38754 takes a complicated direction.

@jmorse
Copy link
Member Author

jmorse commented Mar 7, 2019

NB, even with the placeDbgValues fix (added to r354569) this problem persists. It would appear that something (instcombine most likely) sink the read1+read2 expression into the conditional block and folds it with the other arithmetic there, but doesn't then issue an undef dbg.value or otherwise.

Plus, 'a' is unreadable on the return statement, which is a pain.

@jmorse
Copy link
Member Author

jmorse commented Jun 18, 2019

Coming back to this with a fresh eye: it looks like I got highly confused in the past as I didn't see that "read1+read2" would get CSE'd, thus I misinterpreted the eventual assembly.

It's likely that the cause of the "stale" value is due to variable assignments and line numbers being two independent state machines that don't line up. This probably won't be addressed any time soon.

The matter of the return value is still relevant though, at the end of the compilation pipeline we get:

--------8<--------
; predecessors: %bb.0, %bb.1
liveins: $rax
DBG_VALUE $eax, $noreg, !"a", !DIExpression()
$eax = KILL renamable $eax, implicit killed $rax
RETQ $eax
-------->8--------

According to TargetOpcodes.def, the "KILL" instruction is a noop that adjusts the liveness of registers. DbgEntityHistoryCalculator sees the kill of $rax and (soundly) kills the previous DBG_VALUE, making it cover zero instructions. It's unfortunate that this leads to the return value never being printable.

CC David as he's worked on DbgEntityHistoryCalculator recently. There might not be a good way of fixing this without spraying special cases into DbgEntityHistoryCalculator :(.

@bjope
Copy link
Collaborator

bjope commented Jun 18, 2019

CC David as he's worked on DbgEntityHistoryCalculator recently. There might
not be a good way of fixing this without spraying special cases into
DbgEntityHistoryCalculator :(.

@​dstenb: One thing here is that for our OOT target we remove KILL instructions before late scheduling (probably for historical reasons and our VLIW scheduler not handling KILL instructions very well). So I doubt that we have problem with KILL for our own target. But I believe the DbgValueHistoryCalculator could simply ignore KILL instructions.

@dstenb
Copy link
Mannequin

dstenb mannequin commented Jun 19, 2019

Sorry, I don't think I have anything valuable to add about that.

@llvmbot
Copy link
Member

llvmbot commented Oct 14, 2019

Taken for myself, going to try and get to the bottom of this.

@llvmbot
Copy link
Member

llvmbot commented Oct 24, 2019

so ignoring the KILL instruction and return value for now, I want to address the initially reported stale value for 'a' and for 'cheese'.

The problem was caused by a pass called ReassociateExpressions, found in llvm/lib/Transforms/Reassociate.cpp.

This pass was dropping instructions that were trivially deletable but wasn't then undeffing the debug intrinsics that were referencing them causing dbg.value intrinsics to have 'dangling' pointers that were fixed up to point at empty meta data.

A later pass, combine redundant instructions, would then drop these noop intrinsics completely from the block.

Then comes along the LiveDebugValues pass during the lowering stage in LLC. It's job is to propogate debug value intrinsics into as many blocks where the liveness of the location is preserved for as greater range as possible. Since we didn't have an undeffed intrinsic when the location was dropped by reassociate expressions the liveness of previous intrinsics are extended into subsequent blocks, thus extending the range of the "stale" values further down the function than is correct.

I've written a patch that attempts to address this issue, I'm currently working on a test and doing due-dilligence to ensure I've not messed anything else up in the process.

I'll take a look at the return value for A and the kill instruction afterwards.

@llvmbot
Copy link
Member

llvmbot commented Nov 7, 2019

patch up for your reviewing pleasure

https://reviews.llvm.org/D69943

@llvmbot
Copy link
Member

llvmbot commented Nov 12, 2019

first patch, fix for reassociate pass is now in master.

@llvmbot
Copy link
Member

llvmbot commented Nov 12, 2019

can comfirm that the return value for a is still missing as of TOT, starting investigation.

@llvmbot
Copy link
Member

llvmbot commented Nov 20, 2019

diff up for review on Phab for fixing the return value.

https://reviews.llvm.org/D70497

@llvmbot
Copy link
Member

llvmbot commented Dec 20, 2019

patch up and accepted for KILL instructions here:

https://reviews.llvm.org/D70497

@llvmbot
Copy link
Member

llvmbot commented Feb 24, 2020

@jmorse
Copy link
Member Author

jmorse commented Nov 27, 2021

mentioned in issue #38116

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla wrong-debug
Projects
None yet
Development

No branches or pull requests

4 participants