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.
Files changed (148) hide show
  1. package/README.md +2 -2
  2. package/cpp/test.cpp +66 -3
  3. package/include/usearch/index.hpp +9 -1
  4. package/include/usearch/index_dense.hpp +16 -5
  5. package/numkong/CITATION.cff +13 -9
  6. package/numkong/CONTRIBUTING.md +29 -24
  7. package/numkong/Cargo.toml +1 -1
  8. package/numkong/README.md +21 -7
  9. package/numkong/binding.gyp +47 -31
  10. package/numkong/build.rs +15 -5
  11. package/numkong/c/dispatch.h +0 -1
  12. package/numkong/c/parallel.c +139 -0
  13. package/numkong/c/parallel.h +47 -0
  14. package/numkong/cmake/toolchain-wasi.cmake +39 -5
  15. package/numkong/include/README.md +24 -17
  16. package/numkong/include/numkong/attention/sapphireamx.h +6 -6
  17. package/numkong/include/numkong/attention/sme.h +2 -2
  18. package/numkong/include/numkong/capabilities.h +2 -2
  19. package/numkong/include/numkong/cast/README.md +9 -7
  20. package/numkong/include/numkong/cast/loongsonasx.h +48 -40
  21. package/numkong/include/numkong/cast/serial.h +89 -11
  22. package/numkong/include/numkong/cast.h +3 -3
  23. package/numkong/include/numkong/curved/README.md +10 -10
  24. package/numkong/include/numkong/curved/neon.h +1 -0
  25. package/numkong/include/numkong/curved/neonbfdot.h +1 -0
  26. package/numkong/include/numkong/curved/smef64.h +1 -0
  27. package/numkong/include/numkong/dot/README.md +18 -18
  28. package/numkong/include/numkong/dot/alder.h +8 -8
  29. package/numkong/include/numkong/dot/haswell.h +8 -8
  30. package/numkong/include/numkong/dot/icelake.h +12 -12
  31. package/numkong/include/numkong/dot/loongsonasx.h +6 -6
  32. package/numkong/include/numkong/dot/neon.h +2 -1
  33. package/numkong/include/numkong/dot/neonbfdot.h +1 -0
  34. package/numkong/include/numkong/dot/neonfhm.h +1 -0
  35. package/numkong/include/numkong/dot/neonsdot.h +1 -0
  36. package/numkong/include/numkong/dot/powervsx.h +3 -3
  37. package/numkong/include/numkong/dot/serial.h +19 -6
  38. package/numkong/include/numkong/dot/skylake.h +4 -4
  39. package/numkong/include/numkong/dot/svehalf.h +1 -1
  40. package/numkong/include/numkong/dot/v128relaxed.h +24 -23
  41. package/numkong/include/numkong/dots/README.md +26 -26
  42. package/numkong/include/numkong/dots/genoa.h +3 -1
  43. package/numkong/include/numkong/dots/icelake.h +1 -0
  44. package/numkong/include/numkong/dots/powervsx.h +1 -1
  45. package/numkong/include/numkong/dots/serial.h +32 -33
  46. package/numkong/include/numkong/dots/sierra.h +4 -3
  47. package/numkong/include/numkong/each/README.md +5 -3
  48. package/numkong/include/numkong/each/sapphire.h +2 -0
  49. package/numkong/include/numkong/each/skylake.h +1 -0
  50. package/numkong/include/numkong/geospatial/README.md +6 -6
  51. package/numkong/include/numkong/geospatial/v128relaxed.h +1 -0
  52. package/numkong/include/numkong/maxsim/README.md +5 -5
  53. package/numkong/include/numkong/maxsim/genoa.h +4 -0
  54. package/numkong/include/numkong/maxsim/icelake.h +1 -0
  55. package/numkong/include/numkong/maxsim/serial.h +22 -9
  56. package/numkong/include/numkong/maxsim/sme.h +3 -2
  57. package/numkong/include/numkong/mesh/README.md +7 -4
  58. package/numkong/include/numkong/mesh/genoa.h +2 -2
  59. package/numkong/include/numkong/mesh/haswell.h +8 -8
  60. package/numkong/include/numkong/mesh/neon.h +6 -6
  61. package/numkong/include/numkong/mesh/neonbfdot.h +3 -2
  62. package/numkong/include/numkong/mesh/neonfhm.h +3 -2
  63. package/numkong/include/numkong/mesh/rvv.h +4 -4
  64. package/numkong/include/numkong/mesh/serial.h +17 -17
  65. package/numkong/include/numkong/mesh/skylake.h +4 -4
  66. package/numkong/include/numkong/mesh/v128relaxed.h +4 -4
  67. package/numkong/include/numkong/mesh.hpp +2 -2
  68. package/numkong/include/numkong/numkong.h +1 -1
  69. package/numkong/include/numkong/numkong.hpp +1 -1
  70. package/numkong/include/numkong/probability/README.md +17 -15
  71. package/numkong/include/numkong/probability/skylake.h +1 -1
  72. package/numkong/include/numkong/reduce/README.md +27 -21
  73. package/numkong/include/numkong/reduce/genoa.h +2 -1
  74. package/numkong/include/numkong/reduce/icelake.h +1 -0
  75. package/numkong/include/numkong/reduce/neon.h +1 -1
  76. package/numkong/include/numkong/reduce/serial.h +9 -9
  77. package/numkong/include/numkong/reduce/skylake.h +4 -4
  78. package/numkong/include/numkong/reduce.hpp +38 -0
  79. package/numkong/include/numkong/scalar/README.md +29 -28
  80. package/numkong/include/numkong/set/README.md +17 -14
  81. package/numkong/include/numkong/set/haswell.h +15 -16
  82. package/numkong/include/numkong/set/icelake.h +15 -16
  83. package/numkong/include/numkong/set/loongsonasx.h +12 -10
  84. package/numkong/include/numkong/set/neon.h +15 -19
  85. package/numkong/include/numkong/set/powervsx.h +15 -21
  86. package/numkong/include/numkong/set/serial.h +19 -20
  87. package/numkong/include/numkong/set/v128relaxed.h +10 -8
  88. package/numkong/include/numkong/sets/icelake.h +1 -0
  89. package/numkong/include/numkong/sparse/README.md +4 -4
  90. package/numkong/include/numkong/sparse/icelake.h +1 -0
  91. package/numkong/include/numkong/sparse/neon.h +1 -0
  92. package/numkong/include/numkong/sparse/serial.h +10 -3
  93. package/numkong/include/numkong/sparse/turin.h +1 -0
  94. package/numkong/include/numkong/spatial/README.md +25 -24
  95. package/numkong/include/numkong/spatial/alder.h +2 -1
  96. package/numkong/include/numkong/spatial/haswell.h +48 -40
  97. package/numkong/include/numkong/spatial/icelake.h +2 -1
  98. package/numkong/include/numkong/spatial/neon.h +54 -46
  99. package/numkong/include/numkong/spatial/neonbfdot.h +1 -1
  100. package/numkong/include/numkong/spatial/powervsx.h +54 -46
  101. package/numkong/include/numkong/spatial/serial.h +56 -46
  102. package/numkong/include/numkong/spatial/sierra.h +4 -3
  103. package/numkong/include/numkong/spatial/skylake.h +27 -22
  104. package/numkong/include/numkong/spatial/sve.h +6 -6
  105. package/numkong/include/numkong/spatial/svebfdot.h +1 -1
  106. package/numkong/include/numkong/spatial/svehalf.h +1 -1
  107. package/numkong/include/numkong/spatial/v128relaxed.h +36 -30
  108. package/numkong/include/numkong/spatials/README.md +15 -15
  109. package/numkong/include/numkong/spatials/genoa.h +3 -0
  110. package/numkong/include/numkong/spatials/graniteamx.h +2 -0
  111. package/numkong/include/numkong/spatials/icelake.h +1 -0
  112. package/numkong/include/numkong/spatials/sierra.h +1 -0
  113. package/numkong/include/numkong/tensor.hpp +236 -123
  114. package/numkong/include/numkong/trigonometry/README.md +4 -4
  115. package/numkong/include/numkong/trigonometry/serial.h +6 -6
  116. package/numkong/include/numkong/trigonometry/v128relaxed.h +1 -0
  117. package/numkong/include/numkong/types.hpp +46 -16
  118. package/numkong/include/numkong/vector.hpp +116 -23
  119. package/numkong/javascript/@numkong-darwin-arm64/package.json +1 -1
  120. package/numkong/javascript/@numkong-darwin-x64/package.json +1 -1
  121. package/numkong/javascript/@numkong-linux-arm64/package.json +1 -1
  122. package/numkong/javascript/@numkong-linux-x64/package.json +1 -1
  123. package/numkong/javascript/@numkong-win32-arm64/package.json +1 -1
  124. package/numkong/javascript/@numkong-win32-x64/package.json +1 -1
  125. package/numkong/javascript/README.md +18 -16
  126. package/numkong/javascript/numkong.c +70 -40
  127. package/numkong/package.json +8 -8
  128. package/numkong/rust/README.md +19 -9
  129. package/numkong/rust/cast.rs +52 -1
  130. package/numkong/rust/each.rs +480 -7
  131. package/numkong/rust/matrix.rs +877 -216
  132. package/numkong/rust/numkong.rs +12 -8
  133. package/numkong/rust/reduce.rs +433 -5
  134. package/numkong/rust/tensor.rs +450 -842
  135. package/numkong/rust/vector.rs +520 -101
  136. package/numkong/swift/README.md +5 -3
  137. package/numkong/test/README.md +4 -4
  138. package/numkong/test/test-wasi.mjs +17 -0
  139. package/numkong/test/test_each.cpp +30 -1
  140. package/numkong/test/test_each.py +74 -1
  141. package/numkong/test/test_reduce.cpp +51 -0
  142. package/numkong/test/test_tensor.cpp +2 -63
  143. package/numkong/test/test_tensor.py +93 -0
  144. package/package.json +1 -1
  145. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  146. package/prebuilds/linux-arm64/usearch.node +0 -0
  147. package/prebuilds/linux-x64/usearch.node +0 -0
  148. 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 `nk_f16_to_f32_serial_` as well as buffer-to-buffer
