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/highbd_sad_avx2.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_config.h"
15
#include "config/aom_dsp_rtcd.h"
16
17
#include "aom/aom_integer.h"
18
#include "aom_dsp/x86/synonyms_avx2.h"
19
#include "aom_ports/mem.h"
20
21
// SAD
22
0
static inline unsigned int get_sad_from_mm256_epi32(const __m256i *v) {
23
  // input 8 32-bit summation
24
0
  __m128i lo128, hi128;
25
0
  __m256i u = _mm256_srli_si256(*v, 8);
26
0
  u = _mm256_add_epi32(u, *v);
27
28
  // 4 32-bit summation
29
0
  hi128 = _mm256_extracti128_si256(u, 1);
30
0
  lo128 = _mm256_castsi256_si128(u);
31
0
  lo128 = _mm_add_epi32(hi128, lo128);
32
33
  // 2 32-bit summation
34
0
  hi128 = _mm_srli_si128(lo128, 4);
35
0
  lo128 = _mm_add_epi32(lo128, hi128);
36
37
0
  return (unsigned int)_mm_cvtsi128_si32(lo128);
38
0
}
39
40
static inline void highbd_sad16x4_core_avx2(__m256i *s, __m256i *r,
41
0
                                            __m256i *sad_acc) {
42
0
  const __m256i zero = _mm256_setzero_si256();
43
0
  int i;
44
0
  for (i = 0; i < 4; i++) {
45
0
    s[i] = _mm256_sub_epi16(s[i], r[i]);
46
0
    s[i] = _mm256_abs_epi16(s[i]);
47
0
  }
48
49
0
  s[0] = _mm256_add_epi16(s[0], s[1]);
50
0
  s[0] = _mm256_add_epi16(s[0], s[2]);
51
0
  s[0] = _mm256_add_epi16(s[0], s[3]);
52
53
0
  r[0] = _mm256_unpacklo_epi16(s[0], zero);
54
0
  r[1] = _mm256_unpackhi_epi16(s[0], zero);
55
56
0
  r[0] = _mm256_add_epi32(r[0], r[1]);
57
0
  *sad_acc = _mm256_add_epi32(*sad_acc, r[0]);
58
0
}
59
60
// If sec_ptr = 0, calculate regular SAD. Otherwise, calculate average SAD.
61
static inline void sad16x4(const uint16_t *src_ptr, int src_stride,
62
                           const uint16_t *ref_ptr, int ref_stride,
63
0
                           const uint16_t *sec_ptr, __m256i *sad_acc) {
64
0
  __m256i s[4], r[4];
65
0
  s[0] = _mm256_loadu_si256((const __m256i *)src_ptr);
66
0
  s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride));
67
0
  s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + 2 * src_stride));
68
0
  s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + 3 * src_stride));
69
70
0
  r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr);
71
0
  r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride));
72
0
  r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 2 * ref_stride));
73
0
  r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 3 * ref_stride));
74
75
0
  if (sec_ptr) {
76
0
    r[0] = _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr));
77
0
    r[1] = _mm256_avg_epu16(
78
0
        r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16)));
79
0
    r[2] = _mm256_avg_epu16(
80
0
        r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32)));
81
0
    r[3] = _mm256_avg_epu16(
82
0
        r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48)));
83
0
  }
84
0
  highbd_sad16x4_core_avx2(s, r, sad_acc);
85
0
}
86
87
static AOM_FORCE_INLINE unsigned int aom_highbd_sad16xN_avx2(int N,
88
                                                             const uint8_t *src,
89
                                                             int src_stride,
90
                                                             const uint8_t *ref,
91
0
                                                             int ref_stride) {
92
0
  const uint16_t *src_ptr = CONVERT_TO_SHORTPTR(src);
93
0
  const uint16_t *ref_ptr = CONVERT_TO_SHORTPTR(ref);
94
0
  int i;
95
0
  __m256i sad = _mm256_setzero_si256();
96
0
  for (i = 0; i < N; i += 4) {
97
0
    sad16x4(src_ptr, src_stride, ref_ptr, ref_stride, NULL, &sad);
98
0
    src_ptr += src_stride << 2;
99
0
    ref_ptr += ref_stride << 2;
100
0
  }
101
0
  return (unsigned int)get_sad_from_mm256_epi32(&sad);
102
0
}
103
104
static void sad32x4(const uint16_t *src_ptr, int src_stride,
105
                    const uint16_t *ref_ptr, int ref_stride,
106
0
                    const uint16_t *sec_ptr, __m256i *sad_acc) {
107
0
  __m256i s[4], r[4];
108
0
  int row_sections = 0;
109
110
0
  while (row_sections < 2) {
111
0
    s[0] = _mm256_loadu_si256((const __m256i *)src_ptr);
112
0
    s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + 16));
113
0
    s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride));
114
0
    s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride + 16));
115
116
0
    r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr);
117
0
    r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16));
118
0
    r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride));
119
0
    r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride + 16));
120
121
0
    if (sec_ptr) {
122
0
      r[0] =
123
0
          _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr));
