llvm / llvm/llvm-project

[X86] Constant-fold `vcvtps2ph` when the observed lane is compile-time constant

Open
#215,070 7 comments 0 reactions 1 assignee Claimed by @ParkHanbum View on GitHub
backend:X86 constant-folding missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Summary

LLVM IR currently retains an exact constant F16C conversion followed by a
direct lane-zero extraction:

```llvm
%packed = call <8 x i16> @llvm.x86.vcvtps2ph.128(
<4 x float> , i32 0)
%lane0 = extractelement <8 x i16> %packed, i64 0
ret i16 %lane0
```

For this fixed input and immediate, the observed lane is the binary16 bit
pattern for `1.0`, `0x3c00` (`i16 15360`). The expected result is:

```llvm
ret i16 15360
```

The current `default` planning replay leaves the intrinsic and extract in
place.

## Corpus evidence

An ONNX Runtime x86-64-v4 optimized module contains:

- 32 exact `vcvtps2ph.128` calls with the constant vector
`<1.0, 0.0, 0.0, 0.0>` and immediate zero.
- 8 direct lane-zero `i16` consumers matching this issue's narrow relation.
- The representative current-O3 form retains both the intrinsic and
`extractelement`.

The packet deliberately excludes full-vector/bitcast consumers, other
constants, other lanes, other immediates, masked forms, dynamic inputs, and
constrained-FP cases.

## Relevant prior work

[LLVM PR #162295](https://github.com/llvm/llvm-project/pull/162295),
`[X86][Clang] Allow constexpr evaluation of F16C CVTPS2PH intrinsics`, adds
constexpr handling for the 128-bit and 256-bit Clang F16C builtins. The change
is useful precedent but is not an LLVM IR optimization patch.

The PR's implementation establishes the relevant semantic shape:

- the builtin is marked `Constexpr`;
- the interpreter converts each source element with `APFloat::convert`;
- immediate bits 0-1 select nearest, toward-negative, toward-positive, or
toward-zero rounding;
- immediate bit 2 selects MXCSR rounding behavior;
- constrained floating-point evaluation with MXCSR rounding is accepted only
when the conversion is exact;
- wider destination vectors are zero-filled in the remaining lanes;
- Clang tests cover constant vector results and rounding cases.

This suggests that an IR-level constant folder or target-intrinsic simplifier
could use an equivalent, well-defined semantic path for fully constant inputs,
subject to the same immediate and constrained-FP restrictions.

## Performance impact

The exact minimized source/target pair passes the x86-64-v4 CostGate:

| Metric | Source | Proposed | Change |
|---|---:|---:|---:|
| body instructions per iteration | 7 | 5 | -2 |
| LLVM-MCA uOps / 100 iterations | 1300 | 1000 | -300 |
| LLVM-MCA cycles / 100 iterations | 263 | 209 | -54 |
| block reciprocal throughput | 2.2 | 1.7 | -0.5 |
| `.text` bytes | 24 | 10 | -14 |
| read-only constant bytes | 4 | 0 | -4 |
| total counted object-section bytes | 28 | 10 | -18 |

The source emits a constant-pool load, `vcvtps2ph`, and a vector-to-GPR
transfer. The proposed form is one immediate `movw`.

These are static x86-64-v4 code-generation and llvm-mca results, not an
application-level benchmark.

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.