usearch 2.26.0 → 2.26.2
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 +2 -2
- package/cpp/test.cpp +66 -3
- package/include/usearch/index.hpp +9 -1
- package/include/usearch/index_dense.hpp +16 -5
- package/numkong/CITATION.cff +13 -9
- package/numkong/CONTRIBUTING.md +29 -24
- package/numkong/Cargo.toml +1 -1
- package/numkong/README.md +21 -7
- package/numkong/binding.gyp +47 -31
- package/numkong/build.rs +15 -5
- package/numkong/c/dispatch.h +0 -1
- package/numkong/c/parallel.c +139 -0
- package/numkong/c/parallel.h +47 -0
- package/numkong/cmake/toolchain-wasi.cmake +39 -5
- package/numkong/include/README.md +24 -17
- package/numkong/include/numkong/attention/sapphireamx.h +6 -6
- package/numkong/include/numkong/attention/sme.h +2 -2
- package/numkong/include/numkong/capabilities.h +2 -2
- package/numkong/include/numkong/cast/README.md +9 -7
- package/numkong/include/numkong/cast/loongsonasx.h +48 -40
- package/numkong/include/numkong/cast/serial.h +89 -11
- package/numkong/include/numkong/cast.h +3 -3
- package/numkong/include/numkong/curved/README.md +10 -10
- package/numkong/include/numkong/curved/neon.h +1 -0
- package/numkong/include/numkong/curved/neonbfdot.h +1 -0
- package/numkong/include/numkong/curved/smef64.h +1 -0
- package/numkong/include/numkong/dot/README.md +18 -18
- package/numkong/include/numkong/dot/alder.h +8 -8
- package/numkong/include/numkong/dot/haswell.h +8 -8
- package/numkong/include/numkong/dot/icelake.h +12 -12
- package/numkong/include/numkong/dot/loongsonasx.h +6 -6
- package/numkong/include/numkong/dot/neon.h +2 -1
- package/numkong/include/numkong/dot/neonbfdot.h +1 -0
- package/numkong/include/numkong/dot/neonfhm.h +1 -0
- package/numkong/include/numkong/dot/neonsdot.h +1 -0
- package/numkong/include/numkong/dot/powervsx.h +3 -3
- package/numkong/include/numkong/dot/serial.h +19 -6
- package/numkong/include/numkong/dot/skylake.h +4 -4
- package/numkong/include/numkong/dot/svehalf.h +1 -1
- package/numkong/include/numkong/dot/v128relaxed.h +24 -23
- package/numkong/include/numkong/dots/README.md +26 -26
- package/numkong/include/numkong/dots/genoa.h +3 -1
- package/numkong/include/numkong/dots/icelake.h +1 -0
- package/numkong/include/numkong/dots/powervsx.h +1 -1
- package/numkong/include/numkong/dots/serial.h +32 -33
- package/numkong/include/numkong/dots/sierra.h +4 -3
- package/numkong/include/numkong/each/README.md +5 -3
- package/numkong/include/numkong/each/sapphire.h +2 -0
- package/numkong/include/numkong/each/skylake.h +1 -0
- package/numkong/include/numkong/geospatial/README.md +6 -6
- package/numkong/include/numkong/geospatial/v128relaxed.h +1 -0
- package/numkong/include/numkong/maxsim/README.md +5 -5
- package/numkong/include/numkong/maxsim/genoa.h +4 -0
- package/numkong/include/numkong/maxsim/icelake.h +1 -0
- package/numkong/include/numkong/maxsim/serial.h +22 -9
- package/numkong/include/numkong/maxsim/sme.h +3 -2
- package/numkong/include/numkong/mesh/README.md +7 -4
- package/numkong/include/numkong/mesh/genoa.h +2 -2
- package/numkong/include/numkong/mesh/haswell.h +8 -8
- package/numkong/include/numkong/mesh/neon.h +6 -6
- package/numkong/include/numkong/mesh/neonbfdot.h +3 -2
- package/numkong/include/numkong/mesh/neonfhm.h +3 -2
- package/numkong/include/numkong/mesh/rvv.h +4 -4
- package/numkong/include/numkong/mesh/serial.h +17 -17
- package/numkong/include/numkong/mesh/skylake.h +4 -4
- package/numkong/include/numkong/mesh/v128relaxed.h +4 -4
- package/numkong/include/numkong/mesh.hpp +2 -2
- package/numkong/include/numkong/numkong.h +1 -1
- package/numkong/include/numkong/numkong.hpp +1 -1
- package/numkong/include/numkong/probability/README.md +17 -15
- package/numkong/include/numkong/probability/skylake.h +1 -1
- package/numkong/include/numkong/reduce/README.md +27 -21
- package/numkong/include/numkong/reduce/genoa.h +2 -1
- package/numkong/include/numkong/reduce/icelake.h +1 -0
- package/numkong/include/numkong/reduce/neon.h +1 -1
- package/numkong/include/numkong/reduce/serial.h +9 -9
- package/numkong/include/numkong/reduce/skylake.h +4 -4
- package/numkong/include/numkong/reduce.hpp +38 -0
- package/numkong/include/numkong/scalar/README.md +29 -28
- package/numkong/include/numkong/set/README.md +17 -14
- package/numkong/include/numkong/set/haswell.h +15 -16
- package/numkong/include/numkong/set/icelake.h +15 -16
- package/numkong/include/numkong/set/loongsonasx.h +12 -10
- package/numkong/include/numkong/set/neon.h +15 -19
- package/numkong/include/numkong/set/powervsx.h +15 -21
- package/numkong/include/numkong/set/serial.h +19 -20
- package/numkong/include/numkong/set/v128relaxed.h +10 -8
- package/numkong/include/numkong/sets/icelake.h +1 -0
- package/numkong/include/numkong/sparse/README.md +4 -4
- package/numkong/include/numkong/sparse/icelake.h +1 -0
- package/numkong/include/numkong/sparse/neon.h +1 -0
- package/numkong/include/numkong/sparse/serial.h +10 -3
- package/numkong/include/numkong/sparse/turin.h +1 -0
- package/numkong/include/numkong/spatial/README.md +25 -24
- package/numkong/include/numkong/spatial/alder.h +2 -1
- package/numkong/include/numkong/spatial/haswell.h +48 -40
- package/numkong/include/numkong/spatial/icelake.h +2 -1
- package/numkong/include/numkong/spatial/neon.h +54 -46
- package/numkong/include/numkong/spatial/neonbfdot.h +1 -1
- package/numkong/include/numkong/spatial/powervsx.h +54 -46
- package/numkong/include/numkong/spatial/serial.h +56 -46
- package/numkong/include/numkong/spatial/sierra.h +4 -3
- package/numkong/include/numkong/spatial/skylake.h +27 -22
- package/numkong/include/numkong/spatial/sve.h +6 -6
- package/numkong/include/numkong/spatial/svebfdot.h +1 -1
- package/numkong/include/numkong/spatial/svehalf.h +1 -1
- package/numkong/include/numkong/spatial/v128relaxed.h +36 -30
- package/numkong/include/numkong/spatials/README.md +15 -15
- package/numkong/include/numkong/spatials/genoa.h +3 -0
- package/numkong/include/numkong/spatials/graniteamx.h +2 -0
- package/numkong/include/numkong/spatials/icelake.h +1 -0
- package/numkong/include/numkong/spatials/sierra.h +1 -0
- package/numkong/include/numkong/tensor.hpp +236 -123
- package/numkong/include/numkong/trigonometry/README.md +4 -4
- package/numkong/include/numkong/trigonometry/serial.h +6 -6
- package/numkong/include/numkong/trigonometry/v128relaxed.h +1 -0
- package/numkong/include/numkong/types.hpp +46 -16
- package/numkong/include/numkong/vector.hpp +116 -23
- package/numkong/javascript/@numkong-darwin-arm64/package.json +1 -1
- package/numkong/javascript/@numkong-darwin-x64/package.json +1 -1
- package/numkong/javascript/@numkong-linux-arm64/package.json +1 -1
- package/numkong/javascript/@numkong-linux-x64/package.json +1 -1
- package/numkong/javascript/@numkong-win32-arm64/package.json +1 -1
- package/numkong/javascript/@numkong-win32-x64/package.json +1 -1
- package/numkong/javascript/README.md +18 -16
- package/numkong/javascript/numkong.c +70 -40
- package/numkong/package.json +8 -8
- package/numkong/rust/README.md +19 -9
- package/numkong/rust/cast.rs +52 -1
- package/numkong/rust/each.rs +480 -7
- package/numkong/rust/matrix.rs +877 -216
- package/numkong/rust/numkong.rs +12 -8
- package/numkong/rust/reduce.rs +433 -5
- package/numkong/rust/tensor.rs +450 -842
- package/numkong/rust/vector.rs +520 -101
- package/numkong/swift/README.md +5 -3
- package/numkong/test/README.md +4 -4
- package/numkong/test/test-wasi.mjs +17 -0
- package/numkong/test/test_each.cpp +30 -1
- package/numkong/test/test_each.py +74 -1
- package/numkong/test/test_reduce.cpp +51 -0
- package/numkong/test/test_tensor.cpp +2 -63
- package/numkong/test/test_tensor.py +93 -0
- package/package.json +1 -1
- 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/prebuilds/win32-x64/usearch.node +0 -0
|
@@ -13,17 +13,6 @@
|
|
|
13
13
|
extern "C" {
|
|
14
14
|
#endif
|
|
15
15
|
|
|
16
|
-
/* Keep the serial conversions below actually scalar, regardless of build type.
|
|
17
|
-
* Without this, -O3 + LTO can vectorize or clone the serial kernels under AVX-512
|
|
18
|
-
* callers in dispatch_*.c, which wastes binary and breaks the nk_*_serial-as-scalar-oracle
|
|
19
|
-
* contract. See dots/serial.h. */
|
|
20
|
-
#if defined(__clang__)
|
|
21
|
-
#pragma clang attribute push(__attribute__((noinline)), apply_to = function)
|
|
22
|
-
#elif defined(__GNUC__)
|
|
23
|
-
#pragma GCC push_options
|
|
24
|
-
#pragma GCC optimize("no-tree-vectorize", "no-tree-slp-vectorize", "no-ipa-cp-clone", "no-inline")
|
|
25
|
-
#endif
|
|
26
|
-
|
|
27
16
|
#pragma region Type Punned Loads and Stores
|
|
28
17
|
|
|
29
18
|
/** @brief Type-agnostic 32-bit full load (scalar). */
|
|
@@ -563,6 +552,17 @@ NK_INTERNAL void nk_strided_load_b8x16_serial_(void const *src, nk_size_t stride
|
|
|
563
552
|
|
|
564
553
|
#pragma endregion Type Punned Loads and Stores
|
|
565
554
|
|
|
555
|
+
/* Keep the serial conversions below actually scalar, regardless of build type.
|
|
556
|
+
* Without this, -O3 + LTO can vectorize or clone the serial kernels under AVX-512
|
|
557
|
+
* callers in dispatch_*.c, which wastes binary and breaks the nk_*_serial-as-scalar-oracle
|
|
558
|
+
* contract. See dots/serial.h. */
|
|
559
|
+
#if defined(__clang__)
|
|
560
|
+
#pragma clang attribute push(__attribute__((noinline)), apply_to = function)
|
|
561
|
+
#elif defined(__GNUC__)
|
|
562
|
+
#pragma GCC push_options
|
|
563
|
+
#pragma GCC optimize("no-tree-vectorize", "no-tree-slp-vectorize", "no-ipa-cp-clone", "no-inline")
|
|
564
|
+
#endif
|
|
565
|
+
|
|
566
566
|
/**
|
|
567
567
|
* @brief Expands an `f16` (IEEE-754 16-bit) to a `float`.
|
|
568
568
|
*
|
|
@@ -622,6 +622,12 @@ NK_PUBLIC void nk_f16_to_f32_serial(nk_f16_t const *src, nk_f32_t *dest) {
|
|
|
622
622
|
#endif
|
|
623
623
|
}
|
|
624
624
|
|
|
625
|
+
#if defined(__clang__)
|
|
626
|
+
#pragma clang attribute pop
|
|
627
|
+
#elif defined(__GNUC__)
|
|
628
|
+
#pragma GCC pop_options
|
|
629
|
+
#endif
|
|
630
|
+
|
|
625
631
|
/** @brief Load 4 × f16 from memory and upcast them to 4 × f32. */
|
|
626
632
|
NK_INTERNAL void nk_load_f16x4_to_f32x4_serial_(void const *src, nk_b128_vec_t *dst) {
|
|
627
633
|
nk_f16_t const *scalars = (nk_f16_t const *)src;
|
|
@@ -644,6 +650,13 @@ NK_INTERNAL void nk_partial_load_f16x4_to_f32x4_serial_(nk_f16_t const *src, nk_
|
|
|
644
650
|
}
|
|
645
651
|
}
|
|
646
652
|
|
|
653
|
+
#if defined(__clang__)
|
|
654
|
+
#pragma clang attribute push(__attribute__((noinline)), apply_to = function)
|
|
655
|
+
#elif defined(__GNUC__)
|
|
656
|
+
#pragma GCC push_options
|
|
657
|
+
#pragma GCC optimize("no-tree-vectorize", "no-tree-slp-vectorize", "no-ipa-cp-clone", "no-inline")
|
|
658
|
+
#endif
|
|
659
|
+
|
|
647
660
|
/**
|
|
648
661
|
* @brief Compresses a `float` to an `f16` (IEEE-754 16-bit).
|
|
649
662
|
*
|
|
@@ -946,6 +959,12 @@ NK_PUBLIC void nk_f32_to_e4m3_serial(nk_f32_t const *src, nk_e4m3_t *dest) {
|
|
|
946
959
|
*dest = (nk_e4m3_t)(sign | (exp_field << 3) | mant_field);
|
|
947
960
|
}
|
|
948
961
|
|
|
962
|
+
#if defined(__clang__)
|
|
963
|
+
#pragma clang attribute pop
|
|
964
|
+
#elif defined(__GNUC__)
|
|
965
|
+
#pragma GCC pop_options
|
|
966
|
+
#endif
|
|
967
|
+
|
|
949
968
|
/**
|
|
950
969
|
* @brief Convert FP8 E4M3 to IEEE 754 half-precision float.
|
|
951
970
|
*
|
|
@@ -1039,6 +1058,13 @@ NK_INTERNAL void nk_e5m2_to_f32_manual_(nk_e5m2_t const *src, nk_f32_t *dest) {
|
|
|
1039
1058
|
*dest = conv.f;
|
|
1040
1059
|
}
|
|
1041
1060
|
|
|
1061
|
+
#if defined(__clang__)
|
|
1062
|
+
#pragma clang attribute push(__attribute__((noinline)), apply_to = function)
|
|
1063
|
+
#elif defined(__GNUC__)
|
|
1064
|
+
#pragma GCC push_options
|
|
1065
|
+
#pragma GCC optimize("no-tree-vectorize", "no-tree-slp-vectorize", "no-ipa-cp-clone", "no-inline")
|
|
1066
|
+
#endif
|
|
1067
|
+
|
|
1042
1068
|
NK_PUBLIC void nk_e5m2_to_f32_serial(nk_e5m2_t const *src, nk_f32_t *dest) {
|
|
1043
1069
|
static nk_u32_t const lut[128] = {
|
|
1044
1070
|
0x00000000, 0x37800000, 0x38000000, 0x38400000, // exp=0 sub
|
|
@@ -1181,6 +1207,12 @@ NK_PUBLIC void nk_f32_to_e5m2_serial(nk_f32_t const *src, nk_e5m2_t *dest) {
|
|
|
1181
1207
|
*dest = (nk_e5m2_t)(sign | (exp_field << 2) | mant_field);
|
|
1182
1208
|
}
|
|
1183
1209
|
|
|
1210
|
+
#if defined(__clang__)
|
|
1211
|
+
#pragma clang attribute pop
|
|
1212
|
+
#elif defined(__GNUC__)
|
|
1213
|
+
#pragma GCC pop_options
|
|
1214
|
+
#endif
|
|
1215
|
+
|
|
1184
1216
|
/**
|
|
1185
1217
|
* @brief Convert FP8 E5M2 to IEEE 754 half-precision float.
|
|
1186
1218
|
*
|
|
@@ -1315,6 +1347,13 @@ NK_INTERNAL void nk_e2m3_to_f32_manual_(nk_e2m3_t const *src, nk_f32_t *dest) {
|
|
|
1315
1347
|
*dest = conv.f;
|
|
1316
1348
|
}
|
|
1317
1349
|
|
|
1350
|
+
#if defined(__clang__)
|
|
1351
|
+
#pragma clang attribute push(__attribute__((noinline)), apply_to = function)
|
|
1352
|
+
#elif defined(__GNUC__)
|
|
1353
|
+
#pragma GCC push_options
|
|
1354
|
+
#pragma GCC optimize("no-tree-vectorize", "no-tree-slp-vectorize", "no-ipa-cp-clone", "no-inline")
|
|
1355
|
+
#endif
|
|
1356
|
+
|
|
1318
1357
|
NK_PUBLIC void nk_e2m3_to_f32_serial(nk_e2m3_t const *src, nk_f32_t *dest) {
|
|
1319
1358
|
static nk_u32_t const lut[32] = {
|
|
1320
1359
|
0x00000000, 0x3E000000, 0x3E800000, 0x3EC00000, 0x3F000000, 0x3F200000, 0x3F400000, 0x3F600000, // exp=0 sub
|
|
@@ -1415,6 +1454,12 @@ NK_PUBLIC void nk_f32_to_e2m3_serial(nk_f32_t const *src, nk_e2m3_t *dest) {
|
|
|
1415
1454
|
*dest = (nk_e2m3_t)(sign | (exp_field << 3) | mant_field);
|
|
1416
1455
|
}
|
|
1417
1456
|
|
|
1457
|
+
#if defined(__clang__)
|
|
1458
|
+
#pragma clang attribute pop
|
|
1459
|
+
#elif defined(__GNUC__)
|
|
1460
|
+
#pragma GCC pop_options
|
|
1461
|
+
#endif
|
|
1462
|
+
|
|
1418
1463
|
/**
|
|
1419
1464
|
* @brief Convert FP6 E3M2FN to IEEE 754 single-precision float.
|
|
1420
1465
|
*
|
|
@@ -1452,6 +1497,13 @@ NK_INTERNAL void nk_e3m2_to_f32_manual_(nk_e3m2_t const *src, nk_f32_t *dest) {
|
|
|
1452
1497
|
*dest = conv.f;
|
|
1453
1498
|
}
|
|
1454
1499
|
|
|
1500
|
+
#if defined(__clang__)
|
|
1501
|
+
#pragma clang attribute push(__attribute__((noinline)), apply_to = function)
|
|
1502
|
+
#elif defined(__GNUC__)
|
|
1503
|
+
#pragma GCC push_options
|
|
1504
|
+
#pragma GCC optimize("no-tree-vectorize", "no-tree-slp-vectorize", "no-ipa-cp-clone", "no-inline")
|
|
1505
|
+
#endif
|
|
1506
|
+
|
|
1455
1507
|
NK_PUBLIC void nk_e3m2_to_f32_serial(nk_e3m2_t const *src, nk_f32_t *dest) {
|
|
1456
1508
|
static nk_u32_t const lut[32] = {
|
|
1457
1509
|
0x00000000, 0x3D800000, 0x3E000000, 0x3E400000, // exp=0 sub
|
|
@@ -1557,6 +1609,12 @@ NK_PUBLIC void nk_f32_to_e3m2_serial(nk_f32_t const *src, nk_e3m2_t *dest) {
|
|
|
1557
1609
|
*dest = (nk_e3m2_t)(sign | (exp_field << 2) | mant_field);
|
|
1558
1610
|
}
|
|
1559
1611
|
|
|
1612
|
+
#if defined(__clang__)
|
|
1613
|
+
#pragma clang attribute pop
|
|
1614
|
+
#elif defined(__GNUC__)
|
|
1615
|
+
#pragma GCC pop_options
|
|
1616
|
+
#endif
|
|
1617
|
+
|
|
1560
1618
|
NK_INTERNAL void nk_f16_to_f64_serial(nk_f16_t const *x, nk_f64_t *y) {
|
|
1561
1619
|
nk_f32_t f32;
|
|
1562
1620
|
nk_f16_to_f32_serial(x, &f32);
|
|
@@ -1731,6 +1789,13 @@ NK_INTERNAL void nk_u64_to_bf16_serial(nk_u64_t const *x, nk_bf16_t *y) {
|
|
|
1731
1789
|
nk_f32_to_bf16_serial(&f32, y);
|
|
1732
1790
|
}
|
|
1733
1791
|
|
|
1792
|
+
#if defined(__clang__)
|
|
1793
|
+
#pragma clang attribute push(__attribute__((noinline)), apply_to = function)
|
|
1794
|
+
#elif defined(__GNUC__)
|
|
1795
|
+
#pragma GCC push_options
|
|
1796
|
+
#pragma GCC optimize("no-tree-vectorize", "no-tree-slp-vectorize", "no-ipa-cp-clone", "no-inline")
|
|
1797
|
+
#endif
|
|
1798
|
+
|
|
1734
1799
|
/** @brief Convert a pair of i4 (4-bit signed integer, -8 to 7) nibbles into signed integers. */
|
|
1735
1800
|
NK_PUBLIC void nk_i4x2_to_i8x2_serial(nk_i4x2_t const *src, nk_i8_t *dest) {
|
|
1736
1801
|
nk_u8_t byte = *(nk_u8_t const *)src;
|
|
@@ -1776,6 +1841,12 @@ typedef union NK_MAY_ALIAS_ nk_scalar_buffer_t {
|
|
|
1776
1841
|
nk_u8_t u8;
|
|
1777
1842
|
} nk_scalar_buffer_t;
|
|
1778
1843
|
|
|
1844
|
+
#if defined(__clang__)
|
|
1845
|
+
#pragma clang attribute pop
|
|
1846
|
+
#elif defined(__GNUC__)
|
|
1847
|
+
#pragma GCC pop_options
|
|
1848
|
+
#endif
|
|
1849
|
+
|
|
1779
1850
|
/** @brief Reads a typed scalar from @p buf and writes the widened f64c into @p result.
|
|
1780
1851
|
* Real types set `.imag = 0`. Safe when @p result aliases @p buf (in-place conversion).
|
|
1781
1852
|
* @return 1 on success, 0 for unsupported types (sub-byte, unknown). */
|
|
@@ -2247,6 +2318,13 @@ NK_INTERNAL int nk_scalar_buffer_from_f64(nk_f64_t const *value, nk_scalar_buffe
|
|
|
2247
2318
|
|
|
2248
2319
|
#pragma region Public API
|
|
2249
2320
|
|
|
2321
|
+
#if defined(__clang__)
|
|
2322
|
+
#pragma clang attribute push(__attribute__((noinline)), apply_to = function)
|
|
2323
|
+
#elif defined(__GNUC__)
|
|
2324
|
+
#pragma GCC push_options
|
|
2325
|
+
#pragma GCC optimize("no-tree-vectorize", "no-tree-slp-vectorize", "no-ipa-cp-clone", "no-inline")
|
|
2326
|
+
#endif
|
|
2327
|
+
|
|
2250
2328
|
NK_PUBLIC void nk_cast_serial(void const *from, nk_dtype_t from_type, nk_size_t n, void *to, nk_dtype_t to_type) {
|
|
2251
2329
|
if (from_type == to_type) {
|
|
2252
2330
|
nk_size_t size_bits = nk_dtype_bits(from_type);
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
* - `f16` & `bf16` ↔ `f32` - often used for half-precision dot-products on older CPUs,
|
|
12
12
|
*
|
|
13
13
|
* Unlike most operation classes in NumKong, these are dependent on two input types: "from" & "to".
|
|
14
|
-
* It contains scalar helpers named like `
|
|
15
|
-
* `memcpy`-like vectorized operations, such as `
|
|
16
|
-
* `
|
|
14
|
+
* It contains scalar helpers named like `nk_f16_to_f32_serial` as well as buffer-to-buffer
|
|
15
|
+
* `memcpy`-like vectorized operations, such as `nk_cast` with `nk_cast_serial`,
|
|
16
|
+
* `nk_cast_neon`, `nk_cast_skylake`, and other platform-specific variants.
|
|
17
17
|
*
|
|
18
18
|
* It also includes "partial load" and "partial store" type-punned helper functions for handling
|
|
19
19
|
* IO between memory and registers, that are extensively reused in reductions, elementwise ops, and
|
|
@@ -42,19 +42,19 @@ def bilinear_complex(a: np.ndarray, b: np.ndarray, C: np.ndarray) -> complex:
|
|
|
42
42
|
|
|
43
43
|
Real bilinear and Mahalanobis:
|
|
44
44
|
|
|
45
|
-
| Input Type | Output Type | Description
|
|
46
|
-
| ---------- | ----------- |
|
|
47
|
-
| `f64` | `f64` | 64-bit IEEE 754 double precision
|
|
48
|
-
| `f32` | `
|
|
49
|
-
| `f16` | `f32` | 16-bit IEEE 754 half precision, widened output
|
|
50
|
-
| `bf16` | `f32` | 16-bit brain float, widened output
|
|
45
|
+
| Input Type | Output Type | Description |
|
|
46
|
+
| ---------- | ----------- | ------------------------------------------------ |
|
|
47
|
+
| `f64` | `f64` | 64-bit IEEE 754 double precision |
|
|
48
|
+
| `f32` | `f64` | 32-bit IEEE 754 single precision, widened output |
|
|
49
|
+
| `f16` | `f32` | 16-bit IEEE 754 half precision, widened output |
|
|
50
|
+
| `bf16` | `f32` | 16-bit brain float, widened output |
|
|
51
51
|
|
|
52
52
|
Complex bilinear:
|
|
53
53
|
|
|
54
54
|
| Input Type | Output Type | Description |
|
|
55
55
|
| ---------- | ----------- | ------------------------------------------ |
|
|
56
56
|
| `f64c` | `f64c` | 64-bit complex pairs |
|
|
57
|
-
| `f32c` | `
|
|
57
|
+
| `f32c` | `f64c` | 32-bit complex pairs, widened output |
|
|
58
58
|
| `f16c` | `f32c` | 16-bit complex pairs, widened output |
|
|
59
59
|
| `bf16c` | `f32c` | 16-bit brain complex pairs, widened output |
|
|
60
60
|
|
|
@@ -179,7 +179,7 @@ Measured with Wasmtime v42 (Cranelift backend).
|
|
|
179
179
|
| `nk_bilinear_bf16c_neonbfdot` | 5.05 gso/s, 17.0 ulp | 4.20 gso/s, 17.0 ulp | 4.04 gso/s, 17.0 ulp |
|
|
180
180
|
| __f16c__ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ |
|
|
181
181
|
| `nk_bilinear_f16c_serial` | 2.81 gso/s, 51.8 ulp | 2.54 gso/s, 51.8 ulp | 2.48 gso/s, 51.8 ulp |
|
|
182
|
-
| `
|
|
182
|
+
| `nk_bilinear_f16c_neon` | 5.00 gso/s, 17.3 ulp | 4.16 gso/s, 17.3 ulp | 4.00 gso/s, 16.4 ulp |
|
|
183
183
|
| __f64__ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ |
|
|
184
184
|
| `nk_bilinear_f64_serial` | 0.717 gso/s, 0.4 ulp | 0.711 gso/s, 0.4 ulp | 0.721 gso/s, 0.4 ulp |
|
|
185
185
|
| `nk_mahalanobis_f64_serial` | 0.664 gso/s, 0.5 ulp | 0.667 gso/s, 0.5 ulp | 0.672 gso/s, 0.5 ulp |
|
|
@@ -196,8 +196,8 @@ Measured with Wasmtime v42 (Cranelift backend).
|
|
|
196
196
|
| __f16__ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ |
|
|
197
197
|
| `nk_bilinear_f16_serial` | ? gso/s, ? ulp | ? gso/s, ? ulp | ? gso/s, ? ulp |
|
|
198
198
|
| `nk_mahalanobis_f16_serial` | ? gso/s, ? ulp | ? gso/s, ? ulp | ? gso/s, ? ulp |
|
|
199
|
-
| `
|
|
200
|
-
| `
|
|
199
|
+
| `nk_bilinear_f16_neon` | ? gso/s, ? ulp | ? gso/s, ? ulp | ? gso/s, ? ulp |
|
|
200
|
+
| `nk_mahalanobis_f16_neon` | ? gso/s, ? ulp | ? gso/s, ? ulp | ? gso/s, ? ulp |
|
|
201
201
|
|
|
202
202
|
#### WASM
|
|
203
203
|
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
#include "numkong/types.h" // `nk_bf16_t`
|
|
31
31
|
#include "numkong/spatial/neon.h" // `nk_f32_sqrt_neon`
|
|
32
32
|
#include "numkong/cast/serial.h" // `nk_bf16_to_f32_serial`
|
|
33
|
+
#include "numkong/dot/serial.h" // `nk_dot_f16c_serial`, `nk_vdot_f16c_serial`
|
|
33
34
|
|
|
34
35
|
#if defined(__cplusplus)
|
|
35
36
|
extern "C" {
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
#include "numkong/spatial/neon.h" // `nk_f64_sqrt_neon`
|
|
57
57
|
#include "numkong/dots/sme.h" // `nk_sme_zero_za64_tile_0_`
|
|
58
58
|
#include "numkong/curved/serial.h" // `nk_bilinear_f64_serial`
|
|
59
|
+
#include "numkong/dot/serial.h" // `nk_dot_f16c_serial`, `nk_vdot_f16c_serial`
|
|
59
60
|
|
|
60
61
|
#if defined(__cplusplus)
|
|
61
62
|
extern "C" {
|
|
@@ -46,28 +46,28 @@ def vdot_complex(a: List[number], b: List[number]) -> Tuple[number, number]:
|
|
|
46
46
|
|
|
47
47
|
Real and integer dot products:
|
|
48
48
|
|
|
49
|
-
| Input Type | Output Type | Description
|
|
50
|
-
| ---------- | ----------- |
|
|
51
|
-
| `f64` | `f64` | 64-bit IEEE 754 double precision
|
|
52
|
-
| `f32` | `
|
|
53
|
-
| `f16` | `f32` | 16-bit IEEE 754 half precision, widened output
|
|
54
|
-
| `bf16` | `f32` | 16-bit brain float, widened output
|
|
55
|
-
| `e4m3` | `f32` | 8-bit Float8: 4 exponent, 3 mantissa bits
|
|
56
|
-
| `e5m2` | `f32` | 8-bit Float8: 5 exponent, 2 mantissa bits
|
|
57
|
-
| `e2m3` | `f32` | 8-bit MX format: 2 exponent, 3 mantissa bits
|
|
58
|
-
| `e3m2` | `f32` | 8-bit MX format: 3 exponent, 2 mantissa bits
|
|
59
|
-
| `i8` | `i32` | 8-bit signed integers
|
|
60
|
-
| `u8` | `u32` | 8-bit unsigned integers
|
|
61
|
-
| `i4` | `i32` | 4-bit signed integers, packed nibble pairs
|
|
62
|
-
| `u4` | `u32` | 4-bit unsigned integers, packed nibble pairs
|
|
63
|
-
| `u1` | `u32` | 1-bit binary packed octets, popcount of AND
|
|
49
|
+
| Input Type | Output Type | Description |
|
|
50
|
+
| ---------- | ----------- | ------------------------------------------------ |
|
|
51
|
+
| `f64` | `f64` | 64-bit IEEE 754 double precision |
|
|
52
|
+
| `f32` | `f64` | 32-bit IEEE 754 single precision, widened output |
|
|
53
|
+
| `f16` | `f32` | 16-bit IEEE 754 half precision, widened output |
|
|
54
|
+
| `bf16` | `f32` | 16-bit brain float, widened output |
|
|
55
|
+
| `e4m3` | `f32` | 8-bit Float8: 4 exponent, 3 mantissa bits |
|
|
56
|
+
| `e5m2` | `f32` | 8-bit Float8: 5 exponent, 2 mantissa bits |
|
|
57
|
+
| `e2m3` | `f32` | 8-bit MX format: 2 exponent, 3 mantissa bits |
|
|
58
|
+
| `e3m2` | `f32` | 8-bit MX format: 3 exponent, 2 mantissa bits |
|
|
59
|
+
| `i8` | `i32` | 8-bit signed integers |
|
|
60
|
+
| `u8` | `u32` | 8-bit unsigned integers |
|
|
61
|
+
| `i4` | `i32` | 4-bit signed integers, packed nibble pairs |
|
|
62
|
+
| `u4` | `u32` | 4-bit unsigned integers, packed nibble pairs |
|
|
63
|
+
| `u1` | `u32` | 1-bit binary packed octets, popcount of AND |
|
|
64
64
|
|
|
65
65
|
Complex dot products (both `dot` and `vdot`):
|
|
66
66
|
|
|
67
67
|
| Input Type | Output Type | Description |
|
|
68
68
|
| ---------- | ----------- | ------------------------------------------ |
|
|
69
69
|
| `f64c` | `f64c` | 64-bit complex pairs |
|
|
70
|
-
| `f32c` | `
|
|
70
|
+
| `f32c` | `f64c` | 32-bit complex pairs, widened output |
|
|
71
71
|
| `f16c` | `f32c` | 16-bit complex pairs, widened output |
|
|
72
72
|
| `bf16c` | `f32c` | 16-bit brain complex pairs, widened output |
|
|
73
73
|
|
|
@@ -330,8 +330,8 @@ Measured with Wasmtime v42 (Cranelift backend).
|
|
|
330
330
|
| __f16c__ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ |
|
|
331
331
|
| `nk_dot_f16c_serial` | 15.8 gb/s, 20.8 ulp | 13.0 gb/s, 64.1 ulp | 12.3 gb/s, 73.1 ulp |
|
|
332
332
|
| `nk_vdot_f16c_serial` | 15.8 gb/s, 24.8 ulp | 13.0 gb/s, 31.9 ulp | 12.3 gb/s, 137 ulp |
|
|
333
|
-
| `
|
|
334
|
-
| `
|
|
333
|
+
| `nk_dot_f16c_neon` | 26.1 gb/s, 3.0 ulp | 18.4 gb/s, 6.5 ulp | 16.8 gb/s, 20.5 ulp |
|
|
334
|
+
| `nk_vdot_f16c_neon` | 26.1 gb/s, 34.9 ulp | 18.5 gb/s, 40.7 ulp | 17.0 gb/s, 73.1 ulp |
|
|
335
335
|
| `nk_dot_f16c_neonfhm` | 25.3 gb/s, 3.0 ulp | 17.1 gb/s, 6.5 ulp | 15.9 gb/s, 20.5 ulp |
|
|
336
336
|
| `nk_vdot_f16c_neonfhm` | 25.0 gb/s, 31.4 ulp | 17.0 gb/s, 38.6 ulp | 15.8 gb/s, 67.6 ulp |
|
|
337
337
|
| __f64__ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ | ░░░░░░░░░░░░░░░░░░░░░░░░ |
|
|
@@ -192,8 +192,8 @@ NK_INTERNAL void nk_dot_i8x32_finalize_alder(
|
|
|
192
192
|
nk_dot_i8x32_state_alder_t const *state_c, nk_dot_i8x32_state_alder_t const *state_d, //
|
|
193
193
|
nk_size_t total_dimensions, //
|
|
194
194
|
nk_i32_t a_sum, /* A row sum (unused for i8) */ //
|
|
195
|
-
nk_b128_vec_t
|
|
196
|
-
nk_b128_vec_t *
|
|
195
|
+
nk_b128_vec_t const *b_sums_vec, /* 4 × i32 B column sums */ //
|
|
196
|
+
nk_b128_vec_t *result_vec) {
|
|
197
197
|
nk_unused_(total_dimensions);
|
|
198
198
|
nk_unused_(a_sum);
|
|
199
199
|
|
|
@@ -217,8 +217,8 @@ NK_INTERNAL void nk_dot_i8x32_finalize_alder(
|
|
|
217
217
|
_mm_add_epi32(_mm_unpacklo_epi64(t_ab_high, t_cd_high), _mm_unpackhi_epi64(t_ab_high, t_cd_high)));
|
|
218
218
|
|
|
219
219
|
// Apply compensation: result = biased − 128 × Σb
|
|
220
|
-
__m128i correction_i32x4 = _mm_slli_epi32(
|
|
221
|
-
|
|
220
|
+
__m128i correction_i32x4 = _mm_slli_epi32(b_sums_vec->xmm, 7); // × 128
|
|
221
|
+
result_vec->xmm = _mm_sub_epi32(biased_i32x4, correction_i32x4);
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
NK_PUBLIC void nk_dot_u8_alder(nk_u8_t const *a_scalars, nk_u8_t const *b_scalars, nk_size_t count_scalars,
|
|
@@ -312,8 +312,8 @@ NK_INTERNAL void nk_dot_u8x32_finalize_alder(
|
|
|
312
312
|
nk_dot_u8x32_state_alder_t const *state_c, nk_dot_u8x32_state_alder_t const *state_d, //
|
|
313
313
|
nk_size_t total_dimensions, //
|
|
314
314
|
nk_i32_t a_sum, /* A row sum (unused for u8) */ //
|
|
315
|
-
nk_b128_vec_t
|
|
316
|
-
nk_b128_vec_t *
|
|
315
|
+
nk_b128_vec_t const *b_sums_vec, /* 4 × u32 B column sums */ //
|
|
316
|
+
nk_b128_vec_t *result_vec) {
|
|
317
317
|
nk_unused_(total_dimensions);
|
|
318
318
|
nk_unused_(a_sum);
|
|
319
319
|
|
|
@@ -337,8 +337,8 @@ NK_INTERNAL void nk_dot_u8x32_finalize_alder(
|
|
|
337
337
|
_mm_add_epi32(_mm_unpacklo_epi64(t_ab_high, t_cd_high), _mm_unpackhi_epi64(t_ab_high, t_cd_high)));
|
|
338
338
|
|
|
339
339
|
// Apply compensation: result = biased + 128 × Σb
|
|
340
|
-
__m128i correction_i32x4 = _mm_slli_epi32(
|
|
341
|
-
|
|
340
|
+
__m128i correction_i32x4 = _mm_slli_epi32(b_sums_vec->xmm, 7); // × 128
|
|
341
|
+
result_vec->xmm = _mm_add_epi32(biased_i32x4, correction_i32x4);
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
/**
|
|
@@ -895,7 +895,7 @@ nk_dot_e3m2_haswell_cycle:
|
|
|
895
895
|
|
|
896
896
|
/**
|
|
897
897
|
* @brief Internal helper state for dot-products of low-precision types, where 32-bit accumulation is enough.
|
|
898
|
-
* @sa nk_dot_f16x8_state_haswell_t,
|
|
898
|
+
* @sa nk_dot_f16x8_state_haswell_t, nk_dot_bf16x16_state_haswell_t
|
|
899
899
|
* @sa nk_dot_e4m3x16_state_haswell_t, nk_dot_e5m2x16_state_haswell_t
|
|
900
900
|
*/
|
|
901
901
|
typedef struct nk_dot_through_f32_state_haswell_t_ {
|
|
@@ -904,7 +904,7 @@ typedef struct nk_dot_through_f32_state_haswell_t_ {
|
|
|
904
904
|
|
|
905
905
|
/**
|
|
906
906
|
* @brief Initializes 32-bit accumulators for low-precision dot-products.
|
|
907
|
-
* @sa nk_dot_f16x8_init_haswell,
|
|
907
|
+
* @sa nk_dot_f16x8_init_haswell, nk_dot_bf16x16_init_haswell
|
|
908
908
|
* @sa nk_dot_e4m3x16_init_haswell, nk_dot_e5m2x16_init_haswell
|
|
909
909
|
*/
|
|
910
910
|
NK_INTERNAL void nk_dot_through_f32_init_haswell_(nk_dot_through_f32_state_haswell_t_ *state) {
|
|
@@ -913,7 +913,7 @@ NK_INTERNAL void nk_dot_through_f32_init_haswell_(nk_dot_through_f32_state_haswe
|
|
|
913
913
|
|
|
914
914
|
/**
|
|
915
915
|
* @brief Fuses 32-bit multiplication and accumulation for low-precision dot-products.
|
|
916
|
-
* @sa nk_dot_f16x8_update_haswell,
|
|
916
|
+
* @sa nk_dot_f16x8_update_haswell, nk_dot_bf16x16_update_haswell
|
|
917
917
|
* @sa nk_dot_e4m3x16_update_haswell, nk_dot_e5m2x16_update_haswell
|
|
918
918
|
*/
|
|
919
919
|
NK_INTERNAL void nk_dot_through_f32_update_haswell_(nk_dot_through_f32_state_haswell_t_ *state, nk_b256_vec_t a,
|
|
@@ -991,7 +991,7 @@ NK_INTERNAL void nk_dot_e4m3x32_update_haswell_(nk_dot_through_f32_state_haswell
|
|
|
991
991
|
|
|
992
992
|
/**
|
|
993
993
|
* @brief Finalizes 4x low-precision dot-products placing them into 4x consecutive 32-bit slots.
|
|
994
|
-
* @sa nk_dot_f16x8_finalize_haswell,
|
|
994
|
+
* @sa nk_dot_f16x8_finalize_haswell, nk_dot_bf16x16_finalize_haswell
|
|
995
995
|
* @sa nk_dot_e4m3x16_finalize_haswell, nk_dot_e5m2x16_finalize_haswell
|
|
996
996
|
*
|
|
997
997
|
* The goal of this kernel is simple - compute 4x horizontal reductions, each involving 8x floats.
|
|
@@ -1637,8 +1637,8 @@ NK_INTERNAL void nk_dot_i4x32_finalize_haswell(
|
|
|
1637
1637
|
nk_dot_i4x32_state_haswell_t const *state_c, nk_dot_i4x32_state_haswell_t const *state_d, //
|
|
1638
1638
|
nk_size_t total_dimensions, //
|
|
1639
1639
|
nk_i32_t a_sum, /* A row sum (signed sum of i4 values) */ //
|
|
1640
|
-
nk_b128_vec_t
|
|
1641
|
-
nk_b128_vec_t *
|
|
1640
|
+
nk_b128_vec_t const *b_sums_vec, /* 4 × i32 B column sums */ //
|
|
1641
|
+
nk_b128_vec_t *result_vec) {
|
|
1642
1642
|
|
|
1643
1643
|
// Compensated 4-way reduction with external correction sums.
|
|
1644
1644
|
// Formula: result = biased_product − 8×(Σa + Σb) − 64×depth_padded
|
|
@@ -1666,10 +1666,10 @@ NK_INTERNAL void nk_dot_i4x32_finalize_haswell(
|
|
|
1666
1666
|
|
|
1667
1667
|
// Apply compensation: result = biased − 8×(Σa + Σb) − 64×depth_padded
|
|
1668
1668
|
__m128i a_sum_broadcast_i32x4 = _mm_set1_epi32(a_sum);
|
|
1669
|
-
__m128i ab_sums_i32x4 = _mm_add_epi32(a_sum_broadcast_i32x4,
|
|
1669
|
+
__m128i ab_sums_i32x4 = _mm_add_epi32(a_sum_broadcast_i32x4, b_sums_vec->xmm);
|
|
1670
1670
|
__m128i correction_i32x4 = _mm_slli_epi32(ab_sums_i32x4, 3); // × 8
|
|
1671
1671
|
__m128i offset_i32x4 = _mm_set1_epi32((nk_i32_t)(-64LL * (nk_i64_t)depth_nibbles));
|
|
1672
|
-
|
|
1672
|
+
result_vec->xmm = _mm_add_epi32(_mm_sub_epi32(biased_i32x4, correction_i32x4), offset_i32x4);
|
|
1673
1673
|
}
|
|
1674
1674
|
|
|
1675
1675
|
/**
|
|
@@ -246,8 +246,8 @@ NK_INTERNAL void nk_dot_i8x64_finalize_icelake(
|
|
|
246
246
|
nk_dot_i8x64_state_icelake_t const *state_c, nk_dot_i8x64_state_icelake_t const *state_d, //
|
|
247
247
|
nk_size_t total_dimensions, //
|
|
248
248
|
nk_i32_t a_sum, /* A row sum (unused for i8) */ //
|
|
249
|
-
nk_b128_vec_t
|
|
250
|
-
nk_b128_vec_t *
|
|
249
|
+
nk_b128_vec_t const *b_sums_vec, /* 4 × i32 B column sums */ //
|
|
250
|
+
nk_b128_vec_t *result_vec) {
|
|
251
251
|
nk_unused_(total_dimensions);
|
|
252
252
|
nk_unused_(a_sum);
|
|
253
253
|
|
|
@@ -277,8 +277,8 @@ NK_INTERNAL void nk_dot_i8x64_finalize_icelake(
|
|
|
277
277
|
_mm_add_epi32(_mm_unpacklo_epi64(t_ab_high, t_cd_high), _mm_unpackhi_epi64(t_ab_high, t_cd_high)));
|
|
278
278
|
|
|
279
279
|
// Apply compensation: result = biased − 128 × Σb
|
|
280
|
-
__m128i correction_i32x4 = _mm_slli_epi32(
|
|
281
|
-
|
|
280
|
+
__m128i correction_i32x4 = _mm_slli_epi32(b_sums_vec->xmm, 7); // × 128
|
|
281
|
+
result_vec->xmm = _mm_sub_epi32(biased_i32x4, correction_i32x4);
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
typedef struct nk_dot_u8x64_state_icelake_t {
|
|
@@ -313,8 +313,8 @@ NK_INTERNAL void nk_dot_u8x64_finalize_icelake(
|
|
|
313
313
|
nk_dot_u8x64_state_icelake_t const *state_c, nk_dot_u8x64_state_icelake_t const *state_d, //
|
|
314
314
|
nk_size_t total_dimensions, //
|
|
315
315
|
nk_i32_t a_sum, /* A row sum (unused for u8) */ //
|
|
316
|
-
nk_b128_vec_t
|
|
317
|
-
nk_b128_vec_t *
|
|
316
|
+
nk_b128_vec_t const *b_sums_vec, /* 4 × u32 B column sums */ //
|
|
317
|
+
nk_b128_vec_t *result_vec) {
|
|
318
318
|
nk_unused_(total_dimensions);
|
|
319
319
|
nk_unused_(a_sum);
|
|
320
320
|
|
|
@@ -344,8 +344,8 @@ NK_INTERNAL void nk_dot_u8x64_finalize_icelake(
|
|
|
344
344
|
_mm_add_epi32(_mm_unpacklo_epi64(t_ab_high, t_cd_high), _mm_unpackhi_epi64(t_ab_high, t_cd_high)));
|
|
345
345
|
|
|
346
346
|
// Apply compensation: result = biased + 128 × Σb
|
|
347
|
-
__m128i correction_i32x4 = _mm_slli_epi32(
|
|
348
|
-
|
|
347
|
+
__m128i correction_i32x4 = _mm_slli_epi32(b_sums_vec->xmm, 7); // × 128
|
|
348
|
+
result_vec->xmm = _mm_add_epi32(biased_i32x4, correction_i32x4);
|
|
349
349
|
}
|
|
350
350
|
|
|
351
351
|
/**
|
|
@@ -568,8 +568,8 @@ NK_INTERNAL void nk_dot_i4x128_finalize_icelake(
|
|
|
568
568
|
nk_dot_i4x128_state_icelake_t const *state_c, nk_dot_i4x128_state_icelake_t const *state_d, //
|
|
569
569
|
nk_size_t total_dimensions, //
|
|
570
570
|
nk_i32_t a_sum, /* A row sum (signed sum of i4 values) */ //
|
|
571
|
-
nk_b128_vec_t
|
|
572
|
-
nk_b128_vec_t *
|
|
571
|
+
nk_b128_vec_t const *b_sums_vec, /* 4 × i32 B column sums */ //
|
|
572
|
+
nk_b128_vec_t *result_vec) {
|
|
573
573
|
|
|
574
574
|
// Compensated 4-way reduction with external correction sums.
|
|
575
575
|
// Formula: result = biased_product − 8×(Σa + Σb) − 64×depth_padded
|
|
@@ -606,10 +606,10 @@ NK_INTERNAL void nk_dot_i4x128_finalize_icelake(
|
|
|
606
606
|
|
|
607
607
|
// Apply compensation: result = biased − 8×(Σa + Σb) − 64×depth_padded
|
|
608
608
|
__m128i a_sum_broadcast_i32x4 = _mm_set1_epi32(a_sum);
|
|
609
|
-
__m128i ab_sums_i32x4 = _mm_add_epi32(a_sum_broadcast_i32x4,
|
|
609
|
+
__m128i ab_sums_i32x4 = _mm_add_epi32(a_sum_broadcast_i32x4, b_sums_vec->xmm);
|
|
610
610
|
__m128i correction_i32x4 = _mm_slli_epi32(ab_sums_i32x4, 3); // × 8
|
|
611
611
|
__m128i offset_i32x4 = _mm_set1_epi32((nk_i32_t)(-64LL * (nk_i64_t)depth_nibbles));
|
|
612
|
-
|
|
612
|
+
result_vec->xmm = _mm_add_epi32(_mm_sub_epi32(biased_i32x4, correction_i32x4), offset_i32x4);
|
|
613
613
|
}
|
|
614
614
|
|
|
615
615
|
typedef struct nk_dot_u4x128_state_icelake_t {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* @section dot_loongsonasx_stateful Stateful Streaming Logic
|
|
20
20
|
*
|
|
21
21
|
* - nk_dot_f64x4 state with Dot2 stable dot-products,
|
|
22
|
-
* -
|
|
22
|
+
* - nk_dot_f32x8 state with double-precision numerics,
|
|
23
23
|
* - nk_dot_through_i32 state for 8-bit signed and unsigned integer inputs.
|
|
24
24
|
*/
|
|
25
25
|
#ifndef NK_DOT_LOONGSONASX_H
|
|
@@ -348,7 +348,7 @@ NK_INTERNAL void nk_dot_f32x8_finalize_loongsonasx(
|
|
|
348
348
|
|
|
349
349
|
/**
|
|
350
350
|
* @brief Internal helper state for dot-products of integer types, where 32-bit accumulation is enough.
|
|
351
|
-
* @sa
|
|
351
|
+
* @sa nk_dot_i8x32_state_loongsonasx_t, nk_dot_u8x32_state_loongsonasx_t
|
|
352
352
|
*/
|
|
353
353
|
typedef struct nk_dot_through_i32_state_loongsonasx_t_ {
|
|
354
354
|
__m256i sum_i32x8;
|
|
@@ -356,7 +356,7 @@ typedef struct nk_dot_through_i32_state_loongsonasx_t_ {
|
|
|
356
356
|
|
|
357
357
|
/**
|
|
358
358
|
* @brief Initializes 32-bit accumulators for integer dot-products.
|
|
359
|
-
* @sa
|
|
359
|
+
* @sa nk_dot_i8x32_update_loongsonasx, nk_dot_u8x32_update_loongsonasx
|
|
360
360
|
*/
|
|
361
361
|
NK_INTERNAL void nk_dot_through_i32_init_loongsonasx_(nk_dot_through_i32_state_loongsonasx_t_ *state) {
|
|
362
362
|
state->sum_i32x8 = __lasx_xvreplgr2vr_w(0);
|
|
@@ -364,7 +364,7 @@ NK_INTERNAL void nk_dot_through_i32_init_loongsonasx_(nk_dot_through_i32_state_l
|
|
|
364
364
|
|
|
365
365
|
/**
|
|
366
366
|
* @brief Finalizes 4x integer dot-products placing them into 4x consecutive 32-bit slots.
|
|
367
|
-
* @sa
|
|
367
|
+
* @sa nk_dot_i8x32_update_loongsonasx, nk_dot_u8x32_update_loongsonasx
|
|
368
368
|
*/
|
|
369
369
|
NK_INTERNAL void nk_dot_through_i32_finalize_loongsonasx_( //
|
|
370
370
|
nk_dot_through_i32_state_loongsonasx_t_ const *state_a, nk_dot_through_i32_state_loongsonasx_t_ const *state_b, //
|
|
@@ -474,7 +474,7 @@ NK_INTERNAL void nk_dot_through_f32_init_loongsonasx_(nk_dot_through_f32_state_l
|
|
|
474
474
|
|
|
475
475
|
/**
|
|
476
476
|
* @brief Fuses 32-bit multiplication and accumulation for pre-converted f32 vectors.
|
|
477
|
-
* @sa
|
|
477
|
+
* @sa nk_dot_bf16x16_update_loongsonasx
|
|
478
478
|
*/
|
|
479
479
|
NK_INTERNAL void nk_dot_through_f32_update_loongsonasx_(nk_dot_through_f32_state_loongsonasx_t_ *state, nk_b256_vec_t a,
|
|
480
480
|
nk_b256_vec_t b, nk_size_t depth_offset,
|
|
@@ -486,7 +486,7 @@ NK_INTERNAL void nk_dot_through_f32_update_loongsonasx_(nk_dot_through_f32_state
|
|
|
486
486
|
|
|
487
487
|
/**
|
|
488
488
|
* @brief Finalizes 4x low-precision dot-products placing them into 4x consecutive 32-bit slots.
|
|
489
|
-
* @sa
|
|
489
|
+
* @sa nk_dot_bf16x16_finalize_loongsonasx
|
|
490
490
|
*
|
|
491
491
|
* Computes 4x horizontal reductions, each involving 8x floats, using LASX interleave instructions.
|
|
492
492
|
*/
|
|
@@ -89,7 +89,8 @@
|
|
|
89
89
|
#if NK_TARGET_ARM64_
|
|
90
90
|
#if NK_TARGET_NEON
|
|
91
91
|
|
|
92
|
-
#include "numkong/cast/neon.h"
|
|
92
|
+
#include "numkong/cast/neon.h" // `nk_e4m3x8_to_f16x8_neon_`
|
|
93
|
+
#include "numkong/dot/serial.h" // `nk_dot_f16c_serial`, `nk_vdot_f16c_serial`
|
|
93
94
|
|
|
94
95
|
#if defined(__cplusplus)
|
|
95
96
|
extern "C" {
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
#include "numkong/types.h"
|
|
64
64
|
#include "numkong/cast/serial.h" // `nk_partial_load_b8x8_serial_`
|
|
65
65
|
#include "numkong/cast/neon.h" // `nk_e4m3x8_to_bf16x8_neon_`
|
|
66
|
+
#include "numkong/dot/serial.h" // `nk_dot_bf16c_serial`, `nk_vdot_bf16c_serial`
|
|
66
67
|
|
|
67
68
|
#if defined(__cplusplus)
|
|
68
69
|
extern "C" {
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
#include "numkong/types.h"
|
|
66
66
|
#include "numkong/cast/serial.h" // `nk_partial_load_b8x8_serial_`
|
|
67
67
|
#include "numkong/cast/neon.h" // `nk_e4m3x8_to_f16x8_neon_`
|
|
68
|
+
#include "numkong/dot/serial.h" // `nk_dot_f16c_serial`, `nk_vdot_f16c_serial`
|
|
68
69
|
|
|
69
70
|
#if defined(__cplusplus)
|
|
70
71
|
extern "C" {
|
|
@@ -599,7 +599,7 @@ NK_INTERNAL void nk_dot_i8x16_finalize_powervsx(
|
|
|
599
599
|
nk_dot_i8x16_state_powervsx_t const *state_a, nk_dot_i8x16_state_powervsx_t const *state_b, //
|
|
600
600
|
nk_dot_i8x16_state_powervsx_t const *state_c, nk_dot_i8x16_state_powervsx_t const *state_d, //
|
|
601
601
|
nk_size_t total_dimensions, //
|
|
602
|
-
nk_i32_t a_sum, nk_b128_vec_t
|
|
602
|
+
nk_i32_t a_sum, nk_b128_vec_t const *b_sums_vec, nk_b128_vec_t *result_vec) {
|
|
603
603
|
nk_unused_(total_dimensions);
|
|
604
604
|
nk_unused_(a_sum);
|
|
605
605
|
|
|
@@ -624,8 +624,8 @@ NK_INTERNAL void nk_dot_i8x16_finalize_powervsx(
|
|
|
624
624
|
// Correction: VMSUMMBM(b, a⊕0x80) = Σ(b_i·(a_i+128)) = a·b + 128·Σb
|
|
625
625
|
// So a·b = biased − 128·Σb. B column sums are precomputed during packing.
|
|
626
626
|
nk_vu32x4_t shift_u32x4 = vec_splats((nk_u32_t)7);
|
|
627
|
-
nk_vi32x4_t correction_i32x4 = (nk_vi32x4_t)vec_sl((nk_vu32x4_t)
|
|
628
|
-
|
|
627
|
+
nk_vi32x4_t correction_i32x4 = (nk_vi32x4_t)vec_sl((nk_vu32x4_t)b_sums_vec->vi32x4, shift_u32x4);
|
|
628
|
+
result_vec->vi32x4 = vec_sub(biased_i32x4, correction_i32x4);
|
|
629
629
|
}
|
|
630
630
|
|
|
631
631
|
/** @brief Running state for i8 column sum precomputation on Power VSX. */
|