124
0
      r[1] = _mm256_avg_epu16(
125
0
          r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16)));
126
0
      r[2] = _mm256_avg_epu16(
127
0
          r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32)));
128
0
      r[3] = _mm256_avg_epu16(
129
0
          r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48)));
130
0
      sec_ptr += 32 << 1;
131
0
    }
132
0
    highbd_sad16x4_core_avx2(s, r, sad_acc);
133
134
0
    row_sections += 1;
135
0
    src_ptr += src_stride << 1;
136
0
    ref_ptr += ref_stride << 1;
137
0
  }
138
0
}
139
140
static AOM_FORCE_INLINE unsigned int aom_highbd_sad32xN_avx2(int N,
141
                                                             const uint8_t *src,
142
                                                             int src_stride,
143
                                                             const uint8_t *ref,
144
0
                                                             int ref_stride) {
145
0
  __m256i sad = _mm256_setzero_si256();
146
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
147
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
148
0
  const int left_shift = 2;
149
0
  int i;
150
151
0
  for (i = 0; i < N; i += 4) {
152
0
    sad32x4(srcp, src_stride, refp, ref_stride, NULL, &sad);
153
0
    srcp += src_stride << left_shift;
154
0
    refp += ref_stride << left_shift;
155
0
  }
156
0
  return get_sad_from_mm256_epi32(&sad);
157
0
}
158
159
static void sad64x2(const uint16_t *src_ptr, int src_stride,
160
                    const uint16_t *ref_ptr, int ref_stride,
161
0
                    const uint16_t *sec_ptr, __m256i *sad_acc) {
162
0
  __m256i s[4], r[4];
163
0
  int i;
164
0
  for (i = 0; i < 2; i++) {
165
0
    s[0] = _mm256_loadu_si256((const __m256i *)src_ptr);
166
0
    s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + 16));
167
0
    s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + 32));
168
0
    s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + 48));
169
170
0
    r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr);
171
0
    r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16));
172
0
    r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 32));
173
0
    r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 48));
174
0
    if (sec_ptr) {
175
0
      r[0] =
176
0
          _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr));
177
0
      r[1] = _mm256_avg_epu16(
178
0
          r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16)));
179
0
      r[2] = _mm256_avg_epu16(
180
0
          r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32)));
181
0
      r[3] = _mm256_avg_epu16(
182
0
          r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48)));
183
0
      sec_ptr += 64;
184
0
    }
185
0
    highbd_sad16x4_core_avx2(s, r, sad_acc);
186
0
    src_ptr += src_stride;
187
0
    ref_ptr += ref_stride;
188
0
  }
189
0
}
190
191
static AOM_FORCE_INLINE unsigned int aom_highbd_sad64xN_avx2(int N,
192
                                                             const uint8_t *src,
193
                                                             int src_stride,
194
                                                             const uint8_t *ref,
195
0
                                                             int ref_stride) {
196
0
  __m256i sad = _mm256_setzero_si256();
197
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
198
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
199
0
  const int left_shift = 1;
200
0
  int i;
201
0
  for (i = 0; i < N; i += 2) {
202
0
    sad64x2(srcp, src_stride, refp, ref_stride, NULL, &sad);
203
0
    srcp += src_stride << left_shift;
204
0
    refp += ref_stride << left_shift;
205
0
  }
206
0
  return get_sad_from_mm256_epi32(&sad);
207
0
}
208
209
static void sad128x1(const uint16_t *src_ptr, const uint16_t *ref_ptr,
210
0
                     const uint16_t *sec_ptr, __m256i *sad_acc) {
211
0
  __m256i s[4], r[4];
212
0
  int i;
213
0
  for (i = 0; i < 2; i++) {
214
0
    s[0] = _mm256_loadu_si256((const __m256i *)src_ptr);
215
0
    s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + 16));
216
0
    s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + 32));
217
0
    s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + 48));
218
0
    r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr);
219
0
    r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16));
220
0
    r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 32));
221
0
    r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 48));
222
0
    if (sec_ptr) {
223
0
      r[0] =
224
0
          _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr));
225
0
      r[1] = _mm256_avg_epu16(
226
0
          r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16)));
227
0
      r[2] = _mm256_avg_epu16(
228
0
          r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32)));
229
0
      r[3] = _mm256_avg_epu16(
230
0
          r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48)));
231
0
      sec_ptr += 64;
232
0
    }
233
0
    highbd_sad16x4_core_avx2(s, r, sad_acc);
234
0
    src_ptr += 64;
235
0
    ref_ptr += 64;
236
0
  }
237
0
}
238
239
static AOM_FORCE_INLINE unsigned int aom_highbd_sad128xN_avx2(
240
    int N, const uint8_t *src, int src_stride, const uint8_t *ref,
241
0
    int ref_stride) {
242
0
  __m256i sad = _mm256_setzero_si256();
243
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
244
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
245
0
  int row = 0;
246
0
  while (row < N) {
247
0
    sad128x1(srcp, refp, NULL, &sad);
248
0
    srcp += src_stride;
249
0
    refp += ref_stride;
250
0
    row++;
251
0
  }
252
0
  return get_sad_from_mm256_epi32(&sad);
253
0
}
254
255
#define HIGHBD_SADMXN_AVX2(m, n)                                            \
256
  unsigned int aom_highbd_sad##m##x##n##_avx2(                              \
