/src/ffmpeg/libavutil/x86/crc.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2025 Shreesh Adiga <16567adigashreesh@gmail.com> |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
6 | | * FFmpeg is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * FFmpeg is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with FFmpeg; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #ifndef AVUTIL_X86_CRC_H |
22 | | #define AVUTIL_X86_CRC_H |
23 | | |
24 | | #include "config.h" |
25 | | #include "libavutil/attributes.h" |
26 | | #include "libavutil/attributes_internal.h" |
27 | | #include "libavutil/avassert.h" |
28 | | #include "libavutil/cpu.h" |
29 | | #include "libavutil/crc.h" |
30 | | #include "libavutil/intreadwrite.h" |
31 | | #include "libavutil/reverse.h" |
32 | | #include "libavutil/x86/cpu.h" |
33 | | |
34 | | #if HAVE_CLMUL_EXTERNAL |
35 | | FF_VISIBILITY_PUSH_HIDDEN |
36 | | uint32_t ff_crc_clmul(const AVCRC *ctx, uint32_t crc, |
37 | | const uint8_t *buffer, size_t length); |
38 | | uint32_t ff_crc_le_clmul(const AVCRC *ctx, uint32_t crc, |
39 | | const uint8_t *buffer, size_t length); |
40 | | FF_VISIBILITY_POP_HIDDEN |
41 | | |
42 | | enum { |
43 | | CRC_C = 0, |
44 | | CLMUL_BE, |
45 | | CLMUL_LE, |
46 | | }; |
47 | | |
48 | | static const AVCRC crc_table_clmul[AV_CRC_MAX][17] = { |
49 | | [AV_CRC_8_ATM] = { |
50 | | CLMUL_BE, |
51 | | 0x32000000, 0x0, 0xbc000000, 0x0, |
52 | | 0xc4000000, 0x0, 0x94000000, 0x0, |
53 | | 0x62000000, 0x0, 0x79000000, 0x0, |
54 | | 0x07156a16, 0x1, 0x07000000, 0x1, |
55 | | }, |
56 | | [AV_CRC_8_EBU] = { |
57 | | CLMUL_BE, |
58 | | 0xb5000000, 0x0, 0xf3000000, 0x0, |
59 | | 0xfc000000, 0x0, 0x0d000000, 0x0, |
60 | | 0x6a000000, 0x0, 0x65000000, 0x0, |
61 | | 0x1c4b8192, 0x1, 0x1d000000, 0x1, |
62 | | }, |
63 | | [AV_CRC_16_ANSI] = { |
64 | | CLMUL_BE, |
65 | | 0xf9e30000, 0x0, 0x807d0000, 0x0, |
66 | | 0xf9130000, 0x0, 0xff830000, 0x0, |
67 | | 0x807b0000, 0x0, 0x86630000, 0x0, |
68 | | 0xfffbffe7, 0x1, 0x80050000, 0x1, |
69 | | }, |
70 | | [AV_CRC_16_CCITT] = { |
71 | | CLMUL_BE, |
72 | | 0x60190000, 0x0, 0x59b00000, 0x0, |
73 | | 0xd5f60000, 0x0, 0x45630000, 0x0, |
74 | | 0xaa510000, 0x0, 0xeb230000, 0x0, |
75 | | 0x11303471, 0x1, 0x10210000, 0x1, |
76 | | }, |
77 | | [AV_CRC_24_IEEE] = { |
78 | | CLMUL_BE, |
79 | | 0x1f428700, 0x0, 0x467d2400, 0x0, |
80 | | 0x2c8c9d00, 0x0, 0x64e4d700, 0x0, |
81 | | 0xd9fe8c00, 0x0, 0xfd7e0c00, 0x0, |
82 | | 0xf845fe24, 0x1, 0x864cfb00, 0x1, |
83 | | }, |
84 | | [AV_CRC_32_IEEE] = { |
85 | | CLMUL_BE, |
86 | | 0x8833794c, 0x0, 0xe6228b11, 0x0, |
87 | | 0xc5b9cd4c, 0x0, 0xe8a45605, 0x0, |
88 | | 0x490d678d, 0x0, 0xf200aa66, 0x0, |
89 | | 0x04d101df, 0x1, 0x04c11db7, 0x1, |
90 | | }, |
91 | | [AV_CRC_32_IEEE_LE] = { |
92 | | CLMUL_LE, |
93 | | 0xc6e41596, 0x1, 0x54442bd4, 0x1, |
94 | | 0xccaa009e, 0x0, 0x751997d0, 0x1, |
95 | | 0xccaa009e, 0x0, 0x63cd6124, 0x1, |
96 | | 0xf7011640, 0x1, 0xdb710641, 0x1, |
97 | | }, |
98 | | [AV_CRC_16_ANSI_LE] = { |
99 | | CLMUL_LE, |
100 | | 0x0000bffa, 0x0, 0x1b0c2, 0x0, |
101 | | 0x00018cc2, 0x0, 0x1d0c2, 0x0, |
102 | | 0x00018cc2, 0x0, 0x1bc02, 0x0, |
103 | | 0xcfffbffe, 0x1, 0x14003, 0x0, |
104 | | }, |
105 | | }; |
106 | | |
107 | | static uint64_t reverse(uint64_t p, unsigned int deg) |
108 | 0 | { |
109 | 0 | uint64_t ret = 0; |
110 | 0 | int i; |
111 | 0 | for (i = 0; i < (deg / 8); i += 1) { |
112 | 0 | ret = (ret << 8) | (ff_reverse[p & 0xff]); |
113 | 0 | p >>= 8; |
114 | 0 | } |
115 | 0 | int rem = (deg + 1) - 8 * i; |
116 | 0 | ret = (ret << rem) | (ff_reverse[p & 0xff] >> (8 - rem)); |
117 | 0 | return ret; |
118 | 0 | } |
119 | | |
120 | | static uint64_t xnmodp(unsigned n, uint64_t poly, unsigned deg, uint64_t *div, int bitreverse) |
121 | 0 | { |
122 | 0 | uint64_t mod, mask, high; |
123 | |
|
124 | 0 | if (n < deg) { |
125 | 0 | *div = 0; |
126 | 0 | return poly; |
127 | 0 | } |
128 | 0 | mask = ((uint64_t)1 << deg) - 1; |
129 | 0 | poly &= mask; |
130 | 0 | mod = poly; |
131 | 0 | *div = 1; |
132 | 0 | deg--; |
133 | 0 | while (--n > deg) { |
134 | 0 | high = (mod >> deg) & 1; |
135 | 0 | *div = (*div << 1) | high; |
136 | 0 | mod <<= 1; |
137 | 0 | if (high) |
138 | 0 | mod ^= poly; |
139 | 0 | } |
140 | 0 | uint64_t ret = mod & mask; |
141 | 0 | if (bitreverse) { |
142 | 0 | *div = reverse(*div, deg) << 1; |
143 | 0 | return reverse(ret, deg) << 1; |
144 | 0 | } |
145 | 0 | return ret; |
146 | 0 | } |
147 | | |
148 | | static inline void crc_init_x86(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) |
149 | 0 | { |
150 | 0 | uint64_t poly_; |
151 | 0 | if (le) { |
152 | | // convert the reversed representation to regular form |
153 | 0 | poly = reverse(poly, bits) >> 1; |
154 | 0 | } |
155 | | // convert to 32 degree polynomial |
156 | 0 | poly_ = ((uint64_t)poly) << (32 - bits); |
157 | |
|
158 | 0 | uint64_t div; |
159 | 0 | uint8_t *dst = (uint8_t*)(ctx + 1); |
160 | 0 | if (le) { |
161 | 0 | ctx[0] = CLMUL_LE; |
162 | 0 | AV_WN64(dst, xnmodp(4 * 128 - 32, poly_, 32, &div, le)); |
163 | 0 | AV_WN64(dst + 8, xnmodp(4 * 128 + 32, poly_, 32, &div, le)); |
164 | 0 | uint64_t tmp = xnmodp(128 - 32, poly_, 32, &div, le); |
165 | 0 | AV_WN64(dst + 16, tmp); |
166 | 0 | AV_WN64(dst + 24, xnmodp(128 + 32, poly_, 32, &div, le)); |
167 | 0 | AV_WN64(dst + 32, tmp); |
168 | 0 | AV_WN64(dst + 40, xnmodp(64, poly_, 32, &div, le)); |
169 | 0 | AV_WN64(dst + 48, div); |
170 | 0 | AV_WN64(dst + 56, reverse(poly_ | (1ULL << 32), 32)); |
171 | 0 | } else { |
172 | 0 | ctx[0] = CLMUL_BE; |
173 | 0 | AV_WN64(dst, xnmodp(4 * 128 + 64, poly_, 32, &div, le)); |
174 | 0 | AV_WN64(dst + 8, xnmodp(4 * 128, poly_, 32, &div, le)); |
175 | 0 | AV_WN64(dst + 16, xnmodp(128 + 64, poly_, 32, &div, le)); |
176 | 0 | AV_WN64(dst + 24, xnmodp(128, poly_, 32, &div, le)); |
177 | 0 | AV_WN64(dst + 32, xnmodp(64, poly_, 32, &div, le)); |
178 | 0 | AV_WN64(dst + 48, div); |
179 | 0 | AV_WN64(dst + 40, xnmodp(96, poly_, 32, &div, le)); |
180 | 0 | AV_WN64(dst + 56, poly_ | (1ULL << 32)); |
181 | 0 | } |
182 | 0 | } |
183 | | #endif |
184 | | |
185 | | static inline const AVCRC *ff_crc_get_table_x86(AVCRCId crc_id) |
186 | 0 | { |
187 | 0 | #if HAVE_CLMUL_EXTERNAL |
188 | 0 | int cpu_flags = av_get_cpu_flags(); |
189 | |
|
190 | 0 | if (EXTERNAL_CLMUL(cpu_flags)) { |
191 | 0 | return crc_table_clmul[crc_id]; |
192 | 0 | } |
193 | 0 | #endif |
194 | 0 | return NULL; |
195 | 0 | } |
196 | | |
197 | | static inline av_cold int ff_crc_init_x86(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) |
198 | 0 | { |
199 | 0 | #if HAVE_CLMUL_EXTERNAL |
200 | 0 | int cpu_flags = av_get_cpu_flags(); |
201 | |
|
202 | 0 | if (EXTERNAL_CLMUL(cpu_flags)) { |
203 | 0 | crc_init_x86(ctx, le, bits, poly, ctx_size); |
204 | 0 | return 1; |
205 | 0 | } |
206 | 0 | #endif |
207 | 0 | return 0; |
208 | 0 | } |
209 | | |
210 | | static inline uint32_t ff_crc_x86(const AVCRC *ctx, uint32_t crc, |
211 | | const uint8_t *buffer, size_t length) |
212 | 0 | { |
213 | 0 | switch (ctx[0]) { |
214 | 0 | #if HAVE_CLMUL_EXTERNAL |
215 | 0 | case CLMUL_BE: return ff_crc_clmul(ctx, crc, buffer, length); |
216 | 0 | case CLMUL_LE: return ff_crc_le_clmul(ctx, crc, buffer, length); |
217 | 0 | #endif |
218 | 0 | default: av_unreachable("x86 CRC only uses CLMUL_BE and CLMUL_LE"); |
219 | 0 | } |
220 | 0 | return 0; |
221 | 0 | } |
222 | | |
223 | | #endif /* AVUTIL_X86_CRC_H */ |