Coverage Report

Created: 2026-08-08 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/butil/crc32c.cc
Line
Count
Source
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under the BSD-style license found in the
3
//  LICENSE file in the root directory of this source tree. An additional grant
4
//  of patent rights can be found in the PATENTS file in the same directory.
5
//
6
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7
// Use of this source code is governed by a BSD-style license that can be
8
// found in the LICENSE file. See the AUTHORS file for names of contributors.
9
//
10
// A portable implementation of crc32c, optimized to handle
11
// four bytes at a time.
12
13
#include "butil/crc32c.h"
14
15
#include <string.h>
16
#include <stdint.h>
17
#ifdef __SSE4_2__
18
#include <nmmintrin.h>
19
#endif
20
#include "butil/build_config.h"
21
22
namespace butil {
23
namespace crc32c {
24
25
static const uint32_t table0_[256] = {
26
  0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
27
  0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
28
  0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
29
  0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
30
  0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
31
  0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
32
  0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
33
  0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
34
  0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
35
  0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
36
  0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
37
  0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
38
  0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
39
  0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
40
  0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
41
  0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
42
  0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
43
  0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
44
  0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
45
  0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
46
  0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
47
  0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
48
  0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
49
  0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
50
  0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
51
  0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
52
  0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
53
  0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
54
  0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
55
  0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
56
  0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
57
  0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
58
  0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
59
  0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
60
  0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
61
  0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
62
  0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
63
  0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
64
  0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
65
  0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
66
  0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
67
  0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
68
  0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
69
  0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
70
  0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
71
  0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
72
  0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
73
  0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
74
  0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
75
  0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
76
  0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
77
  0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
78
  0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
79
  0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
80
  0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
81
  0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
82
  0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
83
  0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
84
  0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
85
  0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
86
  0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
87
  0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
88
  0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
89
  0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351
90
};
91
static const uint32_t table1_[256] = {
92
  0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899,
93
  0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945,
94
  0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21,
95
  0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd,
96
  0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918,
97
  0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4,
98
  0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0,
99
  0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c,
100
  0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b,
101
  0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47,
102
  0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823,
103
  0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff,
104
  0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a,
105
  0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6,
106
  0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2,
107
  0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e,
108
  0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d,
109
  0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41,
110
  0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25,
111
  0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9,
112
  0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c,
113
  0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0,
114
  0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4,
115
  0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78,
116
  0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f,
117
  0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43,
118
  0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27,
119
  0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb,
120
  0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e,
121
  0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2,
122
  0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6,
123
  0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a,
124
  0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260,
125
  0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc,
126
  0x66d73941, 0x7575a136, 0x419209af, 0x523091d8,
127
  0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004,
128
  0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1,
129
  0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d,
130
  0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059,
131
  0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185,
132
  0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162,
133
  0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be,
134
  0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da,
135
  0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306,
136
  0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3,
137
  0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f,
138
  0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b,
139
  0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287,
140
  0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464,
141
  0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8,
142
  0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc,
143
  0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600,
144
  0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5,
145
  0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439,
146
  0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d,
147
  0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781,
148
  0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766,
149
  0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba,
150
  0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de,
151
  0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502,
152
  0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7,
153
  0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b,
154
  0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f,
155
  0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483
156
};
157
static const uint32_t table2_[256] = {
158
  0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073,
159
  0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469,
160
  0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6,
161
  0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac,
162
  0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9,
163
  0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3,
164
  0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c,
165
  0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726,
166
  0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67,
167
  0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d,
168
  0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2,
169
  0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8,
170
  0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed,
171
  0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7,
172
  0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828,
173
  0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32,
174
  0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa,
175
  0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0,
176
  0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f,
177
  0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75,
178
  0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20,
179
  0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a,
180
  0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5,
181
  0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff,
182
  0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe,
183
  0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4,
184
  0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b,
185
  0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161,
186
  0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634,
187
  0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e,
188
  0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1,
189
  0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb,
190
  0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730,
191
  0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a,
192
  0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5,
193
  0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def,
194
  0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba,
195
  0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0,
196
  0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f,
197
  0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065,
198
  0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24,
199
  0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e,
200
  0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1,
201
  0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb,
202
  0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae,
203
  0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4,
204
  0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b,
205
  0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71,
206
  0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9,
207
  0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3,
208
  0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c,
209
  0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36,
210
  0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63,
211
  0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79,
212
  0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6,
213
  0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc,
214
  0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd,
215
  0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7,
216
  0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238,
217
  0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622,
218
  0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177,
219
  0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d,
220
  0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2,
221
  0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8
222
};
223
static const uint32_t table3_[256] = {
224
  0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939,
225
  0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca,
226
  0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf,
227
  0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c,
228
  0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804,
229
  0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7,
230
  0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2,
231
  0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11,
232
  0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2,
233
  0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41,
234
  0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54,
235
  0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7,
236
  0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f,
237
  0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c,
238
  0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69,
239
  0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a,
240
  0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de,
241
  0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d,
242
  0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538,
243
  0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb,
244
  0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3,
245
  0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610,
246
  0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405,
247
  0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6,
248
  0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255,
249
  0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6,
250
  0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3,
251
  0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040,
252
  0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368,
253
  0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b,
254
  0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e,
255
  0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d,
256
  0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006,
257
  0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5,
258
  0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0,
259
  0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213,
260
  0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b,
261
  0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8,
262
  0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd,
263
  0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e,
264
  0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d,
265
  0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e,
266
  0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b,
267
  0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698,
268
  0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0,
269
  0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443,
270
  0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656,
271
  0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5,
272
  0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1,
273
  0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12,
274
  0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07,
275
  0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4,
276
  0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc,
277
  0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f,
278
  0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a,
279
  0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9,
280
  0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a,
281
  0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99,
282
  0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c,
283
  0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f,
284
  0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57,
285
  0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4,
286
  0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1,
287
  0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842
288
};
289
290
// Lower-level versions of Get... that read directly from a character buffer
291
// without any bounds checking.
292
293
0
static inline uint32_t DecodeFixed32(const char* ptr) {
294
0
#if defined(ARCH_CPU_LITTLE_ENDIAN) && ARCH_CPU_LITTLE_ENDIAN
295
    // Load the raw bytes
296
0
    uint32_t result;
297
0
    memcpy(&result, ptr, sizeof(result));  // gcc optimizes this to a plain load
298
0
    return result;
299
#else
300
    return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0])))
