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/sse_avx2.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2018, 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 <smmintrin.h>
13
#include <immintrin.h>
14
15
#include "config/aom_config.h"
16
#include "config/aom_dsp_rtcd.h"
17
18
#include "aom_ports/mem.h"
19
#include "aom_dsp/x86/synonyms.h"
20
#include "aom_dsp/x86/synonyms_avx2.h"
21
22
static inline void sse_w32_avx2(__m256i *sum, const uint8_t *a,
23
0
                                const uint8_t *b) {
24
0
  const __m256i v_a0 = yy_loadu_256(a);
25
0
  const __m256i v_b0 = yy_loadu_256(b);
26
0
  const __m256i zero = _mm256_setzero_si256();
27
0
  const __m256i v_a00_w = _mm256_unpacklo_epi8(v_a0, zero);
28
0
  const __m256i v_a01_w = _mm256_unpackhi_epi8(v_a0, zero);
29
0
  const __m256i v_b00_w = _mm256_unpacklo_epi8(v_b0, zero);
30
0
  const __m256i v_b01_w = _mm256_unpackhi_epi8(v_b0, zero);
31
0
  const __m256i v_d00_w = _mm256_sub_epi16(v_a00_w, v_b00_w);
32
0
  const __m256i v_d01_w = _mm256_sub_epi16(v_a01_w, v_b01_w);
33
0
  *sum = _mm256_add_epi32(*sum, _mm256_madd_epi16(v_d00_w, v_d00_w));
34
0
  *sum = _mm256_add_epi32(*sum, _mm256_madd_epi16(v_d01_w, v_d01_w));
35
0
}
36
37
0
static inline int64_t summary_all_avx2(const __m256i *sum_all) {
38
0
  int64_t sum;
39
0
  __m256i zero = _mm256_setzero_si256();
40
0
  const __m256i sum0_4x64 = _mm256_unpacklo_epi32(*sum_all, zero);
41
0
  const __m256i sum1_4x64 = _mm256_unpackhi_epi32(*sum_all, zero);
42
0
  const __m256i sum_4x64 = _mm256_add_epi64(sum0_4x64, sum1_4x64);
43
0
  const __m128i sum_2x64 = _mm_add_epi64(_mm256_castsi256_si128(sum_4x64),
44
0
                                         _mm256_extracti128_si256(sum_4x64, 1));
45
0
  const __m128i sum_1x64 = _mm_add_epi64(sum_2x64, _mm_srli_si128(sum_2x64, 8));
46
0
  xx_storel_64(&sum, sum_1x64);
47
0
  return sum;
48
0
}
49
50
#if CONFIG_AV1_HIGHBITDEPTH
51
0
static inline void summary_32_avx2(const __m256i *sum32, __m256i *sum) {
52
0
  const __m256i sum0_4x64 =
53
0
      _mm256_cvtepu32_epi64(_mm256_castsi256_si128(*sum32));
54
0
  const __m256i sum1_4x64 =
55
0
      _mm256_cvtepu32_epi64(_mm256_extracti128_si256(*sum32, 1));
56
0
  const __m256i sum_4x64 = _mm256_add_epi64(sum0_4x64, sum1_4x64);
57
0
  *sum = _mm256_add_epi64(*sum, sum_4x64);
58
0
}
59
60
0
static inline int64_t summary_4x64_avx2(const __m256i sum_4x64) {
61
0
  int64_t sum;
62
0
  const __m128i sum_2x64 = _mm_add_epi64(_mm256_castsi256_si128(sum_4x64),
63
0
                                         _mm256_extracti128_si256(sum_4x64, 1));
64
0
  const __m128i sum_1x64 = _mm_add_epi64(sum_2x64, _mm_srli_si128(sum_2x64, 8));
65
66
0
  xx_storel_64(&sum, sum_1x64);
67
0
  return sum;
68
0
}
69
#endif
70
71
static inline void sse_w4x4_avx2(const uint8_t *a, int a_stride,
72
0
                                 const uint8_t *b, int b_stride, __m256i *sum) {
73
0
  const __m128i v_a0 = xx_loadl_32(a);
74
0
  const __m128i v_a1 = xx_loadl_32(a + a_stride);
75
0
  const __m128i v_a2 = xx_loadl_32(a + a_stride * 2);
76
0
  const __m128i v_a3 = xx_loadl_32(a + a_stride * 3);
77
0
  const __m128i v_b0 = xx_loadl_32(b);
78
0
  const __m128i v_b1 = xx_loadl_32(b + b_stride);
79
0
  const __m128i v_b2 = xx_loadl_32(b + b_stride * 2);
80
0
  const __m128i v_b3 = xx_loadl_32(b + b_stride * 3);
81
0
  const __m128i v_a0123 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(v_a0, v_a1),
82
0
                                             _mm_unpacklo_epi32(v_a2, v_a3));
