summaryrefslogtreecommitdiff
path: root/neozip/test/test_crc32.cc
blob: 1fb0771119e9fe09f5b79d609b11fb960b418d2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* test_crc32.cc -- crc32 unit test
 * Copyright (C) 2019-2021 IBM Corporation
 * Authors: Rogerio Alves    <rogealve@br.ibm.com>
 *          Matheus Castanho <msc@linux.ibm.com>
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

#include <gtest/gtest.h>

extern "C" {
#  include "zutil_p.h"
#  include "zbuild.h"
#  include "arch_functions.h"
#  include "test_cpu_features.h"
#  include "hash_test_strings_p.h"
}

class crc32_variant : public ::testing::TestWithParam<hash_test> {
public:
    void hash(hash_test param, crc32_func crc32) {
        uint32_t crc = crc32(param.initial_crc, param.buf, param.len);
        EXPECT_EQ(crc, param.expect_crc);
    }
};

/* Specifically to test where we had dodgy alignment in the ARMv8 CRC32
 * function. All others are either byte level access or use intrinsics
 * that work with unaligned access */
class crc32_align : public ::testing::TestWithParam<int> {
public:
    void hash(int param, crc32_func crc32) {
        uint8_t *buf = (uint8_t*)zng_alloc(sizeof(uint8_t) * (128 + param));
        memset(buf + param, 0, 128);
        (void)crc32(0, buf + param, 128);
        zng_free(buf);
    }
};

/* Test large 1MB buffer with known CRC32 */
class crc32_large_buf : public ::testing::Test {
protected:
    static uint8_t *buffer;
    static const size_t buffer_size = 1024 * 1024;

    static void SetUpTestSuite() {
        buffer = (uint8_t*)zng_alloc(buffer_size);
        memset(buffer, 0x55, buffer_size);
    }

    static void TearDownTestSuite() {
        zng_free(buffer);
    }

public:
    void hash(crc32_func crc32) {
        EXPECT_EQ(crc32(0, buffer, buffer_size), 0x0026D5FB);
    }
};

uint8_t *crc32_large_buf::buffer = nullptr;

INSTANTIATE_TEST_SUITE_P(crc32, crc32_variant, testing::ValuesIn(hash_tests));

#define TEST_CRC32(name, func, support_flag) \
    TEST_P(crc32_variant, name) { \
        if (!(support_flag)) { \
            GTEST_SKIP(); \
            return; \
        } \
        hash(GetParam(), func); \
    } \
    TEST_F(crc32_large_buf, name) { \
        if (!(support_flag)) { \
            GTEST_SKIP(); \
            return; \
        } \
        hash(func); \
    }

TEST_CRC32(braid, crc32_braid, 1)

#ifdef DISABLE_RUNTIME_CPU_DETECTION
TEST_CRC32(native, native_crc32, 1)

#else

#if defined(ARM_CRC32) || defined(LOONGARCH_CRC)
static const int align_offsets[] = {
    1, 2, 3, 4, 5, 6, 7
};

#define TEST_CRC32_ALIGN(name, func, support_flag) \
    TEST_P(crc32_align, name) { \
        if (!(support_flag)) { \
            GTEST_SKIP(); \
            return; \
        } \
        hash(GetParam(), func); \
    }
#endif

#ifndef WITHOUT_CHORBA
TEST_CRC32(chorba_c, crc32_chorba, 1)
#endif
#ifdef ARM_CRC32
INSTANTIATE_TEST_SUITE_P(crc32_alignment, crc32_align, testing::ValuesIn(align_offsets));
TEST_CRC32(armv8, crc32_armv8, test_cpu_features.arm.has_crc32)
TEST_CRC32_ALIGN(armv8_align, crc32_armv8, test_cpu_features.arm.has_crc32)
#endif
#ifdef ARM_PMULL_EOR3
TEST_CRC32(armv8_pmull_eor3, crc32_armv8_pmull_eor3, test_cpu_features.arm.has_crc32 && test_cpu_features.arm.has_pmull && test_cpu_features.arm.has_eor3)
TEST_CRC32_ALIGN(armv8_pmull_eor3_align, crc32_armv8_pmull_eor3, test_cpu_features.arm.has_crc32 && test_cpu_features.arm.has_pmull && test_cpu_features.arm.has_eor3)
#endif
#ifdef RISCV_CRC32_ZBC
TEST_CRC32(riscv, crc32_riscv64_zbc, test_cpu_features.riscv.has_zbc)
#endif
#ifdef POWER8_VSX_CRC32
TEST_CRC32(power8, crc32_power8, test_cpu_features.power.has_arch_2_07)
#endif
#ifdef S390_CRC32_VX
TEST_CRC32(vx, crc32_s390_vx, test_cpu_features.s390.has_vx)
#endif
#ifdef X86_PCLMULQDQ_CRC
TEST_CRC32(pclmulqdq, crc32_pclmulqdq, test_cpu_features.x86.has_pclmulqdq)
#endif
#ifdef X86_VPCLMULQDQ_AVX2
TEST_CRC32(vpclmulqdq_avx2, crc32_vpclmulqdq_avx2, (test_cpu_features.x86.has_pclmulqdq && test_cpu_features.x86.has_avx2 && test_cpu_features.x86.has_vpclmulqdq))
#endif
#ifdef X86_VPCLMULQDQ_AVX512
TEST_CRC32(vpclmulqdq_avx512, crc32_vpclmulqdq_avx512, (test_cpu_features.x86.has_pclmulqdq && test_cpu_features.x86.has_avx512_common && test_cpu_features.x86.has_vpclmulqdq))
#endif
#ifndef WITHOUT_CHORBA_SSE
#   ifdef X86_SSE2
    TEST_CRC32(chorba_sse2, crc32_chorba_sse2, test_cpu_features.x86.has_sse2)
#   endif
#   ifdef X86_SSE41
    TEST_CRC32(chorba_sse41, crc32_chorba_sse41, test_cpu_features.x86.has_sse41)
#   endif
#endif
#ifdef LOONGARCH_CRC
INSTANTIATE_TEST_SUITE_P(crc32_alignment, crc32_align, testing::ValuesIn(align_offsets));
TEST_CRC32(loongarch64, crc32_loongarch64, test_cpu_features.loongarch.has_crc)
TEST_CRC32_ALIGN(loongarch64_align, crc32_loongarch64, test_cpu_features.loongarch.has_crc)
#endif

#endif