27 std::array<From,N> first{},second{};
28 a.store(first.data()); b.store(second.data());
29 std::array<To,2*N> lanes{};
30 for(std::size_t i=0;i<N;++i) {
31 lanes[i]=
static_cast<To
>(first[i]);
32 lanes[N+i]=
static_cast<To
>(second[i]);
36#if NATIVE_HAS_WASM_SIMD128
37 return [&]<std::size_t... I>(std::index_sequence<I...>) {
38 using vector_type = To __attribute__((ext_vector_type(2 * N)));
39 auto first = __builtin_bit_cast(vector_type, a.to_native());
40 auto second = __builtin_bit_cast(vector_type, b.to_native());
41 return result::from_native(__builtin_bit_cast(
42 v128_t, __builtin_shufflevector(first, second, (2 * I)..., (2 * N + 2 * I)...)));
43 }(std::make_index_sequence<N>{});
44#elif NATIVE_HAS_ARM_NEON
45 if constexpr (
sizeof(From) == 8)
46 return result::from_native(vreinterpretq_u8_u32(vcombine_u32(
47 vmovn_u64(vreinterpretq_u64_u8(a.to_native())),
48 vmovn_u64(vreinterpretq_u64_u8(b.to_native())))));
49 else if constexpr (
sizeof(From) == 4)
50 return result::from_native(vreinterpretq_u8_u16(vcombine_u16(
51 vmovn_u32(vreinterpretq_u32_u8(a.to_native())),
52 vmovn_u32(vreinterpretq_u32_u8(b.to_native())))));
53 else return result::from_native(vcombine_u8(
54 vmovn_u16(vreinterpretq_u16_u8(a.to_native())),
55 vmovn_u16(vreinterpretq_u16_u8(b.to_native()))));
57 if constexpr (N *
sizeof(From) == 16) {
58 if constexpr (
sizeof(From) == 8)
59 return result::from_native(_mm_unpacklo_epi64(
60 _mm_shuffle_epi32(a.to_native(), _MM_SHUFFLE(2, 0, 2, 0)),
61 _mm_shuffle_epi32(b.to_native(), _MM_SHUFFLE(2, 0, 2, 0))));
62 else if constexpr (
sizeof(From) == 4) {
63 auto mask = _mm_set1_epi32(0xffff);
64 return result::from_native(_mm_packus_epi32(
65 _mm_and_si128(a.to_native(),
mask), _mm_and_si128(b.to_native(),
mask)));
67 auto mask = _mm_set1_epi16(0xff);
68 return result::from_native(_mm_packus_epi16(
69 _mm_and_si128(a.to_native(),
mask), _mm_and_si128(b.to_native(),
mask)));
71 }
else if constexpr (N *
sizeof(From) == 32) {
72 if constexpr (
sizeof(From) == 8) {
73 auto order = _mm256_setr_epi32(0, 2, 4, 6, 0, 2, 4, 6);
74 auto low = _mm256_castsi256_si128(_mm256_permutevar8x32_epi32(a.to_native(), order));
75 auto high = _mm256_castsi256_si128(_mm256_permutevar8x32_epi32(b.to_native(), order));
76 return result::from_native(_mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1));
77 }
else if constexpr (
sizeof(From) == 4) {
78 auto mask = _mm256_set1_epi32(0xffff);
79 auto packed = _mm256_packus_epi32(_mm256_and_si256(a.to_native(),
mask),
80 _mm256_and_si256(b.to_native(),
mask));
81 return result::from_native(_mm256_permute4x64_epi64(packed, _MM_SHUFFLE(3, 1, 2, 0)));
83 auto mask = _mm256_set1_epi16(0xff);
84 auto packed = _mm256_packus_epi16(_mm256_and_si256(a.to_native(),
mask),
85 _mm256_and_si256(b.to_native(),
mask));
86 return result::from_native(_mm256_permute4x64_epi64(packed, _MM_SHUFFLE(3, 1, 2, 0)));
90 auto truncate = [](
auto x) {
91 if constexpr (
sizeof(From) == 8)
return _mm512_cvtepi64_epi32(x);
92 else if constexpr (
sizeof(From) == 4)
return _mm512_cvtepi32_epi16(x);
93 else return _mm512_cvtepi16_epi8(x);
95 auto low = truncate(a.to_native()), high = truncate(b.to_native());
96 return result::from_native(_mm512_inserti64x4(_mm512_castsi256_si512(low), high, 1));