llvm / llvm/llvm-project

[Hexagon] Debug instructions count toward the load-widening block-size limit

Open
#221,634 5 comments 0 reactions 0 assignees View on GitHub
backend:Hexagon
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.