2 * Compute 16-bit sum in ones' complement arithmetic (with end-around carry).
3 * This sum is often used as a simple checksum in networking.
5 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 * See https://llvm.org/LICENSE.txt for license information.
7 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
10 #include "networking.h"
11 #include "chksum_common.h"
14 static inline uint32_t
15 slurp_head32(const void **pptr
, uint32_t *nbytes
)
19 uint32_t off
= (uintptr_t) *pptr
% 4;
22 /* Get rid of bytes 0..off-1 */
23 const unsigned char *ptr32
= align_ptr(*pptr
, 4);
24 uint32_t mask
= ~0U << (CHAR_BIT
* off
);
25 sum
= load32(ptr32
) & mask
;
32 /* Additional loop unrolling would help when not auto-vectorizing */
34 __chksum(const void *ptr
, unsigned int nbytes
)
41 /* 4-byte align pointer */
42 swap
= (uintptr_t) ptr
& 1;
43 sum
= slurp_head32(&ptr
, &nbytes
);
45 /* Else benefit of aligning not worth the overhead */
47 /* Sum all 16-byte chunks */
48 const char *cptr
= ptr
;
49 for (uint32_t nquads
= nbytes
/ 16; nquads
!= 0; nquads
--)
51 uint64_t h0
= load32(cptr
+ 0);
52 uint64_t h1
= load32(cptr
+ 4);
53 uint64_t h2
= load32(cptr
+ 8);
54 uint64_t h3
= load32(cptr
+ 12);
55 sum
+= h0
+ h1
+ h2
+ h3
;
61 /* Handle any trailing 4-byte chunks */
78 sum
+= *(uint8_t *)cptr
;
81 return fold_and_swap(sum
, swap
);