llvm / llvm/llvm-project

[DebugInfo][Reassociate] Canonicalizing a negative `fmul` leaves a debug value with the opposite sign

Open
#220,208 1 comment 0 reactions 0 assignees View on GitHub
debuginfo llvm:optimizations
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Description

`reassociate` transforms `x - (-0.1234 * y)` into the equivalent expression `x + (0.1234 * y)`. This preserves the program result, but the `#dbg_value` for the source variable `mul` remains directly attached to the transformed multiplication.

At the source level, `mul` is the result of `-0.1234 * y`. After the transformation, the multiplication produces `0.1234 * y`, so using that result directly as the debug value reverses the sign of `mul`. With `y = 1.0`, LLDB prints `mul = 0.1234` after `reassociate` instead of the source-level value `-0.1234`.

## Reproducer

`case.c`:

```c
__attribute__((noinline)) double func(double x, double y) {
double mul = -0.1234 * y;
[[gnu::nodebug]] double result = x - mul;
return result;
}

int main(void) {
double result = func(2.0, 1.0);
return result != 0.0;
}
```

Build pipeline:

```sh
clang -g -gdwarf-5 -O0 -Xclang -disable-O0-optnone -fno-discard-value-names -S -emit-llvm case.c -o case.ll
opt -passes=mem2reg -S case.ll -o src.ll
opt -passes=reassociate -S src.ll -o tgt.ll
clang src.ll -o src.out
clang tgt.ll -o tgt.out
```

The complete `src.ll` and `tgt.ll` are available in this [Godbolt link](https://godbolt.org/z/Pj97359M5).

`lldb-commands.txt`:

```text
breakpoint set --source-pattern-regexp 'return result;'
run
frame variable mul
quit
```

Run LLDB on the binaries before and after `reassociate`:

```sh
lldb src.out -s lldb-commands.txt
lldb tgt.out -s lldb-commands.txt
```

## Observed Behavior

Before `reassociate`, LLDB reports the source-level negative product:

```text
== src.out ==
(double) mul = -0.1234
```

After `reassociate`, LLDB reports the transformed positive product:

```text
== tgt.out ==
(double) mul = 0.1234
```

The relevant IR before the pass is:

```llvm
%mul1 = fmul double -1.234000e-01, %y, !dbg !17
#dbg_value(double %mul1, !18, !DIExpression(), !15)
%sub = fsub double %x, %mul1, !dbg !19
ret double %sub, !dbg !20
```

After the pass, the negative multiplication and subtraction become a positive multiplication and addition, but the debug record still describes `mul` directly with `%mul1`:

```llvm
%mul1 = fmul double %y, 1.234000e-01, !dbg !17
#dbg_value(double %mul1, !18, !DIExpression(), !15)
%0 = fadd double %x, %mul1, !dbg !19
ret double %0, !dbg !20
```

Here, `!18` is the source variable `mul`:

```llvm
!18 = !DILocalVariable(name: "mul", scope: !9, file: !1, line: 2, type: !12)
```

## Expected Behavior

The optimized debug information should preserve the sign of the source-level value of `mul`. At the breakpoint on `return result;`, LLDB should report `mul = -0.1234`.

If the negative value cannot be represented after the multiplication is canonicalized, `mul` should be reported as unavailable instead of being described by the positive multiplication result.

## Environment

```text
clang version 24.0.0git
llvm-project revision: d35d0e69980f11c2acbd3670c65fec3cf574224a

LLVM version 24.0.0git
LLDB version 24.0.0git
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the issue with case.c and the shown opt -passes=reassociate pipeline, then compare src.ll and tgt.ll, focusing on the #dbg_value attached to the transformed fmul. Use the LLDB commands to verify the source value before and after the pass. Done means the optimized debug information preserves mul = -0.1234 or reports it as unavailable rather than showing the positive product.

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.