[BasicBlockSections] Debug-only instruction suppresses a landing-pad NOP and changes exception behavior
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
## Summary
Two verifier-valid LLVM IR modules differ by exactly one `#dbg_value` record.
With the same basic-block cluster profile, the version without the record
inserts the NOP required before a zero-offset landing pad and catches a thrown
`bool`. The version with the record omits the NOP and terminates with an
uncaught exception.
This reproduces with an assertions-enabled LLVM 24.0.0git build at revision
`2e3d50b4111f324fb615c3c18d02189caa1ef62d` on x86-64 Linux.
## Reproducer
The following five files are attached. The IR files have a final `.txt`
suffix only because GitHub does not accept `.ll` uploads:
[cluster.txt](https://github.com/user-attachments/files/31595026/cluster.txt)
[reproduce.sh](https://github.com/user-attachments/files/31595025/reproduce.sh)
[runtime-driver.cpp](https://github.com/user-attachments/files/31595029/runtime-driver.cpp)
[with-dbg-value.ll.txt](https://github.com/user-attachments/files/31595028/with-dbg-value.ll.txt)
[without-dbg-value.ll.txt](https://github.com/user-attachments/files/31595027/without-dbg-value.ll.txt)
The cluster file is a valid version-1 Basic Block Sections profile. Both IR
variants use exactly the same profile, and all referenced basic-block IDs are
present in the generated MachineFunction.
Run:
```sh
bash reproduce.sh
```
The script verifies both IR modules with `llvm-as` and
`opt -passes=verify`, enables `-verify-machineinstrs`, compiles both
modules, and runs them.
## Actual behavior
```text
without #dbg_value: NOOP=1 status=0
with #dbg_value: NOOP=0 status=134
terminate called after throwing an instance of 'bool'
```
Immediately before `bbsections-prepare`, the ordinary Machine IR is identical
between the two cases. The additional `#dbg_value` lowers to a `DBG_VALUE` in
a block with no ordinary machine instructions. After the pass, the ordinary
Machine IR differs by the single landing-pad `NOOP` shown above. The runtime
result was stable across 20 runs of each executable.
## Cause
`avoidZeroOffsetLandingPad()` in
`llvm/lib/CodeGen/BasicBlockSections.cpp` uses raw block emptiness when finding
the first non-empty block in each section:
```cpp
MBB.empty() || MBB.getSectionID() == CurrentSection
```
The `DBG_VALUE` makes `MBB.empty()` false even though the block has no ordinary
instructions. This updates `CurrentSection` before the landing pad is visited,
so the landing pad is no longer treated as the first non-empty block in its
section and the NOP is omitted.
## Expected behavior
Debug-only instructions should not affect this decision. Both modules should
insert the landing-pad NOP and catch the exception successfully.
## Scope
The reproducer was reduced from LLVM's upstream
`llvm/test/CodeGen/X86/basic-block-sections-eh.ll` test. A natural C/C++
frontend input producing this exact debug-only block shape is not currently
known.
Contributor guide
Research direction
Start by running bash reproduce.sh and reading llvm/lib/CodeGen/BasicBlockSections.cpp, especially avoidZeroOffsetLandingPad(). Compare the attached IR variants and the upstream llvm/test/CodeGen/X86/basic-block-sections-eh.ll test. Done means debug-only instructions no longer change the landing-pad decision, both variants insert the NOP, and the exception is caught successfully.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100