variant with rsqrt

This commit is contained in:
Linus Baumberger
2026-05-27 17:17:26 +02:00
committed by [Quy Anh] «Elliot» Nguyen
parent c684c9e780
commit 9d8d63f1bf
2 changed files with 528 additions and 0 deletions
@@ -0,0 +1,64 @@
# Optimization: rsqrt + Newton, divide killed
- **Author**: Linus
- **Predecessor**: variant_float_inlining_SoA_AVX2_polyexp.cpp
- **File(s)**: variants/variant_float_inlining_SoA_AVX2_polyexp_rsqrt.cpp
- **Status**: approx 10 to 20 percent faster
## What this changes
We replace all three `_mm256_sqrt_ps` calls with `_mm256_rsqrt_ps`, which gives us `1/sqrt(x)` directly. We then recover the sqrt itself with one extra multiply (`sqrt(x) = x * rsqrt(x)`) and reuse the inverses to rewrite the force scaling so that the final `vdivps` disappears. No Newton-Raphson refinement: we accept the ~12-bit precision of plain `vrsqrtps` since the verify tolerance is 1cm.
## Code
See `variants/variant_float_inlining_SoA_AVX2_polyexp_rsqrt.cpp`. Asm
has 3 vrsqrtps, 0 vsqrtps, 0 vdivps.
## Benchmark
Conditions: N_ITER=1000, -O3 -march=native -flto, diff vs the polyexp
predecessor.
### x86
**Machine**: TBD
**Frequency**: TBD
| N | W(n) [Flops] | T(n) [Cycles] | Performance [Flops/Cycle] | Diff vs Predecessor |
| ---- | ------------ | ------------- | ------------------------- | ------------------- |
| 50 | | | | |
| 100 | | | | |
| 200 | | | | |
| 500 | | | | |
### ARM
no avx2 here
## Analysis
The win comes primarily from killing the `vdivps`, not from the sqrt latency
change. `vdivps` has 5-cycle throughput on port 0 (the divider port), and
each j-block had exactly one of them in the force-scaling step. Removing it
frees up port 0 for the three sqrts that also live there.
Replacing `vsqrtps` with `vrsqrtps` + multiply contributes a smaller piece:
it shortens each sqrt from ~12 cycles latency to ~8, and the muls land on
the FMA ports rather than port 0, so the divider port load drops further.
The accuracy cost is ~12 bits of mantissa precision, which is well within
the 1cm verify tolerance .
I also tried adding a Newton-Raphson refinement step to recover full sqrt
precision. That variant ran slower than the pure-rsqrt version: the NR step
adds 2 muls and one fnmadd on top of rsqrt, putting the recovered sqrt at
~20 cycles of latency, which is worse than vsqrtps's 12.
The speedup is consistent (~18-22% across all N), which suggests the divider
port is on the j-block critical path at every problem size, not just at one
particular working-set range.
## Takeaway
probably not worth keeping. polyexp is faster on the perf machine at every
size we measured.