1bbbf1280Sopenharmony_ci/*
2bbbf1280Sopenharmony_ci * Common code for checksum implementations
3bbbf1280Sopenharmony_ci *
4bbbf1280Sopenharmony_ci * Copyright (c) 2020, Arm Limited.
5bbbf1280Sopenharmony_ci * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6bbbf1280Sopenharmony_ci */
7bbbf1280Sopenharmony_ci
8bbbf1280Sopenharmony_ci#ifndef CHKSUM_COMMON_H
9bbbf1280Sopenharmony_ci#define CHKSUM_COMMON_H
10bbbf1280Sopenharmony_ci
11bbbf1280Sopenharmony_ci#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
12bbbf1280Sopenharmony_ci#error Only little endian supported
13bbbf1280Sopenharmony_ci#endif
14bbbf1280Sopenharmony_ci
15bbbf1280Sopenharmony_ci#include <limits.h>
16bbbf1280Sopenharmony_ci#include <stdbool.h>
17bbbf1280Sopenharmony_ci#include <stdint.h>
18bbbf1280Sopenharmony_ci#include <string.h>
19bbbf1280Sopenharmony_ci
20bbbf1280Sopenharmony_ci/* Assertions must be explicitly enabled */
21bbbf1280Sopenharmony_ci#if WANT_ASSERT
22bbbf1280Sopenharmony_ci#undef NDEBUG
23bbbf1280Sopenharmony_ci#include <assert.h>
24bbbf1280Sopenharmony_ci#define Assert(exp) assert(exp)
25bbbf1280Sopenharmony_ci#else
26bbbf1280Sopenharmony_ci#define Assert(exp) (void) (exp)
27bbbf1280Sopenharmony_ci#endif
28bbbf1280Sopenharmony_ci
29bbbf1280Sopenharmony_ci#ifdef __GNUC__
30bbbf1280Sopenharmony_ci#define likely(x)     __builtin_expect(!!(x), 1)
31bbbf1280Sopenharmony_ci#define unlikely(x)   __builtin_expect(!!(x), 0)
32bbbf1280Sopenharmony_ci#define may_alias     __attribute__((__may_alias__))
33bbbf1280Sopenharmony_ci#define always_inline __attribute__((always_inline))
34bbbf1280Sopenharmony_ci#ifdef __clang__
35bbbf1280Sopenharmony_ci#define no_unroll_loops
36bbbf1280Sopenharmony_ci#else
37bbbf1280Sopenharmony_ci#define no_unroll_loops  __attribute__((optimize("no-unroll-loops")))
38bbbf1280Sopenharmony_ci#endif
39bbbf1280Sopenharmony_ci#define bswap16(x)    __builtin_bswap16((x))
40bbbf1280Sopenharmony_ci#else
41bbbf1280Sopenharmony_ci#define likely(x)     (x)
42bbbf1280Sopenharmony_ci#define unlikely(x)   (x)
43bbbf1280Sopenharmony_ci#define may_alias
44bbbf1280Sopenharmony_ci#define always_inline
45bbbf1280Sopenharmony_ci#define no_unroll_loops
46bbbf1280Sopenharmony_ci#define bswap16(x)    ((uint8_t)((x) >> 8) | ((uint8_t)(x) << 8))
47bbbf1280Sopenharmony_ci#endif
48bbbf1280Sopenharmony_ci
49bbbf1280Sopenharmony_ci#define ALL_ONES ~UINT64_C(0)
50bbbf1280Sopenharmony_ci
51bbbf1280Sopenharmony_cistatic inline
52bbbf1280Sopenharmony_ciuint64_t load64(const void *ptr)
53bbbf1280Sopenharmony_ci{
54bbbf1280Sopenharmony_ci    /* GCC will optimise this to a normal load instruction */
55bbbf1280Sopenharmony_ci    uint64_t v;
56bbbf1280Sopenharmony_ci    memcpy(&v, ptr, sizeof v);
57bbbf1280Sopenharmony_ci    return v;
58bbbf1280Sopenharmony_ci}
59bbbf1280Sopenharmony_ci
60bbbf1280Sopenharmony_cistatic inline
61bbbf1280Sopenharmony_ciuint32_t load32(const void *ptr)
62bbbf1280Sopenharmony_ci{
63bbbf1280Sopenharmony_ci    /* GCC will optimise this to a normal load instruction */
64bbbf1280Sopenharmony_ci    uint32_t v;
65bbbf1280Sopenharmony_ci    memcpy(&v, ptr, sizeof v);
66bbbf1280Sopenharmony_ci    return v;
67bbbf1280Sopenharmony_ci}
68bbbf1280Sopenharmony_ci
69bbbf1280Sopenharmony_cistatic inline
70bbbf1280Sopenharmony_ciuint16_t load16(const void *ptr)
71bbbf1280Sopenharmony_ci{
72bbbf1280Sopenharmony_ci    /* GCC will optimise this to a normal load instruction */
73bbbf1280Sopenharmony_ci    uint16_t v;
74bbbf1280Sopenharmony_ci    memcpy(&v, ptr, sizeof v);
75bbbf1280Sopenharmony_ci    return v;
76bbbf1280Sopenharmony_ci}
77bbbf1280Sopenharmony_ci
78bbbf1280Sopenharmony_ci/* slurp_small() is for small buffers, don't waste cycles on alignment */
79bbbf1280Sopenharmony_cino_unroll_loops
80bbbf1280Sopenharmony_cialways_inline
81bbbf1280Sopenharmony_cistatic inline uint64_t
82bbbf1280Sopenharmony_cislurp_small(const void *ptr, uint32_t nbytes)
83bbbf1280Sopenharmony_ci{
84bbbf1280Sopenharmony_ci    const unsigned char *cptr = ptr;
85bbbf1280Sopenharmony_ci    uint64_t sum = 0;
86bbbf1280Sopenharmony_ci    while (nbytes >= 4)
87bbbf1280Sopenharmony_ci    {
88bbbf1280Sopenharmony_ci	sum += load32(cptr);
89bbbf1280Sopenharmony_ci	cptr += 4;
90bbbf1280Sopenharmony_ci	nbytes -= 4;
91bbbf1280Sopenharmony_ci    }
92bbbf1280Sopenharmony_ci    if (nbytes & 2)
93bbbf1280Sopenharmony_ci    {
94bbbf1280Sopenharmony_ci	sum += load16(cptr);
95bbbf1280Sopenharmony_ci	cptr += 2;
96bbbf1280Sopenharmony_ci    }
97bbbf1280Sopenharmony_ci    if (nbytes & 1)
98bbbf1280Sopenharmony_ci    {
99bbbf1280Sopenharmony_ci	sum += (uint8_t) *cptr;
100bbbf1280Sopenharmony_ci    }
101bbbf1280Sopenharmony_ci    return sum;
102bbbf1280Sopenharmony_ci}
103bbbf1280Sopenharmony_ci
104bbbf1280Sopenharmony_cistatic inline const void *
105bbbf1280Sopenharmony_cialign_ptr(const void *ptr, size_t bytes)
106bbbf1280Sopenharmony_ci{
107bbbf1280Sopenharmony_ci    return (void *) ((uintptr_t) ptr & -(uintptr_t) bytes);
108bbbf1280Sopenharmony_ci}
109bbbf1280Sopenharmony_ci
110bbbf1280Sopenharmony_cialways_inline
111bbbf1280Sopenharmony_cistatic inline uint16_t
112bbbf1280Sopenharmony_cifold_and_swap(uint64_t sum, bool swap)
113bbbf1280Sopenharmony_ci{
114bbbf1280Sopenharmony_ci    /* Fold 64-bit sum to 32 bits */
115bbbf1280Sopenharmony_ci    sum = (sum & 0xffffffff) + (sum >> 32);
116bbbf1280Sopenharmony_ci    sum = (sum & 0xffffffff) + (sum >> 32);
117bbbf1280Sopenharmony_ci    Assert(sum == (uint32_t) sum);
118bbbf1280Sopenharmony_ci
119bbbf1280Sopenharmony_ci    /* Fold 32-bit sum to 16 bits */
120bbbf1280Sopenharmony_ci    sum = (sum & 0xffff) + (sum >> 16);
121bbbf1280Sopenharmony_ci    sum = (sum & 0xffff) + (sum >> 16);
122bbbf1280Sopenharmony_ci    Assert(sum == (uint16_t) sum);
123bbbf1280Sopenharmony_ci
124bbbf1280Sopenharmony_ci    if (unlikely(swap)) /* Odd base pointer is unexpected */
125bbbf1280Sopenharmony_ci    {
126bbbf1280Sopenharmony_ci	sum = bswap16(sum);
127bbbf1280Sopenharmony_ci    }
128bbbf1280Sopenharmony_ci
129bbbf1280Sopenharmony_ci    return (uint16_t) sum;
130bbbf1280Sopenharmony_ci}
131bbbf1280Sopenharmony_ci
132bbbf1280Sopenharmony_ci#endif
133