usearch 2.21.4 → 2.25.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.
Files changed (604) hide show
  1. package/README.md +65 -69
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +8 -8
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +124 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +224 -48
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/README.md +1 -1
  16. package/javascript/dist/cjs/usearch.d.ts +8 -3
  17. package/javascript/dist/cjs/usearch.js +12 -4
  18. package/javascript/dist/esm/usearch.d.ts +8 -3
  19. package/javascript/dist/esm/usearch.js +12 -4
  20. package/javascript/lib.cpp +17 -0
  21. package/javascript/usearch.test.js +117 -94
  22. package/javascript/usearch.ts +14 -6
  23. package/numkong/.clang-tidy +30 -0
  24. package/{simsimd → numkong}/.cmake-format.py +18 -0
  25. package/numkong/.editorconfig +12 -0
  26. package/numkong/.git-blame-ignore-revs +123 -0
  27. package/numkong/.mailmap +15 -0
  28. package/numkong/.spi.yml +11 -0
  29. package/numkong/.swift-format +14 -0
  30. package/numkong/CITATION.cff +81 -0
  31. package/numkong/CONTRIBUTING.md +500 -0
  32. package/numkong/Cargo.toml +54 -0
  33. package/numkong/MANIFEST.in +8 -0
  34. package/numkong/Package.swift +84 -0
  35. package/numkong/README.md +569 -0
  36. package/numkong/bench/README.md +217 -0
  37. package/numkong/bench/bench-browser.html +323 -0
  38. package/numkong/bench/bench.cpp +344 -0
  39. package/numkong/bench/bench.hpp +816 -0
  40. package/numkong/bench/bench.js +148 -0
  41. package/numkong/bench/bench.mjs +616 -0
  42. package/numkong/bench/bench_attention.cpp +113 -0
  43. package/numkong/bench/bench_cast.cpp +264 -0
  44. package/numkong/bench/bench_cross_amx.cpp +62 -0
  45. package/numkong/bench/bench_cross_arm.cpp +245 -0
  46. package/numkong/bench/bench_cross_blas.cpp +309 -0
  47. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  48. package/numkong/bench/bench_cross_power.cpp +84 -0
  49. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  50. package/numkong/bench/bench_cross_serial.cpp +151 -0
  51. package/numkong/bench/bench_cross_sme.cpp +163 -0
  52. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  53. package/numkong/bench/bench_cross_x86.cpp +455 -0
  54. package/numkong/bench/bench_curved.cpp +210 -0
  55. package/numkong/bench/bench_dot.cpp +315 -0
  56. package/numkong/bench/bench_each.cpp +503 -0
  57. package/numkong/bench/bench_geospatial.cpp +112 -0
  58. package/numkong/bench/bench_maxsim.cpp +154 -0
  59. package/numkong/bench/bench_mesh.cpp +148 -0
  60. package/numkong/bench/bench_probability.cpp +60 -0
  61. package/numkong/bench/bench_reduce.cpp +371 -0
  62. package/numkong/bench/bench_set.cpp +73 -0
  63. package/numkong/bench/bench_sparse.cpp +198 -0
  64. package/numkong/bench/bench_spatial.cpp +347 -0
  65. package/numkong/bench/bench_trigonometry.cpp +137 -0
  66. package/numkong/bench/swift/Bench.swift +506 -0
  67. package/numkong/binding.gyp +169 -0
  68. package/numkong/build.rs +484 -0
  69. package/numkong/c/dispatch.h +512 -0
  70. package/numkong/c/dispatch_bf16.c +447 -0
  71. package/numkong/c/dispatch_bf16c.c +52 -0
  72. package/numkong/c/dispatch_e2m3.c +296 -0
  73. package/numkong/c/dispatch_e3m2.c +284 -0
  74. package/numkong/c/dispatch_e4m3.c +318 -0
  75. package/numkong/c/dispatch_e5m2.c +316 -0
  76. package/numkong/c/dispatch_f16.c +452 -0
  77. package/numkong/c/dispatch_f16c.c +58 -0
  78. package/numkong/c/dispatch_f32.c +434 -0
  79. package/numkong/c/dispatch_f32c.c +99 -0
  80. package/numkong/c/dispatch_f64.c +348 -0
  81. package/numkong/c/dispatch_f64c.c +98 -0
  82. package/numkong/c/dispatch_i16.c +96 -0
  83. package/numkong/c/dispatch_i32.c +89 -0
  84. package/numkong/c/dispatch_i4.c +153 -0
  85. package/numkong/c/dispatch_i64.c +86 -0
  86. package/numkong/c/dispatch_i8.c +348 -0
  87. package/numkong/c/dispatch_other.c +348 -0
  88. package/numkong/c/dispatch_u1.c +193 -0
  89. package/numkong/c/dispatch_u16.c +124 -0
  90. package/numkong/c/dispatch_u32.c +118 -0
  91. package/numkong/c/dispatch_u4.c +153 -0
  92. package/numkong/c/dispatch_u64.c +102 -0
  93. package/numkong/c/dispatch_u8.c +364 -0
  94. package/numkong/c/numkong.c +940 -0
  95. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  96. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  97. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_math_lib.cmake +46 -0
  99. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  100. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  101. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  102. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  103. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  104. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  105. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  106. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  107. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  108. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  109. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  110. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  111. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  112. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  113. package/numkong/include/README.md +643 -0
  114. package/numkong/include/module.modulemap +129 -0
  115. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  116. package/numkong/include/numkong/attention/sme.h +2075 -0
  117. package/numkong/include/numkong/attention.h +49 -0
  118. package/numkong/include/numkong/capabilities.h +930 -0
  119. package/numkong/include/numkong/cast/README.md +262 -0
  120. package/numkong/include/numkong/cast/diamond.h +64 -0
  121. package/numkong/include/numkong/cast/haswell.h +823 -0
  122. package/numkong/include/numkong/cast/icelake.h +475 -0
  123. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  124. package/numkong/include/numkong/cast/neon.h +1174 -0
  125. package/numkong/include/numkong/cast/powervsx.h +449 -0
  126. package/numkong/include/numkong/cast/rvv.h +970 -0
  127. package/numkong/include/numkong/cast/sapphire.h +262 -0
  128. package/numkong/include/numkong/cast/serial.h +2336 -0
  129. package/numkong/include/numkong/cast/skylake.h +915 -0
  130. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  131. package/numkong/include/numkong/cast.h +254 -0
  132. package/numkong/include/numkong/cast.hpp +44 -0
  133. package/numkong/include/numkong/curved/README.md +223 -0
  134. package/numkong/include/numkong/curved/genoa.h +182 -0
  135. package/numkong/include/numkong/curved/haswell.h +276 -0
  136. package/numkong/include/numkong/curved/neon.h +329 -0
  137. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  138. package/numkong/include/numkong/curved/rvv.h +305 -0
  139. package/numkong/include/numkong/curved/serial.h +207 -0
  140. package/numkong/include/numkong/curved/skylake.h +457 -0
  141. package/numkong/include/numkong/curved/smef64.h +530 -0
  142. package/numkong/include/numkong/curved.h +513 -0
  143. package/numkong/include/numkong/curved.hpp +144 -0
  144. package/numkong/include/numkong/dot/README.md +442 -0
  145. package/numkong/include/numkong/dot/alder.h +563 -0
  146. package/numkong/include/numkong/dot/diamond.h +158 -0
  147. package/numkong/include/numkong/dot/genoa.h +289 -0
  148. package/numkong/include/numkong/dot/haswell.h +1723 -0
  149. package/numkong/include/numkong/dot/icelake.h +997 -0
  150. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  151. package/numkong/include/numkong/dot/neon.h +869 -0
  152. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  153. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  154. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  155. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  156. package/numkong/include/numkong/dot/powervsx.h +752 -0
  157. package/numkong/include/numkong/dot/rvv.h +722 -0
  158. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  159. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  160. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  161. package/numkong/include/numkong/dot/sapphire.h +141 -0
  162. package/numkong/include/numkong/dot/serial.h +874 -0
  163. package/numkong/include/numkong/dot/sierra.h +405 -0
  164. package/numkong/include/numkong/dot/skylake.h +1116 -0
  165. package/numkong/include/numkong/dot/sve.h +420 -0
  166. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  167. package/numkong/include/numkong/dot/svehalf.h +168 -0
  168. package/numkong/include/numkong/dot/svesdot.h +90 -0
  169. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  170. package/numkong/include/numkong/dot.h +1136 -0
  171. package/numkong/include/numkong/dot.hpp +94 -0
  172. package/numkong/include/numkong/dots/README.md +496 -0
  173. package/numkong/include/numkong/dots/alder.h +117 -0
  174. package/numkong/include/numkong/dots/diamond.h +86 -0
  175. package/numkong/include/numkong/dots/genoa.h +100 -0
  176. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  177. package/numkong/include/numkong/dots/haswell.h +310 -0
  178. package/numkong/include/numkong/dots/icelake.h +180 -0
  179. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  180. package/numkong/include/numkong/dots/neon.h +123 -0
  181. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  182. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  183. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  184. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  185. package/numkong/include/numkong/dots/powervsx.h +194 -0
  186. package/numkong/include/numkong/dots/rvv.h +2593 -0
  187. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  188. package/numkong/include/numkong/dots/serial.h +2867 -0
  189. package/numkong/include/numkong/dots/sierra.h +100 -0
  190. package/numkong/include/numkong/dots/skylake.h +207 -0
  191. package/numkong/include/numkong/dots/sme.h +5041 -0
  192. package/numkong/include/numkong/dots/smebi32.h +477 -0
  193. package/numkong/include/numkong/dots/smef64.h +1328 -0
  194. package/numkong/include/numkong/dots/smehalf.h +47 -0
  195. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  196. package/numkong/include/numkong/dots.h +3110 -0
  197. package/numkong/include/numkong/dots.hpp +641 -0
  198. package/numkong/include/numkong/each/README.md +465 -0
  199. package/numkong/include/numkong/each/haswell.h +1658 -0
  200. package/numkong/include/numkong/each/icelake.h +272 -0
  201. package/numkong/include/numkong/each/neon.h +1138 -0
  202. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  203. package/numkong/include/numkong/each/neonhalf.h +318 -0
  204. package/numkong/include/numkong/each/rvv.h +1121 -0
  205. package/numkong/include/numkong/each/sapphire.h +343 -0
  206. package/numkong/include/numkong/each/serial.h +282 -0
  207. package/numkong/include/numkong/each/skylake.h +1562 -0
  208. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  209. package/numkong/include/numkong/each.h +2232 -0
  210. package/numkong/include/numkong/each.hpp +434 -0
  211. package/numkong/include/numkong/geospatial/README.md +147 -0
  212. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  213. package/numkong/include/numkong/geospatial/neon.h +615 -0
  214. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  215. package/numkong/include/numkong/geospatial/serial.h +309 -0
  216. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  217. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  218. package/numkong/include/numkong/geospatial.h +453 -0
  219. package/numkong/include/numkong/geospatial.hpp +235 -0
  220. package/numkong/include/numkong/matrix.hpp +336 -0
  221. package/numkong/include/numkong/maxsim/README.md +187 -0
  222. package/numkong/include/numkong/maxsim/alder.h +511 -0
  223. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  224. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  225. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  226. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  227. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  228. package/numkong/include/numkong/maxsim/serial.h +490 -0
  229. package/numkong/include/numkong/maxsim/sme.h +993 -0
  230. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  231. package/numkong/include/numkong/maxsim.h +571 -0
  232. package/numkong/include/numkong/maxsim.hpp +133 -0
  233. package/numkong/include/numkong/mesh/README.md +219 -0
  234. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  235. package/numkong/include/numkong/mesh/neon.h +1821 -0
  236. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  237. package/numkong/include/numkong/mesh/rvv.h +936 -0
  238. package/numkong/include/numkong/mesh/serial.h +721 -0
  239. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  240. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  241. package/numkong/include/numkong/mesh.h +666 -0
  242. package/numkong/include/numkong/mesh.hpp +701 -0
  243. package/numkong/include/numkong/numkong.h +78 -0
  244. package/numkong/include/numkong/numkong.hpp +58 -0
  245. package/numkong/include/numkong/probability/README.md +177 -0
  246. package/numkong/include/numkong/probability/haswell.h +267 -0
  247. package/numkong/include/numkong/probability/neon.h +255 -0
  248. package/numkong/include/numkong/probability/rvv.h +414 -0
  249. package/numkong/include/numkong/probability/serial.h +181 -0
  250. package/numkong/include/numkong/probability/skylake.h +324 -0
  251. package/numkong/include/numkong/probability.h +380 -0
  252. package/numkong/include/numkong/probability.hpp +120 -0
  253. package/numkong/include/numkong/random.h +50 -0
  254. package/numkong/include/numkong/random.hpp +285 -0
  255. package/numkong/include/numkong/reduce/README.md +552 -0
  256. package/numkong/include/numkong/reduce/alder.h +636 -0
  257. package/numkong/include/numkong/reduce/genoa.h +201 -0
  258. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  259. package/numkong/include/numkong/reduce/icelake.h +549 -0
  260. package/numkong/include/numkong/reduce/neon.h +3980 -0
  261. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  262. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  263. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  264. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  265. package/numkong/include/numkong/reduce/serial.h +753 -0
  266. package/numkong/include/numkong/reduce/sierra.h +338 -0
  267. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  268. package/numkong/include/numkong/reduce/sve.h +52 -0
  269. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  270. package/numkong/include/numkong/reduce.h +1582 -0
  271. package/numkong/include/numkong/reduce.hpp +778 -0
  272. package/numkong/include/numkong/scalar/README.md +89 -0
  273. package/numkong/include/numkong/scalar/haswell.h +122 -0
  274. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  275. package/numkong/include/numkong/scalar/neon.h +122 -0
  276. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  277. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  278. package/numkong/include/numkong/scalar/rvv.h +211 -0
  279. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  280. package/numkong/include/numkong/scalar/serial.h +332 -0
  281. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  282. package/numkong/include/numkong/scalar.h +696 -0
  283. package/numkong/include/numkong/set/README.md +179 -0
  284. package/numkong/include/numkong/set/haswell.h +334 -0
  285. package/numkong/include/numkong/set/icelake.h +485 -0
  286. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  287. package/numkong/include/numkong/set/neon.h +363 -0
  288. package/numkong/include/numkong/set/powervsx.h +326 -0
  289. package/numkong/include/numkong/set/rvv.h +226 -0
  290. package/numkong/include/numkong/set/rvvbb.h +117 -0
  291. package/numkong/include/numkong/set/serial.h +174 -0
  292. package/numkong/include/numkong/set/sve.h +187 -0
  293. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  294. package/numkong/include/numkong/set.h +471 -0
  295. package/numkong/include/numkong/set.hpp +114 -0
  296. package/numkong/include/numkong/sets/README.md +149 -0
  297. package/numkong/include/numkong/sets/haswell.h +63 -0
  298. package/numkong/include/numkong/sets/icelake.h +66 -0
  299. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  300. package/numkong/include/numkong/sets/neon.h +61 -0
  301. package/numkong/include/numkong/sets/powervsx.h +65 -0
  302. package/numkong/include/numkong/sets/serial.h +43 -0
  303. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  304. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  305. package/numkong/include/numkong/sets.h +382 -0
  306. package/numkong/include/numkong/sparse/README.md +156 -0
  307. package/numkong/include/numkong/sparse/icelake.h +463 -0
  308. package/numkong/include/numkong/sparse/neon.h +288 -0
  309. package/numkong/include/numkong/sparse/serial.h +117 -0
  310. package/numkong/include/numkong/sparse/sve2.h +504 -0
  311. package/numkong/include/numkong/sparse/turin.h +322 -0
  312. package/numkong/include/numkong/sparse.h +363 -0
  313. package/numkong/include/numkong/sparse.hpp +113 -0
  314. package/numkong/include/numkong/spatial/README.md +439 -0
  315. package/numkong/include/numkong/spatial/alder.h +604 -0
  316. package/numkong/include/numkong/spatial/diamond.h +240 -0
  317. package/numkong/include/numkong/spatial/genoa.h +222 -0
  318. package/numkong/include/numkong/spatial/haswell.h +979 -0
  319. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  320. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  321. package/numkong/include/numkong/spatial/neon.h +846 -0
  322. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  323. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  324. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  325. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  326. package/numkong/include/numkong/spatial/rvv.h +991 -0
  327. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  328. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  329. package/numkong/include/numkong/spatial/serial.h +347 -0
  330. package/numkong/include/numkong/spatial/sierra.h +516 -0
  331. package/numkong/include/numkong/spatial/skylake.h +605 -0
  332. package/numkong/include/numkong/spatial/sve.h +246 -0
  333. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  334. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  335. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  336. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  337. package/numkong/include/numkong/spatial.h +1681 -0
  338. package/numkong/include/numkong/spatial.hpp +183 -0
  339. package/numkong/include/numkong/spatials/README.md +580 -0
  340. package/numkong/include/numkong/spatials/alder.h +94 -0
  341. package/numkong/include/numkong/spatials/diamond.h +82 -0
  342. package/numkong/include/numkong/spatials/genoa.h +94 -0
  343. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  344. package/numkong/include/numkong/spatials/haswell.h +219 -0
  345. package/numkong/include/numkong/spatials/icelake.h +113 -0
  346. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  347. package/numkong/include/numkong/spatials/neon.h +109 -0
  348. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  349. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  350. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  351. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  352. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  353. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  354. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  355. package/numkong/include/numkong/spatials/serial.h +248 -0
  356. package/numkong/include/numkong/spatials/sierra.h +96 -0
  357. package/numkong/include/numkong/spatials/skylake.h +184 -0
  358. package/numkong/include/numkong/spatials/sme.h +1927 -0
  359. package/numkong/include/numkong/spatials/smef64.h +483 -0
  360. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  361. package/numkong/include/numkong/spatials.h +3374 -0
  362. package/numkong/include/numkong/spatials.hpp +509 -0
  363. package/numkong/include/numkong/tensor.hpp +1981 -0
  364. package/numkong/include/numkong/trigonometry/README.md +184 -0
  365. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  366. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  367. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  368. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  369. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  370. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  371. package/numkong/include/numkong/trigonometry.h +467 -0
  372. package/numkong/include/numkong/trigonometry.hpp +166 -0
  373. package/numkong/include/numkong/types.h +1695 -0
  374. package/numkong/include/numkong/types.hpp +6027 -0
  375. package/numkong/include/numkong/vector.hpp +766 -0
  376. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  377. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  378. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  380. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  381. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  382. package/numkong/javascript/README.md +254 -0
  383. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  384. package/numkong/javascript/numkong-browser.ts +40 -0
  385. package/numkong/javascript/numkong-wasm.ts +750 -0
  386. package/numkong/javascript/numkong.c +712 -0
  387. package/numkong/javascript/numkong.ts +613 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  389. package/numkong/javascript/tsconfig-cjs.json +13 -0
  390. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  391. package/numkong/javascript/types.ts +784 -0
  392. package/numkong/numkong.gypi +104 -0
  393. package/numkong/package.json +108 -0
  394. package/numkong/probes/arm_neon.c +8 -0
  395. package/numkong/probes/arm_neon_bfdot.c +9 -0
  396. package/numkong/probes/arm_neon_fhm.c +9 -0
  397. package/numkong/probes/arm_neon_half.c +8 -0
  398. package/numkong/probes/arm_neon_sdot.c +9 -0
  399. package/numkong/probes/arm_neonfp8.c +9 -0
  400. package/numkong/probes/arm_sme.c +16 -0
  401. package/numkong/probes/arm_sme2.c +16 -0
  402. package/numkong/probes/arm_sme2p1.c +16 -0
  403. package/numkong/probes/arm_sme_bf16.c +16 -0
  404. package/numkong/probes/arm_sme_bi32.c +16 -0
  405. package/numkong/probes/arm_sme_f64.c +16 -0
  406. package/numkong/probes/arm_sme_fa64.c +14 -0
  407. package/numkong/probes/arm_sme_half.c +16 -0
  408. package/numkong/probes/arm_sme_lut2.c +15 -0
  409. package/numkong/probes/arm_sve.c +18 -0
  410. package/numkong/probes/arm_sve2.c +20 -0
  411. package/numkong/probes/arm_sve2p1.c +18 -0
  412. package/numkong/probes/arm_sve_bfdot.c +20 -0
  413. package/numkong/probes/arm_sve_half.c +18 -0
  414. package/numkong/probes/arm_sve_sdot.c +21 -0
  415. package/numkong/probes/loongarch_lasx.c +12 -0
  416. package/numkong/probes/power_vsx.c +12 -0
  417. package/numkong/probes/probe.js +127 -0
  418. package/numkong/probes/riscv_rvv.c +14 -0
  419. package/numkong/probes/riscv_rvv_bb.c +15 -0
  420. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  421. package/numkong/probes/riscv_rvv_half.c +14 -0
  422. package/numkong/probes/wasm_v128relaxed.c +11 -0
  423. package/numkong/probes/x86_alder.c +17 -0
  424. package/numkong/probes/x86_diamond.c +17 -0
  425. package/numkong/probes/x86_genoa.c +17 -0
  426. package/numkong/probes/x86_graniteamx.c +19 -0
  427. package/numkong/probes/x86_haswell.c +11 -0
  428. package/numkong/probes/x86_icelake.c +17 -0
  429. package/numkong/probes/x86_sapphire.c +16 -0
  430. package/numkong/probes/x86_sapphireamx.c +18 -0
  431. package/numkong/probes/x86_sierra.c +17 -0
  432. package/numkong/probes/x86_skylake.c +15 -0
  433. package/numkong/probes/x86_turin.c +17 -0
  434. package/numkong/rust/README.md +698 -0
  435. package/numkong/rust/capabilities.rs +96 -0
  436. package/numkong/rust/cast.rs +314 -0
  437. package/numkong/rust/curved.rs +391 -0
  438. package/numkong/rust/each.rs +2721 -0
  439. package/numkong/rust/geospatial.rs +343 -0
  440. package/numkong/rust/matrix.rs +5424 -0
  441. package/numkong/rust/maxsim.rs +540 -0
  442. package/numkong/rust/mesh.rs +837 -0
  443. package/numkong/rust/numkong.rs +409 -0
  444. package/numkong/rust/probability.rs +272 -0
  445. package/numkong/rust/reduce.rs +1249 -0
  446. package/numkong/rust/set.rs +194 -0
  447. package/numkong/rust/sparse.rs +513 -0
  448. package/numkong/rust/spatial.rs +1815 -0
  449. package/numkong/rust/tensor.rs +7565 -0
  450. package/numkong/rust/types.rs +3666 -0
  451. package/numkong/rust/vector.rs +1899 -0
  452. package/numkong/rustfmt.toml +2 -0
  453. package/numkong/swift/Matrix.swift +1388 -0
  454. package/numkong/swift/MaxSim.swift +151 -0
  455. package/numkong/swift/NumKong.swift +283 -0
  456. package/numkong/swift/Numerics.swift +329 -0
  457. package/numkong/swift/README.md +433 -0
  458. package/numkong/swift/Scalar.swift +741 -0
  459. package/numkong/swift/Tensor.swift +209 -0
  460. package/numkong/test/README.md +315 -0
  461. package/numkong/test/playwright.config.ts +16 -0
  462. package/numkong/test/swift/Test.swift +534 -0
  463. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  464. package/numkong/test/test-browser-bundle.html +188 -0
  465. package/numkong/test/test-browser-runner.mjs +43 -0
  466. package/numkong/test/test-browser.html +305 -0
  467. package/numkong/test/test-dtypes.mjs +453 -0
  468. package/numkong/test/test-wasm.mjs +267 -0
  469. package/numkong/test/test.cpp +442 -0
  470. package/numkong/test/test.hpp +580 -0
  471. package/numkong/test/test.mjs +363 -0
  472. package/numkong/test/test_base.py +1041 -0
  473. package/numkong/test/test_cast.cpp +242 -0
  474. package/numkong/test/test_cross.hpp +551 -0
  475. package/numkong/test/test_cross.py +467 -0
  476. package/numkong/test/test_cross_amx.cpp +50 -0
  477. package/numkong/test/test_cross_arm.cpp +225 -0
  478. package/numkong/test/test_cross_blas.cpp +354 -0
  479. package/numkong/test/test_cross_loongarch.cpp +90 -0
  480. package/numkong/test/test_cross_power.cpp +73 -0
  481. package/numkong/test/test_cross_rvv.cpp +109 -0
  482. package/numkong/test/test_cross_serial.cpp +181 -0
  483. package/numkong/test/test_cross_sme.cpp +148 -0
  484. package/numkong/test/test_cross_wasm.cpp +141 -0
  485. package/numkong/test/test_cross_x86.cpp +442 -0
  486. package/numkong/test/test_curved.cpp +182 -0
  487. package/numkong/test/test_curved.py +207 -0
  488. package/numkong/test/test_dot.cpp +353 -0
  489. package/numkong/test/test_dot.py +296 -0
  490. package/numkong/test/test_each.cpp +437 -0
  491. package/numkong/test/test_each.py +756 -0
  492. package/numkong/test/test_geospatial.cpp +155 -0
  493. package/numkong/test/test_geospatial.py +241 -0
  494. package/numkong/test/test_maxsim.cpp +138 -0
  495. package/numkong/test/test_maxsim.py +209 -0
  496. package/numkong/test/test_mesh.cpp +203 -0
  497. package/numkong/test/test_mesh.py +394 -0
  498. package/numkong/test/test_probability.cpp +136 -0
  499. package/numkong/test/test_probability.py +166 -0
  500. package/numkong/test/test_reduce.cpp +563 -0
  501. package/numkong/test/test_reduce.py +781 -0
  502. package/numkong/test/test_set.cpp +151 -0
  503. package/numkong/test/test_set.py +120 -0
  504. package/numkong/test/test_similarities.py +579 -0
  505. package/numkong/test/test_sparse.cpp +121 -0
  506. package/numkong/test/test_sparse.py +118 -0
  507. package/numkong/test/test_spatial.cpp +518 -0
  508. package/numkong/test/test_spatial.py +269 -0
  509. package/numkong/test/test_tensor.cpp +884 -0
  510. package/numkong/test/test_tensor.py +1417 -0
  511. package/numkong/test/test_trigonometry.cpp +156 -0
  512. package/numkong/test/test_trigonometry.py +180 -0
  513. package/package.json +7 -8
  514. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  515. package/prebuilds/linux-arm64/usearch.node +0 -0
  516. package/prebuilds/linux-x64/usearch.node +0 -0
  517. package/fp16/CMakeLists.txt +0 -176
  518. package/fp16/LICENSE +0 -11
  519. package/fp16/README.md +0 -20
  520. package/fp16/bench/alt-element.cc +0 -89
  521. package/fp16/bench/from-alt-array.cc +0 -175
  522. package/fp16/bench/from-ieee-array.cc +0 -399
  523. package/fp16/bench/ieee-element.cc +0 -272
  524. package/fp16/bench/to-alt-array.cc +0 -91
  525. package/fp16/bench/to-ieee-array.cc +0 -303
  526. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  527. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  528. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  529. package/fp16/configure.py +0 -65
  530. package/fp16/confu.yaml +0 -8
  531. package/fp16/include/fp16/__init__.py +0 -0
  532. package/fp16/include/fp16/avx.py +0 -50
  533. package/fp16/include/fp16/avx2.py +0 -53
  534. package/fp16/include/fp16/bitcasts.h +0 -92
  535. package/fp16/include/fp16/fp16.h +0 -451
  536. package/fp16/include/fp16/psimd.h +0 -131
  537. package/fp16/include/fp16.h +0 -11
  538. package/fp16/jni/Android.mk +0 -6
  539. package/fp16/jni/Application.mk +0 -4
  540. package/fp16/test/alt-from-fp32-value.cc +0 -498
  541. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  542. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  543. package/fp16/test/alt-to-fp32-value.cc +0 -348
  544. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  545. package/fp16/test/bitcasts.cc +0 -56
  546. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  547. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  548. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  549. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  550. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  551. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  552. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  553. package/fp16/test/peachpy/stubs.py +0 -38
  554. package/fp16/test/tables.cc +0 -530
  555. package/fp16/test/tables.h +0 -13
  556. package/fp16/third-party/THHalf.h +0 -92
  557. package/fp16/third-party/eigen-half.h +0 -170
  558. package/fp16/third-party/float16-compressor.h +0 -80
  559. package/fp16/third-party/half.hpp +0 -2916
  560. package/fp16/third-party/npy-halffloat.h +0 -328
  561. package/simsimd/.git-blame-ignore-revs +0 -2
  562. package/simsimd/CONTRIBUTING.md +0 -321
  563. package/simsimd/Cargo.toml +0 -49
  564. package/simsimd/MANIFEST.in +0 -4
  565. package/simsimd/Package.swift +0 -28
  566. package/simsimd/README.md +0 -1493
  567. package/simsimd/binding.gyp +0 -35
  568. package/simsimd/build.rs +0 -70
  569. package/simsimd/c/lib.c +0 -374
  570. package/simsimd/include/module.modulemap +0 -4
  571. package/simsimd/include/simsimd/binary.h +0 -486
  572. package/simsimd/include/simsimd/curved.h +0 -1541
  573. package/simsimd/include/simsimd/dot.h +0 -1853
  574. package/simsimd/include/simsimd/elementwise.h +0 -2465
  575. package/simsimd/include/simsimd/geospatial.h +0 -43
  576. package/simsimd/include/simsimd/mesh.h +0 -69
  577. package/simsimd/include/simsimd/probability.h +0 -606
  578. package/simsimd/include/simsimd/simsimd.h +0 -2567
  579. package/simsimd/include/simsimd/sparse.h +0 -1384
  580. package/simsimd/include/simsimd/spatial.h +0 -2335
  581. package/simsimd/include/simsimd/types.h +0 -666
  582. package/simsimd/javascript/fallback.ts +0 -233
  583. package/simsimd/javascript/lib.c +0 -125
  584. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  585. package/simsimd/javascript/simsimd.ts +0 -179
  586. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  587. package/simsimd/package-lock.json +0 -1761
  588. package/simsimd/package.json +0 -61
  589. package/simsimd/rust/lib.rs +0 -1821
  590. package/simsimd/scripts/bench.cxx +0 -1170
  591. package/simsimd/scripts/bench.ipynb +0 -187
  592. package/simsimd/scripts/bench.js +0 -127
  593. package/simsimd/scripts/bench.rs +0 -876
  594. package/simsimd/scripts/bench_vectors.py +0 -734
  595. package/simsimd/scripts/bench_vectors_live.py +0 -213
  596. package/simsimd/scripts/test.c +0 -187
  597. package/simsimd/scripts/test.mjs +0 -220
  598. package/simsimd/scripts/test.py +0 -1505
  599. package/simsimd/swift/SimSIMD.swift +0 -149
  600. package/simsimd/swift/Test.swift +0 -128
  601. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  602. /package/{simsimd → numkong}/LICENSE +0 -0
  603. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  604. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,622 @@
