2 * Copyright 2014 The LibYuv Project Authors. All rights reserved.
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.
11 #include "libyuv/row.h"
13 #include "libyuv/basic_types.h"
20 // This module is for GCC Neon armv8 64 bit.
21 #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
23 static uvec8 kVTbl4x4Transpose =
24 { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
26 void TransposeWx8_NEON(const uint8* src, int src_stride,
27 uint8* dst, int dst_stride,
29 const uint8* src_temp = NULL;
30 int64 width64 = (int64) width; // Work around clang 3.4 warning.
32 // loops are on blocks of 8. loop will stop when
33 // counter gets to or below 0. starting the counter
34 // at w-8 allow for this
37 // handle 8x8 blocks. this should be the majority of the plane
42 "ld1 {v0.8b}, [%0], %5 \n"
44 "ld1 {v1.8b}, [%0], %5 \n"
46 "ld1 {v2.8b}, [%0], %5 \n"
48 "ld1 {v3.8b}, [%0], %5 \n"
50 "ld1 {v4.8b}, [%0], %5 \n"
52 "ld1 {v5.8b}, [%0], %5 \n"
54 "ld1 {v6.8b}, [%0], %5 \n"
56 "ld1 {v7.8b}, [%0] \n"
58 "trn2 v16.8b, v0.8b, v1.8b \n"
59 "trn1 v17.8b, v0.8b, v1.8b \n"
60 "trn2 v18.8b, v2.8b, v3.8b \n"
61 "trn1 v19.8b, v2.8b, v3.8b \n"
62 "trn2 v20.8b, v4.8b, v5.8b \n"
63 "trn1 v21.8b, v4.8b, v5.8b \n"
64 "trn2 v22.8b, v6.8b, v7.8b \n"
65 "trn1 v23.8b, v6.8b, v7.8b \n"
67 "trn2 v3.4h, v17.4h, v19.4h \n"
68 "trn1 v1.4h, v17.4h, v19.4h \n"
69 "trn2 v2.4h, v16.4h, v18.4h \n"
70 "trn1 v0.4h, v16.4h, v18.4h \n"
71 "trn2 v7.4h, v21.4h, v23.4h \n"
72 "trn1 v5.4h, v21.4h, v23.4h \n"
73 "trn2 v6.4h, v20.4h, v22.4h \n"
74 "trn1 v4.4h, v20.4h, v22.4h \n"
76 "trn2 v21.2s, v1.2s, v5.2s \n"
77 "trn1 v17.2s, v1.2s, v5.2s \n"
78 "trn2 v20.2s, v0.2s, v4.2s \n"
79 "trn1 v16.2s, v0.2s, v4.2s \n"
80 "trn2 v23.2s, v3.2s, v7.2s \n"
81 "trn1 v19.2s, v3.2s, v7.2s \n"
82 "trn2 v22.2s, v2.2s, v6.2s \n"
83 "trn1 v18.2s, v2.2s, v6.2s \n"
88 "st1 {v17.8b}, [%0], %6 \n"
90 "st1 {v16.8b}, [%0], %6 \n"
92 "st1 {v19.8b}, [%0], %6 \n"
94 "st1 {v18.8b}, [%0], %6 \n"
96 "st1 {v21.8b}, [%0], %6 \n"
98 "st1 {v20.8b}, [%0], %6 \n"
100 "st1 {v23.8b}, [%0], %6 \n"
102 "st1 {v22.8b}, [%0] \n"
104 "add %1, %1, #8 \n" // src += 8
105 "add %2, %2, %6, lsl #3 \n" // dst += 8 * dst_stride
106 "subs %3, %3, #8 \n" // w -= 8
109 // add 8 back to counter. if the result is 0 there are
114 // some residual, so between 1 and 7 lines left to transpose
124 "ld1 {v0.s}[0], [%0], %5 \n"
126 "ld1 {v0.s}[1], [%0], %5 \n"
128 "ld1 {v0.s}[2], [%0], %5 \n"
130 "ld1 {v0.s}[3], [%0], %5 \n"
132 "ld1 {v1.s}[0], [%0], %5 \n"
134 "ld1 {v1.s}[1], [%0], %5 \n"
136 "ld1 {v1.s}[2], [%0], %5 \n"
138 "ld1 {v1.s}[3], [%0] \n"
143 "ld1 {v2.16b}, [%4] \n"
145 "tbl v3.16b, {v0.16b}, v2.16b \n"
146 "tbl v0.16b, {v1.16b}, v2.16b \n"
148 // TODO(frkoenig): Rework shuffle above to
149 // write out with 4 instead of 8 writes.
151 "st1 {v3.s}[0], [%0], %6 \n"
153 "st1 {v3.s}[1], [%0], %6 \n"
155 "st1 {v3.s}[2], [%0], %6 \n"
157 "st1 {v3.s}[3], [%0] \n"
161 "st1 {v0.s}[0], [%0], %6 \n"
163 "st1 {v0.s}[1], [%0], %6 \n"
165 "st1 {v0.s}[2], [%0], %6 \n"
167 "st1 {v0.s}[3], [%0] \n"
169 "add %1, %1, #4 \n" // src += 4
170 "add %2, %2, %6, lsl #2 \n" // dst += 4 * dst_stride
171 "subs %3, %3, #4 \n" // w -= 4
174 // some residual, check to see if it includes a 2x8 block,
183 "ld1 {v0.h}[0], [%0], %5 \n"
185 "ld1 {v1.h}[0], [%0], %5 \n"
187 "ld1 {v0.h}[1], [%0], %5 \n"
189 "ld1 {v1.h}[1], [%0], %5 \n"
191 "ld1 {v0.h}[2], [%0], %5 \n"
193 "ld1 {v1.h}[2], [%0], %5 \n"
195 "ld1 {v0.h}[3], [%0], %5 \n"
197 "ld1 {v1.h}[3], [%0] \n"
199 "trn2 v2.8b, v0.8b, v1.8b \n"
200 "trn1 v3.8b, v0.8b, v1.8b \n"
205 "st1 {v3.8b}, [%0], %6 \n"
207 "st1 {v2.8b}, [%0] \n"
209 "add %1, %1, #2 \n" // src += 2
210 "add %2, %2, %6, lsl #1 \n" // dst += 2 * dst_stride
211 "subs %3, %3, #2 \n" // w -= 2
217 "ld1 {v0.b}[0], [%1], %5 \n"
219 "ld1 {v0.b}[1], [%1], %5 \n"
221 "ld1 {v0.b}[2], [%1], %5 \n"
223 "ld1 {v0.b}[3], [%1], %5 \n"
225 "ld1 {v0.b}[4], [%1], %5 \n"
227 "ld1 {v0.b}[5], [%1], %5 \n"
229 "ld1 {v0.b}[6], [%1], %5 \n"
231 "ld1 {v0.b}[7], [%1] \n"
234 "st1 {v0.8b}, [%2] \n"
238 : "+r"(src_temp), // %0
242 : "r"(&kVTbl4x4Transpose), // %4
243 "r"(static_cast<ptrdiff_t>(src_stride)), // %5
244 "r"(static_cast<ptrdiff_t>(dst_stride)) // %6
245 : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
246 "v17", "v18", "v19", "v20", "v21", "v22", "v23"
250 static uint8 kVTbl4x4TransposeDi[32] =
251 { 0, 16, 32, 48, 2, 18, 34, 50, 4, 20, 36, 52, 6, 22, 38, 54,
252 1, 17, 33, 49, 3, 19, 35, 51, 5, 21, 37, 53, 7, 23, 39, 55};
254 void TransposeUVWx8_NEON(const uint8* src, int src_stride,
255 uint8* dst_a, int dst_stride_a,
256 uint8* dst_b, int dst_stride_b,
258 const uint8* src_temp = NULL;
259 int64 width64 = (int64) width; // Work around clang 3.4 warning.
261 // loops are on blocks of 8. loop will stop when
262 // counter gets to or below 0. starting the counter
263 // at w-8 allow for this
266 // handle 8x8 blocks. this should be the majority of the plane
271 "ld1 {v0.16b}, [%0], %5 \n"
273 "ld1 {v1.16b}, [%0], %5 \n"
275 "ld1 {v2.16b}, [%0], %5 \n"
277 "ld1 {v3.16b}, [%0], %5 \n"
279 "ld1 {v4.16b}, [%0], %5 \n"
281 "ld1 {v5.16b}, [%0], %5 \n"
283 "ld1 {v6.16b}, [%0], %5 \n"
285 "ld1 {v7.16b}, [%0] \n"
287 "trn1 v16.16b, v0.16b, v1.16b \n"
288 "trn2 v17.16b, v0.16b, v1.16b \n"
289 "trn1 v18.16b, v2.16b, v3.16b \n"
290 "trn2 v19.16b, v2.16b, v3.16b \n"
291 "trn1 v20.16b, v4.16b, v5.16b \n"
292 "trn2 v21.16b, v4.16b, v5.16b \n"
293 "trn1 v22.16b, v6.16b, v7.16b \n"
294 "trn2 v23.16b, v6.16b, v7.16b \n"
296 "trn1 v0.8h, v16.8h, v18.8h \n"
297 "trn2 v1.8h, v16.8h, v18.8h \n"
298 "trn1 v2.8h, v20.8h, v22.8h \n"
299 "trn2 v3.8h, v20.8h, v22.8h \n"
300 "trn1 v4.8h, v17.8h, v19.8h \n"
301 "trn2 v5.8h, v17.8h, v19.8h \n"
302 "trn1 v6.8h, v21.8h, v23.8h \n"
303 "trn2 v7.8h, v21.8h, v23.8h \n"
305 "trn1 v16.4s, v0.4s, v2.4s \n"
306 "trn2 v17.4s, v0.4s, v2.4s \n"
307 "trn1 v18.4s, v1.4s, v3.4s \n"
308 "trn2 v19.4s, v1.4s, v3.4s \n"
309 "trn1 v20.4s, v4.4s, v6.4s \n"
310 "trn2 v21.4s, v4.4s, v6.4s \n"
311 "trn1 v22.4s, v5.4s, v7.4s \n"
312 "trn2 v23.4s, v5.4s, v7.4s \n"
317 "st1 {v16.d}[0], [%0], %6 \n"
319 "st1 {v18.d}[0], [%0], %6 \n"
321 "st1 {v17.d}[0], [%0], %6 \n"
323 "st1 {v19.d}[0], [%0], %6 \n"
325 "st1 {v16.d}[1], [%0], %6 \n"
327 "st1 {v18.d}[1], [%0], %6 \n"
329 "st1 {v17.d}[1], [%0], %6 \n"
331 "st1 {v19.d}[1], [%0] \n"
336 "st1 {v20.d}[0], [%0], %7 \n"
338 "st1 {v22.d}[0], [%0], %7 \n"
340 "st1 {v21.d}[0], [%0], %7 \n"
342 "st1 {v23.d}[0], [%0], %7 \n"
344 "st1 {v20.d}[1], [%0], %7 \n"
346 "st1 {v22.d}[1], [%0], %7 \n"
348 "st1 {v21.d}[1], [%0], %7 \n"
350 "st1 {v23.d}[1], [%0] \n"
352 "add %1, %1, #16 \n" // src += 8*2
353 "add %2, %2, %6, lsl #3 \n" // dst_a += 8 * dst_stride_a
354 "add %3, %3, %7, lsl #3 \n" // dst_b += 8 * dst_stride_b
355 "subs %4, %4, #8 \n" // w -= 8
358 // add 8 back to counter. if the result is 0 there are
363 // some residual, so between 1 and 7 lines left to transpose
370 // TODO(frkoenig): Clean this up
374 "ld1 {v0.8b}, [%0], %5 \n"
376 "ld1 {v1.8b}, [%0], %5 \n"
378 "ld1 {v2.8b}, [%0], %5 \n"
380 "ld1 {v3.8b}, [%0], %5 \n"
382 "ld1 {v4.8b}, [%0], %5 \n"
384 "ld1 {v5.8b}, [%0], %5 \n"
386 "ld1 {v6.8b}, [%0], %5 \n"
388 "ld1 {v7.8b}, [%0] \n"
391 "ld1 {v30.16b}, [%8], #16 \n"
392 "ld1 {v31.16b}, [%8] \n"
394 "tbl v16.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v30.16b \n"
395 "tbl v17.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v31.16b \n"
396 "tbl v18.16b, {v4.16b, v5.16b, v6.16b, v7.16b}, v30.16b \n"
397 "tbl v19.16b, {v4.16b, v5.16b, v6.16b, v7.16b}, v31.16b \n"
402 "st1 {v16.s}[0], [%0], %6 \n"
404 "st1 {v16.s}[1], [%0], %6 \n"
406 "st1 {v16.s}[2], [%0], %6 \n"
408 "st1 {v16.s}[3], [%0], %6 \n"
412 "st1 {v18.s}[0], [%0], %6 \n"
414 "st1 {v18.s}[1], [%0], %6 \n"
416 "st1 {v18.s}[2], [%0], %6 \n"
418 "st1 {v18.s}[3], [%0] \n"
423 "st1 {v17.s}[0], [%0], %7 \n"
425 "st1 {v17.s}[1], [%0], %7 \n"
427 "st1 {v17.s}[2], [%0], %7 \n"
429 "st1 {v17.s}[3], [%0], %7 \n"
433 "st1 {v19.s}[0], [%0], %7 \n"
435 "st1 {v19.s}[1], [%0], %7 \n"
437 "st1 {v19.s}[2], [%0], %7 \n"
439 "st1 {v19.s}[3], [%0] \n"
441 "add %1, %1, #8 \n" // src += 4 * 2
442 "add %2, %2, %6, lsl #2 \n" // dst_a += 4 * dst_stride_a
443 "add %3, %3, %7, lsl #2 \n" // dst_b += 4 * dst_stride_b
444 "subs %4, %4, #4 \n" // w -= 4
447 // some residual, check to see if it includes a 2x8 block,
456 "ld2 {v0.h, v1.h}[0], [%0], %5 \n"
458 "ld2 {v2.h, v3.h}[0], [%0], %5 \n"
460 "ld2 {v0.h, v1.h}[1], [%0], %5 \n"
462 "ld2 {v2.h, v3.h}[1], [%0], %5 \n"
464 "ld2 {v0.h, v1.h}[2], [%0], %5 \n"
466 "ld2 {v2.h, v3.h}[2], [%0], %5 \n"
468 "ld2 {v0.h, v1.h}[3], [%0], %5 \n"
470 "ld2 {v2.h, v3.h}[3], [%0] \n"
472 "trn1 v4.8b, v0.8b, v2.8b \n"
473 "trn2 v5.8b, v0.8b, v2.8b \n"
474 "trn1 v6.8b, v1.8b, v3.8b \n"
475 "trn2 v7.8b, v1.8b, v3.8b \n"
480 "st1 {v4.d}[0], [%0], %6 \n"
482 "st1 {v6.d}[0], [%0] \n"
487 "st1 {v5.d}[0], [%0], %7 \n"
489 "st1 {v7.d}[0], [%0] \n"
491 "add %1, %1, #4 \n" // src += 2 * 2
492 "add %2, %2, %6, lsl #1 \n" // dst_a += 2 * dst_stride_a
493 "add %3, %3, %7, lsl #1 \n" // dst_b += 2 * dst_stride_b
494 "subs %4, %4, #2 \n" // w -= 2
500 "ld2 {v0.b, v1.b}[0], [%1], %5 \n"
502 "ld2 {v0.b, v1.b}[1], [%1], %5 \n"
504 "ld2 {v0.b, v1.b}[2], [%1], %5 \n"
506 "ld2 {v0.b, v1.b}[3], [%1], %5 \n"
508 "ld2 {v0.b, v1.b}[4], [%1], %5 \n"
510 "ld2 {v0.b, v1.b}[5], [%1], %5 \n"
512 "ld2 {v0.b, v1.b}[6], [%1], %5 \n"
514 "ld2 {v0.b, v1.b}[7], [%1] \n"
517 "st1 {v0.d}[0], [%2] \n"
519 "st1 {v1.d}[0], [%3] \n"
523 : "+r"(src_temp), // %0
528 : "r"(static_cast<ptrdiff_t>(src_stride)), // %5
529 "r"(static_cast<ptrdiff_t>(dst_stride_a)), // %6
530 "r"(static_cast<ptrdiff_t>(dst_stride_b)), // %7
531 "r"(&kVTbl4x4TransposeDi) // %8
533 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
534 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
538 #endif // !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
542 } // namespace libyuv