Coverage Report

Created: 2026-10-16 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/libdeflate-src/lib/x86/crc32_impl.h
Line
Count
Source
1
/*
2
 * x86/crc32_impl.h - x86 implementations of the gzip CRC-32 algorithm
3
 *
4
 * Copyright 2016 Eric Biggers
5
 *
6
 * Permission is hereby granted, free of charge, to any person
7
 * obtaining a copy of this software and associated documentation
8
 * files (the "Software"), to deal in the Software without
9
 * restriction, including without limitation the rights to use,
10
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following
13
 * conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be
16
 * included in all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
 * OTHER DEALINGS IN THE SOFTWARE.
26
 */
27
28
#ifndef LIB_X86_CRC32_IMPL_H
29
#define LIB_X86_CRC32_IMPL_H
30
31
#include "cpu_features.h"
32
33
/*
34
 * pshufb(x, shift_tab[len..len+15]) left shifts x by 16-len bytes.
35
 * pshufb(x, shift_tab[len+16..len+31]) right shifts x by len bytes.
36
 */
37
static const u8 MAYBE_UNUSED shift_tab[48] = {
38
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
40
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
41
  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
42
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44
};
45
46
#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
47
/*
48
 * PCLMULQDQ implementation.  This targets PCLMULQDQ+SSE4.1, since in practice
49
 * all CPUs that support PCLMULQDQ also support SSE4.1.
50
 */
51
0
#  define crc32_x86_pclmulqdq crc32_x86_pclmulqdq
52
#  define SUFFIX       _pclmulqdq
53
#  define ATTRIBUTES    _target_attribute("pclmul,sse4.1")
54
0
#  define VL      16
55
#  define USE_AVX512    0
56
#  include "crc32_pclmul_template.h"
57
58
/*
59
 * PCLMULQDQ/AVX implementation.  Same as above, but this is compiled with AVX
60
 * enabled so that the compiler can generate VEX-coded instructions which can be
61
 * slightly more efficient.  It still uses 128-bit vectors.
62
 */
63
2
#  define crc32_x86_pclmulqdq_avx crc32_x86_pclmulqdq_avx
64
#  define SUFFIX         _pclmulqdq_avx
65
#  define ATTRIBUTES    _target_attribute("pclmul,avx")
66
543k
#  define VL      16
67
#  define USE_AVX512    0
68
#  include "crc32_pclmul_template.h"
69
#endif
70
71
/*
72
 * VPCLMULQDQ/AVX2 implementation.  This is used on CPUs that have AVX2 and
73
 * VPCLMULQDQ but don't have AVX-512, for example Intel Alder Lake.
74
 *
75
 * Currently this can't be enabled with MSVC because MSVC has a bug where it
76
 * incorrectly assumes that VPCLMULQDQ implies AVX-512:
77
 * https://developercommunity.visualstudio.com/t/Compiler-incorrectly-assumes-VAES-and-VP/10578785
78
 *
79
 * gcc 8.1 and 8.2 had a similar bug where they assumed that
80
 * _mm256_clmulepi64_epi128() always needed AVX512.  It's fixed in gcc 8.3.
81
 *
82
 * _mm256_zextsi128_si256() requires gcc 10.
83
 */
84
#if (GCC_PREREQ(10, 1) || CLANG_PREREQ(6, 0, 10000000)) && \
85
  !defined(LIBDEFLATE_ASSEMBLER_DOES_NOT_SUPPORT_VPCLMULQDQ)
86
0
#  define crc32_x86_vpclmulqdq_avx2 crc32_x86_vpclmulqdq_avx2
87
#  define SUFFIX         _vpclmulqdq_avx2
88
#  define ATTRIBUTES    _target_attribute("vpclmulqdq,pclmul,avx2")
89
0
#  define VL      32
90
#  define USE_AVX512    0
91
#  include "crc32_pclmul_template.h"
92
#endif
93
94
#if (GCC_PREREQ(10, 1) || CLANG_PREREQ(6, 0, 10000000) || MSVC_PREREQ(1920)) && \
95
  !(CLANG_PREREQ(18, 0, 18000000) && !CLANG_PREREQ(19, 0, 19000000)) && \
