// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once // MKL VML runtime detection is only supported on Linux/Unix systems // because it requires dlfcn.h (dlopen/dlsym) which is not available on Windows. #if defined(PADDLE_WITH_MKLML) && !defined(_WIN32) #define PADDLE_MKL_VML_RUNTIME_DETECTION 1 #include #include // Type definitions for MKL VML sin/cos functions // These functions may not be available in lightweight mklml (libmklml_intel.so) // but are present in full Intel MKL. using vmsSin_t = void (*)(MKL_INT, const float*, float*, MKL_INT64); using vmdSin_t = void (*)(MKL_INT, const double*, double*, MKL_INT64); using vmsCos_t = void (*)(MKL_INT, const float*, float*, MKL_INT64); using vmdCos_t = void (*)(MKL_INT, const double*, double*, MKL_INT64); using vmsExp_t = void (*)(MKL_INT, const float*, float*, MKL_INT64); using vmdExp_t = void (*)(MKL_INT, const double*, double*, MKL_INT64); // VML mode constant: VML_HA | VML_FTZDAZ_OFF | VML_ERRMODE_IGNORE // = 0x2 | 0x00140000 | 0x100 = 0x00140102 static constexpr MKL_INT64 VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE = 0x00140102LL; // RTLD_NOLOAD is a GNU extension (available on Linux via _GNU_SOURCE). // Provide a fallback definition in case it is not defined. #ifndef RTLD_NOLOAD #define RTLD_NOLOAD 4 #endif namespace detail { // One-time initialization: try to make MKL VML functions available in global // symbol scope. This handles the case where MKL VML symbols (vmsSin, etc.) // are not directly exported globally, e.g. when other libraries are loaded // with RTLD_LOCAL. // // Strategies tried in order: // 1. Check if symbols are already visible via RTLD_DEFAULT (normal case). // 2. Try to load the full Intel MKL runtime (libmkl_rt.so) and promote it // to global scope so its symbols become visible. // // Thread safety: C++11 guarantees function-local statics are initialized // exactly once, even under concurrent access. inline void ensure_mkl_vml_probed() { static bool probed = false; if (probed) return; probed = true; // Strategy 1: Already in global scope - nothing to do if (dlsym(RTLD_DEFAULT, "vmsSin") != nullptr) return; // Strategy 2: Full Intel MKL runtime library // First check if already loaded (RTLD_NOLOAD), then try a fresh load. void* handle = dlopen("libmkl_rt.so", RTLD_LAZY | RTLD_NOLOAD); if (!handle) { handle = dlopen("libmkl_rt.so", RTLD_LAZY); } if (handle && dlsym(handle, "vmsSin") != nullptr) { // Re-open with RTLD_GLOBAL to make symbols visible via RTLD_DEFAULT dlopen("libmkl_rt.so", RTLD_LAZY | RTLD_GLOBAL); return; } } } // namespace detail // Runtime detection of MKL VML functions via dlsym. // Calls ensure_mkl_vml_probed() once to try multiple strategies for making // MKL VML symbols visible, then resolves each function via RTLD_DEFAULT. // Returns nullptr if the function is not available. inline vmsSin_t get_vmsSin() { static vmsSin_t func = nullptr; static bool checked = false; if (!checked) { checked = true; detail::ensure_mkl_vml_probed(); func = reinterpret_cast(dlsym(RTLD_DEFAULT, "vmsSin")); } return func; } inline vmdSin_t get_vmdSin() { static vmdSin_t func = nullptr; static bool checked = false; if (!checked) { checked = true; detail::ensure_mkl_vml_probed(); func = reinterpret_cast(dlsym(RTLD_DEFAULT, "vmdSin")); } return func; } inline vmsCos_t get_vmsCos() { static vmsCos_t func = nullptr; static bool checked = false; if (!checked) { checked = true; detail::ensure_mkl_vml_probed(); func = reinterpret_cast(dlsym(RTLD_DEFAULT, "vmsCos")); } return func; } inline vmdCos_t get_vmdCos() { static vmdCos_t func = nullptr; static bool checked = false; if (!checked) { checked = true; detail::ensure_mkl_vml_probed(); func = reinterpret_cast(dlsym(RTLD_DEFAULT, "vmdCos")); } return func; } inline vmsExp_t get_vmsExp() { static vmsExp_t func = nullptr; static bool checked = false; if (!checked) { checked = true; detail::ensure_mkl_vml_probed(); func = reinterpret_cast(dlsym(RTLD_DEFAULT, "vmsExp")); } return func; } inline vmdExp_t get_vmdExp() { static vmdExp_t func = nullptr; static bool checked = false; if (!checked) { checked = true; detail::ensure_mkl_vml_probed(); func = reinterpret_cast(dlsym(RTLD_DEFAULT, "vmdExp")); } return func; } // Check if MKL VML sin/cos functions are available at runtime inline bool mkl_vml_sincos_available() { static bool available = false; static bool checked = false; if (!checked) { checked = true; available = (get_vmsSin() != nullptr && get_vmdSin() != nullptr && get_vmsCos() != nullptr && get_vmdCos() != nullptr); } return available; } // Check if MKL VML exp functions are available at runtime inline bool mkl_vml_exp_available() { static bool available = false; static bool checked = false; if (!checked) { checked = true; available = (get_vmsExp() != nullptr && get_vmdExp() != nullptr); } return available; } #endif // PADDLE_WITH_MKLML && !_WIN32 #ifdef PADDLE_WITH_SLEEF #include #if defined(__AVX512F__) || defined(__AVX2__) || defined(__AVX__) #include #endif #if defined(__AVX2__) || defined(__AVX__) #define PADDLE_SLEEF_HAS_AVX2 1 #endif #if defined(__AVX512F__) #define PADDLE_SLEEF_HAS_AVX512 1 #endif #endif // PADDLE_WITH_SLEEF #include #include #include namespace phi { namespace funcs { namespace sleef_vec { // ============================================================================= // Scalar Sleef functions for pow // ============================================================================= #ifdef PADDLE_WITH_SLEEF template inline typename std::enable_if::value, T>::type pow_sleef_scalar(const T a, const T b) { return Sleef_powf1_u10(a, b); } template inline typename std::enable_if::value, T>::type pow_sleef_scalar(const T a, const T b) { return Sleef_powd1_u10(a, b); } #endif // PADDLE_WITH_SLEEF // ============================================================================= // Vectorized Sin/Cos functions - high precision implementation // ============================================================================= #ifdef PADDLE_WITH_SLEEF // ----------------------------------------------------------------------------- // AVX2 implementation (8 floats / 4 doubles at a time) // ----------------------------------------------------------------------------- #ifdef PADDLE_SLEEF_HAS_AVX2 // Vectorized sin for float using AVX2 inline void vsin_avx2_f32(float* out, const float* in, int64_t n) { constexpr int64_t VEC_SIZE = 8; // AVX2: 256-bit = 8 floats int64_t i = 0; // Process 8 floats at a time for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m256 vec_in = _mm256_loadu_ps(in + i); __m256 vec_out = Sleef_sinf8_u35(vec_in); _mm256_storeu_ps(out + i, vec_out); } // Handle remaining elements with scalar version for (; i < n; ++i) { out[i] = Sleef_sinf1_u35(in[i]); } } // Vectorized cos for float using AVX2 inline void vcos_avx2_f32(float* out, const float* in, int64_t n) { constexpr int64_t VEC_SIZE = 8; int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m256 vec_in = _mm256_loadu_ps(in + i); __m256 vec_out = Sleef_cosf8_u35(vec_in); _mm256_storeu_ps(out + i, vec_out); } for (; i < n; ++i) { out[i] = Sleef_cosf1_u35(in[i]); } } // Vectorized sin for double using AVX2 inline void vsin_avx2_f64(double* out, const double* in, int64_t n) { constexpr int64_t VEC_SIZE = 4; // AVX2: 256-bit = 4 doubles int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m256d vec_in = _mm256_loadu_pd(in + i); __m256d vec_out = Sleef_sind4_u10(vec_in); _mm256_storeu_pd(out + i, vec_out); } for (; i < n; ++i) { out[i] = Sleef_sind1_u10(in[i]); } } // Vectorized cos for double using AVX2 inline void vcos_avx2_f64(double* out, const double* in, int64_t n) { constexpr int64_t VEC_SIZE = 4; int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m256d vec_in = _mm256_loadu_pd(in + i); __m256d vec_out = Sleef_cosd4_u10(vec_in); _mm256_storeu_pd(out + i, vec_out); } for (; i < n; ++i) { out[i] = Sleef_cosd1_u10(in[i]); } } // Vectorized pow for float using AVX2 (no native AVX2 pow, use scalar Sleef) inline void vpow_avx2_f32(float* out, const float* x, const float* y, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_powf1_u10(x[i], y[i]); } } // Vectorized pow for double using AVX2 inline void vpow_avx2_f64(double* out, const double* x, const double* y, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_powd1_u10(x[i], y[i]); } } // Vectorized exp for float using AVX2 inline void vexp_avx2_f32(float* out, const float* in, int64_t n) { constexpr int64_t VEC_SIZE = 8; // AVX2: 256-bit = 8 floats int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m256 vec_in = _mm256_loadu_ps(in + i); __m256 vec_out = Sleef_expf8_u10(vec_in); _mm256_storeu_ps(out + i, vec_out); } for (; i < n; ++i) { out[i] = Sleef_expf1_u10(in[i]); } } #endif // PADDLE_SLEEF_HAS_AVX2 // ----------------------------------------------------------------------------- // AVX512 implementation (16 floats / 8 doubles at a time) // ----------------------------------------------------------------------------- #ifdef PADDLE_SLEEF_HAS_AVX512 inline void vsin_avx512_f32(float* out, const float* in, int64_t n) { constexpr int64_t VEC_SIZE = 16; // AVX512: 512-bit = 16 floats int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m512 vec_in = _mm512_loadu_ps(in + i); __m512 vec_out = Sleef_sinf16_u35(vec_in); _mm512_storeu_ps(out + i, vec_out); } // Fallback to AVX2 for remaining >= 8 elements #ifdef PADDLE_SLEEF_HAS_AVX2 for (; i + 8 <= n; i += 8) { __m256 vec_in = _mm256_loadu_ps(in + i); __m256 vec_out = Sleef_sinf8_u35(vec_in); _mm256_storeu_ps(out + i, vec_out); } #endif for (; i < n; ++i) { out[i] = Sleef_sinf1_u35(in[i]); } } inline void vcos_avx512_f32(float* out, const float* in, int64_t n) { constexpr int64_t VEC_SIZE = 16; int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m512 vec_in = _mm512_loadu_ps(in + i); __m512 vec_out = Sleef_cosf16_u35(vec_in); _mm512_storeu_ps(out + i, vec_out); } #ifdef PADDLE_SLEEF_HAS_AVX2 for (; i + 8 <= n; i += 8) { __m256 vec_in = _mm256_loadu_ps(in + i); __m256 vec_out = Sleef_cosf8_u35(vec_in); _mm256_storeu_ps(out + i, vec_out); } #endif for (; i < n; ++i) { out[i] = Sleef_cosf1_u35(in[i]); } } inline void vsin_avx512_f64(double* out, const double* in, int64_t n) { constexpr int64_t VEC_SIZE = 8; // AVX512: 512-bit = 8 doubles int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m512d vec_in = _mm512_loadu_pd(in + i); __m512d vec_out = Sleef_sind8_u10(vec_in); _mm512_storeu_pd(out + i, vec_out); } #ifdef PADDLE_SLEEF_HAS_AVX2 for (; i + 4 <= n; i += 4) { __m256d vec_in = _mm256_loadu_pd(in + i); __m256d vec_out = Sleef_sind4_u10(vec_in); _mm256_storeu_pd(out + i, vec_out); } #endif for (; i < n; ++i) { out[i] = Sleef_sind1_u10(in[i]); } } inline void vcos_avx512_f64(double* out, const double* in, int64_t n) { constexpr int64_t VEC_SIZE = 8; int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m512d vec_in = _mm512_loadu_pd(in + i); __m512d vec_out = Sleef_cosd8_u10(vec_in); _mm512_storeu_pd(out + i, vec_out); } #ifdef PADDLE_SLEEF_HAS_AVX2 for (; i + 4 <= n; i += 4) { __m256d vec_in = _mm256_loadu_pd(in + i); __m256d vec_out = Sleef_cosd4_u10(vec_in); _mm256_storeu_pd(out + i, vec_out); } #endif for (; i < n; ++i) { out[i] = Sleef_cosd1_u10(in[i]); } } // Vectorized pow for float using AVX512 (16 floats at a time) inline void vpow_avx512_f32(float* out, const float* x, const float* y, int64_t n) { constexpr int64_t VEC_SIZE = 16; int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m512 vec_x = _mm512_loadu_ps(x + i); __m512 vec_y = _mm512_loadu_ps(y + i); __m512 vec_out = Sleef_powf16_u10(vec_x, vec_y); _mm512_storeu_ps(out + i, vec_out); } for (; i < n; ++i) { out[i] = Sleef_powf1_u10(x[i], y[i]); } } // Vectorized pow for double using AVX512 (8 doubles at a time) inline void vpow_avx512_f64(double* out, const double* x, const double* y, int64_t n) { constexpr int64_t VEC_SIZE = 8; int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m512d vec_x = _mm512_loadu_pd(x + i); __m512d vec_y = _mm512_loadu_pd(y + i); __m512d vec_out = Sleef_powd8_u10(vec_x, vec_y); _mm512_storeu_pd(out + i, vec_out); } for (; i < n; ++i) { out[i] = Sleef_powd1_u10(x[i], y[i]); } } // Vectorized exp for float using AVX512 (16 floats at a time) inline void vexp_avx512_f32(float* out, const float* in, int64_t n) { constexpr int64_t VEC_SIZE = 16; // AVX512: 512-bit = 16 floats int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m512 vec_in = _mm512_loadu_ps(in + i); __m512 vec_out = Sleef_expf16_u10(vec_in); _mm512_storeu_ps(out + i, vec_out); } #ifdef PADDLE_SLEEF_HAS_AVX2 for (; i + 8 <= n; i += 8) { __m256 vec_in = _mm256_loadu_ps(in + i); __m256 vec_out = Sleef_expf8_u10(vec_in); _mm256_storeu_ps(out + i, vec_out); } #endif for (; i < n; ++i) { out[i] = Sleef_expf1_u10(in[i]); } } // Vectorized exp for double using AVX512 (8 doubles at a time) inline void vexp_avx512_f64(double* out, const double* in, int64_t n) { constexpr int64_t VEC_SIZE = 8; // AVX512: 512-bit = 8 doubles int64_t i = 0; for (; i + VEC_SIZE <= n; i += VEC_SIZE) { __m512d vec_in = _mm512_loadu_pd(in + i); __m512d vec_out = Sleef_expd8_u10(vec_in); _mm512_storeu_pd(out + i, vec_out); } #ifdef PADDLE_SLEEF_HAS_AVX2 for (; i + 4 <= n; i += 4) { __m256d vec_in = _mm256_loadu_pd(in + i); __m256d vec_out = Sleef_expd4_u10(vec_in); _mm256_storeu_pd(out + i, vec_out); } #endif for (; i < n; ++i) { out[i] = Sleef_expd1_u10(in[i]); } } #endif // PADDLE_SLEEF_HAS_AVX512 // ----------------------------------------------------------------------------- // Scalar fallback (when SIMD is not available) // ----------------------------------------------------------------------------- inline void vsin_scalar_f32(float* out, const float* in, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_sinf1_u35(in[i]); } } inline void vcos_scalar_f32(float* out, const float* in, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_cosf1_u35(in[i]); } } inline void vsin_scalar_f64(double* out, const double* in, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_sind1_u10(in[i]); } } inline void vcos_scalar_f64(double* out, const double* in, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_cosd1_u10(in[i]); } } // Scalar pow fallback inline void vpow_scalar_f32(float* out, const float* x, const float* y, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_powf1_u10(x[i], y[i]); } } inline void vpow_scalar_f64(double* out, const double* x, const double* y, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_powd1_u10(x[i], y[i]); } } // Scalar exp fallback inline void vexp_scalar_f32(float* out, const float* in, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_expf1_u10(in[i]); } } inline void vexp_scalar_f64(double* out, const double* in, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = Sleef_expd1_u10(in[i]); } } // No separate MKL VML wrapper functions needed. // Runtime detection is done inline in the dispatch functions below. // ----------------------------------------------------------------------------- // Unified dispatch functions // ----------------------------------------------------------------------------- // Vectorized sin for float - dispatches to best available implementation inline void vsin(float* out, const float* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_sin = get_vmsSin(); if (mkl_sin) { mkl_sin(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif #ifdef PADDLE_SLEEF_HAS_AVX512 vsin_avx512_f32(out, in, n); #elif defined(PADDLE_SLEEF_HAS_AVX2) vsin_avx2_f32(out, in, n); #else vsin_scalar_f32(out, in, n); #endif } // Vectorized cos for float inline void vcos(float* out, const float* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_cos = get_vmsCos(); if (mkl_cos) { mkl_cos(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif #ifdef PADDLE_SLEEF_HAS_AVX512 vcos_avx512_f32(out, in, n); #elif defined(PADDLE_SLEEF_HAS_AVX2) vcos_avx2_f32(out, in, n); #else vcos_scalar_f32(out, in, n); #endif } // Vectorized sin for double inline void vsin(double* out, const double* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_sin = get_vmdSin(); if (mkl_sin) { mkl_sin(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif #ifdef PADDLE_SLEEF_HAS_AVX512 vsin_avx512_f64(out, in, n); #elif defined(PADDLE_SLEEF_HAS_AVX2) vsin_avx2_f64(out, in, n); #else vsin_scalar_f64(out, in, n); #endif } // Vectorized cos for double inline void vcos(double* out, const double* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_cos = get_vmdCos(); if (mkl_cos) { mkl_cos(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif #ifdef PADDLE_SLEEF_HAS_AVX512 vcos_avx512_f64(out, in, n); #elif defined(PADDLE_SLEEF_HAS_AVX2) vcos_avx2_f64(out, in, n); #else vcos_scalar_f64(out, in, n); #endif } // Vectorized pow for float - dispatches to best available SIMD inline void vpow(float* out, const float* x, const float* y, int64_t n) { #ifdef PADDLE_SLEEF_HAS_AVX512 vpow_avx512_f32(out, x, y, n); #elif defined(PADDLE_SLEEF_HAS_AVX2) vpow_avx2_f32(out, x, y, n); #else vpow_scalar_f32(out, x, y, n); #endif } // Vectorized pow for double inline void vpow(double* out, const double* x, const double* y, int64_t n) { #ifdef PADDLE_SLEEF_HAS_AVX512 vpow_avx512_f64(out, x, y, n); #elif defined(PADDLE_SLEEF_HAS_AVX2) vpow_avx2_f64(out, x, y, n); #else vpow_scalar_f64(out, x, y, n); #endif } // Vectorized exp for float - dispatches to best available implementation inline void vexp(float* out, const float* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_exp = get_vmsExp(); if (mkl_exp) { mkl_exp(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif #ifdef PADDLE_SLEEF_HAS_AVX512 vexp_avx512_f32(out, in, n); #elif defined(PADDLE_SLEEF_HAS_AVX2) vexp_avx2_f32(out, in, n); #else vexp_scalar_f32(out, in, n); #endif } // Vectorized exp for double inline void vexp(double* out, const double* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_exp = get_vmdExp(); if (mkl_exp) { mkl_exp(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif #ifdef PADDLE_SLEEF_HAS_AVX512 vexp_avx512_f64(out, in, n); #else vexp_scalar_f64(out, in, n); #endif } #else // !PADDLE_WITH_SLEEF // Fallback to standard library when Sleef is not available #include inline void vsin(float* out, const float* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_sin = get_vmsSin(); if (mkl_sin) { mkl_sin(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif for (int64_t i = 0; i < n; ++i) { out[i] = std::sin(in[i]); } } inline void vcos(float* out, const float* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_cos = get_vmsCos(); if (mkl_cos) { mkl_cos(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif for (int64_t i = 0; i < n; ++i) { out[i] = std::cos(in[i]); } } inline void vsin(double* out, const double* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_sin = get_vmdSin(); if (mkl_sin) { mkl_sin(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif for (int64_t i = 0; i < n; ++i) { out[i] = std::sin(in[i]); } } inline void vcos(double* out, const double* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_cos = get_vmdCos(); if (mkl_cos) { mkl_cos(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif for (int64_t i = 0; i < n; ++i) { out[i] = std::cos(in[i]); } } inline void vpow(float* out, const float* x, const float* y, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = std::pow(x[i], y[i]); } } inline void vpow(double* out, const double* x, const double* y, int64_t n) { for (int64_t i = 0; i < n; ++i) { out[i] = std::pow(x[i], y[i]); } } inline void vexp(float* out, const float* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_exp = get_vmsExp(); if (mkl_exp) { mkl_exp(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif for (int64_t i = 0; i < n; ++i) { out[i] = std::exp(in[i]); } } inline void vexp(double* out, const double* in, int64_t n) { #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION auto mkl_exp = get_vmdExp(); if (mkl_exp) { mkl_exp(static_cast(n), in, out, VML_MODE_HA_FTZDAZ_OFF_ERRIGNORE); return; } #endif for (int64_t i = 0; i < n; ++i) { out[i] = std::exp(in[i]); } } #endif // PADDLE_WITH_SLEEF // ----------------------------------------------------------------------------- // Check if vectorized path should be used // ----------------------------------------------------------------------------- inline bool should_use_vectorized_path(const void* in_ptr, const void* out_ptr, int64_t numel) { // Use vectorized path when: // 1. MKL VML sin/cos functions are available at runtime (works for any size) // 2. SLEEF is available and element count is large enough for SIMD #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION if (mkl_vml_sincos_available()) { return true; // MKL VML works for any size } #endif #ifdef PADDLE_WITH_SLEEF constexpr int64_t MIN_ELEMENTS_FOR_SIMD = 8; return numel >= MIN_ELEMENTS_FOR_SIMD; #else return false; #endif } // Check if vectorized path should be used for exp operations inline bool should_use_vectorized_path_for_exp(const void* in_ptr, const void* out_ptr, int64_t numel) { // Use vectorized path when: // 1. MKL VML exp functions are available at runtime (works for any size) // 2. SLEEF is available and element count is large enough for SIMD #ifdef PADDLE_MKL_VML_RUNTIME_DETECTION if (mkl_vml_exp_available()) { return true; // MKL VML works for any size } #endif #ifdef PADDLE_WITH_SLEEF constexpr int64_t MIN_ELEMENTS_FOR_SIMD = 8; return numel >= MIN_ELEMENTS_FOR_SIMD; #else return false; #endif } } // namespace sleef_vec } // namespace funcs } // namespace phi