257
      const uint8_t *src, int src_stride, const uint8_t *ref,               \
258
0
      int ref_stride) {                                                     \
259
0
    return aom_highbd_sad##m##xN_avx2(n, src, src_stride, ref, ref_stride); \
260
0
  }
Unexecuted instantiation: aom_highbd_sad16x8_avx2
Unexecuted instantiation: aom_highbd_sad16x16_avx2
Unexecuted instantiation: aom_highbd_sad16x32_avx2
Unexecuted instantiation: aom_highbd_sad32x16_avx2
Unexecuted instantiation: aom_highbd_sad32x32_avx2
Unexecuted instantiation: aom_highbd_sad32x64_avx2
Unexecuted instantiation: aom_highbd_sad64x32_avx2
Unexecuted instantiation: aom_highbd_sad64x64_avx2
Unexecuted instantiation: aom_highbd_sad64x128_avx2
Unexecuted instantiation: aom_highbd_sad128x64_avx2
Unexecuted instantiation: aom_highbd_sad128x128_avx2
Unexecuted instantiation: aom_highbd_sad16x4_avx2
Unexecuted instantiation: aom_highbd_sad16x64_avx2
Unexecuted instantiation: aom_highbd_sad32x8_avx2
Unexecuted instantiation: aom_highbd_sad64x16_avx2
261
262
#define HIGHBD_SAD_SKIP_MXN_AVX2(m, n)                                       \
263
  unsigned int aom_highbd_sad_skip_##m##x##n##_avx2(                         \
264
      const uint8_t *src, int src_stride, const uint8_t *ref,                \
265
0
      int ref_stride) {                                                      \
266
0
    return 2 * aom_highbd_sad##m##xN_avx2((n / 2), src, 2 * src_stride, ref, \
267
0
                                          2 * ref_stride);                   \
268
0
  }
