Skip to content

Initial WASM support. #242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ set(CMAKE_C_FLAGS_DEBUG "-g -fsanitize=address")
set(CMAKE_C_FLAGS_RELEASE "-O3")

# Compiler-specific flags
if (CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$")
if (CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
if (NOT APPLE)
add_compile_options(-march=native)
endif ()
Expand Down Expand Up @@ -104,15 +104,25 @@ if (SIMSIMD_BUILD_BENCHMARKS)
endif ()

if (SIMSIMD_BUILD_TESTS)
add_executable(simsimd_test_compile_time scripts/test.c)
target_link_libraries(simsimd_test_compile_time simsimd m)

add_executable(simsimd_test_run_time scripts/test.c c/lib.c)
target_compile_definitions(simsimd_test_run_time PRIVATE SIMSIMD_DYNAMIC_DISPATCH=1)
target_link_libraries(simsimd_test_run_time simsimd m)
if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
add_executable(simsimd_test_compile_time scripts/test.c)

target_compile_definitions(simsimd_test_compile_time PRIVATE _SIMSIMD_TARGET_ARM=1 SIMSIMD_TARGET_WASM=1)
target_compile_options(simsimd_test_compile_time PRIVATE -msimd128 -mfpu=neon)

target_link_libraries(simsimd_test_compile_time simsimd m)
else()
add_executable(simsimd_test_compile_time scripts/test.c)
target_compile_definitions(simsimd_test_compile_time PRIVATE SIMSIMD_TARGET_HASWELL=1)
target_link_libraries(simsimd_test_compile_time simsimd m)

add_executable(simsimd_test_run_time scripts/test.c c/lib.c)
target_compile_definitions(simsimd_test_run_time PRIVATE SIMSIMD_DYNAMIC_DISPATCH=1)
target_link_libraries(simsimd_test_run_time simsimd m)
endif()
endif ()

if (SIMSIMD_BUILD_SHARED)
if (SIMSIMD_BUILD_SHARED AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(SIMSIMD_SOURCES ${SIMSIMD_SOURCES} c/lib.c)
add_library(simsimd_shared SHARED ${SIMSIMD_SOURCES})
target_include_directories(simsimd_shared PUBLIC "${PROJECT_SOURCE_DIR}/include")
Expand Down
3 changes: 1 addition & 2 deletions include/simsimd/curved.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,10 @@ SIMSIMD_MAKE_COMPLEX_BILINEAR(accurate, bf16c, f64, SIMSIMD_BF16_TO_F32) // sims
SIMSIMD_MAKE_MAHALANOBIS(accurate, bf16, f64, SIMSIMD_BF16_TO_F32) // simsimd_mahalanobis_bf16_accurate

#if _SIMSIMD_TARGET_ARM
#if SIMSIMD_TARGET_NEON
#if SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
#pragma GCC push_options
#pragma GCC target("arch=armv8.2-a+simd")
#pragma clang attribute push(__attribute__((target("arch=armv8.2-a+simd"))), apply_to = function)

SIMSIMD_PUBLIC void simsimd_bilinear_f32_neon(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
simsimd_size_t n, simsimd_distance_t *result) {
float32x4_t sum_vec = vdupq_n_f32(0);
Expand Down
4 changes: 2 additions & 2 deletions include/simsimd/dot.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ SIMSIMD_MAKE_COMPLEX_DOT(accurate, bf16c, f64, SIMSIMD_BF16_TO_F32) // simsimd_
SIMSIMD_MAKE_COMPLEX_VDOT(accurate, bf16c, f64, SIMSIMD_BF16_TO_F32) // simsimd_vdot_bf16c_accurate

#if _SIMSIMD_TARGET_ARM
#if SIMSIMD_TARGET_NEON
#if SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
#pragma GCC push_options
#pragma GCC target("arch=armv8.2-a+simd")
#pragma clang attribute push(__attribute__((target("arch=armv8.2-a+simd"))), apply_to = function)
Expand Down Expand Up @@ -398,7 +398,7 @@ SIMSIMD_PUBLIC void simsimd_dot_u8_neon(simsimd_u8_t const *a_scalars, simsimd_u
#pragma GCC pop_options
#endif // SIMSIMD_TARGET_NEON_I8

#if SIMSIMD_TARGET_NEON_F16
#if SIMSIMD_TARGET_NEON_F16 || SIMSIMD_TARGET_WASM
#pragma GCC push_options
#pragma GCC target("arch=armv8.2-a+simd+fp16")
#pragma clang attribute push(__attribute__((target("arch=armv8.2-a+simd+fp16"))), apply_to = function)
Expand Down
2 changes: 1 addition & 1 deletion include/simsimd/elementwise.h
Original file line number Diff line number Diff line change
Expand Up @@ -1942,7 +1942,7 @@ SIMSIMD_PUBLIC void simsimd_fma_u8_sapphire(
#endif // _SIMSIMD_TARGET_X86

#if _SIMSIMD_TARGET_ARM
#if SIMSIMD_TARGET_NEON
#if SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
#pragma GCC push_options
#pragma GCC target("arch=armv8.2-a+simd")
#pragma clang attribute push(__attribute__((target("arch=armv8.2-a+simd"))), apply_to = function)
Expand Down
2 changes: 1 addition & 1 deletion include/simsimd/probability.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ SIMSIMD_MAKE_KL(accurate, bf16, f64, SIMSIMD_BF16_TO_F32, SIMSIMD_F32_DIVISION_E
SIMSIMD_MAKE_JS(accurate, bf16, f64, SIMSIMD_BF16_TO_F32, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_js_bf16_accurate

#if _SIMSIMD_TARGET_ARM
#if SIMSIMD_TARGET_NEON
#if SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
#pragma GCC push_options
#pragma GCC target("arch=armv8.2-a+simd")
#pragma clang attribute push(__attribute__((target("arch=armv8.2-a+simd"))), apply_to = function)
Expand Down
37 changes: 20 additions & 17 deletions include/simsimd/simsimd.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ typedef enum {
simsimd_cap_sve_i8_k = 1 << 27, ///< ARM SVE `i8` capability
simsimd_cap_sve2_k = 1 << 28, ///< ARM SVE2 capability
simsimd_cap_sve2p1_k = 1 << 29, ///< ARM SVE2p1 capability

simsimd_cap_wasm_simd_k = 1 << 30, ///< WASM capability
} simsimd_capability_t;

/**
Expand Down Expand Up @@ -504,6 +504,8 @@ SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_arm(void) {
(simsimd_cap_sve2_k * (supports_sve2)) | //
(simsimd_cap_sve2p1_k * (supports_sve2p1)) | //
(simsimd_cap_serial_k));
#elif defined(SIMSIMD_TARGET_WASM)
return simsimd_cap_wasm_simd_k;
#else // if !_SIMSIMD_DEFINED_LINUX
return simsimd_cap_serial_k;
#endif
Expand Down Expand Up @@ -1465,6 +1467,7 @@ SIMSIMD_PUBLIC int simsimd_uses_sve_f16(void) { return _SIMSIMD_TARGET_ARM && SI
SIMSIMD_PUBLIC int simsimd_uses_sve_bf16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_BF16; }
SIMSIMD_PUBLIC int simsimd_uses_sve_i8(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_I8; }
SIMSIMD_PUBLIC int simsimd_uses_sve2(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE2; }
SIMSIMD_PUBLIC int simsimd_uses_wasm_simd(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_WASM; }
SIMSIMD_PUBLIC int simsimd_uses_haswell(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_HASWELL; }
SIMSIMD_PUBLIC int simsimd_uses_skylake(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SKYLAKE; }
SIMSIMD_PUBLIC int simsimd_uses_ice(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_ICE; }
Expand Down Expand Up @@ -1527,7 +1530,7 @@ SIMSIMD_PUBLIC void simsimd_dot_f16(simsimd_f16_t const *a, simsimd_f16_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE_F16
simsimd_dot_f16_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON_F16
#elif SIMSIMD_TARGET_NEON_F16 || SIMSIMD_TARGET_WASM
simsimd_dot_f16_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SAPPHIRE
simsimd_dot_f16_sapphire(a, b, n, d);
Expand All @@ -1553,7 +1556,7 @@ SIMSIMD_PUBLIC void simsimd_dot_f32(simsimd_f32_t const *a, simsimd_f32_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_dot_f32_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_dot_f32_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_dot_f32_skylake(a, b, n, d);
Expand All @@ -1577,7 +1580,7 @@ SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t con
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE_F16
simsimd_dot_f16c_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON_F16
#elif SIMSIMD_TARGET_NEON_F16 || SIMSIMD_TARGET_WASM
simsimd_dot_f16c_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SAPPHIRE
simsimd_dot_f16c_sapphire(a, b, n, d);
Expand All @@ -1601,7 +1604,7 @@ SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t con
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_dot_f32c_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_dot_f32c_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_dot_f32c_skylake(a, b, n, d);
Expand All @@ -1625,7 +1628,7 @@ SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t co
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_vdot_f16c_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_dot_f16c_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SAPPHIRE
simsimd_dot_f16c_sapphire(a, b, n, d);
Expand All @@ -1649,7 +1652,7 @@ SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t co
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_vdot_f32c_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_dot_f32c_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_dot_f32c_skylake(a, b, n, d);
Expand Down Expand Up @@ -1711,7 +1714,7 @@ SIMSIMD_PUBLIC void simsimd_cos_f16(simsimd_f16_t const *a, simsimd_f16_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE_F16
simsimd_cos_f16_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON_F16
#elif SIMSIMD_TARGET_NEON_F16 || SIMSIMD_TARGET_WASM
simsimd_cos_f16_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SAPPHIRE
simsimd_cos_f16_sapphire(a, b, n, d);
Expand Down Expand Up @@ -1739,7 +1742,7 @@ SIMSIMD_PUBLIC void simsimd_cos_f32(simsimd_f32_t const *a, simsimd_f32_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_cos_f32_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_cos_f32_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_cos_f32_skylake(a, b, n, d);
Expand All @@ -1753,7 +1756,7 @@ SIMSIMD_PUBLIC void simsimd_cos_f64(simsimd_f64_t const *a, simsimd_f64_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_cos_f64_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_cos_f64_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_cos_f64_skylake(a, b, n, d);
Expand Down Expand Up @@ -1789,7 +1792,7 @@ SIMSIMD_PUBLIC void simsimd_l2sq_f16(simsimd_f16_t const *a, simsimd_f16_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE_F16
simsimd_l2sq_f16_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON_F16
#elif SIMSIMD_TARGET_NEON_F16 || SIMSIMD_TARGET_WASM
simsimd_l2sq_f16_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SAPPHIRE
simsimd_l2sq_f16_sapphire(a, b, n, d);
Expand Down Expand Up @@ -1817,7 +1820,7 @@ SIMSIMD_PUBLIC void simsimd_l2sq_f32(simsimd_f32_t const *a, simsimd_f32_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_l2sq_f32_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_l2sq_f32_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_l2sq_f32_skylake(a, b, n, d);
Expand All @@ -1831,7 +1834,7 @@ SIMSIMD_PUBLIC void simsimd_l2sq_f64(simsimd_f64_t const *a, simsimd_f64_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_l2sq_f64_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_l2sq_f64_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_l2sq_f64_skylake(a, b, n, d);
Expand Down Expand Up @@ -1935,7 +1938,7 @@ SIMSIMD_PUBLIC void simsimd_hamming_b8(simsimd_b8_t const *a, simsimd_b8_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_hamming_b8_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_hamming_b8_neon(a, b, n, d);
#elif SIMSIMD_TARGET_ICE
simsimd_hamming_b8_ice(a, b, n, d);
Expand All @@ -1949,7 +1952,7 @@ SIMSIMD_PUBLIC void simsimd_jaccard_b8(simsimd_b8_t const *a, simsimd_b8_t const
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_SVE
simsimd_jaccard_b8_sve(a, b, n, d);
#elif SIMSIMD_TARGET_NEON
#elif SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_jaccard_b8_neon(a, b, n, d);
#elif SIMSIMD_TARGET_ICE
simsimd_jaccard_b8_ice(a, b, n, d);
Expand Down Expand Up @@ -1990,7 +1993,7 @@ SIMSIMD_PUBLIC void simsimd_kl_bf16(simsimd_bf16_t const *a, simsimd_bf16_t cons
}
SIMSIMD_PUBLIC void simsimd_kl_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_NEON
#if SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_kl_f32_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_kl_f32_skylake(a, b, n, d);
Expand Down Expand Up @@ -2018,7 +2021,7 @@ SIMSIMD_PUBLIC void simsimd_js_bf16(simsimd_bf16_t const *a, simsimd_bf16_t cons
}
SIMSIMD_PUBLIC void simsimd_js_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
simsimd_distance_t *d) {
#if SIMSIMD_TARGET_NEON
#if SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
simsimd_js_f32_neon(a, b, n, d);
#elif SIMSIMD_TARGET_SKYLAKE
simsimd_js_f32_skylake(a, b, n, d);
Expand Down
4 changes: 2 additions & 2 deletions include/simsimd/spatial.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ SIMSIMD_MAKE_L2SQ(accurate, bf16, f64, SIMSIMD_BF16_TO_F32) // simsimd_l2sq_bf16
SIMSIMD_MAKE_L2(accurate, bf16, f64, SIMSIMD_BF16_TO_F32) // simsimd_l2_bf16_accurate

#if _SIMSIMD_TARGET_ARM
#if SIMSIMD_TARGET_NEON
#if SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
#pragma GCC push_options
#pragma GCC target("arch=armv8.2-a+simd")
#pragma clang attribute push(__attribute__((target("arch=armv8.2-a+simd"))), apply_to = function)
Expand Down Expand Up @@ -395,7 +395,7 @@ SIMSIMD_PUBLIC void simsimd_cos_f64_neon(simsimd_f64_t const *a, simsimd_f64_t c
#pragma GCC pop_options
#endif // SIMSIMD_TARGET_NEON

#if SIMSIMD_TARGET_NEON_F16
#if SIMSIMD_TARGET_NEON_F16 || SIMSIMD_TARGET_WASM
#pragma GCC push_options
#pragma GCC target("arch=armv8.2-a+simd+fp16")
#pragma clang attribute push(__attribute__((target("arch=armv8.2-a+simd+fp16"))), apply_to = function)
Expand Down
2 changes: 1 addition & 1 deletion include/simsimd/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
#include <intrin.h>
#else

#if SIMSIMD_TARGET_NEON
#if SIMSIMD_TARGET_NEON || SIMSIMD_TARGET_WASM
#include <arm_neon.h>
#endif

Expand Down
2 changes: 2 additions & 0 deletions scripts/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ void test_utilities(void) {
int uses_sapphire = simsimd_uses_sapphire();
int uses_turin = simsimd_uses_turin();
int uses_sierra = simsimd_uses_sierra();
int uses_wasm = simsimd_uses_wasm_simd();

assert(uses_neon == ((capabilities & simsimd_cap_neon_k) != 0));
assert(uses_sve == ((capabilities & simsimd_cap_sve_k) != 0));
Expand All @@ -79,6 +80,7 @@ void test_utilities(void) {
assert(uses_sapphire == ((capabilities & simsimd_cap_sapphire_k) != 0));
assert(uses_turin == ((capabilities & simsimd_cap_turin_k) != 0));
assert(uses_sierra == ((capabilities & simsimd_cap_sierra_k) != 0));
assert(uses_wasm == ((capabilities & simsimd_cap_wasm_simd_k) != 0));
}

/**
Expand Down