134 lines · c
1/*2 * Common code for checksum implementations3 *4 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5 * See https://llvm.org/LICENSE.txt for license information.6 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7 */8 9#ifndef CHKSUM_COMMON_H10#define CHKSUM_COMMON_H11 12#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__13#error Only little endian supported14#endif15 16#include <limits.h>17#include <stdbool.h>18#include <stdint.h>19#include <string.h>20 21/* Assertions must be explicitly enabled */22#if WANT_ASSERT23#undef NDEBUG24#include <assert.h>25#define Assert(exp) assert(exp)26#else27#define Assert(exp) (void) (exp)28#endif29 30#ifdef __GNUC__31#define likely(x) __builtin_expect(!!(x), 1)32#define unlikely(x) __builtin_expect(!!(x), 0)33#define may_alias __attribute__((__may_alias__))34#define always_inline __attribute__((always_inline))35#ifdef __clang__36#define no_unroll_loops37#else38#define no_unroll_loops __attribute__((optimize("no-unroll-loops")))39#endif40#define bswap16(x) __builtin_bswap16((x))41#else42#define likely(x) (x)43#define unlikely(x) (x)44#define may_alias45#define always_inline46#define no_unroll_loops47#define bswap16(x) ((uint8_t)((x) >> 8) | ((uint8_t)(x) << 8))48#endif49 50#define ALL_ONES ~UINT64_C(0)51 52static inline53uint64_t load64(const void *ptr)54{55 /* GCC will optimise this to a normal load instruction */56 uint64_t v;57 memcpy(&v, ptr, sizeof v);58 return v;59}60 61static inline62uint32_t load32(const void *ptr)63{64 /* GCC will optimise this to a normal load instruction */65 uint32_t v;66 memcpy(&v, ptr, sizeof v);67 return v;68}69 70static inline71uint16_t load16(const void *ptr)72{73 /* GCC will optimise this to a normal load instruction */74 uint16_t v;75 memcpy(&v, ptr, sizeof v);76 return v;77}78 79/* slurp_small() is for small buffers, don't waste cycles on alignment */80no_unroll_loops81always_inline82static inline uint64_t83slurp_small(const void *ptr, uint32_t nbytes)84{85 const unsigned char *cptr = ptr;86 uint64_t sum = 0;87 while (nbytes >= 4)88 {89 sum += load32(cptr);90 cptr += 4;91 nbytes -= 4;92 }93 if (nbytes & 2)94 {95 sum += load16(cptr);96 cptr += 2;97 }98 if (nbytes & 1)99 {100 sum += (uint8_t) *cptr;101 }102 return sum;103}104 105static inline const void *106align_ptr(const void *ptr, size_t bytes)107{108 return (void *) ((uintptr_t) ptr & -(uintptr_t) bytes);109}110 111always_inline112static inline uint16_t113fold_and_swap(uint64_t sum, bool swap)114{115 /* Fold 64-bit sum to 32 bits */116 sum = (sum & 0xffffffff) + (sum >> 32);117 sum = (sum & 0xffffffff) + (sum >> 32);118 Assert(sum == (uint32_t) sum);119 120 /* Fold 32-bit sum to 16 bits */121 sum = (sum & 0xffff) + (sum >> 16);122 sum = (sum & 0xffff) + (sum >> 16);123 Assert(sum == (uint16_t) sum);124 125 if (unlikely(swap)) /* Odd base pointer is unexpected */126 {127 sum = bswap16(sum);128 }129 130 return (uint16_t) sum;131}132 133#endif134