[1166] | 1 | // x86 specific conversion optimizations -*- C++ -*-
|
---|
| 2 |
|
---|
| 3 | // Copyright (C) 2020-2021 Free Software Foundation, Inc.
|
---|
| 4 | //
|
---|
| 5 | // This file is part of the GNU ISO C++ Library. This library is free
|
---|
| 6 | // software; you can redistribute it and/or modify it under the
|
---|
| 7 | // terms of the GNU General Public License as published by the
|
---|
| 8 | // Free Software Foundation; either version 3, or (at your option)
|
---|
| 9 | // any later version.
|
---|
| 10 |
|
---|
| 11 | // This library is distributed in the hope that it will be useful,
|
---|
| 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 14 | // GNU General Public License for more details.
|
---|
| 15 |
|
---|
| 16 | // Under Section 7 of GPL version 3, you are granted additional
|
---|
| 17 | // permissions described in the GCC Runtime Library Exception, version
|
---|
| 18 | // 3.1, as published by the Free Software Foundation.
|
---|
| 19 |
|
---|
| 20 | // You should have received a copy of the GNU General Public License and
|
---|
| 21 | // a copy of the GCC Runtime Library Exception along with this program;
|
---|
| 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
---|
| 23 | // <http://www.gnu.org/licenses/>.
|
---|
| 24 |
|
---|
| 25 | #ifndef _GLIBCXX_EXPERIMENTAL_SIMD_X86_CONVERSIONS_H
|
---|
| 26 | #define _GLIBCXX_EXPERIMENTAL_SIMD_X86_CONVERSIONS_H
|
---|
| 27 |
|
---|
| 28 | #if __cplusplus >= 201703L
|
---|
| 29 |
|
---|
| 30 | // work around PR85827
|
---|
| 31 | // 1-arg __convert_x86 {{{1
|
---|
| 32 | template <typename _To, typename _V, typename _Traits>
|
---|
| 33 | _GLIBCXX_SIMD_INTRINSIC _To
|
---|
| 34 | __convert_x86(_V __v)
|
---|
| 35 | {
|
---|
| 36 | static_assert(__is_vector_type_v<_V>);
|
---|
| 37 | using _Tp = typename _Traits::value_type;
|
---|
| 38 | constexpr size_t _Np = _Traits::_S_full_size;
|
---|
| 39 | [[maybe_unused]] const auto __intrin = __to_intrin(__v);
|
---|
| 40 | using _Up = typename _VectorTraits<_To>::value_type;
|
---|
| 41 | constexpr size_t _M = _VectorTraits<_To>::_S_full_size;
|
---|
| 42 |
|
---|
| 43 | // [xyz]_to_[xyz] {{{2
|
---|
| 44 | [[maybe_unused]] constexpr bool __x_to_x
|
---|
| 45 | = sizeof(__v) <= 16 && sizeof(_To) <= 16;
|
---|
| 46 | [[maybe_unused]] constexpr bool __x_to_y
|
---|
| 47 | = sizeof(__v) <= 16 && sizeof(_To) == 32;
|
---|
| 48 | [[maybe_unused]] constexpr bool __x_to_z
|
---|
| 49 | = sizeof(__v) <= 16 && sizeof(_To) == 64;
|
---|
| 50 | [[maybe_unused]] constexpr bool __y_to_x
|
---|
| 51 | = sizeof(__v) == 32 && sizeof(_To) <= 16;
|
---|
| 52 | [[maybe_unused]] constexpr bool __y_to_y
|
---|
| 53 | = sizeof(__v) == 32 && sizeof(_To) == 32;
|
---|
| 54 | [[maybe_unused]] constexpr bool __y_to_z
|
---|
| 55 | = sizeof(__v) == 32 && sizeof(_To) == 64;
|
---|
| 56 | [[maybe_unused]] constexpr bool __z_to_x
|
---|
| 57 | = sizeof(__v) == 64 && sizeof(_To) <= 16;
|
---|
| 58 | [[maybe_unused]] constexpr bool __z_to_y
|
---|
| 59 | = sizeof(__v) == 64 && sizeof(_To) == 32;
|
---|
| 60 | [[maybe_unused]] constexpr bool __z_to_z
|
---|
| 61 | = sizeof(__v) == 64 && sizeof(_To) == 64;
|
---|
| 62 |
|
---|
| 63 | // iX_to_iX {{{2
|
---|
| 64 | [[maybe_unused]] constexpr bool __i_to_i
|
---|
| 65 | = is_integral_v<_Up> && is_integral_v<_Tp>;
|
---|
| 66 | [[maybe_unused]] constexpr bool __i8_to_i16
|
---|
| 67 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 2;
|
---|
| 68 | [[maybe_unused]] constexpr bool __i8_to_i32
|
---|
| 69 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 4;
|
---|
| 70 | [[maybe_unused]] constexpr bool __i8_to_i64
|
---|
| 71 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 8;
|
---|
| 72 | [[maybe_unused]] constexpr bool __i16_to_i8
|
---|
| 73 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 1;
|
---|
| 74 | [[maybe_unused]] constexpr bool __i16_to_i32
|
---|
| 75 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 4;
|
---|
| 76 | [[maybe_unused]] constexpr bool __i16_to_i64
|
---|
| 77 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 8;
|
---|
| 78 | [[maybe_unused]] constexpr bool __i32_to_i8
|
---|
| 79 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 1;
|
---|
| 80 | [[maybe_unused]] constexpr bool __i32_to_i16
|
---|
| 81 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 2;
|
---|
| 82 | [[maybe_unused]] constexpr bool __i32_to_i64
|
---|
| 83 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 8;
|
---|
| 84 | [[maybe_unused]] constexpr bool __i64_to_i8
|
---|
| 85 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 1;
|
---|
| 86 | [[maybe_unused]] constexpr bool __i64_to_i16
|
---|
| 87 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 2;
|
---|
| 88 | [[maybe_unused]] constexpr bool __i64_to_i32
|
---|
| 89 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 4;
|
---|
| 90 |
|
---|
| 91 | // [fsu]X_to_[fsu]X {{{2
|
---|
| 92 | // ibw = integral && byte or word, i.e. char and short with any signedness
|
---|
| 93 | [[maybe_unused]] constexpr bool __s64_to_f32
|
---|
| 94 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 95 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 96 | [[maybe_unused]] constexpr bool __s32_to_f32
|
---|
| 97 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 98 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 99 | [[maybe_unused]] constexpr bool __s16_to_f32
|
---|
| 100 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 101 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 102 | [[maybe_unused]] constexpr bool __s8_to_f32
|
---|
| 103 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 104 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 105 | [[maybe_unused]] constexpr bool __u64_to_f32
|
---|
| 106 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 107 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 108 | [[maybe_unused]] constexpr bool __u32_to_f32
|
---|
| 109 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 110 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 111 | [[maybe_unused]] constexpr bool __u16_to_f32
|
---|
| 112 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 113 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 114 | [[maybe_unused]] constexpr bool __u8_to_f32
|
---|
| 115 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 116 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 117 | [[maybe_unused]] constexpr bool __s64_to_f64
|
---|
| 118 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 119 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 120 | [[maybe_unused]] constexpr bool __s32_to_f64
|
---|
| 121 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 122 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 123 | [[maybe_unused]] constexpr bool __u64_to_f64
|
---|
| 124 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 125 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 126 | [[maybe_unused]] constexpr bool __u32_to_f64
|
---|
| 127 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 128 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 129 | [[maybe_unused]] constexpr bool __f32_to_s64
|
---|
| 130 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
|
---|
| 131 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 132 | [[maybe_unused]] constexpr bool __f32_to_s32
|
---|
| 133 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
|
---|
| 134 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 135 | [[maybe_unused]] constexpr bool __f32_to_u64
|
---|
| 136 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
|
---|
| 137 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 138 | [[maybe_unused]] constexpr bool __f32_to_u32
|
---|
| 139 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
|
---|
| 140 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 141 | [[maybe_unused]] constexpr bool __f64_to_s64
|
---|
| 142 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
|
---|
| 143 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 144 | [[maybe_unused]] constexpr bool __f64_to_s32
|
---|
| 145 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
|
---|
| 146 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 147 | [[maybe_unused]] constexpr bool __f64_to_u64
|
---|
| 148 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
|
---|
| 149 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 150 | [[maybe_unused]] constexpr bool __f64_to_u32
|
---|
| 151 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
|
---|
| 152 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 153 | [[maybe_unused]] constexpr bool __ibw_to_f32
|
---|
| 154 | = is_integral_v<_Tp> && sizeof(_Tp) <= 2
|
---|
| 155 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 156 | [[maybe_unused]] constexpr bool __ibw_to_f64
|
---|
| 157 | = is_integral_v<_Tp> && sizeof(_Tp) <= 2
|
---|
| 158 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 159 | [[maybe_unused]] constexpr bool __f32_to_ibw
|
---|
| 160 | = is_integral_v<_Up> && sizeof(_Up) <= 2
|
---|
| 161 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 162 | [[maybe_unused]] constexpr bool __f64_to_ibw
|
---|
| 163 | = is_integral_v<_Up> && sizeof(_Up) <= 2
|
---|
| 164 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 165 | [[maybe_unused]] constexpr bool __f32_to_f64
|
---|
| 166 | = is_floating_point_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 167 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 168 | [[maybe_unused]] constexpr bool __f64_to_f32
|
---|
| 169 | = is_floating_point_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 170 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 171 |
|
---|
| 172 | if constexpr (__i_to_i && __y_to_x && !__have_avx2) //{{{2
|
---|
| 173 | return __convert_x86<_To>(__lo128(__v), __hi128(__v));
|
---|
| 174 | else if constexpr (__i_to_i && __x_to_y && !__have_avx2) //{{{2
|
---|
| 175 | return __concat(__convert_x86<__vector_type_t<_Up, _M / 2>>(__v),
|
---|
| 176 | __convert_x86<__vector_type_t<_Up, _M / 2>>(
|
---|
| 177 | __extract_part<1, _Np / _M * 2>(__v)));
|
---|
| 178 | else if constexpr (__i_to_i) //{{{2
|
---|
| 179 | {
|
---|
| 180 | static_assert(__x_to_x || __have_avx2,
|
---|
| 181 | "integral conversions with ymm registers require AVX2");
|
---|
| 182 | static_assert(__have_avx512bw
|
---|
| 183 | || ((sizeof(_Tp) >= 4 || sizeof(__v) < 64)
|
---|
| 184 | && (sizeof(_Up) >= 4 || sizeof(_To) < 64)),
|
---|
| 185 | "8/16-bit integers in zmm registers require AVX512BW");
|
---|
| 186 | static_assert((sizeof(__v) < 64 && sizeof(_To) < 64) || __have_avx512f,
|
---|
| 187 | "integral conversions with ymm registers require AVX2");
|
---|
| 188 | }
|
---|
| 189 | if constexpr (is_floating_point_v<_Tp> == is_floating_point_v<_Up> && //{{{2
|
---|
| 190 | sizeof(_Tp) == sizeof(_Up))
|
---|
| 191 | {
|
---|
| 192 | // conversion uses simple bit reinterpretation (or no conversion at all)
|
---|
| 193 | if constexpr (_Np >= _M)
|
---|
| 194 | return __intrin_bitcast<_To>(__v);
|
---|
| 195 | else
|
---|
| 196 | return __zero_extend(__vector_bitcast<_Up>(__v));
|
---|
| 197 | }
|
---|
| 198 | else if constexpr (_Np < _M && sizeof(_To) > 16) //{{{2
|
---|
| 199 | // zero extend (eg. xmm -> ymm)
|
---|
| 200 | return __zero_extend(
|
---|
| 201 | __convert_x86<__vector_type_t<
|
---|
| 202 | _Up, (16 / sizeof(_Up) > _Np) ? 16 / sizeof(_Up) : _Np>>(__v));
|
---|
| 203 | else if constexpr (_Np > _M && sizeof(__v) > 16) //{{{2
|
---|
| 204 | // partial input (eg. ymm -> xmm)
|
---|
| 205 | return __convert_x86<_To>(__extract_part<0, _Np / _M>(__v));
|
---|
| 206 | else if constexpr (__i64_to_i32) //{{{2
|
---|
| 207 | {
|
---|
| 208 | if constexpr (__x_to_x && __have_avx512vl)
|
---|
| 209 | return __intrin_bitcast<_To>(_mm_cvtepi64_epi32(__intrin));
|
---|
| 210 | else if constexpr (__x_to_x)
|
---|
| 211 | return __auto_bitcast(
|
---|
| 212 | _mm_shuffle_ps(__vector_bitcast<float>(__v), __m128(), 8));
|
---|
| 213 | else if constexpr (__y_to_x && __have_avx512vl)
|
---|
| 214 | return __intrin_bitcast<_To>(_mm256_cvtepi64_epi32(__intrin));
|
---|
| 215 | else if constexpr (__y_to_x && __have_avx512f)
|
---|
| 216 | return __intrin_bitcast<_To>(
|
---|
| 217 | __lo128(_mm512_cvtepi64_epi32(__auto_bitcast(__v))));
|
---|
| 218 | else if constexpr (__y_to_x)
|
---|
| 219 | return __intrin_bitcast<_To>(
|
---|
| 220 | __lo128(_mm256_permute4x64_epi64(_mm256_shuffle_epi32(__intrin, 8),
|
---|
| 221 | 0 + 4 * 2)));
|
---|
| 222 | else if constexpr (__z_to_y)
|
---|
| 223 | return __intrin_bitcast<_To>(_mm512_cvtepi64_epi32(__intrin));
|
---|
| 224 | }
|
---|
| 225 | else if constexpr (__i64_to_i16) //{{{2
|
---|
| 226 | {
|
---|
| 227 | if constexpr (__x_to_x && __have_avx512vl)
|
---|
| 228 | return __intrin_bitcast<_To>(_mm_cvtepi64_epi16(__intrin));
|
---|
| 229 | else if constexpr (__x_to_x && __have_avx512f)
|
---|
| 230 | return __intrin_bitcast<_To>(
|
---|
| 231 | __lo128(_mm512_cvtepi64_epi16(__auto_bitcast(__v))));
|
---|
| 232 | else if constexpr (__x_to_x && __have_ssse3)
|
---|
| 233 | {
|
---|
| 234 | return __intrin_bitcast<_To>(
|
---|
| 235 | _mm_shuffle_epi8(__intrin,
|
---|
| 236 | _mm_setr_epi8(0, 1, 8, 9, -0x80, -0x80, -0x80,
|
---|
| 237 | -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 238 | -0x80, -0x80, -0x80, -0x80)));
|
---|
| 239 | // fallback without SSSE3
|
---|
| 240 | }
|
---|
| 241 | else if constexpr (__y_to_x && __have_avx512vl)
|
---|
| 242 | return __intrin_bitcast<_To>(_mm256_cvtepi64_epi16(__intrin));
|
---|
| 243 | else if constexpr (__y_to_x && __have_avx512f)
|
---|
| 244 | return __intrin_bitcast<_To>(
|
---|
| 245 | __lo128(_mm512_cvtepi64_epi16(__auto_bitcast(__v))));
|
---|
| 246 | else if constexpr (__y_to_x)
|
---|
| 247 | {
|
---|
| 248 | const auto __a = _mm256_shuffle_epi8(
|
---|
| 249 | __intrin,
|
---|
| 250 | _mm256_setr_epi8(0, 1, 8, 9, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 251 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 252 | -0x80, -0x80, -0x80, -0x80, 0, 1, 8, 9, -0x80,
|
---|
| 253 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 254 | -0x80));
|
---|
| 255 | return __intrin_bitcast<_To>(__lo128(__a) | __hi128(__a));
|
---|
| 256 | }
|
---|
| 257 | else if constexpr (__z_to_x)
|
---|
| 258 | return __intrin_bitcast<_To>(_mm512_cvtepi64_epi16(__intrin));
|
---|
| 259 | }
|
---|
| 260 | else if constexpr (__i64_to_i8) //{{{2
|
---|
| 261 | {
|
---|
| 262 | if constexpr (__x_to_x && __have_avx512vl)
|
---|
| 263 | return __intrin_bitcast<_To>(_mm_cvtepi64_epi8(__intrin));
|
---|
| 264 | else if constexpr (__x_to_x && __have_avx512f)
|
---|
| 265 | return __intrin_bitcast<_To>(
|
---|
| 266 | __lo128(_mm512_cvtepi64_epi8(__zero_extend(__intrin))));
|
---|
| 267 | else if constexpr (__y_to_x && __have_avx512vl)
|
---|
| 268 | return __intrin_bitcast<_To>(_mm256_cvtepi64_epi8(__intrin));
|
---|
| 269 | else if constexpr (__y_to_x && __have_avx512f)
|
---|
| 270 | return __intrin_bitcast<_To>(
|
---|
| 271 | _mm512_cvtepi64_epi8(__zero_extend(__intrin)));
|
---|
| 272 | else if constexpr (__z_to_x)
|
---|
| 273 | return __intrin_bitcast<_To>(_mm512_cvtepi64_epi8(__intrin));
|
---|
| 274 | }
|
---|
| 275 | else if constexpr (__i32_to_i64) //{{{2
|
---|
| 276 | {
|
---|
| 277 | if constexpr (__have_sse4_1 && __x_to_x)
|
---|
| 278 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 279 | ? _mm_cvtepi32_epi64(__intrin)
|
---|
| 280 | : _mm_cvtepu32_epi64(__intrin));
|
---|
| 281 | else if constexpr (__x_to_x)
|
---|
| 282 | {
|
---|
| 283 | return __intrin_bitcast<_To>(
|
---|
| 284 | _mm_unpacklo_epi32(__intrin, is_signed_v<_Tp>
|
---|
| 285 | ? _mm_srai_epi32(__intrin, 31)
|
---|
| 286 | : __m128i()));
|
---|
| 287 | }
|
---|
| 288 | else if constexpr (__x_to_y)
|
---|
| 289 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 290 | ? _mm256_cvtepi32_epi64(__intrin)
|
---|
| 291 | : _mm256_cvtepu32_epi64(__intrin));
|
---|
| 292 | else if constexpr (__y_to_z)
|
---|
| 293 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 294 | ? _mm512_cvtepi32_epi64(__intrin)
|
---|
| 295 | : _mm512_cvtepu32_epi64(__intrin));
|
---|
| 296 | }
|
---|
| 297 | else if constexpr (__i32_to_i16) //{{{2
|
---|
| 298 | {
|
---|
| 299 | if constexpr (__x_to_x && __have_avx512vl)
|
---|
| 300 | return __intrin_bitcast<_To>(_mm_cvtepi32_epi16(__intrin));
|
---|
| 301 | else if constexpr (__x_to_x && __have_avx512f)
|
---|
| 302 | return __intrin_bitcast<_To>(
|
---|
| 303 | __lo128(_mm512_cvtepi32_epi16(__auto_bitcast(__v))));
|
---|
| 304 | else if constexpr (__x_to_x && __have_ssse3)
|
---|
| 305 | return __intrin_bitcast<_To>(_mm_shuffle_epi8(
|
---|
| 306 | __intrin, _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, -0x80, -0x80,
|
---|
| 307 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80)));
|
---|
| 308 | else if constexpr (__x_to_x)
|
---|
| 309 | {
|
---|
| 310 | auto __a = _mm_unpacklo_epi16(__intrin, __m128i()); // 0o.o 1o.o
|
---|
| 311 | auto __b = _mm_unpackhi_epi16(__intrin, __m128i()); // 2o.o 3o.o
|
---|
| 312 | auto __c = _mm_unpacklo_epi16(__a, __b); // 02oo ..oo
|
---|
| 313 | auto __d = _mm_unpackhi_epi16(__a, __b); // 13oo ..oo
|
---|
| 314 | return __intrin_bitcast<_To>(
|
---|
| 315 | _mm_unpacklo_epi16(__c, __d)); // 0123 oooo
|
---|
| 316 | }
|
---|
| 317 | else if constexpr (__y_to_x && __have_avx512vl)
|
---|
| 318 | return __intrin_bitcast<_To>(_mm256_cvtepi32_epi16(__intrin));
|
---|
| 319 | else if constexpr (__y_to_x && __have_avx512f)
|
---|
| 320 | return __intrin_bitcast<_To>(
|
---|
| 321 | __lo128(_mm512_cvtepi32_epi16(__auto_bitcast(__v))));
|
---|
| 322 | else if constexpr (__y_to_x)
|
---|
| 323 | {
|
---|
| 324 | auto __a = _mm256_shuffle_epi8(
|
---|
| 325 | __intrin,
|
---|
| 326 | _mm256_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, -0x80, -0x80, -0x80,
|
---|
| 327 | -0x80, -0x80, -0x80, -0x80, -0x80, 0, 1, 4, 5, 8,
|
---|
| 328 | 9, 12, 13, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 329 | -0x80, -0x80, -0x80));
|
---|
| 330 | return __intrin_bitcast<_To>(__lo128(
|
---|
| 331 | _mm256_permute4x64_epi64(__a,
|
---|
| 332 | 0xf8))); // __a[0] __a[2] | __a[3] __a[3]
|
---|
| 333 | }
|
---|
| 334 | else if constexpr (__z_to_y)
|
---|
| 335 | return __intrin_bitcast<_To>(_mm512_cvtepi32_epi16(__intrin));
|
---|
| 336 | }
|
---|
| 337 | else if constexpr (__i32_to_i8) //{{{2
|
---|
| 338 | {
|
---|
| 339 | if constexpr (__x_to_x && __have_avx512vl)
|
---|
| 340 | return __intrin_bitcast<_To>(_mm_cvtepi32_epi8(__intrin));
|
---|
| 341 | else if constexpr (__x_to_x && __have_avx512f)
|
---|
| 342 | return __intrin_bitcast<_To>(
|
---|
| 343 | __lo128(_mm512_cvtepi32_epi8(__zero_extend(__intrin))));
|
---|
| 344 | else if constexpr (__x_to_x && __have_ssse3)
|
---|
| 345 | {
|
---|
| 346 | return __intrin_bitcast<_To>(
|
---|
| 347 | _mm_shuffle_epi8(__intrin,
|
---|
| 348 | _mm_setr_epi8(0, 4, 8, 12, -0x80, -0x80, -0x80,
|
---|
| 349 | -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 350 | -0x80, -0x80, -0x80, -0x80)));
|
---|
| 351 | }
|
---|
| 352 | else if constexpr (__x_to_x)
|
---|
| 353 | {
|
---|
| 354 | const auto __a
|
---|
| 355 | = _mm_unpacklo_epi8(__intrin, __intrin); // 0... .... 1... ....
|
---|
| 356 | const auto __b
|
---|
| 357 | = _mm_unpackhi_epi8(__intrin, __intrin); // 2... .... 3... ....
|
---|
| 358 | const auto __c = _mm_unpacklo_epi8(__a, __b); // 02.. .... .... ....
|
---|
| 359 | const auto __d = _mm_unpackhi_epi8(__a, __b); // 13.. .... .... ....
|
---|
| 360 | const auto __e = _mm_unpacklo_epi8(__c, __d); // 0123 .... .... ....
|
---|
| 361 | return __intrin_bitcast<_To>(__e & _mm_cvtsi32_si128(-1));
|
---|
| 362 | }
|
---|
| 363 | else if constexpr (__y_to_x && __have_avx512vl)
|
---|
| 364 | return __intrin_bitcast<_To>(_mm256_cvtepi32_epi8(__intrin));
|
---|
| 365 | else if constexpr (__y_to_x && __have_avx512f)
|
---|
| 366 | return __intrin_bitcast<_To>(
|
---|
| 367 | _mm512_cvtepi32_epi8(__zero_extend(__intrin)));
|
---|
| 368 | else if constexpr (__z_to_x)
|
---|
| 369 | return __intrin_bitcast<_To>(_mm512_cvtepi32_epi8(__intrin));
|
---|
| 370 | }
|
---|
| 371 | else if constexpr (__i16_to_i64) //{{{2
|
---|
| 372 | {
|
---|
| 373 | if constexpr (__x_to_x && __have_sse4_1)
|
---|
| 374 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 375 | ? _mm_cvtepi16_epi64(__intrin)
|
---|
| 376 | : _mm_cvtepu16_epi64(__intrin));
|
---|
| 377 | else if constexpr (__x_to_x && is_signed_v<_Tp>)
|
---|
| 378 | {
|
---|
| 379 | auto __x = _mm_srai_epi16(__intrin, 15);
|
---|
| 380 | auto __y = _mm_unpacklo_epi16(__intrin, __x);
|
---|
| 381 | __x = _mm_unpacklo_epi16(__x, __x);
|
---|
| 382 | return __intrin_bitcast<_To>(_mm_unpacklo_epi32(__y, __x));
|
---|
| 383 | }
|
---|
| 384 | else if constexpr (__x_to_x)
|
---|
| 385 | return __intrin_bitcast<_To>(
|
---|
| 386 | _mm_unpacklo_epi32(_mm_unpacklo_epi16(__intrin, __m128i()),
|
---|
| 387 | __m128i()));
|
---|
| 388 | else if constexpr (__x_to_y)
|
---|
| 389 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 390 | ? _mm256_cvtepi16_epi64(__intrin)
|
---|
| 391 | : _mm256_cvtepu16_epi64(__intrin));
|
---|
| 392 | else if constexpr (__x_to_z)
|
---|
| 393 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 394 | ? _mm512_cvtepi16_epi64(__intrin)
|
---|
| 395 | : _mm512_cvtepu16_epi64(__intrin));
|
---|
| 396 | }
|
---|
| 397 | else if constexpr (__i16_to_i32) //{{{2
|
---|
| 398 | {
|
---|
| 399 | if constexpr (__x_to_x && __have_sse4_1)
|
---|
| 400 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 401 | ? _mm_cvtepi16_epi32(__intrin)
|
---|
| 402 | : _mm_cvtepu16_epi32(__intrin));
|
---|
| 403 | else if constexpr (__x_to_x && is_signed_v<_Tp>)
|
---|
| 404 | return __intrin_bitcast<_To>(
|
---|
| 405 | _mm_srai_epi32(_mm_unpacklo_epi16(__intrin, __intrin), 16));
|
---|
| 406 | else if constexpr (__x_to_x && is_unsigned_v<_Tp>)
|
---|
| 407 | return __intrin_bitcast<_To>(_mm_unpacklo_epi16(__intrin, __m128i()));
|
---|
| 408 | else if constexpr (__x_to_y)
|
---|
| 409 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 410 | ? _mm256_cvtepi16_epi32(__intrin)
|
---|
| 411 | : _mm256_cvtepu16_epi32(__intrin));
|
---|
| 412 | else if constexpr (__y_to_z)
|
---|
| 413 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 414 | ? _mm512_cvtepi16_epi32(__intrin)
|
---|
| 415 | : _mm512_cvtepu16_epi32(__intrin));
|
---|
| 416 | }
|
---|
| 417 | else if constexpr (__i16_to_i8) //{{{2
|
---|
| 418 | {
|
---|
| 419 | if constexpr (__x_to_x && __have_avx512bw_vl)
|
---|
| 420 | return __intrin_bitcast<_To>(_mm_cvtepi16_epi8(__intrin));
|
---|
| 421 | else if constexpr (__x_to_x && __have_avx512bw)
|
---|
| 422 | return __intrin_bitcast<_To>(
|
---|
| 423 | __lo128(_mm512_cvtepi16_epi8(__zero_extend(__intrin))));
|
---|
| 424 | else if constexpr (__x_to_x && __have_ssse3)
|
---|
| 425 | return __intrin_bitcast<_To>(_mm_shuffle_epi8(
|
---|
| 426 | __intrin, _mm_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, -0x80, -0x80,
|
---|
| 427 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80)));
|
---|
| 428 | else if constexpr (__x_to_x)
|
---|
| 429 | {
|
---|
| 430 | auto __a
|
---|
| 431 | = _mm_unpacklo_epi8(__intrin, __intrin); // 00.. 11.. 22.. 33..
|
---|
| 432 | auto __b
|
---|
| 433 | = _mm_unpackhi_epi8(__intrin, __intrin); // 44.. 55.. 66.. 77..
|
---|
| 434 | auto __c = _mm_unpacklo_epi8(__a, __b); // 0404 .... 1515 ....
|
---|
| 435 | auto __d = _mm_unpackhi_epi8(__a, __b); // 2626 .... 3737 ....
|
---|
| 436 | auto __e = _mm_unpacklo_epi8(__c, __d); // 0246 0246 .... ....
|
---|
| 437 | auto __f = _mm_unpackhi_epi8(__c, __d); // 1357 1357 .... ....
|
---|
| 438 | return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__e, __f));
|
---|
| 439 | }
|
---|
| 440 | else if constexpr (__y_to_x && __have_avx512bw_vl)
|
---|
| 441 | return __intrin_bitcast<_To>(_mm256_cvtepi16_epi8(__intrin));
|
---|
| 442 | else if constexpr (__y_to_x && __have_avx512bw)
|
---|
| 443 | return __intrin_bitcast<_To>(
|
---|
| 444 | __lo256(_mm512_cvtepi16_epi8(__zero_extend(__intrin))));
|
---|
| 445 | else if constexpr (__y_to_x)
|
---|
| 446 | {
|
---|
| 447 | auto __a = _mm256_shuffle_epi8(
|
---|
| 448 | __intrin,
|
---|
| 449 | _mm256_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, -0x80, -0x80, -0x80,
|
---|
| 450 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 451 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, 0, 2,
|
---|
| 452 | 4, 6, 8, 10, 12, 14));
|
---|
| 453 | return __intrin_bitcast<_To>(__lo128(__a) | __hi128(__a));
|
---|
| 454 | }
|
---|
| 455 | else if constexpr (__z_to_y && __have_avx512bw)
|
---|
| 456 | return __intrin_bitcast<_To>(_mm512_cvtepi16_epi8(__intrin));
|
---|
| 457 | else if constexpr (__z_to_y)
|
---|
| 458 | __assert_unreachable<_Tp>();
|
---|
| 459 | }
|
---|
| 460 | else if constexpr (__i8_to_i64) //{{{2
|
---|
| 461 | {
|
---|
| 462 | if constexpr (__x_to_x && __have_sse4_1)
|
---|
| 463 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 464 | ? _mm_cvtepi8_epi64(__intrin)
|
---|
| 465 | : _mm_cvtepu8_epi64(__intrin));
|
---|
| 466 | else if constexpr (__x_to_x && is_signed_v<_Tp>)
|
---|
| 467 | {
|
---|
| 468 | if constexpr (__have_ssse3)
|
---|
| 469 | {
|
---|
| 470 | auto __dup = _mm_unpacklo_epi8(__intrin, __intrin);
|
---|
| 471 | auto __epi16 = _mm_srai_epi16(__dup, 8);
|
---|
| 472 | _mm_shuffle_epi8(__epi16,
|
---|
| 473 | _mm_setr_epi8(0, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3,
|
---|
| 474 | 3, 3, 3, 3, 3));
|
---|
| 475 | }
|
---|
| 476 | else
|
---|
| 477 | {
|
---|
| 478 | auto __x = _mm_unpacklo_epi8(__intrin, __intrin);
|
---|
| 479 | __x = _mm_unpacklo_epi16(__x, __x);
|
---|
| 480 | return __intrin_bitcast<_To>(
|
---|
| 481 | _mm_unpacklo_epi32(_mm_srai_epi32(__x, 24),
|
---|
| 482 | _mm_srai_epi32(__x, 31)));
|
---|
| 483 | }
|
---|
| 484 | }
|
---|
| 485 | else if constexpr (__x_to_x)
|
---|
| 486 | {
|
---|
| 487 | return __intrin_bitcast<_To>(_mm_unpacklo_epi32(
|
---|
| 488 | _mm_unpacklo_epi16(_mm_unpacklo_epi8(__intrin, __m128i()),
|
---|
| 489 | __m128i()),
|
---|
| 490 | __m128i()));
|
---|
| 491 | }
|
---|
| 492 | else if constexpr (__x_to_y)
|
---|
| 493 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 494 | ? _mm256_cvtepi8_epi64(__intrin)
|
---|
| 495 | : _mm256_cvtepu8_epi64(__intrin));
|
---|
| 496 | else if constexpr (__x_to_z)
|
---|
| 497 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 498 | ? _mm512_cvtepi8_epi64(__intrin)
|
---|
| 499 | : _mm512_cvtepu8_epi64(__intrin));
|
---|
| 500 | }
|
---|
| 501 | else if constexpr (__i8_to_i32) //{{{2
|
---|
| 502 | {
|
---|
| 503 | if constexpr (__x_to_x && __have_sse4_1)
|
---|
| 504 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 505 | ? _mm_cvtepi8_epi32(__intrin)
|
---|
| 506 | : _mm_cvtepu8_epi32(__intrin));
|
---|
| 507 | else if constexpr (__x_to_x && is_signed_v<_Tp>)
|
---|
| 508 | {
|
---|
| 509 | const auto __x = _mm_unpacklo_epi8(__intrin, __intrin);
|
---|
| 510 | return __intrin_bitcast<_To>(
|
---|
| 511 | _mm_srai_epi32(_mm_unpacklo_epi16(__x, __x), 24));
|
---|
| 512 | }
|
---|
| 513 | else if constexpr (__x_to_x && is_unsigned_v<_Tp>)
|
---|
| 514 | return __intrin_bitcast<_To>(
|
---|
| 515 | _mm_unpacklo_epi16(_mm_unpacklo_epi8(__intrin, __m128i()),
|
---|
| 516 | __m128i()));
|
---|
| 517 | else if constexpr (__x_to_y)
|
---|
| 518 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 519 | ? _mm256_cvtepi8_epi32(__intrin)
|
---|
| 520 | : _mm256_cvtepu8_epi32(__intrin));
|
---|
| 521 | else if constexpr (__x_to_z)
|
---|
| 522 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 523 | ? _mm512_cvtepi8_epi32(__intrin)
|
---|
| 524 | : _mm512_cvtepu8_epi32(__intrin));
|
---|
| 525 | }
|
---|
| 526 | else if constexpr (__i8_to_i16) //{{{2
|
---|
| 527 | {
|
---|
| 528 | if constexpr (__x_to_x && __have_sse4_1)
|
---|
| 529 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 530 | ? _mm_cvtepi8_epi16(__intrin)
|
---|
| 531 | : _mm_cvtepu8_epi16(__intrin));
|
---|
| 532 | else if constexpr (__x_to_x && is_signed_v<_Tp>)
|
---|
| 533 | return __intrin_bitcast<_To>(
|
---|
| 534 | _mm_srai_epi16(_mm_unpacklo_epi8(__intrin, __intrin), 8));
|
---|
| 535 | else if constexpr (__x_to_x && is_unsigned_v<_Tp>)
|
---|
| 536 | return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__intrin, __m128i()));
|
---|
| 537 | else if constexpr (__x_to_y)
|
---|
| 538 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 539 | ? _mm256_cvtepi8_epi16(__intrin)
|
---|
| 540 | : _mm256_cvtepu8_epi16(__intrin));
|
---|
| 541 | else if constexpr (__y_to_z && __have_avx512bw)
|
---|
| 542 | return __intrin_bitcast<_To>(is_signed_v<_Tp>
|
---|
| 543 | ? _mm512_cvtepi8_epi16(__intrin)
|
---|
| 544 | : _mm512_cvtepu8_epi16(__intrin));
|
---|
| 545 | else if constexpr (__y_to_z)
|
---|
| 546 | __assert_unreachable<_Tp>();
|
---|
| 547 | }
|
---|
| 548 | else if constexpr (__f32_to_s64) //{{{2
|
---|
| 549 | {
|
---|
| 550 | if constexpr (__have_avx512dq_vl && __x_to_x)
|
---|
| 551 | return __intrin_bitcast<_To>(_mm_cvttps_epi64(__intrin));
|
---|
| 552 | else if constexpr (__have_avx512dq_vl && __x_to_y)
|
---|
| 553 | return __intrin_bitcast<_To>(_mm256_cvttps_epi64(__intrin));
|
---|
| 554 | else if constexpr (__have_avx512dq && __y_to_z)
|
---|
| 555 | return __intrin_bitcast<_To>(_mm512_cvttps_epi64(__intrin));
|
---|
| 556 | // else use scalar fallback
|
---|
| 557 | }
|
---|
| 558 | else if constexpr (__f32_to_u64) //{{{2
|
---|
| 559 | {
|
---|
| 560 | if constexpr (__have_avx512dq_vl && __x_to_x)
|
---|
| 561 | return __intrin_bitcast<_To>(_mm_cvttps_epu64(__intrin));
|
---|
| 562 | else if constexpr (__have_avx512dq_vl && __x_to_y)
|
---|
| 563 | return __intrin_bitcast<_To>(_mm256_cvttps_epu64(__intrin));
|
---|
| 564 | else if constexpr (__have_avx512dq && __y_to_z)
|
---|
| 565 | return __intrin_bitcast<_To>(_mm512_cvttps_epu64(__intrin));
|
---|
| 566 | // else use scalar fallback
|
---|
| 567 | }
|
---|
| 568 | else if constexpr (__f32_to_s32) //{{{2
|
---|
| 569 | {
|
---|
| 570 | if constexpr (__x_to_x || __y_to_y || __z_to_z)
|
---|
| 571 | {
|
---|
| 572 | // go to fallback, it does the right thing
|
---|
| 573 | }
|
---|
| 574 | else
|
---|
| 575 | __assert_unreachable<_Tp>();
|
---|
| 576 | }
|
---|
| 577 | else if constexpr (__f32_to_u32) //{{{2
|
---|
| 578 | {
|
---|
| 579 | if constexpr (__have_avx512vl && __x_to_x)
|
---|
| 580 | return __auto_bitcast(_mm_cvttps_epu32(__intrin));
|
---|
| 581 | else if constexpr (__have_avx512f && __x_to_x)
|
---|
| 582 | return __auto_bitcast(
|
---|
| 583 | __lo128(_mm512_cvttps_epu32(__auto_bitcast(__v))));
|
---|
| 584 | else if constexpr (__have_avx512vl && __y_to_y)
|
---|
| 585 | return __vector_bitcast<_Up>(_mm256_cvttps_epu32(__intrin));
|
---|
| 586 | else if constexpr (__have_avx512f && __y_to_y)
|
---|
| 587 | return __vector_bitcast<_Up>(
|
---|
| 588 | __lo256(_mm512_cvttps_epu32(__auto_bitcast(__v))));
|
---|
| 589 | else if constexpr (__x_to_x || __y_to_y || __z_to_z)
|
---|
| 590 | {
|
---|
| 591 | // go to fallback, it does the right thing. We can't use the
|
---|
| 592 | // _mm_floor_ps - 0x8000'0000 trick for f32->u32 because it would
|
---|
| 593 | // discard small input values (only 24 mantissa bits)
|
---|
| 594 | }
|
---|
| 595 | else
|
---|
| 596 | __assert_unreachable<_Tp>();
|
---|
| 597 | }
|
---|
| 598 | else if constexpr (__f32_to_ibw) //{{{2
|
---|
| 599 | return __convert_x86<_To>(__convert_x86<__vector_type_t<int, _Np>>(__v));
|
---|
| 600 | else if constexpr (__f64_to_s64) //{{{2
|
---|
| 601 | {
|
---|
| 602 | if constexpr (__have_avx512dq_vl && __x_to_x)
|
---|
| 603 | return __intrin_bitcast<_To>(_mm_cvttpd_epi64(__intrin));
|
---|
| 604 | else if constexpr (__have_avx512dq_vl && __y_to_y)
|
---|
| 605 | return __intrin_bitcast<_To>(_mm256_cvttpd_epi64(__intrin));
|
---|
| 606 | else if constexpr (__have_avx512dq && __z_to_z)
|
---|
| 607 | return __intrin_bitcast<_To>(_mm512_cvttpd_epi64(__intrin));
|
---|
| 608 | // else use scalar fallback
|
---|
| 609 | }
|
---|
| 610 | else if constexpr (__f64_to_u64) //{{{2
|
---|
| 611 | {
|
---|
| 612 | if constexpr (__have_avx512dq_vl && __x_to_x)
|
---|
| 613 | return __intrin_bitcast<_To>(_mm_cvttpd_epu64(__intrin));
|
---|
| 614 | else if constexpr (__have_avx512dq_vl && __y_to_y)
|
---|
| 615 | return __intrin_bitcast<_To>(_mm256_cvttpd_epu64(__intrin));
|
---|
| 616 | else if constexpr (__have_avx512dq && __z_to_z)
|
---|
| 617 | return __intrin_bitcast<_To>(_mm512_cvttpd_epu64(__intrin));
|
---|
| 618 | // else use scalar fallback
|
---|
| 619 | }
|
---|
| 620 | else if constexpr (__f64_to_s32) //{{{2
|
---|
| 621 | {
|
---|
| 622 | if constexpr (__x_to_x)
|
---|
| 623 | return __intrin_bitcast<_To>(_mm_cvttpd_epi32(__intrin));
|
---|
| 624 | else if constexpr (__y_to_x)
|
---|
| 625 | return __intrin_bitcast<_To>(_mm256_cvttpd_epi32(__intrin));
|
---|
| 626 | else if constexpr (__z_to_y)
|
---|
| 627 | return __intrin_bitcast<_To>(_mm512_cvttpd_epi32(__intrin));
|
---|
| 628 | }
|
---|
| 629 | else if constexpr (__f64_to_u32) //{{{2
|
---|
| 630 | {
|
---|
| 631 | if constexpr (__have_avx512vl && __x_to_x)
|
---|
| 632 | return __intrin_bitcast<_To>(_mm_cvttpd_epu32(__intrin));
|
---|
| 633 | else if constexpr (__have_sse4_1 && __x_to_x)
|
---|
| 634 | return __vector_bitcast<_Up, _M>(
|
---|
| 635 | _mm_cvttpd_epi32(_mm_floor_pd(__intrin) - 0x8000'0000u))
|
---|
| 636 | ^ 0x8000'0000u;
|
---|
| 637 | else if constexpr (__x_to_x)
|
---|
| 638 | {
|
---|
| 639 | // use scalar fallback: it's only 2 values to convert, can't get
|
---|
| 640 | // much better than scalar decomposition
|
---|
| 641 | }
|
---|
| 642 | else if constexpr (__have_avx512vl && __y_to_x)
|
---|
| 643 | return __intrin_bitcast<_To>(_mm256_cvttpd_epu32(__intrin));
|
---|
| 644 | else if constexpr (__y_to_x)
|
---|
| 645 | {
|
---|
| 646 | return __intrin_bitcast<_To>(
|
---|
| 647 | __vector_bitcast<_Up>(
|
---|
| 648 | _mm256_cvttpd_epi32(_mm256_floor_pd(__intrin) - 0x8000'0000u))
|
---|
| 649 | ^ 0x8000'0000u);
|
---|
| 650 | }
|
---|
| 651 | else if constexpr (__z_to_y)
|
---|
| 652 | return __intrin_bitcast<_To>(_mm512_cvttpd_epu32(__intrin));
|
---|
| 653 | }
|
---|
| 654 | else if constexpr (__f64_to_ibw) //{{{2
|
---|
| 655 | {
|
---|
| 656 | return __convert_x86<_To>(
|
---|
| 657 | __convert_x86<__vector_type_t<int, (_Np < 4 ? 4 : _Np)>>(__v));
|
---|
| 658 | }
|
---|
| 659 | else if constexpr (__s64_to_f32) //{{{2
|
---|
| 660 | {
|
---|
| 661 | if constexpr (__x_to_x && __have_avx512dq_vl)
|
---|
| 662 | return __intrin_bitcast<_To>(_mm_cvtepi64_ps(__intrin));
|
---|
| 663 | else if constexpr (__y_to_x && __have_avx512dq_vl)
|
---|
| 664 | return __intrin_bitcast<_To>(_mm256_cvtepi64_ps(__intrin));
|
---|
| 665 | else if constexpr (__z_to_y && __have_avx512dq)
|
---|
| 666 | return __intrin_bitcast<_To>(_mm512_cvtepi64_ps(__intrin));
|
---|
| 667 | else if constexpr (__z_to_y)
|
---|
| 668 | return __intrin_bitcast<_To>(
|
---|
| 669 | _mm512_cvtpd_ps(__convert_x86<__vector_type_t<double, 8>>(__v)));
|
---|
| 670 | }
|
---|
| 671 | else if constexpr (__u64_to_f32) //{{{2
|
---|
| 672 | {
|
---|
| 673 | if constexpr (__x_to_x && __have_avx512dq_vl)
|
---|
| 674 | return __intrin_bitcast<_To>(_mm_cvtepu64_ps(__intrin));
|
---|
| 675 | else if constexpr (__y_to_x && __have_avx512dq_vl)
|
---|
| 676 | return __intrin_bitcast<_To>(_mm256_cvtepu64_ps(__intrin));
|
---|
| 677 | else if constexpr (__z_to_y && __have_avx512dq)
|
---|
| 678 | return __intrin_bitcast<_To>(_mm512_cvtepu64_ps(__intrin));
|
---|
| 679 | else if constexpr (__z_to_y)
|
---|
| 680 | {
|
---|
| 681 | return __intrin_bitcast<_To>(
|
---|
| 682 | __lo256(_mm512_cvtepu32_ps(__auto_bitcast(
|
---|
| 683 | _mm512_cvtepi64_epi32(_mm512_srai_epi64(__intrin, 32)))))
|
---|
| 684 | * 0x100000000LL
|
---|
| 685 | + __lo256(_mm512_cvtepu32_ps(
|
---|
| 686 | __auto_bitcast(_mm512_cvtepi64_epi32(__intrin)))));
|
---|
| 687 | }
|
---|
| 688 | }
|
---|
| 689 | else if constexpr (__s32_to_f32) //{{{2
|
---|
| 690 | {
|
---|
| 691 | // use fallback (builtin conversion)
|
---|
| 692 | }
|
---|
| 693 | else if constexpr (__u32_to_f32) //{{{2
|
---|
| 694 | {
|
---|
| 695 | if constexpr (__x_to_x && __have_avx512vl)
|
---|
| 696 | {
|
---|
| 697 | // use fallback
|
---|
| 698 | }
|
---|
| 699 | else if constexpr (__x_to_x && __have_avx512f)
|
---|
| 700 | return __intrin_bitcast<_To>(
|
---|
| 701 | __lo128(_mm512_cvtepu32_ps(__auto_bitcast(__v))));
|
---|
| 702 | else if constexpr (__x_to_x && (__have_fma || __have_fma4))
|
---|
| 703 | // work around PR85819
|
---|
| 704 | return __auto_bitcast(0x10000
|
---|
| 705 | * _mm_cvtepi32_ps(__to_intrin(__v >> 16))
|
---|
| 706 | + _mm_cvtepi32_ps(__to_intrin(__v & 0xffff)));
|
---|
| 707 | else if constexpr (__y_to_y && __have_avx512vl)
|
---|
| 708 | {
|
---|
| 709 | // use fallback
|
---|
| 710 | }
|
---|
| 711 | else if constexpr (__y_to_y && __have_avx512f)
|
---|
| 712 | return __intrin_bitcast<_To>(
|
---|
| 713 | __lo256(_mm512_cvtepu32_ps(__auto_bitcast(__v))));
|
---|
| 714 | else if constexpr (__y_to_y)
|
---|
| 715 | // work around PR85819
|
---|
| 716 | return 0x10000 * _mm256_cvtepi32_ps(__to_intrin(__v >> 16))
|
---|
| 717 | + _mm256_cvtepi32_ps(__to_intrin(__v & 0xffff));
|
---|
| 718 | // else use fallback (builtin conversion)
|
---|
| 719 | }
|
---|
| 720 | else if constexpr (__ibw_to_f32) //{{{2
|
---|
| 721 | {
|
---|
| 722 | if constexpr (_M <= 4 || __have_avx2)
|
---|
| 723 | return __convert_x86<_To>(
|
---|
| 724 | __convert_x86<__vector_type_t<int, _M>>(__v));
|
---|
| 725 | else
|
---|
| 726 | {
|
---|
| 727 | static_assert(__x_to_y);
|
---|
| 728 | __m128i __a, __b;
|
---|
| 729 | if constexpr (__have_sse4_1)
|
---|
| 730 | {
|
---|
| 731 | __a = sizeof(_Tp) == 2
|
---|
| 732 | ? (is_signed_v<_Tp> ? _mm_cvtepi16_epi32(__intrin)
|
---|
| 733 | : _mm_cvtepu16_epi32(__intrin))
|
---|
| 734 | : (is_signed_v<_Tp> ? _mm_cvtepi8_epi32(__intrin)
|
---|
| 735 | : _mm_cvtepu8_epi32(__intrin));
|
---|
| 736 | const auto __w
|
---|
| 737 | = _mm_shuffle_epi32(__intrin, sizeof(_Tp) == 2 ? 0xee : 0xe9);
|
---|
| 738 | __b = sizeof(_Tp) == 2
|
---|
| 739 | ? (is_signed_v<_Tp> ? _mm_cvtepi16_epi32(__w)
|
---|
| 740 | : _mm_cvtepu16_epi32(__w))
|
---|
| 741 | : (is_signed_v<_Tp> ? _mm_cvtepi8_epi32(__w)
|
---|
| 742 | : _mm_cvtepu8_epi32(__w));
|
---|
| 743 | }
|
---|
| 744 | else
|
---|
| 745 | {
|
---|
| 746 | __m128i __tmp;
|
---|
| 747 | if constexpr (sizeof(_Tp) == 1)
|
---|
| 748 | {
|
---|
| 749 | __tmp = is_signed_v<_Tp>
|
---|
| 750 | ? _mm_srai_epi16(_mm_unpacklo_epi8(__intrin,
|
---|
| 751 | __intrin),
|
---|
| 752 | 8)
|
---|
| 753 | : _mm_unpacklo_epi8(__intrin, __m128i());
|
---|
| 754 | }
|
---|
| 755 | else
|
---|
| 756 | {
|
---|
| 757 | static_assert(sizeof(_Tp) == 2);
|
---|
| 758 | __tmp = __intrin;
|
---|
| 759 | }
|
---|
| 760 | __a = is_signed_v<_Tp>
|
---|
| 761 | ? _mm_srai_epi32(_mm_unpacklo_epi16(__tmp, __tmp), 16)
|
---|
| 762 | : _mm_unpacklo_epi16(__tmp, __m128i());
|
---|
| 763 | __b = is_signed_v<_Tp>
|
---|
| 764 | ? _mm_srai_epi32(_mm_unpackhi_epi16(__tmp, __tmp), 16)
|
---|
| 765 | : _mm_unpackhi_epi16(__tmp, __m128i());
|
---|
| 766 | }
|
---|
| 767 | return __convert_x86<_To>(__vector_bitcast<int>(__a),
|
---|
| 768 | __vector_bitcast<int>(__b));
|
---|
| 769 | }
|
---|
| 770 | }
|
---|
| 771 | else if constexpr (__s64_to_f64) //{{{2
|
---|
| 772 | {
|
---|
| 773 | if constexpr (__x_to_x && __have_avx512dq_vl)
|
---|
| 774 | return __intrin_bitcast<_To>(_mm_cvtepi64_pd(__intrin));
|
---|
| 775 | else if constexpr (__y_to_y && __have_avx512dq_vl)
|
---|
| 776 | return __intrin_bitcast<_To>(_mm256_cvtepi64_pd(__intrin));
|
---|
| 777 | else if constexpr (__z_to_z && __have_avx512dq)
|
---|
| 778 | return __intrin_bitcast<_To>(_mm512_cvtepi64_pd(__intrin));
|
---|
| 779 | else if constexpr (__z_to_z)
|
---|
| 780 | {
|
---|
| 781 | return __intrin_bitcast<_To>(
|
---|
| 782 | _mm512_cvtepi32_pd(_mm512_cvtepi64_epi32(__to_intrin(__v >> 32)))
|
---|
| 783 | * 0x100000000LL
|
---|
| 784 | + _mm512_cvtepu32_pd(_mm512_cvtepi64_epi32(__intrin)));
|
---|
| 785 | }
|
---|
| 786 | }
|
---|
| 787 | else if constexpr (__u64_to_f64) //{{{2
|
---|
| 788 | {
|
---|
| 789 | if constexpr (__x_to_x && __have_avx512dq_vl)
|
---|
| 790 | return __intrin_bitcast<_To>(_mm_cvtepu64_pd(__intrin));
|
---|
| 791 | else if constexpr (__y_to_y && __have_avx512dq_vl)
|
---|
| 792 | return __intrin_bitcast<_To>(_mm256_cvtepu64_pd(__intrin));
|
---|
| 793 | else if constexpr (__z_to_z && __have_avx512dq)
|
---|
| 794 | return __intrin_bitcast<_To>(_mm512_cvtepu64_pd(__intrin));
|
---|
| 795 | else if constexpr (__z_to_z)
|
---|
| 796 | {
|
---|
| 797 | return __intrin_bitcast<_To>(
|
---|
| 798 | _mm512_cvtepu32_pd(_mm512_cvtepi64_epi32(__to_intrin(__v >> 32)))
|
---|
| 799 | * 0x100000000LL
|
---|
| 800 | + _mm512_cvtepu32_pd(_mm512_cvtepi64_epi32(__intrin)));
|
---|
| 801 | }
|
---|
| 802 | }
|
---|
| 803 | else if constexpr (__s32_to_f64) //{{{2
|
---|
| 804 | {
|
---|
| 805 | if constexpr (__x_to_x)
|
---|
| 806 | return __intrin_bitcast<_To>(_mm_cvtepi32_pd(__intrin));
|
---|
| 807 | else if constexpr (__x_to_y)
|
---|
| 808 | return __intrin_bitcast<_To>(_mm256_cvtepi32_pd(__intrin));
|
---|
| 809 | else if constexpr (__y_to_z)
|
---|
| 810 | return __intrin_bitcast<_To>(_mm512_cvtepi32_pd(__intrin));
|
---|
| 811 | }
|
---|
| 812 | else if constexpr (__u32_to_f64) //{{{2
|
---|
| 813 | {
|
---|
| 814 | if constexpr (__x_to_x && __have_avx512vl)
|
---|
| 815 | return __intrin_bitcast<_To>(_mm_cvtepu32_pd(__intrin));
|
---|
| 816 | else if constexpr (__x_to_x && __have_avx512f)
|
---|
| 817 | return __intrin_bitcast<_To>(
|
---|
| 818 | __lo128(_mm512_cvtepu32_pd(__auto_bitcast(__v))));
|
---|
| 819 | else if constexpr (__x_to_x)
|
---|
| 820 | return __intrin_bitcast<_To>(
|
---|
| 821 | _mm_cvtepi32_pd(__to_intrin(__v ^ 0x8000'0000u)) + 0x8000'0000u);
|
---|
| 822 | else if constexpr (__x_to_y && __have_avx512vl)
|
---|
| 823 | return __intrin_bitcast<_To>(_mm256_cvtepu32_pd(__intrin));
|
---|
| 824 | else if constexpr (__x_to_y && __have_avx512f)
|
---|
| 825 | return __intrin_bitcast<_To>(
|
---|
| 826 | __lo256(_mm512_cvtepu32_pd(__auto_bitcast(__v))));
|
---|
| 827 | else if constexpr (__x_to_y)
|
---|
| 828 | return __intrin_bitcast<_To>(
|
---|
| 829 | _mm256_cvtepi32_pd(__to_intrin(__v ^ 0x8000'0000u)) + 0x8000'0000u);
|
---|
| 830 | else if constexpr (__y_to_z)
|
---|
| 831 | return __intrin_bitcast<_To>(_mm512_cvtepu32_pd(__intrin));
|
---|
| 832 | }
|
---|
| 833 | else if constexpr (__ibw_to_f64) //{{{2
|
---|
| 834 | {
|
---|
| 835 | return __convert_x86<_To>(
|
---|
| 836 | __convert_x86<__vector_type_t<int, std::max(size_t(4), _M)>>(__v));
|
---|
| 837 | }
|
---|
| 838 | else if constexpr (__f32_to_f64) //{{{2
|
---|
| 839 | {
|
---|
| 840 | if constexpr (__x_to_x)
|
---|
| 841 | return __intrin_bitcast<_To>(_mm_cvtps_pd(__intrin));
|
---|
| 842 | else if constexpr (__x_to_y)
|
---|
| 843 | return __intrin_bitcast<_To>(_mm256_cvtps_pd(__intrin));
|
---|
| 844 | else if constexpr (__y_to_z)
|
---|
| 845 | return __intrin_bitcast<_To>(_mm512_cvtps_pd(__intrin));
|
---|
| 846 | }
|
---|
| 847 | else if constexpr (__f64_to_f32) //{{{2
|
---|
| 848 | {
|
---|
| 849 | if constexpr (__x_to_x)
|
---|
| 850 | return __intrin_bitcast<_To>(_mm_cvtpd_ps(__intrin));
|
---|
| 851 | else if constexpr (__y_to_x)
|
---|
| 852 | return __intrin_bitcast<_To>(_mm256_cvtpd_ps(__intrin));
|
---|
| 853 | else if constexpr (__z_to_y)
|
---|
| 854 | return __intrin_bitcast<_To>(_mm512_cvtpd_ps(__intrin));
|
---|
| 855 | }
|
---|
| 856 | else //{{{2
|
---|
| 857 | __assert_unreachable<_Tp>();
|
---|
| 858 |
|
---|
| 859 | // fallback:{{{2
|
---|
| 860 | return __vector_convert<_To>(__v, make_index_sequence<std::min(_M, _Np)>());
|
---|
| 861 | //}}}
|
---|
| 862 | }
|
---|
| 863 |
|
---|
| 864 | // }}}
|
---|
| 865 | // 2-arg __convert_x86 {{{1
|
---|
| 866 | template <typename _To, typename _V, typename _Traits>
|
---|
| 867 | _GLIBCXX_SIMD_INTRINSIC _To
|
---|
| 868 | __convert_x86(_V __v0, _V __v1)
|
---|
| 869 | {
|
---|
| 870 | static_assert(__is_vector_type_v<_V>);
|
---|
| 871 | using _Tp = typename _Traits::value_type;
|
---|
| 872 | constexpr size_t _Np = _Traits::_S_full_size;
|
---|
| 873 | [[maybe_unused]] const auto __i0 = __to_intrin(__v0);
|
---|
| 874 | [[maybe_unused]] const auto __i1 = __to_intrin(__v1);
|
---|
| 875 | using _Up = typename _VectorTraits<_To>::value_type;
|
---|
| 876 | constexpr size_t _M = _VectorTraits<_To>::_S_full_size;
|
---|
| 877 |
|
---|
| 878 | static_assert(2 * _Np <= _M,
|
---|
| 879 | "__v1 would be discarded; use the one-argument "
|
---|
| 880 | "__convert_x86 overload instead");
|
---|
| 881 |
|
---|
| 882 | // [xyz]_to_[xyz] {{{2
|
---|
| 883 | [[maybe_unused]] constexpr bool __x_to_x
|
---|
| 884 | = sizeof(__v0) <= 16 && sizeof(_To) <= 16;
|
---|
| 885 | [[maybe_unused]] constexpr bool __x_to_y
|
---|
| 886 | = sizeof(__v0) <= 16 && sizeof(_To) == 32;
|
---|
| 887 | [[maybe_unused]] constexpr bool __x_to_z
|
---|
| 888 | = sizeof(__v0) <= 16 && sizeof(_To) == 64;
|
---|
| 889 | [[maybe_unused]] constexpr bool __y_to_x
|
---|
| 890 | = sizeof(__v0) == 32 && sizeof(_To) <= 16;
|
---|
| 891 | [[maybe_unused]] constexpr bool __y_to_y
|
---|
| 892 | = sizeof(__v0) == 32 && sizeof(_To) == 32;
|
---|
| 893 | [[maybe_unused]] constexpr bool __y_to_z
|
---|
| 894 | = sizeof(__v0) == 32 && sizeof(_To) == 64;
|
---|
| 895 | [[maybe_unused]] constexpr bool __z_to_x
|
---|
| 896 | = sizeof(__v0) == 64 && sizeof(_To) <= 16;
|
---|
| 897 | [[maybe_unused]] constexpr bool __z_to_y
|
---|
| 898 | = sizeof(__v0) == 64 && sizeof(_To) == 32;
|
---|
| 899 | [[maybe_unused]] constexpr bool __z_to_z
|
---|
| 900 | = sizeof(__v0) == 64 && sizeof(_To) == 64;
|
---|
| 901 |
|
---|
| 902 | // iX_to_iX {{{2
|
---|
| 903 | [[maybe_unused]] constexpr bool __i_to_i
|
---|
| 904 | = is_integral_v<_Up> && is_integral_v<_Tp>;
|
---|
| 905 | [[maybe_unused]] constexpr bool __i8_to_i16
|
---|
| 906 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 2;
|
---|
| 907 | [[maybe_unused]] constexpr bool __i8_to_i32
|
---|
| 908 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 4;
|
---|
| 909 | [[maybe_unused]] constexpr bool __i8_to_i64
|
---|
| 910 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 8;
|
---|
| 911 | [[maybe_unused]] constexpr bool __i16_to_i8
|
---|
| 912 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 1;
|
---|
| 913 | [[maybe_unused]] constexpr bool __i16_to_i32
|
---|
| 914 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 4;
|
---|
| 915 | [[maybe_unused]] constexpr bool __i16_to_i64
|
---|
| 916 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 8;
|
---|
| 917 | [[maybe_unused]] constexpr bool __i32_to_i8
|
---|
| 918 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 1;
|
---|
| 919 | [[maybe_unused]] constexpr bool __i32_to_i16
|
---|
| 920 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 2;
|
---|
| 921 | [[maybe_unused]] constexpr bool __i32_to_i64
|
---|
| 922 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 8;
|
---|
| 923 | [[maybe_unused]] constexpr bool __i64_to_i8
|
---|
| 924 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 1;
|
---|
| 925 | [[maybe_unused]] constexpr bool __i64_to_i16
|
---|
| 926 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 2;
|
---|
| 927 | [[maybe_unused]] constexpr bool __i64_to_i32
|
---|
| 928 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 4;
|
---|
| 929 |
|
---|
| 930 | // [fsu]X_to_[fsu]X {{{2
|
---|
| 931 | // ibw = integral && byte or word, i.e. char and short with any signedness
|
---|
| 932 | [[maybe_unused]] constexpr bool __i64_to_f32
|
---|
| 933 | = is_integral_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 934 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 935 | [[maybe_unused]] constexpr bool __s32_to_f32
|
---|
| 936 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 937 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 938 | [[maybe_unused]] constexpr bool __s16_to_f32
|
---|
| 939 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 940 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 941 | [[maybe_unused]] constexpr bool __s8_to_f32
|
---|
| 942 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 943 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 944 | [[maybe_unused]] constexpr bool __u32_to_f32
|
---|
| 945 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 946 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 947 | [[maybe_unused]] constexpr bool __u16_to_f32
|
---|
| 948 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 949 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 950 | [[maybe_unused]] constexpr bool __u8_to_f32
|
---|
| 951 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 952 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 953 | [[maybe_unused]] constexpr bool __s64_to_f64
|
---|
| 954 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 955 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 956 | [[maybe_unused]] constexpr bool __s32_to_f64
|
---|
| 957 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 958 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 959 | [[maybe_unused]] constexpr bool __s16_to_f64
|
---|
| 960 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 961 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 962 | [[maybe_unused]] constexpr bool __s8_to_f64
|
---|
| 963 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 964 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 965 | [[maybe_unused]] constexpr bool __u64_to_f64
|
---|
| 966 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 967 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 968 | [[maybe_unused]] constexpr bool __u32_to_f64
|
---|
| 969 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 970 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 971 | [[maybe_unused]] constexpr bool __u16_to_f64
|
---|
| 972 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 973 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 974 | [[maybe_unused]] constexpr bool __u8_to_f64
|
---|
| 975 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 976 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 977 | [[maybe_unused]] constexpr bool __f32_to_s64
|
---|
| 978 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
|
---|
| 979 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 980 | [[maybe_unused]] constexpr bool __f32_to_s32
|
---|
| 981 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
|
---|
| 982 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 983 | [[maybe_unused]] constexpr bool __f32_to_u64
|
---|
| 984 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
|
---|
| 985 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 986 | [[maybe_unused]] constexpr bool __f32_to_u32
|
---|
| 987 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
|
---|
| 988 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 989 | [[maybe_unused]] constexpr bool __f64_to_s64
|
---|
| 990 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
|
---|
| 991 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 992 | [[maybe_unused]] constexpr bool __f64_to_s32
|
---|
| 993 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
|
---|
| 994 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 995 | [[maybe_unused]] constexpr bool __f64_to_u64
|
---|
| 996 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
|
---|
| 997 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 998 | [[maybe_unused]] constexpr bool __f64_to_u32
|
---|
| 999 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
|
---|
| 1000 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 1001 | [[maybe_unused]] constexpr bool __f32_to_ibw
|
---|
| 1002 | = is_integral_v<_Up> && sizeof(_Up) <= 2
|
---|
| 1003 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 1004 | [[maybe_unused]] constexpr bool __f64_to_ibw
|
---|
| 1005 | = is_integral_v<_Up> && sizeof(_Up) <= 2
|
---|
| 1006 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 1007 | [[maybe_unused]] constexpr bool __f32_to_f64
|
---|
| 1008 | = is_floating_point_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 1009 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1010 | [[maybe_unused]] constexpr bool __f64_to_f32
|
---|
| 1011 | = is_floating_point_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 1012 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1013 |
|
---|
| 1014 | if constexpr (__i_to_i && __y_to_x && !__have_avx2) //{{{2
|
---|
| 1015 | // <double, 4>, <double, 4> => <short, 8>
|
---|
| 1016 | return __convert_x86<_To>(__lo128(__v0), __hi128(__v0), __lo128(__v1),
|
---|
| 1017 | __hi128(__v1));
|
---|
| 1018 | else if constexpr (__i_to_i) // assert ISA {{{2
|
---|
| 1019 | {
|
---|
| 1020 | static_assert(__x_to_x || __have_avx2,
|
---|
| 1021 | "integral conversions with ymm registers require AVX2");
|
---|
| 1022 | static_assert(__have_avx512bw
|
---|
| 1023 | || ((sizeof(_Tp) >= 4 || sizeof(__v0) < 64)
|
---|
| 1024 | && (sizeof(_Up) >= 4 || sizeof(_To) < 64)),
|
---|
| 1025 | "8/16-bit integers in zmm registers require AVX512BW");
|
---|
| 1026 | static_assert((sizeof(__v0) < 64 && sizeof(_To) < 64) || __have_avx512f,
|
---|
| 1027 | "integral conversions with ymm registers require AVX2");
|
---|
| 1028 | }
|
---|
| 1029 | // concat => use 1-arg __convert_x86 {{{2
|
---|
| 1030 | if constexpr (sizeof(__v0) < 16 || (sizeof(__v0) == 16 && __have_avx2)
|
---|
| 1031 | || (sizeof(__v0) == 16 && __have_avx
|
---|
| 1032 | && is_floating_point_v<_Tp>)
|
---|
| 1033 | || (sizeof(__v0) == 32 && __have_avx512f
|
---|
| 1034 | && (sizeof(_Tp) >= 4 || __have_avx512bw)))
|
---|
| 1035 | {
|
---|
| 1036 | // The ISA can handle wider input registers, so concat and use one-arg
|
---|
| 1037 | // implementation. This reduces code duplication considerably.
|
---|
| 1038 | return __convert_x86<_To>(__concat(__v0, __v1));
|
---|
| 1039 | }
|
---|
| 1040 | else //{{{2
|
---|
| 1041 | {
|
---|
| 1042 | // conversion using bit reinterpretation (or no conversion at all)
|
---|
| 1043 | // should all go through the concat branch above:
|
---|
| 1044 | static_assert(
|
---|
| 1045 | !(is_floating_point_v<
|
---|
| 1046 | _Tp> == is_floating_point_v<_Up> && sizeof(_Tp) == sizeof(_Up)));
|
---|
| 1047 | // handle all zero extension{{{2
|
---|
| 1048 | if constexpr (2 * _Np < _M && sizeof(_To) > 16)
|
---|
| 1049 | {
|
---|
| 1050 | constexpr size_t Min = 16 / sizeof(_Up);
|
---|
| 1051 | return __zero_extend(
|
---|
| 1052 | __convert_x86<
|
---|
| 1053 | __vector_type_t<_Up, (Min > 2 * _Np) ? Min : 2 * _Np>>(__v0,
|
---|
| 1054 | __v1));
|
---|
| 1055 | }
|
---|
| 1056 | else if constexpr (__i64_to_i32) //{{{2
|
---|
| 1057 | {
|
---|
| 1058 | if constexpr (__x_to_x)
|
---|
| 1059 | return __auto_bitcast(_mm_shuffle_ps(__auto_bitcast(__v0),
|
---|
| 1060 | __auto_bitcast(__v1), 0x88));
|
---|
| 1061 | else if constexpr (__y_to_y)
|
---|
| 1062 | {
|
---|
| 1063 | // AVX512F is not available (would concat otherwise)
|
---|
| 1064 | return __auto_bitcast(
|
---|
| 1065 | __xzyw(_mm256_shuffle_ps(__auto_bitcast(__v0),
|
---|
| 1066 | __auto_bitcast(__v1), 0x88)));
|
---|
| 1067 | // alternative:
|
---|
| 1068 | // const auto v0_abxxcdxx = _mm256_shuffle_epi32(__v0, 8);
|
---|
| 1069 | // const auto v1_efxxghxx = _mm256_shuffle_epi32(__v1, 8);
|
---|
| 1070 | // const auto v_abefcdgh = _mm256_unpacklo_epi64(v0_abxxcdxx,
|
---|
| 1071 | // v1_efxxghxx); return _mm256_permute4x64_epi64(v_abefcdgh,
|
---|
| 1072 | // 0x01 * 0 + 0x04 * 2 + 0x10 * 1 + 0x40 * 3); // abcdefgh
|
---|
| 1073 | }
|
---|
| 1074 | else if constexpr (__z_to_z)
|
---|
| 1075 | return __intrin_bitcast<_To>(
|
---|
| 1076 | __concat(_mm512_cvtepi64_epi32(__i0),
|
---|
| 1077 | _mm512_cvtepi64_epi32(__i1)));
|
---|
| 1078 | }
|
---|
| 1079 | else if constexpr (__i64_to_i16) //{{{2
|
---|
| 1080 | {
|
---|
| 1081 | if constexpr (__x_to_x)
|
---|
| 1082 | {
|
---|
| 1083 | // AVX2 is not available (would concat otherwise)
|
---|
| 1084 | if constexpr (__have_sse4_1)
|
---|
| 1085 | {
|
---|
| 1086 | return __intrin_bitcast<_To>(_mm_shuffle_epi8(
|
---|
| 1087 | _mm_blend_epi16(__i0, _mm_slli_si128(__i1, 4), 0x44),
|
---|
| 1088 | _mm_setr_epi8(0, 1, 8, 9, 4, 5, 12, 13, -0x80, -0x80,
|
---|
| 1089 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80)));
|
---|
| 1090 | }
|
---|
| 1091 | else
|
---|
| 1092 | {
|
---|
| 1093 | return __vector_type_t<_Up, _M>{_Up(__v0[0]), _Up(__v0[1]),
|
---|
| 1094 | _Up(__v1[0]), _Up(__v1[1])};
|
---|
| 1095 | }
|
---|
| 1096 | }
|
---|
| 1097 | else if constexpr (__y_to_x)
|
---|
| 1098 | {
|
---|
| 1099 | auto __a
|
---|
| 1100 | = _mm256_unpacklo_epi16(__i0, __i1); // 04.. .... 26.. ....
|
---|
| 1101 | auto __b
|
---|
| 1102 | = _mm256_unpackhi_epi16(__i0, __i1); // 15.. .... 37.. ....
|
---|
| 1103 | auto __c
|
---|
| 1104 | = _mm256_unpacklo_epi16(__a, __b); // 0145 .... 2367 ....
|
---|
| 1105 | return __intrin_bitcast<_To>(
|
---|
| 1106 | _mm_unpacklo_epi32(__lo128(__c), __hi128(__c))); // 0123 4567
|
---|
| 1107 | }
|
---|
| 1108 | else if constexpr (__z_to_y)
|
---|
| 1109 | return __intrin_bitcast<_To>(
|
---|
| 1110 | __concat(_mm512_cvtepi64_epi16(__i0),
|
---|
| 1111 | _mm512_cvtepi64_epi16(__i1)));
|
---|
| 1112 | }
|
---|
| 1113 | else if constexpr (__i64_to_i8) //{{{2
|
---|
| 1114 | {
|
---|
| 1115 | if constexpr (__x_to_x && __have_sse4_1)
|
---|
| 1116 | {
|
---|
| 1117 | return __intrin_bitcast<_To>(_mm_shuffle_epi8(
|
---|
| 1118 | _mm_blend_epi16(__i0, _mm_slli_si128(__i1, 4), 0x44),
|
---|
| 1119 | _mm_setr_epi8(0, 8, 4, 12, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1120 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1121 | -0x80)));
|
---|
| 1122 | }
|
---|
| 1123 | else if constexpr (__x_to_x && __have_ssse3)
|
---|
| 1124 | {
|
---|
| 1125 | return __intrin_bitcast<_To>(_mm_unpacklo_epi16(
|
---|
| 1126 | _mm_shuffle_epi8(
|
---|
| 1127 | __i0, _mm_setr_epi8(0, 8, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1128 | -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1129 | -0x80, -0x80, -0x80, -0x80)),
|
---|
| 1130 | _mm_shuffle_epi8(
|
---|
| 1131 | __i1, _mm_setr_epi8(0, 8, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1132 | -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1133 | -0x80, -0x80, -0x80, -0x80))));
|
---|
| 1134 | }
|
---|
| 1135 | else if constexpr (__x_to_x)
|
---|
| 1136 | {
|
---|
| 1137 | return __vector_type_t<_Up, _M>{_Up(__v0[0]), _Up(__v0[1]),
|
---|
| 1138 | _Up(__v1[0]), _Up(__v1[1])};
|
---|
| 1139 | }
|
---|
| 1140 | else if constexpr (__y_to_x)
|
---|
| 1141 | {
|
---|
| 1142 | const auto __a = _mm256_shuffle_epi8(
|
---|
| 1143 | _mm256_blend_epi32(__i0, _mm256_slli_epi64(__i1, 32), 0xAA),
|
---|
| 1144 | _mm256_setr_epi8(0, 8, -0x80, -0x80, 4, 12, -0x80, -0x80,
|
---|
| 1145 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1146 | -0x80, -0x80, -0x80, -0x80, 0, 8, -0x80,
|
---|
| 1147 | -0x80, 4, 12, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1148 | -0x80, -0x80, -0x80, -0x80));
|
---|
| 1149 | return __intrin_bitcast<_To>(__lo128(__a) | __hi128(__a));
|
---|
| 1150 | } // __z_to_x uses concat fallback
|
---|
| 1151 | }
|
---|
| 1152 | else if constexpr (__i32_to_i16) //{{{2
|
---|
| 1153 | {
|
---|
| 1154 | if constexpr (__x_to_x)
|
---|
| 1155 | {
|
---|
| 1156 | // AVX2 is not available (would concat otherwise)
|
---|
| 1157 | if constexpr (__have_sse4_1)
|
---|
| 1158 | {
|
---|
| 1159 | return __intrin_bitcast<_To>(_mm_shuffle_epi8(
|
---|
| 1160 | _mm_blend_epi16(__i0, _mm_slli_si128(__i1, 2), 0xaa),
|
---|
| 1161 | _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10,
|
---|
| 1162 | 11, 14, 15)));
|
---|
| 1163 | }
|
---|
| 1164 | else if constexpr (__have_ssse3)
|
---|
| 1165 | {
|
---|
| 1166 | return __intrin_bitcast<_To>(
|
---|
| 1167 | _mm_hadd_epi16(__to_intrin(__v0 << 16),
|
---|
| 1168 | __to_intrin(__v1 << 16)));
|
---|
| 1169 | /*
|
---|
| 1170 | return _mm_unpacklo_epi64(
|
---|
| 1171 | _mm_shuffle_epi8(__i0, _mm_setr_epi8(0, 1, 4, 5, 8, 9,
|
---|
| 1172 | 12, 13, 8, 9, 12, 13, 12, 13, 14, 15)),
|
---|
| 1173 | _mm_shuffle_epi8(__i1, _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12,
|
---|
| 1174 | 13, 8, 9, 12, 13, 12, 13, 14, 15)));
|
---|
| 1175 | */
|
---|
| 1176 | }
|
---|
| 1177 | else
|
---|
| 1178 | {
|
---|
| 1179 | auto __a = _mm_unpacklo_epi16(__i0, __i1); // 04.. 15..
|
---|
| 1180 | auto __b = _mm_unpackhi_epi16(__i0, __i1); // 26.. 37..
|
---|
| 1181 | auto __c = _mm_unpacklo_epi16(__a, __b); // 0246 ....
|
---|
| 1182 | auto __d = _mm_unpackhi_epi16(__a, __b); // 1357 ....
|
---|
| 1183 | return __intrin_bitcast<_To>(
|
---|
| 1184 | _mm_unpacklo_epi16(__c, __d)); // 0123 4567
|
---|
| 1185 | }
|
---|
| 1186 | }
|
---|
| 1187 | else if constexpr (__y_to_y)
|
---|
| 1188 | {
|
---|
| 1189 | const auto __shuf
|
---|
| 1190 | = _mm256_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, -0x80, -0x80,
|
---|
| 1191 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1192 | 0, 1, 4, 5, 8, 9, 12, 13, -0x80, -0x80,
|
---|
| 1193 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80);
|
---|
| 1194 | auto __a = _mm256_shuffle_epi8(__i0, __shuf);
|
---|
| 1195 | auto __b = _mm256_shuffle_epi8(__i1, __shuf);
|
---|
| 1196 | return __intrin_bitcast<_To>(
|
---|
| 1197 | __xzyw(_mm256_unpacklo_epi64(__a, __b)));
|
---|
| 1198 | } // __z_to_z uses concat fallback
|
---|
| 1199 | }
|
---|
| 1200 | else if constexpr (__i32_to_i8) //{{{2
|
---|
| 1201 | {
|
---|
| 1202 | if constexpr (__x_to_x && __have_ssse3)
|
---|
| 1203 | {
|
---|
| 1204 | const auto shufmask
|
---|
| 1205 | = _mm_setr_epi8(0, 4, 8, 12, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1206 | -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1207 | -0x80, -0x80);
|
---|
| 1208 | return __intrin_bitcast<_To>(
|
---|
| 1209 | _mm_unpacklo_epi32(_mm_shuffle_epi8(__i0, shufmask),
|
---|
| 1210 | _mm_shuffle_epi8(__i1, shufmask)));
|
---|
| 1211 | }
|
---|
| 1212 | else if constexpr (__x_to_x)
|
---|
| 1213 | {
|
---|
| 1214 | auto __a = _mm_unpacklo_epi8(__i0, __i1); // 04.. .... 15.. ....
|
---|
| 1215 | auto __b = _mm_unpackhi_epi8(__i0, __i1); // 26.. .... 37.. ....
|
---|
| 1216 | auto __c = _mm_unpacklo_epi8(__a, __b); // 0246 .... .... ....
|
---|
| 1217 | auto __d = _mm_unpackhi_epi8(__a, __b); // 1357 .... .... ....
|
---|
| 1218 | auto __e = _mm_unpacklo_epi8(__c, __d); // 0123 4567 .... ....
|
---|
| 1219 | return __intrin_bitcast<_To>(__e & __m128i{-1, 0});
|
---|
| 1220 | }
|
---|
| 1221 | else if constexpr (__y_to_x)
|
---|
| 1222 | {
|
---|
| 1223 | const auto __a = _mm256_shuffle_epi8(
|
---|
| 1224 | _mm256_blend_epi16(__i0, _mm256_slli_epi32(__i1, 16), 0xAA),
|
---|
| 1225 | _mm256_setr_epi8(0, 4, 8, 12, -0x80, -0x80, -0x80, -0x80, 2,
|
---|
| 1226 | 6, 10, 14, -0x80, -0x80, -0x80, -0x80, -0x80,
|
---|
| 1227 | -0x80, -0x80, -0x80, 0, 4, 8, 12, -0x80,
|
---|
| 1228 | -0x80, -0x80, -0x80, 2, 6, 10, 14));
|
---|
| 1229 | return __intrin_bitcast<_To>(__lo128(__a) | __hi128(__a));
|
---|
| 1230 | } // __z_to_y uses concat fallback
|
---|
| 1231 | }
|
---|
| 1232 | else if constexpr (__i16_to_i8) //{{{2
|
---|
| 1233 | {
|
---|
| 1234 | if constexpr (__x_to_x && __have_ssse3)
|
---|
| 1235 | {
|
---|
| 1236 | const auto __shuf = reinterpret_cast<__m128i>(
|
---|
| 1237 | __vector_type_t<_UChar, 16>{0, 2, 4, 6, 8, 10, 12, 14, 0x80,
|
---|
| 1238 | 0x80, 0x80, 0x80, 0x80, 0x80,
|
---|
| 1239 | 0x80, 0x80});
|
---|
| 1240 | return __intrin_bitcast<_To>(
|
---|
| 1241 | _mm_unpacklo_epi64(_mm_shuffle_epi8(__i0, __shuf),
|
---|
| 1242 | _mm_shuffle_epi8(__i1, __shuf)));
|
---|
| 1243 | }
|
---|
| 1244 | else if constexpr (__x_to_x)
|
---|
| 1245 | {
|
---|
| 1246 | auto __a = _mm_unpacklo_epi8(__i0, __i1); // 08.. 19.. 2A.. 3B..
|
---|
| 1247 | auto __b = _mm_unpackhi_epi8(__i0, __i1); // 4C.. 5D.. 6E.. 7F..
|
---|
| 1248 | auto __c = _mm_unpacklo_epi8(__a, __b); // 048C .... 159D ....
|
---|
| 1249 | auto __d = _mm_unpackhi_epi8(__a, __b); // 26AE .... 37BF ....
|
---|
| 1250 | auto __e = _mm_unpacklo_epi8(__c, __d); // 0246 8ACE .... ....
|
---|
| 1251 | auto __f = _mm_unpackhi_epi8(__c, __d); // 1357 9BDF .... ....
|
---|
| 1252 | return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__e, __f));
|
---|
| 1253 | }
|
---|
| 1254 | else if constexpr (__y_to_y)
|
---|
| 1255 | {
|
---|
| 1256 | return __intrin_bitcast<_To>(__xzyw(_mm256_shuffle_epi8(
|
---|
| 1257 | (__to_intrin(__v0) & _mm256_set1_epi32(0x00ff00ff))
|
---|
| 1258 | | _mm256_slli_epi16(__i1, 8),
|
---|
| 1259 | _mm256_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11,
|
---|
| 1260 | 13, 15, 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5,
|
---|
| 1261 | 7, 9, 11, 13, 15))));
|
---|
| 1262 | } // __z_to_z uses concat fallback
|
---|
| 1263 | }
|
---|
| 1264 | else if constexpr (__i64_to_f32) //{{{2
|
---|
| 1265 | {
|
---|
| 1266 | if constexpr (__x_to_x)
|
---|
| 1267 | return __make_wrapper<float>(__v0[0], __v0[1], __v1[0], __v1[1]);
|
---|
| 1268 | else if constexpr (__y_to_y)
|
---|
| 1269 | {
|
---|
| 1270 | static_assert(__y_to_y && __have_avx2);
|
---|
| 1271 | const auto __a = _mm256_unpacklo_epi32(__i0, __i1); // aeAE cgCG
|
---|
| 1272 | const auto __b = _mm256_unpackhi_epi32(__i0, __i1); // bfBF dhDH
|
---|
| 1273 | const auto __lo32
|
---|
| 1274 | = _mm256_unpacklo_epi32(__a, __b); // abef cdgh
|
---|
| 1275 | const auto __hi32 = __vector_bitcast<
|
---|
| 1276 | conditional_t<is_signed_v<_Tp>, int, _UInt>>(
|
---|
| 1277 | _mm256_unpackhi_epi32(__a, __b)); // ABEF CDGH
|
---|
| 1278 | const auto __hi
|
---|
| 1279 | = 0x100000000LL
|
---|
| 1280 | * __convert_x86<__vector_type_t<float, 8>>(__hi32);
|
---|
| 1281 | const auto __mid
|
---|
| 1282 | = 0x10000 * _mm256_cvtepi32_ps(_mm256_srli_epi32(__lo32, 16));
|
---|
| 1283 | const auto __lo
|
---|
| 1284 | = _mm256_cvtepi32_ps(_mm256_set1_epi32(0x0000ffffu) & __lo32);
|
---|
| 1285 | return __xzyw((__hi + __mid) + __lo);
|
---|
| 1286 | }
|
---|
| 1287 | else if constexpr (__z_to_z && __have_avx512dq)
|
---|
| 1288 | {
|
---|
| 1289 | return is_signed_v<_Tp> ? __concat(_mm512_cvtepi64_ps(__i0),
|
---|
| 1290 | _mm512_cvtepi64_ps(__i1))
|
---|
| 1291 | : __concat(_mm512_cvtepu64_ps(__i0),
|
---|
| 1292 | _mm512_cvtepu64_ps(__i1));
|
---|
| 1293 | }
|
---|
| 1294 | else if constexpr (__z_to_z && is_signed_v<_Tp>)
|
---|
| 1295 | {
|
---|
| 1296 | const __m512 __hi32 = _mm512_cvtepi32_ps(
|
---|
| 1297 | __concat(_mm512_cvtepi64_epi32(__to_intrin(__v0 >> 32)),
|
---|
| 1298 | _mm512_cvtepi64_epi32(__to_intrin(__v1 >> 32))));
|
---|
| 1299 | const __m512i __lo32 = __concat(_mm512_cvtepi64_epi32(__i0),
|
---|
| 1300 | _mm512_cvtepi64_epi32(__i1));
|
---|
| 1301 | // split low 32-bits, because if __hi32 is a small negative
|
---|
| 1302 | // number, the 24-bit mantissa may lose important information if
|
---|
| 1303 | // any of the high 8 bits of __lo32 is set, leading to
|
---|
| 1304 | // catastrophic cancelation in the FMA
|
---|
| 1305 | const __m512 __hi16
|
---|
| 1306 | = _mm512_cvtepu32_ps(_mm512_set1_epi32(0xffff0000u) & __lo32);
|
---|
| 1307 | const __m512 __lo16
|
---|
| 1308 | = _mm512_cvtepi32_ps(_mm512_set1_epi32(0x0000ffffu) & __lo32);
|
---|
| 1309 | return (__hi32 * 0x100000000LL + __hi16) + __lo16;
|
---|
| 1310 | }
|
---|
| 1311 | else if constexpr (__z_to_z && is_unsigned_v<_Tp>)
|
---|
| 1312 | {
|
---|
| 1313 | return __intrin_bitcast<_To>(
|
---|
| 1314 | _mm512_cvtepu32_ps(__concat(
|
---|
| 1315 | _mm512_cvtepi64_epi32(_mm512_srai_epi64(__i0, 32)),
|
---|
| 1316 | _mm512_cvtepi64_epi32(_mm512_srai_epi64(__i1, 32))))
|
---|
| 1317 | * 0x100000000LL
|
---|
| 1318 | + _mm512_cvtepu32_ps(__concat(_mm512_cvtepi64_epi32(__i0),
|
---|
| 1319 | _mm512_cvtepi64_epi32(__i1))));
|
---|
| 1320 | }
|
---|
| 1321 | }
|
---|
| 1322 | else if constexpr (__f64_to_s32) //{{{2
|
---|
| 1323 | {
|
---|
| 1324 | // use concat fallback
|
---|
| 1325 | }
|
---|
| 1326 | else if constexpr (__f64_to_u32) //{{{2
|
---|
| 1327 | {
|
---|
| 1328 | if constexpr (__x_to_x && __have_sse4_1)
|
---|
| 1329 | {
|
---|
| 1330 | return __vector_bitcast<_Up, _M>(_mm_unpacklo_epi64(
|
---|
| 1331 | _mm_cvttpd_epi32(_mm_floor_pd(__i0) - 0x8000'0000u),
|
---|
| 1332 | _mm_cvttpd_epi32(_mm_floor_pd(__i1) - 0x8000'0000u)))
|
---|
| 1333 | ^ 0x8000'0000u;
|
---|
| 1334 | // without SSE4.1 just use the scalar fallback, it's only four
|
---|
| 1335 | // values
|
---|
| 1336 | }
|
---|
| 1337 | else if constexpr (__y_to_y)
|
---|
| 1338 | {
|
---|
| 1339 | return __vector_bitcast<_Up>(
|
---|
| 1340 | __concat(_mm256_cvttpd_epi32(_mm256_floor_pd(__i0)
|
---|
| 1341 | - 0x8000'0000u),
|
---|
| 1342 | _mm256_cvttpd_epi32(_mm256_floor_pd(__i1)
|
---|
| 1343 | - 0x8000'0000u)))
|
---|
| 1344 | ^ 0x8000'0000u;
|
---|
| 1345 | } // __z_to_z uses fallback
|
---|
| 1346 | }
|
---|
| 1347 | else if constexpr (__f64_to_ibw) //{{{2
|
---|
| 1348 | {
|
---|
| 1349 | // one-arg __f64_to_ibw goes via _SimdWrapper<int, ?>. The fallback
|
---|
| 1350 | // would go via two independet conversions to _SimdWrapper<_To> and
|
---|
| 1351 | // subsequent interleaving. This is better, because f64->__i32
|
---|
| 1352 | // allows to combine __v0 and __v1 into one register: if constexpr
|
---|
| 1353 | // (__z_to_x || __y_to_x) {
|
---|
| 1354 | return __convert_x86<_To>(
|
---|
| 1355 | __convert_x86<__vector_type_t<int, _Np * 2>>(__v0, __v1));
|
---|
| 1356 | //}
|
---|
| 1357 | }
|
---|
| 1358 | else if constexpr (__f32_to_ibw) //{{{2
|
---|
| 1359 | {
|
---|
| 1360 | return __convert_x86<_To>(
|
---|
| 1361 | __convert_x86<__vector_type_t<int, _Np>>(__v0),
|
---|
| 1362 | __convert_x86<__vector_type_t<int, _Np>>(__v1));
|
---|
| 1363 | } //}}}
|
---|
| 1364 |
|
---|
| 1365 | // fallback: {{{2
|
---|
| 1366 | if constexpr (sizeof(_To) >= 32)
|
---|
| 1367 | // if _To is ymm or zmm, then _SimdWrapper<_Up, _M / 2> is xmm or ymm
|
---|
| 1368 | return __concat(__convert_x86<__vector_type_t<_Up, _M / 2>>(__v0),
|
---|
| 1369 | __convert_x86<__vector_type_t<_Up, _M / 2>>(__v1));
|
---|
| 1370 | else if constexpr (sizeof(_To) == 16)
|
---|
| 1371 | {
|
---|
| 1372 | const auto __lo = __to_intrin(__convert_x86<_To>(__v0));
|
---|
| 1373 | const auto __hi = __to_intrin(__convert_x86<_To>(__v1));
|
---|
| 1374 | if constexpr (sizeof(_Up) * _Np == 8)
|
---|
| 1375 | {
|
---|
| 1376 | if constexpr (is_floating_point_v<_Up>)
|
---|
| 1377 | return __auto_bitcast(
|
---|
| 1378 | _mm_unpacklo_pd(__vector_bitcast<double>(__lo),
|
---|
| 1379 | __vector_bitcast<double>(__hi)));
|
---|
| 1380 | else
|
---|
| 1381 | return __intrin_bitcast<_To>(_mm_unpacklo_epi64(__lo, __hi));
|
---|
| 1382 | }
|
---|
| 1383 | else if constexpr (sizeof(_Up) * _Np == 4)
|
---|
| 1384 | {
|
---|
| 1385 | if constexpr (is_floating_point_v<_Up>)
|
---|
| 1386 | return __auto_bitcast(
|
---|
| 1387 | _mm_unpacklo_ps(__vector_bitcast<float>(__lo),
|
---|
| 1388 | __vector_bitcast<float>(__hi)));
|
---|
| 1389 | else
|
---|
| 1390 | return __intrin_bitcast<_To>(_mm_unpacklo_epi32(__lo, __hi));
|
---|
| 1391 | }
|
---|
| 1392 | else if constexpr (sizeof(_Up) * _Np == 2)
|
---|
| 1393 | return __intrin_bitcast<_To>(_mm_unpacklo_epi16(__lo, __hi));
|
---|
| 1394 | else
|
---|
| 1395 | __assert_unreachable<_Tp>();
|
---|
| 1396 | }
|
---|
| 1397 | else
|
---|
| 1398 | return __vector_convert<_To>(__v0, __v1, make_index_sequence<_Np>());
|
---|
| 1399 | //}}}
|
---|
| 1400 | }
|
---|
| 1401 | }
|
---|
| 1402 |
|
---|
| 1403 | //}}}1
|
---|
| 1404 | // 4-arg __convert_x86 {{{1
|
---|
| 1405 | template <typename _To, typename _V, typename _Traits>
|
---|
| 1406 | _GLIBCXX_SIMD_INTRINSIC _To
|
---|
| 1407 | __convert_x86(_V __v0, _V __v1, _V __v2, _V __v3)
|
---|
| 1408 | {
|
---|
| 1409 | static_assert(__is_vector_type_v<_V>);
|
---|
| 1410 | using _Tp = typename _Traits::value_type;
|
---|
| 1411 | constexpr size_t _Np = _Traits::_S_full_size;
|
---|
| 1412 | [[maybe_unused]] const auto __i0 = __to_intrin(__v0);
|
---|
| 1413 | [[maybe_unused]] const auto __i1 = __to_intrin(__v1);
|
---|
| 1414 | [[maybe_unused]] const auto __i2 = __to_intrin(__v2);
|
---|
| 1415 | [[maybe_unused]] const auto __i3 = __to_intrin(__v3);
|
---|
| 1416 | using _Up = typename _VectorTraits<_To>::value_type;
|
---|
| 1417 | constexpr size_t _M = _VectorTraits<_To>::_S_full_size;
|
---|
| 1418 |
|
---|
| 1419 | static_assert(4 * _Np <= _M,
|
---|
| 1420 | "__v2/__v3 would be discarded; use the two/one-argument "
|
---|
| 1421 | "__convert_x86 overload instead");
|
---|
| 1422 |
|
---|
| 1423 | // [xyz]_to_[xyz] {{{2
|
---|
| 1424 | [[maybe_unused]] constexpr bool __x_to_x
|
---|
| 1425 | = sizeof(__v0) <= 16 && sizeof(_To) <= 16;
|
---|
| 1426 | [[maybe_unused]] constexpr bool __x_to_y
|
---|
| 1427 | = sizeof(__v0) <= 16 && sizeof(_To) == 32;
|
---|
| 1428 | [[maybe_unused]] constexpr bool __x_to_z
|
---|
| 1429 | = sizeof(__v0) <= 16 && sizeof(_To) == 64;
|
---|
| 1430 | [[maybe_unused]] constexpr bool __y_to_x
|
---|
| 1431 | = sizeof(__v0) == 32 && sizeof(_To) <= 16;
|
---|
| 1432 | [[maybe_unused]] constexpr bool __y_to_y
|
---|
| 1433 | = sizeof(__v0) == 32 && sizeof(_To) == 32;
|
---|
| 1434 | [[maybe_unused]] constexpr bool __y_to_z
|
---|
| 1435 | = sizeof(__v0) == 32 && sizeof(_To) == 64;
|
---|
| 1436 | [[maybe_unused]] constexpr bool __z_to_x
|
---|
| 1437 | = sizeof(__v0) == 64 && sizeof(_To) <= 16;
|
---|
| 1438 | [[maybe_unused]] constexpr bool __z_to_y
|
---|
| 1439 | = sizeof(__v0) == 64 && sizeof(_To) == 32;
|
---|
| 1440 | [[maybe_unused]] constexpr bool __z_to_z
|
---|
| 1441 | = sizeof(__v0) == 64 && sizeof(_To) == 64;
|
---|
| 1442 |
|
---|
| 1443 | // iX_to_iX {{{2
|
---|
| 1444 | [[maybe_unused]] constexpr bool __i_to_i
|
---|
| 1445 | = is_integral_v<_Up> && is_integral_v<_Tp>;
|
---|
| 1446 | [[maybe_unused]] constexpr bool __i8_to_i16
|
---|
| 1447 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 2;
|
---|
| 1448 | [[maybe_unused]] constexpr bool __i8_to_i32
|
---|
| 1449 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 4;
|
---|
| 1450 | [[maybe_unused]] constexpr bool __i8_to_i64
|
---|
| 1451 | = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 8;
|
---|
| 1452 | [[maybe_unused]] constexpr bool __i16_to_i8
|
---|
| 1453 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 1;
|
---|
| 1454 | [[maybe_unused]] constexpr bool __i16_to_i32
|
---|
| 1455 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 4;
|
---|
| 1456 | [[maybe_unused]] constexpr bool __i16_to_i64
|
---|
| 1457 | = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 8;
|
---|
| 1458 | [[maybe_unused]] constexpr bool __i32_to_i8
|
---|
| 1459 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 1;
|
---|
| 1460 | [[maybe_unused]] constexpr bool __i32_to_i16
|
---|
| 1461 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 2;
|
---|
| 1462 | [[maybe_unused]] constexpr bool __i32_to_i64
|
---|
| 1463 | = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 8;
|
---|
| 1464 | [[maybe_unused]] constexpr bool __i64_to_i8
|
---|
| 1465 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 1;
|
---|
| 1466 | [[maybe_unused]] constexpr bool __i64_to_i16
|
---|
| 1467 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 2;
|
---|
| 1468 | [[maybe_unused]] constexpr bool __i64_to_i32
|
---|
| 1469 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 4;
|
---|
| 1470 |
|
---|
| 1471 | // [fsu]X_to_[fsu]X {{{2
|
---|
| 1472 | // ibw = integral && byte or word, i.e. char and short with any signedness
|
---|
| 1473 | [[maybe_unused]] constexpr bool __i64_to_f32
|
---|
| 1474 | = is_integral_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 1475 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1476 | [[maybe_unused]] constexpr bool __s32_to_f32
|
---|
| 1477 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 1478 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1479 | [[maybe_unused]] constexpr bool __s16_to_f32
|
---|
| 1480 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 1481 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1482 | [[maybe_unused]] constexpr bool __s8_to_f32
|
---|
| 1483 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 1484 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1485 | [[maybe_unused]] constexpr bool __u32_to_f32
|
---|
| 1486 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 1487 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1488 | [[maybe_unused]] constexpr bool __u16_to_f32
|
---|
| 1489 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 1490 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1491 | [[maybe_unused]] constexpr bool __u8_to_f32
|
---|
| 1492 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 1493 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1494 | [[maybe_unused]] constexpr bool __s64_to_f64
|
---|
| 1495 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 1496 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1497 | [[maybe_unused]] constexpr bool __s32_to_f64
|
---|
| 1498 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 1499 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1500 | [[maybe_unused]] constexpr bool __s16_to_f64
|
---|
| 1501 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 1502 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1503 | [[maybe_unused]] constexpr bool __s8_to_f64
|
---|
| 1504 | = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 1505 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1506 | [[maybe_unused]] constexpr bool __u64_to_f64
|
---|
| 1507 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 1508 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1509 | [[maybe_unused]] constexpr bool __u32_to_f64
|
---|
| 1510 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 1511 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1512 | [[maybe_unused]] constexpr bool __u16_to_f64
|
---|
| 1513 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
|
---|
| 1514 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1515 | [[maybe_unused]] constexpr bool __u8_to_f64
|
---|
| 1516 | = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
|
---|
| 1517 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1518 | [[maybe_unused]] constexpr bool __f32_to_s64
|
---|
| 1519 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
|
---|
| 1520 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 1521 | [[maybe_unused]] constexpr bool __f32_to_s32
|
---|
| 1522 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
|
---|
| 1523 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 1524 | [[maybe_unused]] constexpr bool __f32_to_u64
|
---|
| 1525 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
|
---|
| 1526 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 1527 | [[maybe_unused]] constexpr bool __f32_to_u32
|
---|
| 1528 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
|
---|
| 1529 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 1530 | [[maybe_unused]] constexpr bool __f64_to_s64
|
---|
| 1531 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
|
---|
| 1532 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 1533 | [[maybe_unused]] constexpr bool __f64_to_s32
|
---|
| 1534 | = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
|
---|
| 1535 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 1536 | [[maybe_unused]] constexpr bool __f64_to_u64
|
---|
| 1537 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
|
---|
| 1538 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 1539 | [[maybe_unused]] constexpr bool __f64_to_u32
|
---|
| 1540 | = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
|
---|
| 1541 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 1542 | [[maybe_unused]] constexpr bool __f32_to_ibw
|
---|
| 1543 | = is_integral_v<_Up> && sizeof(_Up) <= 2
|
---|
| 1544 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
|
---|
| 1545 | [[maybe_unused]] constexpr bool __f64_to_ibw
|
---|
| 1546 | = is_integral_v<_Up> && sizeof(_Up) <= 2
|
---|
| 1547 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 1548 | [[maybe_unused]] constexpr bool __f32_to_f64
|
---|
| 1549 | = is_floating_point_v<_Tp> && sizeof(_Tp) == 4
|
---|
| 1550 | && is_floating_point_v<_Up> && sizeof(_Up) == 8;
|
---|
| 1551 | [[maybe_unused]] constexpr bool __f64_to_f32
|
---|
| 1552 | = is_floating_point_v<_Tp> && sizeof(_Tp) == 8
|
---|
| 1553 | && is_floating_point_v<_Up> && sizeof(_Up) == 4;
|
---|
| 1554 |
|
---|
| 1555 | if constexpr (__i_to_i && __y_to_x && !__have_avx2) //{{{2
|
---|
| 1556 | {
|
---|
| 1557 | // <double, 4>, <double, 4>, <double, 4>, <double, 4> => <char, 16>
|
---|
| 1558 | return __convert_x86<_To>(__lo128(__v0), __hi128(__v0), __lo128(__v1),
|
---|
| 1559 | __hi128(__v1), __lo128(__v2), __hi128(__v2),
|
---|
| 1560 | __lo128(__v3), __hi128(__v3));
|
---|
| 1561 | }
|
---|
| 1562 | else if constexpr (__i_to_i) // assert ISA {{{2
|
---|
| 1563 | {
|
---|
| 1564 | static_assert(__x_to_x || __have_avx2,
|
---|
| 1565 | "integral conversions with ymm registers require AVX2");
|
---|
| 1566 | static_assert(__have_avx512bw
|
---|
| 1567 | || ((sizeof(_Tp) >= 4 || sizeof(__v0) < 64)
|
---|
| 1568 | && (sizeof(_Up) >= 4 || sizeof(_To) < 64)),
|
---|
| 1569 | "8/16-bit integers in zmm registers require AVX512BW");
|
---|
| 1570 | static_assert((sizeof(__v0) < 64 && sizeof(_To) < 64) || __have_avx512f,
|
---|
| 1571 | "integral conversions with ymm registers require AVX2");
|
---|
| 1572 | }
|
---|
| 1573 | // concat => use 2-arg __convert_x86 {{{2
|
---|
| 1574 | if constexpr (sizeof(__v0) < 16 || (sizeof(__v0) == 16 && __have_avx2)
|
---|
| 1575 | || (sizeof(__v0) == 16 && __have_avx
|
---|
| 1576 | && is_floating_point_v<_Tp>)
|
---|
| 1577 | || (sizeof(__v0) == 32 && __have_avx512f))
|
---|
| 1578 | {
|
---|
| 1579 | // The ISA can handle wider input registers, so concat and use two-arg
|
---|
| 1580 | // implementation. This reduces code duplication considerably.
|
---|
| 1581 | return __convert_x86<_To>(__concat(__v0, __v1), __concat(__v2, __v3));
|
---|
| 1582 | }
|
---|
| 1583 | else //{{{2
|
---|
| 1584 | {
|
---|
| 1585 | // conversion using bit reinterpretation (or no conversion at all)
|
---|
| 1586 | // should all go through the concat branch above:
|
---|
| 1587 | static_assert(
|
---|
| 1588 | !(is_floating_point_v<
|
---|
| 1589 | _Tp> == is_floating_point_v<_Up> && sizeof(_Tp) == sizeof(_Up)));
|
---|
| 1590 | // handle all zero extension{{{2
|
---|
| 1591 | if constexpr (4 * _Np < _M && sizeof(_To) > 16)
|
---|
| 1592 | {
|
---|
| 1593 | constexpr size_t Min = 16 / sizeof(_Up);
|
---|
| 1594 | return __zero_extend(
|
---|
| 1595 | __convert_x86<
|
---|
| 1596 | __vector_type_t<_Up, (Min > 4 * _Np) ? Min : 4 * _Np>>(
|
---|
| 1597 | __v0, __v1, __v2, __v3));
|
---|
| 1598 | }
|
---|
| 1599 | else if constexpr (__i64_to_i16) //{{{2
|
---|
| 1600 | {
|
---|
| 1601 | if constexpr (__x_to_x && __have_sse4_1)
|
---|
| 1602 | {
|
---|
| 1603 | return __intrin_bitcast<_To>(_mm_shuffle_epi8(
|
---|
| 1604 | _mm_blend_epi16(
|
---|
| 1605 | _mm_blend_epi16(__i0, _mm_slli_si128(__i1, 2), 0x22),
|
---|
| 1606 | _mm_blend_epi16(_mm_slli_si128(__i2, 4),
|
---|
| 1607 | _mm_slli_si128(__i3, 6), 0x88),
|
---|
| 1608 | 0xcc),
|
---|
| 1609 | _mm_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7,
|
---|
| 1610 | 14, 15)));
|
---|
| 1611 | }
|
---|
| 1612 | else if constexpr (__y_to_y && __have_avx2)
|
---|
| 1613 | {
|
---|
| 1614 | return __intrin_bitcast<_To>(_mm256_shuffle_epi8(
|
---|
| 1615 | __xzyw(_mm256_blend_epi16(
|
---|
| 1616 | __auto_bitcast(
|
---|
| 1617 | _mm256_shuffle_ps(__vector_bitcast<float>(__v0),
|
---|
| 1618 | __vector_bitcast<float>(__v2),
|
---|
| 1619 | 0x88)), // 0.1. 8.9. 2.3. A.B.
|
---|
| 1620 | __to_intrin(__vector_bitcast<int>(_mm256_shuffle_ps(
|
---|
| 1621 | __vector_bitcast<float>(__v1),
|
---|
| 1622 | __vector_bitcast<float>(__v3), 0x88))
|
---|
| 1623 | << 16), // .4.5 .C.D .6.7 .E.F
|
---|
| 1624 | 0xaa) // 0415 8C9D 2637 AEBF
|
---|
| 1625 | ), // 0415 2637 8C9D AEBF
|
---|
| 1626 | _mm256_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11,
|
---|
| 1627 | 14, 15, 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7,
|
---|
| 1628 | 10, 11, 14, 15)));
|
---|
| 1629 | /*
|
---|
| 1630 | auto __a = _mm256_unpacklo_epi16(__v0, __v1); // 04.. .... 26..
|
---|
| 1631 | .... auto __b = _mm256_unpackhi_epi16(__v0, __v1); // 15..
|
---|
| 1632 | .... 37.. .... auto __c = _mm256_unpacklo_epi16(__v2, __v3); //
|
---|
| 1633 | 8C.. .... AE.. .... auto __d = _mm256_unpackhi_epi16(__v2,
|
---|
| 1634 | __v3);
|
---|
| 1635 | // 9D.. .... BF.. .... auto __e = _mm256_unpacklo_epi16(__a,
|
---|
| 1636 | __b);
|
---|
| 1637 | // 0145 .... 2367 .... auto __f = _mm256_unpacklo_epi16(__c,
|
---|
| 1638 | __d);
|
---|
| 1639 | // 89CD .... ABEF .... auto __g = _mm256_unpacklo_epi64(__e,
|
---|
| 1640 | __f);
|
---|
| 1641 | // 0145 89CD 2367 ABEF return __concat(
|
---|
| 1642 | _mm_unpacklo_epi32(__lo128(__g), __hi128(__g)),
|
---|
| 1643 | _mm_unpackhi_epi32(__lo128(__g), __hi128(__g))); // 0123
|
---|
| 1644 | 4567 89AB CDEF
|
---|
| 1645 | */
|
---|
| 1646 | } // else use fallback
|
---|
| 1647 | }
|
---|
| 1648 | else if constexpr (__i64_to_i8) //{{{2
|
---|
| 1649 | {
|
---|
| 1650 | if constexpr (__x_to_x)
|
---|
| 1651 | {
|
---|
| 1652 | // TODO: use fallback for now
|
---|
| 1653 | }
|
---|
| 1654 | else if constexpr (__y_to_x)
|
---|
| 1655 | {
|
---|
| 1656 | auto __a
|
---|
| 1657 | = _mm256_srli_epi32(_mm256_slli_epi32(__i0, 24), 24)
|
---|
| 1658 | | _mm256_srli_epi32(_mm256_slli_epi32(__i1, 24), 16)
|
---|
| 1659 | | _mm256_srli_epi32(_mm256_slli_epi32(__i2, 24), 8)
|
---|
| 1660 | | _mm256_slli_epi32(
|
---|
| 1661 | __i3, 24); // 048C .... 159D .... 26AE .... 37BF ....
|
---|
| 1662 | /*return _mm_shuffle_epi8(
|
---|
| 1663 | _mm_blend_epi32(__lo128(__a) << 32, __hi128(__a), 0x5),
|
---|
| 1664 | _mm_setr_epi8(4, 12, 0, 8, 5, 13, 1, 9, 6, 14, 2, 10, 7, 15,
|
---|
| 1665 | 3, 11));*/
|
---|
| 1666 | auto __b = _mm256_unpackhi_epi64(
|
---|
| 1667 | __a, __a); // 159D .... 159D .... 37BF .... 37BF ....
|
---|
| 1668 | auto __c = _mm256_unpacklo_epi8(
|
---|
| 1669 | __a, __b); // 0145 89CD .... .... 2367 ABEF .... ....
|
---|
| 1670 | return __intrin_bitcast<_To>(
|
---|
| 1671 | _mm_unpacklo_epi16(__lo128(__c),
|
---|
| 1672 | __hi128(__c))); // 0123 4567 89AB CDEF
|
---|
| 1673 | }
|
---|
| 1674 | }
|
---|
| 1675 | else if constexpr (__i32_to_i8) //{{{2
|
---|
| 1676 | {
|
---|
| 1677 | if constexpr (__x_to_x)
|
---|
| 1678 | {
|
---|
| 1679 | if constexpr (__have_ssse3)
|
---|
| 1680 | {
|
---|
| 1681 | const auto __x0 = __vector_bitcast<_UInt>(__v0) & 0xff;
|
---|
| 1682 | const auto __x1 = (__vector_bitcast<_UInt>(__v1) & 0xff)
|
---|
| 1683 | << 8;
|
---|
| 1684 | const auto __x2 = (__vector_bitcast<_UInt>(__v2) & 0xff)
|
---|
| 1685 | << 16;
|
---|
| 1686 | const auto __x3 = __vector_bitcast<_UInt>(__v3) << 24;
|
---|
| 1687 | return __intrin_bitcast<_To>(
|
---|
| 1688 | _mm_shuffle_epi8(__to_intrin(__x0 | __x1 | __x2 | __x3),
|
---|
| 1689 | _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13,
|
---|
| 1690 | 2, 6, 10, 14, 3, 7, 11,
|
---|
| 1691 | 15)));
|
---|
| 1692 | }
|
---|
| 1693 | else
|
---|
| 1694 | {
|
---|
| 1695 | auto __a
|
---|
| 1696 | = _mm_unpacklo_epi8(__i0, __i2); // 08.. .... 19.. ....
|
---|
| 1697 | auto __b
|
---|
| 1698 | = _mm_unpackhi_epi8(__i0, __i2); // 2A.. .... 3B.. ....
|
---|
| 1699 | auto __c
|
---|
| 1700 | = _mm_unpacklo_epi8(__i1, __i3); // 4C.. .... 5D.. ....
|
---|
| 1701 | auto __d
|
---|
| 1702 | = _mm_unpackhi_epi8(__i1, __i3); // 6E.. .... 7F.. ....
|
---|
| 1703 | auto __e
|
---|
| 1704 | = _mm_unpacklo_epi8(__a, __c); // 048C .... .... ....
|
---|
| 1705 | auto __f
|
---|
| 1706 | = _mm_unpackhi_epi8(__a, __c); // 159D .... .... ....
|
---|
| 1707 | auto __g
|
---|
| 1708 | = _mm_unpacklo_epi8(__b, __d); // 26AE .... .... ....
|
---|
| 1709 | auto __h
|
---|
| 1710 | = _mm_unpackhi_epi8(__b, __d); // 37BF .... .... ....
|
---|
| 1711 | return __intrin_bitcast<_To>(_mm_unpacklo_epi8(
|
---|
| 1712 | _mm_unpacklo_epi8(__e, __g), // 0246 8ACE .... ....
|
---|
| 1713 | _mm_unpacklo_epi8(__f, __h) // 1357 9BDF .... ....
|
---|
| 1714 | )); // 0123 4567 89AB CDEF
|
---|
| 1715 | }
|
---|
| 1716 | }
|
---|
| 1717 | else if constexpr (__y_to_y)
|
---|
| 1718 | {
|
---|
| 1719 | const auto __a = _mm256_shuffle_epi8(
|
---|
| 1720 | __to_intrin((__vector_bitcast<_UShort>(_mm256_blend_epi16(
|
---|
| 1721 | __i0, _mm256_slli_epi32(__i1, 16), 0xAA))
|
---|
| 1722 | & 0xff)
|
---|
| 1723 | | (__vector_bitcast<_UShort>(_mm256_blend_epi16(
|
---|
| 1724 | __i2, _mm256_slli_epi32(__i3, 16), 0xAA))
|
---|
| 1725 | << 8)),
|
---|
| 1726 | _mm256_setr_epi8(0, 4, 8, 12, 2, 6, 10, 14, 1, 5, 9, 13, 3, 7,
|
---|
| 1727 | 11, 15, 0, 4, 8, 12, 2, 6, 10, 14, 1, 5, 9,
|
---|
| 1728 | 13, 3, 7, 11, 15));
|
---|
| 1729 | return __intrin_bitcast<_To>(_mm256_permutevar8x32_epi32(
|
---|
| 1730 | __a, _mm256_setr_epi32(0, 4, 1, 5, 2, 6, 3, 7)));
|
---|
| 1731 | }
|
---|
| 1732 | }
|
---|
| 1733 | else if constexpr (__i64_to_f32) //{{{2
|
---|
| 1734 | {
|
---|
| 1735 | // this branch is only relevant with AVX and w/o AVX2 (i.e. no ymm
|
---|
| 1736 | // integers)
|
---|
| 1737 | if constexpr (__x_to_y)
|
---|
| 1738 | {
|
---|
| 1739 | return __make_wrapper<float>(__v0[0], __v0[1], __v1[0], __v1[1],
|
---|
| 1740 | __v2[0], __v2[1], __v3[0],
|
---|
| 1741 | __v3[1]);
|
---|
| 1742 |
|
---|
| 1743 | const auto __a = _mm_unpacklo_epi32(__i0, __i1); // acAC
|
---|
| 1744 | const auto __b = _mm_unpackhi_epi32(__i0, __i1); // bdBD
|
---|
| 1745 | const auto __c = _mm_unpacklo_epi32(__i2, __i3); // egEG
|
---|
| 1746 | const auto __d = _mm_unpackhi_epi32(__i2, __i3); // fhFH
|
---|
| 1747 | const auto __lo32a = _mm_unpacklo_epi32(__a, __b); // abcd
|
---|
| 1748 | const auto __lo32b = _mm_unpacklo_epi32(__c, __d); // efgh
|
---|
| 1749 | const auto __hi32 = __vector_bitcast<
|
---|
| 1750 | conditional_t<is_signed_v<_Tp>, int, _UInt>>(
|
---|
| 1751 | __concat(_mm_unpackhi_epi32(__a, __b),
|
---|
| 1752 | _mm_unpackhi_epi32(__c, __d))); // ABCD EFGH
|
---|
| 1753 | const auto __hi
|
---|
| 1754 | = 0x100000000LL
|
---|
| 1755 | * __convert_x86<__vector_type_t<float, 8>>(__hi32);
|
---|
| 1756 | const auto __mid
|
---|
| 1757 | = 0x10000
|
---|
| 1758 | * _mm256_cvtepi32_ps(__concat(_mm_srli_epi32(__lo32a, 16),
|
---|
| 1759 | _mm_srli_epi32(__lo32b, 16)));
|
---|
| 1760 | const auto __lo = _mm256_cvtepi32_ps(
|
---|
| 1761 | __concat(_mm_set1_epi32(0x0000ffffu) & __lo32a,
|
---|
| 1762 | _mm_set1_epi32(0x0000ffffu) & __lo32b));
|
---|
| 1763 | return (__hi + __mid) + __lo;
|
---|
| 1764 | }
|
---|
| 1765 | }
|
---|
| 1766 | else if constexpr (__f64_to_ibw) //{{{2
|
---|
| 1767 | {
|
---|
| 1768 | return __convert_x86<_To>(
|
---|
| 1769 | __convert_x86<__vector_type_t<int, _Np * 2>>(__v0, __v1),
|
---|
| 1770 | __convert_x86<__vector_type_t<int, _Np * 2>>(__v2, __v3));
|
---|
| 1771 | }
|
---|
| 1772 | else if constexpr (__f32_to_ibw) //{{{2
|
---|
| 1773 | {
|
---|
| 1774 | return __convert_x86<_To>(
|
---|
| 1775 | __convert_x86<__vector_type_t<int, _Np>>(__v0),
|
---|
| 1776 | __convert_x86<__vector_type_t<int, _Np>>(__v1),
|
---|
| 1777 | __convert_x86<__vector_type_t<int, _Np>>(__v2),
|
---|
| 1778 | __convert_x86<__vector_type_t<int, _Np>>(__v3));
|
---|
| 1779 | } //}}}
|
---|
| 1780 |
|
---|
| 1781 | // fallback: {{{2
|
---|
| 1782 | if constexpr (sizeof(_To) >= 32)
|
---|
| 1783 | // if _To is ymm or zmm, then _SimdWrapper<_Up, _M / 2> is xmm or ymm
|
---|
| 1784 | return __concat(__convert_x86<__vector_type_t<_Up, _M / 2>>(__v0,
|
---|
| 1785 | __v1),
|
---|
| 1786 | __convert_x86<__vector_type_t<_Up, _M / 2>>(__v2,
|
---|
| 1787 | __v3));
|
---|
| 1788 | else if constexpr (sizeof(_To) == 16)
|
---|
| 1789 | {
|
---|
| 1790 | const auto __lo = __to_intrin(__convert_x86<_To>(__v0, __v1));
|
---|
| 1791 | const auto __hi = __to_intrin(__convert_x86<_To>(__v2, __v3));
|
---|
| 1792 | if constexpr (sizeof(_Up) * _Np * 2 == 8)
|
---|
| 1793 | {
|
---|
| 1794 | if constexpr (is_floating_point_v<_Up>)
|
---|
| 1795 | return __auto_bitcast(_mm_unpacklo_pd(__lo, __hi));
|
---|
| 1796 | else
|
---|
| 1797 | return __intrin_bitcast<_To>(_mm_unpacklo_epi64(__lo, __hi));
|
---|
| 1798 | }
|
---|
| 1799 | else if constexpr (sizeof(_Up) * _Np * 2 == 4)
|
---|
| 1800 | {
|
---|
| 1801 | if constexpr (is_floating_point_v<_Up>)
|
---|
| 1802 | return __auto_bitcast(_mm_unpacklo_ps(__lo, __hi));
|
---|
| 1803 | else
|
---|
| 1804 | return __intrin_bitcast<_To>(_mm_unpacklo_epi32(__lo, __hi));
|
---|
| 1805 | }
|
---|
| 1806 | else
|
---|
| 1807 | __assert_unreachable<_Tp>();
|
---|
| 1808 | }
|
---|
| 1809 | else
|
---|
| 1810 | return __vector_convert<_To>(__v0, __v1, __v2, __v3,
|
---|
| 1811 | make_index_sequence<_Np>());
|
---|
| 1812 | //}}}2
|
---|
| 1813 | }
|
---|
| 1814 | }
|
---|
| 1815 |
|
---|
| 1816 | //}}}
|
---|
| 1817 | // 8-arg __convert_x86 {{{1
|
---|
| 1818 | template <typename _To, typename _V, typename _Traits>
|
---|
| 1819 | _GLIBCXX_SIMD_INTRINSIC _To
|
---|
| 1820 | __convert_x86(_V __v0, _V __v1, _V __v2, _V __v3, _V __v4, _V __v5, _V __v6,
|
---|
| 1821 | _V __v7)
|
---|
| 1822 | {
|
---|
| 1823 | static_assert(__is_vector_type_v<_V>);
|
---|
| 1824 | using _Tp = typename _Traits::value_type;
|
---|
| 1825 | constexpr size_t _Np = _Traits::_S_full_size;
|
---|
| 1826 | [[maybe_unused]] const auto __i0 = __to_intrin(__v0);
|
---|
| 1827 | [[maybe_unused]] const auto __i1 = __to_intrin(__v1);
|
---|
| 1828 | [[maybe_unused]] const auto __i2 = __to_intrin(__v2);
|
---|
| 1829 | [[maybe_unused]] const auto __i3 = __to_intrin(__v3);
|
---|
| 1830 | [[maybe_unused]] const auto __i4 = __to_intrin(__v4);
|
---|
| 1831 | [[maybe_unused]] const auto __i5 = __to_intrin(__v5);
|
---|
| 1832 | [[maybe_unused]] const auto __i6 = __to_intrin(__v6);
|
---|
| 1833 | [[maybe_unused]] const auto __i7 = __to_intrin(__v7);
|
---|
| 1834 | using _Up = typename _VectorTraits<_To>::value_type;
|
---|
| 1835 | constexpr size_t _M = _VectorTraits<_To>::_S_full_size;
|
---|
| 1836 |
|
---|
| 1837 | static_assert(8 * _Np <= _M,
|
---|
| 1838 | "__v4-__v7 would be discarded; use the four/two/one-argument "
|
---|
| 1839 | "__convert_x86 overload instead");
|
---|
| 1840 |
|
---|
| 1841 | // [xyz]_to_[xyz] {{{2
|
---|
| 1842 | [[maybe_unused]] constexpr bool __x_to_x
|
---|
| 1843 | = sizeof(__v0) <= 16 && sizeof(_To) <= 16;
|
---|
| 1844 | [[maybe_unused]] constexpr bool __x_to_y
|
---|
| 1845 | = sizeof(__v0) <= 16 && sizeof(_To) == 32;
|
---|
| 1846 | [[maybe_unused]] constexpr bool __x_to_z
|
---|
| 1847 | = sizeof(__v0) <= 16 && sizeof(_To) == 64;
|
---|
| 1848 | [[maybe_unused]] constexpr bool __y_to_x
|
---|
| 1849 | = sizeof(__v0) == 32 && sizeof(_To) <= 16;
|
---|
| 1850 | [[maybe_unused]] constexpr bool __y_to_y
|
---|
| 1851 | = sizeof(__v0) == 32 && sizeof(_To) == 32;
|
---|
| 1852 | [[maybe_unused]] constexpr bool __y_to_z
|
---|
| 1853 | = sizeof(__v0) == 32 && sizeof(_To) == 64;
|
---|
| 1854 | [[maybe_unused]] constexpr bool __z_to_x
|
---|
| 1855 | = sizeof(__v0) == 64 && sizeof(_To) <= 16;
|
---|
| 1856 | [[maybe_unused]] constexpr bool __z_to_y
|
---|
| 1857 | = sizeof(__v0) == 64 && sizeof(_To) == 32;
|
---|
| 1858 | [[maybe_unused]] constexpr bool __z_to_z
|
---|
| 1859 | = sizeof(__v0) == 64 && sizeof(_To) == 64;
|
---|
| 1860 |
|
---|
| 1861 | // [if]X_to_i8 {{{2
|
---|
| 1862 | [[maybe_unused]] constexpr bool __i_to_i
|
---|
| 1863 | = is_integral_v<_Up> && is_integral_v<_Tp>;
|
---|
| 1864 | [[maybe_unused]] constexpr bool __i64_to_i8
|
---|
| 1865 | = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 1;
|
---|
| 1866 | [[maybe_unused]] constexpr bool __f64_to_i8
|
---|
| 1867 | = is_integral_v<_Up> && sizeof(_Up) == 1
|
---|
| 1868 | && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
|
---|
| 1869 |
|
---|
| 1870 | if constexpr (__i_to_i) // assert ISA {{{2
|
---|
| 1871 | {
|
---|
| 1872 | static_assert(__x_to_x || __have_avx2,
|
---|
| 1873 | "integral conversions with ymm registers require AVX2");
|
---|
| 1874 | static_assert(__have_avx512bw
|
---|
| 1875 | || ((sizeof(_Tp) >= 4 || sizeof(__v0) < 64)
|
---|
| 1876 | && (sizeof(_Up) >= 4 || sizeof(_To) < 64)),
|
---|
| 1877 | "8/16-bit integers in zmm registers require AVX512BW");
|
---|
| 1878 | static_assert((sizeof(__v0) < 64 && sizeof(_To) < 64) || __have_avx512f,
|
---|
| 1879 | "integral conversions with ymm registers require AVX2");
|
---|
| 1880 | }
|
---|
| 1881 | // concat => use 4-arg __convert_x86 {{{2
|
---|
| 1882 | if constexpr (sizeof(__v0) < 16 || (sizeof(__v0) == 16 && __have_avx2)
|
---|
| 1883 | || (sizeof(__v0) == 16 && __have_avx
|
---|
| 1884 | && is_floating_point_v<_Tp>)
|
---|
| 1885 | || (sizeof(__v0) == 32 && __have_avx512f))
|
---|
| 1886 | {
|
---|
| 1887 | // The ISA can handle wider input registers, so concat and use two-arg
|
---|
| 1888 | // implementation. This reduces code duplication considerably.
|
---|
| 1889 | return __convert_x86<_To>(__concat(__v0, __v1), __concat(__v2, __v3),
|
---|
| 1890 | __concat(__v4, __v5), __concat(__v6, __v7));
|
---|
| 1891 | }
|
---|
| 1892 | else //{{{2
|
---|
| 1893 | {
|
---|
| 1894 | // conversion using bit reinterpretation (or no conversion at all)
|
---|
| 1895 | // should all go through the concat branch above:
|
---|
| 1896 | static_assert(
|
---|
| 1897 | !(is_floating_point_v<
|
---|
| 1898 | _Tp> == is_floating_point_v<_Up> && sizeof(_Tp) == sizeof(_Up)));
|
---|
| 1899 | static_assert(!(8 * _Np < _M && sizeof(_To) > 16),
|
---|
| 1900 | "zero extension should be impossible");
|
---|
| 1901 | if constexpr (__i64_to_i8) //{{{2
|
---|
| 1902 | {
|
---|
| 1903 | if constexpr (__x_to_x && __have_ssse3)
|
---|
| 1904 | {
|
---|
| 1905 | // unsure whether this is better than the variant below
|
---|
| 1906 | return __intrin_bitcast<_To>(_mm_shuffle_epi8(
|
---|
| 1907 | __to_intrin(
|
---|
| 1908 | (((__v0 & 0xff) | ((__v1 & 0xff) << 8))
|
---|
| 1909 | | (((__v2 & 0xff) << 16) | ((__v3 & 0xff) << 24)))
|
---|
| 1910 | | ((((__v4 & 0xff) << 32) | ((__v5 & 0xff) << 40))
|
---|
| 1911 | | (((__v6 & 0xff) << 48) | (__v7 << 56)))),
|
---|
| 1912 | _mm_setr_epi8(0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14,
|
---|
| 1913 | 7, 15)));
|
---|
| 1914 | }
|
---|
| 1915 | else if constexpr (__x_to_x)
|
---|
| 1916 | {
|
---|
| 1917 | const auto __a = _mm_unpacklo_epi8(__i0, __i1); // ac
|
---|
| 1918 | const auto __b = _mm_unpackhi_epi8(__i0, __i1); // bd
|
---|
| 1919 | const auto __c = _mm_unpacklo_epi8(__i2, __i3); // eg
|
---|
| 1920 | const auto __d = _mm_unpackhi_epi8(__i2, __i3); // fh
|
---|
| 1921 | const auto __e = _mm_unpacklo_epi8(__i4, __i5); // ik
|
---|
| 1922 | const auto __f = _mm_unpackhi_epi8(__i4, __i5); // jl
|
---|
| 1923 | const auto __g = _mm_unpacklo_epi8(__i6, __i7); // mo
|
---|
| 1924 | const auto __h = _mm_unpackhi_epi8(__i6, __i7); // np
|
---|
| 1925 | return __intrin_bitcast<_To>(_mm_unpacklo_epi64(
|
---|
| 1926 | _mm_unpacklo_epi32(_mm_unpacklo_epi8(__a, __b), // abcd
|
---|
| 1927 | _mm_unpacklo_epi8(__c, __d)), // efgh
|
---|
| 1928 | _mm_unpacklo_epi32(_mm_unpacklo_epi8(__e, __f), // ijkl
|
---|
| 1929 | _mm_unpacklo_epi8(__g, __h)) // mnop
|
---|
| 1930 | ));
|
---|
| 1931 | }
|
---|
| 1932 | else if constexpr (__y_to_y)
|
---|
| 1933 | {
|
---|
| 1934 | auto __a = // 048C GKOS 159D HLPT 26AE IMQU 37BF JNRV
|
---|
| 1935 | __to_intrin(
|
---|
| 1936 | (((__v0 & 0xff) | ((__v1 & 0xff) << 8))
|
---|
| 1937 | | (((__v2 & 0xff) << 16) | ((__v3 & 0xff) << 24)))
|
---|
| 1938 | | ((((__v4 & 0xff) << 32) | ((__v5 & 0xff) << 40))
|
---|
| 1939 | | (((__v6 & 0xff) << 48) | ((__v7 << 56)))));
|
---|
| 1940 | /*
|
---|
| 1941 | auto __b = _mm256_unpackhi_epi64(__a, __a); // 159D HLPT 159D
|
---|
| 1942 | HLPT 37BF JNRV 37BF JNRV auto __c = _mm256_unpacklo_epi8(__a,
|
---|
| 1943 | __b); // 0145 89CD GHKL OPST 2367 ABEF IJMN QRUV auto __d =
|
---|
| 1944 | __xzyw(__c); // 0145 89CD 2367 ABEF GHKL OPST IJMN QRUV return
|
---|
| 1945 | _mm256_shuffle_epi8(
|
---|
| 1946 | __d, _mm256_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12,
|
---|
| 1947 | 13, 6, 7, 14, 15, 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7,
|
---|
| 1948 | 14, 15));
|
---|
| 1949 | */
|
---|
| 1950 | auto __b = _mm256_shuffle_epi8( // 0145 89CD GHKL OPST 2367 ABEF
|
---|
| 1951 | // IJMN QRUV
|
---|
| 1952 | __a, _mm256_setr_epi8(0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13,
|
---|
| 1953 | 6, 14, 7, 15, 0, 8, 1, 9, 2, 10, 3, 11,
|
---|
| 1954 | 4, 12, 5, 13, 6, 14, 7, 15));
|
---|
| 1955 | auto __c
|
---|
| 1956 | = __xzyw(__b); // 0145 89CD 2367 ABEF GHKL OPST IJMN QRUV
|
---|
| 1957 | return __intrin_bitcast<_To>(_mm256_shuffle_epi8(
|
---|
| 1958 | __c, _mm256_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13,
|
---|
| 1959 | 6, 7, 14, 15, 0, 1, 8, 9, 2, 3, 10, 11,
|
---|
| 1960 | 4, 5, 12, 13, 6, 7, 14, 15)));
|
---|
| 1961 | }
|
---|
| 1962 | else if constexpr (__z_to_z)
|
---|
| 1963 | {
|
---|
| 1964 | return __concat(
|
---|
| 1965 | __convert_x86<__vector_type_t<_Up, _M / 2>>(__v0, __v1, __v2,
|
---|
| 1966 | __v3),
|
---|
| 1967 | __convert_x86<__vector_type_t<_Up, _M / 2>>(__v4, __v5, __v6,
|
---|
| 1968 | __v7));
|
---|
| 1969 | }
|
---|
| 1970 | }
|
---|
| 1971 | else if constexpr (__f64_to_i8) //{{{2
|
---|
| 1972 | {
|
---|
| 1973 | return __convert_x86<_To>(
|
---|
| 1974 | __convert_x86<__vector_type_t<int, _Np * 2>>(__v0, __v1),
|
---|
| 1975 | __convert_x86<__vector_type_t<int, _Np * 2>>(__v2, __v3),
|
---|
| 1976 | __convert_x86<__vector_type_t<int, _Np * 2>>(__v4, __v5),
|
---|
| 1977 | __convert_x86<__vector_type_t<int, _Np * 2>>(__v6, __v7));
|
---|
| 1978 | }
|
---|
| 1979 | else // unreachable {{{2
|
---|
| 1980 | __assert_unreachable<_Tp>();
|
---|
| 1981 | //}}}
|
---|
| 1982 |
|
---|
| 1983 | // fallback: {{{2
|
---|
| 1984 | if constexpr (sizeof(_To) >= 32)
|
---|
| 1985 | // if _To is ymm or zmm, then _SimdWrapper<_Up, _M / 2> is xmm or ymm
|
---|
| 1986 | return __concat(
|
---|
| 1987 | __convert_x86<__vector_type_t<_Up, _M / 2>>(__v0, __v1, __v2, __v3),
|
---|
| 1988 | __convert_x86<__vector_type_t<_Up, _M / 2>>(__v4, __v5, __v6,
|
---|
| 1989 | __v7));
|
---|
| 1990 | else if constexpr (sizeof(_To) == 16)
|
---|
| 1991 | {
|
---|
| 1992 | const auto __lo
|
---|
| 1993 | = __to_intrin(__convert_x86<_To>(__v0, __v1, __v2, __v3));
|
---|
| 1994 | const auto __hi
|
---|
| 1995 | = __to_intrin(__convert_x86<_To>(__v4, __v5, __v6, __v7));
|
---|
| 1996 | static_assert(sizeof(_Up) == 1 && _Np == 2);
|
---|
| 1997 | return __intrin_bitcast<_To>(_mm_unpacklo_epi64(__lo, __hi));
|
---|
| 1998 | }
|
---|
| 1999 | else
|
---|
| 2000 | {
|
---|
| 2001 | __assert_unreachable<_Tp>();
|
---|
| 2002 | // return __vector_convert<_To>(__v0, __v1, __v2, __v3, __v4, __v5,
|
---|
| 2003 | // __v6, __v7,
|
---|
| 2004 | // make_index_sequence<_Np>());
|
---|
| 2005 | } //}}}2
|
---|
| 2006 | }
|
---|
| 2007 | }
|
---|
| 2008 |
|
---|
| 2009 | //}}}
|
---|
| 2010 | // 16-arg __convert_x86 {{{1
|
---|
| 2011 | template <typename _To, typename _V, typename _Traits>
|
---|
| 2012 | _GLIBCXX_SIMD_INTRINSIC _To
|
---|
| 2013 | __convert_x86(_V __v0, _V __v1, _V __v2, _V __v3, _V __v4, _V __v5, _V __v6,
|
---|
| 2014 | _V __v7, _V __v8, _V __v9, _V __v10, _V __v11, _V __v12,
|
---|
| 2015 | _V __v13, _V __v14, _V __v15)
|
---|
| 2016 | {
|
---|
| 2017 | // concat => use 8-arg __convert_x86
|
---|
| 2018 | return __convert_x86<_To>(__concat(__v0, __v1), __concat(__v2, __v3),
|
---|
| 2019 | __concat(__v4, __v5), __concat(__v6, __v7),
|
---|
| 2020 | __concat(__v8, __v9), __concat(__v10, __v11),
|
---|
| 2021 | __concat(__v12, __v13), __concat(__v14, __v15));
|
---|
| 2022 | }
|
---|
| 2023 |
|
---|
| 2024 | //}}}
|
---|
| 2025 |
|
---|
| 2026 | #endif // __cplusplus >= 201703L
|
---|
| 2027 | #endif // _GLIBCXX_EXPERIMENTAL_SIMD_X86_CONVERSIONS_H
|
---|
| 2028 |
|
---|
| 2029 | // vim: foldmethod=marker
|
---|