xref: /isa-l/examples/crc/crc_combine_example.c (revision 9d99f8215d315fe67f178ce3849b0f40e13ee704)
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