Conversation
The per-term acc += c*val - b loop paid a full QM31 multiply + reduce + add-min per packed element. Accumulate the exact 62-bit M31 products in i64x8 lanes instead (even/odd transmute splits, the same primitive mul_doubled_simd uses), with a lazy signed Mersenne-31 fold every 2 terms (arithmetic shift keeps the sign; exact for any signed x) and one exact signed reduction per chunk per coordinate. The per-term b subtraction is hoisted to one scalar sum per chunk. All portable std::simd: no cfg/target_feature/std::arch. Bit-exact: products are exact in 64-bit lanes, folds are exact mod P, and the final reduction equals the per-term reductions by associativity. Measured (Apple Silicon, 8 rayon threads, release, isolated paired A/B at 100 cols x 2^20, blowup 1): 20.5-21.2 -> 10.3-11.7 ms medians (~1.9-2.0x on the stage). CPU-consistency test passes unchanged; 267/267 suite, both feature configs; clippy -D warnings and fmt clean.
PR SummaryMedium Risk Overview The new Behavior is intended to remain bit-exact versus the prior SIMD loop (same algebra, deferred reduction); existing SIMD vs CPU consistency tests are unchanged. Reviewed by Cursor Bugbot for commit 903ca8a. Bugbot is set up for automated code reviews on this repo. Configure here. |
|
The |
|
Withdrawing for the time being — the author needs to run an internal review before this is considered for submission. Will resubmit (or a maintainer can pick the idea up) after that review. Thanks for the CI run. |
What
crates/stwo/src/prover/backend/simd/quotients.rs,accumulate_numerators_on_subdomain: the per-termacc += c*val - bloop paid a full QM31 multiply + reduce + add-min per packed element per term. This PR accumulates the exact 62-bit M31 products ini64x8lanes and reduces once per 64-element chunk instead of per term (deferred reduction / lazy-accumulator style), and hoists the per-termbsubtraction to one scalar sum per chunk.Mechanics: even/odd transmute splits of each packed
u32x16intou64x8products (the same primitivemul_doubled_simduses); a lazy signed Mersenne-31 foldx mod P = (x >> 31) + (x & (2^31-1))every 2 terms — exact for signed values with arithmetic shift — keeps accumulators below2^63; one exact signed final reduction per chunk per coordinate. All portablestd::simd: nocfg, notarget_feature, nostd::arch.Why
Measured on the stage (100 columns × 2^20, blowup 1, Apple Silicon, 8 rayon threads,
--release, isolated paired A/B): 20.5–21.2 → 10.3–11.7 ms medians (~1.9–2.0x).Bit-exactness
< 2^62→ exact ini64lanes; signed two's-complement accumulators handle subtraction terms.test_simd_and_cpu_numerators_are_consistentpasses unchanged; full suite 267/267 with and without theparallelfeature; clippy-D warningsand fmt clean.Scope
Applies to independent-term accumulation sums (this loop; numerator accumulation generally). It does not apply to dependency chains (butterflies, fold chains, batch-inversion prefix/suffix products). Developed while profiling the quotient path; the same structure can serve future accumulation-heavy kernels.