[DebugInfo][Reassociate] Canonicalizing a negative `fmul` leaves a debug value with the opposite sign
- 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
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