19#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
27#define AARU_ALIGN16 __declspec(align(16))
29#define AARU_ALIGN16 __attribute__((aligned(16)))
37static const uint8_t shuffleMasks[] = {
38 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
39 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
42TARGET_WITH_SIMD
FORCE_INLINE void shiftRight128(uint64x2_t in,
size_t n, uint64x2_t *outLeft, uint64x2_t *outRight)
44 const uint64x2_t maskA =
45 vreinterpretq_u64_u32(vld1q_u32((
const uint32_t *)(
const uint64x2_t *)(shuffleMasks + (16 - n))));
46 uint64x2_t b = vreinterpretq_u64_u8(vceqq_u8(vreinterpretq_u8_u64(vreinterpretq_u64_u32(vdupq_n_u32(0))),
47 vreinterpretq_u8_u64(vreinterpretq_u64_u32(vdupq_n_u32(0)))));
48 const uint64x2_t maskB = vreinterpretq_u64_u32(veorq_u32(vreinterpretq_u32_u64(maskA), vreinterpretq_u32_u64(b)));
50 *outLeft = mm_shuffle_epi8(in, maskB);
51 *outRight = mm_shuffle_epi8(in, maskA);
54TARGET_WITH_SIMD
FORCE_INLINE uint64x2_t fold(uint64x2_t in, uint64x2_t foldConstants)
56 return veorq_u64(sse2neon_vmull_p64(vget_low_u64(in), vget_low_u64(foldConstants)),
57 sse2neon_vmull_p64(vget_high_u64(in), vget_high_u64(foldConstants)));
68AARU_EXPORT TARGET_WITH_SIMD uint64_t
AARU_CALL aaruf_crc64_vmull(uint64_t previous_crc,
const uint8_t *data,
long len)
70 TRACE(
"Entering aaruf_crc64_vmull(%llu, %p, %ld)", previous_crc, data, len);
72 const uint64_t k1 = 0xe05dd497ca393ae4;
73 const uint64_t k2 = 0xdabe95afc7875f40;
74 const uint64_t mu = 0x9c3e466c172963d5;
75 const uint64_t p = 0x92d8af2baf0e1e85;
77 const uint64x2_t foldConstants1 = vcombine_u64(vcreate_u64(k1), vcreate_u64(k2));
78 const uint64x2_t foldConstants2 = vcombine_u64(vcreate_u64(mu), vcreate_u64(p));
80 const uint8_t *end = data + len;
83 const uint64x2_t *alignedData = (
const uint64x2_t *)((uintptr_t)data & ~(uintptr_t)15);
84 const uint64x2_t *alignedEnd = (
const uint64x2_t *)(((uintptr_t)end + 15) & ~(uintptr_t)15);
86 const size_t leadInSize = data - (
const uint8_t *)alignedData;
87 const size_t leadOutSize = (
const uint8_t *)alignedEnd - end;
89 const size_t alignedLength = alignedEnd - alignedData;
91 const uint64x2_t leadInMask =
92 vreinterpretq_u64_u32(vld1q_u32((
const uint32_t *)(
const uint64x2_t *)(shuffleMasks + (16 - leadInSize))));
93 uint64x2_t a = vreinterpretq_u64_u32(vdupq_n_u32(0));
94 uint64x2_t b = vreinterpretq_u64_u32(
95 vld1q_u32((
const uint32_t *)alignedData));
96 const uint64x2_t data0 =
97 vreinterpretq_u64_u8(vbslq_u8(vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_u64(leadInMask), 7)),
98 vreinterpretq_u8_u64(b), vreinterpretq_u8_u64(a)));
100 const uint64x2_t initialCrc = vsetq_lane_u64(~previous_crc, vdupq_n_u64(0), 0);
103 if(alignedLength == 1)
106 uint64x2_t crc0, crc1;
107 shiftRight128(initialCrc, 16 - len, &crc0, &crc1);
110 shiftRight128(data0, leadOutSize, &A, &B);
112 const uint64x2_t P = veorq_u64(A, crc0);
113 R = veorq_u64(sse2neon_vmull_p64(vget_low_u64(P), vget_high_u64(foldConstants1)),
114 veorq_u64(mm_srli_si128(P, 8), mm_slli_si128(crc1, 8)));
116 else if(alignedLength == 2)
118 const uint64x2_t data1 = vreinterpretq_u64_u32(vld1q_u32((
const uint32_t *)(alignedData + 1)));
123 uint64x2_t crc0, crc1;
124 shiftRight128(initialCrc, 16 - len, &crc0, &crc1);
126 uint64x2_t A, B, C, D;
127 shiftRight128(data0, leadOutSize, &A, &B);
128 shiftRight128(data1, leadOutSize, &C, &D);
130 const uint64x2_t P = veorq_u64(veorq_u64(B, C), crc0);
131 R = veorq_u64(sse2neon_vmull_p64(vget_low_u64(P), vget_high_u64(foldConstants1)),
132 veorq_u64(mm_srli_si128(P, 8), mm_slli_si128(crc1, 8)));
137 uint64x2_t crc0, crc1;
138 shiftRight128(initialCrc, leadInSize, &crc0, &crc1);
140 uint64x2_t A, B, C, D;
141 shiftRight128(veorq_u64(data0, crc0), leadOutSize, &A, &B);
142 shiftRight128(veorq_u64(data1, crc1), leadOutSize, &C, &D);
144 const uint64x2_t P = veorq_u64(fold(A, foldConstants1), veorq_u64(B, C));
145 R = veorq_u64(sse2neon_vmull_p64(vget_low_u64(P), vget_high_u64(foldConstants1)), mm_srli_si128(P, 8));
151 len -= 16 - leadInSize;
154 uint64x2_t crc0, crc1;
155 shiftRight128(initialCrc, leadInSize, &crc0, &crc1);
157 uint64x2_t accumulator = veorq_u64(fold(veorq_u64(crc0, data0), foldConstants1), crc1);
161 accumulator = fold(veorq_u64(vreinterpretq_u64_u32(vld1q_u32((
const uint32_t *)alignedData)), accumulator),
170 P = veorq_u64(accumulator, vreinterpretq_u64_u32(vld1q_u32((
const uint32_t *)alignedData)));
174 const uint64x2_t end0 =
175 veorq_u64(accumulator, vreinterpretq_u64_u32(vld1q_u32((
const uint32_t *)alignedData)));
179 AARU_ALIGN16 uint8_t temp[16] = {0};
180 const uint8_t *nextBlockAddr = (
const uint8_t *)(alignedData + 1);
183 if(nextBlockAddr < end)
185 size_t available = (size_t)(end - nextBlockAddr);
186 if(available > 16) available = 16;
187 memcpy(temp, nextBlockAddr, available);
190 const uint64x2_t end1 = vreinterpretq_u64_u32(vld1q_u32((
const uint32_t *)temp));
192 uint64x2_t A, B, C, D;
193 shiftRight128(end0, leadOutSize, &A, &B);
194 shiftRight128(end1, leadOutSize, &C, &D);
196 P = veorq_u64(fold(A, foldConstants1),
197 vreinterpretq_u64_u32(vorrq_u32(vreinterpretq_u32_u64(B), vreinterpretq_u32_u64(C))));
200 R = veorq_u64(sse2neon_vmull_p64(vget_low_u64(P), vget_high_u64(foldConstants1)), mm_srli_si128(P, 8));
204 const uint64x2_t T1 = sse2neon_vmull_p64(vget_low_u64(R), vget_low_u64(foldConstants2));
205 const uint64x2_t T2 = veorq_u64(
206 veorq_u64(sse2neon_vmull_p64(vget_low_u64(T1), vget_high_u64(foldConstants2)), mm_slli_si128(T1, 8)), R);
208 TRACE(
"Exiting aaruf_crc64_vmull()");
210 return ~vgetq_lane_u64(T2, 1);