301
        | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) << 8)
302
        | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[2])) << 16)
303
        | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) << 24));
304
#endif
305
0
}
306
307
0
inline uint64_t DecodeFixed64(const char* ptr) {
308
0
#if defined(ARCH_CPU_LITTLE_ENDIAN) && ARCH_CPU_LITTLE_ENDIAN
309
0
    // Load the raw bytes
310
0
    uint64_t result;
311
0
    memcpy(&result, ptr, sizeof(result));  // gcc optimizes this to a plain load
312
0
    return result;
313
0
#else
314
0
    uint64_t lo = DecodeFixed32(ptr);
315
0
    uint64_t hi = DecodeFixed32(ptr + 4);
316
0
    return (hi << 32) | lo;
317
0
#endif
318
0
}
319
320
// Used to fetch a naturally-aligned 32-bit word in little endian byte-order
321
0
static inline uint32_t LE_LOAD32(const uint8_t *p) {
322
0
  return DecodeFixed32(reinterpret_cast<const char*>(p));
323
0
}
324
325
#ifdef __SSE4_2__
326
#ifdef __LP64__
327
static inline uint64_t LE_LOAD64(const uint8_t *p) {
328
  return DecodeFixed64(reinterpret_cast<const char*>(p));
329
}
330
#endif
331
#endif
332
333
0
static inline void Slow_CRC32(uint64_t* l, uint8_t const **p) {
334
0
  uint32_t c = static_cast<uint32_t>(*l ^ LE_LOAD32(*p));
335
0
  *p += 4;
336
0
  *l = table3_[c & 0xff] ^
337
0
  table2_[(c >> 8) & 0xff] ^
338
0
  table1_[(c >> 16) & 0xff] ^
339
0
  table0_[c >> 24];
340
  // DO it twice.
341
0
  c = static_cast<uint32_t>(*l ^ LE_LOAD32(*p));
342
0
  *p += 4;
343
0
  *l = table3_[c & 0xff] ^
344
0
  table2_[(c >> 8) & 0xff] ^
345
0
  table1_[(c >> 16) & 0xff] ^
346
0
  table0_[c >> 24];
347
0
}
348
349
0
static inline void Fast_CRC32(uint64_t* l, uint8_t const **p) {
350
0
#ifdef __SSE4_2__
351
0
#ifdef __LP64__
352
0
  *l = _mm_crc32_u64(*l, LE_LOAD64(*p));
353
0
  *p += 8;
354
0
#else
355
0
  *l = _mm_crc32_u32(static_cast<unsigned int>(*l), LE_LOAD32(*p));
356
0
  *p += 4;
357
0
  *l = _mm_crc32_u32(static_cast<unsigned int>(*l), LE_LOAD32(*p));
358
0
  *p += 4;
359
0
#endif
360
0
#else
361
0
  Slow_CRC32(l, p);
362
0
#endif
363
0
}
364
365
class FastCRC32Functor {
366
public:
367
0
  inline void operator()(uint64_t* l, uint8_t const **p) const {
368
0
    return Fast_CRC32(l , p);
369
0
  }
370
};
371
372
class SlowCRC32Functor {
373
public:
374
0
  inline void operator()(uint64_t* l, uint8_t const **p) const {
375
0
    return Slow_CRC32(l , p);
376
0
  }
377
};
378
379
template<typename CRC32Functor>
380
0
uint32_t ExtendImpl(uint32_t crc, const char* buf, size_t size) {
381
0
  CRC32Functor CRC32;
382
383
0
  const uint8_t *p = reinterpret_cast<const uint8_t *>(buf);
384
0
  const uint8_t *e = p + size;
385
0
  uint64_t l = crc ^ 0xffffffffu;
386
387
// Align n to (1 << m) byte boundary
388
0
#define ALIGN(n, m)     ((n + ((1 << m) - 1)) & ~((1 << m) - 1))
389
390
0
#define STEP1 do {                              \
391
0
    int c = (l & 0xff) ^ *p++;                  \
392
0
    l = table0_[c] ^ (l >> 8);                  \
393
0
} while (0)
394
395
396
  // Point x at first 16-byte aligned byte in string.  This might be
