blob: c4e4dbc3aef932a4d6830eb74d0c16d7572fe083 [file] [log] [blame]
Yue Chen7cae98f2018-08-24 10:43:16 -07001/*
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_ports/mem.h"
18
kyslov7b9d0d62018-12-21 11:12:26 -080019void aom_minmax_8x8_sse2(const uint8_t *s, int p, const uint8_t *d, int dp,
20 int *min, int *max) {
21 __m128i u0, s0, d0, diff, maxabsdiff, minabsdiff, negdiff, absdiff0, absdiff;
22 u0 = _mm_setzero_si128();
23 // Row 0
24 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
25 d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d)), u0);
26 diff = _mm_subs_epi16(s0, d0);
27 negdiff = _mm_subs_epi16(u0, diff);
28 absdiff0 = _mm_max_epi16(diff, negdiff);
29 // Row 1
30 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
31 d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + dp)), u0);
32 diff = _mm_subs_epi16(s0, d0);
33 negdiff = _mm_subs_epi16(u0, diff);
34 absdiff = _mm_max_epi16(diff, negdiff);
35 maxabsdiff = _mm_max_epi16(absdiff0, absdiff);
36 minabsdiff = _mm_min_epi16(absdiff0, absdiff);
37 // Row 2
38 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
39 d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 2 * dp)), u0);
40 diff = _mm_subs_epi16(s0, d0);
41 negdiff = _mm_subs_epi16(u0, diff);
42 absdiff = _mm_max_epi16(diff, negdiff);
43 maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
44 minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
45 // Row 3
46 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
47 d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 3 * dp)), u0);
48 diff = _mm_subs_epi16(s0, d0);
49 negdiff = _mm_subs_epi16(u0, diff);
50 absdiff = _mm_max_epi16(diff, negdiff);
51 maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
52 minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
53 // Row 4
54 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0);
55 d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 4 * dp)), u0);
56 diff = _mm_subs_epi16(s0, d0);
57 negdiff = _mm_subs_epi16(u0, diff);
58 absdiff = _mm_max_epi16(diff, negdiff);
59 maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
60 minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
61 // Row 5
62 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0);
63 d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 5 * dp)), u0);
64 diff = _mm_subs_epi16(s0, d0);
65 negdiff = _mm_subs_epi16(u0, diff);
66 absdiff = _mm_max_epi16(diff, negdiff);
67 maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
68 minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
69 // Row 6
70 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0);
71 d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 6 * dp)), u0);
72 diff = _mm_subs_epi16(s0, d0);
73 negdiff = _mm_subs_epi16(u0, diff);
74 absdiff = _mm_max_epi16(diff, negdiff);
75 maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
76 minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
77 // Row 7
78 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0);
79 d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 7 * dp)), u0);
80 diff = _mm_subs_epi16(s0, d0);
81 negdiff = _mm_subs_epi16(u0, diff);
82 absdiff = _mm_max_epi16(diff, negdiff);
83 maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
84 minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
85
86 maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_si128(maxabsdiff, 8));
87 maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 32));
88 maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 16));
89 *max = _mm_extract_epi16(maxabsdiff, 0);
90
91 minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_si128(minabsdiff, 8));
92 minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 32));
93 minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 16));
94 *min = _mm_extract_epi16(minabsdiff, 0);
95}
96
97unsigned int aom_avg_8x8_sse2(const uint8_t *s, int p) {
98 __m128i s0, s1, u0;
99 unsigned int avg = 0;
100 u0 = _mm_setzero_si128();
101 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
102 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
103 s0 = _mm_adds_epu16(s0, s1);
104 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
105 s0 = _mm_adds_epu16(s0, s1);
106 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
107 s0 = _mm_adds_epu16(s0, s1);
108 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0);
109 s0 = _mm_adds_epu16(s0, s1);
110 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0);
111 s0 = _mm_adds_epu16(s0, s1);
112 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0);
113 s0 = _mm_adds_epu16(s0, s1);
114 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0);
115 s0 = _mm_adds_epu16(s0, s1);
116
117 s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 8));
118 s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 32));
119 s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 16));
120 avg = _mm_extract_epi16(s0, 0);
121 return (avg + 32) >> 6;
122}
123
124unsigned int aom_avg_4x4_sse2(const uint8_t *s, int p) {
125 __m128i s0, s1, u0;
126 unsigned int avg = 0;
127 u0 = _mm_setzero_si128();
128 s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
129 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
130 s0 = _mm_adds_epu16(s0, s1);
131 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
132 s0 = _mm_adds_epu16(s0, s1);
133 s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
134 s0 = _mm_adds_epu16(s0, s1);
135
136 s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 4));
137 s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 16));
138 avg = _mm_extract_epi16(s0, 0);
139 return (avg + 8) >> 4;
140}
141
Scott LaVarnwayc57ea342022-01-12 14:34:35 -0500142static INLINE void hadamard_col4_sse2(__m128i *in, int iter) {
143 const __m128i a0 = in[0];
144 const __m128i a1 = in[1];
145 const __m128i a2 = in[2];
146 const __m128i a3 = in[3];
147 const __m128i b0 = _mm_srai_epi16(_mm_add_epi16(a0, a1), 1);
148 const __m128i b1 = _mm_srai_epi16(_mm_sub_epi16(a0, a1), 1);
149 const __m128i b2 = _mm_srai_epi16(_mm_add_epi16(a2, a3), 1);
150 const __m128i b3 = _mm_srai_epi16(_mm_sub_epi16(a2, a3), 1);
151 in[0] = _mm_add_epi16(b0, b2);
152 in[1] = _mm_add_epi16(b1, b3);
153 in[2] = _mm_sub_epi16(b0, b2);
154 in[3] = _mm_sub_epi16(b1, b3);
155
156 if (iter == 0) {
157 const __m128i ba = _mm_unpacklo_epi16(in[0], in[1]);
158 const __m128i dc = _mm_unpacklo_epi16(in[2], in[3]);
159 const __m128i dcba_lo = _mm_unpacklo_epi32(ba, dc);
160 const __m128i dcba_hi = _mm_unpackhi_epi32(ba, dc);
161 in[0] = dcba_lo;
162 in[1] = _mm_srli_si128(dcba_lo, 8);
163 in[2] = dcba_hi;
164 in[3] = _mm_srli_si128(dcba_hi, 8);
165 }
166}
167
168void aom_hadamard_4x4_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
169 tran_low_t *coeff) {
170 __m128i src[4];
171 src[0] = _mm_loadl_epi64((const __m128i *)src_diff);
172 src[1] = _mm_loadl_epi64((const __m128i *)(src_diff += src_stride));
173 src[2] = _mm_loadl_epi64((const __m128i *)(src_diff += src_stride));
174 src[3] = _mm_loadl_epi64((const __m128i *)(src_diff += src_stride));
175
176 hadamard_col4_sse2(src, 0);
177 hadamard_col4_sse2(src, 1);
178
179 store_tran_low(_mm_unpacklo_epi64(src[0], src[1]), coeff);
180 coeff += 8;
181 store_tran_low(_mm_unpacklo_epi64(src[2], src[3]), coeff);
182}
183
Fyodor Kyslove6d70342019-11-13 16:59:07 -0800184static INLINE void hadamard_col8_sse2(__m128i *in, int iter) {
Yue Chen7cae98f2018-08-24 10:43:16 -0700185 __m128i a0 = in[0];
186 __m128i a1 = in[1];
187 __m128i a2 = in[2];
188 __m128i a3 = in[3];
189 __m128i a4 = in[4];
190 __m128i a5 = in[5];
191 __m128i a6 = in[6];
192 __m128i a7 = in[7];
193
194 __m128i b0 = _mm_add_epi16(a0, a1);
195 __m128i b1 = _mm_sub_epi16(a0, a1);
196 __m128i b2 = _mm_add_epi16(a2, a3);
197 __m128i b3 = _mm_sub_epi16(a2, a3);
198 __m128i b4 = _mm_add_epi16(a4, a5);
199 __m128i b5 = _mm_sub_epi16(a4, a5);
200 __m128i b6 = _mm_add_epi16(a6, a7);
201 __m128i b7 = _mm_sub_epi16(a6, a7);
202
203 a0 = _mm_add_epi16(b0, b2);
204 a1 = _mm_add_epi16(b1, b3);
205 a2 = _mm_sub_epi16(b0, b2);
206 a3 = _mm_sub_epi16(b1, b3);
207 a4 = _mm_add_epi16(b4, b6);
208 a5 = _mm_add_epi16(b5, b7);
209 a6 = _mm_sub_epi16(b4, b6);
210 a7 = _mm_sub_epi16(b5, b7);
211
212 if (iter == 0) {
213 b0 = _mm_add_epi16(a0, a4);
214 b7 = _mm_add_epi16(a1, a5);
215 b3 = _mm_add_epi16(a2, a6);
216 b4 = _mm_add_epi16(a3, a7);
217 b2 = _mm_sub_epi16(a0, a4);
218 b6 = _mm_sub_epi16(a1, a5);
219 b1 = _mm_sub_epi16(a2, a6);
220 b5 = _mm_sub_epi16(a3, a7);
221
222 a0 = _mm_unpacklo_epi16(b0, b1);
223 a1 = _mm_unpacklo_epi16(b2, b3);
224 a2 = _mm_unpackhi_epi16(b0, b1);
225 a3 = _mm_unpackhi_epi16(b2, b3);
226 a4 = _mm_unpacklo_epi16(b4, b5);
227 a5 = _mm_unpacklo_epi16(b6, b7);
228 a6 = _mm_unpackhi_epi16(b4, b5);
229 a7 = _mm_unpackhi_epi16(b6, b7);
230
231 b0 = _mm_unpacklo_epi32(a0, a1);
232 b1 = _mm_unpacklo_epi32(a4, a5);
233 b2 = _mm_unpackhi_epi32(a0, a1);
234 b3 = _mm_unpackhi_epi32(a4, a5);
235 b4 = _mm_unpacklo_epi32(a2, a3);
236 b5 = _mm_unpacklo_epi32(a6, a7);
237 b6 = _mm_unpackhi_epi32(a2, a3);
238 b7 = _mm_unpackhi_epi32(a6, a7);
239
240 in[0] = _mm_unpacklo_epi64(b0, b1);
241 in[1] = _mm_unpackhi_epi64(b0, b1);
242 in[2] = _mm_unpacklo_epi64(b2, b3);
243 in[3] = _mm_unpackhi_epi64(b2, b3);
244 in[4] = _mm_unpacklo_epi64(b4, b5);
245 in[5] = _mm_unpackhi_epi64(b4, b5);
246 in[6] = _mm_unpacklo_epi64(b6, b7);
247 in[7] = _mm_unpackhi_epi64(b6, b7);
248 } else {
249 in[0] = _mm_add_epi16(a0, a4);
250 in[7] = _mm_add_epi16(a1, a5);
251 in[3] = _mm_add_epi16(a2, a6);
252 in[4] = _mm_add_epi16(a3, a7);
253 in[2] = _mm_sub_epi16(a0, a4);
254 in[6] = _mm_sub_epi16(a1, a5);
255 in[1] = _mm_sub_epi16(a2, a6);
256 in[5] = _mm_sub_epi16(a3, a7);
257 }
258}
259
260static INLINE void hadamard_8x8_sse2(const int16_t *src_diff,
261 ptrdiff_t src_stride, tran_low_t *coeff,
262 int is_final) {
263 __m128i src[8];
264 src[0] = _mm_load_si128((const __m128i *)src_diff);
265 src[1] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
266 src[2] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
267 src[3] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
268 src[4] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
269 src[5] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
270 src[6] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
271 src[7] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
272
273 hadamard_col8_sse2(src, 0);
274 hadamard_col8_sse2(src, 1);
275
276 if (is_final) {
277 store_tran_low(src[0], coeff);
278 coeff += 8;
279 store_tran_low(src[1], coeff);
280 coeff += 8;
281 store_tran_low(src[2], coeff);
282 coeff += 8;
283 store_tran_low(src[3], coeff);
284 coeff += 8;
285 store_tran_low(src[4], coeff);
286 coeff += 8;
287 store_tran_low(src[5], coeff);
288 coeff += 8;
289 store_tran_low(src[6], coeff);
290 coeff += 8;
291 store_tran_low(src[7], coeff);
292 } else {
293 int16_t *coeff16 = (int16_t *)coeff;
294 _mm_store_si128((__m128i *)coeff16, src[0]);
295 coeff16 += 8;
296 _mm_store_si128((__m128i *)coeff16, src[1]);
297 coeff16 += 8;
298 _mm_store_si128((__m128i *)coeff16, src[2]);
299 coeff16 += 8;
300 _mm_store_si128((__m128i *)coeff16, src[3]);
301 coeff16 += 8;
302 _mm_store_si128((__m128i *)coeff16, src[4]);
303 coeff16 += 8;
304 _mm_store_si128((__m128i *)coeff16, src[5]);
305 coeff16 += 8;
306 _mm_store_si128((__m128i *)coeff16, src[6]);
307 coeff16 += 8;
308 _mm_store_si128((__m128i *)coeff16, src[7]);
309 }
310}
311
312void aom_hadamard_8x8_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
313 tran_low_t *coeff) {
314 hadamard_8x8_sse2(src_diff, src_stride, coeff, 1);
315}
316
chiyotsaia49340f2021-09-27 13:54:18 -0700317static INLINE void hadamard_lp_8x8_sse2(const int16_t *src_diff,
318 ptrdiff_t src_stride, int16_t *coeff) {
Fyodor Kyslov2ab25442020-01-28 16:41:26 -0800319 __m128i src[8];
320 src[0] = _mm_load_si128((const __m128i *)src_diff);
321 src[1] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
322 src[2] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
323 src[3] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
324 src[4] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
325 src[5] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
326 src[6] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
327 src[7] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
328
329 hadamard_col8_sse2(src, 0);
330 hadamard_col8_sse2(src, 1);
331
332 _mm_store_si128((__m128i *)coeff, src[0]);
333 coeff += 8;
334 _mm_store_si128((__m128i *)coeff, src[1]);
335 coeff += 8;
336 _mm_store_si128((__m128i *)coeff, src[2]);
337 coeff += 8;
338 _mm_store_si128((__m128i *)coeff, src[3]);
339 coeff += 8;
340 _mm_store_si128((__m128i *)coeff, src[4]);
341 coeff += 8;
342 _mm_store_si128((__m128i *)coeff, src[5]);
343 coeff += 8;
344 _mm_store_si128((__m128i *)coeff, src[6]);
345 coeff += 8;
346 _mm_store_si128((__m128i *)coeff, src[7]);
347}
348
chiyotsaia49340f2021-09-27 13:54:18 -0700349void aom_hadamard_lp_8x8_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
350 int16_t *coeff) {
351 hadamard_lp_8x8_sse2(src_diff, src_stride, coeff);
352}
353
354void aom_hadamard_lp_16x16_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
355 int16_t *coeff) {
356 for (int idx = 0; idx < 4; ++idx) {
357 const int16_t *src_ptr =
358 src_diff + (idx >> 1) * 8 * src_stride + (idx & 0x01) * 8;
359 hadamard_lp_8x8_sse2(src_ptr, src_stride, coeff + idx * 64);
360 }
361
362 int16_t *t_coeff = coeff;
363 for (int idx = 0; idx < 64; idx += 8) {
364 __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff);
365 __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 64));
366 __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 128));
367 __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 192));
368
369 __m128i b0 = _mm_add_epi16(coeff0, coeff1);
370 __m128i b1 = _mm_sub_epi16(coeff0, coeff1);
371 __m128i b2 = _mm_add_epi16(coeff2, coeff3);
372 __m128i b3 = _mm_sub_epi16(coeff2, coeff3);
373
374 b0 = _mm_srai_epi16(b0, 1);
375 b1 = _mm_srai_epi16(b1, 1);
376 b2 = _mm_srai_epi16(b2, 1);
377 b3 = _mm_srai_epi16(b3, 1);
378
379 coeff0 = _mm_add_epi16(b0, b2);
380 coeff1 = _mm_add_epi16(b1, b3);
381 coeff2 = _mm_sub_epi16(b0, b2);
382 coeff3 = _mm_sub_epi16(b1, b3);
383
384 _mm_store_si128((__m128i *)t_coeff, coeff0);
385 _mm_store_si128((__m128i *)(t_coeff + 64), coeff1);
386 _mm_store_si128((__m128i *)(t_coeff + 128), coeff2);
387 _mm_store_si128((__m128i *)(t_coeff + 192), coeff3);
388
389 t_coeff += 8;
390 }
391}
392
Yue Chen7cae98f2018-08-24 10:43:16 -0700393static INLINE void hadamard_16x16_sse2(const int16_t *src_diff,
394 ptrdiff_t src_stride, tran_low_t *coeff,
395 int is_final) {
396 // For high bitdepths, it is unnecessary to store_tran_low
397 // (mult/unpack/store), then load_tran_low (load/pack) the same memory in the
398 // next stage. Output to an intermediate buffer first, then store_tran_low()
399 // in the final stage.
400 DECLARE_ALIGNED(32, int16_t, temp_coeff[16 * 16]);
401 int16_t *t_coeff = temp_coeff;
402 int16_t *coeff16 = (int16_t *)coeff;
403 int idx;
404 for (idx = 0; idx < 4; ++idx) {
405 const int16_t *src_ptr =
406 src_diff + (idx >> 1) * 8 * src_stride + (idx & 0x01) * 8;
407 hadamard_8x8_sse2(src_ptr, src_stride, (tran_low_t *)(t_coeff + idx * 64),
408 0);
409 }
410
411 for (idx = 0; idx < 64; idx += 8) {
412 __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff);
413 __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 64));
414 __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 128));
415 __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 192));
416
417 __m128i b0 = _mm_add_epi16(coeff0, coeff1);
418 __m128i b1 = _mm_sub_epi16(coeff0, coeff1);
419 __m128i b2 = _mm_add_epi16(coeff2, coeff3);
420 __m128i b3 = _mm_sub_epi16(coeff2, coeff3);
421
422 b0 = _mm_srai_epi16(b0, 1);
423 b1 = _mm_srai_epi16(b1, 1);
424 b2 = _mm_srai_epi16(b2, 1);
425 b3 = _mm_srai_epi16(b3, 1);
426
427 coeff0 = _mm_add_epi16(b0, b2);
428 coeff1 = _mm_add_epi16(b1, b3);
429 coeff2 = _mm_sub_epi16(b0, b2);
430 coeff3 = _mm_sub_epi16(b1, b3);
431
432 if (is_final) {
433 store_tran_low(coeff0, coeff);
434 store_tran_low(coeff1, coeff + 64);
435 store_tran_low(coeff2, coeff + 128);
436 store_tran_low(coeff3, coeff + 192);
437 coeff += 8;
438 } else {
439 _mm_store_si128((__m128i *)coeff16, coeff0);
440 _mm_store_si128((__m128i *)(coeff16 + 64), coeff1);
441 _mm_store_si128((__m128i *)(coeff16 + 128), coeff2);
442 _mm_store_si128((__m128i *)(coeff16 + 192), coeff3);
443 coeff16 += 8;
444 }
445
446 t_coeff += 8;
447 }
448}
449
450void aom_hadamard_16x16_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
451 tran_low_t *coeff) {
452 hadamard_16x16_sse2(src_diff, src_stride, coeff, 1);
453}
454
455void aom_hadamard_32x32_sse2(const int16_t *src_diff, ptrdiff_t src_stride,
456 tran_low_t *coeff) {
457 // For high bitdepths, it is unnecessary to store_tran_low
458 // (mult/unpack/store), then load_tran_low (load/pack) the same memory in the
459 // next stage. Output to an intermediate buffer first, then store_tran_low()
460 // in the final stage.
461 DECLARE_ALIGNED(32, int16_t, temp_coeff[32 * 32]);
462 int16_t *t_coeff = temp_coeff;
463 int idx;
464 for (idx = 0; idx < 4; ++idx) {
465 const int16_t *src_ptr =
466 src_diff + (idx >> 1) * 16 * src_stride + (idx & 0x01) * 16;
467 hadamard_16x16_sse2(src_ptr, src_stride,
468 (tran_low_t *)(t_coeff + idx * 256), 0);
469 }
470
471 for (idx = 0; idx < 256; idx += 8) {
472 __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff);
473 __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 256));
474 __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 512));
475 __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 768));
476
477 __m128i b0 = _mm_add_epi16(coeff0, coeff1);
478 __m128i b1 = _mm_sub_epi16(coeff0, coeff1);
479 __m128i b2 = _mm_add_epi16(coeff2, coeff3);
480 __m128i b3 = _mm_sub_epi16(coeff2, coeff3);
481
482 b0 = _mm_srai_epi16(b0, 2);
483 b1 = _mm_srai_epi16(b1, 2);
484 b2 = _mm_srai_epi16(b2, 2);
485 b3 = _mm_srai_epi16(b3, 2);
486
487 coeff0 = _mm_add_epi16(b0, b2);
488 coeff1 = _mm_add_epi16(b1, b3);
489 store_tran_low(coeff0, coeff);
490 store_tran_low(coeff1, coeff + 256);
491
492 coeff2 = _mm_sub_epi16(b0, b2);
493 coeff3 = _mm_sub_epi16(b1, b3);
494 store_tran_low(coeff2, coeff + 512);
495 store_tran_low(coeff3, coeff + 768);
496
497 coeff += 8;
498 t_coeff += 8;
499 }
500}
501
502int aom_satd_sse2(const tran_low_t *coeff, int length) {
503 int i;
504 const __m128i zero = _mm_setzero_si128();
Yunqing Wangc694eaa2021-09-29 13:34:47 -0700505 const __m128i one = _mm_set1_epi16(1);
Yue Chen7cae98f2018-08-24 10:43:16 -0700506 __m128i accum = zero;
507
Yunqing Wangc694eaa2021-09-29 13:34:47 -0700508 for (i = 0; i < length; i += 16) {
509 const __m128i src_line0 = load_tran_low(coeff);
510 const __m128i src_line1 = load_tran_low(coeff + 8);
511 const __m128i inv0 = _mm_sub_epi16(zero, src_line0);
512 const __m128i inv1 = _mm_sub_epi16(zero, src_line1);
513 const __m128i abs0 = _mm_max_epi16(src_line0, inv0); // abs(src_line)
514 const __m128i abs1 = _mm_max_epi16(src_line1, inv1); // abs(src_line)
515 const __m128i sum0 = _mm_madd_epi16(abs0, one);
516 const __m128i sum1 = _mm_madd_epi16(abs1, one);
517 accum = _mm_add_epi32(accum, sum0);
518 accum = _mm_add_epi32(accum, sum1);
519 coeff += 16;
Yue Chen7cae98f2018-08-24 10:43:16 -0700520 }
521
522 { // cascading summation of accum
523 __m128i hi = _mm_srli_si128(accum, 8);
524 accum = _mm_add_epi32(accum, hi);
525 hi = _mm_srli_epi64(accum, 32);
526 accum = _mm_add_epi32(accum, hi);
527 }
528
529 return _mm_cvtsi128_si32(accum);
530}
Jerome Jiangee586532019-07-19 16:24:56 -0700531
Yunqing Wangb9e790a2021-09-28 16:08:06 -0700532int aom_satd_lp_sse2(const int16_t *coeff, int length) {
533 const __m128i zero = _mm_setzero_si128();
534 const __m128i one = _mm_set1_epi16(1);
535 __m128i accum = zero;
536
537 for (int i = 0; i < length; i += 16) {
538 const __m128i src_line0 = _mm_loadu_si128((const __m128i *)coeff);
539 const __m128i src_line1 = _mm_loadu_si128((const __m128i *)(coeff + 8));
540 const __m128i inv0 = _mm_sub_epi16(zero, src_line0);
541 const __m128i inv1 = _mm_sub_epi16(zero, src_line1);
542 const __m128i abs0 = _mm_max_epi16(src_line0, inv0); // abs(src_line)
543 const __m128i abs1 = _mm_max_epi16(src_line1, inv1); // abs(src_line)
544 const __m128i sum0 = _mm_madd_epi16(abs0, one);
545 const __m128i sum1 = _mm_madd_epi16(abs1, one);
546 accum = _mm_add_epi32(accum, sum0);
547 accum = _mm_add_epi32(accum, sum1);
548 coeff += 16;
549 }
550
551 { // cascading summation of accum
552 __m128i hi = _mm_srli_si128(accum, 8);
553 accum = _mm_add_epi32(accum, hi);
554 hi = _mm_srli_epi64(accum, 32);
555 accum = _mm_add_epi32(accum, hi);
556 }
557
558 return _mm_cvtsi128_si32(accum);
559}
560
James Zern06e13e82021-12-20 12:30:30 -0800561void aom_int_pro_row_sse2(int16_t hbuf[16], const uint8_t *ref,
Jerome Jiangee586532019-07-19 16:24:56 -0700562 const int ref_stride, const int height) {
Jerome Jiang1fcd64f2019-07-29 15:53:40 -0700563 int idx = 1;
Jerome Jiangee586532019-07-19 16:24:56 -0700564 __m128i zero = _mm_setzero_si128();
565 __m128i src_line = _mm_loadu_si128((const __m128i *)ref);
566 __m128i s0 = _mm_unpacklo_epi8(src_line, zero);
567 __m128i s1 = _mm_unpackhi_epi8(src_line, zero);
568 __m128i t0, t1;
569 int height_1 = height - 1;
570 ref += ref_stride;
Jerome Jiang1fcd64f2019-07-29 15:53:40 -0700571 do {
Jerome Jiangee586532019-07-19 16:24:56 -0700572 src_line = _mm_loadu_si128((const __m128i *)ref);
573 t0 = _mm_unpacklo_epi8(src_line, zero);
574 t1 = _mm_unpackhi_epi8(src_line, zero);
575 s0 = _mm_adds_epu16(s0, t0);
576 s1 = _mm_adds_epu16(s1, t1);
577 ref += ref_stride;
578
579 src_line = _mm_loadu_si128((const __m128i *)ref);
580 t0 = _mm_unpacklo_epi8(src_line, zero);
581 t1 = _mm_unpackhi_epi8(src_line, zero);
582 s0 = _mm_adds_epu16(s0, t0);
583 s1 = _mm_adds_epu16(s1, t1);
584 ref += ref_stride;
Jerome Jiang1fcd64f2019-07-29 15:53:40 -0700585 idx += 2;
586 } while (idx < height_1);
Jerome Jiangee586532019-07-19 16:24:56 -0700587
588 src_line = _mm_loadu_si128((const __m128i *)ref);
589 t0 = _mm_unpacklo_epi8(src_line, zero);
590 t1 = _mm_unpackhi_epi8(src_line, zero);
591 s0 = _mm_adds_epu16(s0, t0);
592 s1 = _mm_adds_epu16(s1, t1);
593 if (height == 128) {
594 s0 = _mm_srai_epi16(s0, 6);
595 s1 = _mm_srai_epi16(s1, 6);
596 } else if (height == 64) {
597 s0 = _mm_srai_epi16(s0, 5);
598 s1 = _mm_srai_epi16(s1, 5);
599 } else if (height == 32) {
600 s0 = _mm_srai_epi16(s0, 4);
601 s1 = _mm_srai_epi16(s1, 4);
602 } else {
Jerome Jiang1fcd64f2019-07-29 15:53:40 -0700603 assert(height == 16);
Jerome Jiangee586532019-07-19 16:24:56 -0700604 s0 = _mm_srai_epi16(s0, 3);
605 s1 = _mm_srai_epi16(s1, 3);
606 }
607
608 _mm_storeu_si128((__m128i *)hbuf, s0);
609 hbuf += 8;
610 _mm_storeu_si128((__m128i *)hbuf, s1);
611}
612
613int16_t aom_int_pro_col_sse2(const uint8_t *ref, const int width) {
614 __m128i zero = _mm_setzero_si128();
Jerome Jiang1fcd64f2019-07-29 15:53:40 -0700615 __m128i src_line = _mm_loadu_si128((const __m128i *)ref);
Jerome Jiangee586532019-07-19 16:24:56 -0700616 __m128i s0 = _mm_sad_epu8(src_line, zero);
617 __m128i s1;
618 int i;
619
620 for (i = 16; i < width; i += 16) {
621 ref += 16;
Jerome Jiang1fcd64f2019-07-29 15:53:40 -0700622 src_line = _mm_loadu_si128((const __m128i *)ref);
Jerome Jiangee586532019-07-19 16:24:56 -0700623 s1 = _mm_sad_epu8(src_line, zero);
624 s0 = _mm_adds_epu16(s0, s1);
625 }
626
627 s1 = _mm_srli_si128(s0, 8);
628 s0 = _mm_adds_epu16(s0, s1);
629
630 return _mm_extract_epi16(s0, 0);
631}