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