Coverage Report

Created: 2026-11-12 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/aom_dsp/x86/subtract_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
#include <assert.h>
12
#include <immintrin.h>
13
#include <stdint.h>
14
15
#include "config/aom_dsp_rtcd.h"
16
#include "aom_dsp/x86/synonyms.h"
17
18
static inline void subtract_block_4xn_avx2(
19
    int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
20
0
    ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
21
0
  assert(rows >= 2 && (rows & 1) == 0);
22
0
  int32_t j = rows >> 1;
23
  // Process 2 rows of 4 pixels per iteration using 128-bit XMM registers
24
  // rather than 4 rows in a 256-bit YMM register:
25
  // 1. xx_loadl_32 + _mm_unpacklo_epi32 loads directly from memory into XMM
26
  //    without GPR-to-XMM inserts (_mm_set_epi32 / vpinsrd on Port 5).
27
  // 2. Staying in a single 128-bit lane avoids the cross-lane latency of
28
  //    _mm256_cvtepu8_epi16 and _mm256_extracti128_si256 needed for 8-byte
29
  //    per-row stores.
30
  // 3. Stepping pointers by stride each row avoids 3 * stride LEA addressing
31
  //    and eliminates a separate 2-row remainder loop.
32
0
  do {
33
0
    const __m128i s0 = xx_loadl_32(src_ptr);
34
0
    src_ptr += src_stride;
35
0
    const __m128i s1 = xx_loadl_32(src_ptr);
36
0
    src_ptr += src_stride;
37
0
    const __m128i p0 = xx_loadl_32(pred_ptr);
38
0
    pred_ptr += pred_stride;
39
0
    const __m128i p1 = xx_loadl_32(pred_ptr);
40
0
    pred_ptr += pred_stride;
41
42
0
    const __m128i d =
43
0
        _mm_sub_epi16(_mm_cvtepu8_epi16(_mm_unpacklo_epi32(s0, s1)),
44
0
                      _mm_cvtepu8_epi16(_mm_unpacklo_epi32(p0, p1)));
45
46
0
    _mm_storel_epi64((__m128i *)diff_ptr, d);
47
0
    diff_ptr += diff_stride;
48
0
    _mm_storeh_pi((__m64 *)diff_ptr, _mm_castsi128_ps(d));
49
0
    diff_ptr += diff_stride;
50
0
  } while (--j != 0);
51
0
}
52
53
static inline void subtract_block_8xn_avx2(
54
    int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
55
0
    ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
56
0
  assert(rows >= 2 && (rows & 1) == 0);
57
0
  int32_t j = rows >> 1;
58
  // Process 2 rows of 8 pixels per iteration using a 256-bit register.
59
0
  do {
60
0
    const __m128i s0 = _mm_loadl_epi64((const __m128i *)src_ptr);
61
0
    src_ptr += src_stride;
62
0
    const __m128i s1 = _mm_loadl_epi64((const __m128i *)src_ptr);
63
0
    src_ptr += src_stride;
64
0
    const __m128i p0 = _mm_loadl_epi64((const __m128i *)pred_ptr);
65
0
    pred_ptr += pred_stride;
66
0
    const __m128i p1 = _mm_loadl_epi64((const __m128i *)pred_ptr);
67
0
    pred_ptr += pred_stride;
68
69
0
    const __m256i d01 =
70
0
        _mm256_sub_epi16(_mm256_cvtepu8_epi16(_mm_unpacklo_epi64(s0, s1)),
71
0
                         _mm256_cvtepu8_epi16(_mm_unpacklo_epi64(p0, p1)));
72
73
0
    _mm_storeu_si128((__m128i *)diff_ptr, _mm256_castsi256_si128(d01));
74
0
    diff_ptr += diff_stride;
75
0
    _mm_storeu_si128((__m128i *)diff_ptr, _mm256_extracti128_si256(d01, 1));
76
0
    diff_ptr += diff_stride;
77
0
  } while (--j != 0);
78
0
}
79
80
static inline void subtract32_avx2(int16_t *diff_ptr, const uint8_t *src_ptr,
81
0
                                   const uint8_t *pred_ptr) {
82
0
  __m256i s = _mm256_lddqu_si256((__m256i *)(src_ptr));
83
0
  __m256i p = _mm256_lddqu_si256((__m256i *)(pred_ptr));
84
0
  __m256i set_one_minusone = _mm256_set1_epi32((int)0xff01ff01);
85
0
  __m256i diff0 = _mm256_unpacklo_epi8(s, p);
86
0
  __m256i diff1 = _mm256_unpackhi_epi8(s, p);
87
0
  diff0 = _mm256_maddubs_epi16(diff0, set_one_minusone);
88
0
  diff1 = _mm256_maddubs_epi16(diff1, set_one_minusone);
89
0
  _mm256_store_si256((__m256i *)(diff_ptr),
90
0
                     _mm256_permute2x128_si256(diff0, diff1, 0x20));
91
0
  _mm256_store_si256((__m256i *)(diff_ptr + 16),
92
0
                     _mm256_permute2x128_si256(diff0, diff1, 0x31));
93
0
}
94
95
static inline void subtract_block_16xn_avx2(
96
    int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
97
0
    ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
98
0
  assert(rows >= 2 && (rows & 1) == 0);
99
0
  int32_t j = rows >> 1;
100
0
  do {
101
0
    const __m128i s0 = _mm_lddqu_si128((const __m128i *)src_ptr);
102
0
    src_ptr += src_stride;
103
0
    const __m128i s1 = _mm_lddqu_si128((const __m128i *)src_ptr);
104
0
    src_ptr += src_stride;
105
0
    const __m128i p0 = _mm_lddqu_si128((const __m128i *)pred_ptr);
106
0
    pred_ptr += pred_stride;
107
0
    const __m128i p1 = _mm_lddqu_si128((const __m128i *)pred_ptr);
108
0
    pred_ptr += pred_stride;
109
0
    const __m256i d0 =
110
0
        _mm256_sub_epi16(_mm256_cvtepu8_epi16(s0), _mm256_cvtepu8_epi16(p0));
111
0
    const __m256i d1 =
112
0
        _mm256_sub_epi16(_mm256_cvtepu8_epi16(s1), _mm256_cvtepu8_epi16(p1));
113
0
    _mm256_store_si256((__m256i *)diff_ptr, d0);
114
0
    diff_ptr += diff_stride;
115
0
    _mm256_store_si256((__m256i *)diff_ptr, d1);
116
0
    diff_ptr += diff_stride;
117
0
  } while (--j != 0);
118
0
}
119
120
static inline void subtract_block_32xn_avx2(
121
    int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
122
0
    ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
123
0
  assert(rows > 0);
124
0
  int32_t j = rows;
125
0
  do {
126
0
    subtract32_avx2(diff_ptr, src_ptr, pred_ptr);
127
0
    src_ptr += src_stride;
128
0
    pred_ptr += pred_stride;
129
0
    diff_ptr += diff_stride;
130
0
  } while (--j != 0);
131
0
}
132
133
static inline void subtract_block_64xn_avx2(
134
    int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
135
0
    ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
136
0
  assert(rows > 0);
137
0
  int32_t j = rows;
138
0
  do {
139
0
    subtract32_avx2(diff_ptr, src_ptr, pred_ptr);
140
0
    subtract32_avx2(diff_ptr + 32, src_ptr + 32, pred_ptr + 32);
141
0
    src_ptr += src_stride;
142
0
    pred_ptr += pred_stride;
143
0
    diff_ptr += diff_stride;
144
0
  } while (--j != 0);
145
0
}
146
147
static inline void subtract_block_128xn_avx2(
148
    int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
149
0
    ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
150
0
  assert(rows > 0);
151
0
  int32_t j = rows;
152
0
  do {
153
0
    subtract32_avx2(diff_ptr, src_ptr, pred_ptr);
154
0
    subtract32_avx2(diff_ptr + 32, src_ptr + 32, pred_ptr + 32);
155
0
    subtract32_avx2(diff_ptr + 64, src_ptr + 64, pred_ptr + 64);
156
0
    subtract32_avx2(diff_ptr + 96, src_ptr + 96, pred_ptr + 96);
157
0
    src_ptr += src_stride;
158
0
    pred_ptr += pred_stride;
159
0
    diff_ptr += diff_stride;
160
0
  } while (--j != 0);
161
0
}
162
163
void aom_subtract_block_avx2(int rows, int cols, int16_t *diff_ptr,
164
                             ptrdiff_t diff_stride, const uint8_t *src_ptr,
165
                             ptrdiff_t src_stride, const uint8_t *pred_ptr,
166
0
                             ptrdiff_t pred_stride) {
167
0
  if (cols >= 16) {
168
0
    assert(((uintptr_t)diff_ptr & 31) == 0 &&
169
0
           ((diff_stride * sizeof(*diff_ptr)) & 31) == 0);
170
0
  }
171
0
  switch (cols) {
172
0
    case 4:
173
0
      subtract_block_4xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride,
174
0
                              pred_ptr, pred_stride);
175
0
      break;
176
0
    case 8:
177
0
      subtract_block_8xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride,
178
0
                              pred_ptr, pred_stride);
179
0
      break;
180
0
    case 16:
181
0
      subtract_block_16xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride,
182
0
                               pred_ptr, pred_stride);
183
0
      break;
184
0
    case 32:
185
0
      subtract_block_32xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride,
186
0
                               pred_ptr, pred_stride);
187
0
      break;
188
0
    case 64:
189
0
      subtract_block_64xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride,
190
0
                               pred_ptr, pred_stride);
191
0
      break;
192
0
    default:
193
0
      assert(cols == 128);
194
0
      subtract_block_128xn_avx2(rows, diff_ptr, diff_stride, src_ptr,
195
0
                                src_stride, pred_ptr, pred_stride);
196
0
      break;
197
0
  }
198
0
}