usearch 2.21.3 → 2.25.0

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 (602) hide show
  1. package/README.md +24 -24
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +7 -7
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +83 -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 +235 -52
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/dist/cjs/usearch.d.ts +8 -3
  16. package/javascript/dist/cjs/usearch.js +12 -4
  17. package/javascript/dist/esm/usearch.d.ts +8 -3
  18. package/javascript/dist/esm/usearch.js +12 -4
  19. package/javascript/lib.cpp +17 -0
  20. package/javascript/usearch.ts +14 -6
  21. package/numkong/.clang-tidy +30 -0
  22. package/{simsimd → numkong}/.cmake-format.py +18 -0
  23. package/numkong/.editorconfig +12 -0
  24. package/numkong/.git-blame-ignore-revs +123 -0
  25. package/numkong/.mailmap +15 -0
  26. package/numkong/.spi.yml +11 -0
  27. package/numkong/.swift-format +14 -0
  28. package/numkong/CITATION.cff +81 -0
  29. package/numkong/CONTRIBUTING.md +500 -0
  30. package/numkong/Cargo.toml +54 -0
  31. package/numkong/MANIFEST.in +8 -0
  32. package/numkong/Package.swift +84 -0
  33. package/numkong/README.md +569 -0
  34. package/numkong/bench/README.md +217 -0
  35. package/numkong/bench/bench-browser.html +323 -0
  36. package/numkong/bench/bench.cpp +344 -0
  37. package/numkong/bench/bench.hpp +816 -0
  38. package/numkong/bench/bench.js +148 -0
  39. package/numkong/bench/bench.mjs +616 -0
  40. package/numkong/bench/bench_attention.cpp +113 -0
  41. package/numkong/bench/bench_cast.cpp +264 -0
  42. package/numkong/bench/bench_cross_amx.cpp +62 -0
  43. package/numkong/bench/bench_cross_arm.cpp +245 -0
  44. package/numkong/bench/bench_cross_blas.cpp +309 -0
  45. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  46. package/numkong/bench/bench_cross_power.cpp +84 -0
  47. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  48. package/numkong/bench/bench_cross_serial.cpp +151 -0
  49. package/numkong/bench/bench_cross_sme.cpp +163 -0
  50. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  51. package/numkong/bench/bench_cross_x86.cpp +455 -0
  52. package/numkong/bench/bench_curved.cpp +210 -0
  53. package/numkong/bench/bench_dot.cpp +315 -0
  54. package/numkong/bench/bench_each.cpp +503 -0
  55. package/numkong/bench/bench_geospatial.cpp +112 -0
  56. package/numkong/bench/bench_maxsim.cpp +154 -0
  57. package/numkong/bench/bench_mesh.cpp +148 -0
  58. package/numkong/bench/bench_probability.cpp +60 -0
  59. package/numkong/bench/bench_reduce.cpp +371 -0
  60. package/numkong/bench/bench_set.cpp +73 -0
  61. package/numkong/bench/bench_sparse.cpp +198 -0
  62. package/numkong/bench/bench_spatial.cpp +347 -0
  63. package/numkong/bench/bench_trigonometry.cpp +137 -0
  64. package/numkong/bench/swift/Bench.swift +506 -0
  65. package/numkong/binding.gyp +169 -0
  66. package/numkong/build.rs +484 -0
  67. package/numkong/c/dispatch.h +512 -0
  68. package/numkong/c/dispatch_bf16.c +447 -0
  69. package/numkong/c/dispatch_bf16c.c +52 -0
  70. package/numkong/c/dispatch_e2m3.c +296 -0
  71. package/numkong/c/dispatch_e3m2.c +284 -0
  72. package/numkong/c/dispatch_e4m3.c +318 -0
  73. package/numkong/c/dispatch_e5m2.c +316 -0
  74. package/numkong/c/dispatch_f16.c +452 -0
  75. package/numkong/c/dispatch_f16c.c +58 -0
  76. package/numkong/c/dispatch_f32.c +434 -0
  77. package/numkong/c/dispatch_f32c.c +99 -0
  78. package/numkong/c/dispatch_f64.c +348 -0
  79. package/numkong/c/dispatch_f64c.c +98 -0
  80. package/numkong/c/dispatch_i16.c +96 -0
  81. package/numkong/c/dispatch_i32.c +89 -0
  82. package/numkong/c/dispatch_i4.c +153 -0
  83. package/numkong/c/dispatch_i64.c +86 -0
  84. package/numkong/c/dispatch_i8.c +348 -0
  85. package/numkong/c/dispatch_other.c +348 -0
  86. package/numkong/c/dispatch_u1.c +193 -0
  87. package/numkong/c/dispatch_u16.c +124 -0
  88. package/numkong/c/dispatch_u32.c +118 -0
  89. package/numkong/c/dispatch_u4.c +153 -0
  90. package/numkong/c/dispatch_u64.c +102 -0
  91. package/numkong/c/dispatch_u8.c +364 -0
  92. package/numkong/c/numkong.c +940 -0
  93. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  94. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  95. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  96. package/numkong/cmake/nk_math_lib.cmake +46 -0
  97. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  99. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  100. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  101. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  102. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  103. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  104. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  105. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  106. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  107. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  108. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  109. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  110. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  111. package/numkong/include/README.md +643 -0
  112. package/numkong/include/module.modulemap +129 -0
  113. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  114. package/numkong/include/numkong/attention/sme.h +2075 -0
  115. package/numkong/include/numkong/attention.h +49 -0
  116. package/numkong/include/numkong/capabilities.h +930 -0
  117. package/numkong/include/numkong/cast/README.md +262 -0
  118. package/numkong/include/numkong/cast/diamond.h +64 -0
  119. package/numkong/include/numkong/cast/haswell.h +823 -0
  120. package/numkong/include/numkong/cast/icelake.h +475 -0
  121. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  122. package/numkong/include/numkong/cast/neon.h +1174 -0
  123. package/numkong/include/numkong/cast/powervsx.h +449 -0
  124. package/numkong/include/numkong/cast/rvv.h +970 -0
  125. package/numkong/include/numkong/cast/sapphire.h +262 -0
  126. package/numkong/include/numkong/cast/serial.h +2336 -0
  127. package/numkong/include/numkong/cast/skylake.h +915 -0
  128. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  129. package/numkong/include/numkong/cast.h +254 -0
  130. package/numkong/include/numkong/cast.hpp +44 -0
  131. package/numkong/include/numkong/curved/README.md +223 -0
  132. package/numkong/include/numkong/curved/genoa.h +182 -0
  133. package/numkong/include/numkong/curved/haswell.h +276 -0
  134. package/numkong/include/numkong/curved/neon.h +329 -0
  135. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  136. package/numkong/include/numkong/curved/rvv.h +305 -0
  137. package/numkong/include/numkong/curved/serial.h +207 -0
  138. package/numkong/include/numkong/curved/skylake.h +457 -0
  139. package/numkong/include/numkong/curved/smef64.h +530 -0
  140. package/numkong/include/numkong/curved.h +513 -0
  141. package/numkong/include/numkong/curved.hpp +144 -0
  142. package/numkong/include/numkong/dot/README.md +442 -0
  143. package/numkong/include/numkong/dot/alder.h +563 -0
  144. package/numkong/include/numkong/dot/diamond.h +158 -0
  145. package/numkong/include/numkong/dot/genoa.h +289 -0
  146. package/numkong/include/numkong/dot/haswell.h +1723 -0
  147. package/numkong/include/numkong/dot/icelake.h +997 -0
  148. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  149. package/numkong/include/numkong/dot/neon.h +869 -0
  150. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  151. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  152. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  153. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  154. package/numkong/include/numkong/dot/powervsx.h +752 -0
  155. package/numkong/include/numkong/dot/rvv.h +722 -0
  156. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  157. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  158. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  159. package/numkong/include/numkong/dot/sapphire.h +141 -0
  160. package/numkong/include/numkong/dot/serial.h +874 -0
  161. package/numkong/include/numkong/dot/sierra.h +405 -0
  162. package/numkong/include/numkong/dot/skylake.h +1116 -0
  163. package/numkong/include/numkong/dot/sve.h +420 -0
  164. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  165. package/numkong/include/numkong/dot/svehalf.h +168 -0
  166. package/numkong/include/numkong/dot/svesdot.h +90 -0
  167. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  168. package/numkong/include/numkong/dot.h +1136 -0
  169. package/numkong/include/numkong/dot.hpp +94 -0
  170. package/numkong/include/numkong/dots/README.md +496 -0
  171. package/numkong/include/numkong/dots/alder.h +117 -0
  172. package/numkong/include/numkong/dots/diamond.h +86 -0
  173. package/numkong/include/numkong/dots/genoa.h +100 -0
  174. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  175. package/numkong/include/numkong/dots/haswell.h +310 -0
  176. package/numkong/include/numkong/dots/icelake.h +180 -0
  177. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  178. package/numkong/include/numkong/dots/neon.h +123 -0
  179. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  180. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  181. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  182. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  183. package/numkong/include/numkong/dots/powervsx.h +194 -0
  184. package/numkong/include/numkong/dots/rvv.h +2593 -0
  185. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  186. package/numkong/include/numkong/dots/serial.h +2867 -0
  187. package/numkong/include/numkong/dots/sierra.h +100 -0
  188. package/numkong/include/numkong/dots/skylake.h +207 -0
  189. package/numkong/include/numkong/dots/sme.h +5041 -0
  190. package/numkong/include/numkong/dots/smebi32.h +477 -0
  191. package/numkong/include/numkong/dots/smef64.h +1328 -0
  192. package/numkong/include/numkong/dots/smehalf.h +47 -0
  193. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  194. package/numkong/include/numkong/dots.h +3110 -0
  195. package/numkong/include/numkong/dots.hpp +641 -0
  196. package/numkong/include/numkong/each/README.md +465 -0
  197. package/numkong/include/numkong/each/haswell.h +1658 -0
  198. package/numkong/include/numkong/each/icelake.h +272 -0
  199. package/numkong/include/numkong/each/neon.h +1138 -0
  200. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  201. package/numkong/include/numkong/each/neonhalf.h +318 -0
  202. package/numkong/include/numkong/each/rvv.h +1121 -0
  203. package/numkong/include/numkong/each/sapphire.h +343 -0
  204. package/numkong/include/numkong/each/serial.h +282 -0
  205. package/numkong/include/numkong/each/skylake.h +1562 -0
  206. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  207. package/numkong/include/numkong/each.h +2232 -0
  208. package/numkong/include/numkong/each.hpp +434 -0
  209. package/numkong/include/numkong/geospatial/README.md +147 -0
  210. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  211. package/numkong/include/numkong/geospatial/neon.h +615 -0
  212. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  213. package/numkong/include/numkong/geospatial/serial.h +309 -0
  214. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  215. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  216. package/numkong/include/numkong/geospatial.h +453 -0
  217. package/numkong/include/numkong/geospatial.hpp +235 -0
  218. package/numkong/include/numkong/matrix.hpp +336 -0
  219. package/numkong/include/numkong/maxsim/README.md +187 -0
  220. package/numkong/include/numkong/maxsim/alder.h +511 -0
  221. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  222. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  223. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  224. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  225. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  226. package/numkong/include/numkong/maxsim/serial.h +490 -0
  227. package/numkong/include/numkong/maxsim/sme.h +993 -0
  228. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  229. package/numkong/include/numkong/maxsim.h +571 -0
  230. package/numkong/include/numkong/maxsim.hpp +133 -0
  231. package/numkong/include/numkong/mesh/README.md +219 -0
  232. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  233. package/numkong/include/numkong/mesh/neon.h +1821 -0
  234. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  235. package/numkong/include/numkong/mesh/rvv.h +936 -0
  236. package/numkong/include/numkong/mesh/serial.h +721 -0
  237. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  238. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  239. package/numkong/include/numkong/mesh.h +666 -0
  240. package/numkong/include/numkong/mesh.hpp +701 -0
  241. package/numkong/include/numkong/numkong.h +78 -0
  242. package/numkong/include/numkong/numkong.hpp +58 -0
  243. package/numkong/include/numkong/probability/README.md +177 -0
  244. package/numkong/include/numkong/probability/haswell.h +267 -0
  245. package/numkong/include/numkong/probability/neon.h +255 -0
  246. package/numkong/include/numkong/probability/rvv.h +414 -0
  247. package/numkong/include/numkong/probability/serial.h +181 -0
  248. package/numkong/include/numkong/probability/skylake.h +324 -0
  249. package/numkong/include/numkong/probability.h +380 -0
  250. package/numkong/include/numkong/probability.hpp +120 -0
  251. package/numkong/include/numkong/random.h +50 -0
  252. package/numkong/include/numkong/random.hpp +285 -0
  253. package/numkong/include/numkong/reduce/README.md +552 -0
  254. package/numkong/include/numkong/reduce/alder.h +636 -0
  255. package/numkong/include/numkong/reduce/genoa.h +201 -0
  256. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  257. package/numkong/include/numkong/reduce/icelake.h +549 -0
  258. package/numkong/include/numkong/reduce/neon.h +3980 -0
  259. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  260. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  261. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  262. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  263. package/numkong/include/numkong/reduce/serial.h +753 -0
  264. package/numkong/include/numkong/reduce/sierra.h +338 -0
  265. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  266. package/numkong/include/numkong/reduce/sve.h +52 -0
  267. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  268. package/numkong/include/numkong/reduce.h +1582 -0
  269. package/numkong/include/numkong/reduce.hpp +778 -0
  270. package/numkong/include/numkong/scalar/README.md +89 -0
  271. package/numkong/include/numkong/scalar/haswell.h +122 -0
  272. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  273. package/numkong/include/numkong/scalar/neon.h +122 -0
  274. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  275. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  276. package/numkong/include/numkong/scalar/rvv.h +211 -0
  277. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  278. package/numkong/include/numkong/scalar/serial.h +332 -0
  279. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  280. package/numkong/include/numkong/scalar.h +696 -0
  281. package/numkong/include/numkong/set/README.md +179 -0
  282. package/numkong/include/numkong/set/haswell.h +334 -0
  283. package/numkong/include/numkong/set/icelake.h +485 -0
  284. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  285. package/numkong/include/numkong/set/neon.h +363 -0
  286. package/numkong/include/numkong/set/powervsx.h +326 -0
  287. package/numkong/include/numkong/set/rvv.h +226 -0
  288. package/numkong/include/numkong/set/rvvbb.h +117 -0
  289. package/numkong/include/numkong/set/serial.h +174 -0
  290. package/numkong/include/numkong/set/sve.h +187 -0
  291. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  292. package/numkong/include/numkong/set.h +471 -0
  293. package/numkong/include/numkong/set.hpp +114 -0
  294. package/numkong/include/numkong/sets/README.md +149 -0
  295. package/numkong/include/numkong/sets/haswell.h +63 -0
  296. package/numkong/include/numkong/sets/icelake.h +66 -0
  297. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  298. package/numkong/include/numkong/sets/neon.h +61 -0
  299. package/numkong/include/numkong/sets/powervsx.h +65 -0
  300. package/numkong/include/numkong/sets/serial.h +43 -0
  301. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  302. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  303. package/numkong/include/numkong/sets.h +382 -0
  304. package/numkong/include/numkong/sparse/README.md +156 -0
  305. package/numkong/include/numkong/sparse/icelake.h +463 -0
  306. package/numkong/include/numkong/sparse/neon.h +288 -0
  307. package/numkong/include/numkong/sparse/serial.h +117 -0
  308. package/numkong/include/numkong/sparse/sve2.h +504 -0
  309. package/numkong/include/numkong/sparse/turin.h +322 -0
  310. package/numkong/include/numkong/sparse.h +363 -0
  311. package/numkong/include/numkong/sparse.hpp +113 -0
  312. package/numkong/include/numkong/spatial/README.md +439 -0
  313. package/numkong/include/numkong/spatial/alder.h +604 -0
  314. package/numkong/include/numkong/spatial/diamond.h +240 -0
  315. package/numkong/include/numkong/spatial/genoa.h +222 -0
  316. package/numkong/include/numkong/spatial/haswell.h +979 -0
  317. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  318. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  319. package/numkong/include/numkong/spatial/neon.h +846 -0
  320. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  321. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  322. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  323. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  324. package/numkong/include/numkong/spatial/rvv.h +991 -0
  325. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  326. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  327. package/numkong/include/numkong/spatial/serial.h +347 -0
  328. package/numkong/include/numkong/spatial/sierra.h +516 -0
  329. package/numkong/include/numkong/spatial/skylake.h +605 -0
  330. package/numkong/include/numkong/spatial/sve.h +246 -0
  331. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  332. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  333. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  334. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  335. package/numkong/include/numkong/spatial.h +1681 -0
  336. package/numkong/include/numkong/spatial.hpp +183 -0
  337. package/numkong/include/numkong/spatials/README.md +580 -0
  338. package/numkong/include/numkong/spatials/alder.h +94 -0
  339. package/numkong/include/numkong/spatials/diamond.h +82 -0
  340. package/numkong/include/numkong/spatials/genoa.h +94 -0
  341. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  342. package/numkong/include/numkong/spatials/haswell.h +219 -0
  343. package/numkong/include/numkong/spatials/icelake.h +113 -0
  344. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  345. package/numkong/include/numkong/spatials/neon.h +109 -0
  346. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  347. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  348. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  349. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  350. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  351. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  352. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  353. package/numkong/include/numkong/spatials/serial.h +248 -0
  354. package/numkong/include/numkong/spatials/sierra.h +96 -0
  355. package/numkong/include/numkong/spatials/skylake.h +184 -0
  356. package/numkong/include/numkong/spatials/sme.h +1927 -0
  357. package/numkong/include/numkong/spatials/smef64.h +483 -0
  358. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  359. package/numkong/include/numkong/spatials.h +3374 -0
  360. package/numkong/include/numkong/spatials.hpp +509 -0
  361. package/numkong/include/numkong/tensor.hpp +1981 -0
  362. package/numkong/include/numkong/trigonometry/README.md +184 -0
  363. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  364. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  365. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  366. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  367. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  368. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  369. package/numkong/include/numkong/trigonometry.h +467 -0
  370. package/numkong/include/numkong/trigonometry.hpp +166 -0
  371. package/numkong/include/numkong/types.h +1695 -0
  372. package/numkong/include/numkong/types.hpp +6027 -0
  373. package/numkong/include/numkong/vector.hpp +766 -0
  374. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  375. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  376. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  377. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  378. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  380. package/numkong/javascript/README.md +254 -0
  381. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  382. package/numkong/javascript/numkong-browser.ts +40 -0
  383. package/numkong/javascript/numkong-wasm.ts +750 -0
  384. package/numkong/javascript/numkong.c +712 -0
  385. package/numkong/javascript/numkong.ts +613 -0
  386. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  387. package/numkong/javascript/tsconfig-cjs.json +13 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  389. package/numkong/javascript/types.ts +784 -0
  390. package/numkong/numkong.gypi +104 -0
  391. package/numkong/package.json +108 -0
  392. package/numkong/probes/arm_neon.c +8 -0
  393. package/numkong/probes/arm_neon_bfdot.c +9 -0
  394. package/numkong/probes/arm_neon_fhm.c +9 -0
  395. package/numkong/probes/arm_neon_half.c +8 -0
  396. package/numkong/probes/arm_neon_sdot.c +9 -0
  397. package/numkong/probes/arm_neonfp8.c +9 -0
  398. package/numkong/probes/arm_sme.c +16 -0
  399. package/numkong/probes/arm_sme2.c +16 -0
  400. package/numkong/probes/arm_sme2p1.c +16 -0
  401. package/numkong/probes/arm_sme_bf16.c +16 -0
  402. package/numkong/probes/arm_sme_bi32.c +16 -0
  403. package/numkong/probes/arm_sme_f64.c +16 -0
  404. package/numkong/probes/arm_sme_fa64.c +14 -0
  405. package/numkong/probes/arm_sme_half.c +16 -0
  406. package/numkong/probes/arm_sme_lut2.c +15 -0
  407. package/numkong/probes/arm_sve.c +18 -0
  408. package/numkong/probes/arm_sve2.c +20 -0
  409. package/numkong/probes/arm_sve2p1.c +18 -0
  410. package/numkong/probes/arm_sve_bfdot.c +20 -0
  411. package/numkong/probes/arm_sve_half.c +18 -0
  412. package/numkong/probes/arm_sve_sdot.c +21 -0
  413. package/numkong/probes/loongarch_lasx.c +12 -0
  414. package/numkong/probes/power_vsx.c +12 -0
  415. package/numkong/probes/probe.js +127 -0
  416. package/numkong/probes/riscv_rvv.c +14 -0
  417. package/numkong/probes/riscv_rvv_bb.c +15 -0
  418. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  419. package/numkong/probes/riscv_rvv_half.c +14 -0
  420. package/numkong/probes/wasm_v128relaxed.c +11 -0
  421. package/numkong/probes/x86_alder.c +17 -0
  422. package/numkong/probes/x86_diamond.c +17 -0
  423. package/numkong/probes/x86_genoa.c +17 -0
  424. package/numkong/probes/x86_graniteamx.c +19 -0
  425. package/numkong/probes/x86_haswell.c +11 -0
  426. package/numkong/probes/x86_icelake.c +17 -0
  427. package/numkong/probes/x86_sapphire.c +16 -0
  428. package/numkong/probes/x86_sapphireamx.c +18 -0
  429. package/numkong/probes/x86_sierra.c +17 -0
  430. package/numkong/probes/x86_skylake.c +15 -0
  431. package/numkong/probes/x86_turin.c +17 -0
  432. package/numkong/rust/README.md +698 -0
  433. package/numkong/rust/capabilities.rs +96 -0
  434. package/numkong/rust/cast.rs +314 -0
  435. package/numkong/rust/curved.rs +391 -0
  436. package/numkong/rust/each.rs +2721 -0
  437. package/numkong/rust/geospatial.rs +343 -0
  438. package/numkong/rust/matrix.rs +5424 -0
  439. package/numkong/rust/maxsim.rs +540 -0
  440. package/numkong/rust/mesh.rs +837 -0
  441. package/numkong/rust/numkong.rs +409 -0
  442. package/numkong/rust/probability.rs +272 -0
  443. package/numkong/rust/reduce.rs +1249 -0
  444. package/numkong/rust/set.rs +194 -0
  445. package/numkong/rust/sparse.rs +513 -0
  446. package/numkong/rust/spatial.rs +1815 -0
  447. package/numkong/rust/tensor.rs +7565 -0
  448. package/numkong/rust/types.rs +3666 -0
  449. package/numkong/rust/vector.rs +1899 -0
  450. package/numkong/rustfmt.toml +2 -0
  451. package/numkong/swift/Matrix.swift +1388 -0
  452. package/numkong/swift/MaxSim.swift +151 -0
  453. package/numkong/swift/NumKong.swift +283 -0
  454. package/numkong/swift/Numerics.swift +329 -0
  455. package/numkong/swift/README.md +433 -0
  456. package/numkong/swift/Scalar.swift +741 -0
  457. package/numkong/swift/Tensor.swift +209 -0
  458. package/numkong/test/README.md +315 -0
  459. package/numkong/test/playwright.config.ts +16 -0
  460. package/numkong/test/swift/Test.swift +534 -0
  461. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  462. package/numkong/test/test-browser-bundle.html +188 -0
  463. package/numkong/test/test-browser-runner.mjs +43 -0
  464. package/numkong/test/test-browser.html +305 -0
  465. package/numkong/test/test-dtypes.mjs +453 -0
  466. package/numkong/test/test-wasm.mjs +267 -0
  467. package/numkong/test/test.cpp +442 -0
  468. package/numkong/test/test.hpp +580 -0
  469. package/numkong/test/test.mjs +363 -0
  470. package/numkong/test/test_base.py +1041 -0
  471. package/numkong/test/test_cast.cpp +242 -0
  472. package/numkong/test/test_cross.hpp +551 -0
  473. package/numkong/test/test_cross.py +467 -0
  474. package/numkong/test/test_cross_amx.cpp +50 -0
  475. package/numkong/test/test_cross_arm.cpp +225 -0
  476. package/numkong/test/test_cross_blas.cpp +354 -0
  477. package/numkong/test/test_cross_loongarch.cpp +90 -0
  478. package/numkong/test/test_cross_power.cpp +73 -0
  479. package/numkong/test/test_cross_rvv.cpp +109 -0
  480. package/numkong/test/test_cross_serial.cpp +181 -0
  481. package/numkong/test/test_cross_sme.cpp +148 -0
  482. package/numkong/test/test_cross_wasm.cpp +141 -0
  483. package/numkong/test/test_cross_x86.cpp +442 -0
  484. package/numkong/test/test_curved.cpp +182 -0
  485. package/numkong/test/test_curved.py +207 -0
  486. package/numkong/test/test_dot.cpp +353 -0
  487. package/numkong/test/test_dot.py +296 -0
  488. package/numkong/test/test_each.cpp +437 -0
  489. package/numkong/test/test_each.py +756 -0
  490. package/numkong/test/test_geospatial.cpp +155 -0
  491. package/numkong/test/test_geospatial.py +241 -0
  492. package/numkong/test/test_maxsim.cpp +138 -0
  493. package/numkong/test/test_maxsim.py +209 -0
  494. package/numkong/test/test_mesh.cpp +203 -0
  495. package/numkong/test/test_mesh.py +394 -0
  496. package/numkong/test/test_probability.cpp +136 -0
  497. package/numkong/test/test_probability.py +166 -0
  498. package/numkong/test/test_reduce.cpp +563 -0
  499. package/numkong/test/test_reduce.py +781 -0
  500. package/numkong/test/test_set.cpp +151 -0
  501. package/numkong/test/test_set.py +120 -0
  502. package/numkong/test/test_similarities.py +579 -0
  503. package/numkong/test/test_sparse.cpp +121 -0
  504. package/numkong/test/test_sparse.py +118 -0
  505. package/numkong/test/test_spatial.cpp +518 -0
  506. package/numkong/test/test_spatial.py +269 -0
  507. package/numkong/test/test_tensor.cpp +884 -0
  508. package/numkong/test/test_tensor.py +1417 -0
  509. package/numkong/test/test_trigonometry.cpp +156 -0
  510. package/numkong/test/test_trigonometry.py +180 -0
  511. package/package.json +7 -8
  512. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  513. package/prebuilds/linux-arm64/usearch.node +0 -0
  514. package/prebuilds/linux-x64/usearch.node +0 -0
  515. package/fp16/CMakeLists.txt +0 -176
  516. package/fp16/LICENSE +0 -11
  517. package/fp16/README.md +0 -20
  518. package/fp16/bench/alt-element.cc +0 -89
  519. package/fp16/bench/from-alt-array.cc +0 -175
  520. package/fp16/bench/from-ieee-array.cc +0 -399
  521. package/fp16/bench/ieee-element.cc +0 -272
  522. package/fp16/bench/to-alt-array.cc +0 -91
  523. package/fp16/bench/to-ieee-array.cc +0 -303
  524. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  525. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  526. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  527. package/fp16/configure.py +0 -65
  528. package/fp16/confu.yaml +0 -8
  529. package/fp16/include/fp16/__init__.py +0 -0
  530. package/fp16/include/fp16/avx.py +0 -50
  531. package/fp16/include/fp16/avx2.py +0 -53
  532. package/fp16/include/fp16/bitcasts.h +0 -92
  533. package/fp16/include/fp16/fp16.h +0 -451
  534. package/fp16/include/fp16/psimd.h +0 -131
  535. package/fp16/include/fp16.h +0 -11
  536. package/fp16/jni/Android.mk +0 -6
  537. package/fp16/jni/Application.mk +0 -4
  538. package/fp16/test/alt-from-fp32-value.cc +0 -498
  539. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  540. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  541. package/fp16/test/alt-to-fp32-value.cc +0 -348
  542. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  543. package/fp16/test/bitcasts.cc +0 -56
  544. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  545. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  546. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  547. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  548. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  549. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  550. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  551. package/fp16/test/peachpy/stubs.py +0 -38
  552. package/fp16/test/tables.cc +0 -530
  553. package/fp16/test/tables.h +0 -13
  554. package/fp16/third-party/THHalf.h +0 -92
  555. package/fp16/third-party/eigen-half.h +0 -170
  556. package/fp16/third-party/float16-compressor.h +0 -80
  557. package/fp16/third-party/half.hpp +0 -2916
  558. package/fp16/third-party/npy-halffloat.h +0 -328
  559. package/simsimd/.git-blame-ignore-revs +0 -2
  560. package/simsimd/CONTRIBUTING.md +0 -321
  561. package/simsimd/Cargo.toml +0 -49
  562. package/simsimd/MANIFEST.in +0 -4
  563. package/simsimd/Package.swift +0 -28
  564. package/simsimd/README.md +0 -1493
  565. package/simsimd/binding.gyp +0 -35
  566. package/simsimd/build.rs +0 -70
  567. package/simsimd/c/lib.c +0 -374
  568. package/simsimd/include/module.modulemap +0 -4
  569. package/simsimd/include/simsimd/binary.h +0 -486
  570. package/simsimd/include/simsimd/curved.h +0 -1541
  571. package/simsimd/include/simsimd/dot.h +0 -1853
  572. package/simsimd/include/simsimd/elementwise.h +0 -2465
  573. package/simsimd/include/simsimd/geospatial.h +0 -43
  574. package/simsimd/include/simsimd/mesh.h +0 -69
  575. package/simsimd/include/simsimd/probability.h +0 -606
  576. package/simsimd/include/simsimd/simsimd.h +0 -2567
  577. package/simsimd/include/simsimd/sparse.h +0 -1384
  578. package/simsimd/include/simsimd/spatial.h +0 -2335
  579. package/simsimd/include/simsimd/types.h +0 -666
  580. package/simsimd/javascript/fallback.ts +0 -233
  581. package/simsimd/javascript/lib.c +0 -125
  582. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  583. package/simsimd/javascript/simsimd.ts +0 -179
  584. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  585. package/simsimd/package-lock.json +0 -1761
  586. package/simsimd/package.json +0 -61
  587. package/simsimd/rust/lib.rs +0 -1821
  588. package/simsimd/scripts/bench.cxx +0 -1170
  589. package/simsimd/scripts/bench.ipynb +0 -187
  590. package/simsimd/scripts/bench.js +0 -127
  591. package/simsimd/scripts/bench.rs +0 -876
  592. package/simsimd/scripts/bench_vectors.py +0 -734
  593. package/simsimd/scripts/bench_vectors_live.py +0 -213
  594. package/simsimd/scripts/test.c +0 -187
  595. package/simsimd/scripts/test.mjs +0 -220
  596. package/simsimd/scripts/test.py +0 -1505
  597. package/simsimd/swift/SimSIMD.swift +0 -149
  598. package/simsimd/swift/Test.swift +0 -128
  599. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  600. /package/{simsimd → numkong}/LICENSE +0 -0
  601. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  602. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,1695 @@
