Coverage Report

Created: 2026-09-07 06:44

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