llvm / llvm/llvm-project

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

Open
#218,630 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 an `sdiv` after proving that its result only affects program behavior when the dividend is strictly between `-42` and `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

int sdiv_elide(int x) {
int quotient = x / 42;
bool in_range = (x < 42) && (x > -42);
return in_range ? quotient : 24;
}

int main(void) { return sdiv_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/G8s1cvWsd).

`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 signed quotient:

```text
== src.out ==
(int) quotient = 1
```

After `correlated-propagation`, LLDB reports the constant used by the optimized computation:

```text
== tgt.out ==
(int) quotient = 0
```

The relevant IR before the pass is:

```llvm
%div = sdiv i32 %x, 42, !dbg !16
#dbg_value(i32 %div, !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 %div, i32 24, !dbg !21
```

After the pass, the `sdiv` 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)
%0 = add i32 %x, 41, !dbg !17
%spec.select = icmp ult i32 %0, 83, !dbg !17
%cond = select i1 %spec.select, 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 signed 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 `sdiv`.

## 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 mismatch using case.c, the clang and opt commands, and the LLDB session described in the issue. Inspect the correlated-propagation pass and its handling of the quotient debug record in src.ll and tgt.ll. Done means optimized debug information preserves the source quotient when representable or marks it unavailable, without changing program behavior.

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
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.