chore(pasta): add fused x86-64 assembly lazy-squaring chains - #239
Draft
TalDerei wants to merge 6 commits into
Draft
chore(pasta): add fused x86-64 assembly lazy-squaring chains#239TalDerei wants to merge 6 commits into
TalDerei wants to merge 6 commits into
Conversation
A transcription of the aarch64-asm backend's five-limb CIOS rounds into one inline asm! block using MULX with dual ADCX/ADOX carry chains, exploiting the shared Pasta modulus shape (p[2] = 0, p[3] = 2^62) so a single routine serves Fp and Fq. Operand limbs are addressed through readonly pointers rather than pinned registers (twelve pinned limbs plus staging temporaries exceed x86-64's allocatable set); squaring routes through the multiplication (measured on Apple silicon and Skylake-X, a dedicated squaring block does not beat it). The sqr_n_mul fallback now routes through the runtime dispatchers so chains square and multiply in assembly on backends without a fused chain. Measured on i9-7960X (Skylake-X): Fp mul 25.96 -> 21.01 ns (-19.8%), Fq mul 20.46 ns; square unchanged. Differential tests: 100k random canonical pairs per field against the portable path, 100k unreduced-lhs near-modulus stress per field, edge matrices, and debug canonicity panics; full 200-test suite green with multicore,orbits,x86_64-asm. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fp/fq benches' square cell called the inherent (always-portable) Fp::square, which shadows Field::square, the runtime-dispatched production path — so the cell measured the portable squaring even under the assembly features. That artifact mis-sized an assembly squaring decision twice: it made the AArch64 inline squaring look no better than portable (it is in fact 5-6% faster than the assembly multiplication; a square-through-mul routing proposed on the bad reading was correctly rejected by measurement on M4 Max), and it made the x86-64 backend's mul-routed squaring look like a wash (with the fixed cell it measures 21.94 -> 20.97 ns, ~1.05x over portable). The cell now calls the trait method explicitly; the x86_64_asm module docs and changelog now state the corrected picture, with a dedicated x86-64 assembly squaring noted as measured headroom. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Transcribes the AArch64 backend's squaring into the x86-64 backend: the 512-bit square as cross products, one doubling pass, and the diagonals (ten MULX against the multiplication's sixteen), four two-sweep Montgomery cancellations on a rotating window (the consumed input pointer's register is reclaimed as the carried fifth limb), the high half folded in under the below-2p bound, and a CMOV conditional subtraction. Measured 2-5% ahead of squaring through the multiplication on Skylake-X (20.0-20.7 vs 21.0 ns across runs), mirroring the AArch64 backend's own square-over-mul margin. Two slower schedulings are pinned in the module docs so they are not retried on this microarchitecture family: squaring routed through the multiplication, and a merged interleaved-ADCX/ADOX Montgomery reduction (staged q*p operands, TEST-cleared dual chains) that measured ~10% slower than the two short sequential sweeps (22.3 vs 20.2 ns) despite the shorter nominal dependency length. Differential tests (100k random canonical squares per field against the portable path, plus edge matrices) and the full suite pass in release and debug under multicore,orbits,x86_64-asm. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Correct the x86_64_asm module's canonicity contract: only the canonical-rhs/canonical-input preconditions are debug-asserted; the unreduced-lhs limb bound is not (and cannot be), no current caller passes an unreduced lhs, and the differential tests pin the allowance. - Drop the stale "(squaring routes through it)" changelog parenthetical that contradicted the dedicated-squaring text in the same entry. - Note in sqr_n_mul_runtime's doc that only the AArch64 backend fuses the chain, and note in CI that the pasta --all-features lanes execute the x86-64 assembly and therefore require ADX/BMI2 runners. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pasta: add fused x86 assembly lazy-squaring chains
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on #222 which already contains single-operation x86 assembly square; the new candidate adds a separate fused assembly loop for whole lazy-squaring chain (the portable rust version was implemented in #218).
Makes squaring chains 0.4–4.1% faster and hash-to-curve 0.4–0.5% faster than #222.