397
  // just past the end of the string.
398
0
  const uintptr_t pval = reinterpret_cast<uintptr_t>(p);
399
0
  const uint8_t* x = reinterpret_cast<const uint8_t*>(ALIGN(pval, 4));
400
0
  if (x <= e) {
401
    // Process bytes until finished or p is 16-byte aligned
402
0
    while (p != x) {
403
0
      STEP1;
404
0
    }
405
0
  }
406
  // Process bytes 16 at a time
407
0
  while ((e-p) >= 16) {
408
0
    CRC32(&l, &p);
409
0
    CRC32(&l, &p);
410
0
  }
411
  // Process bytes 8 at a time
412
0
  while ((e-p) >= 8) {
413
0
    CRC32(&l, &p);
414
0
  }
415
  // Process the last few bytes
416
0
  while (p != e) {
417
0
    STEP1;
418
0
  }
419
0
#undef STEP1
420
0
#undef ALIGN
421
0
  return static_cast<uint32_t>(l ^ 0xffffffffu);
422
0
}
423
424
#if defined(__riscv) && (__riscv_xlen == 64) && (defined(__riscv_zbc) || defined(__riscv_zvbc))
425
#include <stdio.h>
426
#if defined(__riscv_zvbc)
427
#include <riscv_vector.h>
428
#endif
429
430
// RISC-V Zbc carry-less multiplication inline helpers
431
static inline uint64_t rv_clmul(uint64_t a, uint64_t b) {
432
  uint64_t result;
433
  __asm__ volatile ("clmul %0, %1, %2" : "=r"(result) : "r"(a), "r"(b));
434
  return result;
435
}
436
437
static inline uint64_t rv_clmulh(uint64_t a, uint64_t b) {
438
  uint64_t result;
439
  __asm__ volatile ("clmulh %0, %1, %2" : "=r"(result) : "r"(a), "r"(b));
440
  return result;
441
}
442
443
// Bitwise CRC32C fallback for small chunks
444
static inline uint32_t rv_crc32c_bitwise(uint32_t crc, const uint8_t* buf,
445
                                         size_t len) {
446
  uint32_t c = crc;
447
  for (size_t i = 0; i < len; ++i) {
448
    c ^= buf[i];
449
    for (int k = 0; k < 8; ++k) {
450
      c = (c >> 1) ^ ((c & 1) ? 0x82F63B78U : 0);
451
    }
452
  }
453
  return c;
454
}
455
456
// Fold a 128-bit CRC state (lo:hi) with fold constants and XOR in new data
457
static inline void rv_fold_pair_xor_data(uint64_t* lo, uint64_t* hi,
458
                                         uint64_t k0, uint64_t k1,
459
                                         uint64_t d0, uint64_t d1) {
460
  uint64_t l = rv_clmul(*lo, k0) ^ rv_clmul(*hi, k1);
461
  uint64_t h = rv_clmulh(*lo, k0) ^ rv_clmulh(*hi, k1);
462
  *lo = l ^ d0;
463
  *hi = h ^ d1;
464
}
465
466
// Fold a 128-bit CRC state with fold constants and XOR in another state
467
static inline void rv_fold_pair_xor_state(uint64_t* lo, uint64_t* hi,
468
                                          uint64_t k0, uint64_t k1,
469
                                          uint64_t s0, uint64_t s1) {
470
  uint64_t l = rv_clmul(*lo, k0) ^ rv_clmul(*hi, k1);
471
  uint64_t h = rv_clmulh(*lo, k0) ^ rv_clmulh(*hi, k1);
472
  *lo = l ^ s0;
473
  *hi = h ^ s1;
474
}
475
476
// Folding constants for CRC32C (Castagnoli polynomial 0x1EDC6F41)
477
// x^(64*i+64) mod P(x) for i=1..4, in bit-reflected form
478
static const uint64_t crc32c_fold_const[4] __attribute__((aligned(16))) = {
479
  0x00000000740eef02ULL,  // k1: fold 512->256
480
  0x000000009e4addf8ULL,  // k2: fold 512->256
481
  0x00000000f20c0dfeULL,  // k3: fold 256->128
482
  0x00000000493c7d27ULL   // k4: fold 256->128
483
};
484
485
// Barrett reduction constants for CRC32C finalization
486
#define RV_CRC32C_CONST_0    0x00000000dd45aab8ULL  // x^64 mod P
487
#define RV_CRC32C_CONST_1    0x00000000493c7d27ULL  // x^96 mod P
488
#define RV_CRC32C_CONST_QUO  0x0000000dea713f1ULL   // floor(x^64 / P)
489
#define RV_CRC32C_CONST_POLY 0x0000000105ec76f1ULL  // P(x) true LE full
490
#define RV_CRC32_MASK32      0x00000000FFFFFFFFULL
491
492
// Hardware-accelerated CRC32C using RISC-V Zbc carry-less multiplication.
493
// Processes data in 64-byte chunks with 128-bit folding, then Barrett reduces.
494
#if defined(__riscv_zbc)
495
static uint32_t rv_crc32c_clmul(uint32_t crc, const char* buf, size_t len) {
496
  // Convert external CRC to internal register state
497
  crc ^= 0xFFFFFFFF;
498
499
  const uint8_t* p = reinterpret_cast<const uint8_t*>(buf);
500
  size_t n = len;
501
502
  // Small data: use bitwise fallback
503
  if (n < 64) {
504
    return rv_crc32c_bitwise(crc, p, n) ^ 0xFFFFFFFF;
505
  }
506
507
  // Align to 16-byte boundary
508
  uintptr_t mis = (uintptr_t)p & 0xF;
509
  if (mis) {
510
    size_t pre = 16 - mis;
511
    if (pre > n) pre = n;
512
    crc = rv_crc32c_bitwise(crc, p, pre);
513
    p += pre;
514
    n -= pre;
515
    if (n < 64) {
516
      return rv_crc32c_bitwise(crc, p, n) ^ 0xFFFFFFFF;
517
    }
518
  }
519
520
  // Load first 64 bytes and XOR CRC into the first 8 bytes
521
  uint64_t x0, x1, y0, y1, z0, z1, w0, w1;
522
  memcpy(&x0, p + 0, 8);
523
  memcpy(&x1, p + 8, 8);
524
  memcpy(&y0, p + 16, 8);
525
  memcpy(&y1, p + 24, 8);
526
  memcpy(&z0, p + 32, 8);
527
  memcpy(&z1, p + 40, 8);
528
  memcpy(&w0, p + 48, 8);
529
  memcpy(&w1, p + 56, 8);
530
531
  x0 ^= (uint64_t)crc;
532
  p += 64;
533
  n -= 64;
534
535
  const uint64_t k1 = crc32c_fold_const[0];
536
  const uint64_t k2 = crc32c_fold_const[1];
537
  const uint64_t k3 = crc32c_fold_const[2];
538
  const uint64_t k4 = crc32c_fold_const[3];
539
540
  // Main loop: fold 64 bytes per iteration using 128-bit folding
541
  while (n >= 64) {
542
    uint64_t d0, d1;
543
    memcpy(&d0, p + 0, 8);
544
    memcpy(&d1, p + 8, 8);
545
    rv_fold_pair_xor_data(&x0, &x1, k1, k2, d0, d1);
546
    memcpy(&d0, p + 16, 8);
547
    memcpy(&d1, p + 24, 8);
548
    rv_fold_pair_xor_data(&y0, &y1, k1, k2, d0, d1);
549
    memcpy(&d0, p + 32, 8);
550
    memcpy(&d1, p + 40, 8);
551
    rv_fold_pair_xor_data(&z0, &z1, k1, k2, d0, d1);
552
    memcpy(&d0, p + 48, 8);
553
    memcpy(&d1, p + 56, 8);
554
    rv_fold_pair_xor_data(&w0, &w1, k1, k2, d0, d1);
555
    p += 64;
556
    n -= 64;
557
  }
558
559
  // Reduce 4x128-bit to 1x128-bit
560
  rv_fold_pair_xor_state(&x0, &x1, k3, k4, y0, y1);
561
  rv_fold_pair_xor_state(&x0, &x1, k3, k4, z0, z1);
562
  rv_fold_pair_xor_state(&x0, &x1, k3, k4, w0, w1);
563
564
  // Barrett reduction: 128-bit -> 32-bit CRC
565
  uint64_t t4 = rv_clmul(x0, RV_CRC32C_CONST_1);
566
  uint64_t t3 = rv_clmulh(x0, RV_CRC32C_CONST_1);
567
  uint64_t t1 = x1 ^ t4;
568
  t4 = t1 & RV_CRC32_MASK32;
569
  t1 >>= 32;
570
  uint64_t t0 = rv_clmul(t4, RV_CRC32C_CONST_0);
571
  t3 = (t3 << 32) ^ t1 ^ t0;
572
573
  t4 = t3 & RV_CRC32_MASK32;
574
  t4 = rv_clmul(t4, RV_CRC32C_CONST_QUO);
575
  t4 &= RV_CRC32_MASK32;
576
  t4 = rv_clmul(t4, RV_CRC32C_CONST_POLY);
577
  t4 ^= t3;
578
579
  uint32_t c = (uint32_t)((t4 >> 32) & RV_CRC32_MASK32);
580
  // Handle remaining bytes
581
  if (n) {
582
    c = rv_crc32c_bitwise(c, p, n);
583
  }
584
  // Convert internal register state to external CRC
585
  return c ^ 0xFFFFFFFF;
586
}
587
#endif  // __riscv_zbc
588
589
// Runtime detection: check if RISC-V CPU supports Zbc extension
590
static bool is_zbc() {
591
  static const bool zbc_supported = []() {
592
    FILE* f = fopen("/proc/cpuinfo", "r");
593
    if (!f) return false;
594
    bool supported = false;
595
    char line[1024];
596
    while (fgets(line, sizeof(line), f)) {
597
      if (strstr(line, "isa") || strstr(line, "hart isa")) {
598
        char* colon = strchr(line, ':');
599
        if (colon) {
600
          if (strstr(colon, "_zbc")) {
601
            supported = true;
602
            break;
603
          }
604
        }
605
      }
606
    }
607
    fclose(f);
608
    return supported;
609
  }();
610
  return zbc_supported;
611
}
612
613
#if defined(__riscv_zvbc)
614
// Hardware-accelerated CRC32C using RISC-V Zvbc vector carry-less multiplication.
615
// Uses RVV vclmul/vclmulh to process 2 lanes per vector operation (VLEN=128).
616
// With VLEN=128, each vector register holds 2 x 64-bit elements.
617
// 4 lanes are processed using 2 vector register pairs per clmul step.
618
static uint32_t rv_crc32c_vclmul(uint32_t crc, const char* buf, size_t len) {
619
  crc ^= 0xFFFFFFFF;
620
621
  const uint8_t* p = reinterpret_cast<const uint8_t*>(buf);
622
  size_t n = len;
623
624
  if (n < 64) {
625
    return rv_crc32c_bitwise(crc, p, n) ^ 0xFFFFFFFF;
626
  }
627
628
  // Align to 16-byte boundary
629
  uintptr_t mis = (uintptr_t)p & 0xF;
630
  if (mis) {
631
    size_t pre = 16 - mis;
632
    if (pre > n) pre = n;
633
    crc = rv_crc32c_bitwise(crc, p, pre);
634
    p += pre;
635
    n -= pre;
636
    if (n < 64) {
637
      return rv_crc32c_bitwise(crc, p, n) ^ 0xFFFFFFFF;
638
    }
639
  }
640
641
  // Set up RVV for 64-bit elements: vl = min(VLEN/64, 2) = 2 for VLEN=128
642
  // If VLEN < 128, vl will be 1 and the vector path cannot be used; fall back.
643
  size_t vl = __riscv_vsetvl_e64m1(2);
644
  if (vl < 2) {
645
    return rv_crc32c_bitwise(crc, p, n) ^ 0xFFFFFFFF;
646
  }
647
648
  // Construct fold constant vectors: {k1, k2} and {k3, k4}
649
  // Each element gets the appropriate constant for its position:
650
  // element 0 (lo half) uses k1/k3, element 1 (hi half) uses k2/k4
651
  uint64_t k12_arr[2] = { crc32c_fold_const[0], crc32c_fold_const[1] };
652
  uint64_t k34_arr[2] = { crc32c_fold_const[2], crc32c_fold_const[3] };
653
  vuint64m1_t k12_vec = __riscv_vle64_v_u64m1(k12_arr, vl);  // {k1, k2}
654
  vuint64m1_t k34_vec = __riscv_vle64_v_u64m1(k34_arr, vl);  // {k3, k4}
655
656
  // Load first 64 bytes into 4 vector registers.
657
  // Each vector = one 128-bit lane: {lo_64, hi_64}
658
  // Use memcpy to avoid strict-aliasing violations when loading uint8_t* as uint64_t*
659
  uint64_t lane1_buf[2], lane2_buf[2], lane3_buf[2], lane4_buf[2];
660
  memcpy(lane1_buf, p + 0,  16);
661
  memcpy(lane2_buf, p + 16, 16);
662
  memcpy(lane3_buf, p + 32, 16);
663
  memcpy(lane4_buf, p + 48, 16);
664
  vuint64m1_t lane1 = __riscv_vle64_v_u64m1(lane1_buf, vl);
665
  vuint64m1_t lane2 = __riscv_vle64_v_u64m1(lane2_buf, vl);
666
  vuint64m1_t lane3 = __riscv_vle64_v_u64m1(lane3_buf, vl);
667
  vuint64m1_t lane4 = __riscv_vle64_v_u64m1(lane4_buf, vl);
668
669
  // XOR CRC into element 0 of first lane
670
  uint64_t tmp[2];
671
  __riscv_vse64_v_u64m1(tmp, lane1, vl);
672
  tmp[0] ^= (uint64_t)crc;
673
  lane1 = __riscv_vle64_v_u64m1(tmp, vl);
674
675
  p += 64;
676
  n -= 64;
677
678
  // Main loop: fold 64 bytes per iteration using vector carry-less multiply.
679
  //
680
  // For each 128-bit lane {lo, hi}, the fold computes:
681
  //   new_lo = clmul(lo, k1) ^ clmul(hi, k2) ^ data_lo
682
  //   new_hi = clmulh(lo, k1) ^ clmulh(hi, k2) ^ data_hi
683
  //
684
  // With k12_vec = {k1, k2} and element-wise vclmul:
685
  //   vclmul(lane, k12_vec)  = {clmul(lo, k1), clmul(hi, k2)}   (lo halves of products)
686
  //   vclmulh(lane, k12_vec) = {clmulh(lo, k1), clmulh(hi, k2)} (hi halves of products)
687
  //
688
  // The 128-bit XOR of (lo*k1) and (hi*k2) decomposes element-wise:
689
  //   new_lo = clmul(lo,k1) ^ clmul(hi,k2) = vclmul[0] ^ vclmul[1]
690
  //   new_hi = clmulh(lo,k1) ^ clmulh(hi,k2) = vclmulh[0] ^ vclmulh[1]
691
  //
692
  // So we need to XOR across elements. With VLEN=128 (2 elements), we use
693
  // scalar extraction for the cross-element XOR since there's no vector
694
  // permute instruction for just 2 elements that's more efficient.
695
  while (n >= 64) {
696
    uint64_t d1_buf[2], d2_buf[2], d3_buf[2], d4_buf[2];
697
    memcpy(d1_buf, p + 0,  16);
698
    memcpy(d2_buf, p + 16, 16);
699
    memcpy(d3_buf, p + 32, 16);
700
    memcpy(d4_buf, p + 48, 16);
701
    vuint64m1_t d1 = __riscv_vle64_v_u64m1(d1_buf, vl);
702
    vuint64m1_t d2 = __riscv_vle64_v_u64m1(d2_buf, vl);
703
    vuint64m1_t d3 = __riscv_vle64_v_u64m1(d3_buf, vl);
704
    vuint64m1_t d4 = __riscv_vle64_v_u64m1(d4_buf, vl);
705
706
    // Fold each lane using vector clmul with {k1, k2}
707
    uint64_t lo_r[2], hi_r[2], d_r[2];
708
709
    // Lane 1
710
    __riscv_vse64_v_u64m1(lo_r, __riscv_vclmul_vv_u64m1(lane1, k12_vec, vl), vl);
711
    __riscv_vse64_v_u64m1(hi_r, __riscv_vclmulh_vv_u64m1(lane1, k12_vec, vl), vl);
712
    __riscv_vse64_v_u64m1(d_r, d1, vl);
713
    d_r[0] ^= lo_r[0] ^ lo_r[1];
714
    d_r[1] ^= hi_r[0] ^ hi_r[1];
715
    lane1 = __riscv_vle64_v_u64m1(d_r, vl);
716
717
    // Lane 2
718
    __riscv_vse64_v_u64m1(lo_r, __riscv_vclmul_vv_u64m1(lane2, k12_vec, vl), vl);
719
    __riscv_vse64_v_u64m1(hi_r, __riscv_vclmulh_vv_u64m1(lane2, k12_vec, vl), vl);
720
    __riscv_vse64_v_u64m1(d_r, d2, vl);
721
    d_r[0] ^= lo_r[0] ^ lo_r[1];
722
    d_r[1] ^= hi_r[0] ^ hi_r[1];
723
    lane2 = __riscv_vle64_v_u64m1(d_r, vl);
724
725
    // Lane 3
726
    __riscv_vse64_v_u64m1(lo_r, __riscv_vclmul_vv_u64m1(lane3, k12_vec, vl), vl);
727
    __riscv_vse64_v_u64m1(hi_r, __riscv_vclmulh_vv_u64m1(lane3, k12_vec, vl), vl);
728
    __riscv_vse64_v_u64m1(d_r, d3, vl);
729
    d_r[0] ^= lo_r[0] ^ lo_r[1];
730
    d_r[1] ^= hi_r[0] ^ hi_r[1];
731
    lane3 = __riscv_vle64_v_u64m1(d_r, vl);
732
733
    // Lane 4
734
    __riscv_vse64_v_u64m1(lo_r, __riscv_vclmul_vv_u64m1(lane4, k12_vec, vl), vl);
735
    __riscv_vse64_v_u64m1(hi_r, __riscv_vclmulh_vv_u64m1(lane4, k12_vec, vl), vl);
736
    __riscv_vse64_v_u64m1(d_r, d4, vl);
737
    d_r[0] ^= lo_r[0] ^ lo_r[1];
738
    d_r[1] ^= hi_r[0] ^ hi_r[1];
739
    lane4 = __riscv_vle64_v_u64m1(d_r, vl);
740
741
    p += 64;
742
    n -= 64;
743
  }
744
745
  // Reduce 4 lanes to 1 using {k3, k4}
746
  // Same fold pattern: fold lane_a into lane_b
747
  #define FOLD_INTO(dst, src) do { \
748
    uint64_t _lo[2], _hi[2], _d[2]; \
749
    __riscv_vse64_v_u64m1(_lo, __riscv_vclmul_vv_u64m1(src, k34_vec, vl), vl); \
750
    __riscv_vse64_v_u64m1(_hi, __riscv_vclmulh_vv_u64m1(src, k34_vec, vl), vl); \
751
    __riscv_vse64_v_u64m1(_d, dst, vl); \
752
    _d[0] ^= _lo[0] ^ _lo[1]; \
753
    _d[1] ^= _hi[0] ^ _hi[1]; \
754
    dst = __riscv_vle64_v_u64m1(_d, vl); \
755
  } while(0)
