llvm / llvm/llvm-project

[DebugInfo][Attributor] Optimized-out argument is still described as live, causing LLDB to print random values

Open
#209,417 2 comments 0 reactions 0 assignees View on GitHub
debuginfo llvm::Attributor
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Description

After running the Attributor pipeline on a small C test case with debug info, LLDB prints a random value for a source-level function parameter that was optimized away.

The original source passes `99` as the second argument, but after optimization the call site passes `undef`. However, the emitted debug info still describes the source variable `unused` as being located in the physical argument register `RSI`. As a result, LLDB shows whatever happens to be in that register instead of reporting the variable as optimized out, or preserving the original source value if that is intended/possible.

This looks like a debug info correctness issue introduced or exposed by Attributor.

## Reproducer

`source.c`:

```c
int func(int live, int unused, int salt) {
int copy = unused;
return live + salt + (copy & 0);
}

int main(void) {
return func(1, 99, 5);
}
```

Build/reduce pipeline:

```sh
clang -g -O0 -Xclang -disable-O0-optnone -emit-llvm -S source.c -o base.ll
opt -passes="function(declare-to-assign),attributor" base.ll -S -o attributor-opted.ll
clang attributor-opted.ll -o attributor-opted.out
```

Debugging:

```sh
lldb --batch \
-o 'breakpoint set --name func' \
-o run \
-o 'frame variable unused' \
-o 'expression unused' \
-- ./attributor-opted.out
```

## Actual Behavior

LLDB prints a random value for `unused`:

```text
frame #0: ... attributor-opted.out`func(live=1, unused=-9224, salt=5) at source.c:3:15

(lldb) frame variable unused
(int) unused = -9224

(lldb) expression unused
(int) $0 = -9224
```

The exact value changes depending on the register contents.

## Expected Behavior

LLDB should not print an arbitrary/random value for the source variable.

Preferably, `unused` should either:

- be shown as `99`, matching the source-level call `func(1, 99, 5)`, if LLVM can preserve that debug value, or
- be reported as optimized out/unavailable.

It should not be described as a live register value when the optimized program no longer passes a defined value for that argument.

## Relevant Optimized IR

The full unoptimized and optimized IR are put on Compiler Explorer for reference: [Full IR](https://godbolt.org/z/x71d7q8vs).

After `opt -passes="function(declare-to-assign),attributor"`, the call site has:

```llvm
%2 = call i32 @func(i32 noundef 1, i32 undef, i32 noundef 5) #1, !dbg !33
```

Inside `func`, debug assignment tracking still associates the source parameter `unused` with `%1`:

```llvm
define dso_local i32 @func(i32 noundef %0, i32 %1, i32 noundef %2) #0 !dbg !10 {
...
#dbg_assign(i32 %1, !18, !DIExpression(), !25, ptr poison, !DIExpression(), !17)
...
}
```

The generated DWARF contains a location for `unused` in `RSI`:

```text
DW_TAG_formal_parameter
DW_AT_location (
[0x0000000000001139, 0x0000000000001140): DW_OP_reg4 RSI
)
DW_AT_name ("unused")
```

Since the caller passes `undef`, this register location exposes an arbitrary machine value to the debugger.

## Environment

```text
clang version 23.0.0git
llvm-project revision: 58203500b5bd1628401c1a103eb264b7d78ea3bb

lldb version 23.0.0git
```

## Notes

This may be an Attributor/debuginfo interaction. The optimization is valid for program semantics, but the corresponding debug value for the eliminated argument appears to become misleading instead of unavailable.

Contributor guide

Open the contributing guide

Research direction

Reproduce the issue with source.c using the clang, opt, and lldb commands in the report. Compare attributor-opted.ll, the generated DWARF location for unused, and LLDB's frame variable output. Done means unused is no longer exposed as an arbitrary register value and is instead preserved or reported unavailable.

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
Quiet
Clarity
Mostly clear
Newbie friendliness
44/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.