magetypes: no lane-broadcast or lane-shift (blocks porting Highway kernels op-for-op)
@lilith is already working on this.
Since Sep 10, 2026.
- Dominant language
- Rust
- Stars
- 12
- Forks
- 2
- Avg merge
- 13h 55m
- Merged PRs (30d)
- 28
Description
## What's missing
`magetypes::simd::generic::f32x4` / `f32x8` expose no equivalent of Highway's:
- **`Broadcast(v)`** — splat lane `N` across the vector (`vdupq_laneq_f32` on
NEON, `vpermilps`/`vbroadcastss` on x86, `i32x4.shuffle` on wasm)
- **`ShiftLeftLanes(v)`** — shift lanes toward higher indices, zero-filling
(`vextq_f32` against a zero vector on NEON, `vpslldq` on x86)
The f32x4 surface today has `interleave_lo/hi`, `transpose_4x4`, `blend`,
`reduce_*`, but nothing that selects or shifts *lanes* by a compile-time index.
## Why it matters (concrete case)
I was porting jpegli/libjxl's `FastGaussian1D` — the horizontal recursive
Gaussian that SSIMULACRA2 uses — into fast-ssim2, to check whether its form is
faster than ours (it is: 12-14% on NEON). The C++ inner loop is built out of
exactly these two ops:
```cpp
const V in1 = Broadcast<1>(sum);
out_1 = MulAdd(ShiftLeftLanes<1>(mul_in_1), in1, out_1);
```
With `magetypes` the only way to express that is `to_array()` + `splat()`, which
round-trips through memory and measures the emulation rather than the algorithm.
I got around it for this kernel — the shifted coefficient vectors are
loop-invariant, so they can be precomputed as constants, and each input can be
splatted from a scalar load instead of broadcast out of a vector — but that
dodge is specific to this shape. Any kernel that broadcasts a *computed* lane
(this one also carries its IIR state out of lanes 2 and 3 of the previous
result) has nowhere to go.
## Suggested shape
```rust
impl f32x4 {
pub fn broadcast_lane(self) -> Self;
pub fn shift_left_lanes(self) -> Self; // zero-fill
}
```
matching the existing `shr_arithmetic_const::` convention on the integer
types. Same for `f32x8` / `f32x16` (Highway's `Broadcast` is per-128-bit-block;
worth deciding explicitly whether ours is block-wise or whole-vector, since
that's a portability trap either way).
## Not a complaint about priorities
`magetypes` covered everything else this port needed — `bitcast_to_i32`,
`shr_arithmetic_const::<23>`, integer multiply, `blend`, `simd_eq` — which is
how the cube-root half went in cleanly. This is one gap, found by trying to
transliterate someone else's SIMD kernel op-for-op, which is a slightly unusual
thing to ask of a portable-SIMD layer.
Context and measurements: imazen/fast-ssim2 `benchmarks/cbrt_perf_2026-09-09.md`
and `benchmarks/blur_stride_2026-09-09.md`.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.