/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 | } |