aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/check/crc32_aarch64.h
blob: 77b14af4f362402837338b91087ed7e1853e7e32 (plain) (blame)
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
///////////////////////////////////////////////////////////////////////////////
//
/// \file       crc32_aarch64.c
/// \brief      CRC32 calculation with aarch64 optimization
//
//  Authors:    Chenxi Mao
//
//  This file has been put into the public domain.
//  You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////
#ifdef LZMA_CRC_CRC32_AARCH64_H
#	error crc_arm64_clmul.h was included twice.
#endif
#define LZMA_CRC_CRC32_AARCH64_H
#include <sys/auxv.h>
// EDG-based compilers (Intel's classic compiler and compiler for E2K) can
// define __GNUC__ but the attribute must not be used with them.
// The new Clang-based ICX needs the attribute.
//
// NOTE: Build systems check for this too, keep them in sync with this.
#if (defined(__GNUC__) || defined(__clang__)) && !defined(__EDG__)
#	define crc_attr_target \
        __attribute__((__target__("+crc")))
#else
#	define crc_attr_target
#endif
#ifdef BUILDING_CRC32_AARCH64
crc_attr_target
crc_attr_no_sanitize_address
static uint32_t
crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
{
	crc = ~crc;
	while ((uintptr_t)(buf) & 7) {
		crc = __builtin_aarch64_crc32b(crc, *buf);
		buf++;
		size--;
	}
	for (;size>=8;size-=8,buf+=8) {
		crc = __builtin_aarch64_crc32x(crc, aligned_read64le(buf));
	}
	for (;size>0;size--,buf++)
		crc = __builtin_aarch64_crc32b(crc, *buf);
	return ~crc;
}
#endif
#ifdef BUILDING_CRC64_AARCH64
//FIXME: there is no crc64_arch_optimized implementation,
// to make compiler happy, add crc64_generic here.
#ifdef WORDS_BIGENDIAN
#	define A1(x) ((x) >> 56)
#else
#	define A1 A
#endif
crc_attr_target
crc_attr_no_sanitize_address
static uint64_t
crc64_arch_optimized(const uint8_t *buf, size_t size, uint64_t crc)
{
	crc = ~crc;

#ifdef WORDS_BIGENDIAN
	crc = bswap64(crc);
#endif

	if (size > 4) {
		while ((uintptr_t)(buf) & 3) {
			crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
			--size;
		}

		const uint8_t *const limit = buf + (size & ~(size_t)(3));
		size &= (size_t)(3);

		while (buf < limit) {
#ifdef WORDS_BIGENDIAN
			const uint32_t tmp = (uint32_t)(crc >> 32)
					^ aligned_read32ne(buf);
#else
			const uint32_t tmp = (uint32_t)crc
					^ aligned_read32ne(buf);
#endif
			buf += 4;

			crc = lzma_crc64_table[3][A(tmp)]
			    ^ lzma_crc64_table[2][B(tmp)]
			    ^ S32(crc)
			    ^ lzma_crc64_table[1][C(tmp)]
			    ^ lzma_crc64_table[0][D(tmp)];
		}
	}

	while (size-- != 0)
		crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);

#ifdef WORDS_BIGENDIAN
	crc = bswap64(crc);
#endif

	return ~crc;
}
#endif
static inline bool
is_arch_extension_supported(void)
{
	return (getauxval(AT_HWCAP) & HWCAP_CRC32)!=0;
}