xref: /freebsd/contrib/xz/src/liblzma/check/crc64_fast.c (revision 128836d304d93f2d00eb14069c27089ab46c38d4)
1 // SPDX-License-Identifier: 0BSD
2 
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file       crc64.c
6 /// \brief      CRC64 calculation
7 //
8 //  Authors:    Lasse Collin
9 //              Ilya Kurdyukov
10 //
11 ///////////////////////////////////////////////////////////////////////////////
12 
13 #include "check.h"
14 #include "crc_common.h"
15 
16 #if defined(CRC_X86_CLMUL)
17 #	define BUILDING_CRC_CLMUL 64
18 #	include "crc_x86_clmul.h"
19 #endif
20 
21 
22 #ifdef CRC64_GENERIC
23 
24 /////////////////////////////////
25 // Generic slice-by-four CRC64 //
26 /////////////////////////////////
27 
28 #if defined(WORDS_BIGENDIAN)
29 #	include "crc64_table_be.h"
30 #else
31 #	include "crc64_table_le.h"
32 #endif
33 
34 
35 #ifdef HAVE_CRC_X86_ASM
36 extern uint64_t lzma_crc64_generic(
37 		const uint8_t *buf, size_t size, uint64_t crc);
38 #else
39 
40 #ifdef WORDS_BIGENDIAN
41 #	define A1(x) ((x) >> 56)
42 #else
43 #	define A1 A
44 #endif
45 
46 
47 // See the comments in crc32_fast.c. They aren't duplicated here.
48 static uint64_t
lzma_crc64_generic(const uint8_t * buf,size_t size,uint64_t crc)49 lzma_crc64_generic(const uint8_t *buf, size_t size, uint64_t crc)
50 {
51 	crc = ~crc;
52 
53 #ifdef WORDS_BIGENDIAN
54 	crc = byteswap64(crc);
55 #endif
56 
57 	if (size > 4) {
58 		while ((uintptr_t)(buf) & 3) {
59 			crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
60 			--size;
61 		}
62 
63 		const uint8_t *const limit = buf + (size & ~(size_t)(3));
64 		size &= (size_t)(3);
65 
66 		while (buf < limit) {
67 #ifdef WORDS_BIGENDIAN
68 			const uint32_t tmp = (uint32_t)(crc >> 32)
69 					^ aligned_read32ne(buf);
70 #else
71 			const uint32_t tmp = (uint32_t)crc
72 					^ aligned_read32ne(buf);
73 #endif
74 			buf += 4;
75 
76 			crc = lzma_crc64_table[3][A(tmp)]
77 			    ^ lzma_crc64_table[2][B(tmp)]
78 			    ^ S32(crc)
79 			    ^ lzma_crc64_table[1][C(tmp)]
80 			    ^ lzma_crc64_table[0][D(tmp)];
81 		}
82 	}
83 
84 	while (size-- != 0)
85 		crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
86 
87 #ifdef WORDS_BIGENDIAN
88 	crc = byteswap64(crc);
89 #endif
90 
91 	return ~crc;
92 }
93 #endif // HAVE_CRC_X86_ASM
94 #endif // CRC64_GENERIC
95 
96 
97 #if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
98 
99 //////////////////////////
100 // Function dispatching //
101 //////////////////////////
102 
103 // If both the generic and arch-optimized implementations are usable, then
104 // the function that is used is selected at runtime. See crc32_fast.c.
105 
106 typedef uint64_t (*crc64_func_type)(
107 		const uint8_t *buf, size_t size, uint64_t crc);
108 
109 static crc64_func_type
crc64_resolve(void)110 crc64_resolve(void)
111 {
112 	return is_arch_extension_supported()
113 			? &crc64_arch_optimized : &lzma_crc64_generic;
114 }
115 
116 #ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
117 #	define CRC64_SET_FUNC_ATTR __attribute__((__constructor__))
118 static crc64_func_type crc64_func;
119 #else
120 #	define CRC64_SET_FUNC_ATTR
121 static uint64_t crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc);
122 static crc64_func_type crc64_func = &crc64_dispatch;
123 #endif
124 
125 
126 CRC64_SET_FUNC_ATTR
127 static void
crc64_set_func(void)128 crc64_set_func(void)
129 {
130 	crc64_func = crc64_resolve();
131 	return;
132 }
133 
134 
135 #ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
136 static uint64_t
crc64_dispatch(const uint8_t * buf,size_t size,uint64_t crc)137 crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc)
138 {
139 	crc64_set_func();
140 	return crc64_func(buf, size, crc);
141 }
142 #endif
143 #endif
144 
145 
146 extern LZMA_API(uint64_t)
lzma_crc64(const uint8_t * buf,size_t size,uint64_t crc)147 lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
148 {
149 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \
150 		&& defined(_M_IX86) && defined(CRC64_ARCH_OPTIMIZED)
151 	// VS2015-2022 might corrupt the ebx register on 32-bit x86 when
152 	// the CLMUL code is enabled. This hack forces MSVC to store and
153 	// restore ebx. This is only needed here, not in lzma_crc32().
154 	__asm  mov ebx, ebx
155 #endif
156 
157 #if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
158 	return crc64_func(buf, size, crc);
159 
160 #elif defined(CRC64_ARCH_OPTIMIZED)
161 	// If arch-optimized version is used unconditionally without runtime
162 	// CPU detection then omitting the generic version and its 8 KiB
163 	// lookup table makes the library smaller.
164 	return crc64_arch_optimized(buf, size, crc);
165 
166 #else
167 	return lzma_crc64_generic(buf, size, crc);
168 #endif
169 }
170