1 /*
2 * Copyright 2014 The LibYuv Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "libyuv/rotate_row.h"
12 #include "libyuv/row.h"
13
14 #include "libyuv/basic_types.h"
15
16 #ifdef __cplusplus
17 namespace libyuv {
18 extern "C" {
19 #endif
20
21 // This module is for GCC Neon armv8 64 bit.
22 #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
23
24 static const uvec8 kVTbl4x4Transpose = {0, 4, 8, 12, 1, 5, 9, 13,
25 2, 6, 10, 14, 3, 7, 11, 15};
26
TransposeWx8_NEON(const uint8_t * src,int src_stride,uint8_t * dst,int dst_stride,int width)27 void TransposeWx8_NEON(const uint8_t* src,
28 int src_stride,
29 uint8_t* dst,
30 int dst_stride,
31 int width) {
32 const uint8_t* src_temp;
33 asm volatile(
34 // loops are on blocks of 8. loop will stop when
35 // counter gets to or below 0. starting the counter
36 // at w-8 allow for this
37 "sub %w3, %w3, #8 \n"
38
39 // handle 8x8 blocks. this should be the majority of the plane
40 "1: \n"
41 "mov %0, %1 \n"
42
43 "ld1 {v0.8b}, [%0], %5 \n"
44 "ld1 {v1.8b}, [%0], %5 \n"
45 "ld1 {v2.8b}, [%0], %5 \n"
46 "ld1 {v3.8b}, [%0], %5 \n"
47 "ld1 {v4.8b}, [%0], %5 \n"
48 "ld1 {v5.8b}, [%0], %5 \n"
49 "ld1 {v6.8b}, [%0], %5 \n"
50 "ld1 {v7.8b}, [%0] \n"
51
52 "trn2 v16.8b, v0.8b, v1.8b \n"
53 "trn1 v17.8b, v0.8b, v1.8b \n"
54 "trn2 v18.8b, v2.8b, v3.8b \n"
55 "trn1 v19.8b, v2.8b, v3.8b \n"
56 "trn2 v20.8b, v4.8b, v5.8b \n"
57 "trn1 v21.8b, v4.8b, v5.8b \n"
58 "trn2 v22.8b, v6.8b, v7.8b \n"
59 "trn1 v23.8b, v6.8b, v7.8b \n"
60
61 "trn2 v3.4h, v17.4h, v19.4h \n"
62 "trn1 v1.4h, v17.4h, v19.4h \n"
63 "trn2 v2.4h, v16.4h, v18.4h \n"
64 "trn1 v0.4h, v16.4h, v18.4h \n"
65 "trn2 v7.4h, v21.4h, v23.4h \n"
66 "trn1 v5.4h, v21.4h, v23.4h \n"
67 "trn2 v6.4h, v20.4h, v22.4h \n"
68 "trn1 v4.4h, v20.4h, v22.4h \n"
69
70 "trn2 v21.2s, v1.2s, v5.2s \n"
71 "trn1 v17.2s, v1.2s, v5.2s \n"
72 "trn2 v20.2s, v0.2s, v4.2s \n"
73 "trn1 v16.2s, v0.2s, v4.2s \n"
74 "trn2 v23.2s, v3.2s, v7.2s \n"
75 "trn1 v19.2s, v3.2s, v7.2s \n"
76 "trn2 v22.2s, v2.2s, v6.2s \n"
77 "trn1 v18.2s, v2.2s, v6.2s \n"
78
79 "mov %0, %2 \n"
80
81 "st1 {v17.8b}, [%0], %6 \n"
82 "st1 {v16.8b}, [%0], %6 \n"
83 "st1 {v19.8b}, [%0], %6 \n"
84 "st1 {v18.8b}, [%0], %6 \n"
85 "st1 {v21.8b}, [%0], %6 \n"
86 "st1 {v20.8b}, [%0], %6 \n"
87 "st1 {v23.8b}, [%0], %6 \n"
88 "st1 {v22.8b}, [%0] \n"
89
90 "add %1, %1, #8 \n" // src += 8
91 "add %2, %2, %6, lsl #3 \n" // dst += 8 * dst_stride
92 "subs %w3, %w3, #8 \n" // w -= 8
93 "b.ge 1b \n"
94
95 // add 8 back to counter. if the result is 0 there are
96 // no residuals.
97 "adds %w3, %w3, #8 \n"
98 "b.eq 4f \n"
99
100 // some residual, so between 1 and 7 lines left to transpose
101 "cmp %w3, #2 \n"
102 "b.lt 3f \n"
103
104 "cmp %w3, #4 \n"
105 "b.lt 2f \n"
106
107 // 4x8 block
108 "mov %0, %1 \n"
109 "ld1 {v0.s}[0], [%0], %5 \n"
110 "ld1 {v0.s}[1], [%0], %5 \n"
111 "ld1 {v0.s}[2], [%0], %5 \n"
112 "ld1 {v0.s}[3], [%0], %5 \n"
113 "ld1 {v1.s}[0], [%0], %5 \n"
114 "ld1 {v1.s}[1], [%0], %5 \n"
115 "ld1 {v1.s}[2], [%0], %5 \n"
116 "ld1 {v1.s}[3], [%0] \n"
117
118 "mov %0, %2 \n"
119
120 "ld1 {v2.16b}, [%4] \n"
121
122 "tbl v3.16b, {v0.16b}, v2.16b \n"
123 "tbl v0.16b, {v1.16b}, v2.16b \n"
124
125 // TODO(frkoenig): Rework shuffle above to
126 // write out with 4 instead of 8 writes.
127 "st1 {v3.s}[0], [%0], %6 \n"
128 "st1 {v3.s}[1], [%0], %6 \n"
129 "st1 {v3.s}[2], [%0], %6 \n"
130 "st1 {v3.s}[3], [%0] \n"
131
132 "add %0, %2, #4 \n"
133 "st1 {v0.s}[0], [%0], %6 \n"
134 "st1 {v0.s}[1], [%0], %6 \n"
135 "st1 {v0.s}[2], [%0], %6 \n"
136 "st1 {v0.s}[3], [%0] \n"
137
138 "add %1, %1, #4 \n" // src += 4
139 "add %2, %2, %6, lsl #2 \n" // dst += 4 * dst_stride
140 "subs %w3, %w3, #4 \n" // w -= 4
141 "b.eq 4f \n"
142
143 // some residual, check to see if it includes a 2x8 block,
144 // or less
145 "cmp %w3, #2 \n"
146 "b.lt 3f \n"
147
148 // 2x8 block
149 "2: \n"
150 "mov %0, %1 \n"
151 "ld1 {v0.h}[0], [%0], %5 \n"
152 "ld1 {v1.h}[0], [%0], %5 \n"
153 "ld1 {v0.h}[1], [%0], %5 \n"
154 "ld1 {v1.h}[1], [%0], %5 \n"
155 "ld1 {v0.h}[2], [%0], %5 \n"
156 "ld1 {v1.h}[2], [%0], %5 \n"
157 "ld1 {v0.h}[3], [%0], %5 \n"
158 "ld1 {v1.h}[3], [%0] \n"
159
160 "trn2 v2.8b, v0.8b, v1.8b \n"
161 "trn1 v3.8b, v0.8b, v1.8b \n"
162
163 "mov %0, %2 \n"
164
165 "st1 {v3.8b}, [%0], %6 \n"
166 "st1 {v2.8b}, [%0] \n"
167
168 "add %1, %1, #2 \n" // src += 2
169 "add %2, %2, %6, lsl #1 \n" // dst += 2 * dst_stride
170 "subs %w3, %w3, #2 \n" // w -= 2
171 "b.eq 4f \n"
172
173 // 1x8 block
174 "3: \n"
175 "ld1 {v0.b}[0], [%1], %5 \n"
176 "ld1 {v0.b}[1], [%1], %5 \n"
177 "ld1 {v0.b}[2], [%1], %5 \n"
178 "ld1 {v0.b}[3], [%1], %5 \n"
179 "ld1 {v0.b}[4], [%1], %5 \n"
180 "ld1 {v0.b}[5], [%1], %5 \n"
181 "ld1 {v0.b}[6], [%1], %5 \n"
182 "ld1 {v0.b}[7], [%1] \n"
183
184 "st1 {v0.8b}, [%2] \n"
185
186 "4: \n"
187
188 : "=&r"(src_temp), // %0
189 "+r"(src), // %1
190 "+r"(dst), // %2
191 "+r"(width) // %3
192 : "r"(&kVTbl4x4Transpose), // %4
193 "r"(static_cast<ptrdiff_t>(src_stride)), // %5
194 "r"(static_cast<ptrdiff_t>(dst_stride)) // %6
195 : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
196 "v17", "v18", "v19", "v20", "v21", "v22", "v23");
197 }
198
199 static const uint8_t kVTbl4x4TransposeDi[32] = {
200 0, 16, 32, 48, 2, 18, 34, 50, 4, 20, 36, 52, 6, 22, 38, 54,
201 1, 17, 33, 49, 3, 19, 35, 51, 5, 21, 37, 53, 7, 23, 39, 55};
202
TransposeUVWx8_NEON(const uint8_t * src,int src_stride,uint8_t * dst_a,int dst_stride_a,uint8_t * dst_b,int dst_stride_b,int width)203 void TransposeUVWx8_NEON(const uint8_t* src,
204 int src_stride,
205 uint8_t* dst_a,
206 int dst_stride_a,
207 uint8_t* dst_b,
208 int dst_stride_b,
209 int width) {
210 const uint8_t* src_temp;
211 asm volatile(
212 // loops are on blocks of 8. loop will stop when
213 // counter gets to or below 0. starting the counter
214 // at w-8 allow for this
215 "sub %w4, %w4, #8 \n"
216
217 // handle 8x8 blocks. this should be the majority of the plane
218 "1: \n"
219 "mov %0, %1 \n"
220
221 "ld1 {v0.16b}, [%0], %5 \n"
222 "ld1 {v1.16b}, [%0], %5 \n"
223 "ld1 {v2.16b}, [%0], %5 \n"
224 "ld1 {v3.16b}, [%0], %5 \n"
225 "ld1 {v4.16b}, [%0], %5 \n"
226 "ld1 {v5.16b}, [%0], %5 \n"
227 "ld1 {v6.16b}, [%0], %5 \n"
228 "ld1 {v7.16b}, [%0] \n"
229
230 "trn1 v16.16b, v0.16b, v1.16b \n"
231 "trn2 v17.16b, v0.16b, v1.16b \n"
232 "trn1 v18.16b, v2.16b, v3.16b \n"
233 "trn2 v19.16b, v2.16b, v3.16b \n"
234 "trn1 v20.16b, v4.16b, v5.16b \n"
235 "trn2 v21.16b, v4.16b, v5.16b \n"
236 "trn1 v22.16b, v6.16b, v7.16b \n"
237 "trn2 v23.16b, v6.16b, v7.16b \n"
238
239 "trn1 v0.8h, v16.8h, v18.8h \n"
240 "trn2 v1.8h, v16.8h, v18.8h \n"
241 "trn1 v2.8h, v20.8h, v22.8h \n"
242 "trn2 v3.8h, v20.8h, v22.8h \n"
243 "trn1 v4.8h, v17.8h, v19.8h \n"
244 "trn2 v5.8h, v17.8h, v19.8h \n"
245 "trn1 v6.8h, v21.8h, v23.8h \n"
246 "trn2 v7.8h, v21.8h, v23.8h \n"
247
248 "trn1 v16.4s, v0.4s, v2.4s \n"
249 "trn2 v17.4s, v0.4s, v2.4s \n"
250 "trn1 v18.4s, v1.4s, v3.4s \n"
251 "trn2 v19.4s, v1.4s, v3.4s \n"
252 "trn1 v20.4s, v4.4s, v6.4s \n"
253 "trn2 v21.4s, v4.4s, v6.4s \n"
254 "trn1 v22.4s, v5.4s, v7.4s \n"
255 "trn2 v23.4s, v5.4s, v7.4s \n"
256
257 "mov %0, %2 \n"
258
259 "st1 {v16.d}[0], [%0], %6 \n"
260 "st1 {v18.d}[0], [%0], %6 \n"
261 "st1 {v17.d}[0], [%0], %6 \n"
262 "st1 {v19.d}[0], [%0], %6 \n"
263 "st1 {v16.d}[1], [%0], %6 \n"
264 "st1 {v18.d}[1], [%0], %6 \n"
265 "st1 {v17.d}[1], [%0], %6 \n"
266 "st1 {v19.d}[1], [%0] \n"
267
268 "mov %0, %3 \n"
269
270 "st1 {v20.d}[0], [%0], %7 \n"
271 "st1 {v22.d}[0], [%0], %7 \n"
272 "st1 {v21.d}[0], [%0], %7 \n"
273 "st1 {v23.d}[0], [%0], %7 \n"
274 "st1 {v20.d}[1], [%0], %7 \n"
275 "st1 {v22.d}[1], [%0], %7 \n"
276 "st1 {v21.d}[1], [%0], %7 \n"
277 "st1 {v23.d}[1], [%0] \n"
278
279 "add %1, %1, #16 \n" // src += 8*2
280 "add %2, %2, %6, lsl #3 \n" // dst_a += 8 *
281 // dst_stride_a
282 "add %3, %3, %7, lsl #3 \n" // dst_b += 8 *
283 // dst_stride_b
284 "subs %w4, %w4, #8 \n" // w -= 8
285 "b.ge 1b \n"
286
287 // add 8 back to counter. if the result is 0 there are
288 // no residuals.
289 "adds %w4, %w4, #8 \n"
290 "b.eq 4f \n"
291
292 // some residual, so between 1 and 7 lines left to transpose
293 "cmp %w4, #2 \n"
294 "b.lt 3f \n"
295
296 "cmp %w4, #4 \n"
297 "b.lt 2f \n"
298
299 // TODO(frkoenig): Clean this up
300 // 4x8 block
301 "mov %0, %1 \n"
302 "ld1 {v0.8b}, [%0], %5 \n"
303 "ld1 {v1.8b}, [%0], %5 \n"
304 "ld1 {v2.8b}, [%0], %5 \n"
305 "ld1 {v3.8b}, [%0], %5 \n"
306 "ld1 {v4.8b}, [%0], %5 \n"
307 "ld1 {v5.8b}, [%0], %5 \n"
308 "ld1 {v6.8b}, [%0], %5 \n"
309 "ld1 {v7.8b}, [%0] \n"
310
311 "ld1 {v30.16b}, [%8], #16 \n"
312 "ld1 {v31.16b}, [%8] \n"
313
314 "tbl v16.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v30.16b \n"
315 "tbl v17.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v31.16b \n"
316 "tbl v18.16b, {v4.16b, v5.16b, v6.16b, v7.16b}, v30.16b \n"
317 "tbl v19.16b, {v4.16b, v5.16b, v6.16b, v7.16b}, v31.16b \n"
318
319 "mov %0, %2 \n"
320
321 "st1 {v16.s}[0], [%0], %6 \n"
322 "st1 {v16.s}[1], [%0], %6 \n"
323 "st1 {v16.s}[2], [%0], %6 \n"
324 "st1 {v16.s}[3], [%0], %6 \n"
325
326 "add %0, %2, #4 \n"
327 "st1 {v18.s}[0], [%0], %6 \n"
328 "st1 {v18.s}[1], [%0], %6 \n"
329 "st1 {v18.s}[2], [%0], %6 \n"
330 "st1 {v18.s}[3], [%0] \n"
331
332 "mov %0, %3 \n"
333
334 "st1 {v17.s}[0], [%0], %7 \n"
335 "st1 {v17.s}[1], [%0], %7 \n"
336 "st1 {v17.s}[2], [%0], %7 \n"
337 "st1 {v17.s}[3], [%0], %7 \n"
338
339 "add %0, %3, #4 \n"
340 "st1 {v19.s}[0], [%0], %7 \n"
341 "st1 {v19.s}[1], [%0], %7 \n"
342 "st1 {v19.s}[2], [%0], %7 \n"
343 "st1 {v19.s}[3], [%0] \n"
344
345 "add %1, %1, #8 \n" // src += 4 * 2
346 "add %2, %2, %6, lsl #2 \n" // dst_a += 4 *
347 // dst_stride_a
348 "add %3, %3, %7, lsl #2 \n" // dst_b += 4 *
349 // dst_stride_b
350 "subs %w4, %w4, #4 \n" // w -= 4
351 "b.eq 4f \n"
352
353 // some residual, check to see if it includes a 2x8 block,
354 // or less
355 "cmp %w4, #2 \n"
356 "b.lt 3f \n"
357
358 // 2x8 block
359 "2: \n"
360 "mov %0, %1 \n"
361 "ld2 {v0.h, v1.h}[0], [%0], %5 \n"
362 "ld2 {v2.h, v3.h}[0], [%0], %5 \n"
363 "ld2 {v0.h, v1.h}[1], [%0], %5 \n"
364 "ld2 {v2.h, v3.h}[1], [%0], %5 \n"
365 "ld2 {v0.h, v1.h}[2], [%0], %5 \n"
366 "ld2 {v2.h, v3.h}[2], [%0], %5 \n"
367 "ld2 {v0.h, v1.h}[3], [%0], %5 \n"
368 "ld2 {v2.h, v3.h}[3], [%0] \n"
369
370 "trn1 v4.8b, v0.8b, v2.8b \n"
371 "trn2 v5.8b, v0.8b, v2.8b \n"
372 "trn1 v6.8b, v1.8b, v3.8b \n"
373 "trn2 v7.8b, v1.8b, v3.8b \n"
374
375 "mov %0, %2 \n"
376
377 "st1 {v4.d}[0], [%0], %6 \n"
378 "st1 {v6.d}[0], [%0] \n"
379
380 "mov %0, %3 \n"
381
382 "st1 {v5.d}[0], [%0], %7 \n"
383 "st1 {v7.d}[0], [%0] \n"
384
385 "add %1, %1, #4 \n" // src += 2 * 2
386 "add %2, %2, %6, lsl #1 \n" // dst_a += 2 *
387 // dst_stride_a
388 "add %3, %3, %7, lsl #1 \n" // dst_b += 2 *
389 // dst_stride_b
390 "subs %w4, %w4, #2 \n" // w -= 2
391 "b.eq 4f \n"
392
393 // 1x8 block
394 "3: \n"
395 "ld2 {v0.b, v1.b}[0], [%1], %5 \n"
396 "ld2 {v0.b, v1.b}[1], [%1], %5 \n"
397 "ld2 {v0.b, v1.b}[2], [%1], %5 \n"
398 "ld2 {v0.b, v1.b}[3], [%1], %5 \n"
399 "ld2 {v0.b, v1.b}[4], [%1], %5 \n"
400 "ld2 {v0.b, v1.b}[5], [%1], %5 \n"
401 "ld2 {v0.b, v1.b}[6], [%1], %5 \n"
402 "ld2 {v0.b, v1.b}[7], [%1] \n"
403
404 "st1 {v0.d}[0], [%2] \n"
405 "st1 {v1.d}[0], [%3] \n"
406
407 "4: \n"
408
409 : "=&r"(src_temp), // %0
410 "+r"(src), // %1
411 "+r"(dst_a), // %2
412 "+r"(dst_b), // %3
413 "+r"(width) // %4
414 : "r"(static_cast<ptrdiff_t>(src_stride)), // %5
415 "r"(static_cast<ptrdiff_t>(dst_stride_a)), // %6
416 "r"(static_cast<ptrdiff_t>(dst_stride_b)), // %7
417 "r"(&kVTbl4x4TransposeDi) // %8
418 : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
419 "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v30", "v31");
420 }
421 #endif // !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
422
423 #ifdef __cplusplus
424 } // extern "C"
425 } // namespace libyuv
426 #endif
427