Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/torch/include/ATen/cpu/FlushDenormal.h +14 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/Utils.h +36 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional.h +4 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional_base.h +377 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional_bfloat16.h +549 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/intrinsics.h +51 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/sve_helper.h +63 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_common_sve.h +176 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_double.h +505 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_float.h +570 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_int.h +410 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_qint.h +567 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec.h +48 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128.h +14 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_bfloat16_neon.h +556 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_convert.h +64 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_float_neon.h +580 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_half_neon.h +603 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_reduced_precision_common_neon.h +263 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/missing_vld1_neon.h +452 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/missing_vst1_neon.h +8 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256.h +331 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_bfloat16.h +1150 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_complex_double.h +432 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_complex_float.h +469 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_convert.h +328 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_double.h +447 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_float.h +658 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_int.h +1586 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_mask.h +298 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_qint.h +1334 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_bfloat16_vsx.h +73 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_common_vsx.h +246 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_complex_double_vsx.h +584 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_complex_float_vsx.h +660 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_double_vsx.h +477 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_float_vsx.h +499 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int16_vsx.h +402 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int32_vsx.h +333 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int64_vsx.h +286 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_qint32_vsx.h +281 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_qint8_vsx.h +483 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_quint8_vsx.h +501 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vsx_helpers.h +474 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/zarch/vec256_zarch.h +0 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512.h +291 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_bfloat16.h +1670 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_complex_double.h +513 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_complex_float.h +1019 -0
- lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_convert.h +297 -0
lib/python3.12/site-packages/torch/include/ATen/cpu/FlushDenormal.h
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/// Flush-To-Zero and Denormals-Are-Zero mode
|
| 2 |
+
///
|
| 3 |
+
/// Flush-To-Zero (FTZ) and Denormals-Are-Zero (DAZ) are modes that bypass
|
| 4 |
+
/// IEEE 754 methods of dealing with denormal floating-point numbers on x86-64
|
| 5 |
+
/// and some x86 CPUs. They result in reduced precision for values near zero,
|
| 6 |
+
/// but increased performance.
|
| 7 |
+
///
|
| 8 |
+
/// See https://software.intel.com/en-us/articles/x87-and-sse-floating-point-assists-in-ia-32-flush-to-zero-ftz-and-denormals-are-zero-daz
|
| 9 |
+
|
| 10 |
+
namespace at::cpu {
|
| 11 |
+
|
| 12 |
+
bool set_flush_denormal(bool on);
|
| 13 |
+
|
| 14 |
+
} // namespace at::cpu
|
lib/python3.12/site-packages/torch/include/ATen/cpu/Utils.h
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <cstdint>
|
| 4 |
+
|
| 5 |
+
#include <c10/macros/Export.h>
|
| 6 |
+
|
| 7 |
+
namespace at::cpu {
|
| 8 |
+
|
| 9 |
+
TORCH_API bool is_avx2_supported();
|
| 10 |
+
TORCH_API bool is_avx512_supported();
|
| 11 |
+
|
| 12 |
+
// Detect if CPU support Vector Neural Network Instruction.
|
| 13 |
+
TORCH_API bool is_avx512_vnni_supported();
|
| 14 |
+
|
| 15 |
+
// Detect if CPU supports AVX512_BF16 ISA
|
| 16 |
+
TORCH_API bool is_avx512_bf16_supported();
|
| 17 |
+
|
| 18 |
+
// Detect if CPU support Advanced Matrix Extension.
|
| 19 |
+
TORCH_API bool is_amx_tile_supported();
|
| 20 |
+
|
| 21 |
+
// Detect if CPU support Advanced Matrix Extension for fp16.
|
| 22 |
+
TORCH_API bool is_amx_fp16_supported();
|
| 23 |
+
|
| 24 |
+
// Enable the system to use AMX instructions.
|
| 25 |
+
TORCH_API bool init_amx();
|
| 26 |
+
|
| 27 |
+
// Detect if CPU supports Arm(R) architecture SVE ISA
|
| 28 |
+
TORCH_API bool is_arm_sve_supported();
|
| 29 |
+
|
| 30 |
+
// Get the L1 cache size per core in Byte
|
| 31 |
+
TORCH_API uint32_t L1d_cache_size();
|
| 32 |
+
|
| 33 |
+
// Get the L2 cache size per core in Byte
|
| 34 |
+
TORCH_API uint32_t L2_cache_size();
|
| 35 |
+
|
| 36 |
+
} // namespace at::cpu
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional.h
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/functional_base.h>
|
| 4 |
+
#include <ATen/cpu/vec/functional_bfloat16.h>
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional_base.h
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/vec.h>
|
| 7 |
+
#include <c10/util/irange.h>
|
| 8 |
+
|
| 9 |
+
namespace at::vec {
|
| 10 |
+
|
| 11 |
+
// slow path
|
| 12 |
+
template <typename scalar_t, typename Op>
|
| 13 |
+
inline scalar_t vec_reduce_all(
|
| 14 |
+
const Op& vec_fun,
|
| 15 |
+
vec::Vectorized<scalar_t> acc_vec,
|
| 16 |
+
int64_t size) {
|
| 17 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 18 |
+
scalar_t acc_arr[Vec::size()];
|
| 19 |
+
acc_vec.store(acc_arr);
|
| 20 |
+
for (const auto i : c10::irange(1, size)) {
|
| 21 |
+
std::array<scalar_t, Vec::size()> acc_arr_next = {0};
|
| 22 |
+
acc_arr_next[0] = acc_arr[i];
|
| 23 |
+
Vec acc_vec_next = Vec::loadu(acc_arr_next.data());
|
| 24 |
+
acc_vec = vec_fun(acc_vec, acc_vec_next);
|
| 25 |
+
}
|
| 26 |
+
acc_vec.store(acc_arr);
|
| 27 |
+
return acc_arr[0];
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
template <typename scalar_t, typename Op>
|
| 31 |
+
struct VecReduceAllSIMD {
|
| 32 |
+
static inline scalar_t apply(const Op& vec_fun, const Vectorized<scalar_t>& acc_vec) {
|
| 33 |
+
return vec_reduce_all(vec_fun, acc_vec, Vectorized<scalar_t>::size());
|
| 34 |
+
}
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
#if defined(__GNUC__) && (__GNUC__ > 5) && !defined(_MSC_VER) && !defined(C10_MOBILE)
|
| 38 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 39 |
+
template <typename Op>
|
| 40 |
+
struct VecReduceAllSIMD<float, Op> {
|
| 41 |
+
static inline float apply(const Op& vec_fun, const Vectorized<float>& acc_vec) {
|
| 42 |
+
using Vec = Vectorized<float>;
|
| 43 |
+
Vec v = acc_vec;
|
| 44 |
+
// 128-bit shuffle
|
| 45 |
+
Vec v1 = _mm256_permute2f128_ps(v, v, 0x1);
|
| 46 |
+
v = vec_fun(v, v1);
|
| 47 |
+
// 64-bit shuffle
|
| 48 |
+
v1 = _mm256_shuffle_ps(v, v, 0x4E);
|
| 49 |
+
v = vec_fun(v, v1);
|
| 50 |
+
// 32-bit shuffle
|
| 51 |
+
v1 = _mm256_shuffle_ps(v, v, 0xB1);
|
| 52 |
+
v = vec_fun(v, v1);
|
| 53 |
+
return _mm256_cvtss_f32(v);
|
| 54 |
+
}
|
| 55 |
+
};
|
| 56 |
+
#endif // defined(CPU_CAPABILITY_AVX2)
|
| 57 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 58 |
+
template <typename Op>
|
| 59 |
+
struct VecReduceAllSIMD<float, Op> {
|
| 60 |
+
static inline float apply(const Op& vec_fun, const Vectorized<float>& acc_vec) {
|
| 61 |
+
using Vec = Vectorized<float>;
|
| 62 |
+
Vec v = acc_vec;
|
| 63 |
+
// 256-bit shuffle
|
| 64 |
+
Vec v1 = _mm512_shuffle_f32x4(v, v, 0x4E);
|
| 65 |
+
v = vec_fun(v, v1);
|
| 66 |
+
// 128-bit shuffle
|
| 67 |
+
v1 = _mm512_shuffle_f32x4(v, v, 0xB1);
|
| 68 |
+
v = vec_fun(v, v1);
|
| 69 |
+
// 64-bit shuffle
|
| 70 |
+
v1 = _mm512_shuffle_ps(v, v, 0x4E);
|
| 71 |
+
v = vec_fun(v, v1);
|
| 72 |
+
// 32-bit shuffle
|
| 73 |
+
v1 = _mm512_shuffle_ps(v, v, 0xB1);
|
| 74 |
+
v = vec_fun(v, v1);
|
| 75 |
+
return _mm512_cvtss_f32(v);
|
| 76 |
+
}
|
| 77 |
+
};
|
| 78 |
+
#endif // defined(CPU_CAPABILITY_AVX512)
|
| 79 |
+
#endif // defined(__GNUC__) && (__GNUC__ > 5) && !defined(_MSC_VER) && !defined(C10_MOBILE)
|
| 80 |
+
|
| 81 |
+
#if defined(__aarch64__) && !defined(C10_MOBILE) && !defined(__CUDACC__) && !defined(CPU_CAPABILITY_SVE)
|
| 82 |
+
template <typename Op>
|
| 83 |
+
struct VecReduceAllSIMD<float, Op> {
|
| 84 |
+
static inline float apply(const Op& vec_fun, const Vectorized<float>& acc_vec) {
|
| 85 |
+
using Vec = Vectorized<float>;
|
| 86 |
+
Vec v = acc_vec;
|
| 87 |
+
|
| 88 |
+
// 64-bit shuffle: [a1+a5, a2+a6, a3+a7, a4+a8, -, -, -, -] -> [a3+a7, a4+a8, a1+a5, a2+a6, -, -, -, -]
|
| 89 |
+
float32x4_t v1_1 = vextq_f32(v, v, 2);
|
| 90 |
+
Vec v1 = v1_1;
|
| 91 |
+
// [a1+a3+a5+a7, a2+a4+a6+a8, a1+a3+a5+a7, a2+a4+a6+a8, -, -, -, -]
|
| 92 |
+
v = vec_fun(v, v1);
|
| 93 |
+
|
| 94 |
+
// 32-bit shuffle: [a1+a3+a5+a7, a2+a4+a6+a8, a1+a3+a5+a7, a2+a4+a6+a8, -, -, -, -] -> [a2+a4+a6+a8, a1+a3+a5+a7, a2+a4+a6+a8, a1+a3+a5+a7, -, -, -, -]
|
| 95 |
+
v1_1 = vrev64q_f32(v);
|
| 96 |
+
v1 = v1_1;
|
| 97 |
+
// [a1+a2+a3+a4+a5+a6+a7+a8, a1+a2+a3+a4+a5+a6+a7+a8, a1+a2+a3+a4+a5+a6+a7+a8, a1+a2+a3+a4+a5+a6+a7+a8, -, -, -, -]
|
| 98 |
+
v = vec_fun(v, v1);
|
| 99 |
+
|
| 100 |
+
return v[0];
|
| 101 |
+
}
|
| 102 |
+
};
|
| 103 |
+
#endif // defined(__aarch64__)
|
| 104 |
+
|
| 105 |
+
#if defined(__aarch64__) && !defined(C10_MOBILE) && !defined(__CUDACC__) && defined(CPU_CAPABILITY_SVE256)
|
| 106 |
+
template <typename Op>
|
| 107 |
+
struct VecReduceAllSIMD<float, Op> {
|
| 108 |
+
static inline float apply(const Op& vec_fun, const Vectorized<float>& acc_vec) {
|
| 109 |
+
using Vec = Vectorized<float>;
|
| 110 |
+
Vec v = acc_vec;
|
| 111 |
+
// 128-bit shuffle
|
| 112 |
+
svuint32_t ind = svdupq_n_u32(4, 5, 6, 7);
|
| 113 |
+
Vec v1 = svtbl_f32(v, ind);
|
| 114 |
+
v = vec_fun(v, v1);
|
| 115 |
+
// 64-bit shuffle
|
| 116 |
+
ind = svdupq_n_u32(2, 3, 0, 1);
|
| 117 |
+
v1 = svtbl_f32(v, ind);
|
| 118 |
+
v = vec_fun(v, v1);
|
| 119 |
+
// 32-bit shuffle
|
| 120 |
+
ind = svdupq_n_u32(1, 0, 2, 3);
|
| 121 |
+
v1 = svtbl_f32(v, ind);
|
| 122 |
+
v = vec_fun(v, v1);
|
| 123 |
+
return svlasta(svpfalse(), v);
|
| 124 |
+
}
|
| 125 |
+
};
|
| 126 |
+
#endif // defined(__aarch64__)
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
template <typename scalar_t, typename Op>
|
| 130 |
+
inline scalar_t vec_reduce_all(const Op& vec_fun, const Vectorized<scalar_t>& acc_vec) {
|
| 131 |
+
return VecReduceAllSIMD<scalar_t, Op>::apply(vec_fun, acc_vec);
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
template <typename scalar_t, typename Op,
|
| 135 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 136 |
+
inline scalar_t reduce_all(const Op& vec_fun, const scalar_t* data, int64_t size) {
|
| 137 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 138 |
+
if (size < Vec::size())
|
| 139 |
+
return vec_reduce_all(vec_fun, Vec::loadu(data, size), size);
|
| 140 |
+
int64_t d = Vec::size();
|
| 141 |
+
Vec acc_vec = Vec::loadu(data);
|
| 142 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 143 |
+
Vec data_vec = Vec::loadu(data + d);
|
| 144 |
+
acc_vec = vec_fun(acc_vec, data_vec);
|
| 145 |
+
}
|
| 146 |
+
if (size - d > 0) {
|
| 147 |
+
Vec data_vec = Vec::loadu(data + d, size - d);
|
| 148 |
+
acc_vec = Vec::set(acc_vec, vec_fun(acc_vec, data_vec), size - d);
|
| 149 |
+
}
|
| 150 |
+
return vec_reduce_all(vec_fun, acc_vec);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
// similar to reduce_all, but reduces into two outputs
|
| 154 |
+
template <typename scalar_t, typename Op1, typename Op2,
|
| 155 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 156 |
+
inline std::pair<scalar_t, scalar_t> reduce2_all(const Op1& vec_fun1, const Op2& vec_fun2,
|
| 157 |
+
const scalar_t* data, int64_t size) {
|
| 158 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 159 |
+
if (size < Vec::size()) {
|
| 160 |
+
auto loaded_data = Vec::loadu(data, size);
|
| 161 |
+
return std::pair<scalar_t, scalar_t>(
|
| 162 |
+
vec_reduce_all(vec_fun1, loaded_data, size),
|
| 163 |
+
vec_reduce_all(vec_fun2, loaded_data, size));
|
| 164 |
+
}
|
| 165 |
+
int64_t d = Vec::size();
|
| 166 |
+
Vec acc_vec1 = Vec::loadu(data);
|
| 167 |
+
Vec acc_vec2 = Vec::loadu(data);
|
| 168 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 169 |
+
Vec data_vec = Vec::loadu(data + d);
|
| 170 |
+
acc_vec1 = vec_fun1(acc_vec1, data_vec);
|
| 171 |
+
acc_vec2 = vec_fun2(acc_vec2, data_vec);
|
| 172 |
+
}
|
| 173 |
+
if (size - d > 0) {
|
| 174 |
+
Vec data_vec = Vec::loadu(data + d, size - d);
|
| 175 |
+
acc_vec1 = Vec::set(acc_vec1, vec_fun1(acc_vec1, data_vec), size - d);
|
| 176 |
+
acc_vec2 = Vec::set(acc_vec2, vec_fun2(acc_vec2, data_vec), size - d);
|
| 177 |
+
}
|
| 178 |
+
return std::pair<scalar_t, scalar_t>(
|
| 179 |
+
vec_reduce_all(vec_fun1, acc_vec1),
|
| 180 |
+
vec_reduce_all(vec_fun2, acc_vec2));
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
template <typename scalar_t, typename MapOp, typename ReduceOp,
|
| 184 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 185 |
+
inline scalar_t map_reduce_all(
|
| 186 |
+
const MapOp& map_fun,
|
| 187 |
+
const ReduceOp& red_fun,
|
| 188 |
+
const scalar_t* data,
|
| 189 |
+
int64_t size) {
|
| 190 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 191 |
+
if (size < Vec::size())
|
| 192 |
+
return vec_reduce_all(red_fun, map_fun(Vec::loadu(data, size)), size);
|
| 193 |
+
int64_t d = Vec::size();
|
| 194 |
+
Vec acc_vec = map_fun(Vec::loadu(data));
|
| 195 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 196 |
+
Vec data_vec = Vec::loadu(data + d);
|
| 197 |
+
data_vec = map_fun(data_vec);
|
| 198 |
+
acc_vec = red_fun(acc_vec, data_vec);
|
| 199 |
+
}
|
| 200 |
+
if (size - d > 0) {
|
| 201 |
+
Vec data_vec = Vec::loadu(data + d, size - d);
|
| 202 |
+
data_vec = map_fun(data_vec);
|
| 203 |
+
acc_vec = Vec::set(acc_vec, red_fun(acc_vec, data_vec), size - d);
|
| 204 |
+
}
|
| 205 |
+
return vec_reduce_all(red_fun, acc_vec);
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
template <typename scalar_t, typename MapOp, typename ReduceOp,
|
| 209 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 210 |
+
inline scalar_t map2_reduce_all(
|
| 211 |
+
const MapOp& map_fun,
|
| 212 |
+
const ReduceOp& red_fun,
|
| 213 |
+
const scalar_t* data,
|
| 214 |
+
const scalar_t* data2,
|
| 215 |
+
int64_t size) {
|
| 216 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 217 |
+
if (size < Vec::size()) {
|
| 218 |
+
Vec data_vec = Vec::loadu(data, size);
|
| 219 |
+
Vec data2_vec = Vec::loadu(data2, size);
|
| 220 |
+
data_vec = map_fun(data_vec, data2_vec);
|
| 221 |
+
return vec_reduce_all(red_fun, data_vec, size);
|
| 222 |
+
}
|
| 223 |
+
int64_t d = Vec::size();
|
| 224 |
+
Vec acc_vec = map_fun(Vec::loadu(data), Vec::loadu(data2));
|
| 225 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 226 |
+
Vec data_vec = Vec::loadu(data + d);
|
| 227 |
+
Vec data2_vec = Vec::loadu(data2 + d);
|
| 228 |
+
data_vec = map_fun(data_vec, data2_vec);
|
| 229 |
+
acc_vec = red_fun(acc_vec, data_vec);
|
| 230 |
+
}
|
| 231 |
+
if (size - d > 0) {
|
| 232 |
+
Vec data_vec = Vec::loadu(data + d, size - d);
|
| 233 |
+
Vec data2_vec = Vec::loadu(data2 + d, size - d);
|
| 234 |
+
data_vec = map_fun(data_vec, data2_vec);
|
| 235 |
+
acc_vec = Vec::set(acc_vec, red_fun(acc_vec, data_vec), size - d);
|
| 236 |
+
}
|
| 237 |
+
return vec_reduce_all(red_fun, acc_vec);
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
template <typename scalar_t, typename MapOp, typename ReduceOp,
|
| 241 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 242 |
+
inline scalar_t map3_reduce_all(
|
| 243 |
+
const MapOp& map_fun,
|
| 244 |
+
const ReduceOp& red_fun,
|
| 245 |
+
const scalar_t* data,
|
| 246 |
+
const scalar_t* data2,
|
| 247 |
+
const scalar_t* data3,
|
| 248 |
+
int64_t size) {
|
| 249 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 250 |
+
if (size < Vec::size()) {
|
| 251 |
+
Vec data_vec = Vec::loadu(data, size);
|
| 252 |
+
Vec data2_vec = Vec::loadu(data2, size);
|
| 253 |
+
Vec data3_vec = Vec::loadu(data3, size);
|
| 254 |
+
data_vec = map_fun(data_vec, data2_vec, data3_vec);
|
| 255 |
+
return vec_reduce_all(red_fun, data_vec, size);
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
int64_t d = Vec::size();
|
| 259 |
+
Vec acc_vec = map_fun(Vec::loadu(data), Vec::loadu(data2), Vec::loadu(data3));
|
| 260 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 261 |
+
Vec data_vec = Vec::loadu(data + d);
|
| 262 |
+
Vec data2_vec = Vec::loadu(data2 + d);
|
| 263 |
+
Vec data3_vec = Vec::loadu(data3 + d);
|
| 264 |
+
data_vec = map_fun(data_vec, data2_vec, data3_vec);
|
| 265 |
+
acc_vec = red_fun(acc_vec, data_vec);
|
| 266 |
+
}
|
| 267 |
+
if (size - d > 0) {
|
| 268 |
+
Vec data_vec = Vec::loadu(data + d, size - d);
|
| 269 |
+
Vec data2_vec = Vec::loadu(data2 + d, size - d);
|
| 270 |
+
Vec data3_vec = Vec::loadu(data3 + d, size - d);
|
| 271 |
+
data_vec = map_fun(data_vec, data2_vec, data3_vec);
|
| 272 |
+
acc_vec = Vec::set(acc_vec, red_fun(acc_vec, data_vec), size - d);
|
| 273 |
+
}
|
| 274 |
+
return vec_reduce_all(red_fun, acc_vec);
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
template <typename scalar_t, typename Op,
|
| 278 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 279 |
+
inline void map(
|
| 280 |
+
const Op& vec_fun,
|
| 281 |
+
scalar_t* output_data,
|
| 282 |
+
const scalar_t* input_data,
|
| 283 |
+
int64_t size) {
|
| 284 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 285 |
+
int64_t d = 0;
|
| 286 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 287 |
+
Vec output_vec = vec_fun(Vec::loadu(input_data + d));
|
| 288 |
+
output_vec.store(output_data + d);
|
| 289 |
+
}
|
| 290 |
+
if (size - d > 0) {
|
| 291 |
+
Vec output_vec = vec_fun(Vec::loadu(input_data + d, size - d));
|
| 292 |
+
output_vec.store(output_data + d, size - d);
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
template <typename scalar_t, typename Op,
|
| 297 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 298 |
+
inline void map2(
|
| 299 |
+
const Op& vec_fun,
|
| 300 |
+
scalar_t* output_data,
|
| 301 |
+
const scalar_t* input_data,
|
| 302 |
+
const scalar_t* input_data2,
|
| 303 |
+
int64_t size) {
|
| 304 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 305 |
+
int64_t d = 0;
|
| 306 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 307 |
+
Vec data_vec = Vec::loadu(input_data + d);
|
| 308 |
+
Vec data_vec2 = Vec::loadu(input_data2 + d);
|
| 309 |
+
Vec output_vec = vec_fun(data_vec, data_vec2);
|
| 310 |
+
output_vec.store(output_data + d);
|
| 311 |
+
}
|
| 312 |
+
if (size - d > 0) {
|
| 313 |
+
Vec data_vec = Vec::loadu(input_data + d, size - d);
|
| 314 |
+
Vec data_vec2 = Vec::loadu(input_data2 + d, size - d);
|
| 315 |
+
Vec output_vec = vec_fun(data_vec, data_vec2);
|
| 316 |
+
output_vec.store(output_data + d, size - d);
|
| 317 |
+
}
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
template <typename scalar_t, typename Op,
|
| 321 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 322 |
+
inline void map3(
|
| 323 |
+
const Op& vec_fun,
|
| 324 |
+
scalar_t* output_data,
|
| 325 |
+
const scalar_t* input_data1,
|
| 326 |
+
const scalar_t* input_data2,
|
| 327 |
+
const scalar_t* input_data3,
|
| 328 |
+
int64_t size) {
|
| 329 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 330 |
+
int64_t d = 0;
|
| 331 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 332 |
+
Vec data_vec1 = Vec::loadu(input_data1 + d);
|
| 333 |
+
Vec data_vec2 = Vec::loadu(input_data2 + d);
|
| 334 |
+
Vec data_vec3 = Vec::loadu(input_data3 + d);
|
| 335 |
+
Vec output_vec = vec_fun(data_vec1, data_vec2, data_vec3);
|
| 336 |
+
output_vec.store(output_data + d);
|
| 337 |
+
}
|
| 338 |
+
if (size - d > 0) {
|
| 339 |
+
Vec data_vec1 = Vec::loadu(input_data1 + d, size - d);
|
| 340 |
+
Vec data_vec2 = Vec::loadu(input_data2 + d, size - d);
|
| 341 |
+
Vec data_vec3 = Vec::loadu(input_data3 + d, size - d);
|
| 342 |
+
Vec output_vec = vec_fun(data_vec1, data_vec2, data_vec3);
|
| 343 |
+
output_vec.store(output_data + d, size - d);
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
template <typename scalar_t, typename Op,
|
| 348 |
+
typename std::enable_if_t<!is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 349 |
+
inline void map4(
|
| 350 |
+
const Op& vec_fun,
|
| 351 |
+
scalar_t* output_data,
|
| 352 |
+
const scalar_t* input_data1,
|
| 353 |
+
const scalar_t* input_data2,
|
| 354 |
+
const scalar_t* input_data3,
|
| 355 |
+
const scalar_t* input_data4,
|
| 356 |
+
int64_t size) {
|
| 357 |
+
using Vec = vec::Vectorized<scalar_t>;
|
| 358 |
+
int64_t d = 0;
|
| 359 |
+
for (; d < size - (size % Vec::size()); d += Vec::size()) {
|
| 360 |
+
Vec data_vec1 = Vec::loadu(input_data1 + d);
|
| 361 |
+
Vec data_vec2 = Vec::loadu(input_data2 + d);
|
| 362 |
+
Vec data_vec3 = Vec::loadu(input_data3 + d);
|
| 363 |
+
Vec data_vec4 = Vec::loadu(input_data4 + d);
|
| 364 |
+
Vec output_vec = vec_fun(data_vec1, data_vec2, data_vec3, data_vec4);
|
| 365 |
+
output_vec.store(output_data + d);
|
| 366 |
+
}
|
| 367 |
+
if (size - d > 0) {
|
| 368 |
+
Vec data_vec1 = Vec::loadu(input_data1 + d, size - d);
|
| 369 |
+
Vec data_vec2 = Vec::loadu(input_data2 + d, size - d);
|
| 370 |
+
Vec data_vec3 = Vec::loadu(input_data3 + d, size - d);
|
| 371 |
+
Vec data_vec4 = Vec::loadu(input_data4 + d, size - d);
|
| 372 |
+
Vec output_vec = vec_fun(data_vec1, data_vec2, data_vec3, data_vec4);
|
| 373 |
+
output_vec.store(output_data + d, size - d);
|
| 374 |
+
}
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
} // namespace at::vec
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional_bfloat16.h
ADDED
|
@@ -0,0 +1,549 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/vec.h>
|
| 7 |
+
|
| 8 |
+
namespace at::vec {
|
| 9 |
+
|
| 10 |
+
// BFloat16 specification
|
| 11 |
+
template <typename scalar_t> struct VecScalarType { using type = scalar_t; };
|
| 12 |
+
template <> struct VecScalarType<BFloat16> { using type = float; };
|
| 13 |
+
template <> struct VecScalarType<Half> { using type = float; };
|
| 14 |
+
|
| 15 |
+
// This is different from at::acc_type since we only need to specialize BFloat16
|
| 16 |
+
template <typename scalar_t>
|
| 17 |
+
using vec_scalar_t = typename VecScalarType<scalar_t>::type;
|
| 18 |
+
|
| 19 |
+
// Vector conversion between float and bfloat16/half
|
| 20 |
+
template <typename scalar_t,
|
| 21 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 22 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_to_float(const Vectorized<scalar_t>&);
|
| 23 |
+
|
| 24 |
+
template <>
|
| 25 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_to_float<BFloat16> (const Vectorized<BFloat16>& a) {
|
| 26 |
+
return convert_bfloat16_float(a);
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
template <>
|
| 30 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_to_float<Half> (const Vectorized<Half>& a) {
|
| 31 |
+
return convert_half_float(a);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
template <typename scalar_t,
|
| 35 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 36 |
+
inline Vectorized<scalar_t> convert_from_float(const Vectorized<float>&, const Vectorized<float>&);
|
| 37 |
+
|
| 38 |
+
template <>
|
| 39 |
+
inline Vectorized<BFloat16> convert_from_float<BFloat16>(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 40 |
+
return convert_float_bfloat16(a, b);
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
template <>
|
| 44 |
+
inline Vectorized<Half> convert_from_float<Half>(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 45 |
+
return convert_float_half(a, b);
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
template <typename scalar_t,
|
| 49 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 50 |
+
inline void load_to_float(const scalar_t *data, Vectorized<float> &out1, Vectorized<float> &out2);
|
| 51 |
+
|
| 52 |
+
template <>
|
| 53 |
+
inline void load_to_float<BFloat16> (const BFloat16 *data, Vectorized<float> &out1, Vectorized<float> &out2) {
|
| 54 |
+
load_fp32_from_bf16(data, out1, out2);
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
template <>
|
| 58 |
+
inline void load_to_float<Half> (const Half *data, Vectorized<float> &out1, Vectorized<float> &out2) {
|
| 59 |
+
load_fp32_from_fp16(data, out1, out2);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
template <typename scalar_t,
|
| 63 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 64 |
+
inline void load_to_float(const scalar_t *data, Vectorized<float> &out);
|
| 65 |
+
|
| 66 |
+
template <>
|
| 67 |
+
inline void load_to_float<BFloat16> (const BFloat16 *data, Vectorized<float> &out) {
|
| 68 |
+
load_fp32_from_bf16(data, out);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
template <>
|
| 72 |
+
inline void load_to_float<Half> (const Half *data, Vectorized<float> &out) {
|
| 73 |
+
load_fp32_from_fp16(data, out);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
// Note that we already have specialized member of Vectorized<scalar_t> for BFloat16
|
| 77 |
+
// so the following functions would run smoothly:
|
| 78 |
+
// using Vec = Vectorized<BFloat16>;
|
| 79 |
+
// Vec one = Vec(BFloat16(1));
|
| 80 |
+
// vec::map([](Vec x) { return one / (one + x.exp()); }, y_ptr, x_ptr, N);
|
| 81 |
+
//
|
| 82 |
+
// Then why we still need to specialize "functional"?
|
| 83 |
+
// If we do specialization at Vectorized<> level, the above example would need 3 pairs of
|
| 84 |
+
// conversion of bf16->fp32/fp32->bf16, each for ".exp()", "+" and "/".
|
| 85 |
+
// If we do specialization at vec::map<>() level, we have only 1 pair of conversion
|
| 86 |
+
// of bf16->fp32/fp32->bf16, for the input and output BFloat16 vector only.
|
| 87 |
+
//
|
| 88 |
+
// The following BFloat16 functionality will only do data type conversion for input
|
| 89 |
+
// and output vector (reduce functionality will only convert the final scalar back to bf16).
|
| 90 |
+
// Compared to Vectorized<> specialization,
|
| 91 |
+
// 1. better performance since we have less data type conversion;
|
| 92 |
+
// 2. less rounding error since immediate results are kept in fp32;
|
| 93 |
+
// 3. accumulation done on data type of fp32.
|
| 94 |
+
//
|
| 95 |
+
// If you plan to extend this file, please ensure adding unit tests at
|
| 96 |
+
// aten/src/ATen/test/vec_test_all_types.cpp
|
| 97 |
+
//
|
| 98 |
+
template <typename scalar_t, typename Op,
|
| 99 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 100 |
+
inline float reduce_all(const Op& vec_fun, const scalar_t* data, int64_t size) {
|
| 101 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 102 |
+
using fVec = vec::Vectorized<float>;
|
| 103 |
+
if (size < bVec::size()) {
|
| 104 |
+
bVec data_bvec = bVec::loadu(data, size);
|
| 105 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 106 |
+
if (size > fVec::size()) {
|
| 107 |
+
data_fvec0 = fVec::set(data_fvec0, vec_fun(data_fvec0, data_fvec1), size - fVec::size());
|
| 108 |
+
return vec_reduce_all<float>(vec_fun, data_fvec0, fVec::size());
|
| 109 |
+
} else {
|
| 110 |
+
return vec_reduce_all<float>(vec_fun, data_fvec0, size);
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
int64_t d = bVec::size();
|
| 114 |
+
bVec acc_bvec = bVec::loadu(data);
|
| 115 |
+
auto [acc_fvec0, acc_fvec1] = convert_to_float<scalar_t>(acc_bvec);
|
| 116 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 117 |
+
bVec data_bvec = bVec::loadu(data + d);
|
| 118 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 119 |
+
acc_fvec0 = vec_fun(acc_fvec0, data_fvec0);
|
| 120 |
+
acc_fvec1 = vec_fun(acc_fvec1, data_fvec1);
|
| 121 |
+
}
|
| 122 |
+
if (size - d > 0) {
|
| 123 |
+
bVec data_bvec = bVec::loadu(data + d, size - d);
|
| 124 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 125 |
+
if (size - d > fVec::size()) {
|
| 126 |
+
acc_fvec0 = vec_fun(acc_fvec0, data_fvec0);
|
| 127 |
+
acc_fvec1 = fVec::set(acc_fvec1, vec_fun(acc_fvec1, data_fvec1), size - d - fVec::size());
|
| 128 |
+
} else {
|
| 129 |
+
acc_fvec0 = fVec::set(acc_fvec0, vec_fun(acc_fvec0, data_fvec0), size - d);
|
| 130 |
+
}
|
| 131 |
+
}
|
| 132 |
+
acc_fvec0 = vec_fun(acc_fvec0, acc_fvec1);
|
| 133 |
+
return vec_reduce_all<float>(vec_fun, acc_fvec0);
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
template <typename scalar_t, typename Op1, typename Op2,
|
| 137 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 138 |
+
inline std::pair<float, float> reduce2_all(const Op1& vec_fun1, const Op2& vec_fun2,
|
| 139 |
+
const scalar_t* data, int64_t size) {
|
| 140 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 141 |
+
using fVec = vec::Vectorized<float>;
|
| 142 |
+
if (size < bVec::size()) {
|
| 143 |
+
bVec data_bvec = bVec::loadu(data, size);
|
| 144 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 145 |
+
if (size > fVec::size()) {
|
| 146 |
+
fVec acc1_fvec = fVec::set(data_fvec0, vec_fun1(data_fvec0, data_fvec1), size - fVec::size());
|
| 147 |
+
fVec acc2_fvec = fVec::set(data_fvec0, vec_fun2(data_fvec0, data_fvec1), size - fVec::size());
|
| 148 |
+
return std::pair<scalar_t, scalar_t>(
|
| 149 |
+
vec_reduce_all<float>(vec_fun1, acc1_fvec, fVec::size()),
|
| 150 |
+
vec_reduce_all<float>(vec_fun2, acc2_fvec, fVec::size()));
|
| 151 |
+
} else {
|
| 152 |
+
return std::pair<scalar_t, scalar_t>(
|
| 153 |
+
vec_reduce_all<float>(vec_fun1, data_fvec0, size),
|
| 154 |
+
vec_reduce_all<float>(vec_fun2, data_fvec0, size));
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
int64_t d = bVec::size();
|
| 158 |
+
bVec acc_bvec = bVec::loadu(data);
|
| 159 |
+
auto [acc1_fvec0, acc1_fvec1] = convert_to_float<scalar_t>(acc_bvec);
|
| 160 |
+
auto [acc2_fvec0, acc2_fvec1] = convert_to_float<scalar_t>(acc_bvec);
|
| 161 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 162 |
+
bVec data_bvec = bVec::loadu(data + d);
|
| 163 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 164 |
+
acc1_fvec0 = vec_fun1(acc1_fvec0, data_fvec0);
|
| 165 |
+
acc1_fvec1 = vec_fun1(acc1_fvec1, data_fvec1);
|
| 166 |
+
acc2_fvec0 = vec_fun2(acc2_fvec0, data_fvec0);
|
| 167 |
+
acc2_fvec1 = vec_fun2(acc2_fvec1, data_fvec1);
|
| 168 |
+
}
|
| 169 |
+
if (size - d > 0) {
|
| 170 |
+
bVec data_bvec = bVec::loadu(data + d, size - d);
|
| 171 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 172 |
+
if (size - d > fVec::size()) {
|
| 173 |
+
acc1_fvec0 = vec_fun1(acc1_fvec0, data_fvec0);
|
| 174 |
+
acc1_fvec1 = fVec::set(acc1_fvec1, vec_fun1(acc1_fvec1, data_fvec1), size - d - fVec::size());
|
| 175 |
+
acc2_fvec0 = vec_fun2(acc2_fvec0, data_fvec0);
|
| 176 |
+
acc2_fvec1 = fVec::set(acc2_fvec1, vec_fun2(acc2_fvec1, data_fvec1), size - d - fVec::size());
|
| 177 |
+
} else {
|
| 178 |
+
acc1_fvec0 = fVec::set(acc1_fvec0, vec_fun1(acc1_fvec0, data_fvec0), size - d);
|
| 179 |
+
acc2_fvec0 = fVec::set(acc2_fvec0, vec_fun2(acc2_fvec0, data_fvec0), size - d);
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
acc1_fvec0 = vec_fun1(acc1_fvec0, acc1_fvec1);
|
| 183 |
+
acc2_fvec0 = vec_fun2(acc2_fvec0, acc2_fvec1);
|
| 184 |
+
return std::pair<scalar_t, scalar_t>(
|
| 185 |
+
vec_reduce_all<float>(vec_fun1, acc1_fvec0),
|
| 186 |
+
vec_reduce_all<float>(vec_fun2, acc2_fvec0));
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
template <typename scalar_t, typename MapOp, typename ReduceOp,
|
| 190 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 191 |
+
inline float map_reduce_all(
|
| 192 |
+
const MapOp& map_fun,
|
| 193 |
+
const ReduceOp& red_fun,
|
| 194 |
+
const scalar_t* data,
|
| 195 |
+
int64_t size) {
|
| 196 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 197 |
+
using fVec = vec::Vectorized<float>;
|
| 198 |
+
if (size < bVec::size()) {
|
| 199 |
+
bVec data_bvec = bVec::loadu(data, size);
|
| 200 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 201 |
+
if (size > fVec::size()) {
|
| 202 |
+
data_fvec0 = map_fun(data_fvec0);
|
| 203 |
+
data_fvec1 = map_fun(data_fvec1);
|
| 204 |
+
data_fvec0 = fVec::set(data_fvec0, red_fun(data_fvec0, data_fvec1), size - fVec::size());
|
| 205 |
+
return vec_reduce_all<float>(red_fun, data_fvec0, fVec::size());
|
| 206 |
+
} else {
|
| 207 |
+
data_fvec0 = map_fun(data_fvec0);
|
| 208 |
+
return vec_reduce_all<float>(red_fun, data_fvec0, size);
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
int64_t d = bVec::size();
|
| 212 |
+
bVec acc_bvec = bVec::loadu(data);
|
| 213 |
+
auto [acc_fvec0, acc_fvec1] = convert_to_float<scalar_t>(acc_bvec);
|
| 214 |
+
acc_fvec0 = map_fun(acc_fvec0);
|
| 215 |
+
acc_fvec1 = map_fun(acc_fvec1);
|
| 216 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 217 |
+
bVec data_bvec = bVec::loadu(data + d);
|
| 218 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 219 |
+
data_fvec0 = map_fun(data_fvec0);
|
| 220 |
+
data_fvec1 = map_fun(data_fvec1);
|
| 221 |
+
acc_fvec0 = red_fun(acc_fvec0, data_fvec0);
|
| 222 |
+
acc_fvec1 = red_fun(acc_fvec1, data_fvec1);
|
| 223 |
+
}
|
| 224 |
+
if (size - d > 0) {
|
| 225 |
+
bVec data_bvec = bVec::loadu(data + d, size - d);
|
| 226 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 227 |
+
if (size - d > fVec::size()) {
|
| 228 |
+
data_fvec0 = map_fun(data_fvec0);
|
| 229 |
+
data_fvec1 = map_fun(data_fvec1);
|
| 230 |
+
acc_fvec0 = red_fun(acc_fvec0, data_fvec0);
|
| 231 |
+
acc_fvec1 = fVec::set(acc_fvec1, red_fun(acc_fvec1, data_fvec1), size - d - fVec::size());
|
| 232 |
+
} else {
|
| 233 |
+
data_fvec0 = map_fun(data_fvec0);
|
| 234 |
+
acc_fvec0 = fVec::set(acc_fvec0, red_fun(acc_fvec0, data_fvec0), size - d);
|
| 235 |
+
}
|
| 236 |
+
}
|
| 237 |
+
acc_fvec0 = red_fun(acc_fvec0, acc_fvec1);
|
| 238 |
+
return vec_reduce_all<float>(red_fun, acc_fvec0);
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
template <typename scalar_t, typename MapOp, typename ReduceOp,
|
| 242 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 243 |
+
inline float map2_reduce_all(
|
| 244 |
+
const MapOp& map_fun,
|
| 245 |
+
const ReduceOp& red_fun,
|
| 246 |
+
const scalar_t* data,
|
| 247 |
+
const scalar_t* data2,
|
| 248 |
+
int64_t size) {
|
| 249 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 250 |
+
using fVec = vec::Vectorized<float>;
|
| 251 |
+
if (size < bVec::size()) {
|
| 252 |
+
bVec data_bvec = bVec::loadu(data, size);
|
| 253 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 254 |
+
bVec data2_bvec = bVec::loadu(data2, size);
|
| 255 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 256 |
+
if (size > fVec::size()) {
|
| 257 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0);
|
| 258 |
+
data_fvec1 = map_fun(data_fvec1, data2_fvec1);
|
| 259 |
+
data_fvec0 = fVec::set(data_fvec0, red_fun(data_fvec0, data_fvec1), size - fVec::size());
|
| 260 |
+
return vec_reduce_all<float>(red_fun, data_fvec0, fVec::size());
|
| 261 |
+
} else {
|
| 262 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0);
|
| 263 |
+
return vec_reduce_all<float>(red_fun, data_fvec0, size);
|
| 264 |
+
}
|
| 265 |
+
}
|
| 266 |
+
int64_t d = bVec::size();
|
| 267 |
+
bVec acc_bvec = bVec::loadu(data);
|
| 268 |
+
auto [acc_fvec0, acc_fvec1] = convert_to_float<scalar_t>(acc_bvec);
|
| 269 |
+
bVec acc2_bvec = bVec::loadu(data2);
|
| 270 |
+
auto [acc2_fvec0, acc2_fvec1] = convert_to_float<scalar_t>(acc2_bvec);
|
| 271 |
+
acc_fvec0 = map_fun(acc_fvec0, acc2_fvec0);
|
| 272 |
+
acc_fvec1 = map_fun(acc_fvec1, acc2_fvec1);
|
| 273 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 274 |
+
bVec data_bvec = bVec::loadu(data + d);
|
| 275 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 276 |
+
bVec data2_bvec = bVec::loadu(data2 + d);
|
| 277 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 278 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0);
|
| 279 |
+
data_fvec1 = map_fun(data_fvec1, data2_fvec1);
|
| 280 |
+
acc_fvec0 = red_fun(acc_fvec0, data_fvec0);
|
| 281 |
+
acc_fvec1 = red_fun(acc_fvec1, data_fvec1);
|
| 282 |
+
}
|
| 283 |
+
if (size - d > 0) {
|
| 284 |
+
bVec data_bvec = bVec::loadu(data + d, size - d);
|
| 285 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 286 |
+
bVec data2_bvec = bVec::loadu(data2 + d, size - d);
|
| 287 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 288 |
+
if (size - d > fVec::size()) {
|
| 289 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0);
|
| 290 |
+
data_fvec1 = map_fun(data_fvec1, data2_fvec1);
|
| 291 |
+
acc_fvec0 = red_fun(acc_fvec0, data_fvec0);
|
| 292 |
+
acc_fvec1 = fVec::set(acc_fvec1, red_fun(acc_fvec1, data_fvec1), size - d - fVec::size());
|
| 293 |
+
} else {
|
| 294 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0);
|
| 295 |
+
acc_fvec0 = fVec::set(acc_fvec0, red_fun(acc_fvec0, data_fvec0), size - d);
|
| 296 |
+
}
|
| 297 |
+
}
|
| 298 |
+
acc_fvec0 = red_fun(acc_fvec0, acc_fvec1);
|
| 299 |
+
return vec_reduce_all<float>(red_fun, acc_fvec0);
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
template <typename scalar_t, typename MapOp, typename ReduceOp,
|
| 303 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 304 |
+
inline float map3_reduce_all(
|
| 305 |
+
const MapOp& map_fun,
|
| 306 |
+
const ReduceOp& red_fun,
|
| 307 |
+
const scalar_t* data,
|
| 308 |
+
const scalar_t* data2,
|
| 309 |
+
const scalar_t* data3,
|
| 310 |
+
int64_t size) {
|
| 311 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 312 |
+
using fVec = vec::Vectorized<float>;
|
| 313 |
+
if (size < bVec::size()) {
|
| 314 |
+
bVec data_bvec = bVec::loadu(data, size);
|
| 315 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 316 |
+
bVec data2_bvec = bVec::loadu(data2, size);
|
| 317 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 318 |
+
bVec data3_bvec = bVec::loadu(data3, size);
|
| 319 |
+
auto [data3_fvec0, data3_fvec1] = convert_to_float<scalar_t>(data3_bvec);
|
| 320 |
+
if (size > fVec::size()) {
|
| 321 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0, data3_fvec0);
|
| 322 |
+
data_fvec1 = map_fun(data_fvec1, data2_fvec1, data3_fvec1);
|
| 323 |
+
data_fvec0 = fVec::set(data_fvec0, red_fun(data_fvec0, data_fvec1), size - fVec::size());
|
| 324 |
+
return vec_reduce_all<float>(red_fun, data_fvec0, fVec::size());
|
| 325 |
+
} else {
|
| 326 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0, data3_fvec0);
|
| 327 |
+
return vec_reduce_all<float>(red_fun, data_fvec0, size);
|
| 328 |
+
}
|
| 329 |
+
}
|
| 330 |
+
int64_t d = bVec::size();
|
| 331 |
+
bVec acc_bvec = bVec::loadu(data);
|
| 332 |
+
auto [acc_fvec0, acc_fvec1] = convert_to_float<scalar_t>(acc_bvec);
|
| 333 |
+
bVec acc2_bvec = bVec::loadu(data2);
|
| 334 |
+
auto [acc2_fvec0, acc2_fvec1] = convert_to_float<scalar_t>(acc2_bvec);
|
| 335 |
+
bVec acc3_bvec = bVec::loadu(data3);
|
| 336 |
+
auto [acc3_fvec0, acc3_fvec1] = convert_to_float<scalar_t>(acc3_bvec);
|
| 337 |
+
acc_fvec0 = map_fun(acc_fvec0, acc2_fvec0, acc3_fvec0);
|
| 338 |
+
acc_fvec1 = map_fun(acc_fvec1, acc2_fvec1, acc3_fvec1);
|
| 339 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 340 |
+
bVec data_bvec = bVec::loadu(data + d);
|
| 341 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 342 |
+
bVec data2_bvec = bVec::loadu(data2 + d);
|
| 343 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 344 |
+
bVec data3_bvec = bVec::loadu(data3 + d);
|
| 345 |
+
auto [data3_fvec0, data3_fvec1] = convert_to_float<scalar_t>(data3_bvec);
|
| 346 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0, data3_fvec0);
|
| 347 |
+
data_fvec1 = map_fun(data_fvec1, data2_fvec1, data3_fvec1);
|
| 348 |
+
acc_fvec0 = red_fun(acc_fvec0, data_fvec0);
|
| 349 |
+
acc_fvec1 = red_fun(acc_fvec1, data_fvec1);
|
| 350 |
+
}
|
| 351 |
+
if (size - d > 0) {
|
| 352 |
+
bVec data_bvec = bVec::loadu(data + d, size - d);
|
| 353 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 354 |
+
bVec data2_bvec = bVec::loadu(data2 + d, size - d);
|
| 355 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 356 |
+
bVec data3_bvec = bVec::loadu(data3 + d, size - d);
|
| 357 |
+
auto [data3_fvec0, data3_fvec1] = convert_to_float<scalar_t>(data3_bvec);
|
| 358 |
+
if (size - d > fVec::size()) {
|
| 359 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0, data3_fvec0);
|
| 360 |
+
data_fvec1 = map_fun(data_fvec1, data2_fvec1, data3_fvec1);
|
| 361 |
+
acc_fvec0 = red_fun(acc_fvec0, data_fvec0);
|
| 362 |
+
acc_fvec1 = fVec::set(acc_fvec1, red_fun(acc_fvec1, data_fvec1), size - d - fVec::size());
|
| 363 |
+
} else {
|
| 364 |
+
data_fvec0 = map_fun(data_fvec0, data2_fvec0, data3_fvec0);
|
| 365 |
+
acc_fvec0 = fVec::set(acc_fvec0, red_fun(acc_fvec0, data_fvec0), size - d);
|
| 366 |
+
}
|
| 367 |
+
}
|
| 368 |
+
acc_fvec0 = red_fun(acc_fvec0, acc_fvec1);
|
| 369 |
+
return vec_reduce_all<float>(red_fun, acc_fvec0);
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
template <typename scalar_t, typename Op,
|
| 373 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 374 |
+
inline void map(
|
| 375 |
+
const Op& vec_fun,
|
| 376 |
+
scalar_t* output_data,
|
| 377 |
+
const scalar_t* input_data,
|
| 378 |
+
int64_t size) {
|
| 379 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 380 |
+
using fVec = vec::Vectorized<float>;
|
| 381 |
+
int64_t d = 0;
|
| 382 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 383 |
+
bVec data_bvec = bVec::loadu(input_data + d);
|
| 384 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 385 |
+
fVec output_fvec0 = vec_fun(data_fvec0);
|
| 386 |
+
fVec output_fvec1 = vec_fun(data_fvec1);
|
| 387 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 388 |
+
output_bvec.store(output_data + d);
|
| 389 |
+
}
|
| 390 |
+
if (size - d > 0) {
|
| 391 |
+
bVec data_bvec = bVec::loadu(input_data + d, size - d);
|
| 392 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 393 |
+
fVec output_fvec0 = vec_fun(data_fvec0);
|
| 394 |
+
fVec output_fvec1 = vec_fun(data_fvec1);
|
| 395 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 396 |
+
output_bvec.store(output_data + d, size - d);
|
| 397 |
+
}
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
template <typename scalar_t, typename Op,
|
| 401 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 402 |
+
inline void map(
|
| 403 |
+
const Op& vec_fun,
|
| 404 |
+
scalar_t* output_data,
|
| 405 |
+
const float* input_data,
|
| 406 |
+
int64_t size) {
|
| 407 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 408 |
+
using fVec = vec::Vectorized<float>;
|
| 409 |
+
int64_t d = 0;
|
| 410 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 411 |
+
fVec data_fvec0 = fVec::loadu(input_data + d);
|
| 412 |
+
fVec data_fvec1 = fVec::loadu(input_data + d + fVec::size());
|
| 413 |
+
fVec output_fvec0 = vec_fun(data_fvec0);
|
| 414 |
+
fVec output_fvec1 = vec_fun(data_fvec1);
|
| 415 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 416 |
+
output_bvec.store(output_data + d);
|
| 417 |
+
}
|
| 418 |
+
if (size - d > 0) {
|
| 419 |
+
fVec data_fvec0, data_fvec1;
|
| 420 |
+
if (size - d > fVec::size()) {
|
| 421 |
+
data_fvec0 = fVec::loadu(input_data + d);
|
| 422 |
+
data_fvec1 = fVec::loadu(input_data + d + fVec::size(), size - d - fVec::size());
|
| 423 |
+
} else {
|
| 424 |
+
// choose to align with behaviour of bVec::loadu(ptr, size),
|
| 425 |
+
// which leaves data_fvec1 uninitialized
|
| 426 |
+
data_fvec0 = fVec::loadu(input_data + d, size - d);
|
| 427 |
+
}
|
| 428 |
+
fVec output_fvec0 = vec_fun(data_fvec0);
|
| 429 |
+
fVec output_fvec1 = vec_fun(data_fvec1);
|
| 430 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 431 |
+
output_bvec.store(output_data + d, size - d);
|
| 432 |
+
}
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
template <typename scalar_t, typename Op,
|
| 436 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 437 |
+
inline void map2(
|
| 438 |
+
const Op& vec_fun,
|
| 439 |
+
scalar_t* output_data,
|
| 440 |
+
const scalar_t* input_data,
|
| 441 |
+
const scalar_t* input_data2,
|
| 442 |
+
int64_t size) {
|
| 443 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 444 |
+
using fVec = vec::Vectorized<float>;
|
| 445 |
+
int64_t d = 0;
|
| 446 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 447 |
+
bVec data_bvec = bVec::loadu(input_data + d);
|
| 448 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 449 |
+
bVec data2_bvec = bVec::loadu(input_data2 + d);
|
| 450 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 451 |
+
fVec output_fvec0 = vec_fun(data_fvec0, data2_fvec0);
|
| 452 |
+
fVec output_fvec1 = vec_fun(data_fvec1, data2_fvec1);
|
| 453 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 454 |
+
output_bvec.store(output_data + d);
|
| 455 |
+
}
|
| 456 |
+
if (size - d > 0) {
|
| 457 |
+
bVec data_bvec = bVec::loadu(input_data + d, size - d);
|
| 458 |
+
auto [data_fvec0, data_fvec1] = convert_to_float<scalar_t>(data_bvec);
|
| 459 |
+
bVec data2_bvec = bVec::loadu(input_data2 + d, size - d);
|
| 460 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 461 |
+
fVec output_fvec0 = vec_fun(data_fvec0, data2_fvec0);
|
| 462 |
+
fVec output_fvec1 = vec_fun(data_fvec1, data2_fvec1);
|
| 463 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 464 |
+
output_bvec.store(output_data + d, size - d);
|
| 465 |
+
}
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
template <typename scalar_t, typename Op,
|
| 469 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 470 |
+
inline void map3(
|
| 471 |
+
const Op& vec_fun,
|
| 472 |
+
scalar_t* output_data,
|
| 473 |
+
const scalar_t* input_data1,
|
| 474 |
+
const scalar_t* input_data2,
|
| 475 |
+
const scalar_t* input_data3,
|
| 476 |
+
int64_t size) {
|
| 477 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 478 |
+
using fVec = vec::Vectorized<float>;
|
| 479 |
+
int64_t d = 0;
|
| 480 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 481 |
+
bVec data1_bvec = bVec::loadu(input_data1 + d);
|
| 482 |
+
auto [data1_fvec0, data1_fvec1] = convert_to_float<scalar_t>(data1_bvec);
|
| 483 |
+
bVec data2_bvec = bVec::loadu(input_data2 + d);
|
| 484 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 485 |
+
bVec data3_bvec = bVec::loadu(input_data3 + d);
|
| 486 |
+
auto [data3_fvec0, data3_fvec1] = convert_to_float<scalar_t>(data3_bvec);
|
| 487 |
+
fVec output_fvec0 = vec_fun(data1_fvec0, data2_fvec0, data3_fvec0);
|
| 488 |
+
fVec output_fvec1 = vec_fun(data1_fvec1, data2_fvec1, data3_fvec1);
|
| 489 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 490 |
+
output_bvec.store(output_data + d);
|
| 491 |
+
}
|
| 492 |
+
if (size - d > 0) {
|
| 493 |
+
bVec data1_bvec = bVec::loadu(input_data1 + d, size - d);
|
| 494 |
+
auto [data1_fvec0, data1_fvec1] = convert_to_float<scalar_t>(data1_bvec);
|
| 495 |
+
bVec data2_bvec = bVec::loadu(input_data2 + d, size - d);
|
| 496 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 497 |
+
bVec data3_bvec = bVec::loadu(input_data3 + d, size - d);
|
| 498 |
+
auto [data3_fvec0, data3_fvec1] = convert_to_float<scalar_t>(data3_bvec);
|
| 499 |
+
fVec output_fvec0 = vec_fun(data1_fvec0, data2_fvec0, data3_fvec0);
|
| 500 |
+
fVec output_fvec1 = vec_fun(data1_fvec1, data2_fvec1, data3_fvec1);
|
| 501 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 502 |
+
output_bvec.store(output_data + d, size - d);
|
| 503 |
+
}
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
template <typename scalar_t, typename Op,
|
| 507 |
+
typename std::enable_if_t<is_reduced_floating_point_v<scalar_t>, int> = 0>
|
| 508 |
+
inline void map4(
|
| 509 |
+
const Op& vec_fun,
|
| 510 |
+
scalar_t* output_data,
|
| 511 |
+
const scalar_t* input_data1,
|
| 512 |
+
const scalar_t* input_data2,
|
| 513 |
+
const scalar_t* input_data3,
|
| 514 |
+
const scalar_t* input_data4,
|
| 515 |
+
int64_t size) {
|
| 516 |
+
using bVec = vec::Vectorized<scalar_t>;
|
| 517 |
+
using fVec = vec::Vectorized<float>;
|
| 518 |
+
int64_t d = 0;
|
| 519 |
+
for (; d < size - (size % bVec::size()); d += bVec::size()) {
|
| 520 |
+
bVec data1_bvec = bVec::loadu(input_data1 + d);
|
| 521 |
+
auto [data1_fvec0, data1_fvec1] = convert_to_float<scalar_t>(data1_bvec);
|
| 522 |
+
bVec data2_bvec = bVec::loadu(input_data2 + d);
|
| 523 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 524 |
+
bVec data3_bvec = bVec::loadu(input_data3 + d);
|
| 525 |
+
auto [data3_fvec0, data3_fvec1] = convert_to_float<scalar_t>(data3_bvec);
|
| 526 |
+
bVec data4_bvec = bVec::loadu(input_data4 + d);
|
| 527 |
+
auto [data4_fvec0, data4_fvec1] = convert_to_float<scalar_t>(data4_bvec);
|
| 528 |
+
fVec output_fvec0 = vec_fun(data1_fvec0, data2_fvec0, data3_fvec0, data4_fvec0);
|
| 529 |
+
fVec output_fvec1 = vec_fun(data1_fvec1, data2_fvec1, data3_fvec1, data4_fvec1);
|
| 530 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 531 |
+
output_bvec.store(output_data + d);
|
| 532 |
+
}
|
| 533 |
+
if (size - d > 0) {
|
| 534 |
+
bVec data1_bvec = bVec::loadu(input_data1 + d, size - d);
|
| 535 |
+
auto [data1_fvec0, data1_fvec1] = convert_to_float<scalar_t>(data1_bvec);
|
| 536 |
+
bVec data2_bvec = bVec::loadu(input_data2 + d, size - d);
|
| 537 |
+
auto [data2_fvec0, data2_fvec1] = convert_to_float<scalar_t>(data2_bvec);
|
| 538 |
+
bVec data3_bvec = bVec::loadu(input_data3 + d, size - d);
|
| 539 |
+
auto [data3_fvec0, data3_fvec1] = convert_to_float<scalar_t>(data3_bvec);
|
| 540 |
+
bVec data4_bvec = bVec::loadu(input_data4 + d, size - d);
|
| 541 |
+
auto [data4_fvec0, data4_fvec1] = convert_to_float<scalar_t>(data4_bvec);
|
| 542 |
+
fVec output_fvec0 = vec_fun(data1_fvec0, data2_fvec0, data3_fvec0, data4_fvec0);
|
| 543 |
+
fVec output_fvec1 = vec_fun(data1_fvec1, data2_fvec1, data3_fvec1, data4_fvec1);
|
| 544 |
+
bVec output_bvec = convert_from_float<scalar_t>(output_fvec0, output_fvec1);
|
| 545 |
+
output_bvec.store(output_data + d, size - d);
|
| 546 |
+
}
|
| 547 |
+
}
|
| 548 |
+
|
| 549 |
+
} // namespace at::vec
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/intrinsics.h
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
|
| 3 |
+
/* GCC or clang-compatible compiler, targeting x86/x86-64 */
|
| 4 |
+
#include <x86intrin.h>
|
| 5 |
+
#elif defined(__clang__) && (defined(__ARM_NEON__) || defined(__aarch64__))
|
| 6 |
+
/* Clang-compatible compiler, targeting arm neon */
|
| 7 |
+
#include <arm_neon.h>
|
| 8 |
+
#if defined(__ARM_FEATURE_SVE)
|
| 9 |
+
/* CLANG-compatible compiler, targeting ARM with SVE */
|
| 10 |
+
#include <arm_sve.h>
|
| 11 |
+
#endif
|
| 12 |
+
#elif defined(_MSC_VER)
|
| 13 |
+
/* Microsoft C/C++-compatible compiler */
|
| 14 |
+
#include <intrin.h>
|
| 15 |
+
#if _MSC_VER <= 1900
|
| 16 |
+
#define _mm256_extract_epi64(X, Y) (_mm_extract_epi64(_mm256_extractf128_si256(X, Y >> 1), Y % 2))
|
| 17 |
+
#define _mm256_extract_epi32(X, Y) (_mm_extract_epi32(_mm256_extractf128_si256(X, Y >> 2), Y % 4))
|
| 18 |
+
#define _mm256_extract_epi16(X, Y) (_mm_extract_epi16(_mm256_extractf128_si256(X, Y >> 3), Y % 8))
|
| 19 |
+
#define _mm256_extract_epi8(X, Y) (_mm_extract_epi8(_mm256_extractf128_si256(X, Y >> 4), Y % 16))
|
| 20 |
+
#endif
|
| 21 |
+
#elif defined(__GNUC__) && (defined(__ARM_NEON__) || defined(__aarch64__))
|
| 22 |
+
/* GCC-compatible compiler, targeting ARM with NEON */
|
| 23 |
+
#include <arm_neon.h>
|
| 24 |
+
#if defined(__ARM_FEATURE_SVE)
|
| 25 |
+
/* GCC-compatible compiler, targeting ARM with SVE */
|
| 26 |
+
#include <arm_sve.h>
|
| 27 |
+
#endif
|
| 28 |
+
#if defined (MISSING_ARM_VLD1)
|
| 29 |
+
#include <ATen/cpu/vec/vec256/missing_vld1_neon.h>
|
| 30 |
+
#elif defined (MISSING_ARM_VST1)
|
| 31 |
+
#include <ATen/cpu/vec/vec256/missing_vst1_neon.h>
|
| 32 |
+
#endif
|
| 33 |
+
#elif defined(__GNUC__) && defined(__IWMMXT__)
|
| 34 |
+
/* GCC-compatible compiler, targeting ARM with WMMX */
|
| 35 |
+
#include <mmintrin.h>
|
| 36 |
+
#elif defined(__s390x__)
|
| 37 |
+
// targets Z/architecture
|
| 38 |
+
// we will include vecintrin later
|
| 39 |
+
#elif (defined(__GNUC__) || defined(__xlC__)) && \
|
| 40 |
+
(defined(__VEC__) || defined(__ALTIVEC__))
|
| 41 |
+
/* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX */
|
| 42 |
+
#include <altivec.h>
|
| 43 |
+
/* We need to undef those tokens defined by <altivec.h> to avoid conflicts
|
| 44 |
+
with the C++ types. => Can still use __bool/__vector */
|
| 45 |
+
#undef bool
|
| 46 |
+
#undef vector
|
| 47 |
+
#undef pixel
|
| 48 |
+
#elif defined(__GNUC__) && defined(__SPE__)
|
| 49 |
+
/* GCC-compatible compiler, targeting PowerPC with SPE */
|
| 50 |
+
#include <spe.h>
|
| 51 |
+
#endif
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/sve_helper.h
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
|
| 5 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 6 |
+
|
| 7 |
+
#if defined(CPU_CAPABILITY_SVE)
|
| 8 |
+
|
| 9 |
+
// Define the data type of VLS(vector-length specific).
|
| 10 |
+
typedef svbool_t vls_pred_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 11 |
+
typedef svint8_t vls_int8_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 12 |
+
typedef svint16_t vls_int16_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 13 |
+
typedef svint32_t vls_int32_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 14 |
+
typedef svint64_t vls_int64_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 15 |
+
typedef svuint8_t vls_uint8_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 16 |
+
typedef svuint16_t vls_uint16_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 17 |
+
typedef svuint32_t vls_uint32_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 18 |
+
typedef svuint64_t vls_uint64_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 19 |
+
typedef svfloat16_t vls_float16_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 20 |
+
typedef svfloat32_t vls_float32_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 21 |
+
typedef svfloat64_t vls_float64_t __attribute__((arm_sve_vector_bits(VECTOR_WIDTH * 8)));
|
| 22 |
+
|
| 23 |
+
#define ptrue svptrue_b8()
|
| 24 |
+
#define ZERO_S8 svdup_n_s8(0)
|
| 25 |
+
#define ZERO_S16 svdup_n_s16(0)
|
| 26 |
+
#define ZERO_S32 svdup_n_s32(0)
|
| 27 |
+
#define ZERO_S64 svdup_n_s64(0)
|
| 28 |
+
#define ZERO_U8 svdup_n_u8(0)
|
| 29 |
+
#define ZERO_U16 svdup_n_u16(0)
|
| 30 |
+
#define ZERO_U32 svdup_n_u32(0)
|
| 31 |
+
#define ZERO_U64 svdup_n_u64(0)
|
| 32 |
+
#define ZERO_F16 svdup_n_f16(0.f)
|
| 33 |
+
#define ZERO_F32 svdup_n_f32(0.f)
|
| 34 |
+
#define ZERO_F64 svdup_n_f64(0.0)
|
| 35 |
+
#define ONE_S8 svdup_n_s8(1)
|
| 36 |
+
#define ONE_S16 svdup_n_s16(1)
|
| 37 |
+
#define ONE_S32 svdup_n_s32(1)
|
| 38 |
+
#define ONE_S64 svdup_n_s64(1)
|
| 39 |
+
#define ONE_U8 svdup_n_u8(1)
|
| 40 |
+
#define ONE_U16 svdup_n_u16(1)
|
| 41 |
+
#define ONE_U32 svdup_n_u32(1)
|
| 42 |
+
#define ONE_U64 svdup_n_u64(1)
|
| 43 |
+
#define ONE_F16 svdup_n_f16(1.f)
|
| 44 |
+
#define ONE_F32 svdup_n_f32(1.f)
|
| 45 |
+
#define ONE_F64 svdup_n_f64(1.0)
|
| 46 |
+
#define ALL_S8_TRUE_MASK svdup_n_s8(0xff)
|
| 47 |
+
#define ALL_S8_FALSE_MASK svdup_n_s8(0x0)
|
| 48 |
+
#define ALL_S16_TRUE_MASK svdup_n_s16(0xffff)
|
| 49 |
+
#define ALL_S16_FALSE_MASK svdup_n_s16(0x0)
|
| 50 |
+
#define ALL_S32_TRUE_MASK svdup_n_s32(0xffffffff)
|
| 51 |
+
#define ALL_S32_FALSE_MASK svdup_n_s32(0x0)
|
| 52 |
+
#define ALL_S64_TRUE_MASK svdup_n_s64(0xffffffffffffffff)
|
| 53 |
+
#define ALL_S64_FALSE_MASK svdup_n_s64(0x0)
|
| 54 |
+
#define ALL_U8_TRUE_MASK svdup_n_u8(0x01)
|
| 55 |
+
#define ALL_U8_FALSE_MASK svdup_n_u8(0x00)
|
| 56 |
+
#define ALL_F16_TRUE_MASK svreinterpret_f16_s16(ALL_S16_TRUE_MASK)
|
| 57 |
+
#define ALL_F16_FALSE_MASK svreinterpret_f16_s16(ALL_S16_FALSE_MASK)
|
| 58 |
+
#define ALL_F32_TRUE_MASK svreinterpret_f32_s32(ALL_S32_TRUE_MASK)
|
| 59 |
+
#define ALL_F32_FALSE_MASK svreinterpret_f32_s32(ALL_S32_FALSE_MASK)
|
| 60 |
+
#define ALL_F64_TRUE_MASK svreinterpret_f64_s64(ALL_S64_TRUE_MASK)
|
| 61 |
+
#define ALL_F64_FALSE_MASK svreinterpret_f64_s64(ALL_S64_FALSE_MASK)
|
| 62 |
+
|
| 63 |
+
#endif // defined(CPU_CAPABILITY_SVE)
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_common_sve.h
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with SVE]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
|
| 8 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 9 |
+
#include <ATen/cpu/vec/sve/sve_helper.h>
|
| 10 |
+
|
| 11 |
+
#if defined(CPU_CAPABILITY_SVE)
|
| 12 |
+
#include <ATen/cpu/vec/sve/vec_float.h>
|
| 13 |
+
#include <ATen/cpu/vec/sve/vec_double.h>
|
| 14 |
+
#include <ATen/cpu/vec/sve/vec_int.h>
|
| 15 |
+
#include <ATen/cpu/vec/sve/vec_qint.h>
|
| 16 |
+
#endif
|
| 17 |
+
|
| 18 |
+
namespace at {
|
| 19 |
+
namespace vec {
|
| 20 |
+
// Note [CPU_CAPABILITY namespace]
|
| 21 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 22 |
+
// This header, and all of its subheaders, will be compiled with
|
| 23 |
+
// different architecture flags for each supported set of vector
|
| 24 |
+
// intrinsics. So we need to make sure they aren't inadvertently
|
| 25 |
+
// linked together. We do this by declaring objects in an `inline
|
| 26 |
+
// namespace` which changes the name mangling, but can still be
|
| 27 |
+
// accessed as `at::vec`.
|
| 28 |
+
inline namespace CPU_CAPABILITY {
|
| 29 |
+
|
| 30 |
+
#if defined(CPU_CAPABILITY_SVE)
|
| 31 |
+
|
| 32 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CAST ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 33 |
+
|
| 34 |
+
template<>
|
| 35 |
+
inline Vectorized<float> cast<float, double>(const Vectorized<double>& src) {
|
| 36 |
+
return svreinterpret_f32_f64(src);
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
template<>
|
| 40 |
+
inline Vectorized<double> cast<double, float>(const Vectorized<float>& src) {
|
| 41 |
+
return svreinterpret_f64_f32(src);
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
#define DEFINE_FLOAT_INT_CAST(int_t, int_bit, float_t, float_bit) \
|
| 45 |
+
template<> \
|
| 46 |
+
inline Vectorized<int_t> cast<int_t, float_t>(const Vectorized<float_t>& src) { \
|
| 47 |
+
return svreinterpret_s##int_bit##_f##float_bit(src); \
|
| 48 |
+
} \
|
| 49 |
+
template<> \
|
| 50 |
+
inline Vectorized<float_t> cast<float_t, int_t>(const Vectorized<int_t>& src) { \
|
| 51 |
+
return svreinterpret_f##float_bit##_s##int_bit(src); \
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
DEFINE_FLOAT_INT_CAST(int64_t, 64, double, 64)
|
| 55 |
+
DEFINE_FLOAT_INT_CAST(int32_t, 32, double, 64)
|
| 56 |
+
DEFINE_FLOAT_INT_CAST(int16_t, 16, double, 64)
|
| 57 |
+
DEFINE_FLOAT_INT_CAST(int64_t, 64, float, 32)
|
| 58 |
+
DEFINE_FLOAT_INT_CAST(int32_t, 32, float, 32)
|
| 59 |
+
DEFINE_FLOAT_INT_CAST(int16_t, 16, float, 32)
|
| 60 |
+
|
| 61 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GATHER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 62 |
+
|
| 63 |
+
template<int64_t scale = 1>
|
| 64 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<double>>
|
| 65 |
+
inline gather(const double* base_addr, const Vectorized<int64_t>& vindex_) {
|
| 66 |
+
svint64_t vindex = svasrd_n_s64_x(ptrue, svmul_s64_x(ptrue, vindex_, svdup_n_s64(scale)), 3);
|
| 67 |
+
return svld1_gather_s64index_f64(ptrue, base_addr, vindex);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
template<int64_t scale = 1>
|
| 71 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<float>>
|
| 72 |
+
inline gather(const float* base_addr, const Vectorized<int32_t>& vindex_) {
|
| 73 |
+
svint32_t vindex = svasrd_n_s32_x(ptrue, svmul_s32_x(ptrue, vindex_, svdup_n_s32(scale)), 2);
|
| 74 |
+
return svld1_gather_s32index_f32(ptrue, base_addr, vindex);
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MASK GATHER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 78 |
+
|
| 79 |
+
template<int64_t scale = 1>
|
| 80 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<double>>
|
| 81 |
+
inline mask_gather(const Vectorized<double>& src, const double* base_addr,
|
| 82 |
+
const Vectorized<int64_t>& vindex_, const Vectorized<double>& mask_) {
|
| 83 |
+
svbool_t mask = svcmpeq_s64(ptrue, svreinterpret_s64_f64(mask_),
|
| 84 |
+
ALL_S64_TRUE_MASK);
|
| 85 |
+
svint64_t vindex = svasrd_n_s64_x(ptrue, svmul_s64_x(ptrue, vindex_, svdup_n_s64(scale)), 3);
|
| 86 |
+
return svsel_f64(mask, svld1_gather_s64index_f64(mask, base_addr, vindex), src);
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
template<int64_t scale = 1>
|
| 90 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<float>>
|
| 91 |
+
inline mask_gather(const Vectorized<float>& src, const float* base_addr,
|
| 92 |
+
const Vectorized<int32_t>& vindex_, const Vectorized<float>& mask_) {
|
| 93 |
+
svbool_t mask = svcmpeq_s32(ptrue, svreinterpret_s32_f32(mask_),
|
| 94 |
+
ALL_S32_TRUE_MASK);
|
| 95 |
+
svint32_t vindex = svasrd_n_s32_x(ptrue, svmul_s32_x(ptrue, vindex_, svdup_n_s32(scale)), 2);
|
| 96 |
+
return svsel_f32(mask, svld1_gather_s32index_f32(mask, base_addr, vindex), src);
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CONVERT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 100 |
+
|
| 101 |
+
// Only works for inputs in the range: [-2^51, 2^51]
|
| 102 |
+
// From: https://stackoverflow.com/a/41148578
|
| 103 |
+
template<>
|
| 104 |
+
Vectorized<int64_t>
|
| 105 |
+
inline convert_to_int_of_same_size<double>(const Vectorized<double> &src) {
|
| 106 |
+
svfloat64_t x = svadd_f64_x(ptrue, src, svdup_n_f64(0x0018000000000000));
|
| 107 |
+
return svsub_s64_x(ptrue,
|
| 108 |
+
svreinterpret_s64_f64(x),
|
| 109 |
+
svreinterpret_s64_f64(svdup_n_f64(0x0018000000000000)));
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
template<>
|
| 113 |
+
Vectorized<int32_t>
|
| 114 |
+
inline convert_to_int_of_same_size<float>(const Vectorized<float> &src) {
|
| 115 |
+
return svcvt_s32_f32_x(ptrue, src);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTERLEAVE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 119 |
+
|
| 120 |
+
template <>
|
| 121 |
+
std::pair<Vectorized<double>, Vectorized<double>>
|
| 122 |
+
inline interleave2<double>(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 123 |
+
// inputs:
|
| 124 |
+
// a = {a0, a1, a3, a3}
|
| 125 |
+
// b = {b0, b1, b2, b3}
|
| 126 |
+
// group cols crossing lanes:
|
| 127 |
+
// return {a0, b0, a1, b1}
|
| 128 |
+
// {a2, b2, a3, b3}
|
| 129 |
+
return std::make_pair(Vectorized<double>(svzip1_f64(a, b)),
|
| 130 |
+
Vectorized<double>(svzip2_f64(a, b)));
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
template <>
|
| 134 |
+
std::pair<Vectorized<float>, Vectorized<float>>
|
| 135 |
+
inline interleave2<float>(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 136 |
+
// inputs:
|
| 137 |
+
// a = {a0, a1, a2, a3, a4, a5, a6, a7}
|
| 138 |
+
// b = {b0, b1, b2, b3, b4, b5, b6, b7}
|
| 139 |
+
// group cols crossing lanes:
|
| 140 |
+
// return {a0, b0, a1, b1, a2, b2, a3, b3}
|
| 141 |
+
// {a4, b4, a5, b5, a6, b6, a7, b7}
|
| 142 |
+
return std::make_pair(Vectorized<float>(svzip1_f32(a, b)),
|
| 143 |
+
Vectorized<float>(svzip2_f32(a, b)));
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEINTERLEAVE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 147 |
+
|
| 148 |
+
template <>
|
| 149 |
+
std::pair<Vectorized<double>, Vectorized<double>>
|
| 150 |
+
inline deinterleave2<double>(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 151 |
+
// inputs:
|
| 152 |
+
// a = {a0, b0, a1, b1}
|
| 153 |
+
// b = {a2, b2, a3, b3}
|
| 154 |
+
// swap lanes:
|
| 155 |
+
// return {a0, a1, a2, a3}
|
| 156 |
+
// {b0, b1, b2, b3}
|
| 157 |
+
return std::make_pair(Vectorized<double>(svuzp1_f64(a, b)),
|
| 158 |
+
Vectorized<double>(svuzp2_f64(a, b)));
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
template <>
|
| 162 |
+
std::pair<Vectorized<float>, Vectorized<float>>
|
| 163 |
+
inline deinterleave2<float>(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 164 |
+
// inputs:
|
| 165 |
+
// a = {a0, b0, a1, b1, a2, b2, a3, b3}
|
| 166 |
+
// b = {a4, b4, a5, b5, a6, b6, a7, b7}
|
| 167 |
+
// swap lanes:
|
| 168 |
+
// return {a0, a1, a2, a3, a4, a5, a6, a7}
|
| 169 |
+
// {b0, b1, b2, b3, b4, b5, b6, b7}
|
| 170 |
+
return std::make_pair(Vectorized<float>(svuzp1_f32(a, b)),
|
| 171 |
+
Vectorized<float>(svuzp2_f32(a, b)));
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
#endif // defined(CPU_CAPABILITY_SVE)
|
| 175 |
+
|
| 176 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_double.h
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/sve/sve_helper.h>
|
| 6 |
+
#include <cmath>
|
| 7 |
+
#if defined(__aarch64__) && defined(AT_BUILD_ARM_VEC256_WITH_SLEEF)
|
| 8 |
+
#include <sleef.h>
|
| 9 |
+
#define USE_SLEEF(sleef_code, non_sleef_code) sleef_code
|
| 10 |
+
#else
|
| 11 |
+
#define USE_SLEEF(sleef_code, non_sleef_code) non_sleef_code
|
| 12 |
+
#endif
|
| 13 |
+
namespace at {
|
| 14 |
+
namespace vec {
|
| 15 |
+
// Note [CPU_CAPABILITY namespace]
|
| 16 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 17 |
+
// This header, and all of its subheaders, will be compiled with
|
| 18 |
+
// different architecture flags for each supported set of vector
|
| 19 |
+
// intrinsics. So we need to make sure they aren't inadvertently
|
| 20 |
+
// linked together. We do this by declaring objects in an `inline
|
| 21 |
+
// namespace` which changes the name mangling, but can still be
|
| 22 |
+
// accessed as `at::vec`.
|
| 23 |
+
inline namespace CPU_CAPABILITY {
|
| 24 |
+
|
| 25 |
+
#if defined(CPU_CAPABILITY_SVE)
|
| 26 |
+
|
| 27 |
+
template <> class Vectorized<double> {
|
| 28 |
+
private:
|
| 29 |
+
vls_float64_t values;
|
| 30 |
+
public:
|
| 31 |
+
using value_type = double;
|
| 32 |
+
using size_type = int;
|
| 33 |
+
static constexpr size_type size() {
|
| 34 |
+
return VECTOR_WIDTH / sizeof(double);
|
| 35 |
+
}
|
| 36 |
+
Vectorized() {}
|
| 37 |
+
Vectorized(svfloat64_t v) : values(v) {}
|
| 38 |
+
Vectorized(double val) {
|
| 39 |
+
values = svdup_n_f64(val);
|
| 40 |
+
}
|
| 41 |
+
template<typename... Args,
|
| 42 |
+
typename = std::enable_if_t<(sizeof...(Args) == size())>>
|
| 43 |
+
Vectorized(Args... vals) {
|
| 44 |
+
__at_align__ double buffer[size()] = { vals... };
|
| 45 |
+
values = svld1_f64(ptrue, buffer);
|
| 46 |
+
}
|
| 47 |
+
operator svfloat64_t() const {
|
| 48 |
+
return values;
|
| 49 |
+
}
|
| 50 |
+
static Vectorized<double> blendv(const Vectorized<double>& a, const Vectorized<double>& b,
|
| 51 |
+
const Vectorized<double>& mask_) {
|
| 52 |
+
svbool_t mask = svcmpeq_s64(ptrue, svreinterpret_s64_f64(mask_),
|
| 53 |
+
ALL_S64_TRUE_MASK);
|
| 54 |
+
return svsel_f64(mask, b, a);
|
| 55 |
+
}
|
| 56 |
+
template<typename step_t>
|
| 57 |
+
static Vectorized<double> arange(double base = 0., step_t step = static_cast<step_t>(1)) {
|
| 58 |
+
__at_align__ double buffer[size()];
|
| 59 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 60 |
+
buffer[i] = base + i * step;
|
| 61 |
+
}
|
| 62 |
+
return svld1_f64(ptrue, buffer);
|
| 63 |
+
}
|
| 64 |
+
static Vectorized<double> set(const Vectorized<double>& a, const Vectorized<double>& b,
|
| 65 |
+
int64_t count = size()) {
|
| 66 |
+
if (count == 0) {
|
| 67 |
+
return a;
|
| 68 |
+
} else if (count < size()) {
|
| 69 |
+
return svsel_f64(svwhilelt_b64(0ull, count), b, a);
|
| 70 |
+
}
|
| 71 |
+
return b;
|
| 72 |
+
}
|
| 73 |
+
static Vectorized<double> loadu(const void* ptr, int64_t count = size()) {
|
| 74 |
+
if (count == size())
|
| 75 |
+
return svld1_f64(ptrue, reinterpret_cast<const double*>(ptr));
|
| 76 |
+
svbool_t pg = svwhilelt_b64(0ull, count);
|
| 77 |
+
return svld1_f64(pg, reinterpret_cast<const double*>(ptr));
|
| 78 |
+
}
|
| 79 |
+
void store(void* ptr, int64_t count = size()) const {
|
| 80 |
+
if (count == size()) {
|
| 81 |
+
svst1_f64(ptrue, reinterpret_cast<double*>(ptr), values);
|
| 82 |
+
} else {
|
| 83 |
+
svbool_t pg = svwhilelt_b64(0ull, count);
|
| 84 |
+
svst1_f64(pg, reinterpret_cast<double*>(ptr), values);
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
const double& operator[](int idx) const = delete;
|
| 88 |
+
double& operator[](int idx) = delete;
|
| 89 |
+
int64_t zero_mask() const {
|
| 90 |
+
// returns an integer mask where all zero elements are translated to 1-bit and others are translated to 0-bit
|
| 91 |
+
int64_t mask = 0;
|
| 92 |
+
__at_align__ int64_t mask_array[size()];
|
| 93 |
+
|
| 94 |
+
svbool_t svbool_mask = svcmpeq_f64(ptrue, values, ZERO_F64);
|
| 95 |
+
svst1_s64(ptrue, mask_array, svsel_s64(svbool_mask,
|
| 96 |
+
ALL_S64_TRUE_MASK,
|
| 97 |
+
ALL_S64_FALSE_MASK));
|
| 98 |
+
for (int64_t i = 0; i < size(); ++i) {
|
| 99 |
+
if (mask_array[i]) mask |= (1ull << i);
|
| 100 |
+
}
|
| 101 |
+
return mask;
|
| 102 |
+
}
|
| 103 |
+
Vectorized<double> isnan() const {
|
| 104 |
+
// NaN check
|
| 105 |
+
svbool_t mask = svcmpuo_f64(ptrue, values, ZERO_F64);
|
| 106 |
+
return svsel_f64(mask, ALL_F64_TRUE_MASK, ALL_F64_FALSE_MASK);
|
| 107 |
+
}
|
| 108 |
+
bool has_inf_nan() const {
|
| 109 |
+
return svptest_any(ptrue, svcmpuo_f64(ptrue, svsub_f64_x(ptrue, values, values), ZERO_F64));
|
| 110 |
+
}
|
| 111 |
+
Vectorized<double> map(double (*f)(double)) const {
|
| 112 |
+
__at_align__ double tmp[size()];
|
| 113 |
+
store(tmp);
|
| 114 |
+
for (int64_t i = 0; i < size(); ++i) {
|
| 115 |
+
tmp[i] = f(tmp[i]);
|
| 116 |
+
}
|
| 117 |
+
return loadu(tmp);
|
| 118 |
+
}
|
| 119 |
+
Vectorized<double> abs() const {
|
| 120 |
+
return svabs_f64_x(ptrue, values);
|
| 121 |
+
}
|
| 122 |
+
Vectorized<double> angle() const {
|
| 123 |
+
const auto nan_vec = svdup_n_f64(NAN);
|
| 124 |
+
const auto nan_mask = svcmpuo_f64(ptrue, values, ZERO_F64);
|
| 125 |
+
const auto pi = svdup_n_f64(c10::pi<double>);
|
| 126 |
+
|
| 127 |
+
const auto neg_mask = svcmplt_f64(ptrue, values, ZERO_F64);
|
| 128 |
+
auto angle = svsel_f64(neg_mask, pi, ZERO_F64);
|
| 129 |
+
angle = svsel_f64(nan_mask, nan_vec, angle);
|
| 130 |
+
return angle;
|
| 131 |
+
}
|
| 132 |
+
Vectorized<double> real() const {
|
| 133 |
+
return *this;
|
| 134 |
+
}
|
| 135 |
+
Vectorized<double> imag() const {
|
| 136 |
+
return Vectorized<double>(0.0);
|
| 137 |
+
}
|
| 138 |
+
Vectorized<double> conj() const {
|
| 139 |
+
return *this;
|
| 140 |
+
}
|
| 141 |
+
Vectorized<double> acos() const {
|
| 142 |
+
return USE_SLEEF(Vectorized<double>(Sleef_acosdx_u10sve(values)),map(std::acos));
|
| 143 |
+
}
|
| 144 |
+
Vectorized<double> acosh() const {
|
| 145 |
+
return USE_SLEEF( Vectorized<double>(Sleef_acoshdx_u10sve(values)),map(std::acosh));
|
| 146 |
+
}
|
| 147 |
+
Vectorized<double> asin() const {
|
| 148 |
+
return USE_SLEEF(Vectorized<double>(Sleef_asindx_u10sve(values)),map(std::asin));
|
| 149 |
+
}
|
| 150 |
+
Vectorized<double> atan() const {
|
| 151 |
+
return USE_SLEEF(Vectorized<double>(Sleef_atandx_u10sve(values)),map(std::atan));
|
| 152 |
+
}
|
| 153 |
+
Vectorized<double> atanh() const {
|
| 154 |
+
return USE_SLEEF(Vectorized<double>(Sleef_atanhdx_u10sve(values)),map(std::atanh));
|
| 155 |
+
}
|
| 156 |
+
Vectorized<double> atan2(const Vectorized<double> &b) const {
|
| 157 |
+
USE_SLEEF({return Vectorized<double>(Sleef_atan2dx_u10sve(values, b));},
|
| 158 |
+
{
|
| 159 |
+
__at_align__ double tmp[size()];
|
| 160 |
+
__at_align__ double tmp_b[size()];
|
| 161 |
+
store(tmp);
|
| 162 |
+
b.store(tmp_b);
|
| 163 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 164 |
+
tmp[i] = std::atan2(tmp[i], tmp_b[i]);
|
| 165 |
+
}
|
| 166 |
+
return loadu(tmp);
|
| 167 |
+
}
|
| 168 |
+
)
|
| 169 |
+
}
|
| 170 |
+
Vectorized<double> copysign(const Vectorized<double> &sign) const {
|
| 171 |
+
USE_SLEEF( {return Vectorized<double>(Sleef_copysigndx_sve(values, sign));},
|
| 172 |
+
{
|
| 173 |
+
__at_align__ double tmp[size()];
|
| 174 |
+
__at_align__ double tmp_sign[size()];
|
| 175 |
+
store(tmp);
|
| 176 |
+
sign.store(tmp_sign);
|
| 177 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 178 |
+
tmp[i] = std::copysign(tmp[i], tmp_sign[i]);
|
| 179 |
+
}
|
| 180 |
+
return loadu(tmp);
|
| 181 |
+
}
|
| 182 |
+
)
|
| 183 |
+
}
|
| 184 |
+
Vectorized<double> erf() const {
|
| 185 |
+
return USE_SLEEF(Vectorized<double>(Sleef_erfdx_u10sve(values)),map(std::erf));
|
| 186 |
+
}
|
| 187 |
+
Vectorized<double> erfc() const {
|
| 188 |
+
return USE_SLEEF(Vectorized<double>(Sleef_erfcdx_u15sve(values)),map(std::erfc));
|
| 189 |
+
}
|
| 190 |
+
Vectorized<double> erfinv() const {
|
| 191 |
+
return map(calc_erfinv);
|
| 192 |
+
}
|
| 193 |
+
Vectorized<double> exp() const {
|
| 194 |
+
return USE_SLEEF(Vectorized<double>(Sleef_expdx_u10sve(values)),map(std::exp));
|
| 195 |
+
}
|
| 196 |
+
Vectorized<double> exp2() const {
|
| 197 |
+
return USE_SLEEF(Vectorized<double>(Sleef_exp2dx_u10sve(values)),map(std::exp2));
|
| 198 |
+
}
|
| 199 |
+
Vectorized<double> expm1() const {
|
| 200 |
+
return USE_SLEEF(Vectorized<double>(Sleef_expm1dx_u10sve(values)),map(std::expm1));
|
| 201 |
+
}
|
| 202 |
+
Vectorized<double> exp_u20() const {
|
| 203 |
+
return exp();
|
| 204 |
+
}
|
| 205 |
+
Vectorized<double> fmod(const Vectorized<double>& q) const {
|
| 206 |
+
USE_SLEEF({return Vectorized<double>(Sleef_fmoddx_sve(values, q));},
|
| 207 |
+
{
|
| 208 |
+
__at_align__ double tmp[size()];
|
| 209 |
+
__at_align__ double tmp_q[size()];
|
| 210 |
+
store(tmp);
|
| 211 |
+
q.store(tmp_q);
|
| 212 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 213 |
+
tmp[i] = std::fmod(tmp[i], tmp_q[i]);
|
| 214 |
+
}
|
| 215 |
+
return loadu(tmp);
|
| 216 |
+
}
|
| 217 |
+
)
|
| 218 |
+
}
|
| 219 |
+
Vectorized<double> hypot(const Vectorized<double> &b) const {
|
| 220 |
+
USE_SLEEF({return Vectorized<double>(Sleef_hypotdx_u05sve(values, b));},
|
| 221 |
+
{
|
| 222 |
+
__at_align__ double tmp[size()];
|
| 223 |
+
__at_align__ double tmp_b[size()];
|
| 224 |
+
store(tmp);
|
| 225 |
+
b.store(tmp_b);
|
| 226 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 227 |
+
tmp[i] = std::hypot(tmp[i], tmp_b[i]);
|
| 228 |
+
}
|
| 229 |
+
return loadu(tmp);
|
| 230 |
+
})
|
| 231 |
+
}
|
| 232 |
+
Vectorized<double> i0() const {
|
| 233 |
+
return map(calc_i0);
|
| 234 |
+
}
|
| 235 |
+
Vectorized<double> i0e() const {
|
| 236 |
+
return map(calc_i0e);
|
| 237 |
+
}
|
| 238 |
+
Vectorized<double> digamma() const {
|
| 239 |
+
return map(calc_digamma);
|
| 240 |
+
}
|
| 241 |
+
Vectorized<double> igamma(const Vectorized<double> &x) const {
|
| 242 |
+
__at_align__ double tmp[size()];
|
| 243 |
+
__at_align__ double tmp_x[size()];
|
| 244 |
+
store(tmp);
|
| 245 |
+
x.store(tmp_x);
|
| 246 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 247 |
+
tmp[i] = calc_igamma(tmp[i], tmp_x[i]);
|
| 248 |
+
}
|
| 249 |
+
return loadu(tmp);
|
| 250 |
+
}
|
| 251 |
+
Vectorized<double> igammac(const Vectorized<double> &x) const {
|
| 252 |
+
__at_align__ double tmp[size()];
|
| 253 |
+
__at_align__ double tmp_x[size()];
|
| 254 |
+
store(tmp);
|
| 255 |
+
x.store(tmp_x);
|
| 256 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 257 |
+
tmp[i] = calc_igammac(tmp[i], tmp_x[i]);
|
| 258 |
+
}
|
| 259 |
+
return loadu(tmp);
|
| 260 |
+
}
|
| 261 |
+
Vectorized<double> nextafter(const Vectorized<double> &b) const {
|
| 262 |
+
USE_SLEEF(
|
| 263 |
+
{
|
| 264 |
+
return Vectorized<double>(Sleef_nextafterdx_sve(values, b));
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
__at_align__ double tmp[size()];
|
| 268 |
+
__at_align__ double tmp_b[size()];
|
| 269 |
+
store(tmp);
|
| 270 |
+
b.store(tmp_b);
|
| 271 |
+
for (int64_t i = 0; i < size(); ++i) {
|
| 272 |
+
tmp[i] = std::nextafter(tmp[i], tmp_b[i]);
|
| 273 |
+
}
|
| 274 |
+
return loadu(tmp);
|
| 275 |
+
}
|
| 276 |
+
)
|
| 277 |
+
}
|
| 278 |
+
Vectorized<double> log() const {
|
| 279 |
+
return USE_SLEEF(Vectorized<double>(Sleef_logdx_u10sve(values)),map(std::log));
|
| 280 |
+
}
|
| 281 |
+
Vectorized<double> log2() const {
|
| 282 |
+
return USE_SLEEF(Vectorized<double>(Sleef_log2dx_u10sve(values)),map(std::log2));
|
| 283 |
+
}
|
| 284 |
+
Vectorized<double> log10() const {
|
| 285 |
+
return USE_SLEEF(Vectorized<double>(Sleef_log10dx_u10sve(values)),map(std::log10));
|
| 286 |
+
}
|
| 287 |
+
Vectorized<double> log1p() const {
|
| 288 |
+
return USE_SLEEF(Vectorized<double>(Sleef_log1pdx_u10sve(values)),map(std::log1p));
|
| 289 |
+
}
|
| 290 |
+
Vectorized<double> frac() const;
|
| 291 |
+
Vectorized<double> sin() const {
|
| 292 |
+
return USE_SLEEF( Vectorized<double>(Sleef_sindx_u10sve(values)),map(std::sin));
|
| 293 |
+
}
|
| 294 |
+
Vectorized<double> sinh() const {
|
| 295 |
+
return USE_SLEEF(Vectorized<double>(Sleef_sinhdx_u10sve(values)),map(std::sinh));
|
| 296 |
+
}
|
| 297 |
+
Vectorized<double> cos() const {
|
| 298 |
+
return USE_SLEEF(Vectorized<double>(Sleef_cosdx_u10sve(values)),map(std::cos));
|
| 299 |
+
}
|
| 300 |
+
Vectorized<double> cosh() const {
|
| 301 |
+
return USE_SLEEF( Vectorized<double>(Sleef_coshdx_u10sve(values)),map(std::cosh));
|
| 302 |
+
}
|
| 303 |
+
Vectorized<double> ceil() const {
|
| 304 |
+
return svrintp_f64_x(ptrue, values);
|
| 305 |
+
}
|
| 306 |
+
Vectorized<double> floor() const {
|
| 307 |
+
return svrintm_f64_x(ptrue, values);
|
| 308 |
+
}
|
| 309 |
+
Vectorized<double> neg() const {
|
| 310 |
+
return svneg_f64_x(ptrue, values);
|
| 311 |
+
}
|
| 312 |
+
Vectorized<double> round() const {
|
| 313 |
+
return svrinti_f64_x(ptrue, values);
|
| 314 |
+
}
|
| 315 |
+
Vectorized<double> tan() const {
|
| 316 |
+
return USE_SLEEF( Vectorized<double>(Sleef_tandx_u10sve(values)),map(std::tan));
|
| 317 |
+
}
|
| 318 |
+
Vectorized<double> tanh() const {
|
| 319 |
+
return USE_SLEEF( Vectorized<double>(Sleef_tanhdx_u10sve(values)),map(std::tanh));
|
| 320 |
+
}
|
| 321 |
+
Vectorized<double> trunc() const {
|
| 322 |
+
return svrintz_f64_x(ptrue, values);
|
| 323 |
+
}
|
| 324 |
+
Vectorized<double> lgamma() const {
|
| 325 |
+
return USE_SLEEF( Vectorized<double>(Sleef_lgammadx_u10sve(values)),map(std::lgamma));
|
| 326 |
+
}
|
| 327 |
+
Vectorized<double> sqrt() const {
|
| 328 |
+
return svsqrt_f64_x(ptrue, values);
|
| 329 |
+
}
|
| 330 |
+
Vectorized<double> reciprocal() const {
|
| 331 |
+
return svdivr_f64_x(ptrue, values, ONE_F64);
|
| 332 |
+
}
|
| 333 |
+
Vectorized<double> rsqrt() const {
|
| 334 |
+
return svdivr_f64_x(ptrue, svsqrt_f64_x(ptrue, values), ONE_F64);
|
| 335 |
+
}
|
| 336 |
+
Vectorized<double> pow(const Vectorized<double> &b) const {
|
| 337 |
+
USE_SLEEF( {return Vectorized<double>(Sleef_powdx_u10sve(values, b));},
|
| 338 |
+
{
|
| 339 |
+
__at_align__ double tmp[size()];
|
| 340 |
+
__at_align__ double tmp_b[size()];
|
| 341 |
+
store(tmp);
|
| 342 |
+
b.store(tmp_b);
|
| 343 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 344 |
+
tmp[i] = std::pow(tmp[i], tmp_b[i]);
|
| 345 |
+
}
|
| 346 |
+
return loadu(tmp);
|
| 347 |
+
}
|
| 348 |
+
)
|
| 349 |
+
}
|
| 350 |
+
// Comparison using the _CMP_**_OQ predicate.
|
| 351 |
+
// `O`: get false if an operand is NaN
|
| 352 |
+
// `Q`: do not raise if an operand is NaN
|
| 353 |
+
Vectorized<double> operator==(const Vectorized<double>& other) const {
|
| 354 |
+
svbool_t mask = svcmpeq_f64(ptrue, values, other);
|
| 355 |
+
return svsel_f64(mask, ALL_F64_TRUE_MASK, ALL_F64_FALSE_MASK);
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
Vectorized<double> operator!=(const Vectorized<double>& other) const {
|
| 359 |
+
svbool_t mask = svcmpne_f64(ptrue, values, other);
|
| 360 |
+
return svsel_f64(mask, ALL_F64_TRUE_MASK, ALL_F64_FALSE_MASK);
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
Vectorized<double> operator<(const Vectorized<double>& other) const {
|
| 364 |
+
svbool_t mask = svcmplt_f64(ptrue, values, other);
|
| 365 |
+
return svsel_f64(mask, ALL_F64_TRUE_MASK, ALL_F64_FALSE_MASK);
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
Vectorized<double> operator<=(const Vectorized<double>& other) const {
|
| 369 |
+
svbool_t mask = svcmple_f64(ptrue, values, other);
|
| 370 |
+
return svsel_f64(mask, ALL_F64_TRUE_MASK, ALL_F64_FALSE_MASK);
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
Vectorized<double> operator>(const Vectorized<double>& other) const {
|
| 374 |
+
svbool_t mask = svcmpgt_f64(ptrue, values, other);
|
| 375 |
+
return svsel_f64(mask, ALL_F64_TRUE_MASK, ALL_F64_FALSE_MASK);
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
Vectorized<double> operator>=(const Vectorized<double>& other) const {
|
| 379 |
+
svbool_t mask = svcmpge_f64(ptrue, values, other);
|
| 380 |
+
return svsel_f64(mask, ALL_F64_TRUE_MASK, ALL_F64_FALSE_MASK);
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
Vectorized<double> eq(const Vectorized<double>& other) const;
|
| 384 |
+
Vectorized<double> ne(const Vectorized<double>& other) const;
|
| 385 |
+
Vectorized<double> gt(const Vectorized<double>& other) const;
|
| 386 |
+
Vectorized<double> ge(const Vectorized<double>& other) const;
|
| 387 |
+
Vectorized<double> lt(const Vectorized<double>& other) const;
|
| 388 |
+
Vectorized<double> le(const Vectorized<double>& other) const;
|
| 389 |
+
};
|
| 390 |
+
|
| 391 |
+
template <>
|
| 392 |
+
Vectorized<double> inline operator+(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 393 |
+
return svadd_f64_x(ptrue, a, b);
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
template <>
|
| 397 |
+
Vectorized<double> inline operator-(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 398 |
+
return svsub_f64_x(ptrue, a, b);
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
template <>
|
| 402 |
+
Vectorized<double> inline operator*(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 403 |
+
return svmul_f64_x(ptrue, a, b);
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
template <>
|
| 407 |
+
Vectorized<double> inline operator/(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 408 |
+
return svdiv_f64_x(ptrue, a, b);
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
// frac. Implement this here so we can use subtraction
|
| 412 |
+
Vectorized<double> inline Vectorized<double>::frac() const {
|
| 413 |
+
return *this - this->trunc();
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 417 |
+
// either input is a NaN.
|
| 418 |
+
template <>
|
| 419 |
+
Vectorized<double> inline maximum(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 420 |
+
return svmax_f64_x(ptrue, a, b);
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 424 |
+
// either input is a NaN.
|
| 425 |
+
template <>
|
| 426 |
+
Vectorized<double> inline minimum(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 427 |
+
return svmin_f64_x(ptrue, a, b);
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
template <>
|
| 431 |
+
Vectorized<double> inline clamp(const Vectorized<double>& a, const Vectorized<double>& min, const Vectorized<double>& max) {
|
| 432 |
+
return svmin_f64_x(ptrue, max, svmax_f64_x(ptrue, min, a));
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
template <>
|
| 436 |
+
Vectorized<double> inline clamp_max(const Vectorized<double>& a, const Vectorized<double>& max) {
|
| 437 |
+
return svmin_f64_x(ptrue, max, a);
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
template <>
|
| 441 |
+
Vectorized<double> inline clamp_min(const Vectorized<double>& a, const Vectorized<double>& min) {
|
| 442 |
+
return svmax_f64_x(ptrue, min, a);
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
template <>
|
| 446 |
+
Vectorized<double> inline operator&(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 447 |
+
return svreinterpret_f64_s64(svand_s64_x(ptrue, svreinterpret_s64_f64(a), svreinterpret_s64_f64(b)));
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
template <>
|
| 451 |
+
Vectorized<double> inline operator|(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 452 |
+
return svreinterpret_f64_s64(svorr_s64_x(ptrue, svreinterpret_s64_f64(a), svreinterpret_s64_f64(b)));
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
template <>
|
| 456 |
+
Vectorized<double> inline operator^(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 457 |
+
return svreinterpret_f64_s64(sveor_s64_x(ptrue, svreinterpret_s64_f64(a), svreinterpret_s64_f64(b)));
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
Vectorized<double> inline Vectorized<double>::eq(const Vectorized<double>& other) const {
|
| 461 |
+
return (*this == other) & Vectorized<double>(1.0);
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
Vectorized<double> inline Vectorized<double>::ne(const Vectorized<double>& other) const {
|
| 465 |
+
return (*this != other) & Vectorized<double>(1.0);
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
Vectorized<double> inline Vectorized<double>::gt(const Vectorized<double>& other) const {
|
| 469 |
+
return (*this > other) & Vectorized<double>(1.0);
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
Vectorized<double> inline Vectorized<double>::ge(const Vectorized<double>& other) const {
|
| 473 |
+
return (*this >= other) & Vectorized<double>(1.0);
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
Vectorized<double> inline Vectorized<double>::lt(const Vectorized<double>& other) const {
|
| 477 |
+
return (*this < other) & Vectorized<double>(1.0);
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
Vectorized<double> inline Vectorized<double>::le(const Vectorized<double>& other) const {
|
| 481 |
+
return (*this <= other) & Vectorized<double>(1.0);
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
template <>
|
| 485 |
+
inline void convert(const double* src, double* dst, int64_t n) {
|
| 486 |
+
const int64_t fraction = n % Vectorized<double>::size();
|
| 487 |
+
#pragma unroll
|
| 488 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<double>::size()) {
|
| 489 |
+
svst1_f64(ptrue, dst + i, svldnt1_f64(ptrue, src + i));
|
| 490 |
+
}
|
| 491 |
+
#pragma unroll
|
| 492 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<double>::size()) {
|
| 493 |
+
svbool_t pg = svwhilelt_b64(i, n);
|
| 494 |
+
svst1_f64(pg, dst + i, svldnt1_f64(pg, src + i));
|
| 495 |
+
}
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
template <>
|
| 499 |
+
Vectorized<double> inline fmadd(const Vectorized<double>& a, const Vectorized<double>& b, const Vectorized<double>& c) {
|
| 500 |
+
return svmad_f64_x(ptrue, a, b, c);
|
| 501 |
+
}
|
| 502 |
+
|
| 503 |
+
#endif // defined(CPU_CAPABILITY_SVE)
|
| 504 |
+
|
| 505 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_float.h
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/sve/sve_helper.h>
|
| 6 |
+
#include <cmath>
|
| 7 |
+
#if defined(__aarch64__) && defined(AT_BUILD_ARM_VEC256_WITH_SLEEF)
|
| 8 |
+
#include <sleef.h>
|
| 9 |
+
#define USE_SLEEF(sleef_code, non_sleef_code) sleef_code
|
| 10 |
+
#else
|
| 11 |
+
#define USE_SLEEF(sleef_code, non_sleef_code) non_sleef_code
|
| 12 |
+
#endif
|
| 13 |
+
namespace at {
|
| 14 |
+
namespace vec {
|
| 15 |
+
// Note [CPU_CAPABILITY namespace]
|
| 16 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 17 |
+
// This header, and all of its subheaders, will be compiled with
|
| 18 |
+
// different architecture flags for each supported set of vector
|
| 19 |
+
// intrinsics. So we need to make sure they aren't inadvertently
|
| 20 |
+
// linked together. We do this by declaring objects in an `inline
|
| 21 |
+
// namespace` which changes the name mangling, but can still be
|
| 22 |
+
// accessed as `at::vec`.
|
| 23 |
+
inline namespace CPU_CAPABILITY {
|
| 24 |
+
|
| 25 |
+
#if defined(CPU_CAPABILITY_SVE)
|
| 26 |
+
|
| 27 |
+
template <> class Vectorized<float> {
|
| 28 |
+
private:
|
| 29 |
+
vls_float32_t values;
|
| 30 |
+
public:
|
| 31 |
+
using value_type = float;
|
| 32 |
+
using size_type = int;
|
| 33 |
+
static constexpr size_type size() {
|
| 34 |
+
return VECTOR_WIDTH / sizeof(float);
|
| 35 |
+
}
|
| 36 |
+
Vectorized() {}
|
| 37 |
+
Vectorized(svfloat32_t v) : values(v) {}
|
| 38 |
+
Vectorized(float val) {
|
| 39 |
+
values = svdup_n_f32(val);
|
| 40 |
+
}
|
| 41 |
+
template<typename... Args,
|
| 42 |
+
typename = std::enable_if_t<(sizeof...(Args) == size())>>
|
| 43 |
+
Vectorized(Args... vals) {
|
| 44 |
+
__at_align__ float buffer[size()] = { vals... };
|
| 45 |
+
values = svld1_f32(ptrue, buffer);
|
| 46 |
+
}
|
| 47 |
+
operator svfloat32_t() const {
|
| 48 |
+
return values;
|
| 49 |
+
}
|
| 50 |
+
static Vectorized<float> blendv(const Vectorized<float>& a, const Vectorized<float>& b,
|
| 51 |
+
const Vectorized<float>& mask_) {
|
| 52 |
+
svbool_t mask = svcmpeq_s32(ptrue, svreinterpret_s32_f32(mask_),
|
| 53 |
+
ALL_S32_TRUE_MASK);
|
| 54 |
+
return svsel_f32(mask, b, a);
|
| 55 |
+
}
|
| 56 |
+
template<typename step_t>
|
| 57 |
+
static Vectorized<float> arange(float base = 0.f, step_t step = static_cast<step_t>(1)) {
|
| 58 |
+
__at_align__ float buffer[size()];
|
| 59 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 60 |
+
buffer[i] = base + i * step;
|
| 61 |
+
}
|
| 62 |
+
return svld1_f32(ptrue, buffer);
|
| 63 |
+
}
|
| 64 |
+
static Vectorized<float> set(const Vectorized<float>& a, const Vectorized<float>& b,
|
| 65 |
+
int64_t count = size()) {
|
| 66 |
+
if (count == 0) {
|
| 67 |
+
return a;
|
| 68 |
+
} else if (count < size()) {
|
| 69 |
+
return svsel_f32(svwhilelt_b32(0ull, count), b, a);
|
| 70 |
+
}
|
| 71 |
+
return b;
|
| 72 |
+
}
|
| 73 |
+
static Vectorized<float> loadu(const void* ptr, int64_t count = size()) {
|
| 74 |
+
if (count == size())
|
| 75 |
+
return svld1_f32(ptrue, reinterpret_cast<const float*>(ptr));
|
| 76 |
+
svbool_t pg = svwhilelt_b32(0ull, count);
|
| 77 |
+
return svld1_f32(pg, reinterpret_cast<const float*>(ptr));
|
| 78 |
+
}
|
| 79 |
+
void store(void* ptr, int64_t count = size()) const {
|
| 80 |
+
if (count == size()) {
|
| 81 |
+
svst1_f32(ptrue, reinterpret_cast<float*>(ptr), values);
|
| 82 |
+
} else {
|
| 83 |
+
svbool_t pg = svwhilelt_b32(0ull, count);
|
| 84 |
+
svst1_f32(pg, reinterpret_cast<float*>(ptr), values);
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
const float& operator[](int idx) const = delete;
|
| 88 |
+
float& operator[](int idx) = delete;
|
| 89 |
+
int64_t zero_mask() const {
|
| 90 |
+
// returns an integer mask where all zero elements are translated to 1-bit and others are translated to 0-bit
|
| 91 |
+
int64_t mask = 0;
|
| 92 |
+
__at_align__ int32_t mask_array[size()];
|
| 93 |
+
|
| 94 |
+
svbool_t svbool_mask = svcmpeq_f32(ptrue, values, ZERO_F32);
|
| 95 |
+
svst1_s32(ptrue, mask_array, svsel_s32(svbool_mask,
|
| 96 |
+
ALL_S32_TRUE_MASK,
|
| 97 |
+
ALL_S32_FALSE_MASK));
|
| 98 |
+
for (int64_t i = 0; i < size(); ++i) {
|
| 99 |
+
if (mask_array[i]) mask |= (1ull << i);
|
| 100 |
+
}
|
| 101 |
+
return mask;
|
| 102 |
+
}
|
| 103 |
+
Vectorized<float> isnan() const {
|
| 104 |
+
// NaN check
|
| 105 |
+
svbool_t mask = svcmpuo_f32(ptrue, values, ZERO_F32);
|
| 106 |
+
return svsel_f32(mask, ALL_F32_TRUE_MASK, ALL_F32_FALSE_MASK);
|
| 107 |
+
}
|
| 108 |
+
bool has_inf_nan() const {
|
| 109 |
+
return svptest_any(ptrue, svcmpuo_f32(ptrue, svsub_f32_x(ptrue, values, values), ZERO_F32));
|
| 110 |
+
}
|
| 111 |
+
Vectorized<float> map(float (*f)(float)) const {
|
| 112 |
+
__at_align__ float tmp[size()];
|
| 113 |
+
store(tmp);
|
| 114 |
+
for (int64_t i = 0; i < size(); ++i) {
|
| 115 |
+
tmp[i] = f(tmp[i]);
|
| 116 |
+
}
|
| 117 |
+
return loadu(tmp);
|
| 118 |
+
}
|
| 119 |
+
Vectorized<float> abs() const {
|
| 120 |
+
return svabs_f32_x(ptrue, values);
|
| 121 |
+
}
|
| 122 |
+
Vectorized<float> angle() const {
|
| 123 |
+
const auto nan_vec = svdup_n_f32(NAN);
|
| 124 |
+
const auto nan_mask = svcmpuo_f32(ptrue, values, ZERO_F32);
|
| 125 |
+
const auto pi = svdup_n_f32(c10::pi<float>);
|
| 126 |
+
|
| 127 |
+
const auto neg_mask = svcmplt_f32(ptrue, values, ZERO_F32);
|
| 128 |
+
auto angle = svsel_f32(neg_mask, pi, ZERO_F32);
|
| 129 |
+
angle = svsel_f32(nan_mask, nan_vec, angle);
|
| 130 |
+
return angle;
|
| 131 |
+
}
|
| 132 |
+
Vectorized<float> real() const {
|
| 133 |
+
return values;
|
| 134 |
+
}
|
| 135 |
+
Vectorized<float> imag() const {
|
| 136 |
+
return Vectorized<float>(0.f);
|
| 137 |
+
}
|
| 138 |
+
Vectorized<float> conj() const {
|
| 139 |
+
return values;
|
| 140 |
+
}
|
| 141 |
+
Vectorized<float> acos() const {
|
| 142 |
+
return USE_SLEEF(Vectorized<float>(Sleef_acosfx_u10sve(values)),map(std::acos));
|
| 143 |
+
}
|
| 144 |
+
Vectorized<float> acosh() const {
|
| 145 |
+
return USE_SLEEF(Vectorized<float>(Sleef_acoshfx_u10sve(values)),map(std::acosh));
|
| 146 |
+
}
|
| 147 |
+
Vectorized<float> asin() const {
|
| 148 |
+
return USE_SLEEF(Vectorized<float>(Sleef_asinfx_u10sve(values)),map(std::asin));
|
| 149 |
+
}
|
| 150 |
+
Vectorized<float> atan() const {
|
| 151 |
+
return USE_SLEEF(Vectorized<float>(Sleef_atanfx_u10sve(values)),map(std::atan));
|
| 152 |
+
}
|
| 153 |
+
Vectorized<float> atanh() const {
|
| 154 |
+
return USE_SLEEF(Vectorized<float>(Sleef_atanhfx_u10sve(values)),map(std::atanh));
|
| 155 |
+
}
|
| 156 |
+
Vectorized<float> atan2(const Vectorized<float> &b) const {
|
| 157 |
+
USE_SLEEF({return Vectorized<float>(Sleef_atan2fx_u10sve(values, b));},
|
| 158 |
+
{
|
| 159 |
+
__at_align__ float tmp[size()];
|
| 160 |
+
__at_align__ float tmp_b[size()];
|
| 161 |
+
store(tmp);
|
| 162 |
+
b.store(tmp_b);
|
| 163 |
+
for (int64_t i = 0; i < size(); i++){
|
| 164 |
+
tmp[i] = std::atan2(tmp[i], tmp_b[i]);
|
| 165 |
+
}
|
| 166 |
+
return loadu(tmp);
|
| 167 |
+
}
|
| 168 |
+
)
|
| 169 |
+
}
|
| 170 |
+
Vectorized<float> copysign(const Vectorized<float> &sign) const {
|
| 171 |
+
|
| 172 |
+
USE_SLEEF({return Vectorized<float>(Sleef_copysignfx_sve(values, sign));},
|
| 173 |
+
{
|
| 174 |
+
__at_align__ float tmp[size()];
|
| 175 |
+
__at_align__ float tmp_sign[size()];
|
| 176 |
+
store(tmp);
|
| 177 |
+
sign.store(tmp_sign);
|
| 178 |
+
for (int64_t i = 0; i < size(); ++i) {
|
| 179 |
+
tmp[i] = std::copysign(tmp[i], tmp_sign[i]);
|
| 180 |
+
}
|
| 181 |
+
return loadu(tmp);
|
| 182 |
+
})
|
| 183 |
+
}
|
| 184 |
+
Vectorized<float> erf() const {
|
| 185 |
+
return USE_SLEEF(Vectorized<float>(Sleef_erffx_u10sve(values)),map(std::erf));
|
| 186 |
+
}
|
| 187 |
+
Vectorized<float> erfc() const {
|
| 188 |
+
return USE_SLEEF(Vectorized<float>(Sleef_erfcfx_u15sve(values)),map(std::erfc));
|
| 189 |
+
}
|
| 190 |
+
Vectorized<float> erfinv() const {
|
| 191 |
+
return map(calc_erfinv);
|
| 192 |
+
}
|
| 193 |
+
Vectorized<float> exp() const {
|
| 194 |
+
return USE_SLEEF(Vectorized<float>(Sleef_expfx_u10sve(values)),map(std::exp));
|
| 195 |
+
}
|
| 196 |
+
Vectorized<float> exp2() const {
|
| 197 |
+
return USE_SLEEF(Vectorized<float>(Sleef_exp2fx_u10sve(values)),map(std::exp2));
|
| 198 |
+
}
|
| 199 |
+
Vectorized<float> expm1() const {
|
| 200 |
+
return USE_SLEEF(Vectorized<float>(Sleef_expm1fx_u10sve(values)),map(std::expm1));
|
| 201 |
+
}
|
| 202 |
+
Vectorized<float> exp_u20() const {
|
| 203 |
+
return exp();
|
| 204 |
+
}
|
| 205 |
+
Vectorized<float> fmod(const Vectorized<float>& q) const {
|
| 206 |
+
USE_SLEEF({return Vectorized<float>(Sleef_fmodfx_sve(values, q));},
|
| 207 |
+
{
|
| 208 |
+
__at_align__ float tmp[size()];
|
| 209 |
+
__at_align__ float tmp_q[size()];
|
| 210 |
+
store(tmp);
|
| 211 |
+
q.store(tmp_q);
|
| 212 |
+
for (int64_t i = 0; i < size(); ++i) {
|
| 213 |
+
tmp[i] = std::fmod(tmp[i], tmp_q[i]);
|
| 214 |
+
}
|
| 215 |
+
return loadu(tmp);
|
| 216 |
+
})
|
| 217 |
+
}
|
| 218 |
+
Vectorized<float> hypot(const Vectorized<float> &b) const {
|
| 219 |
+
USE_SLEEF( {return Vectorized<float>(Sleef_hypotfx_u05sve(values, b));},
|
| 220 |
+
{
|
| 221 |
+
__at_align__ float tmp[size()];
|
| 222 |
+
__at_align__ float tmp_b[size()];
|
| 223 |
+
store(tmp);
|
| 224 |
+
b.store(tmp_b);
|
| 225 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 226 |
+
tmp[i] = std::hypot(tmp[i], tmp_b[i]);
|
| 227 |
+
}
|
| 228 |
+
return loadu(tmp);
|
| 229 |
+
}
|
| 230 |
+
)
|
| 231 |
+
}
|
| 232 |
+
Vectorized<float> i0() const {
|
| 233 |
+
return map(calc_i0);
|
| 234 |
+
}
|
| 235 |
+
Vectorized<float> i0e() const {
|
| 236 |
+
return map(calc_i0e);
|
| 237 |
+
}
|
| 238 |
+
Vectorized<float> digamma() const {
|
| 239 |
+
return map(calc_digamma);
|
| 240 |
+
}
|
| 241 |
+
Vectorized<float> igamma(const Vectorized<float> &x) const {
|
| 242 |
+
__at_align__ float tmp[size()];
|
| 243 |
+
__at_align__ float tmp_x[size()];
|
| 244 |
+
store(tmp);
|
| 245 |
+
x.store(tmp_x);
|
| 246 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 247 |
+
tmp[i] = calc_igamma(tmp[i], tmp_x[i]);
|
| 248 |
+
}
|
| 249 |
+
return loadu(tmp);
|
| 250 |
+
}
|
| 251 |
+
Vectorized<float> igammac(const Vectorized<float> &x) const {
|
| 252 |
+
__at_align__ float tmp[size()];
|
| 253 |
+
__at_align__ float tmp_x[size()];
|
| 254 |
+
store(tmp);
|
| 255 |
+
x.store(tmp_x);
|
| 256 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 257 |
+
tmp[i] = calc_igammac(tmp[i], tmp_x[i]);
|
| 258 |
+
}
|
| 259 |
+
return loadu(tmp);
|
| 260 |
+
}
|
| 261 |
+
Vectorized<float> nextafter(const Vectorized<float> &b) const {
|
| 262 |
+
USE_SLEEF(
|
| 263 |
+
{
|
| 264 |
+
return Vectorized<float>(Sleef_nextafterfx_sve(values, b));
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
__at_align__ float tmp[size()];
|
| 268 |
+
__at_align__ float tmp_b[size()];
|
| 269 |
+
store(tmp);
|
| 270 |
+
b.store(tmp_b);
|
| 271 |
+
for (int64_t i = 0; i < size(); ++i) {
|
| 272 |
+
tmp[i] = std::nextafter(tmp[i], tmp_b[i]);
|
| 273 |
+
}
|
| 274 |
+
return loadu(tmp);
|
| 275 |
+
}
|
| 276 |
+
)
|
| 277 |
+
}
|
| 278 |
+
Vectorized<float> log() const {
|
| 279 |
+
return USE_SLEEF(Vectorized<float>(Sleef_logfx_u10sve(values)),map(std::log));
|
| 280 |
+
}
|
| 281 |
+
Vectorized<float> log2() const {
|
| 282 |
+
return USE_SLEEF(Vectorized<float>(Sleef_log2fx_u10sve(values)),map(std::log2));
|
| 283 |
+
}
|
| 284 |
+
Vectorized<float> log10() const {
|
| 285 |
+
return USE_SLEEF(Vectorized<float>(Sleef_log10fx_u10sve(values)),map(std::log10));
|
| 286 |
+
}
|
| 287 |
+
Vectorized<float> log1p() const {
|
| 288 |
+
return USE_SLEEF(Vectorized<float>(Sleef_log1pfx_u10sve(values)),map(std::log1p));
|
| 289 |
+
}
|
| 290 |
+
Vectorized<float> frac() const;
|
| 291 |
+
Vectorized<float> sin() const {
|
| 292 |
+
return USE_SLEEF(Vectorized<float>(Sleef_sinfx_u10sve(values)),map(std::sin));
|
| 293 |
+
}
|
| 294 |
+
Vectorized<float> sinh() const {
|
| 295 |
+
return USE_SLEEF(Vectorized<float>(Sleef_sinhfx_u10sve(values)),map(std::sinh));
|
| 296 |
+
}
|
| 297 |
+
Vectorized<float> cos() const {
|
| 298 |
+
return USE_SLEEF(Vectorized<float>(Sleef_cosfx_u10sve(values)),map(std::cos));
|
| 299 |
+
}
|
| 300 |
+
Vectorized<float> cosh() const {
|
| 301 |
+
return USE_SLEEF(Vectorized<float>(Sleef_coshfx_u10sve(values)),map(std::cosh));
|
| 302 |
+
}
|
| 303 |
+
Vectorized<float> ceil() const {
|
| 304 |
+
return svrintp_f32_x(ptrue, values);
|
| 305 |
+
}
|
| 306 |
+
Vectorized<float> floor() const {
|
| 307 |
+
return svrintm_f32_x(ptrue, values);
|
| 308 |
+
}
|
| 309 |
+
Vectorized<float> neg() const {
|
| 310 |
+
return svneg_f32_x(ptrue, values);
|
| 311 |
+
}
|
| 312 |
+
Vectorized<float> round() const {
|
| 313 |
+
return svrinti_f32_x(ptrue, values);
|
| 314 |
+
}
|
| 315 |
+
Vectorized<float> tan() const {
|
| 316 |
+
return USE_SLEEF(Vectorized<float>(Sleef_tanfx_u10sve(values)),map(std::tan));
|
| 317 |
+
}
|
| 318 |
+
Vectorized<float> tanh() const {
|
| 319 |
+
return USE_SLEEF(Vectorized<float>(Sleef_tanhfx_u10sve(values)),map(std::tanh));
|
| 320 |
+
}
|
| 321 |
+
Vectorized<float> trunc() const {
|
| 322 |
+
return svrintz_f32_x(ptrue, values);
|
| 323 |
+
}
|
| 324 |
+
Vectorized<float> lgamma() const {
|
| 325 |
+
return USE_SLEEF(Vectorized<float>(Sleef_lgammafx_u10sve(values)),map(std::lgamma));
|
| 326 |
+
}
|
| 327 |
+
Vectorized<float> sqrt() const {
|
| 328 |
+
return svsqrt_f32_x(ptrue, values);
|
| 329 |
+
}
|
| 330 |
+
Vectorized<float> reciprocal() const {
|
| 331 |
+
return svdivr_f32_x(ptrue, values, ONE_F32);
|
| 332 |
+
}
|
| 333 |
+
Vectorized<float> rsqrt() const {
|
| 334 |
+
return svdivr_f32_x(ptrue, svsqrt_f32_x(ptrue, values), ONE_F32);
|
| 335 |
+
}
|
| 336 |
+
Vectorized<float> pow(const Vectorized<float> &b) const {
|
| 337 |
+
USE_SLEEF( {return Vectorized<float>(Sleef_powfx_u10sve(values, b));},
|
| 338 |
+
{
|
| 339 |
+
__at_align__ float tmp[size()];
|
| 340 |
+
__at_align__ float tmp_b[size()];
|
| 341 |
+
store(tmp);
|
| 342 |
+
b.store(tmp_b);
|
| 343 |
+
for (int64_t i = 0; i < size(); i++) {
|
| 344 |
+
tmp[i] = std::pow(tmp[i], tmp_b[i]);
|
| 345 |
+
}
|
| 346 |
+
return loadu(tmp);
|
| 347 |
+
}
|
| 348 |
+
)
|
| 349 |
+
}
|
| 350 |
+
// Comparison using the _CMP_**_OQ predicate.
|
| 351 |
+
// `O`: get false if an operand is NaN
|
| 352 |
+
// `Q`: do not raise if an operand is NaN
|
| 353 |
+
Vectorized<float> operator==(const Vectorized<float>& other) const {
|
| 354 |
+
svbool_t mask = svcmpeq_f32(ptrue, values, other);
|
| 355 |
+
return svsel_f32(mask, ALL_F32_TRUE_MASK, ALL_F32_FALSE_MASK);
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
Vectorized<float> operator!=(const Vectorized<float>& other) const {
|
| 359 |
+
svbool_t mask = svcmpne_f32(ptrue, values, other);
|
| 360 |
+
return svsel_f32(mask, ALL_F32_TRUE_MASK, ALL_F32_FALSE_MASK);
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
Vectorized<float> operator<(const Vectorized<float>& other) const {
|
| 364 |
+
svbool_t mask = svcmplt_f32(ptrue, values, other);
|
| 365 |
+
return svsel_f32(mask, ALL_F32_TRUE_MASK, ALL_F32_FALSE_MASK);
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
Vectorized<float> operator<=(const Vectorized<float>& other) const {
|
| 369 |
+
svbool_t mask = svcmple_f32(ptrue, values, other);
|
| 370 |
+
return svsel_f32(mask, ALL_F32_TRUE_MASK, ALL_F32_FALSE_MASK);
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
Vectorized<float> operator>(const Vectorized<float>& other) const {
|
| 374 |
+
svbool_t mask = svcmpgt_f32(ptrue, values, other);
|
| 375 |
+
return svsel_f32(mask, ALL_F32_TRUE_MASK, ALL_F32_FALSE_MASK);
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
Vectorized<float> operator>=(const Vectorized<float>& other) const {
|
| 379 |
+
svbool_t mask = svcmpge_f32(ptrue, values, other);
|
| 380 |
+
return svsel_f32(mask, ALL_F32_TRUE_MASK, ALL_F32_FALSE_MASK);
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
Vectorized<float> eq(const Vectorized<float>& other) const;
|
| 384 |
+
Vectorized<float> ne(const Vectorized<float>& other) const;
|
| 385 |
+
Vectorized<float> gt(const Vectorized<float>& other) const;
|
| 386 |
+
Vectorized<float> ge(const Vectorized<float>& other) const;
|
| 387 |
+
Vectorized<float> lt(const Vectorized<float>& other) const;
|
| 388 |
+
Vectorized<float> le(const Vectorized<float>& other) const;
|
| 389 |
+
};
|
| 390 |
+
|
| 391 |
+
template <>
|
| 392 |
+
Vectorized<float> inline operator+(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 393 |
+
return svadd_f32_x(ptrue, a, b);
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
template <>
|
| 397 |
+
Vectorized<float> inline operator-(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 398 |
+
return svsub_f32_x(ptrue, a, b);
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
template <>
|
| 402 |
+
Vectorized<float> inline operator*(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 403 |
+
return svmul_f32_x(ptrue, a, b);
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
template <>
|
| 407 |
+
Vectorized<float> inline operator/(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 408 |
+
return svdiv_f32_x(ptrue, a, b);
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
// frac. Implement this here so we can use subtraction
|
| 412 |
+
Vectorized<float> inline Vectorized<float>::frac() const {
|
| 413 |
+
return *this - this->trunc();
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 417 |
+
// either input is a NaN.
|
| 418 |
+
template <>
|
| 419 |
+
Vectorized<float> inline maximum(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 420 |
+
return svmax_f32_x(ptrue, a, b);
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 424 |
+
// either input is a NaN.
|
| 425 |
+
template <>
|
| 426 |
+
Vectorized<float> inline minimum(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 427 |
+
return svmin_f32_x(ptrue, a, b);
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
template <>
|
| 431 |
+
Vectorized<float> inline clamp(const Vectorized<float>& a, const Vectorized<float>& min, const Vectorized<float>& max) {
|
| 432 |
+
return svmin_f32_x(ptrue, max, svmax_f32_x(ptrue, min, a));
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
template <>
|
| 436 |
+
Vectorized<float> inline clamp_max(const Vectorized<float>& a, const Vectorized<float>& max) {
|
| 437 |
+
return svmin_f32_x(ptrue, max, a);
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
template <>
|
| 441 |
+
Vectorized<float> inline clamp_min(const Vectorized<float>& a, const Vectorized<float>& min) {
|
| 442 |
+
return svmax_f32_x(ptrue, min, a);
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
template <>
|
| 446 |
+
Vectorized<float> inline operator&(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 447 |
+
return svreinterpret_f32_s32(svand_s32_x(ptrue, svreinterpret_s32_f32(a), svreinterpret_s32_f32(b)));
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
template <>
|
| 451 |
+
Vectorized<float> inline operator|(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 452 |
+
return svreinterpret_f32_s32(svorr_s32_x(ptrue, svreinterpret_s32_f32(a), svreinterpret_s32_f32(b)));
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
template <>
|
| 456 |
+
Vectorized<float> inline operator^(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 457 |
+
return svreinterpret_f32_s32(sveor_s32_x(ptrue, svreinterpret_s32_f32(a), svreinterpret_s32_f32(b)));
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
Vectorized<float> inline Vectorized<float>::eq(const Vectorized<float>& other) const {
|
| 461 |
+
return (*this == other) & Vectorized<float>(1.0f);
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
Vectorized<float> inline Vectorized<float>::ne(const Vectorized<float>& other) const {
|
| 465 |
+
return (*this != other) & Vectorized<float>(1.0f);
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
Vectorized<float> inline Vectorized<float>::gt(const Vectorized<float>& other) const {
|
| 469 |
+
return (*this > other) & Vectorized<float>(1.0f);
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
Vectorized<float> inline Vectorized<float>::ge(const Vectorized<float>& other) const {
|
| 473 |
+
return (*this >= other) & Vectorized<float>(1.0f);
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
Vectorized<float> inline Vectorized<float>::lt(const Vectorized<float>& other) const {
|
| 477 |
+
return (*this < other) & Vectorized<float>(1.0f);
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
Vectorized<float> inline Vectorized<float>::le(const Vectorized<float>& other) const {
|
| 481 |
+
return (*this <= other) & Vectorized<float>(1.0f);
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
template <>
|
| 485 |
+
inline void convert(const float* src, float* dst, int64_t n) {
|
| 486 |
+
const int64_t fraction = n % Vectorized<float>::size();
|
| 487 |
+
#pragma unroll
|
| 488 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<float>::size()) {
|
| 489 |
+
svst1_f32(ptrue, dst + i, svldnt1_f32(ptrue, src + i));
|
| 490 |
+
}
|
| 491 |
+
#pragma unroll
|
| 492 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<float>::size()) {
|
| 493 |
+
svbool_t pg = svwhilelt_b32(i, n);
|
| 494 |
+
svst1_f32(pg, dst + i, svldnt1_f32(pg, src + i));
|
| 495 |
+
}
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
template <>
|
| 499 |
+
inline void convert(const float *src, at::Half *dst, int64_t n) {
|
| 500 |
+
const int64_t fraction = n % Vectorized<float>::size();
|
| 501 |
+
svbool_t pg_16 = svwhilelt_b16(0ull, Vectorized<float>::size());
|
| 502 |
+
svbool_t pg_32 = svwhilelt_b32(0ull, Vectorized<float>::size());
|
| 503 |
+
#pragma unroll
|
| 504 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<float>::size()) {
|
| 505 |
+
svfloat16_t src_vec = svuzp1_f16(svcvt_f16_f32_x(ptrue, svldnt1_f32(pg_32, src + i)),
|
| 506 |
+
ZERO_F16);
|
| 507 |
+
svst1_f16(pg_16, reinterpret_cast<float16_t*>(dst) + i, src_vec);
|
| 508 |
+
}
|
| 509 |
+
#pragma unroll
|
| 510 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<float>::size()) {
|
| 511 |
+
pg_16 = svwhilelt_b16(i, n);
|
| 512 |
+
pg_32 = svwhilelt_b32(i, n);
|
| 513 |
+
svfloat16_t src_vec = svuzp1_f16(svcvt_f16_f32_x(ptrue, svldnt1_f32(pg_32, src + i)),
|
| 514 |
+
ZERO_F16);
|
| 515 |
+
svst1_f16(pg_16, reinterpret_cast<float16_t*>(dst) + i, src_vec);
|
| 516 |
+
}
|
| 517 |
+
}
|
| 518 |
+
|
| 519 |
+
template <>
|
| 520 |
+
inline void convert(const at::Half *src, float *dst, int64_t n) {
|
| 521 |
+
const int64_t fraction = n % Vectorized<float>::size();
|
| 522 |
+
svbool_t pg_16 = svwhilelt_b16(0ull, Vectorized<float>::size());
|
| 523 |
+
svbool_t pg_32 = svwhilelt_b32(0ull, Vectorized<float>::size());
|
| 524 |
+
#pragma unroll
|
| 525 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<float>::size()) {
|
| 526 |
+
svfloat16_t src_vec = svzip1_f16(svldnt1_f16(pg_16, reinterpret_cast<const float16_t*>(src) + i),
|
| 527 |
+
ZERO_F16);
|
| 528 |
+
svst1_f32(pg_32, dst + i, svcvt_f32_f16_x(ptrue, src_vec));
|
| 529 |
+
}
|
| 530 |
+
#pragma unroll
|
| 531 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<float>::size()) {
|
| 532 |
+
pg_16 = svwhilelt_b16(i, n);
|
| 533 |
+
pg_32 = svwhilelt_b32(i, n);
|
| 534 |
+
svfloat16_t src_vec = svzip1_f16(svldnt1_f16(pg_16, reinterpret_cast<const float16_t*>(src) + i),
|
| 535 |
+
ZERO_F16);
|
| 536 |
+
svst1_f32(pg_32, dst + i, svcvt_f32_f16_x(ptrue, src_vec));
|
| 537 |
+
}
|
| 538 |
+
}
|
| 539 |
+
|
| 540 |
+
template <>
|
| 541 |
+
inline void convert(const bool *src, float *dst, int64_t n) {
|
| 542 |
+
const int64_t fraction = n % Vectorized<float>::size();
|
| 543 |
+
svbool_t pg_8 = svwhilelt_b8(0ull, Vectorized<float>::size());
|
| 544 |
+
svbool_t pg_32 = svwhilelt_b32(0ull, Vectorized<float>::size());
|
| 545 |
+
#pragma unroll
|
| 546 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<float>::size()) {
|
| 547 |
+
svuint8_t src_vec_u8 = svldnt1_u8(pg_8, reinterpret_cast<const uint8_t*>(src) + i);
|
| 548 |
+
svuint32_t src_vec_u32 = svunpklo_u32(svunpklo_u16(src_vec_u8));
|
| 549 |
+
svbool_t mask = svcmpne_u32(pg_32, src_vec_u32, ZERO_U32);
|
| 550 |
+
svst1_f32(pg_32, dst + i, svsel_f32(mask, ONE_F32, ZERO_F32));
|
| 551 |
+
}
|
| 552 |
+
#pragma unroll
|
| 553 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<float>::size()) {
|
| 554 |
+
pg_8 = svwhilelt_b8(i, n);
|
| 555 |
+
pg_32 = svwhilelt_b32(i, n);
|
| 556 |
+
svuint8_t src_vec_u8 = svldnt1_u8(pg_8, reinterpret_cast<const uint8_t*>(src) + i);
|
| 557 |
+
svuint32_t src_vec_u32 = svunpklo_u32(svunpklo_u16(src_vec_u8));
|
| 558 |
+
svbool_t mask = svcmpne_u32(pg_32, src_vec_u32, ZERO_U32);
|
| 559 |
+
svst1_f32(pg_32, dst + i, svsel_f32(mask, ONE_F32, ZERO_F32));
|
| 560 |
+
}
|
| 561 |
+
}
|
| 562 |
+
|
| 563 |
+
template <>
|
| 564 |
+
Vectorized<float> inline fmadd(const Vectorized<float>& a, const Vectorized<float>& b, const Vectorized<float>& c) {
|
| 565 |
+
return svmad_f32_x(ptrue, a, b, c);
|
| 566 |
+
}
|
| 567 |
+
|
| 568 |
+
#endif // defined(CPU_CAPABILITY_SVE)
|
| 569 |
+
|
| 570 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_int.h
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/sve/sve_helper.h>
|
| 6 |
+
|
| 7 |
+
namespace at {
|
| 8 |
+
namespace vec {
|
| 9 |
+
// Note [CPU_CAPABILITY namespace]
|
| 10 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 11 |
+
// This header, and all of its subheaders, will be compiled with
|
| 12 |
+
// different architecture flags for each supported set of vector
|
| 13 |
+
// intrinsics. So we need to make sure they aren't inadvertently
|
| 14 |
+
// linked together. We do this by declaring objects in an `inline
|
| 15 |
+
// namespace` which changes the name mangling, but can still be
|
| 16 |
+
// accessed as `at::vec`.
|
| 17 |
+
inline namespace CPU_CAPABILITY {
|
| 18 |
+
|
| 19 |
+
#if defined(CPU_CAPABILITY_SVE)
|
| 20 |
+
|
| 21 |
+
#define VEC_INT_SVE_TEMPLATE(vl, bit) \
|
| 22 |
+
template <> class Vectorized<int##bit##_t> { \
|
| 23 |
+
private: \
|
| 24 |
+
vls_int##bit##_t values; \
|
| 25 |
+
public: \
|
| 26 |
+
using value_type = int##bit##_t; \
|
| 27 |
+
using size_type = int; \
|
| 28 |
+
static constexpr size_type size() { \
|
| 29 |
+
return vl; \
|
| 30 |
+
} \
|
| 31 |
+
Vectorized() {} \
|
| 32 |
+
Vectorized(svint##bit##_t v) : values(v) {} \
|
| 33 |
+
Vectorized(int##bit##_t val) { \
|
| 34 |
+
values = svdup_n_s##bit(val); \
|
| 35 |
+
} \
|
| 36 |
+
template<typename... Args, \
|
| 37 |
+
typename = std::enable_if_t<(sizeof...(Args) == size())>> \
|
| 38 |
+
Vectorized(Args... vals) { \
|
| 39 |
+
__at_align__ int##bit##_t buffer[size()] = { vals... }; \
|
| 40 |
+
values = svld1_s##bit(ptrue, buffer); \
|
| 41 |
+
} \
|
| 42 |
+
operator svint##bit##_t() const { \
|
| 43 |
+
return values; \
|
| 44 |
+
} \
|
| 45 |
+
static Vectorized<int##bit##_t> blendv(const Vectorized<int##bit##_t>& a, \
|
| 46 |
+
const Vectorized<int##bit##_t>& b, \
|
| 47 |
+
const Vectorized<int##bit##_t>& mask_) { \
|
| 48 |
+
svbool_t mask = svcmpeq_s##bit(ptrue, mask_, ALL_S##bit##_TRUE_MASK); \
|
| 49 |
+
return svsel_s##bit(mask, b, a); \
|
| 50 |
+
} \
|
| 51 |
+
/* step sometimes requires a higher precision type (e.g., T=int, step_t=double) */ \
|
| 52 |
+
template <typename step_t> \
|
| 53 |
+
static Vectorized<int##bit##_t> arange(int##bit##_t base = 0, step_t step = static_cast<step_t>(1)) { \
|
| 54 |
+
__at_align__ int##bit##_t buffer[size()]; \
|
| 55 |
+
for (int64_t i = 0; i < size(); i++) { \
|
| 56 |
+
buffer[i] = base + i * step; \
|
| 57 |
+
} \
|
| 58 |
+
return svld1_s##bit(ptrue, buffer); \
|
| 59 |
+
} \
|
| 60 |
+
static Vectorized<int##bit##_t> set(const Vectorized<int##bit##_t>& a, \
|
| 61 |
+
const Vectorized<int##bit##_t>& b, \
|
| 62 |
+
int##bit##_t count = size()) { \
|
| 63 |
+
if (count == 0) { \
|
| 64 |
+
return a; \
|
| 65 |
+
} else if (count < size()) { \
|
| 66 |
+
return svsel_s##bit(svwhilelt_b##bit(0ull, count), b, a); \
|
| 67 |
+
} \
|
| 68 |
+
return b; \
|
| 69 |
+
} \
|
| 70 |
+
static Vectorized<int##bit##_t> loadu(const void* ptr, int64_t count = size()) { \
|
| 71 |
+
if (count == size()) \
|
| 72 |
+
return svld1_s##bit(ptrue, reinterpret_cast<const int##bit##_t*>(ptr)); \
|
| 73 |
+
svbool_t pg = svwhilelt_b##bit(0ull, count); \
|
| 74 |
+
return svld1_s##bit(pg, reinterpret_cast<const int##bit##_t*>(ptr)); \
|
| 75 |
+
} \
|
| 76 |
+
void store(void* ptr, int64_t count = size()) const { \
|
| 77 |
+
if (count == size()) { \
|
| 78 |
+
svst1_s##bit(ptrue, reinterpret_cast<int##bit##_t*>(ptr), values); \
|
| 79 |
+
} else { \
|
| 80 |
+
svbool_t pg = svwhilelt_b##bit(0ull, count); \
|
| 81 |
+
svst1_s##bit(pg, reinterpret_cast<int##bit##_t*>(ptr), values); \
|
| 82 |
+
} \
|
| 83 |
+
} \
|
| 84 |
+
const int##bit##_t& operator[](int idx) const = delete; \
|
| 85 |
+
int##bit##_t& operator[](int idx) = delete; \
|
| 86 |
+
Vectorized<int##bit##_t> abs() const { \
|
| 87 |
+
return svabs_s##bit##_x(ptrue, values); \
|
| 88 |
+
} \
|
| 89 |
+
Vectorized<int##bit##_t> real() const { \
|
| 90 |
+
return values; \
|
| 91 |
+
} \
|
| 92 |
+
Vectorized<int##bit##_t> imag() const { \
|
| 93 |
+
return svdup_n_s##bit(0); \
|
| 94 |
+
} \
|
| 95 |
+
Vectorized<int##bit##_t> conj() const { \
|
| 96 |
+
return values; \
|
| 97 |
+
} \
|
| 98 |
+
Vectorized<int##bit##_t> frac() const; \
|
| 99 |
+
Vectorized<int##bit##_t> neg() const { \
|
| 100 |
+
return svneg_s##bit##_x(ptrue, values); \
|
| 101 |
+
} \
|
| 102 |
+
Vectorized<int##bit##_t> operator==(const Vectorized<int##bit##_t>& other) const { \
|
| 103 |
+
svbool_t mask = svcmpeq_s##bit(ptrue, values, other); \
|
| 104 |
+
return svsel_s##bit(mask, ALL_S##bit##_TRUE_MASK, ALL_S##bit##_FALSE_MASK); \
|
| 105 |
+
} \
|
| 106 |
+
Vectorized<int##bit##_t> operator!=(const Vectorized<int##bit##_t>& other) const { \
|
| 107 |
+
svbool_t mask = svcmpne_s##bit(ptrue, values, other); \
|
| 108 |
+
return svsel_s##bit(mask, ALL_S##bit##_TRUE_MASK, ALL_S##bit##_FALSE_MASK); \
|
| 109 |
+
} \
|
| 110 |
+
Vectorized<int##bit##_t> operator<(const Vectorized<int##bit##_t>& other) const { \
|
| 111 |
+
svbool_t mask = svcmplt_s##bit(ptrue, values, other); \
|
| 112 |
+
return svsel_s##bit(mask, ALL_S##bit##_TRUE_MASK, ALL_S##bit##_FALSE_MASK); \
|
| 113 |
+
} \
|
| 114 |
+
Vectorized<int##bit##_t> operator<=(const Vectorized<int##bit##_t>& other) const { \
|
| 115 |
+
svbool_t mask = svcmple_s##bit(ptrue, values, other); \
|
| 116 |
+
return svsel_s##bit(mask, ALL_S##bit##_TRUE_MASK, ALL_S##bit##_FALSE_MASK); \
|
| 117 |
+
} \
|
| 118 |
+
Vectorized<int##bit##_t> operator>(const Vectorized<int##bit##_t>& other) const { \
|
| 119 |
+
svbool_t mask = svcmpgt_s##bit(ptrue, values, other); \
|
| 120 |
+
return svsel_s##bit(mask, ALL_S##bit##_TRUE_MASK, ALL_S##bit##_FALSE_MASK); \
|
| 121 |
+
} \
|
| 122 |
+
Vectorized<int##bit##_t> operator>=(const Vectorized<int##bit##_t>& other) const { \
|
| 123 |
+
svbool_t mask = svcmpge_s##bit(ptrue, values, other); \
|
| 124 |
+
return svsel_s##bit(mask, ALL_S##bit##_TRUE_MASK, ALL_S##bit##_FALSE_MASK); \
|
| 125 |
+
} \
|
| 126 |
+
Vectorized<int##bit##_t> eq(const Vectorized<int##bit##_t>& other) const; \
|
| 127 |
+
Vectorized<int##bit##_t> ne(const Vectorized<int##bit##_t>& other) const; \
|
| 128 |
+
Vectorized<int##bit##_t> gt(const Vectorized<int##bit##_t>& other) const; \
|
| 129 |
+
Vectorized<int##bit##_t> ge(const Vectorized<int##bit##_t>& other) const; \
|
| 130 |
+
Vectorized<int##bit##_t> lt(const Vectorized<int##bit##_t>& other) const; \
|
| 131 |
+
Vectorized<int##bit##_t> le(const Vectorized<int##bit##_t>& other) const; \
|
| 132 |
+
}; \
|
| 133 |
+
template <> \
|
| 134 |
+
Vectorized<int##bit##_t> inline operator+(const Vectorized<int##bit##_t>& a, \
|
| 135 |
+
const Vectorized<int##bit##_t>& b) { \
|
| 136 |
+
return svadd_s##bit##_x(ptrue, a, b); \
|
| 137 |
+
} \
|
| 138 |
+
template <> \
|
| 139 |
+
Vectorized<int##bit##_t> inline operator-(const Vectorized<int##bit##_t>& a, \
|
| 140 |
+
const Vectorized<int##bit##_t>& b) { \
|
| 141 |
+
return svsub_s##bit##_x(ptrue, a, b); \
|
| 142 |
+
} \
|
| 143 |
+
template <> \
|
| 144 |
+
Vectorized<int##bit##_t> inline operator*(const Vectorized<int##bit##_t>& a, \
|
| 145 |
+
const Vectorized<int##bit##_t>& b) { \
|
| 146 |
+
return svmul_s##bit##_x(ptrue, a, b); \
|
| 147 |
+
} \
|
| 148 |
+
template <> \
|
| 149 |
+
Vectorized<int##bit##_t> inline maximum(const Vectorized<int##bit##_t>& a, \
|
| 150 |
+
const Vectorized<int##bit##_t>& b) { \
|
| 151 |
+
return svmax_s##bit##_x(ptrue, a, b); \
|
| 152 |
+
} \
|
| 153 |
+
template <> \
|
| 154 |
+
Vectorized<int##bit##_t> inline minimum(const Vectorized<int##bit##_t>& a, \
|
| 155 |
+
const Vectorized<int##bit##_t>& b) { \
|
| 156 |
+
return svmin_s##bit##_x(ptrue, a, b); \
|
| 157 |
+
} \
|
| 158 |
+
template <> \
|
| 159 |
+
Vectorized<int##bit##_t> inline clamp(const Vectorized<int##bit##_t>& a, \
|
| 160 |
+
const Vectorized<int##bit##_t>& min, \
|
| 161 |
+
const Vectorized<int##bit##_t>& max) { \
|
| 162 |
+
return svmin_s##bit##_x(ptrue, max, svmax_s##bit##_x(ptrue, min, a)); \
|
| 163 |
+
} \
|
| 164 |
+
template <> \
|
| 165 |
+
Vectorized<int##bit##_t> inline clamp_max(const Vectorized<int##bit##_t>& a, \
|
| 166 |
+
const Vectorized<int##bit##_t>& max) { \
|
| 167 |
+
return svmin_s##bit##_x(ptrue, max, a); \
|
| 168 |
+
} \
|
| 169 |
+
template <> \
|
| 170 |
+
Vectorized<int##bit##_t> inline clamp_min(const Vectorized<int##bit##_t>& a, \
|
| 171 |
+
const Vectorized<int##bit##_t>& min) { \
|
| 172 |
+
return svmax_s##bit##_x(ptrue, min, a); \
|
| 173 |
+
} \
|
| 174 |
+
template <> \
|
| 175 |
+
Vectorized<int##bit##_t> inline operator&(const Vectorized<int##bit##_t>& a, \
|
| 176 |
+
const Vectorized<int##bit##_t>& b) { \
|
| 177 |
+
return svand_s##bit##_x(ptrue, a, b); \
|
| 178 |
+
} \
|
| 179 |
+
template <> \
|
| 180 |
+
Vectorized<int##bit##_t> inline operator|(const Vectorized<int##bit##_t>& a, \
|
| 181 |
+
const Vectorized<int##bit##_t>& b) { \
|
| 182 |
+
return svorr_s##bit##_x(ptrue, a, b); \
|
| 183 |
+
} \
|
| 184 |
+
template <> \
|
| 185 |
+
Vectorized<int##bit##_t> inline operator^(const Vectorized<int##bit##_t>& a, \
|
| 186 |
+
const Vectorized<int##bit##_t>& b) { \
|
| 187 |
+
return sveor_s##bit##_x(ptrue, a, b); \
|
| 188 |
+
} \
|
| 189 |
+
template <> \
|
| 190 |
+
inline Vectorized<int##bit##_t> operator~(const Vectorized<int##bit##_t>& a) { \
|
| 191 |
+
return sveor_s##bit##_x(ptrue, a, svdup_n_s##bit(-1)); \
|
| 192 |
+
} \
|
| 193 |
+
Vectorized<int##bit##_t> inline Vectorized<int##bit##_t>::eq(const Vectorized<int##bit##_t>& other) const { \
|
| 194 |
+
return (*this == other) & Vectorized<int##bit##_t>(1); \
|
| 195 |
+
} \
|
| 196 |
+
Vectorized<int##bit##_t> inline Vectorized<int##bit##_t>::ne(const Vectorized<int##bit##_t>& other) const { \
|
| 197 |
+
return (*this != other) & Vectorized<int##bit##_t>(1); \
|
| 198 |
+
} \
|
| 199 |
+
Vectorized<int##bit##_t> inline Vectorized<int##bit##_t>::gt(const Vectorized<int##bit##_t>& other) const { \
|
| 200 |
+
return (*this > other) & Vectorized<int##bit##_t>(1); \
|
| 201 |
+
} \
|
| 202 |
+
Vectorized<int##bit##_t> inline Vectorized<int##bit##_t>::ge(const Vectorized<int##bit##_t>& other) const { \
|
| 203 |
+
return (*this >= other) & Vectorized<int##bit##_t>(1); \
|
| 204 |
+
} \
|
| 205 |
+
Vectorized<int##bit##_t> inline Vectorized<int##bit##_t>::lt(const Vectorized<int##bit##_t>& other) const { \
|
| 206 |
+
return (*this < other) & Vectorized<int##bit##_t>(1); \
|
| 207 |
+
} \
|
| 208 |
+
Vectorized<int##bit##_t> inline Vectorized<int##bit##_t>::le(const Vectorized<int##bit##_t>& other) const { \
|
| 209 |
+
return (*this <= other) & Vectorized<int##bit##_t>(1); \
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
VEC_INT_SVE_TEMPLATE(VECTOR_WIDTH / sizeof(int64_t), 64)
|
| 213 |
+
VEC_INT_SVE_TEMPLATE(VECTOR_WIDTH / sizeof(int32_t), 32)
|
| 214 |
+
VEC_INT_SVE_TEMPLATE(VECTOR_WIDTH / sizeof(int16_t), 16)
|
| 215 |
+
VEC_INT_SVE_TEMPLATE(VECTOR_WIDTH / sizeof(int8_t), 8)
|
| 216 |
+
|
| 217 |
+
template <typename T>
|
| 218 |
+
Vectorized<T> inline intdiv_nosve(const Vectorized<T>& a, const Vectorized<T>& b) {
|
| 219 |
+
T values_a[Vectorized<T>::size()];
|
| 220 |
+
T values_b[Vectorized<T>::size()];
|
| 221 |
+
a.store(values_a);
|
| 222 |
+
b.store(values_b);
|
| 223 |
+
for (int i = 0; i != Vectorized<T>::size(); i++) {
|
| 224 |
+
values_a[i] /= values_b[i];
|
| 225 |
+
}
|
| 226 |
+
return Vectorized<T>::loadu(values_a);
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
template <>
|
| 230 |
+
Vectorized<int64_t> inline operator/(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 231 |
+
return svdiv_s64_x(ptrue, a, b);
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
template <>
|
| 235 |
+
Vectorized<int32_t> inline operator/(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 236 |
+
return svdiv_s32_x(ptrue, a, b);
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
template <>
|
| 240 |
+
Vectorized<int16_t> inline operator/(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 241 |
+
return intdiv_nosve(a, b);
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
template <>
|
| 245 |
+
Vectorized<int8_t> inline operator/(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 246 |
+
return intdiv_nosve(a, b);
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
template <>
|
| 250 |
+
inline void convert(const int32_t *src, int64_t *dst, int64_t n) {
|
| 251 |
+
const int64_t fraction = n % Vectorized<int64_t>::size();
|
| 252 |
+
svbool_t pg_32 = svwhilelt_b32(0ull, Vectorized<int64_t>::size());
|
| 253 |
+
svbool_t pg_64 = svwhilelt_b64(0ull, Vectorized<int64_t>::size());
|
| 254 |
+
#pragma unroll
|
| 255 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<int64_t>::size())
|
| 256 |
+
svst1_s64(pg_64, dst + i, svunpklo_s64(svldnt1_s32(pg_32, src + i)));
|
| 257 |
+
#pragma unroll
|
| 258 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<int64_t>::size()) {
|
| 259 |
+
pg_32 = svwhilelt_b32(i, n);
|
| 260 |
+
pg_64 = svwhilelt_b64(i, n);
|
| 261 |
+
svst1_s64(pg_64, dst + i, svunpklo_s64(svldnt1_s32(pg_32, src + i)));
|
| 262 |
+
}
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
template <>
|
| 266 |
+
inline void convert(const int64_t *src, float *dst, int64_t n) {
|
| 267 |
+
const int64_t fraction = n % Vectorized<int64_t>::size();
|
| 268 |
+
svbool_t pg_32 = svwhilelt_b32(0ull, Vectorized<int64_t>::size());
|
| 269 |
+
svbool_t pg_64 = svwhilelt_b64(0ull, Vectorized<int64_t>::size());
|
| 270 |
+
#pragma unroll
|
| 271 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<int64_t>::size()) {
|
| 272 |
+
svint64_t src_vec_s64 = svldnt1_s64(pg_64, src + i);
|
| 273 |
+
svfloat32_t src_vec_f32 = svuzp1_f32(svcvt_f32_s64_x(pg_64, src_vec_s64), ZERO_F32);
|
| 274 |
+
svst1_f32(pg_32, dst + i, src_vec_f32);
|
| 275 |
+
}
|
| 276 |
+
#pragma unroll
|
| 277 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<int64_t>::size()) {
|
| 278 |
+
pg_32 = svwhilelt_b32(i, n);
|
| 279 |
+
pg_64 = svwhilelt_b64(i, n);
|
| 280 |
+
svint64_t src_vec_s64 = svldnt1_s64(pg_64, src + i);
|
| 281 |
+
svfloat32_t src_vec_f32 = svuzp1_f32(svcvt_f32_s64_x(pg_64, src_vec_s64), ZERO_F32);
|
| 282 |
+
svst1_f32(pg_32, dst + i, src_vec_f32);
|
| 283 |
+
}
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
template <>
|
| 287 |
+
inline void convert(const int32_t *src, float *dst, int64_t n) {
|
| 288 |
+
const int64_t fraction = n % Vectorized<int32_t>::size();
|
| 289 |
+
svbool_t pg = svwhilelt_b32(0ull, Vectorized<int32_t>::size());
|
| 290 |
+
#pragma unroll
|
| 291 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<int32_t>::size()) {
|
| 292 |
+
svint32_t src_vec = svldnt1_s32(pg, src + i);
|
| 293 |
+
svst1_f32(pg, dst + i, svcvt_f32_s32_x(pg, src_vec));
|
| 294 |
+
}
|
| 295 |
+
#pragma unroll
|
| 296 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<int32_t>::size()) {
|
| 297 |
+
pg = svwhilelt_b32(i, n);
|
| 298 |
+
svint32_t src_vec = svldnt1_s32(pg, src + i);
|
| 299 |
+
svst1_f32(pg, dst + i, svcvt_f32_s32_x(pg, src_vec));
|
| 300 |
+
}
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
template <>
|
| 304 |
+
inline void convert(const bool *src, int64_t *dst, int64_t n) {
|
| 305 |
+
const int64_t fraction = n % Vectorized<int64_t>::size();
|
| 306 |
+
svbool_t pg_8 = svwhilelt_b8(0ull, Vectorized<int64_t>::size());
|
| 307 |
+
svbool_t pg_64 = svwhilelt_b64(0ull, Vectorized<int64_t>::size());
|
| 308 |
+
#pragma unroll
|
| 309 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<int64_t>::size()) {
|
| 310 |
+
svuint8_t src_vec_u8 = svldnt1_u8(pg_8, reinterpret_cast<const uint8_t*>(src) + i);
|
| 311 |
+
svuint64_t src_vec_u64 = svunpklo_u64(svunpklo_u32(svunpklo_u16(src_vec_u8)));
|
| 312 |
+
svbool_t mask = svcmpne_u64(pg_64, src_vec_u64, ZERO_U64);
|
| 313 |
+
svst1_s64(pg_64, dst + i, svsel_s64(mask, ONE_S64, ZERO_S64));
|
| 314 |
+
}
|
| 315 |
+
#pragma unroll
|
| 316 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<int64_t>::size()) {
|
| 317 |
+
pg_8 = svwhilelt_b8(i, n);
|
| 318 |
+
pg_64 = svwhilelt_b64(i, n);
|
| 319 |
+
svuint8_t src_vec_u8 = svldnt1_u8(pg_8, reinterpret_cast<const uint8_t*>(src) + i);
|
| 320 |
+
svuint64_t src_vec_u64 = svunpklo_u64(svunpklo_u32(svunpklo_u16(src_vec_u8)));
|
| 321 |
+
svbool_t mask = svcmpne_u64(pg_64, src_vec_u64, ZERO_U64);
|
| 322 |
+
svst1_s64(pg_64, dst + i, svsel_s64(mask, ONE_S64, ZERO_S64));
|
| 323 |
+
}
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
+
template <>
|
| 327 |
+
inline void convert(const bool *src, int32_t *dst, int64_t n) {
|
| 328 |
+
const int64_t fraction = n % Vectorized<int32_t>::size();
|
| 329 |
+
svbool_t pg_8 = svwhilelt_b8(0ull, Vectorized<int32_t>::size());
|
| 330 |
+
svbool_t pg_32 = svwhilelt_b32(0ull, Vectorized<int32_t>::size());
|
| 331 |
+
#pragma unroll
|
| 332 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<int32_t>::size()) {
|
| 333 |
+
svuint8_t src_vec_u8 = svldnt1_u8(pg_8, reinterpret_cast<const uint8_t*>(src) + i);
|
| 334 |
+
svuint32_t src_vec_u32 = svunpklo_u32(svunpklo_u16(src_vec_u8));
|
| 335 |
+
svbool_t mask = svcmpne_u32(pg_32, src_vec_u32, ZERO_U32);
|
| 336 |
+
svst1_s32(pg_32, dst + i, svsel_s32(mask, ONE_S32, ZERO_S32));
|
| 337 |
+
}
|
| 338 |
+
#pragma unroll
|
| 339 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<int32_t>::size()) {
|
| 340 |
+
pg_8 = svwhilelt_b8(i, n);
|
| 341 |
+
pg_32 = svwhilelt_b32(i, n);
|
| 342 |
+
svuint8_t src_vec_u8 = svldnt1_u8(pg_8, reinterpret_cast<const uint8_t*>(src) + i);
|
| 343 |
+
svuint32_t src_vec_u32 = svunpklo_u32(svunpklo_u16(src_vec_u8));
|
| 344 |
+
svbool_t mask = svcmpne_u32(pg_32, src_vec_u32, ZERO_U32);
|
| 345 |
+
svst1_s32(pg_32, dst + i, svsel_s32(mask, ONE_S32, ZERO_S32));
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
template <>
|
| 350 |
+
inline void convert(const uint8_t *src, bool *dst, int64_t n) {
|
| 351 |
+
const int64_t fraction = n % Vectorized<uint8_t>::size();
|
| 352 |
+
svbool_t pg = svwhilelt_b8(0ull, Vectorized<uint8_t>::size());
|
| 353 |
+
#pragma unroll
|
| 354 |
+
for (int64_t i = 0; i < n - fraction; i += Vectorized<uint8_t>::size()) {
|
| 355 |
+
svbool_t mask = svcmpne_u8(pg, svldnt1_u8(pg, src + i), ZERO_U8);
|
| 356 |
+
svst1_u8(pg, reinterpret_cast<uint8_t*>(dst) + i,
|
| 357 |
+
svsel_u8(mask, ALL_U8_TRUE_MASK, ALL_U8_FALSE_MASK));
|
| 358 |
+
}
|
| 359 |
+
#pragma unroll
|
| 360 |
+
for (int64_t i = n - fraction; i < n; i += Vectorized<uint8_t>::size()) {
|
| 361 |
+
pg = svwhilelt_b8(i, n);
|
| 362 |
+
svbool_t mask = svcmpne_u8(pg, svldnt1_u8(pg, src + i), ZERO_U8);
|
| 363 |
+
svst1_u8(pg, reinterpret_cast<uint8_t*>(dst) + i,
|
| 364 |
+
svsel_u8(mask, ALL_U8_TRUE_MASK, ALL_U8_FALSE_MASK));
|
| 365 |
+
}
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
template <>
|
| 369 |
+
Vectorized<int64_t> inline operator<<(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 370 |
+
return svlsl_s64_x(ptrue, a, svreinterpret_u64_s64(b));
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
template <>
|
| 374 |
+
Vectorized<int32_t> inline operator<<(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 375 |
+
return svlsl_s32_x(ptrue, a, svreinterpret_u32_s32(b));
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
template <>
|
| 379 |
+
Vectorized<int16_t> inline operator<<(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 380 |
+
return svlsl_s16_x(ptrue, a, svreinterpret_u16_s16(b));
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
template <>
|
| 384 |
+
Vectorized<int8_t> inline operator<<(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 385 |
+
return svlsl_s8_x(ptrue, a, svreinterpret_u8_s8(b));
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
template <>
|
| 389 |
+
Vectorized<int64_t> inline operator>>(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 390 |
+
return svasr_s64_x(ptrue, a, svreinterpret_u64_s64(b));
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
template <>
|
| 394 |
+
Vectorized<int32_t> inline operator>>(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 395 |
+
return svasr_s32_x(ptrue, a, svreinterpret_u32_s32(b));
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
template <>
|
| 399 |
+
Vectorized<int16_t> inline operator>>(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 400 |
+
return svasr_s16_x(ptrue, a, svreinterpret_u16_s16(b));
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
template <>
|
| 404 |
+
Vectorized<int8_t> inline operator>>(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 405 |
+
return svasr_s8_x(ptrue, a, svreinterpret_u8_s8(b));
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
#endif // defined(CPU_CAPABILITY_SVE)
|
| 409 |
+
|
| 410 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_qint.h
ADDED
|
@@ -0,0 +1,567 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with SVE]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <ATen/native/quantized/AffineQuantizerBase.h>
|
| 9 |
+
#include <c10/util/qint32.h>
|
| 10 |
+
#include <c10/util/qint8.h>
|
| 11 |
+
#include <c10/util/quint8.h>
|
| 12 |
+
|
| 13 |
+
#include <array>
|
| 14 |
+
|
| 15 |
+
// This file defines Vectorized<> for the quantized types.
|
| 16 |
+
//
|
| 17 |
+
//
|
| 18 |
+
// Currently, we simply use these classes as efficient converters between
|
| 19 |
+
// the quantized types and Vectorized<float>, usually in bandwidth-bound cases
|
| 20 |
+
// where doing the arithmetic in full-precision is acceptable (e.g.
|
| 21 |
+
// elementwise operators).
|
| 22 |
+
//
|
| 23 |
+
//
|
| 24 |
+
// Conversions are as follows:
|
| 25 |
+
// Vectorized<qint8> -> 4x Vectorized<float>
|
| 26 |
+
// Vectorized<quint8> -> 4x Vectorized<float>
|
| 27 |
+
// Vectorized<qint32> -> 1x Vectorized<float>
|
| 28 |
+
//
|
| 29 |
+
// The size of the returned float vector is specified by the special
|
| 30 |
+
// constexpr function float_num_vecs. The type of the value returned
|
| 31 |
+
// from dequantize (and expected as an argument to quantize) is
|
| 32 |
+
// specified by float_vec_return_type.
|
| 33 |
+
//
|
| 34 |
+
// When writing kernels with these vectors, it is expected that floating-
|
| 35 |
+
// point operations will be carried out in a loop over Vectorized<T>::float_num_vecs
|
| 36 |
+
// iterations.
|
| 37 |
+
|
| 38 |
+
namespace at {
|
| 39 |
+
namespace vec {
|
| 40 |
+
// Note [CPU_CAPABILITY namespace]
|
| 41 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 42 |
+
// This header, and all of its subheaders, will be compiled with
|
| 43 |
+
// different architecture flags for each supported set of vector
|
| 44 |
+
// intrinsics. So we need to make sure they aren't inadvertently
|
| 45 |
+
// linked together. We do this by declaring objects in an `inline
|
| 46 |
+
// namespace` which changes the name mangling, but can still be
|
| 47 |
+
// accessed as `at::vec`.
|
| 48 |
+
inline namespace CPU_CAPABILITY {
|
| 49 |
+
|
| 50 |
+
#if defined(CPU_CAPABILITY_SVE)
|
| 51 |
+
|
| 52 |
+
// NOTE: These are low-performance implementations that we fall back on
|
| 53 |
+
// if we are not building with SVE. This may not be an issue, because
|
| 54 |
+
// currently for quantization we assume the user has at least SVE
|
| 55 |
+
// installed, so these can simply act as a reference implementation.
|
| 56 |
+
//
|
| 57 |
+
// If in the future we relax this requirement (SVE+), we should probably
|
| 58 |
+
// revisit these implementations
|
| 59 |
+
|
| 60 |
+
template <
|
| 61 |
+
typename T,
|
| 62 |
+
typename float_vec_return_type_,
|
| 63 |
+
typename int_vec_return_type_,
|
| 64 |
+
int size_>
|
| 65 |
+
struct VectorizedQuantizedConverter {
|
| 66 |
+
using size_type = int;
|
| 67 |
+
static constexpr size_type size() {
|
| 68 |
+
return size_;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
static constexpr int float_num_vecs() {
|
| 72 |
+
return size() / Vectorized<float>::size();
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
static constexpr int int_num_vecs() {
|
| 76 |
+
return size() / Vectorized<int32_t>::size();
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
using float_vec_return_type = float_vec_return_type_;
|
| 80 |
+
using int_vec_return_type = int_vec_return_type_;
|
| 81 |
+
|
| 82 |
+
using value_type = typename T::underlying;
|
| 83 |
+
std::array<value_type, size_> vals;
|
| 84 |
+
|
| 85 |
+
VectorizedQuantizedConverter(T val) {
|
| 86 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 87 |
+
vals[i] = val.val_;
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
VectorizedQuantizedConverter(const void* ptr) {
|
| 92 |
+
memcpy(vals.data(), ptr, sizeof(value_type) * size());
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
void store(void* ptr, int count = size()) const {
|
| 96 |
+
memcpy(ptr, vals.data(), count * sizeof(value_type));
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
float_vec_return_type dequantize(
|
| 100 |
+
Vectorized<float> scale,
|
| 101 |
+
Vectorized<float> zero_point,
|
| 102 |
+
Vectorized<float> scale_zp_premul) const {
|
| 103 |
+
float_vec_return_type rv;
|
| 104 |
+
float tmp_scale[Vectorized<float>::size()];
|
| 105 |
+
float tmp_zero_point[Vectorized<float>::size()];
|
| 106 |
+
scale.store(tmp_scale);
|
| 107 |
+
zero_point.store(tmp_zero_point);
|
| 108 |
+
for (int i = 0; i < float_num_vecs(); ++i) {
|
| 109 |
+
float tmp_vals[Vectorized<float>::size()];
|
| 110 |
+
for (int j = 0; j < Vectorized<float>::size(); ++j) {
|
| 111 |
+
tmp_vals[j] =
|
| 112 |
+
at::native::dequantize_val<T>(tmp_scale[j], tmp_zero_point[j], T(vals[Vectorized<float>::size() * i + j]));
|
| 113 |
+
}
|
| 114 |
+
rv[i] = Vectorized<float>::loadu(tmp_vals);
|
| 115 |
+
}
|
| 116 |
+
return rv;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
float_vec_return_type dequantize(
|
| 120 |
+
Vectorized<float> scale,
|
| 121 |
+
Vectorized<float> zero_point) const {
|
| 122 |
+
float_vec_return_type rv;
|
| 123 |
+
float tmp_scale[Vectorized<float>::size()];
|
| 124 |
+
float tmp_zero_point[Vectorized<float>::size()];
|
| 125 |
+
scale.store(tmp_scale);
|
| 126 |
+
zero_point.store(tmp_zero_point);
|
| 127 |
+
for (int i = 0; i < float_num_vecs(); ++i) {
|
| 128 |
+
float tmp_vals[Vectorized<float>::size()];
|
| 129 |
+
for (int j = 0; j < Vectorized<float>::size(); ++j) {
|
| 130 |
+
tmp_vals[j] =
|
| 131 |
+
at::native::dequantize_val<T>(tmp_scale[j], tmp_zero_point[j], T(vals[Vectorized<float>::size() * i + j]));
|
| 132 |
+
}
|
| 133 |
+
rv[i] = Vectorized<float>::loadu(tmp_vals);
|
| 134 |
+
}
|
| 135 |
+
return rv;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
protected:
|
| 139 |
+
VectorizedQuantizedConverter() {}
|
| 140 |
+
};
|
| 141 |
+
|
| 142 |
+
template <>
|
| 143 |
+
struct Vectorized<c10::qint32> : public VectorizedQuantizedConverter<
|
| 144 |
+
c10::qint32,
|
| 145 |
+
std::array<Vectorized<float>, 1>,
|
| 146 |
+
std::array<Vectorized<c10::qint32>, 1>,
|
| 147 |
+
VECTOR_WIDTH / 4> {
|
| 148 |
+
Vectorized()
|
| 149 |
+
: VectorizedQuantizedConverter<
|
| 150 |
+
c10::qint32,
|
| 151 |
+
std::array<Vectorized<float>, 1>,
|
| 152 |
+
std::array<Vectorized<c10::qint32>, 1>,
|
| 153 |
+
VECTOR_WIDTH / 4>() {}
|
| 154 |
+
Vectorized(c10::qint32 val)
|
| 155 |
+
: VectorizedQuantizedConverter<
|
| 156 |
+
c10::qint32,
|
| 157 |
+
std::array<Vectorized<float>, 1>,
|
| 158 |
+
std::array<Vectorized<c10::qint32>, 1>,
|
| 159 |
+
VECTOR_WIDTH / 4>(val) {}
|
| 160 |
+
Vectorized(const void* ptr)
|
| 161 |
+
: VectorizedQuantizedConverter<
|
| 162 |
+
c10::qint32,
|
| 163 |
+
std::array<Vectorized<float>, 1>,
|
| 164 |
+
std::array<Vectorized<c10::qint32>, 1>,
|
| 165 |
+
VECTOR_WIDTH / 4>(ptr) {}
|
| 166 |
+
#if 1
|
| 167 |
+
static Vectorized<c10::qint32> loadu(const void* ptr) {
|
| 168 |
+
return Vectorized<c10::qint32>(ptr);
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
static Vectorized<c10::qint32> loadu(const void* ptr, int64_t count) {
|
| 172 |
+
__at_align__ value_type tmp_values[size()];
|
| 173 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 174 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 175 |
+
// instructions while a loop would be compiled to one instruction.
|
| 176 |
+
for (const auto i : c10::irange(size())) {
|
| 177 |
+
tmp_values[i] = 0;
|
| 178 |
+
}
|
| 179 |
+
std::memcpy(tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 180 |
+
return loadu(tmp_values);
|
| 181 |
+
}
|
| 182 |
+
#else
|
| 183 |
+
static Vectorized<c10::qint32> loadu(const void* ptr, int64_t count = size()) {
|
| 184 |
+
if (count == size())
|
| 185 |
+
return svld1_s32(ptrue, reinterpret_cast<const int32_t*>(ptr));
|
| 186 |
+
svbool_t pg = svwhilelt_b32(0ull, count);
|
| 187 |
+
return svld1_s32(pg, reinterpret_cast<const int32_t*>(ptr));
|
| 188 |
+
}
|
| 189 |
+
#endif
|
| 190 |
+
static Vectorized<c10::qint32> quantize(
|
| 191 |
+
const float_vec_return_type& rhs,
|
| 192 |
+
float scale,
|
| 193 |
+
int32_t zero_point,
|
| 194 |
+
float inverse_scale) {
|
| 195 |
+
std::array<value_type, size()> qvals;
|
| 196 |
+
std::array<float, float_num_vecs() * Vectorized<float>::size()> float_vals;
|
| 197 |
+
|
| 198 |
+
for (int i = 0; i < float_num_vecs(); ++i) {
|
| 199 |
+
rhs[i].store(&float_vals[i * Vectorized<float>::size()], Vectorized<float>::size());
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
at::native::quantize_vec<c10::qint32, /*precision=*/32>(
|
| 203 |
+
scale,
|
| 204 |
+
zero_point,
|
| 205 |
+
float_vals.data(),
|
| 206 |
+
(c10::qint32*)qvals.data(),
|
| 207 |
+
Vectorized<float>::size() * float_num_vecs());
|
| 208 |
+
|
| 209 |
+
return Vectorized<c10::qint32>::loadu(qvals.data());
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
Vectorized<c10::qint32> maximum(Vectorized<c10::qint32> b) const {
|
| 213 |
+
Vectorized<c10::qint32> retval;
|
| 214 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 215 |
+
retval.vals[i] = std::max<value_type>(vals[i], b.vals[i]);
|
| 216 |
+
}
|
| 217 |
+
return retval;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
Vectorized<c10::qint32> minimum(Vectorized<c10::qint32> b) const {
|
| 221 |
+
Vectorized<c10::qint32> retval;
|
| 222 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 223 |
+
retval.vals[i] = std::min<value_type>(vals[i], b.vals[i]);
|
| 224 |
+
}
|
| 225 |
+
return retval;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
Vectorized<c10::qint32> relu(Vectorized<c10::qint32> zero_point) const {
|
| 229 |
+
return maximum(zero_point);
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
Vectorized<c10::qint32> relu6(
|
| 234 |
+
Vectorized<c10::qint32> zero_point,
|
| 235 |
+
Vectorized<c10::qint32> q_six) {
|
| 236 |
+
Vectorized<c10::qint32> retval;
|
| 237 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 238 |
+
retval.vals[i] = std::min<value_type>(
|
| 239 |
+
std::max<value_type>(vals[i], zero_point.vals[i]), q_six.vals[i]);
|
| 240 |
+
}
|
| 241 |
+
return retval;
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
int_vec_return_type widening_subtract(Vectorized<c10::qint32> b) const {
|
| 245 |
+
int_vec_return_type retval;
|
| 246 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 247 |
+
retval[0].vals[i] = vals[i] - b.vals[i];
|
| 248 |
+
}
|
| 249 |
+
return retval;
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
static Vectorized<c10::qint32> requantize_from_int(
|
| 253 |
+
const int_vec_return_type& inp,
|
| 254 |
+
float multiplier,
|
| 255 |
+
int32_t zero_point) {
|
| 256 |
+
Vectorized<c10::qint32> retval;
|
| 257 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 258 |
+
retval.vals[i] =
|
| 259 |
+
nearbyint(static_cast<float>(inp[0].vals[i]) * multiplier) +
|
| 260 |
+
zero_point;
|
| 261 |
+
}
|
| 262 |
+
return retval;
|
| 263 |
+
}
|
| 264 |
+
};
|
| 265 |
+
|
| 266 |
+
template <>
|
| 267 |
+
Vectorized<c10::qint32> inline maximum(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 268 |
+
return a.maximum(b);
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
template <>
|
| 272 |
+
Vectorized<c10::qint32> inline operator*(
|
| 273 |
+
const Vectorized<c10::qint32>& a,
|
| 274 |
+
const Vectorized<c10::qint32>& b) {
|
| 275 |
+
Vectorized<c10::qint32> retval;
|
| 276 |
+
for (size_t i = 0; i < std::decay_t<decltype(a)>::size(); ++i) {
|
| 277 |
+
retval.vals[i] = a.vals[i] * b.vals[i];
|
| 278 |
+
}
|
| 279 |
+
return retval;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
template <>
|
| 283 |
+
Vectorized<c10::qint32> inline operator+(
|
| 284 |
+
const Vectorized<c10::qint32>& a,
|
| 285 |
+
const Vectorized<c10::qint32>& b) {
|
| 286 |
+
Vectorized<c10::qint32> retval;
|
| 287 |
+
for (size_t i = 0; i < std::decay_t<decltype(a)>::size(); ++i) {
|
| 288 |
+
retval.vals[i] = a.vals[i] + b.vals[i];
|
| 289 |
+
}
|
| 290 |
+
return retval;
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
template <>
|
| 294 |
+
struct Vectorized<c10::qint8> : public VectorizedQuantizedConverter<
|
| 295 |
+
c10::qint8,
|
| 296 |
+
std::array<Vectorized<float>, 4>,
|
| 297 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 298 |
+
VECTOR_WIDTH> {
|
| 299 |
+
Vectorized()
|
| 300 |
+
: VectorizedQuantizedConverter<
|
| 301 |
+
c10::qint8,
|
| 302 |
+
std::array<Vectorized<float>, 4>,
|
| 303 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 304 |
+
VECTOR_WIDTH>() {}
|
| 305 |
+
Vectorized(c10::qint8 val)
|
| 306 |
+
: VectorizedQuantizedConverter<
|
| 307 |
+
c10::qint8,
|
| 308 |
+
std::array<Vectorized<float>, 4>,
|
| 309 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 310 |
+
VECTOR_WIDTH>(val) {}
|
| 311 |
+
Vectorized(const void* ptr)
|
| 312 |
+
: VectorizedQuantizedConverter<
|
| 313 |
+
c10::qint8,
|
| 314 |
+
std::array<Vectorized<float>, 4>,
|
| 315 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 316 |
+
VECTOR_WIDTH>(ptr) {}
|
| 317 |
+
|
| 318 |
+
static Vectorized<c10::qint8> loadu(const void* ptr) {
|
| 319 |
+
return Vectorized<c10::qint8>(ptr);
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
static Vectorized<c10::qint8> loadu(const void* ptr, int64_t count) {
|
| 323 |
+
__at_align__ value_type tmp_values[size()];
|
| 324 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 325 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 326 |
+
// instructions while a loop would be compiled to one instruction.
|
| 327 |
+
for (const auto i : c10::irange(size())) {
|
| 328 |
+
tmp_values[i] = 0;
|
| 329 |
+
}
|
| 330 |
+
std::memcpy(tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 331 |
+
return loadu(tmp_values);
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
static Vectorized<c10::qint8> quantize(
|
| 335 |
+
const float_vec_return_type& rhs,
|
| 336 |
+
float scale,
|
| 337 |
+
int32_t zero_point,
|
| 338 |
+
float inverse_scale) {
|
| 339 |
+
std::array<value_type, size()> qvals;
|
| 340 |
+
std::array<float, float_num_vecs() * Vectorized<float>::size()> float_vals;
|
| 341 |
+
|
| 342 |
+
for (int i = 0; i < float_num_vecs(); ++i) {
|
| 343 |
+
rhs[i].store(&float_vals[i * Vectorized<float>::size()], Vectorized<float>::size());
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
at::native::quantize_vec<c10::qint8>(
|
| 347 |
+
scale,
|
| 348 |
+
zero_point,
|
| 349 |
+
float_vals.data(),
|
| 350 |
+
(c10::qint8*)qvals.data(),
|
| 351 |
+
Vectorized<float>::size() * float_num_vecs());
|
| 352 |
+
|
| 353 |
+
return Vectorized<c10::qint8>::loadu(qvals.data());
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
Vectorized<c10::qint8> maximum(Vectorized<c10::qint8> b) const {
|
| 357 |
+
Vectorized<c10::qint8> retval;
|
| 358 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 359 |
+
retval.vals[i] = std::max<value_type>(vals[i], b.vals[i]);
|
| 360 |
+
}
|
| 361 |
+
return retval;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
Vectorized<c10::qint8> minimum(Vectorized<c10::qint8> b) const {
|
| 365 |
+
Vectorized<c10::qint8> retval;
|
| 366 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 367 |
+
retval.vals[i] = std::min<value_type>(vals[i], b.vals[i]);
|
| 368 |
+
}
|
| 369 |
+
return retval;
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
Vectorized<c10::qint8> relu(Vectorized<c10::qint8> zero_point) const {
|
| 373 |
+
return maximum(zero_point);
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
Vectorized<c10::qint8> relu6(
|
| 377 |
+
Vectorized<c10::qint8> zero_point,
|
| 378 |
+
Vectorized<c10::qint8> q_six) {
|
| 379 |
+
Vectorized<c10::qint8> retval;
|
| 380 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 381 |
+
retval.vals[i] = std::min<value_type>(
|
| 382 |
+
std::max<value_type>(vals[i], zero_point.vals[i]), q_six.vals[i]);
|
| 383 |
+
}
|
| 384 |
+
return retval;
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
int_vec_return_type widening_subtract(Vectorized<c10::qint8> b) const {
|
| 388 |
+
int_vec_return_type retval;
|
| 389 |
+
constexpr int elem_per_int_vec = size() / int_num_vecs();
|
| 390 |
+
for (size_t i = 0; i < int_num_vecs(); ++i) {
|
| 391 |
+
for (size_t j = 0; j < elem_per_int_vec; ++j) {
|
| 392 |
+
retval[i].vals[j] =
|
| 393 |
+
static_cast<int32_t>(vals[i * elem_per_int_vec + j]) -
|
| 394 |
+
static_cast<int32_t>(b.vals[i * elem_per_int_vec + j]);
|
| 395 |
+
}
|
| 396 |
+
}
|
| 397 |
+
return retval;
|
| 398 |
+
}
|
| 399 |
+
static Vectorized<c10::qint8> requantize_from_int(
|
| 400 |
+
const int_vec_return_type& inp,
|
| 401 |
+
float multiplier,
|
| 402 |
+
int32_t zero_point) {
|
| 403 |
+
constexpr int elem_per_int_vec = size() / int_num_vecs();
|
| 404 |
+
constexpr auto min_val = std::numeric_limits<value_type>::min();
|
| 405 |
+
constexpr auto max_val = std::numeric_limits<value_type>::max();
|
| 406 |
+
Vectorized<c10::qint8> retval;
|
| 407 |
+
for (size_t i = 0; i < int_num_vecs(); ++i) {
|
| 408 |
+
for (size_t j = 0; j < elem_per_int_vec; ++j) {
|
| 409 |
+
int32_t rounded =
|
| 410 |
+
nearbyint(static_cast<float>(inp[i].vals[j]) * multiplier) +
|
| 411 |
+
zero_point;
|
| 412 |
+
retval.vals[i * elem_per_int_vec + j] =
|
| 413 |
+
std::min<int32_t>(std::max<int32_t>(rounded, min_val), max_val);
|
| 414 |
+
}
|
| 415 |
+
}
|
| 416 |
+
return retval;
|
| 417 |
+
}
|
| 418 |
+
};
|
| 419 |
+
|
| 420 |
+
template <>
|
| 421 |
+
Vectorized<c10::qint8> inline maximum(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 422 |
+
return a.maximum(b);
|
| 423 |
+
}
|
| 424 |
+
|
| 425 |
+
template <>
|
| 426 |
+
struct Vectorized<c10::quint8> : public VectorizedQuantizedConverter<
|
| 427 |
+
c10::quint8,
|
| 428 |
+
std::array<Vectorized<float>, 4>,
|
| 429 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 430 |
+
VECTOR_WIDTH> {
|
| 431 |
+
Vectorized()
|
| 432 |
+
: VectorizedQuantizedConverter<
|
| 433 |
+
c10::quint8,
|
| 434 |
+
std::array<Vectorized<float>, 4>,
|
| 435 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 436 |
+
VECTOR_WIDTH>() {}
|
| 437 |
+
Vectorized(c10::quint8 val)
|
| 438 |
+
: VectorizedQuantizedConverter<
|
| 439 |
+
c10::quint8,
|
| 440 |
+
std::array<Vectorized<float>, 4>,
|
| 441 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 442 |
+
VECTOR_WIDTH>(val) {}
|
| 443 |
+
Vectorized(const void* ptr)
|
| 444 |
+
: VectorizedQuantizedConverter<
|
| 445 |
+
c10::quint8,
|
| 446 |
+
std::array<Vectorized<float>, 4>,
|
| 447 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 448 |
+
VECTOR_WIDTH>(ptr) {}
|
| 449 |
+
#if 1
|
| 450 |
+
static Vectorized<c10::quint8> loadu(const void* ptr) {
|
| 451 |
+
return Vectorized<c10::quint8>(ptr);
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
static Vectorized<c10::quint8> loadu(const void* ptr, int64_t count) {
|
| 455 |
+
__at_align__ value_type tmp_values[size()];
|
| 456 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 457 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 458 |
+
// instructions while a loop would be compiled to one instruction.
|
| 459 |
+
for (const auto i : c10::irange(size())) {
|
| 460 |
+
tmp_values[i] = 0;
|
| 461 |
+
}
|
| 462 |
+
std::memcpy(tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 463 |
+
return loadu(tmp_values);
|
| 464 |
+
}
|
| 465 |
+
#else
|
| 466 |
+
static Vectorized<c10::quint8> loadu(const void* ptr, int64_t count = size()) {
|
| 467 |
+
if (count == size())
|
| 468 |
+
return svld1_u8(ptrue, reinterpret_cast<const uint8_t*>(ptr));
|
| 469 |
+
svbool_t pg = svwhilelt_b8(0ull, count);
|
| 470 |
+
return svld1_u8(pg, reinterpret_cast<const uint8_t*>(ptr));
|
| 471 |
+
}
|
| 472 |
+
#endif
|
| 473 |
+
static Vectorized<c10::quint8> quantize(
|
| 474 |
+
const float_vec_return_type& rhs,
|
| 475 |
+
float scale,
|
| 476 |
+
int32_t zero_point,
|
| 477 |
+
float inverse_scale) {
|
| 478 |
+
std::array<value_type, size()> qvals;
|
| 479 |
+
std::array<float, float_num_vecs() * Vectorized<float>::size()> float_vals;
|
| 480 |
+
|
| 481 |
+
for (int i = 0; i < float_num_vecs(); ++i) {
|
| 482 |
+
rhs[i].store(&float_vals[i * Vectorized<float>::size()], Vectorized<float>::size());
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
at::native::quantize_vec<c10::quint8>(
|
| 486 |
+
scale,
|
| 487 |
+
zero_point,
|
| 488 |
+
float_vals.data(),
|
| 489 |
+
(c10::quint8*)qvals.data(),
|
| 490 |
+
Vectorized<float>::size() * float_num_vecs());
|
| 491 |
+
|
| 492 |
+
return Vectorized<c10::quint8>::loadu(qvals.data());
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
Vectorized<c10::quint8> maximum(Vectorized<c10::quint8> b) const {
|
| 496 |
+
Vectorized<c10::quint8> retval;
|
| 497 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 498 |
+
retval.vals[i] = std::max<value_type>(vals[i], b.vals[i]);
|
| 499 |
+
}
|
| 500 |
+
return retval;
|
| 501 |
+
}
|
| 502 |
+
|
| 503 |
+
Vectorized<c10::quint8> minimum(Vectorized<c10::quint8> b) const {
|
| 504 |
+
Vectorized<c10::quint8> retval;
|
| 505 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 506 |
+
retval.vals[i] = std::min<value_type>(vals[i], b.vals[i]);
|
| 507 |
+
}
|
| 508 |
+
return retval;
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
Vectorized<c10::quint8> relu(Vectorized<c10::quint8> zero_point) const {
|
| 512 |
+
return maximum(zero_point);
|
| 513 |
+
}
|
| 514 |
+
|
| 515 |
+
|
| 516 |
+
Vectorized<c10::quint8> relu6(
|
| 517 |
+
Vectorized<c10::quint8> zero_point,
|
| 518 |
+
Vectorized<c10::quint8> q_six) {
|
| 519 |
+
Vectorized<c10::quint8> retval;
|
| 520 |
+
for (size_t i = 0; i < size(); ++i) {
|
| 521 |
+
retval.vals[i] = std::min<value_type>(
|
| 522 |
+
std::max<value_type>(vals[i], zero_point.vals[i]), q_six.vals[i]);
|
| 523 |
+
}
|
| 524 |
+
return retval;
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
int_vec_return_type widening_subtract(Vectorized<c10::quint8> b) const {
|
| 528 |
+
int_vec_return_type retval;
|
| 529 |
+
constexpr int elem_per_int_vec = size() / int_num_vecs();
|
| 530 |
+
for (size_t i = 0; i < int_num_vecs(); ++i) {
|
| 531 |
+
for (size_t j = 0; j < elem_per_int_vec; ++j) {
|
| 532 |
+
retval[i].vals[j] =
|
| 533 |
+
static_cast<int32_t>(vals[i * elem_per_int_vec + j]) -
|
| 534 |
+
static_cast<int32_t>(b.vals[i * elem_per_int_vec + j]);
|
| 535 |
+
}
|
| 536 |
+
}
|
| 537 |
+
return retval;
|
| 538 |
+
}
|
| 539 |
+
static Vectorized<c10::quint8> requantize_from_int(
|
| 540 |
+
const int_vec_return_type& inp,
|
| 541 |
+
float multiplier,
|
| 542 |
+
int32_t zero_point) {
|
| 543 |
+
constexpr int elem_per_int_vec = size() / int_num_vecs();
|
| 544 |
+
constexpr auto min_val = std::numeric_limits<value_type>::min();
|
| 545 |
+
constexpr auto max_val = std::numeric_limits<value_type>::max();
|
| 546 |
+
Vectorized<c10::quint8> retval;
|
| 547 |
+
for (size_t i = 0; i < int_num_vecs(); ++i) {
|
| 548 |
+
for (size_t j = 0; j < elem_per_int_vec; ++j) {
|
| 549 |
+
int32_t rounded =
|
| 550 |
+
nearbyint(static_cast<float>(inp[i].vals[j]) * multiplier) +
|
| 551 |
+
zero_point;
|
| 552 |
+
retval.vals[i * elem_per_int_vec + j] =
|
| 553 |
+
std::min<int32_t>(std::max<int32_t>(rounded, min_val), max_val);
|
| 554 |
+
}
|
| 555 |
+
}
|
| 556 |
+
return retval;
|
| 557 |
+
}
|
| 558 |
+
};
|
| 559 |
+
|
| 560 |
+
template <>
|
| 561 |
+
Vectorized<c10::quint8> inline maximum(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 562 |
+
return a.maximum(b);
|
| 563 |
+
}
|
| 564 |
+
|
| 565 |
+
#endif // defined(CPU_CAPABILITY_SVE)
|
| 566 |
+
|
| 567 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec.h
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 4 |
+
#include <ATen/cpu/vec/vec512/vec512.h>
|
| 5 |
+
#else
|
| 6 |
+
#include <ATen/cpu/vec/vec128/vec128.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec256/vec256.h>
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
namespace at::vec {
|
| 11 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 12 |
+
inline namespace CPU_CAPABILITY {
|
| 13 |
+
|
| 14 |
+
inline Vectorized<bool> convert_to_bool(Vectorized<int8_t> x) {
|
| 15 |
+
__at_align__ bool buffer[x.size()];
|
| 16 |
+
x.ne(Vectorized<int8_t>(0)).store(buffer);
|
| 17 |
+
|
| 18 |
+
Vectorized<bool> ret;
|
| 19 |
+
static_assert(x.size() == ret.size());
|
| 20 |
+
std::memcpy(ret, buffer, ret.size() * sizeof(bool));
|
| 21 |
+
return ret;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
template <>
|
| 25 |
+
inline Vectorized<bool> Vectorized<bool>::loadu(const void* ptr) {
|
| 26 |
+
// See NOTE [Loading boolean values]
|
| 27 |
+
return convert_to_bool(Vectorized<int8_t>::loadu(ptr));
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
template <>
|
| 31 |
+
inline Vectorized<bool> Vectorized<bool>::loadu(const void* ptr, int64_t count) {
|
| 32 |
+
// See NOTE [Loading boolean values]
|
| 33 |
+
return convert_to_bool(Vectorized<int8_t>::loadu(ptr, count));
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
template <typename VT>
|
| 37 |
+
struct VecHoldType { using hold_type = typename VT::value_type; };
|
| 38 |
+
|
| 39 |
+
template <>
|
| 40 |
+
struct VecHoldType<Vectorized<BFloat16>> { using hold_type = BFloat16; };
|
| 41 |
+
|
| 42 |
+
template <>
|
| 43 |
+
struct VecHoldType<Vectorized<Half>> {using hold_type = Half; };
|
| 44 |
+
|
| 45 |
+
template <typename VT>
|
| 46 |
+
using vechold_type = typename VecHoldType<VT>::hold_type;
|
| 47 |
+
|
| 48 |
+
}} // namespace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128.h
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
// ARM NEON uses 128-bit vector registers.
|
| 3 |
+
|
| 4 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 5 |
+
|
| 6 |
+
#ifdef __aarch64__
|
| 7 |
+
#if !defined(CPU_CAPABILITY_SVE)
|
| 8 |
+
#include <ATen/cpu/vec/vec128/vec128_bfloat16_neon.h>
|
| 9 |
+
#include <ATen/cpu/vec/vec128/vec128_float_neon.h>
|
| 10 |
+
#include <ATen/cpu/vec/vec128/vec128_half_neon.h>
|
| 11 |
+
#endif
|
| 12 |
+
|
| 13 |
+
#include <ATen/cpu/vec/vec128/vec128_convert.h>
|
| 14 |
+
#endif
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_bfloat16_neon.h
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
#include <ATen/cpu/vec/vec128/vec128_float_neon.h>
|
| 6 |
+
#include <ATen/cpu/vec/vec128/vec128_reduced_precision_common_neon.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <c10/util/BFloat16.h>
|
| 9 |
+
#include <c10/util/bit_cast.h>
|
| 10 |
+
#include <c10/util/irange.h>
|
| 11 |
+
|
| 12 |
+
namespace at::vec {
|
| 13 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 14 |
+
inline
|
| 15 |
+
namespace CPU_CAPABILITY {
|
| 16 |
+
|
| 17 |
+
// Following vec128_half_neon.h, we only support aarch64.
|
| 18 |
+
#if !defined(C10_MOBILE) && defined(__aarch64__)
|
| 19 |
+
#ifdef __BIG_ENDIAN__
|
| 20 |
+
#error "Big endian is not supported."
|
| 21 |
+
#endif
|
| 22 |
+
|
| 23 |
+
// Unlike the float16_t family of types, bfloat16_t is not available
|
| 24 |
+
// when we're not targeting bfloat16 hardware support on some
|
| 25 |
+
// platforms (but not Mac, so we have to be careful not to shadow the
|
| 26 |
+
// definitions in case they are actually there!). (See
|
| 27 |
+
// https://godbolt.org/z/orv6e94n4 ) So, we need to handle it as
|
| 28 |
+
// uint16_t in that case.
|
| 29 |
+
#define IMPLEMENT_AT_BF16_SHIM(vec_suffix) \
|
| 30 |
+
inline at_bfloat16x4_t at_vget_low_bf16( \
|
| 31 |
+
at_bfloat16x8_t a) { \
|
| 32 |
+
return vget_low_##vec_suffix(a); \
|
| 33 |
+
} \
|
| 34 |
+
\
|
| 35 |
+
inline at_bfloat16x4_t at_vget_high_bf16( \
|
| 36 |
+
at_bfloat16x8_t a) { \
|
| 37 |
+
return vget_high_##vec_suffix(a); \
|
| 38 |
+
} \
|
| 39 |
+
\
|
| 40 |
+
inline at_bfloat16x8_t at_vcombine_bf16( \
|
| 41 |
+
at_bfloat16x4_t low, \
|
| 42 |
+
at_bfloat16x4_t high) { \
|
| 43 |
+
return vcombine_##vec_suffix(low, high); \
|
| 44 |
+
} \
|
| 45 |
+
\
|
| 46 |
+
inline at_bfloat16x8_t at_vdupq_n_bf16( \
|
| 47 |
+
at_bfloat16_t value) { \
|
| 48 |
+
return vdupq_n_##vec_suffix(value); \
|
| 49 |
+
} \
|
| 50 |
+
\
|
| 51 |
+
inline at_bfloat16x8_t at_vld1q_bf16( \
|
| 52 |
+
const at_bfloat16_t* ptr) { \
|
| 53 |
+
return vld1q_##vec_suffix(ptr); \
|
| 54 |
+
} \
|
| 55 |
+
\
|
| 56 |
+
inline void at_vst1q_bf16( \
|
| 57 |
+
at_bfloat16_t* ptr, \
|
| 58 |
+
at_bfloat16x8_t value) { \
|
| 59 |
+
vst1q_##vec_suffix(ptr, value); \
|
| 60 |
+
} \
|
| 61 |
+
\
|
| 62 |
+
template <typename T> \
|
| 63 |
+
inline at_bfloat16x8_t at_vreinterpretq_bf16_u16(T val) { \
|
| 64 |
+
if constexpr (std::is_same_v<at_bfloat16x8_t, uint16x8_t>) { \
|
| 65 |
+
return val; \
|
| 66 |
+
} else { \
|
| 67 |
+
return vreinterpretq_bf16_u16(val); \
|
| 68 |
+
} \
|
| 69 |
+
} \
|
| 70 |
+
template <typename T> \
|
| 71 |
+
inline at_bfloat16x4_t at_vreinterpret_bf16_u16(T val) { \
|
| 72 |
+
if constexpr (std::is_same_v<at_bfloat16x4_t, uint16x4_t>) { \
|
| 73 |
+
return val; \
|
| 74 |
+
} else { \
|
| 75 |
+
return vreinterpret_bf16_u16(val); \
|
| 76 |
+
} \
|
| 77 |
+
} \
|
| 78 |
+
template <typename T> \
|
| 79 |
+
inline uint16x8_t at_vreinterpretq_u16_bf16(T val) { \
|
| 80 |
+
if constexpr (std::is_same_v<at_bfloat16x8_t, uint16x8_t>) { \
|
| 81 |
+
return val; \
|
| 82 |
+
} else { \
|
| 83 |
+
return vreinterpretq_u16_bf16(val); \
|
| 84 |
+
} \
|
| 85 |
+
} \
|
| 86 |
+
template <typename T> \
|
| 87 |
+
inline uint16x4_t at_vreinterpret_u16_bf16(T val) { \
|
| 88 |
+
if constexpr (std::is_same_v<at_bfloat16x4_t, uint16x4_t>) { \
|
| 89 |
+
return val; \
|
| 90 |
+
} else { \
|
| 91 |
+
return vreinterpret_u16_bf16(val); \
|
| 92 |
+
} \
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
#ifdef __ARM_FEATURE_BF16
|
| 96 |
+
using at_bfloat16x8_t = bfloat16x8_t;
|
| 97 |
+
using at_bfloat16x4_t = bfloat16x4_t;
|
| 98 |
+
using at_bfloat16_t = bfloat16_t;
|
| 99 |
+
IMPLEMENT_AT_BF16_SHIM(bf16)
|
| 100 |
+
#define at_vsetq_lane_bf16 vsetq_lane_bf16
|
| 101 |
+
#define at_vgetq_lane_bf16 vgetq_lane_bf16
|
| 102 |
+
#else
|
| 103 |
+
using at_bfloat16x8_t = uint16x8_t;
|
| 104 |
+
using at_bfloat16x4_t = uint16x4_t;
|
| 105 |
+
using at_bfloat16_t = uint16_t;
|
| 106 |
+
IMPLEMENT_AT_BF16_SHIM(u16)
|
| 107 |
+
#define at_vsetq_lane_bf16 vsetq_lane_u16
|
| 108 |
+
#define at_vgetq_lane_bf16 vgetq_lane_u16
|
| 109 |
+
#endif // __ARM_FEATURE_BF16
|
| 110 |
+
|
| 111 |
+
template <int index, bool mask_val>
|
| 112 |
+
struct BlendBFloat16Regs {
|
| 113 |
+
static at_bfloat16x8_t impl(
|
| 114 |
+
const at_bfloat16x8_t& a,
|
| 115 |
+
const at_bfloat16x8_t& b,
|
| 116 |
+
at_bfloat16x8_t& res);
|
| 117 |
+
};
|
| 118 |
+
|
| 119 |
+
template <int index>
|
| 120 |
+
struct BlendBFloat16Regs<index, true> {
|
| 121 |
+
static at_bfloat16x8_t impl(
|
| 122 |
+
const at_bfloat16x8_t& a,
|
| 123 |
+
const at_bfloat16x8_t& b,
|
| 124 |
+
at_bfloat16x8_t& res) {
|
| 125 |
+
return at_vsetq_lane_bf16(at_vgetq_lane_bf16(b, index), res, index);
|
| 126 |
+
}
|
| 127 |
+
};
|
| 128 |
+
|
| 129 |
+
template <int index>
|
| 130 |
+
struct BlendBFloat16Regs<index, false> {
|
| 131 |
+
static at_bfloat16x8_t impl(
|
| 132 |
+
const at_bfloat16x8_t& a,
|
| 133 |
+
const at_bfloat16x8_t& b,
|
| 134 |
+
at_bfloat16x8_t& res) {
|
| 135 |
+
return at_vsetq_lane_bf16(at_vgetq_lane_bf16(a, index), res, index);
|
| 136 |
+
}
|
| 137 |
+
};
|
| 138 |
+
|
| 139 |
+
template <>
|
| 140 |
+
class Vectorized<c10::BFloat16> : public Vectorized16<at_bfloat16x8_t, c10::BFloat16, BlendBFloat16Regs, Vectorized<c10::BFloat16>> {
|
| 141 |
+
using Base = Vectorized16<at_bfloat16x8_t, c10::BFloat16, BlendBFloat16Regs, Vectorized<c10::BFloat16>>;
|
| 142 |
+
friend Base;
|
| 143 |
+
friend std::tuple<Vectorized<float>, Vectorized<float>> convert_bfloat16_float(const Vectorized<c10::BFloat16>& a);
|
| 144 |
+
friend Vectorized<c10::BFloat16> convert_float_bfloat16(const Vectorized<float>& a, const Vectorized<float>& b);
|
| 145 |
+
private:
|
| 146 |
+
Vectorized<c10::BFloat16> map2(
|
| 147 |
+
const Vectorized<c10::BFloat16>& second,
|
| 148 |
+
c10::BFloat16 (*const f)(c10::BFloat16, c10::BFloat16)) const {
|
| 149 |
+
__at_align__ c10::BFloat16 tmp_first[size()];
|
| 150 |
+
__at_align__ c10::BFloat16 tmp_second[size()];
|
| 151 |
+
store(tmp_first); // store this to tmp_first
|
| 152 |
+
second.store(tmp_second);
|
| 153 |
+
for (const auto i : c10::irange(size())) {
|
| 154 |
+
tmp_first[i] = f(tmp_first[i], tmp_second[i]);
|
| 155 |
+
}
|
| 156 |
+
return loadu(tmp_first);
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
static float32x4_t convert_f32_bf16(at_bfloat16x4_t bf16) {
|
| 160 |
+
#ifdef __ARM_FEATURE_BF16
|
| 161 |
+
return vcvt_f32_bf16(bf16);
|
| 162 |
+
#else
|
| 163 |
+
int32x4_t shift = vdupq_n_s32(16);
|
| 164 |
+
return vreinterpretq_f32_u32(vshlq_u32(vmovl_u16(bf16), shift));
|
| 165 |
+
#endif // __ARM_FEATURE_BF16
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
static at_bfloat16x4_t convert_bf16_f32(const Vectorized<float>& f32) {
|
| 169 |
+
#ifdef __ARM_FEATURE_BF16
|
| 170 |
+
return vcvt_bf16_f32(f32);
|
| 171 |
+
#else
|
| 172 |
+
static_assert(std::is_same_v<uint16x4_t, at_bfloat16x4_t>);
|
| 173 |
+
uint32x4_t as_uint32 = vreinterpretq_u32_f32(f32);
|
| 174 |
+
uint32x4_t rounding_bias = vaddq_u32(vandq_u32(vshrq_n_u32(as_uint32, 16), vdupq_n_u32(1)), vdupq_n_u32(0x7FFF));
|
| 175 |
+
at_bfloat16x4_t rounded = vshrn_n_u32(vaddq_u32(as_uint32, rounding_bias), 16);
|
| 176 |
+
const auto bf16_nan = vdup_n_u16(0x7FC0);
|
| 177 |
+
return vbsl_u16(vmovn_u32(vreinterpretq_u32_f32(f32.isnan())), bf16_nan, rounded);
|
| 178 |
+
#endif // __ARM_FEATURE_BF16
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
Vectorized<c10::BFloat16> map_with_vec_float_method(
|
| 182 |
+
Vectorized<float> (Vectorized<float>::*m)() const) const {
|
| 183 |
+
float32x4_t v00 = convert_f32_bf16(at_vget_low_bf16(values));
|
| 184 |
+
float32x4_t v01 = convert_f32_bf16(at_vget_high_bf16(values));
|
| 185 |
+
Vectorized<float> mv0 = (Vectorized<float>(v00).*m)();
|
| 186 |
+
Vectorized<float> mv1 = (Vectorized<float>(v01).*m)();
|
| 187 |
+
at_bfloat16x4_t r00 = convert_bf16_f32(mv0);
|
| 188 |
+
at_bfloat16x4_t r01 = convert_bf16_f32(mv1);
|
| 189 |
+
return Vectorized<c10::BFloat16>(at_vcombine_bf16(r00, r01));
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
Vectorized<c10::BFloat16> map2_with_vec_float_method(
|
| 193 |
+
const Vectorized<c10::BFloat16>& second,
|
| 194 |
+
Vectorized<float> (Vectorized<float>::*m)(const Vectorized<float>&)
|
| 195 |
+
const) const {
|
| 196 |
+
float32x4_t v00 = convert_f32_bf16(at_vget_low_bf16(values));
|
| 197 |
+
float32x4_t v01 = convert_f32_bf16(at_vget_high_bf16(values));
|
| 198 |
+
float32x4_t second_v00 = convert_f32_bf16(at_vget_low_bf16(second.values));
|
| 199 |
+
float32x4_t second_v01 = convert_f32_bf16(at_vget_high_bf16(second.values));
|
| 200 |
+
Vectorized<float> mv0 = (Vectorized<float>(v00).*m)(second_v00);
|
| 201 |
+
Vectorized<float> mv1 = (Vectorized<float>(v01).*m)(second_v01);
|
| 202 |
+
at_bfloat16x4_t r00 = convert_bf16_f32(mv0);
|
| 203 |
+
at_bfloat16x4_t r01 = convert_bf16_f32(mv1);
|
| 204 |
+
return Vectorized<c10::BFloat16>(at_vcombine_bf16(r00, r01));
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
Vectorized<c10::BFloat16> map2_bitmask_with_vec_float_method(
|
| 208 |
+
const Vectorized<c10::BFloat16>& second,
|
| 209 |
+
Vectorized<float> (Vectorized<float>::*m)(const Vectorized<float>&)
|
| 210 |
+
const) const {
|
| 211 |
+
float32x4_t v00 = convert_f32_bf16(at_vget_low_bf16(values));
|
| 212 |
+
float32x4_t v01 = convert_f32_bf16(at_vget_high_bf16(values));
|
| 213 |
+
float32x4_t second_v00 = convert_f32_bf16(at_vget_low_bf16(second.values));
|
| 214 |
+
float32x4_t second_v01 = convert_f32_bf16(at_vget_high_bf16(second.values));
|
| 215 |
+
Vectorized<float> mv0 = (Vectorized<float>(v00).*m)(second_v00);
|
| 216 |
+
Vectorized<float> mv1 = (Vectorized<float>(v01).*m)(second_v01);
|
| 217 |
+
// Assume the operator returns a bitmask, not "real" floats, and
|
| 218 |
+
// just narrow the bits. All-ones is a NaN and will get mangled by conversion!
|
| 219 |
+
at_bfloat16x4_t r00 = at_vreinterpret_bf16_u16(vmovn_u32(vreinterpretq_u32_f32(mv0)));
|
| 220 |
+
at_bfloat16x4_t r01 = at_vreinterpret_bf16_u16(vmovn_u32(vreinterpretq_u32_f32(mv1)));
|
| 221 |
+
return Vectorized<c10::BFloat16>(at_vcombine_bf16(r00, r01));
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
public:
|
| 225 |
+
using Vectorized16::Vectorized16;
|
| 226 |
+
|
| 227 |
+
Vectorized() = default;
|
| 228 |
+
|
| 229 |
+
Vectorized(c10::BFloat16 val) : Vectorized16(at_vdupq_n_bf16(val.x)) {}
|
| 230 |
+
Vectorized(float val) : Vectorized(c10::BFloat16(val)) {}
|
| 231 |
+
Vectorized(
|
| 232 |
+
value_type val0,
|
| 233 |
+
value_type val1,
|
| 234 |
+
value_type val2,
|
| 235 |
+
value_type val3,
|
| 236 |
+
value_type val4,
|
| 237 |
+
value_type val5,
|
| 238 |
+
value_type val6,
|
| 239 |
+
value_type val7)
|
| 240 |
+
: Vectorized16(at_bfloat16x8_t{
|
| 241 |
+
c10::bit_cast<at_bfloat16_t>(val0.x),
|
| 242 |
+
c10::bit_cast<at_bfloat16_t>(val1.x),
|
| 243 |
+
c10::bit_cast<at_bfloat16_t>(val2.x),
|
| 244 |
+
c10::bit_cast<at_bfloat16_t>(val3.x),
|
| 245 |
+
c10::bit_cast<at_bfloat16_t>(val4.x),
|
| 246 |
+
c10::bit_cast<at_bfloat16_t>(val5.x),
|
| 247 |
+
c10::bit_cast<at_bfloat16_t>(val6.x),
|
| 248 |
+
c10::bit_cast<at_bfloat16_t>(val7.x)}) {}
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
static Vectorized<c10::BFloat16> blendv(
|
| 252 |
+
const Vectorized<c10::BFloat16>& a,
|
| 253 |
+
const Vectorized<c10::BFloat16>& b,
|
| 254 |
+
const Vectorized<c10::BFloat16>& mask) {
|
| 255 |
+
// NOTE: blendv has the same problems as it does for Half; see comments in vec128_half_neon.h.
|
| 256 |
+
Vectorized<c10::BFloat16> vec(mask.values);
|
| 257 |
+
vec.values = at_vreinterpretq_bf16_u16(
|
| 258 |
+
vbslq_u16(
|
| 259 |
+
at_vreinterpretq_u16_bf16(vec.values),
|
| 260 |
+
at_vreinterpretq_u16_bf16(b.values),
|
| 261 |
+
at_vreinterpretq_u16_bf16(a.values)));
|
| 262 |
+
return vec;
|
| 263 |
+
}
|
| 264 |
+
static Vectorized<c10::BFloat16> set(
|
| 265 |
+
const Vectorized<c10::BFloat16>& a,
|
| 266 |
+
const Vectorized<c10::BFloat16>& b,
|
| 267 |
+
int64_t count = size()) {
|
| 268 |
+
uint16_t pre_mask[size()] = {0};
|
| 269 |
+
for (int i = 0; i < count; i++) {
|
| 270 |
+
pre_mask[i] = 0xFFFF;
|
| 271 |
+
}
|
| 272 |
+
uint16x8_t mask = vld1q_u16(pre_mask);
|
| 273 |
+
|
| 274 |
+
Vectorized<c10::BFloat16> vec(
|
| 275 |
+
at_vreinterpretq_bf16_u16(
|
| 276 |
+
vbslq_u16(
|
| 277 |
+
at_vreinterpretq_u16_bf16(mask),
|
| 278 |
+
at_vreinterpretq_u16_bf16(b.values),
|
| 279 |
+
at_vreinterpretq_u16_bf16(a.values))));
|
| 280 |
+
|
| 281 |
+
return vec;
|
| 282 |
+
}
|
| 283 |
+
static Vectorized<c10::BFloat16> loadu(const void* ptr, int64_t count = size()) {
|
| 284 |
+
if (count == size()) {
|
| 285 |
+
return at_vld1q_bf16(reinterpret_cast<const at_bfloat16_t*>(ptr));
|
| 286 |
+
}
|
| 287 |
+
__at_align__ at_bfloat16_t tmp_values[size()];
|
| 288 |
+
for (const auto i : c10::irange(size())) {
|
| 289 |
+
tmp_values[i] = 0;
|
| 290 |
+
}
|
| 291 |
+
std::memcpy(
|
| 292 |
+
tmp_values,
|
| 293 |
+
reinterpret_cast<const at_bfloat16_t*>(ptr),
|
| 294 |
+
count * sizeof(at_bfloat16_t));
|
| 295 |
+
return at_vld1q_bf16(reinterpret_cast<const at_bfloat16_t*>(tmp_values));
|
| 296 |
+
}
|
| 297 |
+
void store(void* ptr, int64_t count = size()) const {
|
| 298 |
+
if (count == size()) {
|
| 299 |
+
at_vst1q_bf16(reinterpret_cast<at_bfloat16_t*>(ptr), values);
|
| 300 |
+
return;
|
| 301 |
+
} else {
|
| 302 |
+
at_bfloat16_t tmp_values[size()];
|
| 303 |
+
at_vst1q_bf16(reinterpret_cast<at_bfloat16_t*>(tmp_values), values);
|
| 304 |
+
std::memcpy(ptr, tmp_values, count * sizeof(at_bfloat16_t));
|
| 305 |
+
}
|
| 306 |
+
}
|
| 307 |
+
Vectorized<c10::BFloat16> isnan() const {
|
| 308 |
+
// NOTE: we could make this faster by doing vectorized checks of
|
| 309 |
+
// exponent/payload bits.
|
| 310 |
+
__at_align__ c10::BFloat16 tmp[size()];
|
| 311 |
+
__at_align__ c10::BFloat16 res[size()];
|
| 312 |
+
store(tmp);
|
| 313 |
+
for (const auto i : c10::irange(size())) {
|
| 314 |
+
if (_isnan(tmp[i])) {
|
| 315 |
+
std::memset(static_cast<void*>(&res[i]), 0xFF, sizeof(c10::BFloat16));
|
| 316 |
+
} else {
|
| 317 |
+
std::memset(static_cast<void*>(&res[i]), 0, sizeof(c10::BFloat16));
|
| 318 |
+
}
|
| 319 |
+
}
|
| 320 |
+
return loadu(res);
|
| 321 |
+
}
|
| 322 |
+
bool has_inf_nan() const {
|
| 323 |
+
__at_align__ c10::BFloat16 tmp[size()];
|
| 324 |
+
store(tmp);
|
| 325 |
+
for (const auto i : c10::irange(size())) {
|
| 326 |
+
if (_isnan(tmp[i]) || _isinf(tmp[i])) {
|
| 327 |
+
return true;
|
| 328 |
+
}
|
| 329 |
+
}
|
| 330 |
+
return false;
|
| 331 |
+
}
|
| 332 |
+
#define DEFINE_UNARY_ELEMENTWISE_FUNC_VIA_FLOAT_METHOD(name) \
|
| 333 |
+
Vectorized name() const { \
|
| 334 |
+
return map_with_vec_float_method(&Vectorized<float>::name); \
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
#define DEFINE_BINARY_COMPARISON_OPERATOR_VIA_FLOAT_METHOD(name) \
|
| 338 |
+
Vectorized name(const Vectorized& other) const { \
|
| 339 |
+
return map2_bitmask_with_vec_float_method(other, &Vectorized<float>::name); \
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
DEFINE_UNARY_ELEMENTWISE_FUNC_VIA_FLOAT_METHOD(abs)
|
| 343 |
+
Vectorized frac() const;
|
| 344 |
+
DEFINE_UNARY_ELEMENTWISE_FUNC_VIA_FLOAT_METHOD(neg)
|
| 345 |
+
DEFINE_UNARY_ELEMENTWISE_FUNC_VIA_FLOAT_METHOD(trunc)
|
| 346 |
+
DEFINE_UNARY_ELEMENTWISE_FUNC_VIA_FLOAT_METHOD(sqrt)
|
| 347 |
+
DEFINE_UNARY_ELEMENTWISE_FUNC_VIA_FLOAT_METHOD(reciprocal)
|
| 348 |
+
DEFINE_BINARY_COMPARISON_OPERATOR_VIA_FLOAT_METHOD(operator==)
|
| 349 |
+
DEFINE_BINARY_COMPARISON_OPERATOR_VIA_FLOAT_METHOD(operator!=)
|
| 350 |
+
DEFINE_BINARY_COMPARISON_OPERATOR_VIA_FLOAT_METHOD(operator<)
|
| 351 |
+
DEFINE_BINARY_COMPARISON_OPERATOR_VIA_FLOAT_METHOD(operator<=)
|
| 352 |
+
DEFINE_BINARY_COMPARISON_OPERATOR_VIA_FLOAT_METHOD(operator>)
|
| 353 |
+
DEFINE_BINARY_COMPARISON_OPERATOR_VIA_FLOAT_METHOD(operator>=)
|
| 354 |
+
|
| 355 |
+
#undef DEFINE_UNARY_ELEMENTWISE_FUNC_VIA_FLOAT_METHOD
|
| 356 |
+
#undef DEFINE_BINARY_ELEMENTWISE_FUNC_VIA_FLOAT_METHOD
|
| 357 |
+
|
| 358 |
+
Vectorized eq(const Vectorized& other) const;
|
| 359 |
+
Vectorized ne(const Vectorized& other) const;
|
| 360 |
+
Vectorized gt(const Vectorized& other) const;
|
| 361 |
+
Vectorized ge(const Vectorized& other) const;
|
| 362 |
+
Vectorized lt(const Vectorized& other) const;
|
| 363 |
+
Vectorized le(const Vectorized& other) const;
|
| 364 |
+
}; // Vectorized<c10::BFloat16>
|
| 365 |
+
|
| 366 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_bfloat16_float(const Vectorized<c10::BFloat16>& a) {
|
| 367 |
+
static_assert(Vectorized<c10::BFloat16>::size() == 2 * Vectorized<float>::size());
|
| 368 |
+
at_bfloat16x8_t x = a;
|
| 369 |
+
float32x4_t x1 = Vectorized<c10::BFloat16>::convert_f32_bf16(at_vget_low_bf16(x));
|
| 370 |
+
float32x4_t x2 = Vectorized<c10::BFloat16>::convert_f32_bf16(at_vget_high_bf16(x));
|
| 371 |
+
return { Vectorized<float>(x1), Vectorized<float>(x2) };
|
| 372 |
+
}
|
| 373 |
+
inline Vectorized<c10::BFloat16> convert_float_bfloat16(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 374 |
+
static_assert(Vectorized<c10::BFloat16>::size() == 2 * Vectorized<float>::size());
|
| 375 |
+
at_bfloat16x4_t x1 = Vectorized<c10::BFloat16>::convert_bf16_f32(a);
|
| 376 |
+
at_bfloat16x4_t x2 = Vectorized<c10::BFloat16>::convert_bf16_f32(b);
|
| 377 |
+
return Vectorized<c10::BFloat16>(at_vcombine_bf16(x1, x2));
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
template <typename Op>
|
| 381 |
+
Vectorized<c10::BFloat16> binary_operator_via_float(
|
| 382 |
+
Op op,
|
| 383 |
+
const Vectorized<c10::BFloat16>& a,
|
| 384 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 385 |
+
const auto [a_float_low, a_float_high] = convert_bfloat16_float(a);
|
| 386 |
+
const auto [b_float_low, b_float_high] = convert_bfloat16_float(b);
|
| 387 |
+
return convert_float_bfloat16(
|
| 388 |
+
op(a_float_low, b_float_low),
|
| 389 |
+
op(a_float_high, b_float_high));
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
template <>
|
| 393 |
+
Vectorized<c10::BFloat16> inline operator+(
|
| 394 |
+
const Vectorized<c10::BFloat16>& a,
|
| 395 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 396 |
+
return binary_operator_via_float(std::plus<Vectorized<float>>(), a, b);
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
template <>
|
| 400 |
+
Vectorized<c10::BFloat16> inline operator-(
|
| 401 |
+
const Vectorized<c10::BFloat16>& a,
|
| 402 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 403 |
+
return binary_operator_via_float(std::minus<Vectorized<float>>(), a, b);
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
template <>
|
| 407 |
+
Vectorized<c10::BFloat16> inline operator*(
|
| 408 |
+
const Vectorized<c10::BFloat16>& a,
|
| 409 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 410 |
+
return binary_operator_via_float(std::multiplies<Vectorized<float>>(), a, b);
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
template <>
|
| 414 |
+
Vectorized<c10::BFloat16> inline operator/(
|
| 415 |
+
const Vectorized<c10::BFloat16>& a,
|
| 416 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 417 |
+
return binary_operator_via_float(std::divides<Vectorized<float>>(), a, b);
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
// frac. Implement this here so we can use subtraction
|
| 421 |
+
inline Vectorized<c10::BFloat16> Vectorized<c10::BFloat16>::frac() const {
|
| 422 |
+
return *this - this->trunc();
|
| 423 |
+
}
|
| 424 |
+
|
| 425 |
+
template <>
|
| 426 |
+
Vectorized<c10::BFloat16> inline maximum(
|
| 427 |
+
const Vectorized<c10::BFloat16>& a,
|
| 428 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 429 |
+
return binary_operator_via_float(
|
| 430 |
+
static_cast<Vectorized<float>(*)(const Vectorized<float>&, const Vectorized<float>&)>(&maximum),
|
| 431 |
+
a,
|
| 432 |
+
b);
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
template <>
|
| 436 |
+
Vectorized<c10::BFloat16> inline minimum(
|
| 437 |
+
const Vectorized<c10::BFloat16>& a,
|
| 438 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 439 |
+
return binary_operator_via_float(
|
| 440 |
+
static_cast<Vectorized<float>(*)(const Vectorized<float>&, const Vectorized<float>&)>(&minimum),
|
| 441 |
+
a,
|
| 442 |
+
b);
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
template <>
|
| 446 |
+
Vectorized<c10::BFloat16> inline clamp(
|
| 447 |
+
const Vectorized<c10::BFloat16>& a,
|
| 448 |
+
const Vectorized<c10::BFloat16>& min,
|
| 449 |
+
const Vectorized<c10::BFloat16>& max) {
|
| 450 |
+
return minimum(max, maximum(min, a));
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
template <>
|
| 454 |
+
Vectorized<c10::BFloat16> inline clamp_max(
|
| 455 |
+
const Vectorized<c10::BFloat16>& a,
|
| 456 |
+
const Vectorized<c10::BFloat16>& max) {
|
| 457 |
+
return minimum(max, a);
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
template <>
|
| 461 |
+
Vectorized<c10::BFloat16> inline clamp_min(
|
| 462 |
+
const Vectorized<c10::BFloat16>& a,
|
| 463 |
+
const Vectorized<c10::BFloat16>& min) {
|
| 464 |
+
return maximum(min, a);
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
template <>
|
| 468 |
+
Vectorized<c10::BFloat16> inline operator&(
|
| 469 |
+
const Vectorized<c10::BFloat16>& a,
|
| 470 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 471 |
+
return Vectorized<c10::BFloat16>(at_vreinterpretq_bf16_u16(vandq_u16(
|
| 472 |
+
at_vreinterpretq_u16_bf16(a), at_vreinterpretq_u16_bf16(b))));
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
template <>
|
| 476 |
+
Vectorized<c10::BFloat16> inline operator|(
|
| 477 |
+
const Vectorized<c10::BFloat16>& a,
|
| 478 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 479 |
+
return Vectorized<c10::BFloat16>(at_vreinterpretq_bf16_u16(vorrq_u16(
|
| 480 |
+
at_vreinterpretq_u16_bf16(a), at_vreinterpretq_u16_bf16(b))));
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
+
template <>
|
| 484 |
+
Vectorized<c10::BFloat16> inline operator^(
|
| 485 |
+
const Vectorized<c10::BFloat16>& a,
|
| 486 |
+
const Vectorized<c10::BFloat16>& b) {
|
| 487 |
+
return Vectorized<c10::BFloat16>(at_vreinterpretq_bf16_u16(veorq_u16(
|
| 488 |
+
at_vreinterpretq_u16_bf16(a), at_vreinterpretq_u16_bf16(b))));
|
| 489 |
+
}
|
| 490 |
+
|
| 491 |
+
inline Vectorized<c10::BFloat16> Vectorized<c10::BFloat16>::eq(
|
| 492 |
+
const Vectorized<c10::BFloat16>& other) const {
|
| 493 |
+
return (*this == other) & Vectorized<c10::BFloat16>(1);
|
| 494 |
+
}
|
| 495 |
+
|
| 496 |
+
inline Vectorized<c10::BFloat16> Vectorized<c10::BFloat16>::ne(
|
| 497 |
+
const Vectorized<c10::BFloat16>& other) const {
|
| 498 |
+
return (*this != other) & Vectorized<c10::BFloat16>(1);
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
inline Vectorized<c10::BFloat16> Vectorized<c10::BFloat16>::gt(
|
| 502 |
+
const Vectorized<c10::BFloat16>& other) const {
|
| 503 |
+
return (*this > other) & Vectorized<c10::BFloat16>(1);
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
inline Vectorized<c10::BFloat16> Vectorized<c10::BFloat16>::ge(
|
| 507 |
+
const Vectorized<c10::BFloat16>& other) const {
|
| 508 |
+
return (*this >= other) & Vectorized<c10::BFloat16>(1);
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
inline Vectorized<c10::BFloat16> Vectorized<c10::BFloat16>::lt(
|
| 512 |
+
const Vectorized<c10::BFloat16>& other) const {
|
| 513 |
+
return (*this < other) & Vectorized<c10::BFloat16>(1);
|
| 514 |
+
}
|
| 515 |
+
|
| 516 |
+
inline Vectorized<c10::BFloat16> Vectorized<c10::BFloat16>::le(
|
| 517 |
+
const Vectorized<c10::BFloat16>& other) const {
|
| 518 |
+
return (*this <= other) & Vectorized<c10::BFloat16>(1);
|
| 519 |
+
}
|
| 520 |
+
|
| 521 |
+
template <>
|
| 522 |
+
Vectorized<c10::BFloat16> inline fmadd(
|
| 523 |
+
const Vectorized<c10::BFloat16>& a,
|
| 524 |
+
const Vectorized<c10::BFloat16>& b,
|
| 525 |
+
const Vectorized<c10::BFloat16>& c) {
|
| 526 |
+
// NOTE [BF16 FMA]: There isn't an FMA that accumulates into BF16! Also,
|
| 527 |
+
// vbfmlalbq_f32 and vbfmlaltq_f32 take the even and odd-numbered
|
| 528 |
+
// elements, not the bottom and top half, so they don't seem
|
| 529 |
+
// particularly useful here. Ideally we would include dot product in
|
| 530 |
+
// the Vectorized interface...
|
| 531 |
+
const auto [a_float_low, a_float_high] = convert_bfloat16_float(a);
|
| 532 |
+
const auto [b_float_low, b_float_high] = convert_bfloat16_float(b);
|
| 533 |
+
const auto [c_float_low, c_float_high] = convert_bfloat16_float(c);
|
| 534 |
+
return convert_float_bfloat16(
|
| 535 |
+
fmadd(a_float_low, b_float_low, c_float_low),
|
| 536 |
+
fmadd(a_float_high, b_float_high, c_float_high));
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
template <>
|
| 540 |
+
Vectorized<c10::BFloat16> inline fmsub(
|
| 541 |
+
const Vectorized<c10::BFloat16>& a,
|
| 542 |
+
const Vectorized<c10::BFloat16>& b,
|
| 543 |
+
const Vectorized<c10::BFloat16>& c) {
|
| 544 |
+
// See NOTE [BF16 FMA] above.
|
| 545 |
+
const auto [a_float_low, a_float_high] = convert_bfloat16_float(a);
|
| 546 |
+
const auto [b_float_low, b_float_high] = convert_bfloat16_float(b);
|
| 547 |
+
const auto [c_float_low, c_float_high] = convert_bfloat16_float(c);
|
| 548 |
+
return convert_float_bfloat16(
|
| 549 |
+
fmsub(a_float_low, b_float_low, c_float_low),
|
| 550 |
+
fmsub(a_float_high, b_float_high, c_float_high));
|
| 551 |
+
}
|
| 552 |
+
|
| 553 |
+
#endif // !defined(C10_MOBILE) && defined(__aarch64__)
|
| 554 |
+
|
| 555 |
+
} // namespace CPU_CAPABILITY
|
| 556 |
+
} // namespace at::vec
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_convert.h
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 3 |
+
#include <ATen/cpu/vec/vec_convert.h>
|
| 4 |
+
|
| 5 |
+
namespace at::vec {
|
| 6 |
+
inline namespace CPU_CAPABILITY {
|
| 7 |
+
#if (defined(__aarch64__) && !defined(CPU_CAPABILITY_SVE256))
|
| 8 |
+
template <typename src_t>
|
| 9 |
+
struct VecConvert<
|
| 10 |
+
float,
|
| 11 |
+
1,
|
| 12 |
+
src_t,
|
| 13 |
+
1,
|
| 14 |
+
typename std::enable_if_t<is_8bit_integer_v<src_t>,
|
| 15 |
+
void>> {
|
| 16 |
+
static inline VectorizedN<float, 1> apply(const VectorizedN<src_t, 1>& src) {
|
| 17 |
+
return convert_int8_half_register_to_float(src[0]);
|
| 18 |
+
}
|
| 19 |
+
};
|
| 20 |
+
template <typename src_t>
|
| 21 |
+
struct VecConvert<
|
| 22 |
+
float,
|
| 23 |
+
2,
|
| 24 |
+
src_t,
|
| 25 |
+
1,
|
| 26 |
+
typename std::enable_if_t<is_8bit_integer_v<src_t>,
|
| 27 |
+
void>> {
|
| 28 |
+
static inline VectorizedN<float, 2> apply(const VectorizedN<src_t, 1>& src) {
|
| 29 |
+
const auto [v0, v1] = convert_int8_to_float(src[0]);
|
| 30 |
+
return VectorizedN<float, 2>(v0, v1);
|
| 31 |
+
}
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
template <>
|
| 35 |
+
struct VecConvert<float, 2, BFloat16, 1> {
|
| 36 |
+
static inline VectorizedN<float, 2> apply(
|
| 37 |
+
const VectorizedN<BFloat16, 1>& src) {
|
| 38 |
+
VectorizedN<float, 2> result;
|
| 39 |
+
uint16x8_t u16_8 = vld1q_u16(reinterpret_cast<const uint16_t*>(&src[0]));
|
| 40 |
+
auto u16_low1 = vget_low_u16(u16_8);
|
| 41 |
+
auto u16_high1 = vget_high_u16(u16_8);
|
| 42 |
+
float32x4_t f32x4_0 = vreinterpretq_f32_u32(vshlq_n_u32(vmovl_u16(u16_low1), 16));
|
| 43 |
+
float32x4_t f32x4_1 = vreinterpretq_f32_u32(vshlq_n_u32(vmovl_u16(u16_high1), 16));
|
| 44 |
+
result[0] = f32x4_0;
|
| 45 |
+
result[1] = f32x4_1;
|
| 46 |
+
return result;
|
| 47 |
+
}
|
| 48 |
+
};
|
| 49 |
+
// Half register to full register.
|
| 50 |
+
template <>
|
| 51 |
+
struct VecConvert<float, 1, BFloat16, 1> {
|
| 52 |
+
static inline VectorizedN<float, 1> apply(
|
| 53 |
+
const VectorizedN<BFloat16, 1>& src) {
|
| 54 |
+
VectorizedN<float, 1> result;
|
| 55 |
+
uint16x4_t u16_8 = vld1_u16(reinterpret_cast<const uint16_t*>(&src[0]));
|
| 56 |
+
float32x4_t f32x4_0 = vreinterpretq_f32_u32(vshlq_n_u32(vmovl_u16(u16_8), 16));
|
| 57 |
+
result[0] = f32x4_0;
|
| 58 |
+
return result;
|
| 59 |
+
}
|
| 60 |
+
};
|
| 61 |
+
|
| 62 |
+
#endif // defined(__aarch64__) && !defined(CPU_CAPABILITY_SVE256)
|
| 63 |
+
} // namespace CPU_CAPABILITY
|
| 64 |
+
} // namespace at::vec
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_float_neon.h
ADDED
|
@@ -0,0 +1,580 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <c10/util/irange.h>
|
| 9 |
+
|
| 10 |
+
#if defined(__aarch64__) && defined(AT_BUILD_ARM_VEC256_WITH_SLEEF)
|
| 11 |
+
#include <sleef.h>
|
| 12 |
+
#endif
|
| 13 |
+
|
| 14 |
+
// Sleef offers vectorized versions of some transcedentals
|
| 15 |
+
// such as sin, cos, tan etc..
|
| 16 |
+
// However for now opting for STL, since we are not building
|
| 17 |
+
// with Sleef for mobile yet.
|
| 18 |
+
|
| 19 |
+
namespace at::vec {
|
| 20 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 21 |
+
inline namespace CPU_CAPABILITY {
|
| 22 |
+
|
| 23 |
+
// Right now contains only aarch64 implementation.
|
| 24 |
+
// Due to follow two reasons aarch32 is not currently supported.
|
| 25 |
+
// 1. Due to difference in ISA been aarch32 and aarch64, intrinsics
|
| 26 |
+
// that work for aarch64 dont work for aarch32.
|
| 27 |
+
// 2. Android NDK r21 has problems with compiling aarch32.
|
| 28 |
+
// Clang seg faults.
|
| 29 |
+
// https://github.com/android/ndk/issues/1248
|
| 30 |
+
// https://bugs.llvm.org/show_bug.cgi?id=45824
|
| 31 |
+
// Most likely we will do aarch32 support with inline asm.
|
| 32 |
+
#if defined(__aarch64__)
|
| 33 |
+
|
| 34 |
+
#ifdef __BIG_ENDIAN__
|
| 35 |
+
#error "Big endian is not supported."
|
| 36 |
+
#endif
|
| 37 |
+
|
| 38 |
+
#if defined(AT_BUILD_ARM_VEC256_WITH_SLEEF)
|
| 39 |
+
#define USE_SLEEF(sleef_code, non_sleef_code) sleef_code
|
| 40 |
+
#else
|
| 41 |
+
#define USE_SLEEF(sleef_code, non_sleef_code) non_sleef_code
|
| 42 |
+
#endif
|
| 43 |
+
|
| 44 |
+
template<int index, bool mask_val>
|
| 45 |
+
struct BlendRegs {
|
| 46 |
+
static float32x4_t impl(
|
| 47 |
+
const float32x4_t& a, const float32x4_t& b, float32x4_t& res);
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
template<int index>
|
| 51 |
+
struct BlendRegs<index, true>{
|
| 52 |
+
static float32x4_t impl(
|
| 53 |
+
const float32x4_t& a, const float32x4_t& b, float32x4_t& res) {
|
| 54 |
+
return vsetq_lane_f32(vgetq_lane_f32(b, index), res, index);
|
| 55 |
+
}
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
template<int index>
|
| 59 |
+
struct BlendRegs<index, false>{
|
| 60 |
+
static float32x4_t impl(
|
| 61 |
+
const float32x4_t& a, const float32x4_t& b, float32x4_t& res) {
|
| 62 |
+
return vsetq_lane_f32(vgetq_lane_f32(a, index), res, index);
|
| 63 |
+
}
|
| 64 |
+
};
|
| 65 |
+
|
| 66 |
+
template <> class Vectorized<float> {
|
| 67 |
+
private:
|
| 68 |
+
float32x4_t values;
|
| 69 |
+
public:
|
| 70 |
+
using value_type = float;
|
| 71 |
+
using size_type = int;
|
| 72 |
+
static constexpr size_type size() {
|
| 73 |
+
return 4;
|
| 74 |
+
}
|
| 75 |
+
Vectorized() {}
|
| 76 |
+
Vectorized(float32x4_t v) : values(v) {}
|
| 77 |
+
Vectorized(float val) : values{vdupq_n_f32(val)} {}
|
| 78 |
+
Vectorized(float val0, float val1, float val2, float val3) :
|
| 79 |
+
values{val0, val1, val2, val3} {}
|
| 80 |
+
Vectorized(float (&arr)[4]) : Vectorized(arr[0], arr[1], arr[2], arr[3]) {}
|
| 81 |
+
operator float32x4_t() const {
|
| 82 |
+
return values;
|
| 83 |
+
}
|
| 84 |
+
template <int64_t mask>
|
| 85 |
+
static Vectorized<float> blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 86 |
+
Vectorized<float> vec;
|
| 87 |
+
vec.values =
|
| 88 |
+
BlendRegs<0, (mask & 0x01)!=0>::impl(
|
| 89 |
+
a.values, b.values, vec.values);
|
| 90 |
+
vec.values =
|
| 91 |
+
BlendRegs<1, (mask & 0x02)!=0>::impl(
|
| 92 |
+
a.values, b.values, vec.values);
|
| 93 |
+
vec.values =
|
| 94 |
+
BlendRegs<2, (mask & 0x04)!=0>::impl(
|
| 95 |
+
a.values, b.values, vec.values);
|
| 96 |
+
vec.values =
|
| 97 |
+
BlendRegs<3, (mask & 0x08)!=0>::impl(
|
| 98 |
+
a.values, b.values, vec.values);
|
| 99 |
+
return vec;
|
| 100 |
+
}
|
| 101 |
+
static Vectorized<float> blendv(const Vectorized<float>& a, const Vectorized<float>& b,
|
| 102 |
+
const Vectorized<float>& mask) {
|
| 103 |
+
// TODO
|
| 104 |
+
// NB: This requires that each value, i.e., each uint value,
|
| 105 |
+
// of the mask either all be zeros or all be 1s.
|
| 106 |
+
// We perhaps need some kind of an assert?
|
| 107 |
+
// But that will affect performance.
|
| 108 |
+
Vectorized<float> vec(mask.values);
|
| 109 |
+
vec.values = vbslq_f32(
|
| 110 |
+
vreinterpretq_u32_f32(vec.values),
|
| 111 |
+
b.values,
|
| 112 |
+
a.values);
|
| 113 |
+
return vec;
|
| 114 |
+
}
|
| 115 |
+
template<typename step_t>
|
| 116 |
+
static Vectorized<float> arange(float base = 0.f, step_t step = static_cast<step_t>(1)) {
|
| 117 |
+
const Vectorized<float> base_vec(base);
|
| 118 |
+
const Vectorized<float> step_vec(step);
|
| 119 |
+
const Vectorized<float> step_sizes(0, 1, 2, 3);
|
| 120 |
+
return fmadd(step_sizes, step_vec, base_vec);
|
| 121 |
+
}
|
| 122 |
+
static Vectorized<float> set(const Vectorized<float>& a, const Vectorized<float>& b,
|
| 123 |
+
int64_t count = size()) {
|
| 124 |
+
switch (count) {
|
| 125 |
+
case 0:
|
| 126 |
+
return a;
|
| 127 |
+
case 1:
|
| 128 |
+
{
|
| 129 |
+
Vectorized<float> vec;
|
| 130 |
+
static uint32x4_t mask_low = {0xFFFFFFFF, 0x0, 0x0, 0x0};
|
| 131 |
+
vec.values = vreinterpretq_f32_u32(mask_low);
|
| 132 |
+
vec.values = vbslq_f32(
|
| 133 |
+
vreinterpretq_u32_f32(vec.values),
|
| 134 |
+
b.values,
|
| 135 |
+
a.values);
|
| 136 |
+
return vec;
|
| 137 |
+
}
|
| 138 |
+
case 2:
|
| 139 |
+
{
|
| 140 |
+
Vectorized<float> vec;
|
| 141 |
+
static uint32x4_t mask_low = {0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0};
|
| 142 |
+
vec.values = vreinterpretq_f32_u32(mask_low);
|
| 143 |
+
vec.values = vbslq_f32(
|
| 144 |
+
vreinterpretq_u32_f32(vec.values),
|
| 145 |
+
b.values,
|
| 146 |
+
a.values);
|
| 147 |
+
return vec;
|
| 148 |
+
}
|
| 149 |
+
case 3:
|
| 150 |
+
{
|
| 151 |
+
Vectorized<float> vec;
|
| 152 |
+
static uint32x4_t mask_low = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0};
|
| 153 |
+
vec.values = vreinterpretq_f32_u32(mask_low);
|
| 154 |
+
vec.values = vbslq_f32(
|
| 155 |
+
vreinterpretq_u32_f32(vec.values),
|
| 156 |
+
b.values,
|
| 157 |
+
a.values);
|
| 158 |
+
return vec;
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
return b;
|
| 162 |
+
}
|
| 163 |
+
static Vectorized<float> loadu(const void* ptr, int64_t count = size()) {
|
| 164 |
+
if (count == size()) {
|
| 165 |
+
return vld1q_f32(reinterpret_cast<const float*>(ptr));
|
| 166 |
+
} else {
|
| 167 |
+
__at_align__ float tmp_values[size()];
|
| 168 |
+
for (const auto i : c10::irange(size())) {
|
| 169 |
+
tmp_values[i] = 0.0;
|
| 170 |
+
}
|
| 171 |
+
std::memcpy(
|
| 172 |
+
tmp_values,
|
| 173 |
+
reinterpret_cast<const float*>(ptr),
|
| 174 |
+
count * sizeof(float));
|
| 175 |
+
return vld1q_f32(reinterpret_cast<const float*>(tmp_values));
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
void store(void* ptr, int64_t count = size()) const {
|
| 179 |
+
if (count == size()) {
|
| 180 |
+
vst1q_f32(reinterpret_cast<float*>(ptr), values);
|
| 181 |
+
} else {
|
| 182 |
+
float tmp_values[size()];
|
| 183 |
+
vst1q_f32(reinterpret_cast<float*>(tmp_values), values);
|
| 184 |
+
std::memcpy(ptr, tmp_values, count * sizeof(float));
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
// Very slow implementation of indexing.
|
| 188 |
+
// Only required because vec256_qint refers to this.
|
| 189 |
+
// Once we specialize that implementation for ARM
|
| 190 |
+
// this should be removed. TODO (kimishpatel)
|
| 191 |
+
float operator[](int idx) const {
|
| 192 |
+
__at_align__ float tmp[size()];
|
| 193 |
+
store(tmp);
|
| 194 |
+
return tmp[idx];
|
| 195 |
+
}
|
| 196 |
+
float operator[](int idx) {
|
| 197 |
+
__at_align__ float tmp[size()];
|
| 198 |
+
store(tmp);
|
| 199 |
+
return tmp[idx];
|
| 200 |
+
}
|
| 201 |
+
// For boolean version where we want to if any 1/all zero
|
| 202 |
+
// etc. can be done faster in a different way.
|
| 203 |
+
int zero_mask() const {
|
| 204 |
+
__at_align__ float tmp[size()];
|
| 205 |
+
store(tmp);
|
| 206 |
+
int mask = 0;
|
| 207 |
+
for (int i = 0; i < size(); ++ i) {
|
| 208 |
+
if (tmp[i] == 0.f) {
|
| 209 |
+
mask |= (1 << i);
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
return mask;
|
| 213 |
+
}
|
| 214 |
+
Vectorized<float> isnan() const {
|
| 215 |
+
return vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(values, values)));
|
| 216 |
+
}
|
| 217 |
+
bool has_inf_nan() const {
|
| 218 |
+
__at_align__ float tmp[size()];
|
| 219 |
+
store(tmp);
|
| 220 |
+
for (const auto i : c10::irange(size())) {
|
| 221 |
+
if(_isnan(tmp[i]) || _isinf(tmp[i])) {
|
| 222 |
+
return true;
|
| 223 |
+
}
|
| 224 |
+
}
|
| 225 |
+
return false;
|
| 226 |
+
}
|
| 227 |
+
Vectorized<float> map(float (*const f)(float)) const {
|
| 228 |
+
__at_align__ float tmp[size()];
|
| 229 |
+
store(tmp);
|
| 230 |
+
for (const auto i : c10::irange(size())) {
|
| 231 |
+
tmp[i] = f(tmp[i]);
|
| 232 |
+
}
|
| 233 |
+
return loadu(tmp);
|
| 234 |
+
}
|
| 235 |
+
Vectorized<float> map2(
|
| 236 |
+
const Vectorized<float>& second,
|
| 237 |
+
float (*const f)(float, float)) const {
|
| 238 |
+
__at_align__ float tmp[size()];
|
| 239 |
+
__at_align__ float tmp_second[size()];
|
| 240 |
+
store(tmp);
|
| 241 |
+
second.store(tmp_second);
|
| 242 |
+
for (const auto i : c10::irange(size())) {
|
| 243 |
+
tmp[i] = f(tmp[i], tmp_second[i]);
|
| 244 |
+
}
|
| 245 |
+
return loadu(tmp);
|
| 246 |
+
}
|
| 247 |
+
Vectorized<float> abs() const {
|
| 248 |
+
return Vectorized<float>(vabsq_f32(values));
|
| 249 |
+
}
|
| 250 |
+
Vectorized<float> angle() const {
|
| 251 |
+
auto zero = Vectorized<float>(0);
|
| 252 |
+
auto pi = Vectorized<float>(c10::pi<float>);
|
| 253 |
+
auto tmp = blendv(zero, pi, *this < zero);
|
| 254 |
+
return blendv(tmp, *this, isnan());
|
| 255 |
+
}
|
| 256 |
+
Vectorized<float> real() const {
|
| 257 |
+
return *this;
|
| 258 |
+
}
|
| 259 |
+
Vectorized<float> imag() const {
|
| 260 |
+
return Vectorized<float>(0.f);
|
| 261 |
+
}
|
| 262 |
+
Vectorized<float> conj() const {
|
| 263 |
+
return *this;
|
| 264 |
+
}
|
| 265 |
+
#define DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(name, sleef_name) \
|
| 266 |
+
Vectorized<float> name() const { \
|
| 267 |
+
return USE_SLEEF( \
|
| 268 |
+
Vectorized<float>(sleef_name(values)), \
|
| 269 |
+
map(std::name) \
|
| 270 |
+
); \
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
#define DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(name) \
|
| 274 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(name, Sleef_##name##f4_u10)
|
| 275 |
+
|
| 276 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(acos)
|
| 277 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(acosh)
|
| 278 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(asin)
|
| 279 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(atan)
|
| 280 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(atanh)
|
| 281 |
+
|
| 282 |
+
#define DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(name, sleef_name) \
|
| 283 |
+
Vectorized<float> name(const Vectorized<float> &arg) const { \
|
| 284 |
+
return USE_SLEEF( \
|
| 285 |
+
Vectorized<float>(sleef_name(values, arg.values)), \
|
| 286 |
+
map2(arg, std::name) \
|
| 287 |
+
); \
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
#define DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC(name) \
|
| 291 |
+
DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(name, Sleef_##name##f4_u10)
|
| 292 |
+
|
| 293 |
+
DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC(atan2)
|
| 294 |
+
DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(copysign, Sleef_copysignf4)
|
| 295 |
+
Vectorized<float> erf() const;
|
| 296 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(erfc, Sleef_erfcf4_u15)
|
| 297 |
+
Vectorized<float> erfinv() const {
|
| 298 |
+
return map(calc_erfinv);
|
| 299 |
+
}
|
| 300 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(exp)
|
| 301 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(exp2)
|
| 302 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(expm1)
|
| 303 |
+
Vectorized<float> exp_u20() const {
|
| 304 |
+
return exp();
|
| 305 |
+
}
|
| 306 |
+
DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(fmod, Sleef_fmodf4)
|
| 307 |
+
DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(hypot, Sleef_hypotf4_u05)
|
| 308 |
+
Vectorized<float> i0() const {
|
| 309 |
+
return map(calc_i0);
|
| 310 |
+
}
|
| 311 |
+
Vectorized<float> i0e() const {
|
| 312 |
+
return map(calc_i0e);
|
| 313 |
+
}
|
| 314 |
+
Vectorized<float> digamma() const {
|
| 315 |
+
return map(calc_digamma);
|
| 316 |
+
}
|
| 317 |
+
Vectorized<float> igamma(const Vectorized<float> &x) const {
|
| 318 |
+
return map2(x, calc_igamma);
|
| 319 |
+
}
|
| 320 |
+
Vectorized<float> igammac(const Vectorized<float> &x) const {
|
| 321 |
+
return map2(x, calc_igammac);
|
| 322 |
+
}
|
| 323 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(log)
|
| 324 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(log10)
|
| 325 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(log1p)
|
| 326 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(log2)
|
| 327 |
+
DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC_WITH_SLEEF_NAME(nextafter, Sleef_nextafterf4)
|
| 328 |
+
Vectorized<float> frac() const;
|
| 329 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(sin)
|
| 330 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(sinh)
|
| 331 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(cos)
|
| 332 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(cosh)
|
| 333 |
+
Vectorized<float> ceil() const {
|
| 334 |
+
return map(at::native::ceil_impl);
|
| 335 |
+
}
|
| 336 |
+
Vectorized<float> floor() const {
|
| 337 |
+
return map(at::native::floor_impl);
|
| 338 |
+
}
|
| 339 |
+
Vectorized<float> neg() const {
|
| 340 |
+
return Vectorized<float>(
|
| 341 |
+
vnegq_f32(values));
|
| 342 |
+
}
|
| 343 |
+
Vectorized<float> round() const {
|
| 344 |
+
// We do not use std::round because we would like to round midway numbers to the nearest even integer.
|
| 345 |
+
return map(at::native::round_impl);
|
| 346 |
+
}
|
| 347 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(tan)
|
| 348 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(tanh)
|
| 349 |
+
Vectorized<float> trunc() const {
|
| 350 |
+
return Vectorized<float>(vrndq_f32(values));
|
| 351 |
+
}
|
| 352 |
+
DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC(lgamma)
|
| 353 |
+
Vectorized<float> sqrt() const {
|
| 354 |
+
return Vectorized<float>(vsqrtq_f32(values));
|
| 355 |
+
}
|
| 356 |
+
Vectorized<float> reciprocal() const {
|
| 357 |
+
return Vectorized<float>(vdivq_f32(vdupq_n_f32(1.0f), values));
|
| 358 |
+
}
|
| 359 |
+
Vectorized<float> rsqrt() const {
|
| 360 |
+
return this->sqrt().reciprocal();
|
| 361 |
+
}
|
| 362 |
+
DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC(pow)
|
| 363 |
+
Vectorized<float> operator==(const Vectorized<float>& other) const {
|
| 364 |
+
return Vectorized<float>(vreinterpretq_f32_u32(vceqq_f32(values, other.values)));
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
Vectorized<float> operator!=(const Vectorized<float>& other) const {
|
| 368 |
+
float32x4_t r0 = vreinterpretq_f32_u32(
|
| 369 |
+
vmvnq_u32(vceqq_f32(values, other.values)));
|
| 370 |
+
return Vectorized<float>(r0);
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
Vectorized<float> operator<(const Vectorized<float>& other) const {
|
| 374 |
+
return Vectorized<float>(vreinterpretq_f32_u32(vcltq_f32(values, other.values)));
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
Vectorized<float> operator<=(const Vectorized<float>& other) const {
|
| 378 |
+
return Vectorized<float>(vreinterpretq_f32_u32(vcleq_f32(values, other.values)));
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
Vectorized<float> operator>(const Vectorized<float>& other) const {
|
| 382 |
+
return Vectorized<float>(vreinterpretq_f32_u32(vcgtq_f32(values, other.values)));
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
Vectorized<float> operator>=(const Vectorized<float>& other) const {
|
| 386 |
+
return Vectorized<float>(vreinterpretq_f32_u32(vcgeq_f32(values, other.values)));
|
| 387 |
+
}
|
| 388 |
+
|
| 389 |
+
Vectorized<float> eq(const Vectorized<float>& other) const;
|
| 390 |
+
Vectorized<float> ne(const Vectorized<float>& other) const;
|
| 391 |
+
Vectorized<float> gt(const Vectorized<float>& other) const;
|
| 392 |
+
Vectorized<float> ge(const Vectorized<float>& other) const;
|
| 393 |
+
Vectorized<float> lt(const Vectorized<float>& other) const;
|
| 394 |
+
Vectorized<float> le(const Vectorized<float>& other) const;
|
| 395 |
+
};
|
| 396 |
+
|
| 397 |
+
template <>
|
| 398 |
+
Vectorized<float> inline operator+(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 399 |
+
return Vectorized<float>(vaddq_f32(a, b));
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
template <>
|
| 403 |
+
Vectorized<float> inline operator-(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 404 |
+
return Vectorized<float>(vsubq_f32(a, b));
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
template <>
|
| 408 |
+
Vectorized<float> inline operator*(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 409 |
+
return Vectorized<float>(vmulq_f32(a, b));
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
template <>
|
| 413 |
+
Vectorized<float> inline operator/(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 414 |
+
return Vectorized<float>(vdivq_f32(a, b));
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
// frac. Implement this here so we can use subtraction
|
| 418 |
+
inline Vectorized<float> Vectorized<float>::frac() const {
|
| 419 |
+
return *this - this->trunc();
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
//Added sleef Implementation for Maximum
|
| 423 |
+
Vectorized<float> inline maximum(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 424 |
+
if(!a.has_inf_nan() && !b.has_inf_nan()){
|
| 425 |
+
return USE_SLEEF(
|
| 426 |
+
Vectorized<float>(Sleef_fmaxf4(a, b)),
|
| 427 |
+
Vectorized<float>(vmaxq_f32(a,b)));
|
| 428 |
+
}
|
| 429 |
+
else{
|
| 430 |
+
return Vectorized<float>(vmaxq_f32(a, b));
|
| 431 |
+
}
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 435 |
+
// either input is a NaN.
|
| 436 |
+
template <>
|
| 437 |
+
Vectorized<float> inline minimum(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 438 |
+
return Vectorized<float>(vminq_f32(a, b));
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
template <>
|
| 442 |
+
Vectorized<float> inline clamp(const Vectorized<float>& a, const Vectorized<float>& min, const Vectorized<float>& max) {
|
| 443 |
+
return minimum(max, maximum(min, a));
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
template <>
|
| 447 |
+
Vectorized<float> inline clamp_max(const Vectorized<float>& a, const Vectorized<float>& max) {
|
| 448 |
+
return minimum(max, a);
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
template <>
|
| 452 |
+
Vectorized<float> inline clamp_min(const Vectorized<float>& a, const Vectorized<float>& min) {
|
| 453 |
+
return maximum(min, a);
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
template <>
|
| 457 |
+
Vectorized<float> inline operator&(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 458 |
+
return Vectorized<float>(vreinterpretq_f32_u32(vandq_u32(
|
| 459 |
+
vreinterpretq_u32_f32(a),
|
| 460 |
+
vreinterpretq_u32_f32(b))));
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
template <>
|
| 464 |
+
Vectorized<float> inline operator|(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 465 |
+
return Vectorized<float>(vreinterpretq_f32_u32(vorrq_u32(
|
| 466 |
+
vreinterpretq_u32_f32(a),
|
| 467 |
+
vreinterpretq_u32_f32(b))));
|
| 468 |
+
}
|
| 469 |
+
|
| 470 |
+
template <>
|
| 471 |
+
Vectorized<float> inline operator^(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 472 |
+
return Vectorized<float>(vreinterpretq_f32_u32(veorq_u32(
|
| 473 |
+
vreinterpretq_u32_f32(a),
|
| 474 |
+
vreinterpretq_u32_f32(b))));
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
inline Vectorized<float> Vectorized<float>::eq(const Vectorized<float>& other) const {
|
| 478 |
+
return (*this == other) & Vectorized<float>(1.0f);
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
inline Vectorized<float> Vectorized<float>::ne(const Vectorized<float>& other) const {
|
| 482 |
+
return (*this != other) & Vectorized<float>(1.0f);
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
inline Vectorized<float> Vectorized<float>::gt(const Vectorized<float>& other) const {
|
| 486 |
+
return (*this > other) & Vectorized<float>(1.0f);
|
| 487 |
+
}
|
| 488 |
+
|
| 489 |
+
inline Vectorized<float> Vectorized<float>::ge(const Vectorized<float>& other) const {
|
| 490 |
+
return (*this >= other) & Vectorized<float>(1.0f);
|
| 491 |
+
}
|
| 492 |
+
|
| 493 |
+
inline Vectorized<float> Vectorized<float>::lt(const Vectorized<float>& other) const {
|
| 494 |
+
return (*this < other) & Vectorized<float>(1.0f);
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
inline Vectorized<float> Vectorized<float>::le(const Vectorized<float>& other) const {
|
| 498 |
+
return (*this <= other) & Vectorized<float>(1.0f);
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
template <>
|
| 502 |
+
inline void convert(const float* src, int32_t* dst, int64_t n) {
|
| 503 |
+
int64_t i;
|
| 504 |
+
#ifndef __msvc_cl__
|
| 505 |
+
#pragma unroll
|
| 506 |
+
#endif
|
| 507 |
+
for (i = 0; i <= (n - Vectorized<float>::size()); i += Vectorized<float>::size()) {
|
| 508 |
+
vst1q_s32(dst + i, vcvtq_s32_f32(vld1q_f32(src + i)));
|
| 509 |
+
}
|
| 510 |
+
#ifndef __msvc_cl__
|
| 511 |
+
#pragma unroll
|
| 512 |
+
#endif
|
| 513 |
+
for (; i < n; i++) {
|
| 514 |
+
dst[i] = static_cast<int32_t>(src[i]);
|
| 515 |
+
}
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
template <>
|
| 519 |
+
inline void convert(const int32_t* src, float* dst, int64_t n) {
|
| 520 |
+
int64_t i;
|
| 521 |
+
#ifndef __msvc_cl__
|
| 522 |
+
#pragma unroll
|
| 523 |
+
#endif
|
| 524 |
+
for (i = 0; i <= (n - Vectorized<float>::size()); i += Vectorized<float>::size()) {
|
| 525 |
+
vst1q_f32(dst + i, vcvtq_f32_s32(vld1q_s32(src + i)));
|
| 526 |
+
}
|
| 527 |
+
#ifndef __msvc_cl__
|
| 528 |
+
#pragma unroll
|
| 529 |
+
#endif
|
| 530 |
+
for (; i < n; i++) {
|
| 531 |
+
dst[i] = static_cast<float>(src[i]);
|
| 532 |
+
}
|
| 533 |
+
}
|
| 534 |
+
|
| 535 |
+
template <>
|
| 536 |
+
Vectorized<float> inline fmadd(const Vectorized<float>& a, const Vectorized<float>& b, const Vectorized<float>& c) {
|
| 537 |
+
return Vectorized<float>(vfmaq_f32(c, a, b));
|
| 538 |
+
}
|
| 539 |
+
|
| 540 |
+
template <>
|
| 541 |
+
Vectorized<float> inline fmsub(const Vectorized<float>& a, const Vectorized<float>& b, const Vectorized<float>& c) {
|
| 542 |
+
return Vectorized<float>(vfmsq_f32(c, a, b));
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
inline Vectorized<float> Vectorized<float>::erf() const{
|
| 546 |
+
// constants
|
| 547 |
+
const Vectorized<float> neg_zero_vec(-0.f);
|
| 548 |
+
const Vectorized<float> one_vec(1.0f);
|
| 549 |
+
const Vectorized<float> p(0.3275911f);
|
| 550 |
+
const Vectorized<float> p1(0.254829592f);
|
| 551 |
+
const Vectorized<float> p2(-0.284496736f);
|
| 552 |
+
const Vectorized<float> p3(1.421413741f);
|
| 553 |
+
const Vectorized<float> p4(-1.453152027f);
|
| 554 |
+
const Vectorized<float> p5(1.061405429f);
|
| 555 |
+
// sign(x)
|
| 556 |
+
auto sign_mask = neg_zero_vec & *this;
|
| 557 |
+
auto abs_vec = this->abs();
|
| 558 |
+
// t = 1 / (p * abs(x) + 1)
|
| 559 |
+
auto tmp0 = fmadd(p, abs_vec, one_vec);
|
| 560 |
+
auto t = one_vec / tmp0;
|
| 561 |
+
// r = p5 * t ^ 4 + p4 * t ^ 3 + p3 * t ^ 2 + p2 * t + p1
|
| 562 |
+
auto tmp1 = fmadd(p5, t, p4);
|
| 563 |
+
auto tmp2 = fmadd(tmp1, t, p3);
|
| 564 |
+
auto tmp3 = fmadd(tmp2, t, p2);
|
| 565 |
+
auto r = fmadd(tmp3, t, p1);
|
| 566 |
+
// - exp(- x * x)
|
| 567 |
+
auto pow_2 = (*this) * (*this);
|
| 568 |
+
auto neg_pow_2 = pow_2 ^ neg_zero_vec;
|
| 569 |
+
auto tmp4 = neg_pow_2.map(std::exp); // This can be swapped for a faster implementation of exp.
|
| 570 |
+
auto tmp5 = tmp4 ^ neg_zero_vec;
|
| 571 |
+
// erf(x) = sign(x) * (1 - r * t * exp(- x * x))
|
| 572 |
+
auto tmp6 = t * tmp5;
|
| 573 |
+
auto tmp7 = fmadd(tmp6, r, one_vec);
|
| 574 |
+
return tmp7 ^ sign_mask;
|
| 575 |
+
}
|
| 576 |
+
#undef DEFINE_SLEEF_COMPATIBLE_BINARY_ELEMENTWISE_FUNC
|
| 577 |
+
#undef DEFINE_SLEEF_COMPATIBLE_UNARY_ELEMENTWISE_FUNC
|
| 578 |
+
#endif /* defined(aarch64) */
|
| 579 |
+
|
| 580 |
+
}} // namespace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_half_neon.h
ADDED
|
@@ -0,0 +1,603 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec128/vec128_convert.h>
|
| 8 |
+
#include <ATen/cpu/vec/vec128/vec128_float_neon.h>
|
| 9 |
+
#include <ATen/cpu/vec/vec128/vec128_reduced_precision_common_neon.h>
|
| 10 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 11 |
+
#include <c10/util/Half.h>
|
| 12 |
+
#include <c10/util/irange.h>
|
| 13 |
+
|
| 14 |
+
namespace at::vec {
|
| 15 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 16 |
+
inline namespace CPU_CAPABILITY {
|
| 17 |
+
|
| 18 |
+
// Right now contains only aarch64 implementation.
|
| 19 |
+
// Due to follow two reasons aarch32 is not currently supported.
|
| 20 |
+
// 1. Due to difference in ISA been aarch32 and aarch64, intrinsics
|
| 21 |
+
// that work for aarch64 dont work for aarch32.
|
| 22 |
+
// 2. Android NDK r21 has problems with compiling aarch32.
|
| 23 |
+
// Clang seg faults.
|
| 24 |
+
// https://github.com/android/ndk/issues/1248
|
| 25 |
+
// https://bugs.llvm.org/show_bug.cgi?id=45824
|
| 26 |
+
// Most likely we will do aarch32 support with inline asm.
|
| 27 |
+
#if !defined(C10_MOBILE) && defined(__aarch64__)
|
| 28 |
+
|
| 29 |
+
#ifdef __BIG_ENDIAN__
|
| 30 |
+
#error "Big endian is not supported."
|
| 31 |
+
#endif
|
| 32 |
+
|
| 33 |
+
template <int index, bool mask_val>
|
| 34 |
+
struct BlendHalfRegs {
|
| 35 |
+
static float16x8_t impl(
|
| 36 |
+
const float16x8_t& a,
|
| 37 |
+
const float16x8_t& b,
|
| 38 |
+
float16x8_t& res);
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
template <int index>
|
| 42 |
+
struct BlendHalfRegs<index, true> {
|
| 43 |
+
static float16x8_t impl(
|
| 44 |
+
const float16x8_t& a,
|
| 45 |
+
const float16x8_t& b,
|
| 46 |
+
float16x8_t& res) {
|
| 47 |
+
return vsetq_lane_f16(vgetq_lane_f16(b, index), res, index);
|
| 48 |
+
}
|
| 49 |
+
};
|
| 50 |
+
|
| 51 |
+
template <int index>
|
| 52 |
+
struct BlendHalfRegs<index, false> {
|
| 53 |
+
static float16x8_t impl(
|
| 54 |
+
const float16x8_t& a,
|
| 55 |
+
const float16x8_t& b,
|
| 56 |
+
float16x8_t& res) {
|
| 57 |
+
return vsetq_lane_f16(vgetq_lane_f16(a, index), res, index);
|
| 58 |
+
}
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
// On ARM, Half type supports float16_t->Half constructor and Half->float16_t
|
| 62 |
+
// conversion
|
| 63 |
+
template <>
|
| 64 |
+
class Vectorized<c10::Half> : public Vectorized16<float16x8_t, c10::Half, BlendHalfRegs, Vectorized<c10::Half>> {
|
| 65 |
+
using Base = Vectorized16<float16x8_t, c10::Half, BlendHalfRegs, Vectorized<c10::Half>>;
|
| 66 |
+
friend Base;
|
| 67 |
+
private:
|
| 68 |
+
// We use these private map functions to implement various methods
|
| 69 |
+
Vectorized<c10::Half> map_with_vec_float_method(
|
| 70 |
+
Vectorized<float> (Vectorized<float>::*m)() const) const {
|
| 71 |
+
float32x4_t v00 = vcvt_f32_f16(vget_low_f16(values));
|
| 72 |
+
float32x4_t v01 = vcvt_f32_f16(vget_high_f16(values));
|
| 73 |
+
Vectorized<float> mv0 = (Vectorized<float>(v00).*m)();
|
| 74 |
+
Vectorized<float> mv1 = (Vectorized<float>(v01).*m)();
|
| 75 |
+
float16x4_t r00 = vcvt_f16_f32(mv0);
|
| 76 |
+
float16x4_t r01 = vcvt_f16_f32(mv1);
|
| 77 |
+
return Vectorized<c10::Half>(vcombine_f16(r00, r01));
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
Vectorized<c10::Half> map2_with_vec_float_method(
|
| 81 |
+
const Vectorized<c10::Half>& second,
|
| 82 |
+
Vectorized<float> (Vectorized<float>::*m)(const Vectorized<float>&)
|
| 83 |
+
const) const {
|
| 84 |
+
float32x4_t v00 = vcvt_f32_f16(vget_low_f16(values));
|
| 85 |
+
float32x4_t v01 = vcvt_f32_f16(vget_high_f16(values));
|
| 86 |
+
float32x4_t second_v00 = vcvt_f32_f16(vget_low_f16(second.values));
|
| 87 |
+
float32x4_t second_v01 = vcvt_f32_f16(vget_high_f16(second.values));
|
| 88 |
+
Vectorized<float> mv0 = (Vectorized<float>(v00).*m)(Vectorized<float>(second_v00));
|
| 89 |
+
Vectorized<float> mv1 = (Vectorized<float>(v01).*m)(Vectorized<float>(second_v01));
|
| 90 |
+
float16x4_t r00 = vcvt_f16_f32(mv0);
|
| 91 |
+
float16x4_t r01 = vcvt_f16_f32(mv1);
|
| 92 |
+
|
| 93 |
+
// Pack result into Vectorized<c10::Half>
|
| 94 |
+
return Vectorized<c10::Half>(vcombine_f16(r00, r01));
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
Vectorized<c10::Half> map2_bitmask_with_vec_float_method(
|
| 98 |
+
const Vectorized<c10::Half>& second,
|
| 99 |
+
Vectorized<float> (Vectorized<float>::*m)(const Vectorized<float>&)
|
| 100 |
+
const) const {
|
| 101 |
+
float32x4_t v00 = vcvt_f32_f16(vget_low_f16(values));
|
| 102 |
+
float32x4_t v01 = vcvt_f32_f16(vget_high_f16(values));
|
| 103 |
+
float32x4_t second_v00 = vcvt_f32_f16(vget_low_f16(second.values));
|
| 104 |
+
float32x4_t second_v01 = vcvt_f32_f16(vget_high_f16(second.values));
|
| 105 |
+
Vectorized<float> mv0 = (Vectorized<float>(v00).*m)(Vectorized<float>(second_v00));
|
| 106 |
+
Vectorized<float> mv1 = (Vectorized<float>(v01).*m)(Vectorized<float>(second_v01));
|
| 107 |
+
// Assume the operator returns a bitmask, not "real" floats, and
|
| 108 |
+
// just narrow the bits. All-ones is a NaN and will get mangled by conversion!
|
| 109 |
+
float16x4_t r00 = vreinterpret_f16_u16(vmovn_u32(vreinterpretq_u32_f32(mv0)));
|
| 110 |
+
float16x4_t r01 = vreinterpret_f16_u16(vmovn_u32(vreinterpretq_u32_f32(mv1)));
|
| 111 |
+
|
| 112 |
+
// Pack result into Vectorized<c10::Half>
|
| 113 |
+
return Vectorized<c10::Half>(vcombine_f16(r00, r01));
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
public:
|
| 117 |
+
using Vectorized16::Vectorized16;
|
| 118 |
+
|
| 119 |
+
Vectorized() = default;
|
| 120 |
+
|
| 121 |
+
// A ctor that accepts c10::Half is needed to fit interface with vec_base.h
|
| 122 |
+
// A second constructor that takes float16_t is also included
|
| 123 |
+
Vectorized(c10::Half val)
|
| 124 |
+
: Vectorized((float16_t)val) {}
|
| 125 |
+
Vectorized(float16_t val)
|
| 126 |
+
: Vectorized16(vdupq_n_f16(val)) {}
|
| 127 |
+
Vectorized(
|
| 128 |
+
value_type val0,
|
| 129 |
+
value_type val1,
|
| 130 |
+
value_type val2,
|
| 131 |
+
value_type val3,
|
| 132 |
+
value_type val4,
|
| 133 |
+
value_type val5,
|
| 134 |
+
value_type val6,
|
| 135 |
+
value_type val7)
|
| 136 |
+
: Vectorized16(float16x8_t{
|
| 137 |
+
val0,
|
| 138 |
+
val1,
|
| 139 |
+
val2,
|
| 140 |
+
val3,
|
| 141 |
+
val4,
|
| 142 |
+
val5,
|
| 143 |
+
val6,
|
| 144 |
+
val7}) {}
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
static Vectorized<c10::Half> blendv(
|
| 148 |
+
const Vectorized<c10::Half>& a,
|
| 149 |
+
const Vectorized<c10::Half>& b,
|
| 150 |
+
const Vectorized<c10::Half>& mask) {
|
| 151 |
+
// Note: using blendv is very awkward because 0xFFFF is one of
|
| 152 |
+
// many NaN's in FP16 It's unfortunate that the mask has type Half
|
| 153 |
+
// (required from vec_base)
|
| 154 |
+
|
| 155 |
+
// TODO
|
| 156 |
+
// NB: This requires that each value, i.e., each uint value,
|
| 157 |
+
// of the mask either all be zeros or all be 1s.
|
| 158 |
+
// We perhaps need some kind of an assert?
|
| 159 |
+
// But that will affect performance.
|
| 160 |
+
|
| 161 |
+
// NOTE [vbslq_f16]: vbslq_f16 doesn't work on clang without
|
| 162 |
+
// __ARM_FEATURE_FP16_VECTOR_ARITHMETIC. vbslq_u16 generates the
|
| 163 |
+
// same instruction anyway. see https://godbolt.org/z/cY4a55Y7P
|
| 164 |
+
Vectorized<c10::Half> vec(mask.values);
|
| 165 |
+
vec.values = vreinterpretq_f16_u16(
|
| 166 |
+
vbslq_u16(
|
| 167 |
+
vreinterpretq_u16_f16(vec.values),
|
| 168 |
+
vreinterpretq_u16_f16(b.values),
|
| 169 |
+
vreinterpretq_u16_f16(a.values)));
|
| 170 |
+
return vec;
|
| 171 |
+
}
|
| 172 |
+
static Vectorized<c10::Half> set(
|
| 173 |
+
const Vectorized<c10::Half>& a,
|
| 174 |
+
const Vectorized<c10::Half>& b,
|
| 175 |
+
int64_t count = size()) {
|
| 176 |
+
uint16_t pre_mask[size()] = {0};
|
| 177 |
+
for (int i = 0; i < count; i++) {
|
| 178 |
+
pre_mask[i] = 0xFFFF;
|
| 179 |
+
}
|
| 180 |
+
uint16x8_t mask = vld1q_u16(pre_mask);
|
| 181 |
+
|
| 182 |
+
// Using blendv is awkward because 0xFFFF is one of many NaN's in FP16
|
| 183 |
+
// so we directly use vbslq_u16 instead. (See NOTE [vbslq_f16] above.)
|
| 184 |
+
Vectorized<c10::Half> vec(
|
| 185 |
+
vreinterpretq_f16_u16(
|
| 186 |
+
vbslq_u16(
|
| 187 |
+
mask,
|
| 188 |
+
vreinterpretq_u16_f16(b.values),
|
| 189 |
+
vreinterpretq_u16_f16(a.values))));
|
| 190 |
+
|
| 191 |
+
return vec;
|
| 192 |
+
}
|
| 193 |
+
static Vectorized<c10::Half> loadu(const void* ptr, int64_t count = size()) {
|
| 194 |
+
if (count == size()) {
|
| 195 |
+
return vld1q_f16(reinterpret_cast<const float16_t*>(ptr));
|
| 196 |
+
}
|
| 197 |
+
__at_align__ float16_t tmp_values[size()];
|
| 198 |
+
for (const auto i : c10::irange(size())) {
|
| 199 |
+
tmp_values[i] = 0;
|
| 200 |
+
}
|
| 201 |
+
std::memcpy(
|
| 202 |
+
tmp_values,
|
| 203 |
+
reinterpret_cast<const float16_t*>(ptr),
|
| 204 |
+
count * sizeof(float16_t));
|
| 205 |
+
return vld1q_f16(reinterpret_cast<const float16_t*>(tmp_values));
|
| 206 |
+
}
|
| 207 |
+
void store(void* ptr, int64_t count = size()) const {
|
| 208 |
+
if (count == size()) {
|
| 209 |
+
vst1q_f16(reinterpret_cast<float16_t*>(ptr), values);
|
| 210 |
+
return;
|
| 211 |
+
} else {
|
| 212 |
+
float16_t tmp_values[size()];
|
| 213 |
+
vst1q_f16(reinterpret_cast<float16_t*>(tmp_values), values);
|
| 214 |
+
std::memcpy(ptr, tmp_values, count * sizeof(float16_t));
|
| 215 |
+
}
|
| 216 |
+
}
|
| 217 |
+
// For boolean version where we want to if any 1/all zero
|
| 218 |
+
// etc. can be done faster in a different way.
|
| 219 |
+
Vectorized<c10::Half> isnan() const {
|
| 220 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 221 |
+
return vreinterpretq_f16_u16(vmvnq_u16(vceqq_f16(values, values)));
|
| 222 |
+
#else
|
| 223 |
+
// NOTE: we could make this faster by doing vectorized checks of
|
| 224 |
+
// exponent/payload bits.
|
| 225 |
+
__at_align__ c10::Half tmp[size()];
|
| 226 |
+
__at_align__ c10::Half res[size()];
|
| 227 |
+
store(tmp);
|
| 228 |
+
for (const auto i : c10::irange(size())) {
|
| 229 |
+
if (_isnan(tmp[i])) {
|
| 230 |
+
std::memset(static_cast<void*>(&res[i]), 0xFF, sizeof(c10::Half));
|
| 231 |
+
} else {
|
| 232 |
+
std::memset(static_cast<void*>(&res[i]), 0, sizeof(c10::Half));
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
return loadu(res);
|
| 236 |
+
#endif
|
| 237 |
+
}
|
| 238 |
+
bool has_inf_nan() const {
|
| 239 |
+
__at_align__ c10::Half tmp[size()];
|
| 240 |
+
store(tmp);
|
| 241 |
+
for (const auto i : c10::irange(size())) {
|
| 242 |
+
if (_isnan(tmp[i]) || _isinf(tmp[i])) {
|
| 243 |
+
return true;
|
| 244 |
+
}
|
| 245 |
+
}
|
| 246 |
+
return false;
|
| 247 |
+
}
|
| 248 |
+
Vectorized<c10::Half> abs() const {
|
| 249 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 250 |
+
return Vectorized<c10::Half>(vabsq_f16(values));
|
| 251 |
+
#else
|
| 252 |
+
return map_with_vec_float_method(&Vectorized<float>::abs);
|
| 253 |
+
#endif
|
| 254 |
+
}
|
| 255 |
+
Vectorized<c10::Half> frac() const;
|
| 256 |
+
Vectorized<c10::Half> neg() const {
|
| 257 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 258 |
+
return Vectorized<c10::Half>(vnegq_f16(values));
|
| 259 |
+
#else
|
| 260 |
+
return map_with_vec_float_method(&Vectorized<float>::neg);
|
| 261 |
+
#endif
|
| 262 |
+
}
|
| 263 |
+
Vectorized<c10::Half> trunc() const {
|
| 264 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 265 |
+
return Vectorized<c10::Half>(vrndq_f16(values));
|
| 266 |
+
#else
|
| 267 |
+
return map_with_vec_float_method(&Vectorized<float>::trunc);
|
| 268 |
+
#endif
|
| 269 |
+
}
|
| 270 |
+
Vectorized<c10::Half> sqrt() const {
|
| 271 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 272 |
+
return Vectorized<c10::Half>(vsqrtq_f16(values));
|
| 273 |
+
#else
|
| 274 |
+
return map_with_vec_float_method(&Vectorized<float>::sqrt);
|
| 275 |
+
#endif
|
| 276 |
+
}
|
| 277 |
+
Vectorized<c10::Half> reciprocal() const {
|
| 278 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 279 |
+
auto ones = vdupq_n_f16(1.0f);
|
| 280 |
+
return Vectorized<c10::Half>(vdivq_f16(ones, values));
|
| 281 |
+
#else
|
| 282 |
+
return map_with_vec_float_method(&Vectorized<float>::reciprocal);
|
| 283 |
+
#endif
|
| 284 |
+
}
|
| 285 |
+
Vectorized<c10::Half> operator==(const Vectorized<c10::Half>& other) const {
|
| 286 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 287 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(vceqq_f16(values, other.values)));
|
| 288 |
+
#else
|
| 289 |
+
return map2_bitmask_with_vec_float_method(other, &Vectorized<float>::operator==);
|
| 290 |
+
#endif
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
Vectorized<c10::Half> operator!=(const Vectorized<c10::Half>& other) const {
|
| 294 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 295 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(
|
| 296 |
+
vmvnq_u16(vceqq_f16(values, other.values))));
|
| 297 |
+
#else
|
| 298 |
+
return map2_bitmask_with_vec_float_method(other, &Vectorized<float>::operator!=);
|
| 299 |
+
#endif
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
Vectorized<c10::Half> operator<(const Vectorized<c10::Half>& other) const {
|
| 303 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 304 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(vcltq_f16(values, other.values)));
|
| 305 |
+
#else
|
| 306 |
+
return map2_bitmask_with_vec_float_method(other, &Vectorized<float>::operator<);
|
| 307 |
+
#endif
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
Vectorized<c10::Half> operator<=(const Vectorized<c10::Half>& other) const {
|
| 311 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 312 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(vcleq_f16(values, other.values)));
|
| 313 |
+
#else
|
| 314 |
+
return map2_bitmask_with_vec_float_method(other, &Vectorized<float>::operator<=);
|
| 315 |
+
#endif
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
Vectorized<c10::Half> operator>(const Vectorized<c10::Half>& other) const {
|
| 319 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 320 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(vcgtq_f16(values, other.values)));
|
| 321 |
+
#else
|
| 322 |
+
return map2_bitmask_with_vec_float_method(other, &Vectorized<float>::operator>);
|
| 323 |
+
#endif
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
+
Vectorized<c10::Half> operator>=(const Vectorized<c10::Half>& other) const {
|
| 327 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 328 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(vcgeq_f16(values, other.values)));
|
| 329 |
+
#else
|
| 330 |
+
return map2_bitmask_with_vec_float_method(other, &Vectorized<float>::operator>=);
|
| 331 |
+
#endif
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
Vectorized<c10::Half> eq(const Vectorized<c10::Half>& other) const;
|
| 335 |
+
Vectorized<c10::Half> ne(const Vectorized<c10::Half>& other) const;
|
| 336 |
+
Vectorized<c10::Half> gt(const Vectorized<c10::Half>& other) const;
|
| 337 |
+
Vectorized<c10::Half> ge(const Vectorized<c10::Half>& other) const;
|
| 338 |
+
Vectorized<c10::Half> lt(const Vectorized<c10::Half>& other) const;
|
| 339 |
+
Vectorized<c10::Half> le(const Vectorized<c10::Half>& other) const;
|
| 340 |
+
}; // Vectorized<Half>
|
| 341 |
+
|
| 342 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_half_float(const Vectorized<Half>& a) {
|
| 343 |
+
static_assert(Vectorized<Half>::size() == 2 * Vectorized<float>::size());
|
| 344 |
+
float16x8_t x = a;
|
| 345 |
+
float32x4_t x1 = vcvt_f32_f16(vget_low_f16(x));
|
| 346 |
+
float32x4_t x2 = vcvt_f32_f16(vget_high_f16(x));
|
| 347 |
+
return { Vectorized<float>(x1), Vectorized<float>(x2) };
|
| 348 |
+
}
|
| 349 |
+
inline Vectorized<Half> convert_float_half(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 350 |
+
static_assert(Vectorized<Half>::size() == 2 * Vectorized<float>::size());
|
| 351 |
+
float32x4_t x = a;
|
| 352 |
+
float32x4_t y = b;
|
| 353 |
+
float16x4_t x1 = vcvt_f16_f32(x);
|
| 354 |
+
float16x4_t x2 = vcvt_f16_f32(y);
|
| 355 |
+
return Vectorized<Half>(vcombine_f16(x1, x2));
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
template <typename Op>
|
| 359 |
+
Vectorized<c10::Half> binary_operator_via_float(
|
| 360 |
+
Op op,
|
| 361 |
+
const Vectorized<c10::Half>& a,
|
| 362 |
+
const Vectorized<c10::Half>& b) {
|
| 363 |
+
const auto [a_float_low, a_float_high] = convert_half_float(a);
|
| 364 |
+
const auto [b_float_low, b_float_high] = convert_half_float(b);
|
| 365 |
+
return convert_float_half(
|
| 366 |
+
op(a_float_low, b_float_low),
|
| 367 |
+
op(a_float_high, b_float_high));
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
template <>
|
| 371 |
+
Vectorized<c10::Half> inline operator+(
|
| 372 |
+
const Vectorized<c10::Half>& a,
|
| 373 |
+
const Vectorized<c10::Half>& b) {
|
| 374 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 375 |
+
return Vectorized<c10::Half>(vaddq_f16(a, b));
|
| 376 |
+
#else
|
| 377 |
+
return binary_operator_via_float(std::plus<Vectorized<float>>(), a, b);
|
| 378 |
+
#endif
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
template <>
|
| 382 |
+
Vectorized<c10::Half> inline operator-(
|
| 383 |
+
const Vectorized<c10::Half>& a,
|
| 384 |
+
const Vectorized<c10::Half>& b) {
|
| 385 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 386 |
+
return Vectorized<c10::Half>(vsubq_f16(a, b));
|
| 387 |
+
#else
|
| 388 |
+
return binary_operator_via_float(std::minus<Vectorized<float>>(), a, b);
|
| 389 |
+
#endif
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
template <>
|
| 393 |
+
Vectorized<c10::Half> inline operator*(
|
| 394 |
+
const Vectorized<c10::Half>& a,
|
| 395 |
+
const Vectorized<c10::Half>& b) {
|
| 396 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 397 |
+
return Vectorized<c10::Half>(vmulq_f16(a, b));
|
| 398 |
+
#else
|
| 399 |
+
return binary_operator_via_float(std::multiplies<Vectorized<float>>(), a, b);
|
| 400 |
+
#endif
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
template <>
|
| 404 |
+
Vectorized<c10::Half> inline operator/(
|
| 405 |
+
const Vectorized<c10::Half>& a,
|
| 406 |
+
const Vectorized<c10::Half>& b) {
|
| 407 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 408 |
+
return Vectorized<c10::Half>(vdivq_f16(a, b));
|
| 409 |
+
#else
|
| 410 |
+
return binary_operator_via_float(std::divides<Vectorized<float>>(), a, b);
|
| 411 |
+
#endif
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
// frac. Implement this here so we can use subtraction
|
| 415 |
+
inline Vectorized<c10::Half> Vectorized<c10::Half>::frac() const {
|
| 416 |
+
return *this - this->trunc();
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 420 |
+
// either input is a NaN.
|
| 421 |
+
template <>
|
| 422 |
+
Vectorized<c10::Half> inline maximum(
|
| 423 |
+
const Vectorized<c10::Half>& a,
|
| 424 |
+
const Vectorized<c10::Half>& b) {
|
| 425 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 426 |
+
return Vectorized<c10::Half>(vmaxq_f16(a, b));
|
| 427 |
+
#else
|
| 428 |
+
return binary_operator_via_float(
|
| 429 |
+
static_cast<Vectorized<float>(*)(const Vectorized<float>&, const Vectorized<float>&)>(&maximum),
|
| 430 |
+
a,
|
| 431 |
+
b);
|
| 432 |
+
#endif
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 436 |
+
// either input is a NaN.
|
| 437 |
+
template <>
|
| 438 |
+
Vectorized<c10::Half> inline minimum(
|
| 439 |
+
const Vectorized<c10::Half>& a,
|
| 440 |
+
const Vectorized<c10::Half>& b) {
|
| 441 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 442 |
+
return Vectorized<c10::Half>(vminq_f16(a, b));
|
| 443 |
+
#else
|
| 444 |
+
return binary_operator_via_float(
|
| 445 |
+
static_cast<Vectorized<float>(*)(const Vectorized<float>&, const Vectorized<float>&)>(&minimum),
|
| 446 |
+
a,
|
| 447 |
+
b);
|
| 448 |
+
#endif
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
template <>
|
| 452 |
+
Vectorized<c10::Half> inline clamp(
|
| 453 |
+
const Vectorized<c10::Half>& a,
|
| 454 |
+
const Vectorized<c10::Half>& min,
|
| 455 |
+
const Vectorized<c10::Half>& max) {
|
| 456 |
+
return minimum(max, maximum(min, a));
|
| 457 |
+
}
|
| 458 |
+
|
| 459 |
+
template <>
|
| 460 |
+
Vectorized<c10::Half> inline clamp_max(
|
| 461 |
+
const Vectorized<c10::Half>& a,
|
| 462 |
+
const Vectorized<c10::Half>& max) {
|
| 463 |
+
return minimum(max, a);
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
template <>
|
| 467 |
+
Vectorized<c10::Half> inline clamp_min(
|
| 468 |
+
const Vectorized<c10::Half>& a,
|
| 469 |
+
const Vectorized<c10::Half>& min) {
|
| 470 |
+
return maximum(min, a);
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
template <>
|
| 474 |
+
Vectorized<c10::Half> inline operator&(
|
| 475 |
+
const Vectorized<c10::Half>& a,
|
| 476 |
+
const Vectorized<c10::Half>& b) {
|
| 477 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(vandq_u16(
|
| 478 |
+
vreinterpretq_u16_f16(a), vreinterpretq_u16_f16(b))));
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
template <>
|
| 482 |
+
Vectorized<c10::Half> inline operator|(
|
| 483 |
+
const Vectorized<c10::Half>& a,
|
| 484 |
+
const Vectorized<c10::Half>& b) {
|
| 485 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(vorrq_u16(
|
| 486 |
+
vreinterpretq_u16_f16(a), vreinterpretq_u16_f16(b))));
|
| 487 |
+
}
|
| 488 |
+
|
| 489 |
+
template <>
|
| 490 |
+
Vectorized<c10::Half> inline operator^(
|
| 491 |
+
const Vectorized<c10::Half>& a,
|
| 492 |
+
const Vectorized<c10::Half>& b) {
|
| 493 |
+
return Vectorized<c10::Half>(vreinterpretq_f16_u16(veorq_u16(
|
| 494 |
+
vreinterpretq_u16_f16(a), vreinterpretq_u16_f16(b))));
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
inline Vectorized<c10::Half> Vectorized<c10::Half>::eq(
|
| 498 |
+
const Vectorized<c10::Half>& other) const {
|
| 499 |
+
return (*this == other) & Vectorized<c10::Half>(1);
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
inline Vectorized<c10::Half> Vectorized<c10::Half>::ne(
|
| 503 |
+
const Vectorized<c10::Half>& other) const {
|
| 504 |
+
return (*this != other) & Vectorized<c10::Half>(1);
|
| 505 |
+
}
|
| 506 |
+
|
| 507 |
+
inline Vectorized<c10::Half> Vectorized<c10::Half>::gt(
|
| 508 |
+
const Vectorized<c10::Half>& other) const {
|
| 509 |
+
return (*this > other) & Vectorized<c10::Half>(1);
|
| 510 |
+
}
|
| 511 |
+
|
| 512 |
+
inline Vectorized<c10::Half> Vectorized<c10::Half>::ge(
|
| 513 |
+
const Vectorized<c10::Half>& other) const {
|
| 514 |
+
return (*this >= other) & Vectorized<c10::Half>(1);
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
inline Vectorized<c10::Half> Vectorized<c10::Half>::lt(
|
| 518 |
+
const Vectorized<c10::Half>& other) const {
|
| 519 |
+
return (*this < other) & Vectorized<c10::Half>(1);
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
inline Vectorized<c10::Half> Vectorized<c10::Half>::le(
|
| 523 |
+
const Vectorized<c10::Half>& other) const {
|
| 524 |
+
return (*this <= other) & Vectorized<c10::Half>(1);
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
// These are global functions, so the defaults in vec_base.h should
|
| 528 |
+
// work fine if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC is not available.
|
| 529 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 530 |
+
template <>
|
| 531 |
+
inline void convert(const float16_t* src, int16_t* dst, int64_t n) {
|
| 532 |
+
int64_t i;
|
| 533 |
+
#ifndef __msvc_cl__
|
| 534 |
+
#pragma unroll
|
| 535 |
+
#endif
|
| 536 |
+
for (i = 0; i <= (n - Vectorized<c10::Half>::size());
|
| 537 |
+
i += Vectorized<c10::Half>::size()) {
|
| 538 |
+
vst1q_s16(dst + i, vcvtq_s16_f16(vld1q_f16(src + i)));
|
| 539 |
+
}
|
| 540 |
+
#ifndef __msvc_cl__
|
| 541 |
+
#pragma unroll
|
| 542 |
+
#endif
|
| 543 |
+
for (; i < n; i++) {
|
| 544 |
+
dst[i] = static_cast<int16_t>(src[i]);
|
| 545 |
+
}
|
| 546 |
+
}
|
| 547 |
+
|
| 548 |
+
template <>
|
| 549 |
+
inline void convert(const int16_t* src, float16_t* dst, int64_t n) {
|
| 550 |
+
int64_t i;
|
| 551 |
+
#ifndef __msvc_cl__
|
| 552 |
+
#pragma unroll
|
| 553 |
+
#endif
|
| 554 |
+
for (i = 0; i <= (n - Vectorized<c10::Half>::size());
|
| 555 |
+
i += Vectorized<c10::Half>::size()) {
|
| 556 |
+
vst1q_f16(dst + i, vcvtq_f16_s16(vld1q_s16(src + i)));
|
| 557 |
+
}
|
| 558 |
+
#ifndef __msvc_cl__
|
| 559 |
+
#pragma unroll
|
| 560 |
+
#endif
|
| 561 |
+
for (; i < n; i++) {
|
| 562 |
+
dst[i] = static_cast<float16_t>(src[i]);
|
| 563 |
+
}
|
| 564 |
+
}
|
| 565 |
+
#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 566 |
+
|
| 567 |
+
template <>
|
| 568 |
+
Vectorized<c10::Half> inline fmadd(
|
| 569 |
+
const Vectorized<c10::Half>& a,
|
| 570 |
+
const Vectorized<c10::Half>& b,
|
| 571 |
+
const Vectorized<c10::Half>& c) {
|
| 572 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 573 |
+
return Vectorized<c10::Half>(vfmaq_f16(c, a, b));
|
| 574 |
+
#else
|
| 575 |
+
const auto [a_float_low, a_float_high] = convert_half_float(a);
|
| 576 |
+
const auto [b_float_low, b_float_high] = convert_half_float(b);
|
| 577 |
+
const auto [c_float_low, c_float_high] = convert_half_float(c);
|
| 578 |
+
return convert_float_half(
|
| 579 |
+
fmadd(a_float_low, b_float_low, c_float_low),
|
| 580 |
+
fmadd(a_float_high, b_float_high, c_float_high));
|
| 581 |
+
#endif
|
| 582 |
+
}
|
| 583 |
+
|
| 584 |
+
template <>
|
| 585 |
+
Vectorized<c10::Half> inline fmsub(
|
| 586 |
+
const Vectorized<c10::Half>& a,
|
| 587 |
+
const Vectorized<c10::Half>& b,
|
| 588 |
+
const Vectorized<c10::Half>& c) {
|
| 589 |
+
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
|
| 590 |
+
return Vectorized<c10::Half>(vfmsq_f16(c, a, b));
|
| 591 |
+
#else
|
| 592 |
+
const auto [a_float_low, a_float_high] = convert_half_float(a);
|
| 593 |
+
const auto [b_float_low, b_float_high] = convert_half_float(b);
|
| 594 |
+
const auto [c_float_low, c_float_high] = convert_half_float(c);
|
| 595 |
+
return convert_float_half(
|
| 596 |
+
fmsub(a_float_low, b_float_low, c_float_low),
|
| 597 |
+
fmsub(a_float_high, b_float_high, c_float_high));
|
| 598 |
+
#endif
|
| 599 |
+
}
|
| 600 |
+
#endif // !defined(C10_MOBILE) && defined(__aarch64__)
|
| 601 |
+
|
| 602 |
+
} // namespace CPU_CAPABILITY
|
| 603 |
+
} // namespace at::vec
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_reduced_precision_common_neon.h
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
// Shared code for bfloat16 and float16.
|
| 3 |
+
|
| 4 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 5 |
+
// See Note [Do not compile initializers with AVX]
|
| 6 |
+
|
| 7 |
+
namespace at::vec {
|
| 8 |
+
inline namespace CPU_CAPABILITY {
|
| 9 |
+
|
| 10 |
+
// Shared implementation between Vectorized<c10::Half> and
|
| 11 |
+
// Vectorized<c10::BFloat16>. Uses CRTP to allow derived class
|
| 12 |
+
// customization.
|
| 13 |
+
template <typename VecT, typename ValueT, template <int, bool> typename BlendRegs, typename Derived>
|
| 14 |
+
struct Vectorized16 {
|
| 15 |
+
protected:
|
| 16 |
+
VecT values;
|
| 17 |
+
public:
|
| 18 |
+
using value_type = ValueT;
|
| 19 |
+
using size_type = int;
|
| 20 |
+
static constexpr size_type size() {
|
| 21 |
+
static_assert(sizeof(VecT) == 8 * sizeof(value_type));
|
| 22 |
+
return 8;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
protected:
|
| 26 |
+
Derived map2(
|
| 27 |
+
const Derived& second,
|
| 28 |
+
value_type (*const f)(value_type, value_type)) const {
|
| 29 |
+
__at_align__ value_type tmp_first[size()];
|
| 30 |
+
__at_align__ value_type tmp_second[size()];
|
| 31 |
+
static_cast<const Derived*>(this)->store(tmp_first); // store this to tmp_first
|
| 32 |
+
second.store(tmp_second);
|
| 33 |
+
for (const auto i : c10::irange(size())) {
|
| 34 |
+
tmp_first[i] = f(tmp_first[i], tmp_second[i]);
|
| 35 |
+
}
|
| 36 |
+
return Derived::loadu(tmp_first);
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
public:
|
| 40 |
+
Vectorized16() = default;
|
| 41 |
+
Vectorized16(VecT v) : values(v) {}
|
| 42 |
+
|
| 43 |
+
operator VecT() const {
|
| 44 |
+
return values;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
template <int64_t mask>
|
| 48 |
+
static Derived blend(const Derived& a, const Derived& b) {
|
| 49 |
+
Derived vec;
|
| 50 |
+
vec.values = BlendRegs<0, (mask & 0x01) != 0>::impl(
|
| 51 |
+
a.values, b.values, vec.values);
|
| 52 |
+
vec.values = BlendRegs<1, (mask & 0x02) != 0>::impl(
|
| 53 |
+
a.values, b.values, vec.values);
|
| 54 |
+
vec.values = BlendRegs<2, (mask & 0x04) != 0>::impl(
|
| 55 |
+
a.values, b.values, vec.values);
|
| 56 |
+
vec.values = BlendRegs<3, (mask & 0x08) != 0>::impl(
|
| 57 |
+
a.values, b.values, vec.values);
|
| 58 |
+
|
| 59 |
+
vec.values = BlendRegs<4, (mask & 0x10) != 0>::impl(
|
| 60 |
+
a.values, b.values, vec.values);
|
| 61 |
+
vec.values = BlendRegs<5, (mask & 0x20) != 0>::impl(
|
| 62 |
+
a.values, b.values, vec.values);
|
| 63 |
+
vec.values = BlendRegs<6, (mask & 0x40) != 0>::impl(
|
| 64 |
+
a.values, b.values, vec.values);
|
| 65 |
+
vec.values = BlendRegs<7, (mask & 0x80) != 0>::impl(
|
| 66 |
+
a.values, b.values, vec.values);
|
| 67 |
+
|
| 68 |
+
return vec;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
template <typename step_t>
|
| 72 |
+
static Derived arange(
|
| 73 |
+
value_type base = 0,
|
| 74 |
+
step_t step = static_cast<step_t>(1)) {
|
| 75 |
+
const Derived base_vec(base);
|
| 76 |
+
const Derived step_vec(step);
|
| 77 |
+
const Derived step_sizes(
|
| 78 |
+
value_type(0),
|
| 79 |
+
value_type(1),
|
| 80 |
+
value_type(2),
|
| 81 |
+
value_type(3),
|
| 82 |
+
value_type(4),
|
| 83 |
+
value_type(5),
|
| 84 |
+
value_type(6),
|
| 85 |
+
value_type(7));
|
| 86 |
+
return fmadd(step_sizes, step_vec, base_vec);
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
// Very slow implementation of indexing.
|
| 90 |
+
// Only required because vec256_qint refers to this.
|
| 91 |
+
// Once we specialize that implementation for ARM
|
| 92 |
+
// this should be removed. TODO (kimishpatel)
|
| 93 |
+
value_type operator[](int idx) const {
|
| 94 |
+
__at_align__ value_type tmp[size()];
|
| 95 |
+
static_cast<const Derived*>(this)->store(tmp);
|
| 96 |
+
return tmp[idx];
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
int zero_mask() const {
|
| 100 |
+
__at_align__ value_type tmp[size()];
|
| 101 |
+
static_cast<const Derived*>(this)->store(tmp);
|
| 102 |
+
int mask = 0;
|
| 103 |
+
for (int i = 0; i < size(); ++i) {
|
| 104 |
+
if (tmp[i] == 0) {
|
| 105 |
+
mask |= (1 << i);
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
return mask;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
Derived map(value_type (*const f)(value_type)) const {
|
| 112 |
+
__at_align__ value_type tmp[size()];
|
| 113 |
+
static_cast<const Derived*>(this)->store(tmp);
|
| 114 |
+
for (const auto i : c10::irange(size())) {
|
| 115 |
+
tmp[i] = f(tmp[i]);
|
| 116 |
+
}
|
| 117 |
+
return Derived::loadu(tmp);
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
Derived angle() const {
|
| 121 |
+
auto zero = Derived(0);
|
| 122 |
+
auto pi = Derived(c10::pi<value_type>);
|
| 123 |
+
auto tmp = Derived::blendv(zero, pi, *static_cast<const Derived*>(this) < zero);
|
| 124 |
+
return Derived::blendv(tmp, *static_cast<const Derived*>(this), static_cast<const Derived*>(this)->isnan());
|
| 125 |
+
}
|
| 126 |
+
Derived real() const {
|
| 127 |
+
return *this;
|
| 128 |
+
}
|
| 129 |
+
Derived imag() const {
|
| 130 |
+
return Derived(0);
|
| 131 |
+
}
|
| 132 |
+
Derived conj() const {
|
| 133 |
+
return *this;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
// Sleef does not support FP16/BF16, so many math functions are applied by
|
| 137 |
+
// converting to FP32, applying the math function, and then converting back to
|
| 138 |
+
// FP16/BF16.
|
| 139 |
+
Derived acos() const {
|
| 140 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::acos);
|
| 141 |
+
}
|
| 142 |
+
Derived acosh() const {
|
| 143 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::acosh);
|
| 144 |
+
}
|
| 145 |
+
Derived asin() const {
|
| 146 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::asin);
|
| 147 |
+
}
|
| 148 |
+
Derived atan() const {
|
| 149 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::atan);
|
| 150 |
+
}
|
| 151 |
+
Derived atanh() const {
|
| 152 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::atanh);
|
| 153 |
+
}
|
| 154 |
+
Derived atan2(const Derived& exp) const {
|
| 155 |
+
return static_cast<const Derived*>(this)->map2_with_vec_float_method(exp, &Vectorized<float>::atan2);
|
| 156 |
+
}
|
| 157 |
+
Derived copysign(const Derived& sign) const {
|
| 158 |
+
return static_cast<const Derived*>(this)->map2_with_vec_float_method(sign, &Vectorized<float>::copysign);
|
| 159 |
+
}
|
| 160 |
+
Derived erf() const {
|
| 161 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::erf);
|
| 162 |
+
}
|
| 163 |
+
Derived erfc() const {
|
| 164 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::erfc);
|
| 165 |
+
}
|
| 166 |
+
Derived erfinv() const {
|
| 167 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::erfinv);
|
| 168 |
+
}
|
| 169 |
+
Derived exp() const {
|
| 170 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::exp);
|
| 171 |
+
}
|
| 172 |
+
Derived exp2() const {
|
| 173 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::exp2);
|
| 174 |
+
}
|
| 175 |
+
Derived expm1() const {
|
| 176 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::expm1);
|
| 177 |
+
}
|
| 178 |
+
Derived exp_u20() const {
|
| 179 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::exp_u20);
|
| 180 |
+
}
|
| 181 |
+
Derived fmod(const Derived& q) const {
|
| 182 |
+
// This function is questionable with a conversion, so we use map2
|
| 183 |
+
return map2(q, std::fmod);
|
| 184 |
+
}
|
| 185 |
+
Derived hypot(const Derived& b) const {
|
| 186 |
+
return static_cast<const Derived*>(this)->map2_with_vec_float_method(b, &Vectorized<float>::hypot);
|
| 187 |
+
}
|
| 188 |
+
Derived i0() const {
|
| 189 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::i0);
|
| 190 |
+
}
|
| 191 |
+
Derived i0e() const {
|
| 192 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::i0e);
|
| 193 |
+
}
|
| 194 |
+
Derived digamma() const {
|
| 195 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::digamma);
|
| 196 |
+
}
|
| 197 |
+
Derived igamma(const Derived& x) const {
|
| 198 |
+
return static_cast<const Derived*>(this)->map2_with_vec_float_method(x, &Vectorized<float>::igamma);
|
| 199 |
+
}
|
| 200 |
+
Derived igammac(const Derived& x) const {
|
| 201 |
+
return static_cast<const Derived*>(this)->map2_with_vec_float_method(x, &Vectorized<float>::igammac);
|
| 202 |
+
}
|
| 203 |
+
Derived log() const {
|
| 204 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::log);
|
| 205 |
+
}
|
| 206 |
+
Derived log10() const {
|
| 207 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::log10);
|
| 208 |
+
}
|
| 209 |
+
Derived log1p() const {
|
| 210 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::log1p);
|
| 211 |
+
}
|
| 212 |
+
Derived log2() const {
|
| 213 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::log2);
|
| 214 |
+
}
|
| 215 |
+
Derived nextafter(const Derived& b) const {
|
| 216 |
+
// This function does not make sense with conversion, so we use map2
|
| 217 |
+
return map2(b, std::nextafter);
|
| 218 |
+
}
|
| 219 |
+
Derived sin() const {
|
| 220 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::sin);
|
| 221 |
+
}
|
| 222 |
+
Derived sinh() const {
|
| 223 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::sinh);
|
| 224 |
+
}
|
| 225 |
+
Derived cos() const {
|
| 226 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::cos);
|
| 227 |
+
}
|
| 228 |
+
Derived cosh() const {
|
| 229 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::cosh);
|
| 230 |
+
}
|
| 231 |
+
Derived ceil() const {
|
| 232 |
+
// This function is questionable with a conversion, so we use map
|
| 233 |
+
return map(at::native::ceil_impl);
|
| 234 |
+
}
|
| 235 |
+
Derived floor() const {
|
| 236 |
+
// This function is questionable with a conversion, so we use map
|
| 237 |
+
return map(at::native::floor_impl);
|
| 238 |
+
}
|
| 239 |
+
Derived round() const {
|
| 240 |
+
// This function is questionable with a conversion, so we use map
|
| 241 |
+
return map(at::native::round_impl);
|
| 242 |
+
}
|
| 243 |
+
Derived tan() const {
|
| 244 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::tan);
|
| 245 |
+
}
|
| 246 |
+
Derived tanh() const {
|
| 247 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::tanh);
|
| 248 |
+
}
|
| 249 |
+
Derived lgamma() const {
|
| 250 |
+
return static_cast<const Derived*>(this)->map_with_vec_float_method(&Vectorized<float>::lgamma);
|
| 251 |
+
}
|
| 252 |
+
Derived rsqrt() const {
|
| 253 |
+
return static_cast<const Derived*>(this)->sqrt().reciprocal();
|
| 254 |
+
}
|
| 255 |
+
Derived pow(const Derived& exp) const {
|
| 256 |
+
return static_cast<const Derived*>(this)->map2_with_vec_float_method(exp, &Vectorized<float>::pow);
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
};
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
} // namespace CPU_CAPABILITY
|
| 263 |
+
} // namespace at::vec
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/missing_vld1_neon.h
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Workaround for missing vld1_*_x2 and vst1_*_x2 intrinsics in gcc-7. */
|
| 2 |
+
|
| 3 |
+
__extension__ extern __inline uint8x8x2_t
|
| 4 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 5 |
+
vld1_u8_x2 (const uint8_t *__a)
|
| 6 |
+
{
|
| 7 |
+
uint8x8x2_t ret;
|
| 8 |
+
asm volatile("ld1 {%S0.8b - %T0.8b}, %1" : "=w" (ret) : "Q"(*__a));
|
| 9 |
+
return ret;
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
__extension__ extern __inline int8x8x2_t
|
| 13 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 14 |
+
vld1_s8_x2 (const int8_t *__a)
|
| 15 |
+
{
|
| 16 |
+
int8x8x2_t ret;
|
| 17 |
+
asm volatile("ld1 {%S0.8b - %T0.8b}, %1" : "=w" (ret) : "Q"(*__a));
|
| 18 |
+
return ret;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
__extension__ extern __inline uint16x4x2_t
|
| 22 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 23 |
+
vld1_u16_x2 (const uint16_t *__a)
|
| 24 |
+
{
|
| 25 |
+
uint16x4x2_t ret;
|
| 26 |
+
asm volatile("ld1 {%S0.4h - %T0.4h}, %1" : "=w" (ret) : "Q"(*__a));
|
| 27 |
+
return ret;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
__extension__ extern __inline int16x4x2_t
|
| 31 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 32 |
+
vld1_s16_x2 (const int16_t *__a)
|
| 33 |
+
{
|
| 34 |
+
int16x4x2_t ret;
|
| 35 |
+
asm volatile("ld1 {%S0.4h - %T0.4h}, %1" : "=w" (ret) : "Q"(*__a));
|
| 36 |
+
return ret;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
__extension__ extern __inline uint32x2x2_t
|
| 40 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 41 |
+
vld1_u32_x2 (const uint32_t *__a)
|
| 42 |
+
{
|
| 43 |
+
uint32x2x2_t ret;
|
| 44 |
+
asm volatile("ld1 {%S0.2s - %T0.2s}, %1" : "=w" (ret) : "Q"(*__a));
|
| 45 |
+
return ret;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
__extension__ extern __inline int32x2x2_t
|
| 49 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 50 |
+
vld1_s32_x2 (const int32_t *__a)
|
| 51 |
+
{
|
| 52 |
+
int32x2x2_t ret;
|
| 53 |
+
asm volatile("ld1 {%S0.2s - %T0.2s}, %1" : "=w" (ret) : "Q"(*__a));
|
| 54 |
+
return ret;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
__extension__ extern __inline uint64x1x2_t
|
| 58 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 59 |
+
vld1_u64_x2 (const uint64_t *__a)
|
| 60 |
+
{
|
| 61 |
+
uint64x1x2_t ret;
|
| 62 |
+
asm volatile("ld1 {%S0.1d - %T0.1d}, %1" : "=w" (ret) : "Q"(*__a));
|
| 63 |
+
return ret;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
__extension__ extern __inline int64x1x2_t
|
| 67 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 68 |
+
vld1_s64_x2 (const int64_t *__a)
|
| 69 |
+
{
|
| 70 |
+
int64x1x2_t ret;
|
| 71 |
+
__builtin_aarch64_simd_oi __o;
|
| 72 |
+
asm volatile("ld1 {%S0.1d - %T0.1d}, %1" : "=w" (ret) : "Q"(*__a));
|
| 73 |
+
return ret;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
__extension__ extern __inline float16x4x2_t
|
| 77 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 78 |
+
vld1_f16_x2 (const float16_t *__a)
|
| 79 |
+
{
|
| 80 |
+
float16x4x2_t ret;
|
| 81 |
+
asm volatile("ld1 {%S0.4h - %T0.4h}, %1" : "=w" (ret) : "Q"(*__a));
|
| 82 |
+
return ret;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
__extension__ extern __inline float32x2x2_t
|
| 86 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 87 |
+
vld1_f32_x2 (const float32_t *__a)
|
| 88 |
+
{
|
| 89 |
+
float32x2x2_t ret;
|
| 90 |
+
asm volatile("ld1 {%S0.2s - %T0.2s}, %1" : "=w" (ret) : "Q"(*__a));
|
| 91 |
+
return ret;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
__extension__ extern __inline float64x1x2_t
|
| 95 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 96 |
+
vld1_f64_x2 (const float64_t *__a)
|
| 97 |
+
{
|
| 98 |
+
float64x1x2_t ret;
|
| 99 |
+
asm volatile("ld1 {%S0.1d - %T0.1d}, %1" : "=w" (ret) : "Q"(*__a));
|
| 100 |
+
return ret;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
__extension__ extern __inline poly8x8x2_t
|
| 104 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 105 |
+
vld1_p8_x2 (const poly8_t *__a)
|
| 106 |
+
{
|
| 107 |
+
poly8x8x2_t ret;
|
| 108 |
+
asm volatile("ld1 {%S0.8b - %T0.8b}, %1" : "=w" (ret) : "Q"(*__a));
|
| 109 |
+
return ret;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
__extension__ extern __inline poly16x4x2_t
|
| 113 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 114 |
+
vld1_p16_x2 (const poly16_t *__a)
|
| 115 |
+
{
|
| 116 |
+
poly16x4x2_t ret;
|
| 117 |
+
asm volatile("ld1 {%S0.4h - %T0.4h}, %1" : "=w" (ret) : "Q"(*__a));
|
| 118 |
+
return ret;
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
__extension__ extern __inline poly64x1x2_t
|
| 122 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 123 |
+
vld1_p64_x2 (const poly64_t *__a)
|
| 124 |
+
{
|
| 125 |
+
poly64x1x2_t ret;
|
| 126 |
+
asm volatile("ld1 {%S0.1d - %T0.1d}, %1" : "=w" (ret) : "Q"(*__a));
|
| 127 |
+
return ret;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
__extension__ extern __inline uint8x16x2_t
|
| 131 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 132 |
+
vld1q_u8_x2 (const uint8_t *__a)
|
| 133 |
+
{
|
| 134 |
+
uint8x16x2_t ret;
|
| 135 |
+
asm volatile("ld1 {%S0.16b - %T0.16b}, %1" : "=w" (ret) : "Q"(*__a));
|
| 136 |
+
return ret;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
__extension__ extern __inline int8x16x2_t
|
| 140 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 141 |
+
vld1q_s8_x2 (const int8_t *__a)
|
| 142 |
+
{
|
| 143 |
+
int8x16x2_t ret;
|
| 144 |
+
asm volatile("ld1 {%S0.16b - %T0.16b}, %1" : "=w" (ret) : "Q"(*__a));
|
| 145 |
+
return ret;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
__extension__ extern __inline uint16x8x2_t
|
| 149 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 150 |
+
vld1q_u16_x2 (const uint16_t *__a)
|
| 151 |
+
{
|
| 152 |
+
uint16x8x2_t ret;
|
| 153 |
+
asm volatile("ld1 {%S0.8h - %T0.8h}, %1" : "=w" (ret) : "Q"(*__a));
|
| 154 |
+
return ret;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
__extension__ extern __inline int16x8x2_t
|
| 158 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 159 |
+
vld1q_s16_x2 (const int16_t *__a)
|
| 160 |
+
{
|
| 161 |
+
int16x8x2_t ret;
|
| 162 |
+
asm volatile("ld1 {%S0.8h - %T0.8h}, %1" : "=w" (ret) : "Q"(*__a));
|
| 163 |
+
return ret;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
__extension__ extern __inline uint32x4x2_t
|
| 167 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 168 |
+
vld1q_u32_x2 (const uint32_t *__a)
|
| 169 |
+
{
|
| 170 |
+
uint32x4x2_t ret;
|
| 171 |
+
asm volatile("ld1 {%S0.4s - %T0.4s}, %1" : "=w" (ret) : "Q"(*__a));
|
| 172 |
+
return ret;
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
__extension__ extern __inline int32x4x2_t
|
| 176 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 177 |
+
vld1q_s32_x2 (const int32_t *__a)
|
| 178 |
+
{
|
| 179 |
+
int32x4x2_t ret;
|
| 180 |
+
asm volatile("ld1 {%S0.4s - %T0.4s}, %1" : "=w" (ret) : "Q"(*__a));
|
| 181 |
+
return ret;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
__extension__ extern __inline uint64x2x2_t
|
| 185 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 186 |
+
vld1q_u64_x2 (const uint64_t *__a)
|
| 187 |
+
{
|
| 188 |
+
uint64x2x2_t ret;
|
| 189 |
+
asm volatile("ld1 {%S0.2d - %T0.2d}, %1" : "=w" (ret) : "Q"(*__a));
|
| 190 |
+
return ret;
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
__extension__ extern __inline int64x2x2_t
|
| 194 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 195 |
+
vld1q_s64_x2 (const int64_t *__a)
|
| 196 |
+
{
|
| 197 |
+
int64x2x2_t ret;
|
| 198 |
+
asm volatile("ld1 {%S0.2d - %T0.2d}, %1" : "=w" (ret) : "Q"(*__a));
|
| 199 |
+
return ret;
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
__extension__ extern __inline float16x8x2_t
|
| 203 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 204 |
+
vld1q_f16_x2 (const float16_t *__a)
|
| 205 |
+
{
|
| 206 |
+
float16x8x2_t ret;
|
| 207 |
+
asm volatile("ld1 {%S0.8h - %T0.8h}, %1" : "=w" (ret) : "Q"(*__a));
|
| 208 |
+
return ret;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
__extension__ extern __inline float32x4x2_t
|
| 212 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 213 |
+
vld1q_f32_x2 (const float32_t *__a)
|
| 214 |
+
{
|
| 215 |
+
float32x4x2_t ret;
|
| 216 |
+
asm volatile("ld1 {%S0.4s - %T0.4s}, %1" : "=w" (ret) : "Q"(*__a));
|
| 217 |
+
return ret;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
__extension__ extern __inline float64x2x2_t
|
| 221 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 222 |
+
vld1q_f64_x2 (const float64_t *__a)
|
| 223 |
+
{
|
| 224 |
+
float64x2x2_t ret;
|
| 225 |
+
asm volatile("ld1 {%S0.2d - %T0.2d}, %1" : "=w" (ret) : "Q"(*__a));
|
| 226 |
+
return ret;
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
__extension__ extern __inline poly8x16x2_t
|
| 230 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 231 |
+
vld1q_p8_x2 (const poly8_t *__a)
|
| 232 |
+
{
|
| 233 |
+
poly8x16x2_t ret;
|
| 234 |
+
asm volatile("ld1 {%S0.16b - %T0.16b}, %1" : "=w" (ret) : "Q"(*__a));
|
| 235 |
+
return ret;
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
__extension__ extern __inline poly16x8x2_t
|
| 239 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 240 |
+
vld1q_p16_x2 (const poly16_t *__a)
|
| 241 |
+
{
|
| 242 |
+
poly16x8x2_t ret;
|
| 243 |
+
asm volatile("ld1 {%S0.8h - %T0.8h}, %1" : "=w" (ret) : "Q"(*__a));
|
| 244 |
+
return ret;
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
__extension__ extern __inline poly64x2x2_t
|
| 248 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 249 |
+
vld1q_p64_x2 (const poly64_t *__a)
|
| 250 |
+
{
|
| 251 |
+
poly64x2x2_t ret;
|
| 252 |
+
asm volatile("ld1 {%S0.2d - %T0.2d}, %1" : "=w" (ret) : "Q"(*__a));
|
| 253 |
+
return ret;
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
/* vst1x2 */
|
| 257 |
+
|
| 258 |
+
__extension__ extern __inline void
|
| 259 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 260 |
+
vst1_s64_x2 (int64_t * __a, int64x1x2_t val)
|
| 261 |
+
{
|
| 262 |
+
asm volatile("st1 {%S1.1d - %T1.1d}, %0" : "=Q" (*__a) : "w" (val));
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
__extension__ extern __inline void
|
| 266 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 267 |
+
vst1_u64_x2 (uint64_t * __a, uint64x1x2_t val)
|
| 268 |
+
{
|
| 269 |
+
asm volatile("st1 {%S1.1d - %T1.1d}, %0" : "=Q" (*__a) : "w" (val));
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
__extension__ extern __inline void
|
| 273 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 274 |
+
vst1_f64_x2 (float64_t * __a, float64x1x2_t val)
|
| 275 |
+
{
|
| 276 |
+
asm volatile("st1 {%S1.1d - %T1.1d}, %0" : "=Q" (*__a) : "w" (val));
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
__extension__ extern __inline void
|
| 280 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 281 |
+
vst1_s8_x2 (int8_t * __a, int8x8x2_t val)
|
| 282 |
+
{
|
| 283 |
+
asm volatile("st1 {%S1.8b - %T1.8b}, %0" : "=Q" (*__a) : "w" (val));
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
__extension__ extern __inline void
|
| 287 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 288 |
+
vst1_p8_x2 (poly8_t * __a, poly8x8x2_t val)
|
| 289 |
+
{
|
| 290 |
+
asm volatile("st1 {%S1.8b - %T1.8b}, %0" : "=Q" (*__a) : "w" (val));
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
__extension__ extern __inline void
|
| 294 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 295 |
+
vst1_s16_x2 (int16_t * __a, int16x4x2_t val)
|
| 296 |
+
{
|
| 297 |
+
asm volatile("st1 {%S1.4h - %T1.4h}, %0" : "=Q" (*__a) : "w" (val));
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
__extension__ extern __inline void
|
| 301 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 302 |
+
vst1_p16_x2 (poly16_t * __a, poly16x4x2_t val)
|
| 303 |
+
{
|
| 304 |
+
asm volatile("st1 {%S1.4h - %T1.4h}, %0" : "=Q" (*__a) : "w" (val));
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
__extension__ extern __inline void
|
| 308 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 309 |
+
vst1_s32_x2 (int32_t * __a, int32x2x2_t val)
|
| 310 |
+
{
|
| 311 |
+
asm volatile("st1 {%S1.2s - %T1.2s}, %0" : "=Q" (*__a) : "w" (val));
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
__extension__ extern __inline void
|
| 315 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 316 |
+
vst1_u8_x2 (uint8_t * __a, uint8x8x2_t val)
|
| 317 |
+
{
|
| 318 |
+
asm volatile("st1 {%S1.8b - %T1.8b}, %0" : "=Q" (*__a) : "w" (val));
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
__extension__ extern __inline void
|
| 322 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 323 |
+
vst1_u16_x2 (uint16_t * __a, uint16x4x2_t val)
|
| 324 |
+
{
|
| 325 |
+
asm volatile("st1 {%S1.4h - %T1.4h}, %0" : "=Q" (*__a) : "w" (val));
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
__extension__ extern __inline void
|
| 329 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 330 |
+
vst1_u32_x2 (uint32_t * __a, uint32x2x2_t val)
|
| 331 |
+
{
|
| 332 |
+
asm volatile("st1 {%S1.2s - %T1.2s}, %0" : "=Q" (*__a) : "w" (val));
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
__extension__ extern __inline void
|
| 336 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 337 |
+
vst1_f16_x2 (float16_t * __a, float16x4x2_t val)
|
| 338 |
+
{
|
| 339 |
+
asm volatile("st1 {%S1.4h - %T1.4h}, %0" : "=Q" (*__a) : "w" (val));
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
__extension__ extern __inline void
|
| 343 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 344 |
+
vst1_f32_x2 (float32_t * __a, float32x2x2_t val)
|
| 345 |
+
{
|
| 346 |
+
asm volatile("st1 {%S1.2s - %T1.2s}, %0" : "=Q" (*__a) : "w" (val));
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
__extension__ extern __inline void
|
| 350 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 351 |
+
vst1_p64_x2 (poly64_t * __a, poly64x1x2_t val)
|
| 352 |
+
{
|
| 353 |
+
asm volatile("st1 {%S1.1d - %T1.1d}, %0" : "=Q" (*__a) : "w" (val));
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
__extension__ extern __inline void
|
| 357 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 358 |
+
vst1q_s8_x2 (int8_t * __a, int8x16x2_t val)
|
| 359 |
+
{
|
| 360 |
+
asm volatile("st1 {%S1.16b - %T1.16b}, %0" : "=Q" (*__a) : "w" (val));
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
__extension__ extern __inline void
|
| 364 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 365 |
+
vst1q_p8_x2 (poly8_t * __a, poly8x16x2_t val)
|
| 366 |
+
{
|
| 367 |
+
asm volatile("st1 {%S1.16b - %T1.16b}, %0" : "=Q" (*__a) : "w" (val));
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
__extension__ extern __inline void
|
| 371 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 372 |
+
vst1q_s16_x2 (int16_t * __a, int16x8x2_t val)
|
| 373 |
+
{
|
| 374 |
+
asm volatile("st1 {%S1.8h - %T1.8h}, %0" : "=Q" (*__a) : "w" (val));
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
__extension__ extern __inline void
|
| 378 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 379 |
+
vst1q_p16_x2 (poly16_t * __a, poly16x8x2_t val)
|
| 380 |
+
{
|
| 381 |
+
asm volatile("st1 {%S1.8h - %T1.8h}, %0" : "=Q" (*__a) : "w" (val));
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
__extension__ extern __inline void
|
| 385 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 386 |
+
vst1q_s32_x2 (int32_t * __a, int32x4x2_t val)
|
| 387 |
+
{
|
| 388 |
+
asm volatile("st1 {%S1.4s - %T1.4s}, %0" : "=Q" (*__a) : "w" (val));
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
__extension__ extern __inline void
|
| 392 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 393 |
+
vst1q_s64_x2 (int64_t * __a, int64x2x2_t val)
|
| 394 |
+
{
|
| 395 |
+
asm volatile("st1 {%S1.2d - %T1.2d}, %0" : "=Q" (*__a) : "w" (val));
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
__extension__ extern __inline void
|
| 399 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 400 |
+
vst1q_u8_x2 (uint8_t * __a, uint8x16x2_t val)
|
| 401 |
+
{
|
| 402 |
+
asm volatile("st1 {%S1.16b - %T1.16b}, %0" : "=Q" (*__a) : "w" (val));
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
__extension__ extern __inline void
|
| 406 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 407 |
+
vst1q_u16_x2 (uint16_t * __a, uint16x8x2_t val)
|
| 408 |
+
{
|
| 409 |
+
asm volatile("st1 {%S1.8h - %T1.8h}, %0" : "=Q" (*__a) : "w" (val));
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
__extension__ extern __inline void
|
| 413 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 414 |
+
vst1q_u32_x2 (uint32_t * __a, uint32x4x2_t val)
|
| 415 |
+
{
|
| 416 |
+
asm volatile("st1 {%S1.4s - %T1.4s}, %0" : "=Q" (*__a) : "w" (val));
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
__extension__ extern __inline void
|
| 420 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 421 |
+
vst1q_u64_x2 (uint64_t * __a, uint64x2x2_t val)
|
| 422 |
+
{
|
| 423 |
+
asm volatile("st1 {%S1.2d - %T1.2d}, %0" : "=Q" (*__a) : "w" (val));
|
| 424 |
+
}
|
| 425 |
+
|
| 426 |
+
__extension__ extern __inline void
|
| 427 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 428 |
+
vst1q_f16_x2 (float16_t * __a, float16x8x2_t val)
|
| 429 |
+
{
|
| 430 |
+
asm volatile("st1 {%S1.8h - %T1.8h}, %0" : "=Q" (*__a) : "w" (val));
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
__extension__ extern __inline void
|
| 434 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 435 |
+
vst1q_f32_x2 (float32_t * __a, float32x4x2_t val)
|
| 436 |
+
{
|
| 437 |
+
asm volatile("st1 {%S1.4s - %T1.4s}, %0" : "=Q" (*__a) : "w" (val));
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
__extension__ extern __inline void
|
| 441 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 442 |
+
vst1q_f64_x2 (float64_t * __a, float64x2x2_t val)
|
| 443 |
+
{
|
| 444 |
+
asm volatile("st1 {%S1.2d - %T1.2d}, %0" : "=Q" (*__a) : "w" (val));
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
__extension__ extern __inline void
|
| 448 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 449 |
+
vst1q_p64_x2 (poly64_t * __a, poly64x2x2_t val)
|
| 450 |
+
{
|
| 451 |
+
asm volatile("st1 {%S1.2d - %T1.2d}, %0" : "=Q" (*__a) : "w" (val));
|
| 452 |
+
}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/missing_vst1_neon.h
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Workaround for missing vst1q_f32_x2 in gcc-8. */
|
| 2 |
+
|
| 3 |
+
__extension__ extern __inline void
|
| 4 |
+
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
| 5 |
+
vst1q_f32_x2 (float32_t * __a, float32x4x2_t val)
|
| 6 |
+
{
|
| 7 |
+
asm volatile("st1 {%S1.4s - %T1.4s}, %0" : "=Q" (*__a) : "w" (val));
|
| 8 |
+
}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256.h
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
|
| 8 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 9 |
+
#if !(defined(__VSX__) || defined(CPU_CAPABILITY_VSX) || defined(CPU_CAPABILITY_ZVECTOR))
|
| 10 |
+
#if defined(CPU_CAPABILITY_SVE256)
|
| 11 |
+
#include <ATen/cpu/vec/sve/vec_common_sve.h>
|
| 12 |
+
#endif
|
| 13 |
+
#include <ATen/cpu/vec/vec256/vec256_float.h>
|
| 14 |
+
#include <ATen/cpu/vec/vec256/vec256_bfloat16.h>
|
| 15 |
+
#include <ATen/cpu/vec/vec256/vec256_double.h>
|
| 16 |
+
#include <ATen/cpu/vec/vec256/vec256_int.h>
|
| 17 |
+
#include <ATen/cpu/vec/vec256/vec256_qint.h>
|
| 18 |
+
#include <ATen/cpu/vec/vec256/vec256_complex_float.h>
|
| 19 |
+
#include <ATen/cpu/vec/vec256/vec256_complex_double.h>
|
| 20 |
+
#elif defined(__VSX__) || defined(CPU_CAPABILITY_VSX)
|
| 21 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_common_vsx.h>
|
| 22 |
+
#else
|
| 23 |
+
#include <ATen/cpu/vec/vec256/zarch/vec256_zarch.h>
|
| 24 |
+
#include <ATen/cpu/vec/vec256/vec256_bfloat16.h>
|
| 25 |
+
#endif
|
| 26 |
+
|
| 27 |
+
#include <ATen/cpu/vec/vec256/vec256_convert.h>
|
| 28 |
+
#include <ATen/cpu/vec/vec256/vec256_mask.h>
|
| 29 |
+
|
| 30 |
+
#include <algorithm>
|
| 31 |
+
#include <cstddef>
|
| 32 |
+
#include <cstdint>
|
| 33 |
+
#include <cstring>
|
| 34 |
+
#include <ostream>
|
| 35 |
+
|
| 36 |
+
namespace at::vec {
|
| 37 |
+
|
| 38 |
+
// Note [CPU_CAPABILITY namespace]
|
| 39 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 40 |
+
// This header, and all of its subheaders, will be compiled with
|
| 41 |
+
// different architecture flags for each supported set of vector
|
| 42 |
+
// intrinsics. So we need to make sure they aren't inadvertently
|
| 43 |
+
// linked together. We do this by declaring objects in an `inline
|
| 44 |
+
// namespace` which changes the name mangling, but can still be
|
| 45 |
+
// accessed as `at::vec`.
|
| 46 |
+
inline namespace CPU_CAPABILITY {
|
| 47 |
+
|
| 48 |
+
inline std::ostream& operator<<(std::ostream& stream, const c10::qint32& val) {
|
| 49 |
+
stream << val.val_;
|
| 50 |
+
return stream;
|
| 51 |
+
}
|
| 52 |
+
inline std::ostream& operator<<(std::ostream& stream, const c10::qint8& val) {
|
| 53 |
+
stream << static_cast<int>(val.val_);
|
| 54 |
+
return stream;
|
| 55 |
+
}
|
| 56 |
+
inline std::ostream& operator<<(std::ostream& stream, const c10::quint8& val) {
|
| 57 |
+
stream << static_cast<unsigned int>(val.val_);
|
| 58 |
+
return stream;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
template <typename T>
|
| 62 |
+
std::ostream& operator<<(std::ostream& stream, const Vectorized<T>& vec) {
|
| 63 |
+
T buf[Vectorized<T>::size()];
|
| 64 |
+
vec.store(buf);
|
| 65 |
+
stream << "vec[";
|
| 66 |
+
for (int i = 0; i != Vectorized<T>::size(); i++) {
|
| 67 |
+
if (i != 0) {
|
| 68 |
+
stream << ", ";
|
| 69 |
+
}
|
| 70 |
+
stream << buf[i];
|
| 71 |
+
}
|
| 72 |
+
stream << "]";
|
| 73 |
+
return stream;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 78 |
+
|
| 79 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CAST (AVX2) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 80 |
+
|
| 81 |
+
template<>
|
| 82 |
+
inline Vectorized<float> cast<float, double>(const Vectorized<double>& src) {
|
| 83 |
+
return _mm256_castpd_ps(src);
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
template<>
|
| 87 |
+
inline Vectorized<double> cast<double, float>(const Vectorized<float>& src) {
|
| 88 |
+
return _mm256_castps_pd(src);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
template<>
|
| 92 |
+
inline Vectorized<float> cast<float, int32_t>(const Vectorized<int32_t>& src) {
|
| 93 |
+
return _mm256_castsi256_ps(src);
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
template<>
|
| 97 |
+
inline Vectorized<double> cast<double, int64_t>(const Vectorized<int64_t>& src) {
|
| 98 |
+
return _mm256_castsi256_pd(src);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GATHER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 102 |
+
#ifndef _MSC_VER
|
| 103 |
+
// MSVC is not working well on complex function overload.
|
| 104 |
+
template<int64_t scale = 1>
|
| 105 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<double>>
|
| 106 |
+
inline gather(const double* base_addr, const Vectorized<int64_t>& vindex) {
|
| 107 |
+
return _mm256_i64gather_pd(base_addr, vindex, scale);
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
template<int64_t scale = 1>
|
| 111 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<float>>
|
| 112 |
+
inline gather(const float* base_addr, const Vectorized<int32_t>& vindex) {
|
| 113 |
+
return _mm256_i32gather_ps(base_addr, vindex, scale);
|
| 114 |
+
}
|
| 115 |
+
#endif
|
| 116 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MASK GATHER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 117 |
+
#ifndef _MSC_VER
|
| 118 |
+
// MSVC is not working well on complex function overload.
|
| 119 |
+
template<int64_t scale = 1>
|
| 120 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<double>>
|
| 121 |
+
inline mask_gather(const Vectorized<double>& src, const double* base_addr,
|
| 122 |
+
const Vectorized<int64_t>& vindex, Vectorized<double>& mask) {
|
| 123 |
+
return _mm256_mask_i64gather_pd(src, base_addr, vindex, mask, scale);
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
template<int64_t scale = 1>
|
| 127 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<float>>
|
| 128 |
+
inline mask_gather(const Vectorized<float>& src, const float* base_addr,
|
| 129 |
+
const Vectorized<int32_t>& vindex, Vectorized<float>& mask) {
|
| 130 |
+
return _mm256_mask_i32gather_ps(src, base_addr, vindex, mask, scale);
|
| 131 |
+
}
|
| 132 |
+
#endif
|
| 133 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CONVERT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 134 |
+
|
| 135 |
+
// Only works for inputs in the range: [-2^51, 2^51]
|
| 136 |
+
// From: https://stackoverflow.com/a/41148578
|
| 137 |
+
template<>
|
| 138 |
+
Vectorized<int64_t>
|
| 139 |
+
inline convert_to_int_of_same_size<double>(const Vectorized<double> &src) {
|
| 140 |
+
auto x = _mm256_add_pd(src, _mm256_set1_pd(0x0018000000000000));
|
| 141 |
+
return _mm256_sub_epi64(
|
| 142 |
+
_mm256_castpd_si256(x),
|
| 143 |
+
_mm256_castpd_si256(_mm256_set1_pd(0x0018000000000000))
|
| 144 |
+
);
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
template<>
|
| 148 |
+
Vectorized<int32_t>
|
| 149 |
+
inline convert_to_int_of_same_size<float>(const Vectorized<float> &src) {
|
| 150 |
+
return _mm256_cvttps_epi32(src);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
// From: https://stackoverflow.com/a/41148578
|
| 154 |
+
template<>
|
| 155 |
+
Vectorized<double>
|
| 156 |
+
inline convert_to_fp_of_same_size<double>(const Vectorized<int64_t> &src) {
|
| 157 |
+
__m256i magic_i_lo = _mm256_set1_epi64x(0x4330000000000000); /* 2^52 */
|
| 158 |
+
__m256i magic_i_hi32 = _mm256_set1_epi64x(0x4530000080000000); /* 2^84 + 2^63 */
|
| 159 |
+
__m256i magic_i_all = _mm256_set1_epi64x(0x4530000080100000); /* 2^84 + 2^63 + 2^52 */
|
| 160 |
+
__m256d magic_d_all = _mm256_castsi256_pd(magic_i_all);
|
| 161 |
+
|
| 162 |
+
__m256i v_lo = _mm256_blend_epi32(magic_i_lo, src, 0b01010101); /* v_low = low32 + 2^52 */
|
| 163 |
+
__m256i v_hi = _mm256_srli_epi64(src, 32);
|
| 164 |
+
v_hi = _mm256_xor_si256(v_hi, magic_i_hi32); /* v_hi = high32*2^32 + 2^84 + 2^63 */
|
| 165 |
+
/* int64 = low32 + high32*2^32 = v_hi + v_lo - 2^52 - 2^63 - 2^84 */
|
| 166 |
+
__m256d v_hi_dbl = _mm256_sub_pd(_mm256_castsi256_pd(v_hi), magic_d_all);
|
| 167 |
+
__m256d result = _mm256_add_pd(v_hi_dbl, _mm256_castsi256_pd(v_lo));
|
| 168 |
+
return result;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
template<>
|
| 172 |
+
Vectorized<float>
|
| 173 |
+
inline convert_to_fp_of_same_size<float>(const Vectorized<int32_t> &src) {
|
| 174 |
+
return _mm256_cvtepi32_ps(src);
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTERLEAVE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 178 |
+
|
| 179 |
+
template <>
|
| 180 |
+
std::pair<Vectorized<double>, Vectorized<double>>
|
| 181 |
+
inline interleave2<double>(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 182 |
+
// inputs:
|
| 183 |
+
// a = {a0, a1, a3, a3}
|
| 184 |
+
// b = {b0, b1, b2, b3}
|
| 185 |
+
|
| 186 |
+
// swap lanes:
|
| 187 |
+
// a_swapped = {a0, a1, b0, b1}
|
| 188 |
+
// b_swapped = {a2, a3, b2, b3}
|
| 189 |
+
auto a_swapped = _mm256_permute2f128_pd(a, b, 0b0100000); // 0, 2. 4 bits apart
|
| 190 |
+
auto b_swapped = _mm256_permute2f128_pd(a, b, 0b0110001); // 1, 3. 4 bits apart
|
| 191 |
+
|
| 192 |
+
// group cols crossing lanes:
|
| 193 |
+
// return {a0, b0, a1, b1}
|
| 194 |
+
// {a2, b2, a3, b3}
|
| 195 |
+
return std::make_pair(_mm256_permute4x64_pd(a_swapped, 0b11011000), // 0, 2, 1, 3
|
| 196 |
+
_mm256_permute4x64_pd(b_swapped, 0b11011000)); // 0, 2, 1, 3
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
template <>
|
| 200 |
+
std::pair<Vectorized<float>, Vectorized<float>>
|
| 201 |
+
inline interleave2<float>(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 202 |
+
// inputs:
|
| 203 |
+
// a = {a0, a1, a2, a3, a4, a5, a6, a7}
|
| 204 |
+
// b = {b0, b1, b2, b3, b4, b5, b6, b7}
|
| 205 |
+
|
| 206 |
+
// swap lanes:
|
| 207 |
+
// a_swapped = {a0, a1, a2, a3, b0, b1, b2, b3}
|
| 208 |
+
// b_swapped = {a4, a5, a6, a7, b4, b5, b6, b7}
|
| 209 |
+
// TODO: can we support caching this?
|
| 210 |
+
auto a_swapped = _mm256_permute2f128_ps(a, b, 0b0100000); // 0, 2. 4 bits apart
|
| 211 |
+
auto b_swapped = _mm256_permute2f128_ps(a, b, 0b0110001); // 1, 3. 4 bits apart
|
| 212 |
+
|
| 213 |
+
// group cols crossing lanes:
|
| 214 |
+
// return {a0, b0, a1, b1, a2, b2, a3, b3}
|
| 215 |
+
// {a4, b4, a5, b5, a6, b6, a7, b7}
|
| 216 |
+
const __m256i group_ctrl = _mm256_setr_epi32(0, 4, 1, 5, 2, 6, 3, 7);
|
| 217 |
+
return std::make_pair(_mm256_permutevar8x32_ps(a_swapped, group_ctrl),
|
| 218 |
+
_mm256_permutevar8x32_ps(b_swapped, group_ctrl));
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEINTERLEAVE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 222 |
+
|
| 223 |
+
template <>
|
| 224 |
+
std::pair<Vectorized<double>, Vectorized<double>>
|
| 225 |
+
inline deinterleave2<double>(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 226 |
+
// inputs:
|
| 227 |
+
// a = {a0, b0, a1, b1}
|
| 228 |
+
// b = {a2, b2, a3, b3}
|
| 229 |
+
|
| 230 |
+
// group cols crossing lanes:
|
| 231 |
+
// a_grouped = {a0, a1, b0, b1}
|
| 232 |
+
// b_grouped = {a2, a3, b2, b3}
|
| 233 |
+
auto a_grouped = _mm256_permute4x64_pd(a, 0b11011000); // 0, 2, 1, 3
|
| 234 |
+
auto b_grouped = _mm256_permute4x64_pd(b, 0b11011000); // 0, 2, 1, 3
|
| 235 |
+
|
| 236 |
+
// swap lanes:
|
| 237 |
+
// return {a0, a1, a2, a3}
|
| 238 |
+
// {b0, b1, b2, b3}
|
| 239 |
+
return std::make_pair(_mm256_permute2f128_pd(a_grouped, b_grouped, 0b0100000), // 0, 2. 4 bits apart
|
| 240 |
+
_mm256_permute2f128_pd(a_grouped, b_grouped, 0b0110001)); // 1, 3. 4 bits apart
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
template <>
|
| 244 |
+
std::pair<Vectorized<float>, Vectorized<float>>
|
| 245 |
+
inline deinterleave2<float>(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 246 |
+
// inputs:
|
| 247 |
+
// a = {a0, b0, a1, b1, a2, b2, a3, b3}
|
| 248 |
+
// b = {a4, b4, a5, b5, a6, b6, a7, b7}
|
| 249 |
+
|
| 250 |
+
// group cols crossing lanes:
|
| 251 |
+
// a_grouped = {a0, a1, a2, a3, b0, b1, b2, b3}
|
| 252 |
+
// b_grouped = {a4, a5, a6, a7, b4, b5, b6, b7}
|
| 253 |
+
// TODO: can we support caching this?
|
| 254 |
+
const __m256i group_ctrl = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7);
|
| 255 |
+
auto a_grouped = _mm256_permutevar8x32_ps(a, group_ctrl);
|
| 256 |
+
auto b_grouped = _mm256_permutevar8x32_ps(b, group_ctrl);
|
| 257 |
+
|
| 258 |
+
// swap lanes:
|
| 259 |
+
// return {a0, a1, a2, a3, a4, a5, a6, a7}
|
| 260 |
+
// {b0, b1, b2, b3, b4, b5, b6, b7}
|
| 261 |
+
return std::make_pair(_mm256_permute2f128_ps(a_grouped, b_grouped, 0b0100000), // 0, 2. 4 bits apart
|
| 262 |
+
_mm256_permute2f128_ps(a_grouped, b_grouped, 0b0110001)); // 1, 3. 4 bits apart
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLIP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 266 |
+
|
| 267 |
+
template<>
|
| 268 |
+
inline Vectorized<float> flip(const Vectorized<float> & v) {
|
| 269 |
+
const __m256i mask_float = _mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7);
|
| 270 |
+
return _mm256_permutevar8x32_ps(v, mask_float);
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
template<>
|
| 274 |
+
inline Vectorized<double> flip(const Vectorized<double> & v) {
|
| 275 |
+
return _mm256_permute4x64_pd(v, 27); // 27 == _MM_SHUFFLE(0, 1, 2, 3)
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
template<>
|
| 279 |
+
inline Vectorized<int64_t> flip(const Vectorized<int64_t> & v) {
|
| 280 |
+
return _mm256_permute4x64_epi64(v, 27); // 27 == _MM_SHUFFLE(0, 1, 2, 3)
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
template<>
|
| 284 |
+
inline Vectorized<int32_t> flip(const Vectorized<int32_t> & v) {
|
| 285 |
+
const __m256i mask_int32 = _mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7);
|
| 286 |
+
return _mm256_permutevar8x32_epi32(v, mask_int32);
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
template<>
|
| 290 |
+
inline Vectorized<int16_t> flip(const Vectorized<int16_t> & v) {
|
| 291 |
+
const __m256i mask = _mm256_set_epi8(
|
| 292 |
+
1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
|
| 293 |
+
1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14
|
| 294 |
+
);
|
| 295 |
+
auto reversed = _mm256_shuffle_epi8(v, mask);
|
| 296 |
+
return _mm256_permute2x128_si256(reversed, reversed, 1);
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
inline __m256i flip8(const __m256i & v) {
|
| 300 |
+
const __m256i mask_int8 = _mm256_set_epi8(
|
| 301 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
| 302 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
| 303 |
+
);
|
| 304 |
+
auto reversed = _mm256_shuffle_epi8(v, mask_int8);
|
| 305 |
+
return _mm256_permute2x128_si256(reversed, reversed, 1);
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
template<>
|
| 309 |
+
inline Vectorized<int8_t> flip(const Vectorized<int8_t> & v) {
|
| 310 |
+
return flip8(v);
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
template<>
|
| 314 |
+
inline Vectorized<uint8_t> flip(const Vectorized<uint8_t> & v) {
|
| 315 |
+
return flip8(v);
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
inline Vectorized<bool> operator&&(
|
| 319 |
+
const Vectorized<bool>& self,
|
| 320 |
+
const Vectorized<bool>& other) {
|
| 321 |
+
const __m256i* self_ = reinterpret_cast<const __m256i*>(self.as_bytes());
|
| 322 |
+
const __m256i* other_ = reinterpret_cast<const __m256i*>(other.as_bytes());
|
| 323 |
+
__m256i out = _mm256_and_si256(*self_, *other_);
|
| 324 |
+
Vectorized<bool> ret;
|
| 325 |
+
std::memcpy(ret, &out, ret.size() * sizeof(bool));
|
| 326 |
+
return ret;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
#endif // (defined(CPU_CAPABILITY_AVX2)
|
| 330 |
+
|
| 331 |
+
}} // namepsace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_bfloat16.h
ADDED
|
@@ -0,0 +1,1150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <c10/util/irange.h>
|
| 9 |
+
|
| 10 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 11 |
+
#define SLEEF_STATIC_LIBS
|
| 12 |
+
#include <sleef.h>
|
| 13 |
+
#endif
|
| 14 |
+
|
| 15 |
+
#pragma GCC diagnostic push
|
| 16 |
+
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
| 17 |
+
|
| 18 |
+
namespace at::vec {
|
| 19 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 20 |
+
inline namespace CPU_CAPABILITY {
|
| 21 |
+
|
| 22 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 23 |
+
|
| 24 |
+
#ifndef SLEEF_CONST
|
| 25 |
+
#if (defined(__GNUC__) || defined(__CLANG__)) && !defined(__INTEL_COMPILER)
|
| 26 |
+
#define SLEEF_CONST const
|
| 27 |
+
#else
|
| 28 |
+
#define SLEEF_CONST
|
| 29 |
+
#endif
|
| 30 |
+
#define SLEEF_CONST_OLD SLEEF_CONST
|
| 31 |
+
#else
|
| 32 |
+
#define SLEEF_CONST_OLD
|
| 33 |
+
#endif
|
| 34 |
+
|
| 35 |
+
// bfloat16 conversion
|
| 36 |
+
static inline void cvtbf16_fp32(const __m128i& a, __m256& o) {
|
| 37 |
+
o = _mm256_castsi256_ps(_mm256_slli_epi32(_mm256_cvtepu16_epi32(a), 16));
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
static inline void cvtbf16_fp32(const __m256i& a, __m256& o1, __m256& o2) {
|
| 41 |
+
__m128i lo = _mm256_extractf128_si256(a, 0);
|
| 42 |
+
__m128i hi = _mm256_extractf128_si256(a, 1);
|
| 43 |
+
cvtbf16_fp32(lo, o1);
|
| 44 |
+
cvtbf16_fp32(hi, o2);
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
static inline __m128i cvtfp32_bf16(const __m256& src) {
|
| 48 |
+
__m256i value = _mm256_castps_si256(src);
|
| 49 |
+
__m256i nan = _mm256_set1_epi32(0xffff);
|
| 50 |
+
__m256i mask = _mm256_castps_si256(_mm256_cmp_ps(src, src, _CMP_ORD_Q));
|
| 51 |
+
__m256i ones = _mm256_set1_epi32(0x1);
|
| 52 |
+
__m256i vec_bias = _mm256_set1_epi32(0x7fff);
|
| 53 |
+
// uint32_t lsb = (input >> 16) & 1;
|
| 54 |
+
auto t_value = _mm256_and_si256(_mm256_srli_epi32(value, 16), ones);
|
| 55 |
+
// uint32_t rounding_bias = 0x7fff + lsb;
|
| 56 |
+
t_value = _mm256_add_epi32(t_value, vec_bias);
|
| 57 |
+
// input += rounding_bias;
|
| 58 |
+
t_value = _mm256_add_epi32(t_value, value);
|
| 59 |
+
// input = input >> 16;
|
| 60 |
+
t_value = _mm256_srli_epi32(t_value, 16);
|
| 61 |
+
// Check NaN before converting back to bf16
|
| 62 |
+
t_value = _mm256_blendv_epi8(nan, t_value, mask);
|
| 63 |
+
t_value = _mm256_packus_epi32(t_value, t_value); // t[4-7] t[4-7] t[0-4] t[0-4]
|
| 64 |
+
t_value = _mm256_permute4x64_epi64(t_value, 0xd8); // 11 01 10 00
|
| 65 |
+
return _mm256_castsi256_si128(t_value);
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
static inline __m256i cvtfp32_bf16(const __m256& a, const __m256& b) {
|
| 69 |
+
__m256i lo = _mm256_castps_si256(a);
|
| 70 |
+
__m256i hi = _mm256_castps_si256(b);
|
| 71 |
+
__m256i nan = _mm256_set1_epi32(0xffff);
|
| 72 |
+
__m256i mask_lo = _mm256_castps_si256(_mm256_cmp_ps(a, a, _CMP_ORD_Q));
|
| 73 |
+
__m256i mask_hi = _mm256_castps_si256(_mm256_cmp_ps(b, b, _CMP_ORD_Q));
|
| 74 |
+
__m256i ones = _mm256_set1_epi32(0x1);
|
| 75 |
+
__m256i vec_bias = _mm256_set1_epi32(0x7fff);
|
| 76 |
+
// uint32_t lsb = (input >> 16) & 1;
|
| 77 |
+
auto t_lo = _mm256_and_si256(_mm256_srli_epi32(lo, 16), ones);
|
| 78 |
+
auto t_hi = _mm256_and_si256(_mm256_srli_epi32(hi, 16), ones);
|
| 79 |
+
// uint32_t rounding_bias = 0x7fff + lsb;
|
| 80 |
+
t_lo = _mm256_add_epi32(t_lo, vec_bias);
|
| 81 |
+
t_hi = _mm256_add_epi32(t_hi, vec_bias);
|
| 82 |
+
// input += rounding_bias;
|
| 83 |
+
t_lo = _mm256_add_epi32(t_lo, lo);
|
| 84 |
+
t_hi = _mm256_add_epi32(t_hi, hi);
|
| 85 |
+
// input = input >> 16;
|
| 86 |
+
t_lo = _mm256_srli_epi32(t_lo, 16);
|
| 87 |
+
t_hi = _mm256_srli_epi32(t_hi, 16);
|
| 88 |
+
// Check NaN before converting back to bf16
|
| 89 |
+
t_lo = _mm256_blendv_epi8(nan, t_lo, mask_lo);
|
| 90 |
+
t_hi = _mm256_blendv_epi8(nan, t_hi, mask_hi);
|
| 91 |
+
|
| 92 |
+
t_lo = _mm256_packus_epi32(t_lo, t_hi); // t_hi[4-7] t_lo[4-7] t_hi[0-4] t_lo[0-4]
|
| 93 |
+
return _mm256_permute4x64_epi64(t_lo, 0xd8); // 11 01 10 00
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
static inline __m256i merge_compare_result(const __m256& a, const __m256& b) {
|
| 97 |
+
__m256i lo = _mm256_castps_si256(a);
|
| 98 |
+
__m256i hi = _mm256_castps_si256(b);
|
| 99 |
+
lo = _mm256_srli_epi32(lo, 16);
|
| 100 |
+
hi = _mm256_srli_epi32(hi, 16);
|
| 101 |
+
auto out = _mm256_packus_epi32(lo, hi);
|
| 102 |
+
return _mm256_permute4x64_epi64(out, 0xd8);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
// float16 conversion
|
| 106 |
+
static inline void cvtfp16_fp32(const __m128i& a, __m256& o) {
|
| 107 |
+
o = _mm256_cvtph_ps(a);
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
static inline void cvtfp16_fp32(const __m256i& a, __m256& o1, __m256& o2) {
|
| 111 |
+
__m128i lo = _mm256_extractf128_si256(a, 0);
|
| 112 |
+
__m128i hi = _mm256_extractf128_si256(a, 1);
|
| 113 |
+
cvtfp16_fp32(lo, o1);
|
| 114 |
+
cvtfp16_fp32(hi, o2);
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
static inline __m128i cvtfp32_fp16(const __m256& src) {
|
| 118 |
+
return _mm256_cvtps_ph(
|
| 119 |
+
src, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
static inline __m256i cvtfp32_fp16(const __m256& a, const __m256& b) {
|
| 123 |
+
__m128i lo = _mm256_cvtps_ph(
|
| 124 |
+
a, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 125 |
+
__m128i hi = _mm256_cvtps_ph(
|
| 126 |
+
b, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 127 |
+
return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), hi, 1);
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
// dtype conversion between float16/bfloat16 and float32
|
| 131 |
+
template <typename T, typename std::enable_if_t<is_reduced_floating_point_v<T>, int> = 0>
|
| 132 |
+
inline void cvt_to_fp32(const __m128i& a, __m256& o);
|
| 133 |
+
template <> inline void cvt_to_fp32<BFloat16>(const __m128i& a, __m256& o) {
|
| 134 |
+
cvtbf16_fp32(a, o);
|
| 135 |
+
}
|
| 136 |
+
template <> inline void cvt_to_fp32<Half>(const __m128i& a, __m256& o) {
|
| 137 |
+
cvtfp16_fp32(a, o);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
template <typename T, typename std::enable_if_t<is_reduced_floating_point_v<T>, int> = 0>
|
| 141 |
+
inline void cvt_to_fp32(const __m256i& a, __m256& o1, __m256& o2);
|
| 142 |
+
template <> inline void cvt_to_fp32<BFloat16>(const __m256i& a, __m256& o1, __m256& o2) {
|
| 143 |
+
cvtbf16_fp32(a, o1, o2);
|
| 144 |
+
}
|
| 145 |
+
template <> inline void cvt_to_fp32<Half>(const __m256i& a, __m256& o1, __m256& o2) {
|
| 146 |
+
cvtfp16_fp32(a, o1, o2);
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
template <typename T, bool is_compare_op = false,
|
| 150 |
+
typename std::enable_if_t<is_reduced_floating_point_v<T>, int> = 0>
|
| 151 |
+
inline __m256i cvt_from_fp32(const __m256& a, const __m256& b);
|
| 152 |
+
template <> inline __m256i cvt_from_fp32<BFloat16, false>(const __m256& a, const __m256& b) {
|
| 153 |
+
return cvtfp32_bf16(a, b);
|
| 154 |
+
}
|
| 155 |
+
template <> inline __m256i cvt_from_fp32<BFloat16, true>(const __m256& a, const __m256& b) {
|
| 156 |
+
return merge_compare_result(a, b);
|
| 157 |
+
}
|
| 158 |
+
template <> inline __m256i cvt_from_fp32<Half, false>(const __m256& a, const __m256& b) {
|
| 159 |
+
return cvtfp32_fp16(a, b);
|
| 160 |
+
}
|
| 161 |
+
template <> inline __m256i cvt_from_fp32<Half, true>(const __m256& a, const __m256& b) {
|
| 162 |
+
return cvtfp32_fp16(a, b);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
template <typename T>
|
| 166 |
+
class Vectorized16 {
|
| 167 |
+
static_assert(
|
| 168 |
+
is_reduced_floating_point_v<T>,
|
| 169 |
+
"Support only float16 and bfloat16.");
|
| 170 |
+
protected:
|
| 171 |
+
__m256i values;
|
| 172 |
+
public:
|
| 173 |
+
using value_type = uint16_t;
|
| 174 |
+
using size_type = int;
|
| 175 |
+
static constexpr size_type size() {
|
| 176 |
+
return 16;
|
| 177 |
+
}
|
| 178 |
+
Vectorized16() {}
|
| 179 |
+
Vectorized16(__m256i v) : values(v) {}
|
| 180 |
+
Vectorized16(T val) {
|
| 181 |
+
value_type uw = val.x;
|
| 182 |
+
values = _mm256_set1_epi16(uw);
|
| 183 |
+
}
|
| 184 |
+
Vectorized16(T val1, T val2, T val3, T val4,
|
| 185 |
+
T val5, T val6, T val7, T val8,
|
| 186 |
+
T val9, T val10, T val11, T val12,
|
| 187 |
+
T val13, T val14, T val15, T val16) {
|
| 188 |
+
values = _mm256_setr_epi16(
|
| 189 |
+
val1.x, val2.x, val3.x, val4.x, val5.x, val6.x, val7.x, val8.x,
|
| 190 |
+
val9.x, val10.x, val11.x, val12.x, val13.x, val14.x, val15.x, val16.x);
|
| 191 |
+
}
|
| 192 |
+
operator __m256i() const {
|
| 193 |
+
return values;
|
| 194 |
+
}
|
| 195 |
+
T& operator[](int idx) = delete;
|
| 196 |
+
const T& operator[](int idx) const = delete;
|
| 197 |
+
int zero_mask() const {
|
| 198 |
+
// returns an integer mask where all zero elements are translated to 1-bit and others are translated to 0-bit
|
| 199 |
+
__m256i cmp = _mm256_cmpeq_epi16(values, _mm256_set1_epi16(0));
|
| 200 |
+
return _mm256_movemask_epi8(cmp);
|
| 201 |
+
}
|
| 202 |
+
static Vectorized<T> loadu(const void* ptr, int16_t count = size()) {
|
| 203 |
+
if (count == size())
|
| 204 |
+
return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(ptr));
|
| 205 |
+
|
| 206 |
+
__at_align__ int16_t tmp_values[size()];
|
| 207 |
+
std::memcpy(tmp_values, ptr, count * sizeof(int16_t));
|
| 208 |
+
return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(tmp_values));
|
| 209 |
+
}
|
| 210 |
+
void store(void* ptr, int count = size()) const {
|
| 211 |
+
if (count == size()) {
|
| 212 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), values);
|
| 213 |
+
} else if (count > 0) {
|
| 214 |
+
__at_align__ int16_t tmp_values[size()];
|
| 215 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(tmp_values), values);
|
| 216 |
+
std::memcpy(ptr, tmp_values, count * sizeof(int16_t));
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
template <int64_t mask>
|
| 220 |
+
static Vectorized<T> blend(const Vectorized<T>& a, const Vectorized<T>& b) {
|
| 221 |
+
__at_align__ int16_t tmp_values[size()];
|
| 222 |
+
a.store(tmp_values);
|
| 223 |
+
if (mask & 0x01)
|
| 224 |
+
tmp_values[0] = _mm256_extract_epi16(b.values, 0);
|
| 225 |
+
if (mask & 0x02)
|
| 226 |
+
tmp_values[1] = _mm256_extract_epi16(b.values, 1);
|
| 227 |
+
if (mask & 0x04)
|
| 228 |
+
tmp_values[2] = _mm256_extract_epi16(b.values, 2);
|
| 229 |
+
if (mask & 0x08)
|
| 230 |
+
tmp_values[3] = _mm256_extract_epi16(b.values, 3);
|
| 231 |
+
if (mask & 0x10)
|
| 232 |
+
tmp_values[4] = _mm256_extract_epi16(b.values, 4);
|
| 233 |
+
if (mask & 0x20)
|
| 234 |
+
tmp_values[5] = _mm256_extract_epi16(b.values, 5);
|
| 235 |
+
if (mask & 0x40)
|
| 236 |
+
tmp_values[6] = _mm256_extract_epi16(b.values, 6);
|
| 237 |
+
if (mask & 0x80)
|
| 238 |
+
tmp_values[7] = _mm256_extract_epi16(b.values, 7);
|
| 239 |
+
if (mask & 0x100)
|
| 240 |
+
tmp_values[8] = _mm256_extract_epi16(b.values, 8);
|
| 241 |
+
if (mask & 0x200)
|
| 242 |
+
tmp_values[9] = _mm256_extract_epi16(b.values, 9);
|
| 243 |
+
if (mask & 0x400)
|
| 244 |
+
tmp_values[10] = _mm256_extract_epi16(b.values, 10);
|
| 245 |
+
if (mask & 0x800)
|
| 246 |
+
tmp_values[11] = _mm256_extract_epi16(b.values, 11);
|
| 247 |
+
if (mask & 0x1000)
|
| 248 |
+
tmp_values[12] = _mm256_extract_epi16(b.values, 12);
|
| 249 |
+
if (mask & 0x2000)
|
| 250 |
+
tmp_values[13] = _mm256_extract_epi16(b.values, 13);
|
| 251 |
+
if (mask & 0x4000)
|
| 252 |
+
tmp_values[14] = _mm256_extract_epi16(b.values, 14);
|
| 253 |
+
if (mask & 0x8000)
|
| 254 |
+
tmp_values[15] = _mm256_extract_epi16(b.values, 15);
|
| 255 |
+
return loadu(tmp_values);
|
| 256 |
+
}
|
| 257 |
+
static Vectorized<T> blendv(const Vectorized<T>& a,
|
| 258 |
+
const Vectorized<T>& b, const Vectorized<T>& mask) {
|
| 259 |
+
return _mm256_blendv_epi8(a.values, b.values, mask.values);
|
| 260 |
+
}
|
| 261 |
+
template<typename step_t>
|
| 262 |
+
static Vectorized<T> arange(T base = 0.f, step_t step = static_cast<step_t>(1)) {
|
| 263 |
+
return Vectorized<T>(
|
| 264 |
+
base, base + step, base + 2 * step, base + 3 * step,
|
| 265 |
+
base + 4 * step, base + 5 * step, base + 6 * step, base + 7 * step,
|
| 266 |
+
base + 8 * step, base + 9 * step, base + 10 * step, base + 11 * step,
|
| 267 |
+
base + 12 * step, base + 13 * step, base + 14 * step, base + 15 * step);
|
| 268 |
+
}
|
| 269 |
+
static Vectorized<T> set(const Vectorized<T>& a,
|
| 270 |
+
const Vectorized<T>& b, int64_t count = size()) {
|
| 271 |
+
switch (count) {
|
| 272 |
+
case 0:
|
| 273 |
+
return a;
|
| 274 |
+
case 1:
|
| 275 |
+
return blend<1>(a, b);
|
| 276 |
+
case 2:
|
| 277 |
+
return blend<3>(a, b);
|
| 278 |
+
case 3:
|
| 279 |
+
return blend<7>(a, b);
|
| 280 |
+
case 4:
|
| 281 |
+
return blend<15>(a, b);
|
| 282 |
+
case 5:
|
| 283 |
+
return blend<31>(a, b);
|
| 284 |
+
case 6:
|
| 285 |
+
return blend<63>(a, b);
|
| 286 |
+
case 7:
|
| 287 |
+
return blend<127>(a, b);
|
| 288 |
+
case 8:
|
| 289 |
+
return blend<255>(a, b);
|
| 290 |
+
case 9:
|
| 291 |
+
return blend<511>(a, b);
|
| 292 |
+
case 10:
|
| 293 |
+
return blend<1023>(a, b);
|
| 294 |
+
case 11:
|
| 295 |
+
return blend<2047>(a, b);
|
| 296 |
+
case 12:
|
| 297 |
+
return blend<4095>(a, b);
|
| 298 |
+
case 13:
|
| 299 |
+
return blend<8191>(a, b);
|
| 300 |
+
case 14:
|
| 301 |
+
return blend<16383>(a, b);
|
| 302 |
+
case 15:
|
| 303 |
+
return blend<32767>(a, b);
|
| 304 |
+
}
|
| 305 |
+
return b;
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
Vectorized<T> map(SLEEF_CONST __m256 (*SLEEF_CONST_OLD vop)(__m256)) const {
|
| 309 |
+
__m256 lo, hi;
|
| 310 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 311 |
+
const auto o1 = vop(lo);
|
| 312 |
+
const auto o2 = vop(hi);
|
| 313 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 314 |
+
}
|
| 315 |
+
Vectorized<T> isnan() const {
|
| 316 |
+
__m256 lo, hi;
|
| 317 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 318 |
+
lo = _mm256_cmp_ps(lo, _mm256_set1_ps(0.0f), _CMP_UNORD_Q);
|
| 319 |
+
hi = _mm256_cmp_ps(hi, _mm256_set1_ps(0.0f), _CMP_UNORD_Q);
|
| 320 |
+
return merge_compare_result(lo, hi);
|
| 321 |
+
}
|
| 322 |
+
Vectorized<T> abs() const {
|
| 323 |
+
return _mm256_andnot_si256(_mm256_set1_epi16(0x8000), values);
|
| 324 |
+
}
|
| 325 |
+
Vectorized<T> angle() const {
|
| 326 |
+
__m256 lo, hi;
|
| 327 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 328 |
+
auto angle_lambda = [](__m256 values_2) {
|
| 329 |
+
const auto zero_vec = _mm256_set1_ps(0.f);
|
| 330 |
+
const auto nan_vec = _mm256_set1_ps(NAN);
|
| 331 |
+
const auto not_nan_mask = _mm256_cmp_ps(values_2, values_2, _CMP_EQ_OQ);
|
| 332 |
+
const auto nan_mask = _mm256_cmp_ps(not_nan_mask, zero_vec, _CMP_EQ_OQ);
|
| 333 |
+
const auto pi = _mm256_set1_ps(c10::pi<float>);
|
| 334 |
+
|
| 335 |
+
const auto neg_mask = _mm256_cmp_ps(values_2, zero_vec, _CMP_LT_OQ);
|
| 336 |
+
auto angle = _mm256_blendv_ps(zero_vec, pi, neg_mask);
|
| 337 |
+
angle = _mm256_blendv_ps(angle, nan_vec, nan_mask);
|
| 338 |
+
return angle;
|
| 339 |
+
};
|
| 340 |
+
auto o1 = angle_lambda(lo);
|
| 341 |
+
auto o2 = angle_lambda(hi);
|
| 342 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 343 |
+
}
|
| 344 |
+
Vectorized<T> real() const {
|
| 345 |
+
return *this;
|
| 346 |
+
}
|
| 347 |
+
Vectorized<T> imag() const {
|
| 348 |
+
return _mm256_set1_epi16(0);
|
| 349 |
+
}
|
| 350 |
+
Vectorized<T> conj() const {
|
| 351 |
+
return *this;
|
| 352 |
+
}
|
| 353 |
+
Vectorized<T> acos() const {
|
| 354 |
+
return map(Sleef_acosf8_u10);
|
| 355 |
+
}
|
| 356 |
+
Vectorized<T> acosh() const {
|
| 357 |
+
return map(Sleef_acoshf8_u10);
|
| 358 |
+
}
|
| 359 |
+
Vectorized<T> asin() const {
|
| 360 |
+
return map(Sleef_asinf8_u10);
|
| 361 |
+
}
|
| 362 |
+
Vectorized<T> atan() const {
|
| 363 |
+
return map(Sleef_atanf8_u10);
|
| 364 |
+
}
|
| 365 |
+
Vectorized<T> atanh() const {
|
| 366 |
+
return map(Sleef_atanhf8_u10);
|
| 367 |
+
}
|
| 368 |
+
Vectorized<T> atan2(const Vectorized<T> &b) const {
|
| 369 |
+
__m256 lo, hi;
|
| 370 |
+
__m256 b1, b2;
|
| 371 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 372 |
+
cvt_to_fp32<T>(b.values, b1, b2);
|
| 373 |
+
auto o1 = Sleef_atan2f8_u10(lo, b1);
|
| 374 |
+
auto o2 = Sleef_atan2f8_u10(hi, b2);
|
| 375 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 376 |
+
}
|
| 377 |
+
Vectorized<T> copysign(const Vectorized<T> &sign) const {
|
| 378 |
+
// copy sign bit (0x8000) from sign and remaining bits from values
|
| 379 |
+
__m256i mask_value = _mm256_set1_epi32(~0x80008000);
|
| 380 |
+
__m256i mask_signbit = _mm256_set1_epi32(0x80008000);
|
| 381 |
+
return Vectorized<T>(
|
| 382 |
+
_mm256_or_si256(
|
| 383 |
+
_mm256_and_si256(values, mask_value),
|
| 384 |
+
_mm256_and_si256(sign, mask_signbit)));
|
| 385 |
+
}
|
| 386 |
+
Vectorized<T> erf() const {
|
| 387 |
+
return map(Sleef_erff8_u10);
|
| 388 |
+
}
|
| 389 |
+
Vectorized<T> erfc() const {
|
| 390 |
+
return map(Sleef_erfcf8_u15);
|
| 391 |
+
}
|
| 392 |
+
Vectorized<T> erfinv() const {
|
| 393 |
+
__m256 lo, hi;
|
| 394 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 395 |
+
__at_align__ float tmp1[size() / 2], tmp2[size() / 2];
|
| 396 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 397 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 398 |
+
for (int64_t i = 0; i < size() / 2; i++) {
|
| 399 |
+
tmp1[i] = calc_erfinv(tmp1[i]);
|
| 400 |
+
tmp2[i] = calc_erfinv(tmp2[i]);
|
| 401 |
+
}
|
| 402 |
+
auto o1 = _mm256_loadu_ps(tmp1);
|
| 403 |
+
auto o2 = _mm256_loadu_ps(tmp2);
|
| 404 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 405 |
+
}
|
| 406 |
+
Vectorized<T> exp() const {
|
| 407 |
+
return map(Sleef_expf8_u10);
|
| 408 |
+
}
|
| 409 |
+
Vectorized<T> exp2() const {
|
| 410 |
+
return map(Sleef_exp2f8_u10);
|
| 411 |
+
}
|
| 412 |
+
Vectorized<T> expm1() const {
|
| 413 |
+
return map(Sleef_expm1f8_u10);
|
| 414 |
+
}
|
| 415 |
+
Vectorized<T> exp_u20() const {
|
| 416 |
+
return exp();
|
| 417 |
+
}
|
| 418 |
+
Vectorized<T> fmod(const Vectorized<T> & q) const {
|
| 419 |
+
__m256 x_lo, x_hi;
|
| 420 |
+
cvt_to_fp32<T>(values, x_lo, x_hi);
|
| 421 |
+
__m256 q_lo, q_hi;
|
| 422 |
+
cvt_to_fp32<T>(q.values, q_lo, q_hi);
|
| 423 |
+
auto o1 = Sleef_fmodf8(x_lo, q_lo);
|
| 424 |
+
auto o2 = Sleef_fmodf8(x_hi, q_hi);
|
| 425 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 426 |
+
}
|
| 427 |
+
Vectorized<T> hypot(const Vectorized<T> &b) const {
|
| 428 |
+
__m256 lo, hi;
|
| 429 |
+
__m256 b1, b2;
|
| 430 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 431 |
+
cvt_to_fp32<T>(b.values, b1, b2);
|
| 432 |
+
auto o1 = Sleef_hypotf8_u05(lo, b1);
|
| 433 |
+
auto o2 = Sleef_hypotf8_u05(hi, b2);
|
| 434 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 435 |
+
}
|
| 436 |
+
Vectorized<T> i0() const {
|
| 437 |
+
__m256 lo, hi;
|
| 438 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 439 |
+
__at_align__ float tmp1[size() / 2], tmp2[size() / 2];
|
| 440 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 441 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 442 |
+
for (int64_t i = 0; i < size() / 2; i++) {
|
| 443 |
+
tmp1[i] = calc_i0(tmp1[i]);
|
| 444 |
+
tmp2[i] = calc_i0(tmp2[i]);
|
| 445 |
+
}
|
| 446 |
+
auto o1 = _mm256_loadu_ps(tmp1);
|
| 447 |
+
auto o2 = _mm256_loadu_ps(tmp2);
|
| 448 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 449 |
+
}
|
| 450 |
+
Vectorized<T> i0e() const {
|
| 451 |
+
__m256 lo, hi;
|
| 452 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 453 |
+
constexpr auto sz = size();
|
| 454 |
+
__at_align__ float tmp1[sz / 2], tmp2[sz / 2];
|
| 455 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 456 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 457 |
+
|
| 458 |
+
for (auto i = decltype(sz){0}; i < sz / 2; i++) {
|
| 459 |
+
tmp1[i] = calc_i0e(tmp1[i]);
|
| 460 |
+
tmp2[i] = calc_i0e(tmp2[i]);
|
| 461 |
+
}
|
| 462 |
+
const auto o1 = _mm256_loadu_ps(tmp1);
|
| 463 |
+
const auto o2 = _mm256_loadu_ps(tmp2);
|
| 464 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 465 |
+
}
|
| 466 |
+
Vectorized<T> digamma() const {
|
| 467 |
+
__m256 lo, hi;
|
| 468 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 469 |
+
constexpr auto sz = size();
|
| 470 |
+
__at_align__ float tmp1[sz / 2], tmp2[sz / 2];
|
| 471 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 472 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 473 |
+
|
| 474 |
+
for (auto i = decltype(sz){0}; i < sz / 2; i++) {
|
| 475 |
+
tmp1[i] = calc_digamma(tmp1[i]);
|
| 476 |
+
tmp2[i] = calc_digamma(tmp2[i]);
|
| 477 |
+
}
|
| 478 |
+
const auto o1 = _mm256_loadu_ps(tmp1);
|
| 479 |
+
const auto o2 = _mm256_loadu_ps(tmp2);
|
| 480 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 481 |
+
}
|
| 482 |
+
Vectorized<T> igamma(const Vectorized<T> &x) const {
|
| 483 |
+
__m256 lo, hi;
|
| 484 |
+
__m256 xlo, xhi;
|
| 485 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 486 |
+
cvt_to_fp32<T>(x.values, xlo, xhi);
|
| 487 |
+
__at_align__ float tmp1[size() / 2], tmp2[size() / 2];
|
| 488 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 489 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 490 |
+
__at_align__ float tmpx1[size() / 2], tmpx2[size() / 2];
|
| 491 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmpx1), xlo);
|
| 492 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmpx2), xhi);
|
| 493 |
+
for (int64_t i = 0; i < size() / 2; ++i) {
|
| 494 |
+
tmp1[i] = calc_igamma(tmp1[i], tmpx1[i]);
|
| 495 |
+
tmp2[i] = calc_igamma(tmp2[i], tmpx2[i]);
|
| 496 |
+
}
|
| 497 |
+
auto o1 = _mm256_loadu_ps(tmp1);
|
| 498 |
+
auto o2 = _mm256_loadu_ps(tmp2);
|
| 499 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
Vectorized<T> igammac(const Vectorized<T> &x) const {
|
| 503 |
+
__m256 lo, hi;
|
| 504 |
+
__m256 xlo, xhi;
|
| 505 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 506 |
+
cvt_to_fp32<T>(x.values, xlo, xhi);
|
| 507 |
+
__at_align__ float tmp1[size() / 2], tmp2[size() / 2];
|
| 508 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 509 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 510 |
+
__at_align__ float tmpx1[size() / 2], tmpx2[size() / 2];
|
| 511 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmpx1), xlo);
|
| 512 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmpx2), xhi);
|
| 513 |
+
for (int64_t i = 0; i < size() / 2; ++i) {
|
| 514 |
+
tmp1[i] = calc_igammac(tmp1[i], tmpx1[i]);
|
| 515 |
+
tmp2[i] = calc_igammac(tmp2[i], tmpx2[i]);
|
| 516 |
+
}
|
| 517 |
+
auto o1 = _mm256_loadu_ps(tmp1);
|
| 518 |
+
auto o2 = _mm256_loadu_ps(tmp2);
|
| 519 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 520 |
+
}
|
| 521 |
+
Vectorized<T> log() const {
|
| 522 |
+
return map(Sleef_logf8_u10);
|
| 523 |
+
}
|
| 524 |
+
Vectorized<T> log2() const {
|
| 525 |
+
return map(Sleef_log2f8_u10);
|
| 526 |
+
}
|
| 527 |
+
Vectorized<T> log10() const {
|
| 528 |
+
return map(Sleef_log10f8_u10);
|
| 529 |
+
}
|
| 530 |
+
Vectorized<T> log1p() const {
|
| 531 |
+
return map(Sleef_log1pf8_u10);
|
| 532 |
+
}
|
| 533 |
+
Vectorized<T> sin() const {
|
| 534 |
+
return map(Sleef_sinf8_u10);
|
| 535 |
+
}
|
| 536 |
+
Vectorized<T> sinh() const {
|
| 537 |
+
return map(Sleef_sinhf8_u10);
|
| 538 |
+
}
|
| 539 |
+
Vectorized<T> cos() const {
|
| 540 |
+
return map(Sleef_cosf8_u10);
|
| 541 |
+
}
|
| 542 |
+
Vectorized<T> cosh() const {
|
| 543 |
+
return map(Sleef_coshf8_u10);
|
| 544 |
+
}
|
| 545 |
+
Vectorized<T> ceil() const {
|
| 546 |
+
__m256 lo, hi;
|
| 547 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 548 |
+
auto o1 = _mm256_ceil_ps(lo);
|
| 549 |
+
auto o2 = _mm256_ceil_ps(hi);
|
| 550 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 551 |
+
}
|
| 552 |
+
Vectorized<T> floor() const {
|
| 553 |
+
__m256 lo, hi;
|
| 554 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 555 |
+
auto o1 = _mm256_floor_ps(lo);
|
| 556 |
+
auto o2 = _mm256_floor_ps(hi);
|
| 557 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 558 |
+
}
|
| 559 |
+
Vectorized<T> neg() const {
|
| 560 |
+
return _mm256_xor_si256(values, _mm256_set1_epi16(0x8000));
|
| 561 |
+
}
|
| 562 |
+
Vectorized<T> round() const {
|
| 563 |
+
__m256 lo, hi;
|
| 564 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 565 |
+
auto o1 = _mm256_round_ps(lo, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 566 |
+
auto o2 = _mm256_round_ps(hi, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 567 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 568 |
+
}
|
| 569 |
+
Vectorized<T> tan() const {
|
| 570 |
+
return map(Sleef_tanf8_u10);
|
| 571 |
+
}
|
| 572 |
+
Vectorized<T> tanh() const {
|
| 573 |
+
return map(Sleef_tanhf8_u10);
|
| 574 |
+
}
|
| 575 |
+
Vectorized<T> trunc() const {
|
| 576 |
+
__m256 lo, hi;
|
| 577 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 578 |
+
auto o1 = _mm256_round_ps(lo, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 579 |
+
auto o2 = _mm256_round_ps(hi, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 580 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 581 |
+
}
|
| 582 |
+
Vectorized<T> lgamma() const {
|
| 583 |
+
return map(Sleef_lgammaf8_u10);
|
| 584 |
+
}
|
| 585 |
+
Vectorized<T> sqrt() const {
|
| 586 |
+
__m256 lo, hi;
|
| 587 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 588 |
+
auto o1 = _mm256_sqrt_ps(lo);
|
| 589 |
+
auto o2 = _mm256_sqrt_ps(hi);
|
| 590 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 591 |
+
}
|
| 592 |
+
Vectorized<T> reciprocal() const {
|
| 593 |
+
__m256 lo, hi;
|
| 594 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 595 |
+
auto ones = _mm256_set1_ps(1);
|
| 596 |
+
auto o1 = _mm256_div_ps(ones, lo);
|
| 597 |
+
auto o2 = _mm256_div_ps(ones, hi);
|
| 598 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 599 |
+
}
|
| 600 |
+
Vectorized<T> rsqrt() const {
|
| 601 |
+
__m256 lo, hi;
|
| 602 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 603 |
+
auto ones = _mm256_set1_ps(1);
|
| 604 |
+
auto o1 = _mm256_div_ps(ones, _mm256_sqrt_ps(lo));
|
| 605 |
+
auto o2 = _mm256_div_ps(ones, _mm256_sqrt_ps(hi));
|
| 606 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 607 |
+
}
|
| 608 |
+
Vectorized<T> pow(const Vectorized<T> &b) const {
|
| 609 |
+
__m256 lo, hi;
|
| 610 |
+
__m256 b1, b2;
|
| 611 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 612 |
+
cvt_to_fp32<T>(b.values, b1, b2);
|
| 613 |
+
auto o1 = Sleef_powf8_u10(lo, b1);
|
| 614 |
+
auto o2 = Sleef_powf8_u10(hi, b2);
|
| 615 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 616 |
+
}
|
| 617 |
+
private:
|
| 618 |
+
template<typename Op>
|
| 619 |
+
Vectorized<T> inline binary_compare(const Vectorized<T>& b, Op op) const {
|
| 620 |
+
__m256 a_lo, a_hi;
|
| 621 |
+
__m256 b_lo, b_hi;
|
| 622 |
+
cvt_to_fp32<T>(values, a_lo, a_hi);
|
| 623 |
+
cvt_to_fp32<T>(b.values, b_lo, b_hi);
|
| 624 |
+
auto o1 = op(a_lo, b_lo);
|
| 625 |
+
auto o2 = op(a_hi, b_hi);
|
| 626 |
+
return cvt_from_fp32<T, /*is_compare_op*/true>(o1, o2);
|
| 627 |
+
}
|
| 628 |
+
|
| 629 |
+
public:
|
| 630 |
+
Vectorized<T> inline operator>(const Vectorized<T>& other) const {
|
| 631 |
+
return binary_compare(other, [](__m256 x, __m256 y) { return _mm256_cmp_ps(x, y, _CMP_GT_OQ); });
|
| 632 |
+
}
|
| 633 |
+
Vectorized<T> inline operator<(const Vectorized<T>& other) const {
|
| 634 |
+
return binary_compare(other, [](__m256 x, __m256 y) { return _mm256_cmp_ps(x, y, _CMP_LT_OQ); });
|
| 635 |
+
}
|
| 636 |
+
Vectorized<T> inline operator>=(const Vectorized<T>& other) const {
|
| 637 |
+
return binary_compare(other, [](__m256 x, __m256 y) { return _mm256_cmp_ps(x, y, _CMP_GE_OQ); });
|
| 638 |
+
}
|
| 639 |
+
Vectorized<T> inline operator<=(const Vectorized<T>& other) const {
|
| 640 |
+
return binary_compare(other, [](__m256 x, __m256 y) { return _mm256_cmp_ps(x, y, _CMP_LE_OQ); });
|
| 641 |
+
}
|
| 642 |
+
Vectorized<T> inline operator==(const Vectorized<T>& other) const {
|
| 643 |
+
return binary_compare(other, [](__m256 x, __m256 y) { return _mm256_cmp_ps(x, y, _CMP_EQ_OQ); });
|
| 644 |
+
}
|
| 645 |
+
Vectorized<T> inline operator!=(const Vectorized<T>& other) const {
|
| 646 |
+
return binary_compare(other, [](__m256 x, __m256 y) { return _mm256_cmp_ps(x, y, _CMP_NEQ_UQ); });
|
| 647 |
+
}
|
| 648 |
+
};
|
| 649 |
+
|
| 650 |
+
template<typename T, typename Op>
|
| 651 |
+
static inline Vectorized<T> binary_op_as_fp32(const Vectorized<T>& a, const Vectorized<T>& b, Op op) {
|
| 652 |
+
__m256 a_lo, a_hi;
|
| 653 |
+
__m256 b_lo, b_hi;
|
| 654 |
+
cvt_to_fp32<T>(__m256i(a), a_lo, a_hi);
|
| 655 |
+
cvt_to_fp32<T>(__m256i(b), b_lo, b_hi);
|
| 656 |
+
auto o1 = op(a_lo, b_lo);
|
| 657 |
+
auto o2 = op(a_hi, b_hi);
|
| 658 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
template <>
|
| 662 |
+
class Vectorized<BFloat16>: public Vectorized16<BFloat16> {
|
| 663 |
+
public:
|
| 664 |
+
using Vectorized16::Vectorized16;
|
| 665 |
+
|
| 666 |
+
using value_type = BFloat16;
|
| 667 |
+
|
| 668 |
+
Vectorized<BFloat16> frac() const;
|
| 669 |
+
|
| 670 |
+
Vectorized<BFloat16> eq(const Vectorized<BFloat16>& other) const;
|
| 671 |
+
Vectorized<BFloat16> ne(const Vectorized<BFloat16>& other) const;
|
| 672 |
+
Vectorized<BFloat16> gt(const Vectorized<BFloat16>& other) const;
|
| 673 |
+
Vectorized<BFloat16> ge(const Vectorized<BFloat16>& other) const;
|
| 674 |
+
Vectorized<BFloat16> lt(const Vectorized<BFloat16>& other) const;
|
| 675 |
+
Vectorized<BFloat16> le(const Vectorized<BFloat16>& other) const;
|
| 676 |
+
};
|
| 677 |
+
|
| 678 |
+
Vectorized<BFloat16> inline operator+(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 679 |
+
return binary_op_as_fp32(a, b, [](const __m256& x, const __m256& y) { return _mm256_add_ps(x, y); });
|
| 680 |
+
}
|
| 681 |
+
Vectorized<BFloat16> inline operator-(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 682 |
+
return binary_op_as_fp32(a, b, [](const __m256& x, const __m256& y) { return _mm256_sub_ps(x, y); });
|
| 683 |
+
}
|
| 684 |
+
Vectorized<BFloat16> inline operator*(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 685 |
+
return binary_op_as_fp32(a, b, [](const __m256& x, const __m256& y) { return _mm256_mul_ps(x, y); });
|
| 686 |
+
}
|
| 687 |
+
Vectorized<BFloat16> inline operator/(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 688 |
+
return binary_op_as_fp32(a, b, [](const __m256& x, const __m256& y) { return _mm256_div_ps(x, y); });
|
| 689 |
+
}
|
| 690 |
+
Vectorized<BFloat16> inline operator&(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 691 |
+
return _mm256_and_si256(a, b);
|
| 692 |
+
}
|
| 693 |
+
Vectorized<BFloat16> inline operator|(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 694 |
+
return _mm256_or_si256(a, b);
|
| 695 |
+
}
|
| 696 |
+
Vectorized<BFloat16> inline operator^(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 697 |
+
return _mm256_xor_si256(a, b);
|
| 698 |
+
}
|
| 699 |
+
|
| 700 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::eq(const Vectorized<BFloat16>& other) const {
|
| 701 |
+
return (*this == other) & Vectorized<BFloat16>(1.0f);
|
| 702 |
+
}
|
| 703 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::ne(const Vectorized<BFloat16>& other) const {
|
| 704 |
+
return (*this != other) & Vectorized<BFloat16>(1.0f);
|
| 705 |
+
}
|
| 706 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::gt(const Vectorized<BFloat16>& other) const {
|
| 707 |
+
return (*this > other) & Vectorized<BFloat16>(1.0f);
|
| 708 |
+
}
|
| 709 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::ge(const Vectorized<BFloat16>& other) const {
|
| 710 |
+
return (*this >= other) & Vectorized<BFloat16>(1.0f);
|
| 711 |
+
}
|
| 712 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::lt(const Vectorized<BFloat16>& other) const {
|
| 713 |
+
return (*this < other) & Vectorized<BFloat16>(1.0f);
|
| 714 |
+
}
|
| 715 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::le(const Vectorized<BFloat16>& other) const {
|
| 716 |
+
return (*this <= other) & Vectorized<BFloat16>(1.0f);
|
| 717 |
+
}
|
| 718 |
+
|
| 719 |
+
// frac. Implement this here so we can use subtraction
|
| 720 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::frac() const {
|
| 721 |
+
return *this - this->trunc();
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 725 |
+
// either input is a NaN.
|
| 726 |
+
template <>
|
| 727 |
+
Vectorized<BFloat16> inline maximum(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 728 |
+
__m256 a_lo, a_hi;
|
| 729 |
+
__m256 b_lo, b_hi;
|
| 730 |
+
cvtbf16_fp32(__m256i(a), a_lo, a_hi);
|
| 731 |
+
cvtbf16_fp32(__m256i(b), b_lo, b_hi);
|
| 732 |
+
auto max_lo = _mm256_max_ps(a_lo, b_lo);
|
| 733 |
+
auto max_hi = _mm256_max_ps(a_hi, b_hi);
|
| 734 |
+
auto nan_lo = _mm256_cmp_ps(a_lo, b_lo, _CMP_UNORD_Q);
|
| 735 |
+
auto nan_hi = _mm256_cmp_ps(a_hi, b_hi, _CMP_UNORD_Q);
|
| 736 |
+
// Exploit the fact that all-ones is a NaN.
|
| 737 |
+
auto o1 = _mm256_or_ps(max_lo, nan_lo);
|
| 738 |
+
auto o2 = _mm256_or_ps(max_hi, nan_hi);
|
| 739 |
+
return cvtfp32_bf16(o1, o2);
|
| 740 |
+
}
|
| 741 |
+
|
| 742 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 743 |
+
// either input is a NaN.
|
| 744 |
+
template <>
|
| 745 |
+
Vectorized<BFloat16> inline minimum(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 746 |
+
__m256 a_lo, a_hi;
|
| 747 |
+
__m256 b_lo, b_hi;
|
| 748 |
+
cvtbf16_fp32(__m256i(a), a_lo, a_hi);
|
| 749 |
+
cvtbf16_fp32(__m256i(b), b_lo, b_hi);
|
| 750 |
+
auto min_lo = _mm256_min_ps(a_lo, b_lo);
|
| 751 |
+
auto min_hi = _mm256_min_ps(a_hi, b_hi);
|
| 752 |
+
auto nan_lo = _mm256_cmp_ps(a_lo, b_lo, _CMP_UNORD_Q);
|
| 753 |
+
auto nan_hi = _mm256_cmp_ps(a_hi, b_hi, _CMP_UNORD_Q);
|
| 754 |
+
// Exploit the fact that all-ones is a NaN.
|
| 755 |
+
auto o1 = _mm256_or_ps(min_lo, nan_lo);
|
| 756 |
+
auto o2 = _mm256_or_ps(min_hi, nan_hi);
|
| 757 |
+
return cvtfp32_bf16(o1, o2);
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
template <>
|
| 761 |
+
Vectorized<BFloat16> inline clamp(const Vectorized<BFloat16>& a,
|
| 762 |
+
const Vectorized<BFloat16>& min, const Vectorized<BFloat16>& max) {
|
| 763 |
+
__m256 a_lo, a_hi;
|
| 764 |
+
__m256 min_lo, min_hi;
|
| 765 |
+
__m256 max_lo, max_hi;
|
| 766 |
+
cvtbf16_fp32(__m256i(a), a_lo, a_hi);
|
| 767 |
+
cvtbf16_fp32(__m256i(min), min_lo, min_hi);
|
| 768 |
+
cvtbf16_fp32(__m256i(max), max_lo, max_hi);
|
| 769 |
+
auto o1 = _mm256_min_ps(max_lo, _mm256_max_ps(min_lo, a_lo));
|
| 770 |
+
auto o2 = _mm256_min_ps(max_hi, _mm256_max_ps(min_hi, a_hi));
|
| 771 |
+
return cvtfp32_bf16(o1, o2);
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
template <>
|
| 775 |
+
Vectorized<BFloat16> inline clamp_max(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& max) {
|
| 776 |
+
__m256 a_lo, a_hi;
|
| 777 |
+
__m256 max_lo, max_hi;
|
| 778 |
+
cvtbf16_fp32(__m256i(a), a_lo, a_hi);
|
| 779 |
+
cvtbf16_fp32(__m256i(max), max_lo, max_hi);
|
| 780 |
+
auto o1 = _mm256_min_ps(max_lo, a_lo);
|
| 781 |
+
auto o2 = _mm256_min_ps(max_hi, a_hi);
|
| 782 |
+
return cvtfp32_bf16(o1, o2);
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
template <>
|
| 786 |
+
Vectorized<BFloat16> inline clamp_min(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& min) {
|
| 787 |
+
__m256 a_lo, a_hi;
|
| 788 |
+
__m256 min_lo, min_hi;
|
| 789 |
+
cvtbf16_fp32(__m256i(a), a_lo, a_hi);
|
| 790 |
+
cvtbf16_fp32(__m256i(min), min_lo, min_hi);
|
| 791 |
+
auto o1 = _mm256_max_ps(min_lo, a_lo);
|
| 792 |
+
auto o2 = _mm256_max_ps(min_hi, a_hi);
|
| 793 |
+
return cvtfp32_bf16(o1, o2);
|
| 794 |
+
}
|
| 795 |
+
|
| 796 |
+
template <>
|
| 797 |
+
inline void convert(const BFloat16* src, BFloat16* dst, int64_t n) {
|
| 798 |
+
int64_t i;
|
| 799 |
+
#ifndef __msvc_cl__
|
| 800 |
+
#pragma unroll
|
| 801 |
+
#endif
|
| 802 |
+
for (i = 0; i <= (n - Vectorized<BFloat16>::size()); i += Vectorized<BFloat16>::size()) {
|
| 803 |
+
auto vsrc = _mm256_loadu_si256(reinterpret_cast<__m256i*>((void*)(src + i)));
|
| 804 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>((void*)(dst + i)), vsrc);
|
| 805 |
+
}
|
| 806 |
+
#ifndef __msvc_cl__
|
| 807 |
+
#pragma unroll
|
| 808 |
+
#endif
|
| 809 |
+
for (; i < n; i++) {
|
| 810 |
+
dst[i] = src[i];
|
| 811 |
+
}
|
| 812 |
+
}
|
| 813 |
+
|
| 814 |
+
template <>
|
| 815 |
+
inline void convert(const float* src, BFloat16* dst, int64_t n) {
|
| 816 |
+
int64_t i;
|
| 817 |
+
for (i = 0; i + Vectorized<BFloat16>::size() <= n; i += Vectorized<BFloat16>::size()) {
|
| 818 |
+
__m256 a = _mm256_loadu_ps(&src[i]);
|
| 819 |
+
__m256 b = _mm256_loadu_ps(&src[i + 8]);
|
| 820 |
+
|
| 821 |
+
__m256i bf = cvtfp32_bf16(a, b);
|
| 822 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(&dst[i]), bf);
|
| 823 |
+
}
|
| 824 |
+
for (; i < n; i++) {
|
| 825 |
+
dst[i] = c10::convert<BFloat16>(src[i]);
|
| 826 |
+
}
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
template <>
|
| 830 |
+
inline void convert(const double* src, BFloat16* dst, int64_t n) {
|
| 831 |
+
auto load_float = [](const double *src) -> __m256 {
|
| 832 |
+
// Load one float vector from an array of doubles
|
| 833 |
+
__m128 a = _mm256_cvtpd_ps(_mm256_loadu_pd(src));
|
| 834 |
+
__m128 b = _mm256_cvtpd_ps(_mm256_loadu_pd(src + 4));
|
| 835 |
+
return _mm256_insertf128_ps(_mm256_castps128_ps256(a), b, 1);
|
| 836 |
+
};
|
| 837 |
+
|
| 838 |
+
int64_t i;
|
| 839 |
+
for (i = 0; i + Vectorized<BFloat16>::size() <= n; i += Vectorized<BFloat16>::size()) {
|
| 840 |
+
__m256 a = load_float(&src[i]);
|
| 841 |
+
__m256 b = load_float(&src[i + 8]);
|
| 842 |
+
|
| 843 |
+
__m256i bf = cvtfp32_bf16(a, b);
|
| 844 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(&dst[i]), bf);
|
| 845 |
+
}
|
| 846 |
+
for (; i < n; i++) {
|
| 847 |
+
dst[i] = c10::convert<BFloat16>(src[i]);
|
| 848 |
+
}
|
| 849 |
+
}
|
| 850 |
+
|
| 851 |
+
template <>
|
| 852 |
+
Vectorized<BFloat16> inline fmadd(const Vectorized<BFloat16>& a,
|
| 853 |
+
const Vectorized<BFloat16>& b, const Vectorized<BFloat16>& c) {
|
| 854 |
+
__m256 a_lo, a_hi;
|
| 855 |
+
__m256 b_lo, b_hi;
|
| 856 |
+
__m256 c_lo, c_hi;
|
| 857 |
+
cvtbf16_fp32(__m256i(a), a_lo, a_hi);
|
| 858 |
+
cvtbf16_fp32(__m256i(b), b_lo, b_hi);
|
| 859 |
+
cvtbf16_fp32(__m256i(c), c_lo, c_hi);
|
| 860 |
+
auto o1 = _mm256_fmadd_ps(a_lo, b_lo, c_lo);
|
| 861 |
+
auto o2 = _mm256_fmadd_ps(a_hi, b_hi, c_hi);
|
| 862 |
+
return cvtfp32_bf16(o1, o2);
|
| 863 |
+
}
|
| 864 |
+
|
| 865 |
+
template <>
|
| 866 |
+
class Vectorized<Half>: public Vectorized16<Half> {
|
| 867 |
+
public:
|
| 868 |
+
using Vectorized16::Vectorized16;
|
| 869 |
+
|
| 870 |
+
using value_type = Half;
|
| 871 |
+
|
| 872 |
+
Vectorized<Half> frac() const;
|
| 873 |
+
|
| 874 |
+
Vectorized<Half> eq(const Vectorized<Half>& other) const;
|
| 875 |
+
Vectorized<Half> ne(const Vectorized<Half>& other) const;
|
| 876 |
+
Vectorized<Half> gt(const Vectorized<Half>& other) const;
|
| 877 |
+
Vectorized<Half> ge(const Vectorized<Half>& other) const;
|
| 878 |
+
Vectorized<Half> lt(const Vectorized<Half>& other) const;
|
| 879 |
+
Vectorized<Half> le(const Vectorized<Half>& other) const;
|
| 880 |
+
};
|
| 881 |
+
|
| 882 |
+
Vectorized<Half> inline operator+(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 883 |
+
return binary_op_as_fp32(a, b, [](const __m256& x, const __m256& y) { return _mm256_add_ps(x, y); });
|
| 884 |
+
}
|
| 885 |
+
Vectorized<Half> inline operator-(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 886 |
+
return binary_op_as_fp32(a, b, [](const __m256& x, const __m256& y) { return _mm256_sub_ps(x, y); });
|
| 887 |
+
}
|
| 888 |
+
Vectorized<Half> inline operator*(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 889 |
+
return binary_op_as_fp32(a, b, [](const __m256& x, const __m256& y) { return _mm256_mul_ps(x, y); });
|
| 890 |
+
}
|
| 891 |
+
Vectorized<Half> inline operator/(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 892 |
+
return binary_op_as_fp32(a, b, [](const __m256& x, const __m256& y) { return _mm256_div_ps(x, y); });
|
| 893 |
+
}
|
| 894 |
+
Vectorized<Half> inline operator&(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 895 |
+
return _mm256_and_si256(a, b);
|
| 896 |
+
}
|
| 897 |
+
Vectorized<Half> inline operator|(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 898 |
+
return _mm256_or_si256(a, b);
|
| 899 |
+
}
|
| 900 |
+
Vectorized<Half> inline operator^(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 901 |
+
return _mm256_xor_si256(a, b);
|
| 902 |
+
}
|
| 903 |
+
|
| 904 |
+
inline Vectorized<Half> Vectorized<Half>::eq(const Vectorized<Half>& other) const {
|
| 905 |
+
return (*this == other) & Vectorized<Half>(1.0f);
|
| 906 |
+
}
|
| 907 |
+
inline Vectorized<Half> Vectorized<Half>::ne(const Vectorized<Half>& other) const {
|
| 908 |
+
return (*this != other) & Vectorized<Half>(1.0f);
|
| 909 |
+
}
|
| 910 |
+
inline Vectorized<Half> Vectorized<Half>::gt(const Vectorized<Half>& other) const {
|
| 911 |
+
return (*this > other) & Vectorized<Half>(1.0f);
|
| 912 |
+
}
|
| 913 |
+
inline Vectorized<Half> Vectorized<Half>::ge(const Vectorized<Half>& other) const {
|
| 914 |
+
return (*this >= other) & Vectorized<Half>(1.0f);
|
| 915 |
+
}
|
| 916 |
+
inline Vectorized<Half> Vectorized<Half>::lt(const Vectorized<Half>& other) const {
|
| 917 |
+
return (*this < other) & Vectorized<Half>(1.0f);
|
| 918 |
+
}
|
| 919 |
+
inline Vectorized<Half> Vectorized<Half>::le(const Vectorized<Half>& other) const {
|
| 920 |
+
return (*this <= other) & Vectorized<Half>(1.0f);
|
| 921 |
+
}
|
| 922 |
+
|
| 923 |
+
// frac. Implement this here so we can use subtraction
|
| 924 |
+
inline Vectorized<Half> Vectorized<Half>::frac() const {
|
| 925 |
+
return *this - this->trunc();
|
| 926 |
+
}
|
| 927 |
+
|
| 928 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 929 |
+
// either input is a NaN.
|
| 930 |
+
template <>
|
| 931 |
+
Vectorized<Half> inline maximum(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 932 |
+
__m256 a_lo, a_hi;
|
| 933 |
+
__m256 b_lo, b_hi;
|
| 934 |
+
cvtfp16_fp32(__m256i(a), a_lo, a_hi);
|
| 935 |
+
cvtfp16_fp32(__m256i(b), b_lo, b_hi);
|
| 936 |
+
auto max_lo = _mm256_max_ps(a_lo, b_lo);
|
| 937 |
+
auto max_hi = _mm256_max_ps(a_hi, b_hi);
|
| 938 |
+
auto nan_lo = _mm256_cmp_ps(a_lo, b_lo, _CMP_UNORD_Q);
|
| 939 |
+
auto nan_hi = _mm256_cmp_ps(a_hi, b_hi, _CMP_UNORD_Q);
|
| 940 |
+
// Exploit the fact that all-ones is a NaN.
|
| 941 |
+
auto o1 = _mm256_or_ps(max_lo, nan_lo);
|
| 942 |
+
auto o2 = _mm256_or_ps(max_hi, nan_hi);
|
| 943 |
+
return cvtfp32_fp16(o1, o2);
|
| 944 |
+
}
|
| 945 |
+
|
| 946 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 947 |
+
// either input is a NaN.
|
| 948 |
+
template <>
|
| 949 |
+
Vectorized<Half> inline minimum(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 950 |
+
__m256 a_lo, a_hi;
|
| 951 |
+
__m256 b_lo, b_hi;
|
| 952 |
+
cvtfp16_fp32(__m256i(a), a_lo, a_hi);
|
| 953 |
+
cvtfp16_fp32(__m256i(b), b_lo, b_hi);
|
| 954 |
+
auto min_lo = _mm256_min_ps(a_lo, b_lo);
|
| 955 |
+
auto min_hi = _mm256_min_ps(a_hi, b_hi);
|
| 956 |
+
auto nan_lo = _mm256_cmp_ps(a_lo, b_lo, _CMP_UNORD_Q);
|
| 957 |
+
auto nan_hi = _mm256_cmp_ps(a_hi, b_hi, _CMP_UNORD_Q);
|
| 958 |
+
// Exploit the fact that all-ones is a NaN.
|
| 959 |
+
auto o1 = _mm256_or_ps(min_lo, nan_lo);
|
| 960 |
+
auto o2 = _mm256_or_ps(min_hi, nan_hi);
|
| 961 |
+
return cvtfp32_fp16(o1, o2);
|
| 962 |
+
}
|
| 963 |
+
|
| 964 |
+
template <>
|
| 965 |
+
Vectorized<Half> inline clamp(const Vectorized<Half>& a,
|
| 966 |
+
const Vectorized<Half>& min, const Vectorized<Half>& max) {
|
| 967 |
+
__m256 a_lo, a_hi;
|
| 968 |
+
__m256 min_lo, min_hi;
|
| 969 |
+
__m256 max_lo, max_hi;
|
| 970 |
+
cvtfp16_fp32(__m256i(a), a_lo, a_hi);
|
| 971 |
+
cvtfp16_fp32(__m256i(min), min_lo, min_hi);
|
| 972 |
+
cvtfp16_fp32(__m256i(max), max_lo, max_hi);
|
| 973 |
+
auto o1 = _mm256_min_ps(max_lo, _mm256_max_ps(min_lo, a_lo));
|
| 974 |
+
auto o2 = _mm256_min_ps(max_hi, _mm256_max_ps(min_hi, a_hi));
|
| 975 |
+
return cvtfp32_fp16(o1, o2);
|
| 976 |
+
}
|
| 977 |
+
|
| 978 |
+
template <>
|
| 979 |
+
Vectorized<Half> inline clamp_max(const Vectorized<Half>& a, const Vectorized<Half>& max) {
|
| 980 |
+
__m256 a_lo, a_hi;
|
| 981 |
+
__m256 max_lo, max_hi;
|
| 982 |
+
cvtfp16_fp32(__m256i(a), a_lo, a_hi);
|
| 983 |
+
cvtfp16_fp32(__m256i(max), max_lo, max_hi);
|
| 984 |
+
auto o1 = _mm256_min_ps(max_lo, a_lo);
|
| 985 |
+
auto o2 = _mm256_min_ps(max_hi, a_hi);
|
| 986 |
+
return cvtfp32_fp16(o1, o2);
|
| 987 |
+
}
|
| 988 |
+
|
| 989 |
+
template <>
|
| 990 |
+
Vectorized<Half> inline clamp_min(const Vectorized<Half>& a, const Vectorized<Half>& min) {
|
| 991 |
+
__m256 a_lo, a_hi;
|
| 992 |
+
__m256 min_lo, min_hi;
|
| 993 |
+
cvtfp16_fp32(__m256i(a), a_lo, a_hi);
|
| 994 |
+
cvtfp16_fp32(__m256i(min), min_lo, min_hi);
|
| 995 |
+
auto o1 = _mm256_max_ps(min_lo, a_lo);
|
| 996 |
+
auto o2 = _mm256_max_ps(min_hi, a_hi);
|
| 997 |
+
return cvtfp32_fp16(o1, o2);
|
| 998 |
+
}
|
| 999 |
+
|
| 1000 |
+
template <>
|
| 1001 |
+
inline void convert(const Half* src, Half* dst, int64_t n) {
|
| 1002 |
+
int64_t i;
|
| 1003 |
+
#ifndef __msvc_cl__
|
| 1004 |
+
#pragma unroll
|
| 1005 |
+
#endif
|
| 1006 |
+
for (i = 0; i <= (n - Vectorized<Half>::size()); i += Vectorized<Half>::size()) {
|
| 1007 |
+
auto vsrc = _mm256_loadu_si256(reinterpret_cast<__m256i*>((void*)(src + i)));
|
| 1008 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>((void*)(dst + i)), vsrc);
|
| 1009 |
+
}
|
| 1010 |
+
#ifndef __msvc_cl__
|
| 1011 |
+
#pragma unroll
|
| 1012 |
+
#endif
|
| 1013 |
+
for (; i < n; i++) {
|
| 1014 |
+
dst[i] = src[i];
|
| 1015 |
+
}
|
| 1016 |
+
}
|
| 1017 |
+
|
| 1018 |
+
template <>
|
| 1019 |
+
inline void convert(const float* src, Half* dst, int64_t n) {
|
| 1020 |
+
int64_t i;
|
| 1021 |
+
for (i = 0; i + Vectorized<Half>::size() <= n; i += Vectorized<Half>::size()) {
|
| 1022 |
+
__m256 a = _mm256_loadu_ps(&src[i]);
|
| 1023 |
+
__m256 b = _mm256_loadu_ps(&src[i + 8]);
|
| 1024 |
+
|
| 1025 |
+
__m256i c = cvtfp32_fp16(a, b);
|
| 1026 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(&dst[i]), c);
|
| 1027 |
+
}
|
| 1028 |
+
for (; i < n; i++) {
|
| 1029 |
+
dst[i] = c10::convert<Half>(src[i]);
|
| 1030 |
+
}
|
| 1031 |
+
}
|
| 1032 |
+
|
| 1033 |
+
template <>
|
| 1034 |
+
inline void convert(const double* src, Half* dst, int64_t n) {
|
| 1035 |
+
auto load_float = [](const double *src) -> __m256 {
|
| 1036 |
+
// Load one float vector from an array of doubles
|
| 1037 |
+
__m128 a = _mm256_cvtpd_ps(_mm256_loadu_pd(src));
|
| 1038 |
+
__m128 b = _mm256_cvtpd_ps(_mm256_loadu_pd(src + 4));
|
| 1039 |
+
return _mm256_insertf128_ps(_mm256_castps128_ps256(a), b, 1);
|
| 1040 |
+
};
|
| 1041 |
+
|
| 1042 |
+
int64_t i;
|
| 1043 |
+
for (i = 0; i + Vectorized<Half>::size() <= n; i += Vectorized<Half>::size()) {
|
| 1044 |
+
__m256 a = load_float(&src[i]);
|
| 1045 |
+
__m256 b = load_float(&src[i + 8]);
|
| 1046 |
+
|
| 1047 |
+
__m256i c = cvtfp32_fp16(a, b);
|
| 1048 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(&dst[i]), c);
|
| 1049 |
+
}
|
| 1050 |
+
for (; i < n; i++) {
|
| 1051 |
+
dst[i] = c10::convert<Half>(src[i]);
|
| 1052 |
+
}
|
| 1053 |
+
}
|
| 1054 |
+
|
| 1055 |
+
template <>
|
| 1056 |
+
Vectorized<Half> inline fmadd(const Vectorized<Half>& a,
|
| 1057 |
+
const Vectorized<Half>& b, const Vectorized<Half>& c) {
|
| 1058 |
+
__m256 a_lo, a_hi;
|
| 1059 |
+
__m256 b_lo, b_hi;
|
| 1060 |
+
__m256 c_lo, c_hi;
|
| 1061 |
+
cvtfp16_fp32(__m256i(a), a_lo, a_hi);
|
| 1062 |
+
cvtfp16_fp32(__m256i(b), b_lo, b_hi);
|
| 1063 |
+
cvtfp16_fp32(__m256i(c), c_lo, c_hi);
|
| 1064 |
+
auto o1 = _mm256_fmadd_ps(a_lo, b_lo, c_lo);
|
| 1065 |
+
auto o2 = _mm256_fmadd_ps(a_hi, b_hi, c_hi);
|
| 1066 |
+
return cvtfp32_fp16(o1, o2);
|
| 1067 |
+
}
|
| 1068 |
+
|
| 1069 |
+
#define CONVERT_VECTORIZED_INIT(type, name) \
|
| 1070 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_##name##_float(const Vectorized<type>& a) { \
|
| 1071 |
+
__m256 o1, o2; \
|
| 1072 |
+
cvt_to_fp32<type>(__m256i(a), o1, o2); \
|
| 1073 |
+
return std::make_tuple(o1, o2); \
|
| 1074 |
+
} \
|
| 1075 |
+
inline Vectorized<type> convert_float_##name(const Vectorized<float>& a, const Vectorized<float>& b) { \
|
| 1076 |
+
return cvt_from_fp32<type>(__m256(a), __m256(b)); \
|
| 1077 |
+
}
|
| 1078 |
+
CONVERT_VECTORIZED_INIT(BFloat16, bfloat16)
|
| 1079 |
+
CONVERT_VECTORIZED_INIT(Half, half)
|
| 1080 |
+
|
| 1081 |
+
#else // defined(CPU_CAPABILITY_AVX2)
|
| 1082 |
+
|
| 1083 |
+
#define CONVERT_NON_VECTORIZED_INIT(type, name) \
|
| 1084 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_##name##_float(const Vectorized<type>& a) { \
|
| 1085 |
+
constexpr int64_t K = Vectorized<type>::size(); \
|
| 1086 |
+
__at_align__ float arr[K]; \
|
| 1087 |
+
__at_align__ type arr2[K]; \
|
| 1088 |
+
a.store(arr2); \
|
| 1089 |
+
convert(arr2, arr, K); \
|
| 1090 |
+
return std::make_tuple( \
|
| 1091 |
+
Vectorized<float>::loadu(arr), \
|
| 1092 |
+
Vectorized<float>::loadu(arr + Vectorized<float>::size())); \
|
| 1093 |
+
} \
|
| 1094 |
+
inline Vectorized<type> convert_float_##name(const Vectorized<float>& a, const Vectorized<float>& b) { \
|
| 1095 |
+
constexpr int64_t K = Vectorized<type>::size(); \
|
| 1096 |
+
__at_align__ float arr[K]; \
|
| 1097 |
+
__at_align__ type arr2[K]; \
|
| 1098 |
+
a.store(arr); \
|
| 1099 |
+
b.store(arr + Vectorized<float>::size()); \
|
| 1100 |
+
convert(arr, arr2, K); \
|
| 1101 |
+
return Vectorized<type>::loadu(arr2); \
|
| 1102 |
+
}
|
| 1103 |
+
#if !(defined(__aarch64__) && !defined(C10_MOBILE) && !defined(__CUDACC__) && !defined(CPU_CAPABILITY_SVE256))
|
| 1104 |
+
CONVERT_NON_VECTORIZED_INIT(BFloat16, bfloat16)
|
| 1105 |
+
CONVERT_NON_VECTORIZED_INIT(Half, half)
|
| 1106 |
+
#endif
|
| 1107 |
+
|
| 1108 |
+
#endif // defined(CPU_CAPABILITY_AVX2)
|
| 1109 |
+
|
| 1110 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 1111 |
+
#define LOAD_FP32_VECTORIZED_INIT(type, name) \
|
| 1112 |
+
inline void load_fp32_from_##name(const type *data, Vectorized<float>& out) { \
|
| 1113 |
+
auto values = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data)); \
|
| 1114 |
+
__m256 out_values; \
|
| 1115 |
+
cvt_to_fp32<type>(values, out_values); \
|
| 1116 |
+
out = out_values; \
|
| 1117 |
+
} \
|
| 1118 |
+
\
|
| 1119 |
+
inline void load_fp32_from_##name(const type *data, Vectorized<float>& out1, Vectorized<float>& out2) { \
|
| 1120 |
+
auto vec = Vectorized<type>::loadu(data); \
|
| 1121 |
+
__m256 out1_values, out2_values; \
|
| 1122 |
+
cvt_to_fp32<type>(vec, out1_values, out2_values); \
|
| 1123 |
+
out1 = out1_values; \
|
| 1124 |
+
out2 = out2_values; \
|
| 1125 |
+
}
|
| 1126 |
+
LOAD_FP32_VECTORIZED_INIT(BFloat16, bf16)
|
| 1127 |
+
LOAD_FP32_VECTORIZED_INIT(Half, fp16)
|
| 1128 |
+
|
| 1129 |
+
#else // defined(CPU_CAPABILITY_AVX2)
|
| 1130 |
+
#define LOAD_FP32_NON_VECTORIZED_INIT(type, name) \
|
| 1131 |
+
inline void load_fp32_from_##name(const type *data, Vectorized<float>& out) { \
|
| 1132 |
+
__at_align__ float values[Vectorized<float>::size()]; \
|
| 1133 |
+
for (const auto k : c10::irange(Vectorized<float>::size())) { \
|
| 1134 |
+
values[k] = data[k]; \
|
| 1135 |
+
} \
|
| 1136 |
+
out = Vectorized<float>::loadu(values); \
|
| 1137 |
+
} \
|
| 1138 |
+
\
|
| 1139 |
+
inline void load_fp32_from_##name(const type *data, Vectorized<float>& out1, Vectorized<float>& out2) { \
|
| 1140 |
+
load_fp32_from_##name(data, out1); \
|
| 1141 |
+
data += Vectorized<float>::size(); \
|
| 1142 |
+
load_fp32_from_##name(data, out2); \
|
| 1143 |
+
}
|
| 1144 |
+
LOAD_FP32_NON_VECTORIZED_INIT(BFloat16, bf16)
|
| 1145 |
+
LOAD_FP32_NON_VECTORIZED_INIT(Half, fp16)
|
| 1146 |
+
|
| 1147 |
+
#endif
|
| 1148 |
+
}} // namsepace at::vec::CPU_CAPABILITY
|
| 1149 |
+
|
| 1150 |
+
#pragma GCC diagnostic pop
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_complex_double.h
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <c10/util/complex.h>
|
| 7 |
+
#include <c10/util/irange.h>
|
| 8 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 9 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 10 |
+
|
| 11 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 12 |
+
#define SLEEF_STATIC_LIBS
|
| 13 |
+
#include <sleef.h>
|
| 14 |
+
#endif
|
| 15 |
+
|
| 16 |
+
namespace at::vec {
|
| 17 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 18 |
+
inline namespace CPU_CAPABILITY {
|
| 19 |
+
|
| 20 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 21 |
+
|
| 22 |
+
template <> class Vectorized<c10::complex<double>> {
|
| 23 |
+
private:
|
| 24 |
+
__m256d values;
|
| 25 |
+
public:
|
| 26 |
+
using value_type = c10::complex<double>;
|
| 27 |
+
using size_type = int;
|
| 28 |
+
static constexpr size_type size() {
|
| 29 |
+
return 2;
|
| 30 |
+
}
|
| 31 |
+
Vectorized() {}
|
| 32 |
+
Vectorized(__m256d v) : values(v) {}
|
| 33 |
+
Vectorized(c10::complex<double> val) {
|
| 34 |
+
double real_value = val.real();
|
| 35 |
+
double imag_value = val.imag();
|
| 36 |
+
values = _mm256_setr_pd(real_value, imag_value,
|
| 37 |
+
real_value, imag_value);
|
| 38 |
+
}
|
| 39 |
+
Vectorized(c10::complex<double> val1, c10::complex<double> val2) {
|
| 40 |
+
values = _mm256_setr_pd(val1.real(), val1.imag(),
|
| 41 |
+
val2.real(), val2.imag());
|
| 42 |
+
}
|
| 43 |
+
operator __m256d() const {
|
| 44 |
+
return values;
|
| 45 |
+
}
|
| 46 |
+
template <int64_t mask>
|
| 47 |
+
static Vectorized<c10::complex<double>> blend(const Vectorized<c10::complex<double>>& a, const Vectorized<c10::complex<double>>& b) {
|
| 48 |
+
// convert c10::complex<V> index mask to V index mask: xy -> xxyy
|
| 49 |
+
static_assert (mask > -1 && mask < 4, "Unexpected mask value");
|
| 50 |
+
switch (mask) {
|
| 51 |
+
case 0:
|
| 52 |
+
return a;
|
| 53 |
+
case 1:
|
| 54 |
+
return _mm256_blend_pd(a.values, b.values, 0x03);
|
| 55 |
+
case 2:
|
| 56 |
+
return _mm256_blend_pd(a.values, b.values, 0x0c);
|
| 57 |
+
case 3: break;
|
| 58 |
+
}
|
| 59 |
+
return b;
|
| 60 |
+
}
|
| 61 |
+
static Vectorized<c10::complex<double>> blendv(const Vectorized<c10::complex<double>>& a, const Vectorized<c10::complex<double>>& b,
|
| 62 |
+
const Vectorized<c10::complex<double>>& mask) {
|
| 63 |
+
// convert c10::complex<V> index mask to V index mask: xy -> xxyy
|
| 64 |
+
auto mask_ = _mm256_unpacklo_pd(mask.values, mask.values);
|
| 65 |
+
return _mm256_blendv_pd(a.values, b.values, mask_);
|
| 66 |
+
|
| 67 |
+
}
|
| 68 |
+
template<typename step_t>
|
| 69 |
+
static Vectorized<c10::complex<double>> arange(c10::complex<double> base = 0., step_t step = static_cast<step_t>(1)) {
|
| 70 |
+
return Vectorized<c10::complex<double>>(base,
|
| 71 |
+
base + step);
|
| 72 |
+
}
|
| 73 |
+
static Vectorized<c10::complex<double>> set(const Vectorized<c10::complex<double>>& a, const Vectorized<c10::complex<double>>& b,
|
| 74 |
+
int64_t count = size()) {
|
| 75 |
+
switch (count) {
|
| 76 |
+
case 0:
|
| 77 |
+
return a;
|
| 78 |
+
case 1:
|
| 79 |
+
return blend<1>(a, b);
|
| 80 |
+
}
|
| 81 |
+
return b;
|
| 82 |
+
}
|
| 83 |
+
static Vectorized<c10::complex<double>> loadu(const void* ptr, int64_t count = size()) {
|
| 84 |
+
if (count == size())
|
| 85 |
+
return _mm256_loadu_pd(reinterpret_cast<const double*>(ptr));
|
| 86 |
+
|
| 87 |
+
__at_align__ double tmp_values[2*size()];
|
| 88 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 89 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 90 |
+
// instructions while a loop would be compiled to one instruction.
|
| 91 |
+
for (const auto i : c10::irange(2*size())) {
|
| 92 |
+
tmp_values[i] = 0.0;
|
| 93 |
+
}
|
| 94 |
+
std::memcpy(
|
| 95 |
+
tmp_values,
|
| 96 |
+
reinterpret_cast<const double*>(ptr),
|
| 97 |
+
count * sizeof(c10::complex<double>));
|
| 98 |
+
return _mm256_load_pd(tmp_values);
|
| 99 |
+
}
|
| 100 |
+
void store(void* ptr, int count = size()) const {
|
| 101 |
+
if (count == size()) {
|
| 102 |
+
_mm256_storeu_pd(reinterpret_cast<double*>(ptr), values);
|
| 103 |
+
} else if (count > 0) {
|
| 104 |
+
double tmp_values[2*size()];
|
| 105 |
+
_mm256_storeu_pd(reinterpret_cast<double*>(tmp_values), values);
|
| 106 |
+
std::memcpy(ptr, tmp_values, count * sizeof(c10::complex<double>));
|
| 107 |
+
}
|
| 108 |
+
}
|
| 109 |
+
const c10::complex<double>& operator[](int idx) const = delete;
|
| 110 |
+
c10::complex<double>& operator[](int idx) = delete;
|
| 111 |
+
Vectorized<c10::complex<double>> map(c10::complex<double> (*const f)(const c10::complex<double> &)) const {
|
| 112 |
+
__at_align__ c10::complex<double> tmp[size()];
|
| 113 |
+
store(tmp);
|
| 114 |
+
for (const auto i : c10::irange(size())) {
|
| 115 |
+
tmp[i] = f(tmp[i]);
|
| 116 |
+
}
|
| 117 |
+
return loadu(tmp);
|
| 118 |
+
}
|
| 119 |
+
__m256d abs_2_() const {
|
| 120 |
+
auto val_2 = _mm256_mul_pd(values, values); // a*a b*b
|
| 121 |
+
return _mm256_hadd_pd(val_2, val_2); // a*a+b*b a*a+b*b
|
| 122 |
+
}
|
| 123 |
+
__m256d abs_() const {
|
| 124 |
+
auto real = _mm256_movedup_pd(values); // real real
|
| 125 |
+
// movehdup_pd does not exist...
|
| 126 |
+
auto imag = _mm256_permute_pd(values, 0xf); // imag imag
|
| 127 |
+
return Sleef_hypotd4_u05(real, imag); // abs abs
|
| 128 |
+
}
|
| 129 |
+
Vectorized<c10::complex<double>> abs() const {
|
| 130 |
+
const __m256d real_mask = _mm256_castsi256_pd(_mm256_setr_epi64x(0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 131 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000));
|
| 132 |
+
return _mm256_and_pd(abs_(), real_mask); // abs 0
|
| 133 |
+
}
|
| 134 |
+
__m256d angle_() const {
|
| 135 |
+
//angle = atan2(b/a)
|
| 136 |
+
auto b_a = _mm256_permute_pd(values, 0x05); // b a
|
| 137 |
+
return Sleef_atan2d4_u10(values, b_a); // 90-angle angle
|
| 138 |
+
}
|
| 139 |
+
Vectorized<c10::complex<double>> angle() const {
|
| 140 |
+
const __m256d real_mask = _mm256_castsi256_pd(_mm256_setr_epi64x(0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 141 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000));
|
| 142 |
+
auto angle = _mm256_permute_pd(angle_(), 0x05); // angle 90-angle
|
| 143 |
+
return _mm256_and_pd(angle, real_mask); // angle 0
|
| 144 |
+
}
|
| 145 |
+
Vectorized<c10::complex<double>> sgn() const {
|
| 146 |
+
auto abs = abs_();
|
| 147 |
+
auto zero = _mm256_setzero_pd();
|
| 148 |
+
auto mask = _mm256_cmp_pd(abs, zero, _CMP_EQ_OQ);
|
| 149 |
+
auto div = _mm256_div_pd(values, abs);
|
| 150 |
+
return _mm256_blendv_pd(div, zero, mask);
|
| 151 |
+
}
|
| 152 |
+
__m256d real_() const {
|
| 153 |
+
const __m256d real_mask = _mm256_castsi256_pd(_mm256_setr_epi64x(0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 154 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000));
|
| 155 |
+
return _mm256_and_pd(values, real_mask);
|
| 156 |
+
}
|
| 157 |
+
Vectorized<c10::complex<double>> real() const {
|
| 158 |
+
return real_();
|
| 159 |
+
}
|
| 160 |
+
__m256d imag_() const {
|
| 161 |
+
const __m256d imag_mask = _mm256_castsi256_pd(_mm256_setr_epi64x(0x0000000000000000, 0xFFFFFFFFFFFFFFFF,
|
| 162 |
+
0x0000000000000000, 0xFFFFFFFFFFFFFFFF));
|
| 163 |
+
return _mm256_and_pd(values, imag_mask);
|
| 164 |
+
}
|
| 165 |
+
Vectorized<c10::complex<double>> imag() const {
|
| 166 |
+
return _mm256_permute_pd(imag_(), 0x05); //b a
|
| 167 |
+
}
|
| 168 |
+
__m256d conj_() const {
|
| 169 |
+
const __m256d sign_mask = _mm256_setr_pd(0.0, -0.0, 0.0, -0.0);
|
| 170 |
+
return _mm256_xor_pd(values, sign_mask); // a -b
|
| 171 |
+
}
|
| 172 |
+
Vectorized<c10::complex<double>> conj() const {
|
| 173 |
+
return conj_();
|
| 174 |
+
}
|
| 175 |
+
Vectorized<c10::complex<double>> log() const {
|
| 176 |
+
// Most trigonomic ops use the log() op to improve complex number performance.
|
| 177 |
+
return map(std::log);
|
| 178 |
+
}
|
| 179 |
+
Vectorized<c10::complex<double>> log2() const {
|
| 180 |
+
const __m256d log2_ = _mm256_set1_pd(std::log(2));
|
| 181 |
+
return _mm256_div_pd(log(), log2_);
|
| 182 |
+
}
|
| 183 |
+
Vectorized<c10::complex<double>> log10() const {
|
| 184 |
+
const __m256d log10_ = _mm256_set1_pd(std::log(10));
|
| 185 |
+
return _mm256_div_pd(log(), log10_);
|
| 186 |
+
}
|
| 187 |
+
Vectorized<c10::complex<double>> log1p() const {
|
| 188 |
+
return map(std::log1p);
|
| 189 |
+
}
|
| 190 |
+
Vectorized<c10::complex<double>> asin() const {
|
| 191 |
+
// asin(x)
|
| 192 |
+
// = -i*ln(iz + sqrt(1 -z^2))
|
| 193 |
+
// = -i*ln((ai - b) + sqrt(1 - (a + bi)*(a + bi)))
|
| 194 |
+
// = -i*ln((-b + ai) + sqrt(1 - (a**2 - b**2) - 2*abi))
|
| 195 |
+
const __m256d one = _mm256_set1_pd(1);
|
| 196 |
+
|
| 197 |
+
auto conj = conj_();
|
| 198 |
+
auto b_a = _mm256_permute_pd(conj, 0x05); //-b a
|
| 199 |
+
auto ab = _mm256_mul_pd(conj, b_a); //-ab -ab
|
| 200 |
+
auto im = _mm256_add_pd(ab, ab); //-2ab -2ab
|
| 201 |
+
|
| 202 |
+
auto val_2 = _mm256_mul_pd(values, values); // a*a b*b
|
| 203 |
+
auto re = _mm256_hsub_pd(val_2, _mm256_permute_pd(val_2, 0x05)); // a*a-b*b b*b-a*a
|
| 204 |
+
re = _mm256_sub_pd(one, re);
|
| 205 |
+
|
| 206 |
+
auto root = Vectorized(_mm256_blend_pd(re, im, 0x0A)).sqrt(); //sqrt(re + i*im)
|
| 207 |
+
auto ln = Vectorized(_mm256_add_pd(b_a, root)).log(); //ln(iz + sqrt())
|
| 208 |
+
return Vectorized(_mm256_permute_pd(ln.values, 0x05)).conj(); //-i*ln()
|
| 209 |
+
}
|
| 210 |
+
Vectorized<c10::complex<double>> acos() const {
|
| 211 |
+
// acos(x) = pi/2 - asin(x)
|
| 212 |
+
constexpr auto pi_2d = c10::pi<double> / 2;
|
| 213 |
+
const __m256d pi_2 = _mm256_setr_pd(pi_2d, 0.0, pi_2d, 0.0);
|
| 214 |
+
return _mm256_sub_pd(pi_2, asin());
|
| 215 |
+
}
|
| 216 |
+
Vectorized<c10::complex<double>> atan() const;
|
| 217 |
+
Vectorized<c10::complex<double>> atanh() const {
|
| 218 |
+
return map(std::atanh);
|
| 219 |
+
}
|
| 220 |
+
Vectorized<c10::complex<double>> exp() const {
|
| 221 |
+
//exp(a + bi)
|
| 222 |
+
// = exp(a)*(cos(b) + sin(b)i)
|
| 223 |
+
auto exp = Sleef_expd4_u10(values); //exp(a) exp(b)
|
| 224 |
+
exp = _mm256_blend_pd(exp, _mm256_permute_pd(exp, 0x05), 0x0A); //exp(a) exp(a)
|
| 225 |
+
|
| 226 |
+
auto sin_cos = Sleef_sincosd4_u10(values); //[sin(a), cos(a)] [sin(b), cos(b)]
|
| 227 |
+
auto cos_sin = _mm256_blend_pd(_mm256_permute_pd(sin_cos.y, 0x05),
|
| 228 |
+
sin_cos.x, 0x0A); //cos(b) sin(b)
|
| 229 |
+
return _mm256_mul_pd(exp, cos_sin);
|
| 230 |
+
}
|
| 231 |
+
Vectorized<c10::complex<double>> exp2() const {
|
| 232 |
+
// Use identity 2**x = exp(log(2) * x)
|
| 233 |
+
const __m256d ln_2 = _mm256_set1_pd(c10::ln_2<double>);
|
| 234 |
+
Vectorized<c10::complex<double>> scaled_values = _mm256_mul_pd(values, ln_2);
|
| 235 |
+
return scaled_values.exp();
|
| 236 |
+
}
|
| 237 |
+
Vectorized<c10::complex<double>> expm1() const {
|
| 238 |
+
return map(std::expm1);
|
| 239 |
+
}
|
| 240 |
+
Vectorized<c10::complex<double>> sin() const {
|
| 241 |
+
return map(std::sin);
|
| 242 |
+
}
|
| 243 |
+
Vectorized<c10::complex<double>> sinh() const {
|
| 244 |
+
return map(std::sinh);
|
| 245 |
+
}
|
| 246 |
+
Vectorized<c10::complex<double>> cos() const {
|
| 247 |
+
return map(std::cos);
|
| 248 |
+
}
|
| 249 |
+
Vectorized<c10::complex<double>> cosh() const {
|
| 250 |
+
return map(std::cosh);
|
| 251 |
+
}
|
| 252 |
+
Vectorized<c10::complex<double>> ceil() const {
|
| 253 |
+
return _mm256_ceil_pd(values);
|
| 254 |
+
}
|
| 255 |
+
Vectorized<c10::complex<double>> floor() const {
|
| 256 |
+
return _mm256_floor_pd(values);
|
| 257 |
+
}
|
| 258 |
+
Vectorized<c10::complex<double>> neg() const {
|
| 259 |
+
auto zero = _mm256_setzero_pd();
|
| 260 |
+
return _mm256_sub_pd(zero, values);
|
| 261 |
+
}
|
| 262 |
+
Vectorized<c10::complex<double>> round() const {
|
| 263 |
+
return _mm256_round_pd(values, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 264 |
+
}
|
| 265 |
+
Vectorized<c10::complex<double>> tan() const {
|
| 266 |
+
return map(std::tan);
|
| 267 |
+
}
|
| 268 |
+
Vectorized<c10::complex<double>> tanh() const {
|
| 269 |
+
return map(std::tanh);
|
| 270 |
+
}
|
| 271 |
+
Vectorized<c10::complex<double>> trunc() const {
|
| 272 |
+
return _mm256_round_pd(values, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 273 |
+
}
|
| 274 |
+
Vectorized<c10::complex<double>> sqrt() const {
|
| 275 |
+
return map(std::sqrt);
|
| 276 |
+
}
|
| 277 |
+
Vectorized<c10::complex<double>> reciprocal() const;
|
| 278 |
+
Vectorized<c10::complex<double>> rsqrt() const {
|
| 279 |
+
return sqrt().reciprocal();
|
| 280 |
+
}
|
| 281 |
+
Vectorized<c10::complex<double>> pow(const Vectorized<c10::complex<double>> &exp) const {
|
| 282 |
+
__at_align__ c10::complex<double> x_tmp[size()];
|
| 283 |
+
__at_align__ c10::complex<double> y_tmp[size()];
|
| 284 |
+
store(x_tmp);
|
| 285 |
+
exp.store(y_tmp);
|
| 286 |
+
for (const auto i : c10::irange(size())) {
|
| 287 |
+
x_tmp[i] = std::pow(x_tmp[i], y_tmp[i]);
|
| 288 |
+
}
|
| 289 |
+
return loadu(x_tmp);
|
| 290 |
+
}
|
| 291 |
+
// Comparison using the _CMP_**_OQ predicate.
|
| 292 |
+
// `O`: get false if an operand is NaN
|
| 293 |
+
// `Q`: do not raise if an operand is NaN
|
| 294 |
+
Vectorized<c10::complex<double>> operator==(const Vectorized<c10::complex<double>>& other) const {
|
| 295 |
+
return _mm256_cmp_pd(values, other.values, _CMP_EQ_OQ);
|
| 296 |
+
}
|
| 297 |
+
Vectorized<c10::complex<double>> operator!=(const Vectorized<c10::complex<double>>& other) const {
|
| 298 |
+
return _mm256_cmp_pd(values, other.values, _CMP_NEQ_UQ);
|
| 299 |
+
}
|
| 300 |
+
Vectorized<c10::complex<double>> operator<(const Vectorized<c10::complex<double>>&) const {
|
| 301 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 302 |
+
}
|
| 303 |
+
Vectorized<c10::complex<double>> operator<=(const Vectorized<c10::complex<double>>&) const {
|
| 304 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 305 |
+
}
|
| 306 |
+
Vectorized<c10::complex<double>> operator>(const Vectorized<c10::complex<double>>&) const {
|
| 307 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 308 |
+
}
|
| 309 |
+
Vectorized<c10::complex<double>> operator>=(const Vectorized<c10::complex<double>>&) const {
|
| 310 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
Vectorized<c10::complex<double>> eq(const Vectorized<c10::complex<double>>& other) const;
|
| 314 |
+
Vectorized<c10::complex<double>> ne(const Vectorized<c10::complex<double>>& other) const;
|
| 315 |
+
};
|
| 316 |
+
|
| 317 |
+
template <> Vectorized<c10::complex<double>> inline operator+(const Vectorized<c10::complex<double>> &a, const Vectorized<c10::complex<double>> &b) {
|
| 318 |
+
return _mm256_add_pd(a, b);
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
template <> Vectorized<c10::complex<double>> inline operator-(const Vectorized<c10::complex<double>> &a, const Vectorized<c10::complex<double>> &b) {
|
| 322 |
+
return _mm256_sub_pd(a, b);
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
template <> Vectorized<c10::complex<double>> inline operator*(const Vectorized<c10::complex<double>> &a, const Vectorized<c10::complex<double>> &b) {
|
| 326 |
+
//(a + bi) * (c + di) = (ac - bd) + (ad + bc)i
|
| 327 |
+
const __m256d sign_mask = _mm256_setr_pd(0.0, -0.0, 0.0, -0.0);
|
| 328 |
+
auto ac_bd = _mm256_mul_pd(a, b); //ac bd
|
| 329 |
+
|
| 330 |
+
auto d_c = _mm256_permute_pd(b, 0x05); //d c
|
| 331 |
+
d_c = _mm256_xor_pd(sign_mask, d_c); //d -c
|
| 332 |
+
auto ad_bc = _mm256_mul_pd(a, d_c); //ad -bc
|
| 333 |
+
|
| 334 |
+
auto ret = _mm256_hsub_pd(ac_bd, ad_bc); //ac - bd ad + bc
|
| 335 |
+
return ret;
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
template <> Vectorized<c10::complex<double>> inline operator/(const Vectorized<c10::complex<double>> &a, const Vectorized<c10::complex<double>> &b) {
|
| 339 |
+
//re + im*i = (a + bi) / (c + di)
|
| 340 |
+
auto mask = _mm256_set1_pd(-0.f);
|
| 341 |
+
auto fabs_cd = _mm256_andnot_pd(mask, b); // |c| |d|
|
| 342 |
+
auto fabs_dc = _mm256_permute_pd(fabs_cd, 0x05); // |d| |c|
|
| 343 |
+
auto scale = _mm256_div_pd(_mm256_set1_pd(1.0f), _mm256_max_pd(fabs_cd, fabs_dc)); // 1/sc 1/sc
|
| 344 |
+
auto a2 = _mm256_mul_pd(a, scale); // a/sc b/sc
|
| 345 |
+
auto b2 = _mm256_mul_pd(b, scale); // c/sc d/sc
|
| 346 |
+
auto acbd2 = _mm256_mul_pd(a2, b2);
|
| 347 |
+
|
| 348 |
+
const __m256d sign_mask = _mm256_setr_pd(-0.0, 0.0, -0.0, 0.0);
|
| 349 |
+
auto dc2 = _mm256_permute_pd(b2, 0x05); // d/sc c/sc
|
| 350 |
+
dc2 = _mm256_xor_pd(sign_mask, dc2); // -d/|c,d| c/sc
|
| 351 |
+
auto adbc2 = _mm256_mul_pd(a2, dc2); //-ad/sc^2 bc/sc^2
|
| 352 |
+
auto res2 = _mm256_hadd_pd(acbd2, adbc2); //(ac+bd)/sc^2 (bc-ad)/sc^2
|
| 353 |
+
|
| 354 |
+
// get the denominator
|
| 355 |
+
auto denom2 = Vectorized<c10::complex<double>>(b2).abs_2_(); // (c^2+d^2)/sc^2 (c^2+d^2)/sc^2
|
| 356 |
+
res2 = _mm256_div_pd(res2, denom2);
|
| 357 |
+
return res2;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
// reciprocal. Implement this here so we can use multiplication.
|
| 361 |
+
inline Vectorized<c10::complex<double>> Vectorized<c10::complex<double>>::reciprocal() const{
|
| 362 |
+
//re + im*i = (a + bi) / (c + di)
|
| 363 |
+
//re = (ac + bd)/abs_2() = c/abs_2()
|
| 364 |
+
//im = (bc - ad)/abs_2() = d/abs_2()
|
| 365 |
+
const __m256d sign_mask = _mm256_setr_pd(0.0, -0.0, 0.0, -0.0);
|
| 366 |
+
auto c_d = _mm256_xor_pd(sign_mask, values); //c -d
|
| 367 |
+
return _mm256_div_pd(c_d, abs_2_());
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
inline Vectorized<c10::complex<double>> Vectorized<c10::complex<double>>::atan() const {
|
| 371 |
+
// atan(x) = i/2 * ln((i + z)/(i - z))
|
| 372 |
+
const __m256d i = _mm256_setr_pd(0.0, 1.0, 0.0, 1.0);
|
| 373 |
+
const Vectorized i_half = _mm256_setr_pd(0.0, 0.5, 0.0, 0.5);
|
| 374 |
+
|
| 375 |
+
auto sum = Vectorized(_mm256_add_pd(i, values)); // a 1+b
|
| 376 |
+
auto sub = Vectorized(_mm256_sub_pd(i, values)); // -a 1-b
|
| 377 |
+
auto ln = (sum/sub).log(); // ln((i + z)/(i - z))
|
| 378 |
+
return i_half*ln; // i/2*ln()
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
template <>
|
| 382 |
+
Vectorized<c10::complex<double>> inline maximum(const Vectorized<c10::complex<double>>& a, const Vectorized<c10::complex<double>>& b) {
|
| 383 |
+
auto abs_a = a.abs_2_();
|
| 384 |
+
auto abs_b = b.abs_2_();
|
| 385 |
+
auto mask = _mm256_cmp_pd(abs_a, abs_b, _CMP_LT_OQ);
|
| 386 |
+
auto max = _mm256_blendv_pd(a, b, mask);
|
| 387 |
+
// Exploit the fact that all-ones is a NaN.
|
| 388 |
+
auto isnan = _mm256_cmp_pd(abs_a, abs_b, _CMP_UNORD_Q);
|
| 389 |
+
return _mm256_or_pd(max, isnan);
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
template <>
|
| 393 |
+
Vectorized<c10::complex<double>> inline minimum(const Vectorized<c10::complex<double>>& a, const Vectorized<c10::complex<double>>& b) {
|
| 394 |
+
auto abs_a = a.abs_2_();
|
| 395 |
+
auto abs_b = b.abs_2_();
|
| 396 |
+
auto mask = _mm256_cmp_pd(abs_a, abs_b, _CMP_GT_OQ);
|
| 397 |
+
auto min = _mm256_blendv_pd(a, b, mask);
|
| 398 |
+
// Exploit the fact that all-ones is a NaN.
|
| 399 |
+
auto isnan = _mm256_cmp_pd(abs_a, abs_b, _CMP_UNORD_Q);
|
| 400 |
+
return _mm256_or_pd(min, isnan);
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
template <>
|
| 404 |
+
Vectorized<c10::complex<double>> inline operator&(const Vectorized<c10::complex<double>>& a, const Vectorized<c10::complex<double>>& b) {
|
| 405 |
+
return _mm256_and_pd(a, b);
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
template <>
|
| 409 |
+
Vectorized<c10::complex<double>> inline operator|(const Vectorized<c10::complex<double>>& a, const Vectorized<c10::complex<double>>& b) {
|
| 410 |
+
return _mm256_or_pd(a, b);
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
template <>
|
| 414 |
+
Vectorized<c10::complex<double>> inline operator^(const Vectorized<c10::complex<double>>& a, const Vectorized<c10::complex<double>>& b) {
|
| 415 |
+
return _mm256_xor_pd(a, b);
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
inline Vectorized<c10::complex<double>> Vectorized<c10::complex<double>>::eq(const Vectorized<c10::complex<double>>& other) const {
|
| 419 |
+
auto eq = (*this == other); // compares real and imag individually
|
| 420 |
+
// If both real numbers and imag numbers are equal, then the complex numbers are equal
|
| 421 |
+
return (eq.real() & eq.imag()) & Vectorized<c10::complex<double>>(_mm256_set1_pd(1.0));
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
inline Vectorized<c10::complex<double>> Vectorized<c10::complex<double>>::ne(const Vectorized<c10::complex<double>>& other) const {
|
| 425 |
+
auto ne = (*this != other); // compares real and imag individually
|
| 426 |
+
// If either real numbers or imag numbers are not equal, then the complex numbers are not equal
|
| 427 |
+
return (ne.real() | ne.imag()) & Vectorized<c10::complex<double>>(_mm256_set1_pd(1.0));
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
#endif
|
| 431 |
+
|
| 432 |
+
}} // namespace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_complex_float.h
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <c10/util/complex.h>
|
| 7 |
+
#include <c10/util/irange.h>
|
| 8 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 9 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 10 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 11 |
+
#define SLEEF_STATIC_LIBS
|
| 12 |
+
#include <sleef.h>
|
| 13 |
+
#endif
|
| 14 |
+
|
| 15 |
+
namespace at::vec {
|
| 16 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 17 |
+
inline namespace CPU_CAPABILITY {
|
| 18 |
+
|
| 19 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 20 |
+
|
| 21 |
+
template <> class Vectorized<c10::complex<float>> {
|
| 22 |
+
private:
|
| 23 |
+
__m256 values;
|
| 24 |
+
public:
|
| 25 |
+
using value_type = c10::complex<float>;
|
| 26 |
+
using size_type = int;
|
| 27 |
+
static constexpr size_type size() {
|
| 28 |
+
return 4;
|
| 29 |
+
}
|
| 30 |
+
Vectorized() {}
|
| 31 |
+
Vectorized(__m256 v) : values(v) {}
|
| 32 |
+
Vectorized(c10::complex<float> val) {
|
| 33 |
+
float real_value = val.real();
|
| 34 |
+
float imag_value = val.imag();
|
| 35 |
+
values = _mm256_setr_ps(real_value, imag_value,
|
| 36 |
+
real_value, imag_value,
|
| 37 |
+
real_value, imag_value,
|
| 38 |
+
real_value, imag_value
|
| 39 |
+
);
|
| 40 |
+
}
|
| 41 |
+
Vectorized(c10::complex<float> val1, c10::complex<float> val2, c10::complex<float> val3, c10::complex<float> val4) {
|
| 42 |
+
values = _mm256_setr_ps(val1.real(), val1.imag(),
|
| 43 |
+
val2.real(), val2.imag(),
|
| 44 |
+
val3.real(), val3.imag(),
|
| 45 |
+
val4.real(), val4.imag()
|
| 46 |
+
);
|
| 47 |
+
}
|
| 48 |
+
operator __m256() const {
|
| 49 |
+
return values;
|
| 50 |
+
}
|
| 51 |
+
template <int64_t mask>
|
| 52 |
+
static Vectorized<c10::complex<float>> blend(const Vectorized<c10::complex<float>>& a, const Vectorized<c10::complex<float>>& b) {
|
| 53 |
+
// convert c10::complex<V> index mask to V index mask: xy -> xxyy
|
| 54 |
+
static_assert(mask > -1 && mask < 16, "Unexpected mask range");
|
| 55 |
+
switch (mask) {
|
| 56 |
+
case 0:
|
| 57 |
+
return a;
|
| 58 |
+
case 1:
|
| 59 |
+
return _mm256_blend_ps(a.values, b.values, 0x03); //b0000 0001 = b0000 0011
|
| 60 |
+
case 2:
|
| 61 |
+
return _mm256_blend_ps(a.values, b.values, 0x0C); //b0000 0010 = b0000 1100
|
| 62 |
+
case 3:
|
| 63 |
+
return _mm256_blend_ps(a.values, b.values, 0x0F); //b0000 0011 = b0000 1111
|
| 64 |
+
case 4:
|
| 65 |
+
return _mm256_blend_ps(a.values, b.values, 0x30); //b0000 0100 = b0011 0000
|
| 66 |
+
case 5:
|
| 67 |
+
return _mm256_blend_ps(a.values, b.values, 0x33); //b0000 0101 = b0011 0011
|
| 68 |
+
case 6:
|
| 69 |
+
return _mm256_blend_ps(a.values, b.values, 0x3C); //b0000 0110 = b0011 1100
|
| 70 |
+
case 7:
|
| 71 |
+
return _mm256_blend_ps(a.values, b.values, 0x3F); //b0000 0111 = b0011 1111
|
| 72 |
+
case 8:
|
| 73 |
+
return _mm256_blend_ps(a.values, b.values, 0xC0); //b0000 1000 = b1100 0000
|
| 74 |
+
case 9:
|
| 75 |
+
return _mm256_blend_ps(a.values, b.values, 0xC3); //b0000 1001 = b1100 0011
|
| 76 |
+
case 10:
|
| 77 |
+
return _mm256_blend_ps(a.values, b.values, 0xCC); //b0000 1010 = b1100 1100
|
| 78 |
+
case 11:
|
| 79 |
+
return _mm256_blend_ps(a.values, b.values, 0xCF); //b0000 1011 = b1100 1111
|
| 80 |
+
case 12:
|
| 81 |
+
return _mm256_blend_ps(a.values, b.values, 0xF0); //b0000 1100 = b1111 0000
|
| 82 |
+
case 13:
|
| 83 |
+
return _mm256_blend_ps(a.values, b.values, 0xF3); //b0000 1101 = b1111 0011
|
| 84 |
+
case 14:
|
| 85 |
+
return _mm256_blend_ps(a.values, b.values, 0xFC); //b0000 1110 = b1111 1100
|
| 86 |
+
default: break;
|
| 87 |
+
}
|
| 88 |
+
return b;
|
| 89 |
+
}
|
| 90 |
+
static Vectorized<c10::complex<float>> blendv(const Vectorized<c10::complex<float>>& a, const Vectorized<c10::complex<float>>& b,
|
| 91 |
+
const Vectorized<c10::complex<float>>& mask) {
|
| 92 |
+
// convert c10::complex<V> index mask to V index mask: xy -> xxyy
|
| 93 |
+
auto mask_ = _mm256_unpacklo_ps(mask.values, mask.values);
|
| 94 |
+
return _mm256_blendv_ps(a.values, b.values, mask_);
|
| 95 |
+
|
| 96 |
+
}
|
| 97 |
+
template<typename step_t>
|
| 98 |
+
static Vectorized<c10::complex<float>> arange(c10::complex<float> base = 0., step_t step = static_cast<step_t>(1)) {
|
| 99 |
+
return Vectorized<c10::complex<float>>(base,
|
| 100 |
+
base + step,
|
| 101 |
+
base + c10::complex<float>(2)*step,
|
| 102 |
+
base + c10::complex<float>(3)*step);
|
| 103 |
+
}
|
| 104 |
+
static Vectorized<c10::complex<float>> set(const Vectorized<c10::complex<float>>& a, const Vectorized<c10::complex<float>>& b,
|
| 105 |
+
int64_t count = size()) {
|
| 106 |
+
switch (count) {
|
| 107 |
+
case 0:
|
| 108 |
+
return a;
|
| 109 |
+
case 1:
|
| 110 |
+
return blend<1>(a, b);
|
| 111 |
+
case 2:
|
| 112 |
+
return blend<3>(a, b);
|
| 113 |
+
case 3:
|
| 114 |
+
return blend<7>(a, b);
|
| 115 |
+
}
|
| 116 |
+
return b;
|
| 117 |
+
}
|
| 118 |
+
static Vectorized<c10::complex<float>> loadu(const void* ptr, int64_t count = size()) {
|
| 119 |
+
if (count == size())
|
| 120 |
+
return _mm256_loadu_ps(reinterpret_cast<const float*>(ptr));
|
| 121 |
+
|
| 122 |
+
__at_align__ float tmp_values[2*size()];
|
| 123 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 124 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 125 |
+
// instructions while a loop would be compiled to one instruction.
|
| 126 |
+
for (const auto i : c10::irange(2*size())) {
|
| 127 |
+
tmp_values[i] = 0.0;
|
| 128 |
+
}
|
| 129 |
+
std::memcpy(
|
| 130 |
+
tmp_values,
|
| 131 |
+
reinterpret_cast<const float*>(ptr),
|
| 132 |
+
count * sizeof(c10::complex<float>));
|
| 133 |
+
return _mm256_load_ps(tmp_values);
|
| 134 |
+
}
|
| 135 |
+
void store(void* ptr, int count = size()) const {
|
| 136 |
+
if (count == size()) {
|
| 137 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(ptr), values);
|
| 138 |
+
} else if (count > 0) {
|
| 139 |
+
float tmp_values[2*size()];
|
| 140 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp_values), values);
|
| 141 |
+
std::memcpy(ptr, tmp_values, count * sizeof(c10::complex<float>));
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
const c10::complex<float>& operator[](int idx) const = delete;
|
| 145 |
+
c10::complex<float>& operator[](int idx) = delete;
|
| 146 |
+
Vectorized<c10::complex<float>> map(c10::complex<float> (*const f)(const c10::complex<float> &)) const {
|
| 147 |
+
__at_align__ c10::complex<float> tmp[size()];
|
| 148 |
+
store(tmp);
|
| 149 |
+
for (const auto i : c10::irange(size())) {
|
| 150 |
+
tmp[i] = f(tmp[i]);
|
| 151 |
+
}
|
| 152 |
+
return loadu(tmp);
|
| 153 |
+
}
|
| 154 |
+
__m256 abs_2_() const {
|
| 155 |
+
auto val_2 = _mm256_mul_ps(values, values); // a*a b*b
|
| 156 |
+
auto ret = _mm256_hadd_ps(val_2, val_2); // a*a+b*b a*a+b*b
|
| 157 |
+
return _mm256_permute_ps(ret, 0xD8);
|
| 158 |
+
}
|
| 159 |
+
__m256 abs_() const {
|
| 160 |
+
auto real = _mm256_moveldup_ps(values); // real real
|
| 161 |
+
auto imag = _mm256_movehdup_ps(values); // imag imag
|
| 162 |
+
return Sleef_hypotf8_u05(real, imag); // abs abs
|
| 163 |
+
}
|
| 164 |
+
Vectorized<c10::complex<float>> abs() const {
|
| 165 |
+
const __m256 real_mask = _mm256_castsi256_ps(_mm256_setr_epi32(0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 166 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000));
|
| 167 |
+
return _mm256_and_ps(abs_(), real_mask); // abs 0
|
| 168 |
+
}
|
| 169 |
+
__m256 angle_() const {
|
| 170 |
+
//angle = atan2(b/a)
|
| 171 |
+
auto b_a = _mm256_permute_ps(values, 0xB1); // b a
|
| 172 |
+
return Sleef_atan2f8_u10(values, b_a); // 90-angle angle
|
| 173 |
+
}
|
| 174 |
+
Vectorized<c10::complex<float>> angle() const {
|
| 175 |
+
const __m256 real_mask = _mm256_castsi256_ps(_mm256_setr_epi32(0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 176 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000));
|
| 177 |
+
auto angle = _mm256_permute_ps(angle_(), 0xB1); // angle 90-angle
|
| 178 |
+
return _mm256_and_ps(angle, real_mask); // angle 0
|
| 179 |
+
}
|
| 180 |
+
Vectorized<c10::complex<float>> sgn() const {
|
| 181 |
+
auto abs = abs_();
|
| 182 |
+
auto zero = _mm256_setzero_ps();
|
| 183 |
+
auto mask = _mm256_cmp_ps(abs, zero, _CMP_EQ_OQ);
|
| 184 |
+
auto div = _mm256_div_ps(values, abs);
|
| 185 |
+
return _mm256_blendv_ps(div, zero, mask);
|
| 186 |
+
}
|
| 187 |
+
__m256 real_() const {
|
| 188 |
+
const __m256 real_mask = _mm256_castsi256_ps(_mm256_setr_epi32(0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 189 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000));
|
| 190 |
+
return _mm256_and_ps(values, real_mask);
|
| 191 |
+
}
|
| 192 |
+
Vectorized<c10::complex<float>> real() const {
|
| 193 |
+
return real_();
|
| 194 |
+
}
|
| 195 |
+
__m256 imag_() const {
|
| 196 |
+
const __m256 imag_mask = _mm256_castsi256_ps(_mm256_setr_epi32(0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
|
| 197 |
+
0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF));
|
| 198 |
+
return _mm256_and_ps(values, imag_mask);
|
| 199 |
+
}
|
| 200 |
+
Vectorized<c10::complex<float>> imag() const {
|
| 201 |
+
return _mm256_permute_ps(imag_(), 0xB1); //b a
|
| 202 |
+
}
|
| 203 |
+
__m256 conj_() const {
|
| 204 |
+
const __m256 sign_mask = _mm256_setr_ps(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 205 |
+
return _mm256_xor_ps(values, sign_mask); // a -b
|
| 206 |
+
}
|
| 207 |
+
Vectorized<c10::complex<float>> conj() const {
|
| 208 |
+
return conj_();
|
| 209 |
+
}
|
| 210 |
+
Vectorized<c10::complex<float>> log() const {
|
| 211 |
+
// Most trigonomic ops use the log() op to improve complex number performance.
|
| 212 |
+
return map(std::log);
|
| 213 |
+
}
|
| 214 |
+
Vectorized<c10::complex<float>> log2() const {
|
| 215 |
+
const __m256 log2_ = _mm256_set1_ps(std::log(2));
|
| 216 |
+
return _mm256_div_ps(log(), log2_);
|
| 217 |
+
}
|
| 218 |
+
Vectorized<c10::complex<float>> log10() const {
|
| 219 |
+
const __m256 log10_ = _mm256_set1_ps(std::log(10));
|
| 220 |
+
return _mm256_div_ps(log(), log10_);
|
| 221 |
+
}
|
| 222 |
+
Vectorized<c10::complex<float>> log1p() const {
|
| 223 |
+
return map(std::log1p);
|
| 224 |
+
}
|
| 225 |
+
Vectorized<c10::complex<float>> asin() const {
|
| 226 |
+
// asin(x)
|
| 227 |
+
// = -i*ln(iz + sqrt(1 -z^2))
|
| 228 |
+
// = -i*ln((ai - b) + sqrt(1 - (a + bi)*(a + bi)))
|
| 229 |
+
// = -i*ln((-b + ai) + sqrt(1 - (a**2 - b**2) - 2*abi))
|
| 230 |
+
const __m256 one = _mm256_set1_ps(1);
|
| 231 |
+
|
| 232 |
+
auto conj = conj_();
|
| 233 |
+
auto b_a = _mm256_permute_ps(conj, 0xB1); //-b a
|
| 234 |
+
auto ab = _mm256_mul_ps(conj, b_a); //-ab -ab
|
| 235 |
+
auto im = _mm256_add_ps(ab, ab); //-2ab -2ab
|
| 236 |
+
|
| 237 |
+
auto val_2 = _mm256_mul_ps(values, values); // a*a b*b
|
| 238 |
+
auto re = _mm256_hsub_ps(val_2, _mm256_permute_ps(val_2, 0xB1)); // a*a-b*b b*b-a*a
|
| 239 |
+
re = _mm256_permute_ps(re, 0xD8);
|
| 240 |
+
re = _mm256_sub_ps(one, re);
|
| 241 |
+
|
| 242 |
+
auto root = Vectorized(_mm256_blend_ps(re, im, 0xAA)).sqrt(); //sqrt(re + i*im)
|
| 243 |
+
auto ln = Vectorized(_mm256_add_ps(b_a, root)).log(); //ln(iz + sqrt())
|
| 244 |
+
return Vectorized(_mm256_permute_ps(ln.values, 0xB1)).conj(); //-i*ln()
|
| 245 |
+
}
|
| 246 |
+
Vectorized<c10::complex<float>> acos() const {
|
| 247 |
+
return map(std::acos);
|
| 248 |
+
}
|
| 249 |
+
Vectorized<c10::complex<float>> atan() const;
|
| 250 |
+
Vectorized<c10::complex<float>> atanh() const {
|
| 251 |
+
return map(std::atanh);
|
| 252 |
+
}
|
| 253 |
+
Vectorized<c10::complex<float>> exp() const {
|
| 254 |
+
//exp(a + bi)
|
| 255 |
+
// = exp(a)*(cos(b) + sin(b)i)
|
| 256 |
+
auto exp = Sleef_expf8_u10(values); //exp(a) exp(b)
|
| 257 |
+
exp = _mm256_blend_ps(exp, _mm256_permute_ps(exp, 0xB1), 0xAA); //exp(a) exp(a)
|
| 258 |
+
|
| 259 |
+
auto sin_cos = Sleef_sincosf8_u10(values); //[sin(a), cos(a)] [sin(b), cos(b)]
|
| 260 |
+
auto cos_sin = _mm256_blend_ps(_mm256_permute_ps(sin_cos.y, 0xB1),
|
| 261 |
+
sin_cos.x, 0xAA); //cos(b) sin(b)
|
| 262 |
+
return _mm256_mul_ps(exp, cos_sin);
|
| 263 |
+
}
|
| 264 |
+
Vectorized<c10::complex<float>> exp2() const {
|
| 265 |
+
// Use identity 2**x = exp(log(2) * x)
|
| 266 |
+
const __m256 ln_2 = _mm256_set1_ps(c10::ln_2<float>);
|
| 267 |
+
Vectorized<c10::complex<float>> scaled_values = _mm256_mul_ps(values, ln_2);
|
| 268 |
+
return scaled_values.exp();
|
| 269 |
+
}
|
| 270 |
+
Vectorized<c10::complex<float>> expm1() const {
|
| 271 |
+
return map(std::expm1);
|
| 272 |
+
}
|
| 273 |
+
Vectorized<c10::complex<float>> sin() const {
|
| 274 |
+
return map(std::sin);
|
| 275 |
+
}
|
| 276 |
+
Vectorized<c10::complex<float>> sinh() const {
|
| 277 |
+
return map(std::sinh);
|
| 278 |
+
}
|
| 279 |
+
Vectorized<c10::complex<float>> cos() const {
|
| 280 |
+
return map(std::cos);
|
| 281 |
+
}
|
| 282 |
+
Vectorized<c10::complex<float>> cosh() const {
|
| 283 |
+
return map(std::cosh);
|
| 284 |
+
}
|
| 285 |
+
Vectorized<c10::complex<float>> ceil() const {
|
| 286 |
+
return _mm256_ceil_ps(values);
|
| 287 |
+
}
|
| 288 |
+
Vectorized<c10::complex<float>> floor() const {
|
| 289 |
+
return _mm256_floor_ps(values);
|
| 290 |
+
}
|
| 291 |
+
Vectorized<c10::complex<float>> neg() const {
|
| 292 |
+
auto zero = _mm256_setzero_ps();
|
| 293 |
+
return _mm256_sub_ps(zero, values);
|
| 294 |
+
}
|
| 295 |
+
Vectorized<c10::complex<float>> round() const {
|
| 296 |
+
return _mm256_round_ps(values, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 297 |
+
}
|
| 298 |
+
Vectorized<c10::complex<float>> tan() const {
|
| 299 |
+
return map(std::tan);
|
| 300 |
+
}
|
| 301 |
+
Vectorized<c10::complex<float>> tanh() const {
|
| 302 |
+
return map(std::tanh);
|
| 303 |
+
}
|
| 304 |
+
Vectorized<c10::complex<float>> trunc() const {
|
| 305 |
+
return _mm256_round_ps(values, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 306 |
+
}
|
| 307 |
+
Vectorized<c10::complex<float>> sqrt() const {
|
| 308 |
+
return map(std::sqrt);
|
| 309 |
+
}
|
| 310 |
+
Vectorized<c10::complex<float>> reciprocal() const;
|
| 311 |
+
Vectorized<c10::complex<float>> rsqrt() const {
|
| 312 |
+
return sqrt().reciprocal();
|
| 313 |
+
}
|
| 314 |
+
Vectorized<c10::complex<float>> pow(const Vectorized<c10::complex<float>> &exp) const {
|
| 315 |
+
__at_align__ c10::complex<float> x_tmp[size()];
|
| 316 |
+
__at_align__ c10::complex<float> y_tmp[size()];
|
| 317 |
+
store(x_tmp);
|
| 318 |
+
exp.store(y_tmp);
|
| 319 |
+
for (const auto i : c10::irange(size())) {
|
| 320 |
+
x_tmp[i] = std::pow(x_tmp[i], y_tmp[i]);
|
| 321 |
+
}
|
| 322 |
+
return loadu(x_tmp);
|
| 323 |
+
}
|
| 324 |
+
// Comparison using the _CMP_**_OQ predicate.
|
| 325 |
+
// `O`: get false if an operand is NaN
|
| 326 |
+
// `Q`: do not raise if an operand is NaN
|
| 327 |
+
Vectorized<c10::complex<float>> operator==(const Vectorized<c10::complex<float>>& other) const {
|
| 328 |
+
return _mm256_cmp_ps(values, other.values, _CMP_EQ_OQ);
|
| 329 |
+
}
|
| 330 |
+
Vectorized<c10::complex<float>> operator!=(const Vectorized<c10::complex<float>>& other) const {
|
| 331 |
+
return _mm256_cmp_ps(values, other.values, _CMP_NEQ_UQ);
|
| 332 |
+
}
|
| 333 |
+
Vectorized<c10::complex<float>> operator<(const Vectorized<c10::complex<float>>& /*other*/) const {
|
| 334 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 335 |
+
}
|
| 336 |
+
Vectorized<c10::complex<float>> operator<=(const Vectorized<c10::complex<float>>& /*other*/) const {
|
| 337 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 338 |
+
}
|
| 339 |
+
Vectorized<c10::complex<float>> operator>(const Vectorized<c10::complex<float>>& /*other*/) const {
|
| 340 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 341 |
+
}
|
| 342 |
+
Vectorized<c10::complex<float>> operator>=(const Vectorized<c10::complex<float>>& /*other*/) const {
|
| 343 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
Vectorized<c10::complex<float>> eq(const Vectorized<c10::complex<float>>& other) const;
|
| 347 |
+
Vectorized<c10::complex<float>> ne(const Vectorized<c10::complex<float>>& other) const;
|
| 348 |
+
};
|
| 349 |
+
|
| 350 |
+
template <> Vectorized<c10::complex<float>> inline operator+(const Vectorized<c10::complex<float>> &a, const Vectorized<c10::complex<float>> &b) {
|
| 351 |
+
return _mm256_add_ps(a, b);
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
+
template <> Vectorized<c10::complex<float>> inline operator-(const Vectorized<c10::complex<float>> &a, const Vectorized<c10::complex<float>> &b) {
|
| 355 |
+
return _mm256_sub_ps(a, b);
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
template <> Vectorized<c10::complex<float>> inline operator*(const Vectorized<c10::complex<float>> &a, const Vectorized<c10::complex<float>> &b) {
|
| 359 |
+
//(a + bi) * (c + di) = (ac - bd) + (ad + bc)i
|
| 360 |
+
const __m256 sign_mask = _mm256_setr_ps(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 361 |
+
auto ac_bd = _mm256_mul_ps(a, b); //ac bd
|
| 362 |
+
|
| 363 |
+
auto d_c = _mm256_permute_ps(b, 0xB1); //d c
|
| 364 |
+
d_c = _mm256_xor_ps(sign_mask, d_c); //d -c
|
| 365 |
+
auto ad_bc = _mm256_mul_ps(a, d_c); //ad -bc
|
| 366 |
+
|
| 367 |
+
auto ret = _mm256_hsub_ps(ac_bd, ad_bc); //ac - bd ad + bc
|
| 368 |
+
ret = _mm256_permute_ps(ret, 0xD8);
|
| 369 |
+
return ret;
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
template <> Vectorized<c10::complex<float>> inline operator/(const Vectorized<c10::complex<float>> &a, const Vectorized<c10::complex<float>> &b) {
|
| 373 |
+
//re + im*i = (a + bi) / (c + di)
|
| 374 |
+
auto mask = _mm256_set1_ps(-0.f);
|
| 375 |
+
auto fabs_cd = _mm256_andnot_ps(mask, b); // |c| |d|
|
| 376 |
+
auto fabs_dc = _mm256_permute_ps(fabs_cd, 0xB1); // |d| |c|
|
| 377 |
+
auto scale = _mm256_rcp_ps(_mm256_max_ps(fabs_cd, fabs_dc)); // 1/sc 1/sc
|
| 378 |
+
auto a2 = _mm256_mul_ps(a, scale); // a/sc b/sc
|
| 379 |
+
auto b2 = _mm256_mul_ps(b, scale); // c/sc d/sc
|
| 380 |
+
auto acbd2 = _mm256_mul_ps(a2, b2);
|
| 381 |
+
|
| 382 |
+
const __m256 sign_mask = _mm256_setr_ps(-0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0);
|
| 383 |
+
auto dc2 = _mm256_permute_ps(b2, 0xB1); // d/sc c/sc
|
| 384 |
+
dc2 = _mm256_xor_ps(sign_mask, dc2); // -d/|c,d| c/sc
|
| 385 |
+
auto adbc2 = _mm256_mul_ps(a2, dc2); //-ad/sc^2 bc/sc^2
|
| 386 |
+
auto res2 = _mm256_hadd_ps(acbd2, adbc2); //(ac+bd)/sc^2 (bc-ad)/sc^2
|
| 387 |
+
res2 = _mm256_permute_ps(res2, 0xD8);
|
| 388 |
+
|
| 389 |
+
// get the denominator
|
| 390 |
+
auto denom2 = Vectorized<c10::complex<float>>(b2).abs_2_(); // (c^2+d^2)/sc^2 (c^2+d^2)/sc^2
|
| 391 |
+
res2 = _mm256_div_ps(res2, denom2);
|
| 392 |
+
return res2;
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
// reciprocal. Implement this here so we can use multiplication.
|
| 396 |
+
inline Vectorized<c10::complex<float>> Vectorized<c10::complex<float>>::reciprocal() const {
|
| 397 |
+
//re + im*i = (a + bi) / (c + di)
|
| 398 |
+
//re = (ac + bd)/abs_2() = c/abs_2()
|
| 399 |
+
//im = (bc - ad)/abs_2() = d/abs_2()
|
| 400 |
+
const __m256 sign_mask = _mm256_setr_ps(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 401 |
+
auto c_d = _mm256_xor_ps(sign_mask, values); //c -d
|
| 402 |
+
return _mm256_div_ps(c_d, abs_2_());
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
inline Vectorized<c10::complex<float>> Vectorized<c10::complex<float>>::atan() const {
|
| 406 |
+
// atan(x) = i/2 * ln((i + z)/(i - z))
|
| 407 |
+
const __m256 i = _mm256_setr_ps(0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
|
| 408 |
+
const Vectorized i_half = _mm256_setr_ps(0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5);
|
| 409 |
+
|
| 410 |
+
auto sum = Vectorized(_mm256_add_ps(i, values)); // a 1+b
|
| 411 |
+
auto sub = Vectorized(_mm256_sub_ps(i, values)); // -a 1-b
|
| 412 |
+
auto ln = (sum/sub).log(); // ln((i + z)/(i - z))
|
| 413 |
+
return i_half*ln; // i/2*ln()
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
template <>
|
| 417 |
+
Vectorized<c10::complex<float>> inline maximum(const Vectorized<c10::complex<float>>& a, const Vectorized<c10::complex<float>>& b) {
|
| 418 |
+
auto abs_a = a.abs_2_();
|
| 419 |
+
auto abs_b = b.abs_2_();
|
| 420 |
+
auto mask = _mm256_cmp_ps(abs_a, abs_b, _CMP_LT_OQ);
|
| 421 |
+
auto max = _mm256_blendv_ps(a, b, mask);
|
| 422 |
+
// Exploit the fact that all-ones is a NaN.
|
| 423 |
+
auto isnan = _mm256_cmp_ps(abs_a, abs_b, _CMP_UNORD_Q);
|
| 424 |
+
return _mm256_or_ps(max, isnan);
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
template <>
|
| 428 |
+
Vectorized<c10::complex<float>> inline minimum(const Vectorized<c10::complex<float>>& a, const Vectorized<c10::complex<float>>& b) {
|
| 429 |
+
auto abs_a = a.abs_2_();
|
| 430 |
+
auto abs_b = b.abs_2_();
|
| 431 |
+
auto mask = _mm256_cmp_ps(abs_a, abs_b, _CMP_GT_OQ);
|
| 432 |
+
auto min = _mm256_blendv_ps(a, b, mask);
|
| 433 |
+
// Exploit the fact that all-ones is a NaN.
|
| 434 |
+
auto isnan = _mm256_cmp_ps(abs_a, abs_b, _CMP_UNORD_Q);
|
| 435 |
+
return _mm256_or_ps(min, isnan);
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
template <>
|
| 439 |
+
Vectorized<c10::complex<float>> inline operator&(const Vectorized<c10::complex<float>>& a, const Vectorized<c10::complex<float>>& b) {
|
| 440 |
+
return _mm256_and_ps(a, b);
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
template <>
|
| 444 |
+
Vectorized<c10::complex<float>> inline operator|(const Vectorized<c10::complex<float>>& a, const Vectorized<c10::complex<float>>& b) {
|
| 445 |
+
return _mm256_or_ps(a, b);
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
template <>
|
| 449 |
+
Vectorized<c10::complex<float>> inline operator^(const Vectorized<c10::complex<float>>& a, const Vectorized<c10::complex<float>>& b) {
|
| 450 |
+
return _mm256_xor_ps(a, b);
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
inline Vectorized<c10::complex<float>> Vectorized<c10::complex<float>>::eq(
|
| 454 |
+
const Vectorized<c10::complex<float>>& other) const {
|
| 455 |
+
auto eq = (*this == other); // compares real and imag individually
|
| 456 |
+
// If both real numbers and imag numbers are equal, then the complex numbers are equal
|
| 457 |
+
return (eq.real() & eq.imag()) & Vectorized<c10::complex<float>>(_mm256_set1_ps(1.0f));
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
inline Vectorized<c10::complex<float>> Vectorized<c10::complex<float>>::ne(
|
| 461 |
+
const Vectorized<c10::complex<float>>& other) const {
|
| 462 |
+
auto ne = (*this != other); // compares real and imag individually
|
| 463 |
+
// If either real numbers or imag numbers are not equal, then the complex numbers are not equal
|
| 464 |
+
return (ne.real() | ne.imag()) & Vectorized<c10::complex<float>>(_mm256_set1_ps(1.0f));
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
#endif
|
| 468 |
+
|
| 469 |
+
}} // namespace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_convert.h
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/functional_bfloat16.h>
|
| 4 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 6 |
+
#include <ATen/cpu/vec/vec_convert.h>
|
| 7 |
+
|
| 8 |
+
namespace at::vec {
|
| 9 |
+
inline namespace CPU_CAPABILITY {
|
| 10 |
+
|
| 11 |
+
#if defined(CPU_CAPABILITY_AVX2) && !defined(_MSC_VER)
|
| 12 |
+
|
| 13 |
+
template <>
|
| 14 |
+
struct VecConvert<float, 1, BFloat16, 1> {
|
| 15 |
+
static inline VectorizedN<float, 1> apply(
|
| 16 |
+
const VectorizedN<BFloat16, 1>& src) {
|
| 17 |
+
VectorizedN<float, 1> result;
|
| 18 |
+
__m256 value;
|
| 19 |
+
cvtbf16_fp32(_mm256_castsi256_si128(src[0]), value);
|
| 20 |
+
result[0] = value;
|
| 21 |
+
return result;
|
| 22 |
+
}
|
| 23 |
+
};
|
| 24 |
+
|
| 25 |
+
template <>
|
| 26 |
+
struct VecConvert<float, 1, Half, 1> {
|
| 27 |
+
static inline VectorizedN<float, 1> apply(const VectorizedN<Half, 1>& src) {
|
| 28 |
+
VectorizedN<float, 1> result;
|
| 29 |
+
__m256 value;
|
| 30 |
+
cvtfp16_fp32(_mm256_castsi256_si128(src[0]), value);
|
| 31 |
+
result[0] = value;
|
| 32 |
+
return result;
|
| 33 |
+
}
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
template <>
|
| 37 |
+
struct VecConvert<BFloat16, 1, float, 1> {
|
| 38 |
+
static inline VectorizedN<BFloat16, 1> apply(
|
| 39 |
+
const VectorizedN<float, 1>& src) {
|
| 40 |
+
VectorizedN<BFloat16, 1> result;
|
| 41 |
+
result[0] = _mm256_castsi128_si256(cvtfp32_bf16(src[0]));
|
| 42 |
+
return result;
|
| 43 |
+
}
|
| 44 |
+
};
|
| 45 |
+
|
| 46 |
+
template <>
|
| 47 |
+
struct VecConvert<BFloat16, 1, float, 2> {
|
| 48 |
+
static inline VectorizedN<BFloat16, 1> apply(
|
| 49 |
+
const VectorizedN<float, 2>& src) {
|
| 50 |
+
VectorizedN<BFloat16, 1> result;
|
| 51 |
+
result[0] = convert_float_bfloat16(src[0], src[1]);
|
| 52 |
+
return result;
|
| 53 |
+
}
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
template <>
|
| 57 |
+
struct VecConvert<float, 2, BFloat16, 1> {
|
| 58 |
+
static inline VectorizedN<float, 2> apply(
|
| 59 |
+
const VectorizedN<BFloat16, 1>& src) {
|
| 60 |
+
VectorizedN<float, 2> result;
|
| 61 |
+
std::tie(result[0], result[1]) = convert_bfloat16_float(src[0]);
|
| 62 |
+
return result;
|
| 63 |
+
}
|
| 64 |
+
};
|
| 65 |
+
|
| 66 |
+
template <>
|
| 67 |
+
struct VecConvert<Half, 1, float, 1> {
|
| 68 |
+
static inline VectorizedN<Half, 1> apply(const VectorizedN<float, 1>& src) {
|
| 69 |
+
VectorizedN<Half, 1> result;
|
| 70 |
+
result[0] = _mm256_castsi128_si256(cvtfp32_fp16(src[0]));
|
| 71 |
+
return result;
|
| 72 |
+
}
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
template <>
|
| 76 |
+
struct VecConvert<Half, 1, float, 2> {
|
| 77 |
+
static inline VectorizedN<Half, 1> apply(const VectorizedN<float, 2>& src) {
|
| 78 |
+
VectorizedN<Half, 1> result;
|
| 79 |
+
result[0] = convert_float_half(src[0], src[1]);
|
| 80 |
+
return result;
|
| 81 |
+
}
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
template <>
|
| 85 |
+
struct VecConvert<float, 2, Half, 1> {
|
| 86 |
+
static inline VectorizedN<float, 2> apply(const VectorizedN<Half, 1>& src) {
|
| 87 |
+
VectorizedN<float, 2> result;
|
| 88 |
+
std::tie(result[0], result[1]) = convert_half_float(src[0]);
|
| 89 |
+
return result;
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
|
| 93 |
+
template <>
|
| 94 |
+
inline Vectorized<double> convert_to_fp_of_same_size<double>(
|
| 95 |
+
const Vectorized<int64_t>& src);
|
| 96 |
+
|
| 97 |
+
template <>
|
| 98 |
+
struct VecConvert<float, 1, int64_t, 2> {
|
| 99 |
+
static inline VectorizedN<float, 1> apply(
|
| 100 |
+
const VectorizedN<int64_t, 2>& src) {
|
| 101 |
+
auto low_double = at::vec::convert_to_fp_of_same_size<double>(src[0]);
|
| 102 |
+
auto low = _mm256_cvtpd_ps(low_double);
|
| 103 |
+
auto high_double = at::vec::convert_to_fp_of_same_size<double>(src[1]);
|
| 104 |
+
auto high = _mm256_cvtpd_ps(high_double);
|
| 105 |
+
return Vectorized<float>(
|
| 106 |
+
_mm256_insertf128_ps(_mm256_castps128_ps256(low), high, 1));
|
| 107 |
+
}
|
| 108 |
+
};
|
| 109 |
+
|
| 110 |
+
template <>
|
| 111 |
+
struct VecConvert<int64_t, 2, float, 1> {
|
| 112 |
+
static inline VectorizedN<int64_t, 2> apply(
|
| 113 |
+
const VectorizedN<float, 1>& src) {
|
| 114 |
+
// Scalarization is the most reliable way of converting fp to int64 on AVX2.
|
| 115 |
+
// Check: https://stackoverflow.com/questions/41144668
|
| 116 |
+
float buffer[8];
|
| 117 |
+
src.store(buffer);
|
| 118 |
+
at::vec::VectorizedN<int64_t, 2> result;
|
| 119 |
+
result[0] = Vectorized<int64_t>(
|
| 120 |
+
static_cast<int64_t>(buffer[0]),
|
| 121 |
+
static_cast<int64_t>(buffer[1]),
|
| 122 |
+
static_cast<int64_t>(buffer[2]),
|
| 123 |
+
static_cast<int64_t>(buffer[3]));
|
| 124 |
+
result[1] = Vectorized<int64_t>(
|
| 125 |
+
static_cast<int64_t>(buffer[4]),
|
| 126 |
+
static_cast<int64_t>(buffer[5]),
|
| 127 |
+
static_cast<int64_t>(buffer[6]),
|
| 128 |
+
static_cast<int64_t>(buffer[7]));
|
| 129 |
+
return result;
|
| 130 |
+
}
|
| 131 |
+
};
|
| 132 |
+
|
| 133 |
+
template <>
|
| 134 |
+
struct VecConvert<int32_t, 1, int64_t, 2> {
|
| 135 |
+
static inline VectorizedN<int32_t, 1> apply(
|
| 136 |
+
const VectorizedN<int64_t, 2>& src) {
|
| 137 |
+
auto low = _mm256_shuffle_epi32(src[0], _MM_SHUFFLE(2, 0, 2, 0));
|
| 138 |
+
auto high = _mm256_shuffle_epi32(src[1], _MM_SHUFFLE(2, 0, 2, 0));
|
| 139 |
+
auto low_perm = _mm256_permute4x64_epi64(low, _MM_SHUFFLE(3, 1, 2, 0));
|
| 140 |
+
auto high_perm = _mm256_permute4x64_epi64(high, _MM_SHUFFLE(3, 1, 2, 0));
|
| 141 |
+
return Vectorized<int32_t>(_mm256_blend_epi32(low_perm, high_perm, 0xF0));
|
| 142 |
+
}
|
| 143 |
+
};
|
| 144 |
+
|
| 145 |
+
template <>
|
| 146 |
+
struct VecConvert<int64_t, 2, int32_t, 1> {
|
| 147 |
+
static inline VectorizedN<int64_t, 2> apply(
|
| 148 |
+
const VectorizedN<int32_t, 1>& src) {
|
| 149 |
+
at::vec::VectorizedN<int64_t, 2> result;
|
| 150 |
+
result[0] = _mm256_cvtepi32_epi64(_mm256_castsi256_si128(src[0]));
|
| 151 |
+
result[1] = _mm256_cvtepi32_epi64(_mm256_extracti128_si256(src[0], 1));
|
| 152 |
+
return result;
|
| 153 |
+
}
|
| 154 |
+
};
|
| 155 |
+
|
| 156 |
+
template <>
|
| 157 |
+
struct VecConvert<int32_t, 1, int8_t, 1> {
|
| 158 |
+
static inline VectorizedN<int32_t, 1> apply(
|
| 159 |
+
const VectorizedN<int8_t, 1>& src) {
|
| 160 |
+
auto src128 = _mm256_castsi256_si128(src[0]);
|
| 161 |
+
return Vectorized<int32_t>(_mm256_cvtepi8_epi32(src128));
|
| 162 |
+
}
|
| 163 |
+
};
|
| 164 |
+
|
| 165 |
+
template <>
|
| 166 |
+
struct VecConvert<int32_t, 1, uint8_t, 1> {
|
| 167 |
+
static inline VectorizedN<int32_t, 1> apply(
|
| 168 |
+
const VectorizedN<uint8_t, 1>& src) {
|
| 169 |
+
auto src128 = _mm256_castsi256_si128(src[0]);
|
| 170 |
+
return Vectorized<int32_t>(_mm256_cvtepu8_epi32(src128));
|
| 171 |
+
}
|
| 172 |
+
};
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
template <>
|
| 176 |
+
struct VecConvert<int32_t, 1, float, 1> {
|
| 177 |
+
static inline VectorizedN<int32_t, 1> apply(
|
| 178 |
+
const VectorizedN<float, 1>& src) {
|
| 179 |
+
return Vectorized<int32_t>(_mm256_cvttps_epi32(src[0]));
|
| 180 |
+
}
|
| 181 |
+
};
|
| 182 |
+
|
| 183 |
+
template <>
|
| 184 |
+
struct VecConvert<float, 1, int32_t, 1> {
|
| 185 |
+
static inline VectorizedN<float, 1> apply(
|
| 186 |
+
const VectorizedN<int32_t, 1>& src) {
|
| 187 |
+
return Vectorized<float>(_mm256_cvtepi32_ps(src[0]));
|
| 188 |
+
}
|
| 189 |
+
};
|
| 190 |
+
|
| 191 |
+
template <>
|
| 192 |
+
struct VecConvert<int16_t, 1, uint8_t, 1> {
|
| 193 |
+
static inline VectorizedN<int16_t, 1> apply(
|
| 194 |
+
const VectorizedN<uint8_t, 1>& src) {
|
| 195 |
+
auto src128 = _mm256_castsi256_si128(src[0]);
|
| 196 |
+
return Vectorized<int16_t>(_mm256_cvtepu8_epi16(src128));
|
| 197 |
+
}
|
| 198 |
+
};
|
| 199 |
+
|
| 200 |
+
template <typename dst_t, typename src_t>
|
| 201 |
+
struct VecConvert<
|
| 202 |
+
dst_t,
|
| 203 |
+
1,
|
| 204 |
+
src_t,
|
| 205 |
+
1,
|
| 206 |
+
typename std::enable_if_t<
|
| 207 |
+
(is_reduced_floating_point_v<dst_t> && is_8bit_integer_v<src_t>) ||
|
| 208 |
+
(is_reduced_floating_point_v<src_t> && is_8bit_integer_v<dst_t>),
|
| 209 |
+
void>> {
|
| 210 |
+
static inline VectorizedN<dst_t, 1> apply(const VectorizedN<src_t, 1>& src) {
|
| 211 |
+
VectorizedN<float, 2> tmp_fp32 = VecConvert<float, 2, src_t, 1>::apply(src);
|
| 212 |
+
return VecConvert<dst_t, 1, float, 2>::apply(tmp_fp32);
|
| 213 |
+
}
|
| 214 |
+
};
|
| 215 |
+
|
| 216 |
+
template <typename dst_t>
|
| 217 |
+
struct VecConvert<
|
| 218 |
+
dst_t,
|
| 219 |
+
1,
|
| 220 |
+
float,
|
| 221 |
+
2,
|
| 222 |
+
typename std::enable_if_t<is_8bit_integer_v<dst_t>,
|
| 223 |
+
void>> {
|
| 224 |
+
static inline VectorizedN<dst_t, 1> apply(const VectorizedN<float, 2>& src) {
|
| 225 |
+
at::vec::Vectorized<dst_t> vec1 = convert_float_to_int8<dst_t>(src[0]);
|
| 226 |
+
at::vec::Vectorized<dst_t> vec2 = convert_float_to_int8<dst_t>(src[1]);
|
| 227 |
+
__m128 lane2 = _mm256_castps256_ps128(_mm256_castsi256_ps(vec2));
|
| 228 |
+
__m256 combined = _mm256_insertf128_ps(_mm256_castsi256_ps(vec1), lane2, 1);
|
| 229 |
+
// Shuffle [191:128] bit from combined in to [127:64] bit of result
|
| 230 |
+
__m256i result = _mm256_permute4x64_epi64(_mm256_castps_si256(combined), 0b11011000);
|
| 231 |
+
return at::vec::Vectorized<dst_t>(result);
|
| 232 |
+
}
|
| 233 |
+
};
|
| 234 |
+
|
| 235 |
+
template <typename dst_t>
|
| 236 |
+
struct VecConvert<
|
| 237 |
+
dst_t,
|
| 238 |
+
1,
|
| 239 |
+
float,
|
| 240 |
+
1,
|
| 241 |
+
typename std::enable_if_t<is_8bit_integer_v<dst_t>,
|
| 242 |
+
void>> {
|
| 243 |
+
static inline VectorizedN<dst_t, 1> apply(const VectorizedN<float, 1>& src) {
|
| 244 |
+
return convert_float_to_int8<dst_t>(src[0]);
|
| 245 |
+
}
|
| 246 |
+
};
|
| 247 |
+
|
| 248 |
+
template <typename src_t>
|
| 249 |
+
struct VecConvert<
|
| 250 |
+
float,
|
| 251 |
+
2,
|
| 252 |
+
src_t,
|
| 253 |
+
1,
|
| 254 |
+
typename std::enable_if_t<is_8bit_integer_v<src_t>,
|
| 255 |
+
void>> {
|
| 256 |
+
static inline VectorizedN<float, 2> apply(const VectorizedN<src_t, 1>& src) {
|
| 257 |
+
// Shuffle [127:64] bit from src[0] in to [191:128] bit of shuffled
|
| 258 |
+
__m256i shuffled = _mm256_permute4x64_epi64(src[0], 0b11011000);
|
| 259 |
+
__m256i src2 = _mm256_castsi128_si256(
|
| 260 |
+
_mm_castps_si128(
|
| 261 |
+
_mm256_extractf128_ps(_mm256_castsi256_ps(shuffled), 1) // Extract the second 128-bit lane
|
| 262 |
+
)
|
| 263 |
+
);
|
| 264 |
+
return VectorizedN<float, 2>(convert_int8_to_float<src_t>(src[0]), convert_int8_to_float<src_t>(src2));
|
| 265 |
+
}
|
| 266 |
+
};
|
| 267 |
+
|
| 268 |
+
template <typename dst_t>
|
| 269 |
+
struct VecConvert<
|
| 270 |
+
dst_t,
|
| 271 |
+
1,
|
| 272 |
+
int64_t,
|
| 273 |
+
2,
|
| 274 |
+
std::enable_if_t<
|
| 275 |
+
std::is_same_v<dst_t, int8_t> ||
|
| 276 |
+
std::is_same_v<dst_t, uint8_t>>> {
|
| 277 |
+
static inline VectorizedN<dst_t, 1> apply(
|
| 278 |
+
const VectorizedN<int64_t, 2>& src) {
|
| 279 |
+
return VecConvert<dst_t, 1, int32_t, 1>::apply(
|
| 280 |
+
VecConvert<int32_t, 1, int64_t, 2>::apply(src));
|
| 281 |
+
}
|
| 282 |
+
};
|
| 283 |
+
|
| 284 |
+
#endif /* defined(CPU_CAPABILITY_AVX2) && !defined(_MSC_VER) */
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
#if (defined(CPU_CAPABILITY_AVX2) && !defined(_MSC_VER))
|
| 288 |
+
template <typename src_t>
|
| 289 |
+
struct VecConvert<
|
| 290 |
+
float,
|
| 291 |
+
1,
|
| 292 |
+
src_t,
|
| 293 |
+
1,
|
| 294 |
+
typename std::enable_if_t<is_8bit_integer_v<src_t>,
|
| 295 |
+
void>> {
|
| 296 |
+
static inline VectorizedN<float, 1> apply(const VectorizedN<src_t, 1>& src) {
|
| 297 |
+
return convert_int8_to_float<src_t>(src[0]);
|
| 298 |
+
}
|
| 299 |
+
};
|
| 300 |
+
#endif
|
| 301 |
+
|
| 302 |
+
template <typename src_t>
|
| 303 |
+
struct VecConvert<
|
| 304 |
+
float,
|
| 305 |
+
1,
|
| 306 |
+
src_t,
|
| 307 |
+
1,
|
| 308 |
+
typename std::enable_if_t<is_reduced_floating_point_v<src_t>, void>> {
|
| 309 |
+
static inline VectorizedN<float, 1> apply(const VectorizedN<src_t, 1>& src) {
|
| 310 |
+
auto [res_vec1, res_vec2] = convert_to_float<src_t>(src[0]);
|
| 311 |
+
return res_vec1;
|
| 312 |
+
}
|
| 313 |
+
};
|
| 314 |
+
|
| 315 |
+
template <typename dst_t>
|
| 316 |
+
struct VecConvert<
|
| 317 |
+
dst_t,
|
| 318 |
+
1,
|
| 319 |
+
float,
|
| 320 |
+
1,
|
| 321 |
+
typename std::enable_if_t<is_reduced_floating_point_v<dst_t>, void>> {
|
| 322 |
+
static inline VectorizedN<dst_t, 1> apply(const VectorizedN<float, 1>& src) {
|
| 323 |
+
return convert_from_float<dst_t>(src[0], src[0]);
|
| 324 |
+
}
|
| 325 |
+
};
|
| 326 |
+
|
| 327 |
+
} // namespace CPU_CAPABILITY
|
| 328 |
+
} // namespace at::vec
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_double.h
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <c10/util/irange.h>
|
| 9 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 10 |
+
#define SLEEF_STATIC_LIBS
|
| 11 |
+
#include <sleef.h>
|
| 12 |
+
#endif
|
| 13 |
+
|
| 14 |
+
namespace at::vec {
|
| 15 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 16 |
+
inline namespace CPU_CAPABILITY {
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 20 |
+
|
| 21 |
+
template <> class Vectorized<double> {
|
| 22 |
+
private:
|
| 23 |
+
__m256d values;
|
| 24 |
+
public:
|
| 25 |
+
using value_type = double;
|
| 26 |
+
using size_type = int;
|
| 27 |
+
static constexpr size_type size() {
|
| 28 |
+
return 4;
|
| 29 |
+
}
|
| 30 |
+
Vectorized() {}
|
| 31 |
+
Vectorized(__m256d v) : values(v) {}
|
| 32 |
+
Vectorized(double val) {
|
| 33 |
+
values = _mm256_set1_pd(val);
|
| 34 |
+
}
|
| 35 |
+
Vectorized(double val1, double val2, double val3, double val4) {
|
| 36 |
+
values = _mm256_setr_pd(val1, val2, val3, val4);
|
| 37 |
+
}
|
| 38 |
+
operator __m256d() const {
|
| 39 |
+
return values;
|
| 40 |
+
}
|
| 41 |
+
template <int64_t mask>
|
| 42 |
+
static Vectorized<double> blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 43 |
+
return _mm256_blend_pd(a.values, b.values, mask);
|
| 44 |
+
}
|
| 45 |
+
static Vectorized<double> blendv(const Vectorized<double>& a, const Vectorized<double>& b,
|
| 46 |
+
const Vectorized<double>& mask) {
|
| 47 |
+
return _mm256_blendv_pd(a.values, b.values, mask.values);
|
| 48 |
+
}
|
| 49 |
+
template<typename step_t>
|
| 50 |
+
static Vectorized<double> arange(double base = 0., step_t step = static_cast<step_t>(1)) {
|
| 51 |
+
return Vectorized<double>(base, base + step, base + 2 * step, base + 3 * step);
|
| 52 |
+
}
|
| 53 |
+
static Vectorized<double> set(const Vectorized<double>& a, const Vectorized<double>& b,
|
| 54 |
+
int64_t count = size()) {
|
| 55 |
+
switch (count) {
|
| 56 |
+
case 0:
|
| 57 |
+
return a;
|
| 58 |
+
case 1:
|
| 59 |
+
return blend<1>(a, b);
|
| 60 |
+
case 2:
|
| 61 |
+
return blend<3>(a, b);
|
| 62 |
+
case 3:
|
| 63 |
+
return blend<7>(a, b);
|
| 64 |
+
}
|
| 65 |
+
return b;
|
| 66 |
+
}
|
| 67 |
+
static Vectorized<double> loadu(const void* ptr, int64_t count = size()) {
|
| 68 |
+
if (count == size())
|
| 69 |
+
return _mm256_loadu_pd(reinterpret_cast<const double*>(ptr));
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
__at_align__ double tmp_values[size()];
|
| 73 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 74 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 75 |
+
// instructions while a loop would be compiled to one instruction.
|
| 76 |
+
for (const auto i : c10::irange(size())) {
|
| 77 |
+
tmp_values[i] = 0.0;
|
| 78 |
+
}
|
| 79 |
+
std::memcpy(
|
| 80 |
+
tmp_values,
|
| 81 |
+
reinterpret_cast<const double*>(ptr),
|
| 82 |
+
count * sizeof(double));
|
| 83 |
+
return _mm256_load_pd(tmp_values);
|
| 84 |
+
}
|
| 85 |
+
void store(void* ptr, int count = size()) const {
|
| 86 |
+
if (count == size()) {
|
| 87 |
+
_mm256_storeu_pd(reinterpret_cast<double*>(ptr), values);
|
| 88 |
+
} else if (count > 0) {
|
| 89 |
+
double tmp_values[size()];
|
| 90 |
+
_mm256_storeu_pd(reinterpret_cast<double*>(tmp_values), values);
|
| 91 |
+
std::memcpy(ptr, tmp_values, count * sizeof(double));
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
const double& operator[](int idx) const = delete;
|
| 95 |
+
double& operator[](int idx) = delete;
|
| 96 |
+
int zero_mask() const {
|
| 97 |
+
// returns an integer mask where all zero elements are translated to 1-bit and others are translated to 0-bit
|
| 98 |
+
__m256d cmp = _mm256_cmp_pd(values, _mm256_set1_pd(0.0), _CMP_EQ_OQ);
|
| 99 |
+
return _mm256_movemask_pd(cmp);
|
| 100 |
+
}
|
| 101 |
+
Vectorized<double> isnan() const {
|
| 102 |
+
return _mm256_cmp_pd(values, _mm256_set1_pd(0.0), _CMP_UNORD_Q);
|
| 103 |
+
}
|
| 104 |
+
bool has_inf_nan() const {
|
| 105 |
+
__m256d self_sub = _mm256_sub_pd(values, values);
|
| 106 |
+
return (_mm256_movemask_epi8(_mm256_castpd_si256(self_sub)) & 0x77777777) != 0;
|
| 107 |
+
}
|
| 108 |
+
Vectorized<double> map(double (*const f)(double)) const {
|
| 109 |
+
__at_align__ double tmp[size()];
|
| 110 |
+
store(tmp);
|
| 111 |
+
for (const auto i : c10::irange(size())) {
|
| 112 |
+
tmp[i] = f(tmp[i]);
|
| 113 |
+
}
|
| 114 |
+
return loadu(tmp);
|
| 115 |
+
}
|
| 116 |
+
Vectorized<double> abs() const {
|
| 117 |
+
auto mask = _mm256_set1_pd(-0.f);
|
| 118 |
+
return _mm256_andnot_pd(mask, values);
|
| 119 |
+
}
|
| 120 |
+
Vectorized<double> angle() const {
|
| 121 |
+
const auto zero_vec = _mm256_set1_pd(0.f);
|
| 122 |
+
const auto nan_vec = _mm256_set1_pd(NAN);
|
| 123 |
+
const auto not_nan_mask = _mm256_cmp_pd(values, values, _CMP_EQ_OQ);
|
| 124 |
+
const auto nan_mask = _mm256_cmp_pd(not_nan_mask, zero_vec, _CMP_EQ_OQ);
|
| 125 |
+
const auto pi = _mm256_set1_pd(c10::pi<double>);
|
| 126 |
+
|
| 127 |
+
const auto neg_mask = _mm256_cmp_pd(values, zero_vec, _CMP_LT_OQ);
|
| 128 |
+
auto angle = _mm256_blendv_pd(zero_vec, pi, neg_mask);
|
| 129 |
+
angle = _mm256_blendv_pd(angle, nan_vec, nan_mask);
|
| 130 |
+
return angle;
|
| 131 |
+
}
|
| 132 |
+
Vectorized<double> real() const {
|
| 133 |
+
return *this;
|
| 134 |
+
}
|
| 135 |
+
Vectorized<double> imag() const {
|
| 136 |
+
return _mm256_set1_pd(0);
|
| 137 |
+
}
|
| 138 |
+
Vectorized<double> conj() const {
|
| 139 |
+
return *this;
|
| 140 |
+
}
|
| 141 |
+
Vectorized<double> acos() const {
|
| 142 |
+
return Vectorized<double>(Sleef_acosd4_u10(values));
|
| 143 |
+
}
|
| 144 |
+
Vectorized<double> acosh() const {
|
| 145 |
+
return Vectorized<double>(Sleef_acoshd4_u10(values));
|
| 146 |
+
}
|
| 147 |
+
Vectorized<double> asin() const {
|
| 148 |
+
return Vectorized<double>(Sleef_asind4_u10(values));
|
| 149 |
+
}
|
| 150 |
+
Vectorized<double> atan() const {
|
| 151 |
+
return Vectorized<double>(Sleef_atand4_u10(values));
|
| 152 |
+
}
|
| 153 |
+
Vectorized<double> atanh() const {
|
| 154 |
+
return Vectorized<double>(Sleef_atanhd4_u10(values));
|
| 155 |
+
}
|
| 156 |
+
Vectorized<double> atan2(const Vectorized<double> &b) const {
|
| 157 |
+
return Vectorized<double>(Sleef_atan2d4_u10(values, b));
|
| 158 |
+
}
|
| 159 |
+
Vectorized<double> copysign(const Vectorized<double> &sign) const {
|
| 160 |
+
return Vectorized<double>(Sleef_copysignd4(values, sign));
|
| 161 |
+
}
|
| 162 |
+
Vectorized<double> erf() const {
|
| 163 |
+
return Vectorized<double>(Sleef_erfd4_u10(values));
|
| 164 |
+
}
|
| 165 |
+
Vectorized<double> erfc() const {
|
| 166 |
+
return Vectorized<double>(Sleef_erfcd4_u15(values));
|
| 167 |
+
}
|
| 168 |
+
Vectorized<double> erfinv() const {
|
| 169 |
+
return map(calc_erfinv);
|
| 170 |
+
}
|
| 171 |
+
Vectorized<double> exp() const {
|
| 172 |
+
return Vectorized<double>(Sleef_expd4_u10(values));
|
| 173 |
+
}
|
| 174 |
+
Vectorized<double> exp2() const {
|
| 175 |
+
return Vectorized<double>(Sleef_exp2d4_u10(values));
|
| 176 |
+
}
|
| 177 |
+
Vectorized<double> expm1() const {
|
| 178 |
+
return Vectorized<double>(Sleef_expm1d4_u10(values));
|
| 179 |
+
}
|
| 180 |
+
Vectorized<double> exp_u20() const {
|
| 181 |
+
return exp();
|
| 182 |
+
}
|
| 183 |
+
Vectorized<double> fmod(const Vectorized<double>& q) const {
|
| 184 |
+
return Vectorized<double>(Sleef_fmodd4(values, q));
|
| 185 |
+
}
|
| 186 |
+
Vectorized<double> hypot(const Vectorized<double> &b) const {
|
| 187 |
+
return Vectorized<double>(Sleef_hypotd4_u05(values, b));
|
| 188 |
+
}
|
| 189 |
+
Vectorized<double> i0() const {
|
| 190 |
+
return map(calc_i0);
|
| 191 |
+
}
|
| 192 |
+
Vectorized<double> i0e() const {
|
| 193 |
+
return map(calc_i0e);
|
| 194 |
+
}
|
| 195 |
+
Vectorized<double> digamma() const {
|
| 196 |
+
return map(calc_digamma);
|
| 197 |
+
}
|
| 198 |
+
Vectorized<double> igamma(const Vectorized<double> &x) const {
|
| 199 |
+
__at_align__ double tmp[size()];
|
| 200 |
+
__at_align__ double tmp_x[size()];
|
| 201 |
+
store(tmp);
|
| 202 |
+
x.store(tmp_x);
|
| 203 |
+
for (const auto i : c10::irange(size())) {
|
| 204 |
+
tmp[i] = calc_igamma(tmp[i], tmp_x[i]);
|
| 205 |
+
}
|
| 206 |
+
return loadu(tmp);
|
| 207 |
+
}
|
| 208 |
+
Vectorized<double> igammac(const Vectorized<double> &x) const {
|
| 209 |
+
__at_align__ double tmp[size()];
|
| 210 |
+
__at_align__ double tmp_x[size()];
|
| 211 |
+
store(tmp);
|
| 212 |
+
x.store(tmp_x);
|
| 213 |
+
for (const auto i : c10::irange(size())) {
|
| 214 |
+
tmp[i] = calc_igammac(tmp[i], tmp_x[i]);
|
| 215 |
+
}
|
| 216 |
+
return loadu(tmp);
|
| 217 |
+
}
|
| 218 |
+
Vectorized<double> log() const {
|
| 219 |
+
return Vectorized<double>(Sleef_logd4_u10(values));
|
| 220 |
+
}
|
| 221 |
+
Vectorized<double> log2() const {
|
| 222 |
+
return Vectorized<double>(Sleef_log2d4_u10(values));
|
| 223 |
+
}
|
| 224 |
+
Vectorized<double> log10() const {
|
| 225 |
+
return Vectorized<double>(Sleef_log10d4_u10(values));
|
| 226 |
+
}
|
| 227 |
+
Vectorized<double> log1p() const {
|
| 228 |
+
return Vectorized<double>(Sleef_log1pd4_u10(values));
|
| 229 |
+
}
|
| 230 |
+
Vectorized<double> sin() const {
|
| 231 |
+
return Vectorized<double>(Sleef_sind4_u10(values));
|
| 232 |
+
}
|
| 233 |
+
Vectorized<double> sinh() const {
|
| 234 |
+
return Vectorized<double>(Sleef_sinhd4_u10(values));
|
| 235 |
+
}
|
| 236 |
+
Vectorized<double> cos() const {
|
| 237 |
+
return Vectorized<double>(Sleef_cosd4_u10(values));
|
| 238 |
+
}
|
| 239 |
+
Vectorized<double> cosh() const {
|
| 240 |
+
return Vectorized<double>(Sleef_coshd4_u10(values));
|
| 241 |
+
}
|
| 242 |
+
Vectorized<double> ceil() const {
|
| 243 |
+
return _mm256_ceil_pd(values);
|
| 244 |
+
}
|
| 245 |
+
Vectorized<double> floor() const {
|
| 246 |
+
return _mm256_floor_pd(values);
|
| 247 |
+
}
|
| 248 |
+
Vectorized<double> frac() const;
|
| 249 |
+
Vectorized<double> neg() const {
|
| 250 |
+
return _mm256_xor_pd(_mm256_set1_pd(-0.), values);
|
| 251 |
+
}
|
| 252 |
+
Vectorized<double> nextafter(const Vectorized<double> &b) const {
|
| 253 |
+
return Vectorized<double>(Sleef_nextafterd4(values, b));
|
| 254 |
+
}
|
| 255 |
+
Vectorized<double> round() const {
|
| 256 |
+
return _mm256_round_pd(values, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 257 |
+
}
|
| 258 |
+
Vectorized<double> tan() const {
|
| 259 |
+
return Vectorized<double>(Sleef_tand4_u10(values));
|
| 260 |
+
}
|
| 261 |
+
Vectorized<double> tanh() const {
|
| 262 |
+
return Vectorized<double>(Sleef_tanhd4_u10(values));
|
| 263 |
+
}
|
| 264 |
+
Vectorized<double> trunc() const {
|
| 265 |
+
return _mm256_round_pd(values, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 266 |
+
}
|
| 267 |
+
Vectorized<double> lgamma() const {
|
| 268 |
+
return Vectorized<double>(Sleef_lgammad4_u10(values));
|
| 269 |
+
}
|
| 270 |
+
Vectorized<double> sqrt() const {
|
| 271 |
+
return _mm256_sqrt_pd(values);
|
| 272 |
+
}
|
| 273 |
+
Vectorized<double> reciprocal() const {
|
| 274 |
+
return _mm256_div_pd(_mm256_set1_pd(1), values);
|
| 275 |
+
}
|
| 276 |
+
Vectorized<double> rsqrt() const {
|
| 277 |
+
return _mm256_div_pd(_mm256_set1_pd(1), _mm256_sqrt_pd(values));
|
| 278 |
+
}
|
| 279 |
+
Vectorized<double> pow(const Vectorized<double> &b) const {
|
| 280 |
+
return Vectorized<double>(Sleef_powd4_u10(values, b));
|
| 281 |
+
}
|
| 282 |
+
// Comparison using the _CMP_**_OQ predicate.
|
| 283 |
+
// `O`: get false if an operand is NaN
|
| 284 |
+
// `Q`: do not raise if an operand is NaN
|
| 285 |
+
Vectorized<double> operator==(const Vectorized<double>& other) const {
|
| 286 |
+
return _mm256_cmp_pd(values, other.values, _CMP_EQ_OQ);
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
Vectorized<double> operator!=(const Vectorized<double>& other) const {
|
| 290 |
+
return _mm256_cmp_pd(values, other.values, _CMP_NEQ_UQ);
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
Vectorized<double> operator<(const Vectorized<double>& other) const {
|
| 294 |
+
return _mm256_cmp_pd(values, other.values, _CMP_LT_OQ);
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
Vectorized<double> operator<=(const Vectorized<double>& other) const {
|
| 298 |
+
return _mm256_cmp_pd(values, other.values, _CMP_LE_OQ);
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
Vectorized<double> operator>(const Vectorized<double>& other) const {
|
| 302 |
+
return _mm256_cmp_pd(values, other.values, _CMP_GT_OQ);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
Vectorized<double> operator>=(const Vectorized<double>& other) const {
|
| 306 |
+
return _mm256_cmp_pd(values, other.values, _CMP_GE_OQ);
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
Vectorized<double> eq(const Vectorized<double>& other) const;
|
| 310 |
+
Vectorized<double> ne(const Vectorized<double>& other) const;
|
| 311 |
+
Vectorized<double> lt(const Vectorized<double>& other) const;
|
| 312 |
+
Vectorized<double> le(const Vectorized<double>& other) const;
|
| 313 |
+
Vectorized<double> gt(const Vectorized<double>& other) const;
|
| 314 |
+
Vectorized<double> ge(const Vectorized<double>& other) const;
|
| 315 |
+
};
|
| 316 |
+
|
| 317 |
+
template <>
|
| 318 |
+
Vectorized<double> inline operator+(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 319 |
+
return _mm256_add_pd(a, b);
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
template <>
|
| 323 |
+
Vectorized<double> inline operator-(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 324 |
+
return _mm256_sub_pd(a, b);
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
template <>
|
| 328 |
+
Vectorized<double> inline operator*(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 329 |
+
return _mm256_mul_pd(a, b);
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
template <>
|
| 333 |
+
Vectorized<double> inline operator/(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 334 |
+
return _mm256_div_pd(a, b);
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
// frac. Implement this here so we can use subtraction.
|
| 338 |
+
inline Vectorized<double> Vectorized<double>::frac() const {
|
| 339 |
+
return *this - this->trunc();
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 343 |
+
// either input is a NaN.
|
| 344 |
+
template <>
|
| 345 |
+
Vectorized<double> inline maximum(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 346 |
+
Vectorized<double> max = _mm256_max_pd(a, b);
|
| 347 |
+
Vectorized<double> isnan = _mm256_cmp_pd(a, b, _CMP_UNORD_Q);
|
| 348 |
+
// Exploit the fact that all-ones is a NaN.
|
| 349 |
+
return _mm256_or_pd(max, isnan);
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 353 |
+
// either input is a NaN.
|
| 354 |
+
template <>
|
| 355 |
+
Vectorized<double> inline minimum(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 356 |
+
Vectorized<double> min = _mm256_min_pd(a, b);
|
| 357 |
+
Vectorized<double> isnan = _mm256_cmp_pd(a, b, _CMP_UNORD_Q);
|
| 358 |
+
// Exploit the fact that all-ones is a NaN.
|
| 359 |
+
return _mm256_or_pd(min, isnan);
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
template <>
|
| 363 |
+
Vectorized<double> inline clamp(const Vectorized<double>& a, const Vectorized<double>& min, const Vectorized<double>& max) {
|
| 364 |
+
return _mm256_min_pd(max, _mm256_max_pd(min, a));
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
template <>
|
| 368 |
+
Vectorized<double> inline clamp_min(const Vectorized<double>& a, const Vectorized<double>& min) {
|
| 369 |
+
return _mm256_max_pd(min, a);
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
template <>
|
| 373 |
+
Vectorized<double> inline clamp_max(const Vectorized<double>& a, const Vectorized<double>& max) {
|
| 374 |
+
return _mm256_min_pd(max, a);
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
template <>
|
| 378 |
+
Vectorized<double> inline operator&(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 379 |
+
return _mm256_and_pd(a, b);
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
template <>
|
| 383 |
+
Vectorized<double> inline operator|(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 384 |
+
return _mm256_or_pd(a, b);
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
template <>
|
| 388 |
+
Vectorized<double> inline operator^(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 389 |
+
return _mm256_xor_pd(a, b);
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
inline Vectorized<double> Vectorized<double>::eq(const Vectorized<double>& other) const {
|
| 393 |
+
return (*this == other) & Vectorized<double>(1.0);
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
inline Vectorized<double> Vectorized<double>::ne(const Vectorized<double>& other) const {
|
| 397 |
+
return (*this != other) & Vectorized<double>(1.0);
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
inline Vectorized<double> Vectorized<double>::gt(const Vectorized<double>& other) const {
|
| 401 |
+
return (*this > other) & Vectorized<double>(1.0);
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
inline Vectorized<double> Vectorized<double>::ge(const Vectorized<double>& other) const {
|
| 405 |
+
return (*this >= other) & Vectorized<double>(1.0);
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
inline Vectorized<double> Vectorized<double>::lt(const Vectorized<double>& other) const {
|
| 409 |
+
return (*this < other) & Vectorized<double>(1.0);
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
inline Vectorized<double> Vectorized<double>::le(const Vectorized<double>& other) const {
|
| 413 |
+
return (*this <= other) & Vectorized<double>(1.0);
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
template <>
|
| 417 |
+
inline void convert(const double* src, double* dst, int64_t n) {
|
| 418 |
+
int64_t i;
|
| 419 |
+
#ifndef __msvc_cl__
|
| 420 |
+
#pragma unroll
|
| 421 |
+
#endif
|
| 422 |
+
for (i = 0; i <= (n - Vectorized<double>::size()); i += Vectorized<double>::size()) {
|
| 423 |
+
_mm256_storeu_pd(dst + i, _mm256_loadu_pd(src + i));
|
| 424 |
+
}
|
| 425 |
+
#ifndef __msvc_cl__
|
| 426 |
+
#pragma unroll
|
| 427 |
+
#endif
|
| 428 |
+
for (; i < n; i++) {
|
| 429 |
+
dst[i] = src[i];
|
| 430 |
+
}
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
#ifdef CPU_CAPABILITY_AVX2
|
| 434 |
+
template <>
|
| 435 |
+
Vectorized<double> inline fmadd(const Vectorized<double>& a, const Vectorized<double>& b, const Vectorized<double>& c) {
|
| 436 |
+
return _mm256_fmadd_pd(a, b, c);
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
template <>
|
| 440 |
+
Vectorized<double> inline fmsub(const Vectorized<double>& a, const Vectorized<double>& b, const Vectorized<double>& c) {
|
| 441 |
+
return _mm256_fmsub_pd(a, b, c);
|
| 442 |
+
}
|
| 443 |
+
#endif
|
| 444 |
+
|
| 445 |
+
#endif
|
| 446 |
+
|
| 447 |
+
}} // namespace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_float.h
ADDED
|
@@ -0,0 +1,658 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <c10/util/irange.h>
|
| 9 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 10 |
+
#define SLEEF_STATIC_LIBS
|
| 11 |
+
#include <sleef.h>
|
| 12 |
+
#endif
|
| 13 |
+
|
| 14 |
+
namespace at::vec {
|
| 15 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 16 |
+
inline namespace CPU_CAPABILITY {
|
| 17 |
+
|
| 18 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 19 |
+
|
| 20 |
+
template <> class Vectorized<float> {
|
| 21 |
+
private:
|
| 22 |
+
__m256 values;
|
| 23 |
+
public:
|
| 24 |
+
using value_type = float;
|
| 25 |
+
using size_type = int;
|
| 26 |
+
static constexpr size_type size() {
|
| 27 |
+
return 8;
|
| 28 |
+
}
|
| 29 |
+
Vectorized() {}
|
| 30 |
+
Vectorized(__m256 v) : values(v) {}
|
| 31 |
+
Vectorized(float val) {
|
| 32 |
+
values = _mm256_set1_ps(val);
|
| 33 |
+
}
|
| 34 |
+
Vectorized(float val1, float val2, float val3, float val4,
|
| 35 |
+
float val5, float val6, float val7, float val8) {
|
| 36 |
+
values = _mm256_setr_ps(val1, val2, val3, val4, val5, val6, val7, val8);
|
| 37 |
+
}
|
| 38 |
+
Vectorized(const float (&arr)[8])
|
| 39 |
+
: Vectorized(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7]) {}
|
| 40 |
+
operator __m256() const {
|
| 41 |
+
return values;
|
| 42 |
+
}
|
| 43 |
+
template <int64_t mask>
|
| 44 |
+
static Vectorized<float> blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 45 |
+
return _mm256_blend_ps(a.values, b.values, mask);
|
| 46 |
+
}
|
| 47 |
+
static Vectorized<float> blendv(const Vectorized<float>& a, const Vectorized<float>& b,
|
| 48 |
+
const Vectorized<float>& mask) {
|
| 49 |
+
return _mm256_blendv_ps(a.values, b.values, mask.values);
|
| 50 |
+
}
|
| 51 |
+
template<typename step_t>
|
| 52 |
+
static Vectorized<float> arange(float base = 0.f, step_t step = static_cast<step_t>(1)) {
|
| 53 |
+
return Vectorized<float>(
|
| 54 |
+
base, base + step, base + 2 * step, base + 3 * step,
|
| 55 |
+
base + 4 * step, base + 5 * step, base + 6 * step, base + 7 * step);
|
| 56 |
+
}
|
| 57 |
+
static Vectorized<float> set(const Vectorized<float>& a, const Vectorized<float>& b,
|
| 58 |
+
int64_t count = size()) {
|
| 59 |
+
switch (count) {
|
| 60 |
+
case 0:
|
| 61 |
+
return a;
|
| 62 |
+
case 1:
|
| 63 |
+
return blend<1>(a, b);
|
| 64 |
+
case 2:
|
| 65 |
+
return blend<3>(a, b);
|
| 66 |
+
case 3:
|
| 67 |
+
return blend<7>(a, b);
|
| 68 |
+
case 4:
|
| 69 |
+
return blend<15>(a, b);
|
| 70 |
+
case 5:
|
| 71 |
+
return blend<31>(a, b);
|
| 72 |
+
case 6:
|
| 73 |
+
return blend<63>(a, b);
|
| 74 |
+
case 7:
|
| 75 |
+
return blend<127>(a, b);
|
| 76 |
+
}
|
| 77 |
+
return b;
|
| 78 |
+
}
|
| 79 |
+
static Vectorized<float> loadu(const void* ptr, int64_t count = size()) {
|
| 80 |
+
if (count == size())
|
| 81 |
+
return _mm256_loadu_ps(reinterpret_cast<const float*>(ptr));
|
| 82 |
+
__at_align__ float tmp_values[size()];
|
| 83 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 84 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 85 |
+
// instructions while a loop would be compiled to one instruction.
|
| 86 |
+
for (const auto i : c10::irange(size())) {
|
| 87 |
+
tmp_values[i] = 0.0;
|
| 88 |
+
}
|
| 89 |
+
std::memcpy(
|
| 90 |
+
tmp_values, reinterpret_cast<const float*>(ptr), count * sizeof(float));
|
| 91 |
+
return _mm256_loadu_ps(tmp_values);
|
| 92 |
+
}
|
| 93 |
+
void store(void* ptr, int64_t count = size()) const {
|
| 94 |
+
if (count == size()) {
|
| 95 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(ptr), values);
|
| 96 |
+
} else if (count > 0) {
|
| 97 |
+
float tmp_values[size()];
|
| 98 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(tmp_values), values);
|
| 99 |
+
std::memcpy(ptr, tmp_values, count * sizeof(float));
|
| 100 |
+
}
|
| 101 |
+
}
|
| 102 |
+
const float& operator[](int idx) const = delete;
|
| 103 |
+
float& operator[](int idx) = delete;
|
| 104 |
+
int zero_mask() const {
|
| 105 |
+
// returns an integer mask where all zero elements are translated to 1-bit and others are translated to 0-bit
|
| 106 |
+
__m256 cmp = _mm256_cmp_ps(values, _mm256_set1_ps(0.0f), _CMP_EQ_OQ);
|
| 107 |
+
return _mm256_movemask_ps(cmp);
|
| 108 |
+
}
|
| 109 |
+
Vectorized<float> isnan() const {
|
| 110 |
+
return _mm256_cmp_ps(values, _mm256_set1_ps(0.0f), _CMP_UNORD_Q);
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
bool has_inf_nan() const {
|
| 114 |
+
__m256 self_sub = _mm256_sub_ps(values, values);
|
| 115 |
+
return (_mm256_movemask_epi8(_mm256_castps_si256(self_sub)) & 0x77777777) != 0;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
Vectorized<float> map(float (*const f)(float)) const {
|
| 119 |
+
__at_align__ float tmp[size()];
|
| 120 |
+
store(tmp);
|
| 121 |
+
for (const auto i : c10::irange(size())) {
|
| 122 |
+
tmp[i] = f(tmp[i]);
|
| 123 |
+
}
|
| 124 |
+
return loadu(tmp);
|
| 125 |
+
}
|
| 126 |
+
Vectorized<float> abs() const {
|
| 127 |
+
auto mask = _mm256_set1_ps(-0.f);
|
| 128 |
+
return _mm256_andnot_ps(mask, values);
|
| 129 |
+
}
|
| 130 |
+
Vectorized<float> angle() const {
|
| 131 |
+
const auto zero_vec = _mm256_set1_ps(0.f);
|
| 132 |
+
const auto nan_vec = _mm256_set1_ps(NAN);
|
| 133 |
+
const auto not_nan_mask = _mm256_cmp_ps(values, values, _CMP_EQ_OQ);
|
| 134 |
+
const auto nan_mask = _mm256_cmp_ps(not_nan_mask, zero_vec, _CMP_EQ_OQ);
|
| 135 |
+
const auto pi = _mm256_set1_ps(c10::pi<float>);
|
| 136 |
+
|
| 137 |
+
const auto neg_mask = _mm256_cmp_ps(values, zero_vec, _CMP_LT_OQ);
|
| 138 |
+
auto angle = _mm256_blendv_ps(zero_vec, pi, neg_mask);
|
| 139 |
+
angle = _mm256_blendv_ps(angle, nan_vec, nan_mask);
|
| 140 |
+
return angle;
|
| 141 |
+
}
|
| 142 |
+
Vectorized<float> real() const {
|
| 143 |
+
return *this;
|
| 144 |
+
}
|
| 145 |
+
Vectorized<float> imag() const {
|
| 146 |
+
return _mm256_set1_ps(0);
|
| 147 |
+
}
|
| 148 |
+
Vectorized<float> conj() const {
|
| 149 |
+
return *this;
|
| 150 |
+
}
|
| 151 |
+
Vectorized<float> acos() const {
|
| 152 |
+
return Vectorized<float>(Sleef_acosf8_u10(values));
|
| 153 |
+
}
|
| 154 |
+
Vectorized<float> acosh() const {
|
| 155 |
+
return Vectorized<float>(Sleef_acoshf8_u10(values));
|
| 156 |
+
}
|
| 157 |
+
Vectorized<float> asin() const {
|
| 158 |
+
return Vectorized<float>(Sleef_asinf8_u10(values));
|
| 159 |
+
}
|
| 160 |
+
Vectorized<float> atan() const {
|
| 161 |
+
return Vectorized<float>(Sleef_atanf8_u10(values));
|
| 162 |
+
}
|
| 163 |
+
Vectorized<float> atanh() const {
|
| 164 |
+
return Vectorized<float>(Sleef_atanhf8_u10(values));
|
| 165 |
+
}
|
| 166 |
+
Vectorized<float> atan2(const Vectorized<float> &b) const {
|
| 167 |
+
return Vectorized<float>(Sleef_atan2f8_u10(values, b));
|
| 168 |
+
}
|
| 169 |
+
Vectorized<float> copysign(const Vectorized<float> &sign) const {
|
| 170 |
+
return Vectorized<float>(Sleef_copysignf8(values, sign));
|
| 171 |
+
}
|
| 172 |
+
Vectorized<float> erf() const {
|
| 173 |
+
// constants
|
| 174 |
+
const auto neg_zero_vec = _mm256_set1_ps(-0.f);
|
| 175 |
+
const auto one_vec = _mm256_set1_ps(1.0f);
|
| 176 |
+
const auto p = _mm256_set1_ps(0.3275911f);
|
| 177 |
+
const auto p1 = _mm256_set1_ps(0.254829592f);
|
| 178 |
+
const auto p2 = _mm256_set1_ps(-0.284496736f);
|
| 179 |
+
const auto p3 = _mm256_set1_ps(1.421413741f);
|
| 180 |
+
const auto p4 = _mm256_set1_ps(-1.453152027f);
|
| 181 |
+
const auto p5 = _mm256_set1_ps(1.061405429f);
|
| 182 |
+
// sign(x)
|
| 183 |
+
auto sign_mask = _mm256_and_ps(neg_zero_vec, values);
|
| 184 |
+
auto abs_vec = _mm256_xor_ps(sign_mask, values);
|
| 185 |
+
// t = 1 / (p * abs(x) + 1)
|
| 186 |
+
auto tmp0 = _mm256_fmadd_ps(p, abs_vec, one_vec);
|
| 187 |
+
auto t = _mm256_div_ps(one_vec, tmp0);
|
| 188 |
+
// r = p5 * t ^ 4 + p4 * t ^ 3 + p3 * t ^ 2 + p2 * t + p1
|
| 189 |
+
auto tmp1 = _mm256_fmadd_ps(p5, t, p4);
|
| 190 |
+
auto tmp2 = _mm256_fmadd_ps(tmp1, t, p3);
|
| 191 |
+
auto tmp3 = _mm256_fmadd_ps(tmp2, t, p2);
|
| 192 |
+
auto r = _mm256_fmadd_ps(tmp3, t, p1);
|
| 193 |
+
// - exp(- x * x)
|
| 194 |
+
auto pow_2 = _mm256_mul_ps(values, values);
|
| 195 |
+
auto neg_pow_2 = _mm256_xor_ps(neg_zero_vec, pow_2);
|
| 196 |
+
// auto tmp4 = exp(neg_pow_2);
|
| 197 |
+
auto tmp4 = Vectorized<float>(Sleef_expf8_u10(neg_pow_2));
|
| 198 |
+
auto tmp5 = _mm256_xor_ps(neg_zero_vec, tmp4);
|
| 199 |
+
// erf(x) = sign(x) * (1 - r * t * exp(- x * x))
|
| 200 |
+
auto tmp6 = _mm256_mul_ps(tmp5, t);
|
| 201 |
+
auto tmp7 = _mm256_fmadd_ps(tmp6, r, one_vec);
|
| 202 |
+
return _mm256_xor_ps(sign_mask, tmp7);
|
| 203 |
+
}
|
| 204 |
+
Vectorized<float> erfc() const {
|
| 205 |
+
return Vectorized<float>(Sleef_erfcf8_u15(values));
|
| 206 |
+
}
|
| 207 |
+
Vectorized<float> erfinv() const {
|
| 208 |
+
return map(calc_erfinv);
|
| 209 |
+
}
|
| 210 |
+
Vectorized<float> exp() const {
|
| 211 |
+
return Vectorized<float>(Sleef_expf8_u10(values));
|
| 212 |
+
}
|
| 213 |
+
Vectorized<float> exp2() const {
|
| 214 |
+
return Vectorized<float>(Sleef_exp2f8_u10(values));
|
| 215 |
+
}
|
| 216 |
+
Vectorized<float> expm1() const {
|
| 217 |
+
return Vectorized<float>(Sleef_expm1f8_u10(values));
|
| 218 |
+
}
|
| 219 |
+
Vectorized<float> exp_u20() const {
|
| 220 |
+
// A faster version of exp with ULP=20
|
| 221 |
+
const __m256 vec_factorial_1 =
|
| 222 |
+
_mm256_set1_ps(0.999999701f); // 1/factorial(1)
|
| 223 |
+
const __m256 vec_factorial_2 =
|
| 224 |
+
_mm256_set1_ps(0.499991506f); // 1/factorial(2)
|
| 225 |
+
const __m256 vec_factorial_3 =
|
| 226 |
+
_mm256_set1_ps(0.166676521f); // 1/factorial(3)
|
| 227 |
+
const __m256 vec_factorial_4 =
|
| 228 |
+
_mm256_set1_ps(0.0418978221f); // 1/factorial(4)
|
| 229 |
+
const __m256 vec_factorial_5 =
|
| 230 |
+
_mm256_set1_ps(0.00828929059f); // 1/factorial(5)
|
| 231 |
+
const __m256 vec_exp_log2ef =
|
| 232 |
+
_mm256_castsi256_ps(_mm256_set1_epi32(0x3fb8aa3b)); // log2(e)
|
| 233 |
+
const __m256 vec_half = _mm256_set1_ps(0.5f);
|
| 234 |
+
const __m256 vec_one = _mm256_set1_ps(1.f);
|
| 235 |
+
const __m256 vec_zero = _mm256_set1_ps(0.f);
|
| 236 |
+
const __m256 vec_two = _mm256_set1_ps(2.f);
|
| 237 |
+
const __m256 vec_ln2f = _mm256_castsi256_ps(_mm256_set1_epi32(0x3f317218)); // ln(2)
|
| 238 |
+
const __m256 vec_ln_flt_min = _mm256_castsi256_ps(_mm256_set1_epi32(0xc2aeac50));
|
| 239 |
+
const __m256 vec_ln_flt_max = _mm256_castsi256_ps(_mm256_set1_epi32(0x42b17218));
|
| 240 |
+
const __m256i vec_127 = _mm256_set1_epi32(0x0000007f);
|
| 241 |
+
const int n_mantissa_bits = 23;
|
| 242 |
+
|
| 243 |
+
// exp(x) =
|
| 244 |
+
// = exp(n * ln(2) + r) // divide x by ln(2) and get quot and rem
|
| 245 |
+
// = 2^n * exp(r) // simplify the exp(n*ln(2)) expression
|
| 246 |
+
|
| 247 |
+
auto less_ln_flt_min_mask =
|
| 248 |
+
_mm256_cmp_ps(values, vec_ln_flt_min, 1 /*_CMP_LT_OS*/);
|
| 249 |
+
auto vec_src = _mm256_min_ps(values, vec_ln_flt_max);
|
| 250 |
+
vec_src = _mm256_max_ps(vec_src, vec_ln_flt_min);
|
| 251 |
+
|
| 252 |
+
// fx = floorf(x * log2ef + 0.5)
|
| 253 |
+
auto vec_fx = _mm256_fmadd_ps(vec_src, vec_exp_log2ef, vec_half);
|
| 254 |
+
vec_fx = _mm256_floor_ps(vec_fx);
|
| 255 |
+
|
| 256 |
+
// x = x - fx * ln2
|
| 257 |
+
auto vec_exp_poly = _mm256_fnmadd_ps(vec_fx, vec_ln2f, vec_src);
|
| 258 |
+
|
| 259 |
+
// compute polynomial
|
| 260 |
+
auto vec_res =
|
| 261 |
+
_mm256_fmadd_ps(vec_exp_poly, vec_factorial_5, vec_factorial_4);
|
| 262 |
+
vec_res = _mm256_fmadd_ps(vec_exp_poly, vec_res, vec_factorial_3);
|
| 263 |
+
vec_res = _mm256_fmadd_ps(vec_exp_poly, vec_res, vec_factorial_2);
|
| 264 |
+
vec_res = _mm256_fmadd_ps(vec_exp_poly, vec_res, vec_factorial_1);
|
| 265 |
+
vec_res = _mm256_fmadd_ps(vec_exp_poly, vec_res, vec_one);
|
| 266 |
+
|
| 267 |
+
// compute 2^(n-1)
|
| 268 |
+
auto vec_exp_number = _mm256_sub_ps(vec_fx, vec_one);
|
| 269 |
+
auto vec_exp_number_i = _mm256_cvtps_epi32(vec_exp_number);
|
| 270 |
+
auto vec_two_pow_n_i = _mm256_add_epi32(vec_exp_number_i, vec_127);
|
| 271 |
+
vec_two_pow_n_i = _mm256_slli_epi32(vec_two_pow_n_i, n_mantissa_bits);
|
| 272 |
+
auto vec_two_pow_n = _mm256_castsi256_ps(vec_two_pow_n_i);
|
| 273 |
+
vec_two_pow_n =
|
| 274 |
+
_mm256_blendv_ps(vec_two_pow_n, vec_zero, less_ln_flt_min_mask);
|
| 275 |
+
|
| 276 |
+
// y = y * 2^n
|
| 277 |
+
vec_res = _mm256_mul_ps(vec_res, vec_two_pow_n);
|
| 278 |
+
vec_res = _mm256_mul_ps(vec_res, vec_two);
|
| 279 |
+
return vec_res;
|
| 280 |
+
}
|
| 281 |
+
Vectorized<float> fmod(const Vectorized<float>& q) const {
|
| 282 |
+
return Vectorized<float>(Sleef_fmodf8(values, q));
|
| 283 |
+
}
|
| 284 |
+
Vectorized<float> log() const {
|
| 285 |
+
return Vectorized<float>(Sleef_logf8_u10(values));
|
| 286 |
+
}
|
| 287 |
+
Vectorized<float> log2() const {
|
| 288 |
+
return Vectorized<float>(Sleef_log2f8_u10(values));
|
| 289 |
+
}
|
| 290 |
+
Vectorized<float> log10() const {
|
| 291 |
+
return Vectorized<float>(Sleef_log10f8_u10(values));
|
| 292 |
+
}
|
| 293 |
+
Vectorized<float> log1p() const {
|
| 294 |
+
return Vectorized<float>(Sleef_log1pf8_u10(values));
|
| 295 |
+
}
|
| 296 |
+
Vectorized<float> frac() const;
|
| 297 |
+
Vectorized<float> sin() const {
|
| 298 |
+
return Vectorized<float>(Sleef_sinf8_u35(values));
|
| 299 |
+
}
|
| 300 |
+
Vectorized<float> sinh() const {
|
| 301 |
+
return Vectorized<float>(Sleef_sinhf8_u10(values));
|
| 302 |
+
}
|
| 303 |
+
Vectorized<float> cos() const {
|
| 304 |
+
return Vectorized<float>(Sleef_cosf8_u35(values));
|
| 305 |
+
}
|
| 306 |
+
Vectorized<float> cosh() const {
|
| 307 |
+
return Vectorized<float>(Sleef_coshf8_u10(values));
|
| 308 |
+
}
|
| 309 |
+
Vectorized<float> ceil() const {
|
| 310 |
+
return _mm256_ceil_ps(values);
|
| 311 |
+
}
|
| 312 |
+
Vectorized<float> floor() const {
|
| 313 |
+
return _mm256_floor_ps(values);
|
| 314 |
+
}
|
| 315 |
+
Vectorized<float> hypot(const Vectorized<float> &b) const {
|
| 316 |
+
return Vectorized<float>(Sleef_hypotf8_u05(values, b));
|
| 317 |
+
}
|
| 318 |
+
Vectorized<float> i0() const {
|
| 319 |
+
return map(calc_i0);
|
| 320 |
+
}
|
| 321 |
+
Vectorized<float> i0e() const {
|
| 322 |
+
return map(calc_i0e);
|
| 323 |
+
}
|
| 324 |
+
Vectorized<float> digamma() const {
|
| 325 |
+
return map(calc_digamma);
|
| 326 |
+
}
|
| 327 |
+
Vectorized<float> igamma(const Vectorized<float> &x) const {
|
| 328 |
+
__at_align__ float tmp[size()];
|
| 329 |
+
__at_align__ float tmp_x[size()];
|
| 330 |
+
store(tmp);
|
| 331 |
+
x.store(tmp_x);
|
| 332 |
+
for (const auto i : c10::irange(size())) {
|
| 333 |
+
tmp[i] = calc_igamma(tmp[i], tmp_x[i]);
|
| 334 |
+
}
|
| 335 |
+
return loadu(tmp);
|
| 336 |
+
}
|
| 337 |
+
Vectorized<float> igammac(const Vectorized<float> &x) const {
|
| 338 |
+
__at_align__ float tmp[size()];
|
| 339 |
+
__at_align__ float tmp_x[size()];
|
| 340 |
+
store(tmp);
|
| 341 |
+
x.store(tmp_x);
|
| 342 |
+
for (const auto i : c10::irange(size())) {
|
| 343 |
+
tmp[i] = calc_igammac(tmp[i], tmp_x[i]);
|
| 344 |
+
}
|
| 345 |
+
return loadu(tmp);
|
| 346 |
+
}
|
| 347 |
+
Vectorized<float> neg() const {
|
| 348 |
+
return _mm256_xor_ps(_mm256_set1_ps(-0.f), values);
|
| 349 |
+
}
|
| 350 |
+
Vectorized<float> nextafter(const Vectorized<float> &b) const {
|
| 351 |
+
return Vectorized<float>(Sleef_nextafterf8(values, b));
|
| 352 |
+
}
|
| 353 |
+
Vectorized<float> round() const {
|
| 354 |
+
return _mm256_round_ps(values, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 355 |
+
}
|
| 356 |
+
Vectorized<float> tan() const {
|
| 357 |
+
return Vectorized<float>(Sleef_tanf8_u10(values));
|
| 358 |
+
}
|
| 359 |
+
Vectorized<float> tanh() const {
|
| 360 |
+
return Vectorized<float>(Sleef_tanhf8_u10(values));
|
| 361 |
+
}
|
| 362 |
+
Vectorized<float> trunc() const {
|
| 363 |
+
return _mm256_round_ps(values, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 364 |
+
}
|
| 365 |
+
Vectorized<float> lgamma() const {
|
| 366 |
+
return Vectorized<float>(Sleef_lgammaf8_u10(values));
|
| 367 |
+
}
|
| 368 |
+
Vectorized<float> sqrt() const {
|
| 369 |
+
return _mm256_sqrt_ps(values);
|
| 370 |
+
}
|
| 371 |
+
Vectorized<float> reciprocal() const {
|
| 372 |
+
return _mm256_div_ps(_mm256_set1_ps(1), values);
|
| 373 |
+
}
|
| 374 |
+
Vectorized<float> rsqrt() const {
|
| 375 |
+
return _mm256_div_ps(_mm256_set1_ps(1), _mm256_sqrt_ps(values));
|
| 376 |
+
}
|
| 377 |
+
Vectorized<float> pow(const Vectorized<float> &b) const {
|
| 378 |
+
return Vectorized<float>(Sleef_powf8_u10(values, b));
|
| 379 |
+
}
|
| 380 |
+
// Comparison using the _CMP_**_OQ predicate.
|
| 381 |
+
// `O`: get false if an operand is NaN
|
| 382 |
+
// `Q`: do not raise if an operand is NaN
|
| 383 |
+
Vectorized<float> operator==(const Vectorized<float>& other) const {
|
| 384 |
+
return _mm256_cmp_ps(values, other.values, _CMP_EQ_OQ);
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
Vectorized<float> operator!=(const Vectorized<float>& other) const {
|
| 388 |
+
return _mm256_cmp_ps(values, other.values, _CMP_NEQ_UQ);
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
Vectorized<float> operator<(const Vectorized<float>& other) const {
|
| 392 |
+
return _mm256_cmp_ps(values, other.values, _CMP_LT_OQ);
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
Vectorized<float> operator<=(const Vectorized<float>& other) const {
|
| 396 |
+
return _mm256_cmp_ps(values, other.values, _CMP_LE_OQ);
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
Vectorized<float> operator>(const Vectorized<float>& other) const {
|
| 400 |
+
return _mm256_cmp_ps(values, other.values, _CMP_GT_OQ);
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
Vectorized<float> operator>=(const Vectorized<float>& other) const {
|
| 404 |
+
return _mm256_cmp_ps(values, other.values, _CMP_GE_OQ);
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
Vectorized<float> eq(const Vectorized<float>& other) const;
|
| 408 |
+
Vectorized<float> ne(const Vectorized<float>& other) const;
|
| 409 |
+
Vectorized<float> gt(const Vectorized<float>& other) const;
|
| 410 |
+
Vectorized<float> ge(const Vectorized<float>& other) const;
|
| 411 |
+
Vectorized<float> lt(const Vectorized<float>& other) const;
|
| 412 |
+
Vectorized<float> le(const Vectorized<float>& other) const;
|
| 413 |
+
};
|
| 414 |
+
|
| 415 |
+
template <>
|
| 416 |
+
Vectorized<float> inline operator+(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 417 |
+
return _mm256_add_ps(a, b);
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
template <>
|
| 421 |
+
Vectorized<float> inline operator-(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 422 |
+
return _mm256_sub_ps(a, b);
|
| 423 |
+
}
|
| 424 |
+
|
| 425 |
+
template <>
|
| 426 |
+
Vectorized<float> inline operator*(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 427 |
+
return _mm256_mul_ps(a, b);
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
template <>
|
| 431 |
+
Vectorized<float> inline operator/(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 432 |
+
return _mm256_div_ps(a, b);
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
// frac. Implement this here so we can use subtraction
|
| 436 |
+
inline Vectorized<float> Vectorized<float>::frac() const {
|
| 437 |
+
return *this - this->trunc();
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 441 |
+
// either input is a NaN.
|
| 442 |
+
template <>
|
| 443 |
+
Vectorized<float> inline maximum(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 444 |
+
Vectorized<float> max = _mm256_max_ps(a, b);
|
| 445 |
+
Vectorized<float> isnan = _mm256_cmp_ps(a, b, _CMP_UNORD_Q);
|
| 446 |
+
// Exploit the fact that all-ones is a NaN.
|
| 447 |
+
return _mm256_or_ps(max, isnan);
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 451 |
+
// either input is a NaN.
|
| 452 |
+
template <>
|
| 453 |
+
Vectorized<float> inline minimum(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 454 |
+
Vectorized<float> min = _mm256_min_ps(a, b);
|
| 455 |
+
Vectorized<float> isnan = _mm256_cmp_ps(a, b, _CMP_UNORD_Q);
|
| 456 |
+
// Exploit the fact that all-ones is a NaN.
|
| 457 |
+
return _mm256_or_ps(min, isnan);
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
template <>
|
| 461 |
+
Vectorized<float> inline clamp(const Vectorized<float>& a, const Vectorized<float>& min, const Vectorized<float>& max) {
|
| 462 |
+
return _mm256_min_ps(max, _mm256_max_ps(min, a));
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
template <>
|
| 466 |
+
Vectorized<float> inline clamp_max(const Vectorized<float>& a, const Vectorized<float>& max) {
|
| 467 |
+
return _mm256_min_ps(max, a);
|
| 468 |
+
}
|
| 469 |
+
|
| 470 |
+
template <>
|
| 471 |
+
Vectorized<float> inline clamp_min(const Vectorized<float>& a, const Vectorized<float>& min) {
|
| 472 |
+
return _mm256_max_ps(min, a);
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
template <>
|
| 476 |
+
Vectorized<float> inline operator&(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 477 |
+
return _mm256_and_ps(a, b);
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
template <>
|
| 481 |
+
Vectorized<float> inline operator|(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 482 |
+
return _mm256_or_ps(a, b);
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
template <>
|
| 486 |
+
Vectorized<float> inline operator^(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 487 |
+
return _mm256_xor_ps(a, b);
|
| 488 |
+
}
|
| 489 |
+
|
| 490 |
+
inline Vectorized<float> Vectorized<float>::eq(const Vectorized<float>& other) const {
|
| 491 |
+
return (*this == other) & Vectorized<float>(1.0f);
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
inline Vectorized<float> Vectorized<float>::ne(const Vectorized<float>& other) const {
|
| 495 |
+
return (*this != other) & Vectorized<float>(1.0f);
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
inline Vectorized<float> Vectorized<float>::gt(const Vectorized<float>& other) const {
|
| 499 |
+
return (*this > other) & Vectorized<float>(1.0f);
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
inline Vectorized<float> Vectorized<float>::ge(const Vectorized<float>& other) const {
|
| 503 |
+
return (*this >= other) & Vectorized<float>(1.0f);
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
inline Vectorized<float> Vectorized<float>::lt(const Vectorized<float>& other) const {
|
| 507 |
+
return (*this < other) & Vectorized<float>(1.0f);
|
| 508 |
+
}
|
| 509 |
+
|
| 510 |
+
inline Vectorized<float> Vectorized<float>::le(const Vectorized<float>& other) const {
|
| 511 |
+
return (*this <= other) & Vectorized<float>(1.0f);
|
| 512 |
+
}
|
| 513 |
+
|
| 514 |
+
template <>
|
| 515 |
+
inline void convert(const float* src, float* dst, int64_t n) {
|
| 516 |
+
int64_t i;
|
| 517 |
+
#ifndef __msvc_cl__
|
| 518 |
+
#pragma unroll
|
| 519 |
+
#endif
|
| 520 |
+
for (i = 0; i <= (n - Vectorized<float>::size()); i += Vectorized<float>::size()) {
|
| 521 |
+
_mm256_storeu_ps(dst + i, _mm256_loadu_ps(src + i));
|
| 522 |
+
}
|
| 523 |
+
#ifndef __msvc_cl__
|
| 524 |
+
#pragma unroll
|
| 525 |
+
#endif
|
| 526 |
+
for (; i < n; i++) {
|
| 527 |
+
dst[i] = src[i];
|
| 528 |
+
}
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
|
| 532 |
+
template <>
|
| 533 |
+
Vectorized<float> inline fmadd(const Vectorized<float>& a, const Vectorized<float>& b, const Vectorized<float>& c) {
|
| 534 |
+
return _mm256_fmadd_ps(a, b, c);
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
template <>
|
| 538 |
+
Vectorized<float> inline fmsub(const Vectorized<float>& a, const Vectorized<float>& b, const Vectorized<float>& c) {
|
| 539 |
+
return _mm256_fmsub_ps(a, b, c);
|
| 540 |
+
}
|
| 541 |
+
|
| 542 |
+
// Used by Inductor CPP codegen
|
| 543 |
+
template<>
|
| 544 |
+
inline void transpose_mxn<float, 8, 8>(
|
| 545 |
+
const float* src,
|
| 546 |
+
int64_t ld_src,
|
| 547 |
+
float* dst,
|
| 548 |
+
int64_t ld_dst) {
|
| 549 |
+
// load from src to registers
|
| 550 |
+
// a: a0 a1 a2 a3 a4 a5 a6 a7
|
| 551 |
+
// b: b0 b1 b2 b3 b4 b5 b6 b7
|
| 552 |
+
// c: c0 c1 c2 c3 c4 c5 c6 c7
|
| 553 |
+
// d: d0 d1 d2 d3 d4 d5 d6 d7
|
| 554 |
+
// e: e0 e1 e2 e3 e4 e5 e6 e7
|
| 555 |
+
// f: f0 f1 f2 f3 f4 f5 f6 f7
|
| 556 |
+
// g: g0 g1 g2 g3 g4 g5 g6 g7
|
| 557 |
+
// h: h0 h1 h2 h3 h4 h5 h6 h7
|
| 558 |
+
__m256 a = _mm256_loadu_ps(&src[0 * ld_src]);
|
| 559 |
+
__m256 b = _mm256_loadu_ps(&src[1 * ld_src]);
|
| 560 |
+
__m256 c = _mm256_loadu_ps(&src[2 * ld_src]);
|
| 561 |
+
__m256 d = _mm256_loadu_ps(&src[3 * ld_src]);
|
| 562 |
+
__m256 e = _mm256_loadu_ps(&src[4 * ld_src]);
|
| 563 |
+
__m256 f = _mm256_loadu_ps(&src[5 * ld_src]);
|
| 564 |
+
__m256 g = _mm256_loadu_ps(&src[6 * ld_src]);
|
| 565 |
+
__m256 h = _mm256_loadu_ps(&src[7 * ld_src]);
|
| 566 |
+
|
| 567 |
+
__m256 ta, tb, tc, td, te, tf, tg, th;
|
| 568 |
+
// unpacking and interleaving 32-bit elements
|
| 569 |
+
// a0 b0 a1 b1 a4 b4 a5 b5
|
| 570 |
+
// a2 b2 a3 b3 a6 b6 a7 b7
|
| 571 |
+
// c0 d0 c1 d1 ...
|
| 572 |
+
// c2 d2 c3 d3 ...
|
| 573 |
+
// e0 f0 e1 f1 ...
|
| 574 |
+
// e2 f2 e3 f3 ...
|
| 575 |
+
// g0 h0 g1 h1 ...
|
| 576 |
+
// g2 h2 g3 h3 ...
|
| 577 |
+
ta = _mm256_unpacklo_ps(a, b);
|
| 578 |
+
tb = _mm256_unpackhi_ps(a, b);
|
| 579 |
+
tc = _mm256_unpacklo_ps(c, d);
|
| 580 |
+
td = _mm256_unpackhi_ps(c, d);
|
| 581 |
+
te = _mm256_unpacklo_ps(e, f);
|
| 582 |
+
tf = _mm256_unpackhi_ps(e, f);
|
| 583 |
+
tg = _mm256_unpacklo_ps(g, h);
|
| 584 |
+
th = _mm256_unpackhi_ps(g, h);
|
| 585 |
+
|
| 586 |
+
// unpacking and interleaving 64-bit elements
|
| 587 |
+
// a0 b0 c0 d0 a4 b4 c4 d4
|
| 588 |
+
// a1 b1 c1 d1 ...
|
| 589 |
+
// a2 b2 c2 d2 ...
|
| 590 |
+
// a3 b3 c3 d3 ...
|
| 591 |
+
// e0 f0 g0 h0 e4 f4 g4 h4
|
| 592 |
+
// e1 f1 g1 h1 ...
|
| 593 |
+
// e2 f2 g2 h2 ...
|
| 594 |
+
// e3 f3 g3 h3 ...
|
| 595 |
+
a = _mm256_castpd_ps(
|
| 596 |
+
_mm256_unpacklo_pd(_mm256_castps_pd(ta), _mm256_castps_pd(tc)));
|
| 597 |
+
b = _mm256_castpd_ps(
|
| 598 |
+
_mm256_unpackhi_pd(_mm256_castps_pd(ta), _mm256_castps_pd(tc)));
|
| 599 |
+
c = _mm256_castpd_ps(
|
| 600 |
+
_mm256_unpacklo_pd(_mm256_castps_pd(tb), _mm256_castps_pd(td)));
|
| 601 |
+
d = _mm256_castpd_ps(
|
| 602 |
+
_mm256_unpackhi_pd(_mm256_castps_pd(tb), _mm256_castps_pd(td)));
|
| 603 |
+
e = _mm256_castpd_ps(
|
| 604 |
+
_mm256_unpacklo_pd(_mm256_castps_pd(te), _mm256_castps_pd(tg)));
|
| 605 |
+
f = _mm256_castpd_ps(
|
| 606 |
+
_mm256_unpackhi_pd(_mm256_castps_pd(te), _mm256_castps_pd(tg)));
|
| 607 |
+
g = _mm256_castpd_ps(
|
| 608 |
+
_mm256_unpacklo_pd(_mm256_castps_pd(tf), _mm256_castps_pd(th)));
|
| 609 |
+
h = _mm256_castpd_ps(
|
| 610 |
+
_mm256_unpackhi_pd(_mm256_castps_pd(tf), _mm256_castps_pd(th)));
|
| 611 |
+
|
| 612 |
+
// shuffle 128-bits (composed of 4 32-bit elements)
|
| 613 |
+
// a0 b0 c0 d0 e0 f0 g0 h0
|
| 614 |
+
// a1 b1 c1 d1 ...
|
| 615 |
+
// a2 b2 c2 d2 ...
|
| 616 |
+
// a3 b3 c3 d3 ...
|
| 617 |
+
// a4 b4 c4 d4 ...
|
| 618 |
+
// a5 b5 c5 d5 ...
|
| 619 |
+
// a6 b6 c6 d6 ...
|
| 620 |
+
// a7 b7 c7 d7 ...
|
| 621 |
+
ta = _mm256_permute2f128_ps(a, e, 0x20);
|
| 622 |
+
tb = _mm256_permute2f128_ps(b, f, 0x20);
|
| 623 |
+
tc = _mm256_permute2f128_ps(c, g, 0x20);
|
| 624 |
+
td = _mm256_permute2f128_ps(d, h, 0x20);
|
| 625 |
+
te = _mm256_permute2f128_ps(a, e, 0x31);
|
| 626 |
+
tf = _mm256_permute2f128_ps(b, f, 0x31);
|
| 627 |
+
tg = _mm256_permute2f128_ps(c, g, 0x31);
|
| 628 |
+
th = _mm256_permute2f128_ps(d, h, 0x31);
|
| 629 |
+
|
| 630 |
+
// store from registers to dst
|
| 631 |
+
_mm256_storeu_ps(&dst[0 * ld_dst], ta);
|
| 632 |
+
_mm256_storeu_ps(&dst[1 * ld_dst], tb);
|
| 633 |
+
_mm256_storeu_ps(&dst[2 * ld_dst], tc);
|
| 634 |
+
_mm256_storeu_ps(&dst[3 * ld_dst], td);
|
| 635 |
+
_mm256_storeu_ps(&dst[4 * ld_dst], te);
|
| 636 |
+
_mm256_storeu_ps(&dst[5 * ld_dst], tf);
|
| 637 |
+
_mm256_storeu_ps(&dst[6 * ld_dst], tg);
|
| 638 |
+
_mm256_storeu_ps(&dst[7 * ld_dst], th);
|
| 639 |
+
}
|
| 640 |
+
|
| 641 |
+
template<>
|
| 642 |
+
inline void transpose_mxn<float, 16, 16>(
|
| 643 |
+
const float* src,
|
| 644 |
+
int64_t ld_src,
|
| 645 |
+
float* dst,
|
| 646 |
+
int64_t ld_dst) {
|
| 647 |
+
transpose_mxn<float, 8, 8>(
|
| 648 |
+
src , ld_src, dst, ld_dst);
|
| 649 |
+
transpose_mxn<float, 8, 8>(
|
| 650 |
+
src + 8, ld_src, dst + 8 * ld_dst, ld_dst);
|
| 651 |
+
transpose_mxn<float, 8, 8>(
|
| 652 |
+
src + 8 * ld_src, ld_src, dst + 8, ld_dst);
|
| 653 |
+
transpose_mxn<float, 8, 8>(
|
| 654 |
+
src + 8 * ld_src + 8, ld_src, dst + 8 * ld_dst + 8, ld_dst);
|
| 655 |
+
}
|
| 656 |
+
#endif
|
| 657 |
+
|
| 658 |
+
}} // namespace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_int.h
ADDED
|
@@ -0,0 +1,1586 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <c10/macros/Macros.h>
|
| 9 |
+
#include <c10/util/irange.h>
|
| 10 |
+
|
| 11 |
+
namespace at::vec {
|
| 12 |
+
inline namespace CPU_CAPABILITY {
|
| 13 |
+
|
| 14 |
+
#ifdef CPU_CAPABILITY_AVX2
|
| 15 |
+
|
| 16 |
+
struct Vectorizedi {
|
| 17 |
+
protected:
|
| 18 |
+
__m256i values;
|
| 19 |
+
|
| 20 |
+
static inline __m256i invert(const __m256i& v) {
|
| 21 |
+
const auto ones = _mm256_set1_epi64x(-1);
|
| 22 |
+
return _mm256_xor_si256(ones, v);
|
| 23 |
+
}
|
| 24 |
+
public:
|
| 25 |
+
Vectorizedi() {}
|
| 26 |
+
Vectorizedi(__m256i v) : values(v) {}
|
| 27 |
+
operator __m256i() const {
|
| 28 |
+
return values;
|
| 29 |
+
}
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
#else
|
| 33 |
+
|
| 34 |
+
struct Vectorizedi {}; // dummy definition to make Vectorizedi always defined
|
| 35 |
+
|
| 36 |
+
#endif // CPU_CAPABILITY_AVX2
|
| 37 |
+
|
| 38 |
+
#ifdef CPU_CAPABILITY_AVX2
|
| 39 |
+
|
| 40 |
+
template <>
|
| 41 |
+
class Vectorized<int64_t> : public Vectorizedi {
|
| 42 |
+
private:
|
| 43 |
+
static const Vectorized<int64_t> ones;
|
| 44 |
+
public:
|
| 45 |
+
using value_type = int64_t;
|
| 46 |
+
using size_type = int;
|
| 47 |
+
static constexpr size_type size() {
|
| 48 |
+
return 4;
|
| 49 |
+
}
|
| 50 |
+
using Vectorizedi::Vectorizedi;
|
| 51 |
+
Vectorized() {}
|
| 52 |
+
Vectorized(int64_t v) { values = _mm256_set1_epi64x(v); }
|
| 53 |
+
Vectorized(int64_t val1, int64_t val2, int64_t val3, int64_t val4) {
|
| 54 |
+
values = _mm256_setr_epi64x(val1, val2, val3, val4);
|
| 55 |
+
}
|
| 56 |
+
template <int64_t mask>
|
| 57 |
+
static Vectorized<int64_t> blend(Vectorized<int64_t> a, Vectorized<int64_t> b) {
|
| 58 |
+
__at_align__ int64_t tmp_values[size()];
|
| 59 |
+
a.store(tmp_values);
|
| 60 |
+
if (mask & 0x01)
|
| 61 |
+
tmp_values[0] = _mm256_extract_epi64(b.values, 0);
|
| 62 |
+
if (mask & 0x02)
|
| 63 |
+
tmp_values[1] = _mm256_extract_epi64(b.values, 1);
|
| 64 |
+
if (mask & 0x04)
|
| 65 |
+
tmp_values[2] = _mm256_extract_epi64(b.values, 2);
|
| 66 |
+
if (mask & 0x08)
|
| 67 |
+
tmp_values[3] = _mm256_extract_epi64(b.values, 3);
|
| 68 |
+
return loadu(tmp_values);
|
| 69 |
+
}
|
| 70 |
+
static Vectorized<int64_t> blendv(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b,
|
| 71 |
+
const Vectorized<int64_t>& mask) {
|
| 72 |
+
return _mm256_blendv_epi8(a.values, b.values, mask.values);
|
| 73 |
+
}
|
| 74 |
+
template <typename step_t>
|
| 75 |
+
static Vectorized<int64_t> arange(int64_t base = 0, step_t step = static_cast<step_t>(1)) {
|
| 76 |
+
return Vectorized<int64_t>(base, base + step, base + 2 * step, base + 3 * step);
|
| 77 |
+
}
|
| 78 |
+
static Vectorized<int64_t>
|
| 79 |
+
set(Vectorized<int64_t> a, Vectorized<int64_t> b, int64_t count = size()) {
|
| 80 |
+
switch (count) {
|
| 81 |
+
case 0:
|
| 82 |
+
return a;
|
| 83 |
+
case 1:
|
| 84 |
+
return blend<1>(a, b);
|
| 85 |
+
case 2:
|
| 86 |
+
return blend<3>(a, b);
|
| 87 |
+
case 3:
|
| 88 |
+
return blend<7>(a, b);
|
| 89 |
+
}
|
| 90 |
+
return b;
|
| 91 |
+
}
|
| 92 |
+
static Vectorized<int64_t> loadu(const void* ptr) {
|
| 93 |
+
return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(ptr));
|
| 94 |
+
}
|
| 95 |
+
static Vectorized<int64_t> loadu(const void* ptr, int64_t count) {
|
| 96 |
+
__at_align__ int64_t tmp_values[size()];
|
| 97 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 98 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 99 |
+
// instructions while a loop would be compiled to one instruction.
|
| 100 |
+
for (const auto i : c10::irange(size())) {
|
| 101 |
+
tmp_values[i] = 0;
|
| 102 |
+
}
|
| 103 |
+
std::memcpy(tmp_values, ptr, count * sizeof(int64_t));
|
| 104 |
+
return loadu(tmp_values);
|
| 105 |
+
}
|
| 106 |
+
void store(void* ptr, int count = size()) const {
|
| 107 |
+
if (count == size()) {
|
| 108 |
+
// ptr need not to be aligned here. See
|
| 109 |
+
// https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/intrinsics/intrinsics-for-intel-advanced-vector-extensions/intrinsics-for-load-and-store-operations-1/mm256-storeu-si256.html
|
| 110 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), values);
|
| 111 |
+
} else if (count > 0) {
|
| 112 |
+
__at_align__ int64_t tmp_values[size()];
|
| 113 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(tmp_values), values);
|
| 114 |
+
std::memcpy(ptr, tmp_values, count * sizeof(int64_t));
|
| 115 |
+
}
|
| 116 |
+
}
|
| 117 |
+
const int64_t& operator[](int idx) const = delete;
|
| 118 |
+
int64_t& operator[](int idx) = delete;
|
| 119 |
+
Vectorized<int64_t> abs() const {
|
| 120 |
+
auto zero = _mm256_set1_epi64x(0);
|
| 121 |
+
auto is_larger = _mm256_cmpgt_epi64(zero, values);
|
| 122 |
+
auto inverse = _mm256_xor_si256(values, is_larger);
|
| 123 |
+
return _mm256_sub_epi64(inverse, is_larger);
|
| 124 |
+
}
|
| 125 |
+
Vectorized<int64_t> real() const {
|
| 126 |
+
return *this;
|
| 127 |
+
}
|
| 128 |
+
Vectorized<int64_t> imag() const {
|
| 129 |
+
return _mm256_set1_epi64x(0);
|
| 130 |
+
}
|
| 131 |
+
Vectorized<int64_t> conj() const {
|
| 132 |
+
return *this;
|
| 133 |
+
}
|
| 134 |
+
Vectorized<int64_t> neg() const;
|
| 135 |
+
Vectorized<int64_t> operator==(const Vectorized<int64_t>& other) const {
|
| 136 |
+
return _mm256_cmpeq_epi64(values, other.values);
|
| 137 |
+
}
|
| 138 |
+
Vectorized<int64_t> operator!=(const Vectorized<int64_t>& other) const {
|
| 139 |
+
return invert(_mm256_cmpeq_epi64(values, other.values));
|
| 140 |
+
}
|
| 141 |
+
Vectorized<int64_t> operator<(const Vectorized<int64_t>& other) const {
|
| 142 |
+
return _mm256_cmpgt_epi64(other.values, values);
|
| 143 |
+
}
|
| 144 |
+
Vectorized<int64_t> operator<=(const Vectorized<int64_t>& other) const {
|
| 145 |
+
return invert(_mm256_cmpgt_epi64(values, other.values));
|
| 146 |
+
}
|
| 147 |
+
Vectorized<int64_t> operator>(const Vectorized<int64_t>& other) const {
|
| 148 |
+
return _mm256_cmpgt_epi64(values, other.values);
|
| 149 |
+
}
|
| 150 |
+
Vectorized<int64_t> operator>=(const Vectorized<int64_t>& other) const {
|
| 151 |
+
return invert(_mm256_cmpgt_epi64(other.values, values));
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
Vectorized<int64_t> eq(const Vectorized<int64_t>& other) const;
|
| 155 |
+
Vectorized<int64_t> ne(const Vectorized<int64_t>& other) const;
|
| 156 |
+
Vectorized<int64_t> gt(const Vectorized<int64_t>& other) const;
|
| 157 |
+
Vectorized<int64_t> ge(const Vectorized<int64_t>& other) const;
|
| 158 |
+
Vectorized<int64_t> lt(const Vectorized<int64_t>& other) const;
|
| 159 |
+
Vectorized<int64_t> le(const Vectorized<int64_t>& other) const;
|
| 160 |
+
};
|
| 161 |
+
|
| 162 |
+
template <>
|
| 163 |
+
class Vectorized<int32_t> : public Vectorizedi {
|
| 164 |
+
private:
|
| 165 |
+
static const Vectorized<int32_t> ones;
|
| 166 |
+
public:
|
| 167 |
+
using value_type = int32_t;
|
| 168 |
+
static constexpr int size() {
|
| 169 |
+
return 8;
|
| 170 |
+
}
|
| 171 |
+
using Vectorizedi::Vectorizedi;
|
| 172 |
+
Vectorized() {}
|
| 173 |
+
Vectorized(int32_t v) { values = _mm256_set1_epi32(v); }
|
| 174 |
+
Vectorized(int32_t val1, int32_t val2, int32_t val3, int32_t val4,
|
| 175 |
+
int32_t val5, int32_t val6, int32_t val7, int32_t val8) {
|
| 176 |
+
values = _mm256_setr_epi32(val1, val2, val3, val4, val5, val6, val7, val8);
|
| 177 |
+
}
|
| 178 |
+
template <int64_t mask>
|
| 179 |
+
static Vectorized<int32_t> blend(Vectorized<int32_t> a, Vectorized<int32_t> b) {
|
| 180 |
+
return _mm256_blend_epi32(a, b, mask);
|
| 181 |
+
}
|
| 182 |
+
static Vectorized<int32_t> blendv(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b,
|
| 183 |
+
const Vectorized<int32_t>& mask) {
|
| 184 |
+
return _mm256_blendv_epi8(a.values, b.values, mask.values);
|
| 185 |
+
}
|
| 186 |
+
template <typename step_t>
|
| 187 |
+
static Vectorized<int32_t> arange(int32_t base = 0, step_t step = static_cast<step_t>(1)) {
|
| 188 |
+
return Vectorized<int32_t>(
|
| 189 |
+
base, base + step, base + 2 * step, base + 3 * step,
|
| 190 |
+
base + 4 * step, base + 5 * step, base + 6 * step, base + 7 * step);
|
| 191 |
+
}
|
| 192 |
+
static Vectorized<int32_t>
|
| 193 |
+
set(Vectorized<int32_t> a, Vectorized<int32_t> b, int32_t count = size()) {
|
| 194 |
+
switch (count) {
|
| 195 |
+
case 0:
|
| 196 |
+
return a;
|
| 197 |
+
case 1:
|
| 198 |
+
return blend<1>(a, b);
|
| 199 |
+
case 2:
|
| 200 |
+
return blend<3>(a, b);
|
| 201 |
+
case 3:
|
| 202 |
+
return blend<7>(a, b);
|
| 203 |
+
case 4:
|
| 204 |
+
return blend<15>(a, b);
|
| 205 |
+
case 5:
|
| 206 |
+
return blend<31>(a, b);
|
| 207 |
+
case 6:
|
| 208 |
+
return blend<63>(a, b);
|
| 209 |
+
case 7:
|
| 210 |
+
return blend<127>(a, b);
|
| 211 |
+
}
|
| 212 |
+
return b;
|
| 213 |
+
}
|
| 214 |
+
static Vectorized<int32_t> loadu(const void* ptr) {
|
| 215 |
+
return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(ptr));
|
| 216 |
+
}
|
| 217 |
+
static Vectorized<int32_t> loadu(const void* ptr, int32_t count) {
|
| 218 |
+
__at_align__ int32_t tmp_values[size()];
|
| 219 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 220 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 221 |
+
// instructions while a loop would be compiled to one instruction.
|
| 222 |
+
for (const auto i : c10::irange(size())) {
|
| 223 |
+
tmp_values[i] = 0;
|
| 224 |
+
}
|
| 225 |
+
std::memcpy(tmp_values, ptr, count * sizeof(int32_t));
|
| 226 |
+
return loadu(tmp_values);
|
| 227 |
+
}
|
| 228 |
+
void store(void* ptr, int count = size()) const {
|
| 229 |
+
if (count == size()) {
|
| 230 |
+
// ptr need not to be aligned here. See
|
| 231 |
+
// https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/intrinsics/intrinsics-for-intel-advanced-vector-extensions/intrinsics-for-load-and-store-operations-1/mm256-storeu-si256.html
|
| 232 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), values);
|
| 233 |
+
} else if (count > 0) {
|
| 234 |
+
__at_align__ int32_t tmp_values[size()];
|
| 235 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(tmp_values), values);
|
| 236 |
+
std::memcpy(ptr, tmp_values, count * sizeof(int32_t));
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
const int32_t& operator[](int idx) const = delete;
|
| 240 |
+
int32_t& operator[](int idx) = delete;
|
| 241 |
+
Vectorized<int32_t> abs() const {
|
| 242 |
+
return _mm256_abs_epi32(values);
|
| 243 |
+
}
|
| 244 |
+
Vectorized<int32_t> real() const {
|
| 245 |
+
return *this;
|
| 246 |
+
}
|
| 247 |
+
Vectorized<int32_t> imag() const {
|
| 248 |
+
return _mm256_set1_epi32(0);
|
| 249 |
+
}
|
| 250 |
+
Vectorized<int32_t> conj() const {
|
| 251 |
+
return *this;
|
| 252 |
+
}
|
| 253 |
+
Vectorized<int32_t> neg() const;
|
| 254 |
+
Vectorized<int32_t> operator==(const Vectorized<int32_t>& other) const {
|
| 255 |
+
return _mm256_cmpeq_epi32(values, other.values);
|
| 256 |
+
}
|
| 257 |
+
Vectorized<int32_t> operator!=(const Vectorized<int32_t>& other) const {
|
| 258 |
+
return invert(_mm256_cmpeq_epi32(values, other.values));
|
| 259 |
+
}
|
| 260 |
+
Vectorized<int32_t> operator<(const Vectorized<int32_t>& other) const {
|
| 261 |
+
return _mm256_cmpgt_epi32(other.values, values);
|
| 262 |
+
}
|
| 263 |
+
Vectorized<int32_t> operator<=(const Vectorized<int32_t>& other) const {
|
| 264 |
+
return invert(_mm256_cmpgt_epi32(values, other.values));
|
| 265 |
+
}
|
| 266 |
+
Vectorized<int32_t> operator>(const Vectorized<int32_t>& other) const {
|
| 267 |
+
return _mm256_cmpgt_epi32(values, other.values);
|
| 268 |
+
}
|
| 269 |
+
Vectorized<int32_t> operator>=(const Vectorized<int32_t>& other) const {
|
| 270 |
+
return invert(_mm256_cmpgt_epi32(other.values, values));
|
| 271 |
+
}
|
| 272 |
+
Vectorized<int32_t> eq(const Vectorized<int32_t>& other) const;
|
| 273 |
+
Vectorized<int32_t> ne(const Vectorized<int32_t>& other) const;
|
| 274 |
+
Vectorized<int32_t> gt(const Vectorized<int32_t>& other) const;
|
| 275 |
+
Vectorized<int32_t> ge(const Vectorized<int32_t>& other) const;
|
| 276 |
+
Vectorized<int32_t> lt(const Vectorized<int32_t>& other) const;
|
| 277 |
+
Vectorized<int32_t> le(const Vectorized<int32_t>& other) const;
|
| 278 |
+
};
|
| 279 |
+
|
| 280 |
+
template <>
|
| 281 |
+
inline void convert(const int32_t *src, float *dst, int64_t n) {
|
| 282 |
+
int64_t i;
|
| 283 |
+
// int32_t and float have same size
|
| 284 |
+
#ifndef _MSC_VER
|
| 285 |
+
# pragma unroll
|
| 286 |
+
#endif
|
| 287 |
+
for (i = 0; i <= (n - Vectorized<int32_t>::size()); i += Vectorized<int32_t>::size()) {
|
| 288 |
+
auto input_vec = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(src + i));
|
| 289 |
+
auto output_vec = _mm256_cvtepi32_ps(input_vec);
|
| 290 |
+
_mm256_storeu_ps(reinterpret_cast<float*>(dst + i), output_vec);
|
| 291 |
+
}
|
| 292 |
+
#ifndef _MSC_VER
|
| 293 |
+
# pragma unroll
|
| 294 |
+
#endif
|
| 295 |
+
for (; i < n; i++) {
|
| 296 |
+
dst[i] = static_cast<float>(src[i]);
|
| 297 |
+
}
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
template <>
|
| 301 |
+
inline void convert(const int32_t *src, double *dst, int64_t n) {
|
| 302 |
+
int64_t i;
|
| 303 |
+
// int32_t has half the size of double
|
| 304 |
+
#ifndef _MSC_VER
|
| 305 |
+
# pragma unroll
|
| 306 |
+
#endif
|
| 307 |
+
for (i = 0; i <= (n - Vectorized<double>::size()); i += Vectorized<double>::size()) {
|
| 308 |
+
auto input_128_vec = _mm_loadu_si128(reinterpret_cast<const __m128i*>(src + i));
|
| 309 |
+
auto output_vec = _mm256_cvtepi32_pd(input_128_vec);
|
| 310 |
+
_mm256_storeu_pd(reinterpret_cast<double*>(dst + i), output_vec);
|
| 311 |
+
}
|
| 312 |
+
#ifndef _MSC_VER
|
| 313 |
+
# pragma unroll
|
| 314 |
+
#endif
|
| 315 |
+
for (; i < n; i++) {
|
| 316 |
+
dst[i] = static_cast<double>(src[i]);
|
| 317 |
+
}
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
template <>
|
| 321 |
+
class Vectorized<int16_t> : public Vectorizedi {
|
| 322 |
+
private:
|
| 323 |
+
static const Vectorized<int16_t> ones;
|
| 324 |
+
public:
|
| 325 |
+
using value_type = int16_t;
|
| 326 |
+
static constexpr int size() {
|
| 327 |
+
return 16;
|
| 328 |
+
}
|
| 329 |
+
using Vectorizedi::Vectorizedi;
|
| 330 |
+
Vectorized() {}
|
| 331 |
+
Vectorized(int16_t v) { values = _mm256_set1_epi16(v); }
|
| 332 |
+
Vectorized(int16_t val1, int16_t val2, int16_t val3, int16_t val4,
|
| 333 |
+
int16_t val5, int16_t val6, int16_t val7, int16_t val8,
|
| 334 |
+
int16_t val9, int16_t val10, int16_t val11, int16_t val12,
|
| 335 |
+
int16_t val13, int16_t val14, int16_t val15, int16_t val16) {
|
| 336 |
+
values = _mm256_setr_epi16(val1, val2, val3, val4, val5, val6, val7, val8,
|
| 337 |
+
val9, val10, val11, val12, val13, val14, val15, val16);
|
| 338 |
+
}
|
| 339 |
+
template <int64_t mask>
|
| 340 |
+
static Vectorized<int16_t> blend(Vectorized<int16_t> a, Vectorized<int16_t> b) {
|
| 341 |
+
__at_align__ int16_t tmp_values[size()];
|
| 342 |
+
a.store(tmp_values);
|
| 343 |
+
if (mask & 0x01)
|
| 344 |
+
tmp_values[0] = _mm256_extract_epi16(b.values, 0);
|
| 345 |
+
if (mask & 0x02)
|
| 346 |
+
tmp_values[1] = _mm256_extract_epi16(b.values, 1);
|
| 347 |
+
if (mask & 0x04)
|
| 348 |
+
tmp_values[2] = _mm256_extract_epi16(b.values, 2);
|
| 349 |
+
if (mask & 0x08)
|
| 350 |
+
tmp_values[3] = _mm256_extract_epi16(b.values, 3);
|
| 351 |
+
if (mask & 0x10)
|
| 352 |
+
tmp_values[4] = _mm256_extract_epi16(b.values, 4);
|
| 353 |
+
if (mask & 0x20)
|
| 354 |
+
tmp_values[5] = _mm256_extract_epi16(b.values, 5);
|
| 355 |
+
if (mask & 0x40)
|
| 356 |
+
tmp_values[6] = _mm256_extract_epi16(b.values, 6);
|
| 357 |
+
if (mask & 0x80)
|
| 358 |
+
tmp_values[7] = _mm256_extract_epi16(b.values, 7);
|
| 359 |
+
if (mask & 0x100)
|
| 360 |
+
tmp_values[8] = _mm256_extract_epi16(b.values, 8);
|
| 361 |
+
if (mask & 0x200)
|
| 362 |
+
tmp_values[9] = _mm256_extract_epi16(b.values, 9);
|
| 363 |
+
if (mask & 0x400)
|
| 364 |
+
tmp_values[10] = _mm256_extract_epi16(b.values, 10);
|
| 365 |
+
if (mask & 0x800)
|
| 366 |
+
tmp_values[11] = _mm256_extract_epi16(b.values, 11);
|
| 367 |
+
if (mask & 0x1000)
|
| 368 |
+
tmp_values[12] = _mm256_extract_epi16(b.values, 12);
|
| 369 |
+
if (mask & 0x2000)
|
| 370 |
+
tmp_values[13] = _mm256_extract_epi16(b.values, 13);
|
| 371 |
+
if (mask & 0x4000)
|
| 372 |
+
tmp_values[14] = _mm256_extract_epi16(b.values, 14);
|
| 373 |
+
if (mask & 0x8000)
|
| 374 |
+
tmp_values[15] = _mm256_extract_epi16(b.values, 15);
|
| 375 |
+
return loadu(tmp_values);
|
| 376 |
+
}
|
| 377 |
+
static Vectorized<int16_t> blendv(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b,
|
| 378 |
+
const Vectorized<int16_t>& mask) {
|
| 379 |
+
return _mm256_blendv_epi8(a.values, b.values, mask.values);
|
| 380 |
+
}
|
| 381 |
+
template <typename step_t>
|
| 382 |
+
static Vectorized<int16_t> arange(int16_t base = 0, step_t step = static_cast<step_t>(1)) {
|
| 383 |
+
return Vectorized<int16_t>(
|
| 384 |
+
base, base + step, base + 2 * step, base + 3 * step,
|
| 385 |
+
base + 4 * step, base + 5 * step, base + 6 * step, base + 7 * step,
|
| 386 |
+
base + 8 * step, base + 9 * step, base + 10 * step, base + 11 * step,
|
| 387 |
+
base + 12 * step, base + 13 * step, base + 14 * step, base + 15 * step);
|
| 388 |
+
}
|
| 389 |
+
static Vectorized<int16_t>
|
| 390 |
+
set(Vectorized<int16_t> a, Vectorized<int16_t> b, int16_t count = size()) {
|
| 391 |
+
switch (count) {
|
| 392 |
+
case 0:
|
| 393 |
+
return a;
|
| 394 |
+
case 1:
|
| 395 |
+
return blend<1>(a, b);
|
| 396 |
+
case 2:
|
| 397 |
+
return blend<3>(a, b);
|
| 398 |
+
case 3:
|
| 399 |
+
return blend<7>(a, b);
|
| 400 |
+
case 4:
|
| 401 |
+
return blend<15>(a, b);
|
| 402 |
+
case 5:
|
| 403 |
+
return blend<31>(a, b);
|
| 404 |
+
case 6:
|
| 405 |
+
return blend<63>(a, b);
|
| 406 |
+
case 7:
|
| 407 |
+
return blend<127>(a, b);
|
| 408 |
+
case 8:
|
| 409 |
+
return blend<255>(a, b);
|
| 410 |
+
case 9:
|
| 411 |
+
return blend<511>(a, b);
|
| 412 |
+
case 10:
|
| 413 |
+
return blend<1023>(a, b);
|
| 414 |
+
case 11:
|
| 415 |
+
return blend<2047>(a, b);
|
| 416 |
+
case 12:
|
| 417 |
+
return blend<4095>(a, b);
|
| 418 |
+
case 13:
|
| 419 |
+
return blend<8191>(a, b);
|
| 420 |
+
case 14:
|
| 421 |
+
return blend<16383>(a, b);
|
| 422 |
+
case 15:
|
| 423 |
+
return blend<32767>(a, b);
|
| 424 |
+
}
|
| 425 |
+
return b;
|
| 426 |
+
}
|
| 427 |
+
static Vectorized<int16_t> loadu(const void* ptr) {
|
| 428 |
+
return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(ptr));
|
| 429 |
+
}
|
| 430 |
+
static Vectorized<int16_t> loadu(const void* ptr, int16_t count) {
|
| 431 |
+
__at_align__ int16_t tmp_values[size()];
|
| 432 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 433 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 434 |
+
// instructions while a loop would be compiled to one instruction.
|
| 435 |
+
for (const auto i : c10::irange(size())) {
|
| 436 |
+
tmp_values[i] = 0;
|
| 437 |
+
}
|
| 438 |
+
std::memcpy(tmp_values, ptr, count * sizeof(int16_t));
|
| 439 |
+
return loadu(tmp_values);
|
| 440 |
+
}
|
| 441 |
+
void store(void* ptr, int count = size()) const {
|
| 442 |
+
if (count == size()) {
|
| 443 |
+
// ptr need not to be aligned here. See
|
| 444 |
+
// https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/intrinsics/intrinsics-for-intel-advanced-vector-extensions/intrinsics-for-load-and-store-operations-1/mm256-storeu-si256.html
|
| 445 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), values);
|
| 446 |
+
} else if (count > 0) {
|
| 447 |
+
__at_align__ int16_t tmp_values[size()];
|
| 448 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(tmp_values), values);
|
| 449 |
+
std::memcpy(ptr, tmp_values, count * sizeof(int16_t));
|
| 450 |
+
}
|
| 451 |
+
}
|
| 452 |
+
const int16_t& operator[](int idx) const = delete;
|
| 453 |
+
int16_t& operator[](int idx) = delete;
|
| 454 |
+
Vectorized<int16_t> abs() const {
|
| 455 |
+
return _mm256_abs_epi16(values);
|
| 456 |
+
}
|
| 457 |
+
Vectorized<int16_t> real() const {
|
| 458 |
+
return *this;
|
| 459 |
+
}
|
| 460 |
+
Vectorized<int16_t> imag() const {
|
| 461 |
+
return _mm256_set1_epi16(0);
|
| 462 |
+
}
|
| 463 |
+
Vectorized<int16_t> conj() const {
|
| 464 |
+
return *this;
|
| 465 |
+
}
|
| 466 |
+
Vectorized<int16_t> neg() const;
|
| 467 |
+
Vectorized<int16_t> operator==(const Vectorized<int16_t>& other) const {
|
| 468 |
+
return _mm256_cmpeq_epi16(values, other.values);
|
| 469 |
+
}
|
| 470 |
+
Vectorized<int16_t> operator!=(const Vectorized<int16_t>& other) const {
|
| 471 |
+
return invert(_mm256_cmpeq_epi16(values, other.values));
|
| 472 |
+
}
|
| 473 |
+
Vectorized<int16_t> operator<(const Vectorized<int16_t>& other) const {
|
| 474 |
+
return _mm256_cmpgt_epi16(other.values, values);
|
| 475 |
+
}
|
| 476 |
+
Vectorized<int16_t> operator<=(const Vectorized<int16_t>& other) const {
|
| 477 |
+
return invert(_mm256_cmpgt_epi16(values, other.values));
|
| 478 |
+
}
|
| 479 |
+
Vectorized<int16_t> operator>(const Vectorized<int16_t>& other) const {
|
| 480 |
+
return _mm256_cmpgt_epi16(values, other.values);
|
| 481 |
+
}
|
| 482 |
+
Vectorized<int16_t> operator>=(const Vectorized<int16_t>& other) const {
|
| 483 |
+
return invert(_mm256_cmpgt_epi16(other.values, values));
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
+
Vectorized<int16_t> eq(const Vectorized<int16_t>& other) const;
|
| 487 |
+
Vectorized<int16_t> ne(const Vectorized<int16_t>& other) const;
|
| 488 |
+
Vectorized<int16_t> gt(const Vectorized<int16_t>& other) const;
|
| 489 |
+
Vectorized<int16_t> ge(const Vectorized<int16_t>& other) const;
|
| 490 |
+
Vectorized<int16_t> lt(const Vectorized<int16_t>& other) const;
|
| 491 |
+
Vectorized<int16_t> le(const Vectorized<int16_t>& other) const;
|
| 492 |
+
};
|
| 493 |
+
|
| 494 |
+
template <typename T>
|
| 495 |
+
class Vectorized8 : public Vectorizedi {
|
| 496 |
+
static_assert(
|
| 497 |
+
std::is_same_v<T, int8_t> || std::is_same_v<T, uint8_t>,
|
| 498 |
+
"Only int8_t/uint8_t are supported");
|
| 499 |
+
protected:
|
| 500 |
+
static const Vectorized<T> ones;
|
| 501 |
+
public:
|
| 502 |
+
using value_type = T;
|
| 503 |
+
static constexpr int size() {
|
| 504 |
+
return 32;
|
| 505 |
+
}
|
| 506 |
+
using Vectorizedi::Vectorizedi;
|
| 507 |
+
Vectorized8() {}
|
| 508 |
+
Vectorized8(T v) { values = _mm256_set1_epi8(v); }
|
| 509 |
+
Vectorized8(T val1, T val2, T val3, T val4,
|
| 510 |
+
T val5, T val6, T val7, T val8,
|
| 511 |
+
T val9, T val10, T val11, T val12,
|
| 512 |
+
T val13, T val14, T val15, T val16,
|
| 513 |
+
T val17, T val18, T val19, T val20,
|
| 514 |
+
T val21, T val22, T val23, T val24,
|
| 515 |
+
T val25, T val26, T val27, T val28,
|
| 516 |
+
T val29, T val30, T val31, T val32) {
|
| 517 |
+
values = _mm256_setr_epi8(val1, val2, val3, val4, val5, val6, val7, val8,
|
| 518 |
+
val9, val10, val11, val12, val13, val14, val15, val16,
|
| 519 |
+
val17, val18, val19, val20, val21, val22, val23, val24,
|
| 520 |
+
val25, val26, val27, val28, val29, val30, val31, val32);
|
| 521 |
+
}
|
| 522 |
+
template <int64_t mask>
|
| 523 |
+
static Vectorized<T> blend(Vectorized<T> a, Vectorized<T> b) {
|
| 524 |
+
__at_align__ T tmp_values[size()];
|
| 525 |
+
a.store(tmp_values);
|
| 526 |
+
if (mask & 0x01)
|
| 527 |
+
tmp_values[0] = _mm256_extract_epi8(b.values, 0);
|
| 528 |
+
if (mask & 0x02)
|
| 529 |
+
tmp_values[1] = _mm256_extract_epi8(b.values, 1);
|
| 530 |
+
if (mask & 0x04)
|
| 531 |
+
tmp_values[2] = _mm256_extract_epi8(b.values, 2);
|
| 532 |
+
if (mask & 0x08)
|
| 533 |
+
tmp_values[3] = _mm256_extract_epi8(b.values, 3);
|
| 534 |
+
if (mask & 0x10)
|
| 535 |
+
tmp_values[4] = _mm256_extract_epi8(b.values, 4);
|
| 536 |
+
if (mask & 0x20)
|
| 537 |
+
tmp_values[5] = _mm256_extract_epi8(b.values, 5);
|
| 538 |
+
if (mask & 0x40)
|
| 539 |
+
tmp_values[6] = _mm256_extract_epi8(b.values, 6);
|
| 540 |
+
if (mask & 0x80)
|
| 541 |
+
tmp_values[7] = _mm256_extract_epi8(b.values, 7);
|
| 542 |
+
if (mask & 0x100)
|
| 543 |
+
tmp_values[8] = _mm256_extract_epi8(b.values, 8);
|
| 544 |
+
if (mask & 0x200)
|
| 545 |
+
tmp_values[9] = _mm256_extract_epi8(b.values, 9);
|
| 546 |
+
if (mask & 0x400)
|
| 547 |
+
tmp_values[10] = _mm256_extract_epi8(b.values, 10);
|
| 548 |
+
if (mask & 0x800)
|
| 549 |
+
tmp_values[11] = _mm256_extract_epi8(b.values, 11);
|
| 550 |
+
if (mask & 0x1000)
|
| 551 |
+
tmp_values[12] = _mm256_extract_epi8(b.values, 12);
|
| 552 |
+
if (mask & 0x2000)
|
| 553 |
+
tmp_values[13] = _mm256_extract_epi8(b.values, 13);
|
| 554 |
+
if (mask & 0x4000)
|
| 555 |
+
tmp_values[14] = _mm256_extract_epi8(b.values, 14);
|
| 556 |
+
if (mask & 0x8000)
|
| 557 |
+
tmp_values[15] = _mm256_extract_epi8(b.values, 15);
|
| 558 |
+
if (mask & 0x010000)
|
| 559 |
+
tmp_values[16] = _mm256_extract_epi8(b.values, 16);
|
| 560 |
+
if (mask & 0x020000)
|
| 561 |
+
tmp_values[17] = _mm256_extract_epi8(b.values, 17);
|
| 562 |
+
if (mask & 0x040000)
|
| 563 |
+
tmp_values[18] = _mm256_extract_epi8(b.values, 18);
|
| 564 |
+
if (mask & 0x080000)
|
| 565 |
+
tmp_values[19] = _mm256_extract_epi8(b.values, 19);
|
| 566 |
+
if (mask & 0x100000)
|
| 567 |
+
tmp_values[20] = _mm256_extract_epi8(b.values, 20);
|
| 568 |
+
if (mask & 0x200000)
|
| 569 |
+
tmp_values[21] = _mm256_extract_epi8(b.values, 21);
|
| 570 |
+
if (mask & 0x400000)
|
| 571 |
+
tmp_values[22] = _mm256_extract_epi8(b.values, 22);
|
| 572 |
+
if (mask & 0x800000)
|
| 573 |
+
tmp_values[23] = _mm256_extract_epi8(b.values, 23);
|
| 574 |
+
if (mask & 0x1000000)
|
| 575 |
+
tmp_values[24] = _mm256_extract_epi8(b.values, 24);
|
| 576 |
+
if (mask & 0x2000000)
|
| 577 |
+
tmp_values[25] = _mm256_extract_epi8(b.values, 25);
|
| 578 |
+
if (mask & 0x4000000)
|
| 579 |
+
tmp_values[26] = _mm256_extract_epi8(b.values, 26);
|
| 580 |
+
if (mask & 0x8000000)
|
| 581 |
+
tmp_values[27] = _mm256_extract_epi8(b.values, 27);
|
| 582 |
+
if (mask & 0x10000000)
|
| 583 |
+
tmp_values[28] = _mm256_extract_epi8(b.values, 28);
|
| 584 |
+
if (mask & 0x20000000)
|
| 585 |
+
tmp_values[29] = _mm256_extract_epi8(b.values, 29);
|
| 586 |
+
if (mask & 0x40000000)
|
| 587 |
+
tmp_values[30] = _mm256_extract_epi8(b.values, 30);
|
| 588 |
+
if (mask & 0x80000000)
|
| 589 |
+
tmp_values[31] = _mm256_extract_epi8(b.values, 31);
|
| 590 |
+
return loadu(tmp_values);
|
| 591 |
+
}
|
| 592 |
+
static Vectorized<T> blendv(const Vectorized<T>& a, const Vectorized<T>& b,
|
| 593 |
+
const Vectorized<T>& mask) {
|
| 594 |
+
return _mm256_blendv_epi8(a.values, b.values, mask.values);
|
| 595 |
+
}
|
| 596 |
+
template <typename step_t>
|
| 597 |
+
static Vectorized<T> arange(T base = 0, step_t step = static_cast<step_t>(1)) {
|
| 598 |
+
return Vectorized<T>(
|
| 599 |
+
base, base + step, base + 2 * step, base + 3 * step,
|
| 600 |
+
base + 4 * step, base + 5 * step, base + 6 * step, base + 7 * step,
|
| 601 |
+
base + 8 * step, base + 9 * step, base + 10 * step, base + 11 * step,
|
| 602 |
+
base + 12 * step, base + 13 * step, base + 14 * step, base + 15 * step,
|
| 603 |
+
base + 16 * step, base + 17 * step, base + 18 * step, base + 19 * step,
|
| 604 |
+
base + 20 * step, base + 21 * step, base + 22 * step, base + 23 * step,
|
| 605 |
+
base + 24 * step, base + 25 * step, base + 26 * step, base + 27 * step,
|
| 606 |
+
base + 28 * step, base + 29 * step, base + 30 * step, base + 31 * step);
|
| 607 |
+
}
|
| 608 |
+
static Vectorized<T>
|
| 609 |
+
set(Vectorized<T> a, Vectorized<T> b, T count = size()) {
|
| 610 |
+
switch (count) {
|
| 611 |
+
case 0:
|
| 612 |
+
return a;
|
| 613 |
+
case 1:
|
| 614 |
+
return blend<0x1>(a, b);
|
| 615 |
+
case 2:
|
| 616 |
+
return blend<0x3>(a, b);
|
| 617 |
+
case 3:
|
| 618 |
+
return blend<0x7>(a, b);
|
| 619 |
+
case 4:
|
| 620 |
+
return blend<0xF>(a, b);
|
| 621 |
+
case 5:
|
| 622 |
+
return blend<0x1F>(a, b);
|
| 623 |
+
case 6:
|
| 624 |
+
return blend<0x3F>(a, b);
|
| 625 |
+
case 7:
|
| 626 |
+
return blend<0x7F>(a, b);
|
| 627 |
+
case 8:
|
| 628 |
+
return blend<0xFF>(a, b);
|
| 629 |
+
case 9:
|
| 630 |
+
return blend<0x1FF>(a, b);
|
| 631 |
+
case 10:
|
| 632 |
+
return blend<0x3FF>(a, b);
|
| 633 |
+
case 11:
|
| 634 |
+
return blend<0x7FF>(a, b);
|
| 635 |
+
case 12:
|
| 636 |
+
return blend<0xFFF>(a, b);
|
| 637 |
+
case 13:
|
| 638 |
+
return blend<0x1FFF>(a, b);
|
| 639 |
+
case 14:
|
| 640 |
+
return blend<0x3FFF>(a, b);
|
| 641 |
+
case 15:
|
| 642 |
+
return blend<0x7FFF>(a, b);
|
| 643 |
+
case 16:
|
| 644 |
+
return blend<0xFFFF>(a, b);
|
| 645 |
+
case 17:
|
| 646 |
+
return blend<0x1FFFF>(a, b);
|
| 647 |
+
case 18:
|
| 648 |
+
return blend<0x3FFFF>(a, b);
|
| 649 |
+
case 19:
|
| 650 |
+
return blend<0x7FFFF>(a, b);
|
| 651 |
+
case 20:
|
| 652 |
+
return blend<0xFFFFF>(a, b);
|
| 653 |
+
case 21:
|
| 654 |
+
return blend<0x1FFFFF>(a, b);
|
| 655 |
+
case 22:
|
| 656 |
+
return blend<0x3FFFFF>(a, b);
|
| 657 |
+
case 23:
|
| 658 |
+
return blend<0x7FFFFF>(a, b);
|
| 659 |
+
case 24:
|
| 660 |
+
return blend<0xFFFFFF>(a, b);
|
| 661 |
+
case 25:
|
| 662 |
+
return blend<0x1FFFFFF>(a, b);
|
| 663 |
+
case 26:
|
| 664 |
+
return blend<0x3FFFFFF>(a, b);
|
| 665 |
+
case 27:
|
| 666 |
+
return blend<0x7FFFFFF>(a, b);
|
| 667 |
+
case 28:
|
| 668 |
+
return blend<0xFFFFFFF>(a, b);
|
| 669 |
+
case 29:
|
| 670 |
+
return blend<0x1FFFFFFF>(a, b);
|
| 671 |
+
case 30:
|
| 672 |
+
return blend<0x3FFFFFFF>(a, b);
|
| 673 |
+
case 31:
|
| 674 |
+
return blend<0x7FFFFFFF>(a, b);
|
| 675 |
+
}
|
| 676 |
+
return b;
|
| 677 |
+
}
|
| 678 |
+
static Vectorized<T> loadu(const void* ptr) {
|
| 679 |
+
return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(ptr));
|
| 680 |
+
}
|
| 681 |
+
static Vectorized<T> loadu_one_fourth(const void* ptr) {
|
| 682 |
+
// Fast path if only load element number of 8.
|
| 683 |
+
// Note: We didn't merge it as fast path of loadu(const void* ptr, T count),
|
| 684 |
+
// Because loadu(const void* ptr, T count) requires zero initialization for upper 128 bits.
|
| 685 |
+
// However, by using _mm256_castsi128_si256, the upper 128 bits of the result are undefined.
|
| 686 |
+
// TODO<leslie> We can use _mm256_zextsi128_si256 in the furture,
|
| 687 |
+
// since gcc 9.3 doesn't support it now.
|
| 688 |
+
__m128i input_128 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(ptr));
|
| 689 |
+
return _mm256_castsi128_si256(input_128);
|
| 690 |
+
}
|
| 691 |
+
static Vectorized<T> loadu(const void* ptr, T count) {
|
| 692 |
+
__at_align__ T tmp_values[size()];
|
| 693 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 694 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 695 |
+
// instructions while a loop would be compiled to one instruction.
|
| 696 |
+
for (const auto i : c10::irange(size())) {
|
| 697 |
+
tmp_values[i] = 0;
|
| 698 |
+
}
|
| 699 |
+
std::memcpy(tmp_values, ptr, count * sizeof(T));
|
| 700 |
+
return loadu(tmp_values);
|
| 701 |
+
}
|
| 702 |
+
void store(void* ptr, int count = size()) const {
|
| 703 |
+
if (count == size()) {
|
| 704 |
+
// ptr need not to be aligned here. See
|
| 705 |
+
// https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/intrinsics/intrinsics-for-intel-advanced-vector-extensions/intrinsics-for-load-and-store-operations-1/mm256-storeu-si256.html
|
| 706 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), values);
|
| 707 |
+
} else if (count > 0) {
|
| 708 |
+
if (count == 8) {
|
| 709 |
+
// Fast path if only store element number of 8
|
| 710 |
+
_mm_storel_epi64(reinterpret_cast<__m128i*>(ptr), _mm256_castsi256_si128(values));
|
| 711 |
+
} else {
|
| 712 |
+
__at_align__ T tmp_values[size()];
|
| 713 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(tmp_values), values);
|
| 714 |
+
std::memcpy(ptr, tmp_values, count * sizeof(T));
|
| 715 |
+
}
|
| 716 |
+
}
|
| 717 |
+
}
|
| 718 |
+
const T& operator[](int idx) const = delete;
|
| 719 |
+
T& operator[](int idx) = delete;
|
| 720 |
+
Vectorized<T> real() const {
|
| 721 |
+
return *this;
|
| 722 |
+
}
|
| 723 |
+
Vectorized<T> imag() const {
|
| 724 |
+
return _mm256_set1_epi8(0);
|
| 725 |
+
}
|
| 726 |
+
Vectorized<T> conj() const {
|
| 727 |
+
return *this;
|
| 728 |
+
}
|
| 729 |
+
};
|
| 730 |
+
|
| 731 |
+
template<>
|
| 732 |
+
class Vectorized<int8_t>: public Vectorized8<int8_t> {
|
| 733 |
+
public:
|
| 734 |
+
using Vectorized8::Vectorized8;
|
| 735 |
+
|
| 736 |
+
Vectorized<int8_t> neg() const;
|
| 737 |
+
|
| 738 |
+
Vectorized<int8_t> abs() const {
|
| 739 |
+
return _mm256_abs_epi8(values);
|
| 740 |
+
}
|
| 741 |
+
|
| 742 |
+
Vectorized<int8_t> operator==(const Vectorized<int8_t>& other) const {
|
| 743 |
+
return _mm256_cmpeq_epi8(values, other.values);
|
| 744 |
+
}
|
| 745 |
+
Vectorized<int8_t> operator!=(const Vectorized<int8_t>& other) const {
|
| 746 |
+
return invert(_mm256_cmpeq_epi8(values, other.values));
|
| 747 |
+
}
|
| 748 |
+
Vectorized<int8_t> operator<(const Vectorized<int8_t>& other) const {
|
| 749 |
+
return _mm256_cmpgt_epi8(other.values, values);
|
| 750 |
+
}
|
| 751 |
+
Vectorized<int8_t> operator<=(const Vectorized<int8_t>& other) const {
|
| 752 |
+
return invert(_mm256_cmpgt_epi8(values, other.values));
|
| 753 |
+
}
|
| 754 |
+
Vectorized<int8_t> operator>(const Vectorized<int8_t>& other) const {
|
| 755 |
+
return other < *this;
|
| 756 |
+
}
|
| 757 |
+
Vectorized<int8_t> operator>=(const Vectorized<int8_t>& other) const {
|
| 758 |
+
return other <= *this;
|
| 759 |
+
}
|
| 760 |
+
|
| 761 |
+
Vectorized<int8_t> eq(const Vectorized<int8_t>& other) const;
|
| 762 |
+
Vectorized<int8_t> ne(const Vectorized<int8_t>& other) const;
|
| 763 |
+
Vectorized<int8_t> gt(const Vectorized<int8_t>& other) const;
|
| 764 |
+
Vectorized<int8_t> ge(const Vectorized<int8_t>& other) const;
|
| 765 |
+
Vectorized<int8_t> lt(const Vectorized<int8_t>& other) const;
|
| 766 |
+
Vectorized<int8_t> le(const Vectorized<int8_t>& other) const;
|
| 767 |
+
};
|
| 768 |
+
|
| 769 |
+
template<>
|
| 770 |
+
class Vectorized<uint8_t>: public Vectorized8<uint8_t> {
|
| 771 |
+
public:
|
| 772 |
+
using Vectorized8::Vectorized8;
|
| 773 |
+
|
| 774 |
+
Vectorized<uint8_t> neg() const;
|
| 775 |
+
|
| 776 |
+
Vectorized<uint8_t> abs() const {
|
| 777 |
+
return *this;
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
Vectorized<uint8_t> operator==(const Vectorized<uint8_t>& other) const {
|
| 781 |
+
return _mm256_cmpeq_epi8(values, other.values);
|
| 782 |
+
}
|
| 783 |
+
Vectorized<uint8_t> operator!=(const Vectorized<uint8_t>& other) const {
|
| 784 |
+
return invert(_mm256_cmpeq_epi8(values, other.values));
|
| 785 |
+
}
|
| 786 |
+
Vectorized<uint8_t> operator<(const Vectorized<uint8_t>& other) const {
|
| 787 |
+
__m256i max = _mm256_max_epu8(values, other.values);
|
| 788 |
+
return invert(_mm256_cmpeq_epi8(max, values));
|
| 789 |
+
}
|
| 790 |
+
Vectorized<uint8_t> operator<=(const Vectorized<uint8_t>& other) const {
|
| 791 |
+
__m256i max = _mm256_max_epu8(values, other.values);
|
| 792 |
+
return _mm256_cmpeq_epi8(max, other.values);
|
| 793 |
+
}
|
| 794 |
+
Vectorized<uint8_t> operator>(const Vectorized<uint8_t>& other) const {
|
| 795 |
+
return other < *this;
|
| 796 |
+
}
|
| 797 |
+
Vectorized<uint8_t> operator>=(const Vectorized<uint8_t>& other) const {
|
| 798 |
+
return other <= *this;
|
| 799 |
+
}
|
| 800 |
+
|
| 801 |
+
Vectorized<uint8_t> eq(const Vectorized<uint8_t>& other) const;
|
| 802 |
+
Vectorized<uint8_t> ne(const Vectorized<uint8_t>& other) const;
|
| 803 |
+
Vectorized<uint8_t> gt(const Vectorized<uint8_t>& other) const;
|
| 804 |
+
Vectorized<uint8_t> ge(const Vectorized<uint8_t>& other) const;
|
| 805 |
+
Vectorized<uint8_t> lt(const Vectorized<uint8_t>& other) const;
|
| 806 |
+
Vectorized<uint8_t> le(const Vectorized<uint8_t>& other) const;
|
| 807 |
+
};
|
| 808 |
+
|
| 809 |
+
template <>
|
| 810 |
+
Vectorized<int64_t> inline operator+(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 811 |
+
return _mm256_add_epi64(a, b);
|
| 812 |
+
}
|
| 813 |
+
|
| 814 |
+
template <>
|
| 815 |
+
Vectorized<int32_t> inline operator+(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 816 |
+
return _mm256_add_epi32(a, b);
|
| 817 |
+
}
|
| 818 |
+
|
| 819 |
+
template <>
|
| 820 |
+
Vectorized<int16_t> inline operator+(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 821 |
+
return _mm256_add_epi16(a, b);
|
| 822 |
+
}
|
| 823 |
+
|
| 824 |
+
template <>
|
| 825 |
+
Vectorized<int8_t> inline operator+(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 826 |
+
return _mm256_add_epi8(a, b);
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
template <>
|
| 830 |
+
Vectorized<uint8_t> inline operator+(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& b) {
|
| 831 |
+
return _mm256_add_epi8(a, b);
|
| 832 |
+
}
|
| 833 |
+
|
| 834 |
+
template <>
|
| 835 |
+
Vectorized<int64_t> inline operator-(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 836 |
+
return _mm256_sub_epi64(a, b);
|
| 837 |
+
}
|
| 838 |
+
|
| 839 |
+
template <>
|
| 840 |
+
Vectorized<int32_t> inline operator-(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 841 |
+
return _mm256_sub_epi32(a, b);
|
| 842 |
+
}
|
| 843 |
+
|
| 844 |
+
template <>
|
| 845 |
+
Vectorized<int16_t> inline operator-(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 846 |
+
return _mm256_sub_epi16(a, b);
|
| 847 |
+
}
|
| 848 |
+
|
| 849 |
+
template <>
|
| 850 |
+
Vectorized<int8_t> inline operator-(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 851 |
+
return _mm256_sub_epi8(a, b);
|
| 852 |
+
}
|
| 853 |
+
|
| 854 |
+
template <>
|
| 855 |
+
Vectorized<uint8_t> inline operator-(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& b) {
|
| 856 |
+
return _mm256_sub_epi8(a, b);
|
| 857 |
+
}
|
| 858 |
+
|
| 859 |
+
// Negation. Defined here so we can utilize operator-
|
| 860 |
+
inline Vectorized<int64_t> Vectorized<int64_t>::neg() const {
|
| 861 |
+
return Vectorized<int64_t>(0) - *this;
|
| 862 |
+
}
|
| 863 |
+
|
| 864 |
+
inline Vectorized<int32_t> Vectorized<int32_t>::neg() const {
|
| 865 |
+
return Vectorized<int32_t>(0) - *this;
|
| 866 |
+
}
|
| 867 |
+
|
| 868 |
+
inline Vectorized<int16_t> Vectorized<int16_t>::neg() const {
|
| 869 |
+
return Vectorized<int16_t>(0) - *this;
|
| 870 |
+
}
|
| 871 |
+
|
| 872 |
+
inline Vectorized<int8_t> Vectorized<int8_t>::neg() const {
|
| 873 |
+
return Vectorized<int8_t>(0) - *this;
|
| 874 |
+
}
|
| 875 |
+
|
| 876 |
+
inline Vectorized<uint8_t> Vectorized<uint8_t>::neg() const {
|
| 877 |
+
return Vectorized<uint8_t>(0) - *this;
|
| 878 |
+
}
|
| 879 |
+
|
| 880 |
+
// Emulate operations with no native 64-bit support in avx,
|
| 881 |
+
// by extracting each element, performing the operation pointwise,
|
| 882 |
+
// then combining the results into a vector.
|
| 883 |
+
template <typename op_t>
|
| 884 |
+
Vectorized<int64_t> inline emulate(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b, const op_t& op) {
|
| 885 |
+
int64_t a0 = _mm256_extract_epi64(a, 0);
|
| 886 |
+
int64_t a1 = _mm256_extract_epi64(a, 1);
|
| 887 |
+
int64_t a2 = _mm256_extract_epi64(a, 2);
|
| 888 |
+
int64_t a3 = _mm256_extract_epi64(a, 3);
|
| 889 |
+
|
| 890 |
+
int64_t b0 = _mm256_extract_epi64(b, 0);
|
| 891 |
+
int64_t b1 = _mm256_extract_epi64(b, 1);
|
| 892 |
+
int64_t b2 = _mm256_extract_epi64(b, 2);
|
| 893 |
+
int64_t b3 = _mm256_extract_epi64(b, 3);
|
| 894 |
+
|
| 895 |
+
int64_t c0 = op(a0, b0);
|
| 896 |
+
int64_t c1 = op(a1, b1);
|
| 897 |
+
int64_t c2 = op(a2, b2);
|
| 898 |
+
int64_t c3 = op(a3, b3);
|
| 899 |
+
|
| 900 |
+
return _mm256_set_epi64x(c3, c2, c1, c0);
|
| 901 |
+
}
|
| 902 |
+
|
| 903 |
+
template <typename op_t>
|
| 904 |
+
Vectorized<int64_t> inline emulate(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b, const Vectorized<int64_t>& c, const op_t& op) {
|
| 905 |
+
int64_t a0 = _mm256_extract_epi64(a, 0);
|
| 906 |
+
int64_t a1 = _mm256_extract_epi64(a, 1);
|
| 907 |
+
int64_t a2 = _mm256_extract_epi64(a, 2);
|
| 908 |
+
int64_t a3 = _mm256_extract_epi64(a, 3);
|
| 909 |
+
|
| 910 |
+
int64_t b0 = _mm256_extract_epi64(b, 0);
|
| 911 |
+
int64_t b1 = _mm256_extract_epi64(b, 1);
|
| 912 |
+
int64_t b2 = _mm256_extract_epi64(b, 2);
|
| 913 |
+
int64_t b3 = _mm256_extract_epi64(b, 3);
|
| 914 |
+
|
| 915 |
+
int64_t c0 = _mm256_extract_epi64(c, 0);
|
| 916 |
+
int64_t c1 = _mm256_extract_epi64(c, 1);
|
| 917 |
+
int64_t c2 = _mm256_extract_epi64(c, 2);
|
| 918 |
+
int64_t c3 = _mm256_extract_epi64(c, 3);
|
| 919 |
+
|
| 920 |
+
int64_t d0 = op(a0, b0, c0);
|
| 921 |
+
int64_t d1 = op(a1, b1, c1);
|
| 922 |
+
int64_t d2 = op(a2, b2, c2);
|
| 923 |
+
int64_t d3 = op(a3, b3, c3);
|
| 924 |
+
|
| 925 |
+
return _mm256_set_epi64x(d3, d2, d1, d0);
|
| 926 |
+
}
|
| 927 |
+
|
| 928 |
+
// AVX2 has no intrinsic for int64_t multiply so it needs to be emulated
|
| 929 |
+
// This could be implemented more efficiently using epi32 instructions
|
| 930 |
+
// This is also technically avx compatible, but then we'll need AVX
|
| 931 |
+
// code for add as well.
|
| 932 |
+
// Note: intentionally ignores undefined behavior like (-lowest * -1).
|
| 933 |
+
template <>
|
| 934 |
+
Vectorized<int64_t> inline operator*(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 935 |
+
return emulate(a, b, [](int64_t a_point, int64_t b_point) __ubsan_ignore_undefined__ {return a_point * b_point;});
|
| 936 |
+
}
|
| 937 |
+
|
| 938 |
+
template <>
|
| 939 |
+
Vectorized<int32_t> inline operator*(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 940 |
+
return _mm256_mullo_epi32(a, b);
|
| 941 |
+
}
|
| 942 |
+
|
| 943 |
+
template <>
|
| 944 |
+
Vectorized<int16_t> inline operator*(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 945 |
+
return _mm256_mullo_epi16(a, b);
|
| 946 |
+
}
|
| 947 |
+
|
| 948 |
+
template <typename T, typename Op>
|
| 949 |
+
Vectorized<T> inline int_elementwise_binary_256(const Vectorized<T>& a, const Vectorized<T>& b, Op op) {
|
| 950 |
+
T values_a[Vectorized<T>::size()];
|
| 951 |
+
T values_b[Vectorized<T>::size()];
|
| 952 |
+
a.store(values_a);
|
| 953 |
+
b.store(values_b);
|
| 954 |
+
for (int i = 0; i != Vectorized<T>::size(); i++) {
|
| 955 |
+
values_a[i] = op(values_a[i], values_b[i]);
|
| 956 |
+
}
|
| 957 |
+
return Vectorized<T>::loadu(values_a);
|
| 958 |
+
}
|
| 959 |
+
|
| 960 |
+
template <>
|
| 961 |
+
Vectorized<int8_t> inline operator*(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 962 |
+
// We don't have an instruction for multiplying int8_t
|
| 963 |
+
#ifndef CPU_CAPABILITY_AVX2
|
| 964 |
+
return int_elementwise_binary_256(a, b, std::multiplies<int8_t>());
|
| 965 |
+
#else
|
| 966 |
+
__m256i mask00FF = _mm256_set1_epi16(0x00FF);
|
| 967 |
+
__m256i a_lo = _mm256_srai_epi16(_mm256_slli_epi16(a, 8), 8);
|
| 968 |
+
__m256i b_lo = _mm256_srai_epi16(_mm256_slli_epi16(b, 8), 8);
|
| 969 |
+
__m256i a_hi = _mm256_srai_epi16(a, 8);
|
| 970 |
+
__m256i b_hi = _mm256_srai_epi16(b, 8);
|
| 971 |
+
__m256i res_lo = _mm256_and_si256(_mm256_mullo_epi16(a_lo, b_lo), mask00FF);
|
| 972 |
+
__m256i res_hi = _mm256_slli_epi16(_mm256_mullo_epi16(a_hi, b_hi), 8);
|
| 973 |
+
__m256i res = _mm256_or_si256(res_hi, res_lo);
|
| 974 |
+
return res;
|
| 975 |
+
#endif
|
| 976 |
+
}
|
| 977 |
+
|
| 978 |
+
template <>
|
| 979 |
+
Vectorized<uint8_t> inline operator*(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& b) {
|
| 980 |
+
// We don't have an instruction for multiplying uint8_t
|
| 981 |
+
#ifndef CPU_CAPABILITY_AVX2
|
| 982 |
+
return int_elementwise_binary_256(a, b, std::multiplies<uint8_t>());
|
| 983 |
+
#else
|
| 984 |
+
__m256i mask00FF = _mm256_set1_epi16(0x00FF);
|
| 985 |
+
__m256i a_lo = _mm256_and_si256 (a, mask00FF);
|
| 986 |
+
__m256i b_lo = _mm256_and_si256 (b, mask00FF);
|
| 987 |
+
__m256i a_hi = _mm256_srli_epi16(a, 8);
|
| 988 |
+
__m256i b_hi = _mm256_srli_epi16(b, 8);
|
| 989 |
+
__m256i res_lo = _mm256_and_si256(_mm256_mullo_epi16(a_lo, b_lo), mask00FF);
|
| 990 |
+
__m256i res_hi = _mm256_slli_epi16(_mm256_mullo_epi16(a_hi, b_hi), 8);
|
| 991 |
+
__m256i res = _mm256_or_si256(res_hi, res_lo);
|
| 992 |
+
return res;
|
| 993 |
+
#endif
|
| 994 |
+
}
|
| 995 |
+
|
| 996 |
+
template <>
|
| 997 |
+
Vectorized<int64_t> inline minimum(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 998 |
+
#ifndef CPU_CAPABILITY_AVX2
|
| 999 |
+
return emulate(a, b, [](int64_t a_point, int64_t b_point) {return std::min(a_point, b_point);});
|
| 1000 |
+
#else
|
| 1001 |
+
__m256i cmp = _mm256_cmpgt_epi64(a, b);
|
| 1002 |
+
return _mm256_blendv_epi8(a, b, cmp);
|
| 1003 |
+
#endif
|
| 1004 |
+
}
|
| 1005 |
+
|
| 1006 |
+
template <>
|
| 1007 |
+
Vectorized<int32_t> inline minimum(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 1008 |
+
return _mm256_min_epi32(a, b);
|
| 1009 |
+
}
|
| 1010 |
+
|
| 1011 |
+
template <>
|
| 1012 |
+
Vectorized<int16_t> inline minimum(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 1013 |
+
return _mm256_min_epi16(a, b);
|
| 1014 |
+
}
|
| 1015 |
+
|
| 1016 |
+
template <>
|
| 1017 |
+
Vectorized<int8_t> inline minimum(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 1018 |
+
return _mm256_min_epi8(a, b);
|
| 1019 |
+
}
|
| 1020 |
+
|
| 1021 |
+
template <>
|
| 1022 |
+
Vectorized<uint8_t> inline minimum(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& b) {
|
| 1023 |
+
return _mm256_min_epu8(a, b);
|
| 1024 |
+
}
|
| 1025 |
+
|
| 1026 |
+
template <>
|
| 1027 |
+
Vectorized<int64_t> inline maximum(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 1028 |
+
#ifndef CPU_CAPABILITY_AVX2
|
| 1029 |
+
return emulate(a, b, [](int64_t a_point, int64_t b_point) {return std::max(a_point, b_point);});
|
| 1030 |
+
#else
|
| 1031 |
+
__m256i cmp = _mm256_cmpgt_epi64(a, b);
|
| 1032 |
+
return _mm256_blendv_epi8(b, a, cmp);
|
| 1033 |
+
#endif
|
| 1034 |
+
}
|
| 1035 |
+
|
| 1036 |
+
template <>
|
| 1037 |
+
Vectorized<int32_t> inline maximum(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 1038 |
+
return _mm256_max_epi32(a, b);
|
| 1039 |
+
}
|
| 1040 |
+
|
| 1041 |
+
template <>
|
| 1042 |
+
Vectorized<int16_t> inline maximum(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 1043 |
+
return _mm256_max_epi16(a, b);
|
| 1044 |
+
}
|
| 1045 |
+
|
| 1046 |
+
template <>
|
| 1047 |
+
Vectorized<int8_t> inline maximum(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 1048 |
+
return _mm256_max_epi8(a, b);
|
| 1049 |
+
}
|
| 1050 |
+
|
| 1051 |
+
template <>
|
| 1052 |
+
Vectorized<uint8_t> inline maximum(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& b) {
|
| 1053 |
+
return _mm256_max_epu8(a, b);
|
| 1054 |
+
}
|
| 1055 |
+
|
| 1056 |
+
template <>
|
| 1057 |
+
Vectorized<int64_t> inline clamp(const Vectorized<int64_t>& a, const Vectorized<int64_t>& min_val, const Vectorized<int64_t>& max_val) {
|
| 1058 |
+
#ifndef CPU_CAPABILITY_AVX2
|
| 1059 |
+
return emulate(a, min_val, max_val, [](int64_t a_point, int64_t min_point, int64_t max_point) {return std::min(max_point, std::max(a_point, min_point));});
|
| 1060 |
+
#else
|
| 1061 |
+
return minimum(maximum(a, min_val), max_val);
|
| 1062 |
+
#endif
|
| 1063 |
+
}
|
| 1064 |
+
|
| 1065 |
+
template <>
|
| 1066 |
+
Vectorized<int32_t> inline clamp(const Vectorized<int32_t>& a, const Vectorized<int32_t>& min_val, const Vectorized<int32_t>& max_val) {
|
| 1067 |
+
return _mm256_min_epi32(max_val, _mm256_max_epi32(a, min_val));
|
| 1068 |
+
}
|
| 1069 |
+
|
| 1070 |
+
template <>
|
| 1071 |
+
Vectorized<int16_t> inline clamp(const Vectorized<int16_t>& a, const Vectorized<int16_t>& min_val, const Vectorized<int16_t>& max_val) {
|
| 1072 |
+
return _mm256_min_epi16(max_val, _mm256_max_epi16(a, min_val));
|
| 1073 |
+
}
|
| 1074 |
+
|
| 1075 |
+
template <>
|
| 1076 |
+
Vectorized<int8_t> inline clamp(const Vectorized<int8_t>& a, const Vectorized<int8_t>& min_val, const Vectorized<int8_t>& max_val) {
|
| 1077 |
+
return _mm256_min_epi8(max_val, _mm256_max_epi8(a, min_val));
|
| 1078 |
+
}
|
| 1079 |
+
|
| 1080 |
+
template <>
|
| 1081 |
+
Vectorized<uint8_t> inline clamp(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& min_val, const Vectorized<uint8_t>& max_val) {
|
| 1082 |
+
return _mm256_min_epu8(max_val, _mm256_max_epu8(a, min_val));
|
| 1083 |
+
}
|
| 1084 |
+
|
| 1085 |
+
template <>
|
| 1086 |
+
Vectorized<int64_t> inline clamp_max(const Vectorized<int64_t>& a, const Vectorized<int64_t>& max_val) {
|
| 1087 |
+
#ifndef CPU_CAPABILITY_AVX2
|
| 1088 |
+
return emulate(a, max_val, [](int64_t a_point, int64_t max_point) {return std::min(max_point, a_point);});
|
| 1089 |
+
#else
|
| 1090 |
+
return minimum(max_val, a);
|
| 1091 |
+
#endif
|
| 1092 |
+
}
|
| 1093 |
+
|
| 1094 |
+
template <>
|
| 1095 |
+
Vectorized<int32_t> inline clamp_max(const Vectorized<int32_t>& a, const Vectorized<int32_t>& max_val) {
|
| 1096 |
+
return _mm256_min_epi32(max_val, a);
|
| 1097 |
+
}
|
| 1098 |
+
|
| 1099 |
+
template <>
|
| 1100 |
+
Vectorized<int16_t> inline clamp_max(const Vectorized<int16_t>& a, const Vectorized<int16_t>& max_val) {
|
| 1101 |
+
return _mm256_min_epi16(max_val, a);
|
| 1102 |
+
}
|
| 1103 |
+
|
| 1104 |
+
template <>
|
| 1105 |
+
Vectorized<int8_t> inline clamp_max(const Vectorized<int8_t>& a, const Vectorized<int8_t>& max_val) {
|
| 1106 |
+
return _mm256_min_epi8(max_val, a);
|
| 1107 |
+
}
|
| 1108 |
+
|
| 1109 |
+
template <>
|
| 1110 |
+
Vectorized<uint8_t> inline clamp_max(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& max_val) {
|
| 1111 |
+
return _mm256_min_epu8(max_val, a);
|
| 1112 |
+
}
|
| 1113 |
+
|
| 1114 |
+
template <>
|
| 1115 |
+
Vectorized<int64_t> inline clamp_min(const Vectorized<int64_t>& a, const Vectorized<int64_t>& min_val) {
|
| 1116 |
+
#ifndef CPU_CAPABILITY_AVX2
|
| 1117 |
+
return emulate(a, min_val, [](int64_t a_point, int64_t min_point) {return std::max(min_point, a_point);});
|
| 1118 |
+
#else
|
| 1119 |
+
return maximum(min_val, a);
|
| 1120 |
+
#endif
|
| 1121 |
+
}
|
| 1122 |
+
|
| 1123 |
+
template <>
|
| 1124 |
+
Vectorized<int32_t> inline clamp_min(const Vectorized<int32_t>& a, const Vectorized<int32_t>& min_val) {
|
| 1125 |
+
return _mm256_max_epi32(min_val, a);
|
| 1126 |
+
}
|
| 1127 |
+
|
| 1128 |
+
template <>
|
| 1129 |
+
Vectorized<int16_t> inline clamp_min(const Vectorized<int16_t>& a, const Vectorized<int16_t>& min_val) {
|
| 1130 |
+
return _mm256_max_epi16(min_val, a);
|
| 1131 |
+
}
|
| 1132 |
+
|
| 1133 |
+
template <>
|
| 1134 |
+
Vectorized<int8_t> inline clamp_min(const Vectorized<int8_t>& a, const Vectorized<int8_t>& min_val) {
|
| 1135 |
+
return _mm256_max_epi8(min_val, a);
|
| 1136 |
+
}
|
| 1137 |
+
|
| 1138 |
+
template <>
|
| 1139 |
+
Vectorized<uint8_t> inline clamp_min(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& min_val) {
|
| 1140 |
+
return _mm256_max_epu8(min_val, a);
|
| 1141 |
+
}
|
| 1142 |
+
|
| 1143 |
+
template<typename T>
|
| 1144 |
+
Vectorized<int32_t> inline convert_to_int32(const T* ptr) {
|
| 1145 |
+
return Vectorized<int32_t>::loadu(ptr);
|
| 1146 |
+
}
|
| 1147 |
+
|
| 1148 |
+
template<>
|
| 1149 |
+
Vectorized<int32_t> inline convert_to_int32<int8_t>(const int8_t* ptr) {
|
| 1150 |
+
return _mm256_cvtepi8_epi32(_mm_loadl_epi64(reinterpret_cast<const __m128i*>(ptr)));
|
| 1151 |
+
}
|
| 1152 |
+
|
| 1153 |
+
template<>
|
| 1154 |
+
Vectorized<int32_t> inline convert_to_int32<uint8_t>(const uint8_t* ptr) {
|
| 1155 |
+
return _mm256_cvtepu8_epi32(_mm_loadl_epi64(reinterpret_cast<const __m128i*>(ptr)));
|
| 1156 |
+
}
|
| 1157 |
+
|
| 1158 |
+
template <>
|
| 1159 |
+
Vectorized<int64_t> inline operator/(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 1160 |
+
return int_elementwise_binary_256(a, b, std::divides<int64_t>());
|
| 1161 |
+
}
|
| 1162 |
+
template <>
|
| 1163 |
+
Vectorized<int32_t> inline operator/(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 1164 |
+
return int_elementwise_binary_256(a, b, std::divides<int32_t>());
|
| 1165 |
+
}
|
| 1166 |
+
template <>
|
| 1167 |
+
Vectorized<int16_t> inline operator/(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 1168 |
+
return int_elementwise_binary_256(a, b, std::divides<int16_t>());
|
| 1169 |
+
}
|
| 1170 |
+
template <>
|
| 1171 |
+
Vectorized<int8_t> inline operator/(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 1172 |
+
return int_elementwise_binary_256(a, b, std::divides<int8_t>());
|
| 1173 |
+
}
|
| 1174 |
+
template <>
|
| 1175 |
+
Vectorized<uint8_t> inline operator/(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& b) {
|
| 1176 |
+
return int_elementwise_binary_256(a, b, std::divides<uint8_t>());
|
| 1177 |
+
}
|
| 1178 |
+
|
| 1179 |
+
template<class T, typename std::enable_if_t<std::is_base_of<Vectorizedi, Vectorized<T>>::value, int> = 0>
|
| 1180 |
+
inline Vectorized<T> operator&(const Vectorized<T>& a, const Vectorized<T>& b) {
|
| 1181 |
+
return _mm256_and_si256(a, b);
|
| 1182 |
+
}
|
| 1183 |
+
template<class T, typename std::enable_if_t<std::is_base_of<Vectorizedi, Vectorized<T>>::value, int> = 0>
|
| 1184 |
+
inline Vectorized<T> operator|(const Vectorized<T>& a, const Vectorized<T>& b) {
|
| 1185 |
+
return _mm256_or_si256(a, b);
|
| 1186 |
+
}
|
| 1187 |
+
template<class T, typename std::enable_if_t<std::is_base_of<Vectorizedi, Vectorized<T>>::value, int> = 0>
|
| 1188 |
+
inline Vectorized<T> operator^(const Vectorized<T>& a, const Vectorized<T>& b) {
|
| 1189 |
+
return _mm256_xor_si256(a, b);
|
| 1190 |
+
}
|
| 1191 |
+
template<class T, typename std::enable_if_t<std::is_base_of<Vectorizedi, Vectorized<T>>::value, int> = 0>
|
| 1192 |
+
inline Vectorized<T> operator~(const Vectorized<T>& a) {
|
| 1193 |
+
return _mm256_xor_si256(a, _mm256_set1_epi32(-1));
|
| 1194 |
+
}
|
| 1195 |
+
|
| 1196 |
+
inline Vectorized<int64_t> Vectorized<int64_t>::eq(const Vectorized<int64_t>& other) const {
|
| 1197 |
+
return (*this == other) & Vectorized<int64_t>(1);
|
| 1198 |
+
}
|
| 1199 |
+
|
| 1200 |
+
inline Vectorized<int64_t> Vectorized<int64_t>::ne(const Vectorized<int64_t>& other) const {
|
| 1201 |
+
return (*this != other) & Vectorized<int64_t>(1);
|
| 1202 |
+
}
|
| 1203 |
+
|
| 1204 |
+
inline Vectorized<int64_t> Vectorized<int64_t>::gt(const Vectorized<int64_t>& other) const {
|
| 1205 |
+
return (*this > other) & Vectorized<int64_t>(1);
|
| 1206 |
+
}
|
| 1207 |
+
|
| 1208 |
+
inline Vectorized<int64_t> Vectorized<int64_t>::ge(const Vectorized<int64_t>& other) const {
|
| 1209 |
+
return (*this >= other) & Vectorized<int64_t>(1);
|
| 1210 |
+
}
|
| 1211 |
+
|
| 1212 |
+
inline Vectorized<int64_t> Vectorized<int64_t>::lt(const Vectorized<int64_t>& other) const {
|
| 1213 |
+
return (*this < other) & Vectorized<int64_t>(1);
|
| 1214 |
+
}
|
| 1215 |
+
|
| 1216 |
+
inline Vectorized<int64_t> Vectorized<int64_t>::le(const Vectorized<int64_t>& other) const {
|
| 1217 |
+
return (*this <= other) & Vectorized<int64_t>(1);
|
| 1218 |
+
}
|
| 1219 |
+
|
| 1220 |
+
inline Vectorized<int32_t> Vectorized<int32_t>::eq(const Vectorized<int32_t>& other) const {
|
| 1221 |
+
return (*this == other) & Vectorized<int32_t>(1);
|
| 1222 |
+
}
|
| 1223 |
+
|
| 1224 |
+
inline Vectorized<int32_t> Vectorized<int32_t>::ne(const Vectorized<int32_t>& other) const {
|
| 1225 |
+
return (*this != other) & Vectorized<int32_t>(1);
|
| 1226 |
+
}
|
| 1227 |
+
|
| 1228 |
+
inline Vectorized<int32_t> Vectorized<int32_t>::gt(const Vectorized<int32_t>& other) const {
|
| 1229 |
+
return (*this > other) & Vectorized<int32_t>(1);
|
| 1230 |
+
}
|
| 1231 |
+
|
| 1232 |
+
inline Vectorized<int32_t> Vectorized<int32_t>::ge(const Vectorized<int32_t>& other) const {
|
| 1233 |
+
return (*this >= other) & Vectorized<int32_t>(1);
|
| 1234 |
+
}
|
| 1235 |
+
|
| 1236 |
+
inline Vectorized<int32_t> Vectorized<int32_t>::lt(const Vectorized<int32_t>& other) const {
|
| 1237 |
+
return (*this < other) & Vectorized<int32_t>(1);
|
| 1238 |
+
}
|
| 1239 |
+
|
| 1240 |
+
inline Vectorized<int32_t> Vectorized<int32_t>::le(const Vectorized<int32_t>& other) const {
|
| 1241 |
+
return (*this <= other) & Vectorized<int32_t>(1);
|
| 1242 |
+
}
|
| 1243 |
+
|
| 1244 |
+
inline Vectorized<int16_t> Vectorized<int16_t>::eq(const Vectorized<int16_t>& other) const {
|
| 1245 |
+
return (*this == other) & Vectorized<int16_t>(1);
|
| 1246 |
+
}
|
| 1247 |
+
|
| 1248 |
+
inline Vectorized<int16_t> Vectorized<int16_t>::ne(const Vectorized<int16_t>& other) const {
|
| 1249 |
+
return (*this != other) & Vectorized<int16_t>(1);
|
| 1250 |
+
}
|
| 1251 |
+
|
| 1252 |
+
inline Vectorized<int16_t> Vectorized<int16_t>::gt(const Vectorized<int16_t>& other) const {
|
| 1253 |
+
return (*this > other) & Vectorized<int16_t>(1);
|
| 1254 |
+
}
|
| 1255 |
+
|
| 1256 |
+
inline Vectorized<int16_t> Vectorized<int16_t>::ge(const Vectorized<int16_t>& other) const {
|
| 1257 |
+
return (*this >= other) & Vectorized<int16_t>(1);
|
| 1258 |
+
}
|
| 1259 |
+
|
| 1260 |
+
inline Vectorized<int16_t> Vectorized<int16_t>::lt(const Vectorized<int16_t>& other) const {
|
| 1261 |
+
return (*this < other) & Vectorized<int16_t>(1);
|
| 1262 |
+
}
|
| 1263 |
+
|
| 1264 |
+
inline Vectorized<int16_t> Vectorized<int16_t>::le(const Vectorized<int16_t>& other) const {
|
| 1265 |
+
return (*this <= other) & Vectorized<int16_t>(1);
|
| 1266 |
+
}
|
| 1267 |
+
|
| 1268 |
+
inline Vectorized<int8_t> Vectorized<int8_t>::eq(const Vectorized<int8_t>& other) const {
|
| 1269 |
+
return (*this == other) & Vectorized<int8_t>(1);
|
| 1270 |
+
}
|
| 1271 |
+
|
| 1272 |
+
inline Vectorized<int8_t> Vectorized<int8_t>::ne(const Vectorized<int8_t>& other) const {
|
| 1273 |
+
return (*this != other) & Vectorized<int8_t>(1);
|
| 1274 |
+
}
|
| 1275 |
+
|
| 1276 |
+
inline Vectorized<int8_t> Vectorized<int8_t>::gt(const Vectorized<int8_t>& other) const {
|
| 1277 |
+
return (*this > other) & Vectorized<int8_t>(1);
|
| 1278 |
+
}
|
| 1279 |
+
|
| 1280 |
+
inline Vectorized<int8_t> Vectorized<int8_t>::ge(const Vectorized<int8_t>& other) const {
|
| 1281 |
+
return (*this >= other) & Vectorized<int8_t>(1);
|
| 1282 |
+
}
|
| 1283 |
+
|
| 1284 |
+
inline Vectorized<int8_t> Vectorized<int8_t>::lt(const Vectorized<int8_t>& other) const {
|
| 1285 |
+
return (*this < other) & Vectorized<int8_t>(1);
|
| 1286 |
+
}
|
| 1287 |
+
|
| 1288 |
+
inline Vectorized<int8_t> Vectorized<int8_t>::le(const Vectorized<int8_t>& other) const {
|
| 1289 |
+
return (*this <= other) & Vectorized<int8_t>(1);
|
| 1290 |
+
}
|
| 1291 |
+
|
| 1292 |
+
inline Vectorized<uint8_t> Vectorized<uint8_t>::eq(const Vectorized<uint8_t>& other) const {
|
| 1293 |
+
return (*this == other) & Vectorized<uint8_t>(1);
|
| 1294 |
+
}
|
| 1295 |
+
|
| 1296 |
+
inline Vectorized<uint8_t> Vectorized<uint8_t>::ne(const Vectorized<uint8_t>& other) const {
|
| 1297 |
+
return (*this != other) & Vectorized<uint8_t>(1);
|
| 1298 |
+
}
|
| 1299 |
+
|
| 1300 |
+
inline Vectorized<uint8_t> Vectorized<uint8_t>::gt(const Vectorized<uint8_t>& other) const {
|
| 1301 |
+
return (*this > other) & Vectorized<uint8_t>(1);
|
| 1302 |
+
}
|
| 1303 |
+
|
| 1304 |
+
inline Vectorized<uint8_t> Vectorized<uint8_t>::ge(const Vectorized<uint8_t>& other) const {
|
| 1305 |
+
return (*this >= other) & Vectorized<uint8_t>(1);
|
| 1306 |
+
}
|
| 1307 |
+
|
| 1308 |
+
inline Vectorized<uint8_t> Vectorized<uint8_t>::lt(const Vectorized<uint8_t>& other) const {
|
| 1309 |
+
return (*this < other) & Vectorized<uint8_t>(1);
|
| 1310 |
+
}
|
| 1311 |
+
|
| 1312 |
+
inline Vectorized<uint8_t> Vectorized<uint8_t>::le(const Vectorized<uint8_t>& other) const {
|
| 1313 |
+
return (*this <= other) & Vectorized<uint8_t>(1);
|
| 1314 |
+
}
|
| 1315 |
+
|
| 1316 |
+
template <bool left_shift>
|
| 1317 |
+
Vectorized<int16_t> inline shift_256_16(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 1318 |
+
// No vector instruction for shifting int16_t, so emulating it instead.
|
| 1319 |
+
|
| 1320 |
+
// Control masks for shuffle operation, treating 256 bits as an
|
| 1321 |
+
// array of 16-bit elements, and considering pairs of neighboring
|
| 1322 |
+
// elements. Specifially, a mask named "ctl_M_N" (M,N in [0,1], and
|
| 1323 |
+
// M!=N) is set so that shuffle will move element with index M from
|
| 1324 |
+
// input pair into element with index N in output pair, and element
|
| 1325 |
+
// with index M in output pair will be set to all 0s.
|
| 1326 |
+
__m256i ctl_0_1 = _mm256_set_epi8(29, 28, 0x80, 0x80, 25, 24, 0x80, 0x80,
|
| 1327 |
+
21, 20, 0x80, 0x80, 17, 16, 0x80, 0x80,
|
| 1328 |
+
13, 12, 0x80, 0x80, 9, 8, 0x80, 0x80,
|
| 1329 |
+
5, 4, 0x80, 0x80, 1, 0, 0x80, 0x80);
|
| 1330 |
+
__m256i ctl_1_0 = _mm256_set_epi8(0x80, 0x80, 31, 30, 0x80, 0x80, 27, 26,
|
| 1331 |
+
0x80, 0x80, 23, 22, 0x80, 0x80, 19, 18,
|
| 1332 |
+
0x80, 0x80, 15, 14, 0x80, 0x80, 11, 10,
|
| 1333 |
+
0x80, 0x80, 7, 6, 0x80, 0x80, 3, 2);
|
| 1334 |
+
|
| 1335 |
+
// Masks for bitwise and operation, treating 256 bits as an array of
|
| 1336 |
+
// 16-bit elements, and considering them in pairs of neighboring
|
| 1337 |
+
// elements. A mask named "keep_M" (M in [0,1]) is set so that
|
| 1338 |
+
// bitwise and will copy element with index M from input pair into
|
| 1339 |
+
// element with the same index in output pair, while the other
|
| 1340 |
+
// element in output pair will be set to all 0s.
|
| 1341 |
+
__m256i keep_0 = _mm256_set1_epi32(0xFFFF);
|
| 1342 |
+
__m256i keep_1 = _mm256_set1_epi32(0xFFFF0000);
|
| 1343 |
+
|
| 1344 |
+
// Take each 16-bit element with idx%2==0 from input array to be
|
| 1345 |
+
// shifted and extend it to 32 bits so that 0s are added to the
|
| 1346 |
+
// right. Then, perform shifting on this 32-bit number. Upper 16
|
| 1347 |
+
// bits will be proper result of shifting original 16-bit number, so
|
| 1348 |
+
// write them to result array, into the same position from which
|
| 1349 |
+
// corresponding input element is taken. Also, make sure that
|
| 1350 |
+
// result array elements with idx%2!=0 are set to all 0s.
|
| 1351 |
+
//
|
| 1352 |
+
// Note that number of bits to shift for is extended to 32 bits by
|
| 1353 |
+
// adding 0s to the left. That means this number is not properly
|
| 1354 |
+
// sign-extended for negative values. However, number of bits to
|
| 1355 |
+
// shift is treated as an unsigned integer by respective shift
|
| 1356 |
+
// intrinsics anyway so if negative then either with or without
|
| 1357 |
+
// proper sign extension, it will be interpreted as a number greater
|
| 1358 |
+
// than 32, and the shifting result will be the same.
|
| 1359 |
+
__m256i a0 = _mm256_shuffle_epi8(a, ctl_0_1);
|
| 1360 |
+
__m256i b0 = _mm256_and_si256(b, keep_0);
|
| 1361 |
+
__m256i c0;
|
| 1362 |
+
if (left_shift)
|
| 1363 |
+
c0 = _mm256_sllv_epi32(a0, b0);
|
| 1364 |
+
else
|
| 1365 |
+
c0 = _mm256_srav_epi32(a0, b0);
|
| 1366 |
+
c0 = _mm256_shuffle_epi8(c0, ctl_1_0);
|
| 1367 |
+
|
| 1368 |
+
// Peform shifting the same way for input array elements with
|
| 1369 |
+
// idx%2==1.
|
| 1370 |
+
__m256i a1 = _mm256_and_si256(a, keep_1);
|
| 1371 |
+
__m256i b1 = _mm256_shuffle_epi8(b, ctl_1_0);
|
| 1372 |
+
__m256i c1;
|
| 1373 |
+
if (left_shift)
|
| 1374 |
+
c1 = _mm256_sllv_epi32(a1, b1);
|
| 1375 |
+
else
|
| 1376 |
+
c1 = _mm256_srav_epi32(a1, b1);
|
| 1377 |
+
c1 = _mm256_and_si256(c1, keep_1);
|
| 1378 |
+
|
| 1379 |
+
// Merge partial results into the final result.
|
| 1380 |
+
__m256i c = _mm256_or_si256(c0, c1);
|
| 1381 |
+
|
| 1382 |
+
return c;
|
| 1383 |
+
}
|
| 1384 |
+
|
| 1385 |
+
template <bool left_shift, typename T, typename std::enable_if_t<std::is_same_v<T, int8_t> || std::is_same_v<T, uint8_t>, int> = 0>
|
| 1386 |
+
Vectorized<T> inline shift_256_8(const Vectorized<T>& a, const Vectorized<T>& b) {
|
| 1387 |
+
// No vector instruction for shifting int8_t/uint8_t, so emulating
|
| 1388 |
+
// it instead.
|
| 1389 |
+
|
| 1390 |
+
// Control masks for shuffle operation, treating 256 bits as an
|
| 1391 |
+
// array of 8-bit elements, and considering quadruples of
|
| 1392 |
+
// neighboring elements. Specifially, a mask named "ctl_M_N" (M,N
|
| 1393 |
+
// in [0,1,2,3], and M!=N) is set so that shuffle will move element
|
| 1394 |
+
// with index M from input quadruple into element with index N in
|
| 1395 |
+
// output quadruple, and other elements in output quadruple will be
|
| 1396 |
+
// set to all 0s.
|
| 1397 |
+
__m256i ctl_0_3 = _mm256_set_epi8(28, 0x80, 0x80, 0x80, 24, 0x80, 0x80, 0x80,
|
| 1398 |
+
20, 0x80, 0x80, 0x80, 16, 0x80, 0x80, 0x80,
|
| 1399 |
+
12, 0x80, 0x80, 0x80, 8, 0x80, 0x80, 0x80,
|
| 1400 |
+
4, 0x80, 0x80, 0x80, 0, 0x80, 0x80, 0x80);
|
| 1401 |
+
__m256i ctl_1_0 = _mm256_set_epi8(0x80, 0x80, 0x80, 29, 0x80, 0x80, 0x80, 25,
|
| 1402 |
+
0x80, 0x80, 0x80, 21, 0x80, 0x80, 0x80, 17,
|
| 1403 |
+
0x80, 0x80, 0x80, 13, 0x80, 0x80, 0x80, 9,
|
| 1404 |
+
0x80, 0x80, 0x80, 5, 0x80, 0x80, 0x80, 1);
|
| 1405 |
+
__m256i ctl_1_3 = _mm256_set_epi8(29, 0x80, 0x80, 0x80, 25, 0x80, 0x80, 0x80,
|
| 1406 |
+
21, 0x80, 0x80, 0x80, 17, 0x80, 0x80, 0x80,
|
| 1407 |
+
13, 0x80, 0x80, 0x80, 9, 0x80, 0x80, 0x80,
|
| 1408 |
+
5, 0x80, 0x80, 0x80, 1, 0x80, 0x80, 0x80);
|
| 1409 |
+
__m256i ctl_2_0 = _mm256_set_epi8(0x80, 0x80, 0x80, 30, 0x80, 0x80, 0x80, 26,
|
| 1410 |
+
0x80, 0x80, 0x80, 22, 0x80, 0x80, 0x80, 18,
|
| 1411 |
+
0x80, 0x80, 0x80, 14, 0x80, 0x80, 0x80, 10,
|
| 1412 |
+
0x80, 0x80, 0x80, 6, 0x80, 0x80, 0x80, 2);
|
| 1413 |
+
__m256i ctl_2_3 = _mm256_set_epi8(30, 0x80, 0x80, 0x80, 26, 0x80, 0x80, 0x80,
|
| 1414 |
+
22, 0x80, 0x80, 0x80, 18, 0x80, 0x80, 0x80,
|
| 1415 |
+
14, 0x80, 0x80, 0x80, 10, 0x80, 0x80, 0x80,
|
| 1416 |
+
6, 0x80, 0x80, 0x80, 2, 0x80, 0x80, 0x80);
|
| 1417 |
+
__m256i ctl_3_0 = _mm256_set_epi8(0x80, 0x80, 0x80, 31, 0x80, 0x80, 0x80, 27,
|
| 1418 |
+
0x80, 0x80, 0x80, 23, 0x80, 0x80, 0x80, 19,
|
| 1419 |
+
0x80, 0x80, 0x80, 15, 0x80, 0x80, 0x80, 11,
|
| 1420 |
+
0x80, 0x80, 0x80, 7, 0x80, 0x80, 0x80, 3);
|
| 1421 |
+
__m256i ctl_3_1 = _mm256_set_epi8(0x80, 0x80, 31, 0x80, 0x80, 0x80, 27, 0x80,
|
| 1422 |
+
0x80, 0x80, 23, 0x80, 0x80, 0x80, 19, 0x80,
|
| 1423 |
+
0x80, 0x80, 15, 0x80, 0x80, 0x80, 11, 0x80,
|
| 1424 |
+
0x80, 0x80, 7, 0x80, 0x80, 0x80, 3, 0x80);
|
| 1425 |
+
__m256i ctl_3_2 = _mm256_set_epi8(0x80, 31, 0x80, 0x80, 0x80, 27, 0x80, 0x80,
|
| 1426 |
+
0x80, 23, 0x80, 0x80, 0x80, 19, 0x80, 0x80,
|
| 1427 |
+
0x80, 15, 0x80, 0x80, 0x80, 11, 0x80, 0x80,
|
| 1428 |
+
0x80, 7, 0x80, 0x80, 0x80, 3, 0x80, 0x80);
|
| 1429 |
+
|
| 1430 |
+
// Masks for bitwise and operation, treating 256 bits as an array of
|
| 1431 |
+
// 8-bit elements, and considering them in quadruples of neighboring
|
| 1432 |
+
// elements. A mask named "keep_M" (M in [0,1,2,3]) is set so that
|
| 1433 |
+
// bitwise and will copy element with index M from input quadruple
|
| 1434 |
+
// into element with the same index in output quadruple, while the
|
| 1435 |
+
// other elements in output quadruple will be set to all 0s.
|
| 1436 |
+
__m256i keep_0 = _mm256_set1_epi32(0xFF);
|
| 1437 |
+
__m256i keep_3 = _mm256_set1_epi32(0xFF000000);
|
| 1438 |
+
|
| 1439 |
+
// Take each 8-bit element with idx%4==0 from input array to be
|
| 1440 |
+
// shifted and extend it to 32 bits so that 0s are added to the
|
| 1441 |
+
// right. Then, perform shifting on this 32-bit number. Upper 8
|
| 1442 |
+
// bits will be proper result of shifting original 8-bit number, so
|
| 1443 |
+
// write them to result array, into the same position from which
|
| 1444 |
+
// corresponding input element is taken. Also, make sure that
|
| 1445 |
+
// result array elements with idx%4!=0 are set to all 0s.
|
| 1446 |
+
//
|
| 1447 |
+
// Note that number of bits to shift for is extended to 32 bits by
|
| 1448 |
+
// adding 0s to the left. That means this number is not properly
|
| 1449 |
+
// sign-extended for negative values. However, number of bits to
|
| 1450 |
+
// shift is treated as an unsigned integer by respective shift
|
| 1451 |
+
// intrinsics anyway so if negative then either with or without
|
| 1452 |
+
// proper sign extension, it will be interpreted as a number greater
|
| 1453 |
+
// than 32, and the shifting result will be the same.
|
| 1454 |
+
__m256i a0 = _mm256_shuffle_epi8(a, ctl_0_3);
|
| 1455 |
+
__m256i b0 = _mm256_and_si256(b, keep_0);
|
| 1456 |
+
__m256i c0;
|
| 1457 |
+
if (left_shift)
|
| 1458 |
+
c0 = _mm256_sllv_epi32(a0, b0);
|
| 1459 |
+
else
|
| 1460 |
+
if constexpr (std::is_same_v<T, int8_t>)
|
| 1461 |
+
c0 = _mm256_srav_epi32(a0, b0);
|
| 1462 |
+
else
|
| 1463 |
+
c0 = _mm256_srlv_epi32(a0, b0);
|
| 1464 |
+
c0 = _mm256_shuffle_epi8(c0, ctl_3_0);
|
| 1465 |
+
|
| 1466 |
+
// Peform shifting the same way for input array elements with
|
| 1467 |
+
// idx%4==1.
|
| 1468 |
+
__m256i a1 = _mm256_shuffle_epi8(a, ctl_1_3);
|
| 1469 |
+
__m256i b1 = _mm256_shuffle_epi8(b, ctl_1_0);
|
| 1470 |
+
__m256i c1;
|
| 1471 |
+
if (left_shift)
|
| 1472 |
+
c1 = _mm256_sllv_epi32(a1, b1);
|
| 1473 |
+
else
|
| 1474 |
+
if constexpr (std::is_same_v<T, int8_t>)
|
| 1475 |
+
c1 = _mm256_srav_epi32(a1, b1);
|
| 1476 |
+
else
|
| 1477 |
+
c1 = _mm256_srlv_epi32(a1, b1);
|
| 1478 |
+
c1 = _mm256_shuffle_epi8(c1, ctl_3_1);
|
| 1479 |
+
|
| 1480 |
+
// Peform shifting the same way for input array elements with
|
| 1481 |
+
// idx%4==2.
|
| 1482 |
+
__m256i a2 = _mm256_shuffle_epi8(a, ctl_2_3);
|
| 1483 |
+
__m256i b2 = _mm256_shuffle_epi8(b, ctl_2_0);
|
| 1484 |
+
__m256i c2;
|
| 1485 |
+
if (left_shift)
|
| 1486 |
+
c2 = _mm256_sllv_epi32(a2, b2);
|
| 1487 |
+
else
|
| 1488 |
+
if constexpr (std::is_same_v<T, int8_t>)
|
| 1489 |
+
c2 = _mm256_srav_epi32(a2, b2);
|
| 1490 |
+
else
|
| 1491 |
+
c2 = _mm256_srlv_epi32(a2, b2);
|
| 1492 |
+
c2 = _mm256_shuffle_epi8(c2, ctl_3_2);
|
| 1493 |
+
|
| 1494 |
+
// Peform shifting the same way for input array elements with
|
| 1495 |
+
// idx%4==3.
|
| 1496 |
+
__m256i a3 = _mm256_and_si256(a, keep_3);
|
| 1497 |
+
__m256i b3 = _mm256_shuffle_epi8(b, ctl_3_0);
|
| 1498 |
+
__m256i c3;
|
| 1499 |
+
if (left_shift)
|
| 1500 |
+
c3 = _mm256_sllv_epi32(a3, b3);
|
| 1501 |
+
else
|
| 1502 |
+
if constexpr (std::is_same_v<T, int8_t>)
|
| 1503 |
+
c3 = _mm256_srav_epi32(a3, b3);
|
| 1504 |
+
else
|
| 1505 |
+
c3 = _mm256_srlv_epi32(a3, b3);
|
| 1506 |
+
c3 = _mm256_and_si256(c3, keep_3);
|
| 1507 |
+
|
| 1508 |
+
// Merge partial results into the final result.
|
| 1509 |
+
__m256i c01 = _mm256_or_si256(c0, c1);
|
| 1510 |
+
__m256i c23 = _mm256_or_si256(c2, c3);
|
| 1511 |
+
__m256i c = _mm256_or_si256(c01, c23);
|
| 1512 |
+
|
| 1513 |
+
return c;
|
| 1514 |
+
}
|
| 1515 |
+
|
| 1516 |
+
template <>
|
| 1517 |
+
Vectorized<int64_t> inline operator<<(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 1518 |
+
return _mm256_sllv_epi64(a, b);
|
| 1519 |
+
}
|
| 1520 |
+
|
| 1521 |
+
template <>
|
| 1522 |
+
Vectorized<int32_t> inline operator<<(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 1523 |
+
return _mm256_sllv_epi32(a, b);
|
| 1524 |
+
}
|
| 1525 |
+
|
| 1526 |
+
template <>
|
| 1527 |
+
Vectorized<int16_t> inline operator<<(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 1528 |
+
return shift_256_16<true>(a, b);
|
| 1529 |
+
}
|
| 1530 |
+
|
| 1531 |
+
template <>
|
| 1532 |
+
Vectorized<int8_t> inline operator<<(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 1533 |
+
return shift_256_8<true>(a, b);
|
| 1534 |
+
}
|
| 1535 |
+
|
| 1536 |
+
template <>
|
| 1537 |
+
Vectorized<uint8_t> inline operator<<(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& b) {
|
| 1538 |
+
return shift_256_8<true>(a, b);
|
| 1539 |
+
}
|
| 1540 |
+
|
| 1541 |
+
template <>
|
| 1542 |
+
Vectorized<int64_t> inline operator>>(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 1543 |
+
// No vector instruction for right arithmetic shifting int64_t, so emulating it
|
| 1544 |
+
// instead.
|
| 1545 |
+
|
| 1546 |
+
// Clamp the shift values such that shift values < 0 and > 64 are changed to 64
|
| 1547 |
+
// which results in -1 for negative input and 0 for non-negative input.
|
| 1548 |
+
__m256i zero = _mm256_set1_epi64x(0);
|
| 1549 |
+
__m256i max_shift = _mm256_set1_epi64x(64);
|
| 1550 |
+
__m256i mask = _mm256_or_si256(_mm256_cmpgt_epi64(zero, b), _mm256_cmpgt_epi64(b, max_shift));
|
| 1551 |
+
__m256i shift = _mm256_blendv_epi8(b, max_shift, mask);
|
| 1552 |
+
// Shift the number logically to the right, thus filling the most
|
| 1553 |
+
// significant bits with 0s. Then, replace these bits with the sign
|
| 1554 |
+
// bit.
|
| 1555 |
+
__m256i sign_bits = _mm256_cmpgt_epi64(zero, a);
|
| 1556 |
+
__m256i sign_shift = _mm256_sub_epi64(max_shift, shift);
|
| 1557 |
+
__m256i sign_ext = _mm256_sllv_epi64(sign_bits, sign_shift);
|
| 1558 |
+
__m256i c = _mm256_srlv_epi64(a, shift);
|
| 1559 |
+
c = _mm256_or_si256(c, sign_ext);
|
| 1560 |
+
|
| 1561 |
+
return c;
|
| 1562 |
+
}
|
| 1563 |
+
|
| 1564 |
+
template <>
|
| 1565 |
+
Vectorized<int32_t> inline operator>>(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 1566 |
+
return _mm256_srav_epi32(a, b);
|
| 1567 |
+
}
|
| 1568 |
+
|
| 1569 |
+
template <>
|
| 1570 |
+
Vectorized<int16_t> inline operator>>(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 1571 |
+
return shift_256_16<false>(a, b);
|
| 1572 |
+
}
|
| 1573 |
+
|
| 1574 |
+
template <>
|
| 1575 |
+
Vectorized<int8_t> inline operator>>(const Vectorized<int8_t>& a, const Vectorized<int8_t>& b) {
|
| 1576 |
+
return shift_256_8<false>(a, b);
|
| 1577 |
+
}
|
| 1578 |
+
|
| 1579 |
+
template <>
|
| 1580 |
+
Vectorized<uint8_t> inline operator>>(const Vectorized<uint8_t>& a, const Vectorized<uint8_t>& b) {
|
| 1581 |
+
return shift_256_8<false>(a, b);
|
| 1582 |
+
}
|
| 1583 |
+
|
| 1584 |
+
#endif
|
| 1585 |
+
|
| 1586 |
+
}} // namespace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_mask.h
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec_mask.h>
|
| 6 |
+
|
| 7 |
+
namespace at::vec {
|
| 8 |
+
inline namespace CPU_CAPABILITY {
|
| 9 |
+
|
| 10 |
+
#if defined(CPU_CAPABILITY_AVX2) && !defined(_MSC_VER)
|
| 11 |
+
|
| 12 |
+
template <typename T, int dst_n, typename mask_t, int mask_n>
|
| 13 |
+
struct VecMaskLoad<
|
| 14 |
+
T,
|
| 15 |
+
dst_n,
|
| 16 |
+
mask_t,
|
| 17 |
+
mask_n,
|
| 18 |
+
typename std::enable_if_t<
|
| 19 |
+
(mask_n == dst_n * 2 && dst_n >= 1) &&
|
| 20 |
+
(std::is_same_v<T, float> || std::is_same_v<T, int32_t>),
|
| 21 |
+
void>> {
|
| 22 |
+
static inline VectorizedN<T, dst_n> apply(
|
| 23 |
+
const T* ptr,
|
| 24 |
+
const VecMask<mask_t, mask_n>& vec_mask) {
|
| 25 |
+
VectorizedN<mask_t, 2> tmp_vec;
|
| 26 |
+
VectorizedN<T, dst_n> result;
|
| 27 |
+
for (int i = 0; i < dst_n; i++) {
|
| 28 |
+
tmp_vec[0] = vec_mask[2 * i];
|
| 29 |
+
tmp_vec[1] = vec_mask[2 * i + 1];
|
| 30 |
+
auto int64_mask = VecMask<mask_t, 2>(tmp_vec).template cast<int64_t, 2>();
|
| 31 |
+
auto int_mask = int64_mask.template cast<int, 1>()[0];
|
| 32 |
+
if constexpr (std::is_same_v<T, float>) {
|
| 33 |
+
result[i] = Vectorized<T>(
|
| 34 |
+
_mm256_maskload_ps(ptr + i * Vectorized<T>::size(), int_mask));
|
| 35 |
+
} else {
|
| 36 |
+
result[i] = Vectorized<T>(
|
| 37 |
+
_mm256_maskload_epi32(ptr + i * Vectorized<T>::size(), int_mask));
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
return result;
|
| 41 |
+
}
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
template <typename T, int dst_n, typename mask_t>
|
| 45 |
+
struct VecMaskLoad<
|
| 46 |
+
T,
|
| 47 |
+
dst_n,
|
| 48 |
+
mask_t,
|
| 49 |
+
dst_n,
|
| 50 |
+
typename std::enable_if_t<
|
| 51 |
+
std::is_same_v<T, float> || std::is_same_v<T, int32_t>,
|
| 52 |
+
void>> {
|
| 53 |
+
static inline VectorizedN<T, dst_n> apply(
|
| 54 |
+
const T* ptr,
|
| 55 |
+
const VecMask<mask_t, dst_n>& vec_mask) {
|
| 56 |
+
VectorizedN<T, dst_n> result;
|
| 57 |
+
#ifndef _MSC_VER
|
| 58 |
+
#pragma unroll
|
| 59 |
+
#endif
|
| 60 |
+
for (int i = 0; i < dst_n; i++) {
|
| 61 |
+
auto tmp_mask = VecMask<mask_t, 1>(vec_mask[i]);
|
| 62 |
+
auto int_mask = tmp_mask.template cast<int, 1>()[0];
|
| 63 |
+
if constexpr (std::is_same_v<T, float>) {
|
| 64 |
+
result[i] = Vectorized<T>(
|
| 65 |
+
_mm256_maskload_ps(ptr + i * Vectorized<T>::size(), int_mask));
|
| 66 |
+
} else {
|
| 67 |
+
result[i] = Vectorized<T>(
|
| 68 |
+
_mm256_maskload_epi32(ptr + i * Vectorized<T>::size(), int_mask));
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
return result;
|
| 72 |
+
}
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
template <typename T, typename mask_t>
|
| 76 |
+
struct VecMaskLoad<
|
| 77 |
+
T,
|
| 78 |
+
2,
|
| 79 |
+
mask_t,
|
| 80 |
+
1,
|
| 81 |
+
typename std::enable_if_t<
|
| 82 |
+
std::is_same_v<T, int64_t> || std::is_same_v<T, double>>> {
|
| 83 |
+
static inline VectorizedN<T, 2> apply(
|
| 84 |
+
const T* ptr,
|
| 85 |
+
const VecMask<mask_t, 1>& vec_mask) {
|
| 86 |
+
auto int64_mask = vec_mask.template cast<int64_t, 2>();
|
| 87 |
+
auto result = at::vec::VectorizedN<T, 2>();
|
| 88 |
+
if constexpr (std::is_same_v<T, double>) {
|
| 89 |
+
result[0] = _mm256_maskload_pd(ptr, int64_mask[0]);
|
| 90 |
+
result[1] = _mm256_maskload_pd(
|
| 91 |
+
ptr + at::vec::Vectorized<T>::size(), int64_mask[1]);
|
| 92 |
+
} else {
|
| 93 |
+
result[0] = _mm256_maskload_epi64(
|
| 94 |
+
reinterpret_cast<const long long*>(ptr), int64_mask[0]);
|
| 95 |
+
result[1] = _mm256_maskload_epi64(
|
| 96 |
+
reinterpret_cast<const long long*>(
|
| 97 |
+
ptr + at::vec::Vectorized<T>::size()),
|
| 98 |
+
int64_mask[1]);
|
| 99 |
+
}
|
| 100 |
+
return result;
|
| 101 |
+
}
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
// TODO: add specialization of VecMaskLoad for bfloat16/half and int8/uint8
|
| 105 |
+
|
| 106 |
+
template <int N>
|
| 107 |
+
struct VecMaskCast<float, N, int, N> {
|
| 108 |
+
static inline VecMask<float, N> apply(const VecMask<int, N>& vec_mask) {
|
| 109 |
+
VectorizedN<float, N> result;
|
| 110 |
+
#ifndef _MSC_VER
|
| 111 |
+
#pragma unroll
|
| 112 |
+
#endif
|
| 113 |
+
for (int i = 0; i < N; ++i) {
|
| 114 |
+
result[i] = _mm256_castsi256_ps(vec_mask[i]);
|
| 115 |
+
}
|
| 116 |
+
return result;
|
| 117 |
+
}
|
| 118 |
+
};
|
| 119 |
+
|
| 120 |
+
template <int N>
|
| 121 |
+
struct VecMaskCast<int, N, float, N> {
|
| 122 |
+
static inline VecMask<int, N> apply(const VecMask<float, N>& vec_mask) {
|
| 123 |
+
VectorizedN<int, N> result;
|
| 124 |
+
#ifndef _MSC_VER
|
| 125 |
+
#pragma unroll
|
| 126 |
+
#endif
|
| 127 |
+
for (int i = 0; i < N; ++i) {
|
| 128 |
+
result[i] = _mm256_castps_si256(vec_mask[i]);
|
| 129 |
+
}
|
| 130 |
+
return result;
|
| 131 |
+
}
|
| 132 |
+
};
|
| 133 |
+
|
| 134 |
+
template <int N>
|
| 135 |
+
struct VecMaskCast<int64_t, N, double, N> {
|
| 136 |
+
static inline VecMask<int64_t, N> apply(const VecMask<double, N>& vec_mask) {
|
| 137 |
+
VectorizedN<int64_t, N> result;
|
| 138 |
+
#ifndef _MSC_VER
|
| 139 |
+
#pragma unroll
|
| 140 |
+
#endif
|
| 141 |
+
for (int i = 0; i < N; ++i) {
|
| 142 |
+
result[i] = _mm256_castpd_si256(vec_mask[i]);
|
| 143 |
+
}
|
| 144 |
+
return result;
|
| 145 |
+
}
|
| 146 |
+
};
|
| 147 |
+
|
| 148 |
+
template <int N>
|
| 149 |
+
struct VecMaskCast<double, N, int64_t, N> {
|
| 150 |
+
static inline VecMask<double, N> apply(const VecMask<int64_t, N>& vec_mask) {
|
| 151 |
+
VectorizedN<double, N> result;
|
| 152 |
+
#ifndef _MSC_VER
|
| 153 |
+
#pragma unroll
|
| 154 |
+
#endif
|
| 155 |
+
for (int i = 0; i < N; ++i) {
|
| 156 |
+
result[i] = _mm256_castsi256_pd(vec_mask[i]);
|
| 157 |
+
}
|
| 158 |
+
return result;
|
| 159 |
+
}
|
| 160 |
+
};
|
| 161 |
+
|
| 162 |
+
template <int dst_n, typename mask_t, int mask_n>
|
| 163 |
+
struct VecMaskCast<
|
| 164 |
+
int64_t,
|
| 165 |
+
dst_n,
|
| 166 |
+
mask_t,
|
| 167 |
+
mask_n,
|
| 168 |
+
typename std::enable_if_t<
|
| 169 |
+
(dst_n == 2 * mask_n) &&
|
| 170 |
+
(std::is_same_v<mask_t, float> || std::is_same_v<mask_t, int>),
|
| 171 |
+
void>> {
|
| 172 |
+
static inline VecMask<int64_t, dst_n> apply(
|
| 173 |
+
const VecMask<mask_t, mask_n>& vec_mask) {
|
| 174 |
+
VectorizedN<int64_t, dst_n> result;
|
| 175 |
+
auto int_mask = vec_mask.template cast<int, mask_n>();
|
| 176 |
+
#ifndef _MSC_VER
|
| 177 |
+
#pragma unroll
|
| 178 |
+
#endif
|
| 179 |
+
for (int i = 0; i < mask_n; ++i) {
|
| 180 |
+
auto int64_vec =
|
| 181 |
+
convert<int64_t, 2, int, 1>(VectorizedN<int, 1>(int_mask[i]));
|
| 182 |
+
result[2 * i] = int64_vec[0];
|
| 183 |
+
result[2 * i + 1] = int64_vec[1];
|
| 184 |
+
}
|
| 185 |
+
return VecMask<int64_t, dst_n>(result);
|
| 186 |
+
}
|
| 187 |
+
};
|
| 188 |
+
|
| 189 |
+
template <typename dst_t, int dst_n, int mask_n>
|
| 190 |
+
struct VecMaskCast<
|
| 191 |
+
dst_t,
|
| 192 |
+
dst_n,
|
| 193 |
+
int64_t,
|
| 194 |
+
mask_n,
|
| 195 |
+
typename std::enable_if_t<
|
| 196 |
+
(mask_n == 2 * dst_n) &&
|
| 197 |
+
(std::is_same_v<dst_t, float> || std::is_same_v<dst_t, int>),
|
| 198 |
+
void>> {
|
| 199 |
+
static inline VecMask<dst_t, dst_n> apply(
|
| 200 |
+
const VecMask<int64_t, mask_n>& vec_mask) {
|
| 201 |
+
VectorizedN<int, dst_n> result;
|
| 202 |
+
VectorizedN<int64_t, 2> int64_vec;
|
| 203 |
+
for (int i = 0; i < dst_n; ++i) {
|
| 204 |
+
int64_vec[0] = vec_mask[2 * i];
|
| 205 |
+
int64_vec[1] = vec_mask[2 * i + 1];
|
| 206 |
+
result[i] = convert<int, 1, int64_t, 2>(int64_vec);
|
| 207 |
+
}
|
| 208 |
+
return VecMask<int, dst_n>(result).template cast<dst_t, dst_n>();
|
| 209 |
+
}
|
| 210 |
+
};
|
| 211 |
+
|
| 212 |
+
template <>
|
| 213 |
+
struct VecMaskCast<double, 2, float, 1> {
|
| 214 |
+
static inline VecMask<double, 2> apply(const VecMask<float, 1>& vec_mask) {
|
| 215 |
+
auto int64_mask = VecMaskCast<int64_t, 2, float, 1>::apply(vec_mask);
|
| 216 |
+
return VecMaskCast<double, 2, int64_t, 2>::apply(int64_mask);
|
| 217 |
+
}
|
| 218 |
+
};
|
| 219 |
+
template <>
|
| 220 |
+
struct VecMaskCast<float, 1, double, 2> {
|
| 221 |
+
static inline VecMask<float, 1> apply(const VecMask<double, 2>& vec_mask) {
|
| 222 |
+
auto int64_mask = VecMaskCast<int64_t, 2, double, 2>::apply(vec_mask);
|
| 223 |
+
return VecMaskCast<float, 1, int64_t, 2>::apply(int64_mask);
|
| 224 |
+
}
|
| 225 |
+
};
|
| 226 |
+
|
| 227 |
+
template <>
|
| 228 |
+
inline bool VecMask<int, 1>::all_zero() const {
|
| 229 |
+
return _mm256_testz_si256(mask_[0], mask_[0]);
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
template <>
|
| 233 |
+
inline bool VecMask<int, 1>::is_masked(int i) const {
|
| 234 |
+
return _mm256_movemask_ps(_mm256_castsi256_ps(mask_[0])) & (1 << i);
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
template <>
|
| 238 |
+
inline bool VecMask<int, 1>::all_masked() const {
|
| 239 |
+
int mask = _mm256_movemask_ps(_mm256_castsi256_ps(mask_[0]));
|
| 240 |
+
return mask == 0xff;
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
template <int N>
|
| 244 |
+
struct VecMaskCheck<int64_t, N> {
|
| 245 |
+
static inline bool all_zero(const VectorizedN<int64_t, N>& vec_mask) {
|
| 246 |
+
bool all_zero = true;
|
| 247 |
+
for (int i = 0; i < N; ++i) {
|
| 248 |
+
all_zero = all_zero && (_mm256_testz_si256(vec_mask[i], vec_mask[i]) > 0);
|
| 249 |
+
if (!all_zero) {
|
| 250 |
+
return all_zero;
|
| 251 |
+
}
|
| 252 |
+
}
|
| 253 |
+
return all_zero;
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
static inline bool is_masked(const VectorizedN<int64_t, N>& vec_mask, int i) {
|
| 257 |
+
for (int j = 0; j < N; ++j) {
|
| 258 |
+
if (i < (j + 1) * 4) {
|
| 259 |
+
return _mm256_movemask_pd(_mm256_castsi256_pd(vec_mask[j])) &
|
| 260 |
+
(1 << (i - j * 4));
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
return false;
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
static inline bool all_masked(const VectorizedN<int64_t, N>& vec_mask) {
|
| 267 |
+
bool all_masked = true;
|
| 268 |
+
for (int i = 0; i < N; ++i) {
|
| 269 |
+
all_masked = all_masked &&
|
| 270 |
+
(_mm256_movemask_pd(_mm256_castsi256_pd(vec_mask[i])) == 0x0f);
|
| 271 |
+
if (!all_masked) {
|
| 272 |
+
return all_masked;
|
| 273 |
+
}
|
| 274 |
+
}
|
| 275 |
+
return all_masked;
|
| 276 |
+
}
|
| 277 |
+
};
|
| 278 |
+
|
| 279 |
+
#define VEC_MASK_METHOD_WITH_CAST_TO_INT( \
|
| 280 |
+
T, N, return_type, method, args_def, args) \
|
| 281 |
+
template <> \
|
| 282 |
+
inline return_type VecMask<T, N>::method args_def const { \
|
| 283 |
+
return cast<int, 1>().method args; \
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
VEC_MASK_METHOD_WITH_CAST_TO_INT(float, 1, bool, all_zero, (), ())
|
| 287 |
+
VEC_MASK_METHOD_WITH_CAST_TO_INT(int64_t, 2, bool, all_zero, (), ())
|
| 288 |
+
VEC_MASK_METHOD_WITH_CAST_TO_INT(float, 1, bool, is_masked, (int i), (i))
|
| 289 |
+
VEC_MASK_METHOD_WITH_CAST_TO_INT(int64_t, 2, bool, is_masked, (int i), (i))
|
| 290 |
+
VEC_MASK_METHOD_WITH_CAST_TO_INT(float, 1, bool, all_masked, (), ())
|
| 291 |
+
VEC_MASK_METHOD_WITH_CAST_TO_INT(int64_t, 2, bool, all_masked, (), ())
|
| 292 |
+
|
| 293 |
+
#undef VEC_MASK_DEFINE_METHOD_WITH_CAST_TO_INT
|
| 294 |
+
|
| 295 |
+
#endif
|
| 296 |
+
|
| 297 |
+
} // namespace CPU_CAPABILITY
|
| 298 |
+
} // namespace at::vec
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_qint.h
ADDED
|
@@ -0,0 +1,1334 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <ATen/native/quantized/AffineQuantizerBase.h>
|
| 9 |
+
|
| 10 |
+
#include <c10/util/irange.h>
|
| 11 |
+
#include <c10/util/qint32.h>
|
| 12 |
+
#include <c10/util/qint8.h>
|
| 13 |
+
#include <c10/util/quint8.h>
|
| 14 |
+
|
| 15 |
+
#include <array>
|
| 16 |
+
#include <cmath>
|
| 17 |
+
|
| 18 |
+
// This file defines Vectorized<> for the quantized types.
|
| 19 |
+
//
|
| 20 |
+
//
|
| 21 |
+
// Currently, we simply use these classes as efficient converters between
|
| 22 |
+
// the quantized types and Vectorized<float>, usually in bandwidth-bound cases
|
| 23 |
+
// where doing the arithmetic in full-precision is acceptable (e.g.
|
| 24 |
+
// elementwise operators).
|
| 25 |
+
//
|
| 26 |
+
//
|
| 27 |
+
// Conversions are as follows:
|
| 28 |
+
// Vectorized<qint8> -> 4x Vectorized<float>
|
| 29 |
+
// Vectorized<quint8> -> 4x Vectorized<float>
|
| 30 |
+
// Vectorized<qint32> -> 1x Vectorized<float>
|
| 31 |
+
//
|
| 32 |
+
// The size of the returned float vector is specified by the special
|
| 33 |
+
// constexpr function float_num_vecs. The type of the value returned
|
| 34 |
+
// from dequantize (and expected as an argument to quantize) is
|
| 35 |
+
// specified by float_vec_return_type.
|
| 36 |
+
//
|
| 37 |
+
// When writing kernels with these vectors, it is expected that floating-
|
| 38 |
+
// point operations will be carried out in a loop over Vectorized<T>::float_num_vecs
|
| 39 |
+
// iterations.
|
| 40 |
+
|
| 41 |
+
namespace at::vec {
|
| 42 |
+
inline namespace CPU_CAPABILITY {
|
| 43 |
+
|
| 44 |
+
#if defined(CPU_CAPABILITY_AVX2)
|
| 45 |
+
|
| 46 |
+
#ifdef _MSC_VER
|
| 47 |
+
__declspec(align(64)) struct Vectorizedqi {
|
| 48 |
+
protected:
|
| 49 |
+
__m256i vals;
|
| 50 |
+
#else
|
| 51 |
+
struct Vectorizedqi {
|
| 52 |
+
protected:
|
| 53 |
+
__m256i vals __attribute__((aligned(64)));
|
| 54 |
+
#endif
|
| 55 |
+
|
| 56 |
+
public:
|
| 57 |
+
Vectorizedqi() {}
|
| 58 |
+
Vectorizedqi(__m256i v) : vals(v) {}
|
| 59 |
+
operator __m256i() const {
|
| 60 |
+
return vals;
|
| 61 |
+
}
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
template <typename T>
|
| 65 |
+
__m256i pack_saturate_and_clamp(
|
| 66 |
+
__m256i first,
|
| 67 |
+
__m256i second,
|
| 68 |
+
T min_val,
|
| 69 |
+
T max_val);
|
| 70 |
+
|
| 71 |
+
template <>
|
| 72 |
+
inline __m256i pack_saturate_and_clamp<int32_t>(
|
| 73 |
+
__m256i /*first*/,
|
| 74 |
+
__m256i /*second*/,
|
| 75 |
+
int32_t /*min_val*/,
|
| 76 |
+
int32_t /*max_val*/) {
|
| 77 |
+
// This function is for linkage only, will not be used
|
| 78 |
+
TORCH_CHECK(false, "pack_saturate_and_clamp<int32_t> is not supported");
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
template <>
|
| 82 |
+
inline __m256i pack_saturate_and_clamp<int8_t>(
|
| 83 |
+
__m256i first,
|
| 84 |
+
__m256i second,
|
| 85 |
+
int8_t min_val,
|
| 86 |
+
int8_t max_val) {
|
| 87 |
+
__m256i packed_and_sat = _mm256_packs_epi16(first, second);
|
| 88 |
+
return _mm256_max_epi8(
|
| 89 |
+
_mm256_set1_epi8(min_val),
|
| 90 |
+
_mm256_min_epi8(packed_and_sat, _mm256_set1_epi8(max_val)));
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
template <>
|
| 94 |
+
inline __m256i pack_saturate_and_clamp<uint8_t>(
|
| 95 |
+
__m256i first,
|
| 96 |
+
__m256i second,
|
| 97 |
+
uint8_t min_val,
|
| 98 |
+
uint8_t max_val) {
|
| 99 |
+
__m256i packed_and_sat = _mm256_packus_epi16(first, second);
|
| 100 |
+
return _mm256_max_epu8(
|
| 101 |
+
_mm256_set1_epi8(min_val),
|
| 102 |
+
_mm256_min_epu8(packed_and_sat, _mm256_set1_epi8(max_val)));
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
template <typename T>
|
| 106 |
+
typename std::enable_if_t<std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>, at::vec::Vectorized<float>>
|
| 107 |
+
inline convert_int8_to_float(at::vec::Vectorized<T> src) {
|
| 108 |
+
// Note: this function only convert inputs number of elements equal to at::vec::Vectorized<float>.size()
|
| 109 |
+
// Only handle first 8*8 bits
|
| 110 |
+
__m128i input_128 = _mm256_castsi256_si128(src);
|
| 111 |
+
// Convert from 8*uint8/int8 to 8*int32
|
| 112 |
+
__m256i input_256_int32;
|
| 113 |
+
if constexpr (std::is_same_v<T, uint8_t>)
|
| 114 |
+
input_256_int32 = _mm256_cvtepu8_epi32(input_128);
|
| 115 |
+
else
|
| 116 |
+
input_256_int32 = _mm256_cvtepi8_epi32(input_128);
|
| 117 |
+
// Convert from 8*int32 to 8*float
|
| 118 |
+
return _mm256_cvtepi32_ps(input_256_int32);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
template <typename T>
|
| 122 |
+
typename std::enable_if_t<std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>, at::vec::Vectorized<T>>
|
| 123 |
+
inline convert_float_to_int8(at::vec::Vectorized<float> src) {
|
| 124 |
+
// Convert from float32 to int32 with truncation
|
| 125 |
+
__m256i x_values_int32 = _mm256_cvttps_epi32(src);
|
| 126 |
+
|
| 127 |
+
// Convert from int32 to int16 using signed saturation
|
| 128 |
+
__m256i xy_packed_v = _mm256_packs_epi32(x_values_int32, x_values_int32);
|
| 129 |
+
|
| 130 |
+
constexpr auto min_val = std::numeric_limits<T>::min();
|
| 131 |
+
constexpr auto max_val = std::numeric_limits<T>::max();
|
| 132 |
+
|
| 133 |
+
// Convert from int16 to uint8/int8 using unsigned saturation
|
| 134 |
+
__m256i xyzw_clamped_v = pack_saturate_and_clamp<T>(
|
| 135 |
+
xy_packed_v, xy_packed_v, min_val, max_val);
|
| 136 |
+
__m256i permute_mask_v =
|
| 137 |
+
_mm256_set_epi32(0x07, 0x03, 0x06, 0x02, 0x05, 0x01, 0x04, 0x00);
|
| 138 |
+
return _mm256_permutevar8x32_epi32(xyzw_clamped_v, permute_mask_v);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
template <typename T>
|
| 142 |
+
__FORCE_INLINE void QuantizeAvx2(
|
| 143 |
+
const float* src,
|
| 144 |
+
T* dst,
|
| 145 |
+
int len,
|
| 146 |
+
float inverse_scale,
|
| 147 |
+
int64_t zero_point) {
|
| 148 |
+
constexpr int VLEN = 8;
|
| 149 |
+
constexpr auto min_val = std::numeric_limits<T>::min();
|
| 150 |
+
constexpr auto max_val = std::numeric_limits<T>::max();
|
| 151 |
+
const __m256i min_v = _mm256_set1_epi32(min_val);
|
| 152 |
+
const __m256i max_v = _mm256_set1_epi32(max_val);
|
| 153 |
+
// This is the largest int32 value < int32_max exactly representable in float
|
| 154 |
+
constexpr int32_t int32_float_max_val =
|
| 155 |
+
std::numeric_limits<int32_t>::max() - 127;
|
| 156 |
+
int i = 0;
|
| 157 |
+
__m256 inverse_scale_v = _mm256_set1_ps(inverse_scale);
|
| 158 |
+
// clang-format off
|
| 159 |
+
static const __m256i shuffle_mask_v = _mm256_set_epi8(
|
| 160 |
+
0xff, 0xff, 0xff, 0xff,
|
| 161 |
+
0xff, 0xff, 0xff, 0xff,
|
| 162 |
+
0xff, 0xff, 0xff, 0xff,
|
| 163 |
+
0x0c, 0x08, 0x04, 0x00,
|
| 164 |
+
0xff, 0xff, 0xff, 0xff,
|
| 165 |
+
0xff, 0xff, 0xff, 0xff,
|
| 166 |
+
0xff, 0xff, 0xff, 0xff,
|
| 167 |
+
0x0c, 0x08, 0x04, 0x00);
|
| 168 |
+
// clang-format on
|
| 169 |
+
__m256i permute_mask_v =
|
| 170 |
+
_mm256_set_epi32(0x07, 0x03, 0x06, 0x02, 0x05, 0x01, 0x04, 0x00);
|
| 171 |
+
__m256i permute_mask_l8_v =
|
| 172 |
+
_mm256_set_epi32(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00);
|
| 173 |
+
int len_aligned = len / (VLEN * 4) * (VLEN * 4);
|
| 174 |
+
for (; i < len_aligned; i += 4 * VLEN) {
|
| 175 |
+
// x
|
| 176 |
+
__m256 x_vals = _mm256_load_ps(src + i);
|
| 177 |
+
__m256 x_transformed_v = _mm256_mul_ps(x_vals, inverse_scale_v);
|
| 178 |
+
// If the floating point value is greater than int32_max,
|
| 179 |
+
// _mm256_cvtps_epi32 converts them to -ve. Clip at int32_float_max_val to
|
| 180 |
+
// Clip at int32_float_max_val to avoid this.
|
| 181 |
+
x_transformed_v =
|
| 182 |
+
_mm256_min_ps(x_transformed_v, _mm256_set1_ps(int32_float_max_val));
|
| 183 |
+
// y
|
| 184 |
+
__m256 y_vals = _mm256_load_ps(src + i + VLEN);
|
| 185 |
+
__m256 y_transformed_v = _mm256_mul_ps(y_vals, inverse_scale_v);
|
| 186 |
+
y_transformed_v =
|
| 187 |
+
_mm256_min_ps(y_transformed_v, _mm256_set1_ps(int32_float_max_val));
|
| 188 |
+
// z
|
| 189 |
+
__m256 z_vals = _mm256_load_ps(src + i + 2 * VLEN);
|
| 190 |
+
__m256 z_transformed_v = _mm256_mul_ps(z_vals, inverse_scale_v);
|
| 191 |
+
z_transformed_v =
|
| 192 |
+
_mm256_min_ps(z_transformed_v, _mm256_set1_ps(int32_float_max_val));
|
| 193 |
+
// w
|
| 194 |
+
__m256 w_vals = _mm256_load_ps(src + i + 3 * VLEN);
|
| 195 |
+
__m256 w_transformed_v = _mm256_mul_ps(w_vals, inverse_scale_v);
|
| 196 |
+
w_transformed_v =
|
| 197 |
+
_mm256_min_ps(w_transformed_v, _mm256_set1_ps(int32_float_max_val));
|
| 198 |
+
|
| 199 |
+
__m256i x_rounded_v = _mm256_cvtps_epi32(x_transformed_v);
|
| 200 |
+
__m256i y_rounded_v = _mm256_cvtps_epi32(y_transformed_v);
|
| 201 |
+
__m256i z_rounded_v = _mm256_cvtps_epi32(z_transformed_v);
|
| 202 |
+
__m256i w_rounded_v = _mm256_cvtps_epi32(w_transformed_v);
|
| 203 |
+
|
| 204 |
+
// add zero point
|
| 205 |
+
x_rounded_v = _mm256_add_epi32(x_rounded_v, _mm256_set1_epi32(zero_point));
|
| 206 |
+
y_rounded_v = _mm256_add_epi32(y_rounded_v, _mm256_set1_epi32(zero_point));
|
| 207 |
+
z_rounded_v = _mm256_add_epi32(z_rounded_v, _mm256_set1_epi32(zero_point));
|
| 208 |
+
w_rounded_v = _mm256_add_epi32(w_rounded_v, _mm256_set1_epi32(zero_point));
|
| 209 |
+
|
| 210 |
+
__m256i xy_packed_v = _mm256_packs_epi32(x_rounded_v, y_rounded_v);
|
| 211 |
+
__m256i zw_packed_v = _mm256_packs_epi32(z_rounded_v, w_rounded_v);
|
| 212 |
+
__m256i xyzw_clamped_v =
|
| 213 |
+
pack_saturate_and_clamp<T>(xy_packed_v, zw_packed_v, min_val, max_val);
|
| 214 |
+
|
| 215 |
+
xyzw_clamped_v =
|
| 216 |
+
_mm256_permutevar8x32_epi32(xyzw_clamped_v, permute_mask_v);
|
| 217 |
+
_mm256_storeu_si256(reinterpret_cast<__m256i*>(dst + i), xyzw_clamped_v);
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
// Additional 8-lane AVX2 version to take advantage when len is smaller
|
| 221 |
+
// based on fbgemm::QuantizeAvx2 (https://github.com/pytorch/FBGEMM)
|
| 222 |
+
for (; i < len / VLEN * VLEN; i += VLEN) {
|
| 223 |
+
__m256 x_vals = _mm256_load_ps(src + i);
|
| 224 |
+
__m256 x_transformed_v = _mm256_mul_ps(x_vals, inverse_scale_v);
|
| 225 |
+
x_transformed_v =
|
| 226 |
+
_mm256_min_ps(x_transformed_v, _mm256_set1_ps(int32_float_max_val));
|
| 227 |
+
__m256i x_rounded_v = _mm256_cvtps_epi32(x_transformed_v);
|
| 228 |
+
x_rounded_v = _mm256_add_epi32(x_rounded_v, _mm256_set1_epi32(zero_point));
|
| 229 |
+
__m256i x_clipped_v =
|
| 230 |
+
_mm256_max_epi32(min_v, _mm256_min_epi32(max_v, x_rounded_v));
|
| 231 |
+
|
| 232 |
+
x_clipped_v = _mm256_shuffle_epi8(x_clipped_v, shuffle_mask_v);
|
| 233 |
+
x_clipped_v = _mm256_permutevar8x32_epi32(x_clipped_v, permute_mask_l8_v);
|
| 234 |
+
_mm_storel_epi64(
|
| 235 |
+
reinterpret_cast<__m128i*>(dst + i),
|
| 236 |
+
_mm256_castsi256_si128(x_clipped_v));
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
for (; i < len; ++i) {
|
| 240 |
+
float transformed = src[i] * inverse_scale;
|
| 241 |
+
|
| 242 |
+
// Not exactly the same behavior as the vectorized code.
|
| 243 |
+
// The vectorized code above always rounds to even in halfway cases
|
| 244 |
+
// (https://software.intel.com/en-us/node/523819), but std::nearbyint
|
| 245 |
+
// does the same only when the current rounding mode is FE_TONEAREST.
|
| 246 |
+
// However, in practice, this should not be a problem because most cases
|
| 247 |
+
// use the default rounding mode FE_TONEAREST.
|
| 248 |
+
// Note that we cannot implement the same behavior as the vectorized code
|
| 249 |
+
// using std::round because it does rounding away from zero in halfway
|
| 250 |
+
// cases.
|
| 251 |
+
transformed = zero_point + std::nearbyint(transformed);
|
| 252 |
+
float clipped =
|
| 253 |
+
std::min(std::max(transformed, float(min_val)), float(max_val));
|
| 254 |
+
dst[i] = clipped;
|
| 255 |
+
}
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
template<>
|
| 259 |
+
struct Vectorized<c10::qint32> : public Vectorizedqi {
|
| 260 |
+
using size_type = int;
|
| 261 |
+
static constexpr size_type kSize = Vectorized<int>::size();
|
| 262 |
+
static constexpr size_type size() {
|
| 263 |
+
return kSize;
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
static constexpr int kFloatNumVecs = kSize / Vectorized<float>::size();
|
| 267 |
+
static constexpr int float_num_vecs() {
|
| 268 |
+
return kFloatNumVecs;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
static constexpr int int_num_vecs() {
|
| 272 |
+
return 1;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
using float_vec_return_type = std::array<Vectorized<float>, kFloatNumVecs>;
|
| 276 |
+
using int_vec_return_type = std::array<Vectorized<c10::qint32>, 1>;
|
| 277 |
+
using value_type = c10::qint32::underlying;
|
| 278 |
+
|
| 279 |
+
public:
|
| 280 |
+
using Vectorizedqi::Vectorizedqi;
|
| 281 |
+
Vectorized() {}
|
| 282 |
+
|
| 283 |
+
Vectorized(__m256i vals_) { vals = vals_;}
|
| 284 |
+
|
| 285 |
+
// Broadcast constructor
|
| 286 |
+
Vectorized(const c10::qint32& val) {
|
| 287 |
+
value_type uw = val.val_;
|
| 288 |
+
vals = _mm256_set1_epi32(uw);
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
void store(void* ptr, int count = size()) const {
|
| 292 |
+
if (count != size()) {
|
| 293 |
+
memcpy(ptr, &vals, count * sizeof(value_type));
|
| 294 |
+
} else {
|
| 295 |
+
_mm256_storeu_si256((__m256i*)ptr, vals);
|
| 296 |
+
}
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
static Vectorized<c10::qint32> loadu(const void* ptr) {
|
| 300 |
+
return Vectorized<c10::qint32>(ptr);
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
static Vectorized<c10::qint32> loadu(const void* ptr, int64_t count) {
|
| 304 |
+
__at_align__ value_type tmp_values[size()];
|
| 305 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 306 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 307 |
+
// instructions while a loop would be compiled to one instruction.
|
| 308 |
+
for (const auto i : c10::irange(size())) {
|
| 309 |
+
tmp_values[i] = 0;
|
| 310 |
+
}
|
| 311 |
+
std::memcpy(
|
| 312 |
+
tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 313 |
+
return _mm256_loadu_si256((const __m256i*)tmp_values);
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
float_vec_return_type dequantize(
|
| 317 |
+
Vectorized<float> scale,
|
| 318 |
+
Vectorized<float> /*zero_point*/,
|
| 319 |
+
Vectorized<float> scale_zp_premul) const {
|
| 320 |
+
__m256 float_vals = _mm256_cvtepi32_ps(vals);
|
| 321 |
+
return {vec::fmadd(scale, Vectorized<float>(float_vals), scale_zp_premul)};
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
float_vec_return_type dequantize(
|
| 325 |
+
Vectorized<float> scale,
|
| 326 |
+
Vectorized<float> zero_point) const {
|
| 327 |
+
__m256 float_vals = _mm256_cvtepi32_ps(vals);
|
| 328 |
+
return {(Vectorized<float>(float_vals) - zero_point) * scale};
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
static Vectorized<c10::qint32> quantize(
|
| 332 |
+
const float_vec_return_type& rhs,
|
| 333 |
+
float scale,
|
| 334 |
+
int32_t zero_point,
|
| 335 |
+
float /*inverse_scale*/) {
|
| 336 |
+
Vectorized<c10::qint32> retval;
|
| 337 |
+
auto rhs_data = (__m256)rhs[0];
|
| 338 |
+
at::native::quantize_vec<c10::qint32, /*precision=*/32>(
|
| 339 |
+
scale, zero_point, (float*)&rhs_data, (c10::qint32*)&retval.vals, size());
|
| 340 |
+
return retval;
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
Vectorized<c10::qint32> maximum(Vectorized<c10::qint32> b) const {
|
| 344 |
+
return _mm256_max_epi32(vals, b.vals);
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
Vectorized<c10::qint32> minimum(Vectorized<c10::qint32> b) const {
|
| 348 |
+
return _mm256_min_epi32(vals, b.vals);
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
Vectorized<c10::qint32> relu(Vectorized<c10::qint32> zero_point) const {
|
| 352 |
+
return maximum(zero_point);
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
Vectorized<c10::qint32> relu6(
|
| 356 |
+
Vectorized<c10::qint32> zero_point,
|
| 357 |
+
Vectorized<c10::qint32> q_six) {
|
| 358 |
+
return _mm256_min_epi32(
|
| 359 |
+
_mm256_max_epi32(vals, zero_point.vals), q_six.vals);
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
int_vec_return_type widening_subtract(Vectorized<c10::qint32> b) const {
|
| 363 |
+
return {_mm256_sub_epi32(vals, b)};
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
static Vectorized<c10::qint32> requantize_from_int(
|
| 367 |
+
const int_vec_return_type& inp,
|
| 368 |
+
float multiplier,
|
| 369 |
+
int32_t zero_point) {
|
| 370 |
+
__m256 multiplier_v = _mm256_set1_ps(multiplier);
|
| 371 |
+
__m256i zero_point_v = _mm256_set1_epi32(zero_point);
|
| 372 |
+
|
| 373 |
+
__m256 scaled = _mm256_mul_ps(_mm256_cvtepi32_ps(inp[0]), multiplier_v);
|
| 374 |
+
__m256i rounded = _mm256_cvtps_epi32(scaled);
|
| 375 |
+
return _mm256_add_epi32(rounded, zero_point_v);
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
private:
|
| 379 |
+
// Load from memory constructor
|
| 380 |
+
Vectorized(const void* ptr) {
|
| 381 |
+
vals = _mm256_loadu_si256((const __m256i*)ptr);
|
| 382 |
+
}
|
| 383 |
+
};
|
| 384 |
+
|
| 385 |
+
template <>
|
| 386 |
+
Vectorized<c10::qint32> inline maximum(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 387 |
+
return a.maximum(b);
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
template <>
|
| 391 |
+
Vectorized<c10::qint32> inline operator*(
|
| 392 |
+
const Vectorized<c10::qint32>& a,
|
| 393 |
+
const Vectorized<c10::qint32>& b) {
|
| 394 |
+
return _mm256_mullo_epi32(a, b);
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
template <>
|
| 398 |
+
Vectorized<c10::qint32> inline operator+(
|
| 399 |
+
const Vectorized<c10::qint32>& a,
|
| 400 |
+
const Vectorized<c10::qint32>& b) {
|
| 401 |
+
return _mm256_add_epi32(a, b);
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
/*
|
| 405 |
+
* Convert values from int32 back to int8/uint8
|
| 406 |
+
*/
|
| 407 |
+
template <typename T>
|
| 408 |
+
__m256i RequantizeAvx2(
|
| 409 |
+
const std::array<Vectorized<c10::qint32>, 4>& inp,
|
| 410 |
+
__m256 multiplier,
|
| 411 |
+
__m256i zp) {
|
| 412 |
+
static_assert(
|
| 413 |
+
std::is_same_v<T, int8_t> || std::is_same_v<T, uint8_t>,
|
| 414 |
+
"Only int8_t/uint8_t are supported");
|
| 415 |
+
constexpr auto min_val = std::numeric_limits<T>::min();
|
| 416 |
+
constexpr auto max_val = std::numeric_limits<T>::max();
|
| 417 |
+
__m256i permute_mask_v =
|
| 418 |
+
_mm256_set_epi32(0x07, 0x03, 0x06, 0x02, 0x05, 0x01, 0x04, 0x00);
|
| 419 |
+
__m256 x_scaled_v = _mm256_mul_ps(_mm256_cvtepi32_ps(inp[0]), multiplier);
|
| 420 |
+
__m256 y_scaled_v = _mm256_mul_ps(_mm256_cvtepi32_ps(inp[1]), multiplier);
|
| 421 |
+
__m256 z_scaled_v = _mm256_mul_ps(_mm256_cvtepi32_ps(inp[2]), multiplier);
|
| 422 |
+
__m256 w_scaled_v = _mm256_mul_ps(_mm256_cvtepi32_ps(inp[3]), multiplier);
|
| 423 |
+
|
| 424 |
+
__m256i x_rounded_v = _mm256_cvtps_epi32(x_scaled_v);
|
| 425 |
+
__m256i y_rounded_v = _mm256_cvtps_epi32(y_scaled_v);
|
| 426 |
+
__m256i z_rounded_v = _mm256_cvtps_epi32(z_scaled_v);
|
| 427 |
+
__m256i w_rounded_v = _mm256_cvtps_epi32(w_scaled_v);
|
| 428 |
+
|
| 429 |
+
/* Add zero point */
|
| 430 |
+
__m256i x_v = _mm256_add_epi32(x_rounded_v, zp);
|
| 431 |
+
__m256i y_v = _mm256_add_epi32(y_rounded_v, zp);
|
| 432 |
+
__m256i z_v = _mm256_add_epi32(z_rounded_v, zp);
|
| 433 |
+
__m256i w_v = _mm256_add_epi32(w_rounded_v, zp);
|
| 434 |
+
|
| 435 |
+
/* Pack to int16_t and saturate */
|
| 436 |
+
__m256i xy_packed_v = _mm256_packs_epi32(x_v, y_v);
|
| 437 |
+
__m256i zw_packed_v = _mm256_packs_epi32(z_v, w_v);
|
| 438 |
+
|
| 439 |
+
__m256i xyzw_clamped_v =
|
| 440 |
+
pack_saturate_and_clamp<T>(xy_packed_v, zw_packed_v, min_val, max_val);
|
| 441 |
+
|
| 442 |
+
/*
|
| 443 |
+
* xyzw_clamped_v has results in the following layout so we need to
|
| 444 |
+
* permute: x0-3 y0-3 z0-3 w0-3 x4-7 y4-7 z4-7 w4-7
|
| 445 |
+
*/
|
| 446 |
+
xyzw_clamped_v = _mm256_permutevar8x32_epi32(xyzw_clamped_v, permute_mask_v);
|
| 447 |
+
return xyzw_clamped_v;
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
template<>
|
| 451 |
+
struct Vectorized<c10::qint8> : public Vectorizedqi {
|
| 452 |
+
static constexpr int kSize = VECTOR_WIDTH;
|
| 453 |
+
static constexpr int size() {
|
| 454 |
+
return kSize;
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
static constexpr int kFloatNumVecs = kSize / Vectorized<float>::size();
|
| 458 |
+
static constexpr int float_num_vecs() {
|
| 459 |
+
return kFloatNumVecs;
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
static constexpr int kIntNumVecs = kSize / Vectorized<int>::size();
|
| 463 |
+
static constexpr int int_num_vecs() {
|
| 464 |
+
return kIntNumVecs;
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
using float_vec_return_type = std::array<Vectorized<float>, kFloatNumVecs>;
|
| 468 |
+
using int_vec_return_type = std::array<Vectorized<c10::qint32>, kIntNumVecs>;
|
| 469 |
+
using value_type = typename c10::qint8::underlying;
|
| 470 |
+
|
| 471 |
+
public:
|
| 472 |
+
using Vectorizedqi::Vectorizedqi;
|
| 473 |
+
|
| 474 |
+
Vectorized() {}
|
| 475 |
+
Vectorized(__m256i vals_) { vals = vals_;}
|
| 476 |
+
|
| 477 |
+
// Broadcast constructor
|
| 478 |
+
Vectorized(const c10::qint8& val) {
|
| 479 |
+
value_type uw = val.val_;
|
| 480 |
+
vals = _mm256_set1_epi8(uw);
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
+
// This is needed because the compiler emits awful code for the default
|
| 484 |
+
// constructor for moving the enum
|
| 485 |
+
// NOLINTNEXTLINE(clang-diagnostic-deprecated-copy)
|
| 486 |
+
C10_CLANG_DIAGNOSTIC_PUSH()
|
| 487 |
+
#if C10_CLANG_HAS_WARNING("-Wdeprecated-copy")
|
| 488 |
+
C10_CLANG_DIAGNOSTIC_IGNORE("-Wdeprecated-copy")
|
| 489 |
+
#endif
|
| 490 |
+
Vectorized(const Vectorized<c10::qint8>& other) : Vectorizedqi(other.vals) { }
|
| 491 |
+
C10_CLANG_DIAGNOSTIC_POP()
|
| 492 |
+
|
| 493 |
+
void store(void* ptr, int count = size()) const {
|
| 494 |
+
if (count != size()) {
|
| 495 |
+
memcpy(ptr, &vals, count * sizeof(value_type));
|
| 496 |
+
} else {
|
| 497 |
+
_mm256_storeu_si256((__m256i*)ptr, vals);
|
| 498 |
+
}
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
static Vectorized<c10::qint8> loadu(const void* ptr) {
|
| 502 |
+
return Vectorized<c10::qint8>(ptr);
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
static Vectorized<c10::qint8> loadu(const void* ptr, int64_t count) {
|
| 506 |
+
__at_align__ value_type tmp_values[size()];
|
| 507 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 508 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 509 |
+
// instructions while a loop would be compiled to one instruction.
|
| 510 |
+
for (const auto i : c10::irange(size())) {
|
| 511 |
+
tmp_values[i] = 0;
|
| 512 |
+
}
|
| 513 |
+
std::memcpy(
|
| 514 |
+
tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 515 |
+
return _mm256_loadu_si256((const __m256i*)tmp_values);
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
private:
|
| 519 |
+
__m256i cvtepi8_epi32(__m128i epi8_vals) const {
|
| 520 |
+
return _mm256_cvtepi8_epi32(epi8_vals);
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
public:
|
| 524 |
+
float_vec_return_type dequantize(
|
| 525 |
+
Vectorized<float> scale,
|
| 526 |
+
Vectorized<float> /*zero_point*/,
|
| 527 |
+
Vectorized<float> scale_neg_zp_premul) const {
|
| 528 |
+
__m128i int_val0 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 0));
|
| 529 |
+
__m128i int_val1 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 1));
|
| 530 |
+
__m128i int_val2 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 2));
|
| 531 |
+
__m128i int_val3 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 3));
|
| 532 |
+
|
| 533 |
+
__m256 float_val0 = _mm256_cvtepi32_ps(cvtepi8_epi32(int_val0));
|
| 534 |
+
__m256 float_val1 = _mm256_cvtepi32_ps(cvtepi8_epi32(int_val1));
|
| 535 |
+
__m256 float_val2 = _mm256_cvtepi32_ps(cvtepi8_epi32(int_val2));
|
| 536 |
+
__m256 float_val3 = _mm256_cvtepi32_ps(cvtepi8_epi32(int_val3));
|
| 537 |
+
|
| 538 |
+
auto val0 =
|
| 539 |
+
vec::fmadd(scale, Vectorized<float>(float_val0), scale_neg_zp_premul);
|
| 540 |
+
auto val1 =
|
| 541 |
+
vec::fmadd(scale, Vectorized<float>(float_val1), scale_neg_zp_premul);
|
| 542 |
+
auto val2 =
|
| 543 |
+
vec::fmadd(scale, Vectorized<float>(float_val2), scale_neg_zp_premul);
|
| 544 |
+
auto val3 =
|
| 545 |
+
vec::fmadd(scale, Vectorized<float>(float_val3), scale_neg_zp_premul);
|
| 546 |
+
return {val0, val1, val2, val3};
|
| 547 |
+
}
|
| 548 |
+
|
| 549 |
+
float_vec_return_type dequantize(
|
| 550 |
+
Vectorized<float> scale,
|
| 551 |
+
Vectorized<float> zero_point) const {
|
| 552 |
+
__m128i int_val0 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 0));
|
| 553 |
+
__m128i int_val1 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 1));
|
| 554 |
+
__m128i int_val2 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 2));
|
| 555 |
+
__m128i int_val3 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 3));
|
| 556 |
+
|
| 557 |
+
__m256 float_val0 = _mm256_cvtepi32_ps(cvtepi8_epi32(int_val0));
|
| 558 |
+
__m256 float_val1 = _mm256_cvtepi32_ps(cvtepi8_epi32(int_val1));
|
| 559 |
+
__m256 float_val2 = _mm256_cvtepi32_ps(cvtepi8_epi32(int_val2));
|
| 560 |
+
__m256 float_val3 = _mm256_cvtepi32_ps(cvtepi8_epi32(int_val3));
|
| 561 |
+
|
| 562 |
+
auto val0 = (Vectorized<float>(float_val0) - zero_point) * scale;
|
| 563 |
+
auto val1 = (Vectorized<float>(float_val1) - zero_point) * scale;
|
| 564 |
+
auto val2 = (Vectorized<float>(float_val2) - zero_point) * scale;
|
| 565 |
+
auto val3 = (Vectorized<float>(float_val3) - zero_point) * scale;
|
| 566 |
+
return {val0, val1, val2, val3};
|
| 567 |
+
}
|
| 568 |
+
|
| 569 |
+
static Vectorized<c10::qint8> quantize(
|
| 570 |
+
const float_vec_return_type& rhs,
|
| 571 |
+
float /*scale*/,
|
| 572 |
+
int32_t zero_point,
|
| 573 |
+
float inverse_scale) {
|
| 574 |
+
auto* rhs_data = (float*)rhs.data();
|
| 575 |
+
int8_t quantized_values[32];
|
| 576 |
+
QuantizeAvx2<value_type>(
|
| 577 |
+
rhs_data, quantized_values, 32, inverse_scale, zero_point);
|
| 578 |
+
return Vectorized<c10::qint8>::loadu(quantized_values);
|
| 579 |
+
}
|
| 580 |
+
|
| 581 |
+
Vectorized<c10::qint8> maximum(Vectorized<c10::qint8> b) const {
|
| 582 |
+
return _mm256_max_epi8(vals, b.vals);
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
Vectorized<c10::qint8> minimum(Vectorized<c10::qint8> b) const {
|
| 586 |
+
return _mm256_min_epi8(vals, b.vals);
|
| 587 |
+
}
|
| 588 |
+
|
| 589 |
+
Vectorized<c10::qint8> relu(Vectorized<c10::qint8> zero_point) const {
|
| 590 |
+
return maximum(zero_point);
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
Vectorized<c10::qint8> relu6(
|
| 594 |
+
Vectorized<c10::qint8> zero_point,
|
| 595 |
+
Vectorized<c10::qint8> q_six) {
|
| 596 |
+
return _mm256_min_epi8(
|
| 597 |
+
_mm256_max_epi8(vals, zero_point.vals), q_six.vals);
|
| 598 |
+
}
|
| 599 |
+
|
| 600 |
+
int_vec_return_type widening_subtract(Vectorized<c10::qint8> b) const {
|
| 601 |
+
__m128i int_val0 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 0));
|
| 602 |
+
__m128i int_val1 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 1));
|
| 603 |
+
__m128i int_val2 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 2));
|
| 604 |
+
__m128i int_val3 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 3));
|
| 605 |
+
|
| 606 |
+
__m256i int32_val0 = cvtepi8_epi32(int_val0);
|
| 607 |
+
__m256i int32_val1 = cvtepi8_epi32(int_val1);
|
| 608 |
+
__m256i int32_val2 = cvtepi8_epi32(int_val2);
|
| 609 |
+
__m256i int32_val3 = cvtepi8_epi32(int_val3);
|
| 610 |
+
|
| 611 |
+
__m128i int_b0 = _mm_set1_epi64x(_mm256_extract_epi64(b, 0));
|
| 612 |
+
__m128i int_b1 = _mm_set1_epi64x(_mm256_extract_epi64(b, 1));
|
| 613 |
+
__m128i int_b2 = _mm_set1_epi64x(_mm256_extract_epi64(b, 2));
|
| 614 |
+
__m128i int_b3 = _mm_set1_epi64x(_mm256_extract_epi64(b, 3));
|
| 615 |
+
|
| 616 |
+
__m256i int32_b0 = cvtepi8_epi32(int_b0);
|
| 617 |
+
__m256i int32_b1 = cvtepi8_epi32(int_b1);
|
| 618 |
+
__m256i int32_b2 = cvtepi8_epi32(int_b2);
|
| 619 |
+
__m256i int32_b3 = cvtepi8_epi32(int_b3);
|
| 620 |
+
|
| 621 |
+
__m256i res_0 = _mm256_sub_epi32(int32_val0, int32_b0);
|
| 622 |
+
__m256i res_1 = _mm256_sub_epi32(int32_val1, int32_b1);
|
| 623 |
+
__m256i res_2 = _mm256_sub_epi32(int32_val2, int32_b2);
|
| 624 |
+
__m256i res_3 = _mm256_sub_epi32(int32_val3, int32_b3);
|
| 625 |
+
|
| 626 |
+
return {Vectorized<c10::qint32>(res_0),
|
| 627 |
+
Vectorized<c10::qint32>(res_1),
|
| 628 |
+
Vectorized<c10::qint32>(res_2),
|
| 629 |
+
Vectorized<c10::qint32>(res_3)};
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
+
static Vectorized<c10::qint8> requantize_from_int(
|
| 633 |
+
const int_vec_return_type& inp,
|
| 634 |
+
float multiplier,
|
| 635 |
+
int32_t zero_point) {
|
| 636 |
+
__m256 multiplier_v = _mm256_set1_ps(multiplier);
|
| 637 |
+
__m256i zero_point_v = _mm256_set1_epi32(zero_point);
|
| 638 |
+
return RequantizeAvx2<value_type>(inp, multiplier_v, zero_point_v);
|
| 639 |
+
}
|
| 640 |
+
|
| 641 |
+
private:
|
| 642 |
+
// Load from memory constructor
|
| 643 |
+
Vectorized(const void* ptr) {
|
| 644 |
+
vals = _mm256_loadu_si256((const __m256i*)ptr);
|
| 645 |
+
}
|
| 646 |
+
};
|
| 647 |
+
|
| 648 |
+
template <>
|
| 649 |
+
Vectorized<c10::qint8> inline maximum(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 650 |
+
return a.maximum(b);
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
template<>
|
| 654 |
+
struct Vectorized<c10::quint8> : public Vectorizedqi {
|
| 655 |
+
static constexpr int kSize = VECTOR_WIDTH;
|
| 656 |
+
static constexpr int size() {
|
| 657 |
+
return kSize;
|
| 658 |
+
}
|
| 659 |
+
|
| 660 |
+
static constexpr int kFloatNumVecs = kSize / Vectorized<float>::size();
|
| 661 |
+
static constexpr int float_num_vecs() {
|
| 662 |
+
return kFloatNumVecs;
|
| 663 |
+
}
|
| 664 |
+
|
| 665 |
+
static constexpr int kIntNumVecs = kSize / Vectorized<int>::size();
|
| 666 |
+
static constexpr int int_num_vecs() {
|
| 667 |
+
return kIntNumVecs;
|
| 668 |
+
}
|
| 669 |
+
|
| 670 |
+
using float_vec_return_type = std::array<Vectorized<float>, kFloatNumVecs>;
|
| 671 |
+
using int_vec_return_type = std::array<Vectorized<c10::qint32>, kIntNumVecs>;
|
| 672 |
+
using value_type = typename c10::quint8::underlying;
|
| 673 |
+
|
| 674 |
+
public:
|
| 675 |
+
using Vectorizedqi::Vectorizedqi;
|
| 676 |
+
Vectorized() {}
|
| 677 |
+
|
| 678 |
+
Vectorized(__m256i vals_) { vals = vals_;}
|
| 679 |
+
|
| 680 |
+
// Broadcast constructor
|
| 681 |
+
Vectorized(const c10::quint8& val) {
|
| 682 |
+
value_type uw = val.val_;
|
| 683 |
+
vals = _mm256_set1_epi8(uw);
|
| 684 |
+
}
|
| 685 |
+
|
| 686 |
+
// NOLINTNEXTLINE(clang-diagnostic-deprecated-copy)
|
| 687 |
+
C10_CLANG_DIAGNOSTIC_PUSH()
|
| 688 |
+
#if C10_CLANG_HAS_WARNING("-Wdeprecated-copy")
|
| 689 |
+
C10_CLANG_DIAGNOSTIC_IGNORE("-Wdeprecated-copy")
|
| 690 |
+
#endif
|
| 691 |
+
Vectorized(const Vectorized<c10::quint8>& other) : Vectorizedqi(other.vals) { }
|
| 692 |
+
C10_CLANG_DIAGNOSTIC_POP()
|
| 693 |
+
|
| 694 |
+
void store(void* ptr, int count = size()) const {
|
| 695 |
+
if (count != size()) {
|
| 696 |
+
memcpy(ptr, &vals, count * sizeof(value_type));
|
| 697 |
+
} else {
|
| 698 |
+
_mm256_storeu_si256((__m256i*)ptr, vals);
|
| 699 |
+
}
|
| 700 |
+
}
|
| 701 |
+
|
| 702 |
+
static Vectorized<c10::quint8> loadu(const void* ptr) {
|
| 703 |
+
return Vectorized<c10::quint8>(ptr);
|
| 704 |
+
}
|
| 705 |
+
|
| 706 |
+
static Vectorized<c10::quint8> loadu(const void* ptr, int64_t count) {
|
| 707 |
+
__at_align__ value_type tmp_values[size()];
|
| 708 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 709 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 710 |
+
// instructions while a loop would be compiled to one instruction.
|
| 711 |
+
for (const auto i : c10::irange(size())) {
|
| 712 |
+
tmp_values[i] = 0;
|
| 713 |
+
}
|
| 714 |
+
std::memcpy(
|
| 715 |
+
tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 716 |
+
return _mm256_loadu_si256((const __m256i*)tmp_values);
|
| 717 |
+
}
|
| 718 |
+
|
| 719 |
+
private:
|
| 720 |
+
__m256i cvtepu8_epi32(__m128i epu8_vals) const {
|
| 721 |
+
return _mm256_cvtepu8_epi32(epu8_vals);
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
public:
|
| 725 |
+
float_vec_return_type dequantize(
|
| 726 |
+
Vectorized<float> scale,
|
| 727 |
+
Vectorized<float> /*zero_point*/,
|
| 728 |
+
Vectorized<float> scale_zp_premul) const {
|
| 729 |
+
__m128i int_val0 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 0));
|
| 730 |
+
__m128i int_val1 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 1));
|
| 731 |
+
__m128i int_val2 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 2));
|
| 732 |
+
__m128i int_val3 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 3));
|
| 733 |
+
|
| 734 |
+
__m256 float_val0 = _mm256_cvtepi32_ps(cvtepu8_epi32(int_val0));
|
| 735 |
+
__m256 float_val1 = _mm256_cvtepi32_ps(cvtepu8_epi32(int_val1));
|
| 736 |
+
__m256 float_val2 = _mm256_cvtepi32_ps(cvtepu8_epi32(int_val2));
|
| 737 |
+
__m256 float_val3 = _mm256_cvtepi32_ps(cvtepu8_epi32(int_val3));
|
| 738 |
+
|
| 739 |
+
auto val0 =
|
| 740 |
+
vec::fmadd(scale, Vectorized<float>(float_val0), scale_zp_premul);
|
| 741 |
+
auto val1 =
|
| 742 |
+
vec::fmadd(scale, Vectorized<float>(float_val1), scale_zp_premul);
|
| 743 |
+
auto val2 =
|
| 744 |
+
vec::fmadd(scale, Vectorized<float>(float_val2), scale_zp_premul);
|
| 745 |
+
auto val3 =
|
| 746 |
+
vec::fmadd(scale, Vectorized<float>(float_val3), scale_zp_premul);
|
| 747 |
+
return {val0, val1, val2, val3};
|
| 748 |
+
}
|
| 749 |
+
|
| 750 |
+
float_vec_return_type dequantize(
|
| 751 |
+
Vectorized<float> scale,
|
| 752 |
+
Vectorized<float> zero_point) const {
|
| 753 |
+
__m128i int_val0 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 0));
|
| 754 |
+
__m128i int_val1 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 1));
|
| 755 |
+
__m128i int_val2 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 2));
|
| 756 |
+
__m128i int_val3 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 3));
|
| 757 |
+
|
| 758 |
+
__m256 float_val0 = _mm256_cvtepi32_ps(cvtepu8_epi32(int_val0));
|
| 759 |
+
__m256 float_val1 = _mm256_cvtepi32_ps(cvtepu8_epi32(int_val1));
|
| 760 |
+
__m256 float_val2 = _mm256_cvtepi32_ps(cvtepu8_epi32(int_val2));
|
| 761 |
+
__m256 float_val3 = _mm256_cvtepi32_ps(cvtepu8_epi32(int_val3));
|
| 762 |
+
|
| 763 |
+
auto val0 = (Vectorized<float>(float_val0) - zero_point) * scale;
|
| 764 |
+
auto val1 = (Vectorized<float>(float_val1) - zero_point) * scale;
|
| 765 |
+
auto val2 = (Vectorized<float>(float_val2) - zero_point) * scale;
|
| 766 |
+
auto val3 = (Vectorized<float>(float_val3) - zero_point) * scale;
|
| 767 |
+
return {val0, val1, val2, val3};
|
| 768 |
+
}
|
| 769 |
+
|
| 770 |
+
static Vectorized<c10::quint8> quantize(
|
| 771 |
+
const float_vec_return_type& rhs,
|
| 772 |
+
float /*scale*/,
|
| 773 |
+
int32_t zero_point,
|
| 774 |
+
float inverse_scale) {
|
| 775 |
+
auto* rhs_data = (float*)rhs.data();
|
| 776 |
+
uint8_t quantized_values[32];
|
| 777 |
+
QuantizeAvx2<value_type>(
|
| 778 |
+
rhs_data, quantized_values, 32, inverse_scale, zero_point);
|
| 779 |
+
return Vectorized<c10::quint8>::loadu(quantized_values);
|
| 780 |
+
}
|
| 781 |
+
|
| 782 |
+
Vectorized<c10::quint8> maximum(Vectorized<c10::quint8> b) const {
|
| 783 |
+
return _mm256_max_epu8(vals, b.vals);
|
| 784 |
+
}
|
| 785 |
+
|
| 786 |
+
Vectorized<c10::quint8> minimum(Vectorized<c10::quint8> b) const {
|
| 787 |
+
return _mm256_min_epu8(vals, b.vals);
|
| 788 |
+
}
|
| 789 |
+
|
| 790 |
+
Vectorized<c10::quint8> relu(Vectorized<c10::quint8> zero_point) const {
|
| 791 |
+
return maximum(zero_point);
|
| 792 |
+
}
|
| 793 |
+
|
| 794 |
+
Vectorized<c10::quint8> relu6(
|
| 795 |
+
Vectorized<c10::quint8> zero_point,
|
| 796 |
+
Vectorized<c10::quint8> q_six) {
|
| 797 |
+
return _mm256_min_epu8(
|
| 798 |
+
_mm256_max_epu8(vals, zero_point.vals), q_six.vals);
|
| 799 |
+
}
|
| 800 |
+
|
| 801 |
+
int_vec_return_type widening_subtract(Vectorized<c10::quint8> b) const {
|
| 802 |
+
__m128i int_val0 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 0));
|
| 803 |
+
__m128i int_val1 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 1));
|
| 804 |
+
__m128i int_val2 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 2));
|
| 805 |
+
__m128i int_val3 = _mm_set1_epi64x(_mm256_extract_epi64(vals, 3));
|
| 806 |
+
|
| 807 |
+
__m256i int32_val0 = cvtepu8_epi32(int_val0);
|
| 808 |
+
__m256i int32_val1 = cvtepu8_epi32(int_val1);
|
| 809 |
+
__m256i int32_val2 = cvtepu8_epi32(int_val2);
|
| 810 |
+
__m256i int32_val3 = cvtepu8_epi32(int_val3);
|
| 811 |
+
|
| 812 |
+
__m128i int_b0 = _mm_set1_epi64x(_mm256_extract_epi64(b, 0));
|
| 813 |
+
__m128i int_b1 = _mm_set1_epi64x(_mm256_extract_epi64(b, 1));
|
| 814 |
+
__m128i int_b2 = _mm_set1_epi64x(_mm256_extract_epi64(b, 2));
|
| 815 |
+
__m128i int_b3 = _mm_set1_epi64x(_mm256_extract_epi64(b, 3));
|
| 816 |
+
|
| 817 |
+
__m256i int32_b0 = cvtepu8_epi32(int_b0);
|
| 818 |
+
__m256i int32_b1 = cvtepu8_epi32(int_b1);
|
| 819 |
+
__m256i int32_b2 = cvtepu8_epi32(int_b2);
|
| 820 |
+
__m256i int32_b3 = cvtepu8_epi32(int_b3);
|
| 821 |
+
|
| 822 |
+
__m256i res_0 = _mm256_sub_epi32(int32_val0, int32_b0);
|
| 823 |
+
__m256i res_1 = _mm256_sub_epi32(int32_val1, int32_b1);
|
| 824 |
+
__m256i res_2 = _mm256_sub_epi32(int32_val2, int32_b2);
|
| 825 |
+
__m256i res_3 = _mm256_sub_epi32(int32_val3, int32_b3);
|
| 826 |
+
return {Vectorized<c10::qint32>(res_0),
|
| 827 |
+
Vectorized<c10::qint32>(res_1),
|
| 828 |
+
Vectorized<c10::qint32>(res_2),
|
| 829 |
+
Vectorized<c10::qint32>(res_3)};
|
| 830 |
+
}
|
| 831 |
+
|
| 832 |
+
static Vectorized<c10::quint8> requantize_from_int(
|
| 833 |
+
const int_vec_return_type& inp,
|
| 834 |
+
float multiplier,
|
| 835 |
+
int32_t zero_point) {
|
| 836 |
+
__m256 multiplier_v = _mm256_set1_ps(multiplier);
|
| 837 |
+
__m256i zero_point_v = _mm256_set1_epi32(zero_point);
|
| 838 |
+
return RequantizeAvx2<value_type>(inp, multiplier_v, zero_point_v);
|
| 839 |
+
}
|
| 840 |
+
|
| 841 |
+
private:
|
| 842 |
+
|
| 843 |
+
// Load from memory constructor
|
| 844 |
+
Vectorized(const void* ptr) {
|
| 845 |
+
vals = _mm256_loadu_si256((const __m256i*)ptr);
|
| 846 |
+
}
|
| 847 |
+
};
|
| 848 |
+
|
| 849 |
+
template <>
|
| 850 |
+
Vectorized<c10::quint8> inline maximum(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 851 |
+
return a.maximum(b);
|
| 852 |
+
}
|
| 853 |
+
|
| 854 |
+
#elif !defined(CPU_CAPABILITY_SVE256)
|
| 855 |
+
|
| 856 |
+
// NOTE: These are low-performance implementations that we fall back on
|
| 857 |
+
// if we are not building with AVX2. This may not be an issue, because
|
| 858 |
+
// currently for quantization we assume the user has at least AVX512
|
| 859 |
+
// installed, so these can simply act as a reference implementation.
|
| 860 |
+
//
|
| 861 |
+
// If in the future we relax this requirement (AVX2+), we should probably
|
| 862 |
+
// revisit these implementations
|
| 863 |
+
|
| 864 |
+
template <
|
| 865 |
+
typename T,
|
| 866 |
+
typename float_vec_return_type_,
|
| 867 |
+
typename int_vec_return_type_,
|
| 868 |
+
int size_>
|
| 869 |
+
struct VectorizedQuantizedConverter {
|
| 870 |
+
static constexpr int size() {
|
| 871 |
+
return size_;
|
| 872 |
+
}
|
| 873 |
+
|
| 874 |
+
static constexpr int float_num_vecs() {
|
| 875 |
+
return size_ / Vectorized<float>::size();
|
| 876 |
+
}
|
| 877 |
+
|
| 878 |
+
static constexpr int int_num_vecs() {
|
| 879 |
+
return size_ / Vectorized<int>::size();
|
| 880 |
+
}
|
| 881 |
+
|
| 882 |
+
using float_vec_return_type = float_vec_return_type_;
|
| 883 |
+
using int_vec_return_type = int_vec_return_type_;
|
| 884 |
+
|
| 885 |
+
using value_type = typename T::underlying;
|
| 886 |
+
std::array<value_type, size_> vals;
|
| 887 |
+
|
| 888 |
+
VectorizedQuantizedConverter(T val) {
|
| 889 |
+
for (const auto i : c10::irange(size())) {
|
| 890 |
+
vals[i] = val.val_;
|
| 891 |
+
}
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
VectorizedQuantizedConverter(const void* ptr) {
|
| 895 |
+
memcpy(vals.data(), ptr, sizeof(value_type) * size());
|
| 896 |
+
}
|
| 897 |
+
|
| 898 |
+
void store(void* ptr, int count = size()) const {
|
| 899 |
+
memcpy(ptr, vals.data(), count * sizeof(value_type));
|
| 900 |
+
}
|
| 901 |
+
|
| 902 |
+
float_vec_return_type dequantize(
|
| 903 |
+
Vectorized<float> scale,
|
| 904 |
+
Vectorized<float> zero_point,
|
| 905 |
+
Vectorized<float> /*scale_zp_premul*/) const {
|
| 906 |
+
float_vec_return_type rv;
|
| 907 |
+
for (const auto i : c10::irange(float_num_vecs())) {
|
| 908 |
+
float tmp_vals[Vectorized<float>::size()];
|
| 909 |
+
for (const auto j : c10::irange(Vectorized<float>::size())) {
|
| 910 |
+
tmp_vals[j] = at::native::dequantize_val<T>(
|
| 911 |
+
scale[j], zero_point[j], T(vals[Vectorized<float>::size() * i + j]));
|
| 912 |
+
}
|
| 913 |
+
rv[i] = Vectorized<float>(tmp_vals);
|
| 914 |
+
}
|
| 915 |
+
return rv;
|
| 916 |
+
}
|
| 917 |
+
|
| 918 |
+
float_vec_return_type dequantize(
|
| 919 |
+
Vectorized<float> scale,
|
| 920 |
+
Vectorized<float> zero_point) const {
|
| 921 |
+
Vectorized<float> scale_zp_premul;
|
| 922 |
+
return dequantize(scale, zero_point, scale_zp_premul);
|
| 923 |
+
}
|
| 924 |
+
|
| 925 |
+
protected:
|
| 926 |
+
VectorizedQuantizedConverter() {}
|
| 927 |
+
};
|
| 928 |
+
|
| 929 |
+
template <>
|
| 930 |
+
struct Vectorized<c10::qint32> : public VectorizedQuantizedConverter<
|
| 931 |
+
c10::qint32,
|
| 932 |
+
std::array<Vectorized<float>, 1>,
|
| 933 |
+
std::array<Vectorized<c10::qint32>, 1>,
|
| 934 |
+
Vectorized<int>::size()> {
|
| 935 |
+
using VectorizedQuantizedConverter::VectorizedQuantizedConverter;
|
| 936 |
+
|
| 937 |
+
static Vectorized<c10::qint32> loadu(const void* ptr) {
|
| 938 |
+
return Vectorized<c10::qint32>(ptr);
|
| 939 |
+
}
|
| 940 |
+
|
| 941 |
+
static Vectorized<c10::qint32> loadu(const void* ptr, int64_t count) {
|
| 942 |
+
__at_align__ value_type tmp_values[size()];
|
| 943 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 944 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 945 |
+
// instructions while a loop would be compiled to one instruction.
|
| 946 |
+
for (const auto i : c10::irange(size())) {
|
| 947 |
+
tmp_values[i] = 0;
|
| 948 |
+
}
|
| 949 |
+
std::memcpy(
|
| 950 |
+
tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 951 |
+
return Vectorized<c10::qint32>(tmp_values);
|
| 952 |
+
}
|
| 953 |
+
|
| 954 |
+
static Vectorized<c10::qint32> quantize(
|
| 955 |
+
const float_vec_return_type& rhs,
|
| 956 |
+
float scale,
|
| 957 |
+
int32_t zero_point,
|
| 958 |
+
float /*inverse_scale*/) {
|
| 959 |
+
std::array<value_type, size()> qvals;
|
| 960 |
+
std::array<float, float_num_vecs() * Vectorized<float>::size()> float_vals;
|
| 961 |
+
|
| 962 |
+
for (const auto i : c10::irange(float_num_vecs())) {
|
| 963 |
+
rhs[i].store(&float_vals[i * Vectorized<float>::size()]);
|
| 964 |
+
}
|
| 965 |
+
|
| 966 |
+
at::native::quantize_vec<c10::qint32, /*precision=*/32>(
|
| 967 |
+
scale,
|
| 968 |
+
zero_point,
|
| 969 |
+
float_vals.data(),
|
| 970 |
+
(c10::qint32*)qvals.data(),
|
| 971 |
+
float_vals.size());
|
| 972 |
+
|
| 973 |
+
return Vectorized<c10::qint32>::loadu(qvals.data());
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
+
Vectorized<c10::qint32> maximum(Vectorized<c10::qint32> b) const {
|
| 977 |
+
Vectorized<c10::qint32> retval;
|
| 978 |
+
for (const auto i : c10::irange(size())) {
|
| 979 |
+
retval.vals[i] = std::max<value_type>(vals[i], b.vals[i]);
|
| 980 |
+
}
|
| 981 |
+
return retval;
|
| 982 |
+
}
|
| 983 |
+
|
| 984 |
+
Vectorized<c10::qint32> minimum(Vectorized<c10::qint32> b) const {
|
| 985 |
+
Vectorized<c10::qint32> retval;
|
| 986 |
+
for (const auto i : c10::irange(size())) {
|
| 987 |
+
retval.vals[i] = std::min<value_type>(vals[i], b.vals[i]);
|
| 988 |
+
}
|
| 989 |
+
return retval;
|
| 990 |
+
}
|
| 991 |
+
|
| 992 |
+
Vectorized<c10::qint32> relu(Vectorized<c10::qint32> zero_point) const {
|
| 993 |
+
return maximum(zero_point);
|
| 994 |
+
}
|
| 995 |
+
|
| 996 |
+
|
| 997 |
+
Vectorized<c10::qint32> relu6(
|
| 998 |
+
Vectorized<c10::qint32> zero_point,
|
| 999 |
+
Vectorized<c10::qint32> q_six) {
|
| 1000 |
+
Vectorized<c10::qint32> retval;
|
| 1001 |
+
for (const auto i : c10::irange(size())) {
|
| 1002 |
+
retval.vals[i] = std::min<value_type>(
|
| 1003 |
+
std::max<value_type>(vals[i], zero_point.vals[i]), q_six.vals[i]);
|
| 1004 |
+
}
|
| 1005 |
+
return retval;
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
int_vec_return_type widening_subtract(Vectorized<c10::qint32> b) const {
|
| 1009 |
+
int_vec_return_type retval;
|
| 1010 |
+
for (const auto i : c10::irange(size())) {
|
| 1011 |
+
retval[0].vals[i] = vals[i] - b.vals[i];
|
| 1012 |
+
}
|
| 1013 |
+
return retval;
|
| 1014 |
+
}
|
| 1015 |
+
|
| 1016 |
+
static Vectorized<c10::qint32> requantize_from_int(
|
| 1017 |
+
const int_vec_return_type& inp,
|
| 1018 |
+
float multiplier,
|
| 1019 |
+
int32_t zero_point) {
|
| 1020 |
+
Vectorized<c10::qint32> retval;
|
| 1021 |
+
for (const auto i : c10::irange(size())) {
|
| 1022 |
+
retval.vals[i] =
|
| 1023 |
+
std::nearbyint(static_cast<float>(inp[0].vals[i]) * multiplier) +
|
| 1024 |
+
zero_point;
|
| 1025 |
+
}
|
| 1026 |
+
return retval;
|
| 1027 |
+
}
|
| 1028 |
+
};
|
| 1029 |
+
|
| 1030 |
+
template <>
|
| 1031 |
+
Vectorized<c10::qint32> inline maximum(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 1032 |
+
return a.maximum(b);
|
| 1033 |
+
}
|
| 1034 |
+
|
| 1035 |
+
template <>
|
| 1036 |
+
Vectorized<c10::qint32> inline operator*(
|
| 1037 |
+
const Vectorized<c10::qint32>& a,
|
| 1038 |
+
const Vectorized<c10::qint32>& b) {
|
| 1039 |
+
Vectorized<c10::qint32> retval;
|
| 1040 |
+
for (const auto i : c10::irange(std::decay_t<decltype(a)>::size())) {
|
| 1041 |
+
retval.vals[i] = a.vals[i] * b.vals[i];
|
| 1042 |
+
}
|
| 1043 |
+
return retval;
|
| 1044 |
+
}
|
| 1045 |
+
|
| 1046 |
+
template <>
|
| 1047 |
+
Vectorized<c10::qint32> inline operator+(
|
| 1048 |
+
const Vectorized<c10::qint32>& a,
|
| 1049 |
+
const Vectorized<c10::qint32>& b) {
|
| 1050 |
+
Vectorized<c10::qint32> retval;
|
| 1051 |
+
for (const auto i : c10::irange(std::decay_t<decltype(a)>::size())) {
|
| 1052 |
+
retval.vals[i] = a.vals[i] + b.vals[i];
|
| 1053 |
+
}
|
| 1054 |
+
return retval;
|
| 1055 |
+
}
|
| 1056 |
+
|
| 1057 |
+
template <>
|
| 1058 |
+
struct Vectorized<c10::qint8> : public VectorizedQuantizedConverter<
|
| 1059 |
+
c10::qint8,
|
| 1060 |
+
std::array<Vectorized<float>, 4>,
|
| 1061 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 1062 |
+
4 * Vectorized<float>::size()> {
|
| 1063 |
+
using VectorizedQuantizedConverter::VectorizedQuantizedConverter;
|
| 1064 |
+
|
| 1065 |
+
static Vectorized<c10::qint8> loadu(const void* ptr) {
|
| 1066 |
+
return Vectorized<c10::qint8>(ptr);
|
| 1067 |
+
}
|
| 1068 |
+
|
| 1069 |
+
static Vectorized<c10::qint8> loadu(const void* ptr, int64_t count) {
|
| 1070 |
+
__at_align__ value_type tmp_values[size()];
|
| 1071 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 1072 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 1073 |
+
// instructions while a loop would be compiled to one instruction.
|
| 1074 |
+
for (const auto i : c10::irange(size())) {
|
| 1075 |
+
tmp_values[i] = 0;
|
| 1076 |
+
}
|
| 1077 |
+
std::memcpy(
|
| 1078 |
+
tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 1079 |
+
return Vectorized<c10::qint8>(tmp_values);
|
| 1080 |
+
}
|
| 1081 |
+
|
| 1082 |
+
static Vectorized<c10::qint8> quantize(
|
| 1083 |
+
const float_vec_return_type& rhs,
|
| 1084 |
+
float scale,
|
| 1085 |
+
int32_t zero_point,
|
| 1086 |
+
float /*inverse_scale*/) {
|
| 1087 |
+
std::array<value_type, size()> qvals;
|
| 1088 |
+
std::array<float, float_num_vecs() * Vectorized<float>::size()> float_vals;
|
| 1089 |
+
|
| 1090 |
+
for (const auto i : c10::irange(float_num_vecs())) {
|
| 1091 |
+
rhs[i].store(&float_vals[i * Vectorized<float>::size()]);
|
| 1092 |
+
}
|
| 1093 |
+
|
| 1094 |
+
at::native::quantize_vec<c10::qint8>(
|
| 1095 |
+
scale,
|
| 1096 |
+
zero_point,
|
| 1097 |
+
float_vals.data(),
|
| 1098 |
+
(c10::qint8*)qvals.data(),
|
| 1099 |
+
float_vals.size());
|
| 1100 |
+
|
| 1101 |
+
return Vectorized<c10::qint8>::loadu(qvals.data());
|
| 1102 |
+
}
|
| 1103 |
+
|
| 1104 |
+
Vectorized<c10::qint8> maximum(Vectorized<c10::qint8> b) const {
|
| 1105 |
+
Vectorized<c10::qint8> retval;
|
| 1106 |
+
for (const auto i : c10::irange(size())) {
|
| 1107 |
+
retval.vals[i] = std::max<value_type>(vals[i], b.vals[i]);
|
| 1108 |
+
}
|
| 1109 |
+
return retval;
|
| 1110 |
+
}
|
| 1111 |
+
|
| 1112 |
+
Vectorized<c10::qint8> minimum(Vectorized<c10::qint8> b) const {
|
| 1113 |
+
Vectorized<c10::qint8> retval;
|
| 1114 |
+
for (const auto i : c10::irange(size())) {
|
| 1115 |
+
retval.vals[i] = std::min<value_type>(vals[i], b.vals[i]);
|
| 1116 |
+
}
|
| 1117 |
+
return retval;
|
| 1118 |
+
}
|
| 1119 |
+
|
| 1120 |
+
Vectorized<c10::qint8> relu(Vectorized<c10::qint8> zero_point) const {
|
| 1121 |
+
return maximum(zero_point);
|
| 1122 |
+
}
|
| 1123 |
+
|
| 1124 |
+
Vectorized<c10::qint8> relu6(
|
| 1125 |
+
Vectorized<c10::qint8> zero_point,
|
| 1126 |
+
Vectorized<c10::qint8> q_six) {
|
| 1127 |
+
Vectorized<c10::qint8> retval;
|
| 1128 |
+
for (const auto i : c10::irange(size())) {
|
| 1129 |
+
retval.vals[i] = std::min<value_type>(
|
| 1130 |
+
std::max<value_type>(vals[i], zero_point.vals[i]), q_six.vals[i]);
|
| 1131 |
+
}
|
| 1132 |
+
return retval;
|
| 1133 |
+
}
|
| 1134 |
+
|
| 1135 |
+
int_vec_return_type widening_subtract(Vectorized<c10::qint8> b) const {
|
| 1136 |
+
int_vec_return_type retval;
|
| 1137 |
+
constexpr int elem_per_int_vec = size() / int_num_vecs();
|
| 1138 |
+
for (const auto i : c10::irange(int_num_vecs())) {
|
| 1139 |
+
for (const auto j : c10::irange(elem_per_int_vec)) {
|
| 1140 |
+
retval[i].vals[j] =
|
| 1141 |
+
static_cast<int32_t>(vals[i * elem_per_int_vec + j]) -
|
| 1142 |
+
static_cast<int32_t>(b.vals[i * elem_per_int_vec + j]);
|
| 1143 |
+
}
|
| 1144 |
+
}
|
| 1145 |
+
return retval;
|
| 1146 |
+
}
|
| 1147 |
+
static Vectorized<c10::qint8> requantize_from_int(
|
| 1148 |
+
const int_vec_return_type& inp,
|
| 1149 |
+
float multiplier,
|
| 1150 |
+
int32_t zero_point) {
|
| 1151 |
+
constexpr int elem_per_int_vec = size() / int_num_vecs();
|
| 1152 |
+
constexpr auto min_val = std::numeric_limits<value_type>::min();
|
| 1153 |
+
constexpr auto max_val = std::numeric_limits<value_type>::max();
|
| 1154 |
+
Vectorized<c10::qint8> retval;
|
| 1155 |
+
for (const auto i : c10::irange(int_num_vecs())) {
|
| 1156 |
+
for (const auto j : c10::irange(elem_per_int_vec)) {
|
| 1157 |
+
int32_t rounded =
|
| 1158 |
+
std::nearbyint(static_cast<float>(inp[i].vals[j]) * multiplier) +
|
| 1159 |
+
zero_point;
|
| 1160 |
+
retval.vals[i * elem_per_int_vec + j] =
|
| 1161 |
+
std::min<int32_t>(std::max<int32_t>(rounded, min_val), max_val);
|
| 1162 |
+
}
|
| 1163 |
+
}
|
| 1164 |
+
return retval;
|
| 1165 |
+
}
|
| 1166 |
+
};
|
| 1167 |
+
|
| 1168 |
+
template <>
|
| 1169 |
+
Vectorized<c10::qint8> inline maximum(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 1170 |
+
return a.maximum(b);
|
| 1171 |
+
}
|
| 1172 |
+
|
| 1173 |
+
template <>
|
| 1174 |
+
struct Vectorized<c10::quint8> : public VectorizedQuantizedConverter<
|
| 1175 |
+
c10::quint8,
|
| 1176 |
+
std::array<Vectorized<float>, 4>,
|
| 1177 |
+
std::array<Vectorized<c10::qint32>, 4>,
|
| 1178 |
+
4 * Vectorized<float>::size()> {
|
| 1179 |
+
using VectorizedQuantizedConverter::VectorizedQuantizedConverter;
|
| 1180 |
+
|
| 1181 |
+
static Vectorized<c10::quint8> loadu(const void* ptr) {
|
| 1182 |
+
return Vectorized<c10::quint8>(ptr);
|
| 1183 |
+
}
|
| 1184 |
+
|
| 1185 |
+
static Vectorized<c10::quint8> loadu(const void* ptr, int64_t count) {
|
| 1186 |
+
__at_align__ value_type tmp_values[size()];
|
| 1187 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 1188 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 1189 |
+
// instructions while a loop would be compiled to one instruction.
|
| 1190 |
+
for (const auto i : c10::irange(size())) {
|
| 1191 |
+
tmp_values[i] = 0;
|
| 1192 |
+
}
|
| 1193 |
+
std::memcpy(
|
| 1194 |
+
tmp_values, reinterpret_cast<const value_type*>(ptr), count * sizeof(value_type));
|
| 1195 |
+
return Vectorized<c10::quint8>(tmp_values);
|
| 1196 |
+
}
|
| 1197 |
+
|
| 1198 |
+
static Vectorized<c10::quint8> quantize(
|
| 1199 |
+
const float_vec_return_type& rhs,
|
| 1200 |
+
float scale,
|
| 1201 |
+
int32_t zero_point,
|
| 1202 |
+
float /*inverse_scale*/) {
|
| 1203 |
+
std::array<value_type, size()> qvals;
|
| 1204 |
+
std::array<float, float_num_vecs() * Vectorized<float>::size()> float_vals;
|
| 1205 |
+
|
| 1206 |
+
for (const auto i : c10::irange(float_num_vecs())) {
|
| 1207 |
+
rhs[i].store(&float_vals[i * Vectorized<float>::size()]);
|
| 1208 |
+
}
|
| 1209 |
+
|
| 1210 |
+
at::native::quantize_vec<c10::quint8>(
|
| 1211 |
+
scale,
|
| 1212 |
+
zero_point,
|
| 1213 |
+
float_vals.data(),
|
| 1214 |
+
(c10::quint8*)qvals.data(),
|
| 1215 |
+
float_vals.size());
|
| 1216 |
+
|
| 1217 |
+
return Vectorized<c10::quint8>::loadu(qvals.data());
|
| 1218 |
+
}
|
| 1219 |
+
|
| 1220 |
+
Vectorized<c10::quint8> maximum(Vectorized<c10::quint8> b) const {
|
| 1221 |
+
Vectorized<c10::quint8> retval;
|
| 1222 |
+
for (const auto i : c10::irange(size())) {
|
| 1223 |
+
retval.vals[i] = std::max<value_type>(vals[i], b.vals[i]);
|
| 1224 |
+
}
|
| 1225 |
+
return retval;
|
| 1226 |
+
}
|
| 1227 |
+
|
| 1228 |
+
Vectorized<c10::quint8> minimum(Vectorized<c10::quint8> b) const {
|
| 1229 |
+
Vectorized<c10::quint8> retval;
|
| 1230 |
+
for (const auto i : c10::irange(size())) {
|
| 1231 |
+
retval.vals[i] = std::min<value_type>(vals[i], b.vals[i]);
|
| 1232 |
+
}
|
| 1233 |
+
return retval;
|
| 1234 |
+
}
|
| 1235 |
+
|
| 1236 |
+
Vectorized<c10::quint8> relu(Vectorized<c10::quint8> zero_point) const {
|
| 1237 |
+
return maximum(zero_point);
|
| 1238 |
+
}
|
| 1239 |
+
|
| 1240 |
+
|
| 1241 |
+
Vectorized<c10::quint8> relu6(
|
| 1242 |
+
Vectorized<c10::quint8> zero_point,
|
| 1243 |
+
Vectorized<c10::quint8> q_six) {
|
| 1244 |
+
Vectorized<c10::quint8> retval;
|
| 1245 |
+
for (const auto i : c10::irange(size())) {
|
| 1246 |
+
retval.vals[i] = std::min<value_type>(
|
| 1247 |
+
std::max<value_type>(vals[i], zero_point.vals[i]), q_six.vals[i]);
|
| 1248 |
+
}
|
| 1249 |
+
return retval;
|
| 1250 |
+
}
|
| 1251 |
+
|
| 1252 |
+
int_vec_return_type widening_subtract(Vectorized<c10::quint8> b) const {
|
| 1253 |
+
int_vec_return_type retval;
|
| 1254 |
+
constexpr int elem_per_int_vec = size() / int_num_vecs();
|
| 1255 |
+
for (const auto i : c10::irange(int_num_vecs())) {
|
| 1256 |
+
for (const auto j : c10::irange(elem_per_int_vec)) {
|
| 1257 |
+
retval[i].vals[j] =
|
| 1258 |
+
static_cast<int32_t>(vals[i * elem_per_int_vec + j]) -
|
| 1259 |
+
static_cast<int32_t>(b.vals[i * elem_per_int_vec + j]);
|
| 1260 |
+
}
|
| 1261 |
+
}
|
| 1262 |
+
return retval;
|
| 1263 |
+
}
|
| 1264 |
+
static Vectorized<c10::quint8> requantize_from_int(
|
| 1265 |
+
const int_vec_return_type& inp,
|
| 1266 |
+
float multiplier,
|
| 1267 |
+
int32_t zero_point) {
|
| 1268 |
+
constexpr int elem_per_int_vec = size() / int_num_vecs();
|
| 1269 |
+
constexpr auto min_val = std::numeric_limits<value_type>::min();
|
| 1270 |
+
constexpr auto max_val = std::numeric_limits<value_type>::max();
|
| 1271 |
+
Vectorized<c10::quint8> retval;
|
| 1272 |
+
for (const auto i : c10::irange(int_num_vecs())) {
|
| 1273 |
+
for (const auto j : c10::irange(elem_per_int_vec)) {
|
| 1274 |
+
int32_t rounded =
|
| 1275 |
+
std::nearbyint(static_cast<float>(inp[i].vals[j]) * multiplier) +
|
| 1276 |
+
zero_point;
|
| 1277 |
+
retval.vals[i * elem_per_int_vec + j] =
|
| 1278 |
+
std::min<int32_t>(std::max<int32_t>(rounded, min_val), max_val);
|
| 1279 |
+
}
|
| 1280 |
+
}
|
| 1281 |
+
return retval;
|
| 1282 |
+
}
|
| 1283 |
+
};
|
| 1284 |
+
|
| 1285 |
+
template <>
|
| 1286 |
+
Vectorized<c10::quint8> inline maximum(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 1287 |
+
return a.maximum(b);
|
| 1288 |
+
}
|
| 1289 |
+
|
| 1290 |
+
#endif // if defined(CPU_CAPABILITY_AVX2)
|
| 1291 |
+
|
| 1292 |
+
#if (defined(__aarch64__) && !defined(CPU_CAPABILITY_SVE256))
|
| 1293 |
+
std::pair<Vectorized<float>, Vectorized<float>>
|
| 1294 |
+
inline convert_int8_to_float(at::vec::Vectorized<int8_t> src) {
|
| 1295 |
+
auto s8x8 = vld1_s8(src.operator const int8_t*());
|
| 1296 |
+
auto s16x8 = vmovl_s8(s8x8);
|
| 1297 |
+
|
| 1298 |
+
auto s32x4_hi = vmovl_s16(vget_high_s16(s16x8));
|
| 1299 |
+
auto s32x4_lo = vmovl_s16(vget_low_s16(s16x8));
|
| 1300 |
+
|
| 1301 |
+
return std::make_pair(Vectorized<float>(vcvtq_f32_s32(s32x4_lo)), Vectorized<float>(vcvtq_f32_s32(s32x4_hi)));
|
| 1302 |
+
}
|
| 1303 |
+
|
| 1304 |
+
std::pair<Vectorized<float>, Vectorized<float>>
|
| 1305 |
+
inline convert_int8_to_float(at::vec::Vectorized<uint8_t> src) {
|
| 1306 |
+
auto u8x8 = vld1_u8(src.operator const uint8_t*());
|
| 1307 |
+
auto u16x8 = vmovl_u8(u8x8);
|
| 1308 |
+
auto u32x4_hi = vmovl_u16(vget_high_u16(u16x8));
|
| 1309 |
+
auto u32x4_lo = vmovl_u16(vget_low_u16(u16x8));
|
| 1310 |
+
|
| 1311 |
+
return std::make_pair(Vectorized<float>(vcvtq_f32_u32(u32x4_lo)), Vectorized<float>(vcvtq_f32_u32(u32x4_hi)));
|
| 1312 |
+
}
|
| 1313 |
+
|
| 1314 |
+
Vectorized<float>
|
| 1315 |
+
inline convert_int8_half_register_to_float(at::vec::Vectorized<int8_t> src) {
|
| 1316 |
+
auto s8x8 = vld1_s8(src.operator const int8_t*());
|
| 1317 |
+
auto s16x8 = vmovl_s8(s8x8);
|
| 1318 |
+
|
| 1319 |
+
auto s32x4_lo = vmovl_s16(vget_low_s16(s16x8));
|
| 1320 |
+
|
| 1321 |
+
return Vectorized<float>(vcvtq_f32_s32(s32x4_lo));
|
| 1322 |
+
}
|
| 1323 |
+
|
| 1324 |
+
Vectorized<float>
|
| 1325 |
+
inline convert_int8_half_register_to_float(at::vec::Vectorized<uint8_t> src) {
|
| 1326 |
+
auto u8x8 = vld1_u8(src.operator const uint8_t*());
|
| 1327 |
+
auto u16x8 = vmovl_u8(u8x8);
|
| 1328 |
+
auto u32x4_lo = vmovl_u16(vget_low_u16(u16x8));
|
| 1329 |
+
|
| 1330 |
+
return Vectorized<float>(vcvtq_f32_u32(u32x4_lo));
|
| 1331 |
+
}
|
| 1332 |
+
|
| 1333 |
+
#endif
|
| 1334 |
+
}} // namespace at::vec::CPU_CAPABILITY
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_bfloat16_vsx.h
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 6 |
+
#include <c10/util/irange.h>
|
| 7 |
+
|
| 8 |
+
namespace at {
|
| 9 |
+
namespace vec {
|
| 10 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 11 |
+
inline namespace CPU_CAPABILITY {
|
| 12 |
+
|
| 13 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_bfloat16_float(
|
| 14 |
+
const Vectorized<BFloat16>& a) {
|
| 15 |
+
constexpr int64_t K = Vectorized<BFloat16>::size();
|
| 16 |
+
__at_align__ float arr[K];
|
| 17 |
+
__at_align__ BFloat16 arr2[K];
|
| 18 |
+
a.store(arr2);
|
| 19 |
+
convert(arr2, arr, K);
|
| 20 |
+
return std::make_tuple(
|
| 21 |
+
Vectorized<float>::loadu(arr),
|
| 22 |
+
Vectorized<float>::loadu(arr + Vectorized<float>::size()));
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
inline Vectorized<BFloat16> convert_float_bfloat16(
|
| 26 |
+
const Vectorized<float>& a,
|
| 27 |
+
const Vectorized<float>& b) {
|
| 28 |
+
constexpr int64_t K = Vectorized<BFloat16>::size();
|
| 29 |
+
__at_align__ float arr[K];
|
| 30 |
+
__at_align__ BFloat16 arr2[K];
|
| 31 |
+
a.store(arr);
|
| 32 |
+
b.store(arr + Vectorized<float>::size());
|
| 33 |
+
convert(arr, arr2, K);
|
| 34 |
+
return Vectorized<BFloat16>::loadu(arr2);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
inline void load_fp32_from_bf16(const c10::BFloat16* data, Vectorized<float>& out) {
|
| 38 |
+
__at_align__ float values[Vectorized<float>::size()];
|
| 39 |
+
for (const auto k : c10::irange(Vectorized<float>::size())) {
|
| 40 |
+
values[k] = data[k];
|
| 41 |
+
}
|
| 42 |
+
out = Vectorized<float>::loadu(values);
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
inline void load_fp32_from_bf16(
|
| 46 |
+
const c10::BFloat16* data,
|
| 47 |
+
Vectorized<float>& out1,
|
| 48 |
+
Vectorized<float>& out2) {
|
| 49 |
+
load_fp32_from_bf16(data, out1);
|
| 50 |
+
data += Vectorized<float>::size();
|
| 51 |
+
load_fp32_from_bf16(data, out2);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
inline void load_fp32_from_fp16(const c10::Half* data, Vectorized<float>& out) {
|
| 55 |
+
__at_align__ float values[Vectorized<float>::size()];
|
| 56 |
+
for (const auto k : c10::irange(Vectorized<float>::size())) {
|
| 57 |
+
values[k] = data[k];
|
| 58 |
+
}
|
| 59 |
+
out = Vectorized<float>::loadu(values);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
inline void load_fp32_from_fp16(
|
| 63 |
+
const c10::Half* data,
|
| 64 |
+
Vectorized<float>& out1,
|
| 65 |
+
Vectorized<float>& out2) {
|
| 66 |
+
load_fp32_from_fp16(data, out1);
|
| 67 |
+
data += Vectorized<float>::size();
|
| 68 |
+
load_fp32_from_fp16(data, out2);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
} // namespace
|
| 72 |
+
} // namespace vec
|
| 73 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_common_vsx.h
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
|
| 7 |
+
// Note: header order is important here
|
| 8 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_double_vsx.h>
|
| 9 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_float_vsx.h>
|
| 10 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_int16_vsx.h>
|
| 11 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_int32_vsx.h>
|
| 12 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_int64_vsx.h>
|
| 13 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_qint32_vsx.h>
|
| 14 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_qint8_vsx.h>
|
| 15 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_quint8_vsx.h>
|
| 16 |
+
|
| 17 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_complex_float_vsx.h>
|
| 18 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_complex_double_vsx.h>
|
| 19 |
+
|
| 20 |
+
#include <ATen/cpu/vec/vec256/vsx/vec256_bfloat16_vsx.h>
|
| 21 |
+
|
| 22 |
+
namespace at {
|
| 23 |
+
namespace vec {
|
| 24 |
+
|
| 25 |
+
inline namespace CPU_CAPABILITY {
|
| 26 |
+
|
| 27 |
+
DEFINE_CLAMP_FUNCS(c10::quint8)
|
| 28 |
+
DEFINE_CLAMP_FUNCS(c10::qint8)
|
| 29 |
+
DEFINE_CLAMP_FUNCS(c10::qint32)
|
| 30 |
+
DEFINE_CLAMP_FUNCS(int16_t)
|
| 31 |
+
DEFINE_CLAMP_FUNCS(int32_t)
|
| 32 |
+
DEFINE_CLAMP_FUNCS(int64_t)
|
| 33 |
+
DEFINE_CLAMP_FUNCS(float)
|
| 34 |
+
DEFINE_CLAMP_FUNCS(double)
|
| 35 |
+
|
| 36 |
+
template <>
|
| 37 |
+
Vectorized<double> C10_ALWAYS_INLINE fmadd(
|
| 38 |
+
const Vectorized<double>& a,
|
| 39 |
+
const Vectorized<double>& b,
|
| 40 |
+
const Vectorized<double>& c) {
|
| 41 |
+
return Vectorized<double>{
|
| 42 |
+
vec_madd(a.vec0(), b.vec0(), c.vec0()),
|
| 43 |
+
vec_madd(a.vec1(), b.vec1(), c.vec1())};
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
template <>
|
| 47 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE fmadd(
|
| 48 |
+
const Vectorized<int64_t>& a,
|
| 49 |
+
const Vectorized<int64_t>& b,
|
| 50 |
+
const Vectorized<int64_t>& c) {
|
| 51 |
+
return Vectorized<int64_t>{
|
| 52 |
+
a.vec0() * b.vec0() + c.vec0(), a.vec1() * b.vec1() + c.vec1()};
|
| 53 |
+
}
|
| 54 |
+
template <>
|
| 55 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE fmadd(
|
| 56 |
+
const Vectorized<int32_t>& a,
|
| 57 |
+
const Vectorized<int32_t>& b,
|
| 58 |
+
const Vectorized<int32_t>& c) {
|
| 59 |
+
return Vectorized<int32_t>{
|
| 60 |
+
a.vec0() * b.vec0() + c.vec0(), a.vec1() * b.vec1() + c.vec1()};
|
| 61 |
+
}
|
| 62 |
+
template <>
|
| 63 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE fmadd(
|
| 64 |
+
const Vectorized<int16_t>& a,
|
| 65 |
+
const Vectorized<int16_t>& b,
|
| 66 |
+
const Vectorized<int16_t>& c) {
|
| 67 |
+
return Vectorized<int16_t>{
|
| 68 |
+
a.vec0() * b.vec0() + c.vec0(), a.vec1() * b.vec1() + c.vec1()};
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
DEFINE_REINTERPRET_CAST_TO_ALL_FUNCS(float)
|
| 72 |
+
DEFINE_REINTERPRET_CAST_TO_ALL_FUNCS(double)
|
| 73 |
+
DEFINE_REINTERPRET_CAST_TO_ALL_FUNCS(int64_t)
|
| 74 |
+
DEFINE_REINTERPRET_CAST_TO_ALL_FUNCS(int32_t)
|
| 75 |
+
DEFINE_REINTERPRET_CAST_TO_ALL_FUNCS(int16_t)
|
| 76 |
+
|
| 77 |
+
template <>
|
| 78 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE
|
| 79 |
+
convert_to_int_of_same_size<double>(const Vectorized<double>& src) {
|
| 80 |
+
return Vectorized<int64_t>{vec_signed(src.vec0()), vec_signed(src.vec1())};
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
template <>
|
| 84 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE
|
| 85 |
+
convert_to_int_of_same_size<float>(
|
| 86 |
+
const Vectorized<float>& src) {
|
| 87 |
+
return Vectorized<int32_t>{vec_signed(src.vec0()), vec_signed(src.vec1())};
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
template <>
|
| 91 |
+
inline void convert(const int32_t* src, float* dst, int64_t n) {
|
| 92 |
+
// int32_t and float have same size
|
| 93 |
+
int64_t i;
|
| 94 |
+
for (i = 0; i <= (n - Vectorized<float>::size()); i += Vectorized<float>::size()) {
|
| 95 |
+
const int32_t* src_a = src + i;
|
| 96 |
+
float* dst_a = dst + i;
|
| 97 |
+
vint32 input_vec0 = vec_vsx_ld(offset0, reinterpret_cast<const vint32*>(src_a));
|
| 98 |
+
vint32 input_vec1 =
|
| 99 |
+
vec_vsx_ld(offset16, reinterpret_cast<const vint32*>(src_a));
|
| 100 |
+
vfloat32 c0 = vec_float(input_vec0);
|
| 101 |
+
vfloat32 c1 = vec_float(input_vec1);
|
| 102 |
+
vec_vsx_st(c0, offset0, dst_a);
|
| 103 |
+
vec_vsx_st(c1, offset16, dst_a);
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
for (; i < n; i++) {
|
| 107 |
+
dst[i] = static_cast<float>(src[i]);
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
template <>
|
| 112 |
+
inline void convert(const int64_t* src, double* dst, int64_t n) {
|
| 113 |
+
int64_t i;
|
| 114 |
+
for (i = 0; i <= (n - Vectorized<double>::size()); i += Vectorized<double>::size()) {
|
| 115 |
+
const int64_t* src_a = src + i;
|
| 116 |
+
double* dst_a = dst + i;
|
| 117 |
+
vint64 input_vec0 =
|
| 118 |
+
vec_vsx_ld(offset0, reinterpret_cast<const vint64*>(src_a));
|
| 119 |
+
vint64 input_vec1 =
|
| 120 |
+
vec_vsx_ld(offset16, reinterpret_cast<const vint64*>(src_a));
|
| 121 |
+
vfloat64 c0 = vec_double(input_vec0);
|
| 122 |
+
vfloat64 c1 = vec_double(input_vec1);
|
| 123 |
+
vec_vsx_st(c0, offset0, reinterpret_cast<double*>(dst_a));
|
| 124 |
+
vec_vsx_st(c1, offset16, reinterpret_cast<double*>(dst_a));
|
| 125 |
+
}
|
| 126 |
+
for (; i < n; i++) {
|
| 127 |
+
dst[i] = static_cast<double>(src[i]);
|
| 128 |
+
}
|
| 129 |
+
}
|
| 130 |
+
//Generic implementation to fix compiler error
|
| 131 |
+
//TO-DO : Add optimized version for ppc64
|
| 132 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_half_float(
|
| 133 |
+
const Vectorized<Half>& a) {
|
| 134 |
+
constexpr int64_t K = Vectorized<Half>::size();
|
| 135 |
+
__at_align__ float arr[K];
|
| 136 |
+
__at_align__ Half arr2[K];
|
| 137 |
+
a.store(arr2);
|
| 138 |
+
convert(arr2, arr, K);
|
| 139 |
+
return std::make_tuple(
|
| 140 |
+
Vectorized<float>::loadu(arr),
|
| 141 |
+
Vectorized<float>::loadu(arr + Vectorized<float>::size()));
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
inline Vectorized<Half> convert_float_half(
|
| 145 |
+
const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 146 |
+
constexpr int64_t K = Vectorized<Half>::size();
|
| 147 |
+
__at_align__ float arr[K];
|
| 148 |
+
__at_align__ Half arr2[K];
|
| 149 |
+
a.store(arr);
|
| 150 |
+
b.store(arr + Vectorized<float>::size());
|
| 151 |
+
convert(arr, arr2, K);
|
| 152 |
+
return Vectorized<Half>::loadu(arr2);
|
| 153 |
+
};
|
| 154 |
+
|
| 155 |
+
template <>
|
| 156 |
+
std::pair<Vectorized<double>, Vectorized<double>> inline interleave2<double>(
|
| 157 |
+
const Vectorized<double>& a,
|
| 158 |
+
const Vectorized<double>& b) {
|
| 159 |
+
// inputs:
|
| 160 |
+
// a = {a0, a1, a2, a3}
|
| 161 |
+
// b = {b0, b1, b2, b3}
|
| 162 |
+
|
| 163 |
+
vfloat64 ab00 = vec_xxpermdi(a.vec0(), b.vec0(), 0);
|
| 164 |
+
vfloat64 ab11 = vec_xxpermdi(a.vec0(), b.vec0(), 3);
|
| 165 |
+
vfloat64 ab2_00 = vec_xxpermdi(a.vec1(), b.vec1(), 0);
|
| 166 |
+
vfloat64 ab2_11 = vec_xxpermdi(a.vec1(), b.vec1(), 3);
|
| 167 |
+
// return {a0, b0, a1, b1}
|
| 168 |
+
// {a2, b2, a3, b3}
|
| 169 |
+
return std::make_pair(
|
| 170 |
+
Vectorized<double>{ab00, ab11}, Vectorized<double>{ab2_00, ab2_11});
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
template <>
|
| 174 |
+
std::pair<Vectorized<double>, Vectorized<double>> inline deinterleave2<double>(
|
| 175 |
+
const Vectorized<double>& a,
|
| 176 |
+
const Vectorized<double>& b) {
|
| 177 |
+
// inputs:
|
| 178 |
+
// a = {a0, b0, a1, b1}
|
| 179 |
+
// b = {a2, b2, a3, b3}
|
| 180 |
+
vfloat64 aa01 = vec_xxpermdi(a.vec0(), a.vec1(), 0);
|
| 181 |
+
vfloat64 aa23 = vec_xxpermdi(b.vec0(), b.vec1(), 0);
|
| 182 |
+
|
| 183 |
+
vfloat64 bb_01 = vec_xxpermdi(a.vec0(), a.vec1(), 3);
|
| 184 |
+
vfloat64 bb_23 = vec_xxpermdi(b.vec0(), b.vec1(), 3);
|
| 185 |
+
|
| 186 |
+
// swap lanes:
|
| 187 |
+
// return {a0, a1, a2, a3}
|
| 188 |
+
// {b0, b1, b2, b3}
|
| 189 |
+
return std::make_pair(
|
| 190 |
+
Vectorized<double>{aa01, aa23}, Vectorized<double>{bb_01, bb_23});
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
template <>
|
| 194 |
+
std::pair<Vectorized<float>, Vectorized<float>> inline interleave2<float>(
|
| 195 |
+
const Vectorized<float>& a,
|
| 196 |
+
const Vectorized<float>& b) {
|
| 197 |
+
// inputs:
|
| 198 |
+
// a = {a0, a1, a2, a3,, a4, a5, a6, a7}
|
| 199 |
+
// b = {b0, b1, b2, b3,, b4, b5, b6, b7}
|
| 200 |
+
|
| 201 |
+
vfloat32 ab0011 = vec_mergeh(a.vec0(), b.vec0());
|
| 202 |
+
vfloat32 ab2233 = vec_mergel(a.vec0(), b.vec0());
|
| 203 |
+
|
| 204 |
+
vfloat32 ab2_0011 = vec_mergeh(a.vec1(), b.vec1());
|
| 205 |
+
vfloat32 ab2_2233 = vec_mergel(a.vec1(), b.vec1());
|
| 206 |
+
// group cols crossing lanes:
|
| 207 |
+
// return {a0, b0, a1, b1,, a2, b2, a3, b3}
|
| 208 |
+
// {a4, b4, a5, b5,, a6, b6, a7, b7}
|
| 209 |
+
|
| 210 |
+
return std::make_pair(
|
| 211 |
+
Vectorized<float>{ab0011, ab2233}, Vectorized<float>{ab2_0011, ab2_2233});
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
template <>
|
| 215 |
+
std::pair<Vectorized<float>, Vectorized<float>> inline deinterleave2<float>(
|
| 216 |
+
const Vectorized<float>& a,
|
| 217 |
+
const Vectorized<float>& b) {
|
| 218 |
+
// inputs:
|
| 219 |
+
// a = {a0, b0, a1, b1,, a2, b2, a3, b3}
|
| 220 |
+
// b = {a4, b4, a5, b5,, a6, b6, a7, b7}
|
| 221 |
+
|
| 222 |
+
// {a0,a2,b0,b2} {a1,a3,b1,b3}
|
| 223 |
+
vfloat32 a0a2b0b2 = vec_mergeh(a.vec0(), a.vec1());
|
| 224 |
+
vfloat32 a1a3b1b3 = vec_mergel(a.vec0(), a.vec1());
|
| 225 |
+
|
| 226 |
+
vfloat32 aa0123 = vec_mergeh(a0a2b0b2, a1a3b1b3);
|
| 227 |
+
vfloat32 bb0123 = vec_mergel(a0a2b0b2, a1a3b1b3);
|
| 228 |
+
|
| 229 |
+
vfloat32 a0a2b0b2_2 = vec_mergeh(b.vec0(), b.vec1());
|
| 230 |
+
vfloat32 a1a3b1b3_2 = vec_mergel(b.vec0(), b.vec1());
|
| 231 |
+
|
| 232 |
+
vfloat32 aa0123_2 = vec_mergeh(a0a2b0b2_2, a1a3b1b3_2);
|
| 233 |
+
vfloat32 bb0123_2 = vec_mergel(a0a2b0b2_2, a1a3b1b3_2);
|
| 234 |
+
|
| 235 |
+
// it could be done with vec_perm ,too
|
| 236 |
+
// swap lanes:
|
| 237 |
+
// return {a0, a1, a2, a3,, a4, a5, a6, a7}
|
| 238 |
+
// {b0, b1, b2, b3,, b4, b5, b6, b7}
|
| 239 |
+
|
| 240 |
+
return std::make_pair(
|
| 241 |
+
Vectorized<float>{aa0123, aa0123_2}, Vectorized<float>{bb0123, bb0123_2});
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
} // namespace
|
| 245 |
+
} // namespace vec
|
| 246 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_complex_double_vsx.h
ADDED
|
@@ -0,0 +1,584 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 3 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 5 |
+
#include <c10/util/complex.h>
|
| 6 |
+
#include <c10/util/irange.h>
|
| 7 |
+
|
| 8 |
+
namespace at {
|
| 9 |
+
namespace vec {
|
| 10 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 11 |
+
inline namespace CPU_CAPABILITY {
|
| 12 |
+
using ComplexDbl = c10::complex<double>;
|
| 13 |
+
|
| 14 |
+
template <>
|
| 15 |
+
class Vectorized<ComplexDbl> {
|
| 16 |
+
union {
|
| 17 |
+
struct {
|
| 18 |
+
vfloat64 _vec0;
|
| 19 |
+
vfloat64 _vec1;
|
| 20 |
+
};
|
| 21 |
+
struct {
|
| 22 |
+
vbool64 _vecb0;
|
| 23 |
+
vbool64 _vecb1;
|
| 24 |
+
};
|
| 25 |
+
|
| 26 |
+
} __attribute__((__may_alias__));
|
| 27 |
+
|
| 28 |
+
public:
|
| 29 |
+
using value_type = ComplexDbl;
|
| 30 |
+
using vec_internal_type = vfloat64;
|
| 31 |
+
using vec_internal_mask_type = vbool64;
|
| 32 |
+
using size_type = int;
|
| 33 |
+
static constexpr size_type size() {
|
| 34 |
+
return 2;
|
| 35 |
+
}
|
| 36 |
+
Vectorized() {}
|
| 37 |
+
C10_ALWAYS_INLINE Vectorized(vfloat64 v) : _vec0{v}, _vec1{v} {}
|
| 38 |
+
C10_ALWAYS_INLINE Vectorized(vbool64 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 39 |
+
C10_ALWAYS_INLINE Vectorized(vfloat64 v1, vfloat64 v2) : _vec0{v1}, _vec1{v2} {}
|
| 40 |
+
C10_ALWAYS_INLINE Vectorized(vbool64 v1, vbool64 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 41 |
+
|
| 42 |
+
Vectorized(ComplexDbl val) {
|
| 43 |
+
double real_value = val.real();
|
| 44 |
+
double imag_value = val.imag();
|
| 45 |
+
_vec0 = vfloat64{real_value, imag_value};
|
| 46 |
+
_vec1 = vfloat64{real_value, imag_value};
|
| 47 |
+
}
|
| 48 |
+
Vectorized(ComplexDbl val1, ComplexDbl val2) {
|
| 49 |
+
_vec0 = vfloat64{val1.real(), val1.imag()};
|
| 50 |
+
_vec1 = vfloat64{val2.real(), val2.imag()};
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 54 |
+
return _vec0;
|
| 55 |
+
}
|
| 56 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 57 |
+
return _vec1;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
template <int64_t mask>
|
| 61 |
+
static std::enable_if_t<blendChoiceComplexDbl(mask) == 0, Vectorized<ComplexDbl>>
|
| 62 |
+
C10_ALWAYS_INLINE
|
| 63 |
+
blend(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 64 |
+
return a;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
template <int64_t mask>
|
| 68 |
+
static std::enable_if_t<blendChoiceComplexDbl(mask) == 1, Vectorized<ComplexDbl>>
|
| 69 |
+
C10_ALWAYS_INLINE
|
| 70 |
+
blend(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 71 |
+
return b;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
template <int64_t mask>
|
| 75 |
+
static std::enable_if_t<blendChoiceComplexDbl(mask) == 2, Vectorized<ComplexDbl>>
|
| 76 |
+
C10_ALWAYS_INLINE
|
| 77 |
+
blend(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 78 |
+
return {b._vec0, a._vec1};
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
template <int64_t mask>
|
| 82 |
+
static std::enable_if_t<blendChoiceComplexDbl(mask) == 3, Vectorized<ComplexDbl>>
|
| 83 |
+
C10_ALWAYS_INLINE
|
| 84 |
+
blend(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 85 |
+
return {a._vec0, b._vec1};
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
template <int64_t mask>
|
| 89 |
+
static Vectorized<ComplexDbl> C10_ALWAYS_INLINE
|
| 90 |
+
el_blend(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 91 |
+
const vbool64 mask_1st = VsxDblMask1(mask);
|
| 92 |
+
const vbool64 mask_2nd = VsxDblMask2(mask);
|
| 93 |
+
return {
|
| 94 |
+
(vfloat64)vec_sel(a._vec0, b._vec0, mask_1st),
|
| 95 |
+
(vfloat64)vec_sel(a._vec1, b._vec1, mask_2nd)};
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
static Vectorized<ComplexDbl> blendv(
|
| 99 |
+
const Vectorized<ComplexDbl>& a,
|
| 100 |
+
const Vectorized<ComplexDbl>& b,
|
| 101 |
+
const Vectorized<ComplexDbl>& mask) {
|
| 102 |
+
// convert std::complex<V> index mask to V index mask: xy -> xxyy
|
| 103 |
+
auto mask_complex =
|
| 104 |
+
Vectorized<ComplexDbl>(vec_splat(mask._vec0, 0), vec_splat(mask._vec1, 0));
|
| 105 |
+
return {
|
| 106 |
+
vec_sel(a._vec0, b._vec0, mask_complex._vecb0),
|
| 107 |
+
vec_sel(a._vec1, b._vec1, mask_complex._vecb1)};
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
static Vectorized<ComplexDbl> C10_ALWAYS_INLINE elwise_blendv(
|
| 111 |
+
const Vectorized<ComplexDbl>& a,
|
| 112 |
+
const Vectorized<ComplexDbl>& b,
|
| 113 |
+
const Vectorized<ComplexDbl>& mask) {
|
| 114 |
+
return {
|
| 115 |
+
vec_sel(a._vec0, b._vec0, mask._vecb0),
|
| 116 |
+
vec_sel(a._vec1, b._vec1, mask._vecb1)};
|
| 117 |
+
}
|
| 118 |
+
template <typename step_t>
|
| 119 |
+
static Vectorized<ComplexDbl> arange(
|
| 120 |
+
ComplexDbl base = 0.,
|
| 121 |
+
step_t step = static_cast<step_t>(1)) {
|
| 122 |
+
return Vectorized<ComplexDbl>(base, base + step);
|
| 123 |
+
}
|
| 124 |
+
static Vectorized<ComplexDbl> set(
|
| 125 |
+
const Vectorized<ComplexDbl>& a,
|
| 126 |
+
const Vectorized<ComplexDbl>& b,
|
| 127 |
+
int64_t count = size()) {
|
| 128 |
+
switch (count) {
|
| 129 |
+
case 0:
|
| 130 |
+
return a;
|
| 131 |
+
case 1:
|
| 132 |
+
return blend<1>(a, b);
|
| 133 |
+
}
|
| 134 |
+
return b;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
static Vectorized<value_type> C10_ALWAYS_INLINE
|
| 138 |
+
loadu(const void* ptr, int count = size()) {
|
| 139 |
+
if (count == size()) {
|
| 140 |
+
return {
|
| 141 |
+
vec_vsx_ld(offset0, reinterpret_cast<const double*>(ptr)),
|
| 142 |
+
vec_vsx_ld(offset16, reinterpret_cast<const double*>(ptr))};
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 146 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 147 |
+
|
| 148 |
+
return {
|
| 149 |
+
vec_vsx_ld(offset0, reinterpret_cast<const double*>(tmp_values)),
|
| 150 |
+
vec_vsx_ld(offset16, reinterpret_cast<const double*>(tmp_values))};
|
| 151 |
+
}
|
| 152 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 153 |
+
if (count == size()) {
|
| 154 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<double*>(ptr));
|
| 155 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<double*>(ptr));
|
| 156 |
+
} else if (count > 0) {
|
| 157 |
+
__at_align__ value_type tmp_values[size()];
|
| 158 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<double*>(tmp_values));
|
| 159 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<double*>(tmp_values));
|
| 160 |
+
std::memcpy(
|
| 161 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 162 |
+
}
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
const ComplexDbl& operator[](int idx) const = delete;
|
| 166 |
+
ComplexDbl& operator[](int idx) = delete;
|
| 167 |
+
|
| 168 |
+
Vectorized<ComplexDbl> map(ComplexDbl (*const f)(ComplexDbl)) const {
|
| 169 |
+
__at_align__ ComplexDbl tmp[size()];
|
| 170 |
+
store(tmp);
|
| 171 |
+
for (const auto i : c10::irange(size())) {
|
| 172 |
+
tmp[i] = f(tmp[i]);
|
| 173 |
+
}
|
| 174 |
+
return loadu(tmp);
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
Vectorized<ComplexDbl> map(ComplexDbl (*const f)(const ComplexDbl&)) const {
|
| 178 |
+
__at_align__ ComplexDbl tmp[size()];
|
| 179 |
+
store(tmp);
|
| 180 |
+
for (const auto i : c10::irange(size())) {
|
| 181 |
+
tmp[i] = f(tmp[i]);
|
| 182 |
+
}
|
| 183 |
+
return loadu(tmp);
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
Vectorized<ComplexDbl> el_swapped() const {
|
| 187 |
+
vfloat64 v0 = vec_xxpermdi(_vec0, _vec0, 2);
|
| 188 |
+
vfloat64 v1 = vec_xxpermdi(_vec1, _vec1, 2);
|
| 189 |
+
return {v0, v1};
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
Vectorized<ComplexDbl> el_madd(
|
| 193 |
+
const Vectorized<ComplexDbl>& multiplier,
|
| 194 |
+
const Vectorized<ComplexDbl>& val) const {
|
| 195 |
+
return {
|
| 196 |
+
vec_madd(_vec0, multiplier._vec0, val._vec0),
|
| 197 |
+
vec_madd(_vec1, multiplier._vec1, val._vec1)};
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
Vectorized<ComplexDbl> el_mergeo() const {
|
| 201 |
+
vfloat64 v0 = vec_splat(_vec0, 1);
|
| 202 |
+
vfloat64 v1 = vec_splat(_vec1, 1);
|
| 203 |
+
return {v0, v1};
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
Vectorized<ComplexDbl> el_mergee() const {
|
| 207 |
+
vfloat64 v0 = vec_splat(_vec0, 0);
|
| 208 |
+
vfloat64 v1 = vec_splat(_vec1, 0);
|
| 209 |
+
return {v0, v1};
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
static Vectorized<ComplexDbl> el_mergee(
|
| 213 |
+
Vectorized<ComplexDbl>& first,
|
| 214 |
+
Vectorized<ComplexDbl>& second) {
|
| 215 |
+
return {
|
| 216 |
+
vec_mergeh(first._vec0, second._vec0),
|
| 217 |
+
vec_mergeh(first._vec1, second._vec1)};
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
static Vectorized<ComplexDbl> el_mergeo(
|
| 221 |
+
Vectorized<ComplexDbl>& first,
|
| 222 |
+
Vectorized<ComplexDbl>& second) {
|
| 223 |
+
return {
|
| 224 |
+
vec_mergel(first._vec0, second._vec0),
|
| 225 |
+
vec_mergel(first._vec1, second._vec1)};
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
Vectorized<ComplexDbl> abs_2_() const {
|
| 229 |
+
auto a = (*this).elwise_mult(*this);
|
| 230 |
+
auto permuted = a.el_swapped();
|
| 231 |
+
a = a + permuted;
|
| 232 |
+
return a;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
Vectorized<ComplexDbl> abs_() const {
|
| 236 |
+
auto vi = el_mergeo();
|
| 237 |
+
auto vr = el_mergee();
|
| 238 |
+
return {Sleef_hypotd2_u05vsx(vr._vec0, vi._vec0), Sleef_hypotd2_u05vsx(vr._vec1, vi._vec1)};
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
Vectorized<ComplexDbl> abs() const {
|
| 242 |
+
return abs_() & vd_real_mask;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
Vectorized<ComplexDbl> angle_() const {
|
| 246 |
+
// angle = atan2(b/a)
|
| 247 |
+
// auto b_a = _mm256_permute_pd(values, 0x05); // b a
|
| 248 |
+
// return Sleef_atan2d4_u10(values, b_a); // 90-angle angle
|
| 249 |
+
Vectorized<ComplexDbl> ret;
|
| 250 |
+
ret._vec0[0] = std::atan2(_vec0[1], _vec0[0]);
|
| 251 |
+
ret._vec1[0] = std::atan2(_vec1[1], _vec1[0]);
|
| 252 |
+
return ret;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
Vectorized<ComplexDbl> angle() const {
|
| 256 |
+
return angle_() & vd_real_mask;
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
Vectorized<ComplexDbl> real_() const {
|
| 260 |
+
return *this & vd_real_mask;
|
| 261 |
+
}
|
| 262 |
+
Vectorized<ComplexDbl> real() const {
|
| 263 |
+
return *this & vd_real_mask;
|
| 264 |
+
}
|
| 265 |
+
Vectorized<ComplexDbl> imag_() const {
|
| 266 |
+
return *this & vd_imag_mask;
|
| 267 |
+
}
|
| 268 |
+
Vectorized<ComplexDbl> imag() const {
|
| 269 |
+
return imag_().el_swapped();
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
Vectorized<ComplexDbl> conj_() const {
|
| 273 |
+
return *this ^ vd_isign_mask;
|
| 274 |
+
}
|
| 275 |
+
Vectorized<ComplexDbl> conj() const {
|
| 276 |
+
return *this ^ vd_isign_mask;
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
Vectorized<ComplexDbl> log() const {
|
| 280 |
+
// Most trigonomic ops use the log() op to improve complex number
|
| 281 |
+
// performance.
|
| 282 |
+
return map(std::log);
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
Vectorized<ComplexDbl> log2() const {
|
| 286 |
+
// log2eB_inv
|
| 287 |
+
auto ret = log();
|
| 288 |
+
return ret.elwise_mult(vd_log2e_inv);
|
| 289 |
+
}
|
| 290 |
+
Vectorized<ComplexDbl> log10() const {
|
| 291 |
+
auto ret = log();
|
| 292 |
+
return ret.elwise_mult(vd_log10e_inv);
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
Vectorized<ComplexDbl> log1p() const {
|
| 296 |
+
return map(std::log1p);
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
Vectorized<ComplexDbl> asin() const {
|
| 300 |
+
// asin(x)
|
| 301 |
+
// = -i*ln(iz + sqrt(1 -z^2))
|
| 302 |
+
// = -i*ln((ai - b) + sqrt(1 - (a + bi)*(a + bi)))
|
| 303 |
+
// = -i*ln((-b + ai) + sqrt(1 - (a**2 - b**2) - 2*abi))
|
| 304 |
+
auto conj = conj_();
|
| 305 |
+
auto b_a = conj.el_swapped();
|
| 306 |
+
auto ab = conj.elwise_mult(b_a);
|
| 307 |
+
auto im = ab + ab;
|
| 308 |
+
auto val_2 = (*this).elwise_mult(*this);
|
| 309 |
+
auto val_2_swapped = val_2.el_swapped();
|
| 310 |
+
auto re = horizontal_sub(val_2, val_2_swapped);
|
| 311 |
+
re = Vectorized<ComplexDbl>(vd_one) - re;
|
| 312 |
+
auto root = el_blend<0x0A>(re, im).sqrt();
|
| 313 |
+
auto ln = (b_a + root).log();
|
| 314 |
+
return ln.el_swapped().conj();
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
Vectorized<ComplexDbl> acos() const {
|
| 318 |
+
// acos(x) = pi/2 - asin(x)
|
| 319 |
+
return Vectorized(vd_pi_2) - asin();
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
Vectorized<ComplexDbl> atan() const {
|
| 323 |
+
// atan(x) = i/2 * ln((i + z)/(i - z))
|
| 324 |
+
auto ione = Vectorized(vd_imag_one);
|
| 325 |
+
auto sum = ione + *this;
|
| 326 |
+
auto sub = ione - *this;
|
| 327 |
+
auto ln = (sum / sub).log(); // ln((i + z)/(i - z))
|
| 328 |
+
return ln * vd_imag_half; // i/2*ln()
|
| 329 |
+
}
|
| 330 |
+
Vectorized<ComplexDbl> atanh() const {
|
| 331 |
+
return map(std::atanh);
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
Vectorized<ComplexDbl> sin() const {
|
| 335 |
+
return map(std::sin);
|
| 336 |
+
}
|
| 337 |
+
Vectorized<ComplexDbl> sinh() const {
|
| 338 |
+
return map(std::sinh);
|
| 339 |
+
}
|
| 340 |
+
Vectorized<ComplexDbl> cos() const {
|
| 341 |
+
return map(std::cos);
|
| 342 |
+
}
|
| 343 |
+
Vectorized<ComplexDbl> cosh() const {
|
| 344 |
+
return map(std::cosh);
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
Vectorized<ComplexDbl> tan() const {
|
| 348 |
+
return map(std::tan);
|
| 349 |
+
}
|
| 350 |
+
Vectorized<ComplexDbl> tanh() const {
|
| 351 |
+
return map(std::tanh);
|
| 352 |
+
}
|
| 353 |
+
Vectorized<ComplexDbl> ceil() const {
|
| 354 |
+
return {vec_ceil(_vec0), vec_ceil(_vec1)};
|
| 355 |
+
}
|
| 356 |
+
Vectorized<ComplexDbl> floor() const {
|
| 357 |
+
return {vec_floor(_vec0), vec_floor(_vec1)};
|
| 358 |
+
}
|
| 359 |
+
Vectorized<ComplexDbl> neg() const {
|
| 360 |
+
auto z = Vectorized<ComplexDbl>(vd_zero);
|
| 361 |
+
return z - *this;
|
| 362 |
+
}
|
| 363 |
+
Vectorized<ComplexDbl> round() const {
|
| 364 |
+
return {vec_rint(_vec0), vec_rint(_vec1)};
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
Vectorized<ComplexDbl> trunc() const {
|
| 368 |
+
return {vec_trunc(_vec0), vec_trunc(_vec1)};
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
Vectorized<ComplexDbl> elwise_sqrt() const {
|
| 372 |
+
return {vec_sqrt(_vec0), vec_sqrt(_vec1)};
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
Vectorized<ComplexDbl> sqrt() const {
|
| 376 |
+
return map(std::sqrt);
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
Vectorized<ComplexDbl> reciprocal() const {
|
| 380 |
+
// re + im*i = (a + bi) / (c + di)
|
| 381 |
+
// re = (ac + bd)/abs_2() = c/abs_2()
|
| 382 |
+
// im = (bc - ad)/abs_2() = d/abs_2()
|
| 383 |
+
auto c_d = *this ^ vd_isign_mask; // c -d
|
| 384 |
+
auto abs = abs_2_();
|
| 385 |
+
return c_d.elwise_div(abs);
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
Vectorized<ComplexDbl> rsqrt() const {
|
| 389 |
+
return sqrt().reciprocal();
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
static Vectorized<ComplexDbl> horizontal_add(
|
| 393 |
+
Vectorized<ComplexDbl>& first,
|
| 394 |
+
Vectorized<ComplexDbl>& second) {
|
| 395 |
+
// Operates on individual floats, see _mm_hadd_ps
|
| 396 |
+
// {f0+f1, s0+s1, f2+f3, s2+s3, ...}
|
| 397 |
+
// i.e. it sums the re and im of each value and interleaves first and second:
|
| 398 |
+
// {f_re0 + f_im0, s_re0 + s_im0, f_re1 + f_im1, s_re1 + s_im1, ...}
|
| 399 |
+
return el_mergee(first, second) + el_mergeo(first, second);
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
static Vectorized<ComplexDbl> horizontal_sub(
|
| 403 |
+
Vectorized<ComplexDbl>& first,
|
| 404 |
+
Vectorized<ComplexDbl>& second) {
|
| 405 |
+
// we will simulate it differently with 6 instructions total
|
| 406 |
+
// lets permute second so that we can add it getting horizontal sums
|
| 407 |
+
auto first_perm = first.el_swapped(); // 2perm
|
| 408 |
+
auto second_perm = second.el_swapped(); // 2perm
|
| 409 |
+
// summ
|
| 410 |
+
auto first_ret = first - first_perm; // 2sub
|
| 411 |
+
auto second_ret = second - second_perm; // 2 sub
|
| 412 |
+
// now lets choose evens
|
| 413 |
+
return el_mergee(first_ret, second_ret); // 2 mergee's
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
Vectorized<ComplexDbl> inline operator*(const Vectorized<ComplexDbl>& b) const {
|
| 417 |
+
//(a + bi) * (c + di) = (ac - bd) + (ad + bc)i
|
| 418 |
+
#if 1
|
| 419 |
+
// this is more vsx friendly than simulating horizontal from x86
|
| 420 |
+
auto vi = b.el_mergeo();
|
| 421 |
+
auto vr = b.el_mergee();
|
| 422 |
+
vi = vi ^ vd_rsign_mask;
|
| 423 |
+
auto ret = elwise_mult(vr);
|
| 424 |
+
auto vx_swapped = el_swapped();
|
| 425 |
+
ret = vx_swapped.el_madd(vi, ret);
|
| 426 |
+
#else
|
| 427 |
+
auto ac_bd = elwise_mult(b);
|
| 428 |
+
auto d_c = b.el_swapped();
|
| 429 |
+
d_c = d_c ^ vd_isign_mask;
|
| 430 |
+
auto ad_bc = elwise_mult(d_c);
|
| 431 |
+
auto ret = horizontal_sub(ac_bd, ad_bc);
|
| 432 |
+
#endif
|
| 433 |
+
return ret;
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
Vectorized<ComplexDbl> inline operator/(const Vectorized<ComplexDbl>& b) const {
|
| 437 |
+
// re + im*i = (a + bi) / (c + di)
|
| 438 |
+
// re = (ac + bd)/abs_2()
|
| 439 |
+
// im = (bc - ad)/abs_2()
|
| 440 |
+
auto fabs_cd = Vectorized{
|
| 441 |
+
vec_andc(b._vec0, vd_sign_mask),
|
| 442 |
+
vec_andc(b._vec1, vd_sign_mask)}; // |c| |d|
|
| 443 |
+
auto fabs_dc = fabs_cd.el_swapped(); // |d| |c|
|
| 444 |
+
auto scale = fabs_cd.elwise_max(fabs_dc); // sc = max(|c|, |d|)
|
| 445 |
+
auto a2 = elwise_div(scale); // a/sc b/sc
|
| 446 |
+
auto b2 = b.elwise_div(scale); // c/sc d/sc
|
| 447 |
+
auto acbd2 = a2.elwise_mult(b2); // ac/sc^2 bd/sc^2
|
| 448 |
+
auto dc2 = b2.el_swapped(); // d/sc c/sc
|
| 449 |
+
dc2 = dc2 ^ vd_rsign_mask; // -d/sc c/sc
|
| 450 |
+
auto adbc2 = a2.elwise_mult(dc2); // -ad/sc^2 bc/sc^2
|
| 451 |
+
auto ret = horizontal_add(acbd2, adbc2); // (ac+bd)/sc^2 (bc-ad)/sc^2
|
| 452 |
+
auto denom2 = b2.abs_2_(); // (c^2+d^2)/sc^2 (c^2+d^2)/sc^2
|
| 453 |
+
ret = ret.elwise_div(denom2);
|
| 454 |
+
return ret;
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
Vectorized<ComplexDbl> exp() const {
|
| 458 |
+
return map(std::exp);
|
| 459 |
+
}
|
| 460 |
+
Vectorized<ComplexDbl> exp2() const {
|
| 461 |
+
return map(exp2_impl);
|
| 462 |
+
}
|
| 463 |
+
Vectorized<ComplexDbl> expm1() const {
|
| 464 |
+
return map(std::expm1);
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
Vectorized<ComplexDbl> pow(const Vectorized<ComplexDbl>& exp) const {
|
| 468 |
+
__at_align__ ComplexDbl x_tmp[size()];
|
| 469 |
+
__at_align__ ComplexDbl y_tmp[size()];
|
| 470 |
+
store(x_tmp);
|
| 471 |
+
exp.store(y_tmp);
|
| 472 |
+
for (const auto i : c10::irange(size())) {
|
| 473 |
+
x_tmp[i] = std::pow(x_tmp[i], y_tmp[i]);
|
| 474 |
+
}
|
| 475 |
+
return loadu(x_tmp);
|
| 476 |
+
}
|
| 477 |
+
|
| 478 |
+
Vectorized<ComplexDbl> sgn() const {
|
| 479 |
+
return map(at::native::sgn_impl);
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
Vectorized<ComplexDbl> operator<(const Vectorized<ComplexDbl>& other) const {
|
| 483 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 484 |
+
}
|
| 485 |
+
Vectorized<ComplexDbl> operator<=(const Vectorized<ComplexDbl>& other) const {
|
| 486 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 487 |
+
}
|
| 488 |
+
Vectorized<ComplexDbl> operator>(const Vectorized<ComplexDbl>& other) const {
|
| 489 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 490 |
+
}
|
| 491 |
+
Vectorized<ComplexDbl> operator>=(const Vectorized<ComplexDbl>& other) const {
|
| 492 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
Vectorized<ComplexDbl> eq(const Vectorized<ComplexDbl>& other) const {
|
| 496 |
+
auto eq = (*this == other); // compares real and imag individually
|
| 497 |
+
// If both real numbers and imag numbers are equal, then the complex numbers are equal
|
| 498 |
+
return (eq.real() & eq.imag()) & vd_one;
|
| 499 |
+
}
|
| 500 |
+
Vectorized<ComplexDbl> ne(const Vectorized<ComplexDbl>& other) const {
|
| 501 |
+
auto ne = (*this != other); // compares real and imag individually
|
| 502 |
+
// If either real numbers or imag numbers are not equal, then the complex numbers are not equal
|
| 503 |
+
return (ne.real() | ne.imag()) & vd_one;
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
DEFINE_MEMBER_OP(operator==, ComplexDbl, vec_cmpeq)
|
| 507 |
+
DEFINE_MEMBER_OP(operator!=, ComplexDbl, vec_cmpne)
|
| 508 |
+
|
| 509 |
+
DEFINE_MEMBER_OP(operator+, ComplexDbl, vec_add)
|
| 510 |
+
DEFINE_MEMBER_OP(operator-, ComplexDbl, vec_sub)
|
| 511 |
+
DEFINE_MEMBER_OP(operator&, ComplexDbl, vec_and)
|
| 512 |
+
DEFINE_MEMBER_OP(operator|, ComplexDbl, vec_or)
|
| 513 |
+
DEFINE_MEMBER_OP(operator^, ComplexDbl, vec_xor)
|
| 514 |
+
// elementwise helpers
|
| 515 |
+
DEFINE_MEMBER_OP(elwise_mult, ComplexDbl, vec_mul)
|
| 516 |
+
DEFINE_MEMBER_OP(elwise_div, ComplexDbl, vec_div)
|
| 517 |
+
DEFINE_MEMBER_OP(elwise_gt, ComplexDbl, vec_cmpgt)
|
| 518 |
+
DEFINE_MEMBER_OP(elwise_ge, ComplexDbl, vec_cmpge)
|
| 519 |
+
DEFINE_MEMBER_OP(elwise_lt, ComplexDbl, vec_cmplt)
|
| 520 |
+
DEFINE_MEMBER_OP(elwise_le, ComplexDbl, vec_cmple)
|
| 521 |
+
DEFINE_MEMBER_OP(elwise_max, ComplexDbl, vec_max)
|
| 522 |
+
};
|
| 523 |
+
|
| 524 |
+
template <>
|
| 525 |
+
Vectorized<ComplexDbl> inline maximum(
|
| 526 |
+
const Vectorized<ComplexDbl>& a,
|
| 527 |
+
const Vectorized<ComplexDbl>& b) {
|
| 528 |
+
auto abs_a = a.abs_2_();
|
| 529 |
+
auto abs_b = b.abs_2_();
|
| 530 |
+
// auto mask = _mm256_cmp_ps(abs_a, abs_b, _CMP_LT_OQ);
|
| 531 |
+
// auto max = _mm256_blendv_ps(a, b, mask);
|
| 532 |
+
auto mask = abs_a.elwise_lt(abs_b);
|
| 533 |
+
auto max = Vectorized<ComplexDbl>::elwise_blendv(a, b, mask);
|
| 534 |
+
|
| 535 |
+
return max;
|
| 536 |
+
// Exploit the fact that all-ones is a NaN.
|
| 537 |
+
// auto isnan = _mm256_cmp_ps(abs_a, abs_b, _CMP_UNORD_Q);
|
| 538 |
+
// return _mm256_or_ps(max, isnan);
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
template <>
|
| 542 |
+
Vectorized<ComplexDbl> inline minimum(
|
| 543 |
+
const Vectorized<ComplexDbl>& a,
|
| 544 |
+
const Vectorized<ComplexDbl>& b) {
|
| 545 |
+
auto abs_a = a.abs_2_();
|
| 546 |
+
auto abs_b = b.abs_2_();
|
| 547 |
+
// auto mask = _mm256_cmp_ps(abs_a, abs_b, _CMP_GT_OQ);
|
| 548 |
+
// auto min = _mm256_blendv_ps(a, b, mask);
|
| 549 |
+
auto mask = abs_a.elwise_gt(abs_b);
|
| 550 |
+
auto min = Vectorized<ComplexDbl>::elwise_blendv(a, b, mask);
|
| 551 |
+
return min;
|
| 552 |
+
// Exploit the fact that all-ones is a NaN.
|
| 553 |
+
// auto isnan = _mm256_cmp_ps(abs_a, abs_b, _CMP_UNORD_Q);
|
| 554 |
+
// return _mm256_or_ps(min, isnan);
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
template <>
|
| 558 |
+
Vectorized<ComplexDbl> C10_ALWAYS_INLINE operator+(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 559 |
+
return Vectorized<ComplexDbl>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 560 |
+
}
|
| 561 |
+
|
| 562 |
+
template <>
|
| 563 |
+
Vectorized<ComplexDbl> C10_ALWAYS_INLINE operator-(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 564 |
+
return Vectorized<ComplexDbl>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 565 |
+
}
|
| 566 |
+
|
| 567 |
+
template <>
|
| 568 |
+
Vectorized<ComplexDbl> C10_ALWAYS_INLINE operator&(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 569 |
+
return Vectorized<ComplexDbl>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 570 |
+
}
|
| 571 |
+
|
| 572 |
+
template <>
|
| 573 |
+
Vectorized<ComplexDbl> C10_ALWAYS_INLINE operator|(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 574 |
+
return Vectorized<ComplexDbl>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 575 |
+
}
|
| 576 |
+
|
| 577 |
+
template <>
|
| 578 |
+
Vectorized<ComplexDbl> C10_ALWAYS_INLINE operator^(const Vectorized<ComplexDbl>& a, const Vectorized<ComplexDbl>& b) {
|
| 579 |
+
return Vectorized<ComplexDbl>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 580 |
+
}
|
| 581 |
+
|
| 582 |
+
} // namespace
|
| 583 |
+
} // namespace vec
|
| 584 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_complex_float_vsx.h
ADDED
|
@@ -0,0 +1,660 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
#pragma once
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
#include <c10/util/complex.h>
|
| 7 |
+
#include <c10/util/irange.h>
|
| 8 |
+
|
| 9 |
+
namespace at {
|
| 10 |
+
namespace vec {
|
| 11 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 12 |
+
inline namespace CPU_CAPABILITY {
|
| 13 |
+
using ComplexFlt = c10::complex<float>;
|
| 14 |
+
|
| 15 |
+
template <>
|
| 16 |
+
class Vectorized<ComplexFlt> {
|
| 17 |
+
private:
|
| 18 |
+
union {
|
| 19 |
+
struct {
|
| 20 |
+
vfloat32 _vec0;
|
| 21 |
+
vfloat32 _vec1;
|
| 22 |
+
};
|
| 23 |
+
struct {
|
| 24 |
+
vbool32 _vecb0;
|
| 25 |
+
vbool32 _vecb1;
|
| 26 |
+
};
|
| 27 |
+
|
| 28 |
+
} __attribute__((__may_alias__));
|
| 29 |
+
|
| 30 |
+
public:
|
| 31 |
+
using value_type = ComplexFlt;
|
| 32 |
+
using vec_internal_type = vfloat32;
|
| 33 |
+
using vec_internal_mask_type = vbool32;
|
| 34 |
+
using size_type = int;
|
| 35 |
+
|
| 36 |
+
static constexpr size_type size() {
|
| 37 |
+
return 4;
|
| 38 |
+
}
|
| 39 |
+
Vectorized() {}
|
| 40 |
+
|
| 41 |
+
C10_ALWAYS_INLINE Vectorized(vfloat32 v) : _vec0{v}, _vec1{v} {}
|
| 42 |
+
C10_ALWAYS_INLINE Vectorized(vbool32 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 43 |
+
C10_ALWAYS_INLINE Vectorized(vfloat32 v1, vfloat32 v2) : _vec0{v1}, _vec1{v2} {}
|
| 44 |
+
C10_ALWAYS_INLINE Vectorized(vbool32 v1, vbool32 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 45 |
+
|
| 46 |
+
Vectorized(ComplexFlt val) {
|
| 47 |
+
float real_value = val.real();
|
| 48 |
+
float imag_value = val.imag();
|
| 49 |
+
_vec0 = vfloat32{real_value, imag_value, real_value, imag_value};
|
| 50 |
+
_vec1 = vfloat32{real_value, imag_value, real_value, imag_value};
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
Vectorized(ComplexFlt val1, ComplexFlt val2, ComplexFlt val3, ComplexFlt val4) {
|
| 54 |
+
_vec0 = vfloat32{val1.real(), val1.imag(), val2.real(), val2.imag()};
|
| 55 |
+
_vec1 = vfloat32{val3.real(), val3.imag(), val4.real(), val4.imag()};
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 59 |
+
return _vec0;
|
| 60 |
+
}
|
| 61 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 62 |
+
return _vec1;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
template <uint64_t mask>
|
| 66 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 0, Vectorized<ComplexFlt>>
|
| 67 |
+
C10_ALWAYS_INLINE
|
| 68 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 69 |
+
return a;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
template <uint64_t mask>
|
| 73 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 1, Vectorized<ComplexFlt>>
|
| 74 |
+
C10_ALWAYS_INLINE
|
| 75 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 76 |
+
return b;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
template <uint64_t mask>
|
| 80 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 2, Vectorized<ComplexFlt>>
|
| 81 |
+
C10_ALWAYS_INLINE
|
| 82 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 83 |
+
return {b._vec0, a._vec1};
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
template <uint64_t mask>
|
| 87 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 3, Vectorized<ComplexFlt>>
|
| 88 |
+
C10_ALWAYS_INLINE
|
| 89 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 90 |
+
return {a._vec0, b._vec1};
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
template <uint64_t mask>
|
| 94 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 4, Vectorized<ComplexFlt>>
|
| 95 |
+
C10_ALWAYS_INLINE
|
| 96 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 97 |
+
const vbool32 mask_1st = VsxComplexMask1(mask);
|
| 98 |
+
return {(vfloat32)vec_sel(a._vec0, b._vec0, mask_1st), a._vec1};
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
template <uint64_t mask>
|
| 102 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 5, Vectorized<ComplexFlt>>
|
| 103 |
+
C10_ALWAYS_INLINE
|
| 104 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 105 |
+
const vbool32 mask_1st = VsxComplexMask1(mask);
|
| 106 |
+
return {(vfloat32)vec_sel(a._vec0, b._vec0, mask_1st), b._vec1};
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
template <uint64_t mask>
|
| 110 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 6, Vectorized<ComplexFlt>>
|
| 111 |
+
C10_ALWAYS_INLINE
|
| 112 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 113 |
+
const vbool32 mask_2nd = VsxComplexMask2(mask);
|
| 114 |
+
// generated masks
|
| 115 |
+
return {a._vec0, (vfloat32)vec_sel(a._vec1, b._vec1, mask_2nd)};
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
template <uint64_t mask>
|
| 119 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 7, Vectorized<ComplexFlt>>
|
| 120 |
+
C10_ALWAYS_INLINE
|
| 121 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 122 |
+
const vbool32 mask_2nd = VsxComplexMask2(mask);
|
| 123 |
+
// generated masks
|
| 124 |
+
return {b._vec0, (vfloat32)vec_sel(a._vec1, b._vec1, mask_2nd)};
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
template <uint64_t mask>
|
| 128 |
+
static std::enable_if_t<blendChoiceComplex(mask) == 8, Vectorized<ComplexFlt>>
|
| 129 |
+
C10_ALWAYS_INLINE
|
| 130 |
+
blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 131 |
+
const vbool32 mask_1st = VsxComplexMask1(mask);
|
| 132 |
+
const vbool32 mask_2nd = VsxComplexMask2(mask);
|
| 133 |
+
return {
|
| 134 |
+
(vfloat32)vec_sel(a._vec0, b._vec0, mask_1st),
|
| 135 |
+
(vfloat32)vec_sel(a._vec1, b._vec1, mask_2nd)};
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
template <int64_t mask>
|
| 139 |
+
static Vectorized<ComplexFlt> C10_ALWAYS_INLINE
|
| 140 |
+
el_blend(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 141 |
+
const vbool32 mask_1st = VsxMask1(mask);
|
| 142 |
+
const vbool32 mask_2nd = VsxMask2(mask);
|
| 143 |
+
return {
|
| 144 |
+
(vfloat32)vec_sel(a._vec0, b._vec0, mask_1st),
|
| 145 |
+
(vfloat32)vec_sel(a._vec1, b._vec1, mask_2nd)};
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
static Vectorized<ComplexFlt> blendv(
|
| 149 |
+
const Vectorized<ComplexFlt>& a,
|
| 150 |
+
const Vectorized<ComplexFlt>& b,
|
| 151 |
+
const Vectorized<ComplexFlt>& mask) {
|
| 152 |
+
// convert std::complex<V> index mask to V index mask: xy -> xxyy
|
| 153 |
+
auto mask_complex = Vectorized<ComplexFlt>(
|
| 154 |
+
vec_mergeh(mask._vec0, mask._vec0), vec_mergeh(mask._vec1, mask._vec1));
|
| 155 |
+
return {
|
| 156 |
+
vec_sel(a._vec0, b._vec0, reinterpret_cast<vbool32>(mask_complex._vec0)),
|
| 157 |
+
vec_sel(a._vec1, b._vec1, reinterpret_cast<vbool32>(mask_complex._vec1)),
|
| 158 |
+
};
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
static Vectorized<ComplexFlt> elwise_blendv(
|
| 162 |
+
const Vectorized<ComplexFlt>& a,
|
| 163 |
+
const Vectorized<ComplexFlt>& b,
|
| 164 |
+
const Vectorized<ComplexFlt>& mask) {
|
| 165 |
+
return {
|
| 166 |
+
vec_sel(a._vec0, b._vec0, reinterpret_cast<vbool32>(mask._vec0)),
|
| 167 |
+
vec_sel(a._vec1, b._vec1, reinterpret_cast<vbool32>(mask._vec1)),
|
| 168 |
+
};
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
template <typename step_t>
|
| 172 |
+
static Vectorized<ComplexFlt> arange(
|
| 173 |
+
ComplexFlt base = 0.,
|
| 174 |
+
step_t step = static_cast<step_t>(1)) {
|
| 175 |
+
return Vectorized<ComplexFlt>(
|
| 176 |
+
base,
|
| 177 |
+
base + step,
|
| 178 |
+
base + ComplexFlt(2) * step,
|
| 179 |
+
base + ComplexFlt(3) * step);
|
| 180 |
+
}
|
| 181 |
+
static Vectorized<ComplexFlt> set(
|
| 182 |
+
const Vectorized<ComplexFlt>& a,
|
| 183 |
+
const Vectorized<ComplexFlt>& b,
|
| 184 |
+
int64_t count = size()) {
|
| 185 |
+
switch (count) {
|
| 186 |
+
case 0:
|
| 187 |
+
return a;
|
| 188 |
+
case 1:
|
| 189 |
+
return blend<1>(a, b);
|
| 190 |
+
case 2:
|
| 191 |
+
return blend<3>(a, b);
|
| 192 |
+
case 3:
|
| 193 |
+
return blend<7>(a, b);
|
| 194 |
+
}
|
| 195 |
+
return b;
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
static Vectorized<value_type> C10_ALWAYS_INLINE
|
| 199 |
+
loadu(const void* ptr, int count = size()) {
|
| 200 |
+
if (count == size()) {
|
| 201 |
+
return {
|
| 202 |
+
vec_vsx_ld(offset0, reinterpret_cast<const float*>(ptr)),
|
| 203 |
+
vec_vsx_ld(offset16, reinterpret_cast<const float*>(ptr))};
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 207 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 208 |
+
|
| 209 |
+
return {
|
| 210 |
+
vec_vsx_ld(offset0, reinterpret_cast<const float*>(tmp_values)),
|
| 211 |
+
vec_vsx_ld(offset16, reinterpret_cast<const float*>(tmp_values))};
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 215 |
+
if (count == size()) {
|
| 216 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<float*>(ptr));
|
| 217 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<float*>(ptr));
|
| 218 |
+
} else if (count > 0) {
|
| 219 |
+
__at_align__ value_type tmp_values[size()];
|
| 220 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<float*>(tmp_values));
|
| 221 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<float*>(tmp_values));
|
| 222 |
+
std::memcpy(
|
| 223 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 224 |
+
}
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
const ComplexFlt& operator[](int idx) const = delete;
|
| 228 |
+
ComplexFlt& operator[](int idx) = delete;
|
| 229 |
+
|
| 230 |
+
Vectorized<ComplexFlt> map(ComplexFlt (*const f)(ComplexFlt)) const {
|
| 231 |
+
__at_align__ ComplexFlt tmp[size()];
|
| 232 |
+
store(tmp);
|
| 233 |
+
for (const auto i : c10::irange(size())) {
|
| 234 |
+
tmp[i] = f(tmp[i]);
|
| 235 |
+
}
|
| 236 |
+
return loadu(tmp);
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
Vectorized<ComplexFlt> map(ComplexFlt (*const f)(const ComplexFlt&)) const {
|
| 240 |
+
__at_align__ ComplexFlt tmp[size()];
|
| 241 |
+
store(tmp);
|
| 242 |
+
for (const auto i : c10::irange(size())) {
|
| 243 |
+
tmp[i] = f(tmp[i]);
|
| 244 |
+
}
|
| 245 |
+
return loadu(tmp);
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
static Vectorized<ComplexFlt> horizontal_add(
|
| 249 |
+
Vectorized<ComplexFlt>& first,
|
| 250 |
+
Vectorized<ComplexFlt>& second) {
|
| 251 |
+
// Operates on individual floats, see _mm_hadd_ps
|
| 252 |
+
// {f0+f1, s0+s1, f2+f3, s2+s3, ...}
|
| 253 |
+
// i.e. it sums the re and im of each value and interleaves first and second:
|
| 254 |
+
// {f_re0 + f_im0, s_re0 + s_im0, f_re1 + f_im1, s_re1 + s_im1, ...}
|
| 255 |
+
return el_mergee(first, second) + el_mergeo(first, second);
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
static Vectorized<ComplexFlt> horizontal_sub_permD8(
|
| 259 |
+
Vectorized<ComplexFlt>& first,
|
| 260 |
+
Vectorized<ComplexFlt>& second) {
|
| 261 |
+
// we will simulate it differently with 6 instructions total
|
| 262 |
+
// lets permute second so that we can add it getting horizontal sums
|
| 263 |
+
auto first_perm = first.el_swapped(); // 2perm
|
| 264 |
+
auto second_perm = second.el_swapped(); // 2perm
|
| 265 |
+
// sum
|
| 266 |
+
auto first_ret = first - first_perm; // 2sub
|
| 267 |
+
auto second_ret = second - second_perm; // 2 sub
|
| 268 |
+
// now lets choose evens
|
| 269 |
+
return el_mergee(first_ret, second_ret); // 2 mergee's
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
Vectorized<ComplexFlt> abs_2_() const {
|
| 273 |
+
auto a = (*this).elwise_mult(*this);
|
| 274 |
+
auto permuted = a.el_swapped();
|
| 275 |
+
a = a + permuted;
|
| 276 |
+
return a.el_mergee();
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
Vectorized<ComplexFlt> abs_() const {
|
| 280 |
+
auto vi = el_mergeo();
|
| 281 |
+
auto vr = el_mergee();
|
| 282 |
+
return {Sleef_hypotf4_u05vsx(vr._vec0, vi._vec0), Sleef_hypotf4_u05vsx(vr._vec1, vi._vec1)};
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
Vectorized<ComplexFlt> abs() const {
|
| 286 |
+
return abs_() & real_mask;
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
Vectorized<ComplexFlt> real_() const {
|
| 290 |
+
return *this & real_mask;
|
| 291 |
+
}
|
| 292 |
+
Vectorized<ComplexFlt> real() const {
|
| 293 |
+
return *this & real_mask;
|
| 294 |
+
}
|
| 295 |
+
Vectorized<ComplexFlt> imag_() const {
|
| 296 |
+
return *this & imag_mask;
|
| 297 |
+
}
|
| 298 |
+
Vectorized<ComplexFlt> imag() const {
|
| 299 |
+
// we can use swap_mask or sldwi
|
| 300 |
+
auto ret = imag_();
|
| 301 |
+
return {
|
| 302 |
+
vec_sldw(ret._vec0, ret._vec0, 3), vec_sldw(ret._vec1, ret._vec1, 3)};
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
Vectorized<ComplexFlt> conj_() const {
|
| 306 |
+
return *this ^ isign_mask;
|
| 307 |
+
}
|
| 308 |
+
Vectorized<ComplexFlt> conj() const {
|
| 309 |
+
return *this ^ isign_mask;
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
Vectorized<ComplexFlt> log() const {
|
| 313 |
+
// Most trigonomic ops use the log() op to improve complex number
|
| 314 |
+
// performance.
|
| 315 |
+
return map(std::log);
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
Vectorized<ComplexFlt> log2() const {
|
| 319 |
+
// log2eB_inv
|
| 320 |
+
auto ret = log();
|
| 321 |
+
return ret.elwise_mult(log2e_inv);
|
| 322 |
+
}
|
| 323 |
+
Vectorized<ComplexFlt> log10() const {
|
| 324 |
+
auto ret = log();
|
| 325 |
+
return ret.elwise_mult(log10e_inv);
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
Vectorized<ComplexFlt> log1p() const {
|
| 329 |
+
return map(std::log1p);
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
Vectorized<ComplexFlt> el_swapped() const {
|
| 333 |
+
vfloat32 v0 = vec_perm(_vec0, _vec0, swap_mask);
|
| 334 |
+
vfloat32 v1 = vec_perm(_vec1, _vec1, swap_mask);
|
| 335 |
+
return {v0, v1};
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
Vectorized<ComplexFlt> el_mergee() const {
|
| 339 |
+
// as mergee phased in , we can use vec_perm with mask
|
| 340 |
+
return {vec_mergee(_vecb0, _vecb0), vec_mergee(_vecb1, _vecb1)};
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
Vectorized<ComplexFlt> el_mergeo() const {
|
| 344 |
+
// as mergeo phased in , we can use vec_perm with mask
|
| 345 |
+
return {vec_mergeo(_vecb0, _vecb0), vec_mergeo(_vecb1, _vecb1)};
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
Vectorized<ComplexFlt> el_madd(
|
| 349 |
+
const Vectorized<ComplexFlt>& multiplier,
|
| 350 |
+
const Vectorized<ComplexFlt>& val) const {
|
| 351 |
+
return {
|
| 352 |
+
vec_madd(_vec0, multiplier._vec0, val._vec0),
|
| 353 |
+
vec_madd(_vec1, multiplier._vec1, val._vec1)};
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
static Vectorized<ComplexFlt> el_mergee(
|
| 357 |
+
Vectorized<ComplexFlt>& first,
|
| 358 |
+
Vectorized<ComplexFlt>& second) {
|
| 359 |
+
return {
|
| 360 |
+
vec_mergee(first._vecb0, second._vecb0),
|
| 361 |
+
vec_mergee(first._vecb1, second._vecb1)};
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
static Vectorized<ComplexFlt> el_mergeo(
|
| 365 |
+
Vectorized<ComplexFlt>& first,
|
| 366 |
+
Vectorized<ComplexFlt>& second) {
|
| 367 |
+
return {
|
| 368 |
+
vec_mergeo(first._vecb0, second._vecb0),
|
| 369 |
+
vec_mergeo(first._vecb1, second._vecb1)};
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
Vectorized<ComplexFlt> angle_() const {
|
| 373 |
+
// angle = atan2(b/a)
|
| 374 |
+
// auto b_a = _mm256_permute_ps(values, 0xB1); // b a
|
| 375 |
+
// return Sleef_atan2f8_u10(values, b_a); // 90-angle angle
|
| 376 |
+
Vectorized<ComplexFlt> ret;
|
| 377 |
+
for (int i = 0; i < 4; i += 2) {
|
| 378 |
+
ret._vec0[i] = std::atan2(_vec0[i + 1], _vec0[i]);
|
| 379 |
+
ret._vec1[i] = std::atan2(_vec1[i + 1], _vec1[i]);
|
| 380 |
+
}
|
| 381 |
+
return ret;
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
Vectorized<ComplexFlt> angle() const {
|
| 385 |
+
return angle_() & real_mask;
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
Vectorized<ComplexFlt> sin() const {
|
| 389 |
+
return map(std::sin);
|
| 390 |
+
}
|
| 391 |
+
Vectorized<ComplexFlt> sinh() const {
|
| 392 |
+
return map(std::sinh);
|
| 393 |
+
}
|
| 394 |
+
Vectorized<ComplexFlt> cos() const {
|
| 395 |
+
return map(std::cos);
|
| 396 |
+
}
|
| 397 |
+
Vectorized<ComplexFlt> cosh() const {
|
| 398 |
+
return map(std::cosh);
|
| 399 |
+
}
|
| 400 |
+
Vectorized<ComplexFlt> ceil() const {
|
| 401 |
+
return {vec_ceil(_vec0), vec_ceil(_vec1)};
|
| 402 |
+
}
|
| 403 |
+
Vectorized<ComplexFlt> floor() const {
|
| 404 |
+
return {vec_floor(_vec0), vec_floor(_vec1)};
|
| 405 |
+
}
|
| 406 |
+
Vectorized<ComplexFlt> neg() const {
|
| 407 |
+
auto z = Vectorized<ComplexFlt>(zero);
|
| 408 |
+
return z - *this;
|
| 409 |
+
}
|
| 410 |
+
Vectorized<ComplexFlt> round() const {
|
| 411 |
+
return {vec_round(_vec0), vec_round(_vec1)};
|
| 412 |
+
}
|
| 413 |
+
Vectorized<ComplexFlt> tan() const {
|
| 414 |
+
return map(std::tan);
|
| 415 |
+
}
|
| 416 |
+
Vectorized<ComplexFlt> tanh() const {
|
| 417 |
+
return map(std::tanh);
|
| 418 |
+
}
|
| 419 |
+
Vectorized<ComplexFlt> trunc() const {
|
| 420 |
+
return {vec_trunc(_vec0), vec_trunc(_vec1)};
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
Vectorized<ComplexFlt> elwise_sqrt() const {
|
| 424 |
+
return {vec_sqrt(_vec0), vec_sqrt(_vec1)};
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
Vectorized<ComplexFlt> sqrt() const {
|
| 428 |
+
return map(std::sqrt);
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
Vectorized<ComplexFlt> reciprocal() const {
|
| 432 |
+
// re + im*i = (a + bi) / (c + di)
|
| 433 |
+
// re = (ac + bd)/abs_2() = c/abs_2()
|
| 434 |
+
// im = (bc - ad)/abs_2() = d/abs_2()
|
| 435 |
+
auto c_d = *this ^ isign_mask; // c -d
|
| 436 |
+
auto abs = abs_2_();
|
| 437 |
+
return c_d.elwise_div(abs);
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
Vectorized<ComplexFlt> rsqrt() const {
|
| 441 |
+
return sqrt().reciprocal();
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
Vectorized<ComplexFlt> pow(const Vectorized<ComplexFlt>& exp) const {
|
| 445 |
+
__at_align__ ComplexFlt x_tmp[size()];
|
| 446 |
+
__at_align__ ComplexFlt y_tmp[size()];
|
| 447 |
+
store(x_tmp);
|
| 448 |
+
exp.store(y_tmp);
|
| 449 |
+
for (const auto i : c10::irange(size())) {
|
| 450 |
+
x_tmp[i] = std::pow(x_tmp[i], y_tmp[i]);
|
| 451 |
+
}
|
| 452 |
+
return loadu(x_tmp);
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
Vectorized<ComplexFlt> atan() const {
|
| 456 |
+
// atan(x) = i/2 * ln((i + z)/(i - z))
|
| 457 |
+
auto ione = Vectorized(imag_one);
|
| 458 |
+
auto sum = ione + *this;
|
| 459 |
+
auto sub = ione - *this;
|
| 460 |
+
auto ln = (sum / sub).log(); // ln((i + z)/(i - z))
|
| 461 |
+
return ln * imag_half; // i/2*ln()
|
| 462 |
+
}
|
| 463 |
+
Vectorized<ComplexFlt> atanh() const {
|
| 464 |
+
return map(std::atanh);
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
Vectorized<ComplexFlt> acos() const {
|
| 468 |
+
// acos(x) = pi/2 - asin(x)
|
| 469 |
+
return Vectorized(pi_2) - asin();
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
Vectorized<ComplexFlt> inline operator*(const Vectorized<ComplexFlt>& b) const {
|
| 473 |
+
//(a + bi) * (c + di) = (ac - bd) + (ad + bc)i
|
| 474 |
+
|
| 475 |
+
#if 1
|
| 476 |
+
// this is more vsx friendly than simulating horizontal from x86
|
| 477 |
+
|
| 478 |
+
auto vi = b.el_mergeo();
|
| 479 |
+
auto vr = b.el_mergee();
|
| 480 |
+
vi = vi ^ rsign_mask;
|
| 481 |
+
auto ret = elwise_mult(vr);
|
| 482 |
+
auto vx_swapped = el_swapped();
|
| 483 |
+
ret = vx_swapped.el_madd(vi, ret);
|
| 484 |
+
return ret;
|
| 485 |
+
|
| 486 |
+
#else
|
| 487 |
+
|
| 488 |
+
auto ac_bd = elwise_mult(b);
|
| 489 |
+
auto d_c = b.el_swapped();
|
| 490 |
+
d_c = d_c ^ isign_mask;
|
| 491 |
+
auto ad_bc = elwise_mult(d_c);
|
| 492 |
+
auto ret = horizontal_sub_permD8(ac_bd, ad_bc);
|
| 493 |
+
return ret;
|
| 494 |
+
#endif
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
Vectorized<ComplexFlt> inline operator/(const Vectorized<ComplexFlt>& b) const {
|
| 498 |
+
// re + im*i = (a + bi) / (c + di)
|
| 499 |
+
// re = (ac + bd)/abs_2()
|
| 500 |
+
// im = (bc - ad)/abs_2()
|
| 501 |
+
auto fabs_cd = Vectorized{
|
| 502 |
+
vec_andc(b._vec0, sign_mask),
|
| 503 |
+
vec_andc(b._vec1, sign_mask)}; // |c| |d|
|
| 504 |
+
auto fabs_dc = fabs_cd.el_swapped(); // |d| |c|
|
| 505 |
+
auto scale = fabs_cd.elwise_max(fabs_dc); // sc = max(|c|, |d|)
|
| 506 |
+
auto a2 = elwise_div(scale); // a/sc b/sc
|
| 507 |
+
auto b2 = b.elwise_div(scale); // c/sc d/sc
|
| 508 |
+
auto acbd2 = a2.elwise_mult(b2); // ac/sc^2 bd/sc^2
|
| 509 |
+
auto dc2 = b2.el_swapped(); // d/sc c/sc
|
| 510 |
+
dc2 = dc2 ^ rsign_mask; // -d/sc c/sc
|
| 511 |
+
auto adbc2 = a2.elwise_mult(dc2); // -ad/sc^2 bc/sc^2
|
| 512 |
+
auto ret = horizontal_add(acbd2, adbc2); // (ac+bd)/sc^2 (bc-ad)/sc^2
|
| 513 |
+
auto denom2 = b2.abs_2_(); // (c^2+d^2)/sc^2 (c^2+d^2)/sc^2
|
| 514 |
+
ret = ret.elwise_div(denom2);
|
| 515 |
+
return ret;
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
Vectorized<ComplexFlt> asin() const {
|
| 519 |
+
// asin(x)
|
| 520 |
+
// = -i*ln(iz + sqrt(1 -z^2))
|
| 521 |
+
// = -i*ln((ai - b) + sqrt(1 - (a + bi)*(a + bi)))
|
| 522 |
+
// = -i*ln((-b + ai) + sqrt(1 - (a**2 - b**2) - 2*abi))
|
| 523 |
+
|
| 524 |
+
#if 1
|
| 525 |
+
auto conj = conj_();
|
| 526 |
+
auto b_a = conj.el_swapped();
|
| 527 |
+
auto ab = conj.elwise_mult(b_a);
|
| 528 |
+
auto im = ab + ab;
|
| 529 |
+
auto val_2 = (*this).elwise_mult(*this);
|
| 530 |
+
auto val_2_swapped = val_2.el_swapped();
|
| 531 |
+
auto re = horizontal_sub_permD8(val_2, val_2_swapped);
|
| 532 |
+
re = Vectorized<ComplexFlt>(one) - re;
|
| 533 |
+
auto root = el_blend<0xAA>(re, im).sqrt();
|
| 534 |
+
auto ln = (b_a + root).log();
|
| 535 |
+
return ln.el_swapped().conj();
|
| 536 |
+
#else
|
| 537 |
+
return map(std::asin);
|
| 538 |
+
#endif
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
Vectorized<ComplexFlt> exp() const {
|
| 542 |
+
return map(std::exp);
|
| 543 |
+
}
|
| 544 |
+
Vectorized<ComplexFlt> exp2() const {
|
| 545 |
+
return map(exp2_impl);
|
| 546 |
+
}
|
| 547 |
+
Vectorized<ComplexFlt> expm1() const {
|
| 548 |
+
return map(std::expm1);
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
Vectorized<ComplexFlt> eq(const Vectorized<ComplexFlt>& other) const {
|
| 552 |
+
auto eq = (*this == other); // compares real and imag individually
|
| 553 |
+
// If both real numbers and imag numbers are equal, then the complex numbers are equal
|
| 554 |
+
return (eq.real() & eq.imag()) & one;
|
| 555 |
+
}
|
| 556 |
+
Vectorized<ComplexFlt> ne(const Vectorized<ComplexFlt>& other) const {
|
| 557 |
+
auto ne = (*this != other); // compares real and imag individually
|
| 558 |
+
// If either real numbers or imag numbers are not equal, then the complex numbers are not equal
|
| 559 |
+
return (ne.real() | ne.imag()) & one;
|
| 560 |
+
}
|
| 561 |
+
|
| 562 |
+
Vectorized<ComplexFlt> sgn() const {
|
| 563 |
+
return map(at::native::sgn_impl);
|
| 564 |
+
}
|
| 565 |
+
|
| 566 |
+
Vectorized<ComplexFlt> operator<(const Vectorized<ComplexFlt>& other) const {
|
| 567 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 568 |
+
}
|
| 569 |
+
|
| 570 |
+
Vectorized<ComplexFlt> operator<=(const Vectorized<ComplexFlt>& other) const {
|
| 571 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 572 |
+
}
|
| 573 |
+
|
| 574 |
+
Vectorized<ComplexFlt> operator>(const Vectorized<ComplexFlt>& other) const {
|
| 575 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 576 |
+
}
|
| 577 |
+
|
| 578 |
+
Vectorized<ComplexFlt> operator>=(const Vectorized<ComplexFlt>& other) const {
|
| 579 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 580 |
+
}
|
| 581 |
+
|
| 582 |
+
DEFINE_MEMBER_OP(operator==, ComplexFlt, vec_cmpeq)
|
| 583 |
+
DEFINE_MEMBER_OP(operator!=, ComplexFlt, vec_cmpne)
|
| 584 |
+
|
| 585 |
+
DEFINE_MEMBER_OP(operator+, ComplexFlt, vec_add)
|
| 586 |
+
DEFINE_MEMBER_OP(operator-, ComplexFlt, vec_sub)
|
| 587 |
+
DEFINE_MEMBER_OP(operator&, ComplexFlt, vec_and)
|
| 588 |
+
DEFINE_MEMBER_OP(operator|, ComplexFlt, vec_or)
|
| 589 |
+
DEFINE_MEMBER_OP(operator^, ComplexFlt, vec_xor)
|
| 590 |
+
// elementwise helpers
|
| 591 |
+
DEFINE_MEMBER_OP(elwise_mult, ComplexFlt, vec_mul)
|
| 592 |
+
DEFINE_MEMBER_OP(elwise_div, ComplexFlt, vec_div)
|
| 593 |
+
DEFINE_MEMBER_OP(elwise_gt, ComplexFlt, vec_cmpgt)
|
| 594 |
+
DEFINE_MEMBER_OP(elwise_ge, ComplexFlt, vec_cmpge)
|
| 595 |
+
DEFINE_MEMBER_OP(elwise_lt, ComplexFlt, vec_cmplt)
|
| 596 |
+
DEFINE_MEMBER_OP(elwise_le, ComplexFlt, vec_cmple)
|
| 597 |
+
DEFINE_MEMBER_OP(elwise_max, ComplexFlt, vec_max)
|
| 598 |
+
};
|
| 599 |
+
|
| 600 |
+
template <>
|
| 601 |
+
Vectorized<ComplexFlt> inline maximum(
|
| 602 |
+
const Vectorized<ComplexFlt>& a,
|
| 603 |
+
const Vectorized<ComplexFlt>& b) {
|
| 604 |
+
auto abs_a = a.abs_2_();
|
| 605 |
+
auto abs_b = b.abs_2_();
|
| 606 |
+
// auto mask = _mm256_cmp_ps(abs_a, abs_b, _CMP_LT_OQ);
|
| 607 |
+
// auto max = _mm256_blendv_ps(a, b, mask);
|
| 608 |
+
auto mask = abs_a.elwise_lt(abs_b);
|
| 609 |
+
auto max = Vectorized<ComplexFlt>::elwise_blendv(a, b, mask);
|
| 610 |
+
|
| 611 |
+
return max;
|
| 612 |
+
// Exploit the fact that all-ones is a NaN.
|
| 613 |
+
// auto isnan = _mm256_cmp_ps(abs_a, abs_b, _CMP_UNORD_Q);
|
| 614 |
+
// return _mm256_or_ps(max, isnan);
|
| 615 |
+
}
|
| 616 |
+
|
| 617 |
+
template <>
|
| 618 |
+
Vectorized<ComplexFlt> inline minimum(
|
| 619 |
+
const Vectorized<ComplexFlt>& a,
|
| 620 |
+
const Vectorized<ComplexFlt>& b) {
|
| 621 |
+
auto abs_a = a.abs_2_();
|
| 622 |
+
auto abs_b = b.abs_2_();
|
| 623 |
+
// auto mask = _mm256_cmp_ps(abs_a, abs_b, _CMP_GT_OQ);
|
| 624 |
+
// auto min = _mm256_blendv_ps(a, b, mask);
|
| 625 |
+
auto mask = abs_a.elwise_gt(abs_b);
|
| 626 |
+
auto min = Vectorized<ComplexFlt>::elwise_blendv(a, b, mask);
|
| 627 |
+
return min;
|
| 628 |
+
// Exploit the fact that all-ones is a NaN.
|
| 629 |
+
// auto isnan = _mm256_cmp_ps(abs_a, abs_b, _CMP_UNORD_Q);
|
| 630 |
+
// return _mm256_or_ps(min, isnan);
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
template <>
|
| 634 |
+
Vectorized<ComplexFlt> C10_ALWAYS_INLINE operator+(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 635 |
+
return Vectorized<ComplexFlt>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 636 |
+
}
|
| 637 |
+
|
| 638 |
+
template <>
|
| 639 |
+
Vectorized<ComplexFlt> C10_ALWAYS_INLINE operator-(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 640 |
+
return Vectorized<ComplexFlt>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 641 |
+
}
|
| 642 |
+
|
| 643 |
+
template <>
|
| 644 |
+
Vectorized<ComplexFlt> C10_ALWAYS_INLINE operator&(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 645 |
+
return Vectorized<ComplexFlt>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
template <>
|
| 649 |
+
Vectorized<ComplexFlt> C10_ALWAYS_INLINE operator|(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 650 |
+
return Vectorized<ComplexFlt>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
template <>
|
| 654 |
+
Vectorized<ComplexFlt> C10_ALWAYS_INLINE operator^(const Vectorized<ComplexFlt>& a, const Vectorized<ComplexFlt>& b) {
|
| 655 |
+
return Vectorized<ComplexFlt>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
} // namespace
|
| 659 |
+
} // namespace vec
|
| 660 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_double_vsx.h
ADDED
|
@@ -0,0 +1,477 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
#include <c10/util/irange.h>
|
| 7 |
+
|
| 8 |
+
#include <sleef.h>
|
| 9 |
+
|
| 10 |
+
namespace at {
|
| 11 |
+
namespace vec {
|
| 12 |
+
|
| 13 |
+
inline namespace CPU_CAPABILITY {
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
template <>
|
| 17 |
+
class Vectorized<double> {
|
| 18 |
+
private:
|
| 19 |
+
union {
|
| 20 |
+
struct {
|
| 21 |
+
vfloat64 _vec0;
|
| 22 |
+
vfloat64 _vec1;
|
| 23 |
+
};
|
| 24 |
+
struct {
|
| 25 |
+
vbool64 _vecb0;
|
| 26 |
+
vbool64 _vecb1;
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
} __attribute__((__may_alias__));
|
| 30 |
+
|
| 31 |
+
public:
|
| 32 |
+
using value_type = double;
|
| 33 |
+
using vec_internal_type = vfloat64;
|
| 34 |
+
using vec_internal_mask_type = vbool64;
|
| 35 |
+
using size_type = int;
|
| 36 |
+
static constexpr size_type size() {
|
| 37 |
+
return 4;
|
| 38 |
+
}
|
| 39 |
+
Vectorized() {}
|
| 40 |
+
C10_ALWAYS_INLINE Vectorized(vfloat64 v) : _vec0{v}, _vec1{v} {}
|
| 41 |
+
C10_ALWAYS_INLINE Vectorized(vbool64 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 42 |
+
C10_ALWAYS_INLINE Vectorized(vfloat64 v1, vfloat64 v2) : _vec0{v1}, _vec1{v2} {}
|
| 43 |
+
C10_ALWAYS_INLINE Vectorized(vbool64 v1, vbool64 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 44 |
+
C10_ALWAYS_INLINE Vectorized(double scalar)
|
| 45 |
+
: _vec0{vec_splats(scalar)}, _vec1{vec_splats(scalar)} {}
|
| 46 |
+
C10_ALWAYS_INLINE Vectorized(
|
| 47 |
+
double scalar1,
|
| 48 |
+
double scalar2,
|
| 49 |
+
double scalar3,
|
| 50 |
+
double scalar4)
|
| 51 |
+
: _vec0{vfloat64{scalar1, scalar2}}, _vec1{vfloat64{scalar3, scalar4}} {}
|
| 52 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 53 |
+
return _vec0;
|
| 54 |
+
}
|
| 55 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 56 |
+
return _vec1;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
int zero_mask() const {
|
| 60 |
+
auto cmp = (*this == vd_zero);
|
| 61 |
+
return (cmp._vecb0[0] & 1) | (cmp._vecb0[1] & 2) | (cmp._vecb1[0] & 4) |
|
| 62 |
+
(cmp._vecb1[1] & 8);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
template <int64_t mask>
|
| 66 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 0, Vectorized<double>> C10_ALWAYS_INLINE
|
| 67 |
+
blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 68 |
+
return a;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
template <int64_t mask>
|
| 72 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 1, Vectorized<double>> C10_ALWAYS_INLINE
|
| 73 |
+
blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 74 |
+
return b;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
template <int64_t mask>
|
| 78 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 2, Vectorized<double>> C10_ALWAYS_INLINE
|
| 79 |
+
blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 80 |
+
return { b._vec0, a._vec1 };
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
template <int64_t mask>
|
| 84 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 3, Vectorized<double>> C10_ALWAYS_INLINE
|
| 85 |
+
blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 86 |
+
return { a._vec0, b._vec1 };
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
template <int64_t mask>
|
| 91 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 4, Vectorized<double>> C10_ALWAYS_INLINE
|
| 92 |
+
blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 93 |
+
const vbool64 mask_1st = VsxDblMask1(mask);
|
| 94 |
+
return { (vfloat64)vec_sel(a._vec0, b._vec0, mask_1st), a._vec1 };
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
template <int64_t mask>
|
| 98 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 5, Vectorized<double>> C10_ALWAYS_INLINE
|
| 99 |
+
blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 100 |
+
const vbool64 mask_1st = VsxDblMask1(mask);
|
| 101 |
+
return { (vfloat64)vec_sel(a._vec0, b._vec0, mask_1st), b._vec1 };
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
template <int64_t mask>
|
| 106 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 6,
|
| 107 |
+
Vectorized<double>>
|
| 108 |
+
C10_ALWAYS_INLINE blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 109 |
+
const vbool64 mask_2nd = VsxDblMask2(mask);
|
| 110 |
+
// generated masks
|
| 111 |
+
return { a._vec0,
|
| 112 |
+
(vfloat64)vec_sel(a._vec1, b._vec1, mask_2nd) };
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
template <int64_t mask>
|
| 116 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 7,
|
| 117 |
+
Vectorized<double>>
|
| 118 |
+
C10_ALWAYS_INLINE blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 119 |
+
const vbool64 mask_2nd = VsxDblMask2(mask);
|
| 120 |
+
// generated masks
|
| 121 |
+
return { b._vec0,
|
| 122 |
+
(vfloat64)vec_sel(a._vec1, b._vec1, mask_2nd) };
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
template <int64_t mask>
|
| 126 |
+
static std::enable_if_t<blendChoiceDbl(mask) == 8, Vectorized<double>>
|
| 127 |
+
C10_ALWAYS_INLINE blend(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 128 |
+
const vbool64 mask_1st = VsxDblMask1(mask);
|
| 129 |
+
const vbool64 mask_2nd = VsxDblMask2(mask);
|
| 130 |
+
return {
|
| 131 |
+
(vfloat64)vec_sel(a._vec0, b._vec0, mask_1st),
|
| 132 |
+
(vfloat64)vec_sel(a._vec1, b._vec1, mask_2nd) };
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
static Vectorized<double> C10_ALWAYS_INLINE blendv(
|
| 137 |
+
const Vectorized<double>& a,
|
| 138 |
+
const Vectorized<double>& b,
|
| 139 |
+
const Vectorized<double>& mask) {
|
| 140 |
+
// the mask used here returned by comparision of vec256
|
| 141 |
+
|
| 142 |
+
return {
|
| 143 |
+
vec_sel(a._vec0, b._vec0, mask._vecb0),
|
| 144 |
+
vec_sel(a._vec1, b._vec1, mask._vecb1)};
|
| 145 |
+
}
|
| 146 |
+
template <typename step_t>
|
| 147 |
+
static Vectorized<double> arange(double base = 0., step_t step = static_cast<step_t>(1)) {
|
| 148 |
+
return Vectorized<double>(base, base + step, base + 2 * step, base + 3 * step);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
static Vectorized<double> C10_ALWAYS_INLINE
|
| 152 |
+
set(const Vectorized<double>& a, const Vectorized<double>& b, size_t count = size()) {
|
| 153 |
+
switch (count) {
|
| 154 |
+
case 0:
|
| 155 |
+
return a;
|
| 156 |
+
case 1:
|
| 157 |
+
return blend<1>(a, b);
|
| 158 |
+
case 2:
|
| 159 |
+
return blend<3>(a, b);
|
| 160 |
+
case 3:
|
| 161 |
+
return blend<7>(a, b);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
return b;
|
| 165 |
+
}
|
| 166 |
+
static Vectorized<value_type> C10_ALWAYS_INLINE
|
| 167 |
+
loadu(const void* ptr, int count = size()) {
|
| 168 |
+
if (count == size()) {
|
| 169 |
+
return {
|
| 170 |
+
vec_vsx_ld(offset0, reinterpret_cast<const value_type*>(ptr)),
|
| 171 |
+
vec_vsx_ld(offset16, reinterpret_cast<const value_type*>(ptr))};
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 175 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 176 |
+
|
| 177 |
+
return {vec_vsx_ld(offset0, tmp_values), vec_vsx_ld(offset16, tmp_values)};
|
| 178 |
+
}
|
| 179 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 180 |
+
if (count == size()) {
|
| 181 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<value_type*>(ptr));
|
| 182 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<value_type*>(ptr));
|
| 183 |
+
} else if (count > 0) {
|
| 184 |
+
__at_align__ value_type tmp_values[size()];
|
| 185 |
+
vec_vsx_st(_vec0, offset0, tmp_values);
|
| 186 |
+
vec_vsx_st(_vec1, offset16, tmp_values);
|
| 187 |
+
std::memcpy(
|
| 188 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
const double& operator[](int idx) const = delete;
|
| 192 |
+
double& operator[](int idx) = delete;
|
| 193 |
+
Vectorized<double> map(double (*const f)(double)) const {
|
| 194 |
+
Vectorized<double> ret;
|
| 195 |
+
for (const auto i : c10::irange(size()/2)) {
|
| 196 |
+
ret._vec0[i] = f(_vec0[i]);
|
| 197 |
+
}
|
| 198 |
+
for (const auto i : c10::irange(size()/2)) {
|
| 199 |
+
ret._vec1[i] = f(_vec1[i]);
|
| 200 |
+
}
|
| 201 |
+
return ret;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
Vectorized<double> mapbi(double (*const f)(double, double), const Vectorized<double>& other)
|
| 205 |
+
const {
|
| 206 |
+
Vectorized<double> ret;
|
| 207 |
+
for (const auto i : c10::irange(size()/2)) {
|
| 208 |
+
ret._vec0[i] = f(_vec0[i], other._vec0[i]);
|
| 209 |
+
}
|
| 210 |
+
for (const auto i : c10::irange(size()/2)) {
|
| 211 |
+
ret._vec1[i] = f(_vec1[i], other._vec1[i]);
|
| 212 |
+
}
|
| 213 |
+
return ret;
|
| 214 |
+
}
|
| 215 |
+
Vectorized<double> C10_ALWAYS_INLINE abs() const {
|
| 216 |
+
return {vec_abs(_vec0), vec_abs(_vec1)};
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
Vectorized<double> C10_ALWAYS_INLINE acos() const {
|
| 220 |
+
return {Sleef_acosd2_u10(_vec0), Sleef_acosd2_u10(_vec1)};
|
| 221 |
+
}
|
| 222 |
+
Vectorized<double> C10_ALWAYS_INLINE acosh() const {
|
| 223 |
+
return {Sleef_acoshd2_u10(_vec0), Sleef_acoshd2_u10(_vec1)};
|
| 224 |
+
}
|
| 225 |
+
Vectorized<double> C10_ALWAYS_INLINE asin() const {
|
| 226 |
+
return {Sleef_asind2_u10(_vec0), Sleef_asind2_u10(_vec1)};
|
| 227 |
+
}
|
| 228 |
+
Vectorized<double> atan() const {
|
| 229 |
+
return {Sleef_atand2_u10(_vec0), Sleef_atand2_u10(_vec1)};
|
| 230 |
+
}
|
| 231 |
+
Vectorized<double> atanh() const {
|
| 232 |
+
return {Sleef_atanhd2_u10(_vec0), Sleef_atanhd2_u10(_vec1)};
|
| 233 |
+
}
|
| 234 |
+
Vectorized<double> atan2(const Vectorized<double>& b) const {
|
| 235 |
+
return {Sleef_atan2d2_u10(_vec0, b._vec0), Sleef_atan2d2_u10(_vec1, b._vec1)};
|
| 236 |
+
}
|
| 237 |
+
Vectorized<double> copysign(const Vectorized<double> &sign) const {
|
| 238 |
+
return {Sleef_copysignd2(_vec0, sign._vec0), Sleef_copysignd2(_vec1, sign._vec1)};
|
| 239 |
+
}
|
| 240 |
+
Vectorized<double> erf() const {
|
| 241 |
+
return {Sleef_erfd2_u10(_vec0), Sleef_erfd2_u10(_vec1)};
|
| 242 |
+
}
|
| 243 |
+
Vectorized<double> erfc() const {
|
| 244 |
+
return {Sleef_erfcd2_u15(_vec0), Sleef_erfcd2_u15(_vec1)};
|
| 245 |
+
}
|
| 246 |
+
Vectorized<double> C10_ALWAYS_INLINE exp() const {
|
| 247 |
+
return {Sleef_expd2_u10(_vec0), Sleef_expd2_u10(_vec1)};
|
| 248 |
+
}
|
| 249 |
+
Vectorized<double> C10_ALWAYS_INLINE exp2() const {
|
| 250 |
+
return {Sleef_exp2d2_u10(_vec0), Sleef_exp2d2_u10(_vec1)};
|
| 251 |
+
}
|
| 252 |
+
Vectorized<double> expm1() const {
|
| 253 |
+
return {Sleef_expm1d2_u10(_vec0), Sleef_expm1d2_u10(_vec1)};
|
| 254 |
+
}
|
| 255 |
+
Vectorized<double> C10_ALWAYS_INLINE exp_u20() const {
|
| 256 |
+
return exp();
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
Vectorized<double> lgamma() const __ubsan_ignore_undefined__ {
|
| 260 |
+
return {Sleef_lgammad2_u10(_vec0), Sleef_lgammad2_u10(_vec1)};
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
Vectorized<double> erfinv() const {
|
| 264 |
+
return map(calc_erfinv);
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
Vectorized<double> angle() const {
|
| 268 |
+
auto tmp = blendv(
|
| 269 |
+
Vectorized<double>(0), Vectorized<double>(c10::pi<double>), *this < Vectorized<double>(0));
|
| 270 |
+
return blendv(tmp, *this, isnan());
|
| 271 |
+
}
|
| 272 |
+
Vectorized<double> real() const {
|
| 273 |
+
return *this;
|
| 274 |
+
}
|
| 275 |
+
Vectorized<double> imag() const {
|
| 276 |
+
return Vectorized<double>{0};
|
| 277 |
+
}
|
| 278 |
+
Vectorized<double> conj() const {
|
| 279 |
+
return *this;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
Vectorized<double> C10_ALWAYS_INLINE log() const {
|
| 283 |
+
return {Sleef_logd2_u10(_vec0), Sleef_logd2_u10(_vec1)};
|
| 284 |
+
}
|
| 285 |
+
Vectorized<double> C10_ALWAYS_INLINE log10() const {
|
| 286 |
+
return {Sleef_log10d2_u10(_vec0), Sleef_log10d2_u10(_vec1)};
|
| 287 |
+
}
|
| 288 |
+
Vectorized<double> C10_ALWAYS_INLINE log1p() const {
|
| 289 |
+
return {Sleef_log1pd2_u10(_vec0), Sleef_log1pd2_u10(_vec1)};
|
| 290 |
+
}
|
| 291 |
+
Vectorized<double> C10_ALWAYS_INLINE log2() const {
|
| 292 |
+
return {Sleef_log2d2_u10(_vec0), Sleef_log2d2_u10(_vec1)};
|
| 293 |
+
}
|
| 294 |
+
Vectorized<double> C10_ALWAYS_INLINE ceil() const {
|
| 295 |
+
return {vec_ceil(_vec0), vec_ceil(_vec1)};
|
| 296 |
+
}
|
| 297 |
+
Vectorized<double> C10_ALWAYS_INLINE cos() const {
|
| 298 |
+
return {Sleef_cosd2_u10(_vec0), Sleef_cosd2_u10(_vec1)};
|
| 299 |
+
}
|
| 300 |
+
Vectorized<double> C10_ALWAYS_INLINE cosh() const {
|
| 301 |
+
return {Sleef_coshd2_u10(_vec0), Sleef_coshd2_u10(_vec1)};
|
| 302 |
+
}
|
| 303 |
+
Vectorized<double> C10_ALWAYS_INLINE floor() const {
|
| 304 |
+
return {vec_floor(_vec0), vec_floor(_vec1)};
|
| 305 |
+
}
|
| 306 |
+
Vectorized<double> C10_ALWAYS_INLINE neg() const {
|
| 307 |
+
return {vec_neg(_vec0), vec_neg(_vec1)};
|
| 308 |
+
}
|
| 309 |
+
Vectorized<double> C10_ALWAYS_INLINE round() const {
|
| 310 |
+
return {vec_rint(_vec0), vec_rint(_vec1)};
|
| 311 |
+
}
|
| 312 |
+
Vectorized<double> C10_ALWAYS_INLINE sin() const {
|
| 313 |
+
return {Sleef_sind2_u10(_vec0), Sleef_sind2_u10(_vec1)};
|
| 314 |
+
}
|
| 315 |
+
Vectorized<double> C10_ALWAYS_INLINE sinh() const {
|
| 316 |
+
return {Sleef_sinhd2_u10(_vec0), Sleef_sinhd2_u10(_vec1)};
|
| 317 |
+
}
|
| 318 |
+
Vectorized<double> C10_ALWAYS_INLINE tan() const {
|
| 319 |
+
return {Sleef_tand2_u10(_vec0), Sleef_tand2_u10(_vec1)};
|
| 320 |
+
}
|
| 321 |
+
Vectorized<double> C10_ALWAYS_INLINE tanh() const {
|
| 322 |
+
return {Sleef_tanhd2_u10(_vec0), Sleef_tanhd2_u10(_vec1)};
|
| 323 |
+
}
|
| 324 |
+
Vectorized<double> C10_ALWAYS_INLINE trunc() const {
|
| 325 |
+
return {vec_trunc(_vec0), vec_trunc(_vec1)};
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
Vectorized<double> C10_ALWAYS_INLINE frac() const {
|
| 329 |
+
return *this - trunc();
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
Vectorized<double> C10_ALWAYS_INLINE sqrt() const {
|
| 333 |
+
return {vec_sqrt(_vec0), vec_sqrt(_vec1)};
|
| 334 |
+
}
|
| 335 |
+
Vectorized<double> C10_ALWAYS_INLINE reciprocal() const {
|
| 336 |
+
return {
|
| 337 |
+
vec_div(vd_one, _vec0), // vec_re(_vec0) is estimated one.
|
| 338 |
+
vec_div(vd_one, _vec1)};
|
| 339 |
+
}
|
| 340 |
+
Vectorized<double> C10_ALWAYS_INLINE rsqrt() const {
|
| 341 |
+
return sqrt().reciprocal();
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
Vectorized<double> C10_ALWAYS_INLINE pow(const Vectorized<double>& b) const {
|
| 345 |
+
return {Sleef_powd2_u10(_vec0, b._vec0), Sleef_powd2_u10(_vec1, b._vec1)};
|
| 346 |
+
}
|
| 347 |
+
Vectorized<double> C10_ALWAYS_INLINE fmod(const Vectorized<double>& b) const {
|
| 348 |
+
return {Sleef_fmodd2(_vec0, b._vec0),Sleef_fmodd2(_vec1, b._vec1)};
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
Vectorized<double> hypot(const Vectorized<double>& b) const {
|
| 352 |
+
return {Sleef_hypotd2_u05(_vec0, b._vec0), Sleef_hypotd2_u05(_vec1, b._vec1)};
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
Vectorized<double> nextafter(const Vectorized<double>& b) const {
|
| 356 |
+
return {Sleef_nextafterd2(_vec0, b._vec0), Sleef_nextafterd2(_vec1, b._vec1)};
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
Vectorized<double> igamma(const Vectorized<double>& x) const {
|
| 360 |
+
return mapbi(calc_igamma, x);
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
Vectorized<double> igammac(const Vectorized<double>& x) const {
|
| 364 |
+
return mapbi(calc_igammac, x);
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
|
| 368 |
+
Vectorized<double> i0() const {
|
| 369 |
+
return map(calc_i0);
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
Vectorized<double> i0e() const {
|
| 373 |
+
return map(calc_i0e);
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
Vectorized<double> digamma() const {
|
| 377 |
+
return map(calc_digamma);
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
Vectorized<double> _nor() const {
|
| 381 |
+
return {vec_nor(_vec0, _vec0), vec_nor(_vec1, _vec1)};
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
Vectorized<double> isnan() const {
|
| 385 |
+
auto x = *this;
|
| 386 |
+
auto ret = (x == x);
|
| 387 |
+
return ret._nor();
|
| 388 |
+
}
|
| 389 |
+
bool has_inf_nan() const {
|
| 390 |
+
for (const auto i : c10::irange(size()/2)) {
|
| 391 |
+
if(_isnan(_vec0[i]) || _isinf(_vec0[i])) {
|
| 392 |
+
return true;
|
| 393 |
+
}
|
| 394 |
+
}
|
| 395 |
+
for (const auto i : c10::irange(size()/2)) {
|
| 396 |
+
if(_isnan(_vec1[i]) || _isinf(_vec1[i])) {
|
| 397 |
+
return true;
|
| 398 |
+
}
|
| 399 |
+
}
|
| 400 |
+
return false;
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
DEFINE_MEMBER_OP(operator==, double, vec_cmpeq)
|
| 404 |
+
DEFINE_MEMBER_OP(operator!=, double, vec_cmpne)
|
| 405 |
+
DEFINE_MEMBER_OP(operator<, double, vec_cmplt)
|
| 406 |
+
DEFINE_MEMBER_OP(operator<=, double, vec_cmple)
|
| 407 |
+
DEFINE_MEMBER_OP(operator>, double, vec_cmpgt)
|
| 408 |
+
DEFINE_MEMBER_OP(operator>=, double, vec_cmpge)
|
| 409 |
+
DEFINE_MEMBER_OP_AND_ONE(eq, double, vec_cmpeq)
|
| 410 |
+
DEFINE_MEMBER_OP_AND_ONE(ne, double, vec_cmpne)
|
| 411 |
+
DEFINE_MEMBER_OP_AND_ONE(lt, double, vec_cmplt)
|
| 412 |
+
DEFINE_MEMBER_OP_AND_ONE(le, double, vec_cmple)
|
| 413 |
+
DEFINE_MEMBER_OP_AND_ONE(gt, double, vec_cmpgt)
|
| 414 |
+
DEFINE_MEMBER_OP_AND_ONE(ge, double, vec_cmpge)
|
| 415 |
+
DEFINE_MEMBER_OP(operator+, double, vec_add)
|
| 416 |
+
DEFINE_MEMBER_OP(operator-, double, vec_sub)
|
| 417 |
+
DEFINE_MEMBER_OP(operator*, double, vec_mul)
|
| 418 |
+
DEFINE_MEMBER_OP(operator/, double, vec_div)
|
| 419 |
+
DEFINE_MEMBER_OP(maximum, double, vec_max_nan2)
|
| 420 |
+
DEFINE_MEMBER_OP(minimum, double, vec_min_nan2)
|
| 421 |
+
DEFINE_MEMBER_OP(operator&, double, vec_and)
|
| 422 |
+
DEFINE_MEMBER_OP(operator|, double, vec_or)
|
| 423 |
+
DEFINE_MEMBER_OP(operator^, double, vec_xor)
|
| 424 |
+
DEFINE_MEMBER_TERNARY_OP(madd, double, vec_madd)
|
| 425 |
+
};
|
| 426 |
+
template <>
|
| 427 |
+
Vectorized<double> inline maximum(
|
| 428 |
+
const Vectorized<double>& a,
|
| 429 |
+
const Vectorized<double>& b) {
|
| 430 |
+
return a.maximum(b);
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
template <>
|
| 434 |
+
Vectorized<double> inline minimum(
|
| 435 |
+
const Vectorized<double>& a,
|
| 436 |
+
const Vectorized<double>& b) {
|
| 437 |
+
return a.minimum(b);
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
template <>
|
| 441 |
+
Vectorized<double> C10_ALWAYS_INLINE operator+(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 442 |
+
return Vectorized<double>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
template <>
|
| 446 |
+
Vectorized<double> C10_ALWAYS_INLINE operator-(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 447 |
+
return Vectorized<double>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
template <>
|
| 451 |
+
Vectorized<double> C10_ALWAYS_INLINE operator*(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 452 |
+
return Vectorized<double>{vec_mul(a.vec0(), b.vec0()), vec_mul(a.vec1(), b.vec1())};
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
template <>
|
| 456 |
+
Vectorized<double> C10_ALWAYS_INLINE operator/(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 457 |
+
return Vectorized<double>{vec_div(a.vec0(), b.vec0()), vec_div(a.vec1(), b.vec1())};
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
template <>
|
| 461 |
+
Vectorized<double> C10_ALWAYS_INLINE operator&(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 462 |
+
return Vectorized<double>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
template <>
|
| 466 |
+
Vectorized<double> C10_ALWAYS_INLINE operator|(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 467 |
+
return Vectorized<double>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 468 |
+
}
|
| 469 |
+
|
| 470 |
+
template <>
|
| 471 |
+
Vectorized<double> C10_ALWAYS_INLINE operator^(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 472 |
+
return Vectorized<double>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
} // namespace
|
| 476 |
+
} // namespace vec
|
| 477 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_float_vsx.h
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
#include <sleef.h>
|
| 7 |
+
namespace at {
|
| 8 |
+
namespace vec {
|
| 9 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 10 |
+
|
| 11 |
+
inline namespace CPU_CAPABILITY {
|
| 12 |
+
|
| 13 |
+
template <>
|
| 14 |
+
class Vectorized<float> {
|
| 15 |
+
private:
|
| 16 |
+
union {
|
| 17 |
+
struct {
|
| 18 |
+
vfloat32 _vec0;
|
| 19 |
+
vfloat32 _vec1;
|
| 20 |
+
};
|
| 21 |
+
struct {
|
| 22 |
+
vbool32 _vecb0;
|
| 23 |
+
vbool32 _vecb1;
|
| 24 |
+
};
|
| 25 |
+
|
| 26 |
+
} __attribute__((__may_alias__));
|
| 27 |
+
|
| 28 |
+
public:
|
| 29 |
+
using value_type = float;
|
| 30 |
+
using vec_internal_type = vfloat32;
|
| 31 |
+
using vec_internal_mask_type = vbool32;
|
| 32 |
+
using size_type = int;
|
| 33 |
+
|
| 34 |
+
static constexpr size_type size() {
|
| 35 |
+
return 8;
|
| 36 |
+
}
|
| 37 |
+
Vectorized() {}
|
| 38 |
+
|
| 39 |
+
C10_ALWAYS_INLINE Vectorized(vfloat32 v) : _vec0{v}, _vec1{v} {}
|
| 40 |
+
C10_ALWAYS_INLINE Vectorized(vbool32 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 41 |
+
C10_ALWAYS_INLINE Vectorized(vfloat32 v1, vfloat32 v2) : _vec0{v1}, _vec1{v2} {}
|
| 42 |
+
C10_ALWAYS_INLINE Vectorized(vbool32 v1, vbool32 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 43 |
+
C10_ALWAYS_INLINE Vectorized(float scalar)
|
| 44 |
+
: _vec0{vec_splats(scalar)}, _vec1{vec_splats(scalar)} {}
|
| 45 |
+
C10_ALWAYS_INLINE Vectorized(
|
| 46 |
+
float scalar1,
|
| 47 |
+
float scalar2,
|
| 48 |
+
float scalar3,
|
| 49 |
+
float scalar4,
|
| 50 |
+
float scalar5,
|
| 51 |
+
float scalar6,
|
| 52 |
+
float scalar7,
|
| 53 |
+
float scalar8)
|
| 54 |
+
: _vec0{vfloat32{scalar1, scalar2, scalar3, scalar4}},
|
| 55 |
+
_vec1{vfloat32{scalar5, scalar6, scalar7, scalar8}} {}
|
| 56 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 57 |
+
return _vec0;
|
| 58 |
+
}
|
| 59 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 60 |
+
return _vec1;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
template <int64_t mask>
|
| 64 |
+
static std::enable_if_t<blendChoice(mask) == 0, Vectorized<float>> C10_ALWAYS_INLINE
|
| 65 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 66 |
+
return a;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
template <int64_t mask>
|
| 70 |
+
static std::enable_if_t<blendChoice(mask) == 1, Vectorized<float>> C10_ALWAYS_INLINE
|
| 71 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 72 |
+
return b;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
template <int64_t mask>
|
| 76 |
+
static std::enable_if_t<blendChoice(mask) == 2, Vectorized<float>> C10_ALWAYS_INLINE
|
| 77 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 78 |
+
return {b._vec0, a._vec1};
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
template <int64_t mask>
|
| 82 |
+
static std::enable_if_t<blendChoice(mask) == 3, Vectorized<float>> C10_ALWAYS_INLINE
|
| 83 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 84 |
+
return {a._vec0, b._vec1};
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
template <int64_t mask>
|
| 88 |
+
static std::enable_if_t<blendChoice(mask) == 4, Vectorized<float>> C10_ALWAYS_INLINE
|
| 89 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 90 |
+
const vbool32 mask_1st = VsxMask1(mask);
|
| 91 |
+
return {(vfloat32)vec_sel(a._vec0, b._vec0, mask_1st), a._vec1};
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
template <int64_t mask>
|
| 95 |
+
static std::enable_if_t<blendChoice(mask) == 5, Vectorized<float>> C10_ALWAYS_INLINE
|
| 96 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 97 |
+
const vbool32 mask_1st = VsxMask1(mask);
|
| 98 |
+
return {(vfloat32)vec_sel(a._vec0, b._vec0, mask_1st), b._vec1};
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
template <int64_t mask>
|
| 102 |
+
static std::enable_if_t<blendChoice(mask) == 6, Vectorized<float>> C10_ALWAYS_INLINE
|
| 103 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 104 |
+
const vbool32 mask_2nd = VsxMask2(mask);
|
| 105 |
+
// generated masks
|
| 106 |
+
return {a._vec0, (vfloat32)vec_sel(a._vec1, b._vec1, mask_2nd)};
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
template <int64_t mask>
|
| 110 |
+
static std::enable_if_t<blendChoice(mask) == 7, Vectorized<float>> C10_ALWAYS_INLINE
|
| 111 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 112 |
+
const vbool32 mask_2nd = VsxMask2(mask);
|
| 113 |
+
// generated masks
|
| 114 |
+
return {b._vec0, (vfloat32)vec_sel(a._vec1, b._vec1, mask_2nd)};
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
template <int64_t mask>
|
| 118 |
+
static std::enable_if_t<blendChoice(mask) == 8, Vectorized<float>> C10_ALWAYS_INLINE
|
| 119 |
+
blend(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 120 |
+
const vbool32 mask_1st = VsxMask1(mask);
|
| 121 |
+
const vbool32 mask_2nd = VsxMask2(mask);
|
| 122 |
+
return {
|
| 123 |
+
(vfloat32)vec_sel(a._vec0, b._vec0, mask_1st),
|
| 124 |
+
(vfloat32)vec_sel(a._vec1, b._vec1, mask_2nd)};
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
static Vectorized<float> C10_ALWAYS_INLINE blendv(
|
| 128 |
+
const Vectorized<float>& a,
|
| 129 |
+
const Vectorized<float>& b,
|
| 130 |
+
const Vectorized<float>& mask) {
|
| 131 |
+
// the mask used here returned by comparision of vec256
|
| 132 |
+
// assuming this we can use the same mask directly with vec_sel
|
| 133 |
+
return {
|
| 134 |
+
vec_sel(a._vec0, b._vec0, mask._vecb0),
|
| 135 |
+
vec_sel(a._vec1, b._vec1, mask._vecb1)};
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
template <typename step_t>
|
| 139 |
+
static Vectorized<float> arange(float base = 0.f, step_t step = static_cast<step_t>(1)) {
|
| 140 |
+
return Vectorized<float>(
|
| 141 |
+
base,
|
| 142 |
+
base + step,
|
| 143 |
+
base + 2 * step,
|
| 144 |
+
base + 3 * step,
|
| 145 |
+
base + 4 * step,
|
| 146 |
+
base + 5 * step,
|
| 147 |
+
base + 6 * step,
|
| 148 |
+
base + 7 * step);
|
| 149 |
+
}
|
| 150 |
+
static Vectorized<float> set(
|
| 151 |
+
const Vectorized<float>& a,
|
| 152 |
+
const Vectorized<float>& b,
|
| 153 |
+
size_t count = size()) {
|
| 154 |
+
switch (count) {
|
| 155 |
+
case 0:
|
| 156 |
+
return a;
|
| 157 |
+
case 1:
|
| 158 |
+
return blend<1>(a, b);
|
| 159 |
+
case 2:
|
| 160 |
+
return blend<3>(a, b);
|
| 161 |
+
case 3:
|
| 162 |
+
return blend<7>(a, b);
|
| 163 |
+
case 4:
|
| 164 |
+
return blend<15>(a, b);
|
| 165 |
+
case 5:
|
| 166 |
+
return blend<31>(a, b);
|
| 167 |
+
case 6:
|
| 168 |
+
return blend<63>(a, b);
|
| 169 |
+
case 7:
|
| 170 |
+
return blend<127>(a, b);
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
return b;
|
| 174 |
+
}
|
| 175 |
+
static Vectorized<value_type> C10_ALWAYS_INLINE
|
| 176 |
+
loadu(const void* ptr, int count = size()) {
|
| 177 |
+
if (count == size()) {
|
| 178 |
+
return {
|
| 179 |
+
vec_vsx_ld(offset0, reinterpret_cast<const value_type*>(ptr)),
|
| 180 |
+
vec_vsx_ld(offset16, reinterpret_cast<const value_type*>(ptr))};
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 184 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 185 |
+
|
| 186 |
+
return {vec_vsx_ld(offset0, tmp_values), vec_vsx_ld(offset16, tmp_values)};
|
| 187 |
+
}
|
| 188 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 189 |
+
if (count == size()) {
|
| 190 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<value_type*>(ptr));
|
| 191 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<value_type*>(ptr));
|
| 192 |
+
} else if (count > 0) {
|
| 193 |
+
__at_align__ value_type tmp_values[size()];
|
| 194 |
+
vec_vsx_st(_vec0, offset0, tmp_values);
|
| 195 |
+
vec_vsx_st(_vec1, offset16, tmp_values);
|
| 196 |
+
std::memcpy(
|
| 197 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 198 |
+
}
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
const float& operator[](int idx) const = delete;
|
| 202 |
+
float& operator[](int idx) = delete;
|
| 203 |
+
|
| 204 |
+
Vectorized<float> map(float (*const f)(float)) const {
|
| 205 |
+
Vectorized<float> ret;
|
| 206 |
+
for (int i = 0; i < size() / 2; i++) {
|
| 207 |
+
ret._vec0[i] = f(_vec0[i]);
|
| 208 |
+
}
|
| 209 |
+
for (int i = 0; i < size() / 2; i++) {
|
| 210 |
+
ret._vec1[i] = f(_vec1[i]);
|
| 211 |
+
}
|
| 212 |
+
return ret;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
Vectorized<float> mapbi(float (*const f)(float, float), const Vectorized<float>& other)
|
| 216 |
+
const {
|
| 217 |
+
Vectorized<float> ret;
|
| 218 |
+
for (int i = 0; i < size() / 2; i++) {
|
| 219 |
+
ret._vec0[i] = f(_vec0[i], other._vec0[i]);
|
| 220 |
+
}
|
| 221 |
+
for (int i = 0; i < size() / 2; i++) {
|
| 222 |
+
ret._vec1[i] = f(_vec1[i], other._vec1[i]);
|
| 223 |
+
}
|
| 224 |
+
return ret;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
Vectorized<float> _nor() const {
|
| 228 |
+
return {vec_nor(_vec0, _vec0), vec_nor(_vec1, _vec1)};
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
Vectorized<float> isnan() const {
|
| 232 |
+
auto x = *this;
|
| 233 |
+
auto ret = (x == x);
|
| 234 |
+
return ret._nor();
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
bool has_inf_nan() const {
|
| 238 |
+
for (const auto i : c10::irange(size()/2)) {
|
| 239 |
+
if(_isnan(_vec0[i]) || _isinf(_vec0[i])) {
|
| 240 |
+
return true;
|
| 241 |
+
}
|
| 242 |
+
}
|
| 243 |
+
for (const auto i : c10::irange(size()/2)) {
|
| 244 |
+
if(_isnan(_vec1[i]) || _isinf(_vec1[i])) {
|
| 245 |
+
return true;
|
| 246 |
+
}
|
| 247 |
+
}
|
| 248 |
+
return false;
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
int zero_mask() const {
|
| 252 |
+
// returns an integer mask where all zero elements are translated to 1-bit
|
| 253 |
+
// and others are translated to 0-bit
|
| 254 |
+
//__m256 cmp = _mm256_cmp_ps(values, _mm256_set1_ps(0.0f), _CMP_EQ_OQ);
|
| 255 |
+
auto cmp = (*this == zero);
|
| 256 |
+
// return _mm256_movemask_ps(cmp);
|
| 257 |
+
// possible simulation //mask= lvsl ( 0 ) vbpermq( vec, mask <<5)
|
| 258 |
+
vuint64 result0 = vec_vbpermq((vuint8)cmp._vecb0, mask_zero_bits);
|
| 259 |
+
vuint64 result1 = vec_vbpermq((vuint8)cmp._vecb1, mask_zero_bits);
|
| 260 |
+
return (result0[1] >> 12 | (result1[1] >> 8));
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
Vectorized<float> C10_ALWAYS_INLINE abs() const {
|
| 264 |
+
return {vec_abs(_vec0), vec_abs(_vec1)};
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
Vectorized<float> C10_ALWAYS_INLINE acos() const {
|
| 268 |
+
return {Sleef_acosf4_u10(_vec0), Sleef_acosf4_u10(_vec1)};
|
| 269 |
+
}
|
| 270 |
+
Vectorized<float> C10_ALWAYS_INLINE acosh() const {
|
| 271 |
+
return {Sleef_acoshf4_u10(_vec0), Sleef_acoshf4_u10(_vec1)};
|
| 272 |
+
}
|
| 273 |
+
Vectorized<float> C10_ALWAYS_INLINE asin() const {
|
| 274 |
+
return {Sleef_asinf4_u10(_vec0), Sleef_asinf4_u10(_vec1)};
|
| 275 |
+
}
|
| 276 |
+
Vectorized<float> atan() const {
|
| 277 |
+
return {Sleef_atanf4_u10(_vec0), Sleef_atanf4_u10(_vec1)};
|
| 278 |
+
}
|
| 279 |
+
Vectorized<float> atanh() const {
|
| 280 |
+
return {Sleef_atanhf4_u10(_vec0), Sleef_atanhf4_u10(_vec1)};
|
| 281 |
+
}
|
| 282 |
+
Vectorized<float> atan2(const Vectorized<float>& b) const {
|
| 283 |
+
return {Sleef_atan2f4_u10(_vec0, b._vec0), Sleef_atan2f4_u10(_vec1, b._vec1)};
|
| 284 |
+
}
|
| 285 |
+
Vectorized<float> copysign(const Vectorized<float> &sign) const {
|
| 286 |
+
return {Sleef_copysignf4(_vec0, sign._vec0), Sleef_copysignf4(_vec1, sign._vec1)};
|
| 287 |
+
}
|
| 288 |
+
Vectorized<float> lgamma() const {
|
| 289 |
+
return {Sleef_lgammaf4_u10(_vec0), Sleef_lgammaf4_u10(_vec1)};
|
| 290 |
+
}
|
| 291 |
+
Vectorized<float> erf() const {
|
| 292 |
+
return {Sleef_erff4_u10(_vec0), Sleef_erff4_u10(_vec1)};
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
Vectorized<float> erfc() const {
|
| 296 |
+
return {Sleef_erfcf4_u15(_vec0), Sleef_erfcf4_u15(_vec1)};
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
Vectorized<float> erfinv() const {
|
| 300 |
+
return map(calc_erfinv);
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
Vectorized<float> angle() const {
|
| 304 |
+
auto tmp = blendv(
|
| 305 |
+
Vectorized<float>(0), Vectorized<float>(c10::pi<float>), *this < Vectorized<float>(0));
|
| 306 |
+
return blendv(tmp, *this, isnan());
|
| 307 |
+
}
|
| 308 |
+
Vectorized<float> real() const {
|
| 309 |
+
return *this;
|
| 310 |
+
}
|
| 311 |
+
Vectorized<float> imag() const {
|
| 312 |
+
return Vectorized<float>{0};
|
| 313 |
+
}
|
| 314 |
+
Vectorized<float> conj() const {
|
| 315 |
+
return *this;
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
Vectorized<float> C10_ALWAYS_INLINE exp() const {
|
| 319 |
+
return {Sleef_expf4_u10(_vec0), Sleef_expf4_u10(_vec1)};
|
| 320 |
+
}
|
| 321 |
+
Vectorized<float> C10_ALWAYS_INLINE exp2() const {
|
| 322 |
+
return {Sleef_exp2f4_u10(_vec0), Sleef_exp2f4_u10(_vec1)};
|
| 323 |
+
}
|
| 324 |
+
Vectorized<float> expm1() const {
|
| 325 |
+
return {Sleef_expm1f4_u10(_vec0), Sleef_expm1f4_u10(_vec1)};
|
| 326 |
+
}
|
| 327 |
+
Vectorized<float> C10_ALWAYS_INLINE exp_u20() const {
|
| 328 |
+
return exp();
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
Vectorized<float> C10_ALWAYS_INLINE log() const {
|
| 332 |
+
return {Sleef_logf4_u10(_vec0), Sleef_logf4_u10(_vec1)};
|
| 333 |
+
}
|
| 334 |
+
Vectorized<float> C10_ALWAYS_INLINE log10() const {
|
| 335 |
+
return {Sleef_log10f4_u10(_vec0), Sleef_log10f4_u10(_vec1)};
|
| 336 |
+
}
|
| 337 |
+
Vectorized<float> C10_ALWAYS_INLINE log1p() const {
|
| 338 |
+
return {Sleef_log1pf4_u10(_vec0), Sleef_log1pf4_u10(_vec1)};
|
| 339 |
+
}
|
| 340 |
+
Vectorized<float> C10_ALWAYS_INLINE log2() const {
|
| 341 |
+
return {Sleef_log2f4_u10(_vec0), Sleef_log2f4_u10(_vec1)};
|
| 342 |
+
}
|
| 343 |
+
Vectorized<float> C10_ALWAYS_INLINE ceil() const {
|
| 344 |
+
return {vec_ceil(_vec0), vec_ceil(_vec1)};
|
| 345 |
+
}
|
| 346 |
+
Vectorized<float> C10_ALWAYS_INLINE cos() const {
|
| 347 |
+
return {Sleef_cosf4_u10(_vec0), Sleef_cosf4_u10(_vec1)};
|
| 348 |
+
}
|
| 349 |
+
Vectorized<float> C10_ALWAYS_INLINE cosh() const {
|
| 350 |
+
return {Sleef_coshf4_u10(_vec0), Sleef_coshf4_u10(_vec1)};
|
| 351 |
+
}
|
| 352 |
+
Vectorized<float> C10_ALWAYS_INLINE floor() const {
|
| 353 |
+
return {vec_floor(_vec0), vec_floor(_vec1)};
|
| 354 |
+
}
|
| 355 |
+
Vectorized<float> C10_ALWAYS_INLINE neg() const {
|
| 356 |
+
return {vec_neg(_vec0), vec_neg(_vec1)};
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
Vectorized<float> C10_ALWAYS_INLINE round() const {
|
| 360 |
+
return {vec_round(_vec0), vec_round(_vec1)};
|
| 361 |
+
}
|
| 362 |
+
Vectorized<float> C10_ALWAYS_INLINE sin() const {
|
| 363 |
+
return {Sleef_sinf4_u10(_vec0), Sleef_sinf4_u10(_vec1)};
|
| 364 |
+
}
|
| 365 |
+
Vectorized<float> C10_ALWAYS_INLINE sinh() const {
|
| 366 |
+
return {Sleef_sinhf4_u10(_vec0), Sleef_sinhf4_u10(_vec1)};
|
| 367 |
+
}
|
| 368 |
+
Vectorized<float> C10_ALWAYS_INLINE tan() const {
|
| 369 |
+
return {Sleef_tanf4_u10(_vec0), Sleef_tanf4_u10(_vec1)};
|
| 370 |
+
}
|
| 371 |
+
Vectorized<float> C10_ALWAYS_INLINE tanh() const {
|
| 372 |
+
return {Sleef_tanhf4_u10(_vec0), Sleef_tanhf4_u10(_vec1)};
|
| 373 |
+
}
|
| 374 |
+
Vectorized<float> C10_ALWAYS_INLINE trunc() const {
|
| 375 |
+
return {vec_trunc(_vec0), vec_trunc(_vec1)};
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
Vectorized<float> C10_ALWAYS_INLINE frac() const {
|
| 379 |
+
return *this - trunc();
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
Vectorized<float> C10_ALWAYS_INLINE sqrt() const {
|
| 383 |
+
return {vec_sqrt(_vec0), vec_sqrt(_vec1)};
|
| 384 |
+
}
|
| 385 |
+
Vectorized<float> C10_ALWAYS_INLINE reciprocal() const {
|
| 386 |
+
return Vectorized<float>(one) / (*this);
|
| 387 |
+
}
|
| 388 |
+
Vectorized<float> C10_ALWAYS_INLINE rsqrt() const {
|
| 389 |
+
return sqrt().reciprocal();
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
Vectorized<float> C10_ALWAYS_INLINE pow(const Vectorized<float>& exp) const {
|
| 393 |
+
return {Sleef_powf4_u10(_vec0, exp._vec0), Sleef_powf4_u10(_vec1, exp._vec1)};
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
Vectorized<float> fmod(const Vectorized<float>& b) const {
|
| 397 |
+
return {Sleef_fmodf4(_vec0, b._vec0),Sleef_fmodf4(_vec1, b._vec1)};
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
Vectorized<float> hypot(const Vectorized<float>& b) const {
|
| 401 |
+
return {Sleef_hypotf4_u05(_vec0, b._vec0), Sleef_hypotf4_u05(_vec1, b._vec1)};
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
Vectorized<float> nextafter(const Vectorized<float>& b) const {
|
| 405 |
+
return {Sleef_nextafterf4(_vec0, b._vec0), Sleef_nextafterf4(_vec1, b._vec1)};
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
Vectorized<float> igamma(const Vectorized<float>& x) const {
|
| 409 |
+
return mapbi(calc_igamma, x);
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
Vectorized<float> igammac(const Vectorized<float>& x) const {
|
| 413 |
+
return mapbi(calc_igammac, x);
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
Vectorized<float> i0() const {
|
| 417 |
+
return map(calc_i0);
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
Vectorized<float> i0e() const {
|
| 421 |
+
return map(calc_i0e);
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
Vectorized<float> digamma() const {
|
| 425 |
+
return map(calc_digamma);
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
DEFINE_MEMBER_OP(operator==, float, vec_cmpeq)
|
| 429 |
+
DEFINE_MEMBER_OP(operator!=, float, vec_cmpne)
|
| 430 |
+
DEFINE_MEMBER_OP(operator<, float, vec_cmplt)
|
| 431 |
+
DEFINE_MEMBER_OP(operator<=, float, vec_cmple)
|
| 432 |
+
DEFINE_MEMBER_OP(operator>, float, vec_cmpgt)
|
| 433 |
+
DEFINE_MEMBER_OP(operator>=, float, vec_cmpge)
|
| 434 |
+
DEFINE_MEMBER_OP_AND_ONE(eq, float, vec_cmpeq)
|
| 435 |
+
DEFINE_MEMBER_OP_AND_ONE(ne, float, vec_cmpne)
|
| 436 |
+
DEFINE_MEMBER_OP_AND_ONE(lt, float, vec_cmplt)
|
| 437 |
+
DEFINE_MEMBER_OP_AND_ONE(le, float, vec_cmple)
|
| 438 |
+
DEFINE_MEMBER_OP_AND_ONE(gt, float, vec_cmpgt)
|
| 439 |
+
DEFINE_MEMBER_OP_AND_ONE(ge, float, vec_cmpge)
|
| 440 |
+
DEFINE_MEMBER_OP(operator+, float, vec_add)
|
| 441 |
+
DEFINE_MEMBER_OP(operator-, float, vec_sub)
|
| 442 |
+
DEFINE_MEMBER_OP(operator*, float, vec_mul)
|
| 443 |
+
DEFINE_MEMBER_OP(operator/, float, vec_div)
|
| 444 |
+
DEFINE_MEMBER_OP(maximum, float, vec_max_nan2)
|
| 445 |
+
DEFINE_MEMBER_OP(minimum, float, vec_min_nan2)
|
| 446 |
+
DEFINE_MEMBER_OP(operator&, float, vec_and)
|
| 447 |
+
DEFINE_MEMBER_OP(operator|, float, vec_or)
|
| 448 |
+
DEFINE_MEMBER_OP(operator^, float, vec_xor)
|
| 449 |
+
DEFINE_MEMBER_TERNARY_OP(madd, float, vec_madd)
|
| 450 |
+
};
|
| 451 |
+
|
| 452 |
+
template <>
|
| 453 |
+
Vectorized<float> inline maximum(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 454 |
+
return a.maximum(b);
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
template <>
|
| 458 |
+
Vectorized<float> inline minimum(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 459 |
+
return a.minimum(b);
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
template <>
|
| 463 |
+
Vectorized<float> C10_ALWAYS_INLINE operator+(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 464 |
+
return Vectorized<float>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
template <>
|
| 468 |
+
Vectorized<float> C10_ALWAYS_INLINE operator-(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 469 |
+
return Vectorized<float>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
template <>
|
| 473 |
+
Vectorized<float> C10_ALWAYS_INLINE operator*(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 474 |
+
return Vectorized<float>{vec_mul(a.vec0(), b.vec0()), vec_mul(a.vec1(), b.vec1())};
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
template <>
|
| 478 |
+
Vectorized<float> C10_ALWAYS_INLINE operator/(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 479 |
+
return Vectorized<float>{vec_div(a.vec0(), b.vec0()), vec_div(a.vec1(), b.vec1())};
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
template <>
|
| 483 |
+
Vectorized<float> C10_ALWAYS_INLINE operator&(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 484 |
+
return Vectorized<float>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
template <>
|
| 488 |
+
Vectorized<float> C10_ALWAYS_INLINE operator|(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 489 |
+
return Vectorized<float>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
template <>
|
| 493 |
+
Vectorized<float> C10_ALWAYS_INLINE operator^(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 494 |
+
return Vectorized<float>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
} // namespace
|
| 498 |
+
} // namespace vec
|
| 499 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int16_vsx.h
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
namespace at {
|
| 7 |
+
namespace vec {
|
| 8 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 9 |
+
inline namespace CPU_CAPABILITY {
|
| 10 |
+
|
| 11 |
+
template <>
|
| 12 |
+
class Vectorized<int16_t> {
|
| 13 |
+
private:
|
| 14 |
+
union {
|
| 15 |
+
struct {
|
| 16 |
+
vint16 _vec0;
|
| 17 |
+
vint16 _vec1;
|
| 18 |
+
};
|
| 19 |
+
struct {
|
| 20 |
+
vbool16 _vecb0;
|
| 21 |
+
vbool16 _vecb1;
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
} __attribute__((__may_alias__));
|
| 25 |
+
|
| 26 |
+
public:
|
| 27 |
+
using value_type = int16_t;
|
| 28 |
+
using vec_internal_type = vint16;
|
| 29 |
+
using vec_internal_mask_type = vbool16;
|
| 30 |
+
using size_type = int;
|
| 31 |
+
static constexpr size_type size() {
|
| 32 |
+
return 16;
|
| 33 |
+
}
|
| 34 |
+
Vectorized() {}
|
| 35 |
+
C10_ALWAYS_INLINE Vectorized(vint16 v) : _vec0{v}, _vec1{v} {}
|
| 36 |
+
C10_ALWAYS_INLINE Vectorized(vbool16 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 37 |
+
C10_ALWAYS_INLINE Vectorized(vint16 v1, vint16 v2) : _vec0{v1}, _vec1{v2} {}
|
| 38 |
+
C10_ALWAYS_INLINE Vectorized(vbool16 v1, vbool16 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 39 |
+
C10_ALWAYS_INLINE Vectorized(int16_t scalar)
|
| 40 |
+
: _vec0{vec_splats(scalar)}, _vec1{vec_splats(scalar)} {}
|
| 41 |
+
|
| 42 |
+
C10_ALWAYS_INLINE Vectorized(
|
| 43 |
+
int16_t scalar1,
|
| 44 |
+
int16_t scalar2,
|
| 45 |
+
int16_t scalar3,
|
| 46 |
+
int16_t scalar4,
|
| 47 |
+
int16_t scalar5,
|
| 48 |
+
int16_t scalar6,
|
| 49 |
+
int16_t scalar7,
|
| 50 |
+
int16_t scalar8,
|
| 51 |
+
int16_t scalar9,
|
| 52 |
+
int16_t scalar10,
|
| 53 |
+
int16_t scalar11,
|
| 54 |
+
int16_t scalar12,
|
| 55 |
+
int16_t scalar13,
|
| 56 |
+
int16_t scalar14,
|
| 57 |
+
int16_t scalar15,
|
| 58 |
+
int16_t scalar16)
|
| 59 |
+
: _vec0{vint16{
|
| 60 |
+
scalar1,
|
| 61 |
+
scalar2,
|
| 62 |
+
scalar3,
|
| 63 |
+
scalar4,
|
| 64 |
+
scalar5,
|
| 65 |
+
scalar6,
|
| 66 |
+
scalar7,
|
| 67 |
+
scalar8}},
|
| 68 |
+
_vec1{vint16{
|
| 69 |
+
scalar9,
|
| 70 |
+
scalar10,
|
| 71 |
+
scalar11,
|
| 72 |
+
scalar12,
|
| 73 |
+
scalar13,
|
| 74 |
+
scalar14,
|
| 75 |
+
scalar15,
|
| 76 |
+
scalar16}} {}
|
| 77 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 78 |
+
return _vec0;
|
| 79 |
+
}
|
| 80 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 81 |
+
return _vec1;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
template <uint64_t mask>
|
| 85 |
+
static std::enable_if_t<mask == 0, Vectorized<int16_t>> C10_ALWAYS_INLINE
|
| 86 |
+
blend(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 87 |
+
return a;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
template <uint64_t mask>
|
| 91 |
+
static std::enable_if_t<(mask & 65535) == 65535, Vectorized<int16_t>>
|
| 92 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 93 |
+
return b;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
template <uint64_t mask>
|
| 97 |
+
static std::enable_if_t<mask == 255, Vectorized<int16_t>> C10_ALWAYS_INLINE
|
| 98 |
+
blend(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 99 |
+
return {b._vec0, a._vec1};
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
template <uint64_t mask>
|
| 103 |
+
static std::enable_if_t<(mask > 0 && mask < 255), Vectorized<int16_t>>
|
| 104 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 105 |
+
constexpr int16_t g0 = (mask & 1) * 0xffff;
|
| 106 |
+
constexpr int16_t g1 = ((mask & 2) >> 1) * 0xffff;
|
| 107 |
+
constexpr int16_t g2 = ((mask & 4) >> 2) * 0xffff;
|
| 108 |
+
constexpr int16_t g3 = ((mask & 8) >> 3) * 0xffff;
|
| 109 |
+
constexpr int16_t g4 = ((mask & 16) >> 4) * 0xffff;
|
| 110 |
+
constexpr int16_t g5 = ((mask & 32) >> 5) * 0xffff;
|
| 111 |
+
constexpr int16_t g6 = ((mask & 64) >> 6) * 0xffff;
|
| 112 |
+
constexpr int16_t g7 = ((mask & 128) >> 7) * 0xffff;
|
| 113 |
+
const vint16 mask_1st = vint16{g0, g1, g2, g3, g4, g5, g6, g7};
|
| 114 |
+
|
| 115 |
+
return {(vint16)vec_sel(a._vec0, b._vec0, (vbool16)mask_1st), a._vec1};
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
template <uint64_t mask>
|
| 119 |
+
static std::enable_if_t<
|
| 120 |
+
(mask > 255 && (mask & 65535) != 65535 && ((mask & 255) == 255)),
|
| 121 |
+
Vectorized<int16_t>>
|
| 122 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 123 |
+
constexpr int16_t g0_2 = (mask & 1) * 0xffff;
|
| 124 |
+
constexpr int16_t g1_2 = ((mask & 2) >> 1) * 0xffff;
|
| 125 |
+
constexpr int16_t g2_2 = ((mask & 4) >> 2) * 0xffff;
|
| 126 |
+
constexpr int16_t g3_2 = ((mask & 8) >> 3) * 0xffff;
|
| 127 |
+
constexpr int16_t g4_2 = ((mask & 16) >> 4) * 0xffff;
|
| 128 |
+
constexpr int16_t g5_2 = ((mask & 32) >> 5) * 0xffff;
|
| 129 |
+
constexpr int16_t g6_2 = ((mask & 64) >> 6) * 0xffff;
|
| 130 |
+
constexpr int16_t g7_2 = ((mask & 128) >> 7) * 0xffff;
|
| 131 |
+
|
| 132 |
+
const vint16 mask_2nd =
|
| 133 |
+
vint16{g0_2, g1_2, g2_2, g3_2, g4_2, g5_2, g6_2, g7_2};
|
| 134 |
+
// generated masks
|
| 135 |
+
return {b._vec0, (vint16)vec_sel(a._vec1, b._vec1, (vbool16)mask_2nd)};
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
template <uint64_t mask>
|
| 139 |
+
static std::enable_if_t<
|
| 140 |
+
(mask > 255 && ((mask & 65535) != 65535) && ((mask & 255) == 0)),
|
| 141 |
+
Vectorized<int16_t>>
|
| 142 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 143 |
+
constexpr int16_t mask2 = (mask & 65535) >> 16;
|
| 144 |
+
constexpr int16_t g0_2 = (mask & 1) * 0xffff;
|
| 145 |
+
constexpr int16_t g1_2 = ((mask & 2) >> 1) * 0xffff;
|
| 146 |
+
constexpr int16_t g2_2 = ((mask & 4) >> 2) * 0xffff;
|
| 147 |
+
constexpr int16_t g3_2 = ((mask & 8) >> 3) * 0xffff;
|
| 148 |
+
constexpr int16_t g4_2 = ((mask & 16) >> 4) * 0xffff;
|
| 149 |
+
constexpr int16_t g5_2 = ((mask & 32) >> 5) * 0xffff;
|
| 150 |
+
constexpr int16_t g6_2 = ((mask & 64) >> 6) * 0xffff;
|
| 151 |
+
constexpr int16_t g7_2 = ((mask & 128) >> 7) * 0xffff;
|
| 152 |
+
|
| 153 |
+
const vint16 mask_2nd =
|
| 154 |
+
vint16{g0_2, g1_2, g2_2, g3_2, g4_2, g5_2, g6_2, g7_2};
|
| 155 |
+
// generated masks
|
| 156 |
+
return {a, (vint16)vec_sel(a._vec1, b._vec1, (vbool16)mask_2nd)};
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
template <uint64_t mask>
|
| 160 |
+
static std::enable_if_t<
|
| 161 |
+
(mask > 255 && ((mask & 65535) != 65535) && ((mask & 255) != 0) &&
|
| 162 |
+
((mask & 255) != 255)),
|
| 163 |
+
Vectorized<int16_t>>
|
| 164 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 165 |
+
constexpr int16_t g0 = (mask & 1) * 0xffff;
|
| 166 |
+
constexpr int16_t g1 = ((mask & 2) >> 1) * 0xffff;
|
| 167 |
+
constexpr int16_t g2 = ((mask & 4) >> 2) * 0xffff;
|
| 168 |
+
constexpr int16_t g3 = ((mask & 8) >> 3) * 0xffff;
|
| 169 |
+
constexpr int16_t g4 = ((mask & 16) >> 4) * 0xffff;
|
| 170 |
+
constexpr int16_t g5 = ((mask & 32) >> 5) * 0xffff;
|
| 171 |
+
constexpr int16_t g6 = ((mask & 64) >> 6) * 0xffff;
|
| 172 |
+
constexpr int16_t g7 = ((mask & 128) >> 7) * 0xffff;
|
| 173 |
+
constexpr int16_t mask2 = (mask & 65535) >> 16;
|
| 174 |
+
constexpr int16_t g0_2 = (mask & 1) * 0xffff;
|
| 175 |
+
constexpr int16_t g1_2 = ((mask & 2) >> 1) * 0xffff;
|
| 176 |
+
constexpr int16_t g2_2 = ((mask & 4) >> 2) * 0xffff;
|
| 177 |
+
constexpr int16_t g3_2 = ((mask & 8) >> 3) * 0xffff;
|
| 178 |
+
constexpr int16_t g4_2 = ((mask & 16) >> 4) * 0xffff;
|
| 179 |
+
constexpr int16_t g5_2 = ((mask & 32) >> 5) * 0xffff;
|
| 180 |
+
constexpr int16_t g6_2 = ((mask & 64) >> 6) * 0xffff;
|
| 181 |
+
constexpr int16_t g7_2 = ((mask & 128) >> 7) * 0xffff;
|
| 182 |
+
|
| 183 |
+
const vint16 mask_1st = vint16{g0, g1, g2, g3, g4, g5, g6, g7};
|
| 184 |
+
const vint16 mask_2nd =
|
| 185 |
+
vint16{g0_2, g1_2, g2_2, g3_2, g4_2, g5_2, g6_2, g7_2};
|
| 186 |
+
// generated masks
|
| 187 |
+
return {
|
| 188 |
+
(vint16)vec_sel(a._vec0, b._vec0, (vbool16)mask_1st),
|
| 189 |
+
(vint16)vec_sel(a._vec1, b._vec1, (vbool16)mask_2nd)};
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
static Vectorized<int16_t> C10_ALWAYS_INLINE blendv(
|
| 193 |
+
const Vectorized<int16_t>& a,
|
| 194 |
+
const Vectorized<int16_t>& b,
|
| 195 |
+
const Vectorized<int16_t>& mask) {
|
| 196 |
+
// the mask used here returned by comparision of vec256
|
| 197 |
+
// assuming this we can use the same mask directly with vec_sel
|
| 198 |
+
// warning intel style mask will not work properly
|
| 199 |
+
return {
|
| 200 |
+
vec_sel(a._vec0, b._vec0, mask._vecb0),
|
| 201 |
+
vec_sel(a._vec1, b._vec1, mask._vecb1)};
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
template <typename step_t>
|
| 205 |
+
static Vectorized<int16_t> arange(int16_t base = 0, step_t step = static_cast<step_t>(1)) {
|
| 206 |
+
return Vectorized<int16_t>(
|
| 207 |
+
base,
|
| 208 |
+
base + step,
|
| 209 |
+
base + 2 * step,
|
| 210 |
+
base + 3 * step,
|
| 211 |
+
base + 4 * step,
|
| 212 |
+
base + 5 * step,
|
| 213 |
+
base + 6 * step,
|
| 214 |
+
base + 7 * step,
|
| 215 |
+
base + 8 * step,
|
| 216 |
+
base + 9 * step,
|
| 217 |
+
base + 10 * step,
|
| 218 |
+
base + 11 * step,
|
| 219 |
+
base + 12 * step,
|
| 220 |
+
base + 13 * step,
|
| 221 |
+
base + 14 * step,
|
| 222 |
+
base + 15 * step);
|
| 223 |
+
}
|
| 224 |
+
static Vectorized<int16_t> set(
|
| 225 |
+
const Vectorized<int16_t>& a,
|
| 226 |
+
const Vectorized<int16_t>& b,
|
| 227 |
+
size_t count = size()) {
|
| 228 |
+
switch (count) {
|
| 229 |
+
case 0:
|
| 230 |
+
return a;
|
| 231 |
+
case 1:
|
| 232 |
+
return blend<1>(a, b);
|
| 233 |
+
case 2:
|
| 234 |
+
return blend<3>(a, b);
|
| 235 |
+
case 3:
|
| 236 |
+
return blend<7>(a, b);
|
| 237 |
+
case 4:
|
| 238 |
+
return blend<15>(a, b);
|
| 239 |
+
case 5:
|
| 240 |
+
return blend<31>(a, b);
|
| 241 |
+
case 6:
|
| 242 |
+
return blend<63>(a, b);
|
| 243 |
+
case 7:
|
| 244 |
+
return blend<127>(a, b);
|
| 245 |
+
case 8:
|
| 246 |
+
return blend<255>(a, b);
|
| 247 |
+
case 9:
|
| 248 |
+
return blend<511>(a, b);
|
| 249 |
+
case 10:
|
| 250 |
+
return blend<1023>(a, b);
|
| 251 |
+
case 11:
|
| 252 |
+
return blend<2047>(a, b);
|
| 253 |
+
case 12:
|
| 254 |
+
return blend<4095>(a, b);
|
| 255 |
+
case 13:
|
| 256 |
+
return blend<8191>(a, b);
|
| 257 |
+
case 14:
|
| 258 |
+
return blend<16383>(a, b);
|
| 259 |
+
case 15:
|
| 260 |
+
return blend<32767>(a, b);
|
| 261 |
+
}
|
| 262 |
+
return b;
|
| 263 |
+
}
|
| 264 |
+
static Vectorized<value_type> C10_ALWAYS_INLINE
|
| 265 |
+
loadu(const void* ptr, int count = size()) {
|
| 266 |
+
if (count == size()) {
|
| 267 |
+
return {
|
| 268 |
+
vec_vsx_ld(offset0, reinterpret_cast<const value_type*>(ptr)),
|
| 269 |
+
vec_vsx_ld(offset16, reinterpret_cast<const value_type*>(ptr))};
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 273 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 274 |
+
|
| 275 |
+
return {vec_vsx_ld(offset0, tmp_values), vec_vsx_ld(offset16, tmp_values)};
|
| 276 |
+
}
|
| 277 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 278 |
+
if (count == size()) {
|
| 279 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<value_type*>(ptr));
|
| 280 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<value_type*>(ptr));
|
| 281 |
+
} else if (count > 0) {
|
| 282 |
+
__at_align__ value_type tmp_values[size()];
|
| 283 |
+
vec_vsx_st(_vec0, offset0, tmp_values);
|
| 284 |
+
vec_vsx_st(_vec1, offset16, tmp_values);
|
| 285 |
+
std::memcpy(ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
const int16_t& operator[](int idx) const = delete;
|
| 289 |
+
int16_t& operator[](int idx) = delete;
|
| 290 |
+
|
| 291 |
+
Vectorized<int16_t> angle() const {
|
| 292 |
+
return blendv(
|
| 293 |
+
Vectorized<int16_t>(0), Vectorized<int16_t>(c10::pi<int16_t>), *this < Vectorized<int16_t>(0));
|
| 294 |
+
}
|
| 295 |
+
Vectorized<int16_t> real() const {
|
| 296 |
+
return *this;
|
| 297 |
+
}
|
| 298 |
+
Vectorized<int16_t> imag() const {
|
| 299 |
+
return Vectorized<int16_t>{0};
|
| 300 |
+
}
|
| 301 |
+
Vectorized<int16_t> conj() const {
|
| 302 |
+
return *this;
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE abs() const {
|
| 306 |
+
return {vec_abs(_vec0), vec_abs(_vec1)};
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE neg() const {
|
| 310 |
+
return {vec_neg(_vec0), vec_neg(_vec1)};
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
DEFINE_MEMBER_UNARY_OP(operator~, int16_t, vec_not)
|
| 314 |
+
DEFINE_MEMBER_OP(operator==, int16_t, vec_cmpeq)
|
| 315 |
+
DEFINE_MEMBER_OP(operator!=, int16_t, vec_cmpne)
|
| 316 |
+
DEFINE_MEMBER_OP(operator<, int16_t, vec_cmplt)
|
| 317 |
+
DEFINE_MEMBER_OP(operator<=, int16_t, vec_cmple)
|
| 318 |
+
DEFINE_MEMBER_OP(operator>, int16_t, vec_cmpgt)
|
| 319 |
+
DEFINE_MEMBER_OP(operator>=, int16_t, vec_cmpge)
|
| 320 |
+
DEFINE_MEMBER_OP_AND_ONE(eq, int16_t, vec_cmpeq)
|
| 321 |
+
DEFINE_MEMBER_OP_AND_ONE(ne, int16_t, vec_cmpne)
|
| 322 |
+
DEFINE_MEMBER_OP_AND_ONE(lt, int16_t, vec_cmplt)
|
| 323 |
+
DEFINE_MEMBER_OP_AND_ONE(le, int16_t, vec_cmple)
|
| 324 |
+
DEFINE_MEMBER_OP_AND_ONE(gt, int16_t, vec_cmpgt)
|
| 325 |
+
DEFINE_MEMBER_OP_AND_ONE(ge, int16_t, vec_cmpge)
|
| 326 |
+
DEFINE_MEMBER_OP(operator+, int16_t, vec_add)
|
| 327 |
+
DEFINE_MEMBER_OP(operator-, int16_t, vec_sub)
|
| 328 |
+
DEFINE_MEMBER_OP(operator*, int16_t, vec_mul)
|
| 329 |
+
DEFINE_MEMBER_EMULATE_BINARY_OP(operator/, int16_t, /)
|
| 330 |
+
DEFINE_MEMBER_OP(maximum, int16_t, vec_max)
|
| 331 |
+
DEFINE_MEMBER_OP(minimum, int16_t, vec_min)
|
| 332 |
+
DEFINE_MEMBER_OP(operator&, int16_t, vec_and)
|
| 333 |
+
DEFINE_MEMBER_OP(operator|, int16_t, vec_or)
|
| 334 |
+
DEFINE_MEMBER_OP(operator^, int16_t, vec_xor)
|
| 335 |
+
};
|
| 336 |
+
|
| 337 |
+
template <>
|
| 338 |
+
Vectorized<int16_t> inline operator<<(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 339 |
+
vuint16 shift_vec0 = reinterpret_cast<vuint16>(b.vec0());
|
| 340 |
+
vuint16 shift_vec1 = reinterpret_cast<vuint16>(b.vec1());
|
| 341 |
+
return Vectorized<int16_t>{vec_sl(a.vec0(), shift_vec0), vec_sl(a.vec1(), shift_vec1)};
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
template <>
|
| 345 |
+
Vectorized<int16_t> inline operator>>(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 346 |
+
vuint16 shift_vec0 = reinterpret_cast<vuint16>(b.vec0());
|
| 347 |
+
vuint16 shift_vec1 = reinterpret_cast<vuint16>(b.vec1()) ;
|
| 348 |
+
return Vectorized<int16_t>{vec_sr(a.vec0(), shift_vec0), vec_sr(a.vec1(), shift_vec1)};
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
template <>
|
| 352 |
+
Vectorized<int16_t> inline maximum(
|
| 353 |
+
const Vectorized<int16_t>& a,
|
| 354 |
+
const Vectorized<int16_t>& b) {
|
| 355 |
+
return a.maximum(b);
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
template <>
|
| 359 |
+
Vectorized<int16_t> inline minimum(
|
| 360 |
+
const Vectorized<int16_t>& a,
|
| 361 |
+
const Vectorized<int16_t>& b) {
|
| 362 |
+
return a.minimum(b);
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
template <>
|
| 366 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE operator+(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 367 |
+
return Vectorized<int16_t>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
template <>
|
| 371 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE operator-(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 372 |
+
return Vectorized<int16_t>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
template <>
|
| 376 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE operator*(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 377 |
+
return Vectorized<int16_t>{vec_mul(a.vec0(), b.vec0()), vec_mul(a.vec1(), b.vec1())};
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
template <>
|
| 381 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE operator/(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 382 |
+
return Vectorized<int16_t>{a.vec0()/b.vec0(), a.vec1()/b.vec1()};
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
template <>
|
| 386 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE operator&(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 387 |
+
return Vectorized<int16_t>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
template <>
|
| 391 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE operator|(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 392 |
+
return Vectorized<int16_t>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
template <>
|
| 396 |
+
Vectorized<int16_t> C10_ALWAYS_INLINE operator^(const Vectorized<int16_t>& a, const Vectorized<int16_t>& b) {
|
| 397 |
+
return Vectorized<int16_t>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
} // namespace
|
| 401 |
+
} // namespace vec
|
| 402 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int32_vsx.h
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
namespace at {
|
| 7 |
+
namespace vec {
|
| 8 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 9 |
+
inline namespace CPU_CAPABILITY {
|
| 10 |
+
|
| 11 |
+
template <>
|
| 12 |
+
class Vectorized<int32_t> {
|
| 13 |
+
private:
|
| 14 |
+
union {
|
| 15 |
+
struct {
|
| 16 |
+
vint32 _vec0;
|
| 17 |
+
vint32 _vec1;
|
| 18 |
+
};
|
| 19 |
+
struct {
|
| 20 |
+
vbool32 _vecb0;
|
| 21 |
+
vbool32 _vecb1;
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
} __attribute__((__may_alias__));
|
| 25 |
+
|
| 26 |
+
public:
|
| 27 |
+
using value_type = int32_t;
|
| 28 |
+
using vec_internal_type = vint32;
|
| 29 |
+
using vec_internal_mask_type = vbool32;
|
| 30 |
+
using size_type = int;
|
| 31 |
+
static constexpr size_type size() {
|
| 32 |
+
return 8;
|
| 33 |
+
}
|
| 34 |
+
Vectorized() {}
|
| 35 |
+
C10_ALWAYS_INLINE Vectorized(vint32 v) : _vec0{v}, _vec1{v} {}
|
| 36 |
+
C10_ALWAYS_INLINE Vectorized(vbool32 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 37 |
+
C10_ALWAYS_INLINE Vectorized(vint32 v1, vint32 v2) : _vec0{v1}, _vec1{v2} {}
|
| 38 |
+
C10_ALWAYS_INLINE Vectorized(vbool32 v1, vbool32 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 39 |
+
C10_ALWAYS_INLINE Vectorized(int32_t scalar)
|
| 40 |
+
: _vec0{vec_splats(scalar)}, _vec1{vec_splats(scalar)} {}
|
| 41 |
+
C10_ALWAYS_INLINE Vectorized(
|
| 42 |
+
int32_t scalar1,
|
| 43 |
+
int32_t scalar2,
|
| 44 |
+
int32_t scalar3,
|
| 45 |
+
int32_t scalar4,
|
| 46 |
+
int32_t scalar5,
|
| 47 |
+
int32_t scalar6,
|
| 48 |
+
int32_t scalar7,
|
| 49 |
+
int32_t scalar8)
|
| 50 |
+
: _vec0{vint32{scalar1, scalar2, scalar3, scalar4}},
|
| 51 |
+
_vec1{vint32{scalar5, scalar6, scalar7, scalar8}} {}
|
| 52 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 53 |
+
return _vec0;
|
| 54 |
+
}
|
| 55 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 56 |
+
return _vec1;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
template <uint64_t mask>
|
| 60 |
+
static std::enable_if_t<mask == 0, Vectorized<int32_t>> C10_ALWAYS_INLINE
|
| 61 |
+
blend(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 62 |
+
return a;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
template <uint64_t mask>
|
| 66 |
+
static std::enable_if_t<(mask & 255) == 255, Vectorized<int32_t>> C10_ALWAYS_INLINE
|
| 67 |
+
blend(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 68 |
+
return b;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
template <uint64_t mask>
|
| 72 |
+
static std::enable_if_t<mask == 15, Vectorized<int32_t>> C10_ALWAYS_INLINE
|
| 73 |
+
blend(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 74 |
+
return {b._vec0, a._vec1};
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
template <uint64_t mask>
|
| 78 |
+
static std::enable_if_t<(mask > 0 && mask < 15), Vectorized<int32_t>>
|
| 79 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 80 |
+
constexpr uint32_t g0 = (mask & 1) * 0xffffffff;
|
| 81 |
+
constexpr uint32_t g1 = ((mask & 2) >> 1) * 0xffffffff;
|
| 82 |
+
constexpr uint32_t g2 = ((mask & 4) >> 2) * 0xffffffff;
|
| 83 |
+
constexpr uint32_t g3 = ((mask & 8) >> 3) * 0xffffffff;
|
| 84 |
+
const vbool32 mask_1st = (vbool32){g0, g1, g2, g3};
|
| 85 |
+
|
| 86 |
+
return {(vint32)vec_sel(a._vec0, b._vec0, (vbool32)mask_1st), a._vec1};
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
template <uint64_t mask>
|
| 90 |
+
static std::enable_if_t<
|
| 91 |
+
(mask > 15 && (mask & 255) != 255 && ((mask & 15) == 15)),
|
| 92 |
+
Vectorized<int32_t>>
|
| 93 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 94 |
+
constexpr uint32_t mask2 = (mask & 255) >> 4;
|
| 95 |
+
constexpr uint32_t g0_2 = (mask2 & 1) * 0xffffffff;
|
| 96 |
+
constexpr uint32_t g1_2 = ((mask2 & 2) >> 1) * 0xffffffff;
|
| 97 |
+
constexpr uint32_t g2_2 = ((mask2 & 4) >> 2) * 0xffffffff;
|
| 98 |
+
constexpr uint32_t g3_2 = ((mask2 & 8) >> 3) * 0xffffffff;
|
| 99 |
+
|
| 100 |
+
const vbool32 mask_2nd = (vbool32){g0_2, g1_2, g2_2, g3_2};
|
| 101 |
+
// generated masks
|
| 102 |
+
return {b._vec0, (vint32)vec_sel(a._vec1, b._vec1, (vbool32)mask_2nd)};
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
template <uint64_t mask>
|
| 106 |
+
static std::enable_if_t<
|
| 107 |
+
(mask > 15 && ((mask & 255) != 255) && ((mask & 15) == 0)),
|
| 108 |
+
Vectorized<int32_t>>
|
| 109 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 110 |
+
constexpr uint32_t mask2 = (mask & 255) >> 4;
|
| 111 |
+
constexpr uint32_t g0_2 = (mask2 & 1) * 0xffffffff;
|
| 112 |
+
constexpr uint32_t g1_2 = ((mask2 & 2) >> 1) * 0xffffffff;
|
| 113 |
+
constexpr uint32_t g2_2 = ((mask2 & 4) >> 2) * 0xffffffff;
|
| 114 |
+
constexpr uint32_t g3_2 = ((mask2 & 8) >> 3) * 0xffffffff;
|
| 115 |
+
|
| 116 |
+
const vbool32 mask_2nd = (vbool32){g0_2, g1_2, g2_2, g3_2};
|
| 117 |
+
// generated masks
|
| 118 |
+
return {a, (vint32)vec_sel(a._vec1, b._vec1, (vbool32)mask_2nd)};
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
template <uint64_t mask>
|
| 122 |
+
static std::enable_if_t<
|
| 123 |
+
(mask > 15 && ((mask & 255) != 255) && ((mask & 15) != 0) &&
|
| 124 |
+
((mask & 15) != 15)),
|
| 125 |
+
Vectorized<int32_t>>
|
| 126 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 127 |
+
constexpr uint32_t g0 = (mask & 1) * 0xffffffff;
|
| 128 |
+
constexpr uint32_t g1 = ((mask & 2) >> 1) * 0xffffffff;
|
| 129 |
+
constexpr uint32_t g2 = ((mask & 4) >> 2) * 0xffffffff;
|
| 130 |
+
constexpr uint32_t g3 = ((mask & 8) >> 3) * 0xffffffff;
|
| 131 |
+
constexpr uint32_t mask2 = (mask & 255) >> 4;
|
| 132 |
+
constexpr uint32_t g0_2 = (mask2 & 1) * 0xffffffff;
|
| 133 |
+
constexpr uint32_t g1_2 = ((mask2 & 2) >> 1) * 0xffffffff;
|
| 134 |
+
constexpr uint32_t g2_2 = ((mask2 & 4) >> 2) * 0xffffffff;
|
| 135 |
+
constexpr uint32_t g3_2 = ((mask2 & 8) >> 3) * 0xffffffff;
|
| 136 |
+
|
| 137 |
+
const vbool32 mask_1st = (vbool32){g0, g1, g2, g3};
|
| 138 |
+
const vbool32 mask_2nd = (vbool32){g0_2, g1_2, g2_2, g3_2};
|
| 139 |
+
// generated masks
|
| 140 |
+
return {
|
| 141 |
+
(vint32)vec_sel(a._vec0, b._vec0, (vbool32)mask_1st),
|
| 142 |
+
(vint32)vec_sel(a._vec1, b._vec1, (vbool32)mask_2nd)};
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
static Vectorized<int32_t> C10_ALWAYS_INLINE blendv(
|
| 146 |
+
const Vectorized<int32_t>& a,
|
| 147 |
+
const Vectorized<int32_t>& b,
|
| 148 |
+
const Vectorized<int32_t>& mask) {
|
| 149 |
+
// the mask used here returned by comparision of vec256
|
| 150 |
+
// assuming this we can use the same mask directly with vec_sel
|
| 151 |
+
// warning intel style mask will not work properly
|
| 152 |
+
return {
|
| 153 |
+
vec_sel(a._vec0, b._vec0, mask._vecb0),
|
| 154 |
+
vec_sel(a._vec1, b._vec1, mask._vecb1)};
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
template <typename step_t>
|
| 158 |
+
static Vectorized<int32_t> arange(int32_t base = 0.f, step_t step = static_cast<step_t>(1)) {
|
| 159 |
+
return Vectorized<int32_t>(
|
| 160 |
+
base,
|
| 161 |
+
base + step,
|
| 162 |
+
base + 2 * step,
|
| 163 |
+
base + 3 * step,
|
| 164 |
+
base + 4 * step,
|
| 165 |
+
base + 5 * step,
|
| 166 |
+
base + 6 * step,
|
| 167 |
+
base + 7 * step);
|
| 168 |
+
}
|
| 169 |
+
static Vectorized<int32_t> set(
|
| 170 |
+
const Vectorized<int32_t>& a,
|
| 171 |
+
const Vectorized<int32_t>& b,
|
| 172 |
+
size_t count = size()) {
|
| 173 |
+
switch (count) {
|
| 174 |
+
case 0:
|
| 175 |
+
return a;
|
| 176 |
+
case 1:
|
| 177 |
+
return blend<1>(a, b);
|
| 178 |
+
case 2:
|
| 179 |
+
return blend<3>(a, b);
|
| 180 |
+
case 3:
|
| 181 |
+
return blend<7>(a, b);
|
| 182 |
+
case 4:
|
| 183 |
+
return blend<15>(a, b);
|
| 184 |
+
case 5:
|
| 185 |
+
return blend<31>(a, b);
|
| 186 |
+
case 6:
|
| 187 |
+
return blend<63>(a, b);
|
| 188 |
+
case 7:
|
| 189 |
+
return blend<127>(a, b);
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
return b;
|
| 193 |
+
}
|
| 194 |
+
static Vectorized<value_type> C10_ALWAYS_INLINE
|
| 195 |
+
loadu(const void* ptr, int count = size()) {
|
| 196 |
+
if (count == size()) {
|
| 197 |
+
return {
|
| 198 |
+
vec_vsx_ld(offset0, reinterpret_cast<const value_type*>(ptr)),
|
| 199 |
+
vec_vsx_ld(offset16, reinterpret_cast<const value_type*>(ptr))};
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 203 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 204 |
+
|
| 205 |
+
return {vec_vsx_ld(offset0, tmp_values), vec_vsx_ld(offset16, tmp_values)};
|
| 206 |
+
}
|
| 207 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 208 |
+
if (count == size()) {
|
| 209 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<value_type*>(ptr));
|
| 210 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<value_type*>(ptr));
|
| 211 |
+
} else if (count > 0) {
|
| 212 |
+
__at_align__ value_type tmp_values[size()];
|
| 213 |
+
vec_vsx_st(_vec0, offset0, tmp_values);
|
| 214 |
+
vec_vsx_st(_vec1, offset16, tmp_values);
|
| 215 |
+
std::memcpy(
|
| 216 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
const int32_t& operator[](int idx) const = delete;
|
| 220 |
+
int32_t& operator[](int idx) = delete;
|
| 221 |
+
|
| 222 |
+
Vectorized<int32_t> angle() const {
|
| 223 |
+
return blendv(
|
| 224 |
+
Vectorized<int32_t>(0), Vectorized<int32_t>(c10::pi<int32_t>), *this < Vectorized<int32_t>(0));
|
| 225 |
+
}
|
| 226 |
+
Vectorized<int32_t> real() const {
|
| 227 |
+
return *this;
|
| 228 |
+
}
|
| 229 |
+
Vectorized<int32_t> imag() const {
|
| 230 |
+
return Vectorized<int32_t>{0};
|
| 231 |
+
}
|
| 232 |
+
Vectorized<int32_t> conj() const {
|
| 233 |
+
return *this;
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE abs() const {
|
| 237 |
+
return {vec_abs(_vec0), vec_abs(_vec1)};
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE neg() const {
|
| 241 |
+
return {vec_neg(_vec0), vec_neg(_vec1)};
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
DEFINE_MEMBER_UNARY_OP(operator~, int32_t, vec_not)
|
| 245 |
+
DEFINE_MEMBER_OP(operator==, int32_t, vec_cmpeq)
|
| 246 |
+
DEFINE_MEMBER_OP(operator!=, int32_t, vec_cmpne)
|
| 247 |
+
DEFINE_MEMBER_OP(operator<, int32_t, vec_cmplt)
|
| 248 |
+
DEFINE_MEMBER_OP(operator<=, int32_t, vec_cmple)
|
| 249 |
+
DEFINE_MEMBER_OP(operator>, int32_t, vec_cmpgt)
|
| 250 |
+
DEFINE_MEMBER_OP(operator>=, int32_t, vec_cmpge)
|
| 251 |
+
DEFINE_MEMBER_OP_AND_ONE(eq, int32_t, vec_cmpeq)
|
| 252 |
+
DEFINE_MEMBER_OP_AND_ONE(ne, int32_t, vec_cmpne)
|
| 253 |
+
DEFINE_MEMBER_OP_AND_ONE(lt, int32_t, vec_cmplt)
|
| 254 |
+
DEFINE_MEMBER_OP_AND_ONE(le, int32_t, vec_cmple)
|
| 255 |
+
DEFINE_MEMBER_OP_AND_ONE(gt, int32_t, vec_cmpgt)
|
| 256 |
+
DEFINE_MEMBER_OP_AND_ONE(ge, int32_t, vec_cmpge)
|
| 257 |
+
DEFINE_MEMBER_OP(operator+, int32_t, vec_add)
|
| 258 |
+
DEFINE_MEMBER_OP(operator-, int32_t, vec_sub)
|
| 259 |
+
DEFINE_MEMBER_OP(operator*, int32_t, vec_mul)
|
| 260 |
+
DEFINE_MEMBER_EMULATE_BINARY_OP(operator/, int32_t, /)
|
| 261 |
+
DEFINE_MEMBER_OP(maximum, int32_t, vec_max)
|
| 262 |
+
DEFINE_MEMBER_OP(minimum, int32_t, vec_min)
|
| 263 |
+
DEFINE_MEMBER_OP(operator&, int32_t, vec_and)
|
| 264 |
+
DEFINE_MEMBER_OP(operator|, int32_t, vec_or)
|
| 265 |
+
DEFINE_MEMBER_OP(operator^, int32_t, vec_xor)
|
| 266 |
+
};
|
| 267 |
+
|
| 268 |
+
template <>
|
| 269 |
+
Vectorized<int32_t> inline operator<<(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 270 |
+
vuint32 shift_vec0 = reinterpret_cast<vuint32>(b.vec0());
|
| 271 |
+
vuint32 shift_vec1 = reinterpret_cast<vuint32>(b.vec1()) ;
|
| 272 |
+
return Vectorized<int32_t>{vec_sl(a.vec0(), shift_vec0), vec_sl(a.vec1(), shift_vec1)};
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
template <>
|
| 276 |
+
Vectorized<int32_t> inline operator>>(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 277 |
+
vuint32 shift_vec0 = reinterpret_cast<vuint32>(b.vec0());
|
| 278 |
+
vuint32 shift_vec1 = reinterpret_cast<vuint32>(b.vec1()) ;
|
| 279 |
+
return Vectorized<int32_t>{vec_sr(a.vec0(), shift_vec0), vec_sr(a.vec1(), shift_vec1)};
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
template <>
|
| 283 |
+
Vectorized<int32_t> inline maximum(
|
| 284 |
+
const Vectorized<int32_t>& a,
|
| 285 |
+
const Vectorized<int32_t>& b) {
|
| 286 |
+
return a.maximum(b);
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
template <>
|
| 290 |
+
Vectorized<int32_t> inline minimum(
|
| 291 |
+
const Vectorized<int32_t>& a,
|
| 292 |
+
const Vectorized<int32_t>& b) {
|
| 293 |
+
return a.minimum(b);
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
template <>
|
| 297 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE operator+(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 298 |
+
return Vectorized<int32_t>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
template <>
|
| 302 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE operator-(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 303 |
+
return Vectorized<int32_t>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
template <>
|
| 307 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE operator*(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 308 |
+
return Vectorized<int32_t>{vec_mul(a.vec0(), b.vec0()), vec_mul(a.vec1(), b.vec1())};
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
template <>
|
| 312 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE operator/(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 313 |
+
return Vectorized<int32_t>{a.vec0()/b.vec0(), a.vec1()/b.vec1()};
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
template <>
|
| 317 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE operator&(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 318 |
+
return Vectorized<int32_t>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
template <>
|
| 322 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE operator|(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 323 |
+
return Vectorized<int32_t>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
+
template <>
|
| 327 |
+
Vectorized<int32_t> C10_ALWAYS_INLINE operator^(const Vectorized<int32_t>& a, const Vectorized<int32_t>& b) {
|
| 328 |
+
return Vectorized<int32_t>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
} // namespace
|
| 332 |
+
} // namespace vec
|
| 333 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int64_vsx.h
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
namespace at {
|
| 7 |
+
namespace vec {
|
| 8 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 9 |
+
inline namespace CPU_CAPABILITY {
|
| 10 |
+
|
| 11 |
+
template <>
|
| 12 |
+
class Vectorized<int64_t> {
|
| 13 |
+
private:
|
| 14 |
+
union {
|
| 15 |
+
struct {
|
| 16 |
+
vint64 _vec0;
|
| 17 |
+
vint64 _vec1;
|
| 18 |
+
};
|
| 19 |
+
struct {
|
| 20 |
+
vbool64 _vecb0;
|
| 21 |
+
vbool64 _vecb1;
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
} __attribute__((__may_alias__));
|
| 25 |
+
|
| 26 |
+
public:
|
| 27 |
+
using value_type = int64_t;
|
| 28 |
+
using vec_internal_type = vint64;
|
| 29 |
+
using vec_internal_mask_type = vbool64;
|
| 30 |
+
using size_type = int;
|
| 31 |
+
using ElementType = signed long long;
|
| 32 |
+
static constexpr size_type size() {
|
| 33 |
+
return 4;
|
| 34 |
+
}
|
| 35 |
+
Vectorized() {}
|
| 36 |
+
C10_ALWAYS_INLINE Vectorized(vint64 v) : _vec0{v}, _vec1{v} {}
|
| 37 |
+
C10_ALWAYS_INLINE Vectorized(vbool64 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 38 |
+
C10_ALWAYS_INLINE Vectorized(vint64 v1, vint64 v2) : _vec0{v1}, _vec1{v2} {}
|
| 39 |
+
C10_ALWAYS_INLINE Vectorized(vbool64 v1, vbool64 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 40 |
+
C10_ALWAYS_INLINE Vectorized(int64_t scalar)
|
| 41 |
+
: _vec0{vec_splats(scalar)}, _vec1{vec_splats(scalar)} {}
|
| 42 |
+
C10_ALWAYS_INLINE Vectorized(
|
| 43 |
+
int64_t scalar1,
|
| 44 |
+
int64_t scalar2,
|
| 45 |
+
int64_t scalar3,
|
| 46 |
+
int64_t scalar4)
|
| 47 |
+
: _vec0{vint64{scalar1, scalar2}}, _vec1{vint64{scalar3, scalar4}} {}
|
| 48 |
+
|
| 49 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 50 |
+
return _vec0;
|
| 51 |
+
}
|
| 52 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 53 |
+
return _vec1;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
template <uint64_t mask>
|
| 57 |
+
static std::enable_if_t<mask == 0, Vectorized<int64_t>> C10_ALWAYS_INLINE
|
| 58 |
+
blend(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 59 |
+
return a;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
template <uint64_t mask>
|
| 63 |
+
static std::enable_if_t<mask == 3, Vectorized<int64_t>> C10_ALWAYS_INLINE
|
| 64 |
+
blend(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 65 |
+
return {b._vec0, a._vec1};
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
template <uint64_t mask>
|
| 69 |
+
static std::enable_if_t<(mask & 15) == 15, Vectorized<int64_t>> C10_ALWAYS_INLINE
|
| 70 |
+
blend(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 71 |
+
return b;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
template <uint64_t mask>
|
| 75 |
+
static std::enable_if_t<(mask > 0 && mask < 3), Vectorized<int64_t>> C10_ALWAYS_INLINE
|
| 76 |
+
blend(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 77 |
+
constexpr uint64_t g0 = (mask & 1) * 0xffffffffffffffff;
|
| 78 |
+
constexpr uint64_t g1 = ((mask & 2) >> 1) * 0xffffffffffffffff;
|
| 79 |
+
const vbool64 mask_1st = (vbool64){g0, g1};
|
| 80 |
+
return {(vint64)vec_sel(a._vec0, b._vec0, (vbool64)mask_1st), a._vec1};
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
template <uint64_t mask>
|
| 84 |
+
static std::enable_if_t<(mask > 3) && (mask & 3) == 0, Vectorized<int64_t>>
|
| 85 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 86 |
+
constexpr uint64_t g0_2 = ((mask & 4) >> 2) * 0xffffffffffffffff;
|
| 87 |
+
constexpr uint64_t g1_2 = ((mask & 8) >> 3) * 0xffffffffffffffff;
|
| 88 |
+
|
| 89 |
+
const vbool64 mask_2nd = (vbool64){g0_2, g1_2};
|
| 90 |
+
return {a._vec0, (vint64)vec_sel(a._vec1, b._vec1, (vbool64)mask_2nd)};
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
template <uint64_t mask>
|
| 94 |
+
static std::enable_if_t<
|
| 95 |
+
(mask > 3) && (mask & 3) != 0 && (mask & 15) != 15,
|
| 96 |
+
Vectorized<int64_t>>
|
| 97 |
+
C10_ALWAYS_INLINE blend(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 98 |
+
constexpr uint64_t g0 = (mask & 1) * 0xffffffffffffffff;
|
| 99 |
+
constexpr uint64_t g1 = ((mask & 2) >> 1) * 0xffffffffffffffff;
|
| 100 |
+
constexpr uint64_t g0_2 = ((mask & 4) >> 2) * 0xffffffffffffffff;
|
| 101 |
+
constexpr uint64_t g1_2 = ((mask & 8) >> 3) * 0xffffffffffffffff;
|
| 102 |
+
|
| 103 |
+
const vbool64 mask_1st = (vbool64){g0, g1};
|
| 104 |
+
const vbool64 mask_2nd = (vbool64){g0_2, g1_2};
|
| 105 |
+
return {
|
| 106 |
+
(vint64)vec_sel(a._vec0, b._vec0, (vbool64)mask_1st),
|
| 107 |
+
(vint64)vec_sel(a._vec1, b._vec1, (vbool64)mask_2nd)};
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
static Vectorized<int64_t> C10_ALWAYS_INLINE blendv(
|
| 111 |
+
const Vectorized<int64_t>& a,
|
| 112 |
+
const Vectorized<int64_t>& b,
|
| 113 |
+
const Vectorized<int64_t>& mask) {
|
| 114 |
+
// the mask used here returned by comparision of vec256
|
| 115 |
+
|
| 116 |
+
return {
|
| 117 |
+
vec_sel(a._vec0, b._vec0, mask._vecb0),
|
| 118 |
+
vec_sel(a._vec1, b._vec1, mask._vecb1)};
|
| 119 |
+
}
|
| 120 |
+
template <typename step_t>
|
| 121 |
+
static Vectorized<int64_t> arange(int64_t base = 0., step_t step = static_cast<step_t>(1)) {
|
| 122 |
+
return Vectorized<int64_t>(base, base + step, base + 2 * step, base + 3 * step);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
static Vectorized<int64_t> C10_ALWAYS_INLINE
|
| 126 |
+
set(const Vectorized<int64_t>& a,
|
| 127 |
+
const Vectorized<int64_t>& b,
|
| 128 |
+
size_t count = size()) {
|
| 129 |
+
switch (count) {
|
| 130 |
+
case 0:
|
| 131 |
+
return a;
|
| 132 |
+
case 1:
|
| 133 |
+
return blend<1>(a, b);
|
| 134 |
+
case 2:
|
| 135 |
+
return blend<3>(a, b);
|
| 136 |
+
case 3:
|
| 137 |
+
return blend<7>(a, b);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
return b;
|
| 141 |
+
}
|
| 142 |
+
static Vectorized<value_type> C10_ALWAYS_INLINE
|
| 143 |
+
loadu(const void* ptr, int count = size()) {
|
| 144 |
+
if (count == size()) {
|
| 145 |
+
static_assert(sizeof(double) == sizeof(value_type));
|
| 146 |
+
const double* dptr = reinterpret_cast<const double*>(ptr);
|
| 147 |
+
return {// treat it as double load
|
| 148 |
+
(vint64)vec_vsx_ld(offset0, dptr),
|
| 149 |
+
(vint64)vec_vsx_ld(offset16, dptr)};
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
__at_align__ double tmp_values[size()] = {};
|
| 153 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 154 |
+
|
| 155 |
+
return {
|
| 156 |
+
(vint64)vec_vsx_ld(offset0, tmp_values),
|
| 157 |
+
(vint64)vec_vsx_ld(offset16, tmp_values)};
|
| 158 |
+
}
|
| 159 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 160 |
+
if (count == size()) {
|
| 161 |
+
double* dptr = reinterpret_cast<double*>(ptr);
|
| 162 |
+
vec_vsx_st((vfloat64)_vec0, offset0, dptr);
|
| 163 |
+
vec_vsx_st((vfloat64)_vec1, offset16, dptr);
|
| 164 |
+
} else if (count > 0) {
|
| 165 |
+
__at_align__ double tmp_values[size()];
|
| 166 |
+
vec_vsx_st((vfloat64)_vec0, offset0, tmp_values);
|
| 167 |
+
vec_vsx_st((vfloat64)_vec1, offset16, tmp_values);
|
| 168 |
+
std::memcpy(
|
| 169 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
const int64_t& operator[](int idx) const = delete;
|
| 173 |
+
int64_t& operator[](int idx) = delete;
|
| 174 |
+
|
| 175 |
+
Vectorized<int64_t> angle() const {
|
| 176 |
+
return blendv(
|
| 177 |
+
Vectorized<int64_t>(0), Vectorized<int64_t>(c10::pi<int64_t>), *this < Vectorized<int64_t>(0));
|
| 178 |
+
}
|
| 179 |
+
Vectorized<int64_t> real() const {
|
| 180 |
+
return *this;
|
| 181 |
+
}
|
| 182 |
+
Vectorized<int64_t> imag() const {
|
| 183 |
+
return Vectorized<int64_t>{0};
|
| 184 |
+
}
|
| 185 |
+
Vectorized<int64_t> conj() const {
|
| 186 |
+
return *this;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE abs() const {
|
| 190 |
+
return {vec_abs(_vec0), vec_abs(_vec1)};
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE neg() const {
|
| 194 |
+
return {vec_neg(_vec0), vec_neg(_vec1)};
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
DEFINE_MEMBER_UNARY_OP(operator~, int64_t, vec_not)
|
| 198 |
+
DEFINE_MEMBER_OP(operator==, int64_t, vec_cmpeq)
|
| 199 |
+
DEFINE_MEMBER_OP(operator!=, int64_t, vec_cmpne)
|
| 200 |
+
DEFINE_MEMBER_OP(operator<, int64_t, vec_cmplt)
|
| 201 |
+
DEFINE_MEMBER_OP(operator<=, int64_t, vec_cmple)
|
| 202 |
+
DEFINE_MEMBER_OP(operator>, int64_t, vec_cmpgt)
|
| 203 |
+
DEFINE_MEMBER_OP(operator>=, int64_t, vec_cmpge)
|
| 204 |
+
DEFINE_MEMBER_OP_AND_ONE(eq, int64_t, vec_cmpeq)
|
| 205 |
+
DEFINE_MEMBER_OP_AND_ONE(ne, int64_t, vec_cmpne)
|
| 206 |
+
DEFINE_MEMBER_OP_AND_ONE(lt, int64_t, vec_cmplt)
|
| 207 |
+
DEFINE_MEMBER_OP_AND_ONE(le, int64_t, vec_cmple)
|
| 208 |
+
DEFINE_MEMBER_OP_AND_ONE(gt, int64_t, vec_cmpgt)
|
| 209 |
+
DEFINE_MEMBER_OP_AND_ONE(ge, int64_t, vec_cmpge)
|
| 210 |
+
DEFINE_MEMBER_OP(operator+, int64_t, vec_add)
|
| 211 |
+
DEFINE_MEMBER_OP(operator-, int64_t, vec_sub)
|
| 212 |
+
DEFINE_MEMBER_OP(operator*, int64_t, vec_mul)
|
| 213 |
+
DEFINE_MEMBER_OP(operator/, int64_t, vec_div)
|
| 214 |
+
DEFINE_MEMBER_OP(maximum, int64_t, vec_max)
|
| 215 |
+
DEFINE_MEMBER_OP(minimum, int64_t, vec_min)
|
| 216 |
+
DEFINE_MEMBER_OP(operator&, int64_t, vec_and)
|
| 217 |
+
DEFINE_MEMBER_OP(operator|, int64_t, vec_or)
|
| 218 |
+
DEFINE_MEMBER_OP(operator^, int64_t, vec_xor)
|
| 219 |
+
};
|
| 220 |
+
|
| 221 |
+
template <>
|
| 222 |
+
Vectorized<int64_t> inline operator<<(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 223 |
+
vuint64 shift_vec0 = reinterpret_cast<vuint64>(b.vec0());
|
| 224 |
+
vuint64 shift_vec1 = reinterpret_cast<vuint64>(b.vec1()) ;
|
| 225 |
+
return Vectorized<int64_t>{vec_sl(a.vec0(), shift_vec0), vec_sl(a.vec1(), shift_vec1)};
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
template <>
|
| 229 |
+
Vectorized<int64_t> inline operator>>(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 230 |
+
vuint64 shift_vec0 = reinterpret_cast<vuint64>(b.vec0());
|
| 231 |
+
vuint64 shift_vec1 = reinterpret_cast<vuint64>(b.vec1()) ;
|
| 232 |
+
return Vectorized<int64_t>{vec_sr(a.vec0(), shift_vec0), vec_sr(a.vec1(), shift_vec1)};
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
template <>
|
| 236 |
+
Vectorized<int64_t> inline maximum(
|
| 237 |
+
const Vectorized<int64_t>& a,
|
| 238 |
+
const Vectorized<int64_t>& b) {
|
| 239 |
+
return a.maximum(b);
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
template <>
|
| 243 |
+
Vectorized<int64_t> inline minimum(
|
| 244 |
+
const Vectorized<int64_t>& a,
|
| 245 |
+
const Vectorized<int64_t>& b) {
|
| 246 |
+
return a.minimum(b);
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
template <>
|
| 250 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE operator+(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 251 |
+
return Vectorized<int64_t>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
template <>
|
| 255 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE operator-(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 256 |
+
return Vectorized<int64_t>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
template <>
|
| 260 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE operator*(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 261 |
+
return Vectorized<int64_t>{vec_mul(a.vec0(), b.vec0()), vec_mul(a.vec1(), b.vec1())};
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
template <>
|
| 265 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE operator/(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 266 |
+
return Vectorized<int64_t>{vec_div(a.vec0(), b.vec0()), vec_div(a.vec1(), b.vec1())};
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
template <>
|
| 270 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE operator&(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 271 |
+
return Vectorized<int64_t>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
template <>
|
| 275 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE operator|(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 276 |
+
return Vectorized<int64_t>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
template <>
|
| 280 |
+
Vectorized<int64_t> C10_ALWAYS_INLINE operator^(const Vectorized<int64_t>& a, const Vectorized<int64_t>& b) {
|
| 281 |
+
return Vectorized<int64_t>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
} // namespace
|
| 285 |
+
} // namespace vec
|
| 286 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_qint32_vsx.h
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
#include <c10/util/qint32.h>
|
| 7 |
+
#include <array>
|
| 8 |
+
|
| 9 |
+
// This file defines Vectorized<> for the quantized types.
|
| 10 |
+
//
|
| 11 |
+
//
|
| 12 |
+
// Currently, we simply use these classes as efficient converters between
|
| 13 |
+
// the quantized types and Vectorized<float>, usually in bandwidth-bound cases
|
| 14 |
+
// where doing the arithmetic in full-precision is acceptable (e.g.
|
| 15 |
+
// elementwise operators).
|
| 16 |
+
//
|
| 17 |
+
//
|
| 18 |
+
// Conversions are as follows:
|
| 19 |
+
// Vectorized<qint32> -> 1x Vectorized<float>
|
| 20 |
+
//
|
| 21 |
+
// The size of the returned float vector is specified by the special
|
| 22 |
+
// constexpr function float_num_vecs. The type of the value returned
|
| 23 |
+
// from dequantize (and expected as an argument to quantize) is
|
| 24 |
+
// specified by float_vec_return_type.
|
| 25 |
+
//
|
| 26 |
+
// When writing kernels with these vectors, it is expected that floating-
|
| 27 |
+
// point operations will be carried out in a loop over Vectorized<T>::float_num_vecs
|
| 28 |
+
// iterations.
|
| 29 |
+
|
| 30 |
+
namespace at {
|
| 31 |
+
namespace vec {
|
| 32 |
+
inline namespace CPU_CAPABILITY {
|
| 33 |
+
|
| 34 |
+
template <>
|
| 35 |
+
struct Vectorized<c10::qint32> {
|
| 36 |
+
private:
|
| 37 |
+
union {
|
| 38 |
+
struct {
|
| 39 |
+
vint32 _vec0;
|
| 40 |
+
vint32 _vec1;
|
| 41 |
+
};
|
| 42 |
+
struct {
|
| 43 |
+
vbool32 _vecb0;
|
| 44 |
+
vbool32 _vecb1;
|
| 45 |
+
};
|
| 46 |
+
|
| 47 |
+
} __attribute__((__may_alias__));
|
| 48 |
+
|
| 49 |
+
public:
|
| 50 |
+
Vectorized() {}
|
| 51 |
+
|
| 52 |
+
using size_type = int;
|
| 53 |
+
static constexpr size_type size() {
|
| 54 |
+
return 8;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
static constexpr size_t float_num_vecs() {
|
| 58 |
+
return 1;
|
| 59 |
+
}
|
| 60 |
+
static constexpr int int_num_vecs() {
|
| 61 |
+
return 1;
|
| 62 |
+
}
|
| 63 |
+
using float_vec_return_type = std::array<Vectorized<float>, 1>;
|
| 64 |
+
using int_vec_return_type = std::array<Vectorized<c10::qint32>, 1>;
|
| 65 |
+
using value_type = c10::qint32::underlying;
|
| 66 |
+
using vec_internal_type = vint32;
|
| 67 |
+
using vec_internal_mask_type = vbool32;
|
| 68 |
+
C10_ALWAYS_INLINE Vectorized(vint32 v) : _vec0{v}, _vec1{v} {}
|
| 69 |
+
C10_ALWAYS_INLINE Vectorized(vbool32 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 70 |
+
C10_ALWAYS_INLINE Vectorized(vint32 v1, vint32 v2) : _vec0{v1}, _vec1{v2} {}
|
| 71 |
+
C10_ALWAYS_INLINE Vectorized(vbool32 v1, vbool32 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 72 |
+
|
| 73 |
+
Vectorized(const c10::qint32& val)
|
| 74 |
+
: _vec0(vec_splats(val.val_)), _vec1(vec_splats(val.val_)) {}
|
| 75 |
+
|
| 76 |
+
static Vectorized<c10::qint32> C10_ALWAYS_INLINE
|
| 77 |
+
loadu(const void* ptr, int count = size()) {
|
| 78 |
+
if (count == size()) {
|
| 79 |
+
return {
|
| 80 |
+
vec_vsx_ld(offset0, reinterpret_cast<const value_type*>(ptr)),
|
| 81 |
+
vec_vsx_ld(offset16, reinterpret_cast<const value_type*>(ptr))};
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 85 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 86 |
+
|
| 87 |
+
return {vec_vsx_ld(offset0, tmp_values), vec_vsx_ld(offset16, tmp_values)};
|
| 88 |
+
}
|
| 89 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 90 |
+
if (count == size()) {
|
| 91 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<value_type*>(ptr));
|
| 92 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<value_type*>(ptr));
|
| 93 |
+
} else if (count > 0) {
|
| 94 |
+
__at_align__ value_type tmp_values[size()];
|
| 95 |
+
vec_vsx_st(_vec0, offset0, tmp_values);
|
| 96 |
+
vec_vsx_st(_vec1, offset16, tmp_values);
|
| 97 |
+
std::memcpy(
|
| 98 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 99 |
+
}
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 103 |
+
return _vec0;
|
| 104 |
+
}
|
| 105 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 106 |
+
return _vec1;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
float_vec_return_type dequantize(
|
| 110 |
+
Vectorized<float> scale,
|
| 111 |
+
Vectorized<float> zero_point,
|
| 112 |
+
Vectorized<float> scale_zp_premul) const {
|
| 113 |
+
vfloat32 float_vals0 = vec_float(_vec0);
|
| 114 |
+
vfloat32 float_vals1 = vec_float(_vec1);
|
| 115 |
+
vfloat32 scale_vec0 = scale.vec0();
|
| 116 |
+
vfloat32 scale_vec1 = scale.vec1();
|
| 117 |
+
vfloat32 scale_zp_premul0 = scale_zp_premul.vec0();
|
| 118 |
+
vfloat32 scale_zp_premul1 = scale_zp_premul.vec1();
|
| 119 |
+
return {Vectorized<float>{
|
| 120 |
+
vec_madd(scale_vec0, float_vals0, scale_zp_premul0),
|
| 121 |
+
vec_madd(scale_vec1, float_vals1, scale_zp_premul1)}};
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
float_vec_return_type dequantize(
|
| 125 |
+
Vectorized<float> scale,
|
| 126 |
+
Vectorized<float> zero_point) const {
|
| 127 |
+
vfloat32 float_vals0 = vec_float(_vec0);
|
| 128 |
+
vfloat32 float_vals1 = vec_float(_vec1);
|
| 129 |
+
vfloat32 scale_vec0 = scale.vec0();
|
| 130 |
+
vfloat32 scale_vec1 = scale.vec1();
|
| 131 |
+
vfloat32 zero_point0 = zero_point.vec0();
|
| 132 |
+
vfloat32 zero_point1 = zero_point.vec1();
|
| 133 |
+
return {Vectorized<float>{
|
| 134 |
+
(float_vals0 - zero_point0) * scale_vec0,
|
| 135 |
+
(float_vals1 - zero_point1) * scale_vec1}};
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
static Vectorized<c10::qint32> quantize(
|
| 139 |
+
const float_vec_return_type& rhs,
|
| 140 |
+
float scale,
|
| 141 |
+
int32_t zero_point,
|
| 142 |
+
float inverse_scale) {
|
| 143 |
+
Vectorized<c10::qint32> retval;
|
| 144 |
+
|
| 145 |
+
const vint32 vmin = vec_splats(std::numeric_limits<value_type>::min());
|
| 146 |
+
const vint32 vmax = vec_splats(std::numeric_limits<value_type>::max());
|
| 147 |
+
vfloat32 inverse_scale_v = vec_splats(inverse_scale);
|
| 148 |
+
vfloat32 vec_zero_point = vec_splats((float)(zero_point));
|
| 149 |
+
Vectorized<float> vf0 = rhs[0];
|
| 150 |
+
|
| 151 |
+
vfloat32 vecf0 = vf0.vec0();
|
| 152 |
+
vfloat32 vecf1 = vf0.vec1();
|
| 153 |
+
vecf0 = vec_mul(vecf0, inverse_scale_v);
|
| 154 |
+
vecf1 = vec_mul(vecf1, inverse_scale_v);
|
| 155 |
+
vecf0 = vec_add(vec_rint(vecf0), vec_zero_point);
|
| 156 |
+
vecf1 = vec_add(vec_rint(vecf1), vec_zero_point);
|
| 157 |
+
vint32 veci0 = vec_signed(vecf0);
|
| 158 |
+
vint32 veci1 = vec_signed(vecf1);
|
| 159 |
+
|
| 160 |
+
veci0 = vec_max(veci0, vmin);
|
| 161 |
+
veci1 = vec_max(veci1, vmin);
|
| 162 |
+
veci0 = vec_min(veci0, vmax);
|
| 163 |
+
veci1 = vec_min(veci1, vmax);
|
| 164 |
+
|
| 165 |
+
return {veci0, veci1};
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
Vectorized<c10::qint32> relu(Vectorized<c10::qint32> zero_point) const {
|
| 169 |
+
return {vec_max(_vec0, zero_point._vec0), vec_max(_vec1, zero_point._vec1)};
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
Vectorized<c10::qint32> relu6(
|
| 173 |
+
Vectorized<c10::qint32> zero_point,
|
| 174 |
+
Vectorized<c10::qint32> q_six) const {
|
| 175 |
+
vint32 max0 = vec_max(_vec0, zero_point._vec0);
|
| 176 |
+
vint32 max1 = vec_max(_vec1, zero_point._vec1);
|
| 177 |
+
return {vec_min(max0, q_six._vec0), vec_min(max1, q_six._vec1)};
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
int_vec_return_type widening_subtract(Vectorized<c10::qint32> b) const {
|
| 181 |
+
return {*this - b};
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
static Vectorized<c10::qint32> requantize_from_int(
|
| 185 |
+
const int_vec_return_type& inp,
|
| 186 |
+
float multiplier,
|
| 187 |
+
int32_t zero_point) {
|
| 188 |
+
const vint32 vmin = vec_splats(std::numeric_limits<value_type>::min());
|
| 189 |
+
const vint32 vmax = vec_splats(std::numeric_limits<value_type>::max());
|
| 190 |
+
vfloat32 vec_mult = vec_splats(multiplier);
|
| 191 |
+
vint32 vec_zero_point = vec_splats(zero_point);
|
| 192 |
+
Vectorized<c10::qint32> vi = inp[0];
|
| 193 |
+
vfloat32 vecf0 = vec_float(vi.vec0());
|
| 194 |
+
vfloat32 vecf1 = vec_float(vi.vec1());
|
| 195 |
+
|
| 196 |
+
vecf0 = vec_mul(vecf0, vec_mult);
|
| 197 |
+
vecf1 = vec_mul(vecf1, vec_mult);
|
| 198 |
+
|
| 199 |
+
vecf0 = vec_rint(vecf0);
|
| 200 |
+
vecf1 = vec_rint(vecf1);
|
| 201 |
+
|
| 202 |
+
vint32 veci0 = vec_add(vec_signed(vecf0),vec_zero_point);
|
| 203 |
+
vint32 veci1 = vec_add(vec_signed(vecf1),vec_zero_point);
|
| 204 |
+
|
| 205 |
+
veci0 = vec_max(veci0, vmin);
|
| 206 |
+
veci1 = vec_max(veci1, vmin);
|
| 207 |
+
veci0 = vec_min(veci0, vmax);
|
| 208 |
+
veci1 = vec_min(veci1, vmax);
|
| 209 |
+
|
| 210 |
+
return {veci0, veci1};
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
DEFINE_MEMBER_OP(operator==, c10::qint32, vec_cmpeq)
|
| 214 |
+
DEFINE_MEMBER_OP(operator!=, c10::qint32, vec_cmpne)
|
| 215 |
+
DEFINE_MEMBER_OP(operator<, c10::qint32, vec_cmplt)
|
| 216 |
+
DEFINE_MEMBER_OP(operator<=, c10::qint32, vec_cmple)
|
| 217 |
+
DEFINE_MEMBER_OP(operator>, c10::qint32, vec_cmpgt)
|
| 218 |
+
DEFINE_MEMBER_OP(operator>=, c10::qint32, vec_cmpge)
|
| 219 |
+
DEFINE_MEMBER_OP(operator+, c10::qint32, vec_add)
|
| 220 |
+
DEFINE_MEMBER_OP(operator-, c10::qint32, vec_sub)
|
| 221 |
+
DEFINE_MEMBER_OP(operator*, c10::qint32, vec_mul)
|
| 222 |
+
DEFINE_MEMBER_EMULATE_BINARY_OP(operator/, c10::qint32, /)
|
| 223 |
+
DEFINE_MEMBER_OP(maximum, c10::qint32, vec_max)
|
| 224 |
+
DEFINE_MEMBER_OP(minimum, c10::qint32, vec_min)
|
| 225 |
+
DEFINE_MEMBER_OP(operator&, c10::qint32, vec_and)
|
| 226 |
+
DEFINE_MEMBER_OP(operator|, c10::qint32, vec_or)
|
| 227 |
+
DEFINE_MEMBER_OP(operator^, c10::qint32, vec_xor)
|
| 228 |
+
};
|
| 229 |
+
|
| 230 |
+
template <>
|
| 231 |
+
Vectorized<c10::qint32> inline maximum(
|
| 232 |
+
const Vectorized<c10::qint32>& a,
|
| 233 |
+
const Vectorized<c10::qint32>& b) {
|
| 234 |
+
return a.maximum(b);
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
template <>
|
| 238 |
+
Vectorized<c10::qint32> inline minimum(
|
| 239 |
+
const Vectorized<c10::qint32>& a,
|
| 240 |
+
const Vectorized<c10::qint32>& b) {
|
| 241 |
+
return a.minimum(b);
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
template <>
|
| 245 |
+
Vectorized<c10::qint32> C10_ALWAYS_INLINE operator+(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 246 |
+
return Vectorized<c10::qint32>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
template <>
|
| 250 |
+
Vectorized<c10::qint32> C10_ALWAYS_INLINE operator-(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 251 |
+
return Vectorized<c10::qint32>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
template <>
|
| 255 |
+
Vectorized<c10::qint32> C10_ALWAYS_INLINE operator*(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 256 |
+
return Vectorized<c10::qint32>{vec_mul(a.vec0(), b.vec0()), vec_mul(a.vec1(), b.vec1())};
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
template <>
|
| 260 |
+
Vectorized<c10::qint32> C10_ALWAYS_INLINE operator/(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 261 |
+
return Vectorized<c10::qint32>{a.vec0()/b.vec0(), a.vec1()/b.vec1()};
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
template <>
|
| 265 |
+
Vectorized<c10::qint32> C10_ALWAYS_INLINE operator&(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 266 |
+
return Vectorized<c10::qint32>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
template <>
|
| 270 |
+
Vectorized<c10::qint32> C10_ALWAYS_INLINE operator|(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 271 |
+
return Vectorized<c10::qint32>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
template <>
|
| 275 |
+
Vectorized<c10::qint32> C10_ALWAYS_INLINE operator^(const Vectorized<c10::qint32>& a, const Vectorized<c10::qint32>& b) {
|
| 276 |
+
return Vectorized<c10::qint32>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
} // namespace
|
| 280 |
+
} // namespace vec
|
| 281 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_qint8_vsx.h
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
#include <c10/util/qint8.h>
|
| 7 |
+
#include <array>
|
| 8 |
+
|
| 9 |
+
// This file defines Vectorized<> for the quantized types.
|
| 10 |
+
//
|
| 11 |
+
//
|
| 12 |
+
// Currently, we simply use these classes as efficient converters between
|
| 13 |
+
// the quantized types and Vectorized<float>, usually in bandwidth-bound cases
|
| 14 |
+
// where doing the arithmetic in full-precision is acceptable (e.g.
|
| 15 |
+
// elementwise operators).
|
| 16 |
+
//
|
| 17 |
+
//
|
| 18 |
+
// Conversions are as follows:
|
| 19 |
+
// Vectorized<qint8> -> 4x Vectorized<float>
|
| 20 |
+
//
|
| 21 |
+
// The size of the returned float vector is specified by the special
|
| 22 |
+
// constexpr function float_num_vecs. The type of the value returned
|
| 23 |
+
// from dequantize (and expected as an argument to quantize) is
|
| 24 |
+
// specified by float_vec_return_type.
|
| 25 |
+
//
|
| 26 |
+
// When writing kernels with these vectors, it is expected that floating-
|
| 27 |
+
// point operations will be carried out in a loop over Vectorized<T>::float_num_vecs
|
| 28 |
+
// iterations.
|
| 29 |
+
|
| 30 |
+
namespace at {
|
| 31 |
+
namespace vec {
|
| 32 |
+
inline namespace CPU_CAPABILITY {
|
| 33 |
+
|
| 34 |
+
template <>
|
| 35 |
+
struct Vectorized<c10::qint8> {
|
| 36 |
+
private:
|
| 37 |
+
union {
|
| 38 |
+
struct {
|
| 39 |
+
vint8 _vec0;
|
| 40 |
+
vint8 _vec1;
|
| 41 |
+
};
|
| 42 |
+
struct {
|
| 43 |
+
vbool8 _vecb0;
|
| 44 |
+
vbool8 _vecb1;
|
| 45 |
+
};
|
| 46 |
+
|
| 47 |
+
} __attribute__((__may_alias__));
|
| 48 |
+
|
| 49 |
+
public:
|
| 50 |
+
Vectorized() {}
|
| 51 |
+
using size_type = int;
|
| 52 |
+
static constexpr size_type size() {
|
| 53 |
+
return 32;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
static constexpr size_t float_num_vecs() {
|
| 57 |
+
return 4;
|
| 58 |
+
}
|
| 59 |
+
static constexpr int int_num_vecs() {
|
| 60 |
+
return 4;
|
| 61 |
+
}
|
| 62 |
+
using float_vec_return_type = std::array<Vectorized<float>, 4>;
|
| 63 |
+
using int_vec_return_type = std::array<Vectorized<c10::qint32>, 4>;
|
| 64 |
+
using value_type = typename c10::qint8::underlying;
|
| 65 |
+
using vec_internal_type = vint8;
|
| 66 |
+
using vec_internal_mask_type = vbool8;
|
| 67 |
+
// Broadcast constructor
|
| 68 |
+
C10_ALWAYS_INLINE Vectorized(const c10::qint8& val)
|
| 69 |
+
: _vec0{vec_splats(val.val_)}, _vec1{vec_splats(val.val_)} {}
|
| 70 |
+
|
| 71 |
+
C10_ALWAYS_INLINE Vectorized(const Vectorized<c10::qint8>& other)
|
| 72 |
+
: _vec0{other._vec0}, _vec1(other._vec1) {}
|
| 73 |
+
|
| 74 |
+
C10_ALWAYS_INLINE Vectorized(vint8 v) : _vec0{v}, _vec1{v} {}
|
| 75 |
+
C10_ALWAYS_INLINE Vectorized(vbool8 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 76 |
+
C10_ALWAYS_INLINE Vectorized(vint8 v1, vint8 v2) : _vec0{v1}, _vec1{v2} {}
|
| 77 |
+
C10_ALWAYS_INLINE Vectorized(vbool8 v1, vbool8 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 78 |
+
|
| 79 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 80 |
+
return _vec0;
|
| 81 |
+
}
|
| 82 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 83 |
+
return _vec1;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
static C10_ALWAYS_INLINE Vectorized<c10::qint8> loadu(
|
| 87 |
+
const void* ptr,
|
| 88 |
+
int count = size()) {
|
| 89 |
+
if (count == size()) {
|
| 90 |
+
return {
|
| 91 |
+
vec_vsx_ld(offset0, reinterpret_cast<const vint8*>(ptr)),
|
| 92 |
+
vec_vsx_ld(offset16, reinterpret_cast<const vint8*>(ptr))};
|
| 93 |
+
}
|
| 94 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 95 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 96 |
+
return {vec_vsx_ld(offset0, tmp_values), vec_vsx_ld(offset16, tmp_values)};
|
| 97 |
+
}
|
| 98 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 99 |
+
if (count == size()) {
|
| 100 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<value_type*>(ptr));
|
| 101 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<value_type*>(ptr));
|
| 102 |
+
} else if (count > 0) {
|
| 103 |
+
__at_align__ value_type tmp_values[size()];
|
| 104 |
+
vec_vsx_st(_vec0, offset0, tmp_values);
|
| 105 |
+
vec_vsx_st(_vec1, offset16, tmp_values);
|
| 106 |
+
std::memcpy(
|
| 107 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
public:
|
| 112 |
+
float_vec_return_type C10_ALWAYS_INLINE dequantize(
|
| 113 |
+
Vectorized<float> scale,
|
| 114 |
+
Vectorized<float> zero_point,
|
| 115 |
+
Vectorized<float> scale_zp_premul) const {
|
| 116 |
+
vint16 vecshi0 = vec_unpackh(_vec0);
|
| 117 |
+
vint16 vecshi1 = vec_unpackl(_vec0);
|
| 118 |
+
|
| 119 |
+
vint16 vecshi2 = vec_unpackh(_vec1);
|
| 120 |
+
vint16 vecshi3 = vec_unpackl(_vec1);
|
| 121 |
+
|
| 122 |
+
vint32 veci0 = vec_unpackh(vecshi0);
|
| 123 |
+
vint32 veci1 = vec_unpackl(vecshi0);
|
| 124 |
+
|
| 125 |
+
vint32 veci2 = vec_unpackh(vecshi1);
|
| 126 |
+
vint32 veci3 = vec_unpackl(vecshi1);
|
| 127 |
+
|
| 128 |
+
vint32 veci4 = vec_unpackh(vecshi2);
|
| 129 |
+
vint32 veci5 = vec_unpackl(vecshi2);
|
| 130 |
+
|
| 131 |
+
vint32 veci6 = vec_unpackh(vecshi3);
|
| 132 |
+
vint32 veci7 = vec_unpackl(vecshi3);
|
| 133 |
+
|
| 134 |
+
vfloat32 vecf0_0 = vec_float(veci0);
|
| 135 |
+
vfloat32 vecf1_0 = vec_float(veci1);
|
| 136 |
+
|
| 137 |
+
vfloat32 vecf0_1 = vec_float(veci2);
|
| 138 |
+
vfloat32 vecf1_1 = vec_float(veci3);
|
| 139 |
+
|
| 140 |
+
vfloat32 vecf0_2 = vec_float(veci4);
|
| 141 |
+
vfloat32 vecf1_2 = vec_float(veci5);
|
| 142 |
+
|
| 143 |
+
vfloat32 vecf0_3 = vec_float(veci6);
|
| 144 |
+
vfloat32 vecf1_3 = vec_float(veci7);
|
| 145 |
+
vfloat32 scale_vec0 = scale.vec0();
|
| 146 |
+
vfloat32 scale_vec1 = scale.vec1();
|
| 147 |
+
vfloat32 scale_zp_premul0 = scale_zp_premul.vec0();
|
| 148 |
+
vfloat32 scale_zp_premul1 = scale_zp_premul.vec1();
|
| 149 |
+
return {
|
| 150 |
+
Vectorized<float>{
|
| 151 |
+
vec_madd(scale_vec0, vecf0_0, scale_zp_premul0),
|
| 152 |
+
vec_madd(scale_vec1, vecf1_0, scale_zp_premul1)},
|
| 153 |
+
Vectorized<float>{
|
| 154 |
+
vec_madd(scale_vec0, vecf0_1, scale_zp_premul0),
|
| 155 |
+
vec_madd(scale_vec1, vecf1_1, scale_zp_premul1)},
|
| 156 |
+
Vectorized<float>{
|
| 157 |
+
vec_madd(scale_vec0, vecf0_2, scale_zp_premul0),
|
| 158 |
+
vec_madd(scale_vec1, vecf1_2, scale_zp_premul1)},
|
| 159 |
+
Vectorized<float>{
|
| 160 |
+
vec_madd(scale_vec0, vecf0_3, scale_zp_premul0),
|
| 161 |
+
vec_madd(scale_vec1, vecf1_3, scale_zp_premul1)}};
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
float_vec_return_type C10_ALWAYS_INLINE dequantize(
|
| 165 |
+
Vectorized<float> scale,
|
| 166 |
+
Vectorized<float> zero_point) const {
|
| 167 |
+
vint16 vecshi0 = vec_unpackh(_vec0);
|
| 168 |
+
vint16 vecshi1 = vec_unpackl(_vec0);
|
| 169 |
+
|
| 170 |
+
vint16 vecshi2 = vec_unpackh(_vec1);
|
| 171 |
+
vint16 vecshi3 = vec_unpackl(_vec1);
|
| 172 |
+
|
| 173 |
+
vint32 veci0 = vec_unpackh(vecshi0);
|
| 174 |
+
vint32 veci1 = vec_unpackl(vecshi0);
|
| 175 |
+
|
| 176 |
+
vint32 veci2 = vec_unpackh(vecshi1);
|
| 177 |
+
vint32 veci3 = vec_unpackl(vecshi1);
|
| 178 |
+
|
| 179 |
+
vint32 veci4 = vec_unpackh(vecshi2);
|
| 180 |
+
vint32 veci5 = vec_unpackl(vecshi2);
|
| 181 |
+
|
| 182 |
+
vint32 veci6 = vec_unpackh(vecshi3);
|
| 183 |
+
vint32 veci7 = vec_unpackl(vecshi3);
|
| 184 |
+
|
| 185 |
+
vfloat32 vecf0_0 = vec_float(veci0);
|
| 186 |
+
vfloat32 vecf1_0 = vec_float(veci1);
|
| 187 |
+
|
| 188 |
+
vfloat32 vecf0_1 = vec_float(veci2);
|
| 189 |
+
vfloat32 vecf1_1 = vec_float(veci3);
|
| 190 |
+
|
| 191 |
+
vfloat32 vecf0_2 = vec_float(veci4);
|
| 192 |
+
vfloat32 vecf1_2 = vec_float(veci5);
|
| 193 |
+
|
| 194 |
+
vfloat32 vecf0_3 = vec_float(veci6);
|
| 195 |
+
vfloat32 vecf1_3 = vec_float(veci7);
|
| 196 |
+
vfloat32 scale_vec0 = scale.vec0();
|
| 197 |
+
vfloat32 scale_vec1 = scale.vec1();
|
| 198 |
+
vfloat32 zero_point0 = zero_point.vec0();
|
| 199 |
+
vfloat32 zero_point1 = zero_point.vec1();
|
| 200 |
+
return {
|
| 201 |
+
Vectorized<float>{
|
| 202 |
+
(vecf0_0 - zero_point0) * scale_vec0,
|
| 203 |
+
(vecf1_0 - zero_point1) * scale_vec1},
|
| 204 |
+
Vectorized<float>{
|
| 205 |
+
(vecf0_1 - zero_point0) * scale_vec0,
|
| 206 |
+
(vecf1_1 - zero_point1) * scale_vec1},
|
| 207 |
+
Vectorized<float>{
|
| 208 |
+
(vecf0_2 - zero_point0) * scale_vec0,
|
| 209 |
+
(vecf1_2 - zero_point1) * scale_vec1},
|
| 210 |
+
Vectorized<float>{
|
| 211 |
+
(vecf0_3 - zero_point0) * scale_vec0,
|
| 212 |
+
(vecf1_3 - zero_point1) * scale_vec1}};
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
static Vectorized<c10::qint8> quantize(
|
| 216 |
+
const float_vec_return_type& rhs,
|
| 217 |
+
float scale,
|
| 218 |
+
int32_t zero_point,
|
| 219 |
+
float inverse_scale) {
|
| 220 |
+
// constexpr int32_t min_val = std::numeric_limits<value_type>::min();
|
| 221 |
+
// constexpr int32_t max_val = std::numeric_limits<value_type>::max();
|
| 222 |
+
|
| 223 |
+
vfloat32 inverse_scale_v = vec_splats(inverse_scale);
|
| 224 |
+
vfloat32 vec_zero_point = vec_splats((float)zero_point);
|
| 225 |
+
// vint32 vmin = vec_splats(min_val);
|
| 226 |
+
// vint32 vmax = vec_splats(max_val);
|
| 227 |
+
|
| 228 |
+
Vectorized<float> vf0 = rhs[0];
|
| 229 |
+
Vectorized<float> vf1 = rhs[1];
|
| 230 |
+
Vectorized<float> vf2 = rhs[2];
|
| 231 |
+
Vectorized<float> vf3 = rhs[3];
|
| 232 |
+
vfloat32 vecf0 = vf0.vec0();
|
| 233 |
+
vfloat32 vecf1 = vf0.vec1();
|
| 234 |
+
vfloat32 vecf2 = vf1.vec0();
|
| 235 |
+
vfloat32 vecf3 = vf1.vec1();
|
| 236 |
+
|
| 237 |
+
vfloat32 vecf4 = vf2.vec0();
|
| 238 |
+
vfloat32 vecf5 = vf2.vec1();
|
| 239 |
+
vfloat32 vecf6 = vf3.vec0();
|
| 240 |
+
vfloat32 vecf7 = vf3.vec1();
|
| 241 |
+
|
| 242 |
+
vecf0 = vec_mul(vecf0, inverse_scale_v);
|
| 243 |
+
vecf1 = vec_mul(vecf1, inverse_scale_v);
|
| 244 |
+
vecf2 = vec_mul(vecf2, inverse_scale_v);
|
| 245 |
+
vecf3 = vec_mul(vecf3, inverse_scale_v);
|
| 246 |
+
|
| 247 |
+
vecf4 = vec_mul(vecf4, inverse_scale_v);
|
| 248 |
+
vecf5 = vec_mul(vecf5, inverse_scale_v);
|
| 249 |
+
vecf6 = vec_mul(vecf6, inverse_scale_v);
|
| 250 |
+
vecf7 = vec_mul(vecf7, inverse_scale_v);
|
| 251 |
+
|
| 252 |
+
vecf0 = vec_add(vec_rint(vecf0), vec_zero_point);
|
| 253 |
+
vecf1 = vec_add(vec_rint(vecf1), vec_zero_point);
|
| 254 |
+
vecf2 = vec_add(vec_rint(vecf2), vec_zero_point);
|
| 255 |
+
vecf3 = vec_add(vec_rint(vecf3), vec_zero_point);
|
| 256 |
+
|
| 257 |
+
vecf4 = vec_add(vec_rint(vecf4), vec_zero_point);
|
| 258 |
+
vecf5 = vec_add(vec_rint(vecf5), vec_zero_point);
|
| 259 |
+
vecf6 = vec_add(vec_rint(vecf6), vec_zero_point);
|
| 260 |
+
vecf7 = vec_add(vec_rint(vecf7), vec_zero_point);
|
| 261 |
+
|
| 262 |
+
vint32 veci0 = vec_signed(vecf0);
|
| 263 |
+
vint32 veci1 = vec_signed(vecf1);
|
| 264 |
+
vint32 veci2 = vec_signed(vecf2);
|
| 265 |
+
vint32 veci3 = vec_signed(vecf3);
|
| 266 |
+
|
| 267 |
+
vint32 veci4 = vec_signed(vecf4);
|
| 268 |
+
vint32 veci5 = vec_signed(vecf5);
|
| 269 |
+
vint32 veci6 = vec_signed(vecf6);
|
| 270 |
+
vint32 veci7 = vec_signed(vecf7);
|
| 271 |
+
|
| 272 |
+
// veci0 = vec_min(vmax, vec_max( vmin, vecf0)) ;
|
| 273 |
+
// veci1 = vec_min(vmax, vec_max( vmin, vecf1)) ;
|
| 274 |
+
// veci2 = vec_min(vmax, vec_max( vmin, vecf2)) ;
|
| 275 |
+
// veci3 = vec_min(vmax, vec_max( vmin, vecf3)) ;
|
| 276 |
+
|
| 277 |
+
// veci4 = vec_min(vmax, vec_max( vmin, vecf4)) ;
|
| 278 |
+
// veci5 = vec_min(vmax, vec_max( vmin, vecf5)) ;
|
| 279 |
+
// veci6 = vec_min(vmax, vec_max( vmin, vecf6)) ;
|
| 280 |
+
// veci7 = vec_min(vmax, vec_max( vmin, vecf7)) ;
|
| 281 |
+
// vec_packs CLAMP already
|
| 282 |
+
vint16 vecshi0 = vec_packs(veci0, veci1);
|
| 283 |
+
vint16 vecshi1 = vec_packs(veci2, veci3);
|
| 284 |
+
vint16 vecshi2 = vec_packs(veci4, veci5);
|
| 285 |
+
vint16 vecshi3 = vec_packs(veci6, veci7);
|
| 286 |
+
|
| 287 |
+
vint8 vec0 = vec_packs(vecshi0, vecshi1);
|
| 288 |
+
vint8 vec1 = vec_packs(vecshi2, vecshi3);
|
| 289 |
+
|
| 290 |
+
return {vec0, vec1};
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE relu(Vectorized<c10::qint8> zero_point) const {
|
| 294 |
+
return {vec_max(_vec0, zero_point._vec0), vec_max(_vec1, zero_point._vec1)};
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE
|
| 298 |
+
relu6(Vectorized<c10::qint8> zero_point, Vectorized<c10::qint8> q_six) const {
|
| 299 |
+
vint8 max0 = vec_max(_vec0, zero_point._vec0);
|
| 300 |
+
vint8 max1 = vec_max(_vec1, zero_point._vec1);
|
| 301 |
+
return {vec_min(max0, q_six._vec0), vec_min(max1, q_six._vec1)};
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
int_vec_return_type widening_subtract(Vectorized<c10::qint8> b) const {
|
| 305 |
+
vint16 vecshi0 = vec_unpackh(_vec0);
|
| 306 |
+
vint16 vecBshi0 = vec_unpackh(b._vec0);
|
| 307 |
+
vint16 vecshi1 = vec_unpackl(_vec0);
|
| 308 |
+
vint16 vecBshi1 = vec_unpackl(b._vec0);
|
| 309 |
+
|
| 310 |
+
vint16 vecshi2 = vec_unpackh(_vec1);
|
| 311 |
+
vint16 vecBshi2 = vec_unpackh(b._vec1);
|
| 312 |
+
vint16 vecshi3 = vec_unpackl(_vec1);
|
| 313 |
+
vint16 vecBshi3 = vec_unpackl(b._vec1);
|
| 314 |
+
|
| 315 |
+
vint32 veci0 = vec_unpackh(vecshi0);
|
| 316 |
+
vint32 vecBi0 = vec_unpackh(vecBshi0);
|
| 317 |
+
vint32 veci1 = vec_unpackl(vecshi0);
|
| 318 |
+
vint32 vecBi1 = vec_unpackl(vecBshi0);
|
| 319 |
+
|
| 320 |
+
vint32 veci2 = vec_unpackh(vecshi1);
|
| 321 |
+
vint32 vecBi2 = vec_unpackh(vecBshi1);
|
| 322 |
+
vint32 veci3 = vec_unpackl(vecshi1);
|
| 323 |
+
vint32 vecBi3 = vec_unpackl(vecBshi1);
|
| 324 |
+
|
| 325 |
+
vint32 veci4 = vec_unpackh(vecshi2);
|
| 326 |
+
vint32 vecBi4 = vec_unpackh(vecBshi2);
|
| 327 |
+
vint32 veci5 = vec_unpackl(vecshi2);
|
| 328 |
+
vint32 vecBi5 = vec_unpackl(vecBshi2);
|
| 329 |
+
|
| 330 |
+
vint32 veci6 = vec_unpackh(vecshi3);
|
| 331 |
+
vint32 vecBi6 = vec_unpackh(vecBshi3);
|
| 332 |
+
vint32 veci7 = vec_unpackl(vecshi3);
|
| 333 |
+
vint32 vecBi7 = vec_unpackl(vecBshi3);
|
| 334 |
+
|
| 335 |
+
return {
|
| 336 |
+
Vectorized<c10::qint32>(veci0 - vecBi0, veci1 - vecBi1),
|
| 337 |
+
Vectorized<c10::qint32>(veci2 - vecBi2, veci3 - vecBi3),
|
| 338 |
+
Vectorized<c10::qint32>(veci4 - vecBi4, veci5 - vecBi5),
|
| 339 |
+
Vectorized<c10::qint32>(veci6 - vecBi6, veci7 - vecBi7)};
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
static Vectorized<c10::qint8> requantize_from_int(
|
| 343 |
+
const int_vec_return_type& inp,
|
| 344 |
+
float multiplier,
|
| 345 |
+
int32_t zero_point) {
|
| 346 |
+
vfloat32 vec_multiplier = vec_splats(multiplier);
|
| 347 |
+
vint32 vec_zero_point = vec_splats(zero_point);
|
| 348 |
+
|
| 349 |
+
Vectorized<c10::qint32> vi0 = inp[0];
|
| 350 |
+
Vectorized<c10::qint32> vi1 = inp[1];
|
| 351 |
+
Vectorized<c10::qint32> vi2 = inp[2];
|
| 352 |
+
Vectorized<c10::qint32> vi3 = inp[3];
|
| 353 |
+
|
| 354 |
+
vfloat32 vecf0 = vec_float(vi0.vec0());
|
| 355 |
+
vfloat32 vecf1 = vec_float(vi0.vec1());
|
| 356 |
+
vfloat32 vecf2 = vec_float(vi1.vec0());
|
| 357 |
+
vfloat32 vecf3 = vec_float(vi1.vec1());
|
| 358 |
+
|
| 359 |
+
vfloat32 vecf4 = vec_float(vi2.vec0());
|
| 360 |
+
vfloat32 vecf5 = vec_float(vi2.vec1());
|
| 361 |
+
vfloat32 vecf6 = vec_float(vi3.vec0());
|
| 362 |
+
vfloat32 vecf7 = vec_float(vi3.vec1());
|
| 363 |
+
|
| 364 |
+
vecf0 = vec_mul(vecf0, vec_multiplier);
|
| 365 |
+
vecf1 = vec_mul(vecf1, vec_multiplier);
|
| 366 |
+
vecf2 = vec_mul(vecf2, vec_multiplier);
|
| 367 |
+
vecf3 = vec_mul(vecf3, vec_multiplier);
|
| 368 |
+
|
| 369 |
+
vecf4 = vec_mul(vecf4, vec_multiplier);
|
| 370 |
+
vecf5 = vec_mul(vecf5, vec_multiplier);
|
| 371 |
+
vecf6 = vec_mul(vecf6, vec_multiplier);
|
| 372 |
+
vecf7 = vec_mul(vecf7, vec_multiplier);
|
| 373 |
+
|
| 374 |
+
vecf0 = vec_rint(vecf0);
|
| 375 |
+
vecf1 = vec_rint(vecf1);
|
| 376 |
+
vecf2 = vec_rint(vecf2);
|
| 377 |
+
vecf3 = vec_rint(vecf3);
|
| 378 |
+
|
| 379 |
+
vecf4 = vec_rint(vecf4);
|
| 380 |
+
vecf5 = vec_rint(vecf5);
|
| 381 |
+
vecf6 = vec_rint(vecf6);
|
| 382 |
+
vecf7 = vec_rint(vecf7);
|
| 383 |
+
|
| 384 |
+
vint32 veci0 = vec_signed(vecf0);
|
| 385 |
+
vint32 veci1 = vec_signed(vecf1);
|
| 386 |
+
vint32 veci2 = vec_signed(vecf2);
|
| 387 |
+
vint32 veci3 = vec_signed(vecf3);
|
| 388 |
+
|
| 389 |
+
vint32 veci4 = vec_signed(vecf4);
|
| 390 |
+
vint32 veci5 = vec_signed(vecf5);
|
| 391 |
+
vint32 veci6 = vec_signed(vecf6);
|
| 392 |
+
vint32 veci7 = vec_signed(vecf7);
|
| 393 |
+
|
| 394 |
+
veci0 = vec_add(veci0, vec_zero_point);
|
| 395 |
+
veci1 = vec_add(veci1, vec_zero_point);
|
| 396 |
+
veci2 = vec_add(veci2, vec_zero_point);
|
| 397 |
+
veci3 = vec_add(veci3, vec_zero_point);
|
| 398 |
+
|
| 399 |
+
veci4 = vec_add(veci4, vec_zero_point);
|
| 400 |
+
veci5 = vec_add(veci5, vec_zero_point);
|
| 401 |
+
veci6 = vec_add(veci6, vec_zero_point);
|
| 402 |
+
veci7 = vec_add(veci7, vec_zero_point);
|
| 403 |
+
|
| 404 |
+
vint16 vecshi0 = vec_packs(veci0, veci1);
|
| 405 |
+
vint16 vecshi1 = vec_packs(veci2, veci3);
|
| 406 |
+
vint16 vecshi2 = vec_packs(veci4, veci5);
|
| 407 |
+
vint16 vecshi3 = vec_packs(veci6, veci7);
|
| 408 |
+
|
| 409 |
+
vint8 vec0 = vec_packs(vecshi0, vecshi1);
|
| 410 |
+
vint8 vec1 = vec_packs(vecshi2, vecshi3);
|
| 411 |
+
|
| 412 |
+
return {vec0, vec1};
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
DEFINE_MEMBER_OP(operator==, c10::qint8, vec_cmpeq)
|
| 416 |
+
DEFINE_MEMBER_OP(operator!=, c10::qint8, vec_cmpne)
|
| 417 |
+
DEFINE_MEMBER_OP(operator<, c10::qint8, vec_cmplt)
|
| 418 |
+
DEFINE_MEMBER_OP(operator<=, c10::qint8, vec_cmple)
|
| 419 |
+
DEFINE_MEMBER_OP(operator>, c10::qint8, vec_cmpgt)
|
| 420 |
+
DEFINE_MEMBER_OP(operator>=, c10::qint8, vec_cmpge)
|
| 421 |
+
DEFINE_MEMBER_OP(operator+, c10::qint8, vec_add)
|
| 422 |
+
DEFINE_MEMBER_OP(operator-, c10::qint8, vec_sub)
|
| 423 |
+
DEFINE_MEMBER_OP(operator*, c10::qint8, vec_mul)
|
| 424 |
+
DEFINE_MEMBER_EMULATE_BINARY_OP(operator/, c10::qint8, /)
|
| 425 |
+
DEFINE_MEMBER_OP(maximum, c10::qint8, vec_max)
|
| 426 |
+
DEFINE_MEMBER_OP(minimum, c10::qint8, vec_min)
|
| 427 |
+
DEFINE_MEMBER_OP(operator&, c10::qint8, vec_and)
|
| 428 |
+
DEFINE_MEMBER_OP(operator|, c10::qint8, vec_or)
|
| 429 |
+
DEFINE_MEMBER_OP(operator^, c10::qint8, vec_xor)
|
| 430 |
+
};
|
| 431 |
+
|
| 432 |
+
template <>
|
| 433 |
+
Vectorized<c10::qint8> inline maximum(
|
| 434 |
+
const Vectorized<c10::qint8>& a,
|
| 435 |
+
const Vectorized<c10::qint8>& b) {
|
| 436 |
+
return a.maximum(b);
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
template <>
|
| 440 |
+
Vectorized<c10::qint8> inline minimum(
|
| 441 |
+
const Vectorized<c10::qint8>& a,
|
| 442 |
+
const Vectorized<c10::qint8>& b) {
|
| 443 |
+
return a.minimum(b);
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
template <>
|
| 447 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE operator+(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 448 |
+
return Vectorized<c10::qint8>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
template <>
|
| 452 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE operator-(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 453 |
+
return Vectorized<c10::qint8>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
template <>
|
| 457 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE operator*(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 458 |
+
return Vectorized<c10::qint8>{vec_mul(a.vec0(), b.vec0()), vec_mul(a.vec1(), b.vec1())};
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
template <>
|
| 462 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE operator/(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 463 |
+
return Vectorized<c10::qint8>{a.vec0()/b.vec0(), a.vec1()/b.vec1()};
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
template <>
|
| 467 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE operator&(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 468 |
+
return Vectorized<c10::qint8>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
template <>
|
| 472 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE operator|(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 473 |
+
return Vectorized<c10::qint8>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
template <>
|
| 477 |
+
Vectorized<c10::qint8> C10_ALWAYS_INLINE operator^(const Vectorized<c10::qint8>& a, const Vectorized<c10::qint8>& b) {
|
| 478 |
+
return Vectorized<c10::qint8>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
} // namespace
|
| 482 |
+
} // namespace vec
|
| 483 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_quint8_vsx.h
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec256/vsx/vsx_helpers.h>
|
| 6 |
+
|
| 7 |
+
#include <c10/util/irange.h>
|
| 8 |
+
#include <c10/util/quint8.h>
|
| 9 |
+
#include <array>
|
| 10 |
+
|
| 11 |
+
// This file defines Vectorized<> for the quantized types.
|
| 12 |
+
//
|
| 13 |
+
//
|
| 14 |
+
// Currently, we simply use these classes as efficient converters between
|
| 15 |
+
// the quantized types and Vectorized<float>, usually in bandwidth-bound cases
|
| 16 |
+
// where doing the arithmetic in full-precision is acceptable (e.g.
|
| 17 |
+
// elementwise operators).
|
| 18 |
+
//
|
| 19 |
+
//
|
| 20 |
+
// Conversions are as follows:
|
| 21 |
+
// Vectorized<quint8> -> 4x Vectorized<float>
|
| 22 |
+
//
|
| 23 |
+
// The size of the returned float vector is specified by the special
|
| 24 |
+
// constexpr function float_num_vecs. The type of the value returned
|
| 25 |
+
// from dequantize (and expected as an argument to quantize) is
|
| 26 |
+
// specified by float_vec_return_type.
|
| 27 |
+
//
|
| 28 |
+
// When writing kernels with these vectors, it is expected that floating-
|
| 29 |
+
// point operations will be carried out in a loop over Vectorized<T>::float_num_vecs
|
| 30 |
+
// iterations.
|
| 31 |
+
|
| 32 |
+
namespace at {
|
| 33 |
+
namespace vec {
|
| 34 |
+
inline namespace CPU_CAPABILITY {
|
| 35 |
+
|
| 36 |
+
const vint16 mask_unsigned = vec_splats((short int)0xFF);
|
| 37 |
+
template <>
|
| 38 |
+
struct Vectorized<c10::quint8> {
|
| 39 |
+
private:
|
| 40 |
+
union {
|
| 41 |
+
struct {
|
| 42 |
+
vuint8 _vec0;
|
| 43 |
+
vuint8 _vec1;
|
| 44 |
+
};
|
| 45 |
+
struct {
|
| 46 |
+
vbool8 _vecb0;
|
| 47 |
+
vbool8 _vecb1;
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
} __attribute__((__may_alias__));
|
| 51 |
+
|
| 52 |
+
public:
|
| 53 |
+
Vectorized() {}
|
| 54 |
+
using size_type = int;
|
| 55 |
+
static constexpr size_type size() {
|
| 56 |
+
return 32;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
static constexpr size_t float_num_vecs() {
|
| 60 |
+
return 4;
|
| 61 |
+
}
|
| 62 |
+
static constexpr int int_num_vecs() {
|
| 63 |
+
return 4;
|
| 64 |
+
}
|
| 65 |
+
using float_vec_return_type = std::array<Vectorized<float>, 4>;
|
| 66 |
+
using int_vec_return_type = std::array<Vectorized<c10::qint32>, 4>;
|
| 67 |
+
using value_type = typename c10::quint8::underlying;
|
| 68 |
+
using vec_internal_type = vuint8;
|
| 69 |
+
using vec_internal_mask_type = vbool8;
|
| 70 |
+
// Broadcast constructor
|
| 71 |
+
C10_ALWAYS_INLINE Vectorized(const c10::quint8& val)
|
| 72 |
+
: _vec0(vec_splats(val.val_)), _vec1(vec_splats(val.val_)) {}
|
| 73 |
+
|
| 74 |
+
C10_ALWAYS_INLINE Vectorized(const Vectorized<c10::quint8>& other)
|
| 75 |
+
: _vec0{other._vec0}, _vec1(other._vec1) {}
|
| 76 |
+
|
| 77 |
+
C10_ALWAYS_INLINE Vectorized(vuint8 v) : _vec0{v}, _vec1{v} {}
|
| 78 |
+
C10_ALWAYS_INLINE Vectorized(vbool8 vmask) : _vecb0{vmask}, _vecb1{vmask} {}
|
| 79 |
+
C10_ALWAYS_INLINE Vectorized(vuint8 v1, vuint8 v2) : _vec0{v1}, _vec1{v2} {}
|
| 80 |
+
C10_ALWAYS_INLINE Vectorized(vbool8 v1, vbool8 v2) : _vecb0{v1}, _vecb1{v2} {}
|
| 81 |
+
|
| 82 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec0() const {
|
| 83 |
+
return _vec0;
|
| 84 |
+
}
|
| 85 |
+
C10_ALWAYS_INLINE const vec_internal_type& vec1() const {
|
| 86 |
+
return _vec1;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
static C10_ALWAYS_INLINE Vectorized<c10::quint8> loadu(
|
| 90 |
+
const void* ptr,
|
| 91 |
+
int count = size()) {
|
| 92 |
+
if (count == size()) {
|
| 93 |
+
return {
|
| 94 |
+
vec_vsx_ld(offset0, reinterpret_cast<const value_type*>(ptr)),
|
| 95 |
+
vec_vsx_ld(offset16, reinterpret_cast<const value_type*>(ptr))};
|
| 96 |
+
}
|
| 97 |
+
__at_align__ value_type tmp_values[size()] = {};
|
| 98 |
+
std::memcpy(tmp_values, ptr, std::min(count, size()) * sizeof(value_type));
|
| 99 |
+
return {vec_vsx_ld(offset0, tmp_values), vec_vsx_ld(offset16, tmp_values)};
|
| 100 |
+
}
|
| 101 |
+
void C10_ALWAYS_INLINE store(void* ptr, int count = size()) const {
|
| 102 |
+
if (count == size()) {
|
| 103 |
+
vec_vsx_st(_vec0, offset0, reinterpret_cast<value_type*>(ptr));
|
| 104 |
+
vec_vsx_st(_vec1, offset16, reinterpret_cast<value_type*>(ptr));
|
| 105 |
+
} else if (count > 0) {
|
| 106 |
+
__at_align__ value_type tmp_values[size()];
|
| 107 |
+
vec_vsx_st(_vec0, offset0, tmp_values);
|
| 108 |
+
vec_vsx_st(_vec1, offset16, tmp_values);
|
| 109 |
+
std::memcpy(
|
| 110 |
+
ptr, tmp_values, std::min(count, size()) * sizeof(value_type));
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
public:
|
| 115 |
+
float_vec_return_type C10_ALWAYS_INLINE dequantize(
|
| 116 |
+
Vectorized<float> scale,
|
| 117 |
+
Vectorized<float> zero_point,
|
| 118 |
+
Vectorized<float> scale_zp_premul) const {
|
| 119 |
+
// unpacking unsigned as signed
|
| 120 |
+
vint16 vecshi0 = vec_unpackh((vint8)_vec0);
|
| 121 |
+
vint16 vecshi1 = vec_unpackl((vint8)_vec0);
|
| 122 |
+
|
| 123 |
+
vint16 vecshi2 = vec_unpackh((vint8)_vec1);
|
| 124 |
+
vint16 vecshi3 = vec_unpackl((vint8)_vec1);
|
| 125 |
+
|
| 126 |
+
// signed -> unsigned
|
| 127 |
+
vecshi0 = vec_and(vecshi0, mask_unsigned);
|
| 128 |
+
vecshi1 = vec_and(vecshi1, mask_unsigned);
|
| 129 |
+
|
| 130 |
+
vecshi2 = vec_and(vecshi2, mask_unsigned);
|
| 131 |
+
vecshi3 = vec_and(vecshi3, mask_unsigned);
|
| 132 |
+
|
| 133 |
+
vint32 veci0 = vec_unpackh(vecshi0);
|
| 134 |
+
vint32 veci1 = vec_unpackl(vecshi0);
|
| 135 |
+
|
| 136 |
+
vint32 veci2 = vec_unpackh(vecshi1);
|
| 137 |
+
vint32 veci3 = vec_unpackl(vecshi1);
|
| 138 |
+
|
| 139 |
+
vint32 veci4 = vec_unpackh(vecshi2);
|
| 140 |
+
vint32 veci5 = vec_unpackl(vecshi2);
|
| 141 |
+
|
| 142 |
+
vint32 veci6 = vec_unpackh(vecshi3);
|
| 143 |
+
vint32 veci7 = vec_unpackl(vecshi3);
|
| 144 |
+
|
| 145 |
+
vfloat32 vecf0_0 = vec_float(veci0);
|
| 146 |
+
vfloat32 vecf1_0 = vec_float(veci1);
|
| 147 |
+
|
| 148 |
+
vfloat32 vecf0_1 = vec_float(veci2);
|
| 149 |
+
vfloat32 vecf1_1 = vec_float(veci3);
|
| 150 |
+
|
| 151 |
+
vfloat32 vecf0_2 = vec_float(veci4);
|
| 152 |
+
vfloat32 vecf1_2 = vec_float(veci5);
|
| 153 |
+
|
| 154 |
+
vfloat32 vecf0_3 = vec_float(veci6);
|
| 155 |
+
vfloat32 vecf1_3 = vec_float(veci7);
|
| 156 |
+
vfloat32 scale_vec0 = scale.vec0();
|
| 157 |
+
vfloat32 scale_vec1 = scale.vec1();
|
| 158 |
+
vfloat32 scale_zp_premul0 = scale_zp_premul.vec0();
|
| 159 |
+
vfloat32 scale_zp_premul1 = scale_zp_premul.vec1();
|
| 160 |
+
return {
|
| 161 |
+
Vectorized<float>{
|
| 162 |
+
vec_madd(scale_vec0, vecf0_0, scale_zp_premul0),
|
| 163 |
+
vec_madd(scale_vec1, vecf1_0, scale_zp_premul1)},
|
| 164 |
+
Vectorized<float>{
|
| 165 |
+
vec_madd(scale_vec0, vecf0_1, scale_zp_premul0),
|
| 166 |
+
vec_madd(scale_vec1, vecf1_1, scale_zp_premul1)},
|
| 167 |
+
Vectorized<float>{
|
| 168 |
+
vec_madd(scale_vec0, vecf0_2, scale_zp_premul0),
|
| 169 |
+
vec_madd(scale_vec1, vecf1_2, scale_zp_premul1)},
|
| 170 |
+
Vectorized<float>{
|
| 171 |
+
vec_madd(scale_vec0, vecf0_3, scale_zp_premul0),
|
| 172 |
+
vec_madd(scale_vec1, vecf1_3, scale_zp_premul1)}};
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
float_vec_return_type C10_ALWAYS_INLINE dequantize(
|
| 176 |
+
Vectorized<float> scale,
|
| 177 |
+
Vectorized<float> zero_point) const {
|
| 178 |
+
// unpacking unsigned as signed
|
| 179 |
+
vint16 vecshi0 = vec_unpackh((vint8)_vec0);
|
| 180 |
+
vint16 vecshi1 = vec_unpackl((vint8)_vec0);
|
| 181 |
+
|
| 182 |
+
vint16 vecshi2 = vec_unpackh((vint8)_vec1);
|
| 183 |
+
vint16 vecshi3 = vec_unpackl((vint8)_vec1);
|
| 184 |
+
|
| 185 |
+
// signed -> unsigned
|
| 186 |
+
vecshi0 = vec_and(vecshi0, mask_unsigned);
|
| 187 |
+
vecshi1 = vec_and(vecshi1, mask_unsigned);
|
| 188 |
+
|
| 189 |
+
vecshi2 = vec_and(vecshi2, mask_unsigned);
|
| 190 |
+
vecshi3 = vec_and(vecshi3, mask_unsigned);
|
| 191 |
+
|
| 192 |
+
vint32 veci0 = vec_unpackh(vecshi0);
|
| 193 |
+
vint32 veci1 = vec_unpackl(vecshi0);
|
| 194 |
+
|
| 195 |
+
vint32 veci2 = vec_unpackh(vecshi1);
|
| 196 |
+
vint32 veci3 = vec_unpackl(vecshi1);
|
| 197 |
+
|
| 198 |
+
vint32 veci4 = vec_unpackh(vecshi2);
|
| 199 |
+
vint32 veci5 = vec_unpackl(vecshi2);
|
| 200 |
+
|
| 201 |
+
vint32 veci6 = vec_unpackh(vecshi3);
|
| 202 |
+
vint32 veci7 = vec_unpackl(vecshi3);
|
| 203 |
+
|
| 204 |
+
vfloat32 vecf0_0 = vec_float(veci0);
|
| 205 |
+
vfloat32 vecf1_0 = vec_float(veci1);
|
| 206 |
+
|
| 207 |
+
vfloat32 vecf0_1 = vec_float(veci2);
|
| 208 |
+
vfloat32 vecf1_1 = vec_float(veci3);
|
| 209 |
+
|
| 210 |
+
vfloat32 vecf0_2 = vec_float(veci4);
|
| 211 |
+
vfloat32 vecf1_2 = vec_float(veci5);
|
| 212 |
+
|
| 213 |
+
vfloat32 vecf0_3 = vec_float(veci6);
|
| 214 |
+
vfloat32 vecf1_3 = vec_float(veci7);
|
| 215 |
+
vfloat32 scale_vec0 = scale.vec0();
|
| 216 |
+
vfloat32 scale_vec1 = scale.vec1();
|
| 217 |
+
vfloat32 zero_point0 = zero_point.vec0();
|
| 218 |
+
vfloat32 zero_point1 = zero_point.vec1();
|
| 219 |
+
return {
|
| 220 |
+
Vectorized<float>{
|
| 221 |
+
(vecf0_0 - zero_point0) * scale_vec0,
|
| 222 |
+
(vecf1_0 - zero_point1) * scale_vec1},
|
| 223 |
+
Vectorized<float>{
|
| 224 |
+
(vecf0_1 - zero_point0) * scale_vec0,
|
| 225 |
+
(vecf1_1 - zero_point1) * scale_vec1},
|
| 226 |
+
Vectorized<float>{
|
| 227 |
+
(vecf0_2 - zero_point0) * scale_vec0,
|
| 228 |
+
(vecf1_2 - zero_point1) * scale_vec1},
|
| 229 |
+
Vectorized<float>{
|
| 230 |
+
(vecf0_3 - zero_point0) * scale_vec0,
|
| 231 |
+
(vecf1_3 - zero_point1) * scale_vec1}};
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
static Vectorized<c10::quint8> quantize(
|
| 235 |
+
const float_vec_return_type& rhs,
|
| 236 |
+
float scale,
|
| 237 |
+
int32_t zero_point,
|
| 238 |
+
float inverse_scale) {
|
| 239 |
+
// constexpr int32_t min_val = std::numeric_limits<value_type>::min();
|
| 240 |
+
// constexpr int32_t max_val = std::numeric_limits<value_type>::max();
|
| 241 |
+
|
| 242 |
+
vfloat32 vec_inverse = vec_splats(inverse_scale);
|
| 243 |
+
vfloat32 vec_zero_point = vec_splats((float)zero_point);
|
| 244 |
+
// vuint32 vmin = vec_splats(min_val);
|
| 245 |
+
// vuint32 vmax = vec_splats(max_val);
|
| 246 |
+
Vectorized<float> vf0 = rhs[0];
|
| 247 |
+
Vectorized<float> vf1 = rhs[1];
|
| 248 |
+
Vectorized<float> vf2 = rhs[2];
|
| 249 |
+
Vectorized<float> vf3 = rhs[3];
|
| 250 |
+
vfloat32 vecf0 = vf0.vec0();
|
| 251 |
+
vfloat32 vecf1 = vf0.vec1();
|
| 252 |
+
vfloat32 vecf2 = vf1.vec0();
|
| 253 |
+
vfloat32 vecf3 = vf1.vec1();
|
| 254 |
+
|
| 255 |
+
vfloat32 vecf4 = vf2.vec0();
|
| 256 |
+
vfloat32 vecf5 = vf2.vec1();
|
| 257 |
+
vfloat32 vecf6 = vf3.vec0();
|
| 258 |
+
vfloat32 vecf7 = vf3.vec1();
|
| 259 |
+
|
| 260 |
+
vecf0 = vec_mul(vecf0, vec_inverse);
|
| 261 |
+
vecf1 = vec_mul(vecf1, vec_inverse);
|
| 262 |
+
vecf2 = vec_mul(vecf2, vec_inverse);
|
| 263 |
+
vecf3 = vec_mul(vecf3, vec_inverse);
|
| 264 |
+
|
| 265 |
+
vecf4 = vec_mul(vecf4, vec_inverse);
|
| 266 |
+
vecf5 = vec_mul(vecf5, vec_inverse);
|
| 267 |
+
vecf6 = vec_mul(vecf6, vec_inverse);
|
| 268 |
+
vecf7 = vec_mul(vecf7, vec_inverse);
|
| 269 |
+
|
| 270 |
+
vecf0 = vec_add(vec_rint(vecf0), vec_zero_point);
|
| 271 |
+
vecf1 = vec_add(vec_rint(vecf1), vec_zero_point);
|
| 272 |
+
vecf2 = vec_add(vec_rint(vecf2), vec_zero_point);
|
| 273 |
+
vecf3 = vec_add(vec_rint(vecf3), vec_zero_point);
|
| 274 |
+
|
| 275 |
+
vecf4 = vec_add(vec_rint(vecf4), vec_zero_point);
|
| 276 |
+
vecf5 = vec_add(vec_rint(vecf5), vec_zero_point);
|
| 277 |
+
vecf6 = vec_add(vec_rint(vecf6), vec_zero_point);
|
| 278 |
+
vecf7 = vec_add(vec_rint(vecf7), vec_zero_point);
|
| 279 |
+
|
| 280 |
+
vint32 veci0 = vec_signed(vecf0);
|
| 281 |
+
vint32 veci1 = vec_signed(vecf1);
|
| 282 |
+
vint32 veci2 = vec_signed(vecf2);
|
| 283 |
+
vint32 veci3 = vec_signed(vecf3);
|
| 284 |
+
|
| 285 |
+
vint32 veci4 = vec_signed(vecf4);
|
| 286 |
+
vint32 veci5 = vec_signed(vecf5);
|
| 287 |
+
vint32 veci6 = vec_signed(vecf6);
|
| 288 |
+
vint32 veci7 = vec_signed(vecf7);
|
| 289 |
+
|
| 290 |
+
vint16 vecshi0 = vec_packs(veci0, veci1);
|
| 291 |
+
vint16 vecshi1 = vec_packs(veci2, veci3);
|
| 292 |
+
vint16 vecshi2 = vec_packs(veci4, veci5);
|
| 293 |
+
vint16 vecshi3 = vec_packs(veci6, veci7);
|
| 294 |
+
|
| 295 |
+
vuint8 vec0 = vec_packsu(vecshi0, vecshi1);
|
| 296 |
+
vuint8 vec1 = vec_packsu(vecshi2, vecshi3);
|
| 297 |
+
|
| 298 |
+
return {vec0, vec1};
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE relu(Vectorized<c10::quint8> zero_point) const {
|
| 302 |
+
return {vec_max(_vec0, zero_point._vec0), vec_max(_vec1, zero_point._vec1)};
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE
|
| 306 |
+
relu6(Vectorized<c10::quint8> zero_point, Vectorized<c10::quint8> q_six) const {
|
| 307 |
+
vuint8 max0 = vec_max(_vec0, zero_point._vec0);
|
| 308 |
+
vuint8 max1 = vec_max(_vec1, zero_point._vec1);
|
| 309 |
+
return {vec_min(max0, q_six._vec0), vec_min(max1, q_six._vec1)};
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
int_vec_return_type widening_subtract(Vectorized<c10::quint8> b) const {
|
| 313 |
+
vint16 vecshi0 = vec_unpackh((vint8)_vec0);
|
| 314 |
+
vint16 vecBshi0 = vec_unpackh((vint8)b._vec0);
|
| 315 |
+
vint16 vecshi1 = vec_unpackl((vint8)_vec0);
|
| 316 |
+
vint16 vecBshi1 = vec_unpackl((vint8)b._vec0);
|
| 317 |
+
|
| 318 |
+
vint16 vecshi2 = vec_unpackh((vint8)_vec1);
|
| 319 |
+
vint16 vecBshi2 = vec_unpackh((vint8)b._vec1);
|
| 320 |
+
vint16 vecshi3 = vec_unpackl((vint8)_vec1);
|
| 321 |
+
vint16 vecBshi3 = vec_unpackl((vint8)b._vec1);
|
| 322 |
+
|
| 323 |
+
vecshi0 = vec_and(vecshi0, mask_unsigned);
|
| 324 |
+
vecBshi0 = vec_and(vecBshi0, mask_unsigned);
|
| 325 |
+
vecshi1 = vec_and(vecshi1, mask_unsigned);
|
| 326 |
+
vecBshi1 = vec_and(vecBshi1, mask_unsigned);
|
| 327 |
+
|
| 328 |
+
vecshi2 = vec_and(vecshi2, mask_unsigned);
|
| 329 |
+
vecBshi2 = vec_and(vecBshi2, mask_unsigned);
|
| 330 |
+
vecshi3 = vec_and(vecshi3, mask_unsigned);
|
| 331 |
+
vecBshi3 = vec_and(vecBshi3, mask_unsigned);
|
| 332 |
+
|
| 333 |
+
vint32 veci0 = vec_unpackh(vecshi0);
|
| 334 |
+
vint32 vecBi0 = vec_unpackh(vecBshi0);
|
| 335 |
+
vint32 veci1 = vec_unpackl(vecshi0);
|
| 336 |
+
vint32 vecBi1 = vec_unpackl(vecBshi0);
|
| 337 |
+
|
| 338 |
+
vint32 veci2 = vec_unpackh(vecshi1);
|
| 339 |
+
vint32 vecBi2 = vec_unpackh(vecBshi1);
|
| 340 |
+
vint32 veci3 = vec_unpackl(vecshi1);
|
| 341 |
+
vint32 vecBi3 = vec_unpackl(vecBshi1);
|
| 342 |
+
|
| 343 |
+
vint32 veci4 = vec_unpackh(vecshi2);
|
| 344 |
+
vint32 vecBi4 = vec_unpackh(vecBshi2);
|
| 345 |
+
vint32 veci5 = vec_unpackl(vecshi2);
|
| 346 |
+
vint32 vecBi5 = vec_unpackl(vecBshi2);
|
| 347 |
+
|
| 348 |
+
vint32 veci6 = vec_unpackh(vecshi3);
|
| 349 |
+
vint32 vecBi6 = vec_unpackh(vecBshi3);
|
| 350 |
+
vint32 veci7 = vec_unpackl(vecshi3);
|
| 351 |
+
vint32 vecBi7 = vec_unpackl(vecBshi3);
|
| 352 |
+
|
| 353 |
+
return {
|
| 354 |
+
Vectorized<c10::qint32>(veci0 - vecBi0, veci1 - vecBi1),
|
| 355 |
+
Vectorized<c10::qint32>(veci2 - vecBi2, veci3 - vecBi3),
|
| 356 |
+
Vectorized<c10::qint32>(veci4 - vecBi4, veci5 - vecBi5),
|
| 357 |
+
Vectorized<c10::qint32>(veci6 - vecBi6, veci7 - vecBi7)};
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
static Vectorized<c10::quint8> requantize_from_int(
|
| 361 |
+
const int_vec_return_type& inp,
|
| 362 |
+
float multiplier,
|
| 363 |
+
int32_t zero_point) {
|
| 364 |
+
vfloat32 vec_multiplier = vec_splats(multiplier);
|
| 365 |
+
vint32 vec_zero_point = vec_splats(zero_point);
|
| 366 |
+
|
| 367 |
+
Vectorized<c10::qint32> vi0 = inp[0];
|
| 368 |
+
Vectorized<c10::qint32> vi1 = inp[1];
|
| 369 |
+
Vectorized<c10::qint32> vi2 = inp[2];
|
| 370 |
+
Vectorized<c10::qint32> vi3 = inp[3];
|
| 371 |
+
|
| 372 |
+
vfloat32 vecf0 = vec_float(vi0.vec0());
|
| 373 |
+
vfloat32 vecf1 = vec_float(vi0.vec1());
|
| 374 |
+
vfloat32 vecf2 = vec_float(vi1.vec0());
|
| 375 |
+
vfloat32 vecf3 = vec_float(vi1.vec1());
|
| 376 |
+
|
| 377 |
+
vfloat32 vecf4 = vec_float(vi2.vec0());
|
| 378 |
+
vfloat32 vecf5 = vec_float(vi2.vec1());
|
| 379 |
+
vfloat32 vecf6 = vec_float(vi3.vec0());
|
| 380 |
+
vfloat32 vecf7 = vec_float(vi3.vec1());
|
| 381 |
+
|
| 382 |
+
vecf0 = vec_mul(vecf0, vec_multiplier);
|
| 383 |
+
vecf1 = vec_mul(vecf1, vec_multiplier);
|
| 384 |
+
vecf2 = vec_mul(vecf2, vec_multiplier);
|
| 385 |
+
vecf3 = vec_mul(vecf3, vec_multiplier);
|
| 386 |
+
|
| 387 |
+
vecf4 = vec_mul(vecf4, vec_multiplier);
|
| 388 |
+
vecf5 = vec_mul(vecf5, vec_multiplier);
|
| 389 |
+
vecf6 = vec_mul(vecf6, vec_multiplier);
|
| 390 |
+
vecf7 = vec_mul(vecf7, vec_multiplier);
|
| 391 |
+
|
| 392 |
+
vecf0 = vec_rint(vecf0);
|
| 393 |
+
vecf1 = vec_rint(vecf1);
|
| 394 |
+
vecf2 = vec_rint(vecf2);
|
| 395 |
+
vecf3 = vec_rint(vecf3);
|
| 396 |
+
|
| 397 |
+
vecf4 = vec_rint(vecf4);
|
| 398 |
+
vecf5 = vec_rint(vecf5);
|
| 399 |
+
vecf6 = vec_rint(vecf6);
|
| 400 |
+
vecf7 = vec_rint(vecf7);
|
| 401 |
+
|
| 402 |
+
vint32 veci0 = vec_signed(vecf0);
|
| 403 |
+
vint32 veci1 = vec_signed(vecf1);
|
| 404 |
+
vint32 veci2 = vec_signed(vecf2);
|
| 405 |
+
vint32 veci3 = vec_signed(vecf3);
|
| 406 |
+
|
| 407 |
+
vint32 veci4 = vec_signed(vecf4);
|
| 408 |
+
vint32 veci5 = vec_signed(vecf5);
|
| 409 |
+
vint32 veci6 = vec_signed(vecf6);
|
| 410 |
+
vint32 veci7 = vec_signed(vecf7);
|
| 411 |
+
|
| 412 |
+
veci0 = vec_add(veci0, vec_zero_point);
|
| 413 |
+
veci1 = vec_add(veci1, vec_zero_point);
|
| 414 |
+
veci2 = vec_add(veci2, vec_zero_point);
|
| 415 |
+
veci3 = vec_add(veci3, vec_zero_point);
|
| 416 |
+
|
| 417 |
+
veci4 = vec_add(veci4, vec_zero_point);
|
| 418 |
+
veci5 = vec_add(veci5, vec_zero_point);
|
| 419 |
+
veci6 = vec_add(veci6, vec_zero_point);
|
| 420 |
+
veci7 = vec_add(veci7, vec_zero_point);
|
| 421 |
+
|
| 422 |
+
vint16 vecshi0 = vec_packs(veci0, veci1);
|
| 423 |
+
vint16 vecshi1 = vec_packs(veci2, veci3);
|
| 424 |
+
vint16 vecshi2 = vec_packs(veci4, veci5);
|
| 425 |
+
vint16 vecshi3 = vec_packs(veci6, veci7);
|
| 426 |
+
|
| 427 |
+
vuint8 vec0 = vec_packsu(vecshi0, vecshi1);
|
| 428 |
+
vuint8 vec1 = vec_packsu(vecshi2, vecshi3);
|
| 429 |
+
|
| 430 |
+
return {vec0, vec1};
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
DEFINE_MEMBER_OP(operator==, c10::quint8, vec_cmpeq)
|
| 434 |
+
DEFINE_MEMBER_OP(operator!=, c10::quint8, vec_cmpne)
|
| 435 |
+
DEFINE_MEMBER_OP(operator<, c10::quint8, vec_cmplt)
|
| 436 |
+
DEFINE_MEMBER_OP(operator<=, c10::quint8, vec_cmple)
|
| 437 |
+
DEFINE_MEMBER_OP(operator>, c10::quint8, vec_cmpgt)
|
| 438 |
+
DEFINE_MEMBER_OP(operator>=, c10::quint8, vec_cmpge)
|
| 439 |
+
DEFINE_MEMBER_OP(operator+, c10::quint8, vec_add)
|
| 440 |
+
DEFINE_MEMBER_OP(operator-, c10::quint8, vec_sub)
|
| 441 |
+
DEFINE_MEMBER_OP(operator*, c10::quint8, vec_mul)
|
| 442 |
+
DEFINE_MEMBER_EMULATE_BINARY_OP(operator/, c10::quint8, /)
|
| 443 |
+
DEFINE_MEMBER_OP(maximum, c10::quint8, vec_max)
|
| 444 |
+
DEFINE_MEMBER_OP(minimum, c10::quint8, vec_min)
|
| 445 |
+
DEFINE_MEMBER_OP(operator&, c10::quint8, vec_and)
|
| 446 |
+
DEFINE_MEMBER_OP(operator|, c10::quint8, vec_or)
|
| 447 |
+
DEFINE_MEMBER_OP(operator^, c10::quint8, vec_xor)
|
| 448 |
+
};
|
| 449 |
+
|
| 450 |
+
template <>
|
| 451 |
+
Vectorized<c10::quint8> inline maximum(
|
| 452 |
+
const Vectorized<c10::quint8>& a,
|
| 453 |
+
const Vectorized<c10::quint8>& b) {
|
| 454 |
+
return a.maximum(b);
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
template <>
|
| 458 |
+
Vectorized<c10::quint8> inline minimum(
|
| 459 |
+
const Vectorized<c10::quint8>& a,
|
| 460 |
+
const Vectorized<c10::quint8>& b) {
|
| 461 |
+
return a.minimum(b);
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
template <>
|
| 465 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE operator+(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 466 |
+
return Vectorized<c10::quint8>{vec_add(a.vec0(), b.vec0()), vec_add(a.vec1(), b.vec1())};
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
template <>
|
| 470 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE operator-(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 471 |
+
return Vectorized<c10::quint8>{vec_sub(a.vec0(), b.vec0()), vec_sub(a.vec1(), b.vec1())};
|
| 472 |
+
}
|
| 473 |
+
|
| 474 |
+
template <>
|
| 475 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE operator*(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 476 |
+
return Vectorized<c10::quint8>{vec_mul(a.vec0(), b.vec0()), vec_mul(a.vec1(), b.vec1())};
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
template <>
|
| 480 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE operator/(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 481 |
+
return Vectorized<c10::quint8>{a.vec0()/b.vec0(), a.vec1()/b.vec1()};
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
template <>
|
| 485 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE operator&(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 486 |
+
return Vectorized<c10::quint8>{vec_and(a.vec0(), b.vec0()), vec_and(a.vec1(), b.vec1())};
|
| 487 |
+
}
|
| 488 |
+
|
| 489 |
+
template <>
|
| 490 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE operator|(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 491 |
+
return Vectorized<c10::quint8>{vec_or(a.vec0(), b.vec0()), vec_or(a.vec1(), b.vec1())};
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
template <>
|
| 495 |
+
Vectorized<c10::quint8> C10_ALWAYS_INLINE operator^(const Vectorized<c10::quint8>& a, const Vectorized<c10::quint8>& b) {
|
| 496 |
+
return Vectorized<c10::quint8>{vec_xor(a.vec0(), b.vec0()), vec_xor(a.vec1(), b.vec1())};
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
} // namespace
|
| 500 |
+
} // namespace vec
|
| 501 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vsx_helpers.h
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include <cstdint>
|
| 3 |
+
#include <c10/macros/Macros.h>
|
| 4 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 5 |
+
|
| 6 |
+
#if defined(__clang__)
|
| 7 |
+
typedef __vector __bool char vbool8;
|
| 8 |
+
typedef __vector __bool short vbool16;
|
| 9 |
+
typedef __vector __bool int vbool32;
|
| 10 |
+
typedef __vector __bool long long vbool64;
|
| 11 |
+
using vint8 = __attribute__((vector_size(16))) signed char;
|
| 12 |
+
using vint16 = __attribute__((vector_size(16))) signed short;
|
| 13 |
+
using vint32 = __attribute__((vector_size(16))) signed int;
|
| 14 |
+
using vint64 = __attribute__((vector_size(16))) signed long long;
|
| 15 |
+
using vuint8 = __attribute__((vector_size(16))) unsigned char;
|
| 16 |
+
using vuint16 = __attribute__((vector_size(16))) unsigned short;
|
| 17 |
+
using vuint32 = __attribute__((vector_size(16))) unsigned int;
|
| 18 |
+
using vuint64 = __attribute__((vector_size(16))) unsigned long long;
|
| 19 |
+
using vfloat32 = __attribute__((vector_size(16))) float;
|
| 20 |
+
using vfloat64 = __attribute__((vector_size(16))) double;
|
| 21 |
+
#else
|
| 22 |
+
using vbool8 = __attribute__((altivec(vector__))) __attribute__((altivec(bool__))) char;
|
| 23 |
+
using vbool16 = __attribute__((altivec(vector__))) __attribute__((altivec(bool__))) short;
|
| 24 |
+
using vbool32 = __attribute__((altivec(vector__))) __attribute__((altivec(bool__))) int;
|
| 25 |
+
using vbool64 = __attribute__((altivec(vector__))) __attribute__((altivec(bool__))) long long;
|
| 26 |
+
using vint8 = __attribute__((altivec(vector__))) signed char;
|
| 27 |
+
using vint16 = __attribute__((altivec(vector__))) signed short;
|
| 28 |
+
using vint32 = __attribute__((altivec(vector__))) signed int;
|
| 29 |
+
using vint64 = __attribute__((altivec(vector__))) signed long long;
|
| 30 |
+
using vuint8 = __attribute__((altivec(vector__))) unsigned char;
|
| 31 |
+
using vuint16 = __attribute__((altivec(vector__))) unsigned short;
|
| 32 |
+
using vuint32 = __attribute__((altivec(vector__))) unsigned int;
|
| 33 |
+
using vuint64 = __attribute__((altivec(vector__))) unsigned long long;
|
| 34 |
+
using vfloat32 = __attribute__((altivec(vector__))) float;
|
| 35 |
+
using vfloat64 = __attribute__((altivec(vector__))) double;
|
| 36 |
+
#endif
|
| 37 |
+
|
| 38 |
+
#if !defined(vec_float)
|
| 39 |
+
C10_ALWAYS_INLINE vfloat32 vec_float(const vint32& vec_in) {
|
| 40 |
+
vfloat32 vec_out;
|
| 41 |
+
__asm__("xvcvsxwsp %x0,%x1" : "=wf"(vec_out) : "wa"(vec_in));
|
| 42 |
+
return vec_out;
|
| 43 |
+
}
|
| 44 |
+
#endif
|
| 45 |
+
|
| 46 |
+
#if !defined(vec_signed)
|
| 47 |
+
C10_ALWAYS_INLINE vint32 vec_signed(const vfloat32& vec_in) {
|
| 48 |
+
vint32 vec_out;
|
| 49 |
+
__asm__("xvcvspsxws %x0,%x1" : "=wa"(vec_out) : "wf"(vec_in));
|
| 50 |
+
return vec_out;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
C10_ALWAYS_INLINE vint64 vec_signed(const vfloat64& vec_in) {
|
| 54 |
+
vint64 vec_out;
|
| 55 |
+
__asm__("xvcvdpsxds %x0,%x1" : "=wa"(vec_out) : "wd"(vec_in));
|
| 56 |
+
return vec_out;
|
| 57 |
+
}
|
| 58 |
+
#endif
|
| 59 |
+
|
| 60 |
+
#if !defined(vec_neg)
|
| 61 |
+
C10_ALWAYS_INLINE vfloat32 vec_neg(const vfloat32& vec_in) {
|
| 62 |
+
vfloat32 vec_out;
|
| 63 |
+
__asm__("xvnegsp %x0,%x1" : "=wf"(vec_out) : "wf"(vec_in));
|
| 64 |
+
return vec_out;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
C10_ALWAYS_INLINE vfloat64 vec_neg(const vfloat64& vec_in) {
|
| 68 |
+
vfloat64 vec_out;
|
| 69 |
+
__asm__("xvnegdp %x0,%x1" : "=wd"(vec_out) : "wd"(vec_in));
|
| 70 |
+
return vec_out;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
C10_ALWAYS_INLINE vint16 vec_neg(const vint16& vec_in) {
|
| 74 |
+
vint16 vint0 = {0, 0, 0, 0 ,0, 0, 0, 0};
|
| 75 |
+
return vec_vsubuhm(vint0, vec_in);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
C10_ALWAYS_INLINE vint32 vec_neg(const vint32& vec_in) {
|
| 79 |
+
vint32 vint0 = {0, 0, 0, 0};
|
| 80 |
+
return vec_vsubuwm(vint0, vec_in);
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
C10_ALWAYS_INLINE vint64 vec_neg(const vint64& vec_in) {
|
| 84 |
+
return -vec_in;
|
| 85 |
+
}
|
| 86 |
+
#endif
|
| 87 |
+
|
| 88 |
+
#if !defined(vec_sldw)
|
| 89 |
+
template <unsigned int C>
|
| 90 |
+
C10_ALWAYS_INLINE vfloat32
|
| 91 |
+
vec_sldw_aux(const vfloat32& vec_in0, const vfloat32& vec_in1) {
|
| 92 |
+
vfloat32 vec_out;
|
| 93 |
+
__asm("xxsldwi %x0, %x1, %x2, %3 "
|
| 94 |
+
: "=wa"(vec_out)
|
| 95 |
+
: "wa"(vec_in0), "wa"(vec_in1), "I"(C));
|
| 96 |
+
return vec_out;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
#define vec_sldw(a, b, c) vec_sldw_aux<c>(a, b)
|
| 100 |
+
#endif
|
| 101 |
+
|
| 102 |
+
#define vec_not(a) vec_nor(a, a)
|
| 103 |
+
#if defined(__clang__) && !defined(vec_splats)
|
| 104 |
+
C10_ALWAYS_INLINE vint64 vec_splats(const int64_t& a) {
|
| 105 |
+
return vec_splats(a);
|
| 106 |
+
}
|
| 107 |
+
#endif
|
| 108 |
+
// Vectorized min/max which return a if any operand is nan
|
| 109 |
+
template <class T>
|
| 110 |
+
C10_ALWAYS_INLINE T vec_min_nan(const T& a, const T& b) {
|
| 111 |
+
return vec_min(a, b);
|
| 112 |
+
}
|
| 113 |
+
template <class T>
|
| 114 |
+
C10_ALWAYS_INLINE T vec_max_nan(const T& a, const T& b) {
|
| 115 |
+
return vec_max(a, b);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
// Specializations for float/double taken from Eigen
|
| 119 |
+
template<>
|
| 120 |
+
C10_ALWAYS_INLINE vfloat32 vec_min_nan<vfloat32>(const vfloat32& a, const vfloat32& b)
|
| 121 |
+
{
|
| 122 |
+
// NOTE: about 10% slower than vec_min, but consistent with std::min and SSE regarding NaN
|
| 123 |
+
vfloat32 ret;
|
| 124 |
+
__asm__ ("xvcmpgesp %x0,%x1,%x2\n\txxsel %x0,%x1,%x2,%x0" : "=&wa" (ret) : "wa" (a), "wa" (b));
|
| 125 |
+
return ret;
|
| 126 |
+
}
|
| 127 |
+
// Specializations for float/double taken from Eigen
|
| 128 |
+
template<>
|
| 129 |
+
C10_ALWAYS_INLINE vfloat32 vec_max_nan<vfloat32>(const vfloat32& a, const vfloat32& b)
|
| 130 |
+
{
|
| 131 |
+
// NOTE: about 10% slower than vec_max, but consistent with std::min and SSE regarding NaN
|
| 132 |
+
vfloat32 ret;
|
| 133 |
+
__asm__ ("xvcmpgtsp %x0,%x2,%x1\n\txxsel %x0,%x1,%x2,%x0" : "=&wa" (ret) : "wa" (a), "wa" (b));
|
| 134 |
+
return ret;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
template<>
|
| 138 |
+
C10_ALWAYS_INLINE vfloat64 vec_min_nan<vfloat64>(const vfloat64& a, const vfloat64& b)
|
| 139 |
+
{
|
| 140 |
+
// NOTE: about 10% slower than vec_min, but consistent with std::min and SSE regarding NaN
|
| 141 |
+
vfloat64 ret;
|
| 142 |
+
__asm__ ("xvcmpgedp %x0,%x1,%x2\n\txxsel %x0,%x1,%x2,%x0" : "=&wa" (ret) : "wa" (a), "wa" (b));
|
| 143 |
+
return ret;
|
| 144 |
+
}
|
| 145 |
+
template<>
|
| 146 |
+
C10_ALWAYS_INLINE vfloat64 vec_max_nan<vfloat64>(const vfloat64& a, const vfloat64& b)
|
| 147 |
+
{
|
| 148 |
+
// NOTE: about 10% slower than vec_max, but consistent with std::max and SSE regarding NaN
|
| 149 |
+
vfloat64 ret;
|
| 150 |
+
__asm__ ("xvcmpgtdp %x0,%x2,%x1\n\txxsel %x0,%x1,%x2,%x0" : "=&wa" (ret) : "wa" (a), "wa" (b));
|
| 151 |
+
return ret;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
// Vectorizes min/max function which returns nan if any side is nan
|
| 155 |
+
#define C10_VSX_VEC_NAN_PROPAG(name, type, btype, func) \
|
| 156 |
+
C10_ALWAYS_INLINE type name(const type& a, const type& b) { \
|
| 157 |
+
type tmp = func(a, b); \
|
| 158 |
+
btype nan_a = vec_cmpne(a, a); \
|
| 159 |
+
btype nan_b = vec_cmpne(b, b); \
|
| 160 |
+
tmp = vec_sel(tmp, a, nan_a); \
|
| 161 |
+
return vec_sel(tmp, b, nan_b); \
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
C10_VSX_VEC_NAN_PROPAG(vec_min_nan2, vfloat32, vbool32, vec_min)
|
| 165 |
+
C10_VSX_VEC_NAN_PROPAG(vec_max_nan2, vfloat32, vbool32, vec_max)
|
| 166 |
+
C10_VSX_VEC_NAN_PROPAG(vec_min_nan2, vfloat64, vbool64, vec_min)
|
| 167 |
+
C10_VSX_VEC_NAN_PROPAG(vec_max_nan2, vfloat64, vbool64, vec_max)
|
| 168 |
+
|
| 169 |
+
#undef C10_VSX_VEC_NAN_PROPAG
|
| 170 |
+
|
| 171 |
+
#define DEFINE_MEMBER_UNARY_OP(op, op_type, func) \
|
| 172 |
+
Vectorized<op_type> C10_ALWAYS_INLINE op() const { \
|
| 173 |
+
return Vectorized<op_type>{func(_vec0), func(_vec1)}; \
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
#define DEFINE_MEMBER_OP(op, op_type, func) \
|
| 177 |
+
Vectorized<op_type> C10_ALWAYS_INLINE op(const Vectorized<op_type>& other) const { \
|
| 178 |
+
return Vectorized<op_type>{ \
|
| 179 |
+
func(_vec0, other._vec0), func(_vec1, other._vec1)}; \
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
#define DEFINE_MEMBER_BITWISE_OP(op, op_type, func) \
|
| 183 |
+
Vectorized<op_type> C10_ALWAYS_INLINE op(const Vectorized<op_type>& other) const { \
|
| 184 |
+
return Vectorized<op_type>{ \
|
| 185 |
+
func(_vecb0, other._vecb0), func(_vecb1, other._vecb1)}; \
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
#define DEFINE_MEMBER_TERNARY_OP(op, op_type, func) \
|
| 189 |
+
Vectorized<op_type> C10_ALWAYS_INLINE op( \
|
| 190 |
+
const Vectorized<op_type>& b, const Vectorized<op_type>& c) const { \
|
| 191 |
+
return Vectorized<op_type>{ \
|
| 192 |
+
func(_vec0, b._vec0, c._vec0), func(_vec1, b._vec1, c._vec1)}; \
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
#define DEFINE_MEMBER_EMULATE_BINARY_OP(op, op_type, binary_op) \
|
| 196 |
+
Vectorized<op_type> C10_ALWAYS_INLINE op(const Vectorized<op_type>& b) const { \
|
| 197 |
+
Vectorized<op_type>::vec_internal_type ret_0; \
|
| 198 |
+
Vectorized<op_type>::vec_internal_type ret_1; \
|
| 199 |
+
for (int i = 0; i < Vectorized<op_type>::size() / 2; i++) { \
|
| 200 |
+
ret_0[i] = _vec0[i] binary_op b._vec0[i]; \
|
| 201 |
+
ret_1[i] = _vec1[i] binary_op b._vec1[i]; \
|
| 202 |
+
} \
|
| 203 |
+
return Vectorized<op_type>{ret_0, ret_1}; \
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
#define DEFINE_MEMBER_OP_AND_ONE(op, op_type, func) \
|
| 208 |
+
Vectorized<op_type> C10_ALWAYS_INLINE op(const Vectorized<op_type>& other) const { \
|
| 209 |
+
using vvtype = Vectorized<op_type>::vec_internal_type; \
|
| 210 |
+
const vvtype v_one = vec_splats(static_cast<op_type>(1.0)); \
|
| 211 |
+
vvtype ret0 = (vvtype)func(_vec0, other._vec0); \
|
| 212 |
+
vvtype ret1 = (vvtype)func(_vec1, other._vec1); \
|
| 213 |
+
return Vectorized<op_type>{vec_and(ret0, v_one), vec_and(ret1, v_one)}; \
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
#define DEFINE_CLAMP_FUNCS(operand_type) \
|
| 217 |
+
template <> \
|
| 218 |
+
Vectorized<operand_type> C10_ALWAYS_INLINE clamp( \
|
| 219 |
+
const Vectorized<operand_type>& a, \
|
| 220 |
+
const Vectorized<operand_type>& min, \
|
| 221 |
+
const Vectorized<operand_type>& max) { \
|
| 222 |
+
return Vectorized<operand_type>{ \
|
| 223 |
+
vec_min_nan(vec_max_nan(a.vec0(), min.vec0()), max.vec0()), \
|
| 224 |
+
vec_min_nan(vec_max_nan(a.vec1(), min.vec1()), max.vec1())}; \
|
| 225 |
+
} \
|
| 226 |
+
template <> \
|
| 227 |
+
Vectorized<operand_type> C10_ALWAYS_INLINE clamp_min( \
|
| 228 |
+
const Vectorized<operand_type>& a, const Vectorized<operand_type>& min) { \
|
| 229 |
+
return Vectorized<operand_type>{ \
|
| 230 |
+
vec_max_nan(a.vec0(), min.vec0()), \
|
| 231 |
+
vec_max_nan(a.vec1(), min.vec1())}; \
|
| 232 |
+
} \
|
| 233 |
+
template <> \
|
| 234 |
+
Vectorized<operand_type> C10_ALWAYS_INLINE clamp_max( \
|
| 235 |
+
const Vectorized<operand_type>& a, const Vectorized<operand_type>& max) { \
|
| 236 |
+
return Vectorized<operand_type>{ \
|
| 237 |
+
vec_min_nan(a.vec0(), max.vec0()), \
|
| 238 |
+
vec_min_nan(a.vec1(), max.vec1())}; \
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
#define DEFINE_REINTERPRET_CAST_FUNCS( \
|
| 242 |
+
first_type, cast_type, cast_inner_vector_type) \
|
| 243 |
+
template <> \
|
| 244 |
+
C10_ALWAYS_INLINE Vectorized<cast_type> cast<cast_type, first_type>( \
|
| 245 |
+
const Vectorized<first_type>& src) { \
|
| 246 |
+
return Vectorized<cast_type>{(cast_inner_vector_type)src.vec0(), \
|
| 247 |
+
(cast_inner_vector_type)src.vec1()}; \
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
#define DEFINE_REINTERPRET_CAST_TO_ALL_FUNCS(first_type) \
|
| 251 |
+
DEFINE_REINTERPRET_CAST_FUNCS(first_type, double, vfloat64) \
|
| 252 |
+
DEFINE_REINTERPRET_CAST_FUNCS(first_type, float, vfloat32) \
|
| 253 |
+
DEFINE_REINTERPRET_CAST_FUNCS(first_type, int64_t, vint64) \
|
| 254 |
+
DEFINE_REINTERPRET_CAST_FUNCS(first_type, int32_t, vint32) \
|
| 255 |
+
DEFINE_REINTERPRET_CAST_FUNCS(first_type, int16_t, vint16)
|
| 256 |
+
|
| 257 |
+
// it can be used to emulate blend faster
|
| 258 |
+
constexpr int blendChoice(uint32_t mask, uint32_t half1 = 0xF, uint32_t half2 = 0xF0) {
|
| 259 |
+
uint32_t none = 0;
|
| 260 |
+
uint32_t both = half1 | half2;
|
| 261 |
+
// clamp it between 0 and both
|
| 262 |
+
mask = mask & both;
|
| 263 |
+
// return (a._vec0, a._vec1)
|
| 264 |
+
if (mask == none) return 0;
|
| 265 |
+
// return (b._vec0,b._vec1)
|
| 266 |
+
else if (mask == both)
|
| 267 |
+
return 1;
|
| 268 |
+
// return (b._vec0,a._vec1)
|
| 269 |
+
else if (mask == half1)
|
| 270 |
+
return 2;
|
| 271 |
+
// return (a._vec0,b._vec1)
|
| 272 |
+
else if (mask == half2)
|
| 273 |
+
return 3;
|
| 274 |
+
// return (*_vec0,a._vec1)
|
| 275 |
+
else if (mask > 0 && mask < half1)
|
| 276 |
+
return 4;
|
| 277 |
+
// return (*_vec0,b._vec1)
|
| 278 |
+
else if ((mask & half2) == half2)
|
| 279 |
+
return 5;
|
| 280 |
+
// return (a._vec0,*_vec1)
|
| 281 |
+
else if ((mask & half1) == 0 && mask > half1)
|
| 282 |
+
return 6;
|
| 283 |
+
// return (b._vec0,*_vec1)
|
| 284 |
+
else if ((mask & half1) == half1 && mask > half1)
|
| 285 |
+
return 7;
|
| 286 |
+
// return (*_vec0,*_vec1)
|
| 287 |
+
return 8;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
// it can be used to emulate blend faster
|
| 291 |
+
constexpr int blendChoiceDbl(uint32_t mask) {
|
| 292 |
+
// clamp it 0 and 0xF
|
| 293 |
+
return blendChoice(mask, 0x3, 0xC);
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
constexpr vbool32 VsxMask1(uint32_t mask) {
|
| 297 |
+
uint32_t g0 = (mask & 1) * 0xffffffff;
|
| 298 |
+
uint32_t g1 = ((mask & 2) >> 1) * 0xffffffff;
|
| 299 |
+
uint32_t g2 = ((mask & 4) >> 2) * 0xffffffff;
|
| 300 |
+
uint32_t g3 = ((mask & 8) >> 3) * 0xffffffff;
|
| 301 |
+
return (vbool32){g0, g1, g2, g3};
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
constexpr vbool32 VsxMask2(uint32_t mask) {
|
| 305 |
+
uint32_t mask2 = (mask & 0xFF) >> 4;
|
| 306 |
+
return VsxMask1(mask2);
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
constexpr vbool64 VsxDblMask1(uint32_t mask) {
|
| 310 |
+
uint64_t g0 = (mask & 1) * 0xffffffffffffffff;
|
| 311 |
+
uint64_t g1 = ((mask & 2) >> 1) * 0xffffffffffffffff;
|
| 312 |
+
return (vbool64){g0, g1};
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
constexpr vbool64 VsxDblMask2(uint32_t mask) {
|
| 316 |
+
uint32_t mask2 = (mask & 0xF) >> 2;
|
| 317 |
+
return VsxDblMask1(mask2);
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
constexpr int maskForComplex(uint32_t mask) {
|
| 321 |
+
mask = mask & 0xF;
|
| 322 |
+
int complex_mask = 0;
|
| 323 |
+
if (mask & 1) complex_mask |= 3;
|
| 324 |
+
if (mask & 2) complex_mask |= (3 << 2);
|
| 325 |
+
if (mask & 4) complex_mask |= (3 << 4);
|
| 326 |
+
if (mask & 8) complex_mask |= (3 << 6);
|
| 327 |
+
return complex_mask;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
constexpr int maskForComplexDbl(uint32_t mask) {
|
| 331 |
+
mask = mask & 0x3;
|
| 332 |
+
int complex_mask = 0;
|
| 333 |
+
if (mask & 1) complex_mask |= 3;
|
| 334 |
+
if (mask & 2) complex_mask |= (3 << 2);
|
| 335 |
+
return complex_mask;
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
constexpr int blendChoiceComplex(uint32_t mask) {
|
| 339 |
+
return blendChoice(maskForComplex(mask));
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
constexpr int blendChoiceComplexDbl(uint32_t mask) {
|
| 343 |
+
return blendChoiceDbl(maskForComplexDbl(mask));
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
constexpr vbool32 VsxComplexMask1(uint32_t mask) {
|
| 347 |
+
return VsxMask1(maskForComplex(mask));
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
constexpr vbool32 VsxComplexMask2(uint32_t mask) {
|
| 351 |
+
uint32_t mask2 = (mask & 0xF) >> 2;
|
| 352 |
+
return VsxMask1(maskForComplex(mask2));
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
constexpr vbool64 VsxComplexDblMask1(uint32_t mask) { return VsxDblMask1(mask); }
|
| 356 |
+
|
| 357 |
+
constexpr vbool64 VsxComplexDblMask2(uint32_t mask) {
|
| 358 |
+
uint32_t mask2 = (mask & 0xF) >> 2;
|
| 359 |
+
return VsxDblMask1(mask2);
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
// constants
|
| 363 |
+
namespace at {
|
| 364 |
+
namespace vec {
|
| 365 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 366 |
+
inline namespace CPU_CAPABILITY {
|
| 367 |
+
//
|
| 368 |
+
constexpr int offset0 = 0;
|
| 369 |
+
constexpr int offset16 = 16;
|
| 370 |
+
|
| 371 |
+
// #Constants
|
| 372 |
+
const vuint8 mask_zero_bits = vuint8{128, 128, 128, 128, 128, 128, 128, 128,
|
| 373 |
+
128, 128, 128, 128, 96, 64, 32, 0};
|
| 374 |
+
|
| 375 |
+
const vuint8 swap_mask =
|
| 376 |
+
vuint8{4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11};
|
| 377 |
+
|
| 378 |
+
const vint32 v0x7f = vec_splats(0x7f);
|
| 379 |
+
const vint32 vi_0 = vec_splats((int)(0));
|
| 380 |
+
const vint32 vi_1 = vec_splats((int)1);
|
| 381 |
+
const vint32 vi_2 = vec_splats((int)2);
|
| 382 |
+
const vint32 vi_4 = vec_splats((int)4);
|
| 383 |
+
const vint32 vi_inv1 = vec_splats((int)~1);
|
| 384 |
+
const vuint32 vu_29 = vec_splats(29u);
|
| 385 |
+
const vuint32 vu_23 = vec_splats(23u);
|
| 386 |
+
|
| 387 |
+
const vbool32 inv_mant_mask = (vbool32)vec_splats((unsigned int)~0xff800000);
|
| 388 |
+
const vbool32 sign_mask = (vbool32)vec_splats((int)0x80000000);
|
| 389 |
+
const vbool32 real_mask = vbool32{0xFFFFFFFF, 0x0, 0xFFFFFFFF, 0x0};
|
| 390 |
+
const vbool32 imag_mask = vbool32{0x0, 0xFFFFFFFF, 0x0, 0xFFFFFFFF};
|
| 391 |
+
const vbool32 isign_mask = vbool32{0x0, 0x80000000, 0x0, 0x80000000};
|
| 392 |
+
const vbool32 rsign_mask = vbool32{0x80000000, 0x0, 0x80000000, 0x0};
|
| 393 |
+
|
| 394 |
+
const vbool64 vd_sign_mask = vbool64{0x8000000000000000, 0x8000000000000000};
|
| 395 |
+
const vbool64 vd_imag_mask = vbool64{0x0, 0xFFFFFFFFFFFFFFFF};
|
| 396 |
+
const vbool64 vd_real_mask = vbool64{0xFFFFFFFFFFFFFFFF, 0x0};
|
| 397 |
+
const vbool64 vd_isign_mask = vbool64{0x0, 0x8000000000000000};
|
| 398 |
+
const vbool64 vd_rsign_mask = vbool64{0x8000000000000000, 0x0};
|
| 399 |
+
|
| 400 |
+
const vfloat32 zero = vec_splats(0.f);
|
| 401 |
+
const vfloat32 half = vec_splats(0.5f);
|
| 402 |
+
const vfloat32 one = vec_splats(1.f);
|
| 403 |
+
const vfloat32 two = vec_splats(2.0f);
|
| 404 |
+
const vfloat32 _4div_pi = vec_splats(1.27323954473516f);
|
| 405 |
+
const vfloat32 v_inf = (vfloat32)vec_splats(0x7f800000u);
|
| 406 |
+
const vfloat32 v_minus_inf = vfloat32{ 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u };
|
| 407 |
+
const vfloat32 v_nan = (vfloat32)vec_splats(0x7fffffff);
|
| 408 |
+
const vfloat32 log10e_inv = vec_splats(0.43429448190325176f);
|
| 409 |
+
const vfloat32 log2e_inv = vec_splats(1.4426950408889634f);
|
| 410 |
+
const vfloat32 log2eB_inv = vec_splats(1.442695036924675f);
|
| 411 |
+
const vfloat32 cephes_SQRTHF = vec_splats(0.707106781186547524f);
|
| 412 |
+
const vfloat32 coscof_p0 = vec_splats(2.443315711809948E-005f);
|
| 413 |
+
const vfloat32 coscof_p1 = vec_splats(-1.388731625493765E-003f);
|
| 414 |
+
const vfloat32 coscof_p2 = vec_splats(4.166664568298827E-002f);
|
| 415 |
+
const vfloat32 exp_hi = vec_splats(104.f);
|
| 416 |
+
const vfloat32 exp_lo = vec_splats(-104.f);
|
| 417 |
+
const vfloat32 exp_p0 = vec_splats(0.000198527617612853646278381f);
|
| 418 |
+
const vfloat32 exp_p1 = vec_splats((0.00139304355252534151077271f));
|
| 419 |
+
const vfloat32 exp_p2 = vec_splats(0.00833336077630519866943359f);
|
| 420 |
+
const vfloat32 exp_p3 = vec_splats(0.0416664853692054748535156f);
|
| 421 |
+
const vfloat32 exp_p4 = vec_splats(0.166666671633720397949219f);
|
| 422 |
+
const vfloat32 exp_p5 = vec_splats(0.5f);
|
| 423 |
+
const vfloat32 log_p0 = vec_splats(7.0376836292E-2f);
|
| 424 |
+
const vfloat32 log_p1 = vec_splats(-1.1514610310E-1f);
|
| 425 |
+
const vfloat32 log_p2 = vec_splats(1.1676998740E-1f);
|
| 426 |
+
const vfloat32 log_p3 = vec_splats(-1.2420140846E-1f);
|
| 427 |
+
const vfloat32 log_p4 = vec_splats(+1.4249322787E-1f);
|
| 428 |
+
const vfloat32 log_p5 = vec_splats(-1.6668057665E-1f);
|
| 429 |
+
const vfloat32 log_p6 = vec_splats(+2.0000714765E-1f);
|
| 430 |
+
const vfloat32 log_p7 = vec_splats(-2.4999993993E-1f);
|
| 431 |
+
const vfloat32 log_p8 = vec_splats(+3.3333331174E-1f);
|
| 432 |
+
const vfloat32 log_q1 = vec_splats(-2.12194440e-4f);
|
| 433 |
+
const vfloat32 log_q2 = vec_splats(0.693359375f);
|
| 434 |
+
const vfloat32 max_logf = vec_splats(88.02969187150841f);
|
| 435 |
+
const vfloat32 max_numf = vec_splats(1.7014117331926442990585209174225846272e38f);
|
| 436 |
+
const vfloat32 min_inf = (vfloat32)vec_splats(0xff800000u);
|
| 437 |
+
const vfloat32 min_norm_pos = (vfloat32)vec_splats(0x0800000u);
|
| 438 |
+
const vfloat32 minus_cephes_dp1 = vec_splats(-0.78515625f);
|
| 439 |
+
const vfloat32 minus_cephes_dp2 = vec_splats(-2.4187564849853515625e-4f);
|
| 440 |
+
const vfloat32 minus_cephes_dp3 = vec_splats(-3.77489497744594108e-8f);
|
| 441 |
+
const vfloat32 negln2f_hi = vec_splats(-0.693145751953125f);
|
| 442 |
+
const vfloat32 negln2f_lo = vec_splats(-1.428606765330187045e-06f);
|
| 443 |
+
const vfloat32 p0 = vec_splats(2.03721912945E-4f);
|
| 444 |
+
const vfloat32 p1 = vec_splats(8.33028376239E-3f);
|
| 445 |
+
const vfloat32 p2 = vec_splats(1.66667160211E-1f);
|
| 446 |
+
const vfloat32 sincof_p0 = vec_splats(-1.9515295891E-4f);
|
| 447 |
+
const vfloat32 sincof_p1 = vec_splats(8.3321608736E-3f);
|
| 448 |
+
const vfloat32 sincof_p2 = vec_splats(-1.6666654611E-1f);
|
| 449 |
+
const vfloat32 tanh_0p625 = vec_splats(0.625f);
|
| 450 |
+
const vfloat32 tanh_half_max = vec_splats(44.014845935754205f);
|
| 451 |
+
const vfloat32 tanh_p0 = vec_splats(-5.70498872745E-3f);
|
| 452 |
+
const vfloat32 tanh_p1 = vec_splats(2.06390887954E-2f);
|
| 453 |
+
const vfloat32 tanh_p2 = vec_splats(-5.37397155531E-2f);
|
| 454 |
+
const vfloat32 tanh_p3 = vec_splats(1.33314422036E-1f);
|
| 455 |
+
const vfloat32 tanh_p4 = vec_splats(-3.33332819422E-1f);
|
| 456 |
+
const vfloat32 vcheck = vec_splats((float)(1LL << 24));
|
| 457 |
+
const vfloat32 imag_one = vfloat32{0.f, 1.f, 0.f, 1.f};
|
| 458 |
+
const vfloat32 imag_half = vfloat32{0.f, 0.5f, 0.f, 0.5f};
|
| 459 |
+
const vfloat32 sqrt2_2 = vfloat32{0.70710676908493042f, 0.70710676908493042,
|
| 460 |
+
0.70710676908493042, 0.70710676908493042};
|
| 461 |
+
const vfloat32 pi_2 = vfloat32{M_PI / 2, 0.0, M_PI / 2, 0.0};
|
| 462 |
+
const vfloat32 vf_89 = vfloat32{89.f, 89.f, 89.f, 89.f};
|
| 463 |
+
const vfloat64 vd_one = vec_splats(1.0);
|
| 464 |
+
const vfloat64 vd_zero = vec_splats(0.0);
|
| 465 |
+
const vfloat64 vd_log10e_inv = vec_splats(0.43429448190325176);
|
| 466 |
+
const vfloat64 vd_log2e_inv = vec_splats(1.4426950408889634);
|
| 467 |
+
const vfloat64 vd_imag_one = vfloat64{0.0, 1.0};
|
| 468 |
+
const vfloat64 vd_imag_half = vfloat64{0.0, 0.5};
|
| 469 |
+
const vfloat64 vd_sqrt2_2 = vfloat64{0.70710678118654757, 0.70710678118654757};
|
| 470 |
+
const vfloat64 vd_pi_2 = vfloat64{M_PI / 2.0, 0.0};
|
| 471 |
+
|
| 472 |
+
} // namespace
|
| 473 |
+
} // namespace vec
|
| 474 |
+
} // namespace at
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/zarch/vec256_zarch.h
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512.h
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
|
| 8 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 9 |
+
#include <ATen/cpu/vec/vec512/vec512_float.h>
|
| 10 |
+
#include <ATen/cpu/vec/vec512/vec512_bfloat16.h>
|
| 11 |
+
#include <ATen/cpu/vec/vec512/vec512_double.h>
|
| 12 |
+
#include <ATen/cpu/vec/vec512/vec512_int.h>
|
| 13 |
+
#include <ATen/cpu/vec/vec512/vec512_qint.h>
|
| 14 |
+
#include <ATen/cpu/vec/vec512/vec512_complex_float.h>
|
| 15 |
+
#include <ATen/cpu/vec/vec512/vec512_complex_double.h>
|
| 16 |
+
#include <ATen/cpu/vec/vec512/vec512_convert.h>
|
| 17 |
+
#include <ATen/cpu/vec/vec512/vec512_mask.h>
|
| 18 |
+
|
| 19 |
+
#include <algorithm>
|
| 20 |
+
#include <cstddef>
|
| 21 |
+
#include <cstdint>
|
| 22 |
+
#include <cstring>
|
| 23 |
+
#include <ostream>
|
| 24 |
+
|
| 25 |
+
namespace at {
|
| 26 |
+
namespace vec {
|
| 27 |
+
|
| 28 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 29 |
+
inline namespace CPU_CAPABILITY {
|
| 30 |
+
|
| 31 |
+
inline std::ostream& operator<<(std::ostream& stream, const c10::qint32& val) {
|
| 32 |
+
stream << val.val_;
|
| 33 |
+
return stream;
|
| 34 |
+
}
|
| 35 |
+
inline std::ostream& operator<<(std::ostream& stream, const c10::qint8& val) {
|
| 36 |
+
stream << static_cast<int>(val.val_);
|
| 37 |
+
return stream;
|
| 38 |
+
}
|
| 39 |
+
inline std::ostream& operator<<(std::ostream& stream, const c10::quint8& val) {
|
| 40 |
+
stream << static_cast<unsigned int>(val.val_);
|
| 41 |
+
return stream;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
template <typename T>
|
| 45 |
+
std::ostream& operator<<(std::ostream& stream, const Vectorized<T>& vec) {
|
| 46 |
+
T buf[Vectorized<T>::size()];
|
| 47 |
+
vec.store(buf);
|
| 48 |
+
stream << "vec[";
|
| 49 |
+
for (int i = 0; i != Vectorized<T>::size(); i++) {
|
| 50 |
+
if (i != 0) {
|
| 51 |
+
stream << ", ";
|
| 52 |
+
}
|
| 53 |
+
stream << buf[i];
|
| 54 |
+
}
|
| 55 |
+
stream << "]";
|
| 56 |
+
return stream;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 61 |
+
|
| 62 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CAST (AVX512) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 63 |
+
|
| 64 |
+
template<>
|
| 65 |
+
inline Vectorized<float> cast<float, double>(const Vectorized<double>& src) {
|
| 66 |
+
return _mm512_castpd_ps(src);
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
template<>
|
| 70 |
+
inline Vectorized<double> cast<double, float>(const Vectorized<float>& src) {
|
| 71 |
+
return _mm512_castps_pd(src);
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
template<>
|
| 75 |
+
inline Vectorized<float> cast<float, int32_t>(const Vectorized<int32_t>& src) {
|
| 76 |
+
return _mm512_castsi512_ps(src);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
template<>
|
| 80 |
+
inline Vectorized<double> cast<double, int64_t>(const Vectorized<int64_t>& src) {
|
| 81 |
+
return _mm512_castsi512_pd(src);
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GATHER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 85 |
+
#ifndef _MSC_VER
|
| 86 |
+
// MSVC is not working well on complex function overload.
|
| 87 |
+
template<int64_t scale = 1>
|
| 88 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<double>>
|
| 89 |
+
inline gather(const double* base_addr, const Vectorized<int64_t>& vindex) {
|
| 90 |
+
return _mm512_i64gather_pd(vindex, base_addr, scale);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
template<int64_t scale = 1>
|
| 94 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<float>>
|
| 95 |
+
inline gather(const float* base_addr, const Vectorized<int32_t>& vindex) {
|
| 96 |
+
return _mm512_i32gather_ps(vindex, base_addr, scale);
|
| 97 |
+
}
|
| 98 |
+
#endif
|
| 99 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MASK GATHER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 100 |
+
#ifndef _MSC_VER
|
| 101 |
+
// MSVC is not working well on complex function overload.
|
| 102 |
+
template<int64_t scale = 1>
|
| 103 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<double>>
|
| 104 |
+
inline mask_gather(const Vectorized<double>& src, const double* base_addr,
|
| 105 |
+
const Vectorized<int64_t>& vindex, Vectorized<double>& mask) {
|
| 106 |
+
auto all_ones = _mm512_castsi512_pd(_mm512_set1_epi64(0xFFFFFFFFFFFFFFFF));
|
| 107 |
+
auto mask_ = _mm512_cmp_pd_mask(all_ones, mask.values, _CMP_EQ_OQ);
|
| 108 |
+
return _mm512_mask_i64gather_pd(src, mask_, vindex, base_addr, scale);
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
template<int64_t scale = 1>
|
| 112 |
+
std::enable_if_t<scale == 1 || scale == 2 || scale == 4 || scale == 8, Vectorized<float>>
|
| 113 |
+
inline mask_gather(const Vectorized<float>& src, const float* base_addr,
|
| 114 |
+
const Vectorized<int32_t>& vindex, Vectorized<float>& mask) {
|
| 115 |
+
auto all_ones = _mm512_castsi512_ps(_mm512_set1_epi32(0xFFFFFFFF));
|
| 116 |
+
auto mask_ = _mm512_cmp_ps_mask(all_ones, mask.values, _CMP_EQ_OQ);
|
| 117 |
+
return _mm512_mask_i32gather_ps(src, mask_, vindex, base_addr, scale);
|
| 118 |
+
}
|
| 119 |
+
#endif
|
| 120 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CONVERT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 121 |
+
|
| 122 |
+
template<>
|
| 123 |
+
Vectorized<int64_t>
|
| 124 |
+
inline convert_to_int_of_same_size<double>(const Vectorized<double> &src) {
|
| 125 |
+
return _mm512_cvtpd_epi64(src);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
template<>
|
| 129 |
+
Vectorized<int32_t>
|
| 130 |
+
inline convert_to_int_of_same_size<float>(const Vectorized<float> &src) {
|
| 131 |
+
return _mm512_cvttps_epi32(src);
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
template<>
|
| 135 |
+
Vectorized<double>
|
| 136 |
+
inline convert_to_fp_of_same_size<double>(const Vectorized<int64_t> &src) {
|
| 137 |
+
return _mm512_cvtepi64_pd(src);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
template<>
|
| 141 |
+
Vectorized<float>
|
| 142 |
+
inline convert_to_fp_of_same_size<float>(const Vectorized<int32_t> &src) {
|
| 143 |
+
return _mm512_cvtepi32_ps(src);
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTERLEAVE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 147 |
+
|
| 148 |
+
template <>
|
| 149 |
+
std::pair<Vectorized<double>, Vectorized<double>>
|
| 150 |
+
inline interleave2<double>(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 151 |
+
// inputs:
|
| 152 |
+
// a = {a0, a1, a3, a3, a4, a5, a6, a7}
|
| 153 |
+
// b = {b0, b1, b2, b3, b4, b5, b6, b7}
|
| 154 |
+
// group cols crossing lanes:
|
| 155 |
+
// return {a0, b0, a1, b1, a2, b2, a3, b3}
|
| 156 |
+
// {a4, b4, a5, b5, a6, b6, a7, b7}
|
| 157 |
+
__m512i idx1 = _mm512_set_epi64(11, 3, 10, 2, 9, 1, 8, 0);
|
| 158 |
+
__m512i idx2 = _mm512_set_epi64(15, 7, 14, 6, 13, 5, 12, 4);
|
| 159 |
+
return std::make_pair(_mm512_mask_permutex2var_pd(a, 0xff, idx1, b),
|
| 160 |
+
_mm512_mask_permutex2var_pd(a, 0xff, idx2, b));
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
template <>
|
| 164 |
+
std::pair<Vectorized<float>, Vectorized<float>>
|
| 165 |
+
inline interleave2<float>(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 166 |
+
// inputs:
|
| 167 |
+
// a = {a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15}
|
| 168 |
+
// b = {b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15}
|
| 169 |
+
//
|
| 170 |
+
// return:
|
| 171 |
+
// {a0, b0, a1, b1, a2, b2, a3, b3, a4, b4, a5, b5, a6, b6, a7, b7}
|
| 172 |
+
// {a8, b8, a9, b9, a10, b10, a11, b11, a12, b12, a13, b13, a14, b14, a15, b15}
|
| 173 |
+
__m512i idx1 = _mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4,
|
| 174 |
+
19, 3, 18, 2, 17, 1, 16, 0);
|
| 175 |
+
__m512i idx2 = _mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12,
|
| 176 |
+
27, 11, 26, 10, 25, 9, 24, 8);
|
| 177 |
+
return std::make_pair(_mm512_mask_permutex2var_ps(a, 0xffff, idx1, b),
|
| 178 |
+
_mm512_mask_permutex2var_ps(a, 0xffff, idx2, b));
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEINTERLEAVE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 182 |
+
|
| 183 |
+
template <>
|
| 184 |
+
std::pair<Vectorized<double>, Vectorized<double>>
|
| 185 |
+
inline deinterleave2<double>(const Vectorized<double>& a, const Vectorized<double>& b) {
|
| 186 |
+
// inputs:
|
| 187 |
+
// a = {a0, b0, a1, b1, a2, b2, a3, b3}
|
| 188 |
+
// b = {a4, b4, a5, b5, a6, b6, a7, b7}
|
| 189 |
+
// output:
|
| 190 |
+
// return {a0, a1, a2, a3, a4, a5, a6, a7}
|
| 191 |
+
// {b0, b1, b2, b3, b4, b5, b6, b7}
|
| 192 |
+
// The members of indices have been written in binary format for better understandability
|
| 193 |
+
__m512i idx1 = _mm512_set_epi64(14, 12, 10, 8, 6, 4, 2, 0);
|
| 194 |
+
__m512i idx2 = _mm512_set_epi64(15, 13, 11, 9, 7, 5, 3, 1);
|
| 195 |
+
|
| 196 |
+
return std::make_pair(_mm512_mask_permutex2var_pd(a, 0xff, idx1, b),
|
| 197 |
+
_mm512_mask_permutex2var_pd(a, 0xff, idx2, b));
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
template <>
|
| 201 |
+
std::pair<Vectorized<float>, Vectorized<float>>
|
| 202 |
+
inline deinterleave2<float>(const Vectorized<float>& a, const Vectorized<float>& b) {
|
| 203 |
+
// inputs:
|
| 204 |
+
// a = {a0, b0, a1, b1, a2, b2, a3, b3, a4, b4, a5, b5, a6, b6, a7, b7}
|
| 205 |
+
// b = {a8, b8, a9, b9, a10, b10, a11, b11, a12, b12, a13, b13, a14, b14, a15, b15}
|
| 206 |
+
// output:
|
| 207 |
+
// return {a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15}
|
| 208 |
+
// {b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15}
|
| 209 |
+
__m512i idx1 = _mm512_set_epi32(30, 28, 26, 24, 22, 20, 18, 16,
|
| 210 |
+
14, 12, 10, 8, 6, 4, 2, 0);
|
| 211 |
+
__m512i idx2 = _mm512_set_epi32(31, 29, 27, 25, 23, 21, 19, 17,
|
| 212 |
+
15, 13, 11, 9, 7, 5, 3, 1);
|
| 213 |
+
|
| 214 |
+
return std::make_pair(_mm512_mask_permutex2var_ps(a, 0xffff, idx1, b),
|
| 215 |
+
_mm512_mask_permutex2var_ps(a, 0xffff, idx2, b));
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLIP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 219 |
+
|
| 220 |
+
template<>
|
| 221 |
+
inline Vectorized<float> flip(const Vectorized<float> & v) {
|
| 222 |
+
const __m512i mask = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7,
|
| 223 |
+
8, 9, 10, 11, 12, 13, 14, 15);
|
| 224 |
+
return _mm512_permutexvar_ps(mask, v);
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
template<>
|
| 228 |
+
inline Vectorized<double> flip(const Vectorized<double> & v) {
|
| 229 |
+
const __m512i mask = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7);
|
| 230 |
+
return _mm512_permutexvar_pd(mask, v);
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
template<>
|
| 234 |
+
inline Vectorized<int64_t> flip(const Vectorized<int64_t> & v) {
|
| 235 |
+
const __m512i mask = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7);
|
| 236 |
+
return _mm512_permutexvar_epi64(mask, v);
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
template<>
|
| 240 |
+
inline Vectorized<int32_t> flip(const Vectorized<int32_t> & v) {
|
| 241 |
+
const __m512i mask = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7,
|
| 242 |
+
8, 9, 10, 11, 12, 13, 14, 15);
|
| 243 |
+
return _mm512_permutexvar_epi32(mask, v);
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
template<>
|
| 247 |
+
inline Vectorized<int16_t> flip(const Vectorized<int16_t> & v) {
|
| 248 |
+
const __m512i mask = _mm512_set_epi16(
|
| 249 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
| 250 |
+
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
|
| 251 |
+
);
|
| 252 |
+
return _mm512_permutexvar_epi16(mask, v);
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
inline __m512i flip8(const __m512i & v) {
|
| 256 |
+
const __m512i mask1 = _mm512_set_epi8(
|
| 257 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
| 258 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
| 259 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
| 260 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
| 261 |
+
);
|
| 262 |
+
const __m512i mask2 = _mm512_set_epi64(1, 0, 3, 2, 5, 4, 7, 6);
|
| 263 |
+
auto reversed_vec = _mm512_shuffle_epi8(v, mask1);
|
| 264 |
+
return _mm512_permutexvar_epi64(mask2, reversed_vec);
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
template<>
|
| 268 |
+
inline Vectorized<int8_t> flip(const Vectorized<int8_t> & v) {
|
| 269 |
+
return flip8(v);
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
template<>
|
| 273 |
+
inline Vectorized<uint8_t> flip(const Vectorized<uint8_t> & v) {
|
| 274 |
+
return flip8(v);
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
inline Vectorized<bool> operator&&(
|
| 278 |
+
const Vectorized<bool>& self,
|
| 279 |
+
const Vectorized<bool>& other) {
|
| 280 |
+
const __m512i* self_ = reinterpret_cast<const __m512i*>(self.as_bytes());
|
| 281 |
+
const __m512i* other_ = reinterpret_cast<const __m512i*>(other.as_bytes());
|
| 282 |
+
__m512i out = _mm512_and_si512(*self_, *other_);
|
| 283 |
+
Vectorized<bool> ret;
|
| 284 |
+
// We do not have a constructer that takes __m512i, so we need to memcpy
|
| 285 |
+
std::memcpy(ret, &out, ret.size() * sizeof(bool));
|
| 286 |
+
return ret;
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
#endif // defined(CPU_CAPABILITY_AVX512)
|
| 290 |
+
|
| 291 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_bfloat16.h
ADDED
|
@@ -0,0 +1,1670 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 7 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 8 |
+
#include <c10/util/irange.h>
|
| 9 |
+
|
| 10 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 11 |
+
#define SLEEF_STATIC_LIBS
|
| 12 |
+
#include <sleef.h>
|
| 13 |
+
#endif
|
| 14 |
+
|
| 15 |
+
namespace at {
|
| 16 |
+
namespace vec {
|
| 17 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 18 |
+
inline namespace CPU_CAPABILITY {
|
| 19 |
+
|
| 20 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 21 |
+
|
| 22 |
+
#ifndef SLEEF_CONST
|
| 23 |
+
#if (defined(__GNUC__) || defined(__CLANG__)) && !defined(__INTEL_COMPILER)
|
| 24 |
+
#define SLEEF_CONST const
|
| 25 |
+
#else
|
| 26 |
+
#define SLEEF_CONST
|
| 27 |
+
#endif
|
| 28 |
+
#define SLEEF_CONST_OLD SLEEF_CONST
|
| 29 |
+
#else
|
| 30 |
+
#define SLEEF_CONST_OLD
|
| 31 |
+
#endif
|
| 32 |
+
|
| 33 |
+
// bfloat16 conversion
|
| 34 |
+
static inline void cvtbf16_fp32(const __m256i& a, __m512& o) {
|
| 35 |
+
o = _mm512_castsi512_ps(_mm512_slli_epi32(_mm512_cvtepu16_epi32(a), 16));
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
static inline void cvtbf16_fp32(const __m512i& a, __m512& o1, __m512& o2) {
|
| 39 |
+
__m256i lo = _mm512_extracti32x8_epi32(a, 0);
|
| 40 |
+
__m256i hi = _mm512_extracti32x8_epi32(a, 1);
|
| 41 |
+
cvtbf16_fp32(lo, o1);
|
| 42 |
+
cvtbf16_fp32(hi, o2);
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
static inline __m256i cvtfp32_bf16(const __m512& src) {
|
| 46 |
+
__m512i value = _mm512_castps_si512(src);
|
| 47 |
+
__m512i nan = _mm512_set1_epi32(0xffff);
|
| 48 |
+
auto mask_value = _mm512_cmp_ps_mask(src, src, _CMP_ORD_Q);
|
| 49 |
+
__m512i ones = _mm512_set1_epi32(0x1);
|
| 50 |
+
__m512i vec_bias = _mm512_set1_epi32(0x7fff);
|
| 51 |
+
// uint32_t lsb = (input >> 16) & 1;
|
| 52 |
+
auto t_value = _mm512_and_si512(_mm512_srli_epi32(value, 16), ones);
|
| 53 |
+
// uint32_t rounding_bias = 0x7fff + lsb;
|
| 54 |
+
t_value = _mm512_add_epi32(t_value, vec_bias);
|
| 55 |
+
// input += rounding_bias;
|
| 56 |
+
t_value = _mm512_add_epi32(t_value, value);
|
| 57 |
+
// input = input >> 16;
|
| 58 |
+
t_value = _mm512_srli_epi32(t_value, 16);
|
| 59 |
+
// Check NaN before converting back to bf16
|
| 60 |
+
t_value = _mm512_mask_blend_epi32(mask_value, nan, t_value);
|
| 61 |
+
return _mm512_cvtusepi32_epi16(t_value);
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
static inline __m512i cvtfp32_bf16(const __m512& a, const __m512& b) {
|
| 65 |
+
__m512i lo = _mm512_castps_si512(a);
|
| 66 |
+
__m512i hi = _mm512_castps_si512(b);
|
| 67 |
+
__m512i nan = _mm512_set1_epi32(0xffff);
|
| 68 |
+
auto mask_lo = _mm512_cmp_ps_mask(a, a, _CMP_ORD_Q);
|
| 69 |
+
auto mask_hi = _mm512_cmp_ps_mask(b, b, _CMP_ORD_Q);
|
| 70 |
+
__m512i ones = _mm512_set1_epi32(0x1);
|
| 71 |
+
__m512i vec_bias = _mm512_set1_epi32(0x7fff);
|
| 72 |
+
// uint32_t lsb = (input >> 16) & 1;
|
| 73 |
+
auto t_lo = _mm512_and_si512(_mm512_srli_epi32(lo, 16), ones);
|
| 74 |
+
auto t_hi = _mm512_and_si512(_mm512_srli_epi32(hi, 16), ones);
|
| 75 |
+
// uint32_t rounding_bias = 0x7fff + lsb;
|
| 76 |
+
t_lo = _mm512_add_epi32(t_lo, vec_bias);
|
| 77 |
+
t_hi = _mm512_add_epi32(t_hi, vec_bias);
|
| 78 |
+
// input += rounding_bias;
|
| 79 |
+
t_lo = _mm512_add_epi32(t_lo, lo);
|
| 80 |
+
t_hi = _mm512_add_epi32(t_hi, hi);
|
| 81 |
+
// input = input >> 16;
|
| 82 |
+
t_lo = _mm512_srli_epi32(t_lo, 16);
|
| 83 |
+
t_hi = _mm512_srli_epi32(t_hi, 16);
|
| 84 |
+
// Check NaN before converting back to bf16
|
| 85 |
+
t_lo = _mm512_mask_blend_epi32(mask_lo, nan, t_lo);
|
| 86 |
+
t_hi = _mm512_mask_blend_epi32(mask_hi, nan, t_hi);
|
| 87 |
+
|
| 88 |
+
t_lo = _mm512_packus_epi32(t_lo, t_hi); // t_hi[4-7] t_lo[4-7] t_hi[0-4] t_lo[0-4]
|
| 89 |
+
__m512i idx = _mm512_set_epi64(7, 5, 3, 1, 6, 4, 2, 0);
|
| 90 |
+
return _mm512_permutexvar_epi64(idx, t_lo);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
static inline __m512i merge_compare_result(const __m512& a, const __m512& b) {
|
| 94 |
+
__m512i lo = _mm512_castps_si512(a);
|
| 95 |
+
__m512i hi = _mm512_castps_si512(b);
|
| 96 |
+
lo = _mm512_srli_epi32(lo, 16);
|
| 97 |
+
hi = _mm512_srli_epi32(hi, 16);
|
| 98 |
+
auto out = _mm512_packus_epi32(lo, hi);
|
| 99 |
+
__m512i idx = _mm512_set_epi64(7, 5, 3, 1, 6, 4, 2, 0);
|
| 100 |
+
return _mm512_permutexvar_epi64(idx, out);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
// float16 conversion
|
| 104 |
+
static inline void cvtfp16_fp32(const __m256i& a, __m512& o) {
|
| 105 |
+
o = _mm512_cvtph_ps(a);
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
static inline void cvtfp16_fp32(const __m512i& a, __m512& o1, __m512& o2) {
|
| 109 |
+
__m256i lo = _mm512_extracti32x8_epi32(a, 0);
|
| 110 |
+
__m256i hi = _mm512_extracti32x8_epi32(a, 1);
|
| 111 |
+
cvtfp16_fp32(lo, o1);
|
| 112 |
+
cvtfp16_fp32(hi, o2);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
static inline __m256i cvtfp32_fp16(const __m512& src) {
|
| 116 |
+
return _mm512_cvtps_ph(
|
| 117 |
+
src, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
static inline __m512i cvtfp32_fp16(const __m512& a, const __m512& b) {
|
| 121 |
+
__m256i lo = _mm512_cvtps_ph(
|
| 122 |
+
a, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 123 |
+
__m256i hi = _mm512_cvtps_ph(
|
| 124 |
+
b, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 125 |
+
__m512 t_lo = _mm512_castsi512_ps(_mm512_castsi256_si512(lo));
|
| 126 |
+
__m256 t_hi = _mm256_castsi256_ps(hi);
|
| 127 |
+
return _mm512_castps_si512(_mm512_insertf32x8(t_lo, t_hi, 1));
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
// dtype conversion between float16/bfloat16 and float32
|
| 131 |
+
template <typename T, typename std::enable_if_t<is_reduced_floating_point_v<T>, int> = 0>
|
| 132 |
+
inline void cvt_to_fp32(const __m256i& a, __m512& o);
|
| 133 |
+
template <> inline void cvt_to_fp32<BFloat16>(const __m256i& a, __m512& o) {
|
| 134 |
+
cvtbf16_fp32(a, o);
|
| 135 |
+
}
|
| 136 |
+
template <> inline void cvt_to_fp32<Half>(const __m256i& a, __m512& o) {
|
| 137 |
+
cvtfp16_fp32(a, o);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
template <typename T, typename std::enable_if_t<is_reduced_floating_point_v<T>, int> = 0>
|
| 141 |
+
inline void cvt_to_fp32(const __m512i& a, __m512& o1, __m512& o2);
|
| 142 |
+
template <> inline void cvt_to_fp32<BFloat16>(const __m512i& a, __m512& o1, __m512& o2) {
|
| 143 |
+
cvtbf16_fp32(a, o1, o2);
|
| 144 |
+
}
|
| 145 |
+
template <> inline void cvt_to_fp32<Half>(const __m512i& a, __m512& o1, __m512& o2) {
|
| 146 |
+
cvtfp16_fp32(a, o1, o2);
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
template <typename T, bool is_compare_op = false,
|
| 150 |
+
typename std::enable_if_t<is_reduced_floating_point_v<T>, int> = 0>
|
| 151 |
+
inline __m512i cvt_from_fp32(const __m512& a, const __m512& b);
|
| 152 |
+
template <> inline __m512i cvt_from_fp32<BFloat16, false>(const __m512& a, const __m512& b) {
|
| 153 |
+
return cvtfp32_bf16(a, b);
|
| 154 |
+
}
|
| 155 |
+
template <> inline __m512i cvt_from_fp32<BFloat16, true>(const __m512& a, const __m512& b) {
|
| 156 |
+
return merge_compare_result(a, b);
|
| 157 |
+
}
|
| 158 |
+
template <> inline __m512i cvt_from_fp32<Half, false>(const __m512& a, const __m512& b) {
|
| 159 |
+
return cvtfp32_fp16(a, b);
|
| 160 |
+
}
|
| 161 |
+
template <> inline __m512i cvt_from_fp32<Half, true>(const __m512& a, const __m512& b) {
|
| 162 |
+
return cvtfp32_fp16(a, b);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
template <typename T>
|
| 166 |
+
class Vectorized16 {
|
| 167 |
+
static_assert(
|
| 168 |
+
is_reduced_floating_point_v<T>,
|
| 169 |
+
"Support only float16 and bfloat16.");
|
| 170 |
+
private:
|
| 171 |
+
__m512i values;
|
| 172 |
+
public:
|
| 173 |
+
using value_type = uint16_t;
|
| 174 |
+
using size_type = int;
|
| 175 |
+
static constexpr size_type size() {
|
| 176 |
+
return 32;
|
| 177 |
+
}
|
| 178 |
+
Vectorized16() {}
|
| 179 |
+
Vectorized16(__m512i v) : values(v) {}
|
| 180 |
+
Vectorized16(T val) {
|
| 181 |
+
value_type uw = val.x;
|
| 182 |
+
values = _mm512_set1_epi16(uw);
|
| 183 |
+
}
|
| 184 |
+
Vectorized16(T val1, T val2, T val3, T val4,
|
| 185 |
+
T val5, T val6, T val7, T val8,
|
| 186 |
+
T val9, T val10, T val11, T val12,
|
| 187 |
+
T val13, T val14, T val15, T val16,
|
| 188 |
+
T val17, T val18, T val19, T val20,
|
| 189 |
+
T val21, T val22, T val23, T val24,
|
| 190 |
+
T val25, T val26, T val27, T val28,
|
| 191 |
+
T val29, T val30, T val31, T val32) {
|
| 192 |
+
values = _mm512_set_epi16(
|
| 193 |
+
val32.x, val31.x, val30.x, val29.x, val28.x, val27.x, val26.x, val25.x,
|
| 194 |
+
val24.x, val23.x, val22.x, val21.x, val20.x, val19.x, val18.x, val17.x,
|
| 195 |
+
val16.x, val15.x, val14.x, val13.x, val12.x, val11.x, val10.x, val9.x,
|
| 196 |
+
val8.x, val7.x, val6.x, val5.x, val4.x, val3.x, val2.x, val1.x);
|
| 197 |
+
}
|
| 198 |
+
operator __m512i() const {
|
| 199 |
+
return values;
|
| 200 |
+
}
|
| 201 |
+
T& operator[](int idx) = delete;
|
| 202 |
+
const T& operator[](int idx) const = delete;
|
| 203 |
+
int zero_mask() const {
|
| 204 |
+
// returns an integer mask where all zero elements are translated to 1-bit and others are translated to 0-bit
|
| 205 |
+
return _mm512_cmpeq_epi16_mask(values, _mm512_set1_epi16(0));
|
| 206 |
+
}
|
| 207 |
+
static Vectorized<T> loadu(const void* ptr, int16_t count = size()) {
|
| 208 |
+
if (count == size())
|
| 209 |
+
return _mm512_loadu_si512(reinterpret_cast<const __m512i*>(ptr));
|
| 210 |
+
|
| 211 |
+
__mmask32 mask = (1ULL << count) - 1;
|
| 212 |
+
return _mm512_maskz_loadu_epi16(mask, ptr);
|
| 213 |
+
}
|
| 214 |
+
void store(void* ptr, int count = size()) const {
|
| 215 |
+
if (count == size()) {
|
| 216 |
+
_mm512_storeu_si512(reinterpret_cast<__m512i*>(ptr), values);
|
| 217 |
+
} else if (count > 0) {
|
| 218 |
+
__mmask32 mask = (1ULL << count) - 1;
|
| 219 |
+
_mm512_mask_storeu_epi16(ptr, mask, values);
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
template <int64_t mask>
|
| 223 |
+
static Vectorized<T> blend(const Vectorized<T>& a, const Vectorized<T>& b) {
|
| 224 |
+
return _mm512_mask_blend_epi16(mask, a.values, b.values);
|
| 225 |
+
}
|
| 226 |
+
static Vectorized<T> blendv(const Vectorized<T>& a,
|
| 227 |
+
const Vectorized<T>& b, const Vectorized<T>& mask) {
|
| 228 |
+
auto all_ones = _mm512_set1_epi16(0xFFFF);
|
| 229 |
+
auto mask_ = _mm512_cmp_epi16_mask(mask, all_ones, _MM_CMPINT_EQ);
|
| 230 |
+
return _mm512_mask_blend_epi16(mask_, a.values, b.values);
|
| 231 |
+
}
|
| 232 |
+
template<typename step_t>
|
| 233 |
+
static Vectorized<T> arange(T base = 0.f, step_t step = static_cast<step_t>(1)) {
|
| 234 |
+
return Vectorized<T>(
|
| 235 |
+
base, base + step, base + 2 * step, base + 3 * step,
|
| 236 |
+
base + 4 * step, base + 5 * step, base + 6 * step, base + 7 * step,
|
| 237 |
+
base + 8 * step, base + 9 * step, base + 10 * step, base + 11 * step,
|
| 238 |
+
base + 12 * step, base + 13 * step, base + 14 * step, base + 15 * step,
|
| 239 |
+
base + 16 * step, base + 17 * step, base + 18 * step, base + 19 * step,
|
| 240 |
+
base + 20 * step, base + 21 * step, base + 22 * step, base + 23 * step,
|
| 241 |
+
base + 24 * step, base + 25 * step, base + 26 * step, base + 27 * step,
|
| 242 |
+
base + 28 * step, base + 29 * step, base + 30 * step, base + 31 * step);
|
| 243 |
+
}
|
| 244 |
+
static Vectorized<T> set(const Vectorized<T>& a,
|
| 245 |
+
const Vectorized<T>& b, int64_t count = size()) {
|
| 246 |
+
switch (count) {
|
| 247 |
+
case 0:
|
| 248 |
+
return a;
|
| 249 |
+
case 1:
|
| 250 |
+
return blend<1>(a, b);
|
| 251 |
+
case 2:
|
| 252 |
+
return blend<3>(a, b);
|
| 253 |
+
case 3:
|
| 254 |
+
return blend<7>(a, b);
|
| 255 |
+
case 4:
|
| 256 |
+
return blend<15>(a, b);
|
| 257 |
+
case 5:
|
| 258 |
+
return blend<31>(a, b);
|
| 259 |
+
case 6:
|
| 260 |
+
return blend<63>(a, b);
|
| 261 |
+
case 7:
|
| 262 |
+
return blend<127>(a, b);
|
| 263 |
+
case 8:
|
| 264 |
+
return blend<255>(a, b);
|
| 265 |
+
case 9:
|
| 266 |
+
return blend<511>(a, b);
|
| 267 |
+
case 10:
|
| 268 |
+
return blend<1023>(a, b);
|
| 269 |
+
case 11:
|
| 270 |
+
return blend<2047>(a, b);
|
| 271 |
+
case 12:
|
| 272 |
+
return blend<4095>(a, b);
|
| 273 |
+
case 13:
|
| 274 |
+
return blend<8191>(a, b);
|
| 275 |
+
case 14:
|
| 276 |
+
return blend<16383>(a, b);
|
| 277 |
+
case 15:
|
| 278 |
+
return blend<32767>(a, b);
|
| 279 |
+
case 16:
|
| 280 |
+
return blend<65535>(a, b);
|
| 281 |
+
case 17:
|
| 282 |
+
return blend<131071>(a, b);
|
| 283 |
+
case 18:
|
| 284 |
+
return blend<262143>(a, b);
|
| 285 |
+
case 19:
|
| 286 |
+
return blend<524287>(a, b);
|
| 287 |
+
case 20:
|
| 288 |
+
return blend<1048575>(a, b);
|
| 289 |
+
case 21:
|
| 290 |
+
return blend<2097151>(a, b);
|
| 291 |
+
case 22:
|
| 292 |
+
return blend<4194303>(a, b);
|
| 293 |
+
case 23:
|
| 294 |
+
return blend<8388607>(a, b);
|
| 295 |
+
case 24:
|
| 296 |
+
return blend<16777215>(a, b);
|
| 297 |
+
case 25:
|
| 298 |
+
return blend<33554431>(a, b);
|
| 299 |
+
case 26:
|
| 300 |
+
return blend<67108863>(a, b);
|
| 301 |
+
case 27:
|
| 302 |
+
return blend<134217727>(a, b);
|
| 303 |
+
case 28:
|
| 304 |
+
return blend<268435455>(a, b);
|
| 305 |
+
case 29:
|
| 306 |
+
return blend<536870911>(a, b);
|
| 307 |
+
case 30:
|
| 308 |
+
return blend<1073741823>(a, b);
|
| 309 |
+
case 31:
|
| 310 |
+
return blend<2147483647>(a, b);
|
| 311 |
+
}
|
| 312 |
+
return b;
|
| 313 |
+
}
|
| 314 |
+
#pragma clang diagnostic push
|
| 315 |
+
#pragma clang diagnostic ignored "-Wignored-qualifiers"
|
| 316 |
+
|
| 317 |
+
Vectorized<T> map(SLEEF_CONST __m512 (*SLEEF_CONST_OLD vop)(__m512)) const {
|
| 318 |
+
__m512 lo, hi;
|
| 319 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 320 |
+
const auto o1 = vop(lo);
|
| 321 |
+
const auto o2 = vop(hi);
|
| 322 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 323 |
+
}
|
| 324 |
+
Vectorized<T> isnan() const {
|
| 325 |
+
__m512 lo, hi;
|
| 326 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 327 |
+
__mmask16 lo_mask, hi_mask;
|
| 328 |
+
__m512 zero = _mm512_set1_ps(0.0);
|
| 329 |
+
__m512i zeroi = _mm512_castps_si512(zero);
|
| 330 |
+
lo_mask = _mm512_cmp_ps_mask(lo, zero, _CMP_UNORD_Q);
|
| 331 |
+
lo = _mm512_castsi512_ps(_mm512_mask_set1_epi32(zeroi, lo_mask, 0xFFFF'FFFF));
|
| 332 |
+
hi_mask = _mm512_cmp_ps_mask(hi, zero, _CMP_UNORD_Q);
|
| 333 |
+
hi = _mm512_castsi512_ps(_mm512_mask_set1_epi32(zeroi, hi_mask, 0xFFFF'FFFF));
|
| 334 |
+
return merge_compare_result(lo, hi);
|
| 335 |
+
}
|
| 336 |
+
#pragma clang diagnostic pop
|
| 337 |
+
Vectorized<T> abs() const {
|
| 338 |
+
return _mm512_andnot_si512(_mm512_set1_epi16(0x8000), values);
|
| 339 |
+
}
|
| 340 |
+
Vectorized<T> angle() const {
|
| 341 |
+
__m512 lo, hi;
|
| 342 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 343 |
+
auto angle_lambda = [](__m512 values) {
|
| 344 |
+
const auto zero_vec = _mm512_set1_ps(0.f);
|
| 345 |
+
const auto nan_vec = _mm512_set1_ps(NAN);
|
| 346 |
+
const auto not_nan_mask = _mm512_cmp_ps_mask(values, values, _CMP_EQ_OQ);
|
| 347 |
+
const auto non_nan_mask_vec = _mm512_mask_set1_epi32(_mm512_castps_si512(zero_vec),
|
| 348 |
+
not_nan_mask, 0xFFFFFFFF);
|
| 349 |
+
const auto nan_mask = _mm512_cmp_ps_mask(_mm512_castsi512_ps(non_nan_mask_vec),
|
| 350 |
+
zero_vec, _CMP_EQ_OQ);
|
| 351 |
+
const auto pi = _mm512_set1_ps(c10::pi<float>);
|
| 352 |
+
|
| 353 |
+
const auto neg_mask = _mm512_cmp_ps_mask(values, zero_vec, _CMP_LT_OQ);
|
| 354 |
+
auto angle = _mm512_mask_blend_ps(neg_mask, zero_vec, pi);
|
| 355 |
+
angle = _mm512_mask_blend_ps(nan_mask, angle, nan_vec);
|
| 356 |
+
return angle;
|
| 357 |
+
};
|
| 358 |
+
auto o1 = angle_lambda(lo);
|
| 359 |
+
auto o2 = angle_lambda(hi);
|
| 360 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 361 |
+
}
|
| 362 |
+
Vectorized<T> real() const {
|
| 363 |
+
return *this;
|
| 364 |
+
}
|
| 365 |
+
Vectorized<T> imag() const {
|
| 366 |
+
return _mm512_set1_epi16(0);
|
| 367 |
+
}
|
| 368 |
+
Vectorized<T> conj() const {
|
| 369 |
+
return *this;
|
| 370 |
+
}
|
| 371 |
+
Vectorized<T> acos() const {
|
| 372 |
+
return map(Sleef_acosf16_u10);
|
| 373 |
+
}
|
| 374 |
+
Vectorized<T> acosh() const {
|
| 375 |
+
return map(Sleef_acoshf16_u10);
|
| 376 |
+
}
|
| 377 |
+
Vectorized<T> asin() const {
|
| 378 |
+
return map(Sleef_asinf16_u10);
|
| 379 |
+
}
|
| 380 |
+
Vectorized<T> atan() const {
|
| 381 |
+
return map(Sleef_atanf16_u10);
|
| 382 |
+
}
|
| 383 |
+
Vectorized<T> atanh() const {
|
| 384 |
+
return map(Sleef_atanhf16_u10);
|
| 385 |
+
}
|
| 386 |
+
Vectorized<T> atan2(const Vectorized<T> &b) const {
|
| 387 |
+
__m512 lo, hi;
|
| 388 |
+
__m512 b1, b2;
|
| 389 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 390 |
+
cvt_to_fp32<T>(b.values, b1, b2);
|
| 391 |
+
auto o1 = Sleef_atan2f16_u10(lo, b1);
|
| 392 |
+
auto o2 = Sleef_atan2f16_u10(hi, b2);
|
| 393 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 394 |
+
}
|
| 395 |
+
Vectorized<T> copysign(const Vectorized<T> &sign) const {
|
| 396 |
+
// copy sign bit (0x8000) from sign and remaining bits from values
|
| 397 |
+
__m512i mask_value = _mm512_set1_epi32(~0x80008000);
|
| 398 |
+
__m512i mask_signbit = _mm512_set1_epi32(0x80008000);
|
| 399 |
+
return Vectorized<T>(
|
| 400 |
+
_mm512_or_si512(
|
| 401 |
+
_mm512_and_si512(values, mask_value),
|
| 402 |
+
_mm512_and_si512(sign, mask_signbit)));
|
| 403 |
+
}
|
| 404 |
+
Vectorized<T> erf() const {
|
| 405 |
+
return map(Sleef_erff16_u10);
|
| 406 |
+
}
|
| 407 |
+
Vectorized<T> erfc() const {
|
| 408 |
+
return map(Sleef_erfcf16_u15);
|
| 409 |
+
}
|
| 410 |
+
Vectorized<T> erfinv() const {
|
| 411 |
+
__m512 lo, hi;
|
| 412 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 413 |
+
__at_align__ float tmp1[size() / 2], tmp2[size() / 2];
|
| 414 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 415 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 416 |
+
for (int64_t i = 0; i < size() / 2; i++) {
|
| 417 |
+
tmp1[i] = calc_erfinv(tmp1[i]);
|
| 418 |
+
tmp2[i] = calc_erfinv(tmp2[i]);
|
| 419 |
+
}
|
| 420 |
+
auto o1 = _mm512_loadu_ps(tmp1);
|
| 421 |
+
auto o2 = _mm512_loadu_ps(tmp2);
|
| 422 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 423 |
+
}
|
| 424 |
+
Vectorized<T> exp() const {
|
| 425 |
+
return map(Sleef_expf16_u10);
|
| 426 |
+
}
|
| 427 |
+
Vectorized<T> exp2() const {
|
| 428 |
+
return map(Sleef_exp2f16_u10);
|
| 429 |
+
}
|
| 430 |
+
Vectorized<T> expm1() const {
|
| 431 |
+
return map(Sleef_expm1f16_u10);
|
| 432 |
+
}
|
| 433 |
+
Vectorized<T> exp_u20() const {
|
| 434 |
+
return exp();
|
| 435 |
+
}
|
| 436 |
+
Vectorized<T> fmod(const Vectorized<T> & q) const {
|
| 437 |
+
__m512 x_lo, x_hi;
|
| 438 |
+
cvt_to_fp32<T>(values, x_lo, x_hi);
|
| 439 |
+
__m512 q_lo, q_hi;
|
| 440 |
+
cvtbf16_fp32(q.values, q_lo, q_hi);
|
| 441 |
+
auto o1 = Sleef_fmodf16(x_lo, q_lo);
|
| 442 |
+
auto o2 = Sleef_fmodf16(x_hi, q_hi);
|
| 443 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 444 |
+
}
|
| 445 |
+
Vectorized<T> hypot(const Vectorized<T> &b) const {
|
| 446 |
+
__m512 lo, hi;
|
| 447 |
+
__m512 b1, b2;
|
| 448 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 449 |
+
cvt_to_fp32<T>(b.values, b1, b2);
|
| 450 |
+
auto o1 = Sleef_hypotf16_u05(lo, b1);
|
| 451 |
+
auto o2 = Sleef_hypotf16_u05(hi, b2);
|
| 452 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 453 |
+
}
|
| 454 |
+
Vectorized<T> i0() const {
|
| 455 |
+
__m512 lo, hi;
|
| 456 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 457 |
+
__at_align__ float tmp1[size() / 2], tmp2[size() / 2];
|
| 458 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 459 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 460 |
+
for (int64_t i = 0; i < size() / 2; i++) {
|
| 461 |
+
tmp1[i] = calc_i0(tmp1[i]);
|
| 462 |
+
tmp2[i] = calc_i0(tmp2[i]);
|
| 463 |
+
}
|
| 464 |
+
auto o1 = _mm512_loadu_ps(tmp1);
|
| 465 |
+
auto o2 = _mm512_loadu_ps(tmp2);
|
| 466 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 467 |
+
}
|
| 468 |
+
Vectorized<T> i0e() const {
|
| 469 |
+
__m512 lo, hi;
|
| 470 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 471 |
+
constexpr auto sz = size();
|
| 472 |
+
__at_align__ float tmp1[sz / 2], tmp2[sz / 2];
|
| 473 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 474 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 475 |
+
|
| 476 |
+
for (auto i = decltype(sz){0}; i < sz / 2; i++) {
|
| 477 |
+
tmp1[i] = calc_i0e(tmp1[i]);
|
| 478 |
+
tmp2[i] = calc_i0e(tmp2[i]);
|
| 479 |
+
}
|
| 480 |
+
const auto o1 = _mm512_loadu_ps(tmp1);
|
| 481 |
+
const auto o2 = _mm512_loadu_ps(tmp2);
|
| 482 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 483 |
+
}
|
| 484 |
+
Vectorized<T> digamma() const {
|
| 485 |
+
__m512 lo, hi;
|
| 486 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 487 |
+
constexpr auto sz = size();
|
| 488 |
+
__at_align__ float tmp1[sz / 2], tmp2[sz / 2];
|
| 489 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 490 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 491 |
+
|
| 492 |
+
for (auto i = decltype(sz){0}; i < sz / 2; i++) {
|
| 493 |
+
tmp1[i] = calc_digamma(tmp1[i]);
|
| 494 |
+
tmp2[i] = calc_digamma(tmp2[i]);
|
| 495 |
+
}
|
| 496 |
+
const auto o1 = _mm512_loadu_ps(tmp1);
|
| 497 |
+
const auto o2 = _mm512_loadu_ps(tmp2);
|
| 498 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 499 |
+
}
|
| 500 |
+
Vectorized<T> igamma(const Vectorized<T> &x) const {
|
| 501 |
+
__m512 lo, hi;
|
| 502 |
+
__m512 xlo, xhi;
|
| 503 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 504 |
+
cvt_to_fp32<T>(x.values, xlo, xhi);
|
| 505 |
+
__at_align__ float tmp1[size() / 2], tmp2[size() / 2];
|
| 506 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 507 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 508 |
+
__at_align__ float tmpx1[size() / 2], tmpx2[size() / 2];
|
| 509 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmpx1), xlo);
|
| 510 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmpx2), xhi);
|
| 511 |
+
for (int64_t i = 0; i < size() / 2; ++i) {
|
| 512 |
+
tmp1[i] = calc_igamma(tmp1[i], tmpx1[i]);
|
| 513 |
+
tmp2[i] = calc_igamma(tmp2[i], tmpx2[i]);
|
| 514 |
+
}
|
| 515 |
+
auto o1 = _mm512_loadu_ps(tmp1);
|
| 516 |
+
auto o2 = _mm512_loadu_ps(tmp2);
|
| 517 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 518 |
+
}
|
| 519 |
+
|
| 520 |
+
Vectorized<T> igammac(const Vectorized<T> &x) const {
|
| 521 |
+
__m512 lo, hi;
|
| 522 |
+
__m512 xlo, xhi;
|
| 523 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 524 |
+
cvt_to_fp32<T>(x.values, xlo, xhi);
|
| 525 |
+
__at_align__ float tmp1[size() / 2], tmp2[size() / 2];
|
| 526 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp1), lo);
|
| 527 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp2), hi);
|
| 528 |
+
__at_align__ float tmpx1[size() / 2], tmpx2[size() / 2];
|
| 529 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmpx1), xlo);
|
| 530 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmpx2), xhi);
|
| 531 |
+
for (int64_t i = 0; i < size() / 2; ++i) {
|
| 532 |
+
tmp1[i] = calc_igammac(tmp1[i], tmpx1[i]);
|
| 533 |
+
tmp2[i] = calc_igammac(tmp2[i], tmpx2[i]);
|
| 534 |
+
}
|
| 535 |
+
auto o1 = _mm512_loadu_ps(tmp1);
|
| 536 |
+
auto o2 = _mm512_loadu_ps(tmp2);
|
| 537 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 538 |
+
}
|
| 539 |
+
Vectorized<T> log() const {
|
| 540 |
+
return map(Sleef_logf16_u10);
|
| 541 |
+
}
|
| 542 |
+
Vectorized<T> log2() const {
|
| 543 |
+
return map(Sleef_log2f16_u10);
|
| 544 |
+
}
|
| 545 |
+
Vectorized<T> log10() const {
|
| 546 |
+
return map(Sleef_log10f16_u10);
|
| 547 |
+
}
|
| 548 |
+
Vectorized<T> log1p() const {
|
| 549 |
+
return map(Sleef_log1pf16_u10);
|
| 550 |
+
}
|
| 551 |
+
Vectorized<T> sin() const {
|
| 552 |
+
return map(Sleef_sinf16_u10);
|
| 553 |
+
}
|
| 554 |
+
Vectorized<T> sinh() const {
|
| 555 |
+
return map(Sleef_sinhf16_u10);
|
| 556 |
+
}
|
| 557 |
+
Vectorized<T> cos() const {
|
| 558 |
+
return map(Sleef_cosf16_u10);
|
| 559 |
+
}
|
| 560 |
+
Vectorized<T> cosh() const {
|
| 561 |
+
return map(Sleef_coshf16_u10);
|
| 562 |
+
}
|
| 563 |
+
Vectorized<T> ceil() const {
|
| 564 |
+
__m512 lo, hi;
|
| 565 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 566 |
+
auto o1 = _mm512_ceil_ps(lo);
|
| 567 |
+
auto o2 = _mm512_ceil_ps(hi);
|
| 568 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 569 |
+
}
|
| 570 |
+
Vectorized<T> floor() const {
|
| 571 |
+
__m512 lo, hi;
|
| 572 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 573 |
+
auto o1 = _mm512_floor_ps(lo);
|
| 574 |
+
auto o2 = _mm512_floor_ps(hi);
|
| 575 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 576 |
+
}
|
| 577 |
+
Vectorized<T> neg() const {
|
| 578 |
+
return _mm512_xor_si512(values, _mm512_set1_epi16(0x8000));
|
| 579 |
+
}
|
| 580 |
+
Vectorized<T> round() const {
|
| 581 |
+
__m512 lo, hi;
|
| 582 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 583 |
+
auto o1 = _mm512_roundscale_ps(lo, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 584 |
+
auto o2 = _mm512_roundscale_ps(hi, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 585 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 586 |
+
}
|
| 587 |
+
Vectorized<T> tan() const {
|
| 588 |
+
return map(Sleef_tanf16_u10);
|
| 589 |
+
}
|
| 590 |
+
Vectorized<T> tanh() const {
|
| 591 |
+
return map(Sleef_tanhf16_u10);
|
| 592 |
+
}
|
| 593 |
+
Vectorized<T> trunc() const {
|
| 594 |
+
__m512 lo, hi;
|
| 595 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 596 |
+
auto o1 = _mm512_roundscale_ps(lo, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 597 |
+
auto o2 = _mm512_roundscale_ps(hi, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 598 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 599 |
+
}
|
| 600 |
+
Vectorized<T> lgamma() const {
|
| 601 |
+
return map(Sleef_lgammaf16_u10);
|
| 602 |
+
}
|
| 603 |
+
Vectorized<T> sqrt() const {
|
| 604 |
+
__m512 lo, hi;
|
| 605 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 606 |
+
auto o1 = _mm512_sqrt_ps(lo);
|
| 607 |
+
auto o2 = _mm512_sqrt_ps(hi);
|
| 608 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 609 |
+
}
|
| 610 |
+
Vectorized<T> reciprocal() const {
|
| 611 |
+
__m512 lo, hi;
|
| 612 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 613 |
+
auto ones = _mm512_set1_ps(1);
|
| 614 |
+
auto o1 = _mm512_div_ps(ones, lo);
|
| 615 |
+
auto o2 = _mm512_div_ps(ones, hi);
|
| 616 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 617 |
+
}
|
| 618 |
+
Vectorized<T> rsqrt() const {
|
| 619 |
+
__m512 lo, hi;
|
| 620 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 621 |
+
auto ones = _mm512_set1_ps(1);
|
| 622 |
+
auto o1 = _mm512_div_ps(ones, _mm512_sqrt_ps(lo));
|
| 623 |
+
auto o2 = _mm512_div_ps(ones, _mm512_sqrt_ps(hi));
|
| 624 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 625 |
+
}
|
| 626 |
+
Vectorized<T> pow(const Vectorized<T> &b) const {
|
| 627 |
+
__m512 lo, hi;
|
| 628 |
+
__m512 b1, b2;
|
| 629 |
+
cvt_to_fp32<T>(values, lo, hi);
|
| 630 |
+
cvt_to_fp32<T>(b.values, b1, b2);
|
| 631 |
+
auto o1 = Sleef_powf16_u10(lo, b1);
|
| 632 |
+
auto o2 = Sleef_powf16_u10(hi, b2);
|
| 633 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 634 |
+
}
|
| 635 |
+
private:
|
| 636 |
+
template<typename Op>
|
| 637 |
+
Vectorized<T> inline binary_compare(const Vectorized<T>& b, Op op) const {
|
| 638 |
+
__m512 a_lo, a_hi;
|
| 639 |
+
__m512 b_lo, b_hi;
|
| 640 |
+
cvt_to_fp32<T>(values, a_lo, a_hi);
|
| 641 |
+
cvt_to_fp32<T>(b.values, b_lo, b_hi);
|
| 642 |
+
auto o1 = op(a_lo, b_lo);
|
| 643 |
+
auto o2 = op(a_hi, b_hi);
|
| 644 |
+
return cvt_from_fp32<T, /*is_compare_op*/true>(o1, o2);
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
+
public:
|
| 648 |
+
Vectorized<T> inline operator>(const Vectorized<T>& other) const {
|
| 649 |
+
return binary_compare(other, [](__m512 x, __m512 y) {
|
| 650 |
+
auto zero_vec = _mm512_set1_epi32(0);
|
| 651 |
+
auto cmp = _mm512_cmp_ps_mask(x, y, _CMP_GT_OQ);
|
| 652 |
+
return _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, cmp, 0xFFFFFFFF));
|
| 653 |
+
});
|
| 654 |
+
}
|
| 655 |
+
Vectorized<T> inline operator<(const Vectorized<T>& other) const {
|
| 656 |
+
return binary_compare(other, [](__m512 x, __m512 y) {
|
| 657 |
+
auto zero_vec = _mm512_set1_epi32(0);
|
| 658 |
+
auto cmp = _mm512_cmp_ps_mask(x, y, _CMP_LT_OQ);
|
| 659 |
+
return _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, cmp, 0xFFFFFFFF));
|
| 660 |
+
});
|
| 661 |
+
}
|
| 662 |
+
Vectorized<T> inline operator>=(const Vectorized<T>& other) const {
|
| 663 |
+
return binary_compare(other, [](__m512 x, __m512 y) {
|
| 664 |
+
auto zero_vec = _mm512_set1_epi32(0);
|
| 665 |
+
auto cmp = _mm512_cmp_ps_mask(x, y, _CMP_GE_OQ);
|
| 666 |
+
return _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, cmp, 0xFFFFFFFF));
|
| 667 |
+
});
|
| 668 |
+
}
|
| 669 |
+
Vectorized<T> inline operator<=(const Vectorized<T>& other) const {
|
| 670 |
+
return binary_compare(other, [](__m512 x, __m512 y) {
|
| 671 |
+
auto zero_vec = _mm512_set1_epi32(0);
|
| 672 |
+
auto cmp = _mm512_cmp_ps_mask(x, y, _CMP_LE_OQ);
|
| 673 |
+
return _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, cmp, 0xFFFFFFFF));
|
| 674 |
+
});
|
| 675 |
+
}
|
| 676 |
+
Vectorized<T> inline operator==(const Vectorized<T>& other) const {
|
| 677 |
+
return binary_compare(other, [](__m512 x, __m512 y) {
|
| 678 |
+
auto zero_vec = _mm512_set1_epi32(0);
|
| 679 |
+
auto cmp = _mm512_cmp_ps_mask(x, y, _CMP_EQ_OQ);
|
| 680 |
+
return _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, cmp, 0xFFFFFFFF));
|
| 681 |
+
});
|
| 682 |
+
}
|
| 683 |
+
Vectorized<T> inline operator!=(const Vectorized<T>& other) const {
|
| 684 |
+
return binary_compare(other, [](__m512 x, __m512 y) {
|
| 685 |
+
auto zero_vec = _mm512_set1_epi32(0);
|
| 686 |
+
auto cmp = _mm512_cmp_ps_mask(x, y, _CMP_NEQ_UQ);
|
| 687 |
+
return _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, cmp, 0xFFFFFFFF));
|
| 688 |
+
});
|
| 689 |
+
}
|
| 690 |
+
};
|
| 691 |
+
|
| 692 |
+
template<typename T, typename Op>
|
| 693 |
+
static inline Vectorized<T> binary_op_as_fp32(const Vectorized<T>& a, const Vectorized<T>& b, Op op) {
|
| 694 |
+
__m512 a_lo, a_hi;
|
| 695 |
+
__m512 b_lo, b_hi;
|
| 696 |
+
cvt_to_fp32<T>(__m512i(a), a_lo, a_hi);
|
| 697 |
+
cvt_to_fp32<T>(__m512i(b), b_lo, b_hi);
|
| 698 |
+
auto o1 = op(a_lo, b_lo);
|
| 699 |
+
auto o2 = op(a_hi, b_hi);
|
| 700 |
+
return cvt_from_fp32<T>(o1, o2);
|
| 701 |
+
}
|
| 702 |
+
|
| 703 |
+
template <>
|
| 704 |
+
class Vectorized<BFloat16>: public Vectorized16<BFloat16> {
|
| 705 |
+
public:
|
| 706 |
+
using Vectorized16::Vectorized16;
|
| 707 |
+
|
| 708 |
+
using value_type = BFloat16;
|
| 709 |
+
|
| 710 |
+
Vectorized<BFloat16> frac() const;
|
| 711 |
+
|
| 712 |
+
Vectorized<BFloat16> eq(const Vectorized<BFloat16>& other) const;
|
| 713 |
+
Vectorized<BFloat16> ne(const Vectorized<BFloat16>& other) const;
|
| 714 |
+
Vectorized<BFloat16> gt(const Vectorized<BFloat16>& other) const;
|
| 715 |
+
Vectorized<BFloat16> ge(const Vectorized<BFloat16>& other) const;
|
| 716 |
+
Vectorized<BFloat16> lt(const Vectorized<BFloat16>& other) const;
|
| 717 |
+
Vectorized<BFloat16> le(const Vectorized<BFloat16>& other) const;
|
| 718 |
+
};
|
| 719 |
+
|
| 720 |
+
Vectorized<BFloat16> inline operator+(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 721 |
+
return binary_op_as_fp32(a, b, [](const __m512& x, const __m512& y) { return _mm512_add_ps(x, y); });
|
| 722 |
+
}
|
| 723 |
+
Vectorized<BFloat16> inline operator-(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 724 |
+
return binary_op_as_fp32(a, b, [](const __m512& x, const __m512& y) { return _mm512_sub_ps(x, y); });
|
| 725 |
+
}
|
| 726 |
+
Vectorized<BFloat16> inline operator*(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 727 |
+
return binary_op_as_fp32(a, b, [](const __m512& x, const __m512& y) { return _mm512_mul_ps(x, y); });
|
| 728 |
+
}
|
| 729 |
+
Vectorized<BFloat16> inline operator/(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 730 |
+
return binary_op_as_fp32(a, b, [](const __m512& x, const __m512& y) { return _mm512_div_ps(x, y); });
|
| 731 |
+
}
|
| 732 |
+
Vectorized<BFloat16> inline operator&(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 733 |
+
return _mm512_and_si512(a, b);
|
| 734 |
+
}
|
| 735 |
+
Vectorized<BFloat16> inline operator|(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 736 |
+
return _mm512_or_si512(a, b);
|
| 737 |
+
}
|
| 738 |
+
Vectorized<BFloat16> inline operator^(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 739 |
+
return _mm512_xor_si512(a, b);
|
| 740 |
+
}
|
| 741 |
+
|
| 742 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::eq(const Vectorized<BFloat16>& other) const {
|
| 743 |
+
return (*this == other) & Vectorized<BFloat16>(1.0f);
|
| 744 |
+
}
|
| 745 |
+
|
| 746 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::ne(const Vectorized<BFloat16>& other) const {
|
| 747 |
+
return (*this != other) & Vectorized<BFloat16>(1.0f);
|
| 748 |
+
}
|
| 749 |
+
|
| 750 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::gt(const Vectorized<BFloat16>& other) const {
|
| 751 |
+
return (*this > other) & Vectorized<BFloat16>(1.0f);
|
| 752 |
+
}
|
| 753 |
+
|
| 754 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::ge(const Vectorized<BFloat16>& other) const {
|
| 755 |
+
return (*this >= other) & Vectorized<BFloat16>(1.0f);
|
| 756 |
+
}
|
| 757 |
+
|
| 758 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::lt(const Vectorized<BFloat16>& other) const {
|
| 759 |
+
return (*this < other) & Vectorized<BFloat16>(1.0f);
|
| 760 |
+
}
|
| 761 |
+
|
| 762 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::le(const Vectorized<BFloat16>& other) const {
|
| 763 |
+
return (*this <= other) & Vectorized<BFloat16>(1.0f);
|
| 764 |
+
}
|
| 765 |
+
|
| 766 |
+
// frac. Implement this here so we can use subtraction
|
| 767 |
+
inline Vectorized<BFloat16> Vectorized<BFloat16>::frac() const {
|
| 768 |
+
return *this - this->trunc();
|
| 769 |
+
}
|
| 770 |
+
|
| 771 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 772 |
+
// either input is a NaN.
|
| 773 |
+
template <>
|
| 774 |
+
Vectorized<BFloat16> inline maximum(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 775 |
+
__m512 a_lo, a_hi;
|
| 776 |
+
__m512 b_lo, b_hi;
|
| 777 |
+
cvtbf16_fp32(__m512i(a), a_lo, a_hi);
|
| 778 |
+
cvtbf16_fp32(__m512i(b), b_lo, b_hi);
|
| 779 |
+
auto max_lo = _mm512_max_ps(a_lo, b_lo);
|
| 780 |
+
auto max_hi = _mm512_max_ps(a_hi, b_hi);
|
| 781 |
+
auto nan_lo_mask = _mm512_cmp_ps_mask(a_lo, b_lo, _CMP_UNORD_Q);
|
| 782 |
+
auto nan_hi_mask = _mm512_cmp_ps_mask(a_hi, b_hi, _CMP_UNORD_Q);
|
| 783 |
+
auto nan_lo = _mm512_castsi512_ps(_mm512_set1_epi32(nan_lo_mask));
|
| 784 |
+
auto nan_hi = _mm512_castsi512_ps(_mm512_set1_epi32(nan_hi_mask));
|
| 785 |
+
// Exploit the fact that all-ones is a NaN.
|
| 786 |
+
auto o1 = _mm512_or_ps(max_lo, nan_lo);
|
| 787 |
+
auto o2 = _mm512_or_ps(max_hi, nan_hi);
|
| 788 |
+
return cvtfp32_bf16(o1, o2);
|
| 789 |
+
}
|
| 790 |
+
|
| 791 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 792 |
+
// either input is a NaN.
|
| 793 |
+
template <>
|
| 794 |
+
Vectorized<BFloat16> inline minimum(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& b) {
|
| 795 |
+
__m512 a_lo, a_hi;
|
| 796 |
+
__m512 b_lo, b_hi;
|
| 797 |
+
__m512i zero_vec = _mm512_set1_epi32(0);
|
| 798 |
+
cvtbf16_fp32(__m512i(a), a_lo, a_hi);
|
| 799 |
+
cvtbf16_fp32(__m512i(b), b_lo, b_hi);
|
| 800 |
+
auto min_lo = _mm512_min_ps(a_lo, b_lo);
|
| 801 |
+
auto min_hi = _mm512_min_ps(a_hi, b_hi);
|
| 802 |
+
auto nan_lo_mask = _mm512_cmp_ps_mask(a_lo, b_lo, _CMP_UNORD_Q);
|
| 803 |
+
auto nan_hi_mask = _mm512_cmp_ps_mask(a_hi, b_hi, _CMP_UNORD_Q);
|
| 804 |
+
auto nan_lo = _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, nan_lo_mask,
|
| 805 |
+
0xFFFFFFFF));
|
| 806 |
+
auto nan_hi = _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, nan_hi_mask,
|
| 807 |
+
0xFFFFFFFF));
|
| 808 |
+
// Exploit the fact that all-ones is a NaN.
|
| 809 |
+
auto o1 = _mm512_or_ps(min_lo, nan_lo);
|
| 810 |
+
auto o2 = _mm512_or_ps(min_hi, nan_hi);
|
| 811 |
+
return cvtfp32_bf16(o1, o2);
|
| 812 |
+
}
|
| 813 |
+
|
| 814 |
+
template <>
|
| 815 |
+
Vectorized<BFloat16> inline clamp(const Vectorized<BFloat16>& a,
|
| 816 |
+
const Vectorized<BFloat16>& min, const Vectorized<BFloat16>& max) {
|
| 817 |
+
__m512 a_lo, a_hi;
|
| 818 |
+
__m512 min_lo, min_hi;
|
| 819 |
+
__m512 max_lo, max_hi;
|
| 820 |
+
cvtbf16_fp32(__m512i(a), a_lo, a_hi);
|
| 821 |
+
cvtbf16_fp32(__m512i(min), min_lo, min_hi);
|
| 822 |
+
cvtbf16_fp32(__m512i(max), max_lo, max_hi);
|
| 823 |
+
auto o1 = _mm512_min_ps(max_lo, _mm512_max_ps(min_lo, a_lo));
|
| 824 |
+
auto o2 = _mm512_min_ps(max_hi, _mm512_max_ps(min_hi, a_hi));
|
| 825 |
+
return cvtfp32_bf16(o1, o2);
|
| 826 |
+
}
|
| 827 |
+
|
| 828 |
+
template <>
|
| 829 |
+
Vectorized<BFloat16> inline clamp_max(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& max) {
|
| 830 |
+
__m512 a_lo, a_hi;
|
| 831 |
+
__m512 max_lo, max_hi;
|
| 832 |
+
cvtbf16_fp32(__m512i(a), a_lo, a_hi);
|
| 833 |
+
cvtbf16_fp32(__m512i(max), max_lo, max_hi);
|
| 834 |
+
auto o1 = _mm512_min_ps(max_lo, a_lo);
|
| 835 |
+
auto o2 = _mm512_min_ps(max_hi, a_hi);
|
| 836 |
+
return cvtfp32_bf16(o1, o2);
|
| 837 |
+
}
|
| 838 |
+
|
| 839 |
+
template <>
|
| 840 |
+
Vectorized<BFloat16> inline clamp_min(const Vectorized<BFloat16>& a, const Vectorized<BFloat16>& min) {
|
| 841 |
+
__m512 a_lo, a_hi;
|
| 842 |
+
__m512 min_lo, min_hi;
|
| 843 |
+
cvtbf16_fp32(__m512i(a), a_lo, a_hi);
|
| 844 |
+
cvtbf16_fp32(__m512i(min), min_lo, min_hi);
|
| 845 |
+
auto o1 = _mm512_max_ps(min_lo, a_lo);
|
| 846 |
+
auto o2 = _mm512_max_ps(min_hi, a_hi);
|
| 847 |
+
return cvtfp32_bf16(o1, o2);
|
| 848 |
+
}
|
| 849 |
+
|
| 850 |
+
template <>
|
| 851 |
+
inline void convert(const BFloat16* src, BFloat16* dst, int64_t n) {
|
| 852 |
+
int64_t i;
|
| 853 |
+
#ifndef __msvc_cl__
|
| 854 |
+
#pragma unroll
|
| 855 |
+
#endif
|
| 856 |
+
for (i = 0; i <= (n - Vectorized<BFloat16>::size()); i += Vectorized<BFloat16>::size()) {
|
| 857 |
+
auto vsrc = _mm512_loadu_si512(reinterpret_cast<__m512i*>((void*)(src + i)));
|
| 858 |
+
_mm512_storeu_si512(reinterpret_cast<__m512i*>((void*)(dst + i)), vsrc);
|
| 859 |
+
}
|
| 860 |
+
#ifndef __msvc_cl__
|
| 861 |
+
#pragma unroll
|
| 862 |
+
#endif
|
| 863 |
+
for (; i < n; i++) {
|
| 864 |
+
dst[i] = src[i];
|
| 865 |
+
}
|
| 866 |
+
}
|
| 867 |
+
|
| 868 |
+
template <>
|
| 869 |
+
inline void convert(const float* src, BFloat16* dst, int64_t n) {
|
| 870 |
+
int64_t i;
|
| 871 |
+
for (i = 0; i + Vectorized<BFloat16>::size() <= n; i += Vectorized<BFloat16>::size()) {
|
| 872 |
+
__m512 a = _mm512_loadu_ps(&src[i]);
|
| 873 |
+
__m512 b = _mm512_loadu_ps(&src[i + 16]);
|
| 874 |
+
|
| 875 |
+
__m512i bf = cvtfp32_bf16(a, b);
|
| 876 |
+
_mm512_storeu_si512(reinterpret_cast<__m512i*>(&dst[i]), bf);
|
| 877 |
+
}
|
| 878 |
+
for (; i < n; i++) {
|
| 879 |
+
dst[i] = c10::convert<BFloat16>(src[i]);
|
| 880 |
+
}
|
| 881 |
+
}
|
| 882 |
+
|
| 883 |
+
template <>
|
| 884 |
+
inline void convert(const double* src, BFloat16* dst, int64_t n) {
|
| 885 |
+
auto load_float = [](const double *src) -> __m512 {
|
| 886 |
+
// Load one float vector from an array of doubles
|
| 887 |
+
__m256 a = _mm512_cvtpd_ps(_mm512_loadu_pd(src));
|
| 888 |
+
__m256 b = _mm512_cvtpd_ps(_mm512_loadu_pd(src + 8));
|
| 889 |
+
return _mm512_insertf32x8(_mm512_castps256_ps512(a), b, 1);
|
| 890 |
+
};
|
| 891 |
+
|
| 892 |
+
int64_t i;
|
| 893 |
+
for (i = 0; i + Vectorized<BFloat16>::size() <= n; i += Vectorized<BFloat16>::size()) {
|
| 894 |
+
__m512 a = load_float(&src[i]);
|
| 895 |
+
__m512 b = load_float(&src[i + 16]);
|
| 896 |
+
|
| 897 |
+
__m512i bf = cvtfp32_bf16(a, b);
|
| 898 |
+
_mm512_storeu_si512(reinterpret_cast<__m512i*>(&dst[i]), bf);
|
| 899 |
+
}
|
| 900 |
+
for (; i < n; i++) {
|
| 901 |
+
dst[i] = c10::convert<BFloat16>(src[i]);
|
| 902 |
+
}
|
| 903 |
+
}
|
| 904 |
+
|
| 905 |
+
template <>
|
| 906 |
+
Vectorized<BFloat16> inline fmadd(const Vectorized<BFloat16>& a,
|
| 907 |
+
const Vectorized<BFloat16>& b, const Vectorized<BFloat16>& c) {
|
| 908 |
+
__m512 a_lo, a_hi;
|
| 909 |
+
__m512 b_lo, b_hi;
|
| 910 |
+
__m512 c_lo, c_hi;
|
| 911 |
+
cvtbf16_fp32(__m512i(a), a_lo, a_hi);
|
| 912 |
+
cvtbf16_fp32(__m512i(b), b_lo, b_hi);
|
| 913 |
+
cvtbf16_fp32(__m512i(c), c_lo, c_hi);
|
| 914 |
+
auto o1 = _mm512_fmadd_ps(a_lo, b_lo, c_lo);
|
| 915 |
+
auto o2 = _mm512_fmadd_ps(a_hi, b_hi, c_hi);
|
| 916 |
+
return cvtfp32_bf16(o1, o2);
|
| 917 |
+
}
|
| 918 |
+
|
| 919 |
+
static inline void _transpose_mxn_half_16_16(__m256i t[], __m512i u[]) {
|
| 920 |
+
__m512i r[8];
|
| 921 |
+
// a0a1 a2a3 a4a5 a6a7 a8a9 a10a11 a12a13 a14a15 e0e1 e2e3 e4e5 e6e7 e8e9 e10e11 e12e13 e14e15
|
| 922 |
+
// b0-b15 f0-f15
|
| 923 |
+
// c0-c15 g0-g15
|
| 924 |
+
// d0-d15 h0-h15
|
| 925 |
+
// i0-i15 m0-m15
|
| 926 |
+
// j0-j15 n0-n15
|
| 927 |
+
// k0-k15 o0-o15
|
| 928 |
+
// l0-l15 p0-p15
|
| 929 |
+
#ifndef __msvc_cl__
|
| 930 |
+
#pragma unroll(4)
|
| 931 |
+
#endif
|
| 932 |
+
for (int i = 0; i < 4; i++) {
|
| 933 |
+
r[i] = _mm512_inserti64x4(_mm512_castsi256_si512(t[i]), t[i + 4], 0x01);
|
| 934 |
+
r[i + 4] = _mm512_inserti64x4(_mm512_castsi256_si512(t[i + 8]), t[i + 12], 0x01);
|
| 935 |
+
}
|
| 936 |
+
|
| 937 |
+
// u0: a0a1 b0b1 a2a3 b2b3 a8a9 b8b9 a10a11 b10b11 e0e1 f0f1 e2e3 f2f3 e8e9 f8f9 e10e11 f10f11
|
| 938 |
+
// u1: a4a5 b4b5 a6a7 b6b7 a12a13 b12b13 a14a15 b14b15 e4e5 f4f5 e6e7 f6f7 e12e13 f12f13 e14e15 f14f15
|
| 939 |
+
// u2: c0c1 d0d1 c2c3 d2d3 c8c9 d8d9 c10c11 d10d11 g0g1 h0h1 g2g3 h2h3 g8g9 h8h9 g10g11 h10h11
|
| 940 |
+
// u3: c4c5 d4b5 c6c7 d6b7 c12c13 d12d13 c14c15 d14d15 g4g5 h4h5 g6g7 h6h7 g12g13 h12h13 g14g15 h14h15
|
| 941 |
+
// i j m n
|
| 942 |
+
// k l o p
|
| 943 |
+
#ifndef __msvc_cl__
|
| 944 |
+
#pragma unroll(4)
|
| 945 |
+
#endif
|
| 946 |
+
for (int i = 0; i < 8; i += 2) {
|
| 947 |
+
u[i] = _mm512_unpacklo_epi32(r[i], r[i + 1]);
|
| 948 |
+
u[i + 1] = _mm512_unpackhi_epi32(r[i], r[i + 1]);
|
| 949 |
+
}
|
| 950 |
+
|
| 951 |
+
// r0: a0a1 b0b1 c0c1 d0d1 a8a9 b8b9 c8c9 d8d9 e0e1 f0f1 g0g1 h0h1 e8e9 f8f9 g8g9 h8h9
|
| 952 |
+
// r1: a2a3 b2b3 c2c3 d2d3 a10a11 b10b11 c10c11 d10d11 e2e3 f2f3 g2g3 h2h3 e10e11 f10f11 g10g11 h10h11
|
| 953 |
+
// r2: a4a5 b4b5 c4c5 d4b5 a12a13 b12b13 c12c13 d12d13
|
| 954 |
+
// r3: a6a7 b6b7 c6c7 d6b7 a14a15 b14b15 c14c15 d14d15
|
| 955 |
+
// r4: i j k l m n o p
|
| 956 |
+
r[0] = _mm512_unpacklo_epi64(u[0], u[2]);
|
| 957 |
+
r[1] = _mm512_unpackhi_epi64(u[0], u[2]);
|
| 958 |
+
r[2] = _mm512_unpacklo_epi64(u[1], u[3]);
|
| 959 |
+
r[3] = _mm512_unpackhi_epi64(u[1], u[3]);
|
| 960 |
+
r[4] = _mm512_unpacklo_epi64(u[4], u[6]);
|
| 961 |
+
r[5] = _mm512_unpackhi_epi64(u[4], u[6]);
|
| 962 |
+
r[6] = _mm512_unpacklo_epi64(u[5], u[7]);
|
| 963 |
+
r[7] = _mm512_unpackhi_epi64(u[5], u[7]);
|
| 964 |
+
|
| 965 |
+
__m512i const1 = _mm512_set_epi32(
|
| 966 |
+
0x00370035,
|
| 967 |
+
0x00330031,
|
| 968 |
+
0x00270025,
|
| 969 |
+
0x00230021,
|
| 970 |
+
0x00170015,
|
| 971 |
+
0x00130011,
|
| 972 |
+
0x00070005,
|
| 973 |
+
0x00030001,
|
| 974 |
+
0x00360034,
|
| 975 |
+
0x00320030,
|
| 976 |
+
0x00260024,
|
| 977 |
+
0x00220020,
|
| 978 |
+
0x00160014,
|
| 979 |
+
0x00120010,
|
| 980 |
+
0x00060004,
|
| 981 |
+
0x00020000);
|
| 982 |
+
__m512i const2 = _mm512_set_epi32(
|
| 983 |
+
0x003f003d,
|
| 984 |
+
0x003b0039,
|
| 985 |
+
0x002f002d,
|
| 986 |
+
0x002b0029,
|
| 987 |
+
0x001f001d,
|
| 988 |
+
0x001b0019,
|
| 989 |
+
0x000f000d,
|
| 990 |
+
0x000b0009,
|
| 991 |
+
0x003e003c,
|
| 992 |
+
0x003a0038,
|
| 993 |
+
0x002e002c,
|
| 994 |
+
0x002a0028,
|
| 995 |
+
0x001e001c,
|
| 996 |
+
0x001a0018,
|
| 997 |
+
0x000e000c,
|
| 998 |
+
0x000a0008);
|
| 999 |
+
// merge values from two regs
|
| 1000 |
+
// 0-- 1--
|
| 1001 |
+
// 8-- 9--
|
| 1002 |
+
// 2-- 3--
|
| 1003 |
+
// 10-- 11--
|
| 1004 |
+
// 4-- 5--
|
| 1005 |
+
// 12-- 13--
|
| 1006 |
+
// 6-- 7--
|
| 1007 |
+
// 14-- 15--
|
| 1008 |
+
#ifndef __msvc_cl__
|
| 1009 |
+
#pragma unroll(4)
|
| 1010 |
+
#endif
|
| 1011 |
+
for (int i = 0; i < 4; i++) {
|
| 1012 |
+
u[i] = _mm512_permutex2var_epi16(r[i], const1, r[i + 4]);
|
| 1013 |
+
u[i + 4] = _mm512_permutex2var_epi16(r[i], const2, r[i + 4]);
|
| 1014 |
+
}
|
| 1015 |
+
}
|
| 1016 |
+
|
| 1017 |
+
// TODO(Leslie): Add the AVX2 Version of transpose_mxn for BFloat16 and Float16
|
| 1018 |
+
// Code referred to FBGEMM:
|
| 1019 |
+
// https://github.com/pytorch/FBGEMM/blob/39a423e4ad1a04b77fea81c7d09c3e6f8984fae9/src/UtilsAvx512.cc#L1483-L1607
|
| 1020 |
+
template<>
|
| 1021 |
+
inline void transpose_mxn<BFloat16, 16, 16>(
|
| 1022 |
+
const BFloat16* src,
|
| 1023 |
+
int64_t ld_src,
|
| 1024 |
+
BFloat16* dst,
|
| 1025 |
+
int64_t ld_dst) {
|
| 1026 |
+
__m256i t[16];
|
| 1027 |
+
// load from src to registers
|
| 1028 |
+
// a: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15
|
| 1029 |
+
// b: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15
|
| 1030 |
+
// c: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15
|
| 1031 |
+
// d: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15
|
| 1032 |
+
// e: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10 e11 e12 e13 e14 e15
|
| 1033 |
+
// f: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15
|
| 1034 |
+
// g: g0 g1 g2 g3 g4 g5 g6 g7 g8 g9 g10 g11 g12 g13 g14 g15
|
| 1035 |
+
// h: h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 h11 h12 h13 h14 h15
|
| 1036 |
+
// i: i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15
|
| 1037 |
+
// j: j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j11 j12 j13 j14 j15
|
| 1038 |
+
// k: k0 k1 k2 k3 k4 k5 k6 k7 k8 k9 k10 k11 k12 k13 k14 k15
|
| 1039 |
+
// l: l0 l1 l2 l3 l4 l5 l6 l7 l8 l9 l10 l11 l12 l13 l14 l15
|
| 1040 |
+
// m: m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15
|
| 1041 |
+
// n: n0 n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12 n13 n14 n15
|
| 1042 |
+
// o: o0 o1 o2 o3 o4 o5 o6 o7 o8 o9 o10 o11 o12 o13 o14 o15
|
| 1043 |
+
// p: p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15
|
| 1044 |
+
#ifndef __msvc_cl__
|
| 1045 |
+
#pragma unroll(16)
|
| 1046 |
+
#endif
|
| 1047 |
+
for (int i = 0; i < 16; i++) {
|
| 1048 |
+
t[i] = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(src + i * ld_src));
|
| 1049 |
+
}
|
| 1050 |
+
|
| 1051 |
+
__m512i u[8];
|
| 1052 |
+
_transpose_mxn_half_16_16(t, u);
|
| 1053 |
+
|
| 1054 |
+
#ifndef __msvc_cl__
|
| 1055 |
+
#pragma unroll(8)
|
| 1056 |
+
#endif
|
| 1057 |
+
for (int i = 0; i < 8; i++) {
|
| 1058 |
+
_mm256_storeu_si256(
|
| 1059 |
+
reinterpret_cast<__m256i*>(dst + (i * 2) * ld_dst),
|
| 1060 |
+
_mm512_extracti32x8_epi32(u[i], 0x0));
|
| 1061 |
+
_mm256_storeu_si256(
|
| 1062 |
+
reinterpret_cast<__m256i*>(dst + (i * 2 + 1) * ld_dst),
|
| 1063 |
+
_mm512_extracti32x8_epi32(u[i], 0x01));
|
| 1064 |
+
}
|
| 1065 |
+
}
|
| 1066 |
+
|
| 1067 |
+
// Code referred to FBGEMM:
|
| 1068 |
+
// https://github.com/pytorch/FBGEMM/blob/39a423e4ad1a04b77fea81c7d09c3e6f8984fae9/src/UtilsAvx512.cc#L1483-L1607
|
| 1069 |
+
template<>
|
| 1070 |
+
inline void transpose_mxn<Half, 16, 16>(
|
| 1071 |
+
const Half* src,
|
| 1072 |
+
int64_t ld_src,
|
| 1073 |
+
Half* dst,
|
| 1074 |
+
int64_t ld_dst) {
|
| 1075 |
+
__m256i t[16];
|
| 1076 |
+
// load from src to registers
|
| 1077 |
+
// Same matrix indices as above transpose_mxn<BFloat16, 16, 16>
|
| 1078 |
+
#ifndef __msvc_cl__
|
| 1079 |
+
#pragma unroll(16)
|
| 1080 |
+
#endif
|
| 1081 |
+
for (int i = 0; i < 16; i++) {
|
| 1082 |
+
t[i] = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(src + i * ld_src));
|
| 1083 |
+
}
|
| 1084 |
+
|
| 1085 |
+
__m512i u[8];
|
| 1086 |
+
_transpose_mxn_half_16_16(t, u);
|
| 1087 |
+
|
| 1088 |
+
#ifndef __msvc_cl__
|
| 1089 |
+
#pragma unroll(8)
|
| 1090 |
+
#endif
|
| 1091 |
+
for (int i = 0; i < 8; i++) {
|
| 1092 |
+
_mm256_storeu_si256(
|
| 1093 |
+
reinterpret_cast<__m256i*>(dst + (i * 2) * ld_dst),
|
| 1094 |
+
_mm512_extracti32x8_epi32(u[i], 0x0));
|
| 1095 |
+
_mm256_storeu_si256(
|
| 1096 |
+
reinterpret_cast<__m256i*>(dst + (i * 2 + 1) * ld_dst),
|
| 1097 |
+
_mm512_extracti32x8_epi32(u[i], 0x01));
|
| 1098 |
+
}
|
| 1099 |
+
}
|
| 1100 |
+
|
| 1101 |
+
static inline void _transpose_mxn_half_32_32(__m512i r[], __m512i d[]) {
|
| 1102 |
+
// t[0]: 0 32 1 33 2 34 3 35 8 40 9 41 10 42 11 43 16 ... 59
|
| 1103 |
+
// t[1]: 4 36 5 37 6 38 7 39 12 44 13 45 14 46 15 47 20 ... 63
|
| 1104 |
+
// t[2]: 64 96 65 97 66 98 67 99 72 104 73 105 74 106 75 ... 123
|
| 1105 |
+
// t[3]: 68 100 69 101 70 102 71 103 76 108 77 109 78 110 79 111 84 ... 127
|
| 1106 |
+
// t[4]: 128 160 129 161 130 162 131 163 136 168 137 169 138 170 139 171 144 ... 187
|
| 1107 |
+
// t[5]: 132 164 133 165 134 166 135 167 140 172 141 173 142 174 143 175 148 ... 191
|
| 1108 |
+
// t[6]: 192 224 193 225 194 226 195 227 200 232 201 233 202 234 203 235 208 ... 251
|
| 1109 |
+
// t[7]: 196 228 197 229 198 230 199 231 204 236 205 237 206 238 207 239 212 ... 255
|
| 1110 |
+
// t[8]: 256 288 257 289 258 290 259 291 264 296 265 297 266 298 267 299 272 ... 315
|
| 1111 |
+
// t[9]: 260 292 261 293 262 294 263 295 268 300 269 301 270 302 271 303 276 ... 319
|
| 1112 |
+
// t[10]: 320 352 321 353 322 354 323 355 328 360 329 361 330 362 331 363 336 ... 379
|
| 1113 |
+
// t[11]: 324 356 325 357 326 358 327 359 332 364 333 365 334 366 335 367 340 ... 383
|
| 1114 |
+
// t[12]: 384 416 385 417 386 418 387 419 392 424 393 425 394 426 395 427 400 ... 443
|
| 1115 |
+
// t[13]: 388 420 389 421 390 422 391 423 396 428 397 429 398 430 399 431 404 ... 447
|
| 1116 |
+
// t[14]: 448 480 449 481 450 482 451 483 456 488 457 489 458 490 459 491 464 ... 507
|
| 1117 |
+
// t[15]: 452 484 453 485 454 486 455 487 460 492 461 493 462 494 463 495 468 ... 511
|
| 1118 |
+
// t[16]: 512 544 513 545 514 546 515 547 520 552 521 553 522 554 523 555 528 ... 571
|
| 1119 |
+
// ...
|
| 1120 |
+
// t[31]: 964 996 965 997 966 998 967 999 972 1004 973 1005 974 1006 975 1007 980 ... 1023
|
| 1121 |
+
#ifndef __msvc_cl__
|
| 1122 |
+
#pragma unroll(16)
|
| 1123 |
+
#endif
|
| 1124 |
+
for (int i = 0; i < 16; ++i) {
|
| 1125 |
+
d[i * 2] = _mm512_unpacklo_epi16(r[i * 2], r[i * 2 + 1]);
|
| 1126 |
+
d[i * 2 + 1] = _mm512_unpackhi_epi16(r[i * 2], r[i * 2 + 1]);
|
| 1127 |
+
}
|
| 1128 |
+
|
| 1129 |
+
// t[0]: 0 32 64 96 1 33 65 97 8 40 72 104 9 41 73 105 16 ... 121
|
| 1130 |
+
// t[1]: 2 34 66 98 3 35 67 99 10 42 74 106 11 43 75 107 18 ... 123
|
| 1131 |
+
// t[2]: 4 36 68 100 5 37 69 101 12 44 76 108 13 45 77 109 20 ... 125
|
| 1132 |
+
// t[3]: 6 38 70 102 7 39 71 103 14 46 78 110 15 47 79 111 22 ... 127
|
| 1133 |
+
// t[4]: 128 160 192 224 129 161 193 225 136 168 200 232 137 169 201 233 144 ... 249
|
| 1134 |
+
// t[5]: 130 162 194 226 131 163 195 227 138 170 202 234 139 171 203 235 146 ... 251
|
| 1135 |
+
// t[6]: 132 164 196 228 133 165 197 229 140 172 204 236 141 173 205 237 148 ... 253
|
| 1136 |
+
// t[7]: 134 166 198 230 135 167 199 231 142 174 206 238 143 175 207 239 150 ... 255
|
| 1137 |
+
// t[8]: 256 288 320 352 257 289 321 353 264 296 328 360 265 297 329 361 272 ... 377
|
| 1138 |
+
// t[9]: 258 290 322 354 259 291 323 355 266 298 330 362 267 299 331 363 274 ... 379
|
| 1139 |
+
// t[10]: 260 292 324 356 261 293 325 357 268 300 332 364 269 301 333 365 276 ... 381
|
| 1140 |
+
// t[11]: 262 294 326 358 263 295 327 359 270 302 334 366 271 303 335 367 278 ... 383
|
| 1141 |
+
// t[12]: 384 416 448 480 385 417 449 481 392 424 456 488 393 425 457 489 400 ... 505
|
| 1142 |
+
// t[13]: 386 418 450 482 387 419 451 483 394 426 458 490 395 427 459 491 402 ... 507
|
| 1143 |
+
// t[14]: 388 420 452 484 389 421 453 485 396 428 460 492 397 429 461 493 404 ... 509
|
| 1144 |
+
// t[15]: 390 422 454 486 391 423 455 487 398 430 462 494 399 431 463 495 406 ... 511
|
| 1145 |
+
// t[16]: 512 544 576 608 513 545 577 609 520 552 584 616 521 553 585 617 528 ... 633
|
| 1146 |
+
// ...
|
| 1147 |
+
// t[31]: 902 934 966 998 903 935 967 999 910 942 974 1006 911 943 975 1007 918 ... 1023
|
| 1148 |
+
#ifndef __msvc_cl__
|
| 1149 |
+
#pragma unroll(8)
|
| 1150 |
+
#endif
|
| 1151 |
+
for (int i = 0; i < 8; ++i) {
|
| 1152 |
+
r[i * 4] = _mm512_unpacklo_epi32(d[i * 4], d[i * 4 + 2]);
|
| 1153 |
+
r[i * 4 + 1] = _mm512_unpackhi_epi32(d[i * 4], d[i * 4 + 2]);
|
| 1154 |
+
r[i * 4 + 2] = _mm512_unpacklo_epi32(d[i * 4 + 1], d[i * 4 + 3]);
|
| 1155 |
+
r[i * 4 + 3] = _mm512_unpackhi_epi32(d[i * 4 + 1], d[i * 4 + 3]);
|
| 1156 |
+
}
|
| 1157 |
+
|
| 1158 |
+
// t[0]: 0 32 64 96 128 160 192 224 8 40 72 104 136 168 200 232 16 ... 248
|
| 1159 |
+
// t[1]: 1 33 65 97 129 161 193 225 9 41 73 105 137 169 201 233 17 ... 249
|
| 1160 |
+
// t[2]: 2 34 66 98 130 162 194 226 10 42 74 106 138 170 202 234 18 ... 250
|
| 1161 |
+
// t[3]: 3 35 67 99 131 163 195 227 11 43 75 107 139 171 203 235 19 ... 251
|
| 1162 |
+
// t[4]: 4 36 68 100 132 164 196 228 12 44 76 108 140 172 204 236 20 ... 252
|
| 1163 |
+
// t[5]: 5 37 69 101 133 165 197 229 13 45 77 109 141 173 205 237 21 ... 253
|
| 1164 |
+
// t[6]: 6 38 70 102 134 166 198 230 14 46 78 110 142 174 206 238 22 ... 254
|
| 1165 |
+
// t[7]: 7 39 71 103 135 167 199 231 15 47 79 111 143 175 207 239 23 ... 255
|
| 1166 |
+
// t[8]: 256 288 320 352 384 416 448 480 264 296 328 360 392 424 456 488 272 ... 504
|
| 1167 |
+
// t[9]: 257 289 321 353 385 417 449 481 265 297 329 361 393 425 457 489 273 ... 505
|
| 1168 |
+
// t[10]: 258 290 322 354 386 418 450 482 266 298 330 362 394 426 458 490 274 ... 506
|
| 1169 |
+
// t[11]: 259 291 323 355 387 419 451 483 267 299 331 363 395 427 459 491 275 ... 507
|
| 1170 |
+
// t[12]: 260 292 324 356 388 420 452 484 268 300 332 364 396 428 460 492 276 ... 508
|
| 1171 |
+
// t[13]: 261 293 325 357 389 421 453 485 269 301 333 365 397 429 461 493 277 ... 509
|
| 1172 |
+
// t[14]: 262 294 326 358 390 422 454 486 270 302 334 366 398 430 462 494 278 ... 510
|
| 1173 |
+
// t[15]: 263 295 327 359 391 423 455 487 271 303 335 367 399 431 463 495 279 ... 511
|
| 1174 |
+
// t[16]: 512 544 576 608 640 672 704 736 520 552 584 616 648 680 712 744 528 ... 760
|
| 1175 |
+
// ...
|
| 1176 |
+
// t[31]: 775 807 839 871 903 935 967 999 783 815 847 879 911 943 975 1007 791 ... 1023
|
| 1177 |
+
#ifndef __msvc_cl__
|
| 1178 |
+
#pragma unroll(4)
|
| 1179 |
+
#endif
|
| 1180 |
+
for (int i = 0; i < 4; ++i) {
|
| 1181 |
+
d[i * 8] = _mm512_unpacklo_epi64(r[i * 8], r[i * 8 + 4]);
|
| 1182 |
+
d[i * 8 + 1] = _mm512_unpackhi_epi64(r[i * 8], r[i * 8 + 4]);
|
| 1183 |
+
d[i * 8 + 2] = _mm512_unpacklo_epi64(r[i * 8 + 1], r[i * 8 + 5]);
|
| 1184 |
+
d[i * 8 + 3] = _mm512_unpackhi_epi64(r[i * 8 + 1], r[i * 8 + 5]);
|
| 1185 |
+
d[i * 8 + 4] = _mm512_unpacklo_epi64(r[i * 8 + 2], r[i * 8 + 6]);
|
| 1186 |
+
d[i * 8 + 5] = _mm512_unpackhi_epi64(r[i * 8 + 2], r[i * 8 + 6]);
|
| 1187 |
+
d[i * 8 + 6] = _mm512_unpacklo_epi64(r[i * 8 + 3], r[i * 8 + 7]);
|
| 1188 |
+
d[i * 8 + 7] = _mm512_unpackhi_epi64(r[i * 8 + 3], r[i * 8 + 7]);
|
| 1189 |
+
}
|
| 1190 |
+
|
| 1191 |
+
// t[0]: 0 32 64 96 128 160 192 224 256 288 320 352 384 416 448 480 16 ... 496
|
| 1192 |
+
// t[1]: 1 33 65 97 129 161 193 225 257 289 321 353 385 417 449 481 17 ... 497
|
| 1193 |
+
// t[2]: 2 34 66 98 130 162 194 226 258 290 322 354 386 418 450 482 18 ... 498
|
| 1194 |
+
// t[3]: 3 35 67 99 131 163 195 227 259 291 323 355 387 419 451 483 19 ... 499
|
| 1195 |
+
// t[4]: 4 36 68 100 132 164 196 228 260 292 324 356 388 420 452 484 20 ... 500
|
| 1196 |
+
// t[5]: 5 37 69 101 133 165 197 229 261 293 325 357 389 421 453 485 21 ... 501
|
| 1197 |
+
// t[6]: 6 38 70 102 134 166 198 230 262 294 326 358 390 422 454 486 22 ... 502
|
| 1198 |
+
// t[7]: 7 39 71 103 135 167 199 231 263 295 327 359 391 423 455 487 23 ... 503
|
| 1199 |
+
// t[8]: 8 40 72 104 136 168 200 232 264 296 328 360 392 424 456 488 24 ... 504
|
| 1200 |
+
// t[9]: 9 41 73 105 137 169 201 233 265 297 329 361 393 425 457 489 25 ... 505
|
| 1201 |
+
// t[10]: 10 42 74 106 138 170 202 234 266 298 330 362 394 426 458 490 26 ... 506
|
| 1202 |
+
// t[11]: 11 43 75 107 139 171 203 235 267 299 331 363 395 427 459 491 27 ... 507
|
| 1203 |
+
// t[12]: 12 44 76 108 140 172 204 236 268 300 332 364 396 428 460 492 28 ... 508
|
| 1204 |
+
// t[13]: 13 45 77 109 141 173 205 237 269 301 333 365 397 429 461 493 29 ... 509
|
| 1205 |
+
// t[14]: 14 46 78 110 142 174 206 238 270 302 334 366 398 430 462 494 30 ... 510
|
| 1206 |
+
// t[15]: 15 47 79 111 143 175 207 239 271 303 335 367 399 431 463 495 31 ... 511
|
| 1207 |
+
// t[16]: 512 544 576 608 640 672 704 736 768 800 832 864 896 928 960 992 528 ... 1008
|
| 1208 |
+
// ...
|
| 1209 |
+
// t[31]: 527 559 591 623 655 687 719 751 783 815 847 879 911 943 975 1007 543 ... 1023
|
| 1210 |
+
__m512i const1 = _mm512_set_epi64(
|
| 1211 |
+
0x000000000000000d,
|
| 1212 |
+
0x000000000000000c,
|
| 1213 |
+
0x0000000000000005,
|
| 1214 |
+
0x0000000000000004,
|
| 1215 |
+
0x0000000000000009,
|
| 1216 |
+
0x0000000000000008,
|
| 1217 |
+
0x0000000000000001,
|
| 1218 |
+
0x0000000000000000);
|
| 1219 |
+
__m512i const2 = _mm512_set_epi64(
|
| 1220 |
+
0x000000000000000f,
|
| 1221 |
+
0x000000000000000e,
|
| 1222 |
+
0x0000000000000007,
|
| 1223 |
+
0x0000000000000006,
|
| 1224 |
+
0x000000000000000b,
|
| 1225 |
+
0x000000000000000a,
|
| 1226 |
+
0x0000000000000003,
|
| 1227 |
+
0x0000000000000002);
|
| 1228 |
+
#ifndef __msvc_cl__
|
| 1229 |
+
#pragma unroll(8)
|
| 1230 |
+
#endif
|
| 1231 |
+
for (int i = 0; i < 8; ++i) {
|
| 1232 |
+
r[i] = _mm512_permutex2var_epi64(d[i], /*idx*/const1, d[i + 8]);
|
| 1233 |
+
r[i + 8] = _mm512_permutex2var_epi64(d[i], /*idx*/const2, d[i + 8]);
|
| 1234 |
+
r[i + 16] = _mm512_permutex2var_epi64(d[i + 16], /*idx*/const1, d[i + 24]);
|
| 1235 |
+
r[i + 24] = _mm512_permutex2var_epi64(d[i + 16], /*idx*/const2, d[i + 24]);
|
| 1236 |
+
}
|
| 1237 |
+
|
| 1238 |
+
// t[0]: 0 32 64 96 128 160 192 224 256 288 320 352 384 416 448 480 512 544 ... 992
|
| 1239 |
+
// t[1]: 1 33 65 97 129 161 193 225 257 289 321 353 385 417 449 481 513 545 ... 993
|
| 1240 |
+
// t[2]: 2 34 66 98 130 162 194 226 258 290 322 354 386 418 450 482 514 546 ... 994
|
| 1241 |
+
// t[3]: 3 35 67 99 131 163 195 227 259 291 323 355 387 419 451 483 515 547 ... 995
|
| 1242 |
+
// t[4]: 4 36 68 100 132 164 196 228 260 292 324 356 388 420 452 484 516 548 ... 996
|
| 1243 |
+
// t[5]: 5 37 69 101 133 165 197 229 261 293 325 357 389 421 453 485 517 549 ... 997
|
| 1244 |
+
// t[6]: 6 38 70 102 134 166 198 230 262 294 326 358 390 422 454 486 518 550 ... 998
|
| 1245 |
+
// t[7]: 7 39 71 103 135 167 199 231 263 295 327 359 391 423 455 487 519 551 ... 999
|
| 1246 |
+
// t[8]: 8 40 72 104 136 168 200 232 264 296 328 360 392 424 456 488 520 552 ... 1000
|
| 1247 |
+
// t[9]: 9 41 73 105 137 169 201 233 265 297 329 361 393 425 457 489 521 553 ... 1001
|
| 1248 |
+
// t[10]: 10 42 74 106 138 170 202 234 266 298 330 362 394 426 458 490 522 554 ... 1002
|
| 1249 |
+
// t[11]: 11 43 75 107 139 171 203 235 267 299 331 363 395 427 459 491 523 555 ... 1003
|
| 1250 |
+
// t[12]: 12 44 76 108 140 172 204 236 268 300 332 364 396 428 460 492 524 556 ... 1004
|
| 1251 |
+
// t[13]: 13 45 77 109 141 173 205 237 269 301 333 365 397 429 461 493 525 557 ... 1005
|
| 1252 |
+
// t[14]: 14 46 78 110 142 174 206 238 270 302 334 366 398 430 462 494 526 558 ... 1006
|
| 1253 |
+
// t[15]: 15 47 79 111 143 175 207 239 271 303 335 367 399 431 463 495 527 559 ... 1007
|
| 1254 |
+
// t[16]: 16 48 80 112 144 176 208 240 272 304 336 368 400 432 464 496 528 560 ... 1008
|
| 1255 |
+
// ...
|
| 1256 |
+
// t[31]: 31 63 95 127 159 191 223 255 287 319 351 383 415 447 479 511 543 575 ... 1023
|
| 1257 |
+
__m512i const3 = _mm512_set_epi64(
|
| 1258 |
+
0x000000000000000b,
|
| 1259 |
+
0x000000000000000a,
|
| 1260 |
+
0x0000000000000009,
|
| 1261 |
+
0x0000000000000008,
|
| 1262 |
+
0x0000000000000003,
|
| 1263 |
+
0x0000000000000002,
|
| 1264 |
+
0x0000000000000001,
|
| 1265 |
+
0x0000000000000000);
|
| 1266 |
+
__m512i const4 = _mm512_set_epi64(
|
| 1267 |
+
0x000000000000000f,
|
| 1268 |
+
0x000000000000000e,
|
| 1269 |
+
0x000000000000000d,
|
| 1270 |
+
0x000000000000000c,
|
| 1271 |
+
0x0000000000000007,
|
| 1272 |
+
0x0000000000000006,
|
| 1273 |
+
0x0000000000000005,
|
| 1274 |
+
0x0000000000000004);
|
| 1275 |
+
#ifndef __msvc_cl__
|
| 1276 |
+
#pragma unroll(16)
|
| 1277 |
+
#endif
|
| 1278 |
+
for (int i = 0; i < 16; ++i) {
|
| 1279 |
+
d[i] = _mm512_permutex2var_epi64(r[i], /*idx*/const3, r[i + 16]);
|
| 1280 |
+
d[i + 16] = _mm512_permutex2var_epi64(r[i], /*idx*/const4, r[i + 16]);
|
| 1281 |
+
}
|
| 1282 |
+
}
|
| 1283 |
+
|
| 1284 |
+
// Code referred to FBGEMM:
|
| 1285 |
+
// https://github.com/pytorch/FBGEMM/blob/39a423e4ad1a04b77fea81c7d09c3e6f8984fae9/src/UtilsAvx512.cc#LL19C6-L19C6
|
| 1286 |
+
template<>
|
| 1287 |
+
inline void transpose_mxn<BFloat16>(const BFloat16* src, int64_t ld_src, BFloat16* dst, int64_t ld_dst, int M, int N) {
|
| 1288 |
+
// load from src
|
| 1289 |
+
TORCH_CHECK(M <= 32 && N <= 32, "transpose_mxn<BFloat16> expects M, N <= 32.");
|
| 1290 |
+
__m512i r[32];
|
| 1291 |
+
int i;
|
| 1292 |
+
if (N == 32) {
|
| 1293 |
+
for (i = 0; i < M; ++i) {
|
| 1294 |
+
r[i] = _mm512_loadu_si512(&src[i * ld_src]);
|
| 1295 |
+
}
|
| 1296 |
+
} else {
|
| 1297 |
+
__mmask32 src_mask = (1 << N) - 1;
|
| 1298 |
+
for (i = 0; i < M; ++i) {
|
| 1299 |
+
r[i] = _mm512_maskz_loadu_epi16(src_mask, &src[i * ld_src]);
|
| 1300 |
+
}
|
| 1301 |
+
}
|
| 1302 |
+
for (; i < 32; ++i) {
|
| 1303 |
+
r[i] = _mm512_setzero_si512();
|
| 1304 |
+
}
|
| 1305 |
+
|
| 1306 |
+
__m512i d[32];
|
| 1307 |
+
_transpose_mxn_half_32_32(r, d);
|
| 1308 |
+
|
| 1309 |
+
// store to dst
|
| 1310 |
+
if (M == 32) {
|
| 1311 |
+
for (i = 0; i < N; ++i) {
|
| 1312 |
+
_mm512_storeu_si512(&dst[i * ld_dst], d[i]);
|
| 1313 |
+
}
|
| 1314 |
+
} else {
|
| 1315 |
+
__mmask32 dst_mask = (1 << M) - 1;
|
| 1316 |
+
for (i = 0; i < N; ++i) {
|
| 1317 |
+
_mm512_mask_storeu_epi16(&dst[i * ld_dst], dst_mask, d[i]);
|
| 1318 |
+
}
|
| 1319 |
+
}
|
| 1320 |
+
}
|
| 1321 |
+
|
| 1322 |
+
template <typename T, int M, int N,
|
| 1323 |
+
typename std::enable_if_t<std::is_same_v<T, BFloat16> && ((M <= 32 && M != 16) || (N <= 32 && N != 16)), int> = 0>
|
| 1324 |
+
inline void transpose_mxn(const BFloat16* src, int64_t ld_src, BFloat16* dst, int64_t ld_dst) {
|
| 1325 |
+
transpose_mxn<BFloat16>(src, ld_src, dst, ld_dst, M, N);
|
| 1326 |
+
}
|
| 1327 |
+
|
| 1328 |
+
template<>
|
| 1329 |
+
inline void transpose_mxn<Half>(const Half* src, int64_t ld_src, Half* dst, int64_t ld_dst, int M, int N) {
|
| 1330 |
+
TORCH_CHECK(M <= 32 && N <= 32, "transpose_mxn<Half> expects M, N <= 32.");
|
| 1331 |
+
// load from src
|
| 1332 |
+
__m512i r[32];
|
| 1333 |
+
int i;
|
| 1334 |
+
if (N == 32) {
|
| 1335 |
+
for (i = 0; i < M; ++i) {
|
| 1336 |
+
r[i] = _mm512_loadu_si512(&src[i * ld_src]);
|
| 1337 |
+
}
|
| 1338 |
+
} else {
|
| 1339 |
+
__mmask32 src_mask = (1 << N) - 1;
|
| 1340 |
+
for (i = 0; i < M; ++i) {
|
| 1341 |
+
r[i] = _mm512_maskz_loadu_epi16(src_mask, &src[i * ld_src]);
|
| 1342 |
+
}
|
| 1343 |
+
}
|
| 1344 |
+
for (; i < 32; ++i) {
|
| 1345 |
+
r[i] = _mm512_setzero_si512();
|
| 1346 |
+
}
|
| 1347 |
+
|
| 1348 |
+
__m512i d[32];
|
| 1349 |
+
_transpose_mxn_half_32_32(r, d);
|
| 1350 |
+
|
| 1351 |
+
// store to dst
|
| 1352 |
+
if (M == 32) {
|
| 1353 |
+
for (i = 0; i < N; ++i) {
|
| 1354 |
+
_mm512_storeu_si512(&dst[i * ld_dst], d[i]);
|
| 1355 |
+
}
|
| 1356 |
+
} else {
|
| 1357 |
+
__mmask32 dst_mask = (1 << M) - 1;
|
| 1358 |
+
for (i = 0; i < N; ++i) {
|
| 1359 |
+
_mm512_mask_storeu_epi16(&dst[i * ld_dst], dst_mask, d[i]);
|
| 1360 |
+
}
|
| 1361 |
+
}
|
| 1362 |
+
}
|
| 1363 |
+
|
| 1364 |
+
template <typename T, int M, int N,
|
| 1365 |
+
typename std::enable_if_t<std::is_same_v<T, Half> && ((M <= 32 && M != 16) || (N <= 32 && N != 16)), int> = 0>
|
| 1366 |
+
inline void transpose_mxn(const Half* src, int64_t ld_src, Half* dst, int64_t ld_dst) {
|
| 1367 |
+
transpose_mxn<Half>(src, ld_src, dst, ld_dst, M, N);
|
| 1368 |
+
}
|
| 1369 |
+
|
| 1370 |
+
template <>
|
| 1371 |
+
class Vectorized<Half>: public Vectorized16<Half> {
|
| 1372 |
+
public:
|
| 1373 |
+
using Vectorized16::Vectorized16;
|
| 1374 |
+
|
| 1375 |
+
using value_type = Half;
|
| 1376 |
+
|
| 1377 |
+
Vectorized<Half> frac() const;
|
| 1378 |
+
|
| 1379 |
+
Vectorized<Half> eq(const Vectorized<Half>& other) const;
|
| 1380 |
+
Vectorized<Half> ne(const Vectorized<Half>& other) const;
|
| 1381 |
+
Vectorized<Half> gt(const Vectorized<Half>& other) const;
|
| 1382 |
+
Vectorized<Half> ge(const Vectorized<Half>& other) const;
|
| 1383 |
+
Vectorized<Half> lt(const Vectorized<Half>& other) const;
|
| 1384 |
+
Vectorized<Half> le(const Vectorized<Half>& other) const;
|
| 1385 |
+
};
|
| 1386 |
+
|
| 1387 |
+
Vectorized<Half> inline operator+(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1388 |
+
return binary_op_as_fp32(a, b, [](const __m512& x, const __m512& y) { return _mm512_add_ps(x, y); });
|
| 1389 |
+
}
|
| 1390 |
+
Vectorized<Half> inline operator-(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1391 |
+
return binary_op_as_fp32(a, b, [](const __m512& x, const __m512& y) { return _mm512_sub_ps(x, y); });
|
| 1392 |
+
}
|
| 1393 |
+
Vectorized<Half> inline operator*(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1394 |
+
return binary_op_as_fp32(a, b, [](const __m512& x, const __m512& y) { return _mm512_mul_ps(x, y); });
|
| 1395 |
+
}
|
| 1396 |
+
Vectorized<Half> inline operator/(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1397 |
+
return binary_op_as_fp32(a, b, [](const __m512& x, const __m512& y) { return _mm512_div_ps(x, y); });
|
| 1398 |
+
}
|
| 1399 |
+
|
| 1400 |
+
Vectorized<Half> inline operator&(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1401 |
+
return _mm512_and_si512(a, b);
|
| 1402 |
+
}
|
| 1403 |
+
Vectorized<Half> inline operator|(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1404 |
+
return _mm512_or_si512(a, b);
|
| 1405 |
+
}
|
| 1406 |
+
Vectorized<Half> inline operator^(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1407 |
+
return _mm512_xor_si512(a, b);
|
| 1408 |
+
}
|
| 1409 |
+
|
| 1410 |
+
inline Vectorized<Half> Vectorized<Half>::eq(const Vectorized<Half>& other) const {
|
| 1411 |
+
return (*this == other) & Vectorized<Half>(1.0f);
|
| 1412 |
+
}
|
| 1413 |
+
|
| 1414 |
+
inline Vectorized<Half> Vectorized<Half>::ne(const Vectorized<Half>& other) const {
|
| 1415 |
+
return (*this != other) & Vectorized<Half>(1.0f);
|
| 1416 |
+
}
|
| 1417 |
+
|
| 1418 |
+
inline Vectorized<Half> Vectorized<Half>::gt(const Vectorized<Half>& other) const {
|
| 1419 |
+
return (*this > other) & Vectorized<Half>(1.0f);
|
| 1420 |
+
}
|
| 1421 |
+
|
| 1422 |
+
inline Vectorized<Half> Vectorized<Half>::ge(const Vectorized<Half>& other) const {
|
| 1423 |
+
return (*this >= other) & Vectorized<Half>(1.0f);
|
| 1424 |
+
}
|
| 1425 |
+
|
| 1426 |
+
inline Vectorized<Half> Vectorized<Half>::lt(const Vectorized<Half>& other) const {
|
| 1427 |
+
return (*this < other) & Vectorized<Half>(1.0f);
|
| 1428 |
+
}
|
| 1429 |
+
|
| 1430 |
+
inline Vectorized<Half> Vectorized<Half>::le(const Vectorized<Half>& other) const {
|
| 1431 |
+
return (*this <= other) & Vectorized<Half>(1.0f);
|
| 1432 |
+
}
|
| 1433 |
+
|
| 1434 |
+
// frac. Implement this here so we can use subtraction
|
| 1435 |
+
inline Vectorized<Half> Vectorized<Half>::frac() const {
|
| 1436 |
+
return *this - this->trunc();
|
| 1437 |
+
}
|
| 1438 |
+
|
| 1439 |
+
// Implements the IEEE 754 201X `maximum` operation, which propagates NaN if
|
| 1440 |
+
// either input is a NaN.
|
| 1441 |
+
template <>
|
| 1442 |
+
Vectorized<Half> inline maximum(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1443 |
+
__m512 a_lo, a_hi;
|
| 1444 |
+
__m512 b_lo, b_hi;
|
| 1445 |
+
cvtfp16_fp32(__m512i(a), a_lo, a_hi);
|
| 1446 |
+
cvtfp16_fp32(__m512i(b), b_lo, b_hi);
|
| 1447 |
+
auto max_lo = _mm512_max_ps(a_lo, b_lo);
|
| 1448 |
+
auto max_hi = _mm512_max_ps(a_hi, b_hi);
|
| 1449 |
+
auto nan_lo_mask = _mm512_cmp_ps_mask(a_lo, b_lo, _CMP_UNORD_Q);
|
| 1450 |
+
auto nan_hi_mask = _mm512_cmp_ps_mask(a_hi, b_hi, _CMP_UNORD_Q);
|
| 1451 |
+
auto nan_lo = _mm512_castsi512_ps(_mm512_set1_epi32(nan_lo_mask));
|
| 1452 |
+
auto nan_hi = _mm512_castsi512_ps(_mm512_set1_epi32(nan_hi_mask));
|
| 1453 |
+
// Exploit the fact that all-ones is a NaN.
|
| 1454 |
+
auto o1 = _mm512_or_ps(max_lo, nan_lo);
|
| 1455 |
+
auto o2 = _mm512_or_ps(max_hi, nan_hi);
|
| 1456 |
+
return cvtfp32_fp16(o1, o2);
|
| 1457 |
+
}
|
| 1458 |
+
|
| 1459 |
+
// Implements the IEEE 754 201X `minimum` operation, which propagates NaN if
|
| 1460 |
+
// either input is a NaN.
|
| 1461 |
+
template <>
|
| 1462 |
+
Vectorized<Half> inline minimum(const Vectorized<Half>& a, const Vectorized<Half>& b) {
|
| 1463 |
+
__m512 a_lo, a_hi;
|
| 1464 |
+
__m512 b_lo, b_hi;
|
| 1465 |
+
__m512i zero_vec = _mm512_set1_epi32(0);
|
| 1466 |
+
cvtfp16_fp32(__m512i(a), a_lo, a_hi);
|
| 1467 |
+
cvtfp16_fp32(__m512i(b), b_lo, b_hi);
|
| 1468 |
+
auto min_lo = _mm512_min_ps(a_lo, b_lo);
|
| 1469 |
+
auto min_hi = _mm512_min_ps(a_hi, b_hi);
|
| 1470 |
+
auto nan_lo_mask = _mm512_cmp_ps_mask(a_lo, b_lo, _CMP_UNORD_Q);
|
| 1471 |
+
auto nan_hi_mask = _mm512_cmp_ps_mask(a_hi, b_hi, _CMP_UNORD_Q);
|
| 1472 |
+
auto nan_lo = _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, nan_lo_mask,
|
| 1473 |
+
0xFFFFFFFF));
|
| 1474 |
+
auto nan_hi = _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vec, nan_hi_mask,
|
| 1475 |
+
0xFFFFFFFF));
|
| 1476 |
+
// Exploit the fact that all-ones is a NaN.
|
| 1477 |
+
auto o1 = _mm512_or_ps(min_lo, nan_lo);
|
| 1478 |
+
auto o2 = _mm512_or_ps(min_hi, nan_hi);
|
| 1479 |
+
return cvtfp32_fp16(o1, o2);
|
| 1480 |
+
}
|
| 1481 |
+
|
| 1482 |
+
template <>
|
| 1483 |
+
Vectorized<Half> inline clamp(const Vectorized<Half>& a,
|
| 1484 |
+
const Vectorized<Half>& min, const Vectorized<Half>& max) {
|
| 1485 |
+
__m512 a_lo, a_hi;
|
| 1486 |
+
__m512 min_lo, min_hi;
|
| 1487 |
+
__m512 max_lo, max_hi;
|
| 1488 |
+
cvtfp16_fp32(__m512i(a), a_lo, a_hi);
|
| 1489 |
+
cvtfp16_fp32(__m512i(min), min_lo, min_hi);
|
| 1490 |
+
cvtfp16_fp32(__m512i(max), max_lo, max_hi);
|
| 1491 |
+
auto o1 = _mm512_min_ps(max_lo, _mm512_max_ps(min_lo, a_lo));
|
| 1492 |
+
auto o2 = _mm512_min_ps(max_hi, _mm512_max_ps(min_hi, a_hi));
|
| 1493 |
+
return cvtfp32_fp16(o1, o2);
|
| 1494 |
+
}
|
| 1495 |
+
|
| 1496 |
+
template <>
|
| 1497 |
+
Vectorized<Half> inline clamp_max(const Vectorized<Half>& a, const Vectorized<Half>& max) {
|
| 1498 |
+
__m512 a_lo, a_hi;
|
| 1499 |
+
__m512 max_lo, max_hi;
|
| 1500 |
+
cvtfp16_fp32(__m512i(a), a_lo, a_hi);
|
| 1501 |
+
cvtfp16_fp32(__m512i(max), max_lo, max_hi);
|
| 1502 |
+
auto o1 = _mm512_min_ps(max_lo, a_lo);
|
| 1503 |
+
auto o2 = _mm512_min_ps(max_hi, a_hi);
|
| 1504 |
+
return cvtfp32_fp16(o1, o2);
|
| 1505 |
+
}
|
| 1506 |
+
|
| 1507 |
+
template <>
|
| 1508 |
+
Vectorized<Half> inline clamp_min(const Vectorized<Half>& a, const Vectorized<Half>& min) {
|
| 1509 |
+
__m512 a_lo, a_hi;
|
| 1510 |
+
__m512 min_lo, min_hi;
|
| 1511 |
+
cvtfp16_fp32(__m512i(a), a_lo, a_hi);
|
| 1512 |
+
cvtfp16_fp32(__m512i(min), min_lo, min_hi);
|
| 1513 |
+
auto o1 = _mm512_max_ps(min_lo, a_lo);
|
| 1514 |
+
auto o2 = _mm512_max_ps(min_hi, a_hi);
|
| 1515 |
+
return cvtfp32_fp16(o1, o2);
|
| 1516 |
+
}
|
| 1517 |
+
|
| 1518 |
+
template <>
|
| 1519 |
+
inline void convert(const Half* src, Half* dst, int64_t n) {
|
| 1520 |
+
int64_t i;
|
| 1521 |
+
#ifndef __msvc_cl__
|
| 1522 |
+
#pragma unroll
|
| 1523 |
+
#endif
|
| 1524 |
+
for (i = 0; i <= (n - Vectorized<Half>::size()); i += Vectorized<Half>::size()) {
|
| 1525 |
+
auto vsrc = _mm512_loadu_si512(reinterpret_cast<__m512i*>((void*)(src + i)));
|
| 1526 |
+
_mm512_storeu_si512(reinterpret_cast<__m512i*>((void*)(dst + i)), vsrc);
|
| 1527 |
+
}
|
| 1528 |
+
#ifndef __msvc_cl__
|
| 1529 |
+
#pragma unroll
|
| 1530 |
+
#endif
|
| 1531 |
+
for (; i < n; i++) {
|
| 1532 |
+
dst[i] = src[i];
|
| 1533 |
+
}
|
| 1534 |
+
}
|
| 1535 |
+
|
| 1536 |
+
template <>
|
| 1537 |
+
inline void convert(const float* src, Half* dst, int64_t n) {
|
| 1538 |
+
int64_t i;
|
| 1539 |
+
for (i = 0; i + Vectorized<Half>::size() <= n; i += Vectorized<Half>::size()) {
|
| 1540 |
+
__m512 a = _mm512_loadu_ps(&src[i]);
|
| 1541 |
+
__m512 b = _mm512_loadu_ps(&src[i + 16]);
|
| 1542 |
+
|
| 1543 |
+
__m512i bf = cvtfp32_fp16(a, b);
|
| 1544 |
+
_mm512_storeu_si512(reinterpret_cast<__m512i*>(&dst[i]), bf);
|
| 1545 |
+
}
|
| 1546 |
+
for (; i < n; i++) {
|
| 1547 |
+
dst[i] = c10::convert<Half>(src[i]);
|
| 1548 |
+
}
|
| 1549 |
+
}
|
| 1550 |
+
|
| 1551 |
+
template <>
|
| 1552 |
+
inline void convert(const double* src, Half* dst, int64_t n) {
|
| 1553 |
+
auto load_float = [](const double *src) -> __m512 {
|
| 1554 |
+
// Load one float vector from an array of doubles
|
| 1555 |
+
__m256 a = _mm512_cvtpd_ps(_mm512_loadu_pd(src));
|
| 1556 |
+
__m256 b = _mm512_cvtpd_ps(_mm512_loadu_pd(src + 8));
|
| 1557 |
+
return _mm512_insertf32x8(_mm512_castps256_ps512(a), b, 1);
|
| 1558 |
+
};
|
| 1559 |
+
|
| 1560 |
+
int64_t i;
|
| 1561 |
+
for (i = 0; i + Vectorized<Half>::size() <= n; i += Vectorized<Half>::size()) {
|
| 1562 |
+
__m512 a = load_float(&src[i]);
|
| 1563 |
+
__m512 b = load_float(&src[i + 16]);
|
| 1564 |
+
|
| 1565 |
+
__m512i bf = cvtfp32_fp16(a, b);
|
| 1566 |
+
_mm512_storeu_si512(reinterpret_cast<__m512i*>(&dst[i]), bf);
|
| 1567 |
+
}
|
| 1568 |
+
for (; i < n; i++) {
|
| 1569 |
+
dst[i] = c10::convert<Half>(src[i]);
|
| 1570 |
+
}
|
| 1571 |
+
}
|
| 1572 |
+
|
| 1573 |
+
template <>
|
| 1574 |
+
Vectorized<Half> inline fmadd(const Vectorized<Half>& a,
|
| 1575 |
+
const Vectorized<Half>& b, const Vectorized<Half>& c) {
|
| 1576 |
+
__m512 a_lo, a_hi;
|
| 1577 |
+
__m512 b_lo, b_hi;
|
| 1578 |
+
__m512 c_lo, c_hi;
|
| 1579 |
+
cvtfp16_fp32(__m512i(a), a_lo, a_hi);
|
| 1580 |
+
cvtfp16_fp32(__m512i(b), b_lo, b_hi);
|
| 1581 |
+
cvtfp16_fp32(__m512i(c), c_lo, c_hi);
|
| 1582 |
+
auto o1 = _mm512_fmadd_ps(a_lo, b_lo, c_lo);
|
| 1583 |
+
auto o2 = _mm512_fmadd_ps(a_hi, b_hi, c_hi);
|
| 1584 |
+
return cvtfp32_fp16(o1, o2);
|
| 1585 |
+
}
|
| 1586 |
+
|
| 1587 |
+
#define CONVERT_VECTORIZED_INIT(type, name) \
|
| 1588 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_##name##_float(const Vectorized<type>& a) { \
|
| 1589 |
+
__m512 o1, o2; \
|
| 1590 |
+
cvt_to_fp32<type>(__m512i(a), o1, o2); \
|
| 1591 |
+
return std::make_tuple(o1, o2); \
|
| 1592 |
+
} \
|
| 1593 |
+
\
|
| 1594 |
+
inline Vectorized<type> convert_float_##name(const Vectorized<float>& a, const Vectorized<float>& b) { \
|
| 1595 |
+
return cvt_from_fp32<type>(__m512(a), __m512(b)); \
|
| 1596 |
+
}
|
| 1597 |
+
CONVERT_VECTORIZED_INIT(BFloat16, bfloat16)
|
| 1598 |
+
CONVERT_VECTORIZED_INIT(Half, half)
|
| 1599 |
+
|
| 1600 |
+
#else //defined(CPU_CAPABILITY_AVX512)
|
| 1601 |
+
|
| 1602 |
+
#define CONVERT_NON_VECTORIZED_INIT(type, name) \
|
| 1603 |
+
inline std::tuple<Vectorized<float>, Vectorized<float>> convert_##name##_float(const Vectorized<type>& a) { \
|
| 1604 |
+
constexpr int64_t K = Vectorized<type>::size(); \
|
| 1605 |
+
__at_align__ float arr[K]; \
|
| 1606 |
+
__at_align__ type arr2[K]; \
|
| 1607 |
+
a.store(arr2); \
|
| 1608 |
+
for (const auto k : c10::irange(K)) { \
|
| 1609 |
+
arr[k] = c10::convert<float>(arr2[k]); \
|
| 1610 |
+
} \
|
| 1611 |
+
return std::make_tuple( \
|
| 1612 |
+
Vectorized<float>::loadu(arr), \
|
| 1613 |
+
Vectorized<float>::loadu(arr + Vectorized<float>::size())); \
|
| 1614 |
+
} \
|
| 1615 |
+
\
|
| 1616 |
+
inline Vectorized<type> convert_float_##name(const Vectorized<float>& a, const Vectorized<float>& b) { \
|
| 1617 |
+
constexpr int64_t K = Vectorized<type>::size(); \
|
| 1618 |
+
__at_align__ float arr[K]; \
|
| 1619 |
+
__at_align__ type arr2[K]; \
|
| 1620 |
+
a.store(arr); \
|
| 1621 |
+
b.store(arr + Vectorized<float>::size()); \
|
| 1622 |
+
for (const auto k : c10::irange(K)) { \
|
| 1623 |
+
arr2[k] = c10::convert<type>(arr[k]); \
|
| 1624 |
+
} \
|
| 1625 |
+
return Vectorized<type>::loadu(arr2); \
|
| 1626 |
+
}
|
| 1627 |
+
CONVERT_NON_VECTORIZED_INIT(BFloat16, bfloat16)
|
| 1628 |
+
CONVERT_NON_VECTORIZED_INIT(Half, half)
|
| 1629 |
+
|
| 1630 |
+
#endif // defined(CPU_CAPABILITY_AVX512)
|
| 1631 |
+
|
| 1632 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 1633 |
+
#define LOAD_FP32_VECTORIZED_INIT(type, name) \
|
| 1634 |
+
inline void load_fp32_from_##name(const type *data, Vectorized<float>& out) { \
|
| 1635 |
+
auto values = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(data)); \
|
| 1636 |
+
__m512 out_values; \
|
| 1637 |
+
cvt_to_fp32<type>(values, out_values); \
|
| 1638 |
+
out = out_values; \
|
| 1639 |
+
} \
|
| 1640 |
+
\
|
| 1641 |
+
inline void load_fp32_from_##name(const type *data, Vectorized<float>& out1, Vectorized<float>& out2) { \
|
| 1642 |
+
auto vec = Vectorized<type>::loadu(data); \
|
| 1643 |
+
__m512 out1_values, out2_values; \
|
| 1644 |
+
cvt_to_fp32<type>(vec, out1_values, out2_values); \
|
| 1645 |
+
out1 = out1_values; \
|
| 1646 |
+
out2 = out2_values; \
|
| 1647 |
+
}
|
| 1648 |
+
LOAD_FP32_VECTORIZED_INIT(BFloat16, bf16)
|
| 1649 |
+
LOAD_FP32_VECTORIZED_INIT(Half, fp16)
|
| 1650 |
+
|
| 1651 |
+
#else // defined(CPU_CAPABILITY_AVX512)
|
| 1652 |
+
#define LOAD_FP32_NON_VECTORIZED_INIT(type, name) \
|
| 1653 |
+
inline void load_fp32_from_##name(const type *data, Vectorized<float>& out) { \
|
| 1654 |
+
__at_align__ float values[Vectorized<float>::size()]; \
|
| 1655 |
+
for (const auto k : c10::irange(Vectorized<float>::size())) { \
|
| 1656 |
+
values[k] = data[k]; \
|
| 1657 |
+
} \
|
| 1658 |
+
out = Vectorized<float>::loadu(values); \
|
| 1659 |
+
} \
|
| 1660 |
+
\
|
| 1661 |
+
inline void load_fp32_from_##name(const type *data, Vectorized<float>& out1, Vectorized<float>& out2) { \
|
| 1662 |
+
load_fp32_from_##name(data, out1); \
|
| 1663 |
+
data += Vectorized<float>::size(); \
|
| 1664 |
+
load_fp32_from_##name(data, out2); \
|
| 1665 |
+
}
|
| 1666 |
+
LOAD_FP32_NON_VECTORIZED_INIT(BFloat16, bf16)
|
| 1667 |
+
LOAD_FP32_NON_VECTORIZED_INIT(Half, fp16)
|
| 1668 |
+
|
| 1669 |
+
#endif
|
| 1670 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_complex_double.h
ADDED
|
@@ -0,0 +1,513 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <c10/util/complex.h>
|
| 7 |
+
#include <c10/util/irange.h>
|
| 8 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 9 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 10 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 11 |
+
#define SLEEF_STATIC_LIBS
|
| 12 |
+
#include <sleef.h>
|
| 13 |
+
#endif
|
| 14 |
+
|
| 15 |
+
namespace at {
|
| 16 |
+
namespace vec {
|
| 17 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 18 |
+
inline namespace CPU_CAPABILITY {
|
| 19 |
+
|
| 20 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 21 |
+
|
| 22 |
+
template <> class Vectorized<c10::complex<double>> {
|
| 23 |
+
private:
|
| 24 |
+
__m512d values;
|
| 25 |
+
static constexpr __m512i zero_vector {0, 0, 0, 0, 0, 0, 0, 0};
|
| 26 |
+
public:
|
| 27 |
+
using value_type = c10::complex<double>;
|
| 28 |
+
using size_type = int;
|
| 29 |
+
static constexpr size_type size() {
|
| 30 |
+
return 4;
|
| 31 |
+
}
|
| 32 |
+
Vectorized() {}
|
| 33 |
+
Vectorized(__m512d v) : values(v) {}
|
| 34 |
+
Vectorized(c10::complex<double> val) {
|
| 35 |
+
double real_value = val.real();
|
| 36 |
+
double imag_value = val.imag();
|
| 37 |
+
values = _mm512_setr_pd(real_value, imag_value, real_value, imag_value,
|
| 38 |
+
real_value, imag_value, real_value, imag_value);
|
| 39 |
+
}
|
| 40 |
+
Vectorized(c10::complex<double> val1, c10::complex<double> val2,
|
| 41 |
+
c10::complex<double> val3, c10::complex<double> val4) {
|
| 42 |
+
values = _mm512_setr_pd(val1.real(), val1.imag(),
|
| 43 |
+
val2.real(), val2.imag(),
|
| 44 |
+
val3.real(), val3.imag(),
|
| 45 |
+
val4.real(), val4.imag());
|
| 46 |
+
}
|
| 47 |
+
operator __m512d() const {
|
| 48 |
+
return values;
|
| 49 |
+
}
|
| 50 |
+
template <int64_t mask>
|
| 51 |
+
static Vectorized<c10::complex<double>> blend(const Vectorized<c10::complex<double>>& a,
|
| 52 |
+
const Vectorized<c10::complex<double>>& b) {
|
| 53 |
+
// convert c10::complex<V> index mask to V index mask: xy -> xxyy
|
| 54 |
+
// NOLINTNEXTLINE(clang-diagnostic-warning)
|
| 55 |
+
switch (mask) {
|
| 56 |
+
case 0:
|
| 57 |
+
return a;
|
| 58 |
+
case 1:
|
| 59 |
+
return _mm512_mask_blend_pd(0x03, a.values, b.values); //b0000 0001 = b0000 0011
|
| 60 |
+
case 2:
|
| 61 |
+
return _mm512_mask_blend_pd(0x0C, a.values, b.values); //b0000 0010 = b0000 1100
|
| 62 |
+
case 3:
|
| 63 |
+
return _mm512_mask_blend_pd(0x0F, a.values, b.values); //b0000 0011 = b0000 1111
|
| 64 |
+
case 4:
|
| 65 |
+
return _mm512_mask_blend_pd(0x30, a.values, b.values); //b0000 0100 = b0011 0000
|
| 66 |
+
case 5:
|
| 67 |
+
return _mm512_mask_blend_pd(0x33, a.values, b.values); //b0000 0101 = b0011 0011
|
| 68 |
+
case 6:
|
| 69 |
+
return _mm512_mask_blend_pd(0x3C, a.values, b.values); //b0000 0110 = b0011 1100
|
| 70 |
+
case 7:
|
| 71 |
+
return _mm512_mask_blend_pd(0x3F, a.values, b.values); //b0000 0111 = b0011 1111
|
| 72 |
+
case 8:
|
| 73 |
+
return _mm512_mask_blend_pd(0xC0, a.values, b.values); //b0000 1000 = b1100 0000
|
| 74 |
+
case 9:
|
| 75 |
+
return _mm512_mask_blend_pd(0xC3, a.values, b.values); //b0000 1001 = b1100 0011
|
| 76 |
+
case 10:
|
| 77 |
+
return _mm512_mask_blend_pd(0xCC, a.values, b.values); //b0000 1010 = b1100 1100
|
| 78 |
+
case 11:
|
| 79 |
+
return _mm512_mask_blend_pd(0xCF, a.values, b.values); //b0000 1011 = b1100 1111
|
| 80 |
+
case 12:
|
| 81 |
+
return _mm512_mask_blend_pd(0xF0, a.values, b.values); //b0000 1100 = b1111 0000
|
| 82 |
+
case 13:
|
| 83 |
+
return _mm512_mask_blend_pd(0xF3, a.values, b.values); //b0000 1101 = b1111 0011
|
| 84 |
+
case 14:
|
| 85 |
+
return _mm512_mask_blend_pd(0xFC, a.values, b.values); //b0000 1110 = b1111 1100
|
| 86 |
+
case 15:
|
| 87 |
+
return _mm512_mask_blend_pd(0xFF, a.values, b.values); //b0000 1111 = b1111 1111
|
| 88 |
+
}
|
| 89 |
+
return b;
|
| 90 |
+
}
|
| 91 |
+
static Vectorized<c10::complex<double>> blendv(const Vectorized<c10::complex<double>>& a,
|
| 92 |
+
const Vectorized<c10::complex<double>>& b,
|
| 93 |
+
const Vectorized<c10::complex<double>>& mask) {
|
| 94 |
+
// convert c10::complex<V> index mask to V index mask: xy -> xxyy
|
| 95 |
+
auto mask_ = _mm512_unpacklo_pd(mask.values, mask.values);
|
| 96 |
+
auto all_ones = _mm512_set1_epi64(0xFFFFFFFFFFFFFFFF);
|
| 97 |
+
auto mmask = _mm512_cmp_epi64_mask(_mm512_castpd_si512(mask_), all_ones, _MM_CMPINT_EQ);
|
| 98 |
+
return _mm512_mask_blend_pd(mmask, a.values, b.values);
|
| 99 |
+
}
|
| 100 |
+
template<typename step_t>
|
| 101 |
+
static Vectorized<c10::complex<double>> arange(c10::complex<double> base = 0.,
|
| 102 |
+
step_t step = static_cast<step_t>(1)) {
|
| 103 |
+
return Vectorized<c10::complex<double>>(base,
|
| 104 |
+
base + c10::complex<double>(1)*step,
|
| 105 |
+
base + c10::complex<double>(2)*step,
|
| 106 |
+
base + c10::complex<double>(3)*step);
|
| 107 |
+
}
|
| 108 |
+
static Vectorized<c10::complex<double>> set(const Vectorized<c10::complex<double>>& a,
|
| 109 |
+
const Vectorized<c10::complex<double>>& b,
|
| 110 |
+
int64_t count = size()) {
|
| 111 |
+
switch (count) {
|
| 112 |
+
case 0:
|
| 113 |
+
return a;
|
| 114 |
+
case 1:
|
| 115 |
+
return blend<1>(a, b);
|
| 116 |
+
case 2:
|
| 117 |
+
return blend<3>(a, b);
|
| 118 |
+
case 3:
|
| 119 |
+
return blend<7>(a, b);
|
| 120 |
+
}
|
| 121 |
+
return b;
|
| 122 |
+
}
|
| 123 |
+
static Vectorized<c10::complex<double>> loadu(const void* ptr, int64_t count = size()) {
|
| 124 |
+
if (count == size())
|
| 125 |
+
return _mm512_loadu_pd(reinterpret_cast<const double*>(ptr));
|
| 126 |
+
|
| 127 |
+
__at_align__ double tmp_values[2*size()];
|
| 128 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 129 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 130 |
+
// instructions while a loop would be compiled to one instruction.
|
| 131 |
+
for (const auto i : c10::irange(2*size())) {
|
| 132 |
+
tmp_values[i] = 0.0;
|
| 133 |
+
}
|
| 134 |
+
std::memcpy(
|
| 135 |
+
tmp_values,
|
| 136 |
+
reinterpret_cast<const double*>(ptr),
|
| 137 |
+
count * sizeof(c10::complex<double>));
|
| 138 |
+
return _mm512_load_pd(tmp_values);
|
| 139 |
+
}
|
| 140 |
+
void store(void* ptr, int count = size()) const {
|
| 141 |
+
if (count == size()) {
|
| 142 |
+
_mm512_storeu_pd(reinterpret_cast<double*>(ptr), values);
|
| 143 |
+
} else if (count > 0) {
|
| 144 |
+
double tmp_values[2*size()];
|
| 145 |
+
_mm512_storeu_pd(reinterpret_cast<double*>(tmp_values), values);
|
| 146 |
+
std::memcpy(ptr, tmp_values, count * sizeof(c10::complex<double>));
|
| 147 |
+
}
|
| 148 |
+
}
|
| 149 |
+
const c10::complex<double>& operator[](int idx) const = delete;
|
| 150 |
+
c10::complex<double>& operator[](int idx) = delete;
|
| 151 |
+
Vectorized<c10::complex<double>> map(c10::complex<double> (*const f)(const c10::complex<double> &)) const {
|
| 152 |
+
__at_align__ c10::complex<double> tmp[size()];
|
| 153 |
+
store(tmp);
|
| 154 |
+
for (const auto i : c10::irange(size())) {
|
| 155 |
+
tmp[i] = f(tmp[i]);
|
| 156 |
+
}
|
| 157 |
+
return loadu(tmp);
|
| 158 |
+
}
|
| 159 |
+
// AVX512 doesn't have horizontal add & horizontal sub instructions.
|
| 160 |
+
// TODO: hadd_pd() & hsub_pd() may have scope for improvement.
|
| 161 |
+
static inline __m512d hadd_pd(__m512d a, __m512d b) {
|
| 162 |
+
__m512i idx1 = _mm512_set_epi64(14, 6, 12, 4, 10, 2, 8, 0);
|
| 163 |
+
__m512i idx2 = _mm512_set_epi64(15, 7, 13, 5, 11, 3, 9, 1);
|
| 164 |
+
return _mm512_add_pd(_mm512_mask_permutex2var_pd(a, 0xff, idx1, b),
|
| 165 |
+
_mm512_mask_permutex2var_pd(a, 0xff, idx2, b));
|
| 166 |
+
}
|
| 167 |
+
static inline __m512d hsub_pd(__m512d a, __m512d b) {
|
| 168 |
+
__m512i idx1 = _mm512_set_epi64(14, 6, 12, 4, 10, 2, 8, 0);
|
| 169 |
+
__m512i idx2 = _mm512_set_epi64(15, 7, 13, 5, 11, 3, 9, 1);
|
| 170 |
+
return _mm512_sub_pd(_mm512_mask_permutex2var_pd(a, 0xff, idx1, b),
|
| 171 |
+
_mm512_mask_permutex2var_pd(a, 0xff, idx2, b));
|
| 172 |
+
}
|
| 173 |
+
__m512d abs_2_() const {
|
| 174 |
+
auto val_2 = _mm512_mul_pd(values, values); // a*a b*b
|
| 175 |
+
return hadd_pd(val_2, val_2); // a*a+b*b a*a+b*b
|
| 176 |
+
}
|
| 177 |
+
__m512d abs_() const {
|
| 178 |
+
auto real = _mm512_movedup_pd(values); // real real
|
| 179 |
+
// movehdup_pd does not exist...
|
| 180 |
+
auto imag = _mm512_permute_pd(values, 0xff); // imag imag
|
| 181 |
+
return Sleef_hypotd8_u05(real, imag); // abs abs
|
| 182 |
+
}
|
| 183 |
+
Vectorized<c10::complex<double>> abs() const {
|
| 184 |
+
const __m512d real_mask = _mm512_castsi512_pd(_mm512_setr_epi64(0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 185 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 186 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 187 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000));
|
| 188 |
+
return _mm512_and_pd(abs_(), real_mask); // abs 0
|
| 189 |
+
}
|
| 190 |
+
__m512d angle_() const {
|
| 191 |
+
//angle = atan2(b/a)
|
| 192 |
+
auto b_a = _mm512_permute_pd(values, 0x55); // b a
|
| 193 |
+
return Sleef_atan2d8_u10(values, b_a); // 90-angle angle
|
| 194 |
+
}
|
| 195 |
+
Vectorized<c10::complex<double>> angle() const {
|
| 196 |
+
const __m512d real_mask = _mm512_castsi512_pd(_mm512_setr_epi64(0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 197 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 198 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 199 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000));
|
| 200 |
+
auto angle = _mm512_permute_pd(angle_(), 0x55); // angle 90-angle
|
| 201 |
+
return _mm512_and_pd(angle, real_mask); // angle 0
|
| 202 |
+
}
|
| 203 |
+
Vectorized<c10::complex<double>> sgn() const {
|
| 204 |
+
auto abs = abs_();
|
| 205 |
+
auto zero = _mm512_setzero_pd();
|
| 206 |
+
auto mask = _mm512_cmp_pd_mask(abs, zero, _CMP_EQ_OQ);
|
| 207 |
+
auto div = _mm512_div_pd(values, abs);
|
| 208 |
+
return _mm512_mask_blend_pd(mask, div, zero);
|
| 209 |
+
}
|
| 210 |
+
__m512d real_() const {
|
| 211 |
+
const __m512d real_mask = _mm512_castsi512_pd(_mm512_setr_epi64(0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 212 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 213 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000,
|
| 214 |
+
0xFFFFFFFFFFFFFFFF, 0x0000000000000000));
|
| 215 |
+
return _mm512_and_pd(values, real_mask);
|
| 216 |
+
}
|
| 217 |
+
Vectorized<c10::complex<double>> real() const {
|
| 218 |
+
return real_();
|
| 219 |
+
}
|
| 220 |
+
__m512d imag_() const {
|
| 221 |
+
const __m512d imag_mask = _mm512_castsi512_pd(_mm512_setr_epi64(0x0000000000000000, 0xFFFFFFFFFFFFFFFF,
|
| 222 |
+
0x0000000000000000, 0xFFFFFFFFFFFFFFFF,
|
| 223 |
+
0x0000000000000000, 0xFFFFFFFFFFFFFFFF,
|
| 224 |
+
0x0000000000000000, 0xFFFFFFFFFFFFFFFF));
|
| 225 |
+
return _mm512_and_pd(values, imag_mask);
|
| 226 |
+
}
|
| 227 |
+
Vectorized<c10::complex<double>> imag() const {
|
| 228 |
+
return _mm512_permute_pd(imag_(), 0x55); //b a
|
| 229 |
+
}
|
| 230 |
+
__m512d conj_() const {
|
| 231 |
+
const __m512d sign_mask = _mm512_setr_pd(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 232 |
+
return _mm512_xor_pd(values, sign_mask); // a -b
|
| 233 |
+
}
|
| 234 |
+
Vectorized<c10::complex<double>> conj() const {
|
| 235 |
+
return conj_();
|
| 236 |
+
}
|
| 237 |
+
Vectorized<c10::complex<double>> log() const {
|
| 238 |
+
// Most trigonomic ops use the log() op to improve complex number performance.
|
| 239 |
+
return map(std::log);
|
| 240 |
+
}
|
| 241 |
+
Vectorized<c10::complex<double>> log2() const {
|
| 242 |
+
const __m512d log2_ = _mm512_set1_pd(std::log(2));
|
| 243 |
+
return _mm512_div_pd(log(), log2_);
|
| 244 |
+
}
|
| 245 |
+
Vectorized<c10::complex<double>> log10() const {
|
| 246 |
+
const __m512d log10_ = _mm512_set1_pd(std::log(10));
|
| 247 |
+
return _mm512_div_pd(log(), log10_);
|
| 248 |
+
}
|
| 249 |
+
Vectorized<c10::complex<double>> log1p() const {
|
| 250 |
+
return map(std::log1p);
|
| 251 |
+
}
|
| 252 |
+
Vectorized<c10::complex<double>> asin() const {
|
| 253 |
+
// asin(x)
|
| 254 |
+
// = -i*ln(iz + sqrt(1 -z^2))
|
| 255 |
+
// = -i*ln((ai - b) + sqrt(1 - (a + bi)*(a + bi)))
|
| 256 |
+
// = -i*ln((-b + ai) + sqrt(1 - (a**2 - b**2) - 2*abi))
|
| 257 |
+
const __m512d one = _mm512_set1_pd(1);
|
| 258 |
+
|
| 259 |
+
auto conj = conj_();
|
| 260 |
+
auto b_a = _mm512_permute_pd(conj, 0x55); //-b a
|
| 261 |
+
auto ab = _mm512_mul_pd(conj, b_a); //-ab -ab
|
| 262 |
+
auto im = _mm512_add_pd(ab, ab); //-2ab -2ab
|
| 263 |
+
|
| 264 |
+
auto val_2 = _mm512_mul_pd(values, values); // a*a b*b
|
| 265 |
+
auto re = hsub_pd(val_2, _mm512_permute_pd(val_2, 0x55)); // a*a-b*b b*b-a*a
|
| 266 |
+
re = _mm512_sub_pd(one, re);
|
| 267 |
+
|
| 268 |
+
auto root = Vectorized(_mm512_mask_blend_pd(0xAA, re, im)).sqrt(); //sqrt(re + i*im)
|
| 269 |
+
auto ln = Vectorized(_mm512_add_pd(b_a, root)).log(); //ln(iz + sqrt())
|
| 270 |
+
return Vectorized(_mm512_permute_pd(ln.values, 0x55)).conj(); //-i*ln()
|
| 271 |
+
}
|
| 272 |
+
Vectorized<c10::complex<double>> acos() const {
|
| 273 |
+
// acos(x) = pi/2 - asin(x)
|
| 274 |
+
constexpr auto pi_2d = c10::pi<double> / 2;
|
| 275 |
+
const __m512d pi_2 = _mm512_setr_pd(pi_2d, 0.0, pi_2d, 0.0, pi_2d, 0.0, pi_2d, 0.0);
|
| 276 |
+
return _mm512_sub_pd(pi_2, asin());
|
| 277 |
+
}
|
| 278 |
+
Vectorized<c10::complex<double>> atan() const;
|
| 279 |
+
Vectorized<c10::complex<double>> atanh() const {
|
| 280 |
+
return map(std::atanh);
|
| 281 |
+
}
|
| 282 |
+
Vectorized<c10::complex<double>> exp() const {
|
| 283 |
+
//exp(a + bi)
|
| 284 |
+
// = exp(a)*(cos(b) + sin(b)i)
|
| 285 |
+
auto exp = Sleef_expd8_u10(values); //exp(a) exp(b)
|
| 286 |
+
exp = _mm512_mask_blend_pd(0xAA, exp, _mm512_permute_pd(exp, 0x55)); //exp(a) exp(a)
|
| 287 |
+
|
| 288 |
+
auto sin_cos = Sleef_sincosd8_u10(values); //[sin(a), cos(a)] [sin(b), cos(b)]
|
| 289 |
+
auto cos_sin = _mm512_mask_blend_pd(0xAA, _mm512_permute_pd(sin_cos.y, 0x55),
|
| 290 |
+
sin_cos.x); //cos(b) sin(b)
|
| 291 |
+
return _mm512_mul_pd(exp, cos_sin);
|
| 292 |
+
}
|
| 293 |
+
Vectorized<c10::complex<double>> exp2() const {
|
| 294 |
+
// Use identity 2**x = exp(log(2) * x)
|
| 295 |
+
const __m512d ln_2 = _mm512_set1_pd(c10::ln_2<double>);
|
| 296 |
+
Vectorized<c10::complex<double>> scaled_values = _mm512_mul_pd(values, ln_2);
|
| 297 |
+
return scaled_values.exp();
|
| 298 |
+
}
|
| 299 |
+
Vectorized<c10::complex<double>> expm1() const {
|
| 300 |
+
return map(std::expm1);
|
| 301 |
+
}
|
| 302 |
+
Vectorized<c10::complex<double>> sin() const {
|
| 303 |
+
return map(std::sin);
|
| 304 |
+
}
|
| 305 |
+
Vectorized<c10::complex<double>> sinh() const {
|
| 306 |
+
return map(std::sinh);
|
| 307 |
+
}
|
| 308 |
+
Vectorized<c10::complex<double>> cos() const {
|
| 309 |
+
return map(std::cos);
|
| 310 |
+
}
|
| 311 |
+
Vectorized<c10::complex<double>> cosh() const {
|
| 312 |
+
return map(std::cosh);
|
| 313 |
+
}
|
| 314 |
+
Vectorized<c10::complex<double>> ceil() const {
|
| 315 |
+
return _mm512_ceil_pd(values);
|
| 316 |
+
}
|
| 317 |
+
Vectorized<c10::complex<double>> floor() const {
|
| 318 |
+
return _mm512_floor_pd(values);
|
| 319 |
+
}
|
| 320 |
+
Vectorized<c10::complex<double>> neg() const {
|
| 321 |
+
auto zero = _mm512_setzero_pd();
|
| 322 |
+
return _mm512_sub_pd(zero, values);
|
| 323 |
+
}
|
| 324 |
+
Vectorized<c10::complex<double>> round() const {
|
| 325 |
+
return _mm512_roundscale_pd(values, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 326 |
+
}
|
| 327 |
+
Vectorized<c10::complex<double>> tan() const {
|
| 328 |
+
return map(std::tan);
|
| 329 |
+
}
|
| 330 |
+
Vectorized<c10::complex<double>> tanh() const {
|
| 331 |
+
return map(std::tanh);
|
| 332 |
+
}
|
| 333 |
+
Vectorized<c10::complex<double>> trunc() const {
|
| 334 |
+
return _mm512_roundscale_pd(values, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 335 |
+
}
|
| 336 |
+
Vectorized<c10::complex<double>> sqrt() const {
|
| 337 |
+
return map(std::sqrt);
|
| 338 |
+
}
|
| 339 |
+
Vectorized<c10::complex<double>> reciprocal() const;
|
| 340 |
+
Vectorized<c10::complex<double>> rsqrt() const {
|
| 341 |
+
return sqrt().reciprocal();
|
| 342 |
+
}
|
| 343 |
+
Vectorized<c10::complex<double>> pow(const Vectorized<c10::complex<double>> &exp) const {
|
| 344 |
+
__at_align__ c10::complex<double> x_tmp[size()];
|
| 345 |
+
__at_align__ c10::complex<double> y_tmp[size()];
|
| 346 |
+
store(x_tmp);
|
| 347 |
+
exp.store(y_tmp);
|
| 348 |
+
for (const auto i : c10::irange(size())) {
|
| 349 |
+
x_tmp[i] = std::pow(x_tmp[i], y_tmp[i]);
|
| 350 |
+
}
|
| 351 |
+
return loadu(x_tmp);
|
| 352 |
+
}
|
| 353 |
+
// Comparison using the _CMP_**_OQ predicate.
|
| 354 |
+
// `O`: get false if an operand is NaN
|
| 355 |
+
// `Q`: do not raise if an operand is NaN
|
| 356 |
+
Vectorized<c10::complex<double>> operator==(const Vectorized<c10::complex<double>>& other) const {
|
| 357 |
+
auto mask = _mm512_cmp_pd_mask(values, other.values, _CMP_EQ_OQ);
|
| 358 |
+
return _mm512_castsi512_pd(_mm512_mask_set1_epi64(zero_vector, mask,
|
| 359 |
+
0xFFFFFFFFFFFFFFFF));
|
| 360 |
+
}
|
| 361 |
+
Vectorized<c10::complex<double>> operator!=(const Vectorized<c10::complex<double>>& other) const {
|
| 362 |
+
auto mask = _mm512_cmp_pd_mask(values, other.values, _CMP_NEQ_UQ);
|
| 363 |
+
return _mm512_castsi512_pd(_mm512_mask_set1_epi64(zero_vector, mask,
|
| 364 |
+
0xFFFFFFFFFFFFFFFF));
|
| 365 |
+
}
|
| 366 |
+
Vectorized<c10::complex<double>> operator<(const Vectorized<c10::complex<double>>& other [[maybe_unused]]) const {
|
| 367 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 368 |
+
}
|
| 369 |
+
Vectorized<c10::complex<double>> operator<=(const Vectorized<c10::complex<double>>& other [[maybe_unused]]) const {
|
| 370 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 371 |
+
}
|
| 372 |
+
Vectorized<c10::complex<double>> operator>(const Vectorized<c10::complex<double>>& other [[maybe_unused]]) const {
|
| 373 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 374 |
+
}
|
| 375 |
+
Vectorized<c10::complex<double>> operator>=(const Vectorized<c10::complex<double>>& other [[maybe_unused]]) const {
|
| 376 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
Vectorized<c10::complex<double>> eq(const Vectorized<c10::complex<double>>& other) const;
|
| 380 |
+
Vectorized<c10::complex<double>> ne(const Vectorized<c10::complex<double>>& other) const;
|
| 381 |
+
};
|
| 382 |
+
|
| 383 |
+
template <> Vectorized<c10::complex<double>> inline operator+(const Vectorized<c10::complex<double>> &a,
|
| 384 |
+
const Vectorized<c10::complex<double>> &b) {
|
| 385 |
+
return _mm512_add_pd(a, b);
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
template <> Vectorized<c10::complex<double>> inline operator-(const Vectorized<c10::complex<double>> &a,
|
| 389 |
+
const Vectorized<c10::complex<double>> &b) {
|
| 390 |
+
return _mm512_sub_pd(a, b);
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
template <> Vectorized<c10::complex<double>> inline operator*(const Vectorized<c10::complex<double>> &a,
|
| 394 |
+
const Vectorized<c10::complex<double>> &b) {
|
| 395 |
+
//(a + bi) * (c + di) = (ac - bd) + (ad + bc)i
|
| 396 |
+
const __m512d sign_mask = _mm512_setr_pd(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 397 |
+
auto ac_bd = _mm512_mul_pd(a, b); //ac bd
|
| 398 |
+
|
| 399 |
+
auto d_c = _mm512_permute_pd(b, 0x55); //d c
|
| 400 |
+
d_c = _mm512_xor_pd(sign_mask, d_c); //d -c
|
| 401 |
+
auto ad_bc = _mm512_mul_pd(a, d_c); //ad -bc
|
| 402 |
+
|
| 403 |
+
auto ret = Vectorized<c10::complex<double>>::hsub_pd(ac_bd, ad_bc); //ac - bd ad + bc
|
| 404 |
+
return ret;
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
template <> Vectorized<c10::complex<double>> inline operator/(const Vectorized<c10::complex<double>> &a,
|
| 408 |
+
const Vectorized<c10::complex<double>> &b) {
|
| 409 |
+
//re + im*i = (a + bi) / (c + di)
|
| 410 |
+
auto mask = _mm512_set1_pd(-0.f);
|
| 411 |
+
auto fabs_cd = _mm512_andnot_pd(mask, b); // |c| |d|
|
| 412 |
+
auto fabs_dc = _mm512_permute_pd(fabs_cd, 0x55); // |d| |c|
|
| 413 |
+
auto scale = _mm512_rcp14_pd(_mm512_max_pd(fabs_cd, fabs_dc)); // 1/sc 1/sc
|
| 414 |
+
auto a2 = _mm512_mul_pd(a, scale); // a/sc b/sc
|
| 415 |
+
auto b2 = _mm512_mul_pd(b, scale); // c/sc d/sc
|
| 416 |
+
auto acbd2 = _mm512_mul_pd(a2, b2);
|
| 417 |
+
|
| 418 |
+
const __m512d sign_mask = _mm512_setr_pd(-0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0);
|
| 419 |
+
auto dc2 = _mm512_permute_pd(b2, 0x55); // d/sc c/sc
|
| 420 |
+
dc2 = _mm512_xor_pd(sign_mask, dc2); // -d/|c,d| c/sc
|
| 421 |
+
auto adbc2 = _mm512_mul_pd(a2, dc2); //-ad/sc^2 bc/sc^2
|
| 422 |
+
auto res2 = Vectorized<c10::complex<double>>::hadd_pd(acbd2, adbc2); //(ac+bd)/sc^2 (bc-ad)/sc^2
|
| 423 |
+
|
| 424 |
+
// get the denominator
|
| 425 |
+
auto denom2 = Vectorized<c10::complex<double>>(b2).abs_2_(); // (c^2+d^2)/sc^2 (c^2+d^2)/sc^2
|
| 426 |
+
res2 = _mm512_div_pd(res2, denom2);
|
| 427 |
+
return res2;
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
// reciprocal. Implement this here so we can use multiplication.
|
| 431 |
+
inline Vectorized<c10::complex<double>> Vectorized<c10::complex<double>>::reciprocal() const{
|
| 432 |
+
//re + im*i = (a + bi) / (c + di)
|
| 433 |
+
//re = (ac + bd)/abs_2() = c/abs_2()
|
| 434 |
+
//im = (bc - ad)/abs_2() = d/abs_2()
|
| 435 |
+
const __m512d sign_mask = _mm512_setr_pd(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 436 |
+
auto c_d = _mm512_xor_pd(sign_mask, values); //c -d
|
| 437 |
+
return _mm512_div_pd(c_d, abs_2_());
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
inline Vectorized<c10::complex<double>> Vectorized<c10::complex<double>>::atan() const {
|
| 441 |
+
// atan(x) = i/2 * ln((i + z)/(i - z))
|
| 442 |
+
const __m512d i = _mm512_setr_pd(0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
|
| 443 |
+
const Vectorized i_half = _mm512_setr_pd(0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5);
|
| 444 |
+
|
| 445 |
+
auto sum = Vectorized(_mm512_add_pd(i, values)); // a 1+b
|
| 446 |
+
auto sub = Vectorized(_mm512_sub_pd(i, values)); // -a 1-b
|
| 447 |
+
auto ln = (sum/sub).log(); // ln((i + z)/(i - z))
|
| 448 |
+
return i_half*ln; // i/2*ln()
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
template <>
|
| 452 |
+
Vectorized<c10::complex<double>> inline maximum(const Vectorized<c10::complex<double>>& a,
|
| 453 |
+
const Vectorized<c10::complex<double>>& b) {
|
| 454 |
+
auto zero_vec = _mm512_set1_epi64(0);
|
| 455 |
+
auto abs_a = a.abs_2_();
|
| 456 |
+
auto abs_b = b.abs_2_();
|
| 457 |
+
auto mask = _mm512_cmp_pd_mask(abs_a, abs_b, _CMP_LT_OQ);
|
| 458 |
+
auto max = _mm512_mask_blend_pd(mask, a, b);
|
| 459 |
+
// Exploit the fact that all-ones is a NaN.
|
| 460 |
+
auto isnan_mask = _mm512_cmp_pd_mask(abs_a, abs_b, _CMP_UNORD_Q);
|
| 461 |
+
auto isnan = _mm512_mask_set1_epi64(zero_vec, isnan_mask,
|
| 462 |
+
0xFFFFFFFFFFFFFFFF);
|
| 463 |
+
return _mm512_or_pd(max, _mm512_castsi512_pd(isnan));
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
template <>
|
| 467 |
+
Vectorized<c10::complex<double>> inline minimum(const Vectorized<c10::complex<double>>& a,
|
| 468 |
+
const Vectorized<c10::complex<double>>& b) {
|
| 469 |
+
auto zero_vec = _mm512_set1_epi64(0);
|
| 470 |
+
auto abs_a = a.abs_2_();
|
| 471 |
+
auto abs_b = b.abs_2_();
|
| 472 |
+
auto mask = _mm512_cmp_pd_mask(abs_a, abs_b, _CMP_GT_OQ);
|
| 473 |
+
auto min = _mm512_mask_blend_pd(mask, a, b);
|
| 474 |
+
// Exploit the fact that all-ones is a NaN.
|
| 475 |
+
auto isnan_mask = _mm512_cmp_pd_mask(abs_a, abs_b, _CMP_UNORD_Q);
|
| 476 |
+
auto isnan = _mm512_mask_set1_epi64(zero_vec, isnan_mask,
|
| 477 |
+
0xFFFFFFFFFFFFFFFF);
|
| 478 |
+
return _mm512_or_pd(min, _mm512_castsi512_pd(isnan));
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
template <>
|
| 482 |
+
Vectorized<c10::complex<double>> inline operator&(const Vectorized<c10::complex<double>>& a,
|
| 483 |
+
const Vectorized<c10::complex<double>>& b) {
|
| 484 |
+
return _mm512_and_pd(a, b);
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
template <>
|
| 488 |
+
Vectorized<c10::complex<double>> inline operator|(const Vectorized<c10::complex<double>>& a,
|
| 489 |
+
const Vectorized<c10::complex<double>>& b) {
|
| 490 |
+
return _mm512_or_pd(a, b);
|
| 491 |
+
}
|
| 492 |
+
|
| 493 |
+
template <>
|
| 494 |
+
Vectorized<c10::complex<double>> inline operator^(const Vectorized<c10::complex<double>>& a,
|
| 495 |
+
const Vectorized<c10::complex<double>>& b) {
|
| 496 |
+
return _mm512_xor_pd(a, b);
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
inline Vectorized<c10::complex<double>> Vectorized<c10::complex<double>>::eq(const Vectorized<c10::complex<double>>& other) const {
|
| 500 |
+
auto eq = (*this == other); // compares real and imag individually
|
| 501 |
+
// If both real numbers and imag numbers are equal, then the complex numbers are equal
|
| 502 |
+
return (eq.real() & eq.imag()) & Vectorized<c10::complex<double>>(_mm512_set1_pd(1.0));
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
inline Vectorized<c10::complex<double>> Vectorized<c10::complex<double>>::ne(const Vectorized<c10::complex<double>>& other) const {
|
| 506 |
+
auto ne = (*this != other); // compares real and imag individually
|
| 507 |
+
// If either real numbers or imag numbers are not equal, then the complex numbers are not equal
|
| 508 |
+
return (ne.real() | ne.imag()) & Vectorized<c10::complex<double>>(_mm512_set1_pd(1.0));
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
#endif
|
| 512 |
+
|
| 513 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_complex_float.h
ADDED
|
@@ -0,0 +1,1019 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
// DO NOT DEFINE STATIC DATA IN THIS HEADER!
|
| 4 |
+
// See Note [Do not compile initializers with AVX]
|
| 5 |
+
|
| 6 |
+
#include <c10/util/complex.h>
|
| 7 |
+
#include <c10/util/irange.h>
|
| 8 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 9 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 10 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 11 |
+
#define SLEEF_STATIC_LIBS
|
| 12 |
+
#include <sleef.h>
|
| 13 |
+
#endif
|
| 14 |
+
|
| 15 |
+
namespace at {
|
| 16 |
+
namespace vec {
|
| 17 |
+
// See Note [CPU_CAPABILITY namespace]
|
| 18 |
+
inline namespace CPU_CAPABILITY {
|
| 19 |
+
|
| 20 |
+
#if defined(CPU_CAPABILITY_AVX512)
|
| 21 |
+
|
| 22 |
+
template <> class Vectorized<c10::complex<float>> {
|
| 23 |
+
private:
|
| 24 |
+
__m512 values;
|
| 25 |
+
static constexpr __m512i zero_vector {0, 0, 0, 0, 0, 0, 0, 0};
|
| 26 |
+
public:
|
| 27 |
+
using value_type = c10::complex<float>;
|
| 28 |
+
using size_type = int;
|
| 29 |
+
static constexpr size_type size() {
|
| 30 |
+
return 8;
|
| 31 |
+
}
|
| 32 |
+
Vectorized() {}
|
| 33 |
+
Vectorized(__m512 v) : values(v) {}
|
| 34 |
+
Vectorized(c10::complex<float> val) {
|
| 35 |
+
float real_value = val.real();
|
| 36 |
+
float imag_value = val.imag();
|
| 37 |
+
values = _mm512_setr_ps(real_value, imag_value,
|
| 38 |
+
real_value, imag_value,
|
| 39 |
+
real_value, imag_value,
|
| 40 |
+
real_value, imag_value,
|
| 41 |
+
real_value, imag_value,
|
| 42 |
+
real_value, imag_value,
|
| 43 |
+
real_value, imag_value,
|
| 44 |
+
real_value, imag_value);
|
| 45 |
+
}
|
| 46 |
+
Vectorized(c10::complex<float> val1, c10::complex<float> val2,
|
| 47 |
+
c10::complex<float> val3, c10::complex<float> val4,
|
| 48 |
+
c10::complex<float> val5, c10::complex<float> val6,
|
| 49 |
+
c10::complex<float> val7, c10::complex<float> val8) {
|
| 50 |
+
values = _mm512_setr_ps(val1.real(), val1.imag(),
|
| 51 |
+
val2.real(), val2.imag(),
|
| 52 |
+
val3.real(), val3.imag(),
|
| 53 |
+
val4.real(), val4.imag(),
|
| 54 |
+
val5.real(), val5.imag(),
|
| 55 |
+
val6.real(), val6.imag(),
|
| 56 |
+
val7.real(), val7.imag(),
|
| 57 |
+
val8.real(), val8.imag());
|
| 58 |
+
}
|
| 59 |
+
operator __m512() const {
|
| 60 |
+
return values;
|
| 61 |
+
}
|
| 62 |
+
template <int64_t mask>
|
| 63 |
+
static Vectorized<c10::complex<float>> blend(const Vectorized<c10::complex<float>>& a,
|
| 64 |
+
const Vectorized<c10::complex<float>>& b) {
|
| 65 |
+
// convert c10::complex<V> index mask to V index mask: xy -> xxyy
|
| 66 |
+
static_assert(mask > -1 && mask < 256, "Unexpected mask value");
|
| 67 |
+
// The compiler would hopefully convert this switch condition
|
| 68 |
+
// into a jump table
|
| 69 |
+
switch (mask) {
|
| 70 |
+
case 0:
|
| 71 |
+
return a;
|
| 72 |
+
case 1:
|
| 73 |
+
return _mm512_mask_blend_ps(0x03, a.values, b.values);
|
| 74 |
+
case 2:
|
| 75 |
+
return _mm512_mask_blend_ps(0x0C, a.values, b.values);
|
| 76 |
+
case 3:
|
| 77 |
+
return _mm512_mask_blend_ps(0x0F, a.values, b.values);
|
| 78 |
+
case 4:
|
| 79 |
+
return _mm512_mask_blend_ps(0x30, a.values, b.values);
|
| 80 |
+
case 5:
|
| 81 |
+
return _mm512_mask_blend_ps(0x33, a.values, b.values);
|
| 82 |
+
case 6:
|
| 83 |
+
return _mm512_mask_blend_ps(0x3C, a.values, b.values);
|
| 84 |
+
case 7:
|
| 85 |
+
return _mm512_mask_blend_ps(0x3F, a.values, b.values);
|
| 86 |
+
case 8:
|
| 87 |
+
return _mm512_mask_blend_ps(0xC0, a.values, b.values);
|
| 88 |
+
case 9:
|
| 89 |
+
return _mm512_mask_blend_ps(0xC3, a.values, b.values);
|
| 90 |
+
case 10:
|
| 91 |
+
return _mm512_mask_blend_ps(0xCC, a.values, b.values);
|
| 92 |
+
case 11:
|
| 93 |
+
return _mm512_mask_blend_ps(0xCF, a.values, b.values);
|
| 94 |
+
case 12:
|
| 95 |
+
return _mm512_mask_blend_ps(0xF0, a.values, b.values);
|
| 96 |
+
case 13:
|
| 97 |
+
return _mm512_mask_blend_ps(0xF3, a.values, b.values);
|
| 98 |
+
case 14:
|
| 99 |
+
return _mm512_mask_blend_ps(0xFC, a.values, b.values);
|
| 100 |
+
case 15:
|
| 101 |
+
return _mm512_mask_blend_ps(0xFF, a.values, b.values);
|
| 102 |
+
case 16:
|
| 103 |
+
return _mm512_mask_blend_ps(0x300, a.values, b.values);
|
| 104 |
+
case 17:
|
| 105 |
+
return _mm512_mask_blend_ps(0x303, a.values, b.values);
|
| 106 |
+
case 18:
|
| 107 |
+
return _mm512_mask_blend_ps(0x30C, a.values, b.values);
|
| 108 |
+
case 19:
|
| 109 |
+
return _mm512_mask_blend_ps(0x30F, a.values, b.values);
|
| 110 |
+
case 20:
|
| 111 |
+
return _mm512_mask_blend_ps(0x330, a.values, b.values);
|
| 112 |
+
case 21:
|
| 113 |
+
return _mm512_mask_blend_ps(0x333, a.values, b.values);
|
| 114 |
+
case 22:
|
| 115 |
+
return _mm512_mask_blend_ps(0x33C, a.values, b.values);
|
| 116 |
+
case 23:
|
| 117 |
+
return _mm512_mask_blend_ps(0x33F, a.values, b.values);
|
| 118 |
+
case 24:
|
| 119 |
+
return _mm512_mask_blend_ps(0x3C0, a.values, b.values);
|
| 120 |
+
case 25:
|
| 121 |
+
return _mm512_mask_blend_ps(0x3C3, a.values, b.values);
|
| 122 |
+
case 26:
|
| 123 |
+
return _mm512_mask_blend_ps(0x3CC, a.values, b.values);
|
| 124 |
+
case 27:
|
| 125 |
+
return _mm512_mask_blend_ps(0x3CF, a.values, b.values);
|
| 126 |
+
case 28:
|
| 127 |
+
return _mm512_mask_blend_ps(0x3F0, a.values, b.values);
|
| 128 |
+
case 29:
|
| 129 |
+
return _mm512_mask_blend_ps(0x3F3, a.values, b.values);
|
| 130 |
+
case 30:
|
| 131 |
+
return _mm512_mask_blend_ps(0x3FC, a.values, b.values);
|
| 132 |
+
case 31:
|
| 133 |
+
return _mm512_mask_blend_ps(0x3FF, a.values, b.values);
|
| 134 |
+
case 32:
|
| 135 |
+
return _mm512_mask_blend_ps(0xC00, a.values, b.values);
|
| 136 |
+
case 33:
|
| 137 |
+
return _mm512_mask_blend_ps(0xC03, a.values, b.values);
|
| 138 |
+
case 34:
|
| 139 |
+
return _mm512_mask_blend_ps(0xC0C, a.values, b.values);
|
| 140 |
+
case 35:
|
| 141 |
+
return _mm512_mask_blend_ps(0xC0F, a.values, b.values);
|
| 142 |
+
case 36:
|
| 143 |
+
return _mm512_mask_blend_ps(0xC30, a.values, b.values);
|
| 144 |
+
case 37:
|
| 145 |
+
return _mm512_mask_blend_ps(0xC33, a.values, b.values);
|
| 146 |
+
case 38:
|
| 147 |
+
return _mm512_mask_blend_ps(0xC3C, a.values, b.values);
|
| 148 |
+
case 39:
|
| 149 |
+
return _mm512_mask_blend_ps(0xC3F, a.values, b.values);
|
| 150 |
+
case 40:
|
| 151 |
+
return _mm512_mask_blend_ps(0xCC0, a.values, b.values);
|
| 152 |
+
case 41:
|
| 153 |
+
return _mm512_mask_blend_ps(0xCC3, a.values, b.values);
|
| 154 |
+
case 42:
|
| 155 |
+
return _mm512_mask_blend_ps(0xCCC, a.values, b.values);
|
| 156 |
+
case 43:
|
| 157 |
+
return _mm512_mask_blend_ps(0xCCF, a.values, b.values);
|
| 158 |
+
case 44:
|
| 159 |
+
return _mm512_mask_blend_ps(0xCF0, a.values, b.values);
|
| 160 |
+
case 45:
|
| 161 |
+
return _mm512_mask_blend_ps(0xCF3, a.values, b.values);
|
| 162 |
+
case 46:
|
| 163 |
+
return _mm512_mask_blend_ps(0xCFC, a.values, b.values);
|
| 164 |
+
case 47:
|
| 165 |
+
return _mm512_mask_blend_ps(0xCFF, a.values, b.values);
|
| 166 |
+
case 48:
|
| 167 |
+
return _mm512_mask_blend_ps(0xF00, a.values, b.values);
|
| 168 |
+
case 49:
|
| 169 |
+
return _mm512_mask_blend_ps(0xF03, a.values, b.values);
|
| 170 |
+
case 50:
|
| 171 |
+
return _mm512_mask_blend_ps(0xF0C, a.values, b.values);
|
| 172 |
+
case 51:
|
| 173 |
+
return _mm512_mask_blend_ps(0xF0F, a.values, b.values);
|
| 174 |
+
case 52:
|
| 175 |
+
return _mm512_mask_blend_ps(0xF30, a.values, b.values);
|
| 176 |
+
case 53:
|
| 177 |
+
return _mm512_mask_blend_ps(0xF33, a.values, b.values);
|
| 178 |
+
case 54:
|
| 179 |
+
return _mm512_mask_blend_ps(0xF3C, a.values, b.values);
|
| 180 |
+
case 55:
|
| 181 |
+
return _mm512_mask_blend_ps(0xF3F, a.values, b.values);
|
| 182 |
+
case 56:
|
| 183 |
+
return _mm512_mask_blend_ps(0xFC0, a.values, b.values);
|
| 184 |
+
case 57:
|
| 185 |
+
return _mm512_mask_blend_ps(0xFC3, a.values, b.values);
|
| 186 |
+
case 58:
|
| 187 |
+
return _mm512_mask_blend_ps(0xFCC, a.values, b.values);
|
| 188 |
+
case 59:
|
| 189 |
+
return _mm512_mask_blend_ps(0xFCF, a.values, b.values);
|
| 190 |
+
case 60:
|
| 191 |
+
return _mm512_mask_blend_ps(0xFF0, a.values, b.values);
|
| 192 |
+
case 61:
|
| 193 |
+
return _mm512_mask_blend_ps(0xFF3, a.values, b.values);
|
| 194 |
+
case 62:
|
| 195 |
+
return _mm512_mask_blend_ps(0xFFC, a.values, b.values);
|
| 196 |
+
case 63:
|
| 197 |
+
return _mm512_mask_blend_ps(0xFFF, a.values, b.values);
|
| 198 |
+
case 64:
|
| 199 |
+
return _mm512_mask_blend_ps(0x3000, a.values, b.values);
|
| 200 |
+
case 65:
|
| 201 |
+
return _mm512_mask_blend_ps(0x3003, a.values, b.values);
|
| 202 |
+
case 66:
|
| 203 |
+
return _mm512_mask_blend_ps(0x300C, a.values, b.values);
|
| 204 |
+
case 67:
|
| 205 |
+
return _mm512_mask_blend_ps(0x300F, a.values, b.values);
|
| 206 |
+
case 68:
|
| 207 |
+
return _mm512_mask_blend_ps(0x3030, a.values, b.values);
|
| 208 |
+
case 69:
|
| 209 |
+
return _mm512_mask_blend_ps(0x3033, a.values, b.values);
|
| 210 |
+
case 70:
|
| 211 |
+
return _mm512_mask_blend_ps(0x303C, a.values, b.values);
|
| 212 |
+
case 71:
|
| 213 |
+
return _mm512_mask_blend_ps(0x303F, a.values, b.values);
|
| 214 |
+
case 72:
|
| 215 |
+
return _mm512_mask_blend_ps(0x30C0, a.values, b.values);
|
| 216 |
+
case 73:
|
| 217 |
+
return _mm512_mask_blend_ps(0X30C3, a.values, b.values);
|
| 218 |
+
case 74:
|
| 219 |
+
return _mm512_mask_blend_ps(0x30CC, a.values, b.values);
|
| 220 |
+
case 75:
|
| 221 |
+
return _mm512_mask_blend_ps(0x30CF, a.values, b.values);
|
| 222 |
+
case 76:
|
| 223 |
+
return _mm512_mask_blend_ps(0x30F0, a.values, b.values);
|
| 224 |
+
case 77:
|
| 225 |
+
return _mm512_mask_blend_ps(0x30F3, a.values, b.values);
|
| 226 |
+
case 78:
|
| 227 |
+
return _mm512_mask_blend_ps(0x30FC, a.values, b.values);
|
| 228 |
+
case 79:
|
| 229 |
+
return _mm512_mask_blend_ps(0x30FF, a.values, b.values);
|
| 230 |
+
case 80:
|
| 231 |
+
return _mm512_mask_blend_ps(0x3300, a.values, b.values);
|
| 232 |
+
case 81:
|
| 233 |
+
return _mm512_mask_blend_ps(0X3303, a.values, b.values);
|
| 234 |
+
case 82:
|
| 235 |
+
return _mm512_mask_blend_ps(0x330C, a.values, b.values);
|
| 236 |
+
case 83:
|
| 237 |
+
return _mm512_mask_blend_ps(0x330F, a.values, b.values);
|
| 238 |
+
case 84:
|
| 239 |
+
return _mm512_mask_blend_ps(0x3330, a.values, b.values);
|
| 240 |
+
case 85:
|
| 241 |
+
return _mm512_mask_blend_ps(0x3333, a.values, b.values);
|
| 242 |
+
case 86:
|
| 243 |
+
return _mm512_mask_blend_ps(0x333C, a.values, b.values);
|
| 244 |
+
case 87:
|
| 245 |
+
return _mm512_mask_blend_ps(0X333F, a.values, b.values);
|
| 246 |
+
case 88:
|
| 247 |
+
return _mm512_mask_blend_ps(0x33C0, a.values, b.values);
|
| 248 |
+
case 89:
|
| 249 |
+
return _mm512_mask_blend_ps(0x33C3, a.values, b.values);
|
| 250 |
+
case 90:
|
| 251 |
+
return _mm512_mask_blend_ps(0x33CC, a.values, b.values);
|
| 252 |
+
case 91:
|
| 253 |
+
return _mm512_mask_blend_ps(0x33CF, a.values, b.values);
|
| 254 |
+
case 92:
|
| 255 |
+
return _mm512_mask_blend_ps(0x33F0, a.values, b.values);
|
| 256 |
+
case 93:
|
| 257 |
+
return _mm512_mask_blend_ps(0x33F3, a.values, b.values);
|
| 258 |
+
case 94:
|
| 259 |
+
return _mm512_mask_blend_ps(0x33FC, a.values, b.values);
|
| 260 |
+
case 95:
|
| 261 |
+
return _mm512_mask_blend_ps(0x33FF, a.values, b.values);
|
| 262 |
+
case 96:
|
| 263 |
+
return _mm512_mask_blend_ps(0X3C00, a.values, b.values);
|
| 264 |
+
case 97:
|
| 265 |
+
return _mm512_mask_blend_ps(0x3C03, a.values, b.values);
|
| 266 |
+
case 98:
|
| 267 |
+
return _mm512_mask_blend_ps(0x3C0C, a.values, b.values);
|
| 268 |
+
case 99:
|
| 269 |
+
return _mm512_mask_blend_ps(0x3C0F, a.values, b.values);
|
| 270 |
+
case 100:
|
| 271 |
+
return _mm512_mask_blend_ps(0x3C30, a.values, b.values);
|
| 272 |
+
case 101:
|
| 273 |
+
return _mm512_mask_blend_ps(0x3C33, a.values, b.values);
|
| 274 |
+
case 102:
|
| 275 |
+
return _mm512_mask_blend_ps(0x3C3C, a.values, b.values);
|
| 276 |
+
case 103:
|
| 277 |
+
return _mm512_mask_blend_ps(0x3C3F, a.values, b.values);
|
| 278 |
+
case 104:
|
| 279 |
+
return _mm512_mask_blend_ps(0x3CC0, a.values, b.values);
|
| 280 |
+
case 105:
|
| 281 |
+
return _mm512_mask_blend_ps(0x3CC3, a.values, b.values);
|
| 282 |
+
case 106:
|
| 283 |
+
return _mm512_mask_blend_ps(0x3CCC, a.values, b.values);
|
| 284 |
+
case 107:
|
| 285 |
+
return _mm512_mask_blend_ps(0x3CCF, a.values, b.values);
|
| 286 |
+
case 108:
|
| 287 |
+
return _mm512_mask_blend_ps(0x3CF0, a.values, b.values);
|
| 288 |
+
case 109:
|
| 289 |
+
return _mm512_mask_blend_ps(0x3CF3, a.values, b.values);
|
| 290 |
+
case 110:
|
| 291 |
+
return _mm512_mask_blend_ps(0x3CFC, a.values, b.values);
|
| 292 |
+
case 111:
|
| 293 |
+
return _mm512_mask_blend_ps(0x3CFF, a.values, b.values);
|
| 294 |
+
case 112:
|
| 295 |
+
return _mm512_mask_blend_ps(0x3F00, a.values, b.values);
|
| 296 |
+
case 113:
|
| 297 |
+
return _mm512_mask_blend_ps(0x3F03, a.values, b.values);
|
| 298 |
+
case 114:
|
| 299 |
+
return _mm512_mask_blend_ps(0x3F0C, a.values, b.values);
|
| 300 |
+
case 115:
|
| 301 |
+
return _mm512_mask_blend_ps(0x3F0F, a.values, b.values);
|
| 302 |
+
case 116:
|
| 303 |
+
return _mm512_mask_blend_ps(0x3F30, a.values, b.values);
|
| 304 |
+
case 117:
|
| 305 |
+
return _mm512_mask_blend_ps(0x3F33, a.values, b.values);
|
| 306 |
+
case 118:
|
| 307 |
+
return _mm512_mask_blend_ps(0x3F3C, a.values, b.values);
|
| 308 |
+
case 119:
|
| 309 |
+
return _mm512_mask_blend_ps(0x3F3F, a.values, b.values);
|
| 310 |
+
case 120:
|
| 311 |
+
return _mm512_mask_blend_ps(0x3FC0, a.values, b.values);
|
| 312 |
+
case 121:
|
| 313 |
+
return _mm512_mask_blend_ps(0x3FC3, a.values, b.values);
|
| 314 |
+
case 122:
|
| 315 |
+
return _mm512_mask_blend_ps(0x3FCC, a.values, b.values);
|
| 316 |
+
case 123:
|
| 317 |
+
return _mm512_mask_blend_ps(0x3FCF, a.values, b.values);
|
| 318 |
+
case 124:
|
| 319 |
+
return _mm512_mask_blend_ps(0x3FF0, a.values, b.values);
|
| 320 |
+
case 125:
|
| 321 |
+
return _mm512_mask_blend_ps(0x3FF3, a.values, b.values);
|
| 322 |
+
case 126:
|
| 323 |
+
return _mm512_mask_blend_ps(0x3FFC, a.values, b.values);
|
| 324 |
+
case 127:
|
| 325 |
+
return _mm512_mask_blend_ps(0x3FFF, a.values, b.values);
|
| 326 |
+
case 128:
|
| 327 |
+
return _mm512_mask_blend_ps(0xC000, a.values, b.values);
|
| 328 |
+
case 129:
|
| 329 |
+
return _mm512_mask_blend_ps(0xC003, a.values, b.values);
|
| 330 |
+
case 130:
|
| 331 |
+
return _mm512_mask_blend_ps(0xC00C, a.values, b.values);
|
| 332 |
+
case 131:
|
| 333 |
+
return _mm512_mask_blend_ps(0xC00F, a.values, b.values);
|
| 334 |
+
case 132:
|
| 335 |
+
return _mm512_mask_blend_ps(0xC030, a.values, b.values);
|
| 336 |
+
case 133:
|
| 337 |
+
return _mm512_mask_blend_ps(0xC033, a.values, b.values);
|
| 338 |
+
case 134:
|
| 339 |
+
return _mm512_mask_blend_ps(0xC03C, a.values, b.values);
|
| 340 |
+
case 135:
|
| 341 |
+
return _mm512_mask_blend_ps(0xC03F, a.values, b.values);
|
| 342 |
+
case 136:
|
| 343 |
+
return _mm512_mask_blend_ps(0xC0C0, a.values, b.values);
|
| 344 |
+
case 137:
|
| 345 |
+
return _mm512_mask_blend_ps(0xC0C3, a.values, b.values);
|
| 346 |
+
case 138:
|
| 347 |
+
return _mm512_mask_blend_ps(0xC0CC, a.values, b.values);
|
| 348 |
+
case 139:
|
| 349 |
+
return _mm512_mask_blend_ps(0xC0CF, a.values, b.values);
|
| 350 |
+
case 140:
|
| 351 |
+
return _mm512_mask_blend_ps(0xC0F0, a.values, b.values);
|
| 352 |
+
case 141:
|
| 353 |
+
return _mm512_mask_blend_ps(0xC0F3, a.values, b.values);
|
| 354 |
+
case 142:
|
| 355 |
+
return _mm512_mask_blend_ps(0xC0FC, a.values, b.values);
|
| 356 |
+
case 143:
|
| 357 |
+
return _mm512_mask_blend_ps(0xC0FF, a.values, b.values);
|
| 358 |
+
case 144:
|
| 359 |
+
return _mm512_mask_blend_ps(0xC300, a.values, b.values);
|
| 360 |
+
case 145:
|
| 361 |
+
return _mm512_mask_blend_ps(0xC303, a.values, b.values);
|
| 362 |
+
case 146:
|
| 363 |
+
return _mm512_mask_blend_ps(0xC30C, a.values, b.values);
|
| 364 |
+
case 147:
|
| 365 |
+
return _mm512_mask_blend_ps(0xC30F, a.values, b.values);
|
| 366 |
+
case 148:
|
| 367 |
+
return _mm512_mask_blend_ps(0xC330, a.values, b.values);
|
| 368 |
+
case 149:
|
| 369 |
+
return _mm512_mask_blend_ps(0xC333, a.values, b.values);
|
| 370 |
+
case 150:
|
| 371 |
+
return _mm512_mask_blend_ps(0xC33C, a.values, b.values);
|
| 372 |
+
case 151:
|
| 373 |
+
return _mm512_mask_blend_ps(0xC33F, a.values, b.values);
|
| 374 |
+
case 152:
|
| 375 |
+
return _mm512_mask_blend_ps(0xC3C0, a.values, b.values);
|
| 376 |
+
case 153:
|
| 377 |
+
return _mm512_mask_blend_ps(0xC3C3, a.values, b.values);
|
| 378 |
+
case 154:
|
| 379 |
+
return _mm512_mask_blend_ps(0xC3CC, a.values, b.values);
|
| 380 |
+
case 155:
|
| 381 |
+
return _mm512_mask_blend_ps(0xC3CF, a.values, b.values);
|
| 382 |
+
case 156:
|
| 383 |
+
return _mm512_mask_blend_ps(0xC3F0, a.values, b.values);
|
| 384 |
+
case 157:
|
| 385 |
+
return _mm512_mask_blend_ps(0xC3F3, a.values, b.values);
|
| 386 |
+
case 158:
|
| 387 |
+
return _mm512_mask_blend_ps(0xC3FC, a.values, b.values);
|
| 388 |
+
case 159:
|
| 389 |
+
return _mm512_mask_blend_ps(0xC3FF, a.values, b.values);
|
| 390 |
+
case 160:
|
| 391 |
+
return _mm512_mask_blend_ps(0xCC00, a.values, b.values);
|
| 392 |
+
case 161:
|
| 393 |
+
return _mm512_mask_blend_ps(0xCC03, a.values, b.values);
|
| 394 |
+
case 162:
|
| 395 |
+
return _mm512_mask_blend_ps(0xCC0C, a.values, b.values);
|
| 396 |
+
case 163:
|
| 397 |
+
return _mm512_mask_blend_ps(0xCC0F, a.values, b.values);
|
| 398 |
+
case 164:
|
| 399 |
+
return _mm512_mask_blend_ps(0xCC30, a.values, b.values);
|
| 400 |
+
case 165:
|
| 401 |
+
return _mm512_mask_blend_ps(0xCC33, a.values, b.values);
|
| 402 |
+
case 166:
|
| 403 |
+
return _mm512_mask_blend_ps(0xCC3C, a.values, b.values);
|
| 404 |
+
case 167:
|
| 405 |
+
return _mm512_mask_blend_ps(0xCC3F, a.values, b.values);
|
| 406 |
+
case 168:
|
| 407 |
+
return _mm512_mask_blend_ps(0xCCC0, a.values, b.values);
|
| 408 |
+
case 169:
|
| 409 |
+
return _mm512_mask_blend_ps(0xCCC3, a.values, b.values);
|
| 410 |
+
case 170:
|
| 411 |
+
return _mm512_mask_blend_ps(0xCCCC, a.values, b.values);
|
| 412 |
+
case 171:
|
| 413 |
+
return _mm512_mask_blend_ps(0xCCCF, a.values, b.values);
|
| 414 |
+
case 172:
|
| 415 |
+
return _mm512_mask_blend_ps(0xCCF0, a.values, b.values);
|
| 416 |
+
case 173:
|
| 417 |
+
return _mm512_mask_blend_ps(0xCCF3, a.values, b.values);
|
| 418 |
+
case 174:
|
| 419 |
+
return _mm512_mask_blend_ps(0xCCFC, a.values, b.values);
|
| 420 |
+
case 175:
|
| 421 |
+
return _mm512_mask_blend_ps(0xCCFF, a.values, b.values);
|
| 422 |
+
case 176:
|
| 423 |
+
return _mm512_mask_blend_ps(0xCF00, a.values, b.values);
|
| 424 |
+
case 177:
|
| 425 |
+
return _mm512_mask_blend_ps(0xCF03, a.values, b.values);
|
| 426 |
+
case 178:
|
| 427 |
+
return _mm512_mask_blend_ps(0xCF0C, a.values, b.values);
|
| 428 |
+
case 179:
|
| 429 |
+
return _mm512_mask_blend_ps(0xCF0F, a.values, b.values);
|
| 430 |
+
case 180:
|
| 431 |
+
return _mm512_mask_blend_ps(0xCF30, a.values, b.values);
|
| 432 |
+
case 181:
|
| 433 |
+
return _mm512_mask_blend_ps(0xCF33, a.values, b.values);
|
| 434 |
+
case 182:
|
| 435 |
+
return _mm512_mask_blend_ps(0xCF3C, a.values, b.values);
|
| 436 |
+
case 183:
|
| 437 |
+
return _mm512_mask_blend_ps(0xCF3F, a.values, b.values);
|
| 438 |
+
case 184:
|
| 439 |
+
return _mm512_mask_blend_ps(0xCFC0, a.values, b.values);
|
| 440 |
+
case 185:
|
| 441 |
+
return _mm512_mask_blend_ps(0xCFC3, a.values, b.values);
|
| 442 |
+
case 186:
|
| 443 |
+
return _mm512_mask_blend_ps(0xCFCC, a.values, b.values);
|
| 444 |
+
case 187:
|
| 445 |
+
return _mm512_mask_blend_ps(0xCFCF, a.values, b.values);
|
| 446 |
+
case 188:
|
| 447 |
+
return _mm512_mask_blend_ps(0xCFF0, a.values, b.values);
|
| 448 |
+
case 189:
|
| 449 |
+
return _mm512_mask_blend_ps(0xCFF3, a.values, b.values);
|
| 450 |
+
case 190:
|
| 451 |
+
return _mm512_mask_blend_ps(0xCFFC, a.values, b.values);
|
| 452 |
+
case 191:
|
| 453 |
+
return _mm512_mask_blend_ps(0xCFFF, a.values, b.values);
|
| 454 |
+
case 192:
|
| 455 |
+
return _mm512_mask_blend_ps(0xF000, a.values, b.values);
|
| 456 |
+
case 193:
|
| 457 |
+
return _mm512_mask_blend_ps(0xF003, a.values, b.values);
|
| 458 |
+
case 194:
|
| 459 |
+
return _mm512_mask_blend_ps(0xF00C, a.values, b.values);
|
| 460 |
+
case 195:
|
| 461 |
+
return _mm512_mask_blend_ps(0xF00F, a.values, b.values);
|
| 462 |
+
case 196:
|
| 463 |
+
return _mm512_mask_blend_ps(0xF030, a.values, b.values);
|
| 464 |
+
case 197:
|
| 465 |
+
return _mm512_mask_blend_ps(0xF033, a.values, b.values);
|
| 466 |
+
case 198:
|
| 467 |
+
return _mm512_mask_blend_ps(0xF03C, a.values, b.values);
|
| 468 |
+
case 199:
|
| 469 |
+
return _mm512_mask_blend_ps(0xF03F, a.values, b.values);
|
| 470 |
+
case 200:
|
| 471 |
+
return _mm512_mask_blend_ps(0XF0C0, a.values, b.values);
|
| 472 |
+
case 201:
|
| 473 |
+
return _mm512_mask_blend_ps(0xF0C3, a.values, b.values);
|
| 474 |
+
case 202:
|
| 475 |
+
return _mm512_mask_blend_ps(0xF0CC, a.values, b.values);
|
| 476 |
+
case 203:
|
| 477 |
+
return _mm512_mask_blend_ps(0xF0CF, a.values, b.values);
|
| 478 |
+
case 204:
|
| 479 |
+
return _mm512_mask_blend_ps(0xF0F0, a.values, b.values);
|
| 480 |
+
case 205:
|
| 481 |
+
return _mm512_mask_blend_ps(0xF0F3, a.values, b.values);
|
| 482 |
+
case 206:
|
| 483 |
+
return _mm512_mask_blend_ps(0xF0FC, a.values, b.values);
|
| 484 |
+
case 207:
|
| 485 |
+
return _mm512_mask_blend_ps(0xF0FF, a.values, b.values);
|
| 486 |
+
case 208:
|
| 487 |
+
return _mm512_mask_blend_ps(0XF300, a.values, b.values);
|
| 488 |
+
case 209:
|
| 489 |
+
return _mm512_mask_blend_ps(0xF303, a.values, b.values);
|
| 490 |
+
case 210:
|
| 491 |
+
return _mm512_mask_blend_ps(0xF30C, a.values, b.values);
|
| 492 |
+
case 211:
|
| 493 |
+
return _mm512_mask_blend_ps(0xF30F, a.values, b.values);
|
| 494 |
+
case 212:
|
| 495 |
+
return _mm512_mask_blend_ps(0xF330, a.values, b.values);
|
| 496 |
+
case 213:
|
| 497 |
+
return _mm512_mask_blend_ps(0xF333, a.values, b.values);
|
| 498 |
+
case 214:
|
| 499 |
+
return _mm512_mask_blend_ps(0XF33C, a.values, b.values);
|
| 500 |
+
case 215:
|
| 501 |
+
return _mm512_mask_blend_ps(0xF33F, a.values, b.values);
|
| 502 |
+
case 216:
|
| 503 |
+
return _mm512_mask_blend_ps(0xF3C0, a.values, b.values);
|
| 504 |
+
case 217:
|
| 505 |
+
return _mm512_mask_blend_ps(0xF3C3, a.values, b.values);
|
| 506 |
+
case 218:
|
| 507 |
+
return _mm512_mask_blend_ps(0xF3CC, a.values, b.values);
|
| 508 |
+
case 219:
|
| 509 |
+
return _mm512_mask_blend_ps(0xF3CF, a.values, b.values);
|
| 510 |
+
case 220:
|
| 511 |
+
return _mm512_mask_blend_ps(0xF3F0, a.values, b.values);
|
| 512 |
+
case 221:
|
| 513 |
+
return _mm512_mask_blend_ps(0xF3F3, a.values, b.values);
|
| 514 |
+
case 222:
|
| 515 |
+
return _mm512_mask_blend_ps(0xF3FC, a.values, b.values);
|
| 516 |
+
case 223:
|
| 517 |
+
return _mm512_mask_blend_ps(0XF3FF, a.values, b.values);
|
| 518 |
+
case 224:
|
| 519 |
+
return _mm512_mask_blend_ps(0xFC00, a.values, b.values);
|
| 520 |
+
case 225:
|
| 521 |
+
return _mm512_mask_blend_ps(0xFC03, a.values, b.values);
|
| 522 |
+
case 226:
|
| 523 |
+
return _mm512_mask_blend_ps(0xFC0C, a.values, b.values);
|
| 524 |
+
case 227:
|
| 525 |
+
return _mm512_mask_blend_ps(0xFC0F, a.values, b.values);
|
| 526 |
+
case 228:
|
| 527 |
+
return _mm512_mask_blend_ps(0xFC30, a.values, b.values);
|
| 528 |
+
case 229:
|
| 529 |
+
return _mm512_mask_blend_ps(0xFC33, a.values, b.values);
|
| 530 |
+
case 230:
|
| 531 |
+
return _mm512_mask_blend_ps(0xFC3C, a.values, b.values);
|
| 532 |
+
case 231:
|
| 533 |
+
return _mm512_mask_blend_ps(0xFC3F, a.values, b.values);
|
| 534 |
+
case 232:
|
| 535 |
+
return _mm512_mask_blend_ps(0xFCC0, a.values, b.values);
|
| 536 |
+
case 233:
|
| 537 |
+
return _mm512_mask_blend_ps(0xFCC3, a.values, b.values);
|
| 538 |
+
case 234:
|
| 539 |
+
return _mm512_mask_blend_ps(0xFCCC, a.values, b.values);
|
| 540 |
+
case 235:
|
| 541 |
+
return _mm512_mask_blend_ps(0xFCCF, a.values, b.values);
|
| 542 |
+
case 236:
|
| 543 |
+
return _mm512_mask_blend_ps(0xFCF0, a.values, b.values);
|
| 544 |
+
case 237:
|
| 545 |
+
return _mm512_mask_blend_ps(0xFCF3, a.values, b.values);
|
| 546 |
+
case 238:
|
| 547 |
+
return _mm512_mask_blend_ps(0xFCFC, a.values, b.values);
|
| 548 |
+
case 239:
|
| 549 |
+
return _mm512_mask_blend_ps(0xFCFF, a.values, b.values);
|
| 550 |
+
case 240:
|
| 551 |
+
return _mm512_mask_blend_ps(0xFF00, a.values, b.values);
|
| 552 |
+
case 241:
|
| 553 |
+
return _mm512_mask_blend_ps(0xFF03, a.values, b.values);
|
| 554 |
+
case 242:
|
| 555 |
+
return _mm512_mask_blend_ps(0xFF0C, a.values, b.values);
|
| 556 |
+
case 243:
|
| 557 |
+
return _mm512_mask_blend_ps(0xFF0F, a.values, b.values);
|
| 558 |
+
case 244:
|
| 559 |
+
return _mm512_mask_blend_ps(0xFF30, a.values, b.values);
|
| 560 |
+
case 245:
|
| 561 |
+
return _mm512_mask_blend_ps(0xFF33, a.values, b.values);
|
| 562 |
+
case 246:
|
| 563 |
+
return _mm512_mask_blend_ps(0xFF3C, a.values, b.values);
|
| 564 |
+
case 247:
|
| 565 |
+
return _mm512_mask_blend_ps(0xFF3F, a.values, b.values);
|
| 566 |
+
case 248:
|
| 567 |
+
return _mm512_mask_blend_ps(0xFFC0, a.values, b.values);
|
| 568 |
+
case 249:
|
| 569 |
+
return _mm512_mask_blend_ps(0xFFC3, a.values, b.values);
|
| 570 |
+
case 250:
|
| 571 |
+
return _mm512_mask_blend_ps(0xFFCC, a.values, b.values);
|
| 572 |
+
case 251:
|
| 573 |
+
return _mm512_mask_blend_ps(0xFFCF, a.values, b.values);
|
| 574 |
+
case 252:
|
| 575 |
+
return _mm512_mask_blend_ps(0xFFF0, a.values, b.values);
|
| 576 |
+
case 253:
|
| 577 |
+
return _mm512_mask_blend_ps(0xFFF3, a.values, b.values);
|
| 578 |
+
case 254:
|
| 579 |
+
return _mm512_mask_blend_ps(0xFFFC, a.values, b.values);
|
| 580 |
+
default: break;
|
| 581 |
+
}
|
| 582 |
+
return b;
|
| 583 |
+
}
|
| 584 |
+
static Vectorized<c10::complex<float>> blendv(const Vectorized<c10::complex<float>>& a,
|
| 585 |
+
const Vectorized<c10::complex<float>>& b,
|
| 586 |
+
const Vectorized<c10::complex<float>>& mask) {
|
| 587 |
+
// convert c10::complex<V> index mask to V index mask: xy -> xxyy
|
| 588 |
+
auto mask_ = _mm512_unpacklo_ps(mask.values, mask.values);
|
| 589 |
+
auto all_ones = _mm512_set1_epi32(0xFFFFFFFF);
|
| 590 |
+
auto mmask = _mm512_cmp_epi32_mask(_mm512_castps_si512(mask_), all_ones, _MM_CMPINT_EQ);
|
| 591 |
+
return _mm512_mask_blend_ps(mmask, a.values, b.values);
|
| 592 |
+
}
|
| 593 |
+
template<typename step_t>
|
| 594 |
+
static Vectorized<c10::complex<float>> arange(c10::complex<float> base = 0.,
|
| 595 |
+
step_t step = static_cast<step_t>(1)) {
|
| 596 |
+
return Vectorized<c10::complex<float>>(base,
|
| 597 |
+
base + step,
|
| 598 |
+
base + c10::complex<float>(2)*step,
|
| 599 |
+
base + c10::complex<float>(3)*step,
|
| 600 |
+
base + c10::complex<float>(4)*step,
|
| 601 |
+
base + c10::complex<float>(5)*step,
|
| 602 |
+
base + c10::complex<float>(6)*step,
|
| 603 |
+
base + c10::complex<float>(7)*step);
|
| 604 |
+
}
|
| 605 |
+
static Vectorized<c10::complex<float>> set(const Vectorized<c10::complex<float>>& a,
|
| 606 |
+
const Vectorized<c10::complex<float>>& b,
|
| 607 |
+
int64_t count = size()) {
|
| 608 |
+
switch (count) {
|
| 609 |
+
case 0:
|
| 610 |
+
return a;
|
| 611 |
+
case 1:
|
| 612 |
+
return blend<1>(a, b);
|
| 613 |
+
case 2:
|
| 614 |
+
return blend<3>(a, b);
|
| 615 |
+
case 3:
|
| 616 |
+
return blend<7>(a, b);
|
| 617 |
+
case 4:
|
| 618 |
+
return blend<15>(a, b);
|
| 619 |
+
case 5:
|
| 620 |
+
return blend<31>(a, b);
|
| 621 |
+
case 6:
|
| 622 |
+
return blend<63>(a, b);
|
| 623 |
+
case 7:
|
| 624 |
+
return blend<127>(a, b);
|
| 625 |
+
}
|
| 626 |
+
return b;
|
| 627 |
+
}
|
| 628 |
+
static Vectorized<c10::complex<float>> loadu(const void* ptr, int64_t count = size()) {
|
| 629 |
+
if (count == size())
|
| 630 |
+
return _mm512_loadu_ps(reinterpret_cast<const float*>(ptr));
|
| 631 |
+
|
| 632 |
+
__at_align__ float tmp_values[2*size()];
|
| 633 |
+
// Ensure uninitialized memory does not change the output value See https://github.com/pytorch/pytorch/issues/32502
|
| 634 |
+
// for more details. We do not initialize arrays to zero using "={0}" because gcc would compile it to two
|
| 635 |
+
// instructions while a loop would be compiled to one instruction.
|
| 636 |
+
for (const auto i : c10::irange(2*size())) {
|
| 637 |
+
tmp_values[i] = 0.0;
|
| 638 |
+
}
|
| 639 |
+
std::memcpy(
|
| 640 |
+
tmp_values,
|
| 641 |
+
reinterpret_cast<const float*>(ptr),
|
| 642 |
+
count * sizeof(c10::complex<float>));
|
| 643 |
+
return _mm512_load_ps(tmp_values);
|
| 644 |
+
}
|
| 645 |
+
void store(void* ptr, int count = size()) const {
|
| 646 |
+
if (count == size()) {
|
| 647 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(ptr), values);
|
| 648 |
+
} else if (count > 0) {
|
| 649 |
+
float tmp_values[2*size()];
|
| 650 |
+
_mm512_storeu_ps(reinterpret_cast<float*>(tmp_values), values);
|
| 651 |
+
std::memcpy(ptr, tmp_values, count * sizeof(c10::complex<float>));
|
| 652 |
+
}
|
| 653 |
+
}
|
| 654 |
+
// AVX512 doesn't have horizontal add & horizontal sub instructions.
|
| 655 |
+
// TODO: hadd_pd() & hsub_pd() may have scope for improvement.
|
| 656 |
+
static inline __m512 hadd_ps(__m512 a, __m512 b) {
|
| 657 |
+
__m512i idx1 = _mm512_set_epi32(30, 14, 28, 12, 26, 10, 24, 8, 22, 6, 20, 4, 18, 2, 16, 0);
|
| 658 |
+
__m512i idx2 = _mm512_set_epi32(31, 15, 29, 13, 27, 11, 25, 9, 23, 7, 21, 5, 19, 3, 17, 1);
|
| 659 |
+
return _mm512_add_ps(_mm512_mask_permutex2var_ps(a, 0xffff, idx1, b),
|
| 660 |
+
_mm512_mask_permutex2var_ps(a, 0xffff, idx2, b));
|
| 661 |
+
}
|
| 662 |
+
static inline __m512 hsub_ps(__m512 a, __m512 b) {
|
| 663 |
+
__m512i idx1 = _mm512_set_epi32(30, 14, 28, 12, 26, 10, 24, 8, 22, 6, 20, 4, 18, 2, 16, 0);
|
| 664 |
+
__m512i idx2 = _mm512_set_epi32(31, 15, 29, 13, 27, 11, 25, 9, 23, 7, 21, 5, 19, 3, 17, 1);
|
| 665 |
+
return _mm512_sub_ps(_mm512_mask_permutex2var_ps(a, 0xffff, idx1, b),
|
| 666 |
+
_mm512_mask_permutex2var_ps(a, 0xffff, idx2, b));
|
| 667 |
+
}
|
| 668 |
+
const c10::complex<float>& operator[](int idx) const = delete;
|
| 669 |
+
c10::complex<float>& operator[](int idx) = delete;
|
| 670 |
+
Vectorized<c10::complex<float>> map(c10::complex<float> (*const f)(const c10::complex<float> &)) const {
|
| 671 |
+
__at_align__ c10::complex<float> tmp[size()];
|
| 672 |
+
store(tmp);
|
| 673 |
+
for (const auto i : c10::irange(size())) {
|
| 674 |
+
tmp[i] = f(tmp[i]);
|
| 675 |
+
}
|
| 676 |
+
return loadu(tmp);
|
| 677 |
+
}
|
| 678 |
+
__m512 abs_2_() const {
|
| 679 |
+
auto val_2 = _mm512_mul_ps(values, values); // a*a b*b
|
| 680 |
+
auto ret = hadd_ps(val_2, val_2); // a*a+b*b a*a+b*b
|
| 681 |
+
return ret;
|
| 682 |
+
}
|
| 683 |
+
__m512 abs_() const {
|
| 684 |
+
auto real = _mm512_moveldup_ps(values); // real real
|
| 685 |
+
auto imag = _mm512_movehdup_ps(values); // imag imag
|
| 686 |
+
return Sleef_hypotf16_u05(real, imag); // abs abs
|
| 687 |
+
}
|
| 688 |
+
Vectorized<c10::complex<float>> abs() const {
|
| 689 |
+
const __m512 real_mask = _mm512_castsi512_ps(_mm512_setr_epi32(0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 690 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 691 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 692 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000));
|
| 693 |
+
return _mm512_and_ps(abs_(), real_mask); // abs 0
|
| 694 |
+
}
|
| 695 |
+
__m512 angle_() const {
|
| 696 |
+
//angle = atan2(b/a)
|
| 697 |
+
auto b_a = _mm512_permute_ps(values, 0xB1); // b a
|
| 698 |
+
return Sleef_atan2f16_u10(values, b_a); // 90-angle angle
|
| 699 |
+
}
|
| 700 |
+
Vectorized<c10::complex<float>> angle() const {
|
| 701 |
+
const __m512 real_mask = _mm512_castsi512_ps(_mm512_setr_epi32(0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 702 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 703 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 704 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000));
|
| 705 |
+
auto angle = _mm512_permute_ps(angle_(), 0xB1); // angle 90-angle
|
| 706 |
+
return _mm512_and_ps(angle, real_mask); // angle 0
|
| 707 |
+
}
|
| 708 |
+
Vectorized<c10::complex<float>> sgn() const {
|
| 709 |
+
auto abs = abs_();
|
| 710 |
+
auto zero = _mm512_setzero_ps();
|
| 711 |
+
auto mask = _mm512_cmp_ps_mask(abs, zero, _CMP_EQ_OQ);
|
| 712 |
+
auto div = _mm512_div_ps(values, abs);
|
| 713 |
+
return _mm512_mask_blend_ps(mask, div, zero);
|
| 714 |
+
}
|
| 715 |
+
__m512 real_() const {
|
| 716 |
+
const __m512 real_mask = _mm512_castsi512_ps(_mm512_setr_epi32(0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 717 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 718 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
| 719 |
+
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000));
|
| 720 |
+
return _mm512_and_ps(values, real_mask);
|
| 721 |
+
}
|
| 722 |
+
Vectorized<c10::complex<float>> real() const {
|
| 723 |
+
return real_();
|
| 724 |
+
}
|
| 725 |
+
__m512 imag_() const {
|
| 726 |
+
const __m512 imag_mask = _mm512_castsi512_ps(_mm512_setr_epi32(0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
|
| 727 |
+
0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
|
| 728 |
+
0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
|
| 729 |
+
0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF));
|
| 730 |
+
return _mm512_and_ps(values, imag_mask);
|
| 731 |
+
}
|
| 732 |
+
Vectorized<c10::complex<float>> imag() const {
|
| 733 |
+
return _mm512_permute_ps(imag_(), 0xB1); //b a
|
| 734 |
+
}
|
| 735 |
+
__m512 conj_() const {
|
| 736 |
+
const __m512 sign_mask = _mm512_setr_ps(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0,
|
| 737 |
+
0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 738 |
+
return _mm512_xor_ps(values, sign_mask); // a -b
|
| 739 |
+
}
|
| 740 |
+
Vectorized<c10::complex<float>> conj() const {
|
| 741 |
+
return conj_();
|
| 742 |
+
}
|
| 743 |
+
Vectorized<c10::complex<float>> log() const {
|
| 744 |
+
// Most trigonomic ops use the log() op to improve complex number performance.
|
| 745 |
+
return map(std::log);
|
| 746 |
+
}
|
| 747 |
+
Vectorized<c10::complex<float>> log2() const {
|
| 748 |
+
const __m512 log2_ = _mm512_set1_ps(std::log(2));
|
| 749 |
+
return _mm512_div_ps(log(), log2_);
|
| 750 |
+
}
|
| 751 |
+
Vectorized<c10::complex<float>> log10() const {
|
| 752 |
+
const __m512 log10_ = _mm512_set1_ps(std::log(10));
|
| 753 |
+
return _mm512_div_ps(log(), log10_);
|
| 754 |
+
}
|
| 755 |
+
Vectorized<c10::complex<float>> log1p() const {
|
| 756 |
+
return map(std::log1p);
|
| 757 |
+
}
|
| 758 |
+
Vectorized<c10::complex<float>> asin() const {
|
| 759 |
+
// asin(x)
|
| 760 |
+
// = -i*ln(iz + sqrt(1 -z^2))
|
| 761 |
+
// = -i*ln((ai - b) + sqrt(1 - (a + bi)*(a + bi)))
|
| 762 |
+
// = -i*ln((-b + ai) + sqrt(1 - (a**2 - b**2) - 2*abi))
|
| 763 |
+
const __m512 one = _mm512_set1_ps(1);
|
| 764 |
+
|
| 765 |
+
auto conj = conj_();
|
| 766 |
+
auto b_a = _mm512_permute_ps(conj, 0xB1); //-b a
|
| 767 |
+
auto ab = _mm512_mul_ps(conj, b_a); //-ab -ab
|
| 768 |
+
auto im = _mm512_add_ps(ab, ab); //-2ab -2ab
|
| 769 |
+
|
| 770 |
+
auto val_2 = _mm512_mul_ps(values, values); // a*a b*b
|
| 771 |
+
auto re = hsub_ps(val_2, _mm512_permute_ps(val_2, 0xB1)); // a*a-b*b b*b-a*a
|
| 772 |
+
re = _mm512_sub_ps(one, re);
|
| 773 |
+
|
| 774 |
+
auto root = Vectorized(_mm512_mask_blend_ps(0xAAAA, re, im)).sqrt(); //sqrt(re + i*im)
|
| 775 |
+
auto ln = Vectorized(_mm512_add_ps(b_a, root)).log(); //ln(iz + sqrt())
|
| 776 |
+
return Vectorized(_mm512_permute_ps(ln.values, 0xB1)).conj(); //-i*ln()
|
| 777 |
+
}
|
| 778 |
+
Vectorized<c10::complex<float>> acos() const {
|
| 779 |
+
return map(std::acos);
|
| 780 |
+
}
|
| 781 |
+
Vectorized<c10::complex<float>> atan() const;
|
| 782 |
+
Vectorized<c10::complex<float>> atanh() const {
|
| 783 |
+
return map(std::atanh);
|
| 784 |
+
}
|
| 785 |
+
Vectorized<c10::complex<float>> exp() const {
|
| 786 |
+
//exp(a + bi)
|
| 787 |
+
// = exp(a)*(cos(b) + sin(b)i)
|
| 788 |
+
auto exp = Sleef_expf16_u10(values); //exp(a) exp(b)
|
| 789 |
+
exp = _mm512_mask_blend_ps(0xAAAA, exp, _mm512_permute_ps(exp, 0xB1)); //exp(a) exp(a)
|
| 790 |
+
|
| 791 |
+
auto sin_cos = Sleef_sincosf16_u10(values); //[sin(a), cos(a)] [sin(b), cos(b)]
|
| 792 |
+
auto cos_sin = _mm512_mask_blend_ps(0xAAAA, _mm512_permute_ps(sin_cos.y, 0xB1),
|
| 793 |
+
sin_cos.x); //cos(b) sin(b)
|
| 794 |
+
return _mm512_mul_ps(exp, cos_sin);
|
| 795 |
+
}
|
| 796 |
+
Vectorized<c10::complex<float>> exp2() const {
|
| 797 |
+
// Use identity 2**x = exp(log(2) * x)
|
| 798 |
+
const __m512 ln_2 = _mm512_set1_ps(c10::ln_2<float>);
|
| 799 |
+
Vectorized<c10::complex<float>> scaled_values = _mm512_mul_ps(values, ln_2);
|
| 800 |
+
return scaled_values.exp();
|
| 801 |
+
}
|
| 802 |
+
Vectorized<c10::complex<float>> expm1() const {
|
| 803 |
+
return map(std::expm1);
|
| 804 |
+
}
|
| 805 |
+
Vectorized<c10::complex<float>> sin() const {
|
| 806 |
+
return map(std::sin);
|
| 807 |
+
}
|
| 808 |
+
Vectorized<c10::complex<float>> sinh() const {
|
| 809 |
+
return map(std::sinh);
|
| 810 |
+
}
|
| 811 |
+
Vectorized<c10::complex<float>> cos() const {
|
| 812 |
+
return map(std::cos);
|
| 813 |
+
}
|
| 814 |
+
Vectorized<c10::complex<float>> cosh() const {
|
| 815 |
+
return map(std::cosh);
|
| 816 |
+
}
|
| 817 |
+
Vectorized<c10::complex<float>> ceil() const {
|
| 818 |
+
return _mm512_ceil_ps(values);
|
| 819 |
+
}
|
| 820 |
+
Vectorized<c10::complex<float>> floor() const {
|
| 821 |
+
return _mm512_floor_ps(values);
|
| 822 |
+
}
|
| 823 |
+
Vectorized<c10::complex<float>> neg() const {
|
| 824 |
+
auto zero = _mm512_setzero_ps();
|
| 825 |
+
return _mm512_sub_ps(zero, values);
|
| 826 |
+
}
|
| 827 |
+
Vectorized<c10::complex<float>> round() const {
|
| 828 |
+
return _mm512_roundscale_ps(values, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
| 829 |
+
}
|
| 830 |
+
Vectorized<c10::complex<float>> tan() const {
|
| 831 |
+
return map(std::tan);
|
| 832 |
+
}
|
| 833 |
+
Vectorized<c10::complex<float>> tanh() const {
|
| 834 |
+
return map(std::tanh);
|
| 835 |
+
}
|
| 836 |
+
Vectorized<c10::complex<float>> trunc() const {
|
| 837 |
+
return _mm512_roundscale_ps(values, (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
| 838 |
+
}
|
| 839 |
+
Vectorized<c10::complex<float>> sqrt() const {
|
| 840 |
+
return map(std::sqrt);
|
| 841 |
+
}
|
| 842 |
+
Vectorized<c10::complex<float>> reciprocal() const;
|
| 843 |
+
Vectorized<c10::complex<float>> rsqrt() const {
|
| 844 |
+
return sqrt().reciprocal();
|
| 845 |
+
}
|
| 846 |
+
Vectorized<c10::complex<float>> pow(const Vectorized<c10::complex<float>> &exp) const {
|
| 847 |
+
__at_align__ c10::complex<float> x_tmp[size()];
|
| 848 |
+
__at_align__ c10::complex<float> y_tmp[size()];
|
| 849 |
+
store(x_tmp);
|
| 850 |
+
exp.store(y_tmp);
|
| 851 |
+
for (const auto i : c10::irange(size())) {
|
| 852 |
+
x_tmp[i] = std::pow(x_tmp[i], y_tmp[i]);
|
| 853 |
+
}
|
| 854 |
+
return loadu(x_tmp);
|
| 855 |
+
}
|
| 856 |
+
// Comparison using the _CMP_**_OQ predicate.
|
| 857 |
+
// `O`: get false if an operand is NaN
|
| 858 |
+
// `Q`: do not raise if an operand is NaN
|
| 859 |
+
Vectorized<c10::complex<float>> operator==(const Vectorized<c10::complex<float>>& other) const {
|
| 860 |
+
auto mask = _mm512_cmp_ps_mask(values, other.values, _CMP_EQ_OQ);
|
| 861 |
+
return _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vector, mask, 0xFFFFFFFF));
|
| 862 |
+
}
|
| 863 |
+
Vectorized<c10::complex<float>> operator!=(const Vectorized<c10::complex<float>>& other) const {
|
| 864 |
+
auto mask = _mm512_cmp_ps_mask(values, other.values, _CMP_NEQ_UQ);
|
| 865 |
+
return _mm512_castsi512_ps(_mm512_mask_set1_epi32(zero_vector, mask, 0xFFFFFFFF));
|
| 866 |
+
}
|
| 867 |
+
Vectorized<c10::complex<float>> operator<(const Vectorized<c10::complex<float>>& other [[maybe_unused]]) const {
|
| 868 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 869 |
+
}
|
| 870 |
+
Vectorized<c10::complex<float>> operator<=(const Vectorized<c10::complex<float>>& other [[maybe_unused]]) const {
|
| 871 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 872 |
+
}
|
| 873 |
+
Vectorized<c10::complex<float>> operator>(const Vectorized<c10::complex<float>>& other [[maybe_unused]]) const {
|
| 874 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 875 |
+
}
|
| 876 |
+
Vectorized<c10::complex<float>> operator>=(const Vectorized<c10::complex<float>>& other [[maybe_unused]]) const {
|
| 877 |
+
TORCH_CHECK(false, "not supported for complex numbers");
|
| 878 |
+
}
|
| 879 |
+
|
| 880 |
+
Vectorized<c10::complex<float>> eq(const Vectorized<c10::complex<float>>& other) const;
|
| 881 |
+
Vectorized<c10::complex<float>> ne(const Vectorized<c10::complex<float>>& other) const;
|
| 882 |
+
};
|
| 883 |
+
|
| 884 |
+
template <> Vectorized<c10::complex<float>> inline operator+(const Vectorized<c10::complex<float>> &a,
|
| 885 |
+
const Vectorized<c10::complex<float>> &b) {
|
| 886 |
+
return _mm512_add_ps(a, b);
|
| 887 |
+
}
|
| 888 |
+
|
| 889 |
+
template <> Vectorized<c10::complex<float>> inline operator-(const Vectorized<c10::complex<float>> &a,
|
| 890 |
+
const Vectorized<c10::complex<float>> &b) {
|
| 891 |
+
return _mm512_sub_ps(a, b);
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
template <> Vectorized<c10::complex<float>> inline operator*(const Vectorized<c10::complex<float>> &a,
|
| 895 |
+
const Vectorized<c10::complex<float>> &b) {
|
| 896 |
+
//(a + bi) * (c + di) = (ac - bd) + (ad + bc)i
|
| 897 |
+
const __m512 sign_mask = _mm512_setr_ps(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0,
|
| 898 |
+
0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 899 |
+
auto ac_bd = _mm512_mul_ps(a, b); //ac bd
|
| 900 |
+
|
| 901 |
+
auto d_c = _mm512_permute_ps(b, 0xB1); //d c
|
| 902 |
+
d_c = _mm512_xor_ps(sign_mask, d_c); //d -c
|
| 903 |
+
auto ad_bc = _mm512_mul_ps(a, d_c); //ad -bc
|
| 904 |
+
|
| 905 |
+
auto ret = Vectorized<c10::complex<float>>::hsub_ps(ac_bd, ad_bc); //ac - bd ad + bc
|
| 906 |
+
return ret;
|
| 907 |
+
}
|
| 908 |
+
|
| 909 |
+
template <> Vectorized<c10::complex<float>> inline operator/(const Vectorized<c10::complex<float>> &a,
|
| 910 |
+
const Vectorized<c10::complex<float>> &b) {
|
| 911 |
+
//re + im*i = (a + bi) / (c + di)
|
| 912 |
+
auto mask = _mm512_set1_ps(-0.f);
|
| 913 |
+
auto fabs_cd = _mm512_andnot_ps(mask, b); // |c| |d|
|
| 914 |
+
auto fabs_dc = _mm512_permute_ps(fabs_cd, 0xB1); // |d| |c|
|
| 915 |
+
auto scale = _mm512_rcp14_ps(_mm512_max_ps(fabs_cd, fabs_dc)); // 1/sc 1/sc
|
| 916 |
+
auto a2 = _mm512_mul_ps(a, scale); // a/sc b/sc
|
| 917 |
+
auto b2 = _mm512_mul_ps(b, scale); // c/sc d/sc
|
| 918 |
+
auto acbd2 = _mm512_mul_ps(a2, b2);
|
| 919 |
+
|
| 920 |
+
const __m512 sign_mask = _mm512_setr_ps(-0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0,
|
| 921 |
+
-0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0);
|
| 922 |
+
auto dc2 = _mm512_permute_ps(b2, 0xB1); // d/sc c/sc
|
| 923 |
+
dc2 = _mm512_xor_ps(sign_mask, dc2); // -d/|c,d| c/sc
|
| 924 |
+
auto adbc2 = _mm512_mul_ps(a2, dc2); //-ad/sc^2 bc/sc^2
|
| 925 |
+
auto res2 = Vectorized<c10::complex<float>>::hadd_ps(acbd2, adbc2); //(ac+bd)/sc^2 (bc-ad)/sc^2
|
| 926 |
+
|
| 927 |
+
// get the denominator
|
| 928 |
+
auto denom2 = Vectorized<c10::complex<float>>(b2).abs_2_(); // (c^2+d^2)/sc^2 (c^2+d^2)/sc^2
|
| 929 |
+
res2 = _mm512_div_ps(res2, denom2);
|
| 930 |
+
return res2;
|
| 931 |
+
}
|
| 932 |
+
|
| 933 |
+
// reciprocal. Implement this here so we can use multiplication.
|
| 934 |
+
inline Vectorized<c10::complex<float>> Vectorized<c10::complex<float>>::reciprocal() const {
|
| 935 |
+
//re + im*i = (a + bi) / (c + di)
|
| 936 |
+
//re = (ac + bd)/abs_2() = c/abs_2()
|
| 937 |
+
//im = (bc - ad)/abs_2() = d/abs_2()
|
| 938 |
+
const __m512 sign_mask = _mm512_setr_ps(0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0,
|
| 939 |
+
0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0);
|
| 940 |
+
auto c_d = _mm512_xor_ps(sign_mask, values); //c -d
|
| 941 |
+
return _mm512_div_ps(c_d, abs_2_());
|
| 942 |
+
}
|
| 943 |
+
|
| 944 |
+
inline Vectorized<c10::complex<float>> Vectorized<c10::complex<float>>::atan() const {
|
| 945 |
+
// atan(x) = i/2 * ln((i + z)/(i - z))
|
| 946 |
+
const __m512 i = _mm512_setr_ps(0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
|
| 947 |
+
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
|
| 948 |
+
const Vectorized i_half = _mm512_setr_ps(0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5,
|
| 949 |
+
0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5);
|
| 950 |
+
|
| 951 |
+
auto sum = Vectorized(_mm512_add_ps(i, values)); // a 1+b
|
| 952 |
+
auto sub = Vectorized(_mm512_sub_ps(i, values)); // -a 1-b
|
| 953 |
+
auto ln = (sum/sub).log(); // ln((i + z)/(i - z))
|
| 954 |
+
return i_half*ln; // i/2*ln()
|
| 955 |
+
}
|
| 956 |
+
|
| 957 |
+
template <>
|
| 958 |
+
Vectorized<c10::complex<float>> inline maximum(const Vectorized<c10::complex<float>>& a,
|
| 959 |
+
const Vectorized<c10::complex<float>>& b) {
|
| 960 |
+
auto zero_vector = _mm512_set1_epi32(0);
|
| 961 |
+
auto abs_a = a.abs_2_();
|
| 962 |
+
auto abs_b = b.abs_2_();
|
| 963 |
+
auto mask = _mm512_cmp_ps_mask(abs_a, abs_b, _CMP_LT_OQ);
|
| 964 |
+
auto max = _mm512_mask_blend_ps(mask, a, b);
|
| 965 |
+
// Exploit the fact that all-ones is a NaN.
|
| 966 |
+
auto isnan_mask = _mm512_cmp_ps_mask(abs_a, abs_b, _CMP_UNORD_Q);
|
| 967 |
+
auto isnan = _mm512_mask_set1_epi32(zero_vector, isnan_mask, 0xFFFFFFFF);
|
| 968 |
+
return _mm512_or_ps(max, _mm512_castsi512_ps(isnan));
|
| 969 |
+
}
|
| 970 |
+
|
| 971 |
+
template <>
|
| 972 |
+
Vectorized<c10::complex<float>> inline minimum(const Vectorized<c10::complex<float>>& a,
|
| 973 |
+
const Vectorized<c10::complex<float>>& b) {
|
| 974 |
+
auto zero_vector = _mm512_set1_epi32(0);
|
| 975 |
+
auto abs_a = a.abs_2_();
|
| 976 |
+
auto abs_b = b.abs_2_();
|
| 977 |
+
auto mask = _mm512_cmp_ps_mask(abs_a, abs_b, _CMP_GT_OQ);
|
| 978 |
+
auto min = _mm512_mask_blend_ps(mask, a, b);
|
| 979 |
+
// Exploit the fact that all-ones is a NaN.
|
| 980 |
+
auto isnan_mask = _mm512_cmp_ps_mask(abs_a, abs_b, _CMP_UNORD_Q);
|
| 981 |
+
auto isnan = _mm512_mask_set1_epi32(zero_vector, isnan_mask, 0xFFFFFFFF);
|
| 982 |
+
return _mm512_or_ps(min, _mm512_castsi512_ps(isnan));
|
| 983 |
+
}
|
| 984 |
+
|
| 985 |
+
template <>
|
| 986 |
+
Vectorized<c10::complex<float>> inline operator&(const Vectorized<c10::complex<float>>& a,
|
| 987 |
+
const Vectorized<c10::complex<float>>& b) {
|
| 988 |
+
return _mm512_and_ps(a, b);
|
| 989 |
+
}
|
| 990 |
+
|
| 991 |
+
template <>
|
| 992 |
+
Vectorized<c10::complex<float>> inline operator|(const Vectorized<c10::complex<float>>& a,
|
| 993 |
+
const Vectorized<c10::complex<float>>& b) {
|
| 994 |
+
return _mm512_or_ps(a, b);
|
| 995 |
+
}
|
| 996 |
+
|
| 997 |
+
template <>
|
| 998 |
+
Vectorized<c10::complex<float>> inline operator^(const Vectorized<c10::complex<float>>& a,
|
| 999 |
+
const Vectorized<c10::complex<float>>& b) {
|
| 1000 |
+
return _mm512_xor_ps(a, b);
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
inline Vectorized<c10::complex<float>> Vectorized<c10::complex<float>>::eq(
|
| 1004 |
+
const Vectorized<c10::complex<float>>& other) const {
|
| 1005 |
+
auto eq = (*this == other); // compares real and imag individually
|
| 1006 |
+
// If both real numbers and imag numbers are equal, then the complex numbers are equal
|
| 1007 |
+
return (eq.real() & eq.imag()) & Vectorized<c10::complex<float>>(_mm512_set1_ps(1.0f));
|
| 1008 |
+
}
|
| 1009 |
+
|
| 1010 |
+
inline Vectorized<c10::complex<float>> Vectorized<c10::complex<float>>::ne(
|
| 1011 |
+
const Vectorized<c10::complex<float>>& other) const {
|
| 1012 |
+
auto ne = (*this != other); // compares real and imag individually
|
| 1013 |
+
// If either real numbers or imag numbers are not equal, then the complex numbers are not equal
|
| 1014 |
+
return (ne.real() | ne.imag()) & Vectorized<c10::complex<float>>(_mm512_set1_ps(1.0f));
|
| 1015 |
+
}
|
| 1016 |
+
|
| 1017 |
+
#endif
|
| 1018 |
+
|
| 1019 |
+
}}}
|
lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_convert.h
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <ATen/cpu/vec/intrinsics.h>
|
| 4 |
+
#include <ATen/cpu/vec/vec512/vec512_bfloat16.h>
|
| 5 |
+
#include <ATen/cpu/vec/vec_base.h>
|
| 6 |
+
#include <ATen/cpu/vec/vec_convert.h>
|
| 7 |
+
|
| 8 |
+
namespace at::vec {
|
| 9 |
+
inline namespace CPU_CAPABILITY {
|
| 10 |
+
|
| 11 |
+
#if defined(CPU_CAPABILITY_AVX512) && !defined(_MSC_VER)
|
| 12 |
+
|
| 13 |
+
template <>
|
| 14 |
+
struct VecConvert<float, 1, BFloat16, 1> {
|
| 15 |
+
static inline VectorizedN<float, 1> apply(
|
| 16 |
+
const VectorizedN<BFloat16, 1>& src) {
|
| 17 |
+
VectorizedN<float, 1> result;
|
| 18 |
+
__m512 value;
|
| 19 |
+
cvtbf16_fp32(_mm512_castsi512_si256(src[0]), value);
|
| 20 |
+
result[0] = value;
|
| 21 |
+
return result;
|
| 22 |
+
}
|
| 23 |
+
};
|
| 24 |
+
|
| 25 |
+
template <>
|
| 26 |
+
struct VecConvert<float, 1, Half, 1> {
|
| 27 |
+
static inline VectorizedN<float, 1> apply(const VectorizedN<Half, 1>& src) {
|
| 28 |
+
VectorizedN<float, 1> result;
|
| 29 |
+
__m512 value;
|
| 30 |
+
cvtfp16_fp32(_mm512_castsi512_si256(src[0]), value);
|
| 31 |
+
result[0] = value;
|
| 32 |
+
return result;
|
| 33 |
+
}
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
template <>
|
| 37 |
+
struct VecConvert<BFloat16, 1, float, 1> {
|
| 38 |
+
static inline VectorizedN<BFloat16, 1> apply(
|
| 39 |
+
const VectorizedN<float, 1>& src) {
|
| 40 |
+
VectorizedN<BFloat16, 1> result;
|
| 41 |
+
result[0] = _mm512_castsi256_si512(cvtfp32_bf16(src[0]));
|
| 42 |
+
return result;
|
| 43 |
+
}
|
| 44 |
+
};
|
| 45 |
+
|
| 46 |
+
template <>
|
| 47 |
+
struct VecConvert<BFloat16, 1, float, 2> {
|
| 48 |
+
static inline VectorizedN<BFloat16, 1> apply(
|
| 49 |
+
const VectorizedN<float, 2>& src) {
|
| 50 |
+
VectorizedN<BFloat16, 1> result;
|
| 51 |
+
result[0] = convert_float_bfloat16(src[0], src[1]);
|
| 52 |
+
return result;
|
| 53 |
+
}
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
template <>
|
| 57 |
+
struct VecConvert<float, 2, BFloat16, 1> {
|
| 58 |
+
static inline VectorizedN<float, 2> apply(
|
| 59 |
+
const VectorizedN<BFloat16, 1>& src) {
|
| 60 |
+
VectorizedN<float, 2> result;
|
| 61 |
+
std::tie(result[0], result[1]) = convert_bfloat16_float(src[0]);
|
| 62 |
+
return result;
|
| 63 |
+
}
|
| 64 |
+
};
|
| 65 |
+
|
| 66 |
+
template <>
|
| 67 |
+
struct VecConvert<Half, 1, float, 1> {
|
| 68 |
+
static inline VectorizedN<Half, 1> apply(const VectorizedN<float, 1>& src) {
|
| 69 |
+
VectorizedN<Half, 1> result;
|
| 70 |
+
result[0] = _mm512_castsi256_si512(cvtfp32_fp16(src[0]));
|
| 71 |
+
return result;
|
| 72 |
+
}
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
template <>
|
| 76 |
+
struct VecConvert<Half, 1, float, 2> {
|
| 77 |
+
static inline VectorizedN<Half, 1> apply(const VectorizedN<float, 2>& src) {
|
| 78 |
+
VectorizedN<Half, 1> result;
|
| 79 |
+
result[0] = convert_float_half(src[0], src[1]);
|
| 80 |
+
return result;
|
| 81 |
+
}
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
template <>
|
| 85 |
+
struct VecConvert<float, 2, Half, 1> {
|
| 86 |
+
static inline VectorizedN<float, 2> apply(const VectorizedN<Half, 1>& src) {
|
| 87 |
+
VectorizedN<float, 2> result;
|
| 88 |
+
std::tie(result[0], result[1]) = convert_half_float(src[0]);
|
| 89 |
+
return result;
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
|
| 93 |
+
template <>
|
| 94 |
+
struct VecConvert<float, 1, int64_t, 2> {
|
| 95 |
+
static inline VectorizedN<float, 1> apply(
|
| 96 |
+
const VectorizedN<int64_t, 2>& src) {
|
| 97 |
+
auto low = _mm512_cvtepi64_ps(src[0]);
|
| 98 |
+
auto high = _mm512_cvtepi64_ps(src[1]);
|
| 99 |
+
return Vectorized<float>(
|
| 100 |
+
_mm512_insertf32x8(_mm512_castps256_ps512(low), high, 1));
|
| 101 |
+
}
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
template <>
|
| 105 |
+
struct VecConvert<int64_t, 2, float, 1> {
|
| 106 |
+
static inline VectorizedN<int64_t, 2> apply(
|
| 107 |
+
const VectorizedN<float, 1>& src) {
|
| 108 |
+
at::vec::VectorizedN<int64_t, 2> result;
|
| 109 |
+
result[0] = _mm512_cvt_roundps_epi64(
|
| 110 |
+
_mm512_castps512_ps256(src[0]), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);
|
| 111 |
+
result[1] = _mm512_cvt_roundps_epi64(
|
| 112 |
+
_mm512_extractf32x8_ps(src[0], 1),
|
| 113 |
+
_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);
|
| 114 |
+
return result;
|
| 115 |
+
}
|
| 116 |
+
};
|
| 117 |
+
|
| 118 |
+
template <>
|
| 119 |
+
struct VecConvert<int32_t, 1, int64_t, 2> {
|
| 120 |
+
static inline VectorizedN<int32_t, 1> apply(
|
| 121 |
+
const VectorizedN<int64_t, 2>& src) {
|
| 122 |
+
auto low = _mm512_cvtepi64_epi32(src[0]);
|
| 123 |
+
auto high = _mm512_cvtepi64_epi32(src[1]);
|
| 124 |
+
return Vectorized<int32_t>(
|
| 125 |
+
_mm512_inserti32x8(_mm512_castsi256_si512(low), high, 1));
|
| 126 |
+
}
|
| 127 |
+
};
|
| 128 |
+
|
| 129 |
+
template <>
|
| 130 |
+
struct VecConvert<int64_t, 2, int32_t, 1> {
|
| 131 |
+
static inline VectorizedN<int64_t, 2> apply(
|
| 132 |
+
const VectorizedN<int32_t, 1>& src) {
|
| 133 |
+
at::vec::VectorizedN<int64_t, 2> result;
|
| 134 |
+
result[0] = _mm512_cvtepi32_epi64(_mm512_castsi512_si256(src[0]));
|
| 135 |
+
result[1] = _mm512_cvtepi32_epi64(_mm512_extracti32x8_epi32(src[0], 1));
|
| 136 |
+
return result;
|
| 137 |
+
}
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
template <>
|
| 141 |
+
struct VecConvert<int32_t, 1, int8_t, 1> {
|
| 142 |
+
static inline VectorizedN<int32_t, 1> apply(
|
| 143 |
+
const VectorizedN<int8_t, 1>& src) {
|
| 144 |
+
auto src128 = _mm512_castsi512_si128(src[0]);
|
| 145 |
+
return Vectorized<int32_t>(_mm512_cvtepi8_epi32(src128));
|
| 146 |
+
}
|
| 147 |
+
};
|
| 148 |
+
|
| 149 |
+
template <>
|
| 150 |
+
struct VecConvert<int32_t, 1, uint8_t, 1> {
|
| 151 |
+
static inline VectorizedN<int32_t, 1> apply(
|
| 152 |
+
const VectorizedN<uint8_t, 1>& src) {
|
| 153 |
+
auto src128 = _mm512_castsi512_si128(src[0]);
|
| 154 |
+
return Vectorized<int32_t>(_mm512_cvtepu8_epi32(src128));
|
| 155 |
+
}
|
| 156 |
+
};
|
| 157 |
+
|
| 158 |
+
template <>
|
| 159 |
+
struct VecConvert<int32_t, 1, float, 1> {
|
| 160 |
+
static inline VectorizedN<int32_t, 1> apply(
|
| 161 |
+
const VectorizedN<float, 1>& src) {
|
| 162 |
+
return Vectorized<int32_t>(_mm512_cvttps_epi32(src[0]));
|
| 163 |
+
}
|
| 164 |
+
};
|
| 165 |
+
|
| 166 |
+
template <>
|
| 167 |
+
struct VecConvert<float, 1, int32_t, 1> {
|
| 168 |
+
static inline VectorizedN<float, 1> apply(
|
| 169 |
+
const VectorizedN<int32_t, 1>& src) {
|
| 170 |
+
return Vectorized<float>(_mm512_cvtepi32_ps(src[0]));
|
| 171 |
+
}
|
| 172 |
+
};
|
| 173 |
+
|
| 174 |
+
template <>
|
| 175 |
+
struct VecConvert<int16_t, 1, uint8_t, 1> {
|
| 176 |
+
static inline VectorizedN<int16_t, 1> apply(
|
| 177 |
+
const VectorizedN<uint8_t, 1>& src) {
|
| 178 |
+
auto src256 = _mm512_castsi512_si256(src[0]);
|
| 179 |
+
return Vectorized<int16_t>(_mm512_cvtepu8_epi16(src256));
|
| 180 |
+
}
|
| 181 |
+
};
|
| 182 |
+
|
| 183 |
+
template <>
|
| 184 |
+
struct VecConvert<int8_t, 1, int32_t, 1> {
|
| 185 |
+
static inline VectorizedN<int8_t, 1> apply(
|
| 186 |
+
const VectorizedN<int32_t, 1>& src) {
|
| 187 |
+
auto src128 = _mm512_cvtepi32_epi8(src[0]);
|
| 188 |
+
return Vectorized<int8_t>(_mm512_castsi128_si512(src128));
|
| 189 |
+
}
|
| 190 |
+
};
|
| 191 |
+
|
| 192 |
+
template <>
|
| 193 |
+
struct VecConvert<int8_t, 1, int16_t, 1> {
|
| 194 |
+
static inline VectorizedN<int8_t, 1> apply(
|
| 195 |
+
const VectorizedN<int16_t, 1>& src) {
|
| 196 |
+
auto src256 = _mm512_cvtepi16_epi8(src[0]);
|
| 197 |
+
return Vectorized<int8_t>(_mm512_castsi256_si512(src256));
|
| 198 |
+
}
|
| 199 |
+
};
|
| 200 |
+
|
| 201 |
+
template <typename dst_t, typename src_t>
|
| 202 |
+
struct VecConvert<
|
| 203 |
+
dst_t,
|
| 204 |
+
1,
|
| 205 |
+
src_t,
|
| 206 |
+
1,
|
| 207 |
+
typename std::enable_if_t<
|
| 208 |
+
(is_reduced_floating_point_v<dst_t> && is_8bit_integer_v<src_t>) ||
|
| 209 |
+
(is_reduced_floating_point_v<src_t> && is_8bit_integer_v<dst_t>),
|
| 210 |
+
void>> {
|
| 211 |
+
static inline VectorizedN<dst_t, 1> apply(const VectorizedN<src_t, 1>& src) {
|
| 212 |
+
VectorizedN<float, 2> tmp_fp32 = VecConvert<float, 2, src_t, 1>::apply(src);
|
| 213 |
+
return VecConvert<dst_t, 1, float, 2>::apply(tmp_fp32);
|
| 214 |
+
}
|
| 215 |
+
};
|
| 216 |
+
|
| 217 |
+
template <typename dst_t>
|
| 218 |
+
struct VecConvert<
|
| 219 |
+
dst_t,
|
| 220 |
+
1,
|
| 221 |
+
float,
|
| 222 |
+
2,
|
| 223 |
+
typename std::enable_if_t<is_8bit_integer_v<dst_t>,
|
| 224 |
+
void>> {
|
| 225 |
+
static inline VectorizedN<dst_t, 1> apply(const VectorizedN<float, 2>& src) {
|
| 226 |
+
at::vec::Vectorized<dst_t> vec1 = convert_float_to_int8<dst_t>(src[0]);
|
| 227 |
+
at::vec::Vectorized<dst_t> vec2 = convert_float_to_int8<dst_t>(src[1]);
|
| 228 |
+
__m128 lane2 = _mm512_castps512_ps128(_mm512_castsi512_ps(vec2));
|
| 229 |
+
__m512 result = _mm512_insertf32x4(_mm512_castsi512_ps(vec1), lane2, 1); // Insert lane2 into the second 128-bit lane
|
| 230 |
+
return at::vec::Vectorized<dst_t>(_mm512_castps_si512(result));
|
| 231 |
+
}
|
| 232 |
+
};
|
| 233 |
+
|
| 234 |
+
template <typename dst_t>
|
| 235 |
+
struct VecConvert<
|
| 236 |
+
dst_t,
|
| 237 |
+
1,
|
| 238 |
+
float,
|
| 239 |
+
1,
|
| 240 |
+
typename std::enable_if_t<is_8bit_integer_v<dst_t>,
|
| 241 |
+
void>> {
|
| 242 |
+
static inline VectorizedN<dst_t, 1> apply(const VectorizedN<float, 1>& src) {
|
| 243 |
+
return convert_float_to_int8<dst_t>(src[0]);
|
| 244 |
+
}
|
| 245 |
+
};
|
| 246 |
+
|
| 247 |
+
template <typename src_t>
|
| 248 |
+
struct VecConvert<
|
| 249 |
+
float,
|
| 250 |
+
2,
|
| 251 |
+
src_t,
|
| 252 |
+
1,
|
| 253 |
+
typename std::enable_if_t<is_8bit_integer_v<src_t>,
|
| 254 |
+
void>> {
|
| 255 |
+
static inline VectorizedN<float, 2> apply(const VectorizedN<src_t, 1>& src) {
|
| 256 |
+
__m512i src2 = _mm512_castsi128_si512(
|
| 257 |
+
_mm_castps_si128(
|
| 258 |
+
_mm512_extractf32x4_ps(_mm512_castsi512_ps(src[0]), 1) // Extract the second 128-bit lane
|
| 259 |
+
)
|
| 260 |
+
);
|
| 261 |
+
return VectorizedN<float, 2>(convert_int8_to_float<src_t>(src[0]), convert_int8_to_float<src_t>(src2));
|
| 262 |
+
}
|
| 263 |
+
};
|
| 264 |
+
|
| 265 |
+
template <typename src_t>
|
| 266 |
+
struct VecConvert<
|
| 267 |
+
float,
|
| 268 |
+
1,
|
| 269 |
+
src_t,
|
| 270 |
+
1,
|
| 271 |
+
typename std::enable_if_t<is_8bit_integer_v<src_t>,
|
| 272 |
+
void>> {
|
| 273 |
+
static inline VectorizedN<float, 1> apply(const VectorizedN<src_t, 1>& src) {
|
| 274 |
+
return convert_int8_to_float<src_t>(src[0]);
|
| 275 |
+
}
|
| 276 |
+
};
|
| 277 |
+
|
| 278 |
+
template <typename dst_t>
|
| 279 |
+
struct VecConvert<
|
| 280 |
+
dst_t,
|
| 281 |
+
1,
|
| 282 |
+
int64_t,
|
| 283 |
+
2,
|
| 284 |
+
std::enable_if_t<
|
| 285 |
+
std::is_same_v<dst_t, int8_t> ||
|
| 286 |
+
std::is_same_v<dst_t, uint8_t>>> {
|
| 287 |
+
static inline VectorizedN<dst_t, 1> apply(
|
| 288 |
+
const VectorizedN<int64_t, 2>& src) {
|
| 289 |
+
return VecConvert<dst_t, 1, int32_t, 1>::apply(
|
| 290 |
+
VecConvert<int32_t, 1, int64_t, 2>::apply(src));
|
| 291 |
+
}
|
| 292 |
+
};
|
| 293 |
+
|
| 294 |
+
#endif
|
| 295 |
+
|
| 296 |
+
} // namespace CPU_CAPABILITY
|
| 297 |
+
} // namespace at::vec
|