756
757
  FOLD_INTO(lane2, lane1);  // lane2 = fold(lane1) ^ lane2
758
  FOLD_INTO(lane3, lane2);  // lane3 = fold(lane2) ^ lane3
759
  FOLD_INTO(lane4, lane3);  // lane4 = fold(lane3) ^ lane4
760
  #undef FOLD_INTO
761
762
  // Extract final 128-bit state from vector register
763
  uint64_t final_state[2];
764
  __riscv_vse64_v_u64m1(final_state, lane4, vl);
765
  uint64_t x0 = final_state[0];
766
  uint64_t x1 = final_state[1];
767
768
  // Barrett reduction: 128-bit -> 32-bit CRC (scalar)
769
  uint64_t t4 = rv_clmul(x0, RV_CRC32C_CONST_1);
770
  uint64_t t3 = rv_clmulh(x0, RV_CRC32C_CONST_1);
771
  uint64_t t1 = x1 ^ t4;
772
  t4 = t1 & RV_CRC32_MASK32;
773
  t1 >>= 32;
774
  uint64_t t0 = rv_clmul(t4, RV_CRC32C_CONST_0);
775
  t3 = (t3 << 32) ^ t1 ^ t0;
776
777
  t4 = t3 & RV_CRC32_MASK32;
778
  t4 = rv_clmul(t4, RV_CRC32C_CONST_QUO);