15
- * `memcpy`-like vectorized operations, such as `nk_cast_f16_to_f32` with `nk_cast_f16_to_f32_serial`,
16
- * `nk_cast_f16_to_f32_neon`, `nk_cast_f16_to_f32_skylake`, and other platform-specific variants.
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` | `f32` | 32-bit IEEE 754 single precision |
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` | `f32c` | 32-bit complex pairs |
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
- | `nk_bilinear_f16c_neonhalf` | 5.00 gso/s, 17.3 ulp | 4.16 gso/s, 17.3 ulp | 4.00 gso/s, 16.4 ulp |
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
- | `nk_bilinear_f16_neonhalf` | ? gso/s, ? ulp | ? gso/s, ? ulp | ? gso/s, ? ulp |
200
- | `nk_mahalanobis_f16_neonhalf` | ? gso/s, ? ulp | ? gso/s, ? ulp | ? gso/s, ? ulp |
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
 
@@ -29,6 +29,7 @@
29
29
 
30
30
  #include "numkong/types.h"
31
31
  #include "numkong/spatial/neon.h" // nk_f64_sqrt_neon
32
+ #include "numkong/dot/serial.h" // `nk_dot_f16c_serial`, `nk_vdot_f16c_serial`
32
33
 
33
34
  #if defined(__cplusplus)
