Files
paddlepaddle--paddle/paddle/phi/kernels/funcs/sleef_vectorized_math.h
T
2026-07-13 12:40:42 +08:00

859 lines
24 KiB
C++

// 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 <dlfcn.h>
#include <mkl.h>
// 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<vmsSin_t>(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<vmdSin_t>(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<vmsCos_t>(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<vmdCos_t>(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<vmsExp_t>(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<vmdExp_t>(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 <sleef.h>
#if defined(__AVX512F__) || defined(__AVX2__) || defined(__AVX__)
#include <immintrin.h>
#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 <cstdint>
#include <cstring>
#include <type_traits>
namespace phi {
namespace funcs {
namespace sleef_vec {
// =============================================================================
// Scalar Sleef functions for pow
// =============================================================================
#ifdef PADDLE_WITH_SLEEF
template <typename T>
inline typename std::enable_if<std::is_same<T, float>::value, T>::type
pow_sleef_scalar(const T a, const T b) {
return Sleef_powf1_u10(a, b);
}
template <typename T>
inline typename std::enable_if<std::is_same<T, double>::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<MKL_INT>(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<MKL_INT>(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<MKL_INT>(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<MKL_INT>(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<MKL_INT>(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<MKL_INT>(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 <cmath>
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<MKL_INT>(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<MKL_INT>(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<MKL_INT>(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<MKL_INT>(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<MKL_INT>(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<MKL_INT>(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