llvm / llvm/llvm-project

[RISCV] RV64 missed optimization? Narrow `trunc(load i64)` to `lbu`

Open
#208,549 4 comments 0 reactions 1 assignee Claimed by @topperc View on GitHub
backend:RISC-V generated by fuzzer missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Summary

For a non-volatile, non-atomic `load i64, align 1` whose only demanded result
is `trunc ... to i8`, RV64 lowering reconstructs the entire unaligned i64 from
eight byte loads and shift/or operations. On little-endian RV64, the requested
result is simply the first byte, so it appears that the backend could emit one
`lbu` instead.

This report asks whether the RV64 behavior is an intended fault/legality
constraint or a missed RISC-V backend combine. It does not claim a correctness
bug.

## Reduced IR

```llvm
target triple = "riscv64-unknown-linux-gnu"

define i8 @decode(ptr %p) {
entry:
%w = load i64, ptr %p, align 1
%r = trunc i64 %w to i8
ret i8 %r
}
```

## Observed RV64 Assembly

`rocket-rv64` emits eight `lbu` instructions and reconstructs the complete
i64 with shifts and ors before returning it. The reduced output is 23
instructions including `ret`.

```asm
lbu a1, 0(a0)
lbu a2, 1(a0)
lbu a3, 2(a0)
lbu a4, 3(a0)
... # remaining bytes and reconstruction
ret
```
It lowers to:

```asm
lbu a0, 0(a0)
ret
```

## Cross-Target Evidence

- x86-64 lowers the current O2 IR to one `movzbl` load.
- AArch64 lowers it to one `ldrb` load.
- RISC-V RV32 also lowers the same current O2 IR to one `lbu` load.
- Only RV64 `rocket-rv64` expands the current form into the bytewise i64
reconstruction.

## Cost Evidence

`llvm-mca --iterations=100` for `rocket-rv64` reports:

| Form | Instructions | Total cycles | Total uOps | Block RThroughput |
|---|---:|---:|---:|---:|
| Current RV64 output | 2300 | 2501 | 2300 | 23.0 |
| Equivalent `load i8` form | 200 | 301 | 200 | 2.0 |

## Question

Is the RV64 expansion required by an intended RISC-V lowering or fault-semantics
constraint? If not, could RV64 recognize the demanded low byte before
legalizing/splitting the unaligned i64 load, analogous to the code generated
for RV32 and the other tested targets?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.