Unexecuted instantiation: aom_highbd_sad_skip_16x16_avx2
Unexecuted instantiation: aom_highbd_sad_skip_16x32_avx2
Unexecuted instantiation: aom_highbd_sad_skip_32x16_avx2
Unexecuted instantiation: aom_highbd_sad_skip_32x32_avx2
Unexecuted instantiation: aom_highbd_sad_skip_32x64_avx2
Unexecuted instantiation: aom_highbd_sad_skip_64x32_avx2
Unexecuted instantiation: aom_highbd_sad_skip_64x64_avx2
Unexecuted instantiation: aom_highbd_sad_skip_64x128_avx2
Unexecuted instantiation: aom_highbd_sad_skip_128x64_avx2
Unexecuted instantiation: aom_highbd_sad_skip_128x128_avx2
Unexecuted instantiation: aom_highbd_sad_skip_16x64_avx2
Unexecuted instantiation: aom_highbd_sad_skip_64x16_avx2
269
270
HIGHBD_SADMXN_AVX2(16, 8)
271
HIGHBD_SADMXN_AVX2(16, 16)
272
HIGHBD_SADMXN_AVX2(16, 32)
273
274
HIGHBD_SADMXN_AVX2(32, 16)
275
HIGHBD_SADMXN_AVX2(32, 32)
276
HIGHBD_SADMXN_AVX2(32, 64)
277
278
HIGHBD_SADMXN_AVX2(64, 32)
279
HIGHBD_SADMXN_AVX2(64, 64)
280
HIGHBD_SADMXN_AVX2(64, 128)
281
282
HIGHBD_SADMXN_AVX2(128, 64)
283
HIGHBD_SADMXN_AVX2(128, 128)
284
285
#if !CONFIG_REALTIME_ONLY
286
HIGHBD_SADMXN_AVX2(16, 4)
287
HIGHBD_SADMXN_AVX2(16, 64)
288
HIGHBD_SADMXN_AVX2(32, 8)
289
HIGHBD_SADMXN_AVX2(64, 16)
290
#endif  // !CONFIG_REALTIME_ONLY
291
292
HIGHBD_SAD_SKIP_MXN_AVX2(16, 16)
293
HIGHBD_SAD_SKIP_MXN_AVX2(16, 32)
294
295
HIGHBD_SAD_SKIP_MXN_AVX2(32, 16)
296
HIGHBD_SAD_SKIP_MXN_AVX2(32, 32)
297
HIGHBD_SAD_SKIP_MXN_AVX2(32, 64)
298
299
HIGHBD_SAD_SKIP_MXN_AVX2(64, 32)
300
HIGHBD_SAD_SKIP_MXN_AVX2(64, 64)
301
HIGHBD_SAD_SKIP_MXN_AVX2(64, 128)
302
303
HIGHBD_SAD_SKIP_MXN_AVX2(128, 64)
304
HIGHBD_SAD_SKIP_MXN_AVX2(128, 128)
305
306
#if !CONFIG_REALTIME_ONLY
307
HIGHBD_SAD_SKIP_MXN_AVX2(16, 64)
308
HIGHBD_SAD_SKIP_MXN_AVX2(64, 16)
309
#endif  // !CONFIG_REALTIME_ONLY
310
311
unsigned int aom_highbd_sad16x8_avg_avx2(const uint8_t *src, int src_stride,
312
                                         const uint8_t *ref, int ref_stride,
313
0
                                         const uint8_t *second_pred) {
314
0
  __m256i sad = _mm256_setzero_si256();
315
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
316
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
317
0
  uint16_t *secp = CONVERT_TO_SHORTPTR(second_pred);
318
319
0
  sad16x4(srcp, src_stride, refp, ref_stride, secp, &sad);
320
321
  // Next 4 rows
322
0
  srcp += src_stride << 2;
323
0
  refp += ref_stride << 2;
324
0
  secp += 64;
325
0
  sad16x4(srcp, src_stride, refp, ref_stride, secp, &sad);
326
0
  return get_sad_from_mm256_epi32(&sad);
327
0
}
328
329
unsigned int aom_highbd_sad16x16_avg_avx2(const uint8_t *src, int src_stride,
330
                                          const uint8_t *ref, int ref_stride,
331
0
                                          const uint8_t *second_pred) {
332
0
  const int left_shift = 3;
333
0
  uint32_t sum = aom_highbd_sad16x8_avg_avx2(src, src_stride, ref, ref_stride,
334
0
                                             second_pred);
335
0
  src += src_stride << left_shift;
336
0
  ref += ref_stride << left_shift;
337
0
  second_pred += 16 << left_shift;
338
0
  sum += aom_highbd_sad16x8_avg_avx2(src, src_stride, ref, ref_stride,
339
0
                                     second_pred);
340
0
  return sum;
341
0
}
342
343
unsigned int aom_highbd_sad16x32_avg_avx2(const uint8_t *src, int src_stride,
344
                                          const uint8_t *ref, int ref_stride,
345
0
                                          const uint8_t *second_pred) {
346
0
  const int left_shift = 4;
347
0
  uint32_t sum = aom_highbd_sad16x16_avg_avx2(src, src_stride, ref, ref_stride,
348
0
                                              second_pred);
349
0
  src += src_stride << left_shift;
350
0
  ref += ref_stride << left_shift;
351
0
  second_pred += 16 << left_shift;
352
0
  sum += aom_highbd_sad16x16_avg_avx2(src, src_stride, ref, ref_stride,
353
0
                                      second_pred);
354
0
  return sum;
355
0
}
356
357
#if !CONFIG_REALTIME_ONLY
358
unsigned int aom_highbd_sad16x64_avg_avx2(const uint8_t *src, int src_stride,
359
                                          const uint8_t *ref, int ref_stride,
360
0
                                          const uint8_t *second_pred) {
361
0
  const int left_shift = 5;
362
0
  uint32_t sum = aom_highbd_sad16x32_avg_avx2(src, src_stride, ref, ref_stride,
363
0
                                              second_pred);
364
0
  src += src_stride << left_shift;
365
0
  ref += ref_stride << left_shift;
366
0
  second_pred += 16 << left_shift;
367
0
  sum += aom_highbd_sad16x32_avg_avx2(src, src_stride, ref, ref_stride,
368
0
                                      second_pred);
369
0
  return sum;
370
0
}
371
372
unsigned int aom_highbd_sad32x8_avg_avx2(const uint8_t *src, int src_stride,
373
                                         const uint8_t *ref, int ref_stride,
374
0
                                         const uint8_t *second_pred) {
375
0
  __m256i sad = _mm256_setzero_si256();
376
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
377
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
378
0
  uint16_t *secp = CONVERT_TO_SHORTPTR(second_pred);
379
0
  const int left_shift = 2;
380
0
  int row_section = 0;
381
382
0
  while (row_section < 2) {
383
0
    sad32x4(srcp, src_stride, refp, ref_stride, secp, &sad);
384
0
    srcp += src_stride << left_shift;
385
0
    refp += ref_stride << left_shift;
386
0
    secp += 32 << left_shift;
387
0
    row_section += 1;
388
0
  }
389
0
  return get_sad_from_mm256_epi32(&sad);
390
0
}
391
#endif  // !CONFIG_REALTIME_ONLY
392
393
unsigned int aom_highbd_sad32x16_avg_avx2(const uint8_t *src, int src_stride,
394
                                          const uint8_t *ref, int ref_stride,
395
0
                                          const uint8_t *second_pred) {
396
0
  __m256i sad = _mm256_setzero_si256();
397
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
398
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
399
0
  uint16_t *secp = CONVERT_TO_SHORTPTR(second_pred);
400
0
  const int left_shift = 2;
401
0
  int row_section = 0;
402
403
0
  while (row_section < 4) {
404
0
    sad32x4(srcp, src_stride, refp, ref_stride, secp, &sad);
405
0
    srcp += src_stride << left_shift;
406
0
    refp += ref_stride << left_shift;
407
0
    secp += 32 << left_shift;
408
0
    row_section += 1;
409
0
  }
410
0
  return get_sad_from_mm256_epi32(&sad);
411
0
}
412
413
unsigned int aom_highbd_sad32x32_avg_avx2(const uint8_t *src, int src_stride,
414
                                          const uint8_t *ref, int ref_stride,
415
0
                                          const uint8_t *second_pred) {
416
0
  const int left_shift = 4;
417
0
  uint32_t sum = aom_highbd_sad32x16_avg_avx2(src, src_stride, ref, ref_stride,
418
0
                                              second_pred);
419
0
  src += src_stride << left_shift;
420
0
  ref += ref_stride << left_shift;
421
0
  second_pred += 32 << left_shift;
422
0
  sum += aom_highbd_sad32x16_avg_avx2(src, src_stride, ref, ref_stride,
423
0
                                      second_pred);
424
0
  return sum;
425
0
}
426
427
unsigned int aom_highbd_sad32x64_avg_avx2(const uint8_t *src, int src_stride,
428
                                          const uint8_t *ref, int ref_stride,
429
0
                                          const uint8_t *second_pred) {
430
0
  const int left_shift = 5;
431
0
  uint32_t sum = aom_highbd_sad32x32_avg_avx2(src, src_stride, ref, ref_stride,
432
0
                                              second_pred);
433
0
  src += src_stride << left_shift;
434
0
  ref += ref_stride << left_shift;
435
0
  second_pred += 32 << left_shift;
436
0
  sum += aom_highbd_sad32x32_avg_avx2(src, src_stride, ref, ref_stride,
437
0
                                      second_pred);
438
0
  return sum;
439
0
}
440
441
#if !CONFIG_REALTIME_ONLY
442
unsigned int aom_highbd_sad64x16_avg_avx2(const uint8_t *src, int src_stride,
443
                                          const uint8_t *ref, int ref_stride,
444
0
                                          const uint8_t *second_pred) {
445
0
  __m256i sad = _mm256_setzero_si256();
446
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
447
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
448
0
  uint16_t *secp = CONVERT_TO_SHORTPTR(second_pred);
449
0
  const int left_shift = 1;
450
0
  int row_section = 0;
451
452
0
  while (row_section < 8) {
453
0
    sad64x2(srcp, src_stride, refp, ref_stride, secp, &sad);
454
0
    srcp += src_stride << left_shift;
455
0
    refp += ref_stride << left_shift;
456
0
    secp += 64 << left_shift;
457
0
    row_section += 1;
458
0
  }
459
0
  return get_sad_from_mm256_epi32(&sad);
460
0
}
461
#endif  // !CONFIG_REALTIME_ONLY
462
463
unsigned int aom_highbd_sad64x32_avg_avx2(const uint8_t *src, int src_stride,
464
                                          const uint8_t *ref, int ref_stride,
465
0
                                          const uint8_t *second_pred) {
466
0
  __m256i sad = _mm256_setzero_si256();
467
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
468
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
469
0
  uint16_t *secp = CONVERT_TO_SHORTPTR(second_pred);
470
0
  const int left_shift = 1;
471
0
  int row_section = 0;
472
473
0
  while (row_section < 16) {
474
0
    sad64x2(srcp, src_stride, refp, ref_stride, secp, &sad);
475
0
    srcp += src_stride << left_shift;
476
0
    refp += ref_stride << left_shift;
477
0
    secp += 64 << left_shift;
478
0
    row_section += 1;
479
0
  }
480
0
  return get_sad_from_mm256_epi32(&sad);
481
0
}
482
483
unsigned int aom_highbd_sad64x64_avg_avx2(const uint8_t *src, int src_stride,
484
                                          const uint8_t *ref, int ref_stride,
485
0
                                          const uint8_t *second_pred) {
486
0
  const int left_shift = 5;
487
0
  uint32_t sum = aom_highbd_sad64x32_avg_avx2(src, src_stride, ref, ref_stride,
488
0
                                              second_pred);
489
0
  src += src_stride << left_shift;
490
0
  ref += ref_stride << left_shift;
491
0
  second_pred += 64 << left_shift;
492
0
  sum += aom_highbd_sad64x32_avg_avx2(src, src_stride, ref, ref_stride,
493
0
                                      second_pred);
494
0
  return sum;
495
0
}
496
497
unsigned int aom_highbd_sad64x128_avg_avx2(const uint8_t *src, int src_stride,
498
                                           const uint8_t *ref, int ref_stride,
499
0
                                           const uint8_t *second_pred) {
500
0
  const int left_shift = 6;
501
0
  uint32_t sum = aom_highbd_sad64x64_avg_avx2(src, src_stride, ref, ref_stride,
502
0
                                              second_pred);
503
0
  src += src_stride << left_shift;
504
0
  ref += ref_stride << left_shift;
505
0
  second_pred += 64 << left_shift;
506
0
  sum += aom_highbd_sad64x64_avg_avx2(src, src_stride, ref, ref_stride,
507
0
                                      second_pred);
508
0
  return sum;
509
0
}
510
511
unsigned int aom_highbd_sad128x64_avg_avx2(const uint8_t *src, int src_stride,
512
                                           const uint8_t *ref, int ref_stride,
513
0
                                           const uint8_t *second_pred) {
514
0
  __m256i sad = _mm256_setzero_si256();
515
0
  uint16_t *srcp = CONVERT_TO_SHORTPTR(src);
516
0
  uint16_t *refp = CONVERT_TO_SHORTPTR(ref);
517
0
  uint16_t *secp = CONVERT_TO_SHORTPTR(second_pred);
518
0
  int row = 0;
519
0
  while (row < 64) {
520
0
    sad128x1(srcp, refp, secp, &sad);
521
0
    srcp += src_stride;
522
0
    refp += ref_stride;
523
0
    secp += 16 << 3;
524
0
    row += 1;
525
0
  }
526
0
  return get_sad_from_mm256_epi32(&sad);
527
0
}
528
529
unsigned int aom_highbd_sad128x128_avg_avx2(const uint8_t *src, int src_stride,
530
                                            const uint8_t *ref, int ref_stride,
531
0
                                            const uint8_t *second_pred) {
532
0
  unsigned int sum;
533
0
  const int left_shift = 6;
534
535
0
  sum = aom_highbd_sad128x64_avg_avx2(src, src_stride, ref, ref_stride,
536
0
                                      second_pred);
537
0
  src += src_stride << left_shift;
538
0
  ref += ref_stride << left_shift;
539
0
  second_pred += 128 << left_shift;
540
0
  sum += aom_highbd_sad128x64_avg_avx2(src, src_stride, ref, ref_stride,
541
0
                                       second_pred);
542
0
  return sum;
543
0
}
544
545
// SAD 4D
546
// Combine 4 __m256i input vectors  v to uint32_t result[4]
547
static inline void get_4d_sad_from_mm256_epi32(const __m256i *v,
548
0
                                               uint32_t *res) {
549
0
  __m256i u0, u1, u2, u3;
550
0
  const __m256i mask = _mm256_set1_epi64x(~0u);
551
0
  __m128i sad;
552
553
  // 8 32-bit summation
554
0
  u0 = _mm256_srli_si256(v[0], 4);
555
0
  u1 = _mm256_srli_si256(v[1], 4);
556
0
  u2 = _mm256_srli_si256(v[2], 4);
557
0
  u3 = _mm256_srli_si256(v[3], 4);
558
559
0
  u0 = _mm256_add_epi32(u0, v[0]);
560
0
  u1 = _mm256_add_epi32(u1, v[1]);
561
0
  u2 = _mm256_add_epi32(u2, v[2]);
562
0
  u3 = _mm256_add_epi32(u3, v[3]);
563
564
0
  u0 = _mm256_and_si256(u0, mask);
565
0
  u1 = _mm256_and_si256(u1, mask);
566
0
  u2 = _mm256_and_si256(u2, mask);
567
0
  u3 = _mm256_and_si256(u3, mask);
568
  // 4 32-bit summation, evenly positioned
569
570
0
  u1 = _mm256_slli_si256(u1, 4);
571
0
  u3 = _mm256_slli_si256(u3, 4);
572
573
0
  u0 = _mm256_or_si256(u0, u1);
574
0
  u2 = _mm256_or_si256(u2, u3);
575
  // 8 32-bit summation, interleaved
576
577
0
  u1 = _mm256_unpacklo_epi64(u0, u2);
578
0
  u3 = _mm256_unpackhi_epi64(u0, u2);
579
580
0
  u0 = _mm256_add_epi32(u1, u3);
581
0
  sad = _mm_add_epi32(_mm256_extractf128_si256(u0, 1),
582
0
                      _mm256_castsi256_si128(u0));
583
0
  _mm_storeu_si128((__m128i *)res, sad);
584
0
}
585
586
static void convert_pointers(const uint8_t *const ref8[],
587
0
                             const uint16_t *ref[]) {
588
0
  ref[0] = CONVERT_TO_SHORTPTR(ref8[0]);
589
0
  ref[1] = CONVERT_TO_SHORTPTR(ref8[1]);
590
0
  ref[2] = CONVERT_TO_SHORTPTR(ref8[2]);
591
0
  ref[3] = CONVERT_TO_SHORTPTR(ref8[3]);
592
0
}
593
594
0
static void init_sad(__m256i *s) {
595
0
  s[0] = _mm256_setzero_si256();
596
0
  s[1] = _mm256_setzero_si256();
597
0
  s[2] = _mm256_setzero_si256();
598
0
  s[3] = _mm256_setzero_si256();
599
0
}
600
601
static AOM_FORCE_INLINE void aom_highbd_sadMxNxD_avx2(
602
    int M, int N, int D, const uint8_t *src, int src_stride,
603
0
    const uint8_t *const ref_array[4], int ref_stride, uint32_t sad_array[4]) {
604
0
  __m256i sad_vec[4];
605
0
  const uint16_t *refp[4];
606
0
  const uint16_t *keep = CONVERT_TO_SHORTPTR(src);
607
0
  const uint16_t *srcp;
608
0
  const int shift_for_rows = (M < 128) + (M < 64);
609
0
  const int row_units = 1 << shift_for_rows;
610
0
  int i, r;
611
612
0
  init_sad(sad_vec);
613
0
  convert_pointers(ref_array, refp);
614
615
0
  for (i = 0; i < D; ++i) {
616
0
    srcp = keep;
617
0
    for (r = 0; r < N; r += row_units) {
618
0
      if (M == 128) {
619
0
        sad128x1(srcp, refp[i], NULL, &sad_vec[i]);
620
0
      } else if (M == 64) {
621
0
        sad64x2(srcp, src_stride, refp[i], ref_stride, NULL, &sad_vec[i]);
622
0
      } else if (M == 32) {
623
0
        sad32x4(srcp, src_stride, refp[i], ref_stride, 0, &sad_vec[i]);
624
0
      } else if (M == 16) {
625
0
        sad16x4(srcp, src_stride, refp[i], ref_stride, 0, &sad_vec[i]);
626
0
      } else {
627
0
        assert(0);
628
0
      }
629
0
      srcp += src_stride << shift_for_rows;
630
0
      refp[i] += ref_stride << shift_for_rows;
631
0
    }
632
0
  }
633
0
  get_4d_sad_from_mm256_epi32(sad_vec, sad_array);
634
0
}
635
636
#define HIGHBD_SAD_MXNX4D_AVX2(m, n)                                          \
637
  void aom_highbd_sad##m##x##n##x4d_avx2(                                     \