96
  !defined(LIBDEFLATE_ASSEMBLER_DOES_NOT_SUPPORT_VPCLMULQDQ)
97
/*
98
 * VPCLMULQDQ/AVX512 implementation using 256-bit vectors.  This is very similar
99
 * to the VPCLMULQDQ/AVX2 implementation but takes advantage of the vpternlog
100
 * instruction and more registers.  This is used on certain older Intel CPUs,
101
 * specifically Ice Lake and Tiger Lake, which support VPCLMULQDQ and AVX512 but
102
 * downclock a bit too eagerly when ZMM registers are used.
103
 *
104
 * _mm256_zextsi128_si256() requires gcc 10.
105
 */
106
0
#  define crc32_x86_vpclmulqdq_avx512_vl256  crc32_x86_vpclmulqdq_avx512_vl256
107
#  define SUFFIX              _vpclmulqdq_avx512_vl256
108
#  define ATTRIBUTES    _target_attribute("vpclmulqdq,pclmul,avx512bw,avx512vl")
109
0
#  define VL      32
110
#  define USE_AVX512    1
111
#  include "crc32_pclmul_template.h"
112
113
/*
114
 * VPCLMULQDQ/AVX512 implementation using 512-bit vectors.  This is used on CPUs
115
 * that have a good AVX-512 implementation including VPCLMULQDQ.
116
 *
117
 * _mm512_zextsi128_si512() requires gcc 10.
118
 */
119
0
#  define crc32_x86_vpclmulqdq_avx512_vl512  crc32_x86_vpclmulqdq_avx512_vl512
120
#  define SUFFIX              _vpclmulqdq_avx512_vl512
121
#  define ATTRIBUTES    _target_attribute("vpclmulqdq,pclmul,avx512bw,avx512vl")
122
0
#  define VL      64
123
#  define USE_AVX512    1
124
#  include "crc32_pclmul_template.h"
125
#endif
126
127
static inline crc32_func_t
128
arch_select_crc32_func(void)
129
2
{
130
2
  const u32 features MAYBE_UNUSED = get_x86_cpu_features();
131
132
2
#ifdef crc32_x86_vpclmulqdq_avx512_vl512
133
2
  if ((features & X86_CPU_FEATURE_ZMM) &&
134
0
      HAVE_VPCLMULQDQ(features) && HAVE_PCLMULQDQ(features) &&
135
0
      HAVE_AVX512BW(features) && HAVE_AVX512VL(features))
136
0
    return crc32_x86_vpclmulqdq_avx512_vl512;
137
2
#endif
138
2
#ifdef crc32_x86_vpclmulqdq_avx512_vl256
139
2
  if (HAVE_VPCLMULQDQ(features) && HAVE_PCLMULQDQ(features) &&
140
0
      HAVE_AVX512BW(features) && HAVE_AVX512VL(features))
141
0
    return crc32_x86_vpclmulqdq_avx512_vl256;
142
2
#endif
143
2
#ifdef crc32_x86_vpclmulqdq_avx2
144
2
  if (HAVE_VPCLMULQDQ(features) && HAVE_PCLMULQDQ(features) &&
145
0
      HAVE_AVX2(features))
146
0
    return crc32_x86_vpclmulqdq_avx2;
147
2
#endif
148
2
#ifdef crc32_x86_pclmulqdq_avx
149
2
  if (HAVE_PCLMULQDQ(features) && HAVE_AVX(features))
150
2
    return crc32_x86_pclmulqdq_avx;
151
0
#endif
152
0
#ifdef crc32_x86_pclmulqdq
153
0
  if (HAVE_PCLMULQDQ(features))
154
0
    return crc32_x86_pclmulqdq;
155
0
#endif
156
0
  return NULL;
157
0
}
158
2
#define arch_select_crc32_func  arch_select_crc32_func
159
160
#endif /* LIB_X86_CRC32_IMPL_H */