1
+ /**
2
+ * @brief SIMD-accelerated Dot Products for NEON SDOT.
3
+ * @file include/numkong/dot/neonsdot.h
4
+ * @author Ash Vardanian
5
+ * @date December 27, 2025
6
+ *
7
+ * @sa include/numkong/dot.h
8
+ *
9
+ * @section dot_neonsdot_instructions ARM NEON SDOT/UDOT Instructions (ARMv8.4-DotProd)
10
+ *
11
+ * Intrinsic Instruction A76 M5
12
+ * vdotq_s32 SDOT (V.4S, V.16B, V.16B) 3cy @ 2p 3cy @ 4p
13
+ * vdotq_u32 UDOT (V.4S, V.16B, V.16B) 3cy @ 2p 3cy @ 4p
14
+ * vld1q_s8 LD1 (V.16B) 4cy @ 2p 4cy @ 3p
15
+ * vld1q_u8 LD1 (V.16B) 4cy @ 2p 4cy @ 3p
16
+ * vaddvq_s32 ADDV (V.4S) 4cy @ 1p 5cy @ 1p
17
+ * vaddvq_u32 ADDV (V.4S) 4cy @ 1p 5cy @ 1p
18
+ * vpaddq_s32 ADDP (V.4S, V.4S, V.4S) 2cy @ 2p 2cy @ 4p
19
+ * vpaddq_u32 ADDP (V.4S, V.4S, V.4S) 2cy @ 2p 2cy @ 4p
20
+ *
21
+ * Extraction ops used for i4/u4 nibble unpacking and e2m3/e3m2 LUT conversion:
22
+ *
23
+ * vshlq_n_s8 SHL (V.16B, #imm) 2cy @ 2p 2cy @ 4p
24
+ * vshrq_n_s8 SSHR (V.16B, #imm) 2cy @ 2p 2cy @ 4p
25
+ * vshrq_n_u8 USHR (V.16B, #imm) 2cy @ 2p 2cy @ 4p
26
+ * vandq_u8 AND (V.16B, V.16B) 1cy @ 2p 2cy @ 4p
27
+ * veorq_u8 EOR (V.16B, V.16B) 1cy @ 2p 2cy @ 4p
28
+ * vqtbl2q_u8 TBL (V.16B, {2reg}, V.16B) 2cy @ 1p 2cy @ 4p
29
+ * vqtbl4q_u8 TBL (V.16B, {4reg}, V.16B) 2cy @ 1p 4cy @ 2p+2p
30
+ * vmlal_s16 SMLAL (V.4S, V.4H, V.4H) 3cy @ 1p 2cy @ 4p
31
+ *
32
+ * The ARMv8.4-DotProd extension provides SDOT/UDOT instructions critical for int8 quantized ML
33
+ * inference. Each instruction computes four dot products of 4-element int8 vectors, accumulating
34
+ * into int32 lanes, processing 16 multiply-accumulates per instruction.
35
+ *
36
+ * SDOT handles signed int8 operands while UDOT handles unsigned. The 3-cycle latency with 2/cy
37
+ * throughput on A76 (4/cy on newer cores) enables int8 matrix multiplication for
38
+ * quantized neural network inference, where 8-bit weights reduce memory bandwidth by 4x vs FP32.
39
+ *
40
+ * @section dot_neonsdot_stateful Stateful Streaming Logic
41
+ *
42
+ * To build memory-optimal tiled algorithms, this file defines following structures and force-inlined
43
+ * `NK_INTERNAL` functions:
44
+ *
45
+ * - nk_dot_i8x16 for 8-bit signed integer inputs using SDOT,
46
+ * - nk_dot_u8x16 for 8-bit unsigned integer inputs using UDOT,
47
+ * - nk_dot_i4x32 for 4-bit signed integer products,
48
+ * - nk_dot_u4x32 for 4-bit unsigned integer products.
49
+ *
50
+ * @code{c}
51
+ * nk_dot_i8x16_state_neonsdot_t state_first, state_second, state_third, state_fourth;
52
+ * int8x16_t query_i8x16, target_first_i8x16, target_second_i8x16, target_third_i8x16, target_fourth_i8x16;
53
+ * nk_dot_i8x16_init_neonsdot(&state_first);
54
+ * nk_dot_i8x16_init_neonsdot(&state_second);
55
+ * nk_dot_i8x16_init_neonsdot(&state_third);
56
+ * nk_dot_i8x16_init_neonsdot(&state_fourth);
57
+ * for (nk_size_t idx = 0; idx + 16 <= depth; idx += 16) {
58
+ * query_i8x16 = vld1q_s8(query_ptr + idx);
59
+ * target_first_i8x16 = vld1q_s8(target_first_ptr + idx);
60
+ * target_second_i8x16 = vld1q_s8(target_second_ptr + idx);
61
+ * target_third_i8x16 = vld1q_s8(target_third_ptr + idx);
62
+ * target_fourth_i8x16 = vld1q_s8(target_fourth_ptr + idx);
63
+ * nk_dot_i8x16_update_neonsdot(&state_first, query_i8x16, target_first_i8x16, idx, 16);
64
+ * nk_dot_i8x16_update_neonsdot(&state_second, query_i8x16, target_second_i8x16, idx, 16);
65
+ * nk_dot_i8x16_update_neonsdot(&state_third, query_i8x16, target_third_i8x16, idx, 16);
66
+ * nk_dot_i8x16_update_neonsdot(&state_fourth, query_i8x16, target_fourth_i8x16, idx, 16);
67
+ * }
68
+ * int32x4_t results_i32x4;
69
+ * nk_dot_i8x16_finalize_neonsdot(&state_first, &state_second, &state_third, &state_fourth, depth, &results_i32x4);
70
+ * @endcode
71
+ *
72
+ * For 4-bit integers, the state manages unpacking and accumulation:
73
+ *
74
+ * @code{c}
75
+ * nk_dot_i4x32_state_neonsdot_t state_first, state_second, state_third, state_fourth;
76
+ * uint8x8_t query_packed, target_first_packed, target_second_packed, target_third_packed, target_fourth_packed;
77
+ * nk_dot_i4x32_init_neonsdot(&state_first);
78
+ * nk_dot_i4x32_init_neonsdot(&state_second);
79
+ * nk_dot_i4x32_init_neonsdot(&state_third);
80
+ * nk_dot_i4x32_init_neonsdot(&state_fourth);
81
+ * for (nk_size_t idx = 0; idx + 16 <= depth; idx += 16) {
82
+ * query_packed = vld1_u8(query_ptr + idx / 2);
83
+ * target_first_packed = vld1_u8(target_first_ptr + idx / 2);
84
+ * target_second_packed = vld1_u8(target_second_ptr + idx / 2);
85
+ * target_third_packed = vld1_u8(target_third_ptr + idx / 2);
86
+ * target_fourth_packed = vld1_u8(target_fourth_ptr + idx / 2);
87
+ * nk_dot_i4x32_update_neonsdot(&state_first, query_packed, target_first_packed, idx, 16);
88
+ * nk_dot_i4x32_update_neonsdot(&state_second, query_packed, target_second_packed, idx, 16);
89
+ * nk_dot_i4x32_update_neonsdot(&state_third, query_packed, target_third_packed, idx, 16);
90
+ * nk_dot_i4x32_update_neonsdot(&state_fourth, query_packed, target_fourth_packed, idx, 16);
91
+ * }
92
+ * int32x4_t results_i32x4;
93
+ * nk_dot_i4x32_finalize_neonsdot(&state_first, &state_second, &state_third, &state_fourth, depth, &results_i32x4);
94
+ * @endcode
95
+ */
96
+ #ifndef NK_DOT_NEONSDOT_H
97
+ #define NK_DOT_NEONSDOT_H
98
+
99
+ #if NK_TARGET_ARM64_
100
+ #if NK_TARGET_NEONSDOT
101
+
102
+ #include "numkong/types.h"
103
+
104
+ #if defined(__cplusplus)
105
+ extern "C" {
106
+ #endif
107
+
108
+ #if defined(__clang__)
109
+ #pragma clang attribute push(__attribute__((target("arch=armv8.2-a+dotprod"))), apply_to = function)
110
+ #elif defined(__GNUC__)
111
+ #pragma GCC push_options
112
+ #pragma GCC target("arch=armv8.2-a+dotprod")
113
+ #endif
114
+
115
+ NK_PUBLIC void nk_dot_i8_neonsdot(nk_i8_t const *a_scalars, nk_i8_t const *b_scalars, nk_size_t count_scalars,
116
+ nk_i32_t *result) {
117
+ int32x4_t sum_i32x4 = vdupq_n_s32(0);
118
+ nk_size_t idx_scalars = 0;
119
+ for (; idx_scalars + 16 <= count_scalars; idx_scalars += 16) {
120
+ int8x16_t a_i8x16 = vld1q_s8(a_scalars + idx_scalars);
121
+ int8x16_t b_i8x16 = vld1q_s8(b_scalars + idx_scalars);
122
+ sum_i32x4 = vdotq_s32(sum_i32x4, a_i8x16, b_i8x16);
123
+ }
124
+ nk_i32_t sum = vaddvq_s32(sum_i32x4);
125
+ for (; idx_scalars < count_scalars; ++idx_scalars) sum += (nk_i32_t)a_scalars[idx_scalars] * b_scalars[idx_scalars];
126
+ *result = sum;
127
+ }
128
+
129
+ NK_PUBLIC void nk_dot_u8_neonsdot(nk_u8_t const *a_scalars, nk_u8_t const *b_scalars, nk_size_t count_scalars,
130
+ nk_u32_t *result) {
131
+ uint32x4_t sum_u32x4 = vdupq_n_u32(0);
132
+ nk_size_t idx_scalars = 0;
133
+ for (; idx_scalars + 16 <= count_scalars; idx_scalars += 16) {
134
+ uint8x16_t a_u8x16 = vld1q_u8(a_scalars + idx_scalars);
135
+ uint8x16_t b_u8x16 = vld1q_u8(b_scalars + idx_scalars);
136
+ sum_u32x4 = vdotq_u32(sum_u32x4, a_u8x16, b_u8x16);
137
+ }
138
+ nk_u32_t sum = vaddvq_u32(sum_u32x4);
139
+ for (; idx_scalars < count_scalars; ++idx_scalars) sum += (nk_u32_t)a_scalars[idx_scalars] * b_scalars[idx_scalars];
140
+ *result = sum;
141
+ }
142
+
143
+ /**
144
+ * @brief Running state for 128-bit dot accumulation over i8 scalars on NEON.
145
+ */
146
+ typedef struct nk_dot_i8x16_state_neonsdot_t {
147
+ int32x4_t sum_i32x4;
148
+ } nk_dot_i8x16_state_neonsdot_t;
149
+
150
+ NK_INTERNAL void nk_dot_i8x16_init_neonsdot(nk_dot_i8x16_state_neonsdot_t *state) { state->sum_i32x4 = vdupq_n_s32(0); }
151
+
152
+ NK_INTERNAL void nk_dot_i8x16_update_neonsdot(nk_dot_i8x16_state_neonsdot_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
153
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
154
+ nk_unused_(depth_offset);
155
+ nk_unused_(active_dimensions);
156
+ int32x4_t sum_i32x4 = state->sum_i32x4;
157
+ sum_i32x4 = vdotq_s32(sum_i32x4, vreinterpretq_s8_u32(a.u32x4), vreinterpretq_s8_u32(b.u32x4));
158
+ state->sum_i32x4 = sum_i32x4;
159
+ }
160
+
161
+ NK_INTERNAL void nk_dot_i8x16_finalize_neonsdot( //
162
+ nk_dot_i8x16_state_neonsdot_t const *state_a, nk_dot_i8x16_state_neonsdot_t const *state_b, //
163
+ nk_dot_i8x16_state_neonsdot_t const *state_c, nk_dot_i8x16_state_neonsdot_t const *state_d, //
164
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
165
+ nk_unused_(total_dimensions);
166
+ int32x4_t ab_i32x4 = vpaddq_s32(state_a->sum_i32x4, state_b->sum_i32x4);
167
+ int32x4_t cd_i32x4 = vpaddq_s32(state_c->sum_i32x4, state_d->sum_i32x4);
168
+ result->i32x4 = vpaddq_s32(ab_i32x4, cd_i32x4);
169
+ }
170
+
171
+ /**
172
+ * @brief Running state for 128-bit dot accumulation over u8 scalars on NEON.
173
+ */
174
+ typedef struct nk_dot_u8x16_state_neonsdot_t {
175
+ uint32x4_t sum_u32x4;
176
+ } nk_dot_u8x16_state_neonsdot_t;
177
+
178
+ NK_INTERNAL void nk_dot_u8x16_init_neonsdot(nk_dot_u8x16_state_neonsdot_t *state) { state->sum_u32x4 = vdupq_n_u32(0); }
179
+
180
+ NK_INTERNAL void nk_dot_u8x16_update_neonsdot(nk_dot_u8x16_state_neonsdot_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
181
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
182
+ nk_unused_(depth_offset);
183
+ nk_unused_(active_dimensions);
184
+ uint32x4_t sum_u32x4 = state->sum_u32x4;
185
+ sum_u32x4 = vdotq_u32(sum_u32x4, vreinterpretq_u8_u32(a.u32x4), vreinterpretq_u8_u32(b.u32x4));
186
+ state->sum_u32x4 = sum_u32x4;
187
+ }
188
+
189
+ NK_INTERNAL void nk_dot_u8x16_finalize_neonsdot( //
190
+ nk_dot_u8x16_state_neonsdot_t const *state_a, nk_dot_u8x16_state_neonsdot_t const *state_b, //
191
+ nk_dot_u8x16_state_neonsdot_t const *state_c, nk_dot_u8x16_state_neonsdot_t const *state_d, //
192
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
193
+ nk_unused_(total_dimensions);
194
+ uint32x4_t ab_u32x4 = vpaddq_u32(state_a->sum_u32x4, state_b->sum_u32x4);
195
+ uint32x4_t cd_u32x4 = vpaddq_u32(state_c->sum_u32x4, state_d->sum_u32x4);
196
+ result->u32x4 = vpaddq_u32(ab_u32x4, cd_u32x4);
197
+ }
198
+
199
+ NK_PUBLIC void nk_dot_i4_neonsdot(nk_i4x2_t const *a, nk_i4x2_t const *b, nk_size_t n, nk_i32_t *result) {
200
+ // i4 values are packed as nibbles: two 4-bit signed values per byte.
201
+ // Parameter `n` is the number of 4-bit values (dimensions), not bytes.
202
+ //
203
+ // ARM NEON SDOT handles signed×signed directly, so we use direct sign-extension:
204
+ // Extract nibbles [0,15], sign-extend to i8 [-8,7] via shift trick, then SDOT.
205
+ // No algebraic correction needed unlike x86 DPBUSD.
206
+ //
207
+ n = nk_size_round_up_to_multiple_(n, 2);
208
+ nk_size_t n_bytes = n / 2;
209
+ int32x4_t sum_i32x4 = vdupq_n_s32(0);
210
+ uint8x16_t a_i4x32_u8x16, b_i4x32_u8x16;
211
+
212
+ nk_dot_i4_neonsdot_cycle:
213
+ if (n_bytes < 16) {
214
+ // Partial load for tail handling
215
+ nk_b128_vec_t a_vec = {0}, b_vec = {0};
216
+ nk_u8_t const *a_ptr = (nk_u8_t const *)a;
217
+ nk_u8_t const *b_ptr = (nk_u8_t const *)b;
218
+ for (nk_size_t i = 0; i < n_bytes; i++) {
219
+ a_vec.u8s[i] = a_ptr[i];
220
+ b_vec.u8s[i] = b_ptr[i];
221
+ }
222
+ a_i4x32_u8x16 = a_vec.u8x16;
223
+ b_i4x32_u8x16 = b_vec.u8x16;
224
+ n_bytes = 0;
225
+ }
226
+ else {
227
+ a_i4x32_u8x16 = vld1q_u8((nk_u8_t const *)a);
228
+ b_i4x32_u8x16 = vld1q_u8((nk_u8_t const *)b);
229
+ a += 16, b += 16, n_bytes -= 16;
230
+ }
231
+
232
+ // Sign-extend low nibbles: SHL 4 discards high nibble, arithmetic SHR 4 sign-extends
233
+ int8x16_t a_low_i8x16 = vshrq_n_s8(vshlq_n_s8(vreinterpretq_s8_u8(a_i4x32_u8x16), 4), 4);
234
+ int8x16_t b_low_i8x16 = vshrq_n_s8(vshlq_n_s8(vreinterpretq_s8_u8(b_i4x32_u8x16), 4), 4);
235
+ // Sign-extend high nibbles: arithmetic SHR 4 directly sign-extends
236
+ int8x16_t a_high_i8x16 = vshrq_n_s8(vreinterpretq_s8_u8(a_i4x32_u8x16), 4);
237
+ int8x16_t b_high_i8x16 = vshrq_n_s8(vreinterpretq_s8_u8(b_i4x32_u8x16), 4);
238
+
239
+ // SDOT for signed dot product - no correction needed!
240
+ sum_i32x4 = vdotq_s32(sum_i32x4, a_low_i8x16, b_low_i8x16);
241
+ sum_i32x4 = vdotq_s32(sum_i32x4, a_high_i8x16, b_high_i8x16);
242
+
243
+ if (n_bytes) goto nk_dot_i4_neonsdot_cycle;
244
+
245
+ *result = vaddvq_s32(sum_i32x4);
246
+ }
247
+
248
+ NK_PUBLIC void nk_dot_u4_neonsdot(nk_u4x2_t const *a, nk_u4x2_t const *b, nk_size_t n, nk_u32_t *result) {
249
+ // u4 values are packed as nibbles: two 4-bit unsigned values per byte.
250
+ // Parameter `n` is the number of 4-bit values (dimensions), not bytes.
251
+ // Values are ∈ [0,15], so UDOT can be used directly.
252
+ //
253
+ n = nk_size_round_up_to_multiple_(n, 2);
254
+ nk_size_t n_bytes = n / 2;
255
+ uint8x16_t const nibble_mask_u8x16 = vdupq_n_u8(0x0F);
256
+ uint32x4_t sum_u32x4 = vdupq_n_u32(0);
257
+ uint8x16_t a_u4x32_u8x16, b_u4x32_u8x16;
258
+
259
+ nk_dot_u4_neonsdot_cycle:
260
+ if (n_bytes < 16) {
261
+ // Partial load for tail handling
262
+ nk_b128_vec_t a_vec = {0}, b_vec = {0};
263
+ nk_u8_t const *a_ptr = (nk_u8_t const *)a;
264
+ nk_u8_t const *b_ptr = (nk_u8_t const *)b;
265
+ for (nk_size_t i = 0; i < n_bytes; i++) {
266
+ a_vec.u8s[i] = a_ptr[i];
267
+ b_vec.u8s[i] = b_ptr[i];
268
+ }
269
+ a_u4x32_u8x16 = a_vec.u8x16;
270
+ b_u4x32_u8x16 = b_vec.u8x16;
271
+ n_bytes = 0;
272
+ }
273
+ else {
274
+ a_u4x32_u8x16 = vld1q_u8((nk_u8_t const *)a);
275
+ b_u4x32_u8x16 = vld1q_u8((nk_u8_t const *)b);
276
+ a += 16, b += 16, n_bytes -= 16;
277
+ }
278
+
279
+ // Extract low and high nibbles - values in [0,15] work directly with UDOT
280
+ uint8x16_t a_low_u8x16 = vandq_u8(a_u4x32_u8x16, nibble_mask_u8x16);
281
+ uint8x16_t a_high_u8x16 = vshrq_n_u8(a_u4x32_u8x16, 4);
282
+ uint8x16_t b_low_u8x16 = vandq_u8(b_u4x32_u8x16, nibble_mask_u8x16);
283
+ uint8x16_t b_high_u8x16 = vshrq_n_u8(b_u4x32_u8x16, 4);
284
+
285
+ // UDOT directly on unsigned nibbles
286
+ sum_u32x4 = vdotq_u32(sum_u32x4, a_low_u8x16, b_low_u8x16);
287
+ sum_u32x4 = vdotq_u32(sum_u32x4, a_high_u8x16, b_high_u8x16);
288
+
289
+ if (n_bytes) goto nk_dot_u4_neonsdot_cycle;
290
+
291
+ *result = vaddvq_u32(sum_u32x4);
292
+ }
293
+
294
+ typedef struct nk_dot_i4x32_state_neonsdot_t {
295
+ int32x4_t product_sum_i32x4;
296
+ } nk_dot_i4x32_state_neonsdot_t;
297
+
298
+ NK_INTERNAL void nk_dot_i4x32_init_neonsdot(nk_dot_i4x32_state_neonsdot_t *state) {
299
+ state->product_sum_i32x4 = vdupq_n_s32(0);
300
+ }
301
+
302
+ NK_INTERNAL void nk_dot_i4x32_update_neonsdot(nk_dot_i4x32_state_neonsdot_t *state, nk_b128_vec_t a_i4x32,
303
+ nk_b128_vec_t b_i4x32, nk_size_t depth_offset,
304
+ nk_size_t active_dimensions) {
305
+ nk_unused_(depth_offset);
306
+ nk_unused_(active_dimensions);
307
+
308
+ // Sign-extend low nibbles: SHL 4 discards high nibble, arithmetic SHR 4 sign-extends (2 ops each)
309
+ int8x16_t a_low_i8x16 = vshrq_n_s8(vshlq_n_s8(vreinterpretq_s8_u8(a_i4x32.u8x16), 4), 4);
310
+ int8x16_t b_low_i8x16 = vshrq_n_s8(vshlq_n_s8(vreinterpretq_s8_u8(b_i4x32.u8x16), 4), 4);
311
+ // Sign-extend high nibbles: arithmetic SHR 4 directly sign-extends (1 op each)
312
+ int8x16_t a_high_i8x16 = vshrq_n_s8(vreinterpretq_s8_u8(a_i4x32.u8x16), 4);
313
+ int8x16_t b_high_i8x16 = vshrq_n_s8(vreinterpretq_s8_u8(b_i4x32.u8x16), 4);
314
+
315
+ // SDOT for signed dot product - no correction needed!
316
+ int32x4_t product_sum_i32x4 = state->product_sum_i32x4;
317
+ product_sum_i32x4 = vdotq_s32(product_sum_i32x4, a_low_i8x16, b_low_i8x16);
318
+ product_sum_i32x4 = vdotq_s32(product_sum_i32x4, a_high_i8x16, b_high_i8x16);
319
+ state->product_sum_i32x4 = product_sum_i32x4;
320
+ }
321
+
322
+ NK_INTERNAL void nk_dot_i4x32_finalize_neonsdot( //
323
+ nk_dot_i4x32_state_neonsdot_t const *state_a, nk_dot_i4x32_state_neonsdot_t const *state_b, //
324
+ nk_dot_i4x32_state_neonsdot_t const *state_c, nk_dot_i4x32_state_neonsdot_t const *state_d, //
325
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
326
+ nk_unused_(total_dimensions);
327
+ // Simple reduction - no correction formula needed with sign-extension approach!
328
+ int32x4_t ab_i32x4 = vpaddq_s32(state_a->product_sum_i32x4, state_b->product_sum_i32x4);
329
+ int32x4_t cd_i32x4 = vpaddq_s32(state_c->product_sum_i32x4, state_d->product_sum_i32x4);
330
+ result->i32x4 = vpaddq_s32(ab_i32x4, cd_i32x4);
331
+ }
332
+
333
+ typedef struct nk_dot_u4x32_state_neonsdot_t {
334
+ uint32x4_t product_sum_u32x4;
335
+ } nk_dot_u4x32_state_neonsdot_t;
336
+
337
+ NK_INTERNAL void nk_dot_u4x32_init_neonsdot(nk_dot_u4x32_state_neonsdot_t *state) {
338
+ state->product_sum_u32x4 = vdupq_n_u32(0);
339
+ }
340
+
341
+ NK_INTERNAL void nk_dot_u4x32_update_neonsdot(nk_dot_u4x32_state_neonsdot_t *state, nk_b128_vec_t a_u4x32,
342
+ nk_b128_vec_t b_u4x32, nk_size_t depth_offset,
343
+ nk_size_t active_dimensions) {
344
+ nk_unused_(depth_offset);
345
+ nk_unused_(active_dimensions);
346
+ uint8x16_t const nibble_mask_u8x16 = vdupq_n_u8(0x0F);
347
+
348
+ // Extract nibbles - values in [0,15] work directly with UDOT
349
+ uint8x16_t a_low_u8x16 = vandq_u8(a_u4x32.u8x16, nibble_mask_u8x16);
350
+ uint8x16_t a_high_u8x16 = vshrq_n_u8(a_u4x32.u8x16, 4);
351
+ uint8x16_t b_low_u8x16 = vandq_u8(b_u4x32.u8x16, nibble_mask_u8x16);
352
+ uint8x16_t b_high_u8x16 = vshrq_n_u8(b_u4x32.u8x16, 4);
353
+
354
+ // UDOT directly on unsigned nibbles
355
+ uint32x4_t product_sum_u32x4 = state->product_sum_u32x4;
356
+ product_sum_u32x4 = vdotq_u32(product_sum_u32x4, a_low_u8x16, b_low_u8x16);
357
+ product_sum_u32x4 = vdotq_u32(product_sum_u32x4, a_high_u8x16, b_high_u8x16);
358
+ state->product_sum_u32x4 = product_sum_u32x4;
359
+ }
360
+
361
+ NK_INTERNAL void nk_dot_u4x32_finalize_neonsdot( //
362
+ nk_dot_u4x32_state_neonsdot_t const *state_a, nk_dot_u4x32_state_neonsdot_t const *state_b, //
363
+ nk_dot_u4x32_state_neonsdot_t const *state_c, nk_dot_u4x32_state_neonsdot_t const *state_d, //
364
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
365
+ nk_unused_(total_dimensions);
366
+ // Simple reduction - no correction formula needed!
367
+ uint32x4_t ab_u32x4 = vpaddq_u32(state_a->product_sum_u32x4, state_b->product_sum_u32x4);
368
+ uint32x4_t cd_u32x4 = vpaddq_u32(state_c->product_sum_u32x4, state_d->product_sum_u32x4);
369
+ result->u32x4 = vpaddq_u32(ab_u32x4, cd_u32x4);
370
+ }
371
+
372
+ NK_PUBLIC void nk_dot_e2m3_neonsdot(nk_e2m3_t const *a_scalars, nk_e2m3_t const *b_scalars, nk_size_t count_scalars,
373
+ nk_f32_t *result) {
374
+ // Integer dot product for e2m3 using SDOT (signed×signed i8 → i32).
375
+ // Every e2m3 value × 16 is an exact integer in [-120, +120], fits signed i8.
376
+ // Result = i32_dot / 256.0f (exact, no rounding error).
377
+ //
378
+ // 32-entry LUT via vqtbl2q_u8 (handles 0-31 indices in one instruction).
379
+ static nk_u8_t const lut_data[32] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
380
+ 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 88, 96, 104, 112, 120};
381
+ uint8x16x2_t lut_magnitude_u8x16x2 = vld1q_u8_x2(lut_data);
382
+ uint8x16_t magnitude_mask_u8x16 = vdupq_n_u8(0x1F);
383
+ uint8x16_t sign_mask_u8x16 = vdupq_n_u8(0x20);
384
+ int32x4_t sum_i32x4 = vdupq_n_s32(0);
385
+ uint8x16_t a_e2m3_u8x16, b_e2m3_u8x16;
386
+
387
+ nk_dot_e2m3_neonsdot_cycle:
388
+ if (count_scalars < 16) {
389
+ nk_b128_vec_t a_vec, b_vec;
390
+ nk_partial_load_b8x16_serial_(a_scalars, &a_vec, count_scalars);
391
+ nk_partial_load_b8x16_serial_(b_scalars, &b_vec, count_scalars);
392
+ a_e2m3_u8x16 = a_vec.u8x16;
393
+ b_e2m3_u8x16 = b_vec.u8x16;
394
+ count_scalars = 0;
395
+ }
396
+ else {
397
+ a_e2m3_u8x16 = vld1q_u8((nk_u8_t const *)a_scalars);
398
+ b_e2m3_u8x16 = vld1q_u8((nk_u8_t const *)b_scalars);
399
+ a_scalars += 16, b_scalars += 16, count_scalars -= 16;
400
+ }
401
+
402
+ // Extract 5-bit magnitude indices and LUT lookup
403
+ uint8x16_t a_magnitude_u8x16 = vandq_u8(a_e2m3_u8x16, magnitude_mask_u8x16);
404
+ uint8x16_t b_magnitude_u8x16 = vandq_u8(b_e2m3_u8x16, magnitude_mask_u8x16);
405
+ uint8x16_t a_unsigned_u8x16 = vqtbl2q_u8(lut_magnitude_u8x16x2, a_magnitude_u8x16);
406
+ uint8x16_t b_unsigned_u8x16 = vqtbl2q_u8(lut_magnitude_u8x16x2, b_magnitude_u8x16);
407
+
408
+ // Combined sign: (a ^ b) & 0x20 — nonzero means negative product
409
+ uint8x16_t sign_combined_u8x16 = vandq_u8(veorq_u8(a_e2m3_u8x16, b_e2m3_u8x16), sign_mask_u8x16);
410
+ uint8x16_t negate_mask_u8x16 = vceqq_u8(sign_combined_u8x16, sign_mask_u8x16);
411
+
412
+ // Negate b where signs differ, keep positive otherwise
413
+ int8x16_t b_signed_i8x16 = vbslq_s8(negate_mask_u8x16, vnegq_s8(vreinterpretq_s8_u8(b_unsigned_u8x16)),
414
+ vreinterpretq_s8_u8(b_unsigned_u8x16));
415
+
416
+ // SDOT: signed×signed, 4 bytes → i32
417
+ sum_i32x4 = vdotq_s32(sum_i32x4, vreinterpretq_s8_u8(a_unsigned_u8x16), b_signed_i8x16);
418
+
419
+ if (count_scalars) goto nk_dot_e2m3_neonsdot_cycle;
420
+ *result = (nk_f32_t)vaddvq_s32(sum_i32x4) / 256.0f;
421
+ }
422
+
423
+ NK_PUBLIC void nk_dot_e3m2_neonsdot(nk_e3m2_t const *a_scalars, nk_e3m2_t const *b_scalars, nk_size_t count_scalars,
424
+ nk_f32_t *result) {
425
+ // Integer dot product for e3m2 using i16 LUT via vqtbl2q_u8 (low bytes) + comparison (high byte) + SMLAL.
426
+ // Every e3m2 value × 16 is an exact integer, but magnitudes reach 448, requiring i16.
427
+ // Result = i32_dot / 256.0f (exact, no rounding error).
428
+ //
429
+ // The 32-entry magnitude LUT low bytes are looked up via vqtbl2q_u8.
430
+ // High byte is 1 only for indices 28-31 (values 256-448), replaced by a >= 28 comparison.
431
+ static nk_u8_t const lut_data[32] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28,
432
+ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0, 64, 128, 192};
433
+ uint8x16x2_t lut_u8x16x2 = vld1q_u8_x2(lut_data);
434
+ uint8x16_t high_threshold_u8x16 = vdupq_n_u8(28);
435
+ uint8x16_t magnitude_mask_u8x16 = vdupq_n_u8(0x1F);
436
+ uint8x16_t sign_mask_u8x16 = vdupq_n_u8(0x20);
437
+ int32x4_t sum0_i32x4 = vdupq_n_s32(0);
438
+ int32x4_t sum1_i32x4 = vdupq_n_s32(0);
439
+ uint8x16_t a_e3m2_u8x16, b_e3m2_u8x16;
440
+
441
+ nk_dot_e3m2_neonsdot_cycle:
442
+ if (count_scalars < 16) {
443
+ nk_b128_vec_t a_vec, b_vec;
444
+ nk_partial_load_b8x16_serial_(a_scalars, &a_vec, count_scalars);
445
+ nk_partial_load_b8x16_serial_(b_scalars, &b_vec, count_scalars);
446
+ a_e3m2_u8x16 = a_vec.u8x16;
447
+ b_e3m2_u8x16 = b_vec.u8x16;
448
+ count_scalars = 0;
449
+ }
450
+ else {
451
+ a_e3m2_u8x16 = vld1q_u8((nk_u8_t const *)a_scalars);
452
+ b_e3m2_u8x16 = vld1q_u8((nk_u8_t const *)b_scalars);
453
+ a_scalars += 16, b_scalars += 16, count_scalars -= 16;
454
+ }
455
+
456
+ // Extract 5-bit magnitude indices
457
+ uint8x16_t a_mag_u8x16 = vandq_u8(a_e3m2_u8x16, magnitude_mask_u8x16);
458
+ uint8x16_t b_mag_u8x16 = vandq_u8(b_e3m2_u8x16, magnitude_mask_u8x16);
459
+
460
+ // LUT lookup for low bytes; high byte via comparison (1 iff index >= 28)
461
+ uint8x16_t a_low_u8x16 = vqtbl2q_u8(lut_u8x16x2, a_mag_u8x16);
462
+ uint8x16_t b_low_u8x16 = vqtbl2q_u8(lut_u8x16x2, b_mag_u8x16);
463
+ uint8x16_t a_high_u8x16 = vandq_u8(vcgeq_u8(a_mag_u8x16, high_threshold_u8x16), vdupq_n_u8(1));
464
+ uint8x16_t b_high_u8x16 = vandq_u8(vcgeq_u8(b_mag_u8x16, high_threshold_u8x16), vdupq_n_u8(1));
465
+
466
+ // Combine low and high bytes into i16 via byte interleave (little-endian: low byte first)
467
+ int16x8_t a_unsigned_low_i16x8 = vreinterpretq_s16_u8(vzip1q_u8(a_low_u8x16, a_high_u8x16));
468
+ int16x8_t a_unsigned_high_i16x8 = vreinterpretq_s16_u8(vzip2q_u8(a_low_u8x16, a_high_u8x16));
469
+ int16x8_t b_unsigned_low_i16x8 = vreinterpretq_s16_u8(vzip1q_u8(b_low_u8x16, b_high_u8x16));
470
+ int16x8_t b_unsigned_high_i16x8 = vreinterpretq_s16_u8(vzip2q_u8(b_low_u8x16, b_high_u8x16));
471
+
472
+ // Combined sign: XOR sign bits, negate only b (saves ~15 ops vs independent negation)
473
+ uint8x16_t sign_combined_u8x16 = vandq_u8(veorq_u8(a_e3m2_u8x16, b_e3m2_u8x16), sign_mask_u8x16);
474
+ uint8x16_t negate_mask_u8x16 = vceqq_u8(sign_combined_u8x16, sign_mask_u8x16);
475
+ uint16x8_t negate_low_u16x8 = vreinterpretq_u16_u8(vzip1q_u8(negate_mask_u8x16, negate_mask_u8x16));
476
+ uint16x8_t negate_high_u16x8 = vreinterpretq_u16_u8(vzip2q_u8(negate_mask_u8x16, negate_mask_u8x16));
477
+ b_unsigned_low_i16x8 = vbslq_s16(negate_low_u16x8, vnegq_s16(b_unsigned_low_i16x8), b_unsigned_low_i16x8);
478
+ b_unsigned_high_i16x8 = vbslq_s16(negate_high_u16x8, vnegq_s16(b_unsigned_high_i16x8), b_unsigned_high_i16x8);
479
+
480
+ // Widening multiply-accumulate: i16×i16 → i32
481
+ sum0_i32x4 = vmlal_s16(sum0_i32x4, vget_low_s16(a_unsigned_low_i16x8), vget_low_s16(b_unsigned_low_i16x8));
482
+ sum0_i32x4 = vmlal_high_s16(sum0_i32x4, a_unsigned_low_i16x8, b_unsigned_low_i16x8);
483
+ sum1_i32x4 = vmlal_s16(sum1_i32x4, vget_low_s16(a_unsigned_high_i16x8), vget_low_s16(b_unsigned_high_i16x8));
484
+ sum1_i32x4 = vmlal_high_s16(sum1_i32x4, a_unsigned_high_i16x8, b_unsigned_high_i16x8);
485
+
486
+ if (count_scalars) goto nk_dot_e3m2_neonsdot_cycle;
487
+ int32x4_t total_i32x4 = vaddq_s32(sum0_i32x4, sum1_i32x4);
488
+ *result = (nk_f32_t)vaddvq_s32(total_i32x4) / 256.0f;
489
+ }
490
+
491
+ /**
492
+ * @brief Running state for 128-bit dot accumulation over e2m3 scalars on NEON SDOT.
493
+ *
494
+ * Uses SDOT on LUT-mapped magnitudes. Every e2m3 value × 16 is an exact integer in [-120, +120],
495
+ * fitting i8. Accumulator is i32; finalize divides by 256.0f.
496
+ */
497
+ typedef struct nk_dot_e2m3x16_state_neonsdot_t {
498
+ int32x4_t sum_i32x4;
499
+ } nk_dot_e2m3x16_state_neonsdot_t;
500
+
501
+ NK_INTERNAL void nk_dot_e2m3x16_init_neonsdot(nk_dot_e2m3x16_state_neonsdot_t *state) {
502
+ state->sum_i32x4 = vdupq_n_s32(0);
503
+ }
504
+
505
+ NK_INTERNAL void nk_dot_e2m3x16_update_neonsdot(nk_dot_e2m3x16_state_neonsdot_t *state, nk_b128_vec_t a,
506
+ nk_b128_vec_t b, nk_size_t depth_offset, nk_size_t active_dimensions) {
507
+ nk_unused_(depth_offset);
508
+ nk_unused_(active_dimensions);
509
+ static nk_u8_t const lut_data[32] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
510
+ 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 88, 96, 104, 112, 120};
511
+ uint8x16x2_t lut_magnitude_u8x16x2 = vld1q_u8_x2(lut_data);
512
+ uint8x16_t magnitude_mask_u8x16 = vdupq_n_u8(0x1F);
513
+ uint8x16_t sign_mask_u8x16 = vdupq_n_u8(0x20);
514
+
515
+ uint8x16_t a_u8x16 = a.u8x16;
516
+ uint8x16_t b_u8x16 = b.u8x16;
517
+
518
+ uint8x16_t a_unsigned_u8x16 = vqtbl2q_u8(lut_magnitude_u8x16x2, vandq_u8(a_u8x16, magnitude_mask_u8x16));
519
+ uint8x16_t b_unsigned_u8x16 = vqtbl2q_u8(lut_magnitude_u8x16x2, vandq_u8(b_u8x16, magnitude_mask_u8x16));
520
+
521
+ uint8x16_t sign_combined_u8x16 = vandq_u8(veorq_u8(a_u8x16, b_u8x16), sign_mask_u8x16);
522
+ uint8x16_t negate_mask_u8x16 = vceqq_u8(sign_combined_u8x16, sign_mask_u8x16);
523
+ int8x16_t b_signed_i8x16 = vbslq_s8(negate_mask_u8x16, vnegq_s8(vreinterpretq_s8_u8(b_unsigned_u8x16)),
524
+ vreinterpretq_s8_u8(b_unsigned_u8x16));
525
+
526
+ state->sum_i32x4 = vdotq_s32(state->sum_i32x4, vreinterpretq_s8_u8(a_unsigned_u8x16), b_signed_i8x16);
527
+ }
528
+
529
+ NK_INTERNAL void nk_dot_e2m3x16_finalize_neonsdot( //
530
+ nk_dot_e2m3x16_state_neonsdot_t const *state_a, nk_dot_e2m3x16_state_neonsdot_t const *state_b, //
531
+ nk_dot_e2m3x16_state_neonsdot_t const *state_c, nk_dot_e2m3x16_state_neonsdot_t const *state_d, //
532
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
533
+ nk_unused_(total_dimensions);
534
+ nk_f32_t const scale = 1.0f / 256.0f;
535
+ int32x4_t ab_i32x4 = vpaddq_s32(state_a->sum_i32x4, state_b->sum_i32x4);
536
+ int32x4_t cd_i32x4 = vpaddq_s32(state_c->sum_i32x4, state_d->sum_i32x4);
537
+ int32x4_t sums_i32x4 = vpaddq_s32(ab_i32x4, cd_i32x4);
538
+ result->f32x4 = vmulq_n_f32(vcvtq_f32_s32(sums_i32x4), scale);
539
+ }
540
+
541
+ /**
542
+ * @brief Running state for 128-bit dot accumulation over e3m2 scalars on NEON SMLAL.
543
+ *
544
+ * Uses i16 widening multiply (SMLAL) since e3m2 magnitudes reach 448, exceeding i8 range.
545
+ * Two i32x4 accumulators handle the low and high halves from interleaved i16 pairs.
546
+ * Finalize divides by 256.0f.
547
+ */
548
+ typedef struct nk_dot_e3m2x16_state_neonsdot_t {
549
+ int32x4_t sum_i32x4;
550
+ } nk_dot_e3m2x16_state_neonsdot_t;
551
+
552
+ NK_INTERNAL void nk_dot_e3m2x16_init_neonsdot(nk_dot_e3m2x16_state_neonsdot_t *state) {
553
+ state->sum_i32x4 = vdupq_n_s32(0);
554
+ }
555
+
556
+ NK_INTERNAL void nk_dot_e3m2x16_update_neonsdot(nk_dot_e3m2x16_state_neonsdot_t *state, nk_b128_vec_t a,
557
+ nk_b128_vec_t b, nk_size_t depth_offset, nk_size_t active_dimensions) {
558
+ nk_unused_(depth_offset);
559
+ nk_unused_(active_dimensions);
560
+ static nk_u8_t const lut_data[32] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28,
561
+ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0, 64, 128, 192};
562
+ uint8x16x2_t lut_u8x16x2 = vld1q_u8_x2(lut_data);
563
+ uint8x16_t high_threshold_u8x16 = vdupq_n_u8(28);
564
+ uint8x16_t magnitude_mask_u8x16 = vdupq_n_u8(0x1F);
565
+ uint8x16_t sign_mask_u8x16 = vdupq_n_u8(0x20);
566
+
567
+ uint8x16_t a_u8x16 = a.u8x16;
568
+ uint8x16_t b_u8x16 = b.u8x16;
569
+
570
+ uint8x16_t a_mag_u8x16 = vandq_u8(a_u8x16, magnitude_mask_u8x16);
571
+ uint8x16_t b_mag_u8x16 = vandq_u8(b_u8x16, magnitude_mask_u8x16);
572
+
573
+ uint8x16_t a_low_u8x16 = vqtbl2q_u8(lut_u8x16x2, a_mag_u8x16);
574
+ uint8x16_t b_low_u8x16 = vqtbl2q_u8(lut_u8x16x2, b_mag_u8x16);
575
+ uint8x16_t a_high_u8x16 = vandq_u8(vcgeq_u8(a_mag_u8x16, high_threshold_u8x16), vdupq_n_u8(1));
576
+ uint8x16_t b_high_u8x16 = vandq_u8(vcgeq_u8(b_mag_u8x16, high_threshold_u8x16), vdupq_n_u8(1));
577
+
578
+ int16x8_t a_unsigned_low_i16x8 = vreinterpretq_s16_u8(vzip1q_u8(a_low_u8x16, a_high_u8x16));
579
+ int16x8_t a_unsigned_high_i16x8 = vreinterpretq_s16_u8(vzip2q_u8(a_low_u8x16, a_high_u8x16));
580
+ int16x8_t b_unsigned_low_i16x8 = vreinterpretq_s16_u8(vzip1q_u8(b_low_u8x16, b_high_u8x16));
581
+ int16x8_t b_unsigned_high_i16x8 = vreinterpretq_s16_u8(vzip2q_u8(b_low_u8x16, b_high_u8x16));
582
+
583
+ uint8x16_t sign_combined_u8x16 = vandq_u8(veorq_u8(a_u8x16, b_u8x16), sign_mask_u8x16);
584
+ uint8x16_t negate_mask_u8x16 = vceqq_u8(sign_combined_u8x16, sign_mask_u8x16);
585
+ uint16x8_t negate_low_u16x8 = vreinterpretq_u16_u8(vzip1q_u8(negate_mask_u8x16, negate_mask_u8x16));
586
+ uint16x8_t negate_high_u16x8 = vreinterpretq_u16_u8(vzip2q_u8(negate_mask_u8x16, negate_mask_u8x16));
587
+ b_unsigned_low_i16x8 = vbslq_s16(negate_low_u16x8, vnegq_s16(b_unsigned_low_i16x8), b_unsigned_low_i16x8);
588
+ b_unsigned_high_i16x8 = vbslq_s16(negate_high_u16x8, vnegq_s16(b_unsigned_high_i16x8), b_unsigned_high_i16x8);
589
+
590
+ state->sum_i32x4 = vmlal_s16(state->sum_i32x4, vget_low_s16(a_unsigned_low_i16x8),
591
+ vget_low_s16(b_unsigned_low_i16x8));
592
+ state->sum_i32x4 = vmlal_high_s16(state->sum_i32x4, a_unsigned_low_i16x8, b_unsigned_low_i16x8);
593
+ state->sum_i32x4 = vmlal_s16(state->sum_i32x4, vget_low_s16(a_unsigned_high_i16x8),
594
+ vget_low_s16(b_unsigned_high_i16x8));
595
+ state->sum_i32x4 = vmlal_high_s16(state->sum_i32x4, a_unsigned_high_i16x8, b_unsigned_high_i16x8);
596
+ }
597
+
598
+ NK_INTERNAL void nk_dot_e3m2x16_finalize_neonsdot( //
599
+ nk_dot_e3m2x16_state_neonsdot_t const *state_a, nk_dot_e3m2x16_state_neonsdot_t const *state_b, //
600
+ nk_dot_e3m2x16_state_neonsdot_t const *state_c, nk_dot_e3m2x16_state_neonsdot_t const *state_d, //
601
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
602
+ nk_unused_(total_dimensions);
603
+ nk_f32_t const scale = 1.0f / 256.0f;
604
+ int32x4_t ab_i32x4 = vpaddq_s32(state_a->sum_i32x4, state_b->sum_i32x4);
605
+ int32x4_t cd_i32x4 = vpaddq_s32(state_c->sum_i32x4, state_d->sum_i32x4);
606
+ int32x4_t sums_i32x4 = vpaddq_s32(ab_i32x4, cd_i32x4);
607
+ result->f32x4 = vmulq_n_f32(vcvtq_f32_s32(sums_i32x4), scale);
608
+ }
609
+
610
+ #if defined(__clang__)
611
+ #pragma clang attribute pop
612
+ #elif defined(__GNUC__)
613
+ #pragma GCC pop_options
614
+ #endif
615
+
616
+ #if defined(__cplusplus)
617
+ } // extern "C"
618
+ #endif
619
+
620
+ #endif // NK_TARGET_NEONSDOT
621
+ #endif // NK_TARGET_ARM64_
622
+ #endif // NK_DOT_NEONSDOT_H