34
35
  extern "C" {
@@ -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` | `f32` | 32-bit IEEE 754 single precision |
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` | `f32c` | 32-bit complex pairs |
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
- | `nk_dot_f16c_neonhalf` | 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_neonhalf` | 26.1 gb/s, 34.9 ulp | 18.5 gb/s, 40.7 ulp | 17.0 gb/s, 73.1 ulp |
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 b_sums, /* 4 × i32 B column sums */ //
196
- nk_b128_vec_t *results) {
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(b_sums.xmm, 7); // × 128
221
- results->xmm = _mm_sub_epi32(biased_i32x4, correction_i32x4);
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 b_sums, /* 4 × u32 B column sums */ //
316
- nk_b128_vec_t *result) {
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(b_sums.xmm, 7); // × 128
341
- result->xmm = _mm_add_epi32(biased_i32x4, correction_i32x4);
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, nk_dot_bf16x8_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, nk_dot_bf16x8_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, nk_dot_bf16x8_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, nk_dot_bf16x8_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 b_sums, /* 4 × i32 B column sums */ //
1641
- nk_b128_vec_t *result) {
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, b_sums.xmm);
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
- result->xmm = _mm_add_epi32(_mm_sub_epi32(biased_i32x4, correction_i32x4), offset_i32x4);
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 b_sums, /* 4 × i32 B column sums */ //
250
- nk_b128_vec_t *results) {
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(b_sums.xmm, 7); // × 128
281
- results->xmm = _mm_sub_epi32(biased_i32x4, correction_i32x4);
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 b_sums, /* 4 × u32 B column sums */ //
317
- nk_b128_vec_t *result) {
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(b_sums.xmm, 7); // × 128
348
- result->xmm = _mm_add_epi32(biased_i32x4, correction_i32x4);
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 b_sums, /* 4 × i32 B column sums */ //
572
- nk_b128_vec_t *result) {
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, b_sums.xmm);
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
- result->xmm = _mm_add_epi32(_mm_sub_epi32(biased_i32x4, correction_i32x4), offset_i32x4);
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
- * - nk_dot_f32x4 state with double-precision numerics,
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 nk_dot_i8x16_state_loongsonasx_t, nk_dot_u8x16_state_loongsonasx_t
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 nk_dot_i8x16_update_loongsonasx, nk_dot_u8x16_update_loongsonasx
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 nk_dot_i8x16_update_loongsonasx, nk_dot_u8x16_update_loongsonasx
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 nk_dot_bf16x8_update_loongsonasx
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 nk_dot_bf16x8_finalize_loongsonasx
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" // `nk_e4m3x8_to_f16x8_neon_`
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" {
@@ -100,6 +100,7 @@
100
100
  #if NK_TARGET_NEONSDOT
101
101
 
102
102
  #include "numkong/types.h"
103
+ #include "numkong/cast/serial.h" // `nk_partial_load_b8x16_serial_`
103
104
 
104
105
  #if defined(__cplusplus)
105
106
  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 b_sums, nk_b128_vec_t *result) {
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)b_sums.vi32x4, shift_u32x4);
628
- result->vi32x4 = vec_sub(biased_i32x4, correction_i32x4);
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. */