83
0
  const __m128i v_b0123 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(v_b0, v_b1),
84
0
                                             _mm_unpacklo_epi32(v_b2, v_b3));
85
0
  const __m256i v_a_w = _mm256_cvtepu8_epi16(v_a0123);
86
0
  const __m256i v_b_w = _mm256_cvtepu8_epi16(v_b0123);
87
0
  const __m256i v_d_w = _mm256_sub_epi16(v_a_w, v_b_w);
88
0
  *sum = _mm256_add_epi32(*sum, _mm256_madd_epi16(v_d_w, v_d_w));
89
0
}
90
91
static inline void sse_w8x2_avx2(const uint8_t *a, int a_stride,
92
0
                                 const uint8_t *b, int b_stride, __m256i *sum) {
93
0
  const __m128i v_a0 = xx_loadl_64(a);
94
0
  const __m128i v_a1 = xx_loadl_64(a + a_stride);
95
0
  const __m128i v_b0 = xx_loadl_64(b);
96
0
  const __m128i v_b1 = xx_loadl_64(b + b_stride);
97
0
  const __m256i v_a_w = _mm256_cvtepu8_epi16(_mm_unpacklo_epi64(v_a0, v_a1));
98
0
  const __m256i v_b_w = _mm256_cvtepu8_epi16(_mm_unpacklo_epi64(v_b0, v_b1));
99
0
  const __m256i v_d_w = _mm256_sub_epi16(v_a_w, v_b_w);
100
0
  *sum = _mm256_add_epi32(*sum, _mm256_madd_epi16(v_d_w, v_d_w));
101
0
}
102
103
int64_t aom_sse_avx2(const uint8_t *a, int a_stride, const uint8_t *b,
104
0
                     int b_stride, int width, int height) {
105
0
  int32_t y = 0;
106
0
  int64_t sse = 0;
107
0
  __m256i sum = _mm256_setzero_si256();
108
0
  __m256i zero = _mm256_setzero_si256();
109
0
  switch (width) {
110
0
    case 4:
111
0
      do {
112
0
        sse_w4x4_avx2(a, a_stride, b, b_stride, &sum);
113
0
        a += a_stride << 2;
114
0
        b += b_stride << 2;
115
0
        y += 4;
116
0
      } while (y < height);
117
0
      sse = summary_all_avx2(&sum);
118
0
      break;
119
0
    case 8:
120
0
      do {
121
0
        sse_w8x2_avx2(a, a_stride, b, b_stride, &sum);
122
0
        a += a_stride << 1;
123
0
        b += b_stride << 1;
124
0
        y += 2;
125
0
      } while (y < height);
126
0
      sse = summary_all_avx2(&sum);
127
0
      break;
128
0
    case 16:
129
0
      do {
130
0
        const __m128i v_a0 = xx_loadu_128(a);
131
0
        const __m128i v_a1 = xx_loadu_128(a + a_stride);
132
0
        const __m128i v_b0 = xx_loadu_128(b);
133
0
        const __m128i v_b1 = xx_loadu_128(b + b_stride);
134
0
        const __m256i v_a =
135
0
            _mm256_insertf128_si256(_mm256_castsi128_si256(v_a0), v_a1, 0x01);
136
0
        const __m256i v_b =
137
0
            _mm256_insertf128_si256(_mm256_castsi128_si256(v_b0), v_b1, 0x01);
138
0
        const __m256i v_al = _mm256_unpacklo_epi8(v_a, zero);
139
0
        const __m256i v_au = _mm256_unpackhi_epi8(v_a, zero);
140
0
        const __m256i v_bl = _mm256_unpacklo_epi8(v_b, zero);
141
0
        const __m256i v_bu = _mm256_unpackhi_epi8(v_b, zero);
142
0
        const __m256i v_asub = _mm256_sub_epi16(v_al, v_bl);
143
0
        const __m256i v_bsub = _mm256_sub_epi16(v_au, v_bu);
144
0
        const __m256i temp =
145
0
            _mm256_add_epi32(_mm256_madd_epi16(v_asub, v_asub),
146
0
                             _mm256_madd_epi16(v_bsub, v_bsub));
147
0
        sum = _mm256_add_epi32(sum, temp);
148
0
        a += a_stride << 1;
149
0
        b += b_stride << 1;
150
0
        y += 2;
151
0
      } while (y < height);
152
0
      sse = summary_all_avx2(&sum);
153
0
      break;
154
0
    case 32:
155
0
      do {
156
0
        sse_w32_avx2(&sum, a, b);
157
0
        a += a_stride;
158
0
        b += b_stride;
159
0
        y += 1;
160
0
      } while (y < height);
161
0
      sse = summary_all_avx2(&sum);
162
0
      break;
163
0
    case 64:
164
0
      do {
165
0
        sse_w32_avx2(&sum, a, b);
166
0
        sse_w32_avx2(&sum, a + 32, b + 32);
167
0
        a += a_stride;
168
0
        b += b_stride;
169
0
        y += 1;
170
0
      } while (y < height);
171
0
      sse = summary_all_avx2(&sum);
172
0
      break;
173
0
    case 128:
174
0
      do {
175
0
        sse_w32_avx2(&sum, a, b);
176
0
        sse_w32_avx2(&sum, a + 32, b + 32);
177
0
        sse_w32_avx2(&sum, a + 64, b + 64);
178
0
        sse_w32_avx2(&sum, a + 96, b + 96);
179
0
        a += a_stride;
180
0
        b += b_stride;
181
0
        y += 1;
182
0
      } while (y < height);
183
0
      sse = summary_all_avx2(&sum);
184
0
      break;
185
0
    default:
186
0
      if ((width & 0x07) == 0) {
187
0
        do {
188
0
          int i = 0;
189
0
          do {
190
0
            sse_w8x2_avx2(a + i, a_stride, b + i, b_stride, &sum);
191
0
            i += 8;
192
0
          } while (i < width);
193
0
          a += a_stride << 1;
194
0
          b += b_stride << 1;
195
0
          y += 2;
196
0
        } while (y < height);
197
0
      } else {
198
0
        do {
199
0
          int i = 0;
200
0
          do {
201
0
            sse_w8x2_avx2(a + i, a_stride, b + i, b_stride, &sum);
202
0
            const uint8_t *a2 = a + i + (a_stride << 1);
203
0
            const uint8_t *b2 = b + i + (b_stride << 1);
204
0
            sse_w8x2_avx2(a2, a_stride, b2, b_stride, &sum);
205
0
            i += 8;
206
0
          } while (i + 4 < width);
207
0
          sse_w4x4_avx2(a + i, a_stride, b + i, b_stride, &sum);
208
0
          a += a_stride << 2;
209
0
          b += b_stride << 2;
210
0
          y += 4;
211
0
        } while (y < height);
212
0
      }
213
0
      sse = summary_all_avx2(&sum);
214
0
      break;
215
0
  }
216
217
0
  return sse;
218
0
}
219
220
#if CONFIG_AV1_HIGHBITDEPTH
221
static inline void highbd_sse_w16_avx2(__m256i *sum, const uint16_t *a,
222
0
                                       const uint16_t *b) {
223
0
  const __m256i v_a_w = yy_loadu_256(a);
224
0
  const __m256i v_b_w = yy_loadu_256(b);
225
0
  const __m256i v_d_w = _mm256_sub_epi16(v_a_w, v_b_w);
226
0
  *sum = _mm256_add_epi32(*sum, _mm256_madd_epi16(v_d_w, v_d_w));
227
0
}
228
229
static inline void highbd_sse_w4x4_avx2(__m256i *sum, const uint16_t *a,
230
                                        int a_stride, const uint16_t *b,
231
0
                                        int b_stride) {
232
0
  const __m128i v_a0 = xx_loadl_64(a);
233
0
  const __m128i v_a1 = xx_loadl_64(a + a_stride);
234
0
  const __m128i v_a2 = xx_loadl_64(a + a_stride * 2);
235
0
  const __m128i v_a3 = xx_loadl_64(a + a_stride * 3);
236
0
  const __m128i v_b0 = xx_loadl_64(b);
237
0
  const __m128i v_b1 = xx_loadl_64(b + b_stride);
238
0
  const __m128i v_b2 = xx_loadl_64(b + b_stride * 2);
239
0
  const __m128i v_b3 = xx_loadl_64(b + b_stride * 3);
240
0
  const __m256i v_a_w = yy_set_m128i(_mm_unpacklo_epi64(v_a0, v_a1),
241
0
                                     _mm_unpacklo_epi64(v_a2, v_a3));
242
0
  const __m256i v_b_w = yy_set_m128i(_mm_unpacklo_epi64(v_b0, v_b1),
243
0
                                     _mm_unpacklo_epi64(v_b2, v_b3));
244
0
  const __m256i v_d_w = _mm256_sub_epi16(v_a_w, v_b_w);
245
0
  *sum = _mm256_add_epi32(*sum, _mm256_madd_epi16(v_d_w, v_d_w));
246
0
}
247
248
static inline void highbd_sse_w8x2_avx2(__m256i *sum, const uint16_t *a,
249
                                        int a_stride, const uint16_t *b,
250
0
                                        int b_stride) {
251
0
  const __m256i v_a_w = yy_loadu2_128(a + a_stride, a);
252
0
  const __m256i v_b_w = yy_loadu2_128(b + b_stride, b);
253
0
  const __m256i v_d_w = _mm256_sub_epi16(v_a_w, v_b_w);
254
0
  *sum = _mm256_add_epi32(*sum, _mm256_madd_epi16(v_d_w, v_d_w));
255
0
}
256
257
int64_t aom_highbd_sse_avx2(const uint8_t *a8, int a_stride, const uint8_t *b8,
258
0
                            int b_stride, int width, int height) {
259
0
  int32_t y = 0;
260
0
  int64_t sse = 0;
261
0
  uint16_t *a = CONVERT_TO_SHORTPTR(a8);
262
0
  uint16_t *b = CONVERT_TO_SHORTPTR(b8);
263
0
  __m256i sum = _mm256_setzero_si256();
264
0
  switch (width) {
265
0
    case 4:
266
0
      do {
267
0
        highbd_sse_w4x4_avx2(&sum, a, a_stride, b, b_stride);
268
0
        a += a_stride << 2;
269
0
        b += b_stride << 2;
270
0
        y += 4;
271
0
      } while (y < height);
272
0
      sse = summary_all_avx2(&sum);
273
0
      break;
274
0
    case 8:
275
0
      do {
276
0
        highbd_sse_w8x2_avx2(&sum, a, a_stride, b, b_stride);
277
0
        a += a_stride << 1;
278
0
        b += b_stride << 1;
279
0
        y += 2;
280
0
      } while (y < height);
281
0
      sse = summary_all_avx2(&sum);
282
0
      break;
283
0
    case 16:
284
0
      do {
285
0
        highbd_sse_w16_avx2(&sum, a, b);
286
0
        a += a_stride;
287
0
        b += b_stride;
288
0
        y += 1;
289
0
      } while (y < height);
290
0
      sse = summary_all_avx2(&sum);
291
0
      break;
292
0
    case 32:
293
0
      do {
294
0
        int l = 0;
295
0
        __m256i sum32 = _mm256_setzero_si256();
296
0
        do {
297
0
          highbd_sse_w16_avx2(&sum32, a, b);
298
0
          highbd_sse_w16_avx2(&sum32, a + 16, b + 16);
299
0
          a += a_stride;
300
0
          b += b_stride;
301
0
          l += 1;
302
0
        } while (l < 64 && l < (height - y));
303
0
        summary_32_avx2(&sum32, &sum);
304
0
        y += 64;
305
0
      } while (y < height);
306
0
      sse = summary_4x64_avx2(sum);
307
0
      break;
308
0
    case 64:
309
0
      do {
310
0
        int l = 0;
311
0
        __m256i sum32 = _mm256_setzero_si256();
312
0
        do {
313
0
          highbd_sse_w16_avx2(&sum32, a, b);
314
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 1, b + 16 * 1);
315
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 2, b + 16 * 2);
316
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 3, b + 16 * 3);
317
0
          a += a_stride;
318
0
          b += b_stride;
319
0
          l += 1;
320
0
        } while (l < 32 && l < (height - y));