638
      const uint8_t *src, int src_stride, const uint8_t *const ref_array[4],  \
639
0
      int ref_stride, uint32_t sad_array[4]) {                                \
640
0
    aom_highbd_sadMxNxD_avx2(m, n, 4, src, src_stride, ref_array, ref_stride, \
641
0
                             sad_array);                                      \
642
0
  }
Unexecuted instantiation: aom_highbd_sad16x8x4d_avx2
Unexecuted instantiation: aom_highbd_sad16x16x4d_avx2
Unexecuted instantiation: aom_highbd_sad16x32x4d_avx2
Unexecuted instantiation: aom_highbd_sad32x16x4d_avx2
Unexecuted instantiation: aom_highbd_sad32x32x4d_avx2
Unexecuted instantiation: aom_highbd_sad32x64x4d_avx2
Unexecuted instantiation: aom_highbd_sad64x32x4d_avx2
Unexecuted instantiation: aom_highbd_sad64x64x4d_avx2
Unexecuted instantiation: aom_highbd_sad64x128x4d_avx2
Unexecuted instantiation: aom_highbd_sad128x64x4d_avx2
Unexecuted instantiation: aom_highbd_sad128x128x4d_avx2
Unexecuted instantiation: aom_highbd_sad16x4x4d_avx2
Unexecuted instantiation: aom_highbd_sad16x64x4d_avx2
Unexecuted instantiation: aom_highbd_sad32x8x4d_avx2
Unexecuted instantiation: aom_highbd_sad64x16x4d_avx2
643
#define HIGHBD_SAD_SKIP_MXNX4D_AVX2(m, n)                                    \
644
  void aom_highbd_sad_skip_##m##x##n##x4d_avx2(                              \
