blob: 2717ed76d68653a8e5496ceb61c51d900601444a [file]
/*
* Copyright 2026 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
// Exhaustive FMA test — compare against native x86 output.
// This test should be run with -mrelaxed-simd, and on an x86 host, so that
// Wasm relaxed SIMD FMA lowers to a hardware fused multiply-add matching
// native x86 FMA behavior bit-for-bit.
// immintrin.h must be included before test_sse.h
// clang-format off
#include <immintrin.h>
#include "test_sse.h"
// clang-format on
bool testNaNBits = false;
float* interesting_floats = get_interesting_floats();
int numInterestingFloats =
sizeof(interesting_floats_) / sizeof(interesting_floats_[0]);
uint32_t* interesting_ints = get_interesting_ints();
int numInterestingInts =
sizeof(interesting_ints_) / sizeof(interesting_ints_[0]);
double* interesting_doubles = get_interesting_doubles();
int numInterestingDoubles =
sizeof(interesting_doubles_) / sizeof(interesting_doubles_[0]);
void test_fmadd(void) {
Ret_M128_M128_M128(__m128, _mm_fmadd_ps);
Ret_M128d_M128d_M128d(__m128d, _mm_fmadd_pd);
Ret_M128_M128_M128(__m128, _mm_fmadd_ss);
Ret_M128d_M128d_M128d(__m128d, _mm_fmadd_sd);
#ifdef __AVX__
Ret_M256_M256_M256(__m256, _mm256_fmadd_ps);
Ret_M256d_M256d_M256d(__m256d, _mm256_fmadd_pd);
#endif
}
void test_fmsub(void) {
Ret_M128_M128_M128(__m128, _mm_fmsub_ps);
Ret_M128d_M128d_M128d(__m128d, _mm_fmsub_pd);
Ret_M128_M128_M128(__m128, _mm_fmsub_ss);
Ret_M128d_M128d_M128d(__m128d, _mm_fmsub_sd);
#ifdef __AVX__
Ret_M256_M256_M256(__m256, _mm256_fmsub_ps);
Ret_M256d_M256d_M256d(__m256d, _mm256_fmsub_pd);
#endif
}
void test_fnmadd(void) {
Ret_M128_M128_M128(__m128, _mm_fnmadd_ps);
Ret_M128d_M128d_M128d(__m128d, _mm_fnmadd_pd);
Ret_M128_M128_M128(__m128, _mm_fnmadd_ss);
Ret_M128d_M128d_M128d(__m128d, _mm_fnmadd_sd);
#ifdef __AVX__
Ret_M256_M256_M256(__m256, _mm256_fnmadd_ps);
Ret_M256d_M256d_M256d(__m256d, _mm256_fnmadd_pd);
#endif
}
void test_fnmsub(void) {
Ret_M128_M128_M128(__m128, _mm_fnmsub_ps);
Ret_M128d_M128d_M128d(__m128d, _mm_fnmsub_pd);
Ret_M128_M128_M128(__m128, _mm_fnmsub_ss);
Ret_M128d_M128d_M128d(__m128d, _mm_fnmsub_sd);
#ifdef __AVX__
Ret_M256_M256_M256(__m256, _mm256_fnmsub_ps);
Ret_M256d_M256d_M256d(__m256d, _mm256_fnmsub_pd);
#endif
}
void test_fmaddsub(void) {
Ret_M128_M128_M128(__m128, _mm_fmaddsub_ps);
Ret_M128d_M128d_M128d(__m128d, _mm_fmaddsub_pd);
#ifdef __AVX__
Ret_M256_M256_M256(__m256, _mm256_fmaddsub_ps);
Ret_M256d_M256d_M256d(__m256d, _mm256_fmaddsub_pd);
#endif
}
void test_fmsubadd(void) {
Ret_M128_M128_M128(__m128, _mm_fmsubadd_ps);
Ret_M128d_M128d_M128d(__m128d, _mm_fmsubadd_pd);
#ifdef __AVX__
Ret_M256_M256_M256(__m256, _mm256_fmsubadd_ps);
Ret_M256d_M256d_M256d(__m256d, _mm256_fmsubadd_pd);
#endif
}
int main() {
assert(numInterestingFloats % 8 == 0);
assert(numInterestingInts % 8 == 0);
assert(numInterestingDoubles % 4 == 0);
test_fmadd();
test_fmsub();
test_fnmadd();
test_fnmsub();
test_fmaddsub();
test_fmsubadd();
}