usearch 2.11.1 → 2.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -30
- package/binding.gyp +11 -12
- package/c/README.md +3 -0
- package/c/lib.cpp +50 -13
- package/c/test.c +60 -55
- package/c/usearch.h +16 -0
- package/cpp/CMakeLists.txt +6 -0
- package/cpp/README.md +34 -13
- package/cpp/bench.cpp +99 -47
- package/cpp/test.cpp +947 -132
- package/include/usearch/index.hpp +894 -272
- package/include/usearch/index_dense.hpp +418 -156
- package/include/usearch/index_plugins.hpp +99 -49
- package/javascript/dist/cjs/usearch.d.ts +39 -1
- package/javascript/dist/cjs/usearch.js +11 -1
- package/javascript/dist/esm/usearch.d.ts +39 -1
- package/javascript/dist/esm/usearch.js +11 -1
- package/javascript/tsconfig-esm.json +3 -2
- package/javascript/usearch.ts +18 -7
- package/package.json +2 -2
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/simsimd/.cmake-format.py +19 -0
- package/simsimd/CONTRIBUTING.md +49 -8
- package/simsimd/Cargo.lock +1 -1
- package/simsimd/Cargo.toml +10 -5
- package/simsimd/Package.swift +16 -0
- package/simsimd/README.md +69 -15
- package/simsimd/binding.gyp +14 -19
- package/simsimd/build.rs +2 -0
- package/simsimd/c/lib.c +18 -0
- package/simsimd/include/module.modulemap +4 -0
- package/simsimd/include/simsimd/binary.h +2 -0
- package/simsimd/include/simsimd/dot.h +466 -32
- package/simsimd/include/simsimd/probability.h +20 -10
- package/simsimd/include/simsimd/simsimd.h +444 -98
- package/simsimd/include/simsimd/spatial.h +480 -44
- package/simsimd/include/simsimd/types.h +161 -39
- package/simsimd/javascript/simsimd.ts +26 -2
- package/simsimd/package.json +1 -1
- package/simsimd/rust/benches/cosine.rs +8 -2
- package/simsimd/rust/benches/native.rs +240 -2
- package/simsimd/rust/benches/sqeuclidean.rs +8 -2
- package/simsimd/rust/lib.rs +50 -13
- package/simsimd/swift/source/SimSIMD.swift +123 -0
- package/simsimd/swift/tests/SimSIMDTests.swift +92 -0
- package/prebuilds/win32-ia32/usearch.node +0 -0
- package/prebuilds/win32-x64/usearch.node +0 -0
- package/simsimd/.releaserc +0 -87
|
@@ -6,17 +6,89 @@
|
|
|
6
6
|
* @copyright Copyright (c) 2023
|
|
7
7
|
*
|
|
8
8
|
* References:
|
|
9
|
-
* x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide
|
|
10
|
-
* Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics
|
|
9
|
+
* x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide
|
|
10
|
+
* Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics
|
|
11
11
|
* Detecting target CPU features at compile time: https://stackoverflow.com/a/28939692/2766161
|
|
12
|
+
*
|
|
13
|
+
* @section Choosing x86 Target Generations
|
|
14
|
+
*
|
|
15
|
+
* It's important to provide fine-grained controls over AVX512 families, as they are very fragmented:
|
|
16
|
+
*
|
|
17
|
+
* - Intel Skylake servers: F, CD, VL, DQ, BW
|
|
18
|
+
* - Intel Cascade Lake workstations: F, CD, VL, DQ, BW, VNNI
|
|
19
|
+
* > In other words, it extends Skylake with VNNI support
|
|
20
|
+
* - Intel Sunny Cove (Ice Lake) servers:
|
|
21
|
+
* F, CD, VL, DQ, BW, VNNI, VPOPCNTDQ, IFMA, VBMI, VAES, GFNI, VBMI2, BITALG, VPCLMULQDQ
|
|
22
|
+
* - AMD Zen4 (Genoa):
|
|
23
|
+
* F, CD, VL, DQ, BW, VNNI, VPOPCNTDQ, IFMA, VBMI, VAES, GFNI, VBMI2, BITALG, VPCLMULQDQ, BF16
|
|
24
|
+
* > In other words, it extends Sunny Cove with BF16 support
|
|
25
|
+
* - Intel Golden Cove (Sapphire Rapids): extends Zen4 and Sunny Cove with FP16 support
|
|
26
|
+
*
|
|
27
|
+
* Intel Palm Cove was an irrelevant intermediate release extending Skylake with IFMA and VBMI.
|
|
28
|
+
* Intel Willow Cove was an irrelevant intermediate release extending Sunny Cove with VP2INTERSECT,
|
|
29
|
+
* that aren't supported by any other CPU built to date... and those are only available in Tiger Lake laptops.
|
|
30
|
+
* Intel Cooper Lake was the only intermediary platform, that supported BF16, but not FP16.
|
|
31
|
+
* It's mostly used in 4-socket and 8-socket high-memory configurations.
|
|
32
|
+
*
|
|
33
|
+
* In practical terms, it makes sense to differentiate only 3 AVX512 generations:
|
|
34
|
+
* 1. Intel Skylake (pre 2019): supports single-precision dot-products.
|
|
35
|
+
* 2. Intel Ice Lake (2019-2021): advanced integer algorithms.
|
|
36
|
+
* 3. AMD Genoa (2023+): brain-floating point support.
|
|
37
|
+
* 4. Intel Sapphire Rapids (2023+): advanced mixed-precision float processing.
|
|
38
|
+
*
|
|
39
|
+
* To list all available macros for x86, take a recent compiler, like GCC 12 and run:
|
|
40
|
+
* gcc-12 -march=sapphirerapids -dM -E - < /dev/null | egrep "SSE|AVX" | sort
|
|
41
|
+
* On Arm machines you may want to check for other flags:
|
|
42
|
+
* gcc-12 -march=native -dM -E - < /dev/null | egrep "NEON|SVE|FP16|FMA" | sort
|
|
43
|
+
*
|
|
44
|
+
* @section Choosing Arm Target Generations
|
|
45
|
+
*
|
|
46
|
+
* Arm CPUs share design IP, but are produced by different vendors, potentially making the platform
|
|
47
|
+
* even more fragmented than x86. There are 2 imporatant families of SIMD extensions - NEON and SVE.
|
|
48
|
+
*
|
|
49
|
+
* - Armv8-A: +fp, +simd
|
|
50
|
+
* - Armv8.1-A: armv8-a, +crc, +lse, +rdma
|
|
51
|
+
* - Armv8.2-A: armv8.1-a
|
|
52
|
+
* - Armv8.3-A: armv8.2-a, +pauth
|
|
53
|
+
* - Armv8.4-A: armv8.3-a, +flagm, +fp16fml, +dotprod
|
|
54
|
+
* - Armv8.5-A: armv8.4-a, +sb, +ssbs, +predres
|
|
55
|
+
* - Armv8.6-A: armv8.5-a, +bf16, +i8mm
|
|
56
|
+
* - Armv8.7-A: armv8.6-a, +ls64
|
|
57
|
+
* - Armv8.8-A: armv8.7-a, +mops
|
|
58
|
+
* - Armv8.9-A: armv8.8-a
|
|
59
|
+
* - Armv9-A: armv8.5-a, +sve, +sve2
|
|
60
|
+
* - Armv9.1-A: armv9-a, +bf16, +i8mm
|
|
61
|
+
* - Armv9.2-A: armv9.1-a, +ls64
|
|
62
|
+
* - Armv9.3-A: armv9.2-a, +mops
|
|
63
|
+
* - Armv9.4-A: armv9.3-a
|
|
64
|
+
*
|
|
65
|
+
* SVE has been optional since Armv8.2-A, but it's a requirement for Armv9.0-A.
|
|
66
|
+
* A 512-bit SVE variant has already been implemented on the Fugaku supercomputer.
|
|
67
|
+
* A more flexible version, 2x256 SVE, was implemented by the AWS Graviton3 ARM processor.
|
|
68
|
+
* Here are the most important recent families of CPU cores designed by Arm:
|
|
69
|
+
*
|
|
70
|
+
* - Neoverse N1: armv8.2-a, extended with Armv8.4 "dotprod" instructions.
|
|
71
|
+
* Used in AWS @b Graviton2 and Amere @b Altra.
|
|
72
|
+
* https://developer.arm.com/Processors/Neoverse%20N1
|
|
73
|
+
* - Neoverse V1: armv8.4-a, extended with Armv8.6 bfloat/int8 "matmul" instructions.
|
|
74
|
+
* Used in AWS @b Graviton3, which also enables `sve`, `svebf16`, and `svei8mm`.
|
|
75
|
+
* https://developer.arm.com/Processors/Neoverse%20V1
|
|
76
|
+
* - Neoverse V2: armv9.0 with SVE2 and SVE bit-permutes
|
|
77
|
+
* Used in AWS @b Graviton4, NVIDIA @b Grace, Google @b Axion.
|
|
78
|
+
* https://developer.arm.com/Processors/Neoverse%20V2
|
|
79
|
+
* The N2 core is very similar to V2 and is used by Microsoft @b Cobalt.
|
|
80
|
+
* https://developer.arm.com/Processors/Neoverse%20N2
|
|
81
|
+
*
|
|
82
|
+
* On Consumer side, Apple is the biggest player with mobile @b A chips and desktop @b M chips.
|
|
83
|
+
* The M1 implements Armv8.5-A, both M2 and M3 implement Armv8.6-A, and M4 is expected to have Armv9.1-A.
|
|
12
84
|
*/
|
|
13
85
|
|
|
14
86
|
#ifndef SIMSIMD_H
|
|
15
87
|
#define SIMSIMD_H
|
|
16
88
|
|
|
17
|
-
#define SIMSIMD_VERSION_MAJOR
|
|
18
|
-
#define SIMSIMD_VERSION_MINOR
|
|
19
|
-
#define SIMSIMD_VERSION_PATCH
|
|
89
|
+
#define SIMSIMD_VERSION_MAJOR 5
|
|
90
|
+
#define SIMSIMD_VERSION_MINOR 0
|
|
91
|
+
#define SIMSIMD_VERSION_PATCH 0
|
|
20
92
|
|
|
21
93
|
/**
|
|
22
94
|
* @brief Removes compile-time dispatching, and replaces it with runtime dispatching.
|
|
@@ -34,11 +106,9 @@
|
|
|
34
106
|
#include "probability.h" // Kullback-Leibler, Jensen–Shannon
|
|
35
107
|
#include "spatial.h" // L2, Cosine
|
|
36
108
|
|
|
37
|
-
|
|
38
|
-
#
|
|
39
|
-
#include <
|
|
40
|
-
#include <sys/auxv.h>
|
|
41
|
-
#endif
|
|
109
|
+
// On Apple Silicon, `mrs` is not allowed in user-space, so we need to use the `sysctl` API.
|
|
110
|
+
#if defined(SIMSIMD_DEFINED_APPLE)
|
|
111
|
+
#include <sys/sysctl.h>
|
|
42
112
|
#endif
|
|
43
113
|
|
|
44
114
|
#ifdef __cplusplus
|
|
@@ -88,14 +158,20 @@ typedef enum {
|
|
|
88
158
|
simsimd_cap_serial_k = 1, ///< Serial (non-SIMD) capability
|
|
89
159
|
simsimd_cap_any_k = 0x7FFFFFFF, ///< Mask representing any capability with `INT_MAX`
|
|
90
160
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
161
|
+
simsimd_cap_haswell_k = 1 << 10, ///< x86 AVX2 capability with FMA and F16C extensions
|
|
162
|
+
simsimd_cap_skylake_k = 1 << 11, ///< x86 AVX512 baseline capability
|
|
163
|
+
simsimd_cap_ice_k = 1 << 12, ///< x86 AVX512 capability with advanced integer algos
|
|
164
|
+
simsimd_cap_genoa_k = 1 << 13, ///< x86 AVX512 capability with `bf16` support
|
|
165
|
+
simsimd_cap_sapphire_k = 1 << 14, ///< x86 AVX512 capability with `f16` support
|
|
166
|
+
|
|
167
|
+
simsimd_cap_neon_k = 1 << 20, ///< ARM NEON capability
|
|
168
|
+
simsimd_cap_neon_f16_k = 1 << 21, ///< ARM NEON FP16 capability
|
|
169
|
+
simsimd_cap_neon_bf16_k = 1 << 22, ///< ARM NEON BF16 capability
|
|
170
|
+
simsimd_cap_neon_i8_k = 1 << 23, ///< ARM NEON Int8 capability
|
|
171
|
+
simsimd_cap_sve_k = 1 << 24, ///< ARM SVE capability
|
|
172
|
+
simsimd_cap_sve_f16_k = 1 << 25, ///< ARM SVE FP16 capability
|
|
173
|
+
simsimd_cap_sve_bf16_k = 1 << 26, ///< ARM SVE BF16 capability
|
|
174
|
+
simsimd_cap_sve_i8_k = 1 << 27, ///< ARM SVE Int8 capability
|
|
99
175
|
|
|
100
176
|
} simsimd_capability_t;
|
|
101
177
|
|
|
@@ -107,16 +183,20 @@ typedef enum {
|
|
|
107
183
|
* interfaces.
|
|
108
184
|
*/
|
|
109
185
|
typedef enum {
|
|
110
|
-
simsimd_datatype_unknown_k, ///< Unknown data type
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
186
|
+
simsimd_datatype_unknown_k = 0, ///< Unknown data type
|
|
187
|
+
|
|
188
|
+
simsimd_datatype_b8_k = 1 << 1, ///< Single-bit values packed into 8-bit words
|
|
189
|
+
simsimd_datatype_i8_k = 1 << 2, ///< 8-bit integer
|
|
190
|
+
|
|
191
|
+
simsimd_datatype_f64_k = 1 << 10, ///< Double precision floating point
|
|
192
|
+
simsimd_datatype_f32_k = 1 << 11, ///< Single precision floating point
|
|
193
|
+
simsimd_datatype_f16_k = 1 << 12, ///< Half precision floating point
|
|
194
|
+
simsimd_datatype_bf16_k = 1 << 13, ///< Brain floating point
|
|
195
|
+
|
|
196
|
+
simsimd_datatype_f64c_k = 1 << 20, ///< Complex double precision floating point
|
|
197
|
+
simsimd_datatype_f32c_k = 1 << 21, ///< Complex single precision floating point
|
|
198
|
+
simsimd_datatype_f16c_k = 1 << 22, ///< Complex half precision floating point
|
|
199
|
+
simsimd_datatype_bf16c_k = 1 << 23, ///< Complex brain floating point
|
|
120
200
|
} simsimd_datatype_t;
|
|
121
201
|
|
|
122
202
|
/**
|
|
@@ -137,13 +217,13 @@ SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
|
|
|
137
217
|
SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void);
|
|
138
218
|
#endif
|
|
139
219
|
|
|
220
|
+
#if SIMSIMD_TARGET_X86
|
|
221
|
+
|
|
140
222
|
/**
|
|
141
|
-
* @brief Function to determine the SIMD capabilities of the current machine at @b runtime.
|
|
223
|
+
* @brief Function to determine the SIMD capabilities of the current 64-bit x86 machine at @b runtime.
|
|
142
224
|
* @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
|
|
143
225
|
*/
|
|
144
|
-
SIMSIMD_PUBLIC simsimd_capability_t
|
|
145
|
-
|
|
146
|
-
#if SIMSIMD_TARGET_X86
|
|
226
|
+
SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities_x86(void) {
|
|
147
227
|
|
|
148
228
|
/// The states of 4 registers populated for a specific "cpuid" assembly call
|
|
149
229
|
union four_registers_t {
|
|
@@ -151,11 +231,12 @@ SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities_implementation(void) {
|
|
|
151
231
|
struct separate_t {
|
|
152
232
|
unsigned eax, ebx, ecx, edx;
|
|
153
233
|
} named;
|
|
154
|
-
} info1, info7;
|
|
234
|
+
} info1, info7, info7sub1;
|
|
155
235
|
|
|
156
|
-
#
|
|
236
|
+
#if defined(_MSC_VER)
|
|
157
237
|
__cpuidex(info1.array, 1, 0);
|
|
158
238
|
__cpuidex(info7.array, 7, 0);
|
|
239
|
+
__cpuidex(info7sub1.array, 7, 1);
|
|
159
240
|
#else
|
|
160
241
|
__asm__ __volatile__("cpuid"
|
|
161
242
|
: "=a"(info1.named.eax), "=b"(info1.named.ebx), "=c"(info1.named.ecx), "=d"(info1.named.edx)
|
|
@@ -163,6 +244,10 @@ SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities_implementation(void) {
|
|
|
163
244
|
__asm__ __volatile__("cpuid"
|
|
164
245
|
: "=a"(info7.named.eax), "=b"(info7.named.ebx), "=c"(info7.named.ecx), "=d"(info7.named.edx)
|
|
165
246
|
: "a"(7), "c"(0));
|
|
247
|
+
__asm__ __volatile__("cpuid"
|
|
248
|
+
: "=a"(info7sub1.named.eax), "=b"(info7sub1.named.ebx), "=c"(info7sub1.named.ecx),
|
|
249
|
+
"=d"(info7sub1.named.edx)
|
|
250
|
+
: "a"(7), "c"(1));
|
|
166
251
|
#endif
|
|
167
252
|
|
|
168
253
|
// Check for AVX2 (Function ID 7, EBX register)
|
|
@@ -188,45 +273,155 @@ SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities_implementation(void) {
|
|
|
188
273
|
unsigned supports_avx512vbmi2 = (info7.named.ecx & 0x00000040) != 0;
|
|
189
274
|
// Check for AVX512VPOPCNTDQ (Function ID 7, ECX register)
|
|
190
275
|
unsigned supports_avx512vpopcntdq = (info7.named.ecx & 0x00004000) != 0;
|
|
276
|
+
// Check for AVX512BF16 (Function ID 7, Sub-leaf 1, EAX register)
|
|
277
|
+
// https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L205
|
|
278
|
+
unsigned supports_avx512bf16 = (info7sub1.named.eax & 0x00000020) != 0;
|
|
191
279
|
|
|
192
280
|
// Convert specific features into CPU generations
|
|
193
281
|
unsigned supports_haswell = supports_avx2 && supports_f16c && supports_fma;
|
|
194
282
|
unsigned supports_skylake = supports_avx512f;
|
|
195
283
|
unsigned supports_ice = supports_avx512vnni && supports_avx512ifma && supports_avx512bitalg &&
|
|
196
284
|
supports_avx512vbmi2 && supports_avx512vpopcntdq;
|
|
285
|
+
unsigned supports_genoa = supports_avx512bf16;
|
|
197
286
|
unsigned supports_sapphire = supports_avx512fp16;
|
|
198
287
|
|
|
199
288
|
return (simsimd_capability_t)( //
|
|
200
289
|
(simsimd_cap_haswell_k * supports_haswell) | //
|
|
201
290
|
(simsimd_cap_skylake_k * supports_skylake) | //
|
|
202
291
|
(simsimd_cap_ice_k * supports_ice) | //
|
|
292
|
+
(simsimd_cap_genoa_k * supports_genoa) | //
|
|
203
293
|
(simsimd_cap_sapphire_k * supports_sapphire) | //
|
|
204
294
|
(simsimd_cap_serial_k));
|
|
295
|
+
}
|
|
205
296
|
|
|
206
297
|
#endif // SIMSIMD_TARGET_X86
|
|
207
298
|
|
|
208
299
|
#if SIMSIMD_TARGET_ARM
|
|
209
300
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
301
|
+
/* Compiling the next section one may get: selected processor does not support system register name 'id_aa64zfr0_el1'.
|
|
302
|
+
* Suppressing assembler errors is very complicated, so when dealing with older ARM CPUs it's simpler to compile this
|
|
303
|
+
* function targetting newer ones.
|
|
304
|
+
*/
|
|
305
|
+
#pragma GCC push_options
|
|
306
|
+
#pragma GCC target("arch=armv8.5-a+sve")
|
|
307
|
+
#pragma clang attribute push(__attribute__((target("arch=armv8.5-a+sve"))), apply_to = function)
|
|
214
308
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
#
|
|
309
|
+
/**
|
|
310
|
+
* @brief Function to determine the SIMD capabilities of the current 64-bit Arm machine at @b runtime.
|
|
311
|
+
* @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
|
|
312
|
+
*/
|
|
313
|
+
SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities_arm(void) {
|
|
314
|
+
#if defined(SIMSIMD_DEFINED_APPLE)
|
|
315
|
+
// On Apple Silicon, `mrs` is not allowed in user-space, so we need to use the `sysctl` API.
|
|
316
|
+
uint32_t supports_neon = 0, supports_fp16 = 0, supports_bf16 = 0, supports_i8mm = 0;
|
|
317
|
+
size_t size = sizeof(supports_neon);
|
|
318
|
+
if (sysctlbyname("hw.optional.neon", &supports_neon, &size, NULL, 0) != 0)
|
|
319
|
+
supports_neon = 0;
|
|
320
|
+
if (sysctlbyname("hw.optional.arm.FEAT_FP16", &supports_fp16, &size, NULL, 0) != 0)
|
|
321
|
+
supports_fp16 = 0;
|
|
322
|
+
if (sysctlbyname("hw.optional.arm.FEAT_BF16", &supports_bf16, &size, NULL, 0) != 0)
|
|
323
|
+
supports_bf16 = 0;
|
|
324
|
+
if (sysctlbyname("hw.optional.arm.FEAT_I8MM", &supports_i8mm, &size, NULL, 0) != 0)
|
|
325
|
+
supports_i8mm = 0;
|
|
326
|
+
|
|
327
|
+
return (simsimd_capability_t)( //
|
|
328
|
+
(simsimd_cap_neon_k * (supports_neon)) | //
|
|
329
|
+
(simsimd_cap_neon_f16_k * (supports_neon && supports_fp16)) | //
|
|
330
|
+
(simsimd_cap_neon_bf16_k * (supports_neon && supports_bf16)) | //
|
|
331
|
+
(simsimd_cap_neon_i8_k * (supports_neon && supports_i8mm)) | //
|
|
332
|
+
(simsimd_cap_serial_k));
|
|
221
333
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
334
|
+
#elif defined(SIMSIMD_DEFINED_LINUX)
|
|
335
|
+
// This is how the `arm-cpusysregs` library does it:
|
|
336
|
+
//
|
|
337
|
+
// int ID_AA64ISAR1_EL1_BF16() const { return (int)(_aa64isar1 >> 44) & 0x0F; }
|
|
338
|
+
// int ID_AA64ZFR0_EL1_BF16() const { return (int)(_aa64zfr0 >> 20) & 0x0F; }
|
|
339
|
+
// int ID_AA64PFR0_EL1_FP() const { return (int)(_aa64pfr0 >> 16) & 0x0F; }
|
|
340
|
+
// int ID_AA64ISAR0_EL1_DP() const { return (int)(_aa64isar0 >> 44) & 0x0F; }
|
|
341
|
+
// int ID_AA64PFR0_EL1_SVE() const { return (int)(_aa64pfr0 >> 32) & 0x0F; }
|
|
342
|
+
// int ID_AA64ZFR0_EL1_SVEver() const { return (int)(_aa64zfr0) & 0x0F; }
|
|
343
|
+
// bool FEAT_BF16() const { return ID_AA64ISAR1_EL1_BF16() >= 1 || ID_AA64ZFR0_EL1_BF16() >= 1; }
|
|
344
|
+
// bool FEAT_FP16() const { return ID_AA64PFR0_EL1_FP() >= 1 && ID_AA64PFR0_EL1_FP() < 15; }
|
|
345
|
+
// bool FEAT_DotProd() const { return ID_AA64ISAR0_EL1_DP() >= 1; }
|
|
346
|
+
// bool FEAT_SVE() const { return ID_AA64PFR0_EL1_SVE() >= 1; }
|
|
347
|
+
// bool FEAT_SVE2() const { return ID_AA64ZFR0_EL1_SVEver() >= 1; }
|
|
348
|
+
// bool FEAT_I8MM() const { return ID_AA64ZFR0_EL1_I8MM() >= 1; }
|
|
349
|
+
//
|
|
350
|
+
// https://github.com/lelegard/arm-cpusysregs/tree/4837c62e619a5e5f12bf41b16a1ee1e71d62c76d
|
|
351
|
+
|
|
352
|
+
// Read CPUID registers directly
|
|
353
|
+
unsigned long id_aa64isar0_el1 = 0, id_aa64isar1_el1 = 0, id_aa64pfr0_el1 = 0, id_aa64zfr0_el1 = 0;
|
|
354
|
+
|
|
355
|
+
// Now let's unpack the status flags from ID_AA64ISAR0_EL1
|
|
356
|
+
// https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0?lang=en
|
|
357
|
+
__asm__ __volatile__("mrs %0, ID_AA64ISAR0_EL1" : "=r"(id_aa64isar0_el1));
|
|
358
|
+
// DP, bits [47:44] of ID_AA64ISAR0_EL1
|
|
359
|
+
unsigned supports_integer_dot_products = ((id_aa64isar0_el1 >> 44) & 0xF) >= 1;
|
|
360
|
+
// Now let's unpack the status flags from ID_AA64ISAR1_EL1
|
|
361
|
+
// https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64ISAR1-EL1--AArch64-Instruction-Set-Attribute-Register-1?lang=en
|
|
362
|
+
__asm__ __volatile__("mrs %0, ID_AA64ISAR1_EL1" : "=r"(id_aa64isar1_el1));
|
|
363
|
+
// I8MM, bits [55:52] of ID_AA64ISAR1_EL1
|
|
364
|
+
unsigned supports_i8mm = ((id_aa64isar1_el1 >> 52) & 0xF) >= 1;
|
|
365
|
+
// BF16, bits [47:44] of ID_AA64ISAR1_EL1
|
|
366
|
+
unsigned supports_bf16 = ((id_aa64isar1_el1 >> 44) & 0xF) >= 1;
|
|
367
|
+
|
|
368
|
+
// Now let's unpack the status flags from ID_AA64PFR0_EL1
|
|
369
|
+
// https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64PFR0-EL1--AArch64-Processor-Feature-Register-0?lang=en
|
|
370
|
+
__asm__ __volatile__("mrs %0, ID_AA64PFR0_EL1" : "=r"(id_aa64pfr0_el1));
|
|
371
|
+
// SVE, bits [35:32] of ID_AA64PFR0_EL1
|
|
372
|
+
unsigned supports_sve = ((id_aa64pfr0_el1 >> 32) & 0xF) >= 1;
|
|
373
|
+
// AdvSIMD, bits [23:20] of ID_AA64PFR0_EL1 can be used to check for `fp16` support
|
|
374
|
+
// - 0b0000: integers, single, double precision arithmetic
|
|
375
|
+
// - 0b0001: includes support for half-precision floating-point arithmetic
|
|
376
|
+
unsigned supports_fp16 = ((id_aa64pfr0_el1 >> 20) & 0xF) == 1;
|
|
377
|
+
|
|
378
|
+
// Now let's unpack the status flags from ID_AA64ZFR0_EL1
|
|
379
|
+
// https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64ZFR0-EL1--SVE-Feature-ID-Register-0?lang=en
|
|
380
|
+
if (supports_sve)
|
|
381
|
+
__asm__ __volatile__("mrs %0, ID_AA64ZFR0_EL1" : "=r"(id_aa64zfr0_el1));
|
|
382
|
+
// I8MM, bits [47:44] of ID_AA64ZFR0_EL1
|
|
383
|
+
unsigned supports_sve_i8mm = ((id_aa64zfr0_el1 >> 44) & 0xF) >= 1;
|
|
384
|
+
// BF16, bits [23:20] of ID_AA64ZFR0_EL1
|
|
385
|
+
unsigned supports_sve_bf16 = ((id_aa64zfr0_el1 >> 20) & 0xF) >= 1;
|
|
386
|
+
// SVEver, bits [3:0] can be used to check for capability levels:
|
|
387
|
+
// - 0b0000: SVE is implemented
|
|
388
|
+
// - 0b0001: SVE2 is implemented
|
|
389
|
+
// - 0b0010: SVE2.1 is implemented
|
|
390
|
+
// This value must match the existing indicator obtained from ID_AA64PFR0_EL1:
|
|
391
|
+
// unsigned supports_sve = ((id_aa64zfr0_el1) & 0xF) >= 1;
|
|
392
|
+
// unsigned supports_sve2 = ((id_aa64zfr0_el1) & 0xF) >= 2;
|
|
393
|
+
unsigned supports_neon = 1; // NEON is always supported
|
|
394
|
+
|
|
395
|
+
return (simsimd_capability_t)( //
|
|
396
|
+
(simsimd_cap_neon_k * (supports_neon)) | //
|
|
397
|
+
(simsimd_cap_neon_f16_k * (supports_neon && supports_fp16)) | //
|
|
398
|
+
(simsimd_cap_neon_bf16_k * (supports_neon && supports_bf16)) | //
|
|
399
|
+
(simsimd_cap_neon_i8_k * (supports_neon && supports_i8mm && supports_integer_dot_products)) | //
|
|
400
|
+
(simsimd_cap_sve_k * (supports_sve)) | //
|
|
401
|
+
(simsimd_cap_sve_f16_k * (supports_sve && supports_fp16)) | //
|
|
402
|
+
(simsimd_cap_sve_bf16_k * (supports_sve && supports_sve_bf16)) | //
|
|
403
|
+
(simsimd_cap_sve_i8_k * (supports_sve && supports_sve_i8mm)) | //
|
|
226
404
|
(simsimd_cap_serial_k));
|
|
405
|
+
#else // SIMSIMD_DEFINED_LINUX
|
|
406
|
+
return simsimd_cap_serial_k;
|
|
407
|
+
#endif
|
|
408
|
+
}
|
|
227
409
|
|
|
228
|
-
#
|
|
410
|
+
#pragma clang attribute pop
|
|
411
|
+
#pragma GCC pop_options
|
|
412
|
+
#endif
|
|
229
413
|
|
|
414
|
+
/**
|
|
415
|
+
* @brief Function to determine the SIMD capabilities of the current 64-bit x86 machine at @b runtime.
|
|
416
|
+
* @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
|
|
417
|
+
*/
|
|
418
|
+
SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities_implementation(void) {
|
|
419
|
+
#if SIMSIMD_TARGET_X86
|
|
420
|
+
return simsimd_capabilities_x86();
|
|
421
|
+
#endif // SIMSIMD_TARGET_X86
|
|
422
|
+
#if SIMSIMD_TARGET_ARM
|
|
423
|
+
return simsimd_capabilities_arm();
|
|
424
|
+
#endif // SIMSIMD_TARGET_ARM
|
|
230
425
|
return simsimd_cap_serial_k;
|
|
231
426
|
}
|
|
232
427
|
|
|
@@ -357,13 +552,13 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
357
552
|
}
|
|
358
553
|
#endif
|
|
359
554
|
#if SIMSIMD_TARGET_NEON
|
|
360
|
-
if (viable &
|
|
555
|
+
if (viable & simsimd_cap_neon_f16_k)
|
|
361
556
|
switch (kind) {
|
|
362
|
-
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_neon, *c =
|
|
363
|
-
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_neon, *c =
|
|
364
|
-
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_neon, *c =
|
|
365
|
-
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_neon, *c =
|
|
366
|
-
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_neon, *c =
|
|
557
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
558
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
559
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
560
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
561
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
367
562
|
default: break;
|
|
368
563
|
}
|
|
369
564
|
#endif
|
|
@@ -402,21 +597,62 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
402
597
|
|
|
403
598
|
break;
|
|
404
599
|
|
|
600
|
+
// Brain floating-point vectors
|
|
601
|
+
case simsimd_datatype_bf16_k:
|
|
602
|
+
#if SIMSIMD_TARGET_NEON_BF16
|
|
603
|
+
if (viable & simsimd_cap_neon_bf16_k)
|
|
604
|
+
switch (kind) {
|
|
605
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
606
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
607
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
608
|
+
default: break;
|
|
609
|
+
}
|
|
610
|
+
#endif
|
|
611
|
+
#if SIMSIMD_TARGET_HASWELL
|
|
612
|
+
if (viable & simsimd_cap_haswell_k)
|
|
613
|
+
switch (kind) {
|
|
614
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_haswell, *c = simsimd_cap_haswell_k; return;
|
|
615
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_haswell, *c = simsimd_cap_haswell_k; return;
|
|
616
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_haswell, *c = simsimd_cap_haswell_k; return;
|
|
617
|
+
default: break;
|
|
618
|
+
}
|
|
619
|
+
#endif
|
|
620
|
+
#if SIMSIMD_TARGET_GENOA
|
|
621
|
+
if (viable & simsimd_cap_genoa_k)
|
|
622
|
+
switch (kind) {
|
|
623
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_genoa, *c = simsimd_cap_genoa_k; return;
|
|
624
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_genoa, *c = simsimd_cap_genoa_k; return;
|
|
625
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_genoa, *c = simsimd_cap_genoa_k; return;
|
|
626
|
+
default: break;
|
|
627
|
+
}
|
|
628
|
+
#endif
|
|
629
|
+
if (viable & simsimd_cap_serial_k)
|
|
630
|
+
switch (kind) {
|
|
631
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_serial, *c = simsimd_cap_serial_k; return;
|
|
632
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_serial, *c = simsimd_cap_serial_k; return;
|
|
633
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_serial, *c = simsimd_cap_serial_k; return;
|
|
634
|
+
case simsimd_metric_js_k: *m = (m_t)&simsimd_js_bf16_serial, *c = simsimd_cap_serial_k; return;
|
|
635
|
+
case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_bf16_serial, *c = simsimd_cap_serial_k; return;
|
|
636
|
+
default: break;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
break;
|
|
640
|
+
|
|
405
641
|
// Single-byte integer vectors
|
|
406
642
|
case simsimd_datatype_i8_k:
|
|
407
643
|
#if SIMSIMD_TARGET_NEON
|
|
408
|
-
if (viable &
|
|
644
|
+
if (viable & simsimd_cap_neon_i8_k)
|
|
409
645
|
switch (kind) {
|
|
410
|
-
case simsimd_metric_dot_k: *m = (m_t)&
|
|
411
|
-
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_neon, *c =
|
|
412
|
-
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_neon, *c =
|
|
646
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_neon, *c = simsimd_cap_neon_i8_k; return;
|
|
647
|
+
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_neon, *c = simsimd_cap_neon_i8_k; return;
|
|
648
|
+
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_neon, *c = simsimd_cap_neon_i8_k; return;
|
|
413
649
|
default: break;
|
|
414
650
|
}
|
|
415
651
|
#endif
|
|
416
652
|
#if SIMSIMD_TARGET_ICE
|
|
417
653
|
if (viable & simsimd_cap_ice_k)
|
|
418
654
|
switch (kind) {
|
|
419
|
-
case simsimd_metric_dot_k: *m = (m_t)&
|
|
655
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_ice, *c = simsimd_cap_ice_k; return;
|
|
420
656
|
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_ice, *c = simsimd_cap_ice_k; return;
|
|
421
657
|
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_ice, *c = simsimd_cap_ice_k; return;
|
|
422
658
|
default: break;
|
|
@@ -425,7 +661,7 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
425
661
|
#if SIMSIMD_TARGET_HASWELL
|
|
426
662
|
if (viable & simsimd_cap_haswell_k)
|
|
427
663
|
switch (kind) {
|
|
428
|
-
case simsimd_metric_dot_k: *m = (m_t)&
|
|
664
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_haswell, *c = simsimd_cap_haswell_k; return;
|
|
429
665
|
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_haswell, *c = simsimd_cap_haswell_k; return;
|
|
430
666
|
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_haswell, *c = simsimd_cap_haswell_k; return;
|
|
431
667
|
default: break;
|
|
@@ -434,7 +670,7 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
434
670
|
|
|
435
671
|
if (viable & simsimd_cap_serial_k)
|
|
436
672
|
switch (kind) {
|
|
437
|
-
case simsimd_metric_dot_k: *m = (m_t)&
|
|
673
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_serial, *c = simsimd_cap_serial_k; return;
|
|
438
674
|
case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_serial, *c = simsimd_cap_serial_k; return;
|
|
439
675
|
case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_serial, *c = simsimd_cap_serial_k; return;
|
|
440
676
|
default: break;
|
|
@@ -505,14 +741,6 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
505
741
|
default: break;
|
|
506
742
|
}
|
|
507
743
|
#endif
|
|
508
|
-
#if SIMSIMD_TARGET_HASWELL
|
|
509
|
-
if (viable & simsimd_cap_haswell_k)
|
|
510
|
-
switch (kind) {
|
|
511
|
-
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
|
|
512
|
-
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
|
|
513
|
-
default: break;
|
|
514
|
-
}
|
|
515
|
-
#endif
|
|
516
744
|
#if SIMSIMD_TARGET_SKYLAKE
|
|
517
745
|
if (viable & simsimd_cap_skylake_k)
|
|
518
746
|
switch (kind) {
|
|
@@ -521,6 +749,14 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
521
749
|
default: break;
|
|
522
750
|
}
|
|
523
751
|
#endif
|
|
752
|
+
#if SIMSIMD_TARGET_HASWELL
|
|
753
|
+
if (viable & simsimd_cap_haswell_k)
|
|
754
|
+
switch (kind) {
|
|
755
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
|
|
756
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
|
|
757
|
+
default: break;
|
|
758
|
+
}
|
|
759
|
+
#endif
|
|
524
760
|
|
|
525
761
|
if (viable & simsimd_cap_serial_k)
|
|
526
762
|
switch (kind) {
|
|
@@ -570,10 +806,18 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
570
806
|
}
|
|
571
807
|
#endif
|
|
572
808
|
#if SIMSIMD_TARGET_NEON
|
|
573
|
-
if (viable &
|
|
809
|
+
if (viable & simsimd_cap_neon_f16_k)
|
|
810
|
+
switch (kind) {
|
|
811
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
812
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
|
|
813
|
+
default: break;
|
|
814
|
+
}
|
|
815
|
+
#endif
|
|
816
|
+
#if SIMSIMD_TARGET_SAPPHIRE
|
|
817
|
+
if (viable & simsimd_cap_sapphire_k)
|
|
574
818
|
switch (kind) {
|
|
575
|
-
case simsimd_metric_dot_k: *m = (m_t)&
|
|
576
|
-
case simsimd_metric_vdot_k: *m = (m_t)&
|
|
819
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
820
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
|
|
577
821
|
default: break;
|
|
578
822
|
}
|
|
579
823
|
#endif
|
|
@@ -585,19 +829,38 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
585
829
|
default: break;
|
|
586
830
|
}
|
|
587
831
|
#endif
|
|
588
|
-
|
|
589
|
-
if (viable &
|
|
832
|
+
|
|
833
|
+
if (viable & simsimd_cap_serial_k)
|
|
590
834
|
switch (kind) {
|
|
591
|
-
case simsimd_metric_dot_k: *m = (m_t)&
|
|
592
|
-
case simsimd_metric_vdot_k: *m = (m_t)&
|
|
835
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_serial, *c = simsimd_cap_serial_k; return;
|
|
836
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_serial, *c = simsimd_cap_serial_k; return;
|
|
837
|
+
default: break;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
break;
|
|
841
|
+
case simsimd_datatype_bf16c_k:
|
|
842
|
+
|
|
843
|
+
#if SIMSIMD_TARGET_NEON_BF16
|
|
844
|
+
if (viable & simsimd_cap_neon_bf16_k)
|
|
845
|
+
switch (kind) {
|
|
846
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
847
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
|
|
848
|
+
default: break;
|
|
849
|
+
}
|
|
850
|
+
#endif
|
|
851
|
+
#if SIMSIMD_TARGET_GENOA
|
|
852
|
+
if (viable & simsimd_cap_genoa_k)
|
|
853
|
+
switch (kind) {
|
|
854
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
|
|
855
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
|
|
593
856
|
default: break;
|
|
594
857
|
}
|
|
595
858
|
#endif
|
|
596
859
|
|
|
597
860
|
if (viable & simsimd_cap_serial_k)
|
|
598
861
|
switch (kind) {
|
|
599
|
-
case simsimd_metric_dot_k: *m = (m_t)&
|
|
600
|
-
case simsimd_metric_vdot_k: *m = (m_t)&
|
|
862
|
+
case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_serial, *c = simsimd_cap_serial_k; return;
|
|
863
|
+
case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_serial, *c = simsimd_cap_serial_k; return;
|
|
601
864
|
default: break;
|
|
602
865
|
}
|
|
603
866
|
|
|
@@ -605,8 +868,8 @@ SIMSIMD_PUBLIC void simsimd_find_metric_punned( //
|
|
|
605
868
|
}
|
|
606
869
|
}
|
|
607
870
|
|
|
608
|
-
#pragma clang diagnostic pop
|
|
609
871
|
#pragma GCC diagnostic pop
|
|
872
|
+
#pragma clang diagnostic pop
|
|
610
873
|
|
|
611
874
|
/**
|
|
612
875
|
* @brief Selects the most suitable metric implementation based on the given metric kind, datatype,
|
|
@@ -642,11 +905,18 @@ SIMSIMD_PUBLIC simsimd_metric_punned_t simsimd_metric_punned( //
|
|
|
642
905
|
* @return 1 if the CPU supports the SIMD instruction set, 0 otherwise.
|
|
643
906
|
*/
|
|
644
907
|
SIMSIMD_DYNAMIC int simsimd_uses_neon(void);
|
|
908
|
+
SIMSIMD_DYNAMIC int simsimd_uses_neon_f16(void);
|
|
909
|
+
SIMSIMD_DYNAMIC int simsimd_uses_neon_bf16(void);
|
|
910
|
+
SIMSIMD_DYNAMIC int simsimd_uses_neon_i8(void);
|
|
645
911
|
SIMSIMD_DYNAMIC int simsimd_uses_sve(void);
|
|
912
|
+
SIMSIMD_DYNAMIC int simsimd_uses_sve_f16(void);
|
|
913
|
+
SIMSIMD_DYNAMIC int simsimd_uses_sve_bf16(void);
|
|
914
|
+
SIMSIMD_DYNAMIC int simsimd_uses_sve_i8(void);
|
|
646
915
|
SIMSIMD_DYNAMIC int simsimd_uses_haswell(void);
|
|
647
916
|
SIMSIMD_DYNAMIC int simsimd_uses_skylake(void);
|
|
648
917
|
SIMSIMD_DYNAMIC int simsimd_uses_ice(void);
|
|
649
918
|
SIMSIMD_DYNAMIC int simsimd_uses_sapphire(void);
|
|
919
|
+
SIMSIMD_DYNAMIC int simsimd_uses_genoa(void);
|
|
650
920
|
SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
|
|
651
921
|
|
|
652
922
|
/* Inner products
|
|
@@ -665,18 +935,24 @@ SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
|
|
|
665
935
|
*/
|
|
666
936
|
SIMSIMD_DYNAMIC void simsimd_dot_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
667
937
|
simsimd_distance_t* d);
|
|
938
|
+
SIMSIMD_DYNAMIC void simsimd_dot_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
939
|
+
simsimd_distance_t* d);
|
|
668
940
|
SIMSIMD_DYNAMIC void simsimd_dot_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
669
941
|
simsimd_distance_t* d);
|
|
670
942
|
SIMSIMD_DYNAMIC void simsimd_dot_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
671
943
|
simsimd_distance_t* d);
|
|
672
944
|
SIMSIMD_DYNAMIC void simsimd_dot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
673
945
|
simsimd_distance_t* d);
|
|
946
|
+
SIMSIMD_DYNAMIC void simsimd_dot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
947
|
+
simsimd_distance_t* d);
|
|
674
948
|
SIMSIMD_DYNAMIC void simsimd_dot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
675
949
|
simsimd_distance_t* d);
|
|
676
950
|
SIMSIMD_DYNAMIC void simsimd_dot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
677
951
|
simsimd_distance_t* d);
|
|
678
952
|
SIMSIMD_DYNAMIC void simsimd_vdot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
679
953
|
simsimd_distance_t* d);
|
|
954
|
+
SIMSIMD_DYNAMIC void simsimd_vdot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
955
|
+
simsimd_distance_t* d);
|
|
680
956
|
SIMSIMD_DYNAMIC void simsimd_vdot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
681
957
|
simsimd_distance_t* d);
|
|
682
958
|
SIMSIMD_DYNAMIC void simsimd_vdot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
@@ -699,6 +975,8 @@ SIMSIMD_DYNAMIC void simsimd_cos_i8(simsimd_i8_t const* a, simsimd_i8_t const* b
|
|
|
699
975
|
simsimd_distance_t* d);
|
|
700
976
|
SIMSIMD_DYNAMIC void simsimd_cos_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
701
977
|
simsimd_distance_t* d);
|
|
978
|
+
SIMSIMD_DYNAMIC void simsimd_cos_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
979
|
+
simsimd_distance_t* d);
|
|
702
980
|
SIMSIMD_DYNAMIC void simsimd_cos_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
703
981
|
simsimd_distance_t* d);
|
|
704
982
|
SIMSIMD_DYNAMIC void simsimd_cos_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
@@ -707,6 +985,8 @@ SIMSIMD_DYNAMIC void simsimd_l2sq_i8(simsimd_i8_t const* a, simsimd_i8_t const*
|
|
|
707
985
|
simsimd_distance_t* d);
|
|
708
986
|
SIMSIMD_DYNAMIC void simsimd_l2sq_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
709
987
|
simsimd_distance_t* d);
|
|
988
|
+
SIMSIMD_DYNAMIC void simsimd_l2sq_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
989
|
+
simsimd_distance_t* d);
|
|
710
990
|
SIMSIMD_DYNAMIC void simsimd_l2sq_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
711
991
|
simsimd_distance_t* d);
|
|
712
992
|
SIMSIMD_DYNAMIC void simsimd_l2sq_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
@@ -746,12 +1026,16 @@ SIMSIMD_DYNAMIC void simsimd_jaccard_b8(simsimd_b8_t const* a, simsimd_b8_t cons
|
|
|
746
1026
|
*/
|
|
747
1027
|
SIMSIMD_DYNAMIC void simsimd_kl_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
748
1028
|
simsimd_distance_t* d);
|
|
1029
|
+
SIMSIMD_DYNAMIC void simsimd_kl_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1030
|
+
simsimd_distance_t* d);
|
|
749
1031
|
SIMSIMD_DYNAMIC void simsimd_kl_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
750
1032
|
simsimd_distance_t* d);
|
|
751
1033
|
SIMSIMD_DYNAMIC void simsimd_kl_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
752
1034
|
simsimd_distance_t* d);
|
|
753
1035
|
SIMSIMD_DYNAMIC void simsimd_js_f16(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
754
1036
|
simsimd_distance_t* d);
|
|
1037
|
+
SIMSIMD_DYNAMIC void simsimd_js_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1038
|
+
simsimd_distance_t* d);
|
|
755
1039
|
SIMSIMD_DYNAMIC void simsimd_js_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
756
1040
|
simsimd_distance_t* d);
|
|
757
1041
|
SIMSIMD_DYNAMIC void simsimd_js_f64(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
@@ -765,17 +1049,28 @@ SIMSIMD_DYNAMIC void simsimd_js_f64(simsimd_f64_t const* a, simsimd_f64_t const*
|
|
|
765
1049
|
* - Check if the CPU supports AVX512F and AVX512BW extensions on Skylake x86 CPUs and newer
|
|
766
1050
|
* - Check if the CPU supports AVX512VNNI, AVX512IFMA, AVX512BITALG, AVX512VBMI2, and AVX512VPOPCNTDQ
|
|
767
1051
|
* extensions on Ice Lake x86 CPUs and newer
|
|
1052
|
+
* - Check if the CPU supports AVX512BF16 extensions on Genoa x86 CPUs and newer
|
|
768
1053
|
* - Check if the CPU supports AVX512FP16 extensions on Sapphire Rapids x86 CPUs and newer
|
|
769
1054
|
*
|
|
770
1055
|
* @return 1 if the CPU supports the SIMD instruction set, 0 otherwise.
|
|
771
1056
|
*/
|
|
1057
|
+
|
|
1058
|
+
// clang-format off
|
|
772
1059
|
SIMSIMD_PUBLIC int simsimd_uses_neon(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON; }
|
|
1060
|
+
SIMSIMD_PUBLIC int simsimd_uses_neon_f16(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON && SIMSIMD_NATIVE_F16; }
|
|
1061
|
+
SIMSIMD_PUBLIC int simsimd_uses_neon_bf16(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON && SIMSIMD_NATIVE_BF16; }
|
|
1062
|
+
SIMSIMD_PUBLIC int simsimd_uses_neon_i8(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON; }
|
|
773
1063
|
SIMSIMD_PUBLIC int simsimd_uses_sve(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE; }
|
|
1064
|
+
SIMSIMD_PUBLIC int simsimd_uses_sve_f16(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE && SIMSIMD_NATIVE_F16; }
|
|
1065
|
+
SIMSIMD_PUBLIC int simsimd_uses_sve_bf16(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE && SIMSIMD_NATIVE_BF16; }
|
|
1066
|
+
SIMSIMD_PUBLIC int simsimd_uses_sve_i8(void) { return SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE; }
|
|
774
1067
|
SIMSIMD_PUBLIC int simsimd_uses_haswell(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_HASWELL; }
|
|
775
1068
|
SIMSIMD_PUBLIC int simsimd_uses_skylake(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SKYLAKE; }
|
|
776
1069
|
SIMSIMD_PUBLIC int simsimd_uses_ice(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_ICE; }
|
|
777
1070
|
SIMSIMD_PUBLIC int simsimd_uses_sapphire(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SAPPHIRE; }
|
|
1071
|
+
SIMSIMD_PUBLIC int simsimd_uses_genoa(void) { return SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_GENOA; }
|
|
778
1072
|
SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void) { return simsimd_capabilities_implementation(); }
|
|
1073
|
+
// clang-format on
|
|
779
1074
|
|
|
780
1075
|
/* Inner products
|
|
781
1076
|
* - Dot product: the sum of the products of the corresponding elements of two vectors.
|
|
@@ -797,15 +1092,26 @@ SIMSIMD_PUBLIC void simsimd_dot_f16(simsimd_f16_t const* a, simsimd_f16_t const*
|
|
|
797
1092
|
simsimd_dot_f16_sve(a, b, n, d);
|
|
798
1093
|
#elif SIMSIMD_TARGET_NEON
|
|
799
1094
|
simsimd_dot_f16_neon(a, b, n, d);
|
|
800
|
-
#elif SIMSIMD_TARGET_HASWELL
|
|
801
|
-
simsimd_dot_f16_haswell(a, b, n, d);
|
|
802
1095
|
#elif SIMSIMD_TARGET_SAPPHIRE
|
|
803
1096
|
simsimd_dot_f16_sapphire(a, b, n, d);
|
|
1097
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1098
|
+
simsimd_dot_f16_haswell(a, b, n, d);
|
|
804
1099
|
#else
|
|
805
1100
|
simsimd_dot_f16_serial(a, b, n, d);
|
|
806
1101
|
#endif
|
|
807
1102
|
}
|
|
808
1103
|
|
|
1104
|
+
SIMSIMD_PUBLIC void simsimd_dot_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1105
|
+
simsimd_distance_t* d) {
|
|
1106
|
+
#if SIMSIMD_TARGET_GENOA
|
|
1107
|
+
simsimd_dot_bf16_genoa(a, b, n, d);
|
|
1108
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1109
|
+
simsimd_dot_bf16_haswell(a, b, n, d);
|
|
1110
|
+
#else
|
|
1111
|
+
simsimd_dot_bf16_serial(a, b, n, d);
|
|
1112
|
+
#endif
|
|
1113
|
+
}
|
|
1114
|
+
|
|
809
1115
|
SIMSIMD_PUBLIC void simsimd_dot_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
810
1116
|
simsimd_distance_t* d) {
|
|
811
1117
|
#if SIMSIMD_TARGET_SVE
|
|
@@ -834,24 +1140,32 @@ SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16_t const* a, simsimd_f16_t const
|
|
|
834
1140
|
simsimd_dot_f16c_sve(a, b, n, d);
|
|
835
1141
|
#elif SIMSIMD_TARGET_NEON
|
|
836
1142
|
simsimd_dot_f16c_neon(a, b, n, d);
|
|
1143
|
+
#elif SIMSIMD_TARGET_SAPPHIRE
|
|
1144
|
+
simsimd_dot_f16c_sapphire(a, b, n, d);
|
|
837
1145
|
#elif SIMSIMD_TARGET_HASWELL
|
|
838
1146
|
simsimd_dot_f16c_haswell(a, b, n, d);
|
|
839
|
-
#elif SIMSIMD_TARGET_sapphire
|
|
840
|
-
simsimd_dot_f16c_sapphire(a, b, n, d);
|
|
841
1147
|
#else
|
|
842
1148
|
simsimd_dot_f16c_serial(a, b, n, d);
|
|
843
1149
|
#endif
|
|
844
1150
|
}
|
|
1151
|
+
SIMSIMD_PUBLIC void simsimd_dot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1152
|
+
simsimd_distance_t* d) {
|
|
1153
|
+
#if SIMSIMD_TARGET_GENOA
|
|
1154
|
+
simsimd_dot_bf16c_genoa(a, b, n, d);
|
|
1155
|
+
#else
|
|
1156
|
+
simsimd_dot_bf16c_serial(a, b, n, d);
|
|
1157
|
+
#endif
|
|
1158
|
+
}
|
|
845
1159
|
SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
846
1160
|
simsimd_distance_t* d) {
|
|
847
1161
|
#if SIMSIMD_TARGET_SVE
|
|
848
1162
|
simsimd_dot_f32c_sve(a, b, n, d);
|
|
849
1163
|
#elif SIMSIMD_TARGET_NEON
|
|
850
1164
|
simsimd_dot_f32c_neon(a, b, n, d);
|
|
851
|
-
#elif SIMSIMD_TARGET_HASWELL
|
|
852
|
-
simsimd_dot_f32c_haswell(a, b, n, d);
|
|
853
1165
|
#elif SIMSIMD_TARGET_SKYLAKE
|
|
854
1166
|
simsimd_dot_f32c_skylake(a, b, n, d);
|
|
1167
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1168
|
+
simsimd_dot_f32c_haswell(a, b, n, d);
|
|
855
1169
|
#else
|
|
856
1170
|
simsimd_dot_f32c_serial(a, b, n, d);
|
|
857
1171
|
#endif
|
|
@@ -869,39 +1183,43 @@ SIMSIMD_PUBLIC void simsimd_dot_f64c(simsimd_f64_t const* a, simsimd_f64_t const
|
|
|
869
1183
|
SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n,
|
|
870
1184
|
simsimd_distance_t* d) {
|
|
871
1185
|
#if SIMSIMD_TARGET_SVE
|
|
872
|
-
|
|
1186
|
+
simsimd_vdot_f16c_sve(a, b, n, d);
|
|
873
1187
|
#elif SIMSIMD_TARGET_NEON
|
|
874
1188
|
simsimd_dot_f16c_neon(a, b, n, d);
|
|
1189
|
+
#elif SIMSIMD_TARGET_SAPPHIRE
|
|
1190
|
+
simsimd_dot_f16c_sapphire(a, b, n, d);
|
|
875
1191
|
#elif SIMSIMD_TARGET_HASWELL
|
|
876
1192
|
simsimd_dot_f16c_haswell(a, b, n, d);
|
|
877
|
-
#elif SIMSIMD_TARGET_sapphire
|
|
878
|
-
simsimd_dot_f16c_sapphire(a, b, n, d);
|
|
879
1193
|
#else
|
|
880
|
-
|
|
1194
|
+
simsimd_vdot_f16c_serial(a, b, n, d);
|
|
881
1195
|
#endif
|
|
882
1196
|
}
|
|
1197
|
+
SIMSIMD_PUBLIC void simsimd_vdot_bf16c(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1198
|
+
simsimd_distance_t* d) {
|
|
1199
|
+
simsimd_vdot_bf16c_serial(a, b, n, d);
|
|
1200
|
+
}
|
|
883
1201
|
SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
884
1202
|
simsimd_distance_t* d) {
|
|
885
1203
|
#if SIMSIMD_TARGET_SVE
|
|
886
|
-
|
|
1204
|
+
simsimd_vdot_f32c_sve(a, b, n, d);
|
|
887
1205
|
#elif SIMSIMD_TARGET_NEON
|
|
888
1206
|
simsimd_dot_f32c_neon(a, b, n, d);
|
|
889
|
-
#elif SIMSIMD_TARGET_HASWELL
|
|
890
|
-
simsimd_dot_f32c_haswell(a, b, n, d);
|
|
891
1207
|
#elif SIMSIMD_TARGET_SKYLAKE
|
|
892
1208
|
simsimd_dot_f32c_skylake(a, b, n, d);
|
|
1209
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1210
|
+
simsimd_dot_f32c_haswell(a, b, n, d);
|
|
893
1211
|
#else
|
|
894
|
-
|
|
1212
|
+
simsimd_vdot_f32c_serial(a, b, n, d);
|
|
895
1213
|
#endif
|
|
896
1214
|
}
|
|
897
1215
|
SIMSIMD_PUBLIC void simsimd_vdot_f64c(simsimd_f64_t const* a, simsimd_f64_t const* b, simsimd_size_t n,
|
|
898
1216
|
simsimd_distance_t* d) {
|
|
899
1217
|
#if SIMSIMD_TARGET_SVE
|
|
900
|
-
|
|
1218
|
+
simsimd_vdot_f64c_sve(a, b, n, d);
|
|
901
1219
|
#elif SIMSIMD_TARGET_SKYLAKE
|
|
902
|
-
|
|
1220
|
+
simsimd_vdot_f64c_skylake(a, b, n, d);
|
|
903
1221
|
#else
|
|
904
|
-
|
|
1222
|
+
simsimd_vdot_f64c_serial(a, b, n, d);
|
|
905
1223
|
#endif
|
|
906
1224
|
}
|
|
907
1225
|
|
|
@@ -956,6 +1274,16 @@ SIMSIMD_PUBLIC void simsimd_cos_f16(simsimd_f16_t const* a, simsimd_f16_t const*
|
|
|
956
1274
|
simsimd_cos_f16_serial(a, b, n, d);
|
|
957
1275
|
#endif
|
|
958
1276
|
}
|
|
1277
|
+
SIMSIMD_PUBLIC void simsimd_cos_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1278
|
+
simsimd_distance_t* d) {
|
|
1279
|
+
#if SIMSIMD_TARGET_GENOA
|
|
1280
|
+
simsimd_cos_bf16_genoa(a, b, n, d);
|
|
1281
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1282
|
+
simsimd_cos_bf16_haswell(a, b, n, d);
|
|
1283
|
+
#else
|
|
1284
|
+
simsimd_cos_bf16_serial(a, b, n, d);
|
|
1285
|
+
#endif
|
|
1286
|
+
}
|
|
959
1287
|
SIMSIMD_PUBLIC void simsimd_cos_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
960
1288
|
simsimd_distance_t* d) {
|
|
961
1289
|
#if SIMSIMD_TARGET_SVE
|
|
@@ -984,7 +1312,7 @@ SIMSIMD_PUBLIC void simsimd_l2sq_f16(simsimd_f16_t const* a, simsimd_f16_t const
|
|
|
984
1312
|
simsimd_l2sq_f16_sve(a, b, n, d);
|
|
985
1313
|
#elif SIMSIMD_TARGET_NEON
|
|
986
1314
|
simsimd_l2sq_f16_neon(a, b, n, d);
|
|
987
|
-
#elif
|
|
1315
|
+
#elif SIMSIMD_TARGET_SAPPHIRE
|
|
988
1316
|
simsimd_l2sq_f16_sapphire(a, b, n, d);
|
|
989
1317
|
#elif SIMSIMD_TARGET_HASWELL
|
|
990
1318
|
simsimd_l2sq_f16_haswell(a, b, n, d);
|
|
@@ -992,6 +1320,16 @@ SIMSIMD_PUBLIC void simsimd_l2sq_f16(simsimd_f16_t const* a, simsimd_f16_t const
|
|
|
992
1320
|
simsimd_l2sq_f16_serial(a, b, n, d);
|
|
993
1321
|
#endif
|
|
994
1322
|
}
|
|
1323
|
+
SIMSIMD_PUBLIC void simsimd_l2sq_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1324
|
+
simsimd_distance_t* d) {
|
|
1325
|
+
#if SIMSIMD_TARGET_GENOA
|
|
1326
|
+
simsimd_l2sq_bf16_genoa(a, b, n, d);
|
|
1327
|
+
#elif SIMSIMD_TARGET_HASWELL
|
|
1328
|
+
simsimd_l2sq_bf16_haswell(a, b, n, d);
|
|
1329
|
+
#else
|
|
1330
|
+
simsimd_l2sq_bf16_serial(a, b, n, d);
|
|
1331
|
+
#endif
|
|
1332
|
+
}
|
|
995
1333
|
SIMSIMD_PUBLIC void simsimd_l2sq_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
996
1334
|
simsimd_distance_t* d) {
|
|
997
1335
|
#if SIMSIMD_TARGET_SVE
|
|
@@ -1081,6 +1419,10 @@ SIMSIMD_PUBLIC void simsimd_kl_f16(simsimd_f16_t const* a, simsimd_f16_t const*
|
|
|
1081
1419
|
simsimd_kl_f16_serial(a, b, n, d);
|
|
1082
1420
|
#endif
|
|
1083
1421
|
}
|
|
1422
|
+
SIMSIMD_PUBLIC void simsimd_kl_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1423
|
+
simsimd_distance_t* d) {
|
|
1424
|
+
simsimd_kl_bf16_serial(a, b, n, d);
|
|
1425
|
+
}
|
|
1084
1426
|
SIMSIMD_PUBLIC void simsimd_kl_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
1085
1427
|
simsimd_distance_t* d) {
|
|
1086
1428
|
#if SIMSIMD_TARGET_NEON
|
|
@@ -1105,6 +1447,10 @@ SIMSIMD_PUBLIC void simsimd_js_f16(simsimd_f16_t const* a, simsimd_f16_t const*
|
|
|
1105
1447
|
simsimd_js_f16_serial(a, b, n, d);
|
|
1106
1448
|
#endif
|
|
1107
1449
|
}
|
|
1450
|
+
SIMSIMD_PUBLIC void simsimd_js_bf16(simsimd_bf16_t const* a, simsimd_bf16_t const* b, simsimd_size_t n,
|
|
1451
|
+
simsimd_distance_t* d) {
|
|
1452
|
+
simsimd_js_bf16_serial(a, b, n, d);
|
|
1453
|
+
}
|
|
1108
1454
|
SIMSIMD_PUBLIC void simsimd_js_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n,
|
|
1109
1455
|
simsimd_distance_t* d) {
|
|
1110
1456
|
#if SIMSIMD_TARGET_NEON
|