Gate record — M4: Tier A AVX2 → v0.2¶
Date: 2026-07-03 · Milestone: M4 (PRD 18 §M4) · Decision: PASS (two evidence items deferred for hardware availability, §7; one PRD amendment proposed, §8).
1. Objective¶
First explicit-SIMD tier: AVX2 backends for all six Tier A families, differential + fuzz machinery proving cross-backend equality, equal-ISA autovec baselines live, fuzz-smoke CI enforced (REQ-CI-005), K5 gather decision recorded.
2. Files created / modified¶
Created: src/kernels/{compare,filter,select,mask,take,reduce}/<f>_avx2.cpp ×6;
tests/fuzz/fuzz_common.h + fuzz_<f>.cpp ×6 + corpus/<f>/ seeds (3 committed seeds per
family + 2 crash-regression inputs + 1 empty-input seed); tests/regression/reg_empty_selvec.cpp
(suite activation, REQ-TEST-011); bench/baselines/baseline_avx2.{h,cpp};
docs/internals/kernel-common.md; docs/testing/fuzzing.md;
docs/investigations/k5-gather-avx2.md; docs/releases/v0.2.0.md; this record.
Modified: src/dispatch/dispatch_tables.cpp (AVX2 backend declarations via the X-macro
list; row slot [2] = &avx2::name on x86-64); src/cpu/cpu_features.{h,cpp} (avx2 tier =
AVX2 and BMI2, leaf 7 EBX bit 8); include/quiver/core.h (+detail::nonnull_sel,
§8-D3); include/quiver/{take,reduce}.h (empty-SelVec disambiguation);
tests/testkit/reference.h (+sum_blocked_expected policy oracle);
tests/differential/diff_isa_reduce.cpp (ISA-aware float-sum expectations; NaN-class rule);
tests/property/prop_take.cpp (output capacity fix, §6-F2); tests/CMakeLists.txt (fuzz
targets + regression suite); CMakeLists.txt + CMakePresets.json (AVX2 TUs, fuzz
preset, QUIVER_ENABLE_FUZZERS); bench/CMakeLists.txt + bench/micro/bench_*.cpp ×6
(baselines lib; autovec-avx2 variants; policy-aware f64 sum validation);
.github/workflows/ci.yml (fuzz-smoke enforced) + nightly.yml (4 h fuzz leg);
.github/scripts/repo_lint.py (intrinsic-header allowance for per-ISA TUs) +
.github/repo-manifest.json (state M4); docs/api/*.md ×6 (per-ISA notes);
docs/internals/cpu-detection.md; docs/testing/README.md; CHANGELOG.md.
3. Requirements satisfied¶
- REQ-SIMD-001..003, -005 — per-ISA TUs under target regions (
"avx2,bmi2"), scalar tails (ADR-015), sanitizer-clean masked handling, shared compaction LUTs. - REQ-SIMD-007 — unaligned intrinsics/
memcpyonly (aligned-only intrinsics removed during review of this milestone's own code). - REQ-TEST-004 — testkit blocked-sum policy oracle parameterized
{w, a}per backend; differential float-sum expectations select the active backend's documented policy. - REQ-TEST-007 — six differential libFuzzer targets, contract-valid decoding, cross-backend equality under ASan+UBSan (library instrumented, not just harness); committed corpora.
- REQ-TEST-009 — sanitizer matrix: ASan+UBSan and TSan on PR, MSan+LSan nightly (existing legs now exercising the AVX2 tier on x86 runners).
- REQ-TEST-011 — regression suite activated by its first defect fix (§6-F1).
- REQ-BENCH-010 —
autovec-avx2variant set produced by recompiling the pure references under the AVX2 target region (ODR-safe private-namespace instantiation). - REQ-BENCH-006 — variant names derive from
active_isa()(verified-by-construction); forced execution via theQUIVER_ISAenv cap. Theset_isa_override-driven runner loop is M5 scope (runner integration; PRD 10 §7 sets baseline-variant completion "by M5"). - REQ-KERNEL-007 / REQ-K5-004 — both K5 paths compiled; decision recorded (§7-D1).
- REQ-CI-005 — fuzz-smoke enforced ≥ 30 s/family on PR; nightly ≥ 4 h total with minimization + artifact upload (see §8-A2 for the REQ-TEST-007 conflict).
- REQ-DISP-004 (maintenance) — avx2 tier tightened to AVX2+BMI2 to match the target
region's instruction set (the AVX2 kernels emit
PDEP/PEXT).
4. ADRs realized¶
- ADR-003 — per-ISA TU + target-region pragmas in production use (6 TUs; MSVC
per-source
/arch:AVX2; non-x86 builds compile the TUs empty). - ADR-011 — equal-ISA autovec baselines live for all six benched entry points.
- ADR-013 — AVX2 blocked float-sum policy implemented with the frozen combine order
(0+2),(1+3), then +(a first draft used(0+1)+(2+3)and was corrected against the ADR text during this milestone — caught by re-reading the ADR, §8-D2). - ADR-015/ADR-016/ADR-023/ADR-025 exercised by the new backends (tails, tail-zeroing, exact-alias in-place compaction, contract-valid fuzz generation).
5. Tests / benchmarks / docs added¶
Tests: 6 fuzz targets (+ shared decoder header), 1 regression suite (3 tests), policy
oracle + ISA-aware expectations in the differential suite. All 72 ctest targets green
natively (ARM64 scalar) and in the x86-64 container (scalar + AVX2 exercised; the
differential/invariant/guard-page suites iterate both tiers via set_isa_override).
Benchmarks: autovec-avx2 variants across the six family benches; policy-aware f64 sum
validation. Docs: per-ISA notes ×6, kernel-common.md, fuzzing.md, K5 investigation
page, cpu-detection update, CHANGELOG 0.2.0.
6. Defects found and fixed during this milestone (differential fuzzing, first session)¶
- F1 — empty-SelVec façade defect (library bug, severity high).
SelVec{nullptr, 0}— the natural value fromstd::vector::data()on an empty vector — was forwarded into the K5/K6 concrete symbols, whose internal convention readssel == nullptras "no selection" (dense). An empty selection therefore silently processed all n elements: heap-buffer overflow in fuseddict_decode(ASan, fuzz artifact committed ascorpus/take/crash-empty-selvec-fused), wrong values from selected reductions. Fixed in the façades viadetail::nonnull_sel(empty selection maps to a non-null sentinel); regression-tested inreg_empty_selvec.cppacross all host backends. K2/K3 selvec forms were already correct (no null branch). - F2 — test under-allocation (test bug).
prop_take.cppgave the bitmap-drivenfilteran output sizedcount+1; the contract requires an n-element capacity region (REQ-MEM-008). Invisible under the scalar backend (touches ≤ count+1), exposed by AVX2 full-vector stores. The guard-page suite — which allocates exact capacity regions — passes unchanged, confirming the kernels honor the documented bound. - F3 — fuzz-harness UB (harness bug).
memcmpwith a null pointer and zero size infuzz_filter.cpp(UBSan). Guarded.
7. Checks: passed / failed / deferred¶
Passed: cmake --preset dev + build + ctest (72/72 native ARM64, 1 skip by design);
x86-64 container (ubuntu:24.04, gcc-13, RelWithDebInfo+asserts): full ctest green with AVX2
active + 25 s/family fuzz runs clean after fixes (first runs found §6); clang++
-fsyntax-only -arch x86_64 -Wall -Wextra -Wpedantic on all new TUs;
python3 .github/scripts/repo_lint.py; mkdocs build --strict; clang-format (pinned
18.1.8).
Deferred:
- D1 — K5 gather-vs-scalar AVX2 evidence (M4 acceptance line). No registered x86
machine exists (only an Apple M-series host; emulated timing is not evidence — Charter
T2, "no invented performance data"). Default = scalar MLP loads held by the Survey §4.2
prior; both paths compiled; protocol + pre-registered decision rule + reopening criteria
in docs/investigations/k5-gather-avx2.md. To be discharged on the first registered x86
machine (M5 ledger work or later).
- D2 — selectivity-flatness evidence for K1/K2/K3 on AVX2 (M4 benchmark line): same
hardware limitation; the bench axes exist and run (bench-smoke), numbers await registered
hardware. (Scalar/NEON flatness on the M-series host is M5 ledger scope.)
- CI matrix legs, tidy, SDE, MSVC: GitHub-side, discharged by the PR checks (recorded in
the PR).
Failed: none outstanding.
8. Ambiguities and deviations¶
- A1 (ambiguity, resolved by owning chapter): PR fuzz budget. REQ-TEST-007 says "PR smoke ≥ 5 min/family batched"; REQ-CI-005 says "each family target runs ≥ 30 s on PR". Implemented REQ-CI-005 (chapter 13 owns CI budgets). Proposed smallest amendment: REQ-TEST-007 → "PR smoke per REQ-CI-005; nightly ≥ 4 h total".
- A2 (spec gap found by fuzzing, amendment proposed): NaN float-sum payloads are not
oracle-reproducible. ADR-013's consequence claims "an exact float oracle"; PRD 08 §3.3
rule 4 requires sums "bit-identical per (version, ISA)". With NaN participants, IEEE
addition returns the payload of whichever operand the hardware sees first, and C++ does
not pin FP operand order — so payloads are deterministic per (version, ISA, build) but
cannot be reproduced by any independently compiled oracle (fuzz artifact
corpus/reduce/crash-nan-payload-sum). Implemented: oracle comparisons treat NaN sums as an equivalence class (both-NaN ⇒ match); run-to-run determinism remains covered byinv_determinism. Proposed smallest amendment: PRD 08 §3.3 rule 4 + ADR-013 consequence: append "NaN sum results are NaN of unspecified payload; test oracles compare NaN results as a class. (Min/max stay payload-normalized via canonical qNaN.)" No kernel behavior change. - D1 (technique deviation, documented): K2 8/16-bit compaction uses BMI2
PDEP/PEXTinstead of the PRD 08 sketch'spshufbnibble tables — same outputs, simpler, exact; Zen 1/2 microcoded-PEXTcaveat recorded for the ledger. Consequence: avx2 tier requires BMI2 (detection tightened; documented). - D2 (self-corrected during milestone): first draft of the AVX2/oracle float-sum
combine used
(0+1)+(2+3); ADR-013 freezes(0+2),(1+3), then +. Corrected in backend, oracle, and bench recompute before merge. - D3 (façade semantics clarified): the concrete-symbol convention "sel == nullptr ⇒
dense" now coexists with the public rule "SelVec{nullptr, 0} ⇒ empty selection" via
detail::nonnull_sel(§6-F1). PRD 04 API contracts already imply the public rule (K5-003: "writes sel.len packed elements"); no PRD text change required. - D4 (mechanism note): REQ-BENCH-010's "recompile under target regions" is implemented
with the ADR-003 pragmas plus a private-namespace re-instantiation of the reference
headers — required to keep the baseline TU's template instantiations ODR-disjoint from
libquiver's scalar ones (otherwise the linker may silently unify them in either
direction, corrupting one variant or the other). Same outcome, documented in
baseline_avx2.cpp.
9. Scope exclusions¶
No NEON (M5), no AVX-512 (M7), no Tier B families (M6), no ledger results or published
numbers (v0.3+), no runner integration (M5), no packaging (M8). QUIVER_PIN_ISA
consumption legs remain M8 (REQ-CI-008).
10. Documentation rationale / debt¶
Per-ISA notes document technique + exactness arguments per family, in ledger-compatible
language (wins and losses will attach at M5). Debt: the K5 investigation page holds an open
decision (by design, evidence-gated); family "Ledger" sections remain "Pending v0.3";
docs/benchmarks/methodology.md gains the autovec-avx2 variant description at M5 when the
runner formalizes forced-variant execution.
11. Final gate decision¶
PASS. All M4 code, test, CI, and doc deliverables are implemented and validated on both architectures (AVX2 exercised in the x86-64 container across differential, invariant, guard-page, regression, and fuzz suites). Two evidence items (§7-D1/D2) are hardware-gated deferrals with pre-registered protocols, not weakened requirements. Release v0.2.0 tags on merge (Gate+ per PRD 18).