Conversation
Gate x86-64-specific isa_variants and the avx3_dl/avx3_spr extra static
libs behind cpu == 'x86_64'. Add a parallel aarch64 block with three tiers:
neon (-march=armv8-a+crypto) — baseline, all Graviton + Apple Silicon
sve (-march=armv8.4-a+sve) — Graviton 3 / Neoverse V1 (Linux only;
Highway marks SVE broken on HWY_OS_APPLE)
sve2 (-march=armv9-a+sve2) — Graviton 4 / Neoverse V2/N2 (Linux only;
requires GCC >= 10 or Clang >= 22)
The three ARM static libs are appended to isa_libs and linked into
libjvector.so via link_whole, exactly as the x86 tiers already are.
An unsupported cpu_family() triggers a hard meson error.
…h #if/#else/#endif Add jvector_arch.h as the single source of truth for JV_ARCH_X86_64 and JV_ARCH_AARCH64 macros, derived from compiler predefined macros (__x86_64__ / __aarch64__). jvector_simd_kernels.h: declare ISA namespaces under a single #if JV_ARCH_X86_64 ... #else ... #endif block so only the namespaces for the current build target are visible to the compiler. jvector_simd.cpp: - MaxIsa enum and its static_assert are now separate per-arch definitions under #if JV_ARCH_X86_64 / #else / #endif — each side carries only the tiers relevant to it (SSE42..AVX3_SPR on x86; NEON/SVE/SVE2 on AArch64). - read_max_isa(), vtable definitions, dispatch_kernels(), and jvector_simd_get_active_isa() all use the same #if/#else/#endif pattern. - Add AArch64 vtable stubs: NEON_vtable (baseline), SVE_vtable (inherits NEON), SVE2_vtable (inherits SVE) — mirroring the x86 inheritance pattern. - Add AArch64 dispatch branch in dispatch_kernels() probing CpuFeature::SVE2, SVE, NEON in descending order (feature detection wired up in next commit).
…RCH_AARCH64 / #endif
assert_hwy_targets.h:
- Replace raw __x86_64__ guard with JV_ARCH_X86_64 from jvector_arch.h.
- Add #elif JV_ARCH_AARCH64 block with exact single-constant assertions:
JV_REQUIRE_HWY_NEON → HWY_STATIC_TARGET == HWY_NEON (-march=armv8-a+crypto
does not enable BF16/dotprod/I8MM so HWY_NEON_BF16 is
never selected; assert the precise constant)
JV_REQUIRE_HWY_SVE → HWY_STATIC_TARGET == HWY_SVE (-march=armv8.4-a+sve
carries no fixed-width hint so HWY_SVE_256 is not used)
JV_REQUIRE_HWY_SVE2 → HWY_STATIC_TARGET == HWY_SVE2 (-march=armv9-a+sve2
carries no fixed-width hint so HWY_SVE2_128 is not used)
jvector_simd_kernels.h / jvector_simd.cpp:
- Convert all back-to-back #if/#if and #if/#else pairs to the canonical
#if JV_ARCH_X86_64 / #elif JV_ARCH_AARCH64 / #endif pattern.
Extend CpuFeature enum with AArch64 tier flags (guarded by
#if JV_ARCH_X86_64 / #elif JV_ARCH_AARCH64 / #endif):
NEON = 200 — NEON + AES, baseline for all AArch64 CPUs
SVE = 201 — Scalable Vector Extension (Graviton 3+, Linux only)
SVE2 = 202 — SVE2 + SVE2-AES (Graviton 4+, Linux only)
Scope the arch-specific includes the same way:
x86-64: <intrin.h> or <cpuid.h>
AArch64: <sys/sysctl.h> on Apple; <sys/auxv.h> + <asm/hwcap.h> on Linux
Fallback macros for HWCAP_SVE, HWCAP2_SVE2, HWCAP2_SVEAES copied from
highway/hwy/targets.cc for older sysroots.
populate_cpu_features() AArch64 branch:
Linux: getauxval(AT_HWCAP) → NEON (HWCAP_AES), SVE (HWCAP_SVE)
getauxval(AT_HWCAP2) → SVE2 (HWCAP2_SVE2 | HWCAP2_SVEAES)
macOS: sysctlbyname("hw.optional.arm.FEAT_AES") → NEON
SVE/SVE2 left false (no Apple Silicon through M4 has SVE)
Extend the os.arch guard to accept 'aarch64' alongside 'amd64'/'x86_64' so the Java layer can load and use libjvector.so on Graviton and Apple Silicon once the library is present.
- Add test_aarch64_cpu_features.cpp: validates populate_cpu_features()
detects NEON/SVE/SVE2 correctly, checks dispatcher does not exceed
hardware capability, and verifies JVECTOR_MAX_ISA=neon cap is honoured.
Uses /proc/cpuinfo 'Features' line as ground truth on Linux, and
sysctlbyname on macOS.
- meson.build: route cpu-features test source to the arch-specific file
(test_x86_cpu_features.cpp on x86_64, test_aarch64_cpu_features.cpp
on aarch64).
- test_x86_cpu_features.cpp: renamed from test_cpu_features.cpp, no
functional change.
- test_helpers.h / test_helpers.cpp: extract parse_cpuinfo_line() and
make_vec() as shared helpers used by both arch-specific test files.
- test_similarity.cpp (IsaDispatch/MaxIsaEnvHonoured): replace the
hardcoded x86-only tier array with an #ifdef __aarch64__ guard that
swaps in {"neon", "sve", "sve2"} on ARM and keeps the existing
x86 list on x86_64.
- test_elementwise.cpp: add IsaDispatch/ActiveIsaIsKnownTier test that
confirms the active ISA name is in the architecture-appropriate tier
list on both x86_64 and aarch64.
All three AArch64 tiers are now pinned to fixed-width Highway targets:
NEON : -march=armv8-a+crypto → HWY_NEON
SVE : -march=armv8.4-a+sve
-msve-vector-bits=256 → HWY_SVE_256 (MaxLanes=8)
SVE2 : -march=armv9-a+sve2
-msve-vector-bits=128 → HWY_SVE2_128 (MaxLanes=4)
Using fixed-width targets gives Highway a concrete compile-time MaxLanes,
so all calculate_partial_sums fast-paths (Shuffle2301, Shuffle1032,
SwapAdjacentBlocks, LoadDup256) work identically to x86 without any
HWY_HAVE_SCALABLE guards or workarounds.
meson.build: add -msve-vector-bits=128 to sve2 args; update comments.
assert_hwy_targets.h: assert HWY_SVE2_128 (was HWY_SVE2) for the SVE2 tier.
jvector_simd_kernels.cpp: remove the #if !HWY_HAVE_SCALABLE guards that
were added as a temporary workaround; no longer needed.
jvector_simd.cpp: update dispatch comment to name the fixed-width targets.
HWY_SVE2_128 requires i8mm and bf16 features in addition to sve2 (documented in highway/hwy/ops/set_macros-inl.h:662, issue #2973). Without them, GCC raises 'target specific option mismatch' because the per-function target attributes added by the SVE2_128 header include +i8mm+bf16 but the TU-level -march= did not enable them. Fix: change -march=armv9-a+sve2 to -march=armv9-a+sve2+i8mm+bf16. Update the assert_hwy_targets.h error message to document the full flag.
SVE vector types (svfloat32_t etc.) are compiler built-ins, not C++ structs, so operator+/-/* cannot be defined for them — unlike NEON and x86 which wrap their intrinsics in Vec128<T,N>/Vec256<T> structs that do define these operators. This affects all SVE targets including the fixed-width HWY_SVE_256 and HWY_SVE2_128. Replace all vector operator- usages in L2SquareDistanceImpl with hn::Sub(), and the one operator+ in calculate_partial_sums_f32 with hn::Add(). hn::Add/Sub are portable across every Highway backend.
…_256 hn::LoadDup128 emits the SVE ld1rq instruction, which triggers an internal compiler error (ICE in convert_move, expr.cc:301) in GCC 14 when compiled with -msve-vector-bits=256 (fixed-width SVE mode). Add BroadcastDup128(), a local helper that achieves the same broadcast using LoadU on a narrower tag + Combine, avoiding ld1rq entirely: D = 4 lanes → plain LoadU D = 8 lanes → LoadU(Half<D>) + Combine D = 16 lanes → LoadU(Quarter<D>) + Combine twice Replace both hn::LoadDup128 call sites in calculate_partial_sums_f32 (size==2 and size==4 fast-paths) with BroadcastDup128. The name is deliberately distinct from hn::LoadDup128 to avoid the ambiguous overload error that occurs on x86_512 targets where hn::LoadDup128 is also defined in the same namespace.
r-devulap
requested review from
MarkWolters,
ashkrisk,
jshook and
tlwillke
as code owners
August 31, 2026 07:01
Contributor
|
Before you submit for review:
If you did not complete any of these, then please explain below. |
Switch the AArch64 SVE and SVE2 builds from fixed-width Highway targets
(HWY_SVE_256 / HWY_SVE2_128) to scalable ones (HWY_SVE / HWY_SVE2).
meson.build:
- sve: drop -msve-vector-bits=256; Highway now selects HWY_SVE
- sve2: drop -msve-vector-bits=128 and +i8mm+bf16 (only required by
HWY_SVE2_128); Highway now selects HWY_SVE2
assert_hwy_targets.h:
- Update static-target assertions from HWY_SVE_256/HWY_SVE2_128 to
HWY_SVE/HWY_SVE2 and remove stale flag references from error messages.
jvector_simd_kernels.cpp:
- BroadcastDup128 / LoadDup256: wrap in #if !HWY_HAVE_SCALABLE with a
comment that they are written for fixed vector lengths and must not be
instantiated on scalable targets.
- calculate_partial_sums_f32 / calculate_partial_sums_self_magnitude_f32:
wrap all fixed-width fast-paths (Shuffle2301/Shuffle1032/SwapAdjacentBlocks
horizontal reductions) in #if !HWY_HAVE_SCALABLE; on scalable SVE
execution falls through to the generic per-centroid fallback.
Fix the general fallback to use const lanes = hn::Lanes() instead of
constexpr kLanes = MaxLanes() as the inner loop stride.
- NVQ kernels: replace constexpr kLanes = MaxLanes() with
const kLanes = Lanes() for all loop counters; keep constexpr kMaxLanes
for stack-array sizing where a compile-time bound is required.
jvector_simd.cpp:
- Update file-top dispatch comment to reflect HWY_SVE/HWY_SVE2 and
scalable (runtime Lanes()) semantics.
On x86 and NEON (HWY_HAVE_SCALABLE=0) MaxLanes==Lanes so all existing
behaviour is preserved exactly.
jvector-native/src/main/native/README.md: - Platform support blurb: drop 'ARM support planned' — NEON, SVE, SVE2 are now live. - Architecture diagram: add AArch64 dispatch tree (SVE2 > SVE > NEON) alongside the existing x86-64 tree; correct the x86-64 -march= flags (-march=sapphirerapids / -march=icelake-server). - ISA dispatch section: note getauxval for AArch64 alongside CPUID/XGETBV for x86; list both dispatch chains. - ISA cap section: add AArch64 JVECTOR_MAX_ISA examples (sve2, sve, neon) and update the accepted-values sentence. README.md: - Building native libraries: add 'Linux AArch64 (NEON, SVE, SVE2)' to the supported-platforms line.
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.
This pull request adds full support for running and building
jvector-nativeon AArch64 (ARM64) systems, including both NEON/SVE/SVE2 SIMD instruction sets. The changes introduce architecture detection macros, update build scripts and CI workflows for ARM64, and extend runtime detection and dispatch of SIMD capabilities to support ARM64 alongside x86_64. This enables native vectorization and testing on ARM64 platforms such as AWS Graviton and Apple Silicon.Key changes:
ARM64 (AArch64) support:
JV_ARCH_X86_64,JV_ARCH_AARCH64) in new headerjvector_arch.hand refactored source code to use these macros for architecture-specific logic.getauxval) and macOS (usingsysctlbyname).Build system and CI improvements:
meson.buildto add ARM64 ISA variants, select appropriate test sources, and error on unsupported architectures.Java integration:
NativeVectorizationProviderto allow native SIMD operations on both x86_64 and aarch64, not just x86_64.pom.xmlto allow non-amd64 Unix builds (enabling ARM64 builds).