xref: /aosp_15_r20/external/libaom/aom_dsp/x86/avg_intrin_sse2.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1 /*
2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <immintrin.h>
13 
14 #include "config/aom_dsp_rtcd.h"
15 #include "aom/aom_integer.h"
16 #include "aom_dsp/x86/bitdepth_conversion_sse2.h"
17 #include "aom_dsp/x86/mem_sse2.h"
18 #include "aom_dsp/x86/synonyms.h"
19 #include "aom_ports/mem.h"
20 
sign_extend_16bit_to_32bit_sse2(__m128i in,__m128i zero,__m128i * out_lo,__m128i * out_hi)21 static inline void sign_extend_16bit_to_32bit_sse2(__m128i in, __m128i zero,
22                                                    __m128i *out_lo,
23                                                    __m128i *out_hi) {
24   const __m128i sign_bits = _mm_cmplt_epi16(in, zero);
25   *out_lo = _mm_unpacklo_epi16(in, sign_bits);
26   *out_hi = _mm_unpackhi_epi16(in, sign_bits);
27 }
28 
invert_sign_32_sse2(__m128i a,__m128i sign)29 static inline __m128i invert_sign_32_sse2(__m128i a, __m128i sign) {
30   a = _mm_xor_si128(a, sign);
31   return _mm_sub_epi32(a, sign);
32 }
33 
aom_minmax_8x8_sse2(const uint8_t * s,int p,const uint8_t * d,int dp,int * min,int * max)34 void aom_minmax_8x8_sse2(const uint8_t *s, int p, const uint8_t *d, int dp,
35                          int *min, int *max) {
36   __m128i u0, s0, d0, diff, maxabsdiff, minabsdiff, negdiff, absdiff0, absdiff;
37   u0 = _mm_setzero_si128();
38   // Row 0
39   s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
40   d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d)), u0);
41   diff = _mm_subs_epi16(s0, d0);
42   negdiff = _mm_subs_epi16(u0, diff);
43   absdiff0 = _mm_max_epi16(diff, negdiff);
44   // Row 1
45   s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
46   d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + dp)), u0);
47   diff = _mm_subs_epi16(s0, d0);
48   negdiff = _mm_subs_epi16(u0, diff);
49   absdiff = _mm_max_epi16(diff, negdiff);
50   maxabsdiff = _mm_max_epi16(absdiff0, absdiff);
51   minabsdiff = _mm_min_epi16(absdiff0, absdiff);
52   // Row 2
53   s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
54   d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 2 * dp)), u0);
55   diff = _mm_subs_epi16(s0, d0);
56   negdiff = _mm_subs_epi16(u0, diff);
57   absdiff = _mm_max_epi16(diff, negdiff);
58   maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
59   minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
60   // Row 3
61   s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
62   d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 3 * dp)), u0);
63   diff = _mm_subs_epi16(s0, d0);
64   negdiff = _mm_subs_epi16(u0, diff);
65   absdiff = _mm_max_epi16(diff, negdiff);
66   maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
67   minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
68   // Row 4
69   s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0);
70   d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 4 * dp)), u0);
71   diff = _mm_subs_epi16(s0, d0);
72   negdiff = _mm_subs_epi16(u0, diff);
73   absdiff = _mm_max_epi16(diff, negdiff);
74   maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
75   minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
76   // Row 5
77   s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0);
78   d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 5 * dp)), u0);
79   diff = _mm_subs_epi16(s0, d0);
80   negdiff = _mm_subs_epi16(u0, diff);
81   absdiff = _mm_max_epi16(diff, negdiff);
82   maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
83   minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
84   // Row 6
85   s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0);
86   d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 6 * dp)), u0);
87   diff = _mm_subs_epi16(s0, d0);
88   negdiff = _mm_subs_epi16(u0, diff);
89   absdiff = _mm_max_epi16(diff, negdiff);
90   maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
91   minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
92   // Row 7
93   s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0);
94   d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 7 * dp)), u0);
95   diff = _mm_subs_epi16(s0, d0);
96   negdiff = _mm_subs_epi16(u0, diff);
97   absdiff = _mm_max_epi16(diff, negdiff);
98   maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
99   minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
100 
101   maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_si128(maxabsdiff, 8));
102   maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 32));
103   maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 16));
104   *max = _mm_extract_epi16(maxabsdiff, 0);
105 
106   minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_si128(minabsdiff, 8));
107   minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 32));
108   minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 16));
109   *min = _mm_extract_epi16(minabsdiff, 0);
110 }
111 
aom_avg_8x8_sse2(const uint8_t * s,int p)112 unsigned int aom_avg_8x8_sse2(const uint8_t *s, int p) {
113   __m128i sum0, sum1, s0, s1, s2, s3, u0;
114   unsigned int avg = 0;
115   u0 = _mm_setzero_si128();
116   s0 = loadh_epi64((const __m128i *)(s + p),
117                    _mm_loadl_epi64((const __m128i *)(s)));
118   s1 = loadh_epi64((const __m128i *)(s + 3 * p),
119                    _mm_loadl_epi64((const __m128i *)(s + 2 * p)));
120   s2 = loadh_epi64((const __m128i *)(s + 5 * p),
121                    _mm_loadl_epi64((const __m128i *)(s + 4 * p)));
122   s3 = loadh_epi64((const __m128i *)(s + 7 * p),
123                    _mm_loadl_epi64((const __m128i *)(s + 6 * p)));
124   s0 = _mm_sad_epu8(s0, u0);
125   s1 = _mm_sad_epu8(s1, u0);
126   s2 = _mm_sad_epu8(s2, u0);
127   s3 = _mm_sad_epu8(s3, u0);
128 
129   sum0 = _mm_add_epi16(s0, s1);
130   sum1 = _mm_add_epi16(s2, s3);
131   sum0 = _mm_add_epi16(sum0, sum1);
132   sum0 = _mm_add_epi16(sum0, _mm_srli_si128(sum0, 8));
133   avg = _mm_cvtsi128_si32(sum0);
134   return (avg + 32) >> 6;
135 }
136 
calc_avg_8x8_dual_sse2(const uint8_t * s,int p,int * avg)137 static void calc_avg_8x8_dual_sse2(const uint8_t *s, int p, int *avg) {
138   __m128i sum0, sum1, s0, s1, s2, s3, u0;
139   u0 = _mm_setzero_si128();
140   s0 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s)), u0);
141   s1 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + p)), u0);
142   s2 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 2 * p)), u0);
143   s3 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 3 * p)), u0);
144   sum0 = _mm_add_epi16(s0, s1);
145   sum1 = _mm_add_epi16(s2, s3);
146   s0 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 4 * p)), u0);
147   s1 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 5 * p)), u0);
148   s2 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 6 * p)), u0);
149   s3 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 7 * p)), u0);
150   sum0 = _mm_add_epi16(sum0, _mm_add_epi16(s0, s1));
151   sum1 = _mm_add_epi16(sum1, _mm_add_epi16(s2, s3));
152   sum0 = _mm_add_epi16(sum0, sum1);
153 
154   // (avg + 32) >> 6
155   __m128i rounding = _mm_set1_epi32(32);
156   sum0 = _mm_add_epi32(sum0, rounding);
157   sum0 = _mm_srli_epi32(sum0, 6);
158   avg[0] = _mm_cvtsi128_si32(sum0);
159   avg[1] = _mm_extract_epi16(sum0, 4);
160 }
161 
aom_avg_8x8_quad_sse2(const uint8_t * s,int p,int x16_idx,int y16_idx,int * avg)162 void aom_avg_8x8_quad_sse2(const uint8_t *s, int p, int x16_idx, int y16_idx,
163                            int *avg) {
164   const uint8_t *s_ptr = s + y16_idx * p + x16_idx;
165   for (int k = 0; k < 2; k++) {
166     calc_avg_8x8_dual_sse2(s_ptr, p, avg + k * 2);
167     s_ptr += 8 * p;
168   }
169 }
170 
aom_avg_4x4_sse2(const uint8_t * s,int p)171 unsigned int aom_avg_4x4_sse2(const uint8_t *s, int p) {
172   __m128i s0, s1, u0;
173   unsigned int avg = 0;
174   u0 = _mm_setzero_si128();
175   s0 = _mm_unpacklo_epi32(xx_loadl_32(s), xx_loadl_32(s + p));
176   s1 = _mm_unpacklo_epi32(xx_loadl_32(s + p * 2), xx_loadl_32(s + p * 3));
177   s0 = _mm_sad_epu8(s0, u0);
178   s1 = _mm_sad_epu8(s1, u0);
179   s0 = _mm_add_epi16(s0, s1);
180   avg = _mm_cvtsi128_si32(s0);
181   return (avg + 8) >> 4;
182 }
183 
hadamard_col4_sse2(__m128i * in,int iter)184 static inline void hadamard_col4_sse2(__m128i *in, int iter) {
185   const __m128i a0 = in[0];
186   const __m128i a1 = in[1];
187   const __m128i a2 = in[2];
188   const __m128i a3 = in[3];
189   const __m128i b0 = _mm_srai_epi16(_mm_add_epi16(a0, a1), 1);
190   const __m128i b1 = _mm_srai_epi16(_mm_sub_epi16(a0, a1), 1);
191   const __m128i b2 = _mm_srai_epi16(_mm_add_epi16(a2, a3), 1);
192   const __m128i b3 = _mm_srai_epi16(_mm_sub_epi16(a2, a3), 1);
193   in[0] = _mm_add_epi16(b0, b2);
194   in[1] = _mm_add_epi16(b1, b3);
195   in[2] = _mm_sub_epi16(b0, b2);
196   in[3] = _mm_sub_epi16(b1, b3);
197 
198   if (iter == 0) {
199     const __m128i ba = _mm_unpacklo_epi16(in[0], in[1]);
200     const __m128i dc = _mm_unpacklo_epi16(in[2], in[3]);
201     const __m128i dcba_lo = _mm_unpacklo_epi32(ba, dc);
202     const __m128i dcba_hi = _mm_unpackhi_epi32(ba, dc);
203     in[0] = dcba_lo;
204     in[1] = _mm_srli_si128(dcba_lo, 8);
205     in[2] = dcba_hi;
206     in[3] = _mm_srli_si128(dcba_hi, 8);
207   }
208 }
209 
aom_hadamard_4x4_sse2(const int16_t * src_diff,ptrdiff_t src_stride,tran_low_t * coeff)210 void aom_hadamard_4x4_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
211                            tran_low_t *coeff) {
212   __m128i src[4];
213   src[0] = _mm_loadl_epi64((const __m128i *)src_diff);
214   src[1] = _mm_loadl_epi64((const __m128i *)(src_diff += src_stride));
215   src[2] = _mm_loadl_epi64((const __m128i *)(src_diff += src_stride));
216   src[3] = _mm_loadl_epi64((const __m128i *)(src_diff + src_stride));
217 
218   hadamard_col4_sse2(src, 0);
219   hadamard_col4_sse2(src, 1);
220 
221   store_tran_low(_mm_unpacklo_epi64(src[0], src[1]), coeff);
222   coeff += 8;
223   store_tran_low(_mm_unpacklo_epi64(src[2], src[3]), coeff);
224 }
225 
hadamard_col8_sse2(__m128i * in,int iter)226 static inline void hadamard_col8_sse2(__m128i *in, int iter) {
227   __m128i a0 = in[0];
228   __m128i a1 = in[1];
229   __m128i a2 = in[2];
230   __m128i a3 = in[3];
231   __m128i a4 = in[4];
232   __m128i a5 = in[5];
233   __m128i a6 = in[6];
234   __m128i a7 = in[7];
235 
236   __m128i b0 = _mm_add_epi16(a0, a1);
237   __m128i b1 = _mm_sub_epi16(a0, a1);
238   __m128i b2 = _mm_add_epi16(a2, a3);
239   __m128i b3 = _mm_sub_epi16(a2, a3);
240   __m128i b4 = _mm_add_epi16(a4, a5);
241   __m128i b5 = _mm_sub_epi16(a4, a5);
242   __m128i b6 = _mm_add_epi16(a6, a7);
243   __m128i b7 = _mm_sub_epi16(a6, a7);
244 
245   a0 = _mm_add_epi16(b0, b2);
246   a1 = _mm_add_epi16(b1, b3);
247   a2 = _mm_sub_epi16(b0, b2);
248   a3 = _mm_sub_epi16(b1, b3);
249   a4 = _mm_add_epi16(b4, b6);
250   a5 = _mm_add_epi16(b5, b7);
251   a6 = _mm_sub_epi16(b4, b6);
252   a7 = _mm_sub_epi16(b5, b7);
253 
254   if (iter == 0) {
255     b0 = _mm_add_epi16(a0, a4);
256     b7 = _mm_add_epi16(a1, a5);
257     b3 = _mm_add_epi16(a2, a6);
258     b4 = _mm_add_epi16(a3, a7);
259     b2 = _mm_sub_epi16(a0, a4);
260     b6 = _mm_sub_epi16(a1, a5);
261     b1 = _mm_sub_epi16(a2, a6);
262     b5 = _mm_sub_epi16(a3, a7);
263 
264     a0 = _mm_unpacklo_epi16(b0, b1);
265     a1 = _mm_unpacklo_epi16(b2, b3);
266     a2 = _mm_unpackhi_epi16(b0, b1);
267     a3 = _mm_unpackhi_epi16(b2, b3);
268     a4 = _mm_unpacklo_epi16(b4, b5);
269     a5 = _mm_unpacklo_epi16(b6, b7);
270     a6 = _mm_unpackhi_epi16(b4, b5);
271     a7 = _mm_unpackhi_epi16(b6, b7);
272 
273     b0 = _mm_unpacklo_epi32(a0, a1);
274     b1 = _mm_unpacklo_epi32(a4, a5);
275     b2 = _mm_unpackhi_epi32(a0, a1);
276     b3 = _mm_unpackhi_epi32(a4, a5);
277     b4 = _mm_unpacklo_epi32(a2, a3);
278     b5 = _mm_unpacklo_epi32(a6, a7);
279     b6 = _mm_unpackhi_epi32(a2, a3);
280     b7 = _mm_unpackhi_epi32(a6, a7);
281 
282     in[0] = _mm_unpacklo_epi64(b0, b1);
283     in[1] = _mm_unpackhi_epi64(b0, b1);
284     in[2] = _mm_unpacklo_epi64(b2, b3);
285     in[3] = _mm_unpackhi_epi64(b2, b3);
286     in[4] = _mm_unpacklo_epi64(b4, b5);
287     in[5] = _mm_unpackhi_epi64(b4, b5);
288     in[6] = _mm_unpacklo_epi64(b6, b7);
289     in[7] = _mm_unpackhi_epi64(b6, b7);
290   } else {
291     in[0] = _mm_add_epi16(a0, a4);
292     in[7] = _mm_add_epi16(a1, a5);
293     in[3] = _mm_add_epi16(a2, a6);
294     in[4] = _mm_add_epi16(a3, a7);
295     in[2] = _mm_sub_epi16(a0, a4);
296     in[6] = _mm_sub_epi16(a1, a5);
297     in[1] = _mm_sub_epi16(a2, a6);
298     in[5] = _mm_sub_epi16(a3, a7);
299   }
300 }
301 
hadamard_8x8_sse2(const int16_t * src_diff,ptrdiff_t src_stride,tran_low_t * coeff,int is_final)302 static inline void hadamard_8x8_sse2(const int16_t *src_diff,
303                                      ptrdiff_t src_stride, tran_low_t *coeff,
304                                      int is_final) {
305   __m128i src[8];
306   src[0] = _mm_load_si128((const __m128i *)src_diff);
307   src[1] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
308   src[2] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
309   src[3] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
310   src[4] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
311   src[5] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
312   src[6] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
313   src[7] = _mm_load_si128((const __m128i *)(src_diff + src_stride));
314 
315   hadamard_col8_sse2(src, 0);
316   hadamard_col8_sse2(src, 1);
317 
318   if (is_final) {
319     store_tran_low(src[0], coeff);
320     coeff += 8;
321     store_tran_low(src[1], coeff);
322     coeff += 8;
323     store_tran_low(src[2], coeff);
324     coeff += 8;
325     store_tran_low(src[3], coeff);
326     coeff += 8;
327     store_tran_low(src[4], coeff);
328     coeff += 8;
329     store_tran_low(src[5], coeff);
330     coeff += 8;
331     store_tran_low(src[6], coeff);
332     coeff += 8;
333     store_tran_low(src[7], coeff);
334   } else {
335     int16_t *coeff16 = (int16_t *)coeff;
336     _mm_store_si128((__m128i *)coeff16, src[0]);
337     coeff16 += 8;
338     _mm_store_si128((__m128i *)coeff16, src[1]);
339     coeff16 += 8;
340     _mm_store_si128((__m128i *)coeff16, src[2]);
341     coeff16 += 8;
342     _mm_store_si128((__m128i *)coeff16, src[3]);
343     coeff16 += 8;
344     _mm_store_si128((__m128i *)coeff16, src[4]);
345     coeff16 += 8;
346     _mm_store_si128((__m128i *)coeff16, src[5]);
347     coeff16 += 8;
348     _mm_store_si128((__m128i *)coeff16, src[6]);
349     coeff16 += 8;
350     _mm_store_si128((__m128i *)coeff16, src[7]);
351   }
352 }
353 
aom_hadamard_8x8_sse2(const int16_t * src_diff,ptrdiff_t src_stride,tran_low_t * coeff)354 void aom_hadamard_8x8_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
355                            tran_low_t *coeff) {
356   hadamard_8x8_sse2(src_diff, src_stride, coeff, 1);
357 }
358 
hadamard_lp_8x8_sse2(const int16_t * src_diff,ptrdiff_t src_stride,int16_t * coeff)359 static inline void hadamard_lp_8x8_sse2(const int16_t *src_diff,
360                                         ptrdiff_t src_stride, int16_t *coeff) {
361   __m128i src[8];
362   src[0] = _mm_load_si128((const __m128i *)src_diff);
363   src[1] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
364   src[2] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
365   src[3] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
366   src[4] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
367   src[5] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
368   src[6] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
369   src[7] = _mm_load_si128((const __m128i *)(src_diff + src_stride));
370 
371   hadamard_col8_sse2(src, 0);
372   hadamard_col8_sse2(src, 1);
373 
374   _mm_store_si128((__m128i *)coeff, src[0]);
375   coeff += 8;
376   _mm_store_si128((__m128i *)coeff, src[1]);
377   coeff += 8;
378   _mm_store_si128((__m128i *)coeff, src[2]);
379   coeff += 8;
380   _mm_store_si128((__m128i *)coeff, src[3]);
381   coeff += 8;
382   _mm_store_si128((__m128i *)coeff, src[4]);
383   coeff += 8;
384   _mm_store_si128((__m128i *)coeff, src[5]);
385   coeff += 8;
386   _mm_store_si128((__m128i *)coeff, src[6]);
387   coeff += 8;
388   _mm_store_si128((__m128i *)coeff, src[7]);
389 }
390 
aom_hadamard_lp_8x8_sse2(const int16_t * src_diff,ptrdiff_t src_stride,int16_t * coeff)391 void aom_hadamard_lp_8x8_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
392                               int16_t *coeff) {
393   hadamard_lp_8x8_sse2(src_diff, src_stride, coeff);
394 }
395 
aom_hadamard_lp_8x8_dual_sse2(const int16_t * src_diff,ptrdiff_t src_stride,int16_t * coeff)396 void aom_hadamard_lp_8x8_dual_sse2(const int16_t *src_diff,
397                                    ptrdiff_t src_stride, int16_t *coeff) {
398   for (int i = 0; i < 2; i++) {
399     hadamard_lp_8x8_sse2(src_diff + (i * 8), src_stride, coeff + (i * 64));
400   }
401 }
402 
aom_hadamard_lp_16x16_sse2(const int16_t * src_diff,ptrdiff_t src_stride,int16_t * coeff)403 void aom_hadamard_lp_16x16_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
404                                 int16_t *coeff) {
405   for (int idx = 0; idx < 4; ++idx) {
406     const int16_t *src_ptr =
407         src_diff + (idx >> 1) * 8 * src_stride + (idx & 0x01) * 8;
408     hadamard_lp_8x8_sse2(src_ptr, src_stride, coeff + idx * 64);
409   }
410 
411   int16_t *t_coeff = coeff;
412   for (int idx = 0; idx < 64; idx += 8) {
413     __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff);
414     __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 64));
415     __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 128));
416     __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 192));
417 
418     __m128i b0 = _mm_add_epi16(coeff0, coeff1);
419     __m128i b1 = _mm_sub_epi16(coeff0, coeff1);
420     __m128i b2 = _mm_add_epi16(coeff2, coeff3);
421     __m128i b3 = _mm_sub_epi16(coeff2, coeff3);
422 
423     b0 = _mm_srai_epi16(b0, 1);
424     b1 = _mm_srai_epi16(b1, 1);
425     b2 = _mm_srai_epi16(b2, 1);
426     b3 = _mm_srai_epi16(b3, 1);
427 
428     coeff0 = _mm_add_epi16(b0, b2);
429     coeff1 = _mm_add_epi16(b1, b3);
430     coeff2 = _mm_sub_epi16(b0, b2);
431     coeff3 = _mm_sub_epi16(b1, b3);
432 
433     _mm_store_si128((__m128i *)t_coeff, coeff0);
434     _mm_store_si128((__m128i *)(t_coeff + 64), coeff1);
435     _mm_store_si128((__m128i *)(t_coeff + 128), coeff2);
436     _mm_store_si128((__m128i *)(t_coeff + 192), coeff3);
437 
438     t_coeff += 8;
439   }
440 }
441 
hadamard_16x16_sse2(const int16_t * src_diff,ptrdiff_t src_stride,tran_low_t * coeff,int is_final)442 static inline void hadamard_16x16_sse2(const int16_t *src_diff,
443                                        ptrdiff_t src_stride, tran_low_t *coeff,
444                                        int is_final) {
445   // For high bitdepths, it is unnecessary to store_tran_low
446   // (mult/unpack/store), then load_tran_low (load/pack) the same memory in the
447   // next stage.  Output to an intermediate buffer first, then store_tran_low()
448   // in the final stage.
449   DECLARE_ALIGNED(32, int16_t, temp_coeff[16 * 16]);
450   int16_t *t_coeff = temp_coeff;
451   int16_t *coeff16 = (int16_t *)coeff;
452   int idx;
453   for (idx = 0; idx < 4; ++idx) {
454     const int16_t *src_ptr =
455         src_diff + (idx >> 1) * 8 * src_stride + (idx & 0x01) * 8;
456     hadamard_8x8_sse2(src_ptr, src_stride, (tran_low_t *)(t_coeff + idx * 64),
457                       0);
458   }
459 
460   for (idx = 0; idx < 64; idx += 8) {
461     __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff);
462     __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 64));
463     __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 128));
464     __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 192));
465 
466     __m128i b0 = _mm_add_epi16(coeff0, coeff1);
467     __m128i b1 = _mm_sub_epi16(coeff0, coeff1);
468     __m128i b2 = _mm_add_epi16(coeff2, coeff3);
469     __m128i b3 = _mm_sub_epi16(coeff2, coeff3);
470 
471     b0 = _mm_srai_epi16(b0, 1);
472     b1 = _mm_srai_epi16(b1, 1);
473     b2 = _mm_srai_epi16(b2, 1);
474     b3 = _mm_srai_epi16(b3, 1);
475 
476     coeff0 = _mm_add_epi16(b0, b2);
477     coeff1 = _mm_add_epi16(b1, b3);
478     coeff2 = _mm_sub_epi16(b0, b2);
479     coeff3 = _mm_sub_epi16(b1, b3);
480 
481     if (is_final) {
482       store_tran_low_offset_4(coeff0, coeff);
483       store_tran_low_offset_4(coeff1, coeff + 64);
484       store_tran_low_offset_4(coeff2, coeff + 128);
485       store_tran_low_offset_4(coeff3, coeff + 192);
486       coeff += 4;
487     } else {
488       _mm_store_si128((__m128i *)coeff16, coeff0);
489       _mm_store_si128((__m128i *)(coeff16 + 64), coeff1);
490       _mm_store_si128((__m128i *)(coeff16 + 128), coeff2);
491       _mm_store_si128((__m128i *)(coeff16 + 192), coeff3);
492       coeff16 += 8;
493     }
494 
495     t_coeff += 8;
496     // Increment the pointer additionally by 0 and 8 in alternate
497     // iterations(instead of 8) to ensure the coherency with the implementation
498     // of store_tran_low_offset_4()
499     coeff += (((idx >> 3) & 1) << 3);
500   }
501 }
502 
aom_hadamard_16x16_sse2(const int16_t * src_diff,ptrdiff_t src_stride,tran_low_t * coeff)503 void aom_hadamard_16x16_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
504                              tran_low_t *coeff) {
505   hadamard_16x16_sse2(src_diff, src_stride, coeff, 1);
506 }
507 
aom_hadamard_32x32_sse2(const int16_t * src_diff,ptrdiff_t src_stride,tran_low_t * coeff)508 void aom_hadamard_32x32_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
509                              tran_low_t *coeff) {
510   // For high bitdepths, it is unnecessary to store_tran_low
511   // (mult/unpack/store), then load_tran_low (load/pack) the same memory in the
512   // next stage.  Output to an intermediate buffer first, then store_tran_low()
513   // in the final stage.
514   DECLARE_ALIGNED(32, int16_t, temp_coeff[32 * 32]);
515   int16_t *t_coeff = temp_coeff;
516   int idx;
517   __m128i coeff0_lo, coeff1_lo, coeff2_lo, coeff3_lo, b0_lo, b1_lo, b2_lo,
518       b3_lo;
519   __m128i coeff0_hi, coeff1_hi, coeff2_hi, coeff3_hi, b0_hi, b1_hi, b2_hi,
520       b3_hi;
521   __m128i b0, b1, b2, b3;
522   const __m128i zero = _mm_setzero_si128();
523   for (idx = 0; idx < 4; ++idx) {
524     const int16_t *src_ptr =
525         src_diff + (idx >> 1) * 16 * src_stride + (idx & 0x01) * 16;
526     hadamard_16x16_sse2(src_ptr, src_stride,
527                         (tran_low_t *)(t_coeff + idx * 256), 0);
528   }
529 
530   for (idx = 0; idx < 256; idx += 8) {
531     __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff);
532     __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 256));
533     __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 512));
534     __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 768));
535 
536     // Sign extend 16 bit to 32 bit.
537     sign_extend_16bit_to_32bit_sse2(coeff0, zero, &coeff0_lo, &coeff0_hi);
538     sign_extend_16bit_to_32bit_sse2(coeff1, zero, &coeff1_lo, &coeff1_hi);
539     sign_extend_16bit_to_32bit_sse2(coeff2, zero, &coeff2_lo, &coeff2_hi);
540     sign_extend_16bit_to_32bit_sse2(coeff3, zero, &coeff3_lo, &coeff3_hi);
541 
542     b0_lo = _mm_add_epi32(coeff0_lo, coeff1_lo);
543     b0_hi = _mm_add_epi32(coeff0_hi, coeff1_hi);
544 
545     b1_lo = _mm_sub_epi32(coeff0_lo, coeff1_lo);
546     b1_hi = _mm_sub_epi32(coeff0_hi, coeff1_hi);
547 
548     b2_lo = _mm_add_epi32(coeff2_lo, coeff3_lo);
549     b2_hi = _mm_add_epi32(coeff2_hi, coeff3_hi);
550 
551     b3_lo = _mm_sub_epi32(coeff2_lo, coeff3_lo);
552     b3_hi = _mm_sub_epi32(coeff2_hi, coeff3_hi);
553 
554     b0_lo = _mm_srai_epi32(b0_lo, 2);
555     b1_lo = _mm_srai_epi32(b1_lo, 2);
556     b2_lo = _mm_srai_epi32(b2_lo, 2);
557     b3_lo = _mm_srai_epi32(b3_lo, 2);
558 
559     b0_hi = _mm_srai_epi32(b0_hi, 2);
560     b1_hi = _mm_srai_epi32(b1_hi, 2);
561     b2_hi = _mm_srai_epi32(b2_hi, 2);
562     b3_hi = _mm_srai_epi32(b3_hi, 2);
563 
564     b0 = _mm_packs_epi32(b0_lo, b0_hi);
565     b1 = _mm_packs_epi32(b1_lo, b1_hi);
566     b2 = _mm_packs_epi32(b2_lo, b2_hi);
567     b3 = _mm_packs_epi32(b3_lo, b3_hi);
568 
569     coeff0 = _mm_add_epi16(b0, b2);
570     coeff1 = _mm_add_epi16(b1, b3);
571     store_tran_low_offset_4(coeff0, coeff);
572     store_tran_low_offset_4(coeff1, coeff + 256);
573 
574     coeff2 = _mm_sub_epi16(b0, b2);
575     coeff3 = _mm_sub_epi16(b1, b3);
576     store_tran_low_offset_4(coeff2, coeff + 512);
577     store_tran_low_offset_4(coeff3, coeff + 768);
578 
579     // Increment the pointer by 4 and 12 in alternate iterations(instead of 8)
580     // to ensure the coherency with the implementation of
581     // store_tran_low_offset_4()
582     coeff += (4 + (((idx >> 3) & 1) << 3));
583     t_coeff += 8;
584   }
585 }
586 
aom_satd_sse2(const tran_low_t * coeff,int length)587 int aom_satd_sse2(const tran_low_t *coeff, int length) {
588   int i;
589   const __m128i zero = _mm_setzero_si128();
590   __m128i accum = zero;
591 
592   for (i = 0; i < length; i += 4) {
593     const __m128i src_line = _mm_load_si128((const __m128i *)coeff);
594     const __m128i coeff_sign = _mm_srai_epi32(src_line, 31);
595     const __m128i abs_coeff = invert_sign_32_sse2(src_line, coeff_sign);
596     accum = _mm_add_epi32(accum, abs_coeff);
597     coeff += 4;
598   }
599 
600   {  // cascading summation of accum
601     __m128i hi = _mm_srli_si128(accum, 8);
602     accum = _mm_add_epi32(accum, hi);
603     hi = _mm_srli_epi64(accum, 32);
604     accum = _mm_add_epi32(accum, hi);
605   }
606 
607   return _mm_cvtsi128_si32(accum);
608 }
609 
aom_satd_lp_sse2(const int16_t * coeff,int length)610 int aom_satd_lp_sse2(const int16_t *coeff, int length) {
611   const __m128i zero = _mm_setzero_si128();
612   const __m128i one = _mm_set1_epi16(1);
613   __m128i accum = zero;
614 
615   for (int i = 0; i < length; i += 16) {
616     const __m128i src_line0 = _mm_loadu_si128((const __m128i *)coeff);
617     const __m128i src_line1 = _mm_loadu_si128((const __m128i *)(coeff + 8));
618     const __m128i inv0 = _mm_sub_epi16(zero, src_line0);
619     const __m128i inv1 = _mm_sub_epi16(zero, src_line1);
620     const __m128i abs0 = _mm_max_epi16(src_line0, inv0);  // abs(src_line)
621     const __m128i abs1 = _mm_max_epi16(src_line1, inv1);  // abs(src_line)
622     const __m128i sum0 = _mm_madd_epi16(abs0, one);
623     const __m128i sum1 = _mm_madd_epi16(abs1, one);
624     accum = _mm_add_epi32(accum, sum0);
625     accum = _mm_add_epi32(accum, sum1);
626     coeff += 16;
627   }
628 
629   {  // cascading summation of accum
630     __m128i hi = _mm_srli_si128(accum, 8);
631     accum = _mm_add_epi32(accum, hi);
632     hi = _mm_srli_epi64(accum, 32);
633     accum = _mm_add_epi32(accum, hi);
634   }
635 
636   return _mm_cvtsi128_si32(accum);
637 }
638 
aom_int_pro_row_sse2(int16_t * hbuf,const uint8_t * ref,const int ref_stride,const int width,const int height,int norm_factor)639 void aom_int_pro_row_sse2(int16_t *hbuf, const uint8_t *ref,
640                           const int ref_stride, const int width,
641                           const int height, int norm_factor) {
642   // SIMD implementation assumes width and height to be multiple of 16 and 2
643   // respectively. For any odd width or height, SIMD support needs to be added.
644   assert(width % 16 == 0 && height % 2 == 0);
645   __m128i zero = _mm_setzero_si128();
646 
647   for (int wd = 0; wd < width; wd += 16) {
648     const uint8_t *ref_tmp = ref + wd;
649     int16_t *hbuf_tmp = hbuf + wd;
650     __m128i s0 = zero;
651     __m128i s1 = zero;
652     int idx = 0;
653     do {
654       __m128i src_line = _mm_loadu_si128((const __m128i *)ref_tmp);
655       __m128i t0 = _mm_unpacklo_epi8(src_line, zero);
656       __m128i t1 = _mm_unpackhi_epi8(src_line, zero);
657       s0 = _mm_add_epi16(s0, t0);
658       s1 = _mm_add_epi16(s1, t1);
659       ref_tmp += ref_stride;
660 
661       src_line = _mm_loadu_si128((const __m128i *)ref_tmp);
662       t0 = _mm_unpacklo_epi8(src_line, zero);
663       t1 = _mm_unpackhi_epi8(src_line, zero);
664       s0 = _mm_add_epi16(s0, t0);
665       s1 = _mm_add_epi16(s1, t1);
666       ref_tmp += ref_stride;
667       idx += 2;
668     } while (idx < height);
669 
670     s0 = _mm_srai_epi16(s0, norm_factor);
671     s1 = _mm_srai_epi16(s1, norm_factor);
672     _mm_storeu_si128((__m128i *)(hbuf_tmp), s0);
673     _mm_storeu_si128((__m128i *)(hbuf_tmp + 8), s1);
674   }
675 }
676 
aom_int_pro_col_sse2(int16_t * vbuf,const uint8_t * ref,const int ref_stride,const int width,const int height,int norm_factor)677 void aom_int_pro_col_sse2(int16_t *vbuf, const uint8_t *ref,
678                           const int ref_stride, const int width,
679                           const int height, int norm_factor) {
680   // SIMD implementation assumes width to be multiple of 16.
681   assert(width % 16 == 0);
682 
683   for (int ht = 0; ht < height; ht++) {
684     const uint8_t *ref_tmp = ref + (ht * ref_stride);
685     __m128i zero = _mm_setzero_si128();
686     __m128i s0 = zero;
687     __m128i s1, src_line;
688     for (int i = 0; i < width; i += 16) {
689       src_line = _mm_loadu_si128((const __m128i *)ref_tmp);
690       s1 = _mm_sad_epu8(src_line, zero);
691       s0 = _mm_add_epi16(s0, s1);
692       ref_tmp += 16;
693     }
694 
695     s1 = _mm_srli_si128(s0, 8);
696     s0 = _mm_add_epi16(s0, s1);
697     vbuf[ht] = _mm_cvtsi128_si32(s0) >> norm_factor;
698   }
699 }
700