645
      const uint8_t *src, int src_stride, const uint8_t *const ref_array[4], \
646
0
      int ref_stride, uint32_t sad_array[4]) {                               \
647
0
    aom_highbd_sadMxNxD_avx2(m, (n / 2), 4, src, 2 * src_stride, ref_array,  \
648
0
                             2 * ref_stride, sad_array);                     \
649
0
    sad_array[0] <<= 1;                                                      \
650
0
    sad_array[1] <<= 1;                                                      \
651
0
    sad_array[2] <<= 1;                                                      \
652
0
    sad_array[3] <<= 1;                                                      \
653
0
  }
Unexecuted instantiation: aom_highbd_sad_skip_16x16x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_16x32x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_32x16x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_32x32x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_32x64x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_64x32x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_64x64x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_64x128x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_128x64x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_128x128x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_16x64x4d_avx2
Unexecuted instantiation: aom_highbd_sad_skip_64x16x4d_avx2
654
#define HIGHBD_SAD_MXNX3D_AVX2(m, n)                                          \
655
  void aom_highbd_sad##m##x##n##x3d_avx2(                                     \
656
      const uint8_t *src, int src_stride, const uint8_t *const ref_array[4],  \
657
0
      int ref_stride, uint32_t sad_array[4]) {                                \
658
0
    aom_highbd_sadMxNxD_avx2(m, n, 3, src, src_stride, ref_array, ref_stride, \
659
0
                             sad_array);                                      \
660
0
  }
