OXYGENHUB
◆ v0.9.0 oxygen / vendor / crc-fast / src / crc32 / fusion / aarch64 / iscsi / crc_pmull.rs
6.7 KiB · Rust · last changed Strata: the cloud stores send through ureq, so every release target links 1 month ago source blame history raw
1
//! Provides CRC-32/ISCSI calculations using a fusion of native CLMUL
2
//! instructions and native CRC calculation instructions on aarch64.
3
//!
4
//! https://dougallj.wordpress.com/2022/05/22/faster-crc32-on-the-apple-m1/
5
//!
6
//! Converted to Rust from the original C code generated by https://github.com/corsix/fast-crc32/
7
//! with the help of Claude.ai.
8
//!
9
//! Modified as necessary for this Rust implementation.
10
//!
11
//! MIT licensed.
12
13
#![cfg(target_arch = "aarch64")]
14
15
use crate::crc32::fusion::aarch64::{clmul_hi_and_xor, clmul_lo_and_xor};
16
use core::arch::aarch64::{
17
    __crc32cb, __crc32cd, veorq_u64, vgetq_lane_u64, vld1q_u64, vmovq_n_u64, vsetq_lane_u64,
18
};
19
20
/// Converted to Rust from the original C code generated by https://github.com/corsix/fast-crc32/
21
/// with the help of Claude.ai using:
22
///
23
/// ./generate -i neon -p crc32c -a v12e_v1
24
///
25
/// Modified as necessary for this Rust implementation.
26
#[inline]
27
#[target_feature(enable = "crc,aes")]
28
pub(crate) unsafe fn crc32_iscsi_v12e_v1(mut crc0: u32, mut buf: *const u8, mut len: usize) -> u32 {
29
    // Align to 8-byte boundary
30
    while len > 0 && (buf as usize & 7) != 0 {
31
        crc0 = __crc32cb(crc0, *buf);
32
        buf = buf.add(1);
33
        len -= 1;
34
    }
35
36
    // Handle 8-byte alignment
37
    if (buf as usize & 8) != 0 && len >= 8 {
38
        crc0 = __crc32cd(crc0, *(buf as *const u64));
39
        buf = buf.add(8);
40
        len -= 8;
41
    }
42
43
    if len >= 192 {
44
        let end = buf.add(len);
45
        let limit = buf.add(len - 192);
46
47
        // First vector chunk
48
        let mut x0 = vld1q_u64(buf as *const u64);
49
        let mut x1 = vld1q_u64(buf.add(16) as *const u64);
50
        let mut x2 = vld1q_u64(buf.add(32) as *const u64);
51
        let mut x3 = vld1q_u64(buf.add(48) as *const u64);
52
        let mut x4 = vld1q_u64(buf.add(64) as *const u64);
53
        let mut x5 = vld1q_u64(buf.add(80) as *const u64);
54
        let mut x6 = vld1q_u64(buf.add(96) as *const u64);
55
        let mut x7 = vld1q_u64(buf.add(112) as *const u64);
56
        let mut x8 = vld1q_u64(buf.add(128) as *const u64);
57
        let mut x9 = vld1q_u64(buf.add(144) as *const u64);
58
        let mut x10 = vld1q_u64(buf.add(160) as *const u64);
59
        let mut x11 = vld1q_u64(buf.add(176) as *const u64);
60
61
        let k_vals: [u64; 2] = [0xa87ab8a8, 0xab7aff2a];
62
        let mut k = vld1q_u64(k_vals.as_ptr());
63
64
        // Create CRC vector and XOR with first vector
65
        let crc_vec = vsetq_lane_u64(crc0 as u64, vmovq_n_u64(0), 0);
66
        x0 = veorq_u64(crc_vec, x0);
67
        buf = buf.add(192);
68
69
        // Main loop
70
        while buf <= limit {
71
            let y0 = clmul_lo_and_xor(x0, k, vld1q_u64(buf as *const u64));
72
            x0 = clmul_hi_and_xor(x0, k, y0);
73
            let y1 = clmul_lo_and_xor(x1, k, vld1q_u64(buf.add(16) as *const u64));
74
            x1 = clmul_hi_and_xor(x1, k, y1);
75
            let y2 = clmul_lo_and_xor(x2, k, vld1q_u64(buf.add(32) as *const u64));
76
            x2 = clmul_hi_and_xor(x2, k, y2);
77
            let y3 = clmul_lo_and_xor(x3, k, vld1q_u64(buf.add(48) as *const u64));
78
            x3 = clmul_hi_and_xor(x3, k, y3);
79
            let y4 = clmul_lo_and_xor(x4, k, vld1q_u64(buf.add(64) as *const u64));
80
            x4 = clmul_hi_and_xor(x4, k, y4);
81
            let y5 = clmul_lo_and_xor(x5, k, vld1q_u64(buf.add(80) as *const u64));
82
            x5 = clmul_hi_and_xor(x5, k, y5);
83
            let y6 = clmul_lo_and_xor(x6, k, vld1q_u64(buf.add(96) as *const u64));
84
            x6 = clmul_hi_and_xor(x6, k, y6);
85
            let y7 = clmul_lo_and_xor(x7, k, vld1q_u64(buf.add(112) as *const u64));
86
            x7 = clmul_hi_and_xor(x7, k, y7);
87
            let y8 = clmul_lo_and_xor(x8, k, vld1q_u64(buf.add(128) as *const u64));
88
            x8 = clmul_hi_and_xor(x8, k, y8);
89
            let y9 = clmul_lo_and_xor(x9, k, vld1q_u64(buf.add(144) as *const u64));
90
            x9 = clmul_hi_and_xor(x9, k, y9);
91
            let y10 = clmul_lo_and_xor(x10, k, vld1q_u64(buf.add(160) as *const u64));
92
            x10 = clmul_hi_and_xor(x10, k, y10);
93
            let y11 = clmul_lo_and_xor(x11, k, vld1q_u64(buf.add(176) as *const u64));
94
            x11 = clmul_hi_and_xor(x11, k, y11);
95
            buf = buf.add(192);
96
        }
97
98
        // Reduce x0 ... x11 to just x0
99
        let k_vals: [u64; 2] = [0xf20c0dfe, 0x493c7d27];
100
        k = vld1q_u64(k_vals.as_ptr());
101
102
        let y0 = clmul_lo_and_xor(x0, k, x1);
103
        x0 = clmul_hi_and_xor(x0, k, y0);
104
        let y2 = clmul_lo_and_xor(x2, k, x3);
105
        x2 = clmul_hi_and_xor(x2, k, y2);
106
        let y4 = clmul_lo_and_xor(x4, k, x5);
107
        x4 = clmul_hi_and_xor(x4, k, y4);
108
        let y6 = clmul_lo_and_xor(x6, k, x7);
109
        x6 = clmul_hi_and_xor(x6, k, y6);
110
        let y8 = clmul_lo_and_xor(x8, k, x9);
111
        x8 = clmul_hi_and_xor(x8, k, y8);
112
        let y10 = clmul_lo_and_xor(x10, k, x11);
113
        x10 = clmul_hi_and_xor(x10, k, y10);
114
115
        let k_vals: [u64; 2] = [0x3da6d0cb, 0xba4fc28e];
116
        k = vld1q_u64(k_vals.as_ptr());
117
118
        let y0 = clmul_lo_and_xor(x0, k, x2);
119
        x0 = clmul_hi_and_xor(x0, k, y0);
120
        let y4 = clmul_lo_and_xor(x4, k, x6);
121
        x4 = clmul_hi_and_xor(x4, k, y4);
122
        let y8 = clmul_lo_and_xor(x8, k, x10);
123
        x8 = clmul_hi_and_xor(x8, k, y8);
124
125
        let k_vals: [u64; 2] = [0x740eef02, 0x9e4addf8];
126
        k = vld1q_u64(k_vals.as_ptr());
127
128
        let y0 = clmul_lo_and_xor(x0, k, x4);
129
        x0 = clmul_hi_and_xor(x0, k, y0);
130
        x4 = x8;
131
        let y0 = clmul_lo_and_xor(x0, k, x4);
132
        x0 = clmul_hi_and_xor(x0, k, y0);
133
134
        // Reduce 128 bits to 32 bits, and multiply by x^32
135
        crc0 = __crc32cd(0, vgetq_lane_u64(x0, 0));
136
        crc0 = __crc32cd(crc0, vgetq_lane_u64(x0, 1));
137
        len = end.offset_from(buf) as usize;
138
    }
139
140
    if len >= 16 {
141
        // First vector chunk
142
        let mut x0 = vld1q_u64(buf as *const u64);
143
144
        let k_vals: [u64; 2] = [0xf20c0dfe, 0x493c7d27];
145
        let k = vld1q_u64(k_vals.as_ptr());
146
147
        // Create CRC vector and XOR with first vector
148
        let crc_vec = vsetq_lane_u64(crc0 as u64, vmovq_n_u64(0), 0);
149
        x0 = veorq_u64(crc_vec, x0);
150
        buf = buf.add(16);
151
        len -= 16;
152
153
        // Main loop
154
        while len >= 16 {
155
            let y0 = clmul_lo_and_xor(x0, k, vld1q_u64(buf as *const u64));
156
            x0 = clmul_hi_and_xor(x0, k, y0);
157
            buf = buf.add(16);
158
            len -= 16;
159
        }
160
161
        // Reduce 128 bits to 32 bits, and multiply by x^32
162
        crc0 = __crc32cd(0, vgetq_lane_u64(x0, 0));
163
        crc0 = __crc32cd(crc0, vgetq_lane_u64(x0, 1));
164
    }
165
166
    while len >= 8 {
167
        crc0 = __crc32cd(crc0, *(buf as *const u64));
168
        buf = buf.add(8);
169
        len -= 8;
170
    }
171
172
    while len > 0 {
173
        crc0 = __crc32cb(crc0, *buf);
174
        buf = buf.add(1);
175
        len -= 1;
176
    }
177
178
    crc0
179
}