779
  t4 &= RV_CRC32_MASK32;
780
  t4 = rv_clmul(t4, RV_CRC32C_CONST_POLY);
781
  t4 ^= t3;
782
783
  uint32_t c = (uint32_t)((t4 >> 32) & RV_CRC32_MASK32);
784
  if (n) {
785
    c = rv_crc32c_bitwise(c, p, n);
786
  }
787
  return c ^ 0xFFFFFFFF;
788
}
789
790
// Runtime detection: check if RISC-V CPU supports Zvbc extension
791
static bool is_zvbc() {
792
  static const bool zvbc_supported = []() {
793
    FILE* f = fopen("/proc/cpuinfo", "r");
794
    if (!f) return false;
795
    bool supported = false;
796
    char line[1024];
797
    while (fgets(line, sizeof(line), f)) {
798
      if (strstr(line, "isa") || strstr(line, "hart isa")) {
799
        char* colon = strchr(line, ':');
800
        if (colon) {
801
          if (strstr(colon, "_zvbc")) {
802
            supported = true;
803
            break;
804
          }
805
        }
806
      }
807
    }
808
    fclose(f);
809
    return supported;
810
  }();
811
  return zvbc_supported;
812
}
813
#endif  // __riscv_zvbc
814
815
#endif  // __riscv && __riscv_xlen == 64 && (__riscv_zbc || __riscv_zvbc)
816
817
// Detect if SSE4.2 or not.
818
#ifdef __SSE4_2__
819
static bool isSSE42() {
820
#if defined(__GNUC__) && defined(__x86_64__) && !defined(IOS_CROSS_COMPILE)
821
  uint32_t c_;
822
  uint32_t d_;
823
  __asm__("cpuid" : "=c"(c_), "=d"(d_) : "a"(1) : "ebx");
824
  return c_ & (1U << 20);  // copied from CpuId.h in Folly.
825
#else
826
  return false;
827
#endif
828
}
829
#endif
830
831
typedef uint32_t (*Function)(uint32_t, const char*, size_t);
832
833
0
static inline Function Choose_Extend() {
834
#ifdef __SSE4_2__
835
  if (isSSE42()) {
836
    return (Function)ExtendImpl<FastCRC32Functor>;
837
  }
838
#endif
839
#if defined(__riscv) && (__riscv_xlen == 64) && (defined(__riscv_zbc) || defined(__riscv_zvbc))
840
#if defined(__riscv_zvbc)
841
  if (is_zvbc()) {
842
    return (Function)rv_crc32c_vclmul;
843
  }
844
#endif
845
#if defined(__riscv_zbc)
846
  if (is_zbc()) {
847
    return (Function)rv_crc32c_clmul;
848
  }
849
#endif
850
#endif
851
0
  return (Function)ExtendImpl<SlowCRC32Functor>;
852
0
}
853
854
0
bool IsFastCrc32Supported() {
855
#ifdef __SSE4_2__
856
  if (isSSE42()) return true;
857
#endif
858
#if defined(__riscv) && (__riscv_xlen == 64) && (defined(__riscv_zbc) || defined(__riscv_zvbc))
859
#if defined(__riscv_zvbc)
860
  if (is_zvbc()) return true;
861
#endif
862
#if defined(__riscv_zbc)
863
  if (is_zbc()) return true;
864
#endif
865
#endif
866
0
  return false;
867
0
}
868
869
0
uint32_t Extend(uint32_t crc, const char* buf, size_t size) {
870
0
  static Function ChosenExtend = Choose_Extend();
871
0
  return ChosenExtend(crc, buf, size);
872
0
}
873
874
}  // namespace crc32c
875
}  // namespace butil