321
0
        summary_32_avx2(&sum32, &sum);
322
0
        y += 32;
323
0
      } while (y < height);
324
0
      sse = summary_4x64_avx2(sum);
325
0
      break;
326
0
    case 128:
327
0
      do {
328
0
        int l = 0;
329
0
        __m256i sum32 = _mm256_setzero_si256();
330
0
        do {
331
0
          highbd_sse_w16_avx2(&sum32, a, b);
332
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 1, b + 16 * 1);
333
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 2, b + 16 * 2);
334
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 3, b + 16 * 3);
335
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 4, b + 16 * 4);
336
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 5, b + 16 * 5);
337
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 6, b + 16 * 6);
338
0
          highbd_sse_w16_avx2(&sum32, a + 16 * 7, b + 16 * 7);
339
0
          a += a_stride;
340
0
          b += b_stride;
341
0
          l += 1;
342
0
        } while (l < 16 && l < (height - y));
343
0
        summary_32_avx2(&sum32, &sum);
344
0
        y += 16;
345
0
      } while (y < height);
346
0
      sse = summary_4x64_avx2(sum);
347
0
      break;
348
0
    default:
349
0
      if (width & 0x7) {
350
0
        do {
351
0
          int i = 0;
352
0
          __m256i sum32 = _mm256_setzero_si256();
353
0
          do {
354
0
            highbd_sse_w8x2_avx2(&sum32, a + i, a_stride, b + i, b_stride);
355
0
            const uint16_t *a2 = a + i + (a_stride << 1);
356
0
            const uint16_t *b2 = b + i + (b_stride << 1);
357
0
            highbd_sse_w8x2_avx2(&sum32, a2, a_stride, b2, b_stride);
358
0
            i += 8;
359
0
          } while (i + 4 < width);
360
0
          highbd_sse_w4x4_avx2(&sum32, a + i, a_stride, b + i, b_stride);
361
0
          summary_32_avx2(&sum32, &sum);
362
0
          a += a_stride << 2;
363
0
          b += b_stride << 2;
364
0
          y += 4;
365
0
        } while (y < height);
366
0
      } else {
367
0
        do {
368
0
          int l = 0;
369
0
          __m256i sum32 = _mm256_setzero_si256();
370
0
          do {
371
0
            int i = 0;
372
0
            do {
373
0
              highbd_sse_w8x2_avx2(&sum32, a + i, a_stride, b + i, b_stride);
374
0
              i += 8;
375
0
            } while (i < width);
376
0
            a += a_stride << 1;
377
0
            b += b_stride << 1;
378
0
            l += 2;
379
0
          } while (l < 8 && l < (height - y));
380
0
          summary_32_avx2(&sum32, &sum);
381
0
          y += 8;
382
0
        } while (y < height);
383
0
      }
384
0
      sse = summary_4x64_avx2(sum);
385
0
      break;
386
0
  }
387
0
  return sse;
388
0
}
389
#endif  // CONFIG_AV1_HIGHBITDEPTH