From 2fdd3d34a5c0533c46105b210838bd7120e19d20 Mon Sep 17 00:00:00 2001 From: Raghuveer Devulapalli Date: Mon, 16 Feb 2026 04:25:51 +0000 Subject: [PATCH 1/3] =?UTF-8?q?SIMD:=20simplify=20AVX=E2=80=91512=20detect?= =?UTF-8?q?ion=20and=20check=20OS=20level=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces manual CPUID bit parsing in jvector_simd_check.c with __builtin_cpu_supports and adds __builtin_cpu_init(). This corrects missing XSAVE runtime checks, preventing #UD exceptions on systems where 512‑bit register state saves are disabled. --- .../src/main/c/jvector_simd_check.c | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/jvector-native/src/main/c/jvector_simd_check.c b/jvector-native/src/main/c/jvector_simd_check.c index bf134805e..c09f0897b 100644 --- a/jvector-native/src/main/c/jvector_simd_check.c +++ b/jvector-native/src/main/c/jvector_simd_check.c @@ -18,20 +18,10 @@ #include "jvector_simd.h" bool check_compatibility(void) { - unsigned int eax, ebx, ecx, edx; - bool avx512f_supported = false, avx512cd_supported = false, - avx512bw_supported = false, avx512dq_supported = false, - avx512vl_supported = false; - - // Check for AVX-512 Foundation (AVX-512F) and other AVX-512 features: - // These are indicated by various bits of EBX from leaf 7, sub-leaf 0. - if (__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx)) { - avx512f_supported = ebx & (1 << 16); // AVX-512F - avx512cd_supported = ebx & (1 << 28); // AVX-512CD - avx512bw_supported = ebx & (1 << 30); // AVX-512BW - avx512dq_supported = ebx & (1 << 17); // AVX-512DQ - avx512vl_supported = ebx & (1 << 31); // AVX-512VL - } - - return avx512f_supported && avx512cd_supported && avx512bw_supported && avx512dq_supported && avx512vl_supported; -} \ No newline at end of file + __builtin_cpu_init(); + return (__builtin_cpu_supports("avx512f") && + __builtin_cpu_supports("avx512cd") && + __builtin_cpu_supports("avx512dq") && + __builtin_cpu_supports("avx512bw") && + __builtin_cpu_supports("avx512vl")); +} From bae46ff7e1dc1cbfb1e53a18399ae9d9ff80d2e6 Mon Sep 17 00:00:00 2001 From: Raghuveer Devulapalli Date: Mon, 16 Feb 2026 04:44:32 +0000 Subject: [PATCH 2/3] Rename check_compatibility to check_avx512_compatibility --- jvector-native/src/main/c/jvector_simd.c | 2 +- jvector-native/src/main/c/jvector_simd.h | 2 +- .../src/main/c/jvector_simd_check.c | 5 +++- .../vector/NativeVectorizationProvider.java | 2 +- .../jvector/vector/cnative/NativeSimdOps.java | 30 +++++++++---------- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/jvector-native/src/main/c/jvector_simd.c b/jvector-native/src/main/c/jvector_simd.c index d9c909c0f..6bfde3f9a 100644 --- a/jvector-native/src/main/c/jvector_simd.c +++ b/jvector-native/src/main/c/jvector_simd.c @@ -26,7 +26,7 @@ __m512i maskEighthBit; __attribute__((constructor)) void initialize_constants() { - if (check_compatibility()) { + if (check_avx512_compatibility()) { initialIndexRegister = _mm512_setr_epi32(-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1); indexIncrement = _mm512_set1_epi32(16); diff --git a/jvector-native/src/main/c/jvector_simd.h b/jvector-native/src/main/c/jvector_simd.h index 55f1a46c1..39da01316 100644 --- a/jvector-native/src/main/c/jvector_simd.h +++ b/jvector-native/src/main/c/jvector_simd.h @@ -20,7 +20,7 @@ #define VECTOR_SIMD_DOT_H // check CPU support -bool check_compatibility(void); +bool check_avx512_compatibility(void); //F32 float dot_product_f32(int preferred_size, const float* a, int aoffset, const float* b, int boffset, int length); diff --git a/jvector-native/src/main/c/jvector_simd_check.c b/jvector-native/src/main/c/jvector_simd_check.c index c09f0897b..50736e85a 100644 --- a/jvector-native/src/main/c/jvector_simd_check.c +++ b/jvector-native/src/main/c/jvector_simd_check.c @@ -17,7 +17,10 @@ #include #include "jvector_simd.h" -bool check_compatibility(void) { +bool check_avx512_compatibility(void) { + /* __builtin_cpu_init required when this is used in ifunc + resolver/__attribute__((constructor)) context, otherwise the CPU + features may not be detected correctly. */ __builtin_cpu_init(); return (__builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512cd") && diff --git a/jvector-native/src/main/java/io/github/jbellis/jvector/vector/NativeVectorizationProvider.java b/jvector-native/src/main/java/io/github/jbellis/jvector/vector/NativeVectorizationProvider.java index 7bb4fa514..5194e1108 100644 --- a/jvector-native/src/main/java/io/github/jbellis/jvector/vector/NativeVectorizationProvider.java +++ b/jvector-native/src/main/java/io/github/jbellis/jvector/vector/NativeVectorizationProvider.java @@ -35,7 +35,7 @@ public NativeVectorizationProvider() { if (!libraryLoaded) { throw new UnsupportedOperationException("Failed to load supporting native library."); } - if (!NativeSimdOps.check_compatibility()) { + if (!NativeSimdOps.check_avx512_compatibility()) { throw new UnsupportedOperationException("Native SIMD operations are not supported on this platform due to missing CPU support."); } this.vectorUtilSupport = new NativeVectorUtilSupport(); diff --git a/jvector-native/src/main/java/io/github/jbellis/jvector/vector/cnative/NativeSimdOps.java b/jvector-native/src/main/java/io/github/jbellis/jvector/vector/cnative/NativeSimdOps.java index 014bdf4b0..5bf5b2f01 100644 --- a/jvector-native/src/main/java/io/github/jbellis/jvector/vector/cnative/NativeSimdOps.java +++ b/jvector-native/src/main/java/io/github/jbellis/jvector/vector/cnative/NativeSimdOps.java @@ -96,11 +96,11 @@ public static int __bool_true_false_are_defined() { return __bool_true_false_are_defined; } - private static class check_compatibility { + private static class check_avx512_compatibility { public static final FunctionDescriptor DESC = FunctionDescriptor.of( NativeSimdOps.C_BOOL ); - public static final MemorySegment ADDR = NativeSimdOps.findOrThrow("check_compatibility"); + public static final MemorySegment ADDR = NativeSimdOps.findOrThrow("check_avx512_compatibility"); public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC, Linker.Option.critical(true)); } @@ -108,43 +108,43 @@ private static class check_compatibility { /** * Function descriptor for: * {@snippet lang=c : - * _Bool check_compatibility() + * _Bool check_avx512_compatibility() * } */ - public static FunctionDescriptor check_compatibility$descriptor() { - return check_compatibility.DESC; + public static FunctionDescriptor check_avx512_compatibility$descriptor() { + return check_avx512_compatibility.DESC; } /** * Downcall method handle for: * {@snippet lang=c : - * _Bool check_compatibility() + * _Bool check_avx512_compatibility() * } */ - public static MethodHandle check_compatibility$handle() { - return check_compatibility.HANDLE; + public static MethodHandle check_avx512_compatibility$handle() { + return check_avx512_compatibility.HANDLE; } /** * Address for: * {@snippet lang=c : - * _Bool check_compatibility() + * _Bool check_avx512_compatibility() * } */ - public static MemorySegment check_compatibility$address() { - return check_compatibility.ADDR; + public static MemorySegment check_avx512_compatibility$address() { + return check_avx512_compatibility.ADDR; } /** * {@snippet lang=c : - * _Bool check_compatibility() + * _Bool check_avx512_compatibility() * } */ - public static boolean check_compatibility() { - var mh$ = check_compatibility.HANDLE; + public static boolean check_avx512_compatibility() { + var mh$ = check_avx512_compatibility.HANDLE; try { if (TRACE_DOWNCALLS) { - traceDowncall("check_compatibility"); + traceDowncall("check_avx512_compatibility"); } return (boolean)mh$.invokeExact(); } catch (Throwable ex$) { From c2bcf57ddc3fc3fa8f2425bd20fd863fca2f5e2d Mon Sep 17 00:00:00 2001 From: Raghuveer Devulapalli Date: Mon, 6 Apr 2026 04:20:58 +0000 Subject: [PATCH 3/3] Add testCheckAvx512CompatibilityMatchesCpuinfo --- .../vector/cnative/NativeSimdOpsTest.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 jvector-native/src/test/java/io/github/jbellis/jvector/vector/cnative/NativeSimdOpsTest.java diff --git a/jvector-native/src/test/java/io/github/jbellis/jvector/vector/cnative/NativeSimdOpsTest.java b/jvector-native/src/test/java/io/github/jbellis/jvector/vector/cnative/NativeSimdOpsTest.java new file mode 100644 index 000000000..68dfca187 --- /dev/null +++ b/jvector-native/src/test/java/io/github/jbellis/jvector/vector/cnative/NativeSimdOpsTest.java @@ -0,0 +1,62 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.jbellis.jvector.vector.cnative; + +import org.junit.Assume; +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class NativeSimdOpsTest { + + /** + * Reads /proc/cpuinfo and returns true if all AVX-512 flags required by + * check_avx512_compatibility() are present: avx512f, avx512cd, avx512dq, + * avx512bw, avx512vl. + */ + private static boolean cpuinfoReportsAvx512() throws IOException { + List lines = Files.readAllLines(Path.of("/proc/cpuinfo")); + List required = List.of("avx512f", "avx512cd", "avx512dq", "avx512bw", "avx512vl"); + for (String line : lines) { + if (line.startsWith("flags")) { + String[] flags = line.split("\\s+"); + List flagList = List.of(flags); + return flagList.containsAll(required); + } + } + return false; + } + + @Test + public void testCheckAvx512CompatibilityMatchesCpuinfo() throws IOException { + boolean libraryLoaded = LibraryLoader.loadJvector(); + Assume.assumeTrue("Native jvector library not available; skipping AVX-512 check", libraryLoaded); + + boolean expectedFromCpuinfo = cpuinfoReportsAvx512(); + boolean actualFromNative = NativeSimdOps.check_avx512_compatibility(); + + assertEquals( + "check_avx512_compatibility() should match AVX-512 flag presence in /proc/cpuinfo", + expectedFromCpuinfo, + actualFromNative); + } +}