Line | Count | Source |
1 | | /* adler32_p.h -- Private inline functions and macros shared with |
2 | | * different computation of the Adler-32 checksum |
3 | | * of a data stream. |
4 | | * Copyright (C) 1995-2011, 2016 Mark Adler |
5 | | * For conditions of distribution and use, see copyright notice in zlib.h |
6 | | */ |
7 | | |
8 | | #ifndef ADLER32_P_H |
9 | | #define ADLER32_P_H |
10 | | |
11 | | #include "zendian.h" |
12 | | |
13 | 107k | #define BASE 65521U /* largest prime smaller than 65536 */ |
14 | 0 | #define NMAX 5552 |
15 | | /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ |
16 | | #define NMAX_ALIGNED32 (NMAX & ~31) |
17 | | /* NMAX rounded down to a multiple of 32 is 5536 */ |
18 | | |
19 | 46.8k | #define ADLER_DO1(sum1, sum2, buf, i) {(sum1) += buf[(i)]; (sum2) += (sum1);} |
20 | 20.0k | #define ADLER_DO2(sum1, sum2, buf, i) {ADLER_DO1(sum1, sum2, buf, i); ADLER_DO1(sum1, sum2, buf, i+1);} |
21 | 6.65k | #define ADLER_DO4(sum1, sum2, buf, i) {ADLER_DO2(sum1, sum2, buf, i); ADLER_DO2(sum1, sum2, buf, i+2);} |
22 | | #define ADLER_DO8(sum1, sum2, buf, i) {ADLER_DO4(sum1, sum2, buf, i); ADLER_DO4(sum1, sum2, buf, i+4);} |
23 | | #define ADLER_DO16(sum1, sum2, buf) {ADLER_DO8(sum1, sum2, buf, 0); ADLER_DO8(sum1, sum2, buf, 8);} |
24 | | |
25 | | Z_FORCEINLINE static void adler32_copy_align(uint32_t *Z_RESTRICT adler, uint8_t *dst, const uint8_t *buf, size_t len, |
26 | 0 | uint32_t *Z_RESTRICT sum2, const int MAX_LEN, const int COPY) { |
27 | 0 | Z_UNUSED(MAX_LEN); |
28 | 0 | if (len & 1) { |
29 | 0 | if (COPY) { |
30 | 0 | *dst = *buf; |
31 | 0 | dst += 1; |
32 | 0 | } |
33 | 0 | ADLER_DO1(*adler, *sum2, buf, 0); |
34 | 0 | buf += 1; |
35 | 0 | } |
36 | 0 | if (len & 2) { |
37 | 0 | if (COPY) { |
38 | 0 | memcpy(dst, buf, 2); |
39 | 0 | dst += 2; |
40 | 0 | } |
41 | 0 | ADLER_DO2(*adler, *sum2, buf, 0); |
42 | 0 | buf += 2; |
43 | 0 | } |
44 | 0 | while (len >= 4) { |
45 | 0 | if (COPY) { |
46 | 0 | memcpy(dst, buf, 4); |
47 | 0 | dst += 4; |
48 | 0 | } |
49 | 0 | len -= 4; |
50 | 0 | ADLER_DO4(*adler, *sum2, buf, 0); |
51 | 0 | buf += 4; |
52 | 0 | } |
53 | 0 | } Unexecuted instantiation: adler32_ssse3.c:adler32_copy_align Unexecuted instantiation: adler32_sse42.c:adler32_copy_align Unexecuted instantiation: adler32_avx2.c:adler32_copy_align Unexecuted instantiation: adler32_avx512.c:adler32_copy_align Unexecuted instantiation: adler32_avx512_vnni.c:adler32_copy_align Unexecuted instantiation: adler32_c.c:adler32_copy_align |
54 | | |
55 | | /* SIMD Within A Register (SWAR) scalar adler32. Splits bytes into |
56 | | * even/odd lanes packed as 4x16-bit in uint64_t, with prefix sums for s2. |
57 | | * Reduction uses multiply-and-shift with positional weight constants. |
58 | | * |
59 | | * Technique pioneered by Michael Niedermayer <michaelni@gmx.at>. |
60 | | * Max chunk: 23 iterations * 8 bytes = 184 (255*23 = 5865 < 65535). */ |
61 | | #define ADLER32_SWAR_MAX_BYTES (23 * 8) |
62 | 0 | #define ADLER32_SWAR_EVEN_MASK 0x00FF00FF00FF00FFULL |
63 | 0 | #define ADLER32_SWAR_HSUM 0x1000100010001ULL |
64 | | |
65 | | Z_FORCEINLINE static void adler32_swar(uint32_t *adler, uint8_t *dst, const uint8_t *buf, size_t len, |
66 | 0 | uint32_t *sum2, const int COPY) { |
67 | 0 | uint64_t sum_even = 0, sum_odd = 0, prefix_even = 0, prefix_odd = 0; |
68 | |
|
69 | 0 | *sum2 += *adler * (uint32_t)len; |
70 | |
|
71 | 0 | const uint64_t *src64 = (const uint64_t *)buf; |
72 | |
|
73 | 0 | while (len >= 16) { |
74 | 0 | uint64_t v0 = src64[0]; |
75 | 0 | uint64_t v1 = src64[1]; |
76 | 0 | if (COPY) { |
77 | 0 | memcpy(dst, &v0, sizeof(v0)); |
78 | 0 | memcpy(dst + 8, &v1, sizeof(v1)); |
79 | 0 | dst += 16; |
80 | 0 | } |
81 | |
|
82 | 0 | prefix_even += sum_even; |
83 | 0 | prefix_odd += sum_odd; |
84 | 0 | sum_even += v0 & ADLER32_SWAR_EVEN_MASK; |
85 | 0 | sum_odd += (v0 >> 8) & ADLER32_SWAR_EVEN_MASK; |
86 | |
|
87 | 0 | prefix_even += sum_even; |
88 | 0 | prefix_odd += sum_odd; |
89 | 0 | sum_even += v1 & ADLER32_SWAR_EVEN_MASK; |
90 | 0 | sum_odd += (v1 >> 8) & ADLER32_SWAR_EVEN_MASK; |
91 | |
|
92 | 0 | src64 += 2; |
93 | 0 | len -= 16; |
94 | 0 | } |
95 | | |
96 | | /* Handle remaining 8 bytes if present */ |
97 | 0 | if (len >= 8) { |
98 | 0 | uint64_t v = *src64; |
99 | 0 | if (COPY) |
100 | 0 | memcpy(dst, &v, sizeof(v)); |
101 | |
|
102 | 0 | prefix_even += sum_even; |
103 | 0 | prefix_odd += sum_odd; |
104 | 0 | sum_even += v & ADLER32_SWAR_EVEN_MASK; |
105 | 0 | sum_odd += (v >> 8) & ADLER32_SWAR_EVEN_MASK; |
106 | 0 | } |
107 | | |
108 | | /* Horizontal sum of 4x16-bit lanes for s1 */ |
109 | 0 | *adler += (uint32_t)(((sum_even + sum_odd) * ADLER32_SWAR_HSUM) >> 48); |
110 | | |
111 | | /* Widen prefix sums to 32-bit pairs and horizontal sum for s2 */ |
112 | 0 | uint64_t pe_lo = prefix_even & 0xFFFF0000FFFFULL; |
113 | 0 | uint64_t pe_hi = (prefix_even >> 16) & 0xFFFF0000FFFFULL; |
114 | 0 | uint64_t po_lo = prefix_odd & 0xFFFF0000FFFFULL; |
115 | 0 | uint64_t po_hi = (prefix_odd >> 16) & 0xFFFF0000FFFFULL; |
116 | |
|
117 | 0 | *sum2 += (uint32_t)(((pe_lo + po_lo + pe_hi + po_hi) * 0x800000008ULL) >> 32); |
118 | | |
119 | | /* Positional weights [8,7,6,5,4,3,2,1] per 8-byte group for s2. |
120 | | * On big-endian the even mask captures odd-index memory bytes (b1,b3,b5,b7) |
121 | | * so HSUM (+1 per odd-index byte) must be applied to sum_even, not sum_odd. */ |
122 | 0 | #if BYTE_ORDER == LITTLE_ENDIAN |
123 | 0 | *sum2 += 2 * (uint32_t)((sum_even * 0x4000300020001ULL) >> 48) |
124 | 0 | + (uint32_t)((sum_odd * ADLER32_SWAR_HSUM) >> 48) |
125 | 0 | + 2 * (uint32_t)((sum_odd * 0x3000200010000ULL) >> 48); |
126 | | #else |
127 | | *sum2 += 2 * (uint32_t)((sum_even * 0x0000100020003ULL) >> 48) |
128 | | + (uint32_t)((sum_even * ADLER32_SWAR_HSUM) >> 48) |
129 | | + 2 * (uint32_t)((sum_odd * 0x1000200030004ULL) >> 48); |
130 | | #endif |
131 | 0 | } Unexecuted instantiation: adler32_ssse3.c:adler32_swar Unexecuted instantiation: adler32_sse42.c:adler32_swar Unexecuted instantiation: adler32_avx2.c:adler32_swar Unexecuted instantiation: adler32_avx512.c:adler32_swar Unexecuted instantiation: adler32_avx512_vnni.c:adler32_swar Unexecuted instantiation: adler32_c.c:adler32_swar |
132 | | |
133 | | Z_FORCEINLINE static uint32_t adler32_copy_tail(uint32_t adler, uint8_t *dst, const uint8_t *buf, size_t len, |
134 | 8.59k | uint32_t sum2, const int REBASE, const int MAX_LEN, const int COPY) { |
135 | 8.59k | if (len) { |
136 | 8.59k | Z_UNUSED(MAX_LEN); |
137 | | /* Process using packed 64-bit arithmetic when source is aligned */ |
138 | 8.59k | while (len >= 8 && ((uintptr_t)buf & 7) == 0) { |
139 | 0 | size_t chunk = MIN(ALIGN_DOWN(len, (size_t)8), (size_t)ADLER32_SWAR_MAX_BYTES); |
140 | 0 | adler32_swar(&adler, dst, buf, chunk, &sum2, COPY); |
141 | 0 | buf += chunk; |
142 | 0 | if (COPY) |
143 | 0 | dst += chunk; |
144 | 0 | len -= chunk; |
145 | 0 | } |
146 | | /* DO4 loop avoids GCC x86 register pressure from hoisted DO8/DO16 loads. */ |
147 | 15.2k | while (len >= 4) { |
148 | 6.65k | if (COPY) { |
149 | 6.65k | memcpy(dst, buf, 4); |
150 | 6.65k | dst += 4; |
151 | 6.65k | } |
152 | 6.65k | len -= 4; |
153 | 6.65k | ADLER_DO4(adler, sum2, buf, 0); |
154 | 6.65k | buf += 4; |
155 | 6.65k | } |
156 | 8.59k | if (len & 2) { |
157 | 6.75k | if (COPY) { |
158 | 6.75k | memcpy(dst, buf, 2); |
159 | 6.75k | dst += 2; |
160 | 6.75k | } |
161 | 6.75k | ADLER_DO2(adler, sum2, buf, 0); |
162 | 6.75k | buf += 2; |
163 | 6.75k | } |
164 | 8.59k | if (len & 1) { |
165 | 6.67k | if (COPY) |
166 | 6.67k | *dst = *buf; |
167 | 6.67k | ADLER_DO1(adler, sum2, buf, 0); |
168 | 6.67k | } |
169 | 8.59k | } |
170 | 8.59k | if (REBASE) { |
171 | 8.59k | adler %= BASE; |
172 | 8.59k | sum2 %= BASE; |
173 | 8.59k | } |
174 | | /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */ |
175 | 8.59k | return adler | (sum2 << 16); |
176 | 8.59k | } Unexecuted instantiation: adler32_ssse3.c:adler32_copy_tail adler32_sse42.c:adler32_copy_tail Line | Count | Source | 134 | 2.01k | uint32_t sum2, const int REBASE, const int MAX_LEN, const int COPY) { | 135 | 2.01k | if (len) { | 136 | 2.01k | Z_UNUSED(MAX_LEN); | 137 | | /* Process using packed 64-bit arithmetic when source is aligned */ | 138 | 2.01k | while (len >= 8 && ((uintptr_t)buf & 7) == 0) { | 139 | 0 | size_t chunk = MIN(ALIGN_DOWN(len, (size_t)8), (size_t)ADLER32_SWAR_MAX_BYTES); | 140 | 0 | adler32_swar(&adler, dst, buf, chunk, &sum2, COPY); | 141 | 0 | buf += chunk; | 142 | 0 | if (COPY) | 143 | 0 | dst += chunk; | 144 | 0 | len -= chunk; | 145 | 0 | } | 146 | | /* DO4 loop avoids GCC x86 register pressure from hoisted DO8/DO16 loads. */ | 147 | 5.34k | while (len >= 4) { | 148 | 3.33k | if (COPY) { | 149 | 3.33k | memcpy(dst, buf, 4); | 150 | 3.33k | dst += 4; | 151 | 3.33k | } | 152 | 3.33k | len -= 4; | 153 | 3.33k | ADLER_DO4(adler, sum2, buf, 0); | 154 | 3.33k | buf += 4; | 155 | 3.33k | } | 156 | 2.01k | if (len & 2) { | 157 | 1.12k | if (COPY) { | 158 | 1.12k | memcpy(dst, buf, 2); | 159 | 1.12k | dst += 2; | 160 | 1.12k | } | 161 | 1.12k | ADLER_DO2(adler, sum2, buf, 0); | 162 | 1.12k | buf += 2; | 163 | 1.12k | } | 164 | 2.01k | if (len & 1) { | 165 | 1.07k | if (COPY) | 166 | 1.07k | *dst = *buf; | 167 | 1.07k | ADLER_DO1(adler, sum2, buf, 0); | 168 | 1.07k | } | 169 | 2.01k | } | 170 | 2.01k | if (REBASE) { | 171 | 2.01k | adler %= BASE; | 172 | 2.01k | sum2 %= BASE; | 173 | 2.01k | } | 174 | | /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */ | 175 | 2.01k | return adler | (sum2 << 16); | 176 | 2.01k | } |
adler32_avx2.c:adler32_copy_tail Line | Count | Source | 134 | 6.57k | uint32_t sum2, const int REBASE, const int MAX_LEN, const int COPY) { | 135 | 6.57k | if (len) { | 136 | 6.57k | Z_UNUSED(MAX_LEN); | 137 | | /* Process using packed 64-bit arithmetic when source is aligned */ | 138 | 6.57k | while (len >= 8 && ((uintptr_t)buf & 7) == 0) { | 139 | 0 | size_t chunk = MIN(ALIGN_DOWN(len, (size_t)8), (size_t)ADLER32_SWAR_MAX_BYTES); | 140 | 0 | adler32_swar(&adler, dst, buf, chunk, &sum2, COPY); | 141 | 0 | buf += chunk; | 142 | 0 | if (COPY) | 143 | 0 | dst += chunk; | 144 | 0 | len -= chunk; | 145 | 0 | } | 146 | | /* DO4 loop avoids GCC x86 register pressure from hoisted DO8/DO16 loads. */ | 147 | 9.90k | while (len >= 4) { | 148 | 3.32k | if (COPY) { | 149 | 3.32k | memcpy(dst, buf, 4); | 150 | 3.32k | dst += 4; | 151 | 3.32k | } | 152 | 3.32k | len -= 4; | 153 | 3.32k | ADLER_DO4(adler, sum2, buf, 0); | 154 | 3.32k | buf += 4; | 155 | 3.32k | } | 156 | 6.57k | if (len & 2) { | 157 | 5.62k | if (COPY) { | 158 | 5.62k | memcpy(dst, buf, 2); | 159 | 5.62k | dst += 2; | 160 | 5.62k | } | 161 | 5.62k | ADLER_DO2(adler, sum2, buf, 0); | 162 | 5.62k | buf += 2; | 163 | 5.62k | } | 164 | 6.57k | if (len & 1) { | 165 | 5.60k | if (COPY) | 166 | 5.60k | *dst = *buf; | 167 | 5.60k | ADLER_DO1(adler, sum2, buf, 0); | 168 | 5.60k | } | 169 | 6.57k | } | 170 | 6.57k | if (REBASE) { | 171 | 6.57k | adler %= BASE; | 172 | 6.57k | sum2 %= BASE; | 173 | 6.57k | } | 174 | | /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */ | 175 | 6.57k | return adler | (sum2 << 16); | 176 | 6.57k | } |
Unexecuted instantiation: adler32_avx512.c:adler32_copy_tail Unexecuted instantiation: adler32_avx512_vnni.c:adler32_copy_tail Unexecuted instantiation: adler32_c.c:adler32_copy_tail |
177 | | |
178 | | #endif /* ADLER32_P_H */ |