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_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_dsp_rtcd.h"
15
#include "aom/aom_integer.h"
16
#include "aom_dsp/x86/bitdepth_conversion_avx2.h"
17
#include "aom_dsp/x86/synonyms_avx2.h"
18
#include "aom_ports/mem.h"
19
20
static inline void sign_extend_16bit_to_32bit_avx2(__m256i in, __m256i zero,
21
                                                   __m256i *out_lo,
22
0
                                                   __m256i *out_hi) {
23
0
  const __m256i sign_bits = _mm256_cmpgt_epi16(zero, in);
24
0
  *out_lo = _mm256_unpacklo_epi16(in, sign_bits);
25
0
  *out_hi = _mm256_unpackhi_epi16(in, sign_bits);
26
0
}
27
28
0
static void hadamard_col8x2_avx2(__m256i *in, int iter) {
29
0
  __m256i a0 = in[0];
30
0
  __m256i a1 = in[1];
31
0
  __m256i a2 = in[2];
32
0
  __m256i a3 = in[3];
33
0
  __m256i a4 = in[4];
34
0
  __m256i a5 = in[5];
35
0
  __m256i a6 = in[6];
36
0
  __m256i a7 = in[7];
37
38
0
  __m256i b0 = _mm256_add_epi16(a0, a1);
39
0
  __m256i b1 = _mm256_sub_epi16(a0, a1);
40
0
  __m256i b2 = _mm256_add_epi16(a2, a3);
41
0
  __m256i b3 = _mm256_sub_epi16(a2, a3);
42
0
  __m256i b4 = _mm256_add_epi16(a4, a5);
43
0
  __m256i b5 = _mm256_sub_epi16(a4, a5);
44
0
  __m256i b6 = _mm256_add_epi16(a6, a7);
45
0
  __m256i b7 = _mm256_sub_epi16(a6, a7);
46
47
0
  a0 = _mm256_add_epi16(b0, b2);
48
0
  a1 = _mm256_add_epi16(b1, b3);
49
0
  a2 = _mm256_sub_epi16(b0, b2);
50
0
  a3 = _mm256_sub_epi16(b1, b3);
51
0
  a4 = _mm256_add_epi16(b4, b6);
52
0
  a5 = _mm256_add_epi16(b5, b7);
53
0
  a6 = _mm256_sub_epi16(b4, b6);
54
0
  a7 = _mm256_sub_epi16(b5, b7);
55
56
0
  if (iter == 0) {
57
0
    b0 = _mm256_add_epi16(a0, a4);
58
0
    b7 = _mm256_add_epi16(a1, a5);
59
0
    b3 = _mm256_add_epi16(a2, a6);
60
0
    b4 = _mm256_add_epi16(a3, a7);
61
0
    b2 = _mm256_sub_epi16(a0, a4);
62
0
    b6 = _mm256_sub_epi16(a1, a5);
63
0
    b1 = _mm256_sub_epi16(a2, a6);
64
0
    b5 = _mm256_sub_epi16(a3, a7);
65
66
0
    a0 = _mm256_unpacklo_epi16(b0, b1);
67
0
    a1 = _mm256_unpacklo_epi16(b2, b3);
68
0
    a2 = _mm256_unpackhi_epi16(b0, b1);
69
0
    a3 = _mm256_unpackhi_epi16(b2, b3);
70
0
    a4 = _mm256_unpacklo_epi16(b4, b5);
71
0
    a5 = _mm256_unpacklo_epi16(b6, b7);
72
0
    a6 = _mm256_unpackhi_epi16(b4, b5);
73
0
    a7 = _mm256_unpackhi_epi16(b6, b7);
74
75
0
    b0 = _mm256_unpacklo_epi32(a0, a1);
76
0
    b1 = _mm256_unpacklo_epi32(a4, a5);
77
0
    b2 = _mm256_unpackhi_epi32(a0, a1);
78
0
    b3 = _mm256_unpackhi_epi32(a4, a5);
79
0
    b4 = _mm256_unpacklo_epi32(a2, a3);
80
0
    b5 = _mm256_unpacklo_epi32(a6, a7);
81
0
    b6 = _mm256_unpackhi_epi32(a2, a3);
82
0
    b7 = _mm256_unpackhi_epi32(a6, a7);
83
84
0
    in[0] = _mm256_unpacklo_epi64(b0, b1);
85
0
    in[1] = _mm256_unpackhi_epi64(b0, b1);
86
0
    in[2] = _mm256_unpacklo_epi64(b2, b3);
87
0
    in[3] = _mm256_unpackhi_epi64(b2, b3);
88
0
    in[4] = _mm256_unpacklo_epi64(b4, b5);
89
0
    in[5] = _mm256_unpackhi_epi64(b4, b5);
90
0
    in[6] = _mm256_unpacklo_epi64(b6, b7);
91
0
    in[7] = _mm256_unpackhi_epi64(b6, b7);
92
0
  } else {
93
0
    in[0] = _mm256_add_epi16(a0, a4);
94
0
    in[7] = _mm256_add_epi16(a1, a5);
95
0
    in[3] = _mm256_add_epi16(a2, a6);
96
0
    in[4] = _mm256_add_epi16(a3, a7);
97
0
    in[2] = _mm256_sub_epi16(a0, a4);
98
0
    in[6] = _mm256_sub_epi16(a1, a5);
99
0
    in[1] = _mm256_sub_epi16(a2, a6);
100
0
    in[5] = _mm256_sub_epi16(a3, a7);
101
0
  }
102
0
}
103
104
void aom_hadamard_lp_8x8_dual_avx2(const int16_t *src_diff,
105
0
                                   ptrdiff_t src_stride, int16_t *coeff) {
106
0
  __m256i src[8];
107
0
  src[0] = _mm256_loadu_si256((const __m256i *)src_diff);
108
0
  src[1] = _mm256_loadu_si256((const __m256i *)(src_diff += src_stride));
109
0
  src[2] = _mm256_loadu_si256((const __m256i *)(src_diff += src_stride));
110
0
  src[3] = _mm256_loadu_si256((const __m256i *)(src_diff += src_stride));
111
0
  src[4] = _mm256_loadu_si256((const __m256i *)(src_diff += src_stride));
112
0
  src[5] = _mm256_loadu_si256((const __m256i *)(src_diff += src_stride));
113
0
  src[6] = _mm256_loadu_si256((const __m256i *)(src_diff += src_stride));
114
0
  src[7] = _mm256_loadu_si256((const __m256i *)(src_diff + src_stride));
115
116
0
  hadamard_col8x2_avx2(src, 0);
117
0
  hadamard_col8x2_avx2(src, 1);
118
119
0
  _mm256_storeu_si256((__m256i *)coeff,
120
0
                      _mm256_permute2x128_si256(src[0], src[1], 0x20));
121
0
  coeff += 16;
122
0
  _mm256_storeu_si256((__m256i *)coeff,
123
0
                      _mm256_permute2x128_si256(src[2], src[3], 0x20));
124
0
  coeff += 16;
125
0
  _mm256_storeu_si256((__m256i *)coeff,
126
0
                      _mm256_permute2x128_si256(src[4], src[5], 0x20));
127
0
  coeff += 16;
128
0
  _mm256_storeu_si256((__m256i *)coeff,
129
0
                      _mm256_permute2x128_si256(src[6], src[7], 0x20));
130
0
  coeff += 16;
131
0
  _mm256_storeu_si256((__m256i *)coeff,
132
0
                      _mm256_permute2x128_si256(src[0], src[1], 0x31));
133
0
  coeff += 16;
134
0
  _mm256_storeu_si256((__m256i *)coeff,
135
0
                      _mm256_permute2x128_si256(src[2], src[3], 0x31));
136
0
  coeff += 16;
137
0
  _mm256_storeu_si256((__m256i *)coeff,
138
0
                      _mm256_permute2x128_si256(src[4], src[5], 0x31));
139
0
  coeff += 16;
140
0
  _mm256_storeu_si256((__m256i *)coeff,
141
0
                      _mm256_permute2x128_si256(src[6], src[7], 0x31));
142
0
}
143
144
static inline void hadamard_16x16_avx2(const int16_t *src_diff,
145
                                       ptrdiff_t src_stride, tran_low_t *coeff,
146
0
                                       int is_final) {
147
0
  DECLARE_ALIGNED(32, int16_t, temp_coeff[16 * 16]);
148
0
  int16_t *t_coeff = temp_coeff;
149
0
  int16_t *coeff16 = (int16_t *)coeff;
150
0
  int idx;
151
0
  for (idx = 0; idx < 2; ++idx) {
152
0
    const int16_t *src_ptr = src_diff + idx * 8 * src_stride;
153
0
    aom_hadamard_lp_8x8_dual_avx2(src_ptr, src_stride,
154
0
                                  t_coeff + (idx * 64 * 2));
155
0
  }
156
157
0
  for (idx = 0; idx < 64; idx += 16) {
158
0
    const __m256i coeff0 = _mm256_loadu_si256((const __m256i *)t_coeff);
159
0
    const __m256i coeff1 = _mm256_loadu_si256((const __m256i *)(t_coeff + 64));
160
0
    const __m256i coeff2 = _mm256_loadu_si256((const __m256i *)(t_coeff + 128));
161
0
    const __m256i coeff3 = _mm256_loadu_si256((const __m256i *)(t_coeff + 192));
162
163
0
    __m256i b0 = _mm256_add_epi16(coeff0, coeff1);
164
0
    __m256i b1 = _mm256_sub_epi16(coeff0, coeff1);
165
0
    __m256i b2 = _mm256_add_epi16(coeff2, coeff3);
166
0
    __m256i b3 = _mm256_sub_epi16(coeff2, coeff3);
167
168
0
    b0 = _mm256_srai_epi16(b0, 1);
169
0
    b1 = _mm256_srai_epi16(b1, 1);
170
0
    b2 = _mm256_srai_epi16(b2, 1);
171
0
    b3 = _mm256_srai_epi16(b3, 1);
172
0
    if (is_final) {
173
0
      store_tran_low(_mm256_add_epi16(b0, b2), coeff);
174
0
      store_tran_low(_mm256_add_epi16(b1, b3), coeff + 64);
175
0
      store_tran_low(_mm256_sub_epi16(b0, b2), coeff + 128);
176
0
      store_tran_low(_mm256_sub_epi16(b1, b3), coeff + 192);
177
0
      coeff += 16;
178
0
    } else {
179
0
      _mm256_storeu_si256((__m256i *)coeff16, _mm256_add_epi16(b0, b2));
180
0
      _mm256_storeu_si256((__m256i *)(coeff16 + 64), _mm256_add_epi16(b1, b3));
181
0
      _mm256_storeu_si256((__m256i *)(coeff16 + 128), _mm256_sub_epi16(b0, b2));
182
0
      _mm256_storeu_si256((__m256i *)(coeff16 + 192), _mm256_sub_epi16(b1, b3));
183
0
      coeff16 += 16;
184
0
    }
185
0
    t_coeff += 16;
186
0
  }
187
0
}
188
189
void aom_hadamard_16x16_avx2(const int16_t *src_diff, ptrdiff_t src_stride,
190
0
                             tran_low_t *coeff) {
191
0
  hadamard_16x16_avx2(src_diff, src_stride, coeff, 1);
192
0
}
193
194
void aom_hadamard_lp_16x16_avx2(const int16_t *src_diff, ptrdiff_t src_stride,
195
0
                                int16_t *coeff) {
196
0
  int16_t *t_coeff = coeff;
197
0
  for (int idx = 0; idx < 2; ++idx) {
198
0
    const int16_t *src_ptr = src_diff + idx * 8 * src_stride;
199
0
    aom_hadamard_lp_8x8_dual_avx2(src_ptr, src_stride,
200
0
                                  t_coeff + (idx * 64 * 2));
201
0
  }
202
203
0
  for (int idx = 0; idx < 64; idx += 16) {
204
0
    const __m256i coeff0 = _mm256_loadu_si256((const __m256i *)t_coeff);
205
0
    const __m256i coeff1 = _mm256_loadu_si256((const __m256i *)(t_coeff + 64));
206
0
    const __m256i coeff2 = _mm256_loadu_si256((const __m256i *)(t_coeff + 128));
207
0
    const __m256i coeff3 = _mm256_loadu_si256((const __m256i *)(t_coeff + 192));
208
209
0
    __m256i b0 = _mm256_add_epi16(coeff0, coeff1);
210
0
    __m256i b1 = _mm256_sub_epi16(coeff0, coeff1);
211
0
    __m256i b2 = _mm256_add_epi16(coeff2, coeff3);
212
0
    __m256i b3 = _mm256_sub_epi16(coeff2, coeff3);
213
214
0
    b0 = _mm256_srai_epi16(b0, 1);
215
0
    b1 = _mm256_srai_epi16(b1, 1);
216
0
    b2 = _mm256_srai_epi16(b2, 1);
217
0
    b3 = _mm256_srai_epi16(b3, 1);
218
0
    _mm256_storeu_si256((__m256i *)coeff, _mm256_add_epi16(b0, b2));
219
0
    _mm256_storeu_si256((__m256i *)(coeff + 64), _mm256_add_epi16(b1, b3));
220
0
    _mm256_storeu_si256((__m256i *)(coeff + 128), _mm256_sub_epi16(b0, b2));
221
0
    _mm256_storeu_si256((__m256i *)(coeff + 192), _mm256_sub_epi16(b1, b3));
222
0
    coeff += 16;
223
0
    t_coeff += 16;
224
0
  }
225
0
}
226
227
void aom_hadamard_32x32_avx2(const int16_t *src_diff, ptrdiff_t src_stride,
228
0
                             tran_low_t *coeff) {
229
  // For high bitdepths, it is unnecessary to store_tran_low
230
  // (mult/unpack/store), then load_tran_low (load/pack) the same memory in the
231
  // next stage.  Output to an intermediate buffer first, then store_tran_low()
232
  // in the final stage.
233
0
  DECLARE_ALIGNED(32, int16_t, temp_coeff[32 * 32]);
234
0
  int16_t *t_coeff = temp_coeff;
235
0
  int idx;
236
0
  __m256i coeff0_lo, coeff1_lo, coeff2_lo, coeff3_lo, b0_lo, b1_lo, b2_lo,
237
0
      b3_lo;
238
0
  __m256i coeff0_hi, coeff1_hi, coeff2_hi, coeff3_hi, b0_hi, b1_hi, b2_hi,
239
0
      b3_hi;
240
0
  __m256i b0, b1, b2, b3;
241
0
  const __m256i zero = _mm256_setzero_si256();
242
0
  for (idx = 0; idx < 4; ++idx) {
243
    // src_diff: 9 bit, dynamic range [-255, 255]
244
0
    const int16_t *src_ptr =
245
0
        src_diff + (idx >> 1) * 16 * src_stride + (idx & 0x01) * 16;
246
0
    hadamard_16x16_avx2(src_ptr, src_stride,
247
0
                        (tran_low_t *)(t_coeff + idx * 256), 0);
248
0
  }
249
250
0
  for (idx = 0; idx < 256; idx += 16) {
251
0
    const __m256i coeff0 = _mm256_loadu_si256((const __m256i *)t_coeff);
252
0
    const __m256i coeff1 = _mm256_loadu_si256((const __m256i *)(t_coeff + 256));
253
0
    const __m256i coeff2 = _mm256_loadu_si256((const __m256i *)(t_coeff + 512));
254
0
    const __m256i coeff3 = _mm256_loadu_si256((const __m256i *)(t_coeff + 768));
255
256
    // Sign extend 16 bit to 32 bit.
257
0
    sign_extend_16bit_to_32bit_avx2(coeff0, zero, &coeff0_lo, &coeff0_hi);
258
0
    sign_extend_16bit_to_32bit_avx2(coeff1, zero, &coeff1_lo, &coeff1_hi);
259
0
    sign_extend_16bit_to_32bit_avx2(coeff2, zero, &coeff2_lo, &coeff2_hi);
260
0
    sign_extend_16bit_to_32bit_avx2(coeff3, zero, &coeff3_lo, &coeff3_hi);
261
262
0
    b0_lo = _mm256_add_epi32(coeff0_lo, coeff1_lo);
263
0
    b0_hi = _mm256_add_epi32(coeff0_hi, coeff1_hi);
264
265
0
    b1_lo = _mm256_sub_epi32(coeff0_lo, coeff1_lo);
266
0
    b1_hi = _mm256_sub_epi32(coeff0_hi, coeff1_hi);
267
268
0
    b2_lo = _mm256_add_epi32(coeff2_lo, coeff3_lo);
269
0
    b2_hi = _mm256_add_epi32(coeff2_hi, coeff3_hi);
270
271
0
    b3_lo = _mm256_sub_epi32(coeff2_lo, coeff3_lo);
272
0
    b3_hi = _mm256_sub_epi32(coeff2_hi, coeff3_hi);
273
274
0
    b0_lo = _mm256_srai_epi32(b0_lo, 2);
275
0
    b1_lo = _mm256_srai_epi32(b1_lo, 2);
276
0
    b2_lo = _mm256_srai_epi32(b2_lo, 2);
277
0
    b3_lo = _mm256_srai_epi32(b3_lo, 2);
278
279
0
    b0_hi = _mm256_srai_epi32(b0_hi, 2);
280
0
    b1_hi = _mm256_srai_epi32(b1_hi, 2);
281
0
    b2_hi = _mm256_srai_epi32(b2_hi, 2);
282
0
    b3_hi = _mm256_srai_epi32(b3_hi, 2);
283
284
0
    b0 = _mm256_packs_epi32(b0_lo, b0_hi);
285
0
    b1 = _mm256_packs_epi32(b1_lo, b1_hi);
286
0
    b2 = _mm256_packs_epi32(b2_lo, b2_hi);
287
0
    b3 = _mm256_packs_epi32(b3_lo, b3_hi);
288
289
0
    store_tran_low(_mm256_add_epi16(b0, b2), coeff);
290
0
    store_tran_low(_mm256_add_epi16(b1, b3), coeff + 256);
291
0
    store_tran_low(_mm256_sub_epi16(b0, b2), coeff + 512);
292
0
    store_tran_low(_mm256_sub_epi16(b1, b3), coeff + 768);
293
294
0
    coeff += 16;
295
0
    t_coeff += 16;
296
0
  }
297
0
}
298
299
#if CONFIG_AV1_HIGHBITDEPTH
300
0
static void highbd_hadamard_col8_avx2(__m256i *in, int iter) {
301
0
  __m256i a0 = in[0];
302
0
  __m256i a1 = in[1];
303
0
  __m256i a2 = in[2];
304
0
  __m256i a3 = in[3];
305
0
  __m256i a4 = in[4];
306
0
  __m256i a5 = in[5];
307
0
  __m256i a6 = in[6];
308
0
  __m256i a7 = in[7];
309
310
0
  __m256i b0 = _mm256_add_epi32(a0, a1);
311
0
  __m256i b1 = _mm256_sub_epi32(a0, a1);
312
0
  __m256i b2 = _mm256_add_epi32(a2, a3);
313
0
  __m256i b3 = _mm256_sub_epi32(a2, a3);
314
0
  __m256i b4 = _mm256_add_epi32(a4, a5);
315
0
  __m256i b5 = _mm256_sub_epi32(a4, a5);
316
0
  __m256i b6 = _mm256_add_epi32(a6, a7);
317
0
  __m256i b7 = _mm256_sub_epi32(a6, a7);
318
319
0
  a0 = _mm256_add_epi32(b0, b2);
320
0
  a1 = _mm256_add_epi32(b1, b3);
321
0
  a2 = _mm256_sub_epi32(b0, b2);
322
0
  a3 = _mm256_sub_epi32(b1, b3);
323
0
  a4 = _mm256_add_epi32(b4, b6);
324
0
  a5 = _mm256_add_epi32(b5, b7);
325
0
  a6 = _mm256_sub_epi32(b4, b6);
326
0
  a7 = _mm256_sub_epi32(b5, b7);
327
328
0
  if (iter == 0) {
329
0
    b0 = _mm256_add_epi32(a0, a4);
330
0
    b7 = _mm256_add_epi32(a1, a5);
331
0
    b3 = _mm256_add_epi32(a2, a6);
332
0
    b4 = _mm256_add_epi32(a3, a7);
333
0
    b2 = _mm256_sub_epi32(a0, a4);
334
0
    b6 = _mm256_sub_epi32(a1, a5);
335
0
    b1 = _mm256_sub_epi32(a2, a6);
336
0
    b5 = _mm256_sub_epi32(a3, a7);
337
338
0
    a0 = _mm256_unpacklo_epi32(b0, b1);
339
0
    a1 = _mm256_unpacklo_epi32(b2, b3);
340
0
    a2 = _mm256_unpackhi_epi32(b0, b1);
341
0
    a3 = _mm256_unpackhi_epi32(b2, b3);
342
0
    a4 = _mm256_unpacklo_epi32(b4, b5);
343
0
    a5 = _mm256_unpacklo_epi32(b6, b7);
344
0
    a6 = _mm256_unpackhi_epi32(b4, b5);
345
0
    a7 = _mm256_unpackhi_epi32(b6, b7);
346
347
0
    b0 = _mm256_unpacklo_epi64(a0, a1);
348
0
    b1 = _mm256_unpacklo_epi64(a4, a5);
349
0
    b2 = _mm256_unpackhi_epi64(a0, a1);
350
0
    b3 = _mm256_unpackhi_epi64(a4, a5);
351
0
    b4 = _mm256_unpacklo_epi64(a2, a3);
352
0
    b5 = _mm256_unpacklo_epi64(a6, a7);
353
0
    b6 = _mm256_unpackhi_epi64(a2, a3);
354
0
    b7 = _mm256_unpackhi_epi64(a6, a7);
355
356
0
    in[0] = _mm256_permute2x128_si256(b0, b1, 0x20);
357
0
    in[1] = _mm256_permute2x128_si256(b0, b1, 0x31);
358
0
    in[2] = _mm256_permute2x128_si256(b2, b3, 0x20);
359
0
    in[3] = _mm256_permute2x128_si256(b2, b3, 0x31);
360
0
    in[4] = _mm256_permute2x128_si256(b4, b5, 0x20);
361
0
    in[5] = _mm256_permute2x128_si256(b4, b5, 0x31);
362
0
    in[6] = _mm256_permute2x128_si256(b6, b7, 0x20);
363
0
    in[7] = _mm256_permute2x128_si256(b6, b7, 0x31);
364
0
  } else {
365
0
    in[0] = _mm256_add_epi32(a0, a4);
366
0
    in[7] = _mm256_add_epi32(a1, a5);
367
0
    in[3] = _mm256_add_epi32(a2, a6);
368
0
    in[4] = _mm256_add_epi32(a3, a7);
369
0
    in[2] = _mm256_sub_epi32(a0, a4);
370
0
    in[6] = _mm256_sub_epi32(a1, a5);
371
0
    in[1] = _mm256_sub_epi32(a2, a6);
372
0
    in[5] = _mm256_sub_epi32(a3, a7);
373
0
  }
374
0
}
375
376
void aom_highbd_hadamard_8x8_avx2(const int16_t *src_diff, ptrdiff_t src_stride,
377
0
                                  tran_low_t *coeff) {
378
0
  __m128i src16[8];
379
0
  __m256i src32[8];
380
381
0
  src16[0] = _mm_loadu_si128((const __m128i *)src_diff);
382
0
  src16[1] = _mm_loadu_si128((const __m128i *)(src_diff += src_stride));
383
0
  src16[2] = _mm_loadu_si128((const __m128i *)(src_diff += src_stride));
384
0
  src16[3] = _mm_loadu_si128((const __m128i *)(src_diff += src_stride));
385
0
  src16[4] = _mm_loadu_si128((const __m128i *)(src_diff += src_stride));
386
0
  src16[5] = _mm_loadu_si128((const __m128i *)(src_diff += src_stride));
387
0
  src16[6] = _mm_loadu_si128((const __m128i *)(src_diff += src_stride));
388
0
  src16[7] = _mm_loadu_si128((const __m128i *)(src_diff + src_stride));
389
390
0
  src32[0] = _mm256_cvtepi16_epi32(src16[0]);
391
0
  src32[1] = _mm256_cvtepi16_epi32(src16[1]);
392
0
  src32[2] = _mm256_cvtepi16_epi32(src16[2]);
393
0
  src32[3] = _mm256_cvtepi16_epi32(src16[3]);
394
0
  src32[4] = _mm256_cvtepi16_epi32(src16[4]);
395
0
  src32[5] = _mm256_cvtepi16_epi32(src16[5]);
396
0
  src32[6] = _mm256_cvtepi16_epi32(src16[6]);
397
0
  src32[7] = _mm256_cvtepi16_epi32(src16[7]);
398
399
0
  highbd_hadamard_col8_avx2(src32, 0);
400
0
  highbd_hadamard_col8_avx2(src32, 1);
401
402
0
  _mm256_storeu_si256((__m256i *)coeff, src32[0]);
403
0
  coeff += 8;
404
0
  _mm256_storeu_si256((__m256i *)coeff, src32[1]);
405
0
  coeff += 8;
406
0
  _mm256_storeu_si256((__m256i *)coeff, src32[2]);
407
0
  coeff += 8;
408
0
  _mm256_storeu_si256((__m256i *)coeff, src32[3]);
409
0
  coeff += 8;
410
0
  _mm256_storeu_si256((__m256i *)coeff, src32[4]);
411
0
  coeff += 8;
412
0
  _mm256_storeu_si256((__m256i *)coeff, src32[5]);
413
0
  coeff += 8;
414
0
  _mm256_storeu_si256((__m256i *)coeff, src32[6]);
415
0
  coeff += 8;
416
0
  _mm256_storeu_si256((__m256i *)coeff, src32[7]);
417
0
}
418
419
void aom_highbd_hadamard_16x16_avx2(const int16_t *src_diff,
420
0
                                    ptrdiff_t src_stride, tran_low_t *coeff) {
421
0
  int idx;
422
0
  tran_low_t *t_coeff = coeff;
423
0
  for (idx = 0; idx < 4; ++idx) {
424
0
    const int16_t *src_ptr =
425
0
        src_diff + (idx >> 1) * 8 * src_stride + (idx & 0x01) * 8;
426
0
    aom_highbd_hadamard_8x8_avx2(src_ptr, src_stride, t_coeff + idx * 64);
427
0
  }
428
429
0
  for (idx = 0; idx < 64; idx += 8) {
430
0
    __m256i coeff0 = _mm256_loadu_si256((const __m256i *)t_coeff);
431
0
    __m256i coeff1 = _mm256_loadu_si256((const __m256i *)(t_coeff + 64));
432
0
    __m256i coeff2 = _mm256_loadu_si256((const __m256i *)(t_coeff + 128));
433
0
    __m256i coeff3 = _mm256_loadu_si256((const __m256i *)(t_coeff + 192));
434
435
0
    __m256i b0 = _mm256_add_epi32(coeff0, coeff1);
436
0
    __m256i b1 = _mm256_sub_epi32(coeff0, coeff1);
437
0
    __m256i b2 = _mm256_add_epi32(coeff2, coeff3);
438
0
    __m256i b3 = _mm256_sub_epi32(coeff2, coeff3);
439
440
0
    b0 = _mm256_srai_epi32(b0, 1);
441
0
    b1 = _mm256_srai_epi32(b1, 1);
442
0
    b2 = _mm256_srai_epi32(b2, 1);
443
0
    b3 = _mm256_srai_epi32(b3, 1);
444
445
0
    coeff0 = _mm256_add_epi32(b0, b2);
446
0
    coeff1 = _mm256_add_epi32(b1, b3);
447
0
    coeff2 = _mm256_sub_epi32(b0, b2);
448
0
    coeff3 = _mm256_sub_epi32(b1, b3);
449
450
0
    _mm256_storeu_si256((__m256i *)coeff, coeff0);
451
0
    _mm256_storeu_si256((__m256i *)(coeff + 64), coeff1);
452
0
    _mm256_storeu_si256((__m256i *)(coeff + 128), coeff2);
453
0
    _mm256_storeu_si256((__m256i *)(coeff + 192), coeff3);
454
455
0
    coeff += 8;
456
0
    t_coeff += 8;
457
0
  }
458
0
}
459
460
void aom_highbd_hadamard_32x32_avx2(const int16_t *src_diff,
461
0
                                    ptrdiff_t src_stride, tran_low_t *coeff) {
462
0
  int idx;
463
0
  tran_low_t *t_coeff = coeff;
464
0
  for (idx = 0; idx < 4; ++idx) {
465
0
    const int16_t *src_ptr =
466
0
        src_diff + (idx >> 1) * 16 * src_stride + (idx & 0x01) * 16;
467
0
    aom_highbd_hadamard_16x16_avx2(src_ptr, src_stride, t_coeff + idx * 256);
468
0
  }
469
470
0
  for (idx = 0; idx < 256; idx += 8) {
471
0
    __m256i coeff0 = _mm256_loadu_si256((const __m256i *)t_coeff);
472
0
    __m256i coeff1 = _mm256_loadu_si256((const __m256i *)(t_coeff + 256));
473
0
    __m256i coeff2 = _mm256_loadu_si256((const __m256i *)(t_coeff + 512));
474
0
    __m256i coeff3 = _mm256_loadu_si256((const __m256i *)(t_coeff + 768));
475
476
0
    __m256i b0 = _mm256_add_epi32(coeff0, coeff1);
477
0
    __m256i b1 = _mm256_sub_epi32(coeff0, coeff1);
478
0
    __m256i b2 = _mm256_add_epi32(coeff2, coeff3);
479
0
    __m256i b3 = _mm256_sub_epi32(coeff2, coeff3);
480
481
0
    b0 = _mm256_srai_epi32(b0, 2);
482
0
    b1 = _mm256_srai_epi32(b1, 2);
483
0
    b2 = _mm256_srai_epi32(b2, 2);
484
0
    b3 = _mm256_srai_epi32(b3, 2);
485
486
0
    coeff0 = _mm256_add_epi32(b0, b2);
487
0
    coeff1 = _mm256_add_epi32(b1, b3);
488
0
    coeff2 = _mm256_sub_epi32(b0, b2);
489
0
    coeff3 = _mm256_sub_epi32(b1, b3);
490
491
0
    _mm256_storeu_si256((__m256i *)coeff, coeff0);
492
0
    _mm256_storeu_si256((__m256i *)(coeff + 256), coeff1);
493
0
    _mm256_storeu_si256((__m256i *)(coeff + 512), coeff2);
494
0
    _mm256_storeu_si256((__m256i *)(coeff + 768), coeff3);
495
496
0
    coeff += 8;
497
0
    t_coeff += 8;
498
0
  }
499
0
}
500
#endif  // CONFIG_AV1_HIGHBITDEPTH
501
502
0
int aom_satd_avx2(const tran_low_t *coeff, int length) {
503
0
  __m256i accum = _mm256_setzero_si256();
504
0
  int i;
505
506
0
  for (i = 0; i < length; i += 8, coeff += 8) {
507
0
    const __m256i src_line = _mm256_loadu_si256((const __m256i *)coeff);
508
0
    const __m256i abs = _mm256_abs_epi32(src_line);
509
0
    accum = _mm256_add_epi32(accum, abs);
510
0
  }
511
512
0
  {  // 32 bit horizontal add
513
0
    const __m256i a = _mm256_srli_si256(accum, 8);
514
0
    const __m256i b = _mm256_add_epi32(accum, a);
515
0
    const __m256i c = _mm256_srli_epi64(b, 32);
516
0
    const __m256i d = _mm256_add_epi32(b, c);
517
0
    const __m128i accum_128 = _mm_add_epi32(_mm256_castsi256_si128(d),
518
0
                                            _mm256_extractf128_si256(d, 1));
519
0
    return _mm_cvtsi128_si32(accum_128);
520
0
  }
521
0
}
522
523
0
int aom_satd_lp_avx2(const int16_t *coeff, int length) {
524
0
  const __m256i one = _mm256_set1_epi16(1);
525
0
  __m256i accum = _mm256_setzero_si256();
526
527
0
  for (int i = 0; i < length; i += 16) {
528
0
    const __m256i src_line = _mm256_loadu_si256((const __m256i *)coeff);
529
0
    const __m256i abs = _mm256_abs_epi16(src_line);
530
0
    const __m256i sum = _mm256_madd_epi16(abs, one);
531
0
    accum = _mm256_add_epi32(accum, sum);
532
0
    coeff += 16;
533
0
  }
534
535
0
  {  // 32 bit horizontal add
536
0
    const __m256i a = _mm256_srli_si256(accum, 8);
537
0
    const __m256i b = _mm256_add_epi32(accum, a);
538
0
    const __m256i c = _mm256_srli_epi64(b, 32);
539
0
    const __m256i d = _mm256_add_epi32(b, c);
540
0
    const __m128i accum_128 = _mm_add_epi32(_mm256_castsi256_si128(d),
541
0
                                            _mm256_extractf128_si256(d, 1));
542
0
    return _mm_cvtsi128_si32(accum_128);
543
0
  }
544
0
}
545
546
void aom_avg_8x8_quad_avx2(const uint8_t *s, int p, int x16_idx, int y16_idx,
547
0
                           int *avg) {
548
0
  const uint8_t *s_y0 = s + y16_idx * p + x16_idx;
549
0
  const uint8_t *s_y1 = s_y0 + 8 * p;
550
0
  __m256i sum0, sum1, s0, s1, s2, s3, u0;
551
0
  u0 = _mm256_setzero_si256();
552
0
  s0 = _mm256_sad_epu8(yy_loadu2_128(s_y1, s_y0), u0);
553
0
  s1 = _mm256_sad_epu8(yy_loadu2_128(s_y1 + p, s_y0 + p), u0);
554
0
  s2 = _mm256_sad_epu8(yy_loadu2_128(s_y1 + 2 * p, s_y0 + 2 * p), u0);
555
0
  s3 = _mm256_sad_epu8(yy_loadu2_128(s_y1 + 3 * p, s_y0 + 3 * p), u0);
556
0
  sum0 = _mm256_add_epi16(s0, s1);
557
0
  sum1 = _mm256_add_epi16(s2, s3);
558
0
  s0 = _mm256_sad_epu8(yy_loadu2_128(s_y1 + 4 * p, s_y0 + 4 * p), u0);
559
0
  s1 = _mm256_sad_epu8(yy_loadu2_128(s_y1 + 5 * p, s_y0 + 5 * p), u0);
560
0
  s2 = _mm256_sad_epu8(yy_loadu2_128(s_y1 + 6 * p, s_y0 + 6 * p), u0);
561
0
  s3 = _mm256_sad_epu8(yy_loadu2_128(s_y1 + 7 * p, s_y0 + 7 * p), u0);
562
0
  sum0 = _mm256_add_epi16(sum0, _mm256_add_epi16(s0, s1));
563
0
  sum1 = _mm256_add_epi16(sum1, _mm256_add_epi16(s2, s3));
564
0
  sum0 = _mm256_add_epi16(sum0, sum1);
565
566
  // (avg + 32) >> 6
567
0
  __m256i rounding = _mm256_set1_epi32(32);
568
0
  sum0 = _mm256_add_epi32(sum0, rounding);
569
0
  sum0 = _mm256_srli_epi32(sum0, 6);
570
0
  __m128i lo = _mm256_castsi256_si128(sum0);
571
0
  __m128i hi = _mm256_extracti128_si256(sum0, 1);
572
0
  avg[0] = _mm_cvtsi128_si32(lo);
573
0
  avg[1] = _mm_extract_epi32(lo, 2);
574
0
  avg[2] = _mm_cvtsi128_si32(hi);
575
0
  avg[3] = _mm_extract_epi32(hi, 2);
576
0
}
577
578
void aom_int_pro_row_avx2(int16_t *hbuf, const uint8_t *ref,
579
                          const int ref_stride, const int width,
580
0
                          const int height, int norm_factor) {
581
  // SIMD implementation assumes width and height to be multiple of 16 and 2
582
  // respectively. For any odd width or height, SIMD support needs to be added.
583
0
  assert(width % 16 == 0 && height % 2 == 0);
584
585
0
  if (width % 32 == 0) {
586
0
    const __m256i zero = _mm256_setzero_si256();
587
0
    for (int wd = 0; wd < width; wd += 32) {
588
0
      const uint8_t *ref_tmp = ref + wd;
589
0
      int16_t *hbuf_tmp = hbuf + wd;
590
0
      __m256i s0 = zero;
591
0
      __m256i s1 = zero;
592
0
      int idx = 0;
593
0
      do {
594
0
        __m256i src_line = _mm256_loadu_si256((const __m256i *)ref_tmp);
595
0
        __m256i t0 = _mm256_unpacklo_epi8(src_line, zero);
596
0
        __m256i t1 = _mm256_unpackhi_epi8(src_line, zero);
597
0
        s0 = _mm256_add_epi16(s0, t0);
598
0
        s1 = _mm256_add_epi16(s1, t1);
599
0
        ref_tmp += ref_stride;
600
601
0
        src_line = _mm256_loadu_si256((const __m256i *)ref_tmp);
602
0
        t0 = _mm256_unpacklo_epi8(src_line, zero);
603
0
        t1 = _mm256_unpackhi_epi8(src_line, zero);
604
0
        s0 = _mm256_add_epi16(s0, t0);
605
0
        s1 = _mm256_add_epi16(s1, t1);
606
0
        ref_tmp += ref_stride;
607
0
        idx += 2;
608
0
      } while (idx < height);
609
0
      s0 = _mm256_srai_epi16(s0, norm_factor);
610
0
      s1 = _mm256_srai_epi16(s1, norm_factor);
611
0
      _mm_storeu_si128((__m128i *)(hbuf_tmp), _mm256_castsi256_si128(s0));
612
0
      _mm_storeu_si128((__m128i *)(hbuf_tmp + 8), _mm256_castsi256_si128(s1));
613
0
      _mm_storeu_si128((__m128i *)(hbuf_tmp + 16),
614
0
                       _mm256_extractf128_si256(s0, 1));
615
0
      _mm_storeu_si128((__m128i *)(hbuf_tmp + 24),
616
0
                       _mm256_extractf128_si256(s1, 1));
617
0
    }
618
0
  } else if (width % 16 == 0) {
619
0
    aom_int_pro_row_sse2(hbuf, ref, ref_stride, width, height, norm_factor);
620
0
  }
621
0
}
622
623
static inline void load_from_src_buf(const uint8_t *ref1, __m256i *src,
624
0
                                     const int stride) {
625
0
  src[0] = _mm256_loadu_si256((const __m256i *)ref1);
626
0
  src[1] = _mm256_loadu_si256((const __m256i *)(ref1 + stride));
627
0
  src[2] = _mm256_loadu_si256((const __m256i *)(ref1 + (2 * stride)));
628
0
  src[3] = _mm256_loadu_si256((const __m256i *)(ref1 + (3 * stride)));
629
0
}
630
631
#define CALC_TOT_SAD_AND_STORE                                                \
632
  /* r00 r10 x x r01 r11 x x | r02 r12 x x r03 r13 x x */                     \
