llvm / llvm/llvm-project

[DebugInfo][BDCE] does not salvage/invalidate debuginfo when removing and/or/xor instructions

Open
#218,890 6 comments 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

BDCE removes `or`, `xor`, and `and` instructions after determining that the affected bits are irrelevant to all remaining program uses. The transformations preserve program behavior, but the `#dbg_value` records for the source variables defined by those instructions are rewritten to describe the original operands without preserving the removed operations.

As a result, LLDB reports each source variable `value` as the function argument `a` rather than the result of the source-level bitwise expression.

This appears to be the same class of problem as #46640, where BDCE rewrites `sext` as `zext`, but here it occurs when BDCE removes bitwise binary operators.

## Reproducer

`case.c`:

```c
#include

volatile uint64_t sink;

__attribute__((noinline)) void use(uint64_t value) { sink = value; }

void func_or(uint64_t a) {
uint64_t value = a | 0x3;
[[gnu::nodebug]] uint64_t ret1 = value & 0x8;
use(ret1);
}

void func_xor(uint64_t a) {
uint64_t value = a ^ 0x3;
[[gnu::nodebug]] uint64_t ret1 = value & 0x8;
use(ret1);
}

void func_and(uint64_t a) {
uint64_t value = a & 0x18;
[[gnu::nodebug]] uint64_t ret1 = value & 0x8;
use(ret1);
}

int main(void) {
func_or(0x1d);
func_xor(0x1d);
func_and(0x1d);
return 0;
}
```

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 -S case.ll -o src.ll
opt -passes=bdce -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/oo1rrj4nE).

`lldb-commands.txt`:

```text
breakpoint set --file case.c --line 9
breakpoint set --file case.c --line 15
breakpoint set --file case.c --line 21
run
frame variable --format hex value
continue
frame variable --format hex value
continue
frame variable --format hex value
quit
```

Run LLDB on the binaries before and after BDCE:

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

## Observed Behavior

Before BDCE, the IR records the results of the three source-level operations:

```llvm
; func_or
%or = or i64 %a, 3, !dbg !29
#dbg_value(i64 %or, !30, !DIExpression(), !28)

; func_xor
%xor = xor i64 %a, 3, !dbg !37
#dbg_value(i64 %xor, !38, !DIExpression(), !36)

; func_and
%and = and i64 %a, 24, !dbg !45
#dbg_value(i64 %and, !46, !DIExpression(), !44)
```

After BDCE removes those instructions, each `#dbg_value` describes `value` directly with `%a` and an empty expression:

```llvm
; func_or
#dbg_value(i64 %a, !29, !DIExpression(), !28)

; func_xor
#dbg_value(i64 %a, !36, !DIExpression(), !35)

; func_and
#dbg_value(i64 %a, !43, !DIExpression(), !42)
```

With `a = 0x1d`, LLDB reports the source-level results before BDCE:

```text
== src.out ==
func_or, line 9: (uint64_t) value = 0x000000000000001f
func_xor, line 15: (uint64_t) value = 0x000000000000001e
func_and, line 21: (uint64_t) value = 0x0000000000000018
```

After BDCE, LLDB reports the argument value for all three variables:

```text
== tgt.out ==
func_or, line 9: (uint64_t) value = 0x000000000000001d
func_xor, line 15: (uint64_t) value = 0x000000000000001d
func_and, line 21: (uint64_t) value = 0x000000000000001d
```

## Expected Behavior

BDCE should salvage the removed bitwise operations in the debug expressions when possible, or invalidate the affected debug values when they cannot be represented. LLDB should not report `value` as the unmodified argument `a`.

At the three breakpoints, the debugger should report the source-level values `0x1f`, `0x1e`, and `0x18`, respectively, or report the variables as unavailable.

## 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

Start by reproducing the issue with case.c and the listed clang, opt, and LLDB commands, then compare src.ll and tgt.ll around the BDCE pass. Trace how removed and/or/xor instructions rewrite their #dbg_value records. Done means the debug values preserve the bitwise expressions when representable or are invalidated instead of reporting the unmodified argument.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.