OXYGENHUB
◆ push-notes oxygen / vendor / crc-fast / src / crc32 / fusion / x86 / iscsi / avx512_vpclmulqdq.rs
6.8 KiB · Rust · last changed Strata: the cloud stores send through ureq, so every release target links 1 month ago source blame history raw
1
//! Converted to Rust from the original C code generated by https://github.com/corsix/fast-crc32/
2
//! with the help of Claude.ai.
3
//!
4
//! MIT licensed.
5
6
#![cfg(target_arch = "x86_64")]
7
8
/// Converted to Rust from the original C code generated by https://github.com/corsix/fast-crc32/
9
/// with the help of Claude.ai using:
10
///
11
/// ./generate -i avx512_vpclmulqdq -p crc32c -a v3x2
12
///
13
/// Modified as necessary for this Rust implementation.
14
///
15
/// Uses AVX-512 VPCLMULQDQ instructions
16
#[inline]
17
#[target_feature(enable = "avx512vl,vpclmulqdq")]
18
pub unsafe fn crc32_iscsi_avx512_vpclmulqdq_v3x2(
19
    mut crc0: u32,
20
    mut buf: *const u8,
21
    mut len: usize,
22
) -> u32 {
23
    use crate::fusion::x86::*;
24
25
    // Align to 8-byte boundary
26
    while len > 0 && (buf as usize & 7) != 0 {
27
        crc0 = _mm_crc32_u8(crc0, *buf);
28
        buf = buf.add(1);
29
        len -= 1;
30
    }
31
32
    // Align to 64-byte boundary (cache line)
33
    while (buf as usize & 56) != 0 && len >= 8 {
34
        crc0 = _mm_crc32_u64(crc0.into(), *(buf as *const u64)) as u32;
35
        buf = buf.add(8);
36
        len -= 8;
37
    }
38
39
    if len >= 384 {
40
        // First vector chunk - load three 512-bit vectors (192 bytes total)
41
        let mut x0 = _mm512_loadu_si512(buf as *const __m512i);
42
        let mut x1 = _mm512_loadu_si512(buf.add(64) as *const __m512i);
43
        let mut x2 = _mm512_loadu_si512(buf.add(128) as *const __m512i);
44
45
        // Create the multiplication constant vector
46
        // Pattern: [0xa87ab8a8, 0, 0xab7aff2a, 0] repeated across all 128-bit lanes
47
        let k_128 = _mm_setr_epi32(0xa87ab8a8u32 as i32, 0, 0xab7aff2au32 as i32, 0);
48
        let mut k = _mm512_broadcast_i32x4(k_128);
49
50
        // XOR the CRC into the first vector's low 32 bits
51
        let crc_vec = _mm512_castsi128_si512(_mm_cvtsi32_si128(crc0 as i32));
52
        x0 = _mm512_xor_si512(crc_vec, x0);
53
54
        // First round of polynomial multiplication
55
        let mut y0 = clmul_lo_avx512_vpclmulqdq(x0, k);
56
        x0 = clmul_hi_avx512_vpclmulqdq(x0, k);
57
        let mut y1 = clmul_lo_avx512_vpclmulqdq(x1, k);
58
        x1 = clmul_hi_avx512_vpclmulqdq(x1, k);
59
        let mut y2 = clmul_lo_avx512_vpclmulqdq(x2, k);
60
        x2 = clmul_hi_avx512_vpclmulqdq(x2, k);
61
62
        // XOR with next chunk of data using ternary logic (A XOR B XOR C)
63
        // 0x96 = A XOR B XOR C in ternary logic notation
64
        x0 = _mm512_ternarylogic_epi64(
65
            x0,
66
            y0,
67
            _mm512_loadu_si512(buf.add(192) as *const __m512i),
68
            0x96,
69
        );
70
        x1 = _mm512_ternarylogic_epi64(
71
            x1,
72
            y1,
73
            _mm512_loadu_si512(buf.add(256) as *const __m512i),
74
            0x96,
75
        );
76
        x2 = _mm512_ternarylogic_epi64(
77
            x2,
78
            y2,
79
            _mm512_loadu_si512(buf.add(320) as *const __m512i),
80
            0x96,
81
        );
82
83
        buf = buf.add(384);
84
        len -= 384;
85
86
        // Main loop - process 384 bytes at a time
87
        while len >= 384 {
88
            // First folding step
89
            y0 = clmul_lo_avx512_vpclmulqdq(x0, k);
90
            x0 = clmul_hi_avx512_vpclmulqdq(x0, k);
91
            y1 = clmul_lo_avx512_vpclmulqdq(x1, k);
92
            x1 = clmul_hi_avx512_vpclmulqdq(x1, k);
93
            y2 = clmul_lo_avx512_vpclmulqdq(x2, k);
94
            x2 = clmul_hi_avx512_vpclmulqdq(x2, k);
95
96
            x0 = _mm512_ternarylogic_epi64(x0, y0, _mm512_loadu_si512(buf as *const __m512i), 0x96);
97
            x1 = _mm512_ternarylogic_epi64(
98
                x1,
99
                y1,
100
                _mm512_loadu_si512(buf.add(64) as *const __m512i),
101
                0x96,
102
            );
103
            x2 = _mm512_ternarylogic_epi64(
104
                x2,
105
                y2,
106
                _mm512_loadu_si512(buf.add(128) as *const __m512i),
107
                0x96,
108
            );
109
110
            // Second folding step
111
            y0 = clmul_lo_avx512_vpclmulqdq(x0, k);
112
            x0 = clmul_hi_avx512_vpclmulqdq(x0, k);
113
            y1 = clmul_lo_avx512_vpclmulqdq(x1, k);
114
            x1 = clmul_hi_avx512_vpclmulqdq(x1, k);
115
            y2 = clmul_lo_avx512_vpclmulqdq(x2, k);
116
            x2 = clmul_hi_avx512_vpclmulqdq(x2, k);
117
118
            x0 = _mm512_ternarylogic_epi64(
119
                x0,
120
                y0,
121
                _mm512_loadu_si512(buf.add(192) as *const __m512i),
122
                0x96,
123
            );
124
            x1 = _mm512_ternarylogic_epi64(
125
                x1,
126
                y1,
127
                _mm512_loadu_si512(buf.add(256) as *const __m512i),
128
                0x96,
129
            );
130
            x2 = _mm512_ternarylogic_epi64(
131
                x2,
132
                y2,
133
                _mm512_loadu_si512(buf.add(320) as *const __m512i),
134
                0x96,
135
            );
136
137
            buf = buf.add(384);
138
            len -= 384;
139
        }
140
141
        // Reduce x0, x1, x2 to just x0
142
        let k_128 = _mm_setr_epi32(0x740eef02u32 as i32, 0, 0x9e4addf8u32 as i32, 0);
143
        k = _mm512_broadcast_i32x4(k_128);
144
145
        y0 = clmul_lo_avx512_vpclmulqdq(x0, k);
146
        x0 = clmul_hi_avx512_vpclmulqdq(x0, k);
147
        x0 = _mm512_ternarylogic_epi64(x0, y0, x1, 0x96);
148
        x1 = x2;
149
150
        y0 = clmul_lo_avx512_vpclmulqdq(x0, k);
151
        x0 = clmul_hi_avx512_vpclmulqdq(x0, k);
152
        x0 = _mm512_ternarylogic_epi64(x0, y0, x1, 0x96);
153
154
        // Reduce 512 bits to 128 bits
155
        // Multiple reduction constants for different parts of the 512-bit vector
156
        k = _mm512_setr_epi32(
157
            0x1c291d04u32 as i32,
158
            0,
159
            0xddc0152bu32 as i32,
160
            0, // Lane 0
161
            0x3da6d0cbu32 as i32,
162
            0,
163
            0xba4fc28eu32 as i32,
164
            0, // Lane 1
165
            0xf20c0dfeu32 as i32,
166
            0,
167
            0x493c7d27u32 as i32,
168
            0, // Lane 2
169
            0,
170
            0,
171
            0,
172
            0, // Lane 3 (unused)
173
        );
174
175
        y0 = clmul_lo_avx512_vpclmulqdq(x0, k);
176
        k = clmul_hi_avx512_vpclmulqdq(x0, k);
177
        y0 = _mm512_xor_si512(y0, k);
178
179
        // Extract 128-bit lanes and combine them
180
        let lane0 = _mm512_castsi512_si128(y0);
181
        let lane1 = _mm512_extracti32x4_epi32(y0, 1);
182
        let lane2 = _mm512_extracti32x4_epi32(y0, 2);
183
        let lane3 = _mm512_extracti32x4_epi32(x0, 3);
184
185
        // Combine all lanes using ternary logic
186
        let mut z0 = _mm_ternarylogic_epi64(lane0, lane1, lane2, 0x96);
187
        z0 = _mm_xor_si128(z0, lane3);
188
189
        // Reduce 128 bits to 32 bits using CRC32 instructions
190
        crc0 = _mm_crc32_u64(0, _mm_extract_epi64(z0, 0) as u64) as u32;
191
        crc0 = _mm_crc32_u64(crc0.into(), _mm_extract_epi64(z0, 1) as u64) as u32;
192
    }
193
194
    // Process remaining 8-byte chunks
195
    while len >= 8 {
196
        crc0 = _mm_crc32_u64(crc0.into(), *(buf as *const u64)) as u32;
197
        buf = buf.add(8);
198
        len -= 8;
199
    }
200
201
    // Process remaining bytes
202
    while len > 0 {
203
        crc0 = _mm_crc32_u8(crc0, *buf);
204
        buf = buf.add(1);
205
        len -= 1;
206
    }
207
208
    crc0
209
}