633
0
  const __m256i r01 = _mm256_add_epi16(_mm256_slli_si256(r1, 2), r0);         \
634
0
  /* r00 r10 r20 x r01 r11 r21 x | r02 r12 r22 x r03 r13 r23 x */             \
635
0
  const __m256i r012 = _mm256_add_epi16(_mm256_slli_si256(r2, 4), r01);       \
636
0
  /* r00 r10 r20 r30 r01 r11 r21 r31 | r02 r12 r22 r32 r03 r13 r23 r33 */     \
637
0
  const __m256i result0 = _mm256_add_epi16(_mm256_slli_si256(r3, 6), r012);   \
638
0
                                                                              \
639
0
  const __m128i results0 = _mm_add_epi16(                                     \
640
0
      _mm256_castsi256_si128(result0), _mm256_extractf128_si256(result0, 1)); \
641
0
  const __m128i results1 =                                                    \
642
0
      _mm_add_epi16(results0, _mm_srli_si128(results0, 8));                   \
643
0
  _mm_storel_epi64((__m128i *)vbuf, _mm_srli_epi16(results1, norm_factor));
644
645
static inline void aom_int_pro_col_16wd_avx2(int16_t *vbuf, const uint8_t *ref,
646
                                             const int ref_stride,
647
                                             const int height,
648
0
                                             int norm_factor) {
649
0
  const __m256i zero = _mm256_setzero_si256();
650
0
  int ht = 0;
651
  // Post sad operation, the data is present in lower 16-bit of each 64-bit lane
652
  // and higher 16-bits are Zero. Here, we are processing 8 rows at a time to
653
  // utilize the higher 16-bits efficiently.
654
0
  do {
655
0
    __m256i src_00 =
656
0
        _mm256_castsi128_si256(_mm_loadu_si128((const __m128i *)(ref)));
657
0
    src_00 = _mm256_inserti128_si256(
658
0
        src_00, _mm_loadu_si128((const __m128i *)(ref + ref_stride * 4)), 1);
659
0
    __m256i src_01 = _mm256_castsi128_si256(
660
0
        _mm_loadu_si128((const __m128i *)(ref + ref_stride * 1)));
661
0
    src_01 = _mm256_inserti128_si256(
662
0
        src_01, _mm_loadu_si128((const __m128i *)(ref + ref_stride * 5)), 1);
663
0
    __m256i src_10 = _mm256_castsi128_si256(
664
0
        _mm_loadu_si128((const __m128i *)(ref + ref_stride * 2)));
665
0
    src_10 = _mm256_inserti128_si256(
666
0
        src_10, _mm_loadu_si128((const __m128i *)(ref + ref_stride * 6)), 1);
667
0
    __m256i src_11 = _mm256_castsi128_si256(
668
0
        _mm_loadu_si128((const __m128i *)(ref + ref_stride * 3)));
669
0
    src_11 = _mm256_inserti128_si256(
670
0
        src_11, _mm_loadu_si128((const __m128i *)(ref + ref_stride * 7)), 1);
671
672
    // s00 x x x s01 x x x | s40 x x x s41 x x x
673
0
    const __m256i s0 = _mm256_sad_epu8(src_00, zero);
674
    // s10 x x x s11 x x x | s50 x x x s51 x x x
675
0
    const __m256i s1 = _mm256_sad_epu8(src_01, zero);
676
    // s20 x x x s21 x x x | s60 x x x s61 x x x
677
0
    const __m256i s2 = _mm256_sad_epu8(src_10, zero);
678
    // s30 x x x s31 x x x | s70 x x x s71 x x x
679
0
    const __m256i s3 = _mm256_sad_epu8(src_11, zero);
680
681
    // s00 s10 x x x x x x | s40 s50 x x x x x x
682
0
    const __m256i s0_lo = _mm256_unpacklo_epi16(s0, s1);
683
    // s01 s11 x x x x x x | s41 s51 x x x x x x
684
0
    const __m256i s0_hi = _mm256_unpackhi_epi16(s0, s1);
685
    // s20 s30 x x x x x x | s60 s70 x x x x x x
686
0
    const __m256i s1_lo = _mm256_unpacklo_epi16(s2, s3);
687
    // s21 s31 x x x x x x | s61 s71 x x x x x x
688
0
    const __m256i s1_hi = _mm256_unpackhi_epi16(s2, s3);
689
690
    // s0 s1 x x x x x x | s4 s5 x x x x x x
691
0
    const __m256i s0_add = _mm256_add_epi16(s0_lo, s0_hi);
692
    // s2 s3 x x x x x x | s6 s7 x x x x x x
693
0
    const __m256i s1_add = _mm256_add_epi16(s1_lo, s1_hi);
694
695
    // s1 s1 s2 s3 s4 s5 s6 s7
696
0
    const __m128i results = _mm256_castsi256_si128(
697
0
        _mm256_permute4x64_epi64(_mm256_unpacklo_epi32(s0_add, s1_add), 0x08));
698
0
    _mm_storeu_si128((__m128i *)vbuf, _mm_srli_epi16(results, norm_factor));
699
0
    vbuf += 8;
700
0
    ref += (ref_stride << 3);
701
0
    ht += 8;
702
0
  } while (ht < height);
703
0
}
704
705
void aom_int_pro_col_avx2(int16_t *vbuf, const uint8_t *ref,
706
                          const int ref_stride, const int width,
707
0
                          const int height, int norm_factor) {
708
0
  assert(width % 16 == 0);
709
0
  if (width == 128) {
710
0
    const __m256i zero = _mm256_setzero_si256();
711
0
    for (int ht = 0; ht < height; ht += 4) {
712
0
      __m256i src[16];
713
      // Load source data.
714
0
      load_from_src_buf(ref, &src[0], ref_stride);
715
0
      load_from_src_buf(ref + 32, &src[4], ref_stride);
716
0
      load_from_src_buf(ref + 64, &src[8], ref_stride);
717
0
      load_from_src_buf(ref + 96, &src[12], ref_stride);
718
719
      // Row0 output: r00 x x x r01 x x x | r02 x x x r03 x x x
720
0
      const __m256i s0 = _mm256_add_epi16(_mm256_sad_epu8(src[0], zero),
721
0
                                          _mm256_sad_epu8(src[4], zero));
722
0
      const __m256i s1 = _mm256_add_epi16(_mm256_sad_epu8(src[8], zero),
723
0
                                          _mm256_sad_epu8(src[12], zero));
724
0
      const __m256i r0 = _mm256_add_epi16(s0, s1);
725
      // Row1 output: r10 x x x r11 x x x | r12 x x x r13 x x x
726
0
      const __m256i s2 = _mm256_add_epi16(_mm256_sad_epu8(src[1], zero),
727
0
                                          _mm256_sad_epu8(src[5], zero));
728
0
      const __m256i s3 = _mm256_add_epi16(_mm256_sad_epu8(src[9], zero),
729
0
                                          _mm256_sad_epu8(src[13], zero));
730
0
      const __m256i r1 = _mm256_add_epi16(s2, s3);
731
      // Row2 output: r20 x x x r21 x x x | r22 x x x r23 x x x
732
0
      const __m256i s4 = _mm256_add_epi16(_mm256_sad_epu8(src[2], zero),
733
0
                                          _mm256_sad_epu8(src[6], zero));
734
0
      const __m256i s5 = _mm256_add_epi16(_mm256_sad_epu8(src[10], zero),
735
0
                                          _mm256_sad_epu8(src[14], zero));
736
0
      const __m256i r2 = _mm256_add_epi16(s4, s5);
737
      // Row3 output: r30 x x x r31 x x x | r32 x x x r33 x x x
738
0
      const __m256i s6 = _mm256_add_epi16(_mm256_sad_epu8(src[3], zero),
739
0
                                          _mm256_sad_epu8(src[7], zero));
740
0
      const __m256i s7 = _mm256_add_epi16(_mm256_sad_epu8(src[11], zero),
741
0
                                          _mm256_sad_epu8(src[15], zero));
742
0
      const __m256i r3 = _mm256_add_epi16(s6, s7);
743
744
0
      CALC_TOT_SAD_AND_STORE
745
0
      vbuf += 4;
746
0
      ref += ref_stride << 2;
747
0
    }
748
0
  } else if (width == 64) {
749
0
    const __m256i zero = _mm256_setzero_si256();
750
0
    for (int ht = 0; ht < height; ht += 4) {
751
0
      __m256i src[8];
752
      // Load source data.
753
0
      load_from_src_buf(ref, &src[0], ref_stride);
754
0
      load_from_src_buf(ref + 32, &src[4], ref_stride);
755
756
      // Row0 output: r00 x x x r01 x x x | r02 x x x r03 x x x
757
0
      const __m256i s0 = _mm256_sad_epu8(src[0], zero);
758
0
      const __m256i s1 = _mm256_sad_epu8(src[4], zero);
759
0
      const __m256i r0 = _mm256_add_epi16(s0, s1);
760
      // Row1 output: r10 x x x r11 x x x | r12 x x x r13 x x x
761
0
      const __m256i s2 = _mm256_sad_epu8(src[1], zero);
762
0
      const __m256i s3 = _mm256_sad_epu8(src[5], zero);
763
0
      const __m256i r1 = _mm256_add_epi16(s2, s3);
764
      // Row2 output: r20 x x x r21 x x x | r22 x x x r23 x x x
765
0
      const __m256i s4 = _mm256_sad_epu8(src[2], zero);
766
0
      const __m256i s5 = _mm256_sad_epu8(src[6], zero);
767
0
      const __m256i r2 = _mm256_add_epi16(s4, s5);
768
      // Row3 output: r30 x x x r31 x x x | r32 x x x r33 x x x
769
0
      const __m256i s6 = _mm256_sad_epu8(src[3], zero);
770
0
      const __m256i s7 = _mm256_sad_epu8(src[7], zero);
771
0
      const __m256i r3 = _mm256_add_epi16(s6, s7);
772
773
0
      CALC_TOT_SAD_AND_STORE
774
0
      vbuf += 4;
775
0
      ref += ref_stride << 2;
776
0
    }
777
0
  } else if (width == 32) {
778
0
    assert(height % 2 == 0);
779
0
    const __m256i zero = _mm256_setzero_si256();
780
0
    for (int ht = 0; ht < height; ht += 4) {
781
0
      __m256i src[4];
782
      // Load source data.
783
0
      load_from_src_buf(ref, &src[0], ref_stride);
784
785
      // s00 x x x s01 x x x s02 x x x s03 x x x
786
0
      const __m256i r0 = _mm256_sad_epu8(src[0], zero);
787
      // s10 x x x s11 x x x s12 x x x s13 x x x
788
0
      const __m256i r1 = _mm256_sad_epu8(src[1], zero);
789
      // s20 x x x s21 x x x s22 x x x s23 x x x
790
0
      const __m256i r2 = _mm256_sad_epu8(src[2], zero);
791
      // s30 x x x s31 x x x s32 x x x s33 x x x
792
0
      const __m256i r3 = _mm256_sad_epu8(src[3], zero);
793
794
0
      CALC_TOT_SAD_AND_STORE
795
0
      vbuf += 4;
796
0
      ref += ref_stride << 2;
797
0
    }
798
0
  } else if (width == 16) {
799
0
    aom_int_pro_col_16wd_avx2(vbuf, ref, ref_stride, height, norm_factor);
800
0
  }
801
0
}
802
803
static inline void calc_vector_mean_sse_64wd(const int16_t *ref,
804
                                             const int16_t *src, __m256i *mean,
805
0
                                             __m256i *sse) {
806
0
  const __m256i src_line0 = _mm256_loadu_si256((const __m256i *)src);
807
0
  const __m256i src_line1 = _mm256_loadu_si256((const __m256i *)(src + 16));
808
0
  const __m256i src_line2 = _mm256_loadu_si256((const __m256i *)(src + 32));
809
0
  const __m256i src_line3 = _mm256_loadu_si256((const __m256i *)(src + 48));
810
0
  const __m256i ref_line0 = _mm256_loadu_si256((const __m256i *)ref);
811
0
  const __m256i ref_line1 = _mm256_loadu_si256((const __m256i *)(ref + 16));
812
0
  const __m256i ref_line2 = _mm256_loadu_si256((const __m256i *)(ref + 32));
813
0
  const __m256i ref_line3 = _mm256_loadu_si256((const __m256i *)(ref + 48));
814
815
0
  const __m256i diff0 = _mm256_sub_epi16(ref_line0, src_line0);
816
0
  const __m256i diff1 = _mm256_sub_epi16(ref_line1, src_line1);
817
0
  const __m256i diff2 = _mm256_sub_epi16(ref_line2, src_line2);
818
0
  const __m256i diff3 = _mm256_sub_epi16(ref_line3, src_line3);
819
0
  const __m256i diff_sqr0 = _mm256_madd_epi16(diff0, diff0);
820
0
  const __m256i diff_sqr1 = _mm256_madd_epi16(diff1, diff1);
821
0
  const __m256i diff_sqr2 = _mm256_madd_epi16(diff2, diff2);
822
0
  const __m256i diff_sqr3 = _mm256_madd_epi16(diff3, diff3);
823
824
0
  *mean = _mm256_add_epi16(*mean, _mm256_add_epi16(diff0, diff1));
825
0
  *mean = _mm256_add_epi16(*mean, diff2);
826
0
  *mean = _mm256_add_epi16(*mean, diff3);
827
0
  *sse = _mm256_add_epi32(*sse, _mm256_add_epi32(diff_sqr0, diff_sqr1));
828
0
  *sse = _mm256_add_epi32(*sse, diff_sqr2);
829
0
  *sse = _mm256_add_epi32(*sse, diff_sqr3);
830
0
}
831
832
#define CALC_VAR_FROM_MEAN_SSE(mean, sse)                                    \
833
0
  {                                                                          \
834
0
    mean = _mm256_madd_epi16(mean, _mm256_set1_epi16(1));                    \
835
0
    mean = _mm256_hadd_epi32(mean, sse);                                     \
836
0
    mean = _mm256_add_epi32(mean, _mm256_bsrli_epi128(mean, 4));             \
837
0
    const __m128i result = _mm_add_epi32(_mm256_castsi256_si128(mean),       \
838
0
                                         _mm256_extractf128_si256(mean, 1)); \
839
0
    /*(mean * mean): dynamic range 31 bits.*/                                \
840
0
    const int mean_int = _mm_extract_epi32(result, 0);                       \
841
0
    const int sse_int = _mm_extract_epi32(result, 2);                        \
842
0
    const unsigned int mean_abs = abs(mean_int);                             \
843
0
    var = sse_int - ((mean_abs * mean_abs) >> (bwl + 2));                    \
844
0
  }
