ZhengyangZhang commited on
Commit
5815ea1
·
verified ·
1 Parent(s): 13a5289

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/torch/include/ATen/cpu/FlushDenormal.h +14 -0
  2. lib/python3.12/site-packages/torch/include/ATen/cpu/Utils.h +36 -0
  3. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional.h +4 -0
  4. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional_base.h +377 -0
  5. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/functional_bfloat16.h +549 -0
  6. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/intrinsics.h +51 -0
  7. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/sve_helper.h +63 -0
  8. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_common_sve.h +176 -0
  9. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_double.h +505 -0
  10. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_float.h +570 -0
  11. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_int.h +410 -0
  12. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/sve/vec_qint.h +567 -0
  13. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec.h +48 -0
  14. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128.h +14 -0
  15. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_bfloat16_neon.h +556 -0
  16. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_convert.h +64 -0
  17. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_float_neon.h +580 -0
  18. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_half_neon.h +603 -0
  19. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec128/vec128_reduced_precision_common_neon.h +263 -0
  20. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/missing_vld1_neon.h +452 -0
  21. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/missing_vst1_neon.h +8 -0
  22. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256.h +331 -0
  23. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_bfloat16.h +1150 -0
  24. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_complex_double.h +432 -0
  25. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_complex_float.h +469 -0
  26. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_convert.h +328 -0
  27. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_double.h +447 -0
  28. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_float.h +658 -0
  29. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_int.h +1586 -0
  30. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_mask.h +298 -0
  31. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vec256_qint.h +1334 -0
  32. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_bfloat16_vsx.h +73 -0
  33. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_common_vsx.h +246 -0
  34. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_complex_double_vsx.h +584 -0
  35. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_complex_float_vsx.h +660 -0
  36. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_double_vsx.h +477 -0
  37. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_float_vsx.h +499 -0
  38. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int16_vsx.h +402 -0
  39. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int32_vsx.h +333 -0
  40. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_int64_vsx.h +286 -0
  41. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_qint32_vsx.h +281 -0
  42. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_qint8_vsx.h +483 -0
  43. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vec256_quint8_vsx.h +501 -0
  44. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/vsx/vsx_helpers.h +474 -0
  45. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec256/zarch/vec256_zarch.h +0 -0
  46. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512.h +291 -0
  47. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_bfloat16.h +1670 -0
  48. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_complex_double.h +513 -0
  49. lib/python3.12/site-packages/torch/include/ATen/cpu/vec/vec512/vec512_complex_float.h +1019 -0
  50. 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