[DebugInfo][CorrelatedValuePropagation] Rewriting `srem` through `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` rewrites an `srem` as negation, `urem`, and another negation after proving that the remainder only affects program behavior when the dividend is negative. This preserves the program result, but the `#dbg_value` for the source variable `remainder` is changed to describe the rewritten expression for every input.
For a positive input, the rewritten expression does not equal the source signed remainder. Consequently, LLDB prints `remainder` as `-30` after the pass instead of the source-level value `16`.
## Reproducer
`case.c`:
```c
int srem_to_urem(int x) {
int remainder = x % 42;
return x < 0 ? remainder : 24;
}
int main(void) { return srem_to_urem(100) != 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' -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/W7qWoxKx3).
`lldb-commands.txt`:
```text
breakpoint set --file case.c --line 3
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 signed remainder:
```text
== src.out ==
(int) remainder = 16
```
After `correlated-propagation`, LLDB reports a different value:
```text
== tgt.out ==
(int) remainder = -30
```
The relevant IR before the pass is:
```llvm
%rem = srem i32 %x, 42, !dbg !16
#dbg_value(i32 %rem, !17, !DIExpression(), !15)
```
After the pass, the signed remainder is rewritten through `urem`, and the debug record describes `remainder` with the final negated result:
```llvm
%x.nonneg = sub i32 0, %x, !dbg !16
%rem1 = urem i32 %x.nonneg, 42, !dbg !16
%rem1.neg = sub i32 0, %rem1, !dbg !16
#dbg_value(i32 %rem1.neg, !17, !DIExpression(), !15)
```
Here, `!17` is the source variable `remainder`:
```llvm
!17 = !DILocalVariable(name: "remainder", scope: !9, file: !1, line: 2, type: !12)
```
## Expected Behavior
The optimized debug information should not describe `remainder` with the rewritten unsigned-remainder expression when it differs from the source-level signed remainder. At the breakpoint on line 3, LLDB should either report the original value `16` or report `remainder` as unavailable if the source value cannot be represented after the transformation.
## 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 with the case.c reproducer and run the listed clang, opt, and LLDB commands to compare src.ll with tgt.ll. Then trace the correlated-propagation pass where the srem is rewritten and inspect how its #dbg_value is updated. Done means the optimized debug value is either the correct signed remainder or unavailable when it cannot be represented.
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
- 55/100