845
846
// ref: [0 - 510]
847
// src: [0 - 510]
848
// bwl: {2, 3, 4, 5}
849
0
int aom_vector_var_avx2(const int16_t *ref, const int16_t *src, int bwl) {
850
0
  const int width = 4 << bwl;
851
0
  assert(width % 16 == 0 && width <= 128);
852
0
  int var = 0;
853
854
  // Instead of having a loop over width 16, considered loop unrolling to avoid
855
  // some addition operations.
856
0
  if (width == 128) {
857
0
    __m256i mean = _mm256_setzero_si256();
858
0
    __m256i sse = _mm256_setzero_si256();
859
860
0
    calc_vector_mean_sse_64wd(src, ref, &mean, &sse);
861
0
    calc_vector_mean_sse_64wd(src + 64, ref + 64, &mean, &sse);
862
0
    CALC_VAR_FROM_MEAN_SSE(mean, sse)
863
0
  } else if (width == 64) {
864
0
    __m256i mean = _mm256_setzero_si256();
865
0
    __m256i sse = _mm256_setzero_si256();
866
867
0
    calc_vector_mean_sse_64wd(src, ref, &mean, &sse);
868
0
    CALC_VAR_FROM_MEAN_SSE(mean, sse)
869
0
  } else if (width == 32) {
870
0
    const __m256i src_line0 = _mm256_loadu_si256((const __m256i *)src);
871
0
    const __m256i ref_line0 = _mm256_loadu_si256((const __m256i *)ref);
872
0
    const __m256i src_line1 = _mm256_loadu_si256((const __m256i *)(src + 16));
873
0
    const __m256i ref_line1 = _mm256_loadu_si256((const __m256i *)(ref + 16));
874
875
0
    const __m256i diff0 = _mm256_sub_epi16(ref_line0, src_line0);
876
0
    const __m256i diff1 = _mm256_sub_epi16(ref_line1, src_line1);
877
0
    const __m256i diff_sqr0 = _mm256_madd_epi16(diff0, diff0);
878
0
    const __m256i diff_sqr1 = _mm256_madd_epi16(diff1, diff1);
879
0
    const __m256i sse = _mm256_add_epi32(diff_sqr0, diff_sqr1);
880
0
    __m256i mean = _mm256_add_epi16(diff0, diff1);
881
882
0
    CALC_VAR_FROM_MEAN_SSE(mean, sse)
883
0
  } else if (width == 16) {
884
0
    const __m256i src_line = _mm256_loadu_si256((const __m256i *)src);
885
0
    const __m256i ref_line = _mm256_loadu_si256((const __m256i *)ref);
886
0
    __m256i mean = _mm256_sub_epi16(ref_line, src_line);
887
0
    const __m256i sse = _mm256_madd_epi16(mean, mean);
888
889
    CALC_VAR_FROM_MEAN_SSE(mean, sse)
890
0
  }
891
0
  return var;
892
0
}