Unexecuted instantiation: aom_highbd_sad16x8x3d_avx2
Unexecuted instantiation: aom_highbd_sad16x16x3d_avx2
Unexecuted instantiation: aom_highbd_sad16x32x3d_avx2
Unexecuted instantiation: aom_highbd_sad32x16x3d_avx2
Unexecuted instantiation: aom_highbd_sad32x32x3d_avx2
Unexecuted instantiation: aom_highbd_sad32x64x3d_avx2
Unexecuted instantiation: aom_highbd_sad64x32x3d_avx2
Unexecuted instantiation: aom_highbd_sad64x64x3d_avx2
Unexecuted instantiation: aom_highbd_sad64x128x3d_avx2
Unexecuted instantiation: aom_highbd_sad128x64x3d_avx2
Unexecuted instantiation: aom_highbd_sad128x128x3d_avx2
Unexecuted instantiation: aom_highbd_sad16x4x3d_avx2
Unexecuted instantiation: aom_highbd_sad16x64x3d_avx2
Unexecuted instantiation: aom_highbd_sad32x8x3d_avx2
Unexecuted instantiation: aom_highbd_sad64x16x3d_avx2
661
662
HIGHBD_SAD_MXNX4D_AVX2(16, 8)
663
HIGHBD_SAD_MXNX4D_AVX2(16, 16)
664
HIGHBD_SAD_MXNX4D_AVX2(16, 32)
665
666
HIGHBD_SAD_MXNX4D_AVX2(32, 16)
667
HIGHBD_SAD_MXNX4D_AVX2(32, 32)
668
HIGHBD_SAD_MXNX4D_AVX2(32, 64)
669
670
HIGHBD_SAD_MXNX4D_AVX2(64, 32)
671
HIGHBD_SAD_MXNX4D_AVX2(64, 64)
672
HIGHBD_SAD_MXNX4D_AVX2(64, 128)
673
674
HIGHBD_SAD_MXNX4D_AVX2(128, 64)
675
HIGHBD_SAD_MXNX4D_AVX2(128, 128)
676
677
#if !CONFIG_REALTIME_ONLY
678
HIGHBD_SAD_MXNX4D_AVX2(16, 4)
679
HIGHBD_SAD_MXNX4D_AVX2(16, 64)
680
HIGHBD_SAD_MXNX4D_AVX2(32, 8)
681
HIGHBD_SAD_MXNX4D_AVX2(64, 16)
682
#endif  // !CONFIG_REALTIME_ONLY
683
684
HIGHBD_SAD_SKIP_MXNX4D_AVX2(16, 16)
685
HIGHBD_SAD_SKIP_MXNX4D_AVX2(16, 32)
686
687
HIGHBD_SAD_SKIP_MXNX4D_AVX2(32, 16)
688
HIGHBD_SAD_SKIP_MXNX4D_AVX2(32, 32)
689
HIGHBD_SAD_SKIP_MXNX4D_AVX2(32, 64)
690
691
HIGHBD_SAD_SKIP_MXNX4D_AVX2(64, 32)
692
HIGHBD_SAD_SKIP_MXNX4D_AVX2(64, 64)
693
HIGHBD_SAD_SKIP_MXNX4D_AVX2(64, 128)
694
695
HIGHBD_SAD_SKIP_MXNX4D_AVX2(128, 64)
696
HIGHBD_SAD_SKIP_MXNX4D_AVX2(128, 128)
697
698
#if !CONFIG_REALTIME_ONLY
699
HIGHBD_SAD_SKIP_MXNX4D_AVX2(16, 64)
700
HIGHBD_SAD_SKIP_MXNX4D_AVX2(64, 16)
701
#endif  // !CONFIG_REALTIME_ONLY
702
703
HIGHBD_SAD_MXNX3D_AVX2(16, 8)
704
HIGHBD_SAD_MXNX3D_AVX2(16, 16)
705
HIGHBD_SAD_MXNX3D_AVX2(16, 32)
706
707
HIGHBD_SAD_MXNX3D_AVX2(32, 16)
708
HIGHBD_SAD_MXNX3D_AVX2(32, 32)
709
HIGHBD_SAD_MXNX3D_AVX2(32, 64)
710
711
HIGHBD_SAD_MXNX3D_AVX2(64, 32)
712
HIGHBD_SAD_MXNX3D_AVX2(64, 64)
713
HIGHBD_SAD_MXNX3D_AVX2(64, 128)
714
715
HIGHBD_SAD_MXNX3D_AVX2(128, 64)
716
HIGHBD_SAD_MXNX3D_AVX2(128, 128)
717
718
#if !CONFIG_REALTIME_ONLY
719
HIGHBD_SAD_MXNX3D_AVX2(16, 4)
720
HIGHBD_SAD_MXNX3D_AVX2(16, 64)
721
HIGHBD_SAD_MXNX3D_AVX2(32, 8)
722
HIGHBD_SAD_MXNX3D_AVX2(64, 16)
723
#endif  // !CONFIG_REALTIME_ONLY