[Hexagon] Debug instructions count toward the load-widening block-size limit
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Hexagon load widening uses the raw number of `MachineInstr`s in a block as a
compile-time guard. As a result, debug-only instructions can push an otherwise
identical block over the limit and disable widening.
A compact C reproducer places an aligned adjacent-load pair in a block with
exactly 1000 ordinary machine instructions. Compiling the same source with
`-g` adds eight `DBG_VALUE`s without changing the ordinary pre-pass Machine IR.
The two builds then produce different ordinary Hexagon assembly.
This was reproduced with an assertions-enabled LLVM 24.0.0git build at
revision `502e51aa4df687807fbe51fa0b419baf65e9615f` on x86-64 Linux.
## Reproducer
Attach these two files individually:
- `source-trigger.c`
- `reproduce.sh`
[reproduce.sh](https://github.com/user-attachments/files/31897269/reproduce.sh)
[source-trigger.c](https://github.com/user-attachments/files/31897270/source-trigger.c)
Run:
```bash
bash reproduce.sh
```
Observed output:
```text
-g0: memd=1 memw=1
-g: memd=0 memw=3
```
The `-g0` build combines the two 32-bit loads into one `memd`. The `-g` build
leaves them as two `memw` loads; both builds also contain the same `memw`
store. Both inputs pass `-verify-machineinstrs`.
## Cause
`HexagonLoadStoreWidening::processBasicBlock()` contains this compile-time
guard:
```cpp
if (MBB.size() > MaxMBBSizeForLoadStoreWidening)
return false;
```
`MachineBasicBlock::size()` includes debug instructions. The baseline block
has raw size 1000 and is processed, while the debug block has raw size 1008 and
is skipped. Immediately before `hexagon-widen-loads`, their ordinary Machine
IR projections are identical.
A bounded padding check localizes the threshold: nearby cases diverge only
when the debug records place one variant above the limit, and reconverge once
both variants exceed it.
## Possible fix
LLVM already provides the matching budget predicate:
```cpp
if (MBB.sizeWithoutDebugLargerThan(MaxMBBSizeForLoadStoreWidening))
return false;
```
With this change, both source variants emit `memd=1 memw=1`. A compact MIR
regression adds one `DBG_VALUE` to a block with eight ordinary instructions.
At a limit of 8 it verifies that widening still occurs; at a limit of 7 it
verifies that the ordinary-instruction limit is still enforced.
## Expected behavior and scope
Debug-only instructions should not affect this optimization's block-size
budget. The `-g0` and `-g` builds should make the same widening decision.
This is a deterministic code-quality difference from a natural C input. Both
compilations succeed, and no wrong-code or runtime failure is claimed.
Contributor guide
Research direction
Start at HexagonLoadStoreWidening::processBasicBlock() and inspect the existing block-size guard, then review the compact MIR regression described in the issue. Run reproduce.sh with and without -g to confirm the differing widening decisions. Done means debug instructions no longer change the budget and the regression still enforces the ordinary-instruction limit at both thresholds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bash, c, cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100