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,970 @@
1
+ /**
2
+ * @brief SIMD-accelerated Type Conversions for RISC-V.
3
+ * @file include/numkong/cast/rvv.h
4
+ * @author Ash Vardanian
5
+ * @date January 13, 2026
6
+ *
7
+ * @sa include/numkong/cast.h
8
+ *
9
+ * SpacemiT K1 and similar chips implement RVA22 profile with base RVV 1.0.
10
+ * This file provides vectorized type conversions for:
11
+ * - BF16 ↔ F32 (bit manipulation, no hardware support)
12
+ * - F16 ↔ F32 (bit manipulation, no hardware support)
13
+ * - E4M3 ↔ F32 (FP8 format for ML inference)
14
+ * - E5M2 ↔ F32 (FP8 format for ML training)
15
+ * - i4/u4 unpacking to i8/u8
16
+ *
17
+ * Mini-float conversions use sign-symmetric magnitude LUTs: every mini-float
18
+ * format is sign|magnitude, so we store only the positive-half (magnitude)
19
+ * entries and extract the sign bit separately. This cuts LUT memory by 50-87%
20
+ * and fixes the E2M3FN NaN bug (E2M3FN has NO NaN; index 31 is +7.5, not NaN).
21
+ *
22
+ * 8-bit formats (e4m3, e5m2): sign = bit 7, magnitude = bits 6:0 (128 entries)
23
+ * 6-bit formats (e2m3, e3m2): sign = bit 5, magnitude = bits 4:0 (32 entries)
24
+ *
25
+ * @section rvv_cast_instructions Key RVV Cast Instructions
26
+ *
27
+ * Intrinsic Purpose
28
+ * vzext_vf4_u32m4 Zero-extend u8 → u32 (4x widening)
29
+ * vsext_vf4_i32m4 Sign-extend i8 → i32 (4x widening)
30
+ * vsll_vx / vsrl_vx Bit shifts for field extraction
31
+ * vand_vx Bit masking
32
+ * vor_vv Combining bit fields
33
+ * vfcvt_f_xu_v Unsigned int → float
34
+ * vmseq_vx Compare for conditional selection
35
+ * vmerge_vvm Conditional select (blend)
36
+ */
37
+ #ifndef NK_CAST_RVV_H
38
+ #define NK_CAST_RVV_H
39
+
40
+ #if NK_TARGET_RISCV64_
41
+ #if NK_TARGET_RVV
42
+
43
+ #include "numkong/types.h"
44
+ #include "numkong/cast/serial.h" // `nk_cast_serial`
45
+
46
+ #if defined(__clang__)
47
+ #pragma clang attribute push(__attribute__((target("arch=+v"))), apply_to = function)
48
+ #elif defined(__GNUC__)
49
+ #pragma GCC push_options
50
+ #pragma GCC target("arch=+v")
51
+ #endif
52
+
53
+ #if defined(__cplusplus)
54
+ extern "C" {
55
+ #endif
56
+
57
+ #pragma region Register to Register Helpers
58
+
59
+ /**
60
+ * @brief Convert bf16 (m1) to f32 (m2) register-to-register.
61
+ *
62
+ * BF16 is the upper 16 bits of F32 (same sign + exponent + top 7 mantissa bits).
63
+ * Conversion is simply: f32_bits = bf16_bits << 16.
64
+ */
65
+ NK_INTERNAL vfloat32m2_t nk_bf16m1_to_f32m2_rvv_(vuint16m1_t bf16_u16m1, nk_size_t vector_length) {
66
+ vuint32m2_t bits_u32m2 = __riscv_vzext_vf2_u32m2(bf16_u16m1, vector_length);
67
+ bits_u32m2 = __riscv_vsll_vx_u32m2(bits_u32m2, 16, vector_length);
68
+ return __riscv_vreinterpret_v_u32m2_f32m2(bits_u32m2);
69
+ }
70
+
71
+ /**
72
+ * @brief Convert f32 (m2) to bf16 (m1) register-to-register.
73
+ *
74
+ * Conversion with round-to-nearest-even (RNE): add (0x7FFF + lsb) to match hardware BF16 behavior.
75
+ */
76
+ NK_INTERNAL vuint16m1_t nk_f32m2_to_bf16m1_rvv_(vfloat32m2_t f32_f32m2, nk_size_t vector_length) {
77
+ vuint32m2_t bits_u32m2 = __riscv_vreinterpret_v_f32m2_u32m2(f32_f32m2);
78
+ // Extract LSB of result (bit 16) for round-to-nearest-even
79
+ vuint32m2_t lsb_u32m2 = __riscv_vand_vx_u32m2(__riscv_vsrl_vx_u32m2(bits_u32m2, 16, vector_length), 1,
80
+ vector_length);
81
+ vuint32m2_t rounding_u32m2 = __riscv_vadd_vx_u32m2(lsb_u32m2, 0x7FFF, vector_length);
82
+ vuint32m2_t rounded_u32m2 = __riscv_vadd_vv_u32m2(bits_u32m2, rounding_u32m2, vector_length);
83
+ vuint32m2_t shifted_u32m2 = __riscv_vsrl_vx_u32m2(rounded_u32m2, 16, vector_length);
84
+ return __riscv_vncvt_x_x_w_u16m1(shifted_u32m2, vector_length);
85
+ }
86
+
87
+ /**
88
+ * @brief Convert f16 (m1) to f32 (m2) register-to-register.
89
+ *
90
+ * F16 format: S EEEEE MMMMMMMMMM (1 sign, 5 exponent bits with bias=15, 10 mantissa bits)
91
+ * F32 format: S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM (1 sign, 8 exponent bits with bias=127, 23 mantissa bits)
92
+ *
93
+ * Uses the Giesen magic-multiply trick: treat the magnitude bits as a denormal f32 and
94
+ * multiply by 2^112 to rebias the exponent. This correctly handles ±zero, denormals,
95
+ * and normals in a single FP multiply; only inf/NaN needs a fixup compare+merge.
96
+ *
97
+ * https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
98
+ */
99
+ NK_INTERNAL vfloat32m2_t nk_f16m1_to_f32m2_rvv_(vuint16m1_t f16_u16m1, nk_size_t vector_length) {
100
+ // Widen to 32-bit for manipulation
101
+ vuint32m2_t bits_u32m2 = __riscv_vzext_vf2_u32m2(f16_u16m1, vector_length);
102
+ // Extract sign: (raw >> 15) << 31
103
+ vuint32m2_t sign_u32m2 = __riscv_vsll_vx_u32m2(__riscv_vsrl_vx_u32m2(bits_u32m2, 15, vector_length), 31,
104
+ vector_length);
105
+ // Strip sign, shift magnitude into f32 mantissa position.
106
+ // For a normal f16 with exp E, this places E into the f32 exponent field,
107
+ // creating a tiny f32 whose value is proportional to the f16 magnitude.
108
+ vuint32m2_t nonsign_u32m2 = __riscv_vand_vx_u32m2(bits_u32m2, 0x7FFF, vector_length);
109
+ vuint32m2_t shifted_u32m2 = __riscv_vsll_vx_u32m2(nonsign_u32m2, 13, vector_length);
110
+ // Multiply by 2^112 (= magic 0x77800000 as f32) to rebias the exponent.
111
+ // This single multiply correctly handles zero, denormals, and normals:
112
+ // zero: 0.0 × 2^112 = 0.0
113
+ // denormal: (M × 2^-136) × 2^112 = M × 2^-24 (correct f16 denormal value)
114
+ // normal: (2^(E-127) × …) × 2^112 = 2^(E-15) × … (correct rebiased value)
115
+ vfloat32m2_t magic_f32m2 = __riscv_vreinterpret_v_u32m2_f32m2(
116
+ __riscv_vmv_v_x_u32m2(((nk_u32_t)(254 - 15) << 23), vector_length));
117
+ vfloat32m2_t result_f32m2 = __riscv_vfmul_vv_f32m2(__riscv_vreinterpret_v_u32m2_f32m2(shifted_u32m2), magic_f32m2,
118
+ vector_length);
119
+ // Inf/NaN fixup: the multiply maps f16 exp=31 to a large finite f32.
120
+ // Detect those lanes and force the f32 exponent to 255 (inf/NaN).
121
+ // Threshold 0x47800000 = 2^16; any f16 with exp=31 exceeds it after scaling.
122
+ vfloat32m2_t infnan_threshold_f32m2 = __riscv_vreinterpret_v_u32m2_f32m2(
123
+ __riscv_vmv_v_x_u32m2(((nk_u32_t)(127 + 16) << 23), vector_length));
124
+ vbool16_t is_infnan = __riscv_vmfge_vv_f32m2_b16(result_f32m2, infnan_threshold_f32m2, vector_length);
125
+ vuint32m2_t result_u32m2 = __riscv_vreinterpret_v_f32m2_u32m2(result_f32m2);
126
+ vuint32m2_t fixed_u32m2 = __riscv_vor_vx_u32m2(result_u32m2, 0x7F800000, vector_length);
127
+ result_u32m2 = __riscv_vmerge_vvm_u32m2(result_u32m2, fixed_u32m2, is_infnan, vector_length);
128
+ // Restore sign
129
+ result_u32m2 = __riscv_vor_vv_u32m2(result_u32m2, sign_u32m2, vector_length);
130
+ return __riscv_vreinterpret_v_u32m2_f32m2(result_u32m2);
131
+ }
132
+
133
+ /**
134
+ * @brief Convert f32 (m2) to f16 (m1) register-to-register.
135
+ *
136
+ * Conversion: Rebias exponent from 127 to 15, truncate mantissa from 23 to 10 bits with rounding.
137
+ */
138
+ NK_INTERNAL vuint16m1_t nk_f32m2_to_f16m1_rvv_(vfloat32m2_t f32_f32m2, nk_size_t vector_length) {
139
+ vuint32m2_t bits_u32m2 = __riscv_vreinterpret_v_f32m2_u32m2(f32_f32m2);
140
+ // Extract sign: (raw >> 31) << 15
141
+ vuint32m2_t sign_u32m2 = __riscv_vsll_vx_u32m2(__riscv_vsrl_vx_u32m2(bits_u32m2, 31, vector_length), 15,
142
+ vector_length);
143
+ // Extract exponent: (raw >> 23) & 0xFF
144
+ vuint32m2_t exponent_u32m2 = __riscv_vand_vx_u32m2(__riscv_vsrl_vx_u32m2(bits_u32m2, 23, vector_length), 0xFF,
145
+ vector_length);
146
+ // Extract mantissa: raw & 0x7FFFFF
147
+ vuint32m2_t mantissa_u32m2 = __riscv_vand_vx_u32m2(bits_u32m2, 0x7FFFFF, vector_length);
148
+ // Rebias exponent (127 → 15): subtract 112, clamp to [0, 31]
149
+ // Note: This is a simplified conversion that doesn't handle subnormals or overflow properly
150
+ vint32m2_t exponent_i32m2 = __riscv_vsub_vx_i32m2(__riscv_vreinterpret_v_u32m2_i32m2(exponent_u32m2), 112,
151
+ vector_length);
152
+ exponent_i32m2 = __riscv_vmax_vx_i32m2(exponent_i32m2, 0, vector_length);
153
+ vuint32m2_t f16_exponent_u32m2 = __riscv_vreinterpret_v_i32m2_u32m2(
154
+ __riscv_vmin_vx_i32m2(exponent_i32m2, 31, vector_length));
155
+ // Round mantissa: add 0x1000 (half of truncated bits) then shift
156
+ vuint32m2_t rounded_mantissa_u32m2 = __riscv_vadd_vx_u32m2(mantissa_u32m2, 0x1000, vector_length);
157
+ vuint32m2_t f16_mantissa_u32m2 = __riscv_vsrl_vx_u32m2(rounded_mantissa_u32m2, 13, vector_length);
158
+ f16_mantissa_u32m2 = __riscv_vand_vx_u32m2(f16_mantissa_u32m2, 0x3FF, vector_length);
159
+ // Combine: sign | (exponent << 10) | mantissa
160
+ vuint32m2_t result_u32m2 = __riscv_vor_vv_u32m2(
161
+ sign_u32m2,
162
+ __riscv_vor_vv_u32m2(__riscv_vsll_vx_u32m2(f16_exponent_u32m2, 10, vector_length), f16_mantissa_u32m2,
163
+ vector_length),
164
+ vector_length);
165
+ return __riscv_vncvt_x_x_w_u16m1(result_u32m2, vector_length);
166
+ }
167
+
168
+ /**
169
+ * @brief Convert e4m3 (m1) to f32 (m4) via Giesen magic-multiply.
170
+ * Reinterprets magnitude bits as a tiny f32, then multiplies by 2^(127-bias) to rebias.
171
+ * Handles zero, subnormals, and normals in a single vfmul. NaN fixup for magnitude 0x7F.
172
+ * https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
173
+ */
174
+ NK_INTERNAL vfloat32m4_t nk_e4m3m1_to_f32m4_rvv_(vuint8m1_t e4m3_u8m1, nk_size_t vector_length) {
175
+ // Extract sign: (raw & 0x80) → bit 7, shift to bit 31
176
+ vuint32m4_t sign_u32m4 = __riscv_vsll_vx_u32m4(
177
+ __riscv_vzext_vf4_u32m4(__riscv_vand_vx_u8m1(e4m3_u8m1, 0x80, vector_length), vector_length), 24,
178
+ vector_length);
179
+ // Strip sign to get 7-bit magnitude, widen to u32, shift left by 20
180
+ vuint8m1_t nonsign_u8m1 = __riscv_vand_vx_u8m1(e4m3_u8m1, 0x7F, vector_length);
181
+ vuint32m4_t nonsign_u32m4 = __riscv_vzext_vf4_u32m4(nonsign_u8m1, vector_length);
182
+ vuint32m4_t shifted_u32m4 = __riscv_vsll_vx_u32m4(nonsign_u32m4, 20, vector_length);
183
+
184
+ // Magic multiply: reinterpret as f32 × 2^120 rebiases from E4M3 (bias=7) to f32 (bias=127).
185
+ vfloat32m4_t magic_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(
186
+ __riscv_vmv_v_x_u32m4(0x7B800000, vector_length)); // 2^120 = (254-7)<<23
187
+ vfloat32m4_t result_f32m4 = __riscv_vfmul_vv_f32m4(__riscv_vreinterpret_v_u32m4_f32m4(shifted_u32m4), magic_f32m4,
188
+ vector_length);
189
+
190
+ // NaN fixup: masked OR writes sign|0x7FC00000 only into NaN lanes
191
+ vbool8_t is_nan = __riscv_vmseq_vx_u8m1_b8(nonsign_u8m1, 0x7F, vector_length);
192
+ vuint32m4_t result_u32m4 = __riscv_vor_vx_u32m4_mu(is_nan, __riscv_vreinterpret_v_f32m4_u32m4(result_f32m4),
193
+ sign_u32m4, 0x7FC00000, vector_length);
194
+
195
+ // Restore sign
196
+ result_u32m4 = __riscv_vor_vv_u32m4(result_u32m4, sign_u32m4, vector_length);
197
+ return __riscv_vreinterpret_v_u32m4_f32m4(result_u32m4);
198
+ }
199
+
200
+ /**
201
+ * @brief Convert e5m2 (m1) to f32 (m4) via Giesen magic-multiply.
202
+ * Reinterprets magnitude bits as a tiny f32, then multiplies by 2^(127-bias) to rebias.
203
+ * Handles zero, subnormals, and normals in a single vfmul. Inf/NaN fixup for exp=31.
204
+ * https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
205
+ */
206
+ NK_INTERNAL vfloat32m4_t nk_e5m2m1_to_f32m4_rvv_(vuint8m1_t e5m2_u8m1, nk_size_t vector_length) {
207
+ // Extract sign: (raw & 0x80) → bit 7, shift to bit 31
208
+ vuint32m4_t sign_u32m4 = __riscv_vsll_vx_u32m4(
209
+ __riscv_vzext_vf4_u32m4(__riscv_vand_vx_u8m1(e5m2_u8m1, 0x80, vector_length), vector_length), 24,
210
+ vector_length);
211
+ // Strip sign to get 7-bit magnitude, widen to u32, shift left by 21
212
+ vuint32m4_t nonsign_u32m4 = __riscv_vzext_vf4_u32m4(__riscv_vand_vx_u8m1(e5m2_u8m1, 0x7F, vector_length),
213
+ vector_length);
214
+ vuint32m4_t shifted_u32m4 = __riscv_vsll_vx_u32m4(nonsign_u32m4, 21, vector_length);
215
+
216
+ // Magic multiply: reinterpret as f32 × 2^112 rebiases from E5M2 (bias=15) to f32 (bias=127).
217
+ vfloat32m4_t magic_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(
218
+ __riscv_vmv_v_x_u32m4(0x77800000, vector_length)); // 2^112 = (254-15)<<23
219
+ vfloat32m4_t result_f32m4 = __riscv_vfmul_vv_f32m4(__riscv_vreinterpret_v_u32m4_f32m4(shifted_u32m4), magic_f32m4,
220
+ vector_length);
221
+
222
+ // Inf/NaN fixup: masked OR writes 0x7F800000 only into inf/NaN lanes (nonsign > 123)
223
+ vbool8_t is_infnan = __riscv_vmsgtu_vx_u32m4_b8(nonsign_u32m4, 123, vector_length);
224
+ vuint32m4_t result_u32m4 = __riscv_vor_vx_u32m4_mu(is_infnan, __riscv_vreinterpret_v_f32m4_u32m4(result_f32m4),
225
+ __riscv_vreinterpret_v_f32m4_u32m4(result_f32m4), 0x7F800000,
226
+ vector_length);
227
+
228
+ // Restore sign
229
+ result_u32m4 = __riscv_vor_vv_u32m4(result_u32m4, sign_u32m4, vector_length);
230
+ return __riscv_vreinterpret_v_u32m4_f32m4(result_u32m4);
231
+ }
232
+
233
+ /**
234
+ * @brief Convert e2m3 (m1) to f32 (m4) via Giesen magic-multiply.
235
+ * Reinterprets magnitude bits as a tiny f32, then multiplies by 2^(127-bias) to rebias.
236
+ * Handles zero, subnormals, and normals in a single vfmul. No inf/NaN in E2M3FN.
237
+ * https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
238
+ */
239
+ NK_INTERNAL vfloat32m4_t nk_e2m3m1_to_f32m4_rvv_(vuint8m1_t e2m3_u8m1, nk_size_t vector_length) {
240
+ // Extract sign: bit 5 → bit 31
241
+ vuint32m4_t sign_u32m4 = __riscv_vsll_vx_u32m4(
242
+ __riscv_vzext_vf4_u32m4(__riscv_vand_vx_u8m1(e2m3_u8m1, 0x20, vector_length), vector_length), 26,
243
+ vector_length);
244
+ // Strip sign to get 5-bit magnitude, widen to u32, shift left by 20
245
+ vuint32m4_t nonsign_u32m4 = __riscv_vzext_vf4_u32m4(__riscv_vand_vx_u8m1(e2m3_u8m1, 0x1F, vector_length),
246
+ vector_length);
247
+ vuint32m4_t shifted_u32m4 = __riscv_vsll_vx_u32m4(nonsign_u32m4, 20, vector_length);
248
+
249
+ // Magic multiply: reinterpret as f32 × 2^126 rebiases from E2M3 (bias=1) to f32 (bias=127).
250
+ vfloat32m4_t magic_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(
251
+ __riscv_vmv_v_x_u32m4(0x7E800000, vector_length)); // 2^126 = (254-1)<<23
252
+ vfloat32m4_t result_f32m4 = __riscv_vfmul_vv_f32m4(__riscv_vreinterpret_v_u32m4_f32m4(shifted_u32m4), magic_f32m4,
253
+ vector_length);
254
+
255
+ // Restore sign (no inf/NaN fixup needed for E2M3FN)
256
+ vuint32m4_t result_u32m4 = __riscv_vor_vv_u32m4(__riscv_vreinterpret_v_f32m4_u32m4(result_f32m4), sign_u32m4,
257
+ vector_length);
258
+ return __riscv_vreinterpret_v_u32m4_f32m4(result_u32m4);
259
+ }
260
+
261
+ /**
262
+ * @brief Convert e3m2 (m1) to f32 (m4) via Giesen magic-multiply.
263
+ * Reinterprets magnitude bits as a tiny f32, then multiplies by 2^(127-bias) to rebias.
264
+ * Handles zero, subnormals, and normals in a single vfmul. No inf/NaN in E3M2FN.
265
+ * https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
266
+ */
267
+ NK_INTERNAL vfloat32m4_t nk_e3m2m1_to_f32m4_rvv_(vuint8m1_t e3m2_u8m1, nk_size_t vector_length) {
268
+ // Extract sign: bit 5 → bit 31
269
+ vuint32m4_t sign_u32m4 = __riscv_vsll_vx_u32m4(
270
+ __riscv_vzext_vf4_u32m4(__riscv_vand_vx_u8m1(e3m2_u8m1, 0x20, vector_length), vector_length), 26,
271
+ vector_length);
272
+ // Strip sign to get 5-bit magnitude, widen to u32, shift left by 21
273
+ vuint32m4_t nonsign_u32m4 = __riscv_vzext_vf4_u32m4(__riscv_vand_vx_u8m1(e3m2_u8m1, 0x1F, vector_length),
274
+ vector_length);
275
+ vuint32m4_t shifted_u32m4 = __riscv_vsll_vx_u32m4(nonsign_u32m4, 21, vector_length);
276
+
277
+ // Magic multiply: reinterpret as f32 × 2^124 rebiases from E3M2 (bias=3) to f32 (bias=127).
278
+ vfloat32m4_t magic_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(
279
+ __riscv_vmv_v_x_u32m4(0x7D800000, vector_length)); // 2^124 = (254-3)<<23
280
+ vfloat32m4_t result_f32m4 = __riscv_vfmul_vv_f32m4(__riscv_vreinterpret_v_u32m4_f32m4(shifted_u32m4), magic_f32m4,
281
+ vector_length);
282
+
283
+ // Restore sign (no inf/NaN fixup needed for E3M2FN)
284
+ vuint32m4_t result_u32m4 = __riscv_vor_vv_u32m4(__riscv_vreinterpret_v_f32m4_u32m4(result_f32m4), sign_u32m4,
285
+ vector_length);
286
+ return __riscv_vreinterpret_v_u32m4_f32m4(result_u32m4);
287
+ }
288
+
289
+ /** @brief Convert e4m3 (m1) to bf16 (m2) via Giesen magic-multiply.
290
+ * Magic-multiply to f32, truncate upper 16 bits to bf16. NaN fixup for magnitude 0x7F. */
291
+ NK_INTERNAL vuint16m2_t nk_e4m3m1_to_bf16m2_rvv_(vuint8m1_t e4m3_u8m1, nk_size_t vector_length) {
292
+ vuint8m1_t sign_u8m1 = __riscv_vand_vx_u8m1(e4m3_u8m1, 0x80, vector_length);
293
+ vuint8m1_t nonsign_u8m1 = __riscv_vand_vx_u8m1(e4m3_u8m1, 0x7F, vector_length);
294
+ vuint32m4_t nonsign_u32m4 = __riscv_vzext_vf4_u32m4(nonsign_u8m1, vector_length);
295
+ vuint32m4_t shifted_u32m4 = __riscv_vsll_vx_u32m4(nonsign_u32m4, 20, vector_length);
296
+ // Magic multiply: reinterpret as f32 × 2^120
297
+ vfloat32m4_t magic_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(__riscv_vmv_v_x_u32m4(0x7B800000, vector_length));
298
+ vfloat32m4_t result_f32m4 = __riscv_vfmul_vv_f32m4(__riscv_vreinterpret_v_u32m4_f32m4(shifted_u32m4), magic_f32m4,
299
+ vector_length);
300
+ // Truncate f32 → bf16 (right shift 16, exact for all e4m3 values)
301
+ vuint16m2_t result_u16m2 = __riscv_vnsrl_wx_u16m2(__riscv_vreinterpret_v_f32m4_u32m4(result_f32m4), 16,
302
+ vector_length);
303
+ // NaN fixup: magnitude 0x7F → bf16 quiet NaN 0x7FC0
304
+ vbool8_t is_nan = __riscv_vmseq_vx_u8m1_b8(nonsign_u8m1, 0x7F, vector_length);
305
+ result_u16m2 = __riscv_vmerge_vxm_u16m2(result_u16m2, 0x7FC0, is_nan, vector_length);
306
+ // Restore sign: bit 7 → bf16 bit 15 (<<8)
307
+ vuint16m2_t sign_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(sign_u8m1, vector_length), 8, vector_length);
308
+ return __riscv_vor_vv_u16m2(result_u16m2, sign_u16m2, vector_length);
309
+ }
310
+
311
+ /** @brief Convert e5m2 (m1) to bf16 (m2) via Giesen magic-multiply.
312
+ * Magic-multiply to f32, inf/NaN fixup, truncate upper 16 bits to bf16. */
313
+ NK_INTERNAL vuint16m2_t nk_e5m2m1_to_bf16m2_rvv_(vuint8m1_t e5m2_u8m1, nk_size_t vector_length) {
314
+ vuint8m1_t sign_u8m1 = __riscv_vand_vx_u8m1(e5m2_u8m1, 0x80, vector_length);
315
+ vuint8m1_t nonsign_u8m1 = __riscv_vand_vx_u8m1(e5m2_u8m1, 0x7F, vector_length);
316
+ vuint32m4_t nonsign_u32m4 = __riscv_vzext_vf4_u32m4(nonsign_u8m1, vector_length);
317
+ vuint32m4_t shifted_u32m4 = __riscv_vsll_vx_u32m4(nonsign_u32m4, 21, vector_length);
318
+ // Magic multiply: reinterpret as f32 × 2^112
319
+ vfloat32m4_t magic_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(__riscv_vmv_v_x_u32m4(0x77800000, vector_length));
320
+ vfloat32m4_t result_f32m4 = __riscv_vfmul_vv_f32m4(__riscv_vreinterpret_v_u32m4_f32m4(shifted_u32m4), magic_f32m4,
321
+ vector_length);
322
+ // Inf/NaN fixup: masked OR writes 0x7F800000 only into inf/NaN lanes (nonsign > 123)
323
+ vbool8_t is_infnan = __riscv_vmsgtu_vx_u32m4_b8(nonsign_u32m4, 123, vector_length);
324
+ vuint32m4_t f32_bits = __riscv_vor_vx_u32m4_mu(is_infnan, __riscv_vreinterpret_v_f32m4_u32m4(result_f32m4),
325
+ __riscv_vreinterpret_v_f32m4_u32m4(result_f32m4), 0x7F800000,
326
+ vector_length);
327
+ // Truncate f32 → bf16 (right shift 16, exact for all e5m2 values)
328
+ vuint16m2_t result_u16m2 = __riscv_vnsrl_wx_u16m2(f32_bits, 16, vector_length);
329
+ // Restore sign: bit 7 → bf16 bit 15 (<<8)
330
+ vuint16m2_t sign_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(sign_u8m1, vector_length), 8, vector_length);
331
+ return __riscv_vor_vv_u16m2(result_u16m2, sign_u16m2, vector_length);
332
+ }
333
+
334
+ /** @brief Convert e2m3 (m1) to bf16 (m2) via Giesen magic-multiply.
335
+ * Magic-multiply to f32, truncate upper 16 bits to bf16. No inf/NaN in E2M3FN. */
336
+ NK_INTERNAL vuint16m2_t nk_e2m3m1_to_bf16m2_rvv_(vuint8m1_t e2m3_u8m1, nk_size_t vector_length) {
337
+ vuint8m1_t sign_u8m1 = __riscv_vand_vx_u8m1(e2m3_u8m1, 0x20, vector_length);
338
+ vuint8m1_t nonsign_u8m1 = __riscv_vand_vx_u8m1(e2m3_u8m1, 0x1F, vector_length);
339
+ vuint32m4_t nonsign_u32m4 = __riscv_vzext_vf4_u32m4(nonsign_u8m1, vector_length);
340
+ vuint32m4_t shifted_u32m4 = __riscv_vsll_vx_u32m4(nonsign_u32m4, 20, vector_length);
341
+ // Magic multiply: reinterpret as f32 × 2^126
342
+ vfloat32m4_t magic_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(__riscv_vmv_v_x_u32m4(0x7E800000, vector_length));
343
+ vfloat32m4_t result_f32m4 = __riscv_vfmul_vv_f32m4(__riscv_vreinterpret_v_u32m4_f32m4(shifted_u32m4), magic_f32m4,
344
+ vector_length);
345
+ // Truncate f32 → bf16 (right shift 16, exact for all e2m3 values)
346
+ vuint16m2_t result_u16m2 = __riscv_vnsrl_wx_u16m2(__riscv_vreinterpret_v_f32m4_u32m4(result_f32m4), 16,
347
+ vector_length);
348
+ // Restore sign: bit 5 → bf16 bit 15 (<<10)
349
+ vuint16m2_t sign_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(sign_u8m1, vector_length), 10,
350
+ vector_length);
351
+ return __riscv_vor_vv_u16m2(result_u16m2, sign_u16m2, vector_length);
352
+ }
353
+
354
+ /** @brief Convert e3m2 (m1) to bf16 (m2) via Giesen magic-multiply.
355
+ * Magic-multiply to f32, truncate upper 16 bits to bf16. No inf/NaN in E3M2FN. */
356
+ NK_INTERNAL vuint16m2_t nk_e3m2m1_to_bf16m2_rvv_(vuint8m1_t e3m2_u8m1, nk_size_t vector_length) {
357
+ vuint8m1_t sign_u8m1 = __riscv_vand_vx_u8m1(e3m2_u8m1, 0x20, vector_length);
358
+ vuint8m1_t nonsign_u8m1 = __riscv_vand_vx_u8m1(e3m2_u8m1, 0x1F, vector_length);
359
+ vuint32m4_t nonsign_u32m4 = __riscv_vzext_vf4_u32m4(nonsign_u8m1, vector_length);
360
+ vuint32m4_t shifted_u32m4 = __riscv_vsll_vx_u32m4(nonsign_u32m4, 21, vector_length);
361
+ // Magic multiply: reinterpret as f32 × 2^124
362
+ vfloat32m4_t magic_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(__riscv_vmv_v_x_u32m4(0x7D800000, vector_length));
363
+ vfloat32m4_t result_f32m4 = __riscv_vfmul_vv_f32m4(__riscv_vreinterpret_v_u32m4_f32m4(shifted_u32m4), magic_f32m4,
364
+ vector_length);
365
+ // Truncate f32 → bf16 (right shift 16, exact for all e3m2 values)
366
+ vuint16m2_t result_u16m2 = __riscv_vnsrl_wx_u16m2(__riscv_vreinterpret_v_f32m4_u32m4(result_f32m4), 16,
367
+ vector_length);
368
+ // Restore sign: bit 5 → bf16 bit 15 (<<10)
369
+ vuint16m2_t sign_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(sign_u8m1, vector_length), 10,
370
+ vector_length);
371
+ return __riscv_vor_vv_u16m2(result_u16m2, sign_u16m2, vector_length);
372
+ }
373
+
374
+ /** @brief Convert e4m3 (m1) to f16 (m2) via sign-symmetric magnitude LUT. Sign bit 7 → f16 bit 15 (<<8). */
375
+ NK_INTERNAL vuint16m2_t nk_e4m3m1_to_f16m2_rvv_(vuint8m1_t e4m3_u8m1, nk_size_t vector_length) {
376
+ static nk_u16_t const nk_e4m3_mag_to_f16_lut_[128] = {
377
+ 0x0000u, 0x1800u, 0x1C00u, 0x1E00u, 0x2000u, 0x2100u, 0x2200u, 0x2300u, /* [ 0.. 7] */
378
+ 0x2400u, 0x2480u, 0x2500u, 0x2580u, 0x2600u, 0x2680u, 0x2700u, 0x2780u, /* [ 8.. 15] */
379
+ 0x2800u, 0x2880u, 0x2900u, 0x2980u, 0x2A00u, 0x2A80u, 0x2B00u, 0x2B80u, /* [ 16.. 23] */
380
+ 0x2C00u, 0x2C80u, 0x2D00u, 0x2D80u, 0x2E00u, 0x2E80u, 0x2F00u, 0x2F80u, /* [ 24.. 31] */
381
+ 0x3000u, 0x3080u, 0x3100u, 0x3180u, 0x3200u, 0x3280u, 0x3300u, 0x3380u, /* [ 32.. 39] */
382
+ 0x3400u, 0x3480u, 0x3500u, 0x3580u, 0x3600u, 0x3680u, 0x3700u, 0x3780u, /* [ 40.. 47] */
383
+ 0x3800u, 0x3880u, 0x3900u, 0x3980u, 0x3A00u, 0x3A80u, 0x3B00u, 0x3B80u, /* [ 48.. 55] */
384
+ 0x3C00u, 0x3C80u, 0x3D00u, 0x3D80u, 0x3E00u, 0x3E80u, 0x3F00u, 0x3F80u, /* [ 56.. 63] */
385
+ 0x4000u, 0x4080u, 0x4100u, 0x4180u, 0x4200u, 0x4280u, 0x4300u, 0x4380u, /* [ 64.. 71] */
386
+ 0x4400u, 0x4480u, 0x4500u, 0x4580u, 0x4600u, 0x4680u, 0x4700u, 0x4780u, /* [ 72.. 79] */
387
+ 0x4800u, 0x4880u, 0x4900u, 0x4980u, 0x4A00u, 0x4A80u, 0x4B00u, 0x4B80u, /* [ 80.. 87] */
388
+ 0x4C00u, 0x4C80u, 0x4D00u, 0x4D80u, 0x4E00u, 0x4E80u, 0x4F00u, 0x4F80u, /* [ 88.. 95] */
389
+ 0x5000u, 0x5080u, 0x5100u, 0x5180u, 0x5200u, 0x5280u, 0x5300u, 0x5380u, /* [ 96..103] */
390
+ 0x5400u, 0x5480u, 0x5500u, 0x5580u, 0x5600u, 0x5680u, 0x5700u, 0x5780u, /* [104..111] */
391
+ 0x5800u, 0x5880u, 0x5900u, 0x5980u, 0x5A00u, 0x5A80u, 0x5B00u, 0x5B80u, /* [112..119] */
392
+ 0x5C00u, 0x5C80u, 0x5D00u, 0x5D80u, 0x5E00u, 0x5E80u, 0x5F00u, 0x7E00u /* [120..127] */
393
+ };
394
+ vuint8m1_t sign_u8m1 = __riscv_vand_vx_u8m1(e4m3_u8m1, 0x80, vector_length);
395
+ vuint8m1_t nonsign_u8m1 = __riscv_vand_vx_u8m1(e4m3_u8m1, 0x7F, vector_length);
396
+ vuint16m2_t offsets_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(nonsign_u8m1, vector_length), 1,
397
+ vector_length);
398
+ vuint16m2_t result_u16m2 = __riscv_vluxei16_v_u16m2(nk_e4m3_mag_to_f16_lut_, offsets_u16m2, vector_length);
399
+ vuint16m2_t sign_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(sign_u8m1, vector_length), 8, vector_length);
400
+ return __riscv_vor_vv_u16m2(result_u16m2, sign_u16m2, vector_length);
401
+ }
402
+
403
+ /** @brief Convert e2m3 (m1) to f16 (m2) via sign-symmetric magnitude LUT. Sign bit 5 → f16 bit 15 (<<10). */
404
+ NK_INTERNAL vuint16m2_t nk_e2m3m1_to_f16m2_rvv_(vuint8m1_t e2m3_u8m1, nk_size_t vector_length) {
405
+ static nk_u16_t const nk_e2m3_mag_to_f16_lut_[32] = {
406
+ 0x0000u, 0x3000u, 0x3400u, 0x3600u, 0x3800u, 0x3900u, 0x3A00u, 0x3B00u, /* [ 0.. 7] */
407
+ 0x3C00u, 0x3C80u, 0x3D00u, 0x3D80u, 0x3E00u, 0x3E80u, 0x3F00u, 0x3F80u, /* [ 8.. 15] */
408
+ 0x4000u, 0x4080u, 0x4100u, 0x4180u, 0x4200u, 0x4280u, 0x4300u, 0x4380u, /* [ 16.. 23] */
409
+ 0x4400u, 0x4480u, 0x4500u, 0x4580u, 0x4600u, 0x4680u, 0x4700u, 0x4780u /* [ 24.. 31] */
410
+ };
411
+ vuint8m1_t sign_u8m1 = __riscv_vand_vx_u8m1(e2m3_u8m1, 0x20, vector_length);
412
+ vuint8m1_t nonsign_u8m1 = __riscv_vand_vx_u8m1(e2m3_u8m1, 0x1F, vector_length);
413
+ vuint16m2_t offsets_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(nonsign_u8m1, vector_length), 1,
414
+ vector_length);
415
+ vuint16m2_t result_u16m2 = __riscv_vluxei16_v_u16m2(nk_e2m3_mag_to_f16_lut_, offsets_u16m2, vector_length);
416
+ vuint16m2_t sign_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(sign_u8m1, vector_length), 10,
417
+ vector_length);
418
+ return __riscv_vor_vv_u16m2(result_u16m2, sign_u16m2, vector_length);
419
+ }
420
+
421
+ /** @brief Convert e3m2 (m1) to f16 (m2) via sign-symmetric magnitude LUT. Sign bit 5 → f16 bit 15 (<<10). */
422
+ NK_INTERNAL vuint16m2_t nk_e3m2m1_to_f16m2_rvv_(vuint8m1_t e3m2_u8m1, nk_size_t vector_length) {
423
+ static nk_u16_t const nk_e3m2_mag_to_f16_lut_[32] = {
424
+ 0x0000u, 0x2C00u, 0x3000u, 0x3200u, 0x3400u, 0x3500u, 0x3600u, 0x3700u, /* [ 0.. 7] */
425
+ 0x3800u, 0x3900u, 0x3A00u, 0x3B00u, 0x3C00u, 0x3D00u, 0x3E00u, 0x3F00u, /* [ 8.. 15] */
426
+ 0x4000u, 0x4100u, 0x4200u, 0x4300u, 0x4400u, 0x4500u, 0x4600u, 0x4700u, /* [ 16.. 23] */
427
+ 0x4800u, 0x4900u, 0x4A00u, 0x4B00u, 0x4C00u, 0x4D00u, 0x4E00u, 0x4F00u /* [ 24.. 31] */
428
+ };
429
+ vuint8m1_t sign_u8m1 = __riscv_vand_vx_u8m1(e3m2_u8m1, 0x20, vector_length);
430
+ vuint8m1_t nonsign_u8m1 = __riscv_vand_vx_u8m1(e3m2_u8m1, 0x1F, vector_length);
431
+ vuint16m2_t offsets_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(nonsign_u8m1, vector_length), 1,
432
+ vector_length);
433
+ vuint16m2_t result_u16m2 = __riscv_vluxei16_v_u16m2(nk_e3m2_mag_to_f16_lut_, offsets_u16m2, vector_length);
434
+ vuint16m2_t sign_u16m2 = __riscv_vsll_vx_u16m2(__riscv_vzext_vf2_u16m2(sign_u8m1, vector_length), 10,
435
+ vector_length);
436
+ return __riscv_vor_vv_u16m2(result_u16m2, sign_u16m2, vector_length);
437
+ }
438
+
439
+ /**
440
+ * @brief Unpack i4 (m1) nibbles to i8 (m2) register-to-register.
441
+ *
442
+ * Packed format: byte[i] contains two nibbles:
443
+ * - High nibble (bits [7:4]) → output[i*2]
444
+ * - Low nibble (bits [3:0]) → output[i*2+1]
445
+ *
446
+ * Sign extension: 4-bit signed value [-8,7] extended to 8-bit.
447
+ * Trick: (x ^ 8) - 8 sign-extends a 4-bit value to larger type.
448
+ *
449
+ * Returns a tuple of two m1 vectors (high nibbles, low nibbles) for segment store.
450
+ */
451
+ NK_INTERNAL vint8m1x2_t nk_i4m1_to_i8m2_rvv_(vuint8m1_t packed_u8m1, nk_size_t vector_length) {
452
+ // Extract high nibble (even indices in output)
453
+ vuint8m1_t high_u8m1 = __riscv_vsrl_vx_u8m1(packed_u8m1, 4, vector_length);
454
+ // Sign extend: (x ^ 8) - 8
455
+ vint8m1_t high_i8m1 = __riscv_vsub_vx_i8m1(
456
+ __riscv_vxor_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(high_u8m1), 8, vector_length), 8, vector_length);
457
+
458
+ // Extract low nibble (odd indices in output)
459
+ vuint8m1_t low_u8m1 = __riscv_vand_vx_u8m1(packed_u8m1, 0x0F, vector_length);
460
+ // Sign extend: (x ^ 8) - 8
461
+ vint8m1_t low_i8m1 = __riscv_vsub_vx_i8m1(
462
+ __riscv_vxor_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(low_u8m1), 8, vector_length), 8, vector_length);
463
+
464
+ return __riscv_vcreate_v_i8m1x2(high_i8m1, low_i8m1);
465
+ }
466
+
467
+ /**
468
+ * @brief Unpack u4 (m1) nibbles to u8 (m2) register-to-register.
469
+ *
470
+ * Returns a tuple of two m1 vectors (high nibbles, low nibbles) for segment store.
471
+ */
472
+ NK_INTERNAL vuint8m1x2_t nk_u4m1_to_u8m2_rvv_(vuint8m1_t packed_u8m1, nk_size_t vector_length) {
473
+ // Extract high nibble (even indices in output)
474
+ vuint8m1_t high_u8m1 = __riscv_vsrl_vx_u8m1(packed_u8m1, 4, vector_length);
475
+
476
+ // Extract low nibble (odd indices in output)
477
+ vuint8m1_t low_u8m1 = __riscv_vand_vx_u8m1(packed_u8m1, 0x0F, vector_length);
478
+
479
+ return __riscv_vcreate_v_u8m1x2(high_u8m1, low_u8m1);
480
+ }
481
+
482
+ /**
483
+ * @brief Pack i8 (m2) to i4 (m1) nibbles register-to-register.
484
+ *
485
+ * Takes a tuple of two m1 vectors (high nibbles, low nibbles from segment load).
486
+ * Values are clamped to [-8, 7] before packing.
487
+ */
488
+ NK_INTERNAL vuint8m1_t nk_i8m2_to_i4m1_rvv_(vint8m1_t high_i8m1, vint8m1_t low_i8m1, nk_size_t vector_length) {
489
+ // Clamp to [-8, 7]
490
+ high_i8m1 = __riscv_vmax_vx_i8m1(__riscv_vmin_vx_i8m1(high_i8m1, 7, vector_length), -8, vector_length);
491
+ low_i8m1 = __riscv_vmax_vx_i8m1(__riscv_vmin_vx_i8m1(low_i8m1, 7, vector_length), -8, vector_length);
492
+
493
+ // Convert to unsigned nibbles: value & 0x0F
494
+ vuint8m1_t high_u4m1 = __riscv_vand_vx_u8m1(__riscv_vreinterpret_v_i8m1_u8m1(high_i8m1), 0x0F, vector_length);
495
+ vuint8m1_t low_u4m1 = __riscv_vand_vx_u8m1(__riscv_vreinterpret_v_i8m1_u8m1(low_i8m1), 0x0F, vector_length);
496
+
497
+ // Pack: (hi << 4) | lo
498
+ return __riscv_vor_vv_u8m1(__riscv_vsll_vx_u8m1(high_u4m1, 4, vector_length), low_u4m1, vector_length);
499
+ }
500
+
501
+ /**
502
+ * @brief Pack u8 (m2) to u4 (m1) nibbles register-to-register.
503
+ *
504
+ * Takes a tuple of two m1 vectors (high nibbles, low nibbles from segment load).
505
+ * Values are clamped to [0, 15] before packing.
506
+ */
507
+ NK_INTERNAL vuint8m1_t nk_u8m2_to_u4m1_rvv_(vuint8m1_t high_u8m1, vuint8m1_t low_u8m1, nk_size_t vector_length) {
508
+ // Clamp to [0, 15]
509
+ high_u8m1 = __riscv_vminu_vx_u8m1(high_u8m1, 15, vector_length);
510
+ low_u8m1 = __riscv_vminu_vx_u8m1(low_u8m1, 15, vector_length);
511
+
512
+ // Pack: (hi << 4) | lo
513
+ return __riscv_vor_vv_u8m1(__riscv_vsll_vx_u8m1(high_u8m1, 4, vector_length), low_u8m1, vector_length);
514
+ }
515
+
516
+ /**
517
+ * @brief Convert f32 (m4) to e4m3 (m1) register-to-register.
518
+ *
519
+ * E4M3FN format: S EEEE MMM (1 sign, 4 exponent bits with bias=7, 3 mantissa bits)
520
+ * Handles normal, subnormal, overflow, and NaN. Uses RNE mantissa rounding.
521
+ * E4M3FN quirk: exp=15 with mant=7 is NaN (0x7F), so max finite is 0x7E (exp=15, mant=6).
522
+ */
523
+ NK_INTERNAL vuint8m1_t nk_f32m4_to_e4m3m1_rvv_(vfloat32m4_t f32_f32m4, nk_size_t vector_length) {
524
+ vuint32m4_t bits_u32m4 = __riscv_vreinterpret_v_f32m4_u32m4(f32_f32m4);
525
+ vuint32m4_t sign_u32m4 = __riscv_vsrl_vx_u32m4(bits_u32m4, 31, vector_length);
526
+ vuint32m4_t abs_bits_u32m4 = __riscv_vand_vx_u32m4(bits_u32m4, 0x7FFFFFFF, vector_length);
527
+ vuint32m4_t f32_exp_u32m4 = __riscv_vand_vx_u32m4(__riscv_vsrl_vx_u32m4(bits_u32m4, 23, vector_length), 0xFF,
528
+ vector_length);
529
+
530
+ // Round mantissa from 23 to 3 bits using RNE (round to nearest, ties to even)
531
+ vuint32m4_t significand_u32m4 = __riscv_vor_vx_u32m4(__riscv_vand_vx_u32m4(bits_u32m4, 0x007FFFFF, vector_length),
532
+ 0x00800000, vector_length);
533
+ vuint32m4_t lsb_u32m4 = __riscv_vand_vx_u32m4(__riscv_vsrl_vx_u32m4(significand_u32m4, 20, vector_length), 1,
534
+ vector_length);
535
+ vuint32m4_t rounding_bias_u32m4 = __riscv_vadd_vx_u32m4(lsb_u32m4, 0x0007FFFF, vector_length);
536
+ vuint32m4_t rounded_sig_u32m4 = __riscv_vadd_vv_u32m4(significand_u32m4, rounding_bias_u32m4, vector_length);
537
+ vuint32m4_t carry_u32m4 = __riscv_vsrl_vx_u32m4(rounded_sig_u32m4, 24, vector_length);
538
+ vuint32m4_t f32_mantissa_u32m4 = __riscv_vand_vx_u32m4(__riscv_vsrl_vx_u32m4(rounded_sig_u32m4, 20, vector_length),
539
+ 0x07, vector_length);
540
+ // If carry, mantissa becomes 0 (rounded up to next power of 2)
541
+ vbool8_t has_carry_b8 = __riscv_vmsne_vx_u32m4_b8(carry_u32m4, 0, vector_length);
542
+ f32_mantissa_u32m4 = __riscv_vmerge_vxm_u32m4(f32_mantissa_u32m4, 0, has_carry_b8, vector_length);
543
+
544
+ // e4m3_exp = f32_exp + carry - 120
545
+ vint32m4_t e4m3_exp_i32m4 = __riscv_vsub_vx_i32m4(
546
+ __riscv_vreinterpret_v_u32m4_i32m4(__riscv_vadd_vv_u32m4(f32_exp_u32m4, carry_u32m4, vector_length)), 120,
547
+ vector_length);
548
+
549
+ // Detect subnormal (exp <= 0) and overflow (exp > 15)
550
+ vbool8_t is_subnormal_b8 = __riscv_vmsle_vx_i32m4_b8(e4m3_exp_i32m4, 0, vector_length);
551
+ vbool8_t is_overflow_b8 = __riscv_vmsgt_vx_i32m4_b8(e4m3_exp_i32m4, 15, vector_length);
552
+
553
+ // Normal path: clamp exp to [1,15]
554
+ vint32m4_t clamped_exp_i32m4 = __riscv_vmax_vx_i32m4(e4m3_exp_i32m4, 1, vector_length);
555
+ clamped_exp_i32m4 = __riscv_vmin_vx_i32m4(clamped_exp_i32m4, 15, vector_length);
556
+ // E4M3FN quirk: exp=15 with mant=7 is NaN, so cap mantissa to 6 when exp=15
557
+ vbool8_t is_max_exp_b8 = __riscv_vmseq_vx_i32m4_b8(clamped_exp_i32m4, 15, vector_length);
558
+ vuint32m4_t max_mant_u32m4 = __riscv_vmerge_vxm_u32m4(__riscv_vmv_v_x_u32m4(7, vector_length), 6, is_max_exp_b8,
559
+ vector_length);
560
+ vuint32m4_t normal_mant_u32m4 = __riscv_vminu_vv_u32m4(f32_mantissa_u32m4, max_mant_u32m4, vector_length);
561
+ // On overflow, saturate to max finite (exp=15, mant=6 = 0x7E with sign)
562
+ normal_mant_u32m4 = __riscv_vmerge_vxm_u32m4(normal_mant_u32m4, 0x06, is_overflow_b8, vector_length);
563
+ vuint32m4_t normal_u32m4 = __riscv_vor_vv_u32m4(
564
+ __riscv_vsll_vx_u32m4(sign_u32m4, 7, vector_length),
565
+ __riscv_vor_vv_u32m4(
566
+ __riscv_vsll_vx_u32m4(__riscv_vreinterpret_v_i32m4_u32m4(clamped_exp_i32m4), 3, vector_length),
567
+ normal_mant_u32m4, vector_length),
568
+ vector_length);
569
+
570
+ // Subnormal path: mantissa = round(|f32| * 512)
571
+ vfloat32m4_t abs_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(abs_bits_u32m4);
572
+ vfloat32m4_t scaled_f32m4 = __riscv_vfmul_vf_f32m4(abs_f32m4, 512.0f, vector_length);
573
+ vint32m4_t subnorm_mant_i32m4 = __riscv_vfcvt_x_f_v_i32m4(scaled_f32m4, vector_length); // RNE rounding
574
+ // If rounds to 8+, promote to first normal (exp=1, mant=0 = 0x08)
575
+ vbool8_t promotes_b8 = __riscv_vmsgt_vx_i32m4_b8(subnorm_mant_i32m4, 7, vector_length);
576
+ subnorm_mant_i32m4 = __riscv_vmin_vx_i32m4(subnorm_mant_i32m4, 7, vector_length);
577
+ subnorm_mant_i32m4 = __riscv_vmax_vx_i32m4(subnorm_mant_i32m4, 0, vector_length);
578
+ vuint32m4_t subnorm_u32m4 = __riscv_vor_vv_u32m4(__riscv_vsll_vx_u32m4(sign_u32m4, 7, vector_length),
579
+ __riscv_vreinterpret_v_i32m4_u32m4(subnorm_mant_i32m4),
580
+ vector_length);
581
+ vuint32m4_t first_normal_u32m4 = __riscv_vor_vx_u32m4(__riscv_vsll_vx_u32m4(sign_u32m4, 7, vector_length), 0x08,
582
+ vector_length);
583
+ subnorm_u32m4 = __riscv_vmerge_vvm_u32m4(subnorm_u32m4, first_normal_u32m4, promotes_b8, vector_length);
584
+
585
+ // Select: subnormal when exp <= 0, else normal
586
+ vuint32m4_t result_u32m4 = __riscv_vmerge_vvm_u32m4(normal_u32m4, subnorm_u32m4, is_subnormal_b8, vector_length);
587
+
588
+ // Handle NaN: f32 NaN (abs_bits > 0x7F800000) → e4m3 NaN (sign | 0x7F)
589
+ vbool8_t is_nan_b8 = __riscv_vmsgtu_vx_u32m4_b8(abs_bits_u32m4, 0x7F800000, vector_length);
590
+ vuint32m4_t nan_u32m4 = __riscv_vor_vx_u32m4(__riscv_vsll_vx_u32m4(sign_u32m4, 7, vector_length), 0x7F,
591
+ vector_length);
592
+ result_u32m4 = __riscv_vmerge_vvm_u32m4(result_u32m4, nan_u32m4, is_nan_b8, vector_length);
593
+
594
+ // Narrow u32m4 → u16m2 → u8m1
595
+ vuint16m2_t result_u16m2 = __riscv_vncvt_x_x_w_u16m2(result_u32m4, vector_length);
596
+ return __riscv_vncvt_x_x_w_u8m1(result_u16m2, vector_length);
597
+ }
598
+
599
+ /**
600
+ * @brief Convert f32 (m4) to e5m2 (m1) register-to-register.
601
+ *
602
+ * E5M2 format: S EEEEE MM (1 sign, 5 exponent bits with bias=15, 2 mantissa bits)
603
+ * Handles normal, subnormal, overflow (→ infinity), and NaN. Uses RNE mantissa rounding.
604
+ */
605
+ NK_INTERNAL vuint8m1_t nk_f32m4_to_e5m2m1_rvv_(vfloat32m4_t f32_f32m4, nk_size_t vector_length) {
606
+ vuint32m4_t bits_u32m4 = __riscv_vreinterpret_v_f32m4_u32m4(f32_f32m4);
607
+ vuint32m4_t sign_u32m4 = __riscv_vsrl_vx_u32m4(bits_u32m4, 31, vector_length);
608
+ vuint32m4_t abs_bits_u32m4 = __riscv_vand_vx_u32m4(bits_u32m4, 0x7FFFFFFF, vector_length);
609
+ vuint32m4_t f32_exp_u32m4 = __riscv_vand_vx_u32m4(__riscv_vsrl_vx_u32m4(bits_u32m4, 23, vector_length), 0xFF,
610
+ vector_length);
611
+
612
+ // Round mantissa from 23 to 2 bits using RNE
613
+ vuint32m4_t significand_u32m4 = __riscv_vor_vx_u32m4(__riscv_vand_vx_u32m4(bits_u32m4, 0x007FFFFF, vector_length),
614
+ 0x00800000, vector_length);
615
+ vuint32m4_t lsb_u32m4 = __riscv_vand_vx_u32m4(__riscv_vsrl_vx_u32m4(significand_u32m4, 21, vector_length), 1,
616
+ vector_length);
617
+ vuint32m4_t rounding_bias_u32m4 = __riscv_vadd_vx_u32m4(lsb_u32m4, 0x000FFFFF, vector_length);
618
+ vuint32m4_t rounded_sig_u32m4 = __riscv_vadd_vv_u32m4(significand_u32m4, rounding_bias_u32m4, vector_length);
619
+ vuint32m4_t carry_u32m4 = __riscv_vsrl_vx_u32m4(rounded_sig_u32m4, 24, vector_length);
620
+ vuint32m4_t f32_mantissa_u32m4 = __riscv_vand_vx_u32m4(__riscv_vsrl_vx_u32m4(rounded_sig_u32m4, 21, vector_length),
621
+ 0x03, vector_length);
622
+ vbool8_t has_carry_b8 = __riscv_vmsne_vx_u32m4_b8(carry_u32m4, 0, vector_length);
623
+ f32_mantissa_u32m4 = __riscv_vmerge_vxm_u32m4(f32_mantissa_u32m4, 0, has_carry_b8, vector_length);
624
+
625
+ // e5m2_exp = f32_exp + carry - 112
626
+ vint32m4_t e5m2_exp_i32m4 = __riscv_vsub_vx_i32m4(
627
+ __riscv_vreinterpret_v_u32m4_i32m4(__riscv_vadd_vv_u32m4(f32_exp_u32m4, carry_u32m4, vector_length)), 112,
628
+ vector_length);
629
+
630
+ // Detect subnormal (exp <= 0) and overflow (exp > 31)
631
+ vbool8_t is_subnormal_b8 = __riscv_vmsle_vx_i32m4_b8(e5m2_exp_i32m4, 0, vector_length);
632
+ vbool8_t is_overflow_b8 = __riscv_vmsgt_vx_i32m4_b8(e5m2_exp_i32m4, 31, vector_length);
633
+
634
+ // Normal path: clamp exp to [1,31], on overflow return infinity (exp=31, mant=0)
635
+ vint32m4_t clamped_exp_i32m4 = __riscv_vmax_vx_i32m4(e5m2_exp_i32m4, 1, vector_length);
636
+ clamped_exp_i32m4 = __riscv_vmin_vx_i32m4(clamped_exp_i32m4, 31, vector_length);
637
+ vuint32m4_t normal_mant_u32m4 = __riscv_vmerge_vxm_u32m4(f32_mantissa_u32m4, 0, is_overflow_b8, vector_length);
638
+ vuint32m4_t normal_u32m4 = __riscv_vor_vv_u32m4(
639
+ __riscv_vsll_vx_u32m4(sign_u32m4, 7, vector_length),
640
+ __riscv_vor_vv_u32m4(
641
+ __riscv_vsll_vx_u32m4(__riscv_vreinterpret_v_i32m4_u32m4(clamped_exp_i32m4), 2, vector_length),
642
+ normal_mant_u32m4, vector_length),
643
+ vector_length);
644
+
645
+ // Subnormal path: mantissa = round(|f32| * 65536)
646
+ vfloat32m4_t abs_f32m4 = __riscv_vreinterpret_v_u32m4_f32m4(abs_bits_u32m4);
647
+ vfloat32m4_t scaled_f32m4 = __riscv_vfmul_vf_f32m4(abs_f32m4, 65536.0f, vector_length);
648
+ vint32m4_t subnorm_mant_i32m4 = __riscv_vfcvt_x_f_v_i32m4(scaled_f32m4, vector_length);
649
+ vbool8_t promotes_b8 = __riscv_vmsgt_vx_i32m4_b8(subnorm_mant_i32m4, 3, vector_length);
650
+ subnorm_mant_i32m4 = __riscv_vmin_vx_i32m4(subnorm_mant_i32m4, 3, vector_length);
651
+ subnorm_mant_i32m4 = __riscv_vmax_vx_i32m4(subnorm_mant_i32m4, 0, vector_length);
652
+ vuint32m4_t subnorm_u32m4 = __riscv_vor_vv_u32m4(__riscv_vsll_vx_u32m4(sign_u32m4, 7, vector_length),
653
+ __riscv_vreinterpret_v_i32m4_u32m4(subnorm_mant_i32m4),
654
+ vector_length);
655
+ vuint32m4_t first_normal_u32m4 = __riscv_vor_vx_u32m4(__riscv_vsll_vx_u32m4(sign_u32m4, 7, vector_length), 0x04,
656
+ vector_length);
657
+ subnorm_u32m4 = __riscv_vmerge_vvm_u32m4(subnorm_u32m4, first_normal_u32m4, promotes_b8, vector_length);
658
+
659
+ // Select: subnormal when exp <= 0, else normal
660
+ vuint32m4_t result_u32m4 = __riscv_vmerge_vvm_u32m4(normal_u32m4, subnorm_u32m4, is_subnormal_b8, vector_length);
661
+
662
+ // Handle NaN: f32 NaN (abs_bits > 0x7F800000) → e5m2 NaN (sign | 0x7D)
663
+ vbool8_t is_nan_b8 = __riscv_vmsgtu_vx_u32m4_b8(abs_bits_u32m4, 0x7F800000, vector_length);
664
+ vuint32m4_t nan_u32m4 = __riscv_vor_vx_u32m4(__riscv_vsll_vx_u32m4(sign_u32m4, 7, vector_length), 0x7D,
665
+ vector_length);
666
+ result_u32m4 = __riscv_vmerge_vvm_u32m4(result_u32m4, nan_u32m4, is_nan_b8, vector_length);
667
+
668
+ // Narrow u32m4 → u16m2 → u8m1
669
+ vuint16m2_t result_u16m2 = __riscv_vncvt_x_x_w_u16m2(result_u32m4, vector_length);
670
+ return __riscv_vncvt_x_x_w_u8m1(result_u16m2, vector_length);
671
+ }
672
+
673
+ #pragma endregion Register - to - Register Helpers
674
+
675
+ #pragma region Unified Cast Dispatcher
676
+
677
+ NK_PUBLIC void nk_cast_rvv(void const *from, nk_dtype_t from_type, nk_size_t count, void *to, nk_dtype_t to_type) {
678
+ // bf16 → f32
679
+ if (from_type == nk_bf16_k && to_type == nk_f32_k) {
680
+ nk_bf16_t const *source = (nk_bf16_t const *)from;
681
+ nk_f32_t *destination = (nk_f32_t *)to;
682
+ for (nk_size_t vector_length; count > 0;
683
+ count -= vector_length, source += vector_length, destination += vector_length) {
684
+ vector_length = __riscv_vsetvl_e16m1(count);
685
+ vuint16m1_t bf16_u16m1 = __riscv_vle16_v_u16m1((nk_u16_t const *)source, vector_length);
686
+ vfloat32m2_t f32_f32m2 = nk_bf16m1_to_f32m2_rvv_(bf16_u16m1, vector_length);
687
+ __riscv_vse32_v_f32m2(destination, f32_f32m2, vector_length);
688
+ }
689
+ return;
690
+ }
691
+
692
+ // f32 → bf16
693
+ if (from_type == nk_f32_k && to_type == nk_bf16_k) {
694
+ nk_f32_t const *source = (nk_f32_t const *)from;
695
+ nk_bf16_t *destination = (nk_bf16_t *)to;
696
+ for (nk_size_t vector_length; count > 0;
697
+ count -= vector_length, source += vector_length, destination += vector_length) {
698
+ vector_length = __riscv_vsetvl_e32m2(count);
699
+ vfloat32m2_t f32_f32m2 = __riscv_vle32_v_f32m2(source, vector_length);
700
+ vuint16m1_t bf16_u16m1 = nk_f32m2_to_bf16m1_rvv_(f32_f32m2, vector_length);
701
+ __riscv_vse16_v_u16m1((nk_u16_t *)destination, bf16_u16m1, vector_length);
702
+ }
703
+ return;
704
+ }
705
+
706
+ // f16 → f32
707
+ if (from_type == nk_f16_k && to_type == nk_f32_k) {
708
+ nk_f16_t const *source = (nk_f16_t const *)from;
709
+ nk_f32_t *destination = (nk_f32_t *)to;
710
+ for (nk_size_t vector_length; count > 0;
711
+ count -= vector_length, source += vector_length, destination += vector_length) {
712
+ vector_length = __riscv_vsetvl_e16m1(count);
713
+ vuint16m1_t f16_u16m1 = __riscv_vle16_v_u16m1((nk_u16_t const *)source, vector_length);
714
+ vfloat32m2_t f32_f32m2 = nk_f16m1_to_f32m2_rvv_(f16_u16m1, vector_length);
715
+ __riscv_vse32_v_f32m2(destination, f32_f32m2, vector_length);
716
+ }
717
+ return;
718
+ }
719
+
720
+ // f32 → f16
721
+ if (from_type == nk_f32_k && to_type == nk_f16_k) {
722
+ nk_f32_t const *source = (nk_f32_t const *)from;
723
+ nk_f16_t *destination = (nk_f16_t *)to;
724
+ for (nk_size_t vector_length; count > 0;
725
+ count -= vector_length, source += vector_length, destination += vector_length) {
726
+ vector_length = __riscv_vsetvl_e32m2(count);
727
+ vfloat32m2_t f32_f32m2 = __riscv_vle32_v_f32m2(source, vector_length);
728
+ vuint16m1_t f16_u16m1 = nk_f32m2_to_f16m1_rvv_(f32_f32m2, vector_length);
729
+ __riscv_vse16_v_u16m1((nk_u16_t *)destination, f16_u16m1, vector_length);
730
+ }
731
+ return;
732
+ }
733
+
734
+ // e4m3 → f32
735
+ if (from_type == nk_e4m3_k && to_type == nk_f32_k) {
736
+ nk_e4m3_t const *source = (nk_e4m3_t const *)from;
737
+ nk_f32_t *destination = (nk_f32_t *)to;
738
+ for (nk_size_t vector_length; count > 0;
739
+ count -= vector_length, source += vector_length, destination += vector_length) {
740
+ vector_length = __riscv_vsetvl_e8m1(count);
741
+ vuint8m1_t e4m3_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
742
+ vfloat32m4_t f32_f32m4 = nk_e4m3m1_to_f32m4_rvv_(e4m3_u8m1, vector_length);
743
+ __riscv_vse32_v_f32m4(destination, f32_f32m4, vector_length);
744
+ }
745
+ return;
746
+ }
747
+
748
+ // e5m2 → f32
749
+ if (from_type == nk_e5m2_k && to_type == nk_f32_k) {
750
+ nk_e5m2_t const *source = (nk_e5m2_t const *)from;
751
+ nk_f32_t *destination = (nk_f32_t *)to;
752
+ for (nk_size_t vector_length; count > 0;
753
+ count -= vector_length, source += vector_length, destination += vector_length) {
754
+ vector_length = __riscv_vsetvl_e8m1(count);
755
+ vuint8m1_t e5m2_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
756
+ vfloat32m4_t f32_f32m4 = nk_e5m2m1_to_f32m4_rvv_(e5m2_u8m1, vector_length);
757
+ __riscv_vse32_v_f32m4(destination, f32_f32m4, vector_length);
758
+ }
759
+ return;
760
+ }
761
+
762
+ // e2m3 → f32
763
+ if (from_type == nk_e2m3_k && to_type == nk_f32_k) {
764
+ nk_e2m3_t const *source = (nk_e2m3_t const *)from;
765
+ nk_f32_t *destination = (nk_f32_t *)to;
766
+ for (nk_size_t vector_length; count > 0;
767
+ count -= vector_length, source += vector_length, destination += vector_length) {
768
+ vector_length = __riscv_vsetvl_e8m1(count);
769
+ vuint8m1_t e2m3_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
770
+ vfloat32m4_t f32_f32m4 = nk_e2m3m1_to_f32m4_rvv_(e2m3_u8m1, vector_length);
771
+ __riscv_vse32_v_f32m4(destination, f32_f32m4, vector_length);
772
+ }
773
+ return;
774
+ }
775
+
776
+ // e3m2 → f32
777
+ if (from_type == nk_e3m2_k && to_type == nk_f32_k) {
778
+ nk_e3m2_t const *source = (nk_e3m2_t const *)from;
779
+ nk_f32_t *destination = (nk_f32_t *)to;
780
+ for (nk_size_t vector_length; count > 0;
781
+ count -= vector_length, source += vector_length, destination += vector_length) {
782
+ vector_length = __riscv_vsetvl_e8m1(count);
783
+ vuint8m1_t e3m2_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
784
+ vfloat32m4_t f32_f32m4 = nk_e3m2m1_to_f32m4_rvv_(e3m2_u8m1, vector_length);
785
+ __riscv_vse32_v_f32m4(destination, f32_f32m4, vector_length);
786
+ }
787
+ return;
788
+ }
789
+
790
+ // e4m3 → bf16
791
+ if (from_type == nk_e4m3_k && to_type == nk_bf16_k) {
792
+ nk_e4m3_t const *source = (nk_e4m3_t const *)from;
793
+ nk_bf16_t *destination = (nk_bf16_t *)to;
794
+ for (nk_size_t vector_length; count > 0;
795
+ count -= vector_length, source += vector_length, destination += vector_length) {
796
+ vector_length = __riscv_vsetvl_e8m1(count);
797
+ vuint8m1_t e4m3_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
798
+ vuint16m2_t bf16_u16m2 = nk_e4m3m1_to_bf16m2_rvv_(e4m3_u8m1, vector_length);
799
+ __riscv_vse16_v_u16m2((nk_u16_t *)destination, bf16_u16m2, vector_length);
800
+ }
801
+ return;
802
+ }
803
+
804
+ // e5m2 → bf16
805
+ if (from_type == nk_e5m2_k && to_type == nk_bf16_k) {
806
+ nk_e5m2_t const *source = (nk_e5m2_t const *)from;
807
+ nk_bf16_t *destination = (nk_bf16_t *)to;
808
+ for (nk_size_t vector_length; count > 0;
809
+ count -= vector_length, source += vector_length, destination += vector_length) {
810
+ vector_length = __riscv_vsetvl_e8m1(count);
811
+ vuint8m1_t e5m2_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
812
+ vuint16m2_t bf16_u16m2 = nk_e5m2m1_to_bf16m2_rvv_(e5m2_u8m1, vector_length);
813
+ __riscv_vse16_v_u16m2((nk_u16_t *)destination, bf16_u16m2, vector_length);
814
+ }
815
+ return;
816
+ }
817
+
818
+ // e2m3 → bf16
819
+ if (from_type == nk_e2m3_k && to_type == nk_bf16_k) {
820
+ nk_e2m3_t const *source = (nk_e2m3_t const *)from;
821
+ nk_bf16_t *destination = (nk_bf16_t *)to;
822
+ for (nk_size_t vector_length; count > 0;
823
+ count -= vector_length, source += vector_length, destination += vector_length) {
824
+ vector_length = __riscv_vsetvl_e8m1(count);
825
+ vuint8m1_t e2m3_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
826
+ vuint16m2_t bf16_u16m2 = nk_e2m3m1_to_bf16m2_rvv_(e2m3_u8m1, vector_length);
827
+ __riscv_vse16_v_u16m2((nk_u16_t *)destination, bf16_u16m2, vector_length);
828
+ }
829
+ return;
830
+ }
831
+
832
+ // e3m2 → bf16
833
+ if (from_type == nk_e3m2_k && to_type == nk_bf16_k) {
834
+ nk_e3m2_t const *source = (nk_e3m2_t const *)from;
835
+ nk_bf16_t *destination = (nk_bf16_t *)to;
836
+ for (nk_size_t vector_length; count > 0;
837
+ count -= vector_length, source += vector_length, destination += vector_length) {
838
+ vector_length = __riscv_vsetvl_e8m1(count);
839
+ vuint8m1_t e3m2_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
840
+ vuint16m2_t bf16_u16m2 = nk_e3m2m1_to_bf16m2_rvv_(e3m2_u8m1, vector_length);
841
+ __riscv_vse16_v_u16m2((nk_u16_t *)destination, bf16_u16m2, vector_length);
842
+ }
843
+ return;
844
+ }
845
+
846
+ // e4m3 → f16
847
+ if (from_type == nk_e4m3_k && to_type == nk_f16_k) {
848
+ nk_e4m3_t const *source = (nk_e4m3_t const *)from;
849
+ nk_f16_t *destination = (nk_f16_t *)to;
850
+ for (nk_size_t vector_length; count > 0;
851
+ count -= vector_length, source += vector_length, destination += vector_length) {
852
+ vector_length = __riscv_vsetvl_e8m1(count);
853
+ vuint8m1_t e4m3_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
854
+ vuint16m2_t f16_u16m2 = nk_e4m3m1_to_f16m2_rvv_(e4m3_u8m1, vector_length);
855
+ __riscv_vse16_v_u16m2((nk_u16_t *)destination, f16_u16m2, vector_length);
856
+ }
857
+ return;
858
+ }
859
+
860
+ // e2m3 → f16
861
+ if (from_type == nk_e2m3_k && to_type == nk_f16_k) {
862
+ nk_e2m3_t const *source = (nk_e2m3_t const *)from;
863
+ nk_f16_t *destination = (nk_f16_t *)to;
864
+ for (nk_size_t vector_length; count > 0;
865
+ count -= vector_length, source += vector_length, destination += vector_length) {
866
+ vector_length = __riscv_vsetvl_e8m1(count);
867
+ vuint8m1_t e2m3_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
868
+ vuint16m2_t f16_u16m2 = nk_e2m3m1_to_f16m2_rvv_(e2m3_u8m1, vector_length);
869
+ __riscv_vse16_v_u16m2((nk_u16_t *)destination, f16_u16m2, vector_length);
870
+ }
871
+ return;
872
+ }
873
+
874
+ // e3m2 → f16
875
+ if (from_type == nk_e3m2_k && to_type == nk_f16_k) {
876
+ nk_e3m2_t const *source = (nk_e3m2_t const *)from;
877
+ nk_f16_t *destination = (nk_f16_t *)to;
878
+ for (nk_size_t vector_length; count > 0;
879
+ count -= vector_length, source += vector_length, destination += vector_length) {
880
+ vector_length = __riscv_vsetvl_e8m1(count);
881
+ vuint8m1_t e3m2_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
882
+ vuint16m2_t f16_u16m2 = nk_e3m2m1_to_f16m2_rvv_(e3m2_u8m1, vector_length);
883
+ __riscv_vse16_v_u16m2((nk_u16_t *)destination, f16_u16m2, vector_length);
884
+ }
885
+ return;
886
+ }
887
+
888
+ // i4 → i8
889
+ if (from_type == nk_i4_k && to_type == nk_i8_k) {
890
+ nk_i4x2_t const *source = (nk_i4x2_t const *)from;
891
+ nk_i8_t *destination = (nk_i8_t *)to;
892
+ nk_size_t n_bytes = count / 2;
893
+ for (nk_size_t vector_length; n_bytes > 0;
894
+ n_bytes -= vector_length, source += vector_length, destination += vector_length * 2) {
895
+ vector_length = __riscv_vsetvl_e8m1(n_bytes);
896
+ vuint8m1_t packed_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
897
+ vint8m1x2_t unpacked_i8m1x2 = nk_i4m1_to_i8m2_rvv_(packed_u8m1, vector_length);
898
+ __riscv_vsseg2e8_v_i8m1x2(destination, unpacked_i8m1x2, vector_length);
899
+ }
900
+ return;
901
+ }
902
+
903
+ // u4 → u8
904
+ if (from_type == nk_u4_k && to_type == nk_u8_k) {
905
+ nk_u4x2_t const *source = (nk_u4x2_t const *)from;
906
+ nk_u8_t *destination = (nk_u8_t *)to;
907
+ nk_size_t n_bytes = count / 2;
908
+ for (nk_size_t vector_length; n_bytes > 0;
909
+ n_bytes -= vector_length, source += vector_length, destination += vector_length * 2) {
910
+ vector_length = __riscv_vsetvl_e8m1(n_bytes);
911
+ vuint8m1_t packed_u8m1 = __riscv_vle8_v_u8m1((nk_u8_t const *)source, vector_length);
912
+ vuint8m1x2_t unpacked_u8m1x2 = nk_u4m1_to_u8m2_rvv_(packed_u8m1, vector_length);
913
+ __riscv_vsseg2e8_v_u8m1x2(destination, unpacked_u8m1x2, vector_length);
914
+ }
915
+ return;
916
+ }
917
+
918
+ // i8 → i4
919
+ if (from_type == nk_i8_k && to_type == nk_i4_k) {
920
+ nk_i8_t const *source = (nk_i8_t const *)from;
921
+ nk_i4x2_t *destination = (nk_i4x2_t *)to;
922
+ nk_size_t n_bytes = count / 2;
923
+ for (nk_size_t vector_length; n_bytes > 0;
924
+ n_bytes -= vector_length, source += vector_length * 2, destination += vector_length) {
925
+ vector_length = __riscv_vsetvl_e8m1(n_bytes);
926
+ vint8m1x2_t loaded_i8m1x2 = __riscv_vlseg2e8_v_i8m1x2(source, vector_length);
927
+ vint8m1_t high_i8m1 = __riscv_vget_v_i8m1x2_i8m1(loaded_i8m1x2, 0);
928
+ vint8m1_t low_i8m1 = __riscv_vget_v_i8m1x2_i8m1(loaded_i8m1x2, 1);
929
+ vuint8m1_t packed_u8m1 = nk_i8m2_to_i4m1_rvv_(high_i8m1, low_i8m1, vector_length);
930
+ __riscv_vse8_v_u8m1((nk_u8_t *)destination, packed_u8m1, vector_length);
931
+ }
932
+ return;
933
+ }
934
+
935
+ // u8 → u4
936
+ if (from_type == nk_u8_k && to_type == nk_u4_k) {
937
+ nk_u8_t const *source = (nk_u8_t const *)from;
938
+ nk_u4x2_t *destination = (nk_u4x2_t *)to;
939
+ nk_size_t n_bytes = count / 2;
940
+ for (nk_size_t vector_length; n_bytes > 0;
941
+ n_bytes -= vector_length, source += vector_length * 2, destination += vector_length) {
942
+ vector_length = __riscv_vsetvl_e8m1(n_bytes);
943
+ vuint8m1x2_t loaded_u8m1x2 = __riscv_vlseg2e8_v_u8m1x2(source, vector_length);
944
+ vuint8m1_t high_u8m1 = __riscv_vget_v_u8m1x2_u8m1(loaded_u8m1x2, 0);
945
+ vuint8m1_t low_u8m1 = __riscv_vget_v_u8m1x2_u8m1(loaded_u8m1x2, 1);
946
+ vuint8m1_t packed_u8m1 = nk_u8m2_to_u4m1_rvv_(high_u8m1, low_u8m1, vector_length);
947
+ __riscv_vse8_v_u8m1((nk_u8_t *)destination, packed_u8m1, vector_length);
948
+ }
949
+ return;
950
+ }
951
+
952
+ // Fallback to serial for unimplemented conversions
953
+ nk_cast_serial(from, from_type, count, to, to_type);
954
+ }
955
+
956
+ #pragma endregion Unified Cast Dispatcher
957
+
958
+ #if defined(__cplusplus)
959
+ } // extern "C"
960
+ #endif
961
+
962
+ #if defined(__clang__)
963
+ #pragma clang attribute pop
964
+ #elif defined(__GNUC__)
965
+ #pragma GCC pop_options
966
+ #endif
967
+
968
+ #endif // NK_TARGET_RVV
969
+ #endif // NK_TARGET_RISCV64_
970
+ #endif // NK_CAST_RVV_H