adler32_neon.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /* Copyright (C) 1995-2011, 2016 Mark Adler
  2. * Copyright (C) 2017 ARM Holdings Inc.
  3. * Authors:
  4. * Adenilson Cavalcanti <adenilson.cavalcanti@arm.com>
  5. * Adam Stylinski <kungfujesus06@gmail.com>
  6. * For conditions of distribution and use, see copyright notice in zlib.h
  7. */
  8. #ifdef ARM_NEON
  9. #include "neon_intrins.h"
  10. #include "zbuild.h"
  11. #include "adler32_p.h"
  12. static void NEON_accum32(uint32_t *s, const uint8_t *buf, size_t len) {
  13. static const uint16_t ALIGNED_(16) taps[64] = {
  14. 64, 63, 62, 61, 60, 59, 58, 57,
  15. 56, 55, 54, 53, 52, 51, 50, 49,
  16. 48, 47, 46, 45, 44, 43, 42, 41,
  17. 40, 39, 38, 37, 36, 35, 34, 33,
  18. 32, 31, 30, 29, 28, 27, 26, 25,
  19. 24, 23, 22, 21, 20, 19, 18, 17,
  20. 16, 15, 14, 13, 12, 11, 10, 9,
  21. 8, 7, 6, 5, 4, 3, 2, 1 };
  22. uint32x4_t adacc = vdupq_n_u32(0);
  23. uint32x4_t s2acc = vdupq_n_u32(0);
  24. uint32x4_t s2acc_0 = vdupq_n_u32(0);
  25. uint32x4_t s2acc_1 = vdupq_n_u32(0);
  26. uint32x4_t s2acc_2 = vdupq_n_u32(0);
  27. adacc = vsetq_lane_u32(s[0], adacc, 0);
  28. s2acc = vsetq_lane_u32(s[1], s2acc, 0);
  29. uint32x4_t s3acc = vdupq_n_u32(0);
  30. uint32x4_t adacc_prev = adacc;
  31. uint16x8_t s2_0, s2_1, s2_2, s2_3;
  32. s2_0 = s2_1 = s2_2 = s2_3 = vdupq_n_u16(0);
  33. uint16x8_t s2_4, s2_5, s2_6, s2_7;
  34. s2_4 = s2_5 = s2_6 = s2_7 = vdupq_n_u16(0);
  35. size_t num_iter = len >> 2;
  36. int rem = len & 3;
  37. for (size_t i = 0; i < num_iter; ++i) {
  38. uint8x16x4_t d0_d3 = vld1q_u8_x4(buf);
  39. /* Unfortunately it doesn't look like there's a direct sum 8 bit to 32
  40. * bit instruction, we'll have to make due summing to 16 bits first */
  41. uint16x8x2_t hsum, hsum_fold;
  42. hsum.val[0] = vpaddlq_u8(d0_d3.val[0]);
  43. hsum.val[1] = vpaddlq_u8(d0_d3.val[1]);
  44. hsum_fold.val[0] = vpadalq_u8(hsum.val[0], d0_d3.val[2]);
  45. hsum_fold.val[1] = vpadalq_u8(hsum.val[1], d0_d3.val[3]);
  46. adacc = vpadalq_u16(adacc, hsum_fold.val[0]);
  47. s3acc = vaddq_u32(s3acc, adacc_prev);
  48. adacc = vpadalq_u16(adacc, hsum_fold.val[1]);
  49. /* If we do straight widening additions to the 16 bit values, we don't incur
  50. * the usual penalties of a pairwise add. We can defer the multiplications
  51. * until the very end. These will not overflow because we are incurring at
  52. * most 408 loop iterations (NMAX / 64), and a given lane is only going to be
  53. * summed into once. This means for the maximum input size, the largest value
  54. * we will see is 255 * 102 = 26010, safely under uint16 max */
  55. s2_0 = vaddw_u8(s2_0, vget_low_u8(d0_d3.val[0]));
  56. s2_1 = vaddw_high_u8(s2_1, d0_d3.val[0]);
  57. s2_2 = vaddw_u8(s2_2, vget_low_u8(d0_d3.val[1]));
  58. s2_3 = vaddw_high_u8(s2_3, d0_d3.val[1]);
  59. s2_4 = vaddw_u8(s2_4, vget_low_u8(d0_d3.val[2]));
  60. s2_5 = vaddw_high_u8(s2_5, d0_d3.val[2]);
  61. s2_6 = vaddw_u8(s2_6, vget_low_u8(d0_d3.val[3]));
  62. s2_7 = vaddw_high_u8(s2_7, d0_d3.val[3]);
  63. adacc_prev = adacc;
  64. buf += 64;
  65. }
  66. s3acc = vshlq_n_u32(s3acc, 6);
  67. if (rem) {
  68. uint32x4_t s3acc_0 = vdupq_n_u32(0);
  69. while (rem--) {
  70. uint8x16_t d0 = vld1q_u8(buf);
  71. uint16x8_t adler;
  72. adler = vpaddlq_u8(d0);
  73. s2_6 = vaddw_u8(s2_6, vget_low_u8(d0));
  74. s2_7 = vaddw_high_u8(s2_7, d0);
  75. adacc = vpadalq_u16(adacc, adler);
  76. s3acc_0 = vaddq_u32(s3acc_0, adacc_prev);
  77. adacc_prev = adacc;
  78. buf += 16;
  79. }
  80. s3acc_0 = vshlq_n_u32(s3acc_0, 4);
  81. s3acc = vaddq_u32(s3acc_0, s3acc);
  82. }
  83. uint16x8x4_t t0_t3 = vld1q_u16_x4(taps);
  84. uint16x8x4_t t4_t7 = vld1q_u16_x4(taps + 32);
  85. s2acc = vmlal_high_u16(s2acc, t0_t3.val[0], s2_0);
  86. s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[0]), vget_low_u16(s2_0));
  87. s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[1], s2_1);
  88. s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[1]), vget_low_u16(s2_1));
  89. s2acc = vmlal_high_u16(s2acc, t0_t3.val[2], s2_2);
  90. s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[2]), vget_low_u16(s2_2));
  91. s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[3], s2_3);
  92. s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[3]), vget_low_u16(s2_3));
  93. s2acc = vmlal_high_u16(s2acc, t4_t7.val[0], s2_4);
  94. s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[0]), vget_low_u16(s2_4));
  95. s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[1], s2_5);
  96. s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[1]), vget_low_u16(s2_5));
  97. s2acc = vmlal_high_u16(s2acc, t4_t7.val[2], s2_6);
  98. s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[2]), vget_low_u16(s2_6));
  99. s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[3], s2_7);
  100. s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[3]), vget_low_u16(s2_7));
  101. s2acc = vaddq_u32(s2acc_0, s2acc);
  102. s2acc_2 = vaddq_u32(s2acc_1, s2acc_2);
  103. s2acc = vaddq_u32(s2acc, s2acc_2);
  104. uint32x2_t adacc2, s2acc2, as;
  105. s2acc = vaddq_u32(s2acc, s3acc);
  106. adacc2 = vpadd_u32(vget_low_u32(adacc), vget_high_u32(adacc));
  107. s2acc2 = vpadd_u32(vget_low_u32(s2acc), vget_high_u32(s2acc));
  108. as = vpadd_u32(adacc2, s2acc2);
  109. s[0] = vget_lane_u32(as, 0);
  110. s[1] = vget_lane_u32(as, 1);
  111. }
  112. static void NEON_handle_tail(uint32_t *pair, const uint8_t *buf, size_t len) {
  113. unsigned int i;
  114. for (i = 0; i < len; ++i) {
  115. pair[0] += buf[i];
  116. pair[1] += pair[0];
  117. }
  118. }
  119. Z_INTERNAL uint32_t adler32_neon(uint32_t adler, const uint8_t *buf, size_t len) {
  120. /* split Adler-32 into component sums */
  121. uint32_t sum2 = (adler >> 16) & 0xffff;
  122. adler &= 0xffff;
  123. /* in case user likes doing a byte at a time, keep it fast */
  124. if (len == 1)
  125. return adler32_len_1(adler, buf, sum2);
  126. /* initial Adler-32 value (deferred check for len == 1 speed) */
  127. if (buf == NULL)
  128. return 1L;
  129. /* in case short lengths are provided, keep it somewhat fast */
  130. if (len < 16)
  131. return adler32_len_16(adler, buf, len, sum2);
  132. uint32_t pair[2];
  133. int n = NMAX;
  134. unsigned int done = 0;
  135. /* Split Adler-32 into component sums, it can be supplied by
  136. * the caller sites (e.g. in a PNG file).
  137. */
  138. pair[0] = adler;
  139. pair[1] = sum2;
  140. /* If memory is not SIMD aligned, do scalar sums to an aligned
  141. * offset, provided that doing so doesn't completely eliminate
  142. * SIMD operation. Aligned loads are still faster on ARM, even
  143. * though there's no explicit aligned load instruction */
  144. unsigned int align_offset = ((uintptr_t)buf & 15);
  145. unsigned int align_adj = (align_offset) ? 16 - align_offset : 0;
  146. if (align_offset && len >= (16 + align_adj)) {
  147. NEON_handle_tail(pair, buf, align_adj);
  148. n -= align_adj;
  149. done += align_adj;
  150. } else {
  151. /* If here, we failed the len criteria test, it wouldn't be
  152. * worthwhile to do scalar aligning sums */
  153. align_adj = 0;
  154. }
  155. while (done < len) {
  156. int remaining = (int)(len - done);
  157. n = MIN(remaining, (done == align_adj) ? n : NMAX);
  158. if (n < 16)
  159. break;
  160. NEON_accum32(pair, buf + done, n >> 4);
  161. pair[0] %= BASE;
  162. pair[1] %= BASE;
  163. int actual_nsums = (n >> 4) << 4;
  164. done += actual_nsums;
  165. }
  166. /* Handle the tail elements. */
  167. if (done < len) {
  168. NEON_handle_tail(pair, (buf + done), len - done);
  169. pair[0] %= BASE;
  170. pair[1] %= BASE;
  171. }
  172. /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */
  173. return (pair[1] << 16) | pair[0];
  174. }
  175. #endif