[DebugInfo][CorrelatedValuePropagation] Eliminating `urem` 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 `urem` after proving that its result only affects program behavior when the unsigned dividend is less than `42`. Within that range, `x % 42` is equal to `x`, so replacing the remainder with the dividend preserves the program result.
However, the pass also changes the `#dbg_value` for the source variable `remainder` to describe `%x` directly. For inputs outside the inferred range, `%x` does not equal the source remainder even though `remainder` is still a source variable that can be inspected. With `x = 42`, LLDB prints `remainder` as `42` after the pass instead of the source-level value `0`.
## Reproducer
`case.c`:
```c
#include
unsigned int urem_elide(unsigned int x) {
unsigned int remainder = x % 42u;
bool in_range = x < 42u;
return in_range ? remainder : 24u;
}
int main(void) { return urem_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/dYqGeh6f7).
`lldb-commands.txt`:
```text
breakpoint set --file case.c --line 5
run
frame variable remainder
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 remainder:
```text
== src.out ==
(unsigned int) remainder = 0
```
After `correlated-propagation`, LLDB reports the dividend instead:
```text
== tgt.out ==
(unsigned int) remainder = 42
```
The relevant IR before the pass is:
```llvm
%rem = urem i32 %x, 42, !dbg !16
#dbg_value(i32 %rem, !17, !DIExpression(), !15)
%cmp = icmp ult i32 %x, 42, !dbg !18
%rem. = select i1 %cmp, i32 %rem, i32 24, !dbg !21
```
After the pass, the `urem` is removed and `%x` is used both by the select and by the debug record for `remainder`:
```llvm
#dbg_value(i32 %x, !16, !DIExpression(), !15)
%cmp = icmp ult i32 %x, 42, !dbg !17
%rem. = select i1 %cmp, i32 %x, i32 24, !dbg !20
```
Here, `!16` in the optimized IR is the source variable `remainder`:
```llvm
!16 = !DILocalVariable(name: "remainder", scope: !9, file: !1, line: 4, type: !12)
```
## Expected Behavior
The optimized debug information should not describe `remainder` with `%x` when it differs from the source-level unsigned remainder. At the breakpoint on line 5, LLDB should either report the original value `0` or report `remainder` as unavailable if the source value cannot be represented after eliminating the `urem`.
## 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
Reproduce the issue with case.c, the shown opt pipeline, src.ll and tgt.ll, then compare the #dbg_value records before and after correlated-propagation. Start by tracing how the pass handles the eliminated urem and its debug value. Done means the optimized debug information does not report remainder as %x when the source remainder differs; LLDB should show 0 or mark it unavailable.
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
- 45/100