CratonVM
JIT round 10, lane intr — proposals
Findings from a read-only-plus-doc-fix audit of the intrinsic catalogue,
direct-helper table, and SIMD emission owned by this lane
(jit/src/intrinsic_catalogue.rs, jit/src/runtime_lowering.rs,
jit/src/direct_helpers.rs, jit/src/x64/simd.rs,
jit/src/x64/simd_analysis.rs, jit/src/x64/vec_emit.rs,
jit/src/x64/cpu_features.rs). Two directions worth doing on a future round;
neither is a bug fix, both are net-new mechanism.
1. Retire or finish JitIntrinsic::ScopedMemoryGet*Unaligned
What: four enum variants (ScopedMemoryGetShortUnaligned /
GetCharUnaligned / GetIntUnaligned / GetLongUnaligned) have existed since
this file's SCOPED_MEMORY_UNALIGNED region was written, are never registered
by any matcher, and have no emitter arm — see
docs/known-issues/jit/r10-intr-scoped-memory-unaligned-dead-variants-20260920.md
for the full trace. The feature they were meant to provide is already served,
completely separately, by direct_helpers::ScopedMemoryOp +
DirectHelperTable.
Mechanism to retire them: a lane that owns intrinsic_catalogue.rs alone
for a full round (no concurrent editor of files matching on JitIntrinsic
variants) deletes the four variants and their region markers, runs a full
build, and confirms nothing outside this file named them (this audit found
none, but a build is the only real confirmation). Cost: near zero — the
variant set shift is safe because every consumer recomputes .as_entry() from
the enum rather than hard-coding a discriminant, per the type's own
documented invariant.
Mechanism to finish them instead: would duplicate
direct_helpers::ScopedMemoryOp, which already has the ABI checklist
(DIRECT_HELPER_FN_SIGS, the win64/sysv stack-argument census, the
hand-written vs. marshalled path distinction) this new work would need to
rebuild from scratch. Not recommended — there is no benefit to a second
mechanism for the same four JDK methods, and the Put* half was never even
started on this side, so "finishing" is actually "building the majority of a
new feature."
Recommendation: retire. Low cost, removes stale enum surface, and the
known-issues page this round leaves behind gives the next lane the exact
diff to make.
2. Wire VecPlan/emit_vector_loop into x64.rs, with an AVX-vs-AVX2 split
What: jit/src/x64/simd_analysis.rs's admit_vectorization gate and
jit/src/x64/vec_emit.rs's emit_vector_loop are a complete, well-tested
general loop-vectorization pipeline — guards, alignment, tail strategy,
register-pool allocation, a reduction epilogue — that nothing calls yet
(emit_vector_loop's own doc: "deliberately not wired into x64.rs: the call
site is added separately"). The production SIMD path today
(jit/src/x64/simd.rs) is a much narrower hand-written set of whole-loop
replacements (int-array sum, element-wise, matrix dot, bulk byte fill/sieve),
each recognising one exact bytecode shape.
Gap found in the unwired pipeline that the wiring lane should close as it
goes: VectorIsa::detect() offers sse41()/sse2() (128-bit) targets when
the host lacks AVX2, but emit_vector_loop refuses unconditionally without
AVX2 (HostVectorSupport only tracks one bit). Every encoding
emit_vector_loop writes today is VEX; 128-bit VEX-encoded integer
instructions (VPADDD xmm, VMOVDQU xmm, etc.) are legitimately AVX
instructions — they do not need AVX2, only the 256-bit (VEX.256) integer
forms do. See
docs/known-issues/jit/r10-intr-vecplan-non-avx2-isa-branch-is-unreachable-20260920.md.
Mechanism:
- Add
has_avx()tocpu_features.rs(CPUID.1:ECX bit 28 + OSXSAVE +XGETBV, i.e. the AVX half of the existingdetect_avx2check without the leaf-7 AVX2 bit) and anavx: boolfield alongsideavx2onHostVectorSupport. - Give
emit_vector_looptwo encoding modes selected byplan.width_bytes: 32 still requireshost.avx2, 16 requireshost.avx(which every AVX2 host also has, so no regression for the existing width). - Wire one
x64.rscall site: after the existing hand-written detectors insimd.rsdecline a loop (they are narrower and should stay first, since they also drivesingle_pass_only's IR-tier veto), tryadmit_vectorization/emit_vector_loopfor the general case. - Decide, and write down, how the two pipelines' de-specialization vetoes
compose —
single_pass_only.rs'shas_avx2()veto currently assumes the only live vector transforms need AVX2; a 128-bit AVX-only plan would need its own veto predicate.
Cost: this is a multi-day feature, not a bug fix — cpu_features.rs is
small and low-risk, but step 3/4 touches x64.rs and single_pass_only.rs,
neither owned by this lane, and needs a real differential-testing pass (the
ir_vs_singlepass / differential test suites already in jit/tests/ are
the right harness) before it can be trusted on real workloads. The payoff is
vectorizing element-wise/reduction loops on the (now rare, but not zero)
AVX-without-AVX2 hosts, and — more valuably — giving the general gate a
second, narrower width to fall back to instead of an all-or-nothing AVX2
requirement, which is useful once AVX-512 masked tails are considered (a
three-tier width ladder is the natural extension point;
VectorIsa::masked_tail already exists as a field for exactly that, unused).
3. (Smaller) Give HostVectorSupport/VecEmitPolicy a real production
caller for simd_sum_forms_enabled-style measurement
Not a code change, a process note: simd_sum_forms_enabled()
(simd_analysis.rs) and VecEmitPolicy::from_flags (vec_emit.rs) read the
same environment key (super::vec_emit::VECTORIZE_FLAG) with different
default-on/off rules, documented as deliberate ("this answer does not depend
on it") because the second reader has no production caller yet. Once proposal
2 lands and VecEmitPolicy gets a real caller, this divergence needs a single
paragraph explaining why the same flag means two different defaults in two
places, or the two should be unified — worth flagging for whoever does the
wiring so it is not rediscovered as a surprise.