1
+ /**
2
+ * @brief Shared definitions for the NumKong library.
3
+ * @file include/numkong/types.h
4
+ * @author Ash Vardanian
5
+ * @date October 2, 2023
6
+ *
7
+ * Defines:
8
+ *
9
+ * - Sized aliases for numeric types, like: `nk_i32_t` and `nk_f64_t`.
10
+ * - Macros for internal compiler/hardware checks, like: `NK_TARGET_ARM64_`.
11
+ * - Macros for feature controls, like: `NK_TARGET_NEON`
12
+ *
13
+ * @section fp8_types FP8 Numeric Types
14
+ *
15
+ * There are several variants of 8-bit floating point types supported by different industry memebers
16
+ * with different hardware support. None are part of the IEEE 754 standard, but some are part of the
17
+ * Open Compute Project (OCP) 8-bit Floating Point Specification (OFP8):
18
+ *
19
+ * Format Bias Sign Exp Mant Range Infinity NaN Standard
20
+ * E4M3FN 7 1 4 3 ±448 ❌ No Only 0x7F/0xFF OCP, NVIDIA, ONNX
21
+ * E5M2 15 1 5 2 ±57344 ✅ Yes (0x7C/0xFC) 0x7D-7F, 0xFD-FF OCP, IEEE-like
22
+ * E4M3FNUZ 8 1 4 3 ±240 ❌ No 0x80 only GraphCore, ONNX
23
+ * E5M2FNUZ 16 1 5 2 ±57344 ❌ No 0x80 only GraphCore, ONNX
24
+ *
25
+ * In currently available and soon incoming harware, only two series of models prioritze FNUZ over OCP:
26
+ *
27
+ * - GraphCore IPUs were the original platform proposing FNUZ
28
+ * - AMD MI300 series based on CDNA3 implements FNUZ, but not OCP
29
+ * - AMD MI350+ series based on CDNA4 switch to OCP and remove FNUZ
30
+ * - NVIDIA Hopper and Blackwell only support E4M3FN, E5M2
31
+ * - Intel AVX10.2 defines HF8 (E4M3FN) and BF8 (E5M2) - OCP-aligned
32
+ * - Arm implements E4M3 (meaning E4M3FN) and E5M2 with a shared `__mfp8` type and a `FPMR` format selector
33
+ *
34
+ * For brevety, across NumKong, "E4M3" implies "E4M3FN".
35
+ *
36
+ * @see https://www.opencompute.org/documents/ocp-8-bit-floating-point-specification-ofp8-revision-1-0-2023-12-01-pdf-1
37
+ * @see FP8 Formats for Deep Learning: https://arxiv.org/pdf/2209.05433
38
+ * @see ONNX Float8 Types: https://onnx.ai/onnx/technical/float8.html
39
+ *
40
+ * @section fp6_types FP6 Numeric Types
41
+ *
42
+ * The OCP Microscaling (MX) v1.0 specification defines two 6-bit floating-point formats
43
+ * for block-scaled quantization. Both are "FN" (finite-numeric): all bit patterns map
44
+ * to real numbers with no Inf or NaN codes. Stored byte-aligned with 2 bits of padding.
45
+ *
46
+ * Format Bias Sign Exp Mant Range Subnormals Infinity NaN Standard
47
+ * E2M3 1 1 2 3 ±7.5 14 of 64 ❌ No ❌ OCP MX v1.0
48
+ * E3M2 3 1 3 2 ±28 6 of 64 ❌ No ❌ OCP MX v1.0
49
+ *
50
+ * E2M3 favors mantissa precision (3 bits) for narrow dynamic range — ideal for activations.
51
+ * E3M2 favors exponent range (3 bits) for wider dynamic range — suited for weights.
52
+ * Both follow IEEE 754 subnormal rules: when exp=0, the implicit leading bit is 0,
53
+ * giving value = (-1)^s × 0.mmm × 2^(1-bias). This provides gradual underflow to zero.
54
+ *
55
+ * No hardware directly computes on FP6. On Arm with FEAT_FP8DOT4, E2M3 values can be
56
+ * losslessly promoted to E4M3 (same mantissa width, rebias exponent by +6) and E3M2 to
57
+ * E5M2 (same mantissa width, rebias exponent by +12), then fed to FDOT instructions.
58
+ * Subnormal values (exp=0) require normalization during this promotion.
59
+ *
60
+ * @see https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
61
+ * @see https://arxiv.org/abs/2401.14112 (FP6-LLM paper)
62
+ */
63
+ #ifndef NK_TYPES_H
64
+ #define NK_TYPES_H
65
+
66
+ // On Linux, `_GNU_SOURCE` must be defined before any system headers
67
+ // to expose `syscall` and other GNU extensions when C extensions are disabled.
68
+ #if defined(__linux__) && !defined(_GNU_SOURCE)
69
+ #define _GNU_SOURCE
70
+ #endif
71
+
72
+ // MSan (MemorySanitizer) cannot track data flow through SVE horizontal reductions
73
+ // like `svaddv`, which move data from vector registers to scalar registers via
74
+ // architecture-specific paths invisible to the compiler. `nk_unpoison_` marks the
75
+ // resulting scalar as initialized so MSan does not report false positives.
76
+ #if defined(__has_feature)
77
+ #if __has_feature(memory_sanitizer)
78
+ #include <sanitizer/msan_interface.h>
79
+ #define nk_unpoison_(ptr, size) __msan_unpoison((ptr), (size))
80
+ #endif
81
+ #endif
82
+ #ifndef nk_unpoison_
83
+ #define nk_unpoison_(ptr, size) (void)(ptr), (void)(size)
84
+ #endif
85
+
86
+ // Inferring target OS: Windows, macOS, Linux, or FreeBSD
87
+ #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
88
+ #define NK_DEFINED_WINDOWS_ 1
89
+ #elif defined(__APPLE__) && defined(__MACH__)
90
+ #define NK_DEFINED_APPLE_ 1
91
+ #elif defined(__linux__)
92
+ #define NK_DEFINED_LINUX_ 1
93
+ #elif defined(__FreeBSD__)
94
+ #define NK_DEFINED_FREEBSD_ 1
95
+ #endif
96
+
97
+ // Annotation for the public API symbols:
98
+ //
99
+ // - `NK_PUBLIC` is used for functions that are part of the public API.
100
+ // - `NK_INTERNAL` is used for internal helper functions with unstable APIs.
101
+ // - `NK_DYNAMIC` is used for functions that are part of the public API, but are dispatched at runtime.
102
+ //
103
+ // On GCC we mark the functions as `nonnull` informing that none of the arguments can be `NULL`.
104
+ // Marking with `pure` and `const` isn't possible as outputting to a pointer is a "side effect".
105
+ #if defined(__GNUC__) || defined(__clang__)
106
+ #define NK_PUBLIC __attribute__((unused)) inline static
107
+ #define NK_INTERNAL __attribute__((always_inline)) inline static
108
+ #elif defined(_MSC_VER)
109
+ #define NK_PUBLIC inline static
110
+ #define NK_INTERNAL __forceinline static
111
+ #else
112
+ #define NK_PUBLIC inline static
113
+ #define NK_INTERNAL inline static
114
+ #endif // defined(__GNUC__) || defined(__clang__)
115
+
116
+ #if NK_DYNAMIC_DISPATCH
117
+ #if defined(_WIN32) || defined(__CYGWIN__)
118
+ #define NK_DYNAMIC __declspec(dllexport)
119
+ #elif defined(__GNUC__) || defined(__clang__)
120
+ #define NK_DYNAMIC __attribute__((visibility("default")))
121
+ #else
122
+ #define NK_DYNAMIC NK_PUBLIC
123
+ #endif
124
+ #else
125
+ #define NK_DYNAMIC NK_PUBLIC
126
+ #endif // NK_DYNAMIC_DISPATCH
127
+
128
+ // Vector union types use type punning by design (write as f16, read as f32, etc.).
129
+ // Without this, GCC at -O2 assumes strict aliasing and may optimize away valid accesses.
130
+ #if defined(__GNUC__) || defined(__clang__)
131
+ #define NK_MAY_ALIAS_ __attribute__((may_alias))
132
+ #else
133
+ #define NK_MAY_ALIAS_
134
+ #endif
135
+
136
+ #if defined(__has_builtin)
137
+ #define nk_has_builtin_(x) __has_builtin(x)
138
+ #else
139
+ #define nk_has_builtin_(x) 0
140
+ #endif
141
+
142
+ // Allow SIMD kernels to redirect small inputs to serial implementations.
143
+ // Enabled by default for production use. Tests and benchmarks may disable
144
+ // this to isolate SIMD path behavior on small inputs.
145
+ #if !defined(NK_ALLOW_ISA_REDIRECT)
146
+ #define NK_ALLOW_ISA_REDIRECT 1
147
+ #endif
148
+
149
+ // Compiling for 64-bit Arm: NK_TARGET_ARM64_
150
+ // https://arm-software.github.io/acle/main/acle.html
151
+ #if !defined(NK_TARGET_ARM64_)
152
+ #if defined(__aarch64__) || defined(_M_ARM64)
153
+ #define NK_TARGET_ARM64_ 1
154
+ #else
155
+ #define NK_TARGET_ARM64_ 0
156
+ #endif // defined(__aarch64__) || defined(_M_ARM64)
157
+ #endif // !defined(NK_TARGET_ARM64_)
158
+
159
+ // Compiling for x86: NK_TARGET_X8664_
160
+ // https://www.intel.com/content/www/us/en/docs/dpcpp-cpp-compiler/developer-guide-reference/2024-2/additional-predefined-macros.html
161
+ #if !defined(NK_TARGET_X8664_)
162
+ #if defined(__x86_64__) || defined(_M_X64)
163
+ #define NK_TARGET_X8664_ 1
164
+ #else
165
+ #define NK_TARGET_X8664_ 0
166
+ #endif // defined(__x86_64__) || defined(_M_X64)
167
+ #endif // !defined(NK_TARGET_X8664_)
168
+
169
+ // Compiling for RISC-V: NK_TARGET_RISCV64_
170
+ #if !defined(NK_TARGET_RISCV64_)
171
+ #if defined(__riscv) && (__riscv_xlen == 64)
172
+ #define NK_TARGET_RISCV64_ 1
173
+ #else
174
+ #define NK_TARGET_RISCV64_ 0
175
+ #endif // defined(__riscv) && (__riscv_xlen == 64)
176
+ #endif // !defined(NK_TARGET_RISCV64_)
177
+
178
+ // Compiling for LoongArch: NK_TARGET_LOONGARCH64_
179
+ #if !defined(NK_TARGET_LOONGARCH64_)
180
+ #if defined(__loongarch__)
181
+ #define NK_TARGET_LOONGARCH64_ 1
182
+ #else
183
+ #define NK_TARGET_LOONGARCH64_ 0
184
+ #endif // defined(__loongarch__)
185
+ #endif // !defined(NK_TARGET_LOONGARCH64_)
186
+
187
+ // Compiling for Power: NK_TARGET_POWER64_
188
+ #if !defined(NK_TARGET_POWER64_)
189
+ #if defined(__powerpc64__) || defined(__ppc64__) || defined(_ARCH_PPC64)
190
+ #define NK_TARGET_POWER64_ 1
191
+ #else
192
+ #define NK_TARGET_POWER64_ 0
193
+ #endif // defined(__powerpc64__) || defined(__ppc64__) || defined(_ARCH_PPC64)
194
+ #endif // !defined(NK_TARGET_POWER64_)
195
+
196
+ // Compiling for WASM: NK_TARGET_WASM_
197
+ #if !defined(NK_TARGET_WASM_)
198
+ #if defined(__wasm__) || defined(__EMSCRIPTEN__)
199
+ #define NK_TARGET_WASM_ 1
200
+ #else
201
+ #define NK_TARGET_WASM_ 0
202
+ #endif
203
+ #endif // !defined(NK_TARGET_WASM_)
204
+
205
+ // WASI hosted mode: NK_DEFINED_WASI_
206
+ // When NK_WASI_HOSTED=ON in CMake, this is predefined to 1 so the library
207
+ // imports capability probes (nk_has_v128, nk_has_relaxed) from the host.
208
+ // Standalone runtimes (Wasmer, Wasmtime CLI) cannot supply those imports,
209
+ // so the default for plain __wasi__ builds is 0 (compile-time detection).
210
+ #if !defined(NK_DEFINED_WASI_)
211
+ #define NK_DEFINED_WASI_ 0
212
+ #endif // !defined(NK_DEFINED_WASI_)
213
+
214
+ // Compiling for WASM with Relaxed SIMD: NK_TARGET_V128RELAXED
215
+ // Requires -mrelaxed-simd for FMA instructions (f32x4.relaxed_madd, f64x2.relaxed_madd)
216
+ #if !defined(NK_TARGET_V128RELAXED) || (NK_TARGET_V128RELAXED && !NK_TARGET_WASM_)
217
+ #if defined(__wasm_relaxed_simd__)
218
+ #define NK_TARGET_V128RELAXED 1
219
+ #else
220
+ #undef NK_TARGET_V128RELAXED
221
+ #define NK_TARGET_V128RELAXED 0
222
+ #endif
223
+ #endif // !defined(NK_TARGET_V128RELAXED) || ...
224
+
225
+ // Compiling for RISC-V Vector: NK_TARGET_RVV
226
+ #if !defined(NK_TARGET_RVV) || (NK_TARGET_RVV && !NK_TARGET_RISCV64_)
227
+ #if defined(__riscv_v) && (__riscv_v >= 1000000)
228
+ #define NK_TARGET_RVV 1
229
+ #else
230
+ #undef NK_TARGET_RVV
231
+ #define NK_TARGET_RVV 0
232
+ #endif // defined(__riscv_v) && (__riscv_v >= 1000000)
233
+ #endif // !defined(NK_TARGET_RVV) || ...
234
+
235
+ // Compiling for RISC-V Vector with Zvfh (f16): NK_TARGET_RVVHALF
236
+ // Requires GCC 14+ or Clang 18+ for full intrinsic support
237
+ #if !defined(NK_TARGET_RVVHALF) || (NK_TARGET_RVVHALF && !NK_TARGET_RVV)
238
+ #if defined(__riscv_zvfh) && (__riscv_zvfh > 0)
239
+ #define NK_TARGET_RVVHALF 1
240
+ #else
241
+ #undef NK_TARGET_RVVHALF
242
+ #define NK_TARGET_RVVHALF 0
243
+ #endif // defined(__riscv_zvfh) && (__riscv_zvfh > 0)
244
+ #endif // !defined(NK_TARGET_RVVHALF) || ...
245
+
246
+ // Compiling for RISC-V Vector with Zvfbfwma (bf16 widening FMA): NK_TARGET_RVVBF16
247
+ // Requires GCC 14+ or Clang 18+ for full intrinsic support
248
+ #if !defined(NK_TARGET_RVVBF16) || (NK_TARGET_RVVBF16 && !NK_TARGET_RVV)
249
+ #if defined(__riscv_zvfbfwma) && (__riscv_zvfbfwma > 0)
250
+ #define NK_TARGET_RVVBF16 1
251
+ #else
252
+ #undef NK_TARGET_RVVBF16
253
+ #define NK_TARGET_RVVBF16 0
254
+ #endif // defined(__riscv_zvfbfwma) && (__riscv_zvfbfwma > 0)
255
+ #endif // !defined(NK_TARGET_RVVBF16) || ...
256
+
257
+ // Compiling for RISC-V Vector with Zvbb (basic bit-manipulation): NK_TARGET_RVVBB
258
+ // Provides vcpop.v (per-element popcount), vclz.v, vctz.v, vbrev.v, vrol.v, vror.v
259
+ #if !defined(NK_TARGET_RVVBB) || (NK_TARGET_RVVBB && !NK_TARGET_RVV)
260
+ #if defined(__riscv_zvbb) && (__riscv_zvbb > 0)
261
+ #define NK_TARGET_RVVBB 1
262
+ #else
263
+ #undef NK_TARGET_RVVBB
264
+ #define NK_TARGET_RVVBB 0
265
+ #endif // defined(__riscv_zvbb) && (__riscv_zvbb > 0)
266
+ #endif // !defined(NK_TARGET_RVVBB) || ...
267
+
268
+ // Compiling for LoongArch LASX (256-bit SIMD): NK_TARGET_LOONGSONASX
269
+ // LASX provides 32 × 256-bit vector registers, widening integer multiply-accumulate,
270
+ // and f32-to-f64 conversion (xvfcvtl_d_s / xvfcvth_d_s) but no widening FMA.
271
+ #if !defined(NK_TARGET_LOONGSONASX) || (NK_TARGET_LOONGSONASX && !NK_TARGET_LOONGARCH64_)
272
+ #if defined(__loongarch_asx)
273
+ #define NK_TARGET_LOONGSONASX 1
274
+ #else
275
+ #undef NK_TARGET_LOONGSONASX
276
+ #define NK_TARGET_LOONGSONASX 0
277
+ #endif // defined(__loongarch_asx)
278
+ #endif // !defined(NK_TARGET_LOONGSONASX) || ...
279
+
280
+ // Compiling for Power VSX (128-bit SIMD, POWER9+ baseline): NK_TARGET_POWERVSX
281
+ // VSX provides 64 × 128-bit registers, FMA (vec_madd), vec_msum (multiply-sum), hardware f16
282
+ // conversion (vec_extract_fp32_from_shorth/l), length-limited loads (vec_xl_len), per-byte
283
+ // popcount (vec_popcnt), and vec_cmpne. Requires POWER9 (ISA 3.0) or newer.
284
+ #if !defined(NK_TARGET_POWERVSX) || (NK_TARGET_POWERVSX && !NK_TARGET_POWER64_)
285
+ #if defined(__VSX__) && defined(__POWER9_VECTOR__)
286
+ #define NK_TARGET_POWERVSX 1
287
+ #else
288
+ #undef NK_TARGET_POWERVSX
289
+ #define NK_TARGET_POWERVSX 0
290
+ #endif // defined(__VSX__)
291
+ #endif // !defined(NK_TARGET_POWERVSX) || ...
292
+
293
+ // Compiling for Arm: NK_TARGET_NEON (AArch64 only, AArch32 NEON is not supported)
294
+ #if !defined(NK_TARGET_NEON) || (NK_TARGET_NEON && !NK_TARGET_ARM64_)
295
+ #if (defined(__ARM_NEON) && defined(__aarch64__)) || (defined(_MSC_VER) && defined(_M_ARM64))
296
+ #define NK_TARGET_NEON 1
297
+ #else
298
+ #undef NK_TARGET_NEON
299
+ #define NK_TARGET_NEON 0
300
+ #endif // (defined(__ARM_NEON) && defined(__aarch64__)) || ...
301
+ #endif // !defined(NK_TARGET_NEON) || ...
302
+
303
+ // Compiling for Arm: NK_TARGET_NEONSDOT (FEAT_DotProd, AArch64 only)
304
+ #if !defined(NK_TARGET_NEONSDOT) || (NK_TARGET_NEONSDOT && !NK_TARGET_ARM64_)
305
+ #if (defined(__ARM_FEATURE_DOTPROD) && defined(__aarch64__)) || \
306
+ (defined(_MSC_VER) && defined(_M_ARM64) && __ARM_ARCH >= 804)
307
+ #define NK_TARGET_NEONSDOT 1
308
+ #else
309
+ #undef NK_TARGET_NEONSDOT
310
+ #define NK_TARGET_NEONSDOT 0
311
+ #endif
312
+ #endif // !defined(NK_TARGET_NEONSDOT) || ...
313
+
314
+ // Compiling for Arm: NK_TARGET_NEONHALF (FEAT_FP16, AArch64 only)
315
+ #if !defined(NK_TARGET_NEONHALF) || (NK_TARGET_NEONHALF && !NK_TARGET_ARM64_)
316
+ #if (defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(__aarch64__)) || \
317
+ (defined(_MSC_VER) && defined(_M_ARM64) && __ARM_ARCH >= 802)
318
+ #define NK_TARGET_NEONHALF 1
319
+ #else
320
+ #undef NK_TARGET_NEONHALF
321
+ #define NK_TARGET_NEONHALF 0
322
+ #endif
323
+ #endif // !defined(NK_TARGET_NEONHALF) || ...
324
+
325
+ // Compiling for Arm: NK_TARGET_NEONFHM (FEAT_FHM, AArch64 only)
326
+ #if !defined(NK_TARGET_NEONFHM) || (NK_TARGET_NEONFHM && !NK_TARGET_ARM64_)
327
+ #if (defined(__ARM_FEATURE_FP16_FML) && defined(__aarch64__)) || \
328
+ (defined(_MSC_VER) && defined(_M_ARM64) && __ARM_ARCH >= 804)
329
+ #define NK_TARGET_NEONFHM 1
330
+ #else
331
+ #undef NK_TARGET_NEONFHM
332
+ #define NK_TARGET_NEONFHM 0
333
+ #endif
334
+ #endif // !defined(NK_TARGET_NEONFHM) || ...
335
+
336
+ // Compiling for Arm: NK_TARGET_NEONBFDOT (FEAT_BF16, AArch64 only)
337
+ #if !defined(NK_TARGET_NEONBFDOT) || (NK_TARGET_NEONBFDOT && !NK_TARGET_ARM64_)
338
+ #if (defined(__ARM_FEATURE_BF16_VECTOR_ARITHMETIC) && defined(__aarch64__)) || \
339
+ (defined(_MSC_VER) && defined(_M_ARM64) && __ARM_ARCH >= 806)
340
+ #define NK_TARGET_NEONBFDOT 1
341
+ #else
342
+ #undef NK_TARGET_NEONBFDOT
343
+ #define NK_TARGET_NEONBFDOT 0
344
+ #endif
345
+ #endif // !defined(NK_TARGET_NEONBFDOT) || ...
346
+
347
+ // Compiling for Arm: NK_TARGET_NEONFP8 (NEON FP8 extensions, FEAT_FP8DOT4)
348
+ // ACLE macro __ARM_FEATURE_FP8DOT4 defined by GCC 15+ and Clang 21+ when +fp8dot4 is enabled.
349
+ // Older compilers lack mfloat8x16_t and the fp8dot4 target attribute entirely.
350
+ #if !defined(NK_TARGET_NEONFP8) || (NK_TARGET_NEONFP8 && !NK_TARGET_ARM64_)
351
+ #if defined(__ARM_FEATURE_FP8DOT4) && defined(__aarch64__)
352
+ #define NK_TARGET_NEONFP8 1
353
+ #else
354
+ #undef NK_TARGET_NEONFP8
355
+ #define NK_TARGET_NEONFP8 0
356
+ #endif // defined(__ARM_FEATURE_FP8DOT4)
357
+ #endif // !defined(NK_TARGET_NEONFP8) || ...
358
+
359
+ // Compiling for Arm: NK_TARGET_SVE
360
+ #if !defined(NK_TARGET_SVE) || (NK_TARGET_SVE && !NK_TARGET_ARM64_)
361
+ #if defined(__ARM_FEATURE_SVE)
362
+ #define NK_TARGET_SVE 1
363
+ #else
364
+ #undef NK_TARGET_SVE
365
+ #define NK_TARGET_SVE 0
366
+ #endif // defined(__ARM_FEATURE_SVE)
367
+ #endif // !defined(NK_TARGET_SVE) || ...
368
+
369
+ // Compiling for Arm: NK_TARGET_SVESDOT
370
+ #if !defined(NK_TARGET_SVESDOT) || (NK_TARGET_SVESDOT && !NK_TARGET_ARM64_)
371
+ #if defined(__ARM_FEATURE_SVE)
372
+ #define NK_TARGET_SVESDOT 1
373
+ #else
374
+ #undef NK_TARGET_SVESDOT
375
+ #define NK_TARGET_SVESDOT 0
376
+ #endif // defined(__ARM_FEATURE_SVE)
377
+ #endif // !defined(NK_TARGET_SVESDOT) || ...
378
+
379
+ // Compiling for Arm: NK_TARGET_SVEHALF
380
+ #if !defined(NK_TARGET_SVEHALF) || (NK_TARGET_SVEHALF && !NK_TARGET_ARM64_)
381
+ #if defined(__ARM_FEATURE_SVE)
382
+ #define NK_TARGET_SVEHALF 1
383
+ #else
384
+ #undef NK_TARGET_SVEHALF
385
+ #define NK_TARGET_SVEHALF 0
386
+ #endif // defined(__ARM_FEATURE_SVE)
387
+ #endif // !defined(NK_TARGET_SVEHALF) || ...
388
+
389
+ // Compiling for Arm: NK_TARGET_SVEBFDOT
390
+ #if !defined(NK_TARGET_SVEBFDOT) || (NK_TARGET_SVEBFDOT && !NK_TARGET_ARM64_)
391
+ #if defined(__ARM_FEATURE_SVE)
392
+ #define NK_TARGET_SVEBFDOT 1
393
+ #else
394
+ #undef NK_TARGET_SVEBFDOT
395
+ #define NK_TARGET_SVEBFDOT 0
396
+ #endif // defined(__ARM_FEATURE_SVE)
397
+ #endif // !defined(NK_TARGET_SVEBFDOT) || ...
398
+
399
+ // Compiling for Arm: NK_TARGET_SVE2
400
+ #if !defined(NK_TARGET_SVE2) || (NK_TARGET_SVE2 && !NK_TARGET_ARM64_)
401
+ #if defined(__ARM_FEATURE_SVE2)
402
+ #define NK_TARGET_SVE2 1
403
+ #else
404
+ #undef NK_TARGET_SVE2
405
+ #define NK_TARGET_SVE2 0
406
+ #endif // defined(__ARM_FEATURE_SVE2)
407
+ #endif // !defined(NK_TARGET_SVE2) || ...
408
+
409
+ // Compiling for Arm: NK_TARGET_SVE2P1
410
+ #if !defined(NK_TARGET_SVE2P1) || (NK_TARGET_SVE2P1 && !NK_TARGET_ARM64_)
411
+ #undef NK_TARGET_SVE2P1
412
+ #define NK_TARGET_SVE2P1 0
413
+ #endif // !defined(NK_TARGET_SVE2P1) || ...
414
+
415
+ // Compiling for Arm: NK_TARGET_SME (Scalable Matrix Extension)
416
+ #if !defined(NK_TARGET_SME) || (NK_TARGET_SME && !NK_TARGET_ARM64_)
417
+ #if defined(__ARM_FEATURE_SME)
418
+ #define NK_TARGET_SME 1
419
+ #else
420
+ #undef NK_TARGET_SME
421
+ #define NK_TARGET_SME 0
422
+ #endif // defined(__ARM_FEATURE_SME)
423
+ #endif // !defined(NK_TARGET_SME) || ...
424
+
425
+ #if !defined(NK_TARGET_SME2) || (NK_TARGET_SME2 && !NK_TARGET_ARM64_)
426
+ #if defined(__ARM_FEATURE_SME2)
427
+ #define NK_TARGET_SME2 1
428
+ #else
429
+ #undef NK_TARGET_SME2
430
+ #define NK_TARGET_SME2 0
431
+ #endif // defined(__ARM_FEATURE_SME2)
432
+ #endif // !defined(NK_TARGET_SME2) || ...
433
+
434
+ // Compiling for Arm: NK_TARGET_SME2P1 (FEAT_SME2p1)
435
+ // ACLE macro: __ARM_FEATURE_SME2p1 (note lowercase 'p')
436
+ #if !defined(NK_TARGET_SME2P1) || (NK_TARGET_SME2P1 && !NK_TARGET_ARM64_)
437
+ #if defined(__ARM_FEATURE_SME2p1)
438
+ #define NK_TARGET_SME2P1 1
439
+ #else
440
+ #undef NK_TARGET_SME2P1
441
+ #define NK_TARGET_SME2P1 0
442
+ #endif // defined(__ARM_FEATURE_SME2p1)
443
+ #endif // !defined(NK_TARGET_SME2P1) || ...
444
+
445
+ // AppleClang 17 exposes SME sub-features through `arm_sme.h` builtin aliases,
446
+ // not dedicated `__ARM_FEATURE_*` predefines for every matrix subtype.
447
+ #if !defined(NK_TARGET_SMEF64) || (NK_TARGET_SMEF64 && !NK_TARGET_ARM64_)
448
+ #if defined(__ARM_FEATURE_SME_F64F64) || nk_has_builtin_(__builtin_sme_svmopa_za64_f64_m)
449
+ #define NK_TARGET_SMEF64 1
450
+ #else
451
+ #undef NK_TARGET_SMEF64
452
+ #define NK_TARGET_SMEF64 0
453
+ #endif // defined(__ARM_FEATURE_SME_F64F64) || ...
454
+ #endif // !defined(NK_TARGET_SMEF64) || ...
455
+
456
+ #if !defined(NK_TARGET_SMEBI32) || (NK_TARGET_SMEBI32 && !NK_TARGET_ARM64_)
457
+ #if nk_has_builtin_(__builtin_sme_svbmopa_za32_u32_m)
458
+ #define NK_TARGET_SMEBI32 1
459
+ #else
460
+ #undef NK_TARGET_SMEBI32
461
+ #define NK_TARGET_SMEBI32 0
462
+ #endif // nk_has_builtin_(__builtin_sme_svbmopa_za32_u32_m)
463
+ #endif // !defined(NK_TARGET_SMEBI32) || ...
464
+
465
+ #if !defined(NK_TARGET_SMEHALF) || (NK_TARGET_SMEHALF && !NK_TARGET_ARM64_)
466
+ #if defined(__ARM_FEATURE_SME_F16F16) || nk_has_builtin_(__builtin_sme_svmopa_za32_f16_m)
467
+ #define NK_TARGET_SMEHALF 1
468
+ #else
469
+ #undef NK_TARGET_SMEHALF
470
+ #define NK_TARGET_SMEHALF 0
471
+ #endif // nk_has_builtin_(__builtin_sme_svmopa_za32_f16_m)
472
+ #endif // !defined(NK_TARGET_SMEHALF) || ...
473
+
474
+ #if !defined(NK_TARGET_SMEBF16) || (NK_TARGET_SMEBF16 && !NK_TARGET_ARM64_)
475
+ #if nk_has_builtin_(__builtin_sme_svmopa_za32_bf16_m)
476
+ #define NK_TARGET_SMEBF16 1
477
+ #else
478
+ #undef NK_TARGET_SMEBF16
479
+ #define NK_TARGET_SMEBF16 0
480
+ #endif // nk_has_builtin_(__builtin_sme_svmopa_za32_bf16_m)
481
+ #endif // !defined(NK_TARGET_SMEBF16) || ...
482
+
483
+ #if !defined(NK_TARGET_SMELUT2) || (NK_TARGET_SMELUT2 && !NK_TARGET_ARM64_)
484
+ #if nk_has_builtin_(__builtin_sme_svluti2_lane_zt_u8)
485
+ #define NK_TARGET_SMELUT2 1
486
+ #else
487
+ #undef NK_TARGET_SMELUT2
488
+ #define NK_TARGET_SMELUT2 0
489
+ #endif // nk_has_builtin_(__builtin_sme_svluti2_lane_zt_u8)
490
+ #endif // !defined(NK_TARGET_SMELUT2) || ...
491
+
492
+ // Compiling for Arm: NK_TARGET_SMEFA64 (FEAT_SME_FA64, full SVE2 in streaming mode)
493
+ #if !defined(NK_TARGET_SMEFA64) || (NK_TARGET_SMEFA64 && !NK_TARGET_ARM64_)
494
+ #if defined(__ARM_FEATURE_SME_FA64)
495
+ #define NK_TARGET_SMEFA64 1
496
+ #else
497
+ #undef NK_TARGET_SMEFA64
498
+ #define NK_TARGET_SMEFA64 0
499
+ #endif // defined(__ARM_FEATURE_SME_FA64)
500
+ #endif // !defined(NK_TARGET_SMEFA64) || ...
501
+
502
+ // Compiling for x86: NK_TARGET_HASWELL
503
+ //
504
+ // Starting with Ivy Bridge, Intel supports the `F16C` extensions for fast half-precision
505
+ // to single-precision floating-point conversions. On AMD those instructions
506
+ // are supported on all CPUs starting with Jaguar 2009.
507
+ // Starting with Sandy Bridge, Intel adds basic AVX support in their CPUs and in 2013
508
+ // extends it with AVX2 in the Haswell generation. Moreover, Haswell adds FMA support.
509
+ //
510
+ // On MSVC, most GCC-style ISA macros are unavailable. MSVC defines __AVX__, __AVX2__,
511
+ // __AVX512F/BW/CD/DQ/VL__, and __AVX10_VER__, but NOT __AVXVNNI__, __AVX512VNNI__,
512
+ // __AVX512BF16__, __AVX512FP16__, __AMX_*__, etc.
513
+ // Instead, MSVC makes all intrinsics available once the toolset version supports them,
514
+ // without requiring `/arch:AVX512`. We gate on _MSC_VER to auto-enable targets:
515
+ // - _MSC_VER >= 1900 (VS 2015+): AVX2/FMA/F16C (Haswell)
516
+ // - _MSC_VER >= 1920 (VS 2019+): AVX-512 base (Skylake, Icelake), AVX-VNNI (Alder)
517
+ // - _MSC_VER >= 1944 (VS 2022 17.14+): BF16, FP16, VP2INTERSECT, VNNI-INT8 (Sierra), AMX
518
+ #if !defined(NK_TARGET_HASWELL) || (NK_TARGET_HASWELL && !NK_TARGET_X8664_)
519
+ #if (defined(__AVX2__) && defined(__FMA__) && defined(__F16C__)) || (defined(_MSC_VER) && _MSC_VER >= 1900)
520
+ #define NK_TARGET_HASWELL 1
521
+ #else
522
+ #undef NK_TARGET_HASWELL
523
+ #define NK_TARGET_HASWELL 0
524
+ #endif // defined(__AVX2__)
525
+ #endif // !defined(NK_TARGET_HASWELL) || ...
526
+
527
+ // Compiling for x86: NK_TARGET_SKYLAKE, NK_TARGET_ICELAKE, NK_TARGET_GENOA,
528
+ // NK_TARGET_SAPPHIRE, NK_TARGET_TURIN, NK_TARGET_SIERRA
529
+ //
530
+ // To list all available macros for x86, take a recent compiler, like GCC 12 and run:
531
+ // gcc-12 -march=sapphirerapids -dM -E - < /dev/null | egrep "SSE|AVX" | sort
532
+ // On Arm machines you may want to check for other flags:
533
+ // gcc-12 -march=native -dM -E - < /dev/null | egrep "NEON|SVE|FP16|FMA" | sort
534
+ #if !defined(NK_TARGET_SKYLAKE) || (NK_TARGET_SKYLAKE && !NK_TARGET_X8664_)
535
+ #if (defined(__AVX512F__) && defined(__AVX512CD__) && defined(__AVX512VL__) && defined(__AVX512DQ__) && \
536
+ defined(__AVX512BW__)) || \
537
+ (defined(_MSC_VER) && _MSC_VER >= 1920)
538
+ #define NK_TARGET_SKYLAKE 1
539
+ #else
540
+ #undef NK_TARGET_SKYLAKE
541
+ #define NK_TARGET_SKYLAKE 0
542
+ #endif
543
+ #endif // !defined(NK_TARGET_SKYLAKE) || ...
544
+
545
+ #if !defined(NK_TARGET_ICELAKE) || (NK_TARGET_ICELAKE && !NK_TARGET_X8664_)
546
+ #if (defined(__AVX512VNNI__) && defined(__AVX512IFMA__) && defined(__AVX512BITALG__) && defined(__AVX512VBMI__) && \
547
+ defined(__AVX512VBMI2__) && defined(__AVX512VPOPCNTDQ__)) || \
548
+ (defined(_MSC_VER) && _MSC_VER >= 1920)
549
+ #define NK_TARGET_ICELAKE 1
550
+ #else
551
+ #undef NK_TARGET_ICELAKE
552
+ #define NK_TARGET_ICELAKE 0
553
+ #endif
554
+ #endif // !defined(NK_TARGET_ICELAKE) || ...
555
+
556
+ #if !defined(NK_TARGET_GENOA) || (NK_TARGET_GENOA && !NK_TARGET_X8664_)
557
+ #if defined(__AVX512BF16__) || (defined(_MSC_VER) && _MSC_VER >= 1944)
558
+ #define NK_TARGET_GENOA 1
559
+ #else
560
+ #undef NK_TARGET_GENOA
561
+ #define NK_TARGET_GENOA 0
562
+ #endif // defined(__AVX512BF16__) || ...
563
+ #endif // !defined(NK_TARGET_GENOA) || ...
564
+
565
+ // Compiling for x86: NK_TARGET_DIAMOND (AVX10.2, Diamond Rapids)
566
+ // GCC 14+: defines __AVX10_2__ with -mavx10.2-512
567
+ // Clang 19+: defines __AVX10_2__ with -mavx10.2-512
568
+ // MSVC: defines __AVX10_VER__ >= 2 with /arch:AVX10.2 (VS 2026+, not yet released)
569
+ #if !defined(NK_TARGET_DIAMOND) || (NK_TARGET_DIAMOND && !NK_TARGET_X8664_)
570
+ #if defined(__AVX10_2__) || (defined(__AVX10_VER__) && __AVX10_VER__ >= 2)
571
+ #define NK_TARGET_DIAMOND 1
572
+ #else
573
+ #undef NK_TARGET_DIAMOND
574
+ #define NK_TARGET_DIAMOND 0
575
+ #endif // defined(__AVX10_2__) || ...
576
+ #endif // !defined(NK_TARGET_DIAMOND) || ...
577
+
578
+ #if !defined(NK_TARGET_SAPPHIRE) || (NK_TARGET_SAPPHIRE && !NK_TARGET_X8664_)
579
+ #if defined(__AVX512FP16__) || (defined(_MSC_VER) && _MSC_VER >= 1944)
580
+ #define NK_TARGET_SAPPHIRE 1
581
+ #else
582
+ #undef NK_TARGET_SAPPHIRE
583
+ #define NK_TARGET_SAPPHIRE 0
584
+ #endif
585
+ #endif // !defined(NK_TARGET_SAPPHIRE) || ...
586
+
587
+ #if !defined(NK_TARGET_SAPPHIREAMX) || (NK_TARGET_SAPPHIREAMX && !NK_TARGET_X8664_)
588
+ #if (defined(__AMX_TILE__) && defined(__AMX_BF16__) && defined(__AMX_INT8__)) || (defined(_MSC_VER) && _MSC_VER >= 1944)
589
+ #define NK_TARGET_SAPPHIREAMX 1
590
+ #else
591
+ #undef NK_TARGET_SAPPHIREAMX
592
+ #define NK_TARGET_SAPPHIREAMX 0
593
+ #endif
594
+ #endif // !defined(NK_TARGET_SAPPHIREAMX) || ...
595
+
596
+ #if !defined(NK_TARGET_GRANITEAMX) || (NK_TARGET_GRANITEAMX && !NK_TARGET_X8664_)
597
+ #if (defined(__AMX_TILE__) && defined(__AMX_FP16__)) || (defined(_MSC_VER) && _MSC_VER >= 1944)
598
+ #define NK_TARGET_GRANITEAMX 1
599
+ #else
600
+ #undef NK_TARGET_GRANITEAMX
601
+ #define NK_TARGET_GRANITEAMX 0
602
+ #endif
603
+ #endif // !defined(NK_TARGET_GRANITEAMX) || ...
604
+
605
+ #if !defined(NK_TARGET_TURIN) || (NK_TARGET_TURIN && !NK_TARGET_X8664_)
606
+ #if defined(__AVX512VP2INTERSECT__) || (defined(_MSC_VER) && _MSC_VER >= 1944)
607
+ #define NK_TARGET_TURIN 1
608
+ #else
609
+ #undef NK_TARGET_TURIN
610
+ #define NK_TARGET_TURIN 0
611
+ #endif
612
+ #endif // !defined(NK_TARGET_TURIN) || ...
613
+
614
+ #if !defined(NK_TARGET_ALDER) || (NK_TARGET_ALDER && !NK_TARGET_X8664_)
615
+ #if defined(__AVXVNNI__) || (defined(_MSC_VER) && _MSC_VER >= 1920)
616
+ #define NK_TARGET_ALDER 1
617
+ #else
618
+ #undef NK_TARGET_ALDER
619
+ #define NK_TARGET_ALDER 0
620
+ #endif
621
+ #endif // !defined(NK_TARGET_ALDER) || ...
622
+
623
+ #if !defined(NK_TARGET_SIERRA) || (NK_TARGET_SIERRA && !NK_TARGET_X8664_)
624
+ #if defined(__AVXVNNIINT8__) || (defined(_MSC_VER) && _MSC_VER >= 1944)
625
+ #define NK_TARGET_SIERRA 1
626
+ #else
627
+ #undef NK_TARGET_SIERRA
628
+ #define NK_TARGET_SIERRA 0
629
+ #endif
630
+ #endif // !defined(NK_TARGET_SIERRA) || ...
631
+
632
+ // Include the relevant intrinsics headers
633
+ #if defined(_MSC_VER)
634
+ #include <intrin.h>
635
+ #endif
636
+ #if NK_TARGET_NEON
637
+ #include <arm_neon.h>
638
+ #endif
639
+ #if NK_TARGET_SVE || NK_TARGET_SVE2
640
+ #include <arm_sve.h>
641
+ #endif
642
+ #if NK_TARGET_SME || NK_TARGET_SME2 || NK_TARGET_SMEBI32
643
+ #include <arm_sme.h>
644
+ #endif
645
+ #if NK_TARGET_HASWELL || NK_TARGET_SKYLAKE
646
+ #include <immintrin.h>
647
+ #endif
648
+ #if NK_TARGET_RVV
649
+ #include <riscv_vector.h>
650
+ #endif
651
+ #if NK_TARGET_LOONGSONASX
652
+ #include <lsxintrin.h> // `__m128i` for LSX SIMD
653
+ #include <lasxintrin.h> // `__m256i` for LASX SIMD
654
+ #endif
655
+ #if NK_TARGET_POWERVSX
656
+ #include <altivec.h>
657
+ #endif
658
+ #if NK_TARGET_V128RELAXED
659
+ #include <wasm_simd128.h>
660
+ #endif
661
+
662
+ #if !defined(NK_F64_DIVISION_EPSILON)
663
+ #define NK_F64_DIVISION_EPSILON (1e-15)
664
+ #endif
665
+
666
+ #if !defined(NK_F32_DIVISION_EPSILON)
667
+ #define NK_F32_DIVISION_EPSILON (1e-7f)
668
+ #endif
669
+
670
+ #if !defined(NK_F16_DIVISION_EPSILON)
671
+ #define NK_F16_DIVISION_EPSILON (1e-3f)
672
+ #endif
673
+
674
+ /**
675
+ * @brief The compile-time constant defining the capacity of `nk_tensor_position_t`.
676
+ * Matches `PyBUF_MAX_NDIM` by default.
677
+ */
678
+ #if !defined(NK_TENSOR_MAX_RANK)
679
+ #define NK_TENSOR_MAX_RANK (64)
680
+ #endif
681
+
682
+ /**
683
+ * @brief Aligns a variable to a 64-byte boundary using compiler extensions for
684
+ * compatibility with C 99, as `alignas(64)` is only available in C 11 or C++.
685
+ * Used internally and recommended for external users.
686
+ */
687
+ #if defined(_MSC_VER)
688
+ #define NK_ALIGN64 __declspec(align(64))
689
+ #elif defined(__GNUC__) || defined(__clang__)
690
+ #define NK_ALIGN64 __attribute__((aligned(64)))
691
+ #endif
692
+
693
+ /**
694
+ * ARM Streaming attributes (require SME-capable compiler: GCC 14+, Clang 16+).
695
+ * NK_STREAMING_ marks functions that require streaming SVE mode (e.g. FCVTLT).
696
+ * NK_STREAMING_COMPATIBLE_ marks helpers callable from both streaming and non-streaming mode.
697
+ */
698
+ #if NK_TARGET_ARM64_ && NK_TARGET_SME
699
+ #define NK_STREAMING_ __arm_streaming
700
+ #define NK_STREAMING_COMPATIBLE_ __arm_streaming_compatible
701
+ #else
702
+ #define NK_STREAMING_
703
+ #define NK_STREAMING_COMPATIBLE_
704
+ #endif
705
+
706
+ /**
707
+ * @brief Portable casts between SIMD vector types.
708
+ * MSVC typedefs `__m512bh`, `__m512h`, `__m256bh` as aliases for `__m512i`/`__m256i`,
709
+ * but rejects C-style casts between them. GCC/Clang define them as distinct types.
710
+ */
711
+ #if NK_TARGET_X8664_
712
+ #if defined(_MSC_VER)
713
+ #define nk_m512bh_from_m512i_(x) (x)
714
+ #define nk_m512h_from_m512i_(x) (x)
715
+ #define nk_m512i_from_m512h_(x) (x)
716
+ #define nk_m256bh_from_m256i_(x) (x)
717
+ #define nk_m256i_from_m256bh_(x) (x)
718
+ #else
719
+ #define nk_m512bh_from_m512i_(x) ((__m512bh)(x))
720
+ #define nk_m512h_from_m512i_(x) ((__m512h)(x))
721
+ #define nk_m512i_from_m512h_(x) ((__m512i)(x))
722
+ #define nk_m256bh_from_m256i_(x) ((__m256bh)(x))
723
+ #define nk_m256i_from_m256bh_(x) ((__m256i)(x))
724
+ #endif
725
+ #endif
726
+
727
+ /* AltiVec defines `bool`, `vector`, and `pixel` as macros, which conflict with C++.
728
+ * We use `__vector` directly in our code, so undef the problematic macros.
729
+ */
730
+ #if NK_TARGET_POWERVSX
731
+ #ifdef __cplusplus
732
+ #undef bool
733
+ #undef vector
734
+ #undef pixel
735
+ #endif
736
+ typedef __vector unsigned char nk_vu8x16_t;
737
+ typedef __vector unsigned short nk_vu16x8_t;
738
+ typedef __vector unsigned int nk_vu32x4_t;
739
+ typedef __vector unsigned long long nk_vu64x2_t;
740
+ typedef __vector signed char nk_vi8x16_t;
741
+ typedef __vector signed short nk_vi16x8_t;
742
+ typedef __vector signed int nk_vi32x4_t;
743
+ typedef __vector signed long long nk_vi64x2_t;
744
+ typedef __vector float nk_vf32x4_t;
745
+ typedef __vector double nk_vf64x2_t;
746
+ #endif // NK_TARGET_POWERVSX
747
+
748
+ /** Copy 16 bits (2 bytes) from source to destination */
749
+ #if defined(__GNUC__) || defined(__clang__)
750
+ #define nk_copy_bytes_(destination_ptr, source_ptr, count) __builtin_memcpy((destination_ptr), (source_ptr), count)
751
+ #else
752
+ #include <string.h> // `memcpy`
753
+ #define nk_copy_bytes_(destination_ptr, source_ptr, count) memcpy((destination_ptr), (source_ptr), count)
754
+ #endif
755
+
756
+ /** Macro to mark unused parameters (cleaner than (void)variable) */
757
+ #define nk_unused_(x) ((void)(x))
758
+
759
+ /**
760
+ * @brief C99 static array parameter annotation for minimum array size.
761
+ *
762
+ * In C, expands to `static n` enabling compiler bounds checking.
763
+ * In C++, expands to nothing as this syntax is not supported.
764
+ * @see https://lwn.net/Articles/1046840/
765
+ *
766
+ * Example usage:
767
+ * @code{.c}
768
+ * void hash_digest(uint8_t digest[nk_at_least_(32)]);
769
+ * void lookup(uint8_t const lut[nk_at_least_(256)]);
770
+ * @endcode
771
+ */
772
+ #if defined(__cplusplus) || defined(_MSC_VER)
773
+ #define nk_at_least_(n)
774
+ #else
775
+ #define nk_at_least_(n) static n
776
+ #endif
777
+
778
+ #ifdef __cplusplus
779
+ extern "C" {
780
+ #endif
781
+
782
+ /** @brief Packed 8-bit bit-vector (8 booleans in one byte), LSB = dimension 0.
783
+ * Used for Hamming distance and Jaccard similarity via popcount.
784
+ * Dimension count must be a multiple of 8; unused bits in the final byte must be zeroed. */
785
+ typedef unsigned char nk_u1x8_t;
786
+ /** @brief Packed 4-bit signed integer pair (2 × i4 in one byte), [high nibble : low nibble].
787
+ * Range per element: [−8, +7]. Elements sign-extended to i8 for arithmetic.
788
+ * Dimension count must be a multiple of 2; unused nibbles in the final byte must be zeroed. */
789
+ typedef unsigned char nk_i4x2_t;
790
+ /** @brief Packed 4-bit unsigned integer pair (2 × u4 in one byte), [high nibble : low nibble].
791
+ * Range per element: [0, 15]. Elements zero-extended to u8 for arithmetic.
792
+ * Dimension count must be a multiple of 2; unused nibbles in the final byte must be zeroed. */
793
+ typedef unsigned char nk_u4x2_t;
794
+
795
+ /** @brief 8-bit E4M3 float (OCP FP8): sign(1) + exponent(4) + mantissa(3), bias=7.
796
+ * Range: ±448, no infinities (all-ones exponent → NaN at 0x7F/0xFF).
797
+ * 114 of 254 finite values (44.9%) fall in [−1, +1]. */
798
+ typedef unsigned char nk_e4m3_t;
799
+ /** @brief 8-bit E5M2 float (OCP FP8): sign(1) + exponent(5) + mantissa(2), bias=15.
800
+ * Range: ±57 344, supports infinities at 0x7C/0xFC.
801
+ * 122 of 248 finite values (49.2%) fall in [−1, +1]. */
802
+ typedef unsigned char nk_e5m2_t;
803
+ /** @brief 6-bit E2M3 micro-float (OCP MX v1.0): sign(1) + exponent(2) + mantissa(3), bias=1.
804
+ * Stored as 0b00SEEMMM with 2 bits of padding. Range: ±7.5, no infinities or NaN.
805
+ * 64 total codes: 48 normal, 14 subnormal (exp=0, mant≠0), 2 zeros (±0).
806
+ * 18 of 64 values (28.1%) fall in [−1, +1]. Subnormal values span [±0.125, ±0.875].
807
+ * Losslessly promotable to E4M3 by rebiasing exponent +6 (normals) or normalizing (subnormals). */
808
+ typedef unsigned char nk_e2m3_t;
809
+ /** @brief 6-bit E3M2 micro-float (OCP MX v1.0): sign(1) + exponent(3) + mantissa(2), bias=3.
810
+ * Stored as 0b00SEEEMM with 2 bits of padding. Range: ±28, no infinities or NaN.
811
+ * 64 total codes: 56 normal, 6 subnormal (exp=0, mant≠0), 2 zeros (±0).
812
+ * 26 of 64 values (40.6%) fall in [−1, +1]. Subnormal values span [±0.0625, ±0.1875].
813
+ * Losslessly promotable to E5M2 by rebiasing exponent +12 (normals) or normalizing (subnormals). */
814
+ typedef unsigned char nk_e3m2_t;
815
+
816
+ /** @brief Signed 8-bit integer. Range: [−128, +127]. */
817
+ typedef signed char nk_i8_t;
818
+ /** @brief Unsigned 8-bit integer. Range: [0, 255]. */
819
+ typedef unsigned char nk_u8_t;
820
+ /** @brief Signed 16-bit integer. Range: [−32 768, +32 767]. */
821
+ typedef signed short nk_i16_t;
822
+ /** @brief Unsigned 16-bit integer. Range: [0, 65 535]. */
823
+ typedef unsigned short nk_u16_t;
824
+ /** @brief Signed 32-bit integer. Range: [−2³¹, +2³¹−1]. */
825
+ typedef signed int nk_i32_t;
826
+ /** @brief Unsigned 32-bit integer. Range: [0, 2³²−1]. */
827
+ typedef unsigned int nk_u32_t;
828
+ /* On LP64 targets (Linux ARM64, RISC-V 64), `long` and `long long` are both 64-bit but distinct types.
829
+ * NEON/RVV intrinsics on Linux expect `long*`, while Apple's NEON intrinsics expect `long long*`.
830
+ * Windows uses LLP64 where `long` is 32-bit, so it must use `long long` for 64-bit types. */
831
+ #if ((NK_TARGET_ARM64_ && !defined(NK_DEFINED_APPLE_)) || NK_TARGET_RISCV64_) && !defined(NK_DEFINED_WINDOWS_)
832
+ /** @brief Signed 64-bit integer. Range: [−2⁶³, +2⁶³−1]. */
833
+ typedef signed long nk_i64_t;
834
+ /** @brief Unsigned 64-bit integer. Range: [0, 2⁶⁴−1]. */
835
+ typedef unsigned long nk_u64_t;
836
+ #else
837
+ /** @brief Signed 64-bit integer. Range: [−2⁶³, +2⁶³−1]. */
838
+ typedef signed long long nk_i64_t;
839
+ /** @brief Unsigned 64-bit integer. Range: [0, 2⁶⁴−1]. */
840
+ typedef unsigned long long nk_u64_t;
841
+ #endif
842
+
843
+ /** @brief Single-precision (32-bit) IEEE 754 float. sign(1) + exponent(8) + mantissa(23), bias=127. */
844
+ typedef float nk_f32_t;
845
+ /** @brief Double-precision (64-bit) IEEE 754 float. sign(1) + exponent(11) + mantissa(52), bias=1023. */
846
+ typedef double nk_f64_t;
847
+
848
+ #if NK_TARGET_X8664_ || NK_TARGET_ARM64_ || NK_TARGET_RISCV64_ || NK_TARGET_POWER64_ || NK_TARGET_LOONGARCH64_
849
+ #define NK_IS_64BIT_ 1
850
+ #else
851
+ #define NK_IS_64BIT_ 0
852
+ #endif
853
+
854
+ #if NK_IS_64BIT_
855
+ typedef nk_u64_t nk_size_t;
856
+ typedef nk_i64_t nk_ssize_t;
857
+ #else
858
+ typedef nk_u32_t nk_size_t;
859
+ typedef nk_i32_t nk_ssize_t;
860
+ #endif
861
+ typedef nk_f64_t nk_fmax_t;
862
+
863
+ #define NK_SIZE_MAX ((nk_size_t) - 1)
864
+
865
+ #define NK_F64_MAX 1.7976931348623157e+308
866
+ #define NK_F64_MIN (-1.7976931348623157e+308)
867
+ #define NK_F32_MAX 3.402823466e+38f
868
+ #define NK_F32_MIN (-3.402823466e+38f)
869
+
870
+ #define NK_I64_MAX 9223372036854775807LL
871
+ #define NK_I64_MIN (-9223372036854775807LL - 1LL)
872
+ #define NK_U64_MAX 18446744073709551615ULL
873
+ #define NK_U64_MIN 0x0ULL
874
+
875
+ #define NK_I32_MAX 2147483647
876
+ #define NK_I32_MIN (-2147483647 - 1)
877
+ #define NK_U32_MAX 4294967295U
878
+ #define NK_U32_MIN 0x0U
879
+
880
+ #define NK_I16_MAX 32767
881
+ #define NK_I16_MIN (-32767 - 1)
882
+ #define NK_U16_MAX 65535U
883
+ #define NK_U16_MIN 0x0U
884
+
885
+ #define NK_I8_MAX 127
886
+ #define NK_I8_MIN (-127 - 1)
887
+ #define NK_U8_MAX 255U
888
+ #define NK_U8_MIN 0x0U
889
+
890
+ #define NK_F16_MAX_AS_U16 0x7BFF // IEEE 754 binary16: +65504.0
891
+ #define NK_F16_MIN_AS_U16 0xFBFF // IEEE 754 binary16: -65504.0
892
+
893
+ #define NK_F16_MAX nk_u16_as_f16_(0x7BFF)
894
+ #define NK_F16_MIN nk_u16_as_f16_(0xFBFF)
895
+
896
+ #define NK_BF16_MAX_AS_U16 0x7F7F // BFloat16: ~+3.39e38
897
+ #define NK_BF16_MIN_AS_U16 0xFF7F // BFloat16: ~-3.39e38
898
+
899
+ #define NK_BF16_MAX nk_u16_as_bf16_(0x7F7F)
900
+ #define NK_BF16_MIN nk_u16_as_bf16_(0xFF7F)
901
+
902
+ #define NK_E4M3_MAX 0x7E // FP8 E4M3: +448.0
903
+ #define NK_E4M3_MIN 0xFE // FP8 E4M3: -448.0
904
+
905
+ #define NK_E5M2_MAX 0x7B // FP8 E5M2: +57344.0
906
+ #define NK_E5M2_MIN 0xFB // FP8 E5M2: -57344.0
907
+
908
+ #define NK_E2M3_MAX 0x1F // FP6 E2M3: +7.5
909
+ #define NK_E2M3_MIN 0x3F // FP6 E2M3: -7.5
910
+
911
+ #define NK_E3M2_MAX 0x1F // FP6 E3M2: +28.0
912
+ #define NK_E3M2_MIN 0x3F // FP6 E3M2: -28.0
913
+
914
+ #define NK_BITS_PER_BYTE 8
915
+
916
+ /**
917
+ * @brief Enumeration of supported scalar data types.
918
+ *
919
+ * Includes complex type descriptors which in C code would use the real counterparts,
920
+ * but the independent flags contain metadata to be passed between programming language
921
+ * interfaces.
922
+ */
923
+ typedef enum {
924
+ nk_dtype_unknown_k = 0, ///< Unknown data type
925
+ nk_u1_k = 1 << 1, ///< Single-bit values packed into 8-bit words
926
+
927
+ nk_i8_k = 1 << 2, ///< 8-bit signed integer
928
+ nk_i16_k = 1 << 3, ///< 16-bit signed integer
929
+ nk_i32_k = 1 << 4, ///< 32-bit signed integer
930
+ nk_i64_k = 1 << 5, ///< 64-bit signed integer
931
+
932
+ nk_u8_k = 1 << 6, ///< 8-bit unsigned integer
933
+ nk_u16_k = 1 << 7, ///< 16-bit unsigned integer
934
+ nk_u32_k = 1 << 8, ///< 32-bit unsigned integer
935
+ nk_u64_k = 1 << 9, ///< 64-bit unsigned integer
936
+
937
+ nk_f64_k = 1 << 10, ///< Double precision floating point
938
+ nk_f32_k = 1 << 11, ///< Single precision floating point
939
+ nk_f16_k = 1 << 12, ///< Half precision floating point
940
+ nk_bf16_k = 1 << 13, ///< Brain floating point
941
+
942
+ nk_e4m3_k = 1 << 14, ///< FP8 E4M3 floating point
943
+ nk_e5m2_k = 1 << 15, ///< FP8 E5M2 floating point
944
+ nk_i4_k = 1 << 16, ///< 4-bit signed integers packed into 8-bit words
945
+ nk_u4_k = 1 << 17, ///< 4-bit unsigned integers packed into 8-bit words
946
+ nk_e2m3_k = 1 << 18, ///< FP6 E2M3 floating point
947
+ nk_e3m2_k = 1 << 19, ///< FP6 E3M2 floating point
948
+
949
+ nk_f64c_k = 1 << 20, ///< Complex double precision floating point
950
+ nk_f32c_k = 1 << 21, ///< Complex single precision floating point
951
+ nk_f16c_k = 1 << 22, ///< Complex half precision floating point
952
+ nk_bf16c_k = 1 << 23, ///< Complex brain floating point
953
+ } nk_dtype_t;
954
+
955
+ typedef enum {
956
+ nk_dtype_family_unknown_k = 0,
957
+ nk_dtype_family_float_k,
958
+ nk_dtype_family_complex_float_k,
959
+ nk_dtype_family_int_k,
960
+ nk_dtype_family_uint_k,
961
+ } nk_dtype_family_t;
962
+
963
+ /** @brief Classifies the family of the dtype. */
964
+ NK_PUBLIC nk_dtype_family_t nk_dtype_family(nk_dtype_t dtype) {
965
+ switch (dtype) {
966
+ case nk_f64_k: return nk_dtype_family_float_k;
967
+ case nk_f32_k: return nk_dtype_family_float_k;
968
+ case nk_f16_k: return nk_dtype_family_float_k;
969
+ case nk_bf16_k: return nk_dtype_family_float_k;
970
+ case nk_e4m3_k: return nk_dtype_family_float_k;
971
+ case nk_e5m2_k: return nk_dtype_family_float_k;
972
+ case nk_e2m3_k: return nk_dtype_family_float_k;
973
+ case nk_e3m2_k: return nk_dtype_family_float_k;
974
+ case nk_f64c_k: return nk_dtype_family_complex_float_k;
975
+ case nk_f32c_k: return nk_dtype_family_complex_float_k;
976
+ case nk_f16c_k: return nk_dtype_family_complex_float_k;
977
+ case nk_bf16c_k: return nk_dtype_family_complex_float_k;
978
+ case nk_u1_k: return nk_dtype_family_uint_k;
979
+ case nk_u4_k: return nk_dtype_family_uint_k;
980
+ case nk_u8_k: return nk_dtype_family_uint_k;
981
+ case nk_u16_k: return nk_dtype_family_uint_k;
982
+ case nk_u32_k: return nk_dtype_family_uint_k;
983
+ case nk_u64_k: return nk_dtype_family_uint_k;
984
+ case nk_i4_k: return nk_dtype_family_int_k;
985
+ case nk_i8_k: return nk_dtype_family_int_k;
986
+ case nk_i16_k: return nk_dtype_family_int_k;
987
+ case nk_i32_k: return nk_dtype_family_int_k;
988
+ case nk_i64_k: return nk_dtype_family_int_k;
989
+ default: return nk_dtype_family_unknown_k;
990
+ }
991
+ }
992
+
993
+ /** @brief Returns the number of bits in a single scalar of a given type. */
994
+ NK_PUBLIC nk_size_t nk_dtype_bits(nk_dtype_t dtype) {
995
+ switch (dtype) {
996
+ case nk_f64_k: return 64;
997
+ case nk_f32_k: return 32;
998
+ case nk_f16_k: return 16;
999
+ case nk_bf16_k: return 16;
1000
+ case nk_e4m3_k: return 8;
1001
+ case nk_e5m2_k: return 8;
1002
+ case nk_e2m3_k: return 8;
1003
+ case nk_e3m2_k: return 8;
1004
+ case nk_f64c_k: return 128;
1005
+ case nk_f32c_k: return 64;
1006
+ case nk_f16c_k: return 32;
1007
+ case nk_bf16c_k: return 32;
1008
+ case nk_u1_k: return 1;
1009
+ case nk_u4_k: return 4;
1010
+ case nk_u8_k: return 8;
1011
+ case nk_u16_k: return 16;
1012
+ case nk_u32_k: return 32;
1013
+ case nk_u64_k: return 64;
1014
+ case nk_i4_k: return 4;
1015
+ case nk_i8_k: return 8;
1016
+ case nk_i16_k: return 16;
1017
+ case nk_i32_k: return 32;
1018
+ case nk_i64_k: return 64;
1019
+ default: return 0;
1020
+ }
1021
+ }
1022
+
1023
+ /** @brief Returns how many logical dimensions are packed into one storage value.
1024
+ * For sub-byte types multiple dimensions share a single byte container.
1025
+ * For byte-or-larger types this is always 1. */
1026
+ NK_PUBLIC nk_size_t nk_dimensions_per_value(nk_dtype_t dtype) {
1027
+ switch (dtype) {
1028
+ case nk_u1_k: return 8;
1029
+ case nk_i4_k: return 2;
1030
+ case nk_u4_k: return 2;
1031
+ default: return 1;
1032
+ }
1033
+ }
1034
+
1035
+ /** @brief Half-precision (16-bit) IEEE 754 float.
1036
+ *
1037
+ * Layout: sign(1) + exponent(5) + mantissa(10), bias=15.
1038
+ * Range: ±65 504, epsilon at 1.0 ≈ 9.77×10⁻⁴. 30 722 of 63 488 finite values (48.4%) in [−1, +1].
1039
+ *
1040
+ * - GCC or Clang on 64-bit Arm: `__fp16`, may require `-mfp16-format` option.
1041
+ * - GCC or Clang on 64-bit x86: `_Float16`.
1042
+ * - Default: `unsigned short`.
1043
+ */
1044
+ #if !defined(NK_NATIVE_F16) || NK_NATIVE_F16
1045
+ #if (defined(__GNUC__) || defined(__clang__)) && (defined(__ARM_ARCH) || defined(__aarch64__)) && \
1046
+ (defined(__ARM_FP16_FORMAT_IEEE))
1047
+ #undef NK_NATIVE_F16
1048
+ #define NK_NATIVE_F16 1
1049
+ typedef __fp16 nk_f16_t;
1050
+ #elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__i386__)) && \
1051
+ (defined(__AVX512FP16__)))
1052
+ typedef _Float16 nk_f16_t;
1053
+ #undef NK_NATIVE_F16
1054
+ #define NK_NATIVE_F16 1
1055
+ #else // Unknown compiler or architecture
1056
+ #undef NK_NATIVE_F16
1057
+ #define NK_NATIVE_F16 0
1058
+ #endif // Unknown compiler or architecture
1059
+ #endif // !NK_NATIVE_F16
1060
+
1061
+ #if !NK_NATIVE_F16
1062
+ typedef unsigned short nk_f16_t;
1063
+ #endif
1064
+
1065
+ #if !defined(NK_NATIVE_BF16) || NK_NATIVE_BF16
1066
+ /** @brief BFloat16 (16-bit) float — truncated IEEE 754 single-precision.
1067
+ *
1068
+ * Layout: sign(1) + exponent(8) + mantissa(7), bias=127.
1069
+ * Same dynamic range as f32, epsilon ≈ 7.81×10⁻³.
1070
+ * 32 514 of 65 280 finite values (49.8%) in [−1, +1]. Wider range than f16 but lower precision.
1071
+ *
1072
+ * - GCC or Clang: `__bf16`
1073
+ * - Default: `unsigned short`.
1074
+ *
1075
+ * The compilers have added `__bf16` support in compliance with the x86-64 psABI spec.
1076
+ * The motivation for this new special type is summed up as:
1077
+ *
1078
+ * Currently `__bfloat16` is a typedef of short, which creates a problem where the
1079
+ * compiler does not raise any alarms if it is used to add, subtract, multiply or
1080
+ * divide, but the result of the calculation is actually meaningless.
1081
+ * To solve this problem, a real scalar type `__Bfloat16` needs to be introduced.
1082
+ * It is mainly used for intrinsics, not available for C standard operators.
1083
+ * `__Bfloat16` will also be used for movement like passing parameter, load and store,
1084
+ * vector initialization, vector shuffle, and etc. It creates a need for a
1085
+ * corresponding psABI.
1086
+ *
1087
+ * @warning Apple Clang has hard time with bf16.
1088
+ * https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms
1089
+ * https://forums.developer.apple.com/forums/thread/726201
1090
+ * https://www.phoronix.com/news/GCC-LLVM-bf16-BFloat16-Type
1091
+ */
1092
+ #if (defined(__GNUC__) || defined(__clang__)) && ((defined(__ARM_BF16_FORMAT_ALTERNATIVE)) || (defined(__AVX512BF16__)))
1093
+ #undef NK_NATIVE_BF16
1094
+ #define NK_NATIVE_BF16 1
1095
+ typedef __bf16 nk_bf16_t;
1096
+ #else // Unknown compiler or architecture
1097
+ #undef NK_NATIVE_BF16
1098
+ #define NK_NATIVE_BF16 0
1099
+ #endif // Unknown compiler or architecture
1100
+ #endif // !NK_NATIVE_BF16
1101
+
1102
+ #if !NK_NATIVE_BF16
1103
+ typedef unsigned short nk_bf16_t;
1104
+ #endif
1105
+
1106
+ /**
1107
+ * @brief Alias for the half-precision floating-point type on Arm.
1108
+ *
1109
+ * Clang and GCC bring the `float16_t` symbol when you compile for Aarch64.
1110
+ * MSVC lacks it, and it's `vld1_f16`-like intrinsics are in reality macros,
1111
+ * that cast to 16-bit integers internally, instead of using floats.
1112
+ * Some of those are defined as aliases, so we use `#define` preprocessor
1113
+ * directives instead of `typedef` to avoid errors.
1114
+ */
1115
+ #if NK_TARGET_ARM64_
1116
+ #if defined(_MSC_VER)
1117
+ #define nk_f16_for_arm_simd_t nk_f16_t
1118
+ #define nk_bf16_for_arm_simd_t nk_bf16_t
1119
+ #else
1120
+ #define nk_f16_for_arm_simd_t float16_t
1121
+ #define nk_bf16_for_arm_simd_t bfloat16_t
1122
+ #endif
1123
+ #endif
1124
+
1125
+ /**
1126
+ * RISC-V Vector (RVV) intrinsics use `_Float16` for half-precision floats.
1127
+ * This is the standard C23 type, also available in GCC/Clang with RVV extensions.
1128
+ */
1129
+ #if NK_TARGET_RISCV64_
1130
+ #define nk_f16_for_rvv_intrinsics_t _Float16
1131
+ #endif
1132
+
1133
+ /*
1134
+ * Let's make sure the sizes of the types are as expected.
1135
+ * In C the `_Static_assert` is only available with C11 and later.
1136
+ */
1137
+ #define NK_STATIC_ASSERT(cond, msg) typedef char static_assertion_##msg[(cond) ? 1 : -1]
1138
+ NK_STATIC_ASSERT(sizeof(nk_u1x8_t) == 1, nk_u1x8_t_must_be_1_byte);
1139
+ NK_STATIC_ASSERT(sizeof(nk_i4x2_t) == 1, nk_i4_t_must_be_1_byte);
1140
+ NK_STATIC_ASSERT(sizeof(nk_u4x2_t) == 1, nk_u4_t_must_be_1_byte);
1141
+ NK_STATIC_ASSERT(sizeof(nk_e4m3_t) == 1, nk_e4m3_t_must_be_1_byte);
1142
+ NK_STATIC_ASSERT(sizeof(nk_e5m2_t) == 1, nk_e5m2_t_must_be_1_byte);
1143
+ NK_STATIC_ASSERT(sizeof(nk_i8_t) == 1, nk_i8_t_must_be_1_byte);
1144
+ NK_STATIC_ASSERT(sizeof(nk_u8_t) == 1, nk_u8_t_must_be_1_byte);
1145
+ NK_STATIC_ASSERT(sizeof(nk_i16_t) == 2, nk_i16_t_must_be_2_bytes);
1146
+ NK_STATIC_ASSERT(sizeof(nk_u16_t) == 2, nk_u16_t_must_be_2_bytes);
1147
+ NK_STATIC_ASSERT(sizeof(nk_i32_t) == 4, nk_i32_t_must_be_4_bytes);
1148
+ NK_STATIC_ASSERT(sizeof(nk_u32_t) == 4, nk_u32_t_must_be_4_bytes);
1149
+ NK_STATIC_ASSERT(sizeof(nk_i64_t) == 8, nk_i64_t_must_be_8_bytes);
1150
+ NK_STATIC_ASSERT(sizeof(nk_u64_t) == 8, nk_u64_t_must_be_8_bytes);
1151
+ NK_STATIC_ASSERT(sizeof(nk_f32_t) == 4, nk_f32_t_must_be_4_bytes);
1152
+ NK_STATIC_ASSERT(sizeof(nk_f64_t) == 8, nk_f64_t_must_be_8_bytes);
1153
+ NK_STATIC_ASSERT(sizeof(nk_f16_t) == 2, nk_f16_t_must_be_2_bytes);
1154
+ NK_STATIC_ASSERT(sizeof(nk_bf16_t) == 2, nk_bf16_t_must_be_2_bytes);
1155
+
1156
+ #define nk_assign_from_to_(src, dest) (*(dest) = *(src))
1157
+
1158
+ /** @brief 16-bit union for f16/bf16/u16/i16 bit manipulation. */
1159
+ typedef union NK_MAY_ALIAS_ {
1160
+ nk_u16_t u;
1161
+ nk_i16_t i;
1162
+ nk_f16_t f;
1163
+ nk_bf16_t bf;
1164
+ } nk_fui16_t;
1165
+
1166
+ /** @brief 32-bit union for f32/u32/i32 bit manipulation. */
1167
+ typedef union NK_MAY_ALIAS_ {
1168
+ nk_u32_t u;
1169
+ nk_i32_t i;
1170
+ nk_f32_t f;
1171
+ } nk_fui32_t;
1172
+
1173
+ /** @brief 64-bit union for f64/u64/i64 bit manipulation. */
1174
+ typedef union NK_MAY_ALIAS_ {
1175
+ nk_u64_t u;
1176
+ nk_i64_t i;
1177
+ nk_f64_t f;
1178
+ } nk_fui64_t;
1179
+
1180
+ /** @brief Half-precision (32-bit) complex number — {real: f16, imag: f16}. Kernel outputs widened to f32c. */
1181
+ typedef struct {
1182
+ nk_f16_t real;
1183
+ nk_f16_t imag;
1184
+ } nk_f16c_t;
1185
+
1186
+ /** @brief BFloat16 (32-bit) complex number — {real: bf16, imag: bf16}. Kernel outputs widened to f32c. */
1187
+ typedef struct {
1188
+ nk_bf16_t real;
1189
+ nk_bf16_t imag;
1190
+ } nk_bf16c_t;
1191
+
1192
+ /** @brief Single-precision (64-bit) complex number — {real: f32, imag: f32}. */
1193
+ typedef struct {
1194
+ nk_f32_t real;
1195
+ nk_f32_t imag;
1196
+ } nk_f32c_t;
1197
+
1198
+ /** @brief Double-precision (128-bit) complex number — {real: f64, imag: f64}. */
1199
+ typedef struct {
1200
+ nk_f64_t real;
1201
+ nk_f64_t imag;
1202
+ } nk_f64c_t;
1203
+
1204
+ /** @brief Small 4-byte memory slice viewable as different types. */
1205
+ typedef union NK_MAY_ALIAS_ nk_b32_vec_t {
1206
+ nk_u32_t u32;
1207
+ nk_i32_t i32;
1208
+ nk_f32_t f32;
1209
+ nk_u8_t u8s[4];
1210
+ nk_i8_t i8s[4];
1211
+ nk_u16_t u16s[2];
1212
+ nk_i16_t i16s[2];
1213
+ nk_e4m3_t e4m3s[4];
1214
+ nk_e5m2_t e5m2s[4];
1215
+ } nk_b32_vec_t;
1216
+
1217
+ /** @brief Small 8-byte memory slice viewable as different types. */
1218
+ typedef union NK_MAY_ALIAS_ nk_b64_vec_t {
1219
+ #if NK_TARGET_NEON
1220
+ uint8x8_t u8x8;
1221
+ uint16x4_t u16x4;
1222
+ uint32x2_t u32x2;
1223
+ int8x8_t i8x8;
1224
+ int16x4_t i16x4;
1225
+ int32x2_t i32x2;
1226
+ float32x2_t f32x2;
1227
+ #endif
1228
+ #if NK_TARGET_NEONHALF
1229
+ float16x4_t f16x4;
1230
+ #endif
1231
+ nk_u8_t u8s[8];
1232
+ nk_u16_t u16s[4];
1233
+ nk_u32_t u32s[2];
1234
+ nk_u64_t u64;
1235
+ nk_i8_t i8s[8];
1236
+ nk_i16_t i16s[4];
1237
+ nk_i32_t i32s[2];
1238
+ nk_i64_t i64;
1239
+ nk_f16_t f16s[4];
1240
+ nk_bf16_t bf16s[4];
1241
+ nk_f32_t f32s[2];
1242
+ } nk_b64_vec_t;
1243
+
1244
+ /** @brief Small 16-byte memory slice viewable as different types. */
1245
+ typedef union NK_MAY_ALIAS_ nk_b128_vec_t {
1246
+ #if NK_TARGET_HASWELL || NK_TARGET_LOONGSONASX
1247
+ __m128i xmm;
1248
+ __m128d xmm_pd;
1249
+ __m128 xmm_ps;
1250
+ #endif
1251
+ #if NK_TARGET_V128RELAXED
1252
+ v128_t v128;
1253
+ #endif
1254
+ #if NK_TARGET_NEON
1255
+ uint8x16_t u8x16;
1256
+ uint16x8_t u16x8;
1257
+ uint32x4_t u32x4;
1258
+ uint64x2_t u64x2;
1259
+ int8x16_t i8x16;
1260
+ int16x8_t i16x8;
1261
+ int32x4_t i32x4;
1262
+ int64x2_t i64x2;
1263
+ float32x4_t f32x4;
1264
+ #endif
1265
+ #if NK_TARGET_NEON && NK_TARGET_ARM64_ // double-precision NEON requires AArch64
1266
+ float64x2_t f64x2;
1267
+ #endif
1268
+ #if NK_TARGET_NEONHALF
1269
+ float16x8_t f16x8;
1270
+ #endif
1271
+ #if NK_TARGET_POWERVSX
1272
+ nk_vu8x16_t vu8x16;
1273
+ nk_vu16x8_t vu16x8;
1274
+ nk_vu32x4_t vu32x4;
1275
+ nk_vu64x2_t vu64x2;
1276
+ nk_vi8x16_t vi8x16;
1277
+ nk_vi16x8_t vi16x8;
1278
+ nk_vi32x4_t vi32x4;
1279
+ nk_vi64x2_t vi64x2;
1280
+ nk_vf32x4_t vf32x4;
1281
+ nk_vf64x2_t vf64x2;
1282
+ #endif
1283
+
1284
+ nk_u8_t u8s[16];
1285
+ nk_u16_t u16s[8];
1286
+ nk_u32_t u32s[4];
1287
+ nk_u64_t u64s[2];
1288
+ nk_i8_t i8s[16];
1289
+ nk_i16_t i16s[8];
1290
+ nk_i32_t i32s[4];
1291
+ nk_i64_t i64s[2];
1292
+ nk_f16_t f16s[8];
1293
+ nk_bf16_t bf16s[8];
1294
+ nk_e4m3_t e4m3s[16];
1295
+ nk_e5m2_t e5m2s[16];
1296
+ nk_e2m3_t e2m3s[16];
1297
+ nk_e3m2_t e3m2s[16];
1298
+ nk_f32_t f32s[4];
1299
+ nk_f64_t f64s[2];
1300
+ } nk_b128_vec_t;
1301
+
1302
+ /** @brief Small 32-byte memory slice viewable as different types. */
1303
+ typedef union NK_MAY_ALIAS_ nk_b256_vec_t {
1304
+ #if NK_TARGET_HASWELL || NK_TARGET_LOONGSONASX
1305
+ __m256i ymm;
1306
+ __m256d ymm_pd;
1307
+ __m256 ymm_ps;
1308
+ __m128i xmms[2];
1309
+ #endif
1310
+ #if NK_TARGET_V128RELAXED
1311
+ v128_t v128s[2];
1312
+ #endif
1313
+ #if NK_TARGET_NEON
1314
+ uint8x16_t u8x16s[2];
1315
+ uint16x8_t u16x8s[2];
1316
+ uint32x4_t u32x4s[2];
1317
+ uint64x2_t u64x2s[2];
1318
+ int8x16_t i8x16s[2];
1319
+ int16x8_t i16x8s[2];
1320
+ int32x4_t i32x4s[2];
1321
+ int64x2_t i64x2s[2];
1322
+ float32x4_t f32x4s[2];
1323
+ #endif
1324
+ #if NK_TARGET_NEON && NK_TARGET_ARM64_ // double-precision NEON requires AArch64
1325
+ float64x2_t f64x2s[2];
1326
+ #endif
1327
+ #if NK_TARGET_POWERVSX
1328
+ nk_vu8x16_t vu8x16s[2];
1329
+ nk_vu16x8_t vu16x8s[2];
1330
+ nk_vu32x4_t vu32x4s[2];
1331
+ nk_vu64x2_t vu64x2s[2];
1332
+ nk_vi8x16_t vi8x16s[2];
1333
+ nk_vi16x8_t vi16x8s[2];
1334
+ nk_vi32x4_t vi32x4s[2];
1335
+ nk_vi64x2_t vi64x2s[2];
1336
+ nk_vf32x4_t vf32x4s[2];
1337
+ nk_vf64x2_t vf64x2s[2];
1338
+ #endif
1339
+
1340
+ nk_u8_t u8s[32];
1341
+ nk_u16_t u16s[16];
1342
+ nk_u32_t u32s[8];
1343
+ nk_u64_t u64s[4];
1344
+ nk_i8_t i8s[32];
1345
+ nk_i16_t i16s[16];
1346
+ nk_i32_t i32s[8];
1347
+ nk_i64_t i64s[4];
1348
+ nk_f16_t f16s[16];
1349
+ nk_bf16_t bf16s[16];
1350
+ nk_e4m3_t e4m3s[32];
1351
+ nk_e5m2_t e5m2s[32];
1352
+ nk_e2m3_t e2m3s[32];
1353
+ nk_e3m2_t e3m2s[32];
1354
+ nk_f32_t f32s[8];
1355
+ nk_f64_t f64s[4];
1356
+ } nk_b256_vec_t;
1357
+
1358
+ /** @brief Small 64-byte memory slice viewable as different types.
1359
+ *
1360
+ * TODO: On GCC and Clang we use `__transparent_union__` attribute to allow implicit conversions
1361
+ * between the different vector types when passing them as function arguments. The most important side-effect
1362
+ * of this is that the argument of such type is passed to functions using the calling convention of the first
1363
+ * member of the union, which in our case is a register-based calling convention for SIMD types.
1364
+ */
1365
+ typedef union NK_MAY_ALIAS_ nk_b512_vec_t {
1366
+ #if NK_TARGET_SKYLAKE
1367
+ __m512i zmm;
1368
+ __m512d zmm_pd;
1369
+ __m512 zmm_ps;
1370
+ #endif
1371
+ #if NK_TARGET_HASWELL
1372
+ __m256i ymms[2];
1373
+ __m256d ymms_pd[2];
1374
+ __m256 ymms_ps[2];
1375
+ __m128i xmms[4];
1376
+ __m128d xmms_pd[4];
1377
+ __m128 xmms_ps[4];
1378
+ #endif
1379
+ #if NK_TARGET_NEON
1380
+ uint8x16_t u8x16s[4];
1381
+ uint16x8_t u16x8s[4];
1382
+ uint32x4_t u32x4s[4];
1383
+ uint64x2_t u64x2s[4];
1384
+ #endif
1385
+ nk_u8_t u8s[64];
1386
+ nk_u16_t u16s[32];
1387
+ nk_u32_t u32s[16];
1388
+ nk_u64_t u64s[8];
1389
+ nk_i8_t i8s[64];
1390
+ nk_i16_t i16s[32];
1391
+ nk_i32_t i32s[16];
1392
+ nk_i64_t i64s[8];
1393
+ nk_f16_t f16s[32];
1394
+ nk_bf16_t bf16s[32];
1395
+ nk_f32_t f32s[16];
1396
+ nk_f64_t f64s[8];
1397
+ nk_e4m3_t e4m3s[64];
1398
+ nk_e5m2_t e5m2s[64];
1399
+ nk_e2m3_t e2m3s[64];
1400
+ nk_e3m2_t e3m2s[64];
1401
+ } nk_b512_vec_t;
1402
+
1403
+ /**
1404
+ * @brief Advances the Multi-Dimensional iterator to the next set of indicies.
1405
+ * @param[in] extents The extents of the tensor, defined by an array of at least `rank` scalars.
1406
+ * @param[in] strides The @b signed strides of the tensor in bytes, defined by an array of at least `rank` scalars.
1407
+ * @param[in] rank The number of dimensions in the tensor (its rank).
1408
+ * @param[inout] coordinates The array of offsets along each of `rank` dimensions, which will be updated.
1409
+ * @param[inout] byte_offset The @b signed byte offset of the current element, which will be advanced.
1410
+ * @return 1 if the iterator was successfully advanced, 0 if the end of iteration was reached.
1411
+ *
1412
+ * For flexibility, the API is decoupled from from the `nk_tensor_position_t` structure, and
1413
+ * can be used on any-rank tensors, independent of the `NK_TENSOR_MAX_RANK` constant.
1414
+ */
1415
+ NK_PUBLIC int nk_tensor_position_next( //
1416
+ nk_size_t const *extents, nk_ssize_t const *strides, nk_size_t rank, //
1417
+ nk_size_t *coordinates, nk_ssize_t *byte_offset) {
1418
+ // Start from last dimension and move backward
1419
+ for (nk_size_t i = rank; i-- > 0;) {
1420
+ coordinates[i]++;
1421
+ *byte_offset += strides[i];
1422
+ if (coordinates[i] < extents[i]) return 1; // Successfully moved to the next index
1423
+ coordinates[i] = 0; // Reset this dimension counter
1424
+ *byte_offset -= strides[i] * extents[i]; // Discard the running progress along this dimension
1425
+ }
1426
+ // If we reach here, we've iterated over all elements
1427
+ return 0; // End of iteration
1428
+ }
1429
+
1430
+ /**
1431
+ * @brief Advances the Multi-Dimensional iterator to the provided coordinates, updating the byte offset.
1432
+ * @param[in] extents The extents of the tensor, defined by an array of at least `rank` scalars.
1433
+ * @param[in] strides The @b signed strides of the tensor in bytes, defined by an array of at least `rank` scalars.
1434
+ * @param[in] rank The number of dimensions in the tensor (its rank).
1435
+ * @param[in] coordinates The array of offsets along each of `rank` dimensions, which will be updated.
1436
+ * @param[out] byte_offset The byte offset of the current element, which will be advanced.
1437
+ * @return 1 if the offset was successfully advanced, 0 if the end of iteration was reached.
1438
+ */
1439
+ NK_PUBLIC int nk_tensor_position_linearize( //
1440
+ nk_size_t const *extents, nk_ssize_t const *strides, nk_size_t rank, //
1441
+ nk_size_t const *coordinates, nk_ssize_t *byte_offset) {
1442
+
1443
+ nk_ssize_t result = 0;
1444
+ for (nk_size_t i = 0; i < rank; i++) {
1445
+ // Ensure the coordinates is within bounds for the given dimension
1446
+ if (coordinates[i] >= extents[i]) return 0; // Invalid coordinates, out of bounds
1447
+ // Update the byte offset by multiplying the coordinates by the stride
1448
+ result += coordinates[i] * strides[i];
1449
+ }
1450
+ *byte_offset = result;
1451
+ return 1; // Successfully calculated global and byte offsets
1452
+ }
1453
+
1454
+ /**
1455
+ * @brief A @b beefy structure to iterate through Multi-Dimensional arrays.
1456
+ * Occupies 512 + 8 = 520 bytes on a 64-bit machine, or @b 9 cache-lines, by default.
1457
+ *
1458
+ * When advancing through a structure, its overall size and strides should be stored somewhere else.
1459
+ * The `byte_offset` starts at zero and grow monotonically during iteration, if the strides are positive.
1460
+ */
1461
+ typedef struct nk_tensor_position_t {
1462
+ nk_size_t coordinates[NK_TENSOR_MAX_RANK]; // Coordinate offsets along each dimension
1463
+ nk_ssize_t byte_offset; // Byte offset of the current element
1464
+ } nk_tensor_position_t;
1465
+
1466
+ NK_PUBLIC void nk_tensor_position_init(nk_tensor_position_t *tensor_position) {
1467
+ for (nk_size_t i = 0; i < NK_TENSOR_MAX_RANK; i++) tensor_position->coordinates[i] = 0;
1468
+ tensor_position->byte_offset = 0;
1469
+ }
1470
+
1471
+ /**
1472
+ * @brief A @b beefy structure describing the shape and memory layout of a Multi-Dimensional array.
1473
+ * Similar to `md::span` in C++20 and `numpy.ndarray` in Python, but with a focus on compatibility.
1474
+ * Occupies 512 + 512 + 8 = 2052 bytes on a 64-bit machine, or @b 17 cache-lines, by default.
1475
+ *
1476
+ * Unlike NumPy and the CPython "Buffer Protocol", we don't use `suboffsets` for pointer indirection.
1477
+ * The logic is that such layouts aren't friendly to conventional SIMD operations and dense matrix algorithms.
1478
+ * If the tensor is sparse, consider using a different data structure or a different memory layout.
1479
+ *
1480
+ * Most NumKong algorithms don't work with the entire structure, but expect the fields to be passed separately.
1481
+ * It would also require storing the @b start-pointer and the @b dtype/item-size separately, as it's not
1482
+ * stored inside the structure.
1483
+ */
1484
+ typedef struct nk_tensor_shape_t {
1485
+ nk_size_t extents[NK_TENSOR_MAX_RANK]; /// Number of elements along each dimension
1486
+ nk_ssize_t strides[NK_TENSOR_MAX_RANK]; /// Strides of the tensor in bytes
1487
+ nk_size_t rank; /// Number of dimensions in the tensor
1488
+ } nk_tensor_shape_t;
1489
+
1490
+ NK_PUBLIC void nk_tensor_shape_init(nk_tensor_shape_t *tensor_shape) {
1491
+ for (nk_size_t i = 0; i < NK_TENSOR_MAX_RANK; i++) tensor_shape->extents[i] = 0, tensor_shape->strides[i] = 0;
1492
+ tensor_shape->rank = 0;
1493
+ }
1494
+
1495
+ NK_INTERNAL nk_u32_t nk_u32_rol(nk_u32_t x, int n) { return (x << n) | (x >> (32 - n)); }
1496
+ NK_INTERNAL nk_u16_t nk_u16_rol(nk_u16_t x, int n) { return (x << n) | (x >> (16 - n)); }
1497
+ NK_INTERNAL nk_u8_t nk_u8_rol(nk_u8_t x, int n) { return (x << n) | (x >> (8 - n)); }
1498
+ NK_INTERNAL nk_u32_t nk_u32_ror(nk_u32_t x, int n) { return (x >> n) | (x << (32 - n)); }
1499
+ NK_INTERNAL nk_u16_t nk_u16_ror(nk_u16_t x, int n) { return (x >> n) | (x << (16 - n)); }
1500
+ NK_INTERNAL nk_u8_t nk_u8_ror(nk_u8_t x, int n) { return (x >> n) | (x << (8 - n)); }
1501
+
1502
+ /**
1503
+ * @brief SWAR population count for 64-bit integers.
1504
+ *
1505
+ * Classic algorithm from Hacker's Delight using parallel bit summation:
1506
+ * - Step 1: Count bits in pairs (2-bit sums)
1507
+ * - Step 2: Count bits in nibbles (4-bit sums)
1508
+ * - Step 3: Count bits in bytes (8-bit sums)
1509
+ * - Step 4: Horizontal sum via multiply - each byte contributes to bits 56-63
1510
+ *
1511
+ * Cost: ~12 ALU ops, zero memory access (vs 8 table lookups for byte-wise).
1512
+ */
1513
+ NK_INTERNAL nk_u64_t nk_u64_popcount_(nk_u64_t x) {
1514
+ x = x - ((x >> 1) & 0x5555555555555555ull);
1515
+ x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull);
1516
+ x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0Full;
1517
+ return (x * 0x0101010101010101ull) >> 56;
1518
+ }
1519
+
1520
+ NK_INTERNAL unsigned char nk_u1x8_popcount_(nk_u1x8_t x) {
1521
+ static unsigned char lookup_table[256] = {
1522
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, //
1523
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1524
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1525
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1526
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1527
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1528
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1529
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
1530
+ return lookup_table[x];
1531
+ }
1532
+
1533
+ /** @brief Divides the number rounding up to the next multiple of the given divisor. */
1534
+ NK_PUBLIC nk_size_t nk_size_divide_round_up_(nk_size_t number, nk_size_t divisor) NK_STREAMING_COMPATIBLE_ {
1535
+ return (number + divisor - 1) / divisor;
1536
+ }
1537
+
1538
+ /** @brief Rounds up the number to the next multiple of the given divisor. */
1539
+ NK_PUBLIC nk_size_t nk_size_round_up_to_multiple_(nk_size_t number, nk_size_t divisor) NK_STREAMING_COMPATIBLE_ {
1540
+ return nk_size_divide_round_up_(number, divisor) * divisor;
1541
+ }
1542
+
1543
+ NK_INTERNAL nk_f32_t nk_f32_abs_(nk_f32_t x) { return x < 0 ? -x : x; }
1544
+ NK_INTERNAL nk_f64_t nk_f64_abs_(nk_f64_t x) { return x < 0 ? -x : x; }
1545
+ NK_INTERNAL nk_i64_t nk_i64_abs_(nk_i64_t x) { return x < 0 ? -x : x; }
1546
+ NK_INTERNAL nk_u64_t nk_u64_abs_(nk_u64_t x) { return x; }
1547
+ NK_INTERNAL nk_i64_t nk_i32_abs_(nk_i32_t x) { return x < 0 ? -x : x; }
1548
+ NK_INTERNAL nk_u32_t nk_u32_abs_(nk_u32_t x) { return x; }
1549
+
1550
+ /** @brief Extract low (bits 0-3) unsigned nibble from packed u4x2 byte. */
1551
+ NK_INTERNAL nk_u8_t nk_u4x2_low_(nk_u4x2_t byte_val) { return byte_val & 0x0F; }
1552
+ /** @brief Extract high (bits 4-7) unsigned nibble from packed u4x2 byte. */
1553
+ NK_INTERNAL nk_u8_t nk_u4x2_high_(nk_u4x2_t byte_val) { return (byte_val >> 4) & 0x0F; }
1554
+
1555
+ /** @brief Extract low (bits 0-3) signed nibble from packed i4x2 byte as i8. */
1556
+ NK_INTERNAL nk_i8_t nk_i4x2_low_(nk_i4x2_t byte_val) { return (nk_i8_t)(((byte_val & 0x0F) ^ 8) - 8); }
1557
+ /** @brief Extract high (bits 4-7) signed nibble from packed i4x2 byte as i8. */
1558
+ NK_INTERNAL nk_i8_t nk_i4x2_high_(nk_i4x2_t byte_val) { return (nk_i8_t)((((byte_val >> 4) & 0x0F) ^ 8) - 8); }
1559
+
1560
+ /** @brief Extract n-th nibble (n=0: low, n=1: high) — branchless. */
1561
+ NK_INTERNAL nk_u8_t nk_u4x2_get_(nk_u4x2_t byte_val, int n) { return (byte_val >> ((n & 1) * 4)) & 0x0F; }
1562
+ NK_INTERNAL nk_i8_t nk_i4x2_get_(nk_i4x2_t byte_val, int n) {
1563
+ nk_u8_t nibble = (byte_val >> ((n & 1) * 4)) & 0x0F;
1564
+ return (nk_i8_t)((nibble ^ 8) - 8);
1565
+ }
1566
+
1567
+ /** @brief Extract bit at position n (0-7) from packed u1x8 byte. */
1568
+ NK_INTERNAL nk_u8_t nk_u1x8_get_(nk_u1x8_t byte_val, int n) { return (byte_val >> (n & 7)) & 1; }
1569
+
1570
+ NK_INTERNAL nk_f16_t nk_u16_as_f16_(nk_u16_t bits) {
1571
+ nk_fui16_t c;
1572
+ c.u = bits;
1573
+ return c.f;
1574
+ }
1575
+ NK_INTERNAL nk_u16_t nk_f16_as_u16_(nk_f16_t x) {
1576
+ nk_fui16_t c;
1577
+ c.f = x;
1578
+ return c.u;
1579
+ }
1580
+ NK_INTERNAL nk_bf16_t nk_u16_as_bf16_(nk_u16_t bits) {
1581
+ nk_fui16_t c;
1582
+ c.u = bits;
1583
+ return c.bf;
1584
+ }
1585
+
1586
+ NK_INTERNAL void nk_f64_from_i64_(nk_i64_t const *src, nk_f64_t *dest) { *dest = (nk_f64_t)*src; }
1587
+ NK_INTERNAL void nk_f64_from_u64_(nk_u64_t const *src, nk_f64_t *dest) { *dest = (nk_f64_t)*src; }
1588
+ NK_INTERNAL void nk_f32_from_i32_(nk_i32_t const *src, nk_f32_t *dest) { *dest = (nk_f32_t)*src; }
1589
+ NK_INTERNAL void nk_f32_from_u32_(nk_u32_t const *src, nk_f32_t *dest) { *dest = (nk_f32_t)*src; }
1590
+ NK_INTERNAL void nk_f32_from_f64_(nk_f64_t const *src, nk_f32_t *dest) { *dest = (nk_f32_t)*src; }
1591
+
1592
+ /** @brief E4M3: NaN when (raw & 0x7F) == 0x7F (two NaN values: 0x7F, 0xFF). */
1593
+ NK_INTERNAL int nk_e4m3_is_nan_(nk_e4m3_t x) { return (x & 0x7F) == 0x7F; }
1594
+
1595
+ /** @brief E5M2: NaN when exponent=31 and mantissa!=0, i.e. (raw & 0x7F) > 0x7C.
1596
+ * Values: 0x7D-0x7F (positive), 0xFD-0xFF (negative). Infinity = 0x7C/0xFC is NOT NaN. */
1597
+ NK_INTERNAL int nk_e5m2_is_nan_(nk_e5m2_t x) { return (x & 0x7F) > 0x7C; }
1598
+
1599
+ /** @brief F16: NaN when (raw & 0x7FFF) > 0x7C00. */
1600
+ NK_INTERNAL int nk_f16_is_nan_(nk_f16_t x) {
1601
+ nk_fui16_t x_fui;
1602
+ x_fui.f = x;
1603
+ return (x_fui.u & 0x7FFF) > 0x7C00;
1604
+ }
1605
+
1606
+ /** @brief BF16: NaN when (raw & 0x7FFF) > 0x7F80. */
1607
+ NK_INTERNAL int nk_bf16_is_nan_(nk_bf16_t x) {
1608
+ nk_fui16_t x_fui;
1609
+ x_fui.bf = x;
1610
+ return (x_fui.u & 0x7FFF) > 0x7F80;
1611
+ }
1612
+
1613
+ /* Safe SVE vector-length queries usable from non-streaming context.
1614
+ * On Apple M4 (and other SME-only-SVE cores), SVE instructions like CNTW/CNTH/CNTB
1615
+ * trap with SIGILL outside streaming mode. These helpers bracket the query with
1616
+ * SMSTART SM / SMSTOP SM so the calling function's ABI is unchanged.
1617
+ * Inside `__arm_locally_streaming` functions the plain `svcntXX()` intrinsics are fine.
1618
+ */
1619
+ #if NK_TARGET_ARM64_ && NK_TARGET_SME
1620
+ /** @brief Streaming SVL byte-element count (SVL/8) via SMSTART SM bracket. */
1621
+ NK_INTERNAL nk_size_t nk_sme_cntb_(void) {
1622
+ nk_u64_t r;
1623
+ __asm__ __volatile__("smstart sm\n\t" "cntb %0\n\t" "smstop sm" : "=r"(r));
1624
+ return (nk_size_t)r;
1625
+ }
1626
+ /** @brief Streaming SVL half-element count (SVL/16) via SMSTART SM bracket. */
1627
+ NK_INTERNAL nk_size_t nk_sme_cnth_(void) {
1628
+ nk_u64_t r;
1629
+ __asm__ __volatile__("smstart sm\n\t" "cnth %0\n\t" "smstop sm" : "=r"(r));
1630
+ return (nk_size_t)r;
1631
+ }
1632
+ /** @brief Streaming SVL word-element count (SVL/32) via SMSTART SM bracket. */
1633
+ NK_INTERNAL nk_size_t nk_sme_cntw_(void) {
1634
+ nk_u64_t r;
1635
+ __asm__ __volatile__("smstart sm\n\t" "cntw %0\n\t" "smstop sm" : "=r"(r));
1636
+ return (nk_size_t)r;
1637
+ }
1638
+ /** @brief Streaming SVL double-element count (SVL/64) via SMSTART SM bracket. */
1639
+ NK_INTERNAL nk_size_t nk_sme_cntd_(void) {
1640
+ nk_u64_t r;
1641
+ __asm__ __volatile__("smstart sm\n\t" "cntd %0\n\t" "smstop sm" : "=r"(r));
1642
+ return (nk_size_t)r;
1643
+ }
1644
+
1645
+ /** @brief Enter streaming SVE mode (PSTATE.SM = 1). Caller is responsible for smstop. */
1646
+ NK_INTERNAL void nk_sme_start_streaming_(void) { __asm__ __volatile__("smstart sm" ::: "memory"); }
1647
+ /** @brief Exit streaming SVE mode (PSTATE.SM = 0). Must pair with nk_sme_start_streaming_. */
1648
+ NK_INTERNAL void nk_sme_stop_streaming_(void) { __asm__ __volatile__("smstop sm" ::: "memory"); }
1649
+
1650
+ /**
1651
+ * SME runtime stubs — weak definitions for symbols the compiler may reference
1652
+ * from __arm_streaming or __arm_new("za") functions. Every TU that includes
1653
+ * this header emits a weak copy; the linker deduplicates to one.
1654
+ *
1655
+ * - __arm_tpidr2_save / __arm_tpidr2_restore: lazy ZA save/restore protocol
1656
+ * used in __arm_new("za") prologues. Always no-ops in NumKong because no
1657
+ * NK_PUBLIC function carries ZA state (TPIDR2_EL0 is always null at entry).
1658
+ *
1659
+ * - __arm_sc_memset / __arm_sc_memcpy / __arm_sc_memmove: streaming-compatible
1660
+ * memory routines the compiler may emit inside __arm_streaming functions.
1661
+ * Apple Clang provides these in its runtime; upstream LLVM does not.
1662
+ */
1663
+ __attribute__((weak)) void __arm_tpidr2_save(void) {}
1664
+ __attribute__((weak)) void __arm_tpidr2_restore(void *blk) { nk_unused_(blk); }
1665
+ __attribute__((weak, target("+sme"))) void *__arm_sc_memset(void *d, int c, __SIZE_TYPE__ n) __arm_streaming_compatible {
1666
+ unsigned char *p = (unsigned char *)d;
1667
+ for (__SIZE_TYPE__ i = 0; i < n; i++) p[i] = (unsigned char)c;
1668
+ return d;
1669
+ }
1670
+ __attribute__((weak, target("+sme"))) void *__arm_sc_memcpy(void *d, void const *s,
1671
+ __SIZE_TYPE__ n) __arm_streaming_compatible {
1672
+ unsigned char *dp = (unsigned char *)d;
1673
+ unsigned char const *sp = (unsigned char const *)s;
1674
+ for (__SIZE_TYPE__ i = 0; i < n; i++) dp[i] = sp[i];
1675
+ return d;
1676
+ }
1677
+ __attribute__((weak, target("+sme"))) void *__arm_sc_memmove(void *d, void const *s,
1678
+ __SIZE_TYPE__ n) __arm_streaming_compatible {
1679
+ unsigned char *dp = (unsigned char *)d;
1680
+ unsigned char const *sp = (unsigned char const *)s;
1681
+ if (dp < sp) {
1682
+ for (__SIZE_TYPE__ i = 0; i < n; i++) dp[i] = sp[i];
1683
+ }
1684
+ else {
1685
+ for (__SIZE_TYPE__ i = n; i > 0; i--) dp[i - 1] = sp[i - 1];
1686
+ }
1687
+ return d;
1688
+ }
1689
+ #endif
1690
+
1691
+ #ifdef __cplusplus
1692
+ } // extern "C"
1693
+ #endif
1694
+
1695
+ #endif // NK_TYPES_H