37 using U = std::conditional_t<
sizeof(T)==1,std::uint16_t,
38 std::conditional_t<
sizeof(T)==2,std::uint32_t,std::uint64_t>>;
39 using result =
simd<U,N/2,Arch>;
41 std::array<T,N> source{};
42 value.store(source.data());
43 std::array<U,N/2> lanes{};
44 for(std::size_t i=0;i<N/2;++i) lanes[i]=U(source[2*i])+source[2*i+1];
47 if constexpr (
sizeof(T)==4 && N==2) {
50 auto lanes = value.to_native();
51 return result(std::uint64_t(lanes[0]) + lanes[1]);
53#if NATIVE_HAS_ARM_NEON
54 if constexpr (
sizeof(T)==1)
55 return result::from_native(vreinterpretq_u8_u16(vpaddlq_u8(value.to_native())));
56 else if constexpr (
sizeof(T)==2)
57 return result::from_native(vreinterpretq_u8_u32(vpaddlq_u16(vreinterpretq_u16_u8(value.to_native()))));
58 else return result::from_native(vreinterpretq_u8_u64(vpaddlq_u32(vreinterpretq_u32_u8(value.to_native()))));
59#elif NATIVE_HAS_WASM_SIMD128
60 if constexpr (
sizeof(T) == 1) {
61 return result::from_native(wasm_u16x8_extadd_pairwise_u8x16(value.to_native()));
62 }
else if constexpr (
sizeof(T) == 2) {
63 return result::from_native(wasm_u32x4_extadd_pairwise_u16x8(value.to_native()));
65 auto even = wasm_i32x4_shuffle(value.to_native(), value.to_native(), 0, 2, 0, 0);
66 auto odd = wasm_i32x4_shuffle(value.to_native(), value.to_native(), 1, 3, 0, 0);
67 return result::from_native(wasm_i64x2_add(
68 wasm_u64x2_extend_low_u32x4(even), wasm_u64x2_extend_low_u32x4(odd)));
74 if constexpr (
sizeof(T)==1 &&
sizeof(T)*N==16)
75 return result::from_native(_mm_maddubs_epi16(value.to_native(),_mm_set1_epi8(1)));
76 else if constexpr (
sizeof(T)==1 &&
sizeof(T)*N==32)
77 return result::from_native(_mm256_maddubs_epi16(value.to_native(),_mm256_set1_epi8(1)));
80#if NATIVE_HAS_AVX512BW
81 if constexpr (
sizeof(T)==1 &&
sizeof(T)*N==64)
82 return result::from_native(_mm512_maddubs_epi16(value.to_native(),_mm512_set1_epi8(1)));
87 return (words & result(U(std::numeric_limits<T>::max()))) + words.template right<8*sizeof(T)>();
99 std::array<T,N> lanes{};
100 value.store(lanes.data());
101 for(
auto &lane:lanes) lane=T(std::popcount(lane));
102 return result(lanes);
104 if constexpr (N==1)
return result(T(std::popcount(value.to_native())));
105 else if constexpr (
sizeof(T)==4 && (N==2 || N==3))
106 return result::from_storage(
popcount(value.to_storage()));
107#if NATIVE_HAS_AVX512F && !NATIVE_HAS_AVX512BW
108 else if constexpr (
sizeof(T)*N==64) {
112 constexpr T
all = std::numeric_limits<T>::max();
113 value = value - (value.template right<1>() & result(T(
all/3)));
114 value = (value & result(T(
all/5))) + (value.template right<2>() & result(T(
all/5)));
115 value = (value + value.template right<4>()) & result(T(
all/17));
116 value = value + value.template right<8>();
117 value = value + value.template right<16>();
118 if constexpr (
sizeof(T)==8) value = value + value.template right<32>();
119 return value & result(T(127));
122 else if constexpr (
sizeof(T)>1)
124 std::conditional_t<
sizeof(T)==2,std::uint8_t,
125 std::conditional_t<
sizeof(T)==4,std::uint16_t,std::uint32_t>>>(value)));
127#if NATIVE_HAS_WASM_SIMD128
128 return result::from_native(wasm_i8x16_popcnt(value.to_native()));
130#if NATIVE_HAS_ARM_NEON
131 return result::from_native(vcntq_u8(value.to_native()));
134 if constexpr (N==16) {
135 auto table = _mm_setr_epi8(0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4);
136 auto mask = _mm_set1_epi8(15);
137 auto data = value.to_native();
138 return result::from_native(_mm_add_epi8(
139 _mm_shuffle_epi8(table,_mm_and_si128(data,
mask)),
140 _mm_shuffle_epi8(table,_mm_and_si128(_mm_srli_epi16(data,4),
mask))));
141 }
else if constexpr (N==32) {
142 auto table = _mm256_broadcastsi128_si256(_mm_setr_epi8(0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4));
143 auto mask = _mm256_set1_epi8(15);
144 auto data = value.to_native();
145 return result::from_native(_mm256_add_epi8(
146 _mm256_shuffle_epi8(table,_mm256_and_si256(data,
mask)),
147 _mm256_shuffle_epi8(table,_mm256_and_si256(_mm256_srli_epi16(data,4),
mask))));
150#if NATIVE_HAS_AVX512BW
151 if constexpr (N==64) {
152 auto table = _mm512_broadcast_i32x4(_mm_setr_epi8(0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4));
153 auto mask = _mm512_set1_epi8(15);
154 auto data = value.to_native();
155 return result::from_native(_mm512_add_epi8(
156 _mm512_shuffle_epi8(table,_mm512_and_si512(data,
mask)),
157 _mm512_shuffle_epi8(table,_mm512_and_si512(_mm512_srli_epi16(data,4),
mask))));
170 std::array<T,N> lanes{};
171 value.store(lanes.data());
173 for(
auto lane:lanes) sum+=lane;
176 if constexpr (N==1)
return value.to_native();
177 else if constexpr (
sizeof(T)==4 && (N==2 || N==3)) {
178 auto lanes = value.to_native();
179 auto sum = std::uint64_t(lanes[0]) + lanes[1];
180 if constexpr (N==3) sum += lanes[2];
184#if NATIVE_HAS_WASM_SIMD128
186 if constexpr (
sizeof(T) == 1) {
188 }
else if constexpr (
sizeof(T) == 2) {
194 return sums.template get<0>() + sums.template get<1>();
196#if NATIVE_HAS_ARM_NEON
197 if constexpr (
sizeof(T)==1)
return vaddlvq_u8(value.to_native());
198 else if constexpr (
sizeof(T)==2)
return vaddlvq_u16(vreinterpretq_u16_u8(value.to_native()));
199 else return vaddlvq_u32(vreinterpretq_u32_u8(value.to_native()));
203 if constexpr (
sizeof(T)==1) {
204 if constexpr (N==16)
return _mm_sad_epu8(value.to_native(),_mm_setzero_si128());
205 else if constexpr (N==32)
return _mm256_sad_epu8(value.to_native(),_mm256_setzero_si256());
206#if NATIVE_HAS_AVX512BW
207 else return _mm512_sad_epu8(value.to_native(),_mm512_setzero_si512());
209 }
else if constexpr (
sizeof(T)==2)
213 if constexpr (
sizeof(T)*N==16)
214 return std::uint64_t(_mm_cvtsi128_si64(_mm_add_epi64(sums,_mm_srli_si128(sums,8))));
215 else if constexpr (
sizeof(T)*N==32) {
216 auto halves = _mm_add_epi64(_mm256_castsi256_si128(sums),_mm256_extracti128_si256(sums,1));
217 return std::uint64_t(_mm_cvtsi128_si64(_mm_add_epi64(halves,_mm_srli_si128(halves,8))));
219#if NATIVE_HAS_AVX512F
220 else return std::uint64_t(_mm512_reduce_add_epi64(sums));