rotate_neon64.cc 19 KB

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