Coverage Report

Created: 2026-09-07 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/av1/common/x86/cdef_block_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 "aom_dsp/aom_simd.h"
13
#define SIMD_FUNC(name) name##_avx2
14
#include "av1/common/cdef_block_simd.h"
15
16
/* partial A is a 16-bit vector of the form:
17
[x8 - - x1 | x16 - - x9] and partial B has the form:
18
[0  y1 - y7 | 0 y9 - y15].
19
This function computes (x1^2+y1^2)*C1 + (x2^2+y2^2)*C2 + ...
20
(x7^2+y2^7)*C7 + (x8^2+0^2)*C8 on each 128-bit lane. Here the C1..C8 constants
21
are in const1 and const2. */
22
static inline __m256i fold_mul_and_sum_avx2(__m256i *partiala,
23
                                            __m256i *partialb,
24
                                            const __m256i *const1,
25
57.7M
                                            const __m256i *const2) {
26
  // Mask used to shuffle the elements present in 256bit register.
27
57.7M
  static const int shuffle_reg_256bit[8] = { 0x0b0a0d0c, 0x07060908, 0x03020504,
28
57.7M
                                             0x0f0e0100, 0x0b0a0d0c, 0x07060908,
29
57.7M
                                             0x03020504, 0x0f0e0100 };
30
57.7M
  __m256i tmp;
31
  /* Reverse partial B. */
32
57.7M
  *partialb = _mm256_shuffle_epi8(
33
57.7M
      *partialb, _mm256_loadu_si256((const __m256i *)shuffle_reg_256bit));
34
35
  /* Interleave the x and y values of identical indices and pair x8 with 0. */
36
57.7M
  tmp = *partiala;
37
57.7M
  *partiala = _mm256_unpacklo_epi16(*partiala, *partialb);
38
57.7M
  *partialb = _mm256_unpackhi_epi16(tmp, *partialb);
39
40
  /* Square and add the corresponding x and y values. */
41
57.7M
  *partiala = _mm256_madd_epi16(*partiala, *partiala);
42
57.7M
  *partialb = _mm256_madd_epi16(*partialb, *partialb);
43
  /* Multiply by constant. */
44
57.7M
  *partiala = _mm256_mullo_epi32(*partiala, *const1);
45
57.7M
  *partialb = _mm256_mullo_epi32(*partialb, *const2);
46
  /* Sum all results. */
47
57.7M
  *partiala = _mm256_add_epi32(*partiala, *partialb);
48
57.7M
  return *partiala;
49
57.7M
}
50
51
static inline __m256i hsum4_avx2(__m256i *x0, __m256i *x1, __m256i *x2,
52
19.2M
                                 __m256i *x3) {
53
19.2M
  const __m256i t0 = _mm256_unpacklo_epi32(*x0, *x1);
54
19.2M
  const __m256i t1 = _mm256_unpacklo_epi32(*x2, *x3);
55
19.2M
  const __m256i t2 = _mm256_unpackhi_epi32(*x0, *x1);
56
19.2M
  const __m256i t3 = _mm256_unpackhi_epi32(*x2, *x3);
57
58
19.2M
  *x0 = _mm256_unpacklo_epi64(t0, t1);
59
19.2M
  *x1 = _mm256_unpackhi_epi64(t0, t1);
60
19.2M
  *x2 = _mm256_unpacklo_epi64(t2, t3);
61
19.2M
  *x3 = _mm256_unpackhi_epi64(t2, t3);
62
19.2M
  return _mm256_add_epi32(_mm256_add_epi32(*x0, *x1),
63
19.2M
                          _mm256_add_epi32(*x2, *x3));
64
19.2M
}
65
66
/* Computes cost for directions 0, 5, 6 and 7. We can call this function again
67
to compute the remaining directions. */
68
static inline __m256i compute_directions_avx2(__m256i *lines,
69
                                              int32_t cost_frist_8x8[4],
70
19.2M
                                              int32_t cost_second_8x8[4]) {
71
19.2M
  __m256i partial4a, partial4b, partial5a, partial5b, partial7a, partial7b;
72
19.2M
  __m256i partial6;
73
19.2M
  __m256i tmp;
74
  /* Partial sums for lines 0 and 1. */
75
19.2M
  partial4a = _mm256_slli_si256(lines[0], 14);
76
19.2M
  partial4b = _mm256_srli_si256(lines[0], 2);
77
19.2M
  partial4a = _mm256_add_epi16(partial4a, _mm256_slli_si256(lines[1], 12));
78
19.2M
  partial4b = _mm256_add_epi16(partial4b, _mm256_srli_si256(lines[1], 4));
79
19.2M
  tmp = _mm256_add_epi16(lines[0], lines[1]);
80
19.2M
  partial5a = _mm256_slli_si256(tmp, 10);
81
19.2M
  partial5b = _mm256_srli_si256(tmp, 6);
82
19.2M
  partial7a = _mm256_slli_si256(tmp, 4);
83
19.2M
  partial7b = _mm256_srli_si256(tmp, 12);
84
19.2M
  partial6 = tmp;
85
86
  /* Partial sums for lines 2 and 3. */
87
19.2M
  partial4a = _mm256_add_epi16(partial4a, _mm256_slli_si256(lines[2], 10));
88
19.2M
  partial4b = _mm256_add_epi16(partial4b, _mm256_srli_si256(lines[2], 6));
89
19.2M
  partial4a = _mm256_add_epi16(partial4a, _mm256_slli_si256(lines[3], 8));
90
19.2M
  partial4b = _mm256_add_epi16(partial4b, _mm256_srli_si256(lines[3], 8));
91
19.2M
  tmp = _mm256_add_epi16(lines[2], lines[3]);
92
19.2M
  partial5a = _mm256_add_epi16(partial5a, _mm256_slli_si256(tmp, 8));
93
19.2M
  partial5b = _mm256_add_epi16(partial5b, _mm256_srli_si256(tmp, 8));
94
19.2M
  partial7a = _mm256_add_epi16(partial7a, _mm256_slli_si256(tmp, 6));
95
19.2M
  partial7b = _mm256_add_epi16(partial7b, _mm256_srli_si256(tmp, 10));
96
19.2M
  partial6 = _mm256_add_epi16(partial6, tmp);
97
98
  /* Partial sums for lines 4 and 5. */
99
19.2M
  partial4a = _mm256_add_epi16(partial4a, _mm256_slli_si256(lines[4], 6));
100
19.2M
  partial4b = _mm256_add_epi16(partial4b, _mm256_srli_si256(lines[4], 10));
101
19.2M
  partial4a = _mm256_add_epi16(partial4a, _mm256_slli_si256(lines[5], 4));
102
19.2M
  partial4b = _mm256_add_epi16(partial4b, _mm256_srli_si256(lines[5], 12));
103
19.2M
  tmp = _mm256_add_epi16(lines[4], lines[5]);
104
19.2M
  partial5a = _mm256_add_epi16(partial5a, _mm256_slli_si256(tmp, 6));
105
19.2M
  partial5b = _mm256_add_epi16(partial5b, _mm256_srli_si256(tmp, 10));
106
19.2M
  partial7a = _mm256_add_epi16(partial7a, _mm256_slli_si256(tmp, 8));
107
19.2M
  partial7b = _mm256_add_epi16(partial7b, _mm256_srli_si256(tmp, 8));
108
19.2M
  partial6 = _mm256_add_epi16(partial6, tmp);
109
110
  /* Partial sums for lines 6 and 7. */
111
19.2M
  partial4a = _mm256_add_epi16(partial4a, _mm256_slli_si256(lines[6], 2));
112
19.2M
  partial4b = _mm256_add_epi16(partial4b, _mm256_srli_si256(lines[6], 14));
113
19.2M
  partial4a = _mm256_add_epi16(partial4a, lines[7]);
114
19.2M
  tmp = _mm256_add_epi16(lines[6], lines[7]);
115
19.2M
  partial5a = _mm256_add_epi16(partial5a, _mm256_slli_si256(tmp, 4));
116
19.2M
  partial5b = _mm256_add_epi16(partial5b, _mm256_srli_si256(tmp, 12));
117
19.2M
  partial7a = _mm256_add_epi16(partial7a, _mm256_slli_si256(tmp, 10));
118
19.2M
  partial7b = _mm256_add_epi16(partial7b, _mm256_srli_si256(tmp, 6));
119
19.2M
  partial6 = _mm256_add_epi16(partial6, tmp);
120
121
19.2M
  const __m256i const_reg_1 =
122
19.2M
      _mm256_set_epi32(210, 280, 420, 840, 210, 280, 420, 840);
123
19.2M
  const __m256i const_reg_2 =
124
19.2M
      _mm256_set_epi32(105, 120, 140, 168, 105, 120, 140, 168);
125
19.2M
  const __m256i const_reg_3 = _mm256_set_epi32(210, 420, 0, 0, 210, 420, 0, 0);
126
19.2M
  const __m256i const_reg_4 =
127
19.2M
      _mm256_set_epi32(105, 105, 105, 140, 105, 105, 105, 140);
128
129
  /* Compute costs in terms of partial sums. */
130
19.2M
  partial4a =
131
19.2M
      fold_mul_and_sum_avx2(&partial4a, &partial4b, &const_reg_1, &const_reg_2);
132
19.2M
  partial7a =
133
19.2M
      fold_mul_and_sum_avx2(&partial7a, &partial7b, &const_reg_3, &const_reg_4);
134
19.2M
  partial5a =
135
19.2M
      fold_mul_and_sum_avx2(&partial5a, &partial5b, &const_reg_3, &const_reg_4);
136
19.2M
  partial6 = _mm256_madd_epi16(partial6, partial6);
137
19.2M
  partial6 = _mm256_mullo_epi32(partial6, _mm256_set1_epi32(105));
138
139
19.2M
  partial4a = hsum4_avx2(&partial4a, &partial5a, &partial6, &partial7a);
140
19.2M
  _mm_storeu_si128((__m128i *)cost_frist_8x8,
141
19.2M
                   _mm256_castsi256_si128(partial4a));
142
19.2M
  _mm_storeu_si128((__m128i *)cost_second_8x8,
143
19.2M
                   _mm256_extractf128_si256(partial4a, 1));
144
145
19.2M
  return partial4a;
146
19.2M
}
147
148
/* transpose and reverse the order of the lines -- equivalent to a 90-degree
149
counter-clockwise rotation of the pixels. */
150
9.63M
static inline void array_reverse_transpose_8x8_avx2(__m256i *in, __m256i *res) {
151
9.63M
  const __m256i tr0_0 = _mm256_unpacklo_epi16(in[0], in[1]);
152
9.63M
  const __m256i tr0_1 = _mm256_unpacklo_epi16(in[2], in[3]);
153
9.63M
  const __m256i tr0_2 = _mm256_unpackhi_epi16(in[0], in[1]);
154
9.63M
  const __m256i tr0_3 = _mm256_unpackhi_epi16(in[2], in[3]);
155
9.63M
  const __m256i tr0_4 = _mm256_unpacklo_epi16(in[4], in[5]);
156
9.63M
  const __m256i tr0_5 = _mm256_unpacklo_epi16(in[6], in[7]);
157
9.63M
  const __m256i tr0_6 = _mm256_unpackhi_epi16(in[4], in[5]);
158
9.63M
  const __m256i tr0_7 = _mm256_unpackhi_epi16(in[6], in[7]);
159
160
9.63M
  const __m256i tr1_0 = _mm256_unpacklo_epi32(tr0_0, tr0_1);
161
9.63M
  const __m256i tr1_1 = _mm256_unpacklo_epi32(tr0_4, tr0_5);
162
9.63M
  const __m256i tr1_2 = _mm256_unpackhi_epi32(tr0_0, tr0_1);
163
9.63M
  const __m256i tr1_3 = _mm256_unpackhi_epi32(tr0_4, tr0_5);
164
9.63M
  const __m256i tr1_4 = _mm256_unpacklo_epi32(tr0_2, tr0_3);
165
9.63M
  const __m256i tr1_5 = _mm256_unpacklo_epi32(tr0_6, tr0_7);
166
9.63M
  const __m256i tr1_6 = _mm256_unpackhi_epi32(tr0_2, tr0_3);
167
9.63M
  const __m256i tr1_7 = _mm256_unpackhi_epi32(tr0_6, tr0_7);
168
169
9.63M
  res[7] = _mm256_unpacklo_epi64(tr1_0, tr1_1);
170
9.63M
  res[6] = _mm256_unpackhi_epi64(tr1_0, tr1_1);
171
9.63M
  res[5] = _mm256_unpacklo_epi64(tr1_2, tr1_3);
172
9.63M
  res[4] = _mm256_unpackhi_epi64(tr1_2, tr1_3);
173
9.63M
  res[3] = _mm256_unpacklo_epi64(tr1_4, tr1_5);
174
9.63M
  res[2] = _mm256_unpackhi_epi64(tr1_4, tr1_5);
175
9.63M
  res[1] = _mm256_unpacklo_epi64(tr1_6, tr1_7);
176
9.63M
  res[0] = _mm256_unpackhi_epi64(tr1_6, tr1_7);
177
9.63M
}
178
179
void cdef_find_dir_dual_avx2(const uint16_t *img1, const uint16_t *img2,
180
                             int stride, int32_t *var_out_1st,
181
                             int32_t *var_out_2nd, int coeff_shift,
182
9.61M
                             int *out_dir_1st_8x8, int *out_dir_2nd_8x8) {
183
9.61M
  int32_t cost_first_8x8[8];
184
9.61M
  int32_t cost_second_8x8[8];
185
  // Used to store the best cost for 2 8x8's.
186
9.61M
  int32_t best_cost[2] = { 0 };
187
  // Best direction for 2 8x8's.
188
9.61M
  int best_dir[2] = { 0 };
189
190
9.61M
  const __m128i const_coeff_shift_reg = _mm_cvtsi32_si128(coeff_shift);
191
9.61M
  const __m256i const_128_reg = _mm256_set1_epi16(128);
192
9.61M
  __m256i lines[8];
193
86.5M
  for (int i = 0; i < 8; i++) {
194
76.9M
    const __m128i src_1 = _mm_loadu_si128((const __m128i *)&img1[i * stride]);
195
76.9M
    const __m128i src_2 = _mm_loadu_si128((const __m128i *)&img2[i * stride]);
196
197
76.9M
    lines[i] = _mm256_insertf128_si256(_mm256_castsi128_si256(src_1), src_2, 1);
198
76.9M
    lines[i] = _mm256_sub_epi16(
199
76.9M
        _mm256_sra_epi16(lines[i], const_coeff_shift_reg), const_128_reg);
200
76.9M
  }
201
202
  /* Compute "mostly vertical" directions. */
203
9.61M
  const __m256i dir47 =
204
9.61M
      compute_directions_avx2(lines, cost_first_8x8 + 4, cost_second_8x8 + 4);
205
206
  /* Transpose and reverse the order of the lines. */
207
9.61M
  array_reverse_transpose_8x8_avx2(lines, lines);
208
209
  /* Compute "mostly horizontal" directions. */
210
9.61M
  const __m256i dir03 =
211
9.61M
      compute_directions_avx2(lines, cost_first_8x8, cost_second_8x8);
212
213
9.61M
  __m256i max = _mm256_max_epi32(dir03, dir47);
214
9.61M
  max =
215
9.61M
      _mm256_max_epi32(max, _mm256_or_si256(_mm256_srli_si256(max, 8),
216
9.61M
                                            _mm256_slli_si256(max, 16 - (8))));
217
9.61M
  max =
218
9.61M
      _mm256_max_epi32(max, _mm256_or_si256(_mm256_srli_si256(max, 4),
219
9.61M
                                            _mm256_slli_si256(max, 16 - (4))));
220
221
9.61M
  const __m128i first_8x8_output = _mm256_castsi256_si128(max);
222
9.61M
  const __m128i second_8x8_output = _mm256_extractf128_si256(max, 1);
223
9.61M
  const __m128i cmpeg_res_00 =
224
9.61M
      _mm_cmpeq_epi32(first_8x8_output, _mm256_castsi256_si128(dir47));
225
9.61M
  const __m128i cmpeg_res_01 =
226
9.61M
      _mm_cmpeq_epi32(first_8x8_output, _mm256_castsi256_si128(dir03));
227
9.61M
  const __m128i cmpeg_res_10 =
228
9.61M
      _mm_cmpeq_epi32(second_8x8_output, _mm256_extractf128_si256(dir47, 1));
229
9.61M
  const __m128i cmpeg_res_11 =
230
9.61M
      _mm_cmpeq_epi32(second_8x8_output, _mm256_extractf128_si256(dir03, 1));
231
9.61M
  const __m128i t_first_8x8 = _mm_packs_epi32(cmpeg_res_01, cmpeg_res_00);
232
9.61M
  const __m128i t_second_8x8 = _mm_packs_epi32(cmpeg_res_11, cmpeg_res_10);
233
234
9.61M
  best_cost[0] = _mm_cvtsi128_si32(_mm256_castsi256_si128(max));
235
9.61M
  best_cost[1] = _mm_cvtsi128_si32(second_8x8_output);
236
9.61M
  best_dir[0] = _mm_movemask_epi8(_mm_packs_epi16(t_first_8x8, t_first_8x8));
237
9.61M
  best_dir[0] =
238
9.61M
      get_msb(best_dir[0] ^ (best_dir[0] - 1));  // Count trailing zeros
239
9.61M
  best_dir[1] = _mm_movemask_epi8(_mm_packs_epi16(t_second_8x8, t_second_8x8));
240
9.61M
  best_dir[1] =
241
9.61M
      get_msb(best_dir[1] ^ (best_dir[1] - 1));  // Count trailing zeros
242
243
  /* Difference between the optimal variance and the variance along the
244
     orthogonal direction. Again, the sum(x^2) terms cancel out. */
245
9.61M
  *var_out_1st = best_cost[0] - cost_first_8x8[(best_dir[0] + 4) & 7];
246
9.61M
  *var_out_2nd = best_cost[1] - cost_second_8x8[(best_dir[1] + 4) & 7];
247
248
  /* We'd normally divide by 840, but dividing by 1024 is close enough
249
  for what we're going to do with this. */
250
9.61M
  *var_out_1st >>= 10;
251
9.61M
  *var_out_2nd >>= 10;
252
9.61M
  *out_dir_1st_8x8 = best_dir[0];
253
9.61M
  *out_dir_2nd_8x8 = best_dir[1];
254
9.61M
}
255
256
void cdef_copy_rect8_8bit_to_16bit_avx2(uint16_t *dst, int dstride,
257
                                        const uint8_t *src, int sstride,
258
612k
                                        int width, int height) {
259
612k
  int j = 0;
260
612k
  int remaining_width = width;
261
612k
  assert(height % 2 == 0);
262
612k
  assert(height > 0);
263
613k
  assert(width > 0);
264
265
  // Process multiple 32 pixels at a time.
266
613k
  if (remaining_width > 31) {
267
601k
    int i = 0;
268
9.27M
    do {
269
9.27M
      j = 0;
270
15.4M
      do {
271
15.4M
        __m128i row00 =
272
15.4M
            _mm_loadu_si128((const __m128i *)&src[(i + 0) * sstride + (j + 0)]);
273
15.4M
        __m128i row01 = _mm_loadu_si128(
274
15.4M
            (const __m128i *)&src[(i + 0) * sstride + (j + 16)]);
275
15.4M
        __m128i row10 =
276
15.4M
            _mm_loadu_si128((const __m128i *)&src[(i + 1) * sstride + (j + 0)]);
277
15.4M
        __m128i row11 = _mm_loadu_si128(
278
15.4M
            (const __m128i *)&src[(i + 1) * sstride + (j + 16)]);
279
15.4M
        _mm256_storeu_si256((__m256i *)&dst[(i + 0) * dstride + (j + 0)],
280
15.4M
                            _mm256_cvtepu8_epi16(row00));
281
15.4M
        _mm256_storeu_si256((__m256i *)&dst[(i + 0) * dstride + (j + 16)],
282
15.4M
                            _mm256_cvtepu8_epi16(row01));
283
15.4M
        _mm256_storeu_si256((__m256i *)&dst[(i + 1) * dstride + (j + 0)],
284
15.4M
                            _mm256_cvtepu8_epi16(row10));
285
15.4M
        _mm256_storeu_si256((__m256i *)&dst[(i + 1) * dstride + (j + 16)],
286
15.4M
                            _mm256_cvtepu8_epi16(row11));
287
15.4M
        j += 32;
288
15.4M
      } while (j <= width - 32);
289
9.27M
      i += 2;
290
9.27M
    } while (i < height);
291
601k
    remaining_width = width & 31;
292
601k
  }
293
294
  // Process 16 pixels at a time.
295
613k
  if (remaining_width > 15) {
296
49.9k
    int i = 0;
297
280k
    do {
298
280k
      __m128i row0 =
299
280k
          _mm_loadu_si128((const __m128i *)&src[(i + 0) * sstride + j]);
300
280k
      __m128i row1 =
301
280k
          _mm_loadu_si128((const __m128i *)&src[(i + 1) * sstride + j]);
302
280k
      _mm256_storeu_si256((__m256i *)&dst[(i + 0) * dstride + j],
303
280k
                          _mm256_cvtepu8_epi16(row0));
304
280k
      _mm256_storeu_si256((__m256i *)&dst[(i + 1) * dstride + j],
305
280k
                          _mm256_cvtepu8_epi16(row1));
306
280k
      i += 2;
307
280k
    } while (i < height);
308
49.9k
    remaining_width = width & 15;
309
49.9k
    j += 16;
310
49.9k
  }
311
312
  // Process 8 pixels at a time.
313
613k
  if (remaining_width > 7) {
314
434k
    int i = 0;
315
8.79M
    do {
316
8.79M
      __m128i row0 =
317
8.79M
          _mm_loadl_epi64((const __m128i *)&src[(i + 0) * sstride + j]);
318
8.79M
      __m128i row1 =
319
8.79M
          _mm_loadl_epi64((const __m128i *)&src[(i + 1) * sstride + j]);
320
8.79M
      _mm_storeu_si128((__m128i *)&dst[(i + 0) * dstride + j],
321
8.79M
                       _mm_unpacklo_epi8(row0, _mm_setzero_si128()));
322
8.79M
      _mm_storeu_si128((__m128i *)&dst[(i + 1) * dstride + j],
323
8.79M
                       _mm_unpacklo_epi8(row1, _mm_setzero_si128()));
324
8.79M
      i += 2;
325
8.79M
    } while (i < height);
326
434k
    remaining_width = width & 7;
327
434k
    j += 8;
328
434k
  }
329
330
  // Process 4 pixels at a time.
331
613k
  if (remaining_width > 3) {
332
10.3k
    int i = 0;
333
138k
    do {
334
138k
      __m128i row0 =
335
138k
          _mm_cvtsi32_si128(*((const int32_t *)&src[(i + 0) * sstride + j]));
336
138k
      __m128i row1 =
337
138k
          _mm_cvtsi32_si128(*((const int32_t *)&src[(i + 1) * sstride + j]));
338
138k
      _mm_storel_epi64((__m128i *)&dst[(i + 0) * dstride + j],
339
138k
                       _mm_unpacklo_epi8(row0, _mm_setzero_si128()));
340
138k
      _mm_storel_epi64((__m128i *)&dst[(i + 1) * dstride + j],
341
138k
                       _mm_unpacklo_epi8(row1, _mm_setzero_si128()));
342
138k
      i += 2;
343
138k
    } while (i < height);
344
10.3k
    remaining_width = width & 3;
345
10.3k
    j += 4;
346
10.3k
  }
347
348
  // Process the remaining pixels.
349
613k
  if (remaining_width) {
350
0
    for (int i = 0; i < height; i++) {
351
0
      for (int k = j; k < width; k++) {
352
0
        dst[i * dstride + k] = src[i * sstride + k];
353
0
      }
354
0
    }
355
0
  }
356
613k
}