14cbd2858SGreg Tucker /**********************************************************************
24cbd2858SGreg Tucker Copyright(c) 2011-2023 Intel Corporation All rights reserved.
34cbd2858SGreg Tucker
44cbd2858SGreg Tucker Redistribution and use in source and binary forms, with or without
54cbd2858SGreg Tucker modification, are permitted provided that the following conditions
64cbd2858SGreg Tucker are met:
74cbd2858SGreg Tucker * Redistributions of source code must retain the above copyright
84cbd2858SGreg Tucker notice, this list of conditions and the following disclaimer.
94cbd2858SGreg Tucker * Redistributions in binary form must reproduce the above copyright
104cbd2858SGreg Tucker notice, this list of conditions and the following disclaimer in
114cbd2858SGreg Tucker the documentation and/or other materials provided with the
124cbd2858SGreg Tucker distribution.
134cbd2858SGreg Tucker * Neither the name of Intel Corporation nor the names of its
144cbd2858SGreg Tucker contributors may be used to endorse or promote products derived
154cbd2858SGreg Tucker from this software without specific prior written permission.
164cbd2858SGreg Tucker
174cbd2858SGreg Tucker THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
184cbd2858SGreg Tucker "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
194cbd2858SGreg Tucker LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
204cbd2858SGreg Tucker A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
214cbd2858SGreg Tucker OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
224cbd2858SGreg Tucker SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
234cbd2858SGreg Tucker LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
244cbd2858SGreg Tucker DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
254cbd2858SGreg Tucker THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
264cbd2858SGreg Tucker (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
274cbd2858SGreg Tucker OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
284cbd2858SGreg Tucker **********************************************************************/
294cbd2858SGreg Tucker
304cbd2858SGreg Tucker /**
314cbd2858SGreg Tucker * @file crc_combine_example.c
324cbd2858SGreg Tucker * @brief Example of CRC combine logic.
334cbd2858SGreg Tucker *
344cbd2858SGreg Tucker * Combine functions can produce the CRC from independent pieces as though they
354cbd2858SGreg Tucker * were computed sequentially. The example includes combine functions that are
364cbd2858SGreg Tucker * split into two parts; one that depends on length only, and another with
374cbd2858SGreg Tucker * optimizations that uses the previous and individual CRCs to combine. By
384cbd2858SGreg Tucker * splitting, the length-dependent constants can be pre-computed and the
394cbd2858SGreg Tucker * remaining combine logic kept fast and simple.
404cbd2858SGreg Tucker *
414cbd2858SGreg Tucker */
424cbd2858SGreg Tucker
434cbd2858SGreg Tucker // Compile as c++ for multi-function versions
444cbd2858SGreg Tucker
454cbd2858SGreg Tucker #include <stdio.h>
464cbd2858SGreg Tucker #include <inttypes.h>
474cbd2858SGreg Tucker #include <immintrin.h>
484cbd2858SGreg Tucker #include <isa-l.h>
494cbd2858SGreg Tucker
504cbd2858SGreg Tucker int verbose; // Global for tests
514cbd2858SGreg Tucker
524cbd2858SGreg Tucker #if defined(_MSC_VER)
534cbd2858SGreg Tucker #define __builtin_parity(x) (__popcnt64(x) & 1)
544cbd2858SGreg Tucker #endif
554cbd2858SGreg Tucker
564cbd2858SGreg Tucker #if defined(__GNUC__) || defined(__clang__)
574cbd2858SGreg Tucker #define ATTRIBUTE_TARGET(x) __attribute__((target(x)))
584cbd2858SGreg Tucker #else
594cbd2858SGreg Tucker #define ATTRIBUTE_TARGET(x)
604cbd2858SGreg Tucker #endif
614cbd2858SGreg Tucker
624cbd2858SGreg Tucker struct crc64_desc {
634cbd2858SGreg Tucker uint64_t poly;
644cbd2858SGreg Tucker uint64_t k5;
654cbd2858SGreg Tucker uint64_t k7;
664cbd2858SGreg Tucker uint64_t k8;
674cbd2858SGreg Tucker };
684cbd2858SGreg Tucker
69*9d99f821SMarcel Cornu void
gen_crc64_refl_consts(uint64_t poly,struct crc64_desc * c)70*9d99f821SMarcel Cornu gen_crc64_refl_consts(uint64_t poly, struct crc64_desc *c)
714cbd2858SGreg Tucker {
724cbd2858SGreg Tucker uint64_t quotienth = 0;
734cbd2858SGreg Tucker uint64_t div;
744cbd2858SGreg Tucker uint64_t rem = 1ull;
754cbd2858SGreg Tucker int i;
764cbd2858SGreg Tucker
774cbd2858SGreg Tucker for (i = 0; i < 64; i++) {
784cbd2858SGreg Tucker div = (rem & 1ull) != 0;
794cbd2858SGreg Tucker quotienth = (quotienth >> 1) | (div ? 0x8000000000000000ull : 0);
804cbd2858SGreg Tucker rem = (div ? poly : 0) ^ (rem >> 1);
814cbd2858SGreg Tucker }
824cbd2858SGreg Tucker c->k5 = rem;
834cbd2858SGreg Tucker c->poly = poly;
844cbd2858SGreg Tucker c->k7 = quotienth;
854cbd2858SGreg Tucker c->k8 = poly << 1;
864cbd2858SGreg Tucker }
874cbd2858SGreg Tucker
88*9d99f821SMarcel Cornu void
gen_crc64_norm_consts(uint64_t poly,struct crc64_desc * c)89*9d99f821SMarcel Cornu gen_crc64_norm_consts(uint64_t poly, struct crc64_desc *c)
904cbd2858SGreg Tucker {
914cbd2858SGreg Tucker uint64_t quotientl = 0;
924cbd2858SGreg Tucker uint64_t div;
934cbd2858SGreg Tucker uint64_t rem = 1ull << 63;
944cbd2858SGreg Tucker int i;
954cbd2858SGreg Tucker
964cbd2858SGreg Tucker for (i = 0; i < 65; i++) {
974cbd2858SGreg Tucker div = (rem & 0x8000000000000000ull) != 0;
984cbd2858SGreg Tucker quotientl = (quotientl << 1) | div;
994cbd2858SGreg Tucker rem = (div ? poly : 0) ^ (rem << 1);
1004cbd2858SGreg Tucker }
1014cbd2858SGreg Tucker
1024cbd2858SGreg Tucker c->poly = poly;
1034cbd2858SGreg Tucker c->k5 = rem;
1044cbd2858SGreg Tucker c->k7 = quotientl;
1054cbd2858SGreg Tucker c->k8 = poly;
1064cbd2858SGreg Tucker }
1074cbd2858SGreg Tucker
108*9d99f821SMarcel Cornu uint32_t
calc_xi_mod(int n)109*9d99f821SMarcel Cornu calc_xi_mod(int n)
1104cbd2858SGreg Tucker {
1114cbd2858SGreg Tucker uint32_t rem = 0x1ul;
1124cbd2858SGreg Tucker int i, j;
1134cbd2858SGreg Tucker
1144cbd2858SGreg Tucker const uint32_t poly = 0x82f63b78;
1154cbd2858SGreg Tucker
1164cbd2858SGreg Tucker if (n < 16)
1174cbd2858SGreg Tucker return 0;
1184cbd2858SGreg Tucker
1194cbd2858SGreg Tucker for (i = 0; i < n - 8; i++)
1204cbd2858SGreg Tucker for (j = 0; j < 8; j++)
1214cbd2858SGreg Tucker rem = (rem & 0x1ul) ? (rem >> 1) ^ poly : (rem >> 1);
1224cbd2858SGreg Tucker
1234cbd2858SGreg Tucker return rem;
1244cbd2858SGreg Tucker }
1254cbd2858SGreg Tucker
126*9d99f821SMarcel Cornu uint64_t
calc64_refl_xi_mod(int n,struct crc64_desc * c)127*9d99f821SMarcel Cornu calc64_refl_xi_mod(int n, struct crc64_desc *c)
1284cbd2858SGreg Tucker {
1294cbd2858SGreg Tucker uint64_t rem = 1ull;
1304cbd2858SGreg Tucker int i, j;
1314cbd2858SGreg Tucker
1324cbd2858SGreg Tucker const uint64_t poly = c->poly;
1334cbd2858SGreg Tucker
1344cbd2858SGreg Tucker if (n < 32)
1354cbd2858SGreg Tucker return 0;
1364cbd2858SGreg Tucker
1374cbd2858SGreg Tucker for (i = 0; i < n - 16; i++)
1384cbd2858SGreg Tucker for (j = 0; j < 8; j++)
1394cbd2858SGreg Tucker rem = (rem & 0x1ull) ? (rem >> 1) ^ poly : (rem >> 1);
1404cbd2858SGreg Tucker
1414cbd2858SGreg Tucker return rem;
1424cbd2858SGreg Tucker }
1434cbd2858SGreg Tucker
144*9d99f821SMarcel Cornu uint64_t
calc64_norm_xi_mod(int n,struct crc64_desc * c)145*9d99f821SMarcel Cornu calc64_norm_xi_mod(int n, struct crc64_desc *c)
1464cbd2858SGreg Tucker {
1474cbd2858SGreg Tucker uint64_t rem = 1ull;
1484cbd2858SGreg Tucker int i, j;
1494cbd2858SGreg Tucker
1504cbd2858SGreg Tucker const uint64_t poly = c->poly;
1514cbd2858SGreg Tucker
1524cbd2858SGreg Tucker if (n < 32)
1534cbd2858SGreg Tucker return 0;
1544cbd2858SGreg Tucker
1554cbd2858SGreg Tucker for (i = 0; i < n - 8; i++)
1564cbd2858SGreg Tucker for (j = 0; j < 8; j++)
1574cbd2858SGreg Tucker rem = (rem & 0x8000000000000000ull ? poly : 0) ^ (rem << 1);
1584cbd2858SGreg Tucker
1594cbd2858SGreg Tucker return rem;
1604cbd2858SGreg Tucker }
1614cbd2858SGreg Tucker
1624cbd2858SGreg Tucker // Base function for crc32_iscsi_shiftx() if c++ multi-function versioning
1634cbd2858SGreg Tucker #ifdef __cplusplus
1644cbd2858SGreg Tucker
165*9d99f821SMarcel Cornu static inline uint32_t
bit_reverse32(uint32_t x)166*9d99f821SMarcel Cornu bit_reverse32(uint32_t x)
1674cbd2858SGreg Tucker {
1684cbd2858SGreg Tucker x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
1694cbd2858SGreg Tucker x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
1704cbd2858SGreg Tucker x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
1714cbd2858SGreg Tucker x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
1724cbd2858SGreg Tucker return ((x >> 16) | (x << 16));
1734cbd2858SGreg Tucker }
1744cbd2858SGreg Tucker
1754cbd2858SGreg Tucker // Base function for crc32_iscsi_shiftx without clmul optimizations
1764cbd2858SGreg Tucker
1774cbd2858SGreg Tucker ATTRIBUTE_TARGET("default")
178*9d99f821SMarcel Cornu uint32_t
crc32_iscsi_shiftx(uint32_t crc1,uint32_t x)179*9d99f821SMarcel Cornu crc32_iscsi_shiftx(uint32_t crc1, uint32_t x)
1804cbd2858SGreg Tucker {
1814cbd2858SGreg Tucker int i;
1824cbd2858SGreg Tucker uint64_t xrev, q = 0;
1834cbd2858SGreg Tucker union {
1844cbd2858SGreg Tucker uint8_t a[8];
1854cbd2858SGreg Tucker uint64_t q;
1864cbd2858SGreg Tucker } qu;
1874cbd2858SGreg Tucker
1884cbd2858SGreg Tucker xrev = bit_reverse32(x);
1894cbd2858SGreg Tucker xrev <<= 32;
1904cbd2858SGreg Tucker
1914cbd2858SGreg Tucker for (i = 0; i < 64; i++, xrev >>= 1)
1924cbd2858SGreg Tucker q = (q << 1) | __builtin_parity(crc1 & xrev);
1934cbd2858SGreg Tucker
1944cbd2858SGreg Tucker qu.q = q;
1954cbd2858SGreg Tucker return crc32_iscsi(qu.a, 8, 0);
1964cbd2858SGreg Tucker }
1974cbd2858SGreg Tucker #endif // cplusplus
1984cbd2858SGreg Tucker
1994cbd2858SGreg Tucker ATTRIBUTE_TARGET("pclmul,sse4.2")
200*9d99f821SMarcel Cornu uint32_t
crc32_iscsi_shiftx(uint32_t crc1,uint32_t x)201*9d99f821SMarcel Cornu crc32_iscsi_shiftx(uint32_t crc1, uint32_t x)
2024cbd2858SGreg Tucker {
2034cbd2858SGreg Tucker __m128i crc1x, constx;
2044cbd2858SGreg Tucker uint64_t crc64;
2054cbd2858SGreg Tucker
2064cbd2858SGreg Tucker crc1x = _mm_setr_epi32(crc1, 0, 0, 0);
2074cbd2858SGreg Tucker constx = _mm_setr_epi32(x, 0, 0, 0);
2084cbd2858SGreg Tucker crc1x = _mm_clmulepi64_si128(crc1x, constx, 0);
2094cbd2858SGreg Tucker crc64 = _mm_cvtsi128_si64(crc1x);
2104cbd2858SGreg Tucker crc64 = _mm_crc32_u64(0, crc64);
2114cbd2858SGreg Tucker return crc64 & 0xffffffff;
2124cbd2858SGreg Tucker }
2134cbd2858SGreg Tucker
2144cbd2858SGreg Tucker ATTRIBUTE_TARGET("pclmul,sse4.2")
215*9d99f821SMarcel Cornu uint64_t
crc64_refl_shiftx(uint64_t crc1,uint64_t x,struct crc64_desc * c)216*9d99f821SMarcel Cornu crc64_refl_shiftx(uint64_t crc1, uint64_t x, struct crc64_desc *c)
2174cbd2858SGreg Tucker {
2184cbd2858SGreg Tucker __m128i crc1x, crc2x, crc3x, constx;
2194cbd2858SGreg Tucker const __m128i rk5 = _mm_loadu_si64(&c->k5);
2204cbd2858SGreg Tucker const __m128i rk7 = _mm_loadu_si128((__m128i *) &c->k7);
2214cbd2858SGreg Tucker
2224cbd2858SGreg Tucker crc1x = _mm_cvtsi64_si128(crc1);
2234cbd2858SGreg Tucker constx = _mm_cvtsi64_si128(x);
2244cbd2858SGreg Tucker crc1x = _mm_clmulepi64_si128(crc1x, constx, 0x00);
2254cbd2858SGreg Tucker
2264cbd2858SGreg Tucker // Fold to 64b
2274cbd2858SGreg Tucker crc2x = _mm_clmulepi64_si128(crc1x, rk5, 0x00);
2284cbd2858SGreg Tucker crc3x = _mm_bsrli_si128(crc1x, 8);
2294cbd2858SGreg Tucker crc1x = _mm_xor_si128(crc2x, crc3x);
2304cbd2858SGreg Tucker
2314cbd2858SGreg Tucker // Reduce
2324cbd2858SGreg Tucker crc2x = _mm_clmulepi64_si128(crc1x, rk7, 0x00);
2334cbd2858SGreg Tucker crc3x = _mm_clmulepi64_si128(crc2x, rk7, 0x10);
2344cbd2858SGreg Tucker crc2x = _mm_bslli_si128(crc2x, 8);
2354cbd2858SGreg Tucker crc1x = _mm_xor_si128(crc1x, crc2x);
2364cbd2858SGreg Tucker crc1x = _mm_xor_si128(crc1x, crc3x);
2374cbd2858SGreg Tucker return _mm_extract_epi64(crc1x, 1);
2384cbd2858SGreg Tucker }
2394cbd2858SGreg Tucker
2404cbd2858SGreg Tucker ATTRIBUTE_TARGET("pclmul,sse4.2")
241*9d99f821SMarcel Cornu uint64_t
crc64_norm_shiftx(uint64_t crc1,uint64_t x,struct crc64_desc * c)242*9d99f821SMarcel Cornu crc64_norm_shiftx(uint64_t crc1, uint64_t x, struct crc64_desc *c)
2434cbd2858SGreg Tucker {
2444cbd2858SGreg Tucker __m128i crc1x, crc2x, crc3x, constx;
2454cbd2858SGreg Tucker const __m128i rk5 = _mm_loadu_si64(&c->k5);
2464cbd2858SGreg Tucker const __m128i rk7 = _mm_loadu_si128((__m128i *) &c->k7);
2474cbd2858SGreg Tucker
2484cbd2858SGreg Tucker crc1x = _mm_cvtsi64_si128(crc1);
2494cbd2858SGreg Tucker constx = _mm_cvtsi64_si128(x);
2504cbd2858SGreg Tucker crc1x = _mm_clmulepi64_si128(crc1x, constx, 0x00);
2514cbd2858SGreg Tucker
2524cbd2858SGreg Tucker // Fold to 64b
2534cbd2858SGreg Tucker crc2x = _mm_clmulepi64_si128(crc1x, rk5, 0x01);
2544cbd2858SGreg Tucker crc3x = _mm_bslli_si128(crc1x, 8);
2554cbd2858SGreg Tucker crc1x = _mm_xor_si128(crc2x, crc3x);
2564cbd2858SGreg Tucker
2574cbd2858SGreg Tucker // Reduce
2584cbd2858SGreg Tucker crc2x = _mm_clmulepi64_si128(crc1x, rk7, 0x01);
2594cbd2858SGreg Tucker crc2x = _mm_xor_si128(crc1x, crc2x);
2604cbd2858SGreg Tucker crc3x = _mm_clmulepi64_si128(crc2x, rk7, 0x11);
2614cbd2858SGreg Tucker crc1x = _mm_xor_si128(crc1x, crc3x);
2624cbd2858SGreg Tucker return _mm_extract_epi64(crc1x, 0);
2634cbd2858SGreg Tucker }
2644cbd2858SGreg Tucker
265*9d99f821SMarcel Cornu uint32_t
crc32_iscsi_combine_4k(uint32_t * crc_array,int n)266*9d99f821SMarcel Cornu crc32_iscsi_combine_4k(uint32_t *crc_array, int n)
2674cbd2858SGreg Tucker {
2684cbd2858SGreg Tucker const uint32_t cn4k = 0x82f89c77; // calc_xi_mod(4*1024);
2694cbd2858SGreg Tucker int i;
2704cbd2858SGreg Tucker
2714cbd2858SGreg Tucker if (n < 1)
2724cbd2858SGreg Tucker return 0;
2734cbd2858SGreg Tucker
2744cbd2858SGreg Tucker uint32_t crc = crc_array[0];
2754cbd2858SGreg Tucker
2764cbd2858SGreg Tucker for (i = 1; i < n; i++)
2774cbd2858SGreg Tucker crc = crc32_iscsi_shiftx(crc, cn4k) ^ crc_array[i];
2784cbd2858SGreg Tucker
2794cbd2858SGreg Tucker return crc;
2804cbd2858SGreg Tucker }
2814cbd2858SGreg Tucker
2824cbd2858SGreg Tucker // Tests
2834cbd2858SGreg Tucker
284*9d99f821SMarcel Cornu #define printv(...) \
285*9d99f821SMarcel Cornu { \
286*9d99f821SMarcel Cornu if (verbose) \
287*9d99f821SMarcel Cornu printf(__VA_ARGS__); \
288*9d99f821SMarcel Cornu else \
289*9d99f821SMarcel Cornu printf("."); \
290*9d99f821SMarcel Cornu }
2914cbd2858SGreg Tucker
292*9d99f821SMarcel Cornu uint64_t
test_combine64(uint8_t * inp,size_t len,uint64_t poly,int reflected,uint64_t (* func)(uint64_t,const uint8_t *,uint64_t))293*9d99f821SMarcel Cornu test_combine64(uint8_t *inp, size_t len, uint64_t poly, int reflected,
2944cbd2858SGreg Tucker uint64_t (*func)(uint64_t, const uint8_t *, uint64_t))
2954cbd2858SGreg Tucker {
2964cbd2858SGreg Tucker
2974cbd2858SGreg Tucker uint64_t crc64_init, crc64, crc64a, crc64b;
2984cbd2858SGreg Tucker uint64_t crc64_1, crc64_2, crc64_3, crc64_n, err = 0;
2994cbd2858SGreg Tucker uint64_t xi_mod;
3004cbd2858SGreg Tucker struct crc64_desc crc64_c;
3014cbd2858SGreg Tucker size_t l1, l2, l3;
3024cbd2858SGreg Tucker
3034cbd2858SGreg Tucker l1 = len / 2;
3044cbd2858SGreg Tucker l2 = len - l1;
3054cbd2858SGreg Tucker
3064cbd2858SGreg Tucker crc64_init = rand();
3074cbd2858SGreg Tucker crc64 = func(crc64_init, inp, len);
3084cbd2858SGreg Tucker printv("\ncrc64 all = 0x%" PRIx64 "\n", crc64);
3094cbd2858SGreg Tucker
3104cbd2858SGreg Tucker // Do a sequential crc update
3114cbd2858SGreg Tucker crc64a = func(crc64_init, &inp[0], l1);
3124cbd2858SGreg Tucker crc64b = func(crc64a, &inp[l1], l2);
3134cbd2858SGreg Tucker printv("crc64 seq = 0x%" PRIx64 "\n", crc64b);
3144cbd2858SGreg Tucker
3154cbd2858SGreg Tucker // Split into 2 independent crc calc and combine
3164cbd2858SGreg Tucker crc64_1 = func(crc64_init, &inp[0], l1);
3174cbd2858SGreg Tucker crc64_2 = func(0, &inp[l1], l2);
3184cbd2858SGreg Tucker
3194cbd2858SGreg Tucker if (reflected) {
3204cbd2858SGreg Tucker gen_crc64_refl_consts(poly, &crc64_c);
3214cbd2858SGreg Tucker xi_mod = calc64_refl_xi_mod(l1, &crc64_c);
3224cbd2858SGreg Tucker crc64_1 = crc64_refl_shiftx(crc64_1, xi_mod, &crc64_c);
3234cbd2858SGreg Tucker } else {
3244cbd2858SGreg Tucker gen_crc64_norm_consts(poly, &crc64_c);
3254cbd2858SGreg Tucker xi_mod = calc64_norm_xi_mod(l1, &crc64_c);
3264cbd2858SGreg Tucker crc64_1 = crc64_norm_shiftx(crc64_1, xi_mod, &crc64_c);
3274cbd2858SGreg Tucker }
3284cbd2858SGreg Tucker crc64_n = crc64_1 ^ crc64_2;
3294cbd2858SGreg Tucker
3304cbd2858SGreg Tucker printv("crc64 combined2 = 0x%" PRIx64 "\n", crc64_n);
3314cbd2858SGreg Tucker err |= crc64_n ^ crc64;
3324cbd2858SGreg Tucker if (err)
3334cbd2858SGreg Tucker return err;
3344cbd2858SGreg Tucker
3354cbd2858SGreg Tucker // Split into 3 uneven segments and combine
3364cbd2858SGreg Tucker l1 = len / 3;
3374cbd2858SGreg Tucker l2 = (len / 3) - 3;
3384cbd2858SGreg Tucker l3 = len - l2 - l1;
3394cbd2858SGreg Tucker crc64_1 = func(crc64_init, &inp[0], l1);
3404cbd2858SGreg Tucker crc64_2 = func(0, &inp[l1], l2);
3414cbd2858SGreg Tucker crc64_3 = func(0, &inp[l1 + l2], l3);
3424cbd2858SGreg Tucker if (reflected) {
3434cbd2858SGreg Tucker xi_mod = calc64_refl_xi_mod(l3, &crc64_c);
3444cbd2858SGreg Tucker crc64_2 = crc64_refl_shiftx(crc64_2, xi_mod, &crc64_c);
3454cbd2858SGreg Tucker xi_mod = calc64_refl_xi_mod(len - l1, &crc64_c);
3464cbd2858SGreg Tucker crc64_1 = crc64_refl_shiftx(crc64_1, xi_mod, &crc64_c);
3474cbd2858SGreg Tucker } else {
3484cbd2858SGreg Tucker xi_mod = calc64_norm_xi_mod(l3, &crc64_c);
3494cbd2858SGreg Tucker crc64_2 = crc64_norm_shiftx(crc64_2, xi_mod, &crc64_c);
3504cbd2858SGreg Tucker xi_mod = calc64_norm_xi_mod(len - l1, &crc64_c);
3514cbd2858SGreg Tucker crc64_1 = crc64_norm_shiftx(crc64_1, xi_mod, &crc64_c);
3524cbd2858SGreg Tucker }
3534cbd2858SGreg Tucker crc64_n = crc64_1 ^ crc64_2 ^ crc64_3;
3544cbd2858SGreg Tucker
3554cbd2858SGreg Tucker printv("crc64 combined3 = 0x%" PRIx64 "\n", crc64_n);
3564cbd2858SGreg Tucker err |= crc64_n ^ crc64;
3574cbd2858SGreg Tucker
3584cbd2858SGreg Tucker return err;
3594cbd2858SGreg Tucker }
3604cbd2858SGreg Tucker
3614cbd2858SGreg Tucker #define N (1024)
3624cbd2858SGreg Tucker #define B (2 * N)
3634cbd2858SGreg Tucker #define T (3 * N)
3644cbd2858SGreg Tucker #define N4k (4 * 1024)
3654cbd2858SGreg Tucker #define NMAX 32
3664cbd2858SGreg Tucker #define NMAX_SIZE (NMAX * N4k)
3674cbd2858SGreg Tucker
368*9d99f821SMarcel Cornu int
main(int argc,char * argv[])369*9d99f821SMarcel Cornu main(int argc, char *argv[])
3704cbd2858SGreg Tucker {
3714cbd2858SGreg Tucker int i;
3724cbd2858SGreg Tucker uint32_t crc, crca, crcb, crc1, crc2, crc3, crcn;
3734cbd2858SGreg Tucker uint32_t crc_init = rand();
3744cbd2858SGreg Tucker uint32_t err = 0;
3754cbd2858SGreg Tucker uint8_t *inp = (uint8_t *) malloc(NMAX_SIZE);
3764cbd2858SGreg Tucker verbose = argc - 1;
3774cbd2858SGreg Tucker
3784cbd2858SGreg Tucker if (NULL == inp)
3794cbd2858SGreg Tucker return -1;
3804cbd2858SGreg Tucker
3814cbd2858SGreg Tucker for (int i = 0; i < NMAX_SIZE; i++)
3824cbd2858SGreg Tucker inp[i] = rand();
3834cbd2858SGreg Tucker
3844cbd2858SGreg Tucker printf("crc_combine_test:");
3854cbd2858SGreg Tucker
3864cbd2858SGreg Tucker // Calc crc all at once
3874cbd2858SGreg Tucker crc = crc32_iscsi(inp, B, crc_init);
3884cbd2858SGreg Tucker printv("\ncrcB all = 0x%" PRIx32 "\n", crc);
3894cbd2858SGreg Tucker
3904cbd2858SGreg Tucker // Do a sequential crc update
3914cbd2858SGreg Tucker crca = crc32_iscsi(&inp[0], N, crc_init);
3924cbd2858SGreg Tucker crcb = crc32_iscsi(&inp[N], N, crca);
3934cbd2858SGreg Tucker printv("crcB seq = 0x%" PRIx32 "\n", crcb);
3944cbd2858SGreg Tucker
3954cbd2858SGreg Tucker // Split into 2 independent crc calc and combine
3964cbd2858SGreg Tucker crc1 = crc32_iscsi(&inp[0], N, crc_init);
3974cbd2858SGreg Tucker crc2 = crc32_iscsi(&inp[N], N, 0);
3984cbd2858SGreg Tucker crcn = crc32_iscsi_shiftx(crc1, calc_xi_mod(N)) ^ crc2;
3994cbd2858SGreg Tucker printv("crcB combined2 = 0x%" PRIx32 "\n", crcn);
4004cbd2858SGreg Tucker err |= crcn ^ crc;
4014cbd2858SGreg Tucker
4024cbd2858SGreg Tucker // Split into 3 uneven segments and combine
4034cbd2858SGreg Tucker crc1 = crc32_iscsi(&inp[0], 100, crc_init);
4044cbd2858SGreg Tucker crc2 = crc32_iscsi(&inp[100], 100, 0);
4054cbd2858SGreg Tucker crc3 = crc32_iscsi(&inp[200], B - 200, 0);
406*9d99f821SMarcel Cornu crcn = crc3 ^ crc32_iscsi_shiftx(crc2, calc_xi_mod(B - 200)) ^
4074cbd2858SGreg Tucker crc32_iscsi_shiftx(crc1, calc_xi_mod(B - 100));
4084cbd2858SGreg Tucker printv("crcB combined3 = 0x%" PRIx32 "\n\n", crcn);
4094cbd2858SGreg Tucker err |= crcn ^ crc;
4104cbd2858SGreg Tucker
4114cbd2858SGreg Tucker // Call all size T at once
4124cbd2858SGreg Tucker crc = crc32_iscsi(inp, T, crc_init);
4134cbd2858SGreg Tucker printv("crcT all = 0x%" PRIx32 "\n", crc);
4144cbd2858SGreg Tucker
4154cbd2858SGreg Tucker // Split into 3 segments and combine with 2 consts
4164cbd2858SGreg Tucker crc1 = crc32_iscsi(&inp[0], N, crc_init);
4174cbd2858SGreg Tucker crc2 = crc32_iscsi(&inp[N], N, 0);
4184cbd2858SGreg Tucker crc3 = crc32_iscsi(&inp[2 * N], N, 0);
419*9d99f821SMarcel Cornu crcn = crc3 ^ crc32_iscsi_shiftx(crc2, calc_xi_mod(N)) ^
4204cbd2858SGreg Tucker crc32_iscsi_shiftx(crc1, calc_xi_mod(2 * N));
4214cbd2858SGreg Tucker printv("crcT combined3 = 0x%" PRIx32 "\n", crcn);
4224cbd2858SGreg Tucker err |= crcn ^ crc;
4234cbd2858SGreg Tucker
4244cbd2858SGreg Tucker // Combine 3 segments with one const by sequential shift
4254cbd2858SGreg Tucker uint32_t xi_mod_n = calc_xi_mod(N);
426*9d99f821SMarcel Cornu crcn = crc3 ^ crc32_iscsi_shiftx(crc32_iscsi_shiftx(crc1, xi_mod_n) ^ crc2, xi_mod_n);
4274cbd2858SGreg Tucker printv("crcT comb3 seq = 0x%" PRIx32 "\n\n", crcn);
4284cbd2858SGreg Tucker err |= crcn ^ crc;
4294cbd2858SGreg Tucker
4304cbd2858SGreg Tucker // Test 4k array function
4314cbd2858SGreg Tucker crc = crc32_iscsi(inp, NMAX_SIZE, crc_init);
4324cbd2858SGreg Tucker printv("crc 4k x n all = 0x%" PRIx32 "\n", crc);
4334cbd2858SGreg Tucker
4344cbd2858SGreg Tucker // Test crc 4k array combine function
4354cbd2858SGreg Tucker uint32_t crcs[NMAX];
4364cbd2858SGreg Tucker crcs[0] = crc32_iscsi(&inp[0], N4k, crc_init);
4374cbd2858SGreg Tucker for (i = 1; i < NMAX; i++)
4384cbd2858SGreg Tucker crcs[i] = crc32_iscsi(&inp[i * N4k], N4k, 0);
4394cbd2858SGreg Tucker
4404cbd2858SGreg Tucker crcn = crc32_iscsi_combine_4k(crcs, NMAX);
4414cbd2858SGreg Tucker printv("crc4k_array = 0x%" PRIx32 "\n", crcn);
4424cbd2858SGreg Tucker err |= crcn ^ crc;
4434cbd2858SGreg Tucker
4444cbd2858SGreg Tucker // CRC64 generic poly tests - reflected
4454cbd2858SGreg Tucker uint64_t len = NMAX_SIZE;
4464cbd2858SGreg Tucker err |= test_combine64(inp, len, 0xc96c5795d7870f42ull, 1, crc64_ecma_refl);
4474cbd2858SGreg Tucker err |= test_combine64(inp, len, 0xd800000000000000ull, 1, crc64_iso_refl);
4484cbd2858SGreg Tucker err |= test_combine64(inp, len, 0x95ac9329ac4bc9b5ull, 1, crc64_jones_refl);
4494cbd2858SGreg Tucker
4504cbd2858SGreg Tucker // CRC64 non-reflected polynomial tests
4514cbd2858SGreg Tucker err |= test_combine64(inp, len, 0x42f0e1eba9ea3693ull, 0, crc64_ecma_norm);
4524cbd2858SGreg Tucker err |= test_combine64(inp, len, 0x000000000000001bull, 0, crc64_iso_norm);
4534cbd2858SGreg Tucker err |= test_combine64(inp, len, 0xad93d23594c935a9ull, 0, crc64_jones_norm);
4544cbd2858SGreg Tucker
4554cbd2858SGreg Tucker printf(err == 0 ? "pass\n" : "fail\n");
4564cbd2858SGreg Tucker free(inp);
4574cbd2858SGreg Tucker return err;
4584cbd2858SGreg Tucker }
459