llvm / llvm/llvm-project

[DebugInfo][CorrelatedValuePropagation] Eliminating `urem` leaves a wrong debug value

Open
#218,633 1 comment 0 reactions 0 assignees View on GitHub
debuginfo llvm:transforms
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.