usearch 2.21.4 → 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.
- package/README.md +24 -24
- package/binding.gyp +15 -37
- package/c/CMakeLists.txt +4 -5
- package/c/README.md +7 -7
- package/c/lib.cpp +32 -14
- package/c/test.c +83 -1
- package/c/usearch.h +24 -3
- package/cpp/CMakeLists.txt +4 -0
- package/cpp/README.md +5 -5
- package/cpp/bench.cpp +97 -116
- package/cpp/test.cpp +117 -20
- package/include/usearch/index.hpp +224 -48
- package/include/usearch/index_dense.hpp +105 -40
- package/include/usearch/index_plugins.hpp +1387 -204
- package/javascript/dist/cjs/usearch.d.ts +8 -3
- package/javascript/dist/cjs/usearch.js +12 -4
- package/javascript/dist/esm/usearch.d.ts +8 -3
- package/javascript/dist/esm/usearch.js +12 -4
- package/javascript/lib.cpp +17 -0
- package/javascript/usearch.ts +14 -6
- package/numkong/.clang-tidy +30 -0
- package/{simsimd → numkong}/.cmake-format.py +18 -0
- package/numkong/.editorconfig +12 -0
- package/numkong/.git-blame-ignore-revs +123 -0
- package/numkong/.mailmap +15 -0
- package/numkong/.spi.yml +11 -0
- package/numkong/.swift-format +14 -0
- package/numkong/CITATION.cff +81 -0
- package/numkong/CONTRIBUTING.md +500 -0
- package/numkong/Cargo.toml +54 -0
- package/numkong/MANIFEST.in +8 -0
- package/numkong/Package.swift +84 -0
- package/numkong/README.md +569 -0
- package/numkong/bench/README.md +217 -0
- package/numkong/bench/bench-browser.html +323 -0
- package/numkong/bench/bench.cpp +344 -0
- package/numkong/bench/bench.hpp +816 -0
- package/numkong/bench/bench.js +148 -0
- package/numkong/bench/bench.mjs +616 -0
- package/numkong/bench/bench_attention.cpp +113 -0
- package/numkong/bench/bench_cast.cpp +264 -0
- package/numkong/bench/bench_cross_amx.cpp +62 -0
- package/numkong/bench/bench_cross_arm.cpp +245 -0
- package/numkong/bench/bench_cross_blas.cpp +309 -0
- package/numkong/bench/bench_cross_loongarch.cpp +106 -0
- package/numkong/bench/bench_cross_power.cpp +84 -0
- package/numkong/bench/bench_cross_rvv.cpp +121 -0
- package/numkong/bench/bench_cross_serial.cpp +151 -0
- package/numkong/bench/bench_cross_sme.cpp +163 -0
- package/numkong/bench/bench_cross_wasm.cpp +142 -0
- package/numkong/bench/bench_cross_x86.cpp +455 -0
- package/numkong/bench/bench_curved.cpp +210 -0
- package/numkong/bench/bench_dot.cpp +315 -0
- package/numkong/bench/bench_each.cpp +503 -0
- package/numkong/bench/bench_geospatial.cpp +112 -0
- package/numkong/bench/bench_maxsim.cpp +154 -0
- package/numkong/bench/bench_mesh.cpp +148 -0
- package/numkong/bench/bench_probability.cpp +60 -0
- package/numkong/bench/bench_reduce.cpp +371 -0
- package/numkong/bench/bench_set.cpp +73 -0
- package/numkong/bench/bench_sparse.cpp +198 -0
- package/numkong/bench/bench_spatial.cpp +347 -0
- package/numkong/bench/bench_trigonometry.cpp +137 -0
- package/numkong/bench/swift/Bench.swift +506 -0
- package/numkong/binding.gyp +169 -0
- package/numkong/build.rs +484 -0
- package/numkong/c/dispatch.h +512 -0
- package/numkong/c/dispatch_bf16.c +447 -0
- package/numkong/c/dispatch_bf16c.c +52 -0
- package/numkong/c/dispatch_e2m3.c +296 -0
- package/numkong/c/dispatch_e3m2.c +284 -0
- package/numkong/c/dispatch_e4m3.c +318 -0
- package/numkong/c/dispatch_e5m2.c +316 -0
- package/numkong/c/dispatch_f16.c +452 -0
- package/numkong/c/dispatch_f16c.c +58 -0
- package/numkong/c/dispatch_f32.c +434 -0
- package/numkong/c/dispatch_f32c.c +99 -0
- package/numkong/c/dispatch_f64.c +348 -0
- package/numkong/c/dispatch_f64c.c +98 -0
- package/numkong/c/dispatch_i16.c +96 -0
- package/numkong/c/dispatch_i32.c +89 -0
- package/numkong/c/dispatch_i4.c +153 -0
- package/numkong/c/dispatch_i64.c +86 -0
- package/numkong/c/dispatch_i8.c +348 -0
- package/numkong/c/dispatch_other.c +348 -0
- package/numkong/c/dispatch_u1.c +193 -0
- package/numkong/c/dispatch_u16.c +124 -0
- package/numkong/c/dispatch_u32.c +118 -0
- package/numkong/c/dispatch_u4.c +153 -0
- package/numkong/c/dispatch_u64.c +102 -0
- package/numkong/c/dispatch_u8.c +364 -0
- package/numkong/c/numkong.c +940 -0
- package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
- package/numkong/cmake/nk_isa_probe.cmake +90 -0
- package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
- package/numkong/cmake/nk_math_lib.cmake +46 -0
- package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
- package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
- package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
- package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
- package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
- package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
- package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
- package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
- package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
- package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
- package/numkong/cmake/toolchain-wasi.cmake +77 -0
- package/numkong/cmake/toolchain-wasm.cmake +70 -0
- package/numkong/cmake/toolchain-wasm64.cmake +62 -0
- package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
- package/numkong/include/README.md +643 -0
- package/numkong/include/module.modulemap +129 -0
- package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
- package/numkong/include/numkong/attention/sme.h +2075 -0
- package/numkong/include/numkong/attention.h +49 -0
- package/numkong/include/numkong/capabilities.h +930 -0
- package/numkong/include/numkong/cast/README.md +262 -0
- package/numkong/include/numkong/cast/diamond.h +64 -0
- package/numkong/include/numkong/cast/haswell.h +823 -0
- package/numkong/include/numkong/cast/icelake.h +475 -0
- package/numkong/include/numkong/cast/loongsonasx.h +252 -0
- package/numkong/include/numkong/cast/neon.h +1174 -0
- package/numkong/include/numkong/cast/powervsx.h +449 -0
- package/numkong/include/numkong/cast/rvv.h +970 -0
- package/numkong/include/numkong/cast/sapphire.h +262 -0
- package/numkong/include/numkong/cast/serial.h +2336 -0
- package/numkong/include/numkong/cast/skylake.h +915 -0
- package/numkong/include/numkong/cast/v128relaxed.h +537 -0
- package/numkong/include/numkong/cast.h +254 -0
- package/numkong/include/numkong/cast.hpp +44 -0
- package/numkong/include/numkong/curved/README.md +223 -0
- package/numkong/include/numkong/curved/genoa.h +182 -0
- package/numkong/include/numkong/curved/haswell.h +276 -0
- package/numkong/include/numkong/curved/neon.h +329 -0
- package/numkong/include/numkong/curved/neonbfdot.h +211 -0
- package/numkong/include/numkong/curved/rvv.h +305 -0
- package/numkong/include/numkong/curved/serial.h +207 -0
- package/numkong/include/numkong/curved/skylake.h +457 -0
- package/numkong/include/numkong/curved/smef64.h +530 -0
- package/numkong/include/numkong/curved.h +513 -0
- package/numkong/include/numkong/curved.hpp +144 -0
- package/numkong/include/numkong/dot/README.md +442 -0
- package/numkong/include/numkong/dot/alder.h +563 -0
- package/numkong/include/numkong/dot/diamond.h +158 -0
- package/numkong/include/numkong/dot/genoa.h +289 -0
- package/numkong/include/numkong/dot/haswell.h +1723 -0
- package/numkong/include/numkong/dot/icelake.h +997 -0
- package/numkong/include/numkong/dot/loongsonasx.h +671 -0
- package/numkong/include/numkong/dot/neon.h +869 -0
- package/numkong/include/numkong/dot/neonbfdot.h +243 -0
- package/numkong/include/numkong/dot/neonfhm.h +358 -0
- package/numkong/include/numkong/dot/neonfp8.h +323 -0
- package/numkong/include/numkong/dot/neonsdot.h +622 -0
- package/numkong/include/numkong/dot/powervsx.h +752 -0
- package/numkong/include/numkong/dot/rvv.h +722 -0
- package/numkong/include/numkong/dot/rvvbb.h +72 -0
- package/numkong/include/numkong/dot/rvvbf16.h +123 -0
- package/numkong/include/numkong/dot/rvvhalf.h +129 -0
- package/numkong/include/numkong/dot/sapphire.h +141 -0
- package/numkong/include/numkong/dot/serial.h +874 -0
- package/numkong/include/numkong/dot/sierra.h +405 -0
- package/numkong/include/numkong/dot/skylake.h +1116 -0
- package/numkong/include/numkong/dot/sve.h +420 -0
- package/numkong/include/numkong/dot/svebfdot.h +75 -0
- package/numkong/include/numkong/dot/svehalf.h +168 -0
- package/numkong/include/numkong/dot/svesdot.h +90 -0
- package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
- package/numkong/include/numkong/dot.h +1136 -0
- package/numkong/include/numkong/dot.hpp +94 -0
- package/numkong/include/numkong/dots/README.md +496 -0
- package/numkong/include/numkong/dots/alder.h +117 -0
- package/numkong/include/numkong/dots/diamond.h +86 -0
- package/numkong/include/numkong/dots/genoa.h +100 -0
- package/numkong/include/numkong/dots/graniteamx.h +733 -0
- package/numkong/include/numkong/dots/haswell.h +310 -0
- package/numkong/include/numkong/dots/icelake.h +180 -0
- package/numkong/include/numkong/dots/loongsonasx.h +176 -0
- package/numkong/include/numkong/dots/neon.h +123 -0
- package/numkong/include/numkong/dots/neonbfdot.h +59 -0
- package/numkong/include/numkong/dots/neonfhm.h +96 -0
- package/numkong/include/numkong/dots/neonfp8.h +99 -0
- package/numkong/include/numkong/dots/neonsdot.h +144 -0
- package/numkong/include/numkong/dots/powervsx.h +194 -0
- package/numkong/include/numkong/dots/rvv.h +2593 -0
- package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
- package/numkong/include/numkong/dots/serial.h +2867 -0
- package/numkong/include/numkong/dots/sierra.h +100 -0
- package/numkong/include/numkong/dots/skylake.h +207 -0
- package/numkong/include/numkong/dots/sme.h +5041 -0
- package/numkong/include/numkong/dots/smebi32.h +477 -0
- package/numkong/include/numkong/dots/smef64.h +1328 -0
- package/numkong/include/numkong/dots/smehalf.h +47 -0
- package/numkong/include/numkong/dots/v128relaxed.h +317 -0
- package/numkong/include/numkong/dots.h +3110 -0
- package/numkong/include/numkong/dots.hpp +641 -0
- package/numkong/include/numkong/each/README.md +465 -0
- package/numkong/include/numkong/each/haswell.h +1658 -0
- package/numkong/include/numkong/each/icelake.h +272 -0
- package/numkong/include/numkong/each/neon.h +1138 -0
- package/numkong/include/numkong/each/neonbfdot.h +211 -0
- package/numkong/include/numkong/each/neonhalf.h +318 -0
- package/numkong/include/numkong/each/rvv.h +1121 -0
- package/numkong/include/numkong/each/sapphire.h +343 -0
- package/numkong/include/numkong/each/serial.h +282 -0
- package/numkong/include/numkong/each/skylake.h +1562 -0
- package/numkong/include/numkong/each/v128relaxed.h +562 -0
- package/numkong/include/numkong/each.h +2232 -0
- package/numkong/include/numkong/each.hpp +434 -0
- package/numkong/include/numkong/geospatial/README.md +147 -0
- package/numkong/include/numkong/geospatial/haswell.h +633 -0
- package/numkong/include/numkong/geospatial/neon.h +615 -0
- package/numkong/include/numkong/geospatial/rvv.h +701 -0
- package/numkong/include/numkong/geospatial/serial.h +309 -0
- package/numkong/include/numkong/geospatial/skylake.h +613 -0
- package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
- package/numkong/include/numkong/geospatial.h +453 -0
- package/numkong/include/numkong/geospatial.hpp +235 -0
- package/numkong/include/numkong/matrix.hpp +336 -0
- package/numkong/include/numkong/maxsim/README.md +187 -0
- package/numkong/include/numkong/maxsim/alder.h +511 -0
- package/numkong/include/numkong/maxsim/genoa.h +115 -0
- package/numkong/include/numkong/maxsim/haswell.h +553 -0
- package/numkong/include/numkong/maxsim/icelake.h +480 -0
- package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
- package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
- package/numkong/include/numkong/maxsim/serial.h +490 -0
- package/numkong/include/numkong/maxsim/sme.h +993 -0
- package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
- package/numkong/include/numkong/maxsim.h +571 -0
- package/numkong/include/numkong/maxsim.hpp +133 -0
- package/numkong/include/numkong/mesh/README.md +219 -0
- package/numkong/include/numkong/mesh/haswell.h +2013 -0
- package/numkong/include/numkong/mesh/neon.h +1821 -0
- package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
- package/numkong/include/numkong/mesh/rvv.h +936 -0
- package/numkong/include/numkong/mesh/serial.h +721 -0
- package/numkong/include/numkong/mesh/skylake.h +2344 -0
- package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
- package/numkong/include/numkong/mesh.h +666 -0
- package/numkong/include/numkong/mesh.hpp +701 -0
- package/numkong/include/numkong/numkong.h +78 -0
- package/numkong/include/numkong/numkong.hpp +58 -0
- package/numkong/include/numkong/probability/README.md +177 -0
- package/numkong/include/numkong/probability/haswell.h +267 -0
- package/numkong/include/numkong/probability/neon.h +255 -0
- package/numkong/include/numkong/probability/rvv.h +414 -0
- package/numkong/include/numkong/probability/serial.h +181 -0
- package/numkong/include/numkong/probability/skylake.h +324 -0
- package/numkong/include/numkong/probability.h +380 -0
- package/numkong/include/numkong/probability.hpp +120 -0
- package/numkong/include/numkong/random.h +50 -0
- package/numkong/include/numkong/random.hpp +285 -0
- package/numkong/include/numkong/reduce/README.md +552 -0
- package/numkong/include/numkong/reduce/alder.h +636 -0
- package/numkong/include/numkong/reduce/genoa.h +201 -0
- package/numkong/include/numkong/reduce/haswell.h +3785 -0
- package/numkong/include/numkong/reduce/icelake.h +549 -0
- package/numkong/include/numkong/reduce/neon.h +3980 -0
- package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
- package/numkong/include/numkong/reduce/neonfhm.h +293 -0
- package/numkong/include/numkong/reduce/neonsdot.h +357 -0
- package/numkong/include/numkong/reduce/rvv.h +3533 -0
- package/numkong/include/numkong/reduce/serial.h +753 -0
- package/numkong/include/numkong/reduce/sierra.h +338 -0
- package/numkong/include/numkong/reduce/skylake.h +3794 -0
- package/numkong/include/numkong/reduce/sve.h +52 -0
- package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
- package/numkong/include/numkong/reduce.h +1582 -0
- package/numkong/include/numkong/reduce.hpp +778 -0
- package/numkong/include/numkong/scalar/README.md +89 -0
- package/numkong/include/numkong/scalar/haswell.h +122 -0
- package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
- package/numkong/include/numkong/scalar/neon.h +122 -0
- package/numkong/include/numkong/scalar/neonhalf.h +70 -0
- package/numkong/include/numkong/scalar/powervsx.h +96 -0
- package/numkong/include/numkong/scalar/rvv.h +211 -0
- package/numkong/include/numkong/scalar/sapphire.h +74 -0
- package/numkong/include/numkong/scalar/serial.h +332 -0
- package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
- package/numkong/include/numkong/scalar.h +696 -0
- package/numkong/include/numkong/set/README.md +179 -0
- package/numkong/include/numkong/set/haswell.h +334 -0
- package/numkong/include/numkong/set/icelake.h +485 -0
- package/numkong/include/numkong/set/loongsonasx.h +181 -0
- package/numkong/include/numkong/set/neon.h +363 -0
- package/numkong/include/numkong/set/powervsx.h +326 -0
- package/numkong/include/numkong/set/rvv.h +226 -0
- package/numkong/include/numkong/set/rvvbb.h +117 -0
- package/numkong/include/numkong/set/serial.h +174 -0
- package/numkong/include/numkong/set/sve.h +187 -0
- package/numkong/include/numkong/set/v128relaxed.h +240 -0
- package/numkong/include/numkong/set.h +471 -0
- package/numkong/include/numkong/set.hpp +114 -0
- package/numkong/include/numkong/sets/README.md +149 -0
- package/numkong/include/numkong/sets/haswell.h +63 -0
- package/numkong/include/numkong/sets/icelake.h +66 -0
- package/numkong/include/numkong/sets/loongsonasx.h +52 -0
- package/numkong/include/numkong/sets/neon.h +61 -0
- package/numkong/include/numkong/sets/powervsx.h +65 -0
- package/numkong/include/numkong/sets/serial.h +43 -0
- package/numkong/include/numkong/sets/smebi32.h +1135 -0
- package/numkong/include/numkong/sets/v128relaxed.h +58 -0
- package/numkong/include/numkong/sets.h +382 -0
- package/numkong/include/numkong/sparse/README.md +156 -0
- package/numkong/include/numkong/sparse/icelake.h +463 -0
- package/numkong/include/numkong/sparse/neon.h +288 -0
- package/numkong/include/numkong/sparse/serial.h +117 -0
- package/numkong/include/numkong/sparse/sve2.h +504 -0
- package/numkong/include/numkong/sparse/turin.h +322 -0
- package/numkong/include/numkong/sparse.h +363 -0
- package/numkong/include/numkong/sparse.hpp +113 -0
- package/numkong/include/numkong/spatial/README.md +439 -0
- package/numkong/include/numkong/spatial/alder.h +604 -0
- package/numkong/include/numkong/spatial/diamond.h +240 -0
- package/numkong/include/numkong/spatial/genoa.h +222 -0
- package/numkong/include/numkong/spatial/haswell.h +979 -0
- package/numkong/include/numkong/spatial/icelake.h +1067 -0
- package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
- package/numkong/include/numkong/spatial/neon.h +846 -0
- package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
- package/numkong/include/numkong/spatial/neonfp8.h +258 -0
- package/numkong/include/numkong/spatial/neonsdot.h +429 -0
- package/numkong/include/numkong/spatial/powervsx.h +738 -0
- package/numkong/include/numkong/spatial/rvv.h +991 -0
- package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
- package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
- package/numkong/include/numkong/spatial/serial.h +347 -0
- package/numkong/include/numkong/spatial/sierra.h +516 -0
- package/numkong/include/numkong/spatial/skylake.h +605 -0
- package/numkong/include/numkong/spatial/sve.h +246 -0
- package/numkong/include/numkong/spatial/svebfdot.h +125 -0
- package/numkong/include/numkong/spatial/svehalf.h +136 -0
- package/numkong/include/numkong/spatial/svesdot.h +143 -0
- package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
- package/numkong/include/numkong/spatial.h +1681 -0
- package/numkong/include/numkong/spatial.hpp +183 -0
- package/numkong/include/numkong/spatials/README.md +580 -0
- package/numkong/include/numkong/spatials/alder.h +94 -0
- package/numkong/include/numkong/spatials/diamond.h +82 -0
- package/numkong/include/numkong/spatials/genoa.h +94 -0
- package/numkong/include/numkong/spatials/graniteamx.h +173 -0
- package/numkong/include/numkong/spatials/haswell.h +219 -0
- package/numkong/include/numkong/spatials/icelake.h +113 -0
- package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
- package/numkong/include/numkong/spatials/neon.h +109 -0
- package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
- package/numkong/include/numkong/spatials/neonfhm.h +92 -0
- package/numkong/include/numkong/spatials/neonfp8.h +111 -0
- package/numkong/include/numkong/spatials/neonsdot.h +143 -0
- package/numkong/include/numkong/spatials/powervsx.h +153 -0
- package/numkong/include/numkong/spatials/rvv.h +1976 -0
- package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
- package/numkong/include/numkong/spatials/serial.h +248 -0
- package/numkong/include/numkong/spatials/sierra.h +96 -0
- package/numkong/include/numkong/spatials/skylake.h +184 -0
- package/numkong/include/numkong/spatials/sme.h +1927 -0
- package/numkong/include/numkong/spatials/smef64.h +483 -0
- package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
- package/numkong/include/numkong/spatials.h +3374 -0
- package/numkong/include/numkong/spatials.hpp +509 -0
- package/numkong/include/numkong/tensor.hpp +1981 -0
- package/numkong/include/numkong/trigonometry/README.md +184 -0
- package/numkong/include/numkong/trigonometry/haswell.h +653 -0
- package/numkong/include/numkong/trigonometry/neon.h +638 -0
- package/numkong/include/numkong/trigonometry/rvv.h +700 -0
- package/numkong/include/numkong/trigonometry/serial.h +703 -0
- package/numkong/include/numkong/trigonometry/skylake.h +725 -0
- package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
- package/numkong/include/numkong/trigonometry.h +467 -0
- package/numkong/include/numkong/trigonometry.hpp +166 -0
- package/numkong/include/numkong/types.h +1695 -0
- package/numkong/include/numkong/types.hpp +6027 -0
- package/numkong/include/numkong/vector.hpp +766 -0
- package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
- package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
- package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
- package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
- package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
- package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
- package/numkong/javascript/README.md +254 -0
- package/numkong/javascript/node-gyp-build.d.ts +4 -0
- package/numkong/javascript/numkong-browser.ts +40 -0
- package/numkong/javascript/numkong-wasm.ts +750 -0
- package/numkong/javascript/numkong.c +712 -0
- package/numkong/javascript/numkong.ts +613 -0
- package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
- package/numkong/javascript/tsconfig-cjs.json +13 -0
- package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
- package/numkong/javascript/types.ts +784 -0
- package/numkong/numkong.gypi +104 -0
- package/numkong/package.json +108 -0
- package/numkong/probes/arm_neon.c +8 -0
- package/numkong/probes/arm_neon_bfdot.c +9 -0
- package/numkong/probes/arm_neon_fhm.c +9 -0
- package/numkong/probes/arm_neon_half.c +8 -0
- package/numkong/probes/arm_neon_sdot.c +9 -0
- package/numkong/probes/arm_neonfp8.c +9 -0
- package/numkong/probes/arm_sme.c +16 -0
- package/numkong/probes/arm_sme2.c +16 -0
- package/numkong/probes/arm_sme2p1.c +16 -0
- package/numkong/probes/arm_sme_bf16.c +16 -0
- package/numkong/probes/arm_sme_bi32.c +16 -0
- package/numkong/probes/arm_sme_f64.c +16 -0
- package/numkong/probes/arm_sme_fa64.c +14 -0
- package/numkong/probes/arm_sme_half.c +16 -0
- package/numkong/probes/arm_sme_lut2.c +15 -0
- package/numkong/probes/arm_sve.c +18 -0
- package/numkong/probes/arm_sve2.c +20 -0
- package/numkong/probes/arm_sve2p1.c +18 -0
- package/numkong/probes/arm_sve_bfdot.c +20 -0
- package/numkong/probes/arm_sve_half.c +18 -0
- package/numkong/probes/arm_sve_sdot.c +21 -0
- package/numkong/probes/loongarch_lasx.c +12 -0
- package/numkong/probes/power_vsx.c +12 -0
- package/numkong/probes/probe.js +127 -0
- package/numkong/probes/riscv_rvv.c +14 -0
- package/numkong/probes/riscv_rvv_bb.c +15 -0
- package/numkong/probes/riscv_rvv_bf16.c +17 -0
- package/numkong/probes/riscv_rvv_half.c +14 -0
- package/numkong/probes/wasm_v128relaxed.c +11 -0
- package/numkong/probes/x86_alder.c +17 -0
- package/numkong/probes/x86_diamond.c +17 -0
- package/numkong/probes/x86_genoa.c +17 -0
- package/numkong/probes/x86_graniteamx.c +19 -0
- package/numkong/probes/x86_haswell.c +11 -0
- package/numkong/probes/x86_icelake.c +17 -0
- package/numkong/probes/x86_sapphire.c +16 -0
- package/numkong/probes/x86_sapphireamx.c +18 -0
- package/numkong/probes/x86_sierra.c +17 -0
- package/numkong/probes/x86_skylake.c +15 -0
- package/numkong/probes/x86_turin.c +17 -0
- package/numkong/rust/README.md +698 -0
- package/numkong/rust/capabilities.rs +96 -0
- package/numkong/rust/cast.rs +314 -0
- package/numkong/rust/curved.rs +391 -0
- package/numkong/rust/each.rs +2721 -0
- package/numkong/rust/geospatial.rs +343 -0
- package/numkong/rust/matrix.rs +5424 -0
- package/numkong/rust/maxsim.rs +540 -0
- package/numkong/rust/mesh.rs +837 -0
- package/numkong/rust/numkong.rs +409 -0
- package/numkong/rust/probability.rs +272 -0
- package/numkong/rust/reduce.rs +1249 -0
- package/numkong/rust/set.rs +194 -0
- package/numkong/rust/sparse.rs +513 -0
- package/numkong/rust/spatial.rs +1815 -0
- package/numkong/rust/tensor.rs +7565 -0
- package/numkong/rust/types.rs +3666 -0
- package/numkong/rust/vector.rs +1899 -0
- package/numkong/rustfmt.toml +2 -0
- package/numkong/swift/Matrix.swift +1388 -0
- package/numkong/swift/MaxSim.swift +151 -0
- package/numkong/swift/NumKong.swift +283 -0
- package/numkong/swift/Numerics.swift +329 -0
- package/numkong/swift/README.md +433 -0
- package/numkong/swift/Scalar.swift +741 -0
- package/numkong/swift/Tensor.swift +209 -0
- package/numkong/test/README.md +315 -0
- package/numkong/test/playwright.config.ts +16 -0
- package/numkong/test/swift/Test.swift +534 -0
- package/numkong/test/test-browser-bundle-runner.mjs +36 -0
- package/numkong/test/test-browser-bundle.html +188 -0
- package/numkong/test/test-browser-runner.mjs +43 -0
- package/numkong/test/test-browser.html +305 -0
- package/numkong/test/test-dtypes.mjs +453 -0
- package/numkong/test/test-wasm.mjs +267 -0
- package/numkong/test/test.cpp +442 -0
- package/numkong/test/test.hpp +580 -0
- package/numkong/test/test.mjs +363 -0
- package/numkong/test/test_base.py +1041 -0
- package/numkong/test/test_cast.cpp +242 -0
- package/numkong/test/test_cross.hpp +551 -0
- package/numkong/test/test_cross.py +467 -0
- package/numkong/test/test_cross_amx.cpp +50 -0
- package/numkong/test/test_cross_arm.cpp +225 -0
- package/numkong/test/test_cross_blas.cpp +354 -0
- package/numkong/test/test_cross_loongarch.cpp +90 -0
- package/numkong/test/test_cross_power.cpp +73 -0
- package/numkong/test/test_cross_rvv.cpp +109 -0
- package/numkong/test/test_cross_serial.cpp +181 -0
- package/numkong/test/test_cross_sme.cpp +148 -0
- package/numkong/test/test_cross_wasm.cpp +141 -0
- package/numkong/test/test_cross_x86.cpp +442 -0
- package/numkong/test/test_curved.cpp +182 -0
- package/numkong/test/test_curved.py +207 -0
- package/numkong/test/test_dot.cpp +353 -0
- package/numkong/test/test_dot.py +296 -0
- package/numkong/test/test_each.cpp +437 -0
- package/numkong/test/test_each.py +756 -0
- package/numkong/test/test_geospatial.cpp +155 -0
- package/numkong/test/test_geospatial.py +241 -0
- package/numkong/test/test_maxsim.cpp +138 -0
- package/numkong/test/test_maxsim.py +209 -0
- package/numkong/test/test_mesh.cpp +203 -0
- package/numkong/test/test_mesh.py +394 -0
- package/numkong/test/test_probability.cpp +136 -0
- package/numkong/test/test_probability.py +166 -0
- package/numkong/test/test_reduce.cpp +563 -0
- package/numkong/test/test_reduce.py +781 -0
- package/numkong/test/test_set.cpp +151 -0
- package/numkong/test/test_set.py +120 -0
- package/numkong/test/test_similarities.py +579 -0
- package/numkong/test/test_sparse.cpp +121 -0
- package/numkong/test/test_sparse.py +118 -0
- package/numkong/test/test_spatial.cpp +518 -0
- package/numkong/test/test_spatial.py +269 -0
- package/numkong/test/test_tensor.cpp +884 -0
- package/numkong/test/test_tensor.py +1417 -0
- package/numkong/test/test_trigonometry.cpp +156 -0
- package/numkong/test/test_trigonometry.py +180 -0
- package/package.json +7 -8
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/fp16/CMakeLists.txt +0 -176
- package/fp16/LICENSE +0 -11
- package/fp16/README.md +0 -20
- package/fp16/bench/alt-element.cc +0 -89
- package/fp16/bench/from-alt-array.cc +0 -175
- package/fp16/bench/from-ieee-array.cc +0 -399
- package/fp16/bench/ieee-element.cc +0 -272
- package/fp16/bench/to-alt-array.cc +0 -91
- package/fp16/bench/to-ieee-array.cc +0 -303
- package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
- package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
- package/fp16/cmake/DownloadPSimd.cmake +0 -15
- package/fp16/configure.py +0 -65
- package/fp16/confu.yaml +0 -8
- package/fp16/include/fp16/__init__.py +0 -0
- package/fp16/include/fp16/avx.py +0 -50
- package/fp16/include/fp16/avx2.py +0 -53
- package/fp16/include/fp16/bitcasts.h +0 -92
- package/fp16/include/fp16/fp16.h +0 -451
- package/fp16/include/fp16/psimd.h +0 -131
- package/fp16/include/fp16.h +0 -11
- package/fp16/jni/Android.mk +0 -6
- package/fp16/jni/Application.mk +0 -4
- package/fp16/test/alt-from-fp32-value.cc +0 -498
- package/fp16/test/alt-to-fp32-bits.cc +0 -263
- package/fp16/test/alt-to-fp32-psimd.cc +0 -145
- package/fp16/test/alt-to-fp32-value.cc +0 -348
- package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
- package/fp16/test/bitcasts.cc +0 -56
- package/fp16/test/ieee-from-fp32-value.cc +0 -523
- package/fp16/test/ieee-to-fp32-bits.cc +0 -333
- package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
- package/fp16/test/ieee-to-fp32-value.cc +0 -420
- package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
- package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
- package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
- package/fp16/test/peachpy/stubs.py +0 -38
- package/fp16/test/tables.cc +0 -530
- package/fp16/test/tables.h +0 -13
- package/fp16/third-party/THHalf.h +0 -92
- package/fp16/third-party/eigen-half.h +0 -170
- package/fp16/third-party/float16-compressor.h +0 -80
- package/fp16/third-party/half.hpp +0 -2916
- package/fp16/third-party/npy-halffloat.h +0 -328
- package/simsimd/.git-blame-ignore-revs +0 -2
- package/simsimd/CONTRIBUTING.md +0 -321
- package/simsimd/Cargo.toml +0 -49
- package/simsimd/MANIFEST.in +0 -4
- package/simsimd/Package.swift +0 -28
- package/simsimd/README.md +0 -1493
- package/simsimd/binding.gyp +0 -35
- package/simsimd/build.rs +0 -70
- package/simsimd/c/lib.c +0 -374
- package/simsimd/include/module.modulemap +0 -4
- package/simsimd/include/simsimd/binary.h +0 -486
- package/simsimd/include/simsimd/curved.h +0 -1541
- package/simsimd/include/simsimd/dot.h +0 -1853
- package/simsimd/include/simsimd/elementwise.h +0 -2465
- package/simsimd/include/simsimd/geospatial.h +0 -43
- package/simsimd/include/simsimd/mesh.h +0 -69
- package/simsimd/include/simsimd/probability.h +0 -606
- package/simsimd/include/simsimd/simsimd.h +0 -2567
- package/simsimd/include/simsimd/sparse.h +0 -1384
- package/simsimd/include/simsimd/spatial.h +0 -2335
- package/simsimd/include/simsimd/types.h +0 -666
- package/simsimd/javascript/fallback.ts +0 -233
- package/simsimd/javascript/lib.c +0 -125
- package/simsimd/javascript/node-gyp-build.d.ts +0 -1
- package/simsimd/javascript/simsimd.ts +0 -179
- package/simsimd/javascript/tsconfig-cjs.json +0 -8
- package/simsimd/package-lock.json +0 -1761
- package/simsimd/package.json +0 -61
- package/simsimd/rust/lib.rs +0 -1821
- package/simsimd/scripts/bench.cxx +0 -1170
- package/simsimd/scripts/bench.ipynb +0 -187
- package/simsimd/scripts/bench.js +0 -127
- package/simsimd/scripts/bench.rs +0 -876
- package/simsimd/scripts/bench_vectors.py +0 -734
- package/simsimd/scripts/bench_vectors_live.py +0 -213
- package/simsimd/scripts/test.c +0 -187
- package/simsimd/scripts/test.mjs +0 -220
- package/simsimd/scripts/test.py +0 -1505
- package/simsimd/swift/SimSIMD.swift +0 -149
- package/simsimd/swift/Test.swift +0 -128
- /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
- /package/{simsimd → numkong}/LICENSE +0 -0
- /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
- /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
|
@@ -0,0 +1,823 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @brief SIMD-accelerated Type Conversions for Haswell.
|
|
3
|
+
* @file include/numkong/cast/haswell.h
|
|
4
|
+
* @author Ash Vardanian
|
|
5
|
+
* @date January 2, 2026
|
|
6
|
+
*
|
|
7
|
+
* @section haswell_cast_instructions Key F16C/AVX2 Conversion Instructions
|
|
8
|
+
*
|
|
9
|
+
* Intrinsic Instruction Haswell Genoa
|
|
10
|
+
* _mm256_cvtph_ps VCVTPH2PS (YMM, XMM) 5cy @ p01 4cy @ p12+p23
|
|
11
|
+
* _mm256_cvtps_ph VCVTPS2PH (XMM, YMM, I8) 5cy @ p01 4cy @ p12+p23
|
|
12
|
+
* _mm256_cvtepi16_epi32 VPMOVSXWD (YMM, XMM) 1cy @ p5 2cy @ p12
|
|
13
|
+
* _mm256_slli_epi32 VPSLLD (YMM, YMM, I8) 1cy @ p0 1cy @ p23
|
|
14
|
+
* _mm256_blendv_ps VBLENDVPS (YMM, YMM, YMM, YMM) 2cy @ p015 1cy @ p01
|
|
15
|
+
*
|
|
16
|
+
* F16C provides hardware F16<->F32 conversion. BF16 lacks hardware support and is emulated via
|
|
17
|
+
* bit manipulation (shift upper 16 bits). FP8 formats (E4M3/E5M2) use lookup tables for subnormal
|
|
18
|
+
* handling combined with arithmetic for normal values. All conversions hub through F32.
|
|
19
|
+
*/
|
|
20
|
+
#ifndef NK_CAST_HASWELL_H
|
|
21
|
+
#define NK_CAST_HASWELL_H
|
|
22
|
+
|
|
23
|
+
#if NK_TARGET_X8664_
|
|
24
|
+
#if NK_TARGET_HASWELL
|
|
25
|
+
|
|
26
|
+
#include "numkong/types.h"
|
|
27
|
+
#include "numkong/cast/serial.h" // `nk_partial_load_b16x16_serial_`
|
|
28
|
+
|
|
29
|
+
#if defined(__cplusplus)
|
|
30
|
+
extern "C" {
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#if defined(__clang__)
|
|
34
|
+
#pragma clang attribute push(__attribute__((target("avx2,f16c,fma,bmi,bmi2"))), apply_to = function)
|
|
35
|
+
#elif defined(__GNUC__)
|
|
36
|
+
#pragma GCC push_options
|
|
37
|
+
#pragma GCC target("avx2", "f16c", "fma", "bmi", "bmi2")
|
|
38
|
+
#endif
|
|
39
|
+
|
|
40
|
+
NK_PUBLIC void nk_f32_to_f16_haswell(nk_f32_t const *from, nk_f16_t *to) {
|
|
41
|
+
*(nk_u16_t *)to = (nk_u16_t)_mm_cvtsi128_si32(_mm_cvtps_ph(_mm_set_ss(*from), _MM_FROUND_TO_NEAREST_INT));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
NK_PUBLIC void nk_f16_to_f32_haswell(nk_f16_t const *from, nk_f32_t *to) {
|
|
45
|
+
*to = _mm_cvtss_f32(_mm_cvtph_ps(_mm_cvtsi32_si128(*(nk_u16_t const *)from)));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#pragma region Type Punned Loads and Stores
|
|
49
|
+
|
|
50
|
+
/** @brief Type-agnostic 256-bit full load (Haswell AVX2). */
|
|
51
|
+
NK_INTERNAL void nk_load_b256_haswell_(void const *src, nk_b256_vec_t *dst) {
|
|
52
|
+
dst->ymm = _mm256_loadu_si256((const __m256i *)src);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** @brief Type-agnostic 256-bit full store (Haswell AVX2). */
|
|
56
|
+
NK_INTERNAL void nk_store_b256_haswell_(nk_b256_vec_t const *src, void *dst) {
|
|
57
|
+
_mm256_storeu_si256((__m256i *)dst, src->ymm);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @brief Type-agnostic 128-bit full load (Haswell AVX2). */
|
|
61
|
+
NK_INTERNAL void nk_load_b128_haswell_(void const *src, nk_b128_vec_t *dst) {
|
|
62
|
+
dst->xmm = _mm_loadu_si128((const __m128i *)src);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** @brief Type-agnostic 128-bit full store (SSE2). */
|
|
66
|
+
NK_INTERNAL void nk_store_b128_haswell_(nk_b128_vec_t const *src, void *dst) {
|
|
67
|
+
_mm_storeu_si128((__m128i *)dst, src->xmm);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** @brief Type-agnostic 128-bit partial load with AVX maskload. */
|
|
71
|
+
NK_INTERNAL void nk_partial_load_b32x4_haswell_(void const *src, nk_b128_vec_t *dst, nk_size_t n) {
|
|
72
|
+
__m128i idx_i32x4 = _mm_setr_epi32(0, 1, 2, 3);
|
|
73
|
+
__m128i limit_i32x4 = _mm_set1_epi32((int)n);
|
|
74
|
+
__m128i mask_i32x4 = _mm_cmpgt_epi32(limit_i32x4, idx_i32x4);
|
|
75
|
+
dst->xmm = _mm_castps_si128(_mm_maskload_ps((float const *)src, mask_i32x4));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @brief Type-agnostic 128-bit partial store with AVX maskstore. */
|
|
79
|
+
NK_INTERNAL void nk_partial_store_b32x4_haswell_(nk_b128_vec_t const *src, void *dst, nk_size_t n) {
|
|
80
|
+
__m128i idx_i32x4 = _mm_setr_epi32(0, 1, 2, 3);
|
|
81
|
+
__m128i limit_i32x4 = _mm_set1_epi32((int)n);
|
|
82
|
+
__m128i mask_i32x4 = _mm_cmpgt_epi32(limit_i32x4, idx_i32x4);
|
|
83
|
+
_mm_maskstore_ps((float *)dst, mask_i32x4, _mm_castsi128_ps(src->xmm));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** @brief Type-agnostic 256-bit partial load with AVX2 maskload. */
|
|
87
|
+
NK_INTERNAL void nk_partial_load_b64x4_haswell_(void const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
88
|
+
__m256i idx_i64x4 = _mm256_setr_epi64x(0, 1, 2, 3);
|
|
89
|
+
__m256i limit_i64x4 = _mm256_set1_epi64x((long long)n);
|
|
90
|
+
__m256i mask_i64x4 = _mm256_cmpgt_epi64(limit_i64x4, idx_i64x4);
|
|
91
|
+
dst->ymm = _mm256_castpd_si256(_mm256_maskload_pd((double const *)src, mask_i64x4));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** @brief Type-agnostic 256-bit partial store with AVX2 maskstore. */
|
|
95
|
+
NK_INTERNAL void nk_partial_store_b64x4_haswell_(nk_b256_vec_t const *src, void *dst, nk_size_t n) {
|
|
96
|
+
__m256i idx_i64x4 = _mm256_setr_epi64x(0, 1, 2, 3);
|
|
97
|
+
__m256i limit_i64x4 = _mm256_set1_epi64x((long long)n);
|
|
98
|
+
__m256i mask_i64x4 = _mm256_cmpgt_epi64(limit_i64x4, idx_i64x4);
|
|
99
|
+
_mm256_maskstore_pd((double *)dst, mask_i64x4, _mm256_castsi256_pd(src->ymm));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#pragma endregion Type Punned Loads and Stores
|
|
103
|
+
|
|
104
|
+
#pragma region Vectorized Conversions
|
|
105
|
+
|
|
106
|
+
/** @brief Convert 8x bf16 → 8x f32 by shifting left 16 bits (AVX2). */
|
|
107
|
+
NK_INTERNAL __m256 nk_bf16x8_to_f32x8_haswell_(__m128i bf16_i16x8) {
|
|
108
|
+
return _mm256_castsi256_ps(_mm256_slli_epi32(_mm256_cvtepu16_epi32(bf16_i16x8), 16));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** @brief Convert 8x f32 → 8x bf16 by truncating with RNE rounding (AVX2). */
|
|
112
|
+
NK_INTERNAL __m128i nk_f32x8_to_bf16x8_haswell_(__m256 f32x8) {
|
|
113
|
+
__m256i bits_i32x8 = _mm256_castps_si256(f32x8);
|
|
114
|
+
// RNE rounding: add (0x7FFF + lsb) where lsb is bit 16
|
|
115
|
+
__m256i lsb_i32x8 = _mm256_and_si256(_mm256_srli_epi32(bits_i32x8, 16), _mm256_set1_epi32(1));
|
|
116
|
+
__m256i rounded_i32x8 = _mm256_add_epi32(bits_i32x8, _mm256_add_epi32(_mm256_set1_epi32(0x7FFF), lsb_i32x8));
|
|
117
|
+
__m256i bf16_i32x8 = _mm256_srli_epi32(rounded_i32x8, 16);
|
|
118
|
+
// Pack 8x i32 to 8x i16
|
|
119
|
+
__m128i low_i32x4 = _mm256_castsi256_si128(bf16_i32x8);
|
|
120
|
+
__m128i high_i32x4 = _mm256_extracti128_si256(bf16_i32x8, 1);
|
|
121
|
+
return _mm_packus_epi32(low_i32x4, high_i32x4);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** @brief Integer upcasts to f32x8 (AVX2). */
|
|
125
|
+
NK_INTERNAL __m256 nk_i8x8_to_f32x8_haswell_(__m128i i8x8) { return _mm256_cvtepi32_ps(_mm256_cvtepi8_epi32(i8x8)); }
|
|
126
|
+
NK_INTERNAL __m256 nk_u8x8_to_f32x8_haswell_(__m128i u8x8) { return _mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(u8x8)); }
|
|
127
|
+
NK_INTERNAL __m256 nk_i16x8_to_f32x8_haswell_(__m128i i16x8) {
|
|
128
|
+
return _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(i16x8));
|
|
129
|
+
}
|
|
130
|
+
NK_INTERNAL __m256 nk_u16x8_to_f32x8_haswell_(__m128i u16x8) {
|
|
131
|
+
return _mm256_cvtepi32_ps(_mm256_cvtepu16_epi32(u16x8));
|
|
132
|
+
}
|
|
133
|
+
NK_INTERNAL __m256 nk_i32x8_to_f32x8_haswell_(__m256i i32x8) { return _mm256_cvtepi32_ps(i32x8); }
|
|
134
|
+
NK_INTERNAL __m256 nk_u32x8_to_f32x8_haswell_(__m256i u32x8) {
|
|
135
|
+
__m256i low_i32x8 = _mm256_and_si256(u32x8, _mm256_set1_epi32(0xFFFF));
|
|
136
|
+
__m256i high_i32x8 = _mm256_srli_epi32(u32x8, 16);
|
|
137
|
+
return _mm256_add_ps(_mm256_cvtepi32_ps(low_i32x8),
|
|
138
|
+
_mm256_mul_ps(_mm256_cvtepi32_ps(high_i32x8), _mm256_set1_ps(65536.0f)));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** @brief Saturating f32x8 downcasts to integers (AVX2). */
|
|
142
|
+
NK_INTERNAL __m256i nk_f32x8_to_i32x8_haswell_(__m256 f32x8) { return _mm256_cvtps_epi32(f32x8); }
|
|
143
|
+
NK_INTERNAL __m256i nk_f32x8_to_u32x8_haswell_(__m256 f32x8) {
|
|
144
|
+
__m256 clamped_f32x8 = _mm256_max_ps(_mm256_min_ps(f32x8, _mm256_set1_ps((float)NK_U32_MAX)), _mm256_setzero_ps());
|
|
145
|
+
__m256 threshold_f32x8 = _mm256_set1_ps(2147483648.0f);
|
|
146
|
+
__m256i mask_i32x8 = _mm256_castps_si256(_mm256_cmp_ps(clamped_f32x8, threshold_f32x8, _CMP_GE_OQ));
|
|
147
|
+
__m256 adjusted_f32x8 = _mm256_sub_ps(clamped_f32x8,
|
|
148
|
+
_mm256_and_ps(_mm256_castsi256_ps(mask_i32x8), threshold_f32x8));
|
|
149
|
+
return _mm256_add_epi32(_mm256_cvtps_epi32(adjusted_f32x8),
|
|
150
|
+
_mm256_and_si256(mask_i32x8, _mm256_set1_epi32((int)0x80000000)));
|
|
151
|
+
}
|
|
152
|
+
NK_INTERNAL __m128i nk_f32x8_to_i16x8_haswell_(__m256 f32x8) {
|
|
153
|
+
__m256 clamped_f32x8 = _mm256_min_ps(_mm256_max_ps(f32x8, _mm256_set1_ps(-32768.0f)), _mm256_set1_ps(32767.0f));
|
|
154
|
+
__m256i i32x8 = _mm256_cvtps_epi32(clamped_f32x8);
|
|
155
|
+
return _mm_packs_epi32(_mm256_castsi256_si128(i32x8), _mm256_extracti128_si256(i32x8, 1));
|
|
156
|
+
}
|
|
157
|
+
NK_INTERNAL __m128i nk_f32x8_to_u16x8_haswell_(__m256 f32x8) {
|
|
158
|
+
__m256 clamped_f32x8 = _mm256_min_ps(_mm256_max_ps(f32x8, _mm256_setzero_ps()), _mm256_set1_ps(65535.0f));
|
|
159
|
+
__m256i i32x8 = _mm256_cvtps_epi32(clamped_f32x8);
|
|
160
|
+
return _mm_packus_epi32(_mm256_castsi256_si128(i32x8), _mm256_extracti128_si256(i32x8, 1));
|
|
161
|
+
}
|
|
162
|
+
NK_INTERNAL __m128i nk_f32x8_to_i8x8_haswell_(__m256 f32x8) {
|
|
163
|
+
__m256 clamped_f32x8 = _mm256_min_ps(_mm256_max_ps(f32x8, _mm256_set1_ps(-128.0f)), _mm256_set1_ps(127.0f));
|
|
164
|
+
__m256i i32x8 = _mm256_cvtps_epi32(clamped_f32x8);
|
|
165
|
+
__m128i i16x8 = _mm_packs_epi32(_mm256_castsi256_si128(i32x8), _mm256_extracti128_si256(i32x8, 1));
|
|
166
|
+
return _mm_packs_epi16(i16x8, _mm_setzero_si128());
|
|
167
|
+
}
|
|
168
|
+
NK_INTERNAL __m128i nk_f32x8_to_u8x8_haswell_(__m256 f32x8) {
|
|
169
|
+
__m256 clamped_f32x8 = _mm256_min_ps(_mm256_max_ps(f32x8, _mm256_setzero_ps()), _mm256_set1_ps(255.0f));
|
|
170
|
+
__m256i i32x8 = _mm256_cvtps_epi32(clamped_f32x8);
|
|
171
|
+
__m128i u16x8 = _mm_packus_epi32(_mm256_castsi256_si128(i32x8), _mm256_extracti128_si256(i32x8, 1));
|
|
172
|
+
return _mm_packus_epi16(u16x8, _mm_setzero_si128());
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** @brief Convert 8x e4m3 → 8x f32 via bit manipulation (AVX2).
|
|
176
|
+
* E4M3 format: S EEEE MMM (bias=7). F32: sign<<31, (exp+120)<<23, mant<<20.
|
|
177
|
+
* Subnormals (exp=0): looked up via vpermps from an 8-entry register LUT.
|
|
178
|
+
* NaN detection uses a single comparison on the 7-bit magnitude (0x7F). */
|
|
179
|
+
NK_INTERNAL __m256 nk_e4m3x8_to_f32x8_haswell_(__m128i e4m3_i8x8) {
|
|
180
|
+
__m256i e4m3_i32x8 = _mm256_cvtepu8_epi32(e4m3_i8x8);
|
|
181
|
+
|
|
182
|
+
// Extract fields
|
|
183
|
+
__m256i exp_i32x8 = _mm256_and_si256(_mm256_srli_epi32(e4m3_i32x8, 3), _mm256_set1_epi32(0x0F));
|
|
184
|
+
__m256i mant_i32x8 = _mm256_and_si256(e4m3_i32x8, _mm256_set1_epi32(0x07));
|
|
185
|
+
|
|
186
|
+
// Build F32 sign bit
|
|
187
|
+
__m256i f32_sign_i32x8 = _mm256_slli_epi32(_mm256_srli_epi32(e4m3_i32x8, 7), 31);
|
|
188
|
+
|
|
189
|
+
// Normal path: sign | ((exp+120)<<23) | (mant<<20)
|
|
190
|
+
__m256i f32_exp_i32x8 = _mm256_slli_epi32(_mm256_add_epi32(exp_i32x8, _mm256_set1_epi32(120)), 23);
|
|
191
|
+
__m256i f32_mant_i32x8 = _mm256_slli_epi32(mant_i32x8, 20);
|
|
192
|
+
__m256i normal_bits_i32x8 = _mm256_or_si256(f32_sign_i32x8, _mm256_or_si256(f32_exp_i32x8, f32_mant_i32x8));
|
|
193
|
+
|
|
194
|
+
// Subnormal path: vpermps from 8-entry register LUT (3 cy latency, no memory access)
|
|
195
|
+
__m256 subnorm_lut_f32x8 = _mm256_setr_ps(0, 1.0f / 512, 2.0f / 512, 3.0f / 512, //
|
|
196
|
+
4.0f / 512, 5.0f / 512, 6.0f / 512, 7.0f / 512);
|
|
197
|
+
__m256i subnorm_bits_i32x8 = _mm256_or_si256( //
|
|
198
|
+
_mm256_castps_si256(_mm256_permutevar8x32_ps(subnorm_lut_f32x8, mant_i32x8)), f32_sign_i32x8);
|
|
199
|
+
|
|
200
|
+
// Bitwise select: if exp==0, use subnormal; otherwise use normal
|
|
201
|
+
__m256i exp_zero_mask = _mm256_cmpeq_epi32(exp_i32x8, _mm256_setzero_si256());
|
|
202
|
+
__m256i result_i32x8 = _mm256_or_si256( //
|
|
203
|
+
_mm256_and_si256(exp_zero_mask, subnorm_bits_i32x8), //
|
|
204
|
+
_mm256_andnot_si256(exp_zero_mask, normal_bits_i32x8));
|
|
205
|
+
|
|
206
|
+
// NaN: E4M3FN has NaN only at magnitude 0x7F (exp=15, mant=7)
|
|
207
|
+
__m256i lower7_i32x8 = _mm256_and_si256(e4m3_i32x8, _mm256_set1_epi32(0x7F));
|
|
208
|
+
__m256i is_nan_mask = _mm256_cmpeq_epi32(lower7_i32x8, _mm256_set1_epi32(0x7F));
|
|
209
|
+
__m256i nan_i32x8 = _mm256_or_si256(f32_sign_i32x8, _mm256_set1_epi32(0x7FC00000));
|
|
210
|
+
result_i32x8 = _mm256_or_si256( //
|
|
211
|
+
_mm256_and_si256(is_nan_mask, nan_i32x8), //
|
|
212
|
+
_mm256_andnot_si256(is_nan_mask, result_i32x8));
|
|
213
|
+
return _mm256_castsi256_ps(result_i32x8);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** @brief Convert 8x e5m2 → 8x f32 via bit manipulation (AVX2).
|
|
217
|
+
* E5M2 format: S EEEEE MM (bias=15). F32: sign<<31, (exp+112)<<23, mant<<21.
|
|
218
|
+
* Subnormals (exp=0): value = mantissa × 2⁽¹⁻¹⁵⁾ × 2⁻² = mantissa ÷ 65536. */
|
|
219
|
+
NK_INTERNAL __m256 nk_e5m2x8_to_f32x8_haswell_(__m128i e5m2_i8x8) {
|
|
220
|
+
__m256i e5m2_i32x8 = _mm256_cvtepu8_epi32(e5m2_i8x8);
|
|
221
|
+
|
|
222
|
+
// Extract fields
|
|
223
|
+
__m256i exp_i32x8 = _mm256_and_si256(_mm256_srli_epi32(e5m2_i32x8, 2), _mm256_set1_epi32(0x1F));
|
|
224
|
+
__m256i mant_i32x8 = _mm256_and_si256(e5m2_i32x8, _mm256_set1_epi32(0x03));
|
|
225
|
+
|
|
226
|
+
// Build F32 sign bit
|
|
227
|
+
__m256i f32_sign_i32x8 = _mm256_slli_epi32(_mm256_srli_epi32(e5m2_i32x8, 7), 31);
|
|
228
|
+
|
|
229
|
+
// Normal path: sign | ((exp+112)<<23) | (mant<<21)
|
|
230
|
+
__m256i f32_exp_i32x8 = _mm256_slli_epi32(_mm256_add_epi32(exp_i32x8, _mm256_set1_epi32(112)), 23);
|
|
231
|
+
__m256i f32_mant_i32x8 = _mm256_slli_epi32(mant_i32x8, 21);
|
|
232
|
+
__m256i normal_bits_i32x8 = _mm256_or_si256(f32_sign_i32x8, _mm256_or_si256(f32_exp_i32x8, f32_mant_i32x8));
|
|
233
|
+
|
|
234
|
+
// Subnormal path: value = mantissa / 65536.0f, then apply sign
|
|
235
|
+
__m256 subnorm_abs_f32x8 = _mm256_mul_ps(_mm256_cvtepi32_ps(mant_i32x8), _mm256_set1_ps(1.0f / 65536.0f));
|
|
236
|
+
__m256 subnorm_f32x8 = _mm256_or_ps(subnorm_abs_f32x8, _mm256_castsi256_ps(f32_sign_i32x8));
|
|
237
|
+
|
|
238
|
+
// Blend: if exp==0, use subnormal result; otherwise use normal bits
|
|
239
|
+
__m256i exp_zero_mask = _mm256_cmpeq_epi32(exp_i32x8, _mm256_setzero_si256());
|
|
240
|
+
return _mm256_blendv_ps(_mm256_castsi256_ps(normal_bits_i32x8), subnorm_f32x8, _mm256_castsi256_ps(exp_zero_mask));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** @brief Convert 8x f32 → 8x e4m3 via bit manipulation (AVX2).
|
|
244
|
+
* E4M3 format: S EEEE MMM (bias=7). Handles normal, subnormal, and overflow cases.
|
|
245
|
+
* Subnormals (f32_exp ≤ 120): mantissa = round(abs_f32 * 512), clamped to [0,7]. */
|
|
246
|
+
NK_INTERNAL __m128i nk_f32x8_to_e4m3x8_haswell_(__m256 f32x8) {
|
|
247
|
+
__m256i bits_i32x8 = _mm256_castps_si256(f32x8);
|
|
248
|
+
__m256i sign_i32x8 = _mm256_srli_epi32(bits_i32x8, 31);
|
|
249
|
+
__m256i f32_exp_i32x8 = _mm256_and_si256(_mm256_srli_epi32(bits_i32x8, 23), _mm256_set1_epi32(0xFF));
|
|
250
|
+
|
|
251
|
+
// Round mantissa from 23 to 3 bits using RNE (round to nearest, ties to even)
|
|
252
|
+
// RNE trick: add (half - 1 + lsb) where lsb is the bit that will become the new lsb after shift
|
|
253
|
+
__m256i significand_i32x8 = _mm256_or_si256(_mm256_and_si256(bits_i32x8, _mm256_set1_epi32(0x007FFFFF)),
|
|
254
|
+
_mm256_set1_epi32(0x00800000)); // Add implicit 1 bit
|
|
255
|
+
__m256i lsb_i32x8 = _mm256_and_si256(_mm256_srli_epi32(significand_i32x8, 20), _mm256_set1_epi32(1));
|
|
256
|
+
__m256i rounding_bias_i32x8 = _mm256_add_epi32(_mm256_set1_epi32(0x0007FFFF), lsb_i32x8);
|
|
257
|
+
__m256i rounded_sig_i32x8 = _mm256_add_epi32(significand_i32x8, rounding_bias_i32x8);
|
|
258
|
+
__m256i carry_i32x8 = _mm256_srli_epi32(rounded_sig_i32x8, 24); // Carry into exponent if bit 24 set
|
|
259
|
+
__m256i f32_mantissa_i32x8 = _mm256_and_si256(_mm256_srli_epi32(rounded_sig_i32x8, 20), _mm256_set1_epi32(0x07));
|
|
260
|
+
// If carry, mantissa becomes 0 (we rounded up to next power of 2)
|
|
261
|
+
f32_mantissa_i32x8 = _mm256_andnot_si256(_mm256_slli_epi32(carry_i32x8, 31), f32_mantissa_i32x8);
|
|
262
|
+
__m256i e4m3_exp_i32x8 = _mm256_sub_epi32(_mm256_add_epi32(f32_exp_i32x8, carry_i32x8), _mm256_set1_epi32(120));
|
|
263
|
+
|
|
264
|
+
// Detect underflow (exp <= 0, maps to subnormal/zero) and overflow (exp > 15)
|
|
265
|
+
__m256i is_subnormal_i32x8 = _mm256_cmpgt_epi32(_mm256_set1_epi32(1), e4m3_exp_i32x8);
|
|
266
|
+
__m256i overflow_i32x8 = _mm256_cmpgt_epi32(e4m3_exp_i32x8, _mm256_set1_epi32(15));
|
|
267
|
+
|
|
268
|
+
// Normal path: clamp exp to [1,15], extract mantissa bits
|
|
269
|
+
// e4m3FN quirk: exp=15 with mantissa=7 is NaN (0x7F), so clamp mantissa to 6 when exp=15.
|
|
270
|
+
__m256i clamped_exp_i32x8 = _mm256_max_epi32(e4m3_exp_i32x8, _mm256_set1_epi32(1));
|
|
271
|
+
clamped_exp_i32x8 = _mm256_min_epi32(clamped_exp_i32x8, _mm256_set1_epi32(15));
|
|
272
|
+
__m256i is_max_exp_i32x8 = _mm256_cmpeq_epi32(clamped_exp_i32x8, _mm256_set1_epi32(15));
|
|
273
|
+
__m256i max_mantissa_i32x8 = _mm256_blendv_epi8(_mm256_set1_epi32(7), _mm256_set1_epi32(6), is_max_exp_i32x8);
|
|
274
|
+
__m256i normal_mantissa_i32x8 = _mm256_min_epi32(f32_mantissa_i32x8, max_mantissa_i32x8);
|
|
275
|
+
normal_mantissa_i32x8 = _mm256_blendv_epi8(normal_mantissa_i32x8, _mm256_set1_epi32(0x06), overflow_i32x8);
|
|
276
|
+
__m256i normal_e4m3_i32x8 = _mm256_or_si256(
|
|
277
|
+
_mm256_slli_epi32(sign_i32x8, 7),
|
|
278
|
+
_mm256_or_si256(_mm256_slli_epi32(clamped_exp_i32x8, 3), normal_mantissa_i32x8));
|
|
279
|
+
|
|
280
|
+
// Subnormal path: mantissa = round(abs_f32 * 512)
|
|
281
|
+
// If mantissa rounds to 8 or higher, promote to first normal (exp_field=1, mantissa=0) = 0x08
|
|
282
|
+
__m256 abs_f32x8 = _mm256_and_ps(f32x8, _mm256_castsi256_ps(_mm256_set1_epi32(0x7FFFFFFF)));
|
|
283
|
+
__m256 scaled_f32x8 = _mm256_mul_ps(abs_f32x8, _mm256_set1_ps(512.0f));
|
|
284
|
+
__m256i subnorm_mantissa_i32x8 = _mm256_cvtps_epi32(scaled_f32x8);
|
|
285
|
+
__m256i promotes_to_normal_i32x8 = _mm256_cmpgt_epi32(subnorm_mantissa_i32x8, _mm256_set1_epi32(7));
|
|
286
|
+
subnorm_mantissa_i32x8 = _mm256_min_epi32(subnorm_mantissa_i32x8, _mm256_set1_epi32(7));
|
|
287
|
+
subnorm_mantissa_i32x8 = _mm256_max_epi32(subnorm_mantissa_i32x8, _mm256_setzero_si256());
|
|
288
|
+
__m256i subnorm_e4m3_i32x8 = _mm256_or_si256(_mm256_slli_epi32(sign_i32x8, 7), subnorm_mantissa_i32x8);
|
|
289
|
+
// When mantissa rounds to 8, use first normal value (0x08) instead of clamped subnormal
|
|
290
|
+
__m256i first_normal_e4m3_i32x8 = _mm256_or_si256(_mm256_slli_epi32(sign_i32x8, 7), _mm256_set1_epi32(0x08));
|
|
291
|
+
subnorm_e4m3_i32x8 = _mm256_blendv_epi8(subnorm_e4m3_i32x8, first_normal_e4m3_i32x8, promotes_to_normal_i32x8);
|
|
292
|
+
|
|
293
|
+
// Blend: use subnormal result when exp <= 0, else normal
|
|
294
|
+
__m256i e4m3_i32x8 = _mm256_blendv_epi8(normal_e4m3_i32x8, subnorm_e4m3_i32x8, is_subnormal_i32x8);
|
|
295
|
+
|
|
296
|
+
// Pack 8 i32s to 8 unsigned i8s (use unsigned saturation to preserve values 128-255)
|
|
297
|
+
__m128i low_i32x4 = _mm256_castsi256_si128(e4m3_i32x8);
|
|
298
|
+
__m128i high_i32x4 = _mm256_extracti128_si256(e4m3_i32x8, 1);
|
|
299
|
+
__m128i packed_i16x8 = _mm_packus_epi32(low_i32x4, high_i32x4);
|
|
300
|
+
__m128i packed_i8x8 = _mm_packus_epi16(packed_i16x8, packed_i16x8);
|
|
301
|
+
return packed_i8x8;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** @brief Convert 8x f32 → 8x e5m2 via bit manipulation (AVX2).
|
|
305
|
+
* E5M2 format: S EEEEE MM (bias=15). Handles normal, subnormal, and overflow cases.
|
|
306
|
+
* Uses RNE (round to nearest even) for mantissa rounding. */
|
|
307
|
+
NK_INTERNAL __m128i nk_f32x8_to_e5m2x8_haswell_(__m256 f32x8) {
|
|
308
|
+
__m256i bits_i32x8 = _mm256_castps_si256(f32x8);
|
|
309
|
+
__m256i sign_i32x8 = _mm256_srli_epi32(bits_i32x8, 31);
|
|
310
|
+
__m256i f32_exp_i32x8 = _mm256_and_si256(_mm256_srli_epi32(bits_i32x8, 23), _mm256_set1_epi32(0xFF));
|
|
311
|
+
|
|
312
|
+
// Round mantissa from 23 to 2 bits using RNE (round to nearest, ties to even)
|
|
313
|
+
// RNE trick: add (half - 1 + lsb) where lsb is the bit that will become the new lsb after shift
|
|
314
|
+
__m256i significand_i32x8 = _mm256_or_si256(_mm256_and_si256(bits_i32x8, _mm256_set1_epi32(0x007FFFFF)),
|
|
315
|
+
_mm256_set1_epi32(0x00800000)); // Add implicit 1 bit
|
|
316
|
+
__m256i lsb_i32x8 = _mm256_and_si256(_mm256_srli_epi32(significand_i32x8, 21), _mm256_set1_epi32(1));
|
|
317
|
+
__m256i rounding_bias_i32x8 = _mm256_add_epi32(_mm256_set1_epi32(0x000FFFFF), lsb_i32x8); // half = 0x100000
|
|
318
|
+
__m256i rounded_sig_i32x8 = _mm256_add_epi32(significand_i32x8, rounding_bias_i32x8);
|
|
319
|
+
__m256i carry_i32x8 = _mm256_srli_epi32(rounded_sig_i32x8, 24); // Carry into exponent if bit 24 set
|
|
320
|
+
__m256i f32_mantissa_i32x8 = _mm256_and_si256(_mm256_srli_epi32(rounded_sig_i32x8, 21), _mm256_set1_epi32(0x03));
|
|
321
|
+
// If carry, mantissa becomes 0 (we rounded up to next power of 2)
|
|
322
|
+
f32_mantissa_i32x8 = _mm256_andnot_si256(_mm256_slli_epi32(carry_i32x8, 31), f32_mantissa_i32x8);
|
|
323
|
+
__m256i e5m2_exp_i32x8 = _mm256_sub_epi32(_mm256_add_epi32(f32_exp_i32x8, carry_i32x8), _mm256_set1_epi32(112));
|
|
324
|
+
|
|
325
|
+
// Detect subnormal (exp <= 0) and overflow (exp > 31)
|
|
326
|
+
__m256i is_subnormal_i32x8 = _mm256_cmpgt_epi32(_mm256_set1_epi32(1), e5m2_exp_i32x8);
|
|
327
|
+
__m256i overflow_i32x8 = _mm256_cmpgt_epi32(e5m2_exp_i32x8, _mm256_set1_epi32(31));
|
|
328
|
+
|
|
329
|
+
// Normal path: clamp exp to [1,31], on overflow return infinity (exp=31, mantissa=0 = 0x7C)
|
|
330
|
+
__m256i clamped_exp_i32x8 = _mm256_max_epi32(e5m2_exp_i32x8, _mm256_set1_epi32(1));
|
|
331
|
+
clamped_exp_i32x8 = _mm256_min_epi32(clamped_exp_i32x8, _mm256_set1_epi32(31));
|
|
332
|
+
__m256i normal_mantissa_i32x8 = _mm256_blendv_epi8(f32_mantissa_i32x8, _mm256_setzero_si256(), overflow_i32x8);
|
|
333
|
+
__m256i normal_e5m2_i32x8 = _mm256_or_si256(
|
|
334
|
+
_mm256_slli_epi32(sign_i32x8, 7),
|
|
335
|
+
_mm256_or_si256(_mm256_slli_epi32(clamped_exp_i32x8, 2), normal_mantissa_i32x8));
|
|
336
|
+
|
|
337
|
+
// Subnormal path: mantissa = round(abs_f32 * 65536)
|
|
338
|
+
// If mantissa rounds to 4 or higher, promote to first normal (exp_field=1, mantissa=0) = 0x04
|
|
339
|
+
__m256 abs_f32x8 = _mm256_and_ps(f32x8, _mm256_castsi256_ps(_mm256_set1_epi32(0x7FFFFFFF)));
|
|
340
|
+
__m256 scaled_f32x8 = _mm256_mul_ps(abs_f32x8, _mm256_set1_ps(65536.0f));
|
|
341
|
+
__m256i subnorm_mantissa_i32x8 = _mm256_cvtps_epi32(scaled_f32x8);
|
|
342
|
+
__m256i promotes_to_normal_i32x8 = _mm256_cmpgt_epi32(subnorm_mantissa_i32x8, _mm256_set1_epi32(3));
|
|
343
|
+
subnorm_mantissa_i32x8 = _mm256_min_epi32(subnorm_mantissa_i32x8, _mm256_set1_epi32(3));
|
|
344
|
+
subnorm_mantissa_i32x8 = _mm256_max_epi32(subnorm_mantissa_i32x8, _mm256_setzero_si256());
|
|
345
|
+
__m256i subnorm_e5m2_i32x8 = _mm256_or_si256(_mm256_slli_epi32(sign_i32x8, 7), subnorm_mantissa_i32x8);
|
|
346
|
+
// When mantissa rounds to 4, use first normal value (0x04) instead of clamped subnormal
|
|
347
|
+
__m256i first_normal_e5m2_i32x8 = _mm256_or_si256(_mm256_slli_epi32(sign_i32x8, 7), _mm256_set1_epi32(0x04));
|
|
348
|
+
subnorm_e5m2_i32x8 = _mm256_blendv_epi8(subnorm_e5m2_i32x8, first_normal_e5m2_i32x8, promotes_to_normal_i32x8);
|
|
349
|
+
|
|
350
|
+
// Blend: use subnormal result when exp <= 0
|
|
351
|
+
__m256i e5m2_i32x8 = _mm256_blendv_epi8(normal_e5m2_i32x8, subnorm_e5m2_i32x8, is_subnormal_i32x8);
|
|
352
|
+
|
|
353
|
+
// Pack 8 i32s to 8 unsigned i8s (use unsigned saturation to preserve values 128-255)
|
|
354
|
+
__m128i low_i32x4 = _mm256_castsi256_si128(e5m2_i32x8);
|
|
355
|
+
__m128i high_i32x4 = _mm256_extracti128_si256(e5m2_i32x8, 1);
|
|
356
|
+
__m128i packed_i16x8 = _mm_packus_epi32(low_i32x4, high_i32x4);
|
|
357
|
+
__m128i packed_i8x8 = _mm_packus_epi16(packed_i16x8, packed_i16x8);
|
|
358
|
+
return packed_i8x8;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/** @brief Convert 8x e2m3 → 8x f32 via bit manipulation (AVX2).
|
|
362
|
+
* E2M3 format: S EE MMM (bias=1). F32: sign<<31, (exp+126)<<23, mantissa<<20.
|
|
363
|
+
* Subnormals (exp=0): value = mantissa × 2⁽¹⁻¹⁾ × 2⁻³ = mantissa ÷ 8. */
|
|
364
|
+
NK_INTERNAL __m256 nk_e2m3x8_to_f32x8_haswell_(__m128i e2m3_i8x8) {
|
|
365
|
+
__m256i e2m3_i32x8 = _mm256_cvtepu8_epi32(e2m3_i8x8);
|
|
366
|
+
|
|
367
|
+
// Extract fields (only 6 bits used: S EE MMM)
|
|
368
|
+
__m256i exp_i32x8 = _mm256_and_si256(_mm256_srli_epi32(e2m3_i32x8, 3), _mm256_set1_epi32(0x03));
|
|
369
|
+
__m256i mant_i32x8 = _mm256_and_si256(e2m3_i32x8, _mm256_set1_epi32(0x07));
|
|
370
|
+
|
|
371
|
+
// Build F32 sign bit
|
|
372
|
+
__m256i f32_sign_i32x8 = _mm256_slli_epi32(_mm256_srli_epi32(e2m3_i32x8, 5), 31);
|
|
373
|
+
|
|
374
|
+
// Normal path: sign | ((exp+126)<<23) | (mant<<20)
|
|
375
|
+
__m256i f32_exp_i32x8 = _mm256_slli_epi32(_mm256_add_epi32(exp_i32x8, _mm256_set1_epi32(126)), 23);
|
|
376
|
+
__m256i f32_mant_i32x8 = _mm256_slli_epi32(mant_i32x8, 20);
|
|
377
|
+
__m256i normal_bits_i32x8 = _mm256_or_si256(f32_sign_i32x8, _mm256_or_si256(f32_exp_i32x8, f32_mant_i32x8));
|
|
378
|
+
|
|
379
|
+
// Subnormal path: value = mantissa / 8.0f, then apply sign
|
|
380
|
+
__m256 subnorm_abs_f32x8 = _mm256_mul_ps(_mm256_cvtepi32_ps(mant_i32x8), _mm256_set1_ps(1.0f / 8.0f));
|
|
381
|
+
__m256 subnorm_f32x8 = _mm256_or_ps(subnorm_abs_f32x8, _mm256_castsi256_ps(f32_sign_i32x8));
|
|
382
|
+
|
|
383
|
+
// Blend: if exp==0, use subnormal result; otherwise use normal bits
|
|
384
|
+
__m256i exp_zero_mask = _mm256_cmpeq_epi32(exp_i32x8, _mm256_setzero_si256());
|
|
385
|
+
return _mm256_blendv_ps(_mm256_castsi256_ps(normal_bits_i32x8), subnorm_f32x8, _mm256_castsi256_ps(exp_zero_mask));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** @brief Convert 8x e3m2 → 8x f32 via bit manipulation (AVX2).
|
|
389
|
+
* E3M2 format: S EEE MM (bias=3). F32: sign<<31, (exp+124)<<23, mantissa<<21.
|
|
390
|
+
* Subnormals (exp=0): value = mantissa × 2⁽¹⁻³⁾ × 2⁻² = mantissa ÷ 16. */
|
|
391
|
+
NK_INTERNAL __m256 nk_e3m2x8_to_f32x8_haswell_(__m128i e3m2_i8x8) {
|
|
392
|
+
__m256i e3m2_i32x8 = _mm256_cvtepu8_epi32(e3m2_i8x8);
|
|
393
|
+
|
|
394
|
+
// Extract fields (only 6 bits used: S EEE MM)
|
|
395
|
+
__m256i exp_i32x8 = _mm256_and_si256(_mm256_srli_epi32(e3m2_i32x8, 2), _mm256_set1_epi32(0x07));
|
|
396
|
+
__m256i mant_i32x8 = _mm256_and_si256(e3m2_i32x8, _mm256_set1_epi32(0x03));
|
|
397
|
+
|
|
398
|
+
// Build F32 sign bit
|
|
399
|
+
__m256i f32_sign_i32x8 = _mm256_slli_epi32(_mm256_srli_epi32(e3m2_i32x8, 5), 31);
|
|
400
|
+
|
|
401
|
+
// Normal path: sign | ((exp+124)<<23) | (mant<<21)
|
|
402
|
+
__m256i f32_exp_i32x8 = _mm256_slli_epi32(_mm256_add_epi32(exp_i32x8, _mm256_set1_epi32(124)), 23);
|
|
403
|
+
__m256i f32_mant_i32x8 = _mm256_slli_epi32(mant_i32x8, 21);
|
|
404
|
+
__m256i normal_bits_i32x8 = _mm256_or_si256(f32_sign_i32x8, _mm256_or_si256(f32_exp_i32x8, f32_mant_i32x8));
|
|
405
|
+
|
|
406
|
+
// Subnormal path: value = mantissa / 16.0f, then apply sign
|
|
407
|
+
__m256 subnorm_abs_f32x8 = _mm256_mul_ps(_mm256_cvtepi32_ps(mant_i32x8), _mm256_set1_ps(1.0f / 16.0f));
|
|
408
|
+
__m256 subnorm_f32x8 = _mm256_or_ps(subnorm_abs_f32x8, _mm256_castsi256_ps(f32_sign_i32x8));
|
|
409
|
+
|
|
410
|
+
// Blend: if exp==0, use subnormal result; otherwise use normal bits
|
|
411
|
+
__m256i exp_zero_mask = _mm256_cmpeq_epi32(exp_i32x8, _mm256_setzero_si256());
|
|
412
|
+
return _mm256_blendv_ps(_mm256_castsi256_ps(normal_bits_i32x8), subnorm_f32x8, _mm256_castsi256_ps(exp_zero_mask));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** @brief Convert 8x f32 → 8x e2m3 via bit manipulation (AVX2).
|
|
416
|
+
* E2M3 format: S EE MMM (bias=1). Handles normal, subnormal, and overflow cases.
|
|
417
|
+
* Subnormals (f32_exp ≤ 126): mantissa = round(abs_f32 * 8), clamped to [0,7]. */
|
|
418
|
+
NK_INTERNAL __m128i nk_f32x8_to_e2m3x8_haswell_(__m256 f32x8) {
|
|
419
|
+
__m256i bits_i32x8 = _mm256_castps_si256(f32x8);
|
|
420
|
+
__m256i sign_i32x8 = _mm256_srli_epi32(bits_i32x8, 31);
|
|
421
|
+
__m256i f32_exp_i32x8 = _mm256_and_si256(_mm256_srli_epi32(bits_i32x8, 23), _mm256_set1_epi32(0xFF));
|
|
422
|
+
|
|
423
|
+
// Round mantissa from 23 to 3 bits using RNE (round to nearest, ties to even)
|
|
424
|
+
__m256i significand_i32x8 = _mm256_or_si256(_mm256_and_si256(bits_i32x8, _mm256_set1_epi32(0x007FFFFF)),
|
|
425
|
+
_mm256_set1_epi32(0x00800000)); // Add implicit 1 bit
|
|
426
|
+
__m256i lsb_i32x8 = _mm256_and_si256(_mm256_srli_epi32(significand_i32x8, 20), _mm256_set1_epi32(1));
|
|
427
|
+
__m256i rounding_bias_i32x8 = _mm256_add_epi32(_mm256_set1_epi32(0x0007FFFF), lsb_i32x8);
|
|
428
|
+
__m256i rounded_sig_i32x8 = _mm256_add_epi32(significand_i32x8, rounding_bias_i32x8);
|
|
429
|
+
__m256i carry_i32x8 = _mm256_srli_epi32(rounded_sig_i32x8, 24); // Carry into exponent if bit 24 set
|
|
430
|
+
__m256i f32_mantissa_i32x8 = _mm256_and_si256(_mm256_srli_epi32(rounded_sig_i32x8, 20), _mm256_set1_epi32(0x07));
|
|
431
|
+
// If carry, mantissa becomes 0 (we rounded up to next power of 2)
|
|
432
|
+
f32_mantissa_i32x8 = _mm256_andnot_si256(_mm256_slli_epi32(carry_i32x8, 31), f32_mantissa_i32x8);
|
|
433
|
+
__m256i e2m3_exp_i32x8 = _mm256_sub_epi32(_mm256_add_epi32(f32_exp_i32x8, carry_i32x8), _mm256_set1_epi32(126));
|
|
434
|
+
|
|
435
|
+
// Detect underflow (exp <= 0, maps to subnormal/zero) and overflow (exp > 3)
|
|
436
|
+
__m256i is_subnormal_i32x8 = _mm256_cmpgt_epi32(_mm256_set1_epi32(1), e2m3_exp_i32x8);
|
|
437
|
+
__m256i overflow_i32x8 = _mm256_cmpgt_epi32(e2m3_exp_i32x8, _mm256_set1_epi32(3));
|
|
438
|
+
|
|
439
|
+
// Normal path: clamp exp to [1,3], extract mantissa bits
|
|
440
|
+
__m256i clamped_exp_i32x8 = _mm256_max_epi32(e2m3_exp_i32x8, _mm256_set1_epi32(1));
|
|
441
|
+
clamped_exp_i32x8 = _mm256_min_epi32(clamped_exp_i32x8, _mm256_set1_epi32(3));
|
|
442
|
+
__m256i normal_mantissa_i32x8 = _mm256_blendv_epi8(f32_mantissa_i32x8, _mm256_set1_epi32(0x07), overflow_i32x8);
|
|
443
|
+
__m256i normal_e2m3_i32x8 = _mm256_or_si256(
|
|
444
|
+
_mm256_slli_epi32(sign_i32x8, 5),
|
|
445
|
+
_mm256_or_si256(_mm256_slli_epi32(clamped_exp_i32x8, 3), normal_mantissa_i32x8));
|
|
446
|
+
|
|
447
|
+
// Subnormal path: mantissa = round(abs_f32 * 8)
|
|
448
|
+
// If mantissa rounds to 8 or higher, promote to first normal (exp_field=1, mantissa=0) = 0x08
|
|
449
|
+
__m256 abs_f32x8 = _mm256_and_ps(f32x8, _mm256_castsi256_ps(_mm256_set1_epi32(0x7FFFFFFF)));
|
|
450
|
+
__m256 scaled_f32x8 = _mm256_mul_ps(abs_f32x8, _mm256_set1_ps(8.0f));
|
|
451
|
+
__m256i subnorm_mantissa_i32x8 = _mm256_cvtps_epi32(scaled_f32x8);
|
|
452
|
+
__m256i promotes_to_normal_i32x8 = _mm256_cmpgt_epi32(subnorm_mantissa_i32x8, _mm256_set1_epi32(7));
|
|
453
|
+
subnorm_mantissa_i32x8 = _mm256_min_epi32(subnorm_mantissa_i32x8, _mm256_set1_epi32(7));
|
|
454
|
+
subnorm_mantissa_i32x8 = _mm256_max_epi32(subnorm_mantissa_i32x8, _mm256_setzero_si256());
|
|
455
|
+
__m256i subnorm_e2m3_i32x8 = _mm256_or_si256(_mm256_slli_epi32(sign_i32x8, 5), subnorm_mantissa_i32x8);
|
|
456
|
+
// When mantissa rounds to 8, use first normal value (0x08) instead of clamped subnormal
|
|
457
|
+
__m256i first_normal_e2m3_i32x8 = _mm256_or_si256(_mm256_slli_epi32(sign_i32x8, 5), _mm256_set1_epi32(0x08));
|
|
458
|
+
subnorm_e2m3_i32x8 = _mm256_blendv_epi8(subnorm_e2m3_i32x8, first_normal_e2m3_i32x8, promotes_to_normal_i32x8);
|
|
459
|
+
|
|
460
|
+
// Blend: use subnormal result when exp <= 0, else normal
|
|
461
|
+
__m256i e2m3_i32x8 = _mm256_blendv_epi8(normal_e2m3_i32x8, subnorm_e2m3_i32x8, is_subnormal_i32x8);
|
|
462
|
+
|
|
463
|
+
// Pack 8 i32s to 8 unsigned i8s (use unsigned saturation to preserve values 128-255)
|
|
464
|
+
__m128i low_i32x4 = _mm256_castsi256_si128(e2m3_i32x8);
|
|
465
|
+
__m128i high_i32x4 = _mm256_extracti128_si256(e2m3_i32x8, 1);
|
|
466
|
+
__m128i packed_i16x8 = _mm_packus_epi32(low_i32x4, high_i32x4);
|
|
467
|
+
__m128i packed_i8x8 = _mm_packus_epi16(packed_i16x8, packed_i16x8);
|
|
468
|
+
return packed_i8x8;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** @brief Convert 8x f32 → 8x e3m2 via bit manipulation (AVX2).
|
|
472
|
+
* E3M2 format: S EEE MM (bias=3). Handles normal, subnormal, and overflow cases.
|
|
473
|
+
* Subnormals (f32_exp ≤ 124): mantissa = round(abs_f32 * 16), clamped to [0,3]. */
|
|
474
|
+
NK_INTERNAL __m128i nk_f32x8_to_e3m2x8_haswell_(__m256 f32x8) {
|
|
475
|
+
__m256i bits_i32x8 = _mm256_castps_si256(f32x8);
|
|
476
|
+
__m256i sign_i32x8 = _mm256_srli_epi32(bits_i32x8, 31);
|
|
477
|
+
__m256i f32_exp_i32x8 = _mm256_and_si256(_mm256_srli_epi32(bits_i32x8, 23), _mm256_set1_epi32(0xFF));
|
|
478
|
+
|
|
479
|
+
// Round mantissa from 23 to 2 bits using RNE (round to nearest, ties to even)
|
|
480
|
+
__m256i significand_i32x8 = _mm256_or_si256(_mm256_and_si256(bits_i32x8, _mm256_set1_epi32(0x007FFFFF)),
|
|
481
|
+
_mm256_set1_epi32(0x00800000)); // Add implicit 1 bit
|
|
482
|
+
__m256i lsb_i32x8 = _mm256_and_si256(_mm256_srli_epi32(significand_i32x8, 21), _mm256_set1_epi32(1));
|
|
483
|
+
__m256i rounding_bias_i32x8 = _mm256_add_epi32(_mm256_set1_epi32(0x000FFFFF), lsb_i32x8);
|
|
484
|
+
__m256i rounded_sig_i32x8 = _mm256_add_epi32(significand_i32x8, rounding_bias_i32x8);
|
|
485
|
+
__m256i carry_i32x8 = _mm256_srli_epi32(rounded_sig_i32x8, 24); // Carry into exponent if bit 24 set
|
|
486
|
+
__m256i f32_mantissa_i32x8 = _mm256_and_si256(_mm256_srli_epi32(rounded_sig_i32x8, 21), _mm256_set1_epi32(0x03));
|
|
487
|
+
// If carry, mantissa becomes 0 (we rounded up to next power of 2)
|
|
488
|
+
f32_mantissa_i32x8 = _mm256_andnot_si256(_mm256_slli_epi32(carry_i32x8, 31), f32_mantissa_i32x8);
|
|
489
|
+
__m256i e3m2_exp_i32x8 = _mm256_sub_epi32(_mm256_add_epi32(f32_exp_i32x8, carry_i32x8), _mm256_set1_epi32(124));
|
|
490
|
+
|
|
491
|
+
// Detect underflow (exp <= 0, maps to subnormal/zero) and overflow (exp > 7)
|
|
492
|
+
__m256i is_subnormal_i32x8 = _mm256_cmpgt_epi32(_mm256_set1_epi32(1), e3m2_exp_i32x8);
|
|
493
|
+
__m256i overflow_i32x8 = _mm256_cmpgt_epi32(e3m2_exp_i32x8, _mm256_set1_epi32(7));
|
|
494
|
+
|
|
495
|
+
// Normal path: clamp exp to [1,7], extract mantissa bits
|
|
496
|
+
__m256i clamped_exp_i32x8 = _mm256_max_epi32(e3m2_exp_i32x8, _mm256_set1_epi32(1));
|
|
497
|
+
clamped_exp_i32x8 = _mm256_min_epi32(clamped_exp_i32x8, _mm256_set1_epi32(7));
|
|
498
|
+
__m256i normal_mantissa_i32x8 = _mm256_blendv_epi8(f32_mantissa_i32x8, _mm256_set1_epi32(0x03), overflow_i32x8);
|
|
499
|
+
__m256i normal_e3m2_i32x8 = _mm256_or_si256(
|
|
500
|
+
_mm256_slli_epi32(sign_i32x8, 5),
|
|
501
|
+
_mm256_or_si256(_mm256_slli_epi32(clamped_exp_i32x8, 2), normal_mantissa_i32x8));
|
|
502
|
+
|
|
503
|
+
// Subnormal path: mantissa = round(abs_f32 * 16)
|
|
504
|
+
// If mantissa rounds to 4 or higher, promote to first normal (exp_field=1, mantissa=0) = 0x04
|
|
505
|
+
__m256 abs_f32x8 = _mm256_and_ps(f32x8, _mm256_castsi256_ps(_mm256_set1_epi32(0x7FFFFFFF)));
|
|
506
|
+
__m256 scaled_f32x8 = _mm256_mul_ps(abs_f32x8, _mm256_set1_ps(16.0f));
|
|
507
|
+
__m256i subnorm_mantissa_i32x8 = _mm256_cvtps_epi32(scaled_f32x8);
|
|
508
|
+
__m256i promotes_to_normal_i32x8 = _mm256_cmpgt_epi32(subnorm_mantissa_i32x8, _mm256_set1_epi32(3));
|
|
509
|
+
subnorm_mantissa_i32x8 = _mm256_min_epi32(subnorm_mantissa_i32x8, _mm256_set1_epi32(3));
|
|
510
|
+
subnorm_mantissa_i32x8 = _mm256_max_epi32(subnorm_mantissa_i32x8, _mm256_setzero_si256());
|
|
511
|
+
__m256i subnorm_e3m2_i32x8 = _mm256_or_si256(_mm256_slli_epi32(sign_i32x8, 5), subnorm_mantissa_i32x8);
|
|
512
|
+
// When mantissa rounds to 4, use first normal value (0x04) instead of clamped subnormal
|
|
513
|
+
__m256i first_normal_e3m2_i32x8 = _mm256_or_si256(_mm256_slli_epi32(sign_i32x8, 5), _mm256_set1_epi32(0x04));
|
|
514
|
+
subnorm_e3m2_i32x8 = _mm256_blendv_epi8(subnorm_e3m2_i32x8, first_normal_e3m2_i32x8, promotes_to_normal_i32x8);
|
|
515
|
+
|
|
516
|
+
// Blend: use subnormal result when exp <= 0
|
|
517
|
+
__m256i e3m2_i32x8 = _mm256_blendv_epi8(normal_e3m2_i32x8, subnorm_e3m2_i32x8, is_subnormal_i32x8);
|
|
518
|
+
|
|
519
|
+
// Pack 8 i32s to 8 unsigned i8s (use unsigned saturation to preserve values 128-255)
|
|
520
|
+
__m128i low_i32x4 = _mm256_castsi256_si128(e3m2_i32x8);
|
|
521
|
+
__m128i high_i32x4 = _mm256_extracti128_si256(e3m2_i32x8, 1);
|
|
522
|
+
__m128i packed_i16x8 = _mm_packus_epi32(low_i32x4, high_i32x4);
|
|
523
|
+
__m128i packed_i8x8 = _mm_packus_epi16(packed_i16x8, packed_i16x8);
|
|
524
|
+
return packed_i8x8;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
#pragma endregion Vectorized Conversions
|
|
528
|
+
|
|
529
|
+
#pragma region Converting Loads and Stores
|
|
530
|
+
|
|
531
|
+
/** @brief Full load for f16 elements (8) with conversion to f32 via F16C. */
|
|
532
|
+
NK_INTERNAL void nk_load_f16x8_to_f32x8_haswell_(void const *src, nk_b256_vec_t *dst) {
|
|
533
|
+
dst->ymm_ps = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const *)src));
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/** @brief Partial load for f16 elements (up to 8) with conversion to f32 via F16C. */
|
|
537
|
+
NK_INTERNAL void nk_partial_load_f16x8_to_f32x8_haswell_(nk_f16_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
538
|
+
nk_b128_vec_t vec;
|
|
539
|
+
nk_partial_load_b16x8_serial_(src, &vec, n);
|
|
540
|
+
dst->ymm_ps = _mm256_cvtph_ps(vec.xmm);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/** @brief Full load for bf16 elements (8) with conversion to f32. */
|
|
544
|
+
NK_INTERNAL void nk_load_bf16x8_to_f32x8_haswell_(void const *src, nk_b256_vec_t *dst) {
|
|
545
|
+
dst->ymm_ps = nk_bf16x8_to_f32x8_haswell_(_mm_loadu_si128((__m128i const *)src));
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/** @brief Partial load for bf16 elements (up to 8) with conversion to f32. */
|
|
549
|
+
NK_INTERNAL void nk_partial_load_bf16x8_to_f32x8_haswell_(nk_bf16_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
550
|
+
nk_b128_vec_t vec;
|
|
551
|
+
nk_partial_load_b16x8_serial_(src, &vec, n);
|
|
552
|
+
dst->ymm_ps = nk_bf16x8_to_f32x8_haswell_(vec.xmm);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** @brief Full load for e4m3 elements (8) with conversion to f32. */
|
|
556
|
+
NK_INTERNAL void nk_load_e4m3x8_to_f32x8_haswell_(void const *src, nk_b256_vec_t *dst) {
|
|
557
|
+
dst->ymm_ps = nk_e4m3x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)src));
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/** @brief Partial load for e4m3 elements (up to 8) with conversion to f32. */
|
|
561
|
+
NK_INTERNAL void nk_partial_load_e4m3x8_to_f32x8_haswell_(nk_e4m3_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
562
|
+
nk_b64_vec_t vec;
|
|
563
|
+
nk_partial_load_b8x8_serial_(src, &vec, n);
|
|
564
|
+
dst->ymm_ps = nk_e4m3x8_to_f32x8_haswell_(_mm_cvtsi64_si128(vec.u64));
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/** @brief Full load for e5m2 elements (8) with conversion to f32. */
|
|
568
|
+
NK_INTERNAL void nk_load_e5m2x8_to_f32x8_haswell_(void const *src, nk_b256_vec_t *dst) {
|
|
569
|
+
dst->ymm_ps = nk_e5m2x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)src));
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/** @brief Partial load for e5m2 elements (up to 8) with conversion to f32. */
|
|
573
|
+
NK_INTERNAL void nk_partial_load_e5m2x8_to_f32x8_haswell_(nk_e5m2_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
574
|
+
nk_b64_vec_t vec;
|
|
575
|
+
nk_partial_load_b8x8_serial_(src, &vec, n);
|
|
576
|
+
dst->ymm_ps = nk_e5m2x8_to_f32x8_haswell_(_mm_cvtsi64_si128(vec.u64));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/** @brief Full load for e2m3 elements (8) with conversion to f32. */
|
|
580
|
+
NK_INTERNAL void nk_load_e2m3x8_to_f32x8_haswell_(void const *src, nk_b256_vec_t *dst) {
|
|
581
|
+
dst->ymm_ps = nk_e2m3x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)src));
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/** @brief Partial load for e2m3 elements (up to 8) with conversion to f32. */
|
|
585
|
+
NK_INTERNAL void nk_partial_load_e2m3x8_to_f32x8_haswell_(nk_e2m3_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
586
|
+
nk_b64_vec_t vec;
|
|
587
|
+
nk_partial_load_b8x8_serial_(src, &vec, n);
|
|
588
|
+
dst->ymm_ps = nk_e2m3x8_to_f32x8_haswell_(_mm_cvtsi64_si128(vec.u64));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/** @brief Full load for e3m2 elements (8) with conversion to f32. */
|
|
592
|
+
NK_INTERNAL void nk_load_e3m2x8_to_f32x8_haswell_(void const *src, nk_b256_vec_t *dst) {
|
|
593
|
+
dst->ymm_ps = nk_e3m2x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)src));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** @brief Partial load for e3m2 elements (up to 8) with conversion to f32. */
|
|
597
|
+
NK_INTERNAL void nk_partial_load_e3m2x8_to_f32x8_haswell_(nk_e3m2_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
598
|
+
nk_b64_vec_t vec;
|
|
599
|
+
nk_partial_load_b8x8_serial_(src, &vec, n);
|
|
600
|
+
dst->ymm_ps = nk_e3m2x8_to_f32x8_haswell_(_mm_cvtsi64_si128(vec.u64));
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/** @brief Partial load for i8 elements (up to 8) with conversion to f32. */
|
|
604
|
+
NK_INTERNAL void nk_partial_load_i8x8_to_f32x8_haswell_(nk_i8_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
605
|
+
nk_b64_vec_t vec;
|
|
606
|
+
nk_partial_load_b8x8_serial_(src, &vec, n);
|
|
607
|
+
dst->ymm_ps = nk_i8x8_to_f32x8_haswell_(_mm_cvtsi64_si128(vec.u64));
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/** @brief Partial load for u8 elements (up to 8) with conversion to f32. */
|
|
611
|
+
NK_INTERNAL void nk_partial_load_u8x8_to_f32x8_haswell_(nk_u8_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
612
|
+
nk_b64_vec_t vec;
|
|
613
|
+
nk_partial_load_b8x8_serial_(src, &vec, n);
|
|
614
|
+
dst->ymm_ps = nk_u8x8_to_f32x8_haswell_(_mm_cvtsi64_si128(vec.u64));
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/** @brief Partial load for i16 elements (up to 8) with conversion to f32. */
|
|
618
|
+
NK_INTERNAL void nk_partial_load_i16x8_to_f32x8_haswell_(nk_i16_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
619
|
+
nk_b128_vec_t vec;
|
|
620
|
+
nk_partial_load_b16x8_serial_(src, &vec, n);
|
|
621
|
+
dst->ymm_ps = nk_i16x8_to_f32x8_haswell_(vec.xmm);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/** @brief Partial load for u16 elements (up to 8) with conversion to f32. */
|
|
625
|
+
NK_INTERNAL void nk_partial_load_u16x8_to_f32x8_haswell_(nk_u16_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
626
|
+
nk_b128_vec_t vec;
|
|
627
|
+
nk_partial_load_b16x8_serial_(src, &vec, n);
|
|
628
|
+
dst->ymm_ps = nk_u16x8_to_f32x8_haswell_(vec.xmm);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/** @brief Partial load for i32 elements (up to 8) with conversion to f32. */
|
|
632
|
+
NK_INTERNAL void nk_partial_load_i32x8_to_f32x8_haswell_(nk_i32_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
633
|
+
nk_b256_vec_t vec;
|
|
634
|
+
nk_partial_load_b32x8_serial_(src, &vec, n);
|
|
635
|
+
dst->ymm_ps = nk_i32x8_to_f32x8_haswell_(vec.ymm);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/** @brief Partial load for u32 elements (up to 8) with conversion to f32. */
|
|
639
|
+
NK_INTERNAL void nk_partial_load_u32x8_to_f32x8_haswell_(nk_u32_t const *src, nk_b256_vec_t *dst, nk_size_t n) {
|
|
640
|
+
nk_b256_vec_t vec;
|
|
641
|
+
nk_partial_load_b32x8_serial_(src, &vec, n);
|
|
642
|
+
dst->ymm_ps = nk_u32x8_to_f32x8_haswell_(vec.ymm);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
#pragma endregion Converting Loads and Stores
|
|
646
|
+
|
|
647
|
+
#pragma region Public API
|
|
648
|
+
|
|
649
|
+
NK_PUBLIC void nk_cast_haswell(void const *from, nk_dtype_t from_type, nk_size_t n, void *to, nk_dtype_t to_type) {
|
|
650
|
+
// Same-type fast path
|
|
651
|
+
if (from_type == to_type) {
|
|
652
|
+
nk_size_t size_bits = nk_dtype_bits(from_type);
|
|
653
|
+
if (size_bits > 0) nk_copy_bytes_(to, from, nk_size_divide_round_up_(n * size_bits, NK_BITS_PER_BYTE));
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Supported types: floats (f32, f16, bf16, e4m3, e5m2, e2m3, e3m2) and integers (i8, u8, i16, u16, i32, u32)
|
|
658
|
+
int from_supported = (from_type == nk_f32_k || from_type == nk_f16_k || from_type == nk_bf16_k ||
|
|
659
|
+
from_type == nk_e4m3_k || from_type == nk_e5m2_k || from_type == nk_e2m3_k ||
|
|
660
|
+
from_type == nk_e3m2_k || from_type == nk_i8_k || from_type == nk_u8_k ||
|
|
661
|
+
from_type == nk_i16_k || from_type == nk_u16_k || from_type == nk_i32_k ||
|
|
662
|
+
from_type == nk_u32_k);
|
|
663
|
+
int to_supported = (to_type == nk_f32_k || to_type == nk_f16_k || to_type == nk_bf16_k || to_type == nk_e4m3_k ||
|
|
664
|
+
to_type == nk_e5m2_k || to_type == nk_e2m3_k || to_type == nk_e3m2_k || to_type == nk_i8_k ||
|
|
665
|
+
to_type == nk_u8_k || to_type == nk_i16_k || to_type == nk_u16_k || to_type == nk_i32_k ||
|
|
666
|
+
to_type == nk_u32_k);
|
|
667
|
+
if (!from_supported || !to_supported) {
|
|
668
|
+
nk_cast_serial(from, from_type, n, to, to_type);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Fall back to serial for i32/u32↔i32/u32 (f32 intermediate loses precision for large values)
|
|
673
|
+
int from_32bit_int = (from_type == nk_i32_k || from_type == nk_u32_k);
|
|
674
|
+
int to_32bit_int = (to_type == nk_i32_k || to_type == nk_u32_k);
|
|
675
|
+
if (from_32bit_int && to_32bit_int) {
|
|
676
|
+
nk_cast_serial(from, from_type, n, to, to_type);
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Byte steps per 8 elements
|
|
681
|
+
nk_size_t from_step = 8 * nk_dtype_bits(from_type) / NK_BITS_PER_BYTE;
|
|
682
|
+
nk_size_t to_step = 8 * nk_dtype_bits(to_type) / NK_BITS_PER_BYTE;
|
|
683
|
+
|
|
684
|
+
nk_u8_t const *from_ptr = (nk_u8_t const *)from;
|
|
685
|
+
nk_u8_t *to_ptr = (nk_u8_t *)to;
|
|
686
|
+
nk_size_t batches = n / 8;
|
|
687
|
+
nk_size_t tail = n % 8;
|
|
688
|
+
nk_b256_vec_t hub;
|
|
689
|
+
|
|
690
|
+
for (nk_size_t idx = 0; idx < batches; ++idx, from_ptr += from_step, to_ptr += to_step) {
|
|
691
|
+
// Upcast to f32x8
|
|
692
|
+
if (from_type == nk_f32_k) hub.ymm_ps = _mm256_loadu_ps((float const *)from_ptr);
|
|
693
|
+
else if (from_type == nk_f16_k) hub.ymm_ps = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const *)from_ptr));
|
|
694
|
+
else if (from_type == nk_bf16_k)
|
|
695
|
+
hub.ymm_ps = nk_bf16x8_to_f32x8_haswell_(_mm_loadu_si128((__m128i const *)from_ptr));
|
|
696
|
+
else if (from_type == nk_e4m3_k)
|
|
697
|
+
hub.ymm_ps = nk_e4m3x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)from_ptr));
|
|
698
|
+
else if (from_type == nk_e5m2_k)
|
|
699
|
+
hub.ymm_ps = nk_e5m2x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)from_ptr));
|
|
700
|
+
else if (from_type == nk_e2m3_k)
|
|
701
|
+
hub.ymm_ps = nk_e2m3x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)from_ptr));
|
|
702
|
+
else if (from_type == nk_e3m2_k)
|
|
703
|
+
hub.ymm_ps = nk_e3m2x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)from_ptr));
|
|
704
|
+
else if (from_type == nk_i8_k)
|
|
705
|
+
hub.ymm_ps = nk_i8x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)from_ptr));
|
|
706
|
+
else if (from_type == nk_u8_k)
|
|
707
|
+
hub.ymm_ps = nk_u8x8_to_f32x8_haswell_(_mm_loadl_epi64((__m128i const *)from_ptr));
|
|
708
|
+
else if (from_type == nk_i16_k)
|
|
709
|
+
hub.ymm_ps = nk_i16x8_to_f32x8_haswell_(_mm_loadu_si128((__m128i const *)from_ptr));
|
|
710
|
+
else if (from_type == nk_u16_k)
|
|
711
|
+
hub.ymm_ps = nk_u16x8_to_f32x8_haswell_(_mm_loadu_si128((__m128i const *)from_ptr));
|
|
712
|
+
else if (from_type == nk_i32_k)
|
|
713
|
+
hub.ymm_ps = nk_i32x8_to_f32x8_haswell_(_mm256_loadu_si256((__m256i const *)from_ptr));
|
|
714
|
+
else if (from_type == nk_u32_k)
|
|
715
|
+
hub.ymm_ps = nk_u32x8_to_f32x8_haswell_(_mm256_loadu_si256((__m256i const *)from_ptr));
|
|
716
|
+
|
|
717
|
+
// Downcast from f32x8
|
|
718
|
+
if (to_type == nk_f32_k) _mm256_storeu_ps((float *)to_ptr, hub.ymm_ps);
|
|
719
|
+
else if (to_type == nk_f16_k)
|
|
720
|
+
_mm_storeu_si128((__m128i *)to_ptr, _mm256_cvtps_ph(hub.ymm_ps, _MM_FROUND_TO_NEAREST_INT));
|
|
721
|
+
else if (to_type == nk_bf16_k) _mm_storeu_si128((__m128i *)to_ptr, nk_f32x8_to_bf16x8_haswell_(hub.ymm_ps));
|
|
722
|
+
else if (to_type == nk_e4m3_k) _mm_storel_epi64((__m128i *)to_ptr, nk_f32x8_to_e4m3x8_haswell_(hub.ymm_ps));
|
|
723
|
+
else if (to_type == nk_e5m2_k) _mm_storel_epi64((__m128i *)to_ptr, nk_f32x8_to_e5m2x8_haswell_(hub.ymm_ps));
|
|
724
|
+
else if (to_type == nk_e2m3_k) _mm_storel_epi64((__m128i *)to_ptr, nk_f32x8_to_e2m3x8_haswell_(hub.ymm_ps));
|
|
725
|
+
else if (to_type == nk_e3m2_k) _mm_storel_epi64((__m128i *)to_ptr, nk_f32x8_to_e3m2x8_haswell_(hub.ymm_ps));
|
|
726
|
+
else if (to_type == nk_i8_k) _mm_storel_epi64((__m128i *)to_ptr, nk_f32x8_to_i8x8_haswell_(hub.ymm_ps));
|
|
727
|
+
else if (to_type == nk_u8_k) _mm_storel_epi64((__m128i *)to_ptr, nk_f32x8_to_u8x8_haswell_(hub.ymm_ps));
|
|
728
|
+
else if (to_type == nk_i16_k) _mm_storeu_si128((__m128i *)to_ptr, nk_f32x8_to_i16x8_haswell_(hub.ymm_ps));
|
|
729
|
+
else if (to_type == nk_u16_k) _mm_storeu_si128((__m128i *)to_ptr, nk_f32x8_to_u16x8_haswell_(hub.ymm_ps));
|
|
730
|
+
else if (to_type == nk_i32_k) _mm256_storeu_si256((__m256i *)to_ptr, nk_f32x8_to_i32x8_haswell_(hub.ymm_ps));
|
|
731
|
+
else if (to_type == nk_u32_k) _mm256_storeu_si256((__m256i *)to_ptr, nk_f32x8_to_u32x8_haswell_(hub.ymm_ps));
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Handle tail with partial loads/stores
|
|
735
|
+
if (tail) {
|
|
736
|
+
// Upcast tail to f32x8
|
|
737
|
+
if (from_type == nk_f32_k) nk_partial_load_b32x8_serial_(from_ptr, &hub, tail);
|
|
738
|
+
else if (from_type == nk_f16_k) nk_partial_load_f16x8_to_f32x8_haswell_((nk_f16_t const *)from_ptr, &hub, tail);
|
|
739
|
+
else if (from_type == nk_bf16_k)
|
|
740
|
+
nk_partial_load_bf16x8_to_f32x8_haswell_((nk_bf16_t const *)from_ptr, &hub, tail);
|
|
741
|
+
else if (from_type == nk_e4m3_k)
|
|
742
|
+
nk_partial_load_e4m3x8_to_f32x8_haswell_((nk_e4m3_t const *)from_ptr, &hub, tail);
|
|
743
|
+
else if (from_type == nk_e5m2_k)
|
|
744
|
+
nk_partial_load_e5m2x8_to_f32x8_haswell_((nk_e5m2_t const *)from_ptr, &hub, tail);
|
|
745
|
+
else if (from_type == nk_e2m3_k)
|
|
746
|
+
nk_partial_load_e2m3x8_to_f32x8_haswell_((nk_e2m3_t const *)from_ptr, &hub, tail);
|
|
747
|
+
else if (from_type == nk_e3m2_k)
|
|
748
|
+
nk_partial_load_e3m2x8_to_f32x8_haswell_((nk_e3m2_t const *)from_ptr, &hub, tail);
|
|
749
|
+
else if (from_type == nk_i8_k) nk_partial_load_i8x8_to_f32x8_haswell_((nk_i8_t const *)from_ptr, &hub, tail);
|
|
750
|
+
else if (from_type == nk_u8_k) nk_partial_load_u8x8_to_f32x8_haswell_((nk_u8_t const *)from_ptr, &hub, tail);
|
|
751
|
+
else if (from_type == nk_i16_k) nk_partial_load_i16x8_to_f32x8_haswell_((nk_i16_t const *)from_ptr, &hub, tail);
|
|
752
|
+
else if (from_type == nk_u16_k) nk_partial_load_u16x8_to_f32x8_haswell_((nk_u16_t const *)from_ptr, &hub, tail);
|
|
753
|
+
else if (from_type == nk_i32_k) nk_partial_load_i32x8_to_f32x8_haswell_((nk_i32_t const *)from_ptr, &hub, tail);
|
|
754
|
+
else if (from_type == nk_u32_k) nk_partial_load_u32x8_to_f32x8_haswell_((nk_u32_t const *)from_ptr, &hub, tail);
|
|
755
|
+
|
|
756
|
+
// Downcast and store tail
|
|
757
|
+
if (to_type == nk_f32_k) nk_partial_store_b32x8_serial_(&hub, to_ptr, tail);
|
|
758
|
+
else if (to_type == nk_f16_k) {
|
|
759
|
+
hub.xmms[0] = _mm256_cvtps_ph(hub.ymm_ps, _MM_FROUND_TO_NEAREST_INT);
|
|
760
|
+
nk_partial_store_b16x8_serial_((nk_b128_vec_t *)&hub, to_ptr, tail);
|
|
761
|
+
}
|
|
762
|
+
else if (to_type == nk_bf16_k) {
|
|
763
|
+
hub.xmms[0] = nk_f32x8_to_bf16x8_haswell_(hub.ymm_ps);
|
|
764
|
+
nk_partial_store_b16x8_serial_((nk_b128_vec_t *)&hub, to_ptr, tail);
|
|
765
|
+
}
|
|
766
|
+
else if (to_type == nk_e4m3_k) {
|
|
767
|
+
hub.xmms[0] = nk_f32x8_to_e4m3x8_haswell_(hub.ymm_ps);
|
|
768
|
+
nk_partial_store_b8x8_serial_((nk_b64_vec_t *)&hub, to_ptr, tail);
|
|
769
|
+
}
|
|
770
|
+
else if (to_type == nk_e5m2_k) {
|
|
771
|
+
hub.xmms[0] = nk_f32x8_to_e5m2x8_haswell_(hub.ymm_ps);
|
|
772
|
+
nk_partial_store_b8x8_serial_((nk_b64_vec_t *)&hub, to_ptr, tail);
|
|
773
|
+
}
|
|
774
|
+
else if (to_type == nk_e2m3_k) {
|
|
775
|
+
hub.xmms[0] = nk_f32x8_to_e2m3x8_haswell_(hub.ymm_ps);
|
|
776
|
+
nk_partial_store_b8x8_serial_((nk_b64_vec_t *)&hub, to_ptr, tail);
|
|
777
|
+
}
|
|
778
|
+
else if (to_type == nk_e3m2_k) {
|
|
779
|
+
hub.xmms[0] = nk_f32x8_to_e3m2x8_haswell_(hub.ymm_ps);
|
|
780
|
+
nk_partial_store_b8x8_serial_((nk_b64_vec_t *)&hub, to_ptr, tail);
|
|
781
|
+
}
|
|
782
|
+
else if (to_type == nk_i8_k) {
|
|
783
|
+
hub.xmms[0] = nk_f32x8_to_i8x8_haswell_(hub.ymm_ps);
|
|
784
|
+
nk_partial_store_b8x8_serial_((nk_b64_vec_t *)&hub, to_ptr, tail);
|
|
785
|
+
}
|
|
786
|
+
else if (to_type == nk_u8_k) {
|
|
787
|
+
hub.xmms[0] = nk_f32x8_to_u8x8_haswell_(hub.ymm_ps);
|
|
788
|
+
nk_partial_store_b8x8_serial_((nk_b64_vec_t *)&hub, to_ptr, tail);
|
|
789
|
+
}
|
|
790
|
+
else if (to_type == nk_i16_k) {
|
|
791
|
+
hub.xmms[0] = nk_f32x8_to_i16x8_haswell_(hub.ymm_ps);
|
|
792
|
+
nk_partial_store_b16x8_serial_((nk_b128_vec_t *)&hub, to_ptr, tail);
|
|
793
|
+
}
|
|
794
|
+
else if (to_type == nk_u16_k) {
|
|
795
|
+
hub.xmms[0] = nk_f32x8_to_u16x8_haswell_(hub.ymm_ps);
|
|
796
|
+
nk_partial_store_b16x8_serial_((nk_b128_vec_t *)&hub, to_ptr, tail);
|
|
797
|
+
}
|
|
798
|
+
else if (to_type == nk_i32_k) {
|
|
799
|
+
hub.ymm = nk_f32x8_to_i32x8_haswell_(hub.ymm_ps);
|
|
800
|
+
nk_partial_store_b32x8_serial_(&hub, to_ptr, tail);
|
|
801
|
+
}
|
|
802
|
+
else if (to_type == nk_u32_k) {
|
|
803
|
+
hub.ymm = nk_f32x8_to_u32x8_haswell_(hub.ymm_ps);
|
|
804
|
+
nk_partial_store_b32x8_serial_(&hub, to_ptr, tail);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
#pragma endregion Public API
|
|
810
|
+
|
|
811
|
+
#if defined(__clang__)
|
|
812
|
+
#pragma clang attribute pop
|
|
813
|
+
#elif defined(__GNUC__)
|
|
814
|
+
#pragma GCC pop_options
|
|
815
|
+
#endif
|
|
816
|
+
|
|
817
|
+
#if defined(__cplusplus)
|
|
818
|
+
} // extern "C"
|
|
819
|
+
#endif
|
|
820
|
+
|
|
821
|
+
#endif // NK_TARGET_HASWELL
|
|
822
|
+
#endif // NK_TARGET_X8664_
|
|
823
|
+
#endif // NK_CAST_HASWELL_H
|