[DebugInfo][CorrelatedValuePropagation] Eliminating `udiv` leaves a wrong debug value
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
## Description
`correlated-propagation` eliminates a `udiv` after proving that its result only affects program behavior when the unsigned dividend is less than `42`. Within that range, `x / 42` is always `0`, so replacing the quotient with zero preserves the program result.
However, the pass also changes the `#dbg_value` for the source variable `quotient` to describe the constant `0`. For inputs outside the inferred range, the source quotient is not necessarily zero even though `quotient` is still a source variable that can be inspected. With `x = 42`, LLDB prints `quotient` as `0` after the pass instead of the source-level value `1`.
## Reproducer
`case.c`:
```c
#include
unsigned int udiv_elide(unsigned int x) {
unsigned int quotient = x / 42u;
bool in_range = x < 42u;
return in_range ? quotient : 24u;
}
int main(void) { return udiv_elide(42) != 24; }
```
Build pipeline:
```sh
clang -g -O0 -Xclang -disable-O0-optnone -fno-discard-value-names -S -emit-llvm case.c -o case.ll
opt -passes='mem2reg,simplifycfg,instcombine' -S case.ll -o src.ll
opt -passes=correlated-propagation -S src.ll -o tgt.ll
clang src.ll -o src.out
clang tgt.ll -o tgt.out
```
Here are the complete [src.ll and tgt.ll](https://godbolt.org/z/41KrYdsK6).
`lldb-commands.txt`:
```text
breakpoint set --file case.c --line 5
run
frame variable quotient
quit
```
Run LLDB on the binaries before and after `correlated-propagation`:
```sh
lldb src.out -s lldb-commands.txt
lldb tgt.out -s lldb-commands.txt
```
## Observed Behavior
Before `correlated-propagation`, LLDB reports the unsigned quotient:
```text
== src.out ==
(unsigned int) quotient = 1
```
After `correlated-propagation`, LLDB reports the constant used by the optimized computation:
```text
== tgt.out ==
(unsigned int) quotient = 0
```
The relevant IR before the pass is:
```llvm
%div = udiv i32 %x, 42, !dbg !16
#dbg_value(i32 %div, !17, !DIExpression(), !15)
%cmp = icmp ult i32 %x, 42, !dbg !18
%div. = select i1 %cmp, i32 %div, i32 24, !dbg !21
```
After the pass, the `udiv` is removed and zero is used both by the select and by the debug record for `quotient`:
```llvm
#dbg_value(i32 0, !16, !DIExpression(), !15)
%cmp = icmp ult i32 %x, 42, !dbg !17
%div. = select i1 %cmp, i32 0, i32 24, !dbg !20
```
Here, `!16` in the optimized IR is the source variable `quotient`:
```llvm
!16 = !DILocalVariable(name: "quotient", scope: !9, file: !1, line: 4, type: !12)
```
## Expected Behavior
The optimized debug information should not describe `quotient` with the constant `0` when it differs from the source-level unsigned quotient. At the breakpoint on line 5, LLDB should either report the original value `1` or report `quotient` as unavailable if the source value cannot be represented after eliminating the `udiv`.
## Environment
```text
clang version 24.0.0git
llvm-project revision: f6ea145aa8e89631ae04f72df32580b20256d40c
LLVM version 24.0.0git
lldb version 24.0.0git
```
Contributor guide
Research direction
Start by running the provided case.c build pipeline and comparing the src.ll and tgt.ll debug records around the eliminated udiv. Trace correlated-propagation's handling of the quotient variable, then verify that LLDB reports the original value or marks it unavailable and add a regression test covering the reproducer.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100