serializer/machine/
simd.rs1#[cfg(all(target_arch = "x86_64", target_feature = "sse4.2"))]
10pub mod x86_64 {
11 #[cfg(target_arch = "x86_64")]
12 use std::arch::x86_64::*;
13
14 use crate::machine::slot::DxMachineSlot;
15
16 impl DxMachineSlot {
17 #[inline]
22 #[target_feature(enable = "sse4.2")]
23 pub unsafe fn eq_inline_simd(&self, needle: &str) -> bool {
24 if !self.is_inline() {
25 return false;
26 }
27
28 let len = self.inline_len();
29 if len != needle.len() {
30 return false;
31 }
32
33 let slot_vec = _mm_loadu_si128(self.data.as_ptr() as *const __m128i);
37
38 let mut needle_aligned = [0u8; 16];
41 needle_aligned[0] = len as u8;
42 needle_aligned[1..1 + len].copy_from_slice(needle.as_bytes());
43
44 let needle_vec = _mm_loadu_si128(needle_aligned.as_ptr() as *const __m128i);
46
47 let cmp = _mm_cmpeq_epi8(slot_vec, needle_vec);
49 let mask = _mm_movemask_epi8(cmp);
50
51 let expected_mask = (1 << (len + 1)) - 1;
53 mask & expected_mask == expected_mask
54 }
55
56 #[inline]
58 #[target_feature(enable = "sse4.2")]
59 pub unsafe fn eq_inline_bytes_simd(&self, needle: &[u8]) -> bool {
60 if !self.is_inline() {
61 return false;
62 }
63
64 let len = self.inline_len();
65 if len != needle.len() {
66 return false;
67 }
68
69 if len == 0 {
70 return true;
71 }
72
73 if len <= 4 {
75 return self.inline_data() == needle;
76 }
77
78 let slot_vec = _mm_loadu_si128(self.data.as_ptr().add(1) as *const __m128i);
83 let needle_vec = _mm_loadu_si128(needle.as_ptr() as *const __m128i);
88
89 let cmp = _mm_cmpeq_epi8(slot_vec, needle_vec);
90 let mask = _mm_movemask_epi8(cmp);
91
92 let expected_mask = (1 << len) - 1;
93 mask & expected_mask == expected_mask
94 }
95 }
96
97 #[inline]
99 #[target_feature(enable = "sse4.2")]
100 pub unsafe fn load_u32x4(ptr: *const u8) -> [u32; 4] {
101 let vec = _mm_loadu_si128(ptr as *const __m128i);
104 [
105 _mm_extract_epi32(vec, 0) as u32,
106 _mm_extract_epi32(vec, 1) as u32,
107 _mm_extract_epi32(vec, 2) as u32,
108 _mm_extract_epi32(vec, 3) as u32,
109 ]
110 }
111
112 #[inline]
114 #[target_feature(enable = "sse4.2")]
115 pub unsafe fn load_u64x2(ptr: *const u8) -> [u64; 2] {
116 let vec = _mm_loadu_si128(ptr as *const __m128i);
119 [
120 _mm_extract_epi64(vec, 0) as u64,
121 _mm_extract_epi64(vec, 1) as u64,
122 ]
123 }
124}
125
126#[cfg(all(target_arch = "x86_64", target_feature = "avx2"))]
128pub mod avx2 {
129 #[cfg(target_arch = "x86_64")]
130 use std::arch::x86_64::*;
131
132 #[inline]
134 #[target_feature(enable = "avx2")]
135 pub unsafe fn eq_bytes_32(a: &[u8], b: &[u8]) -> bool {
136 debug_assert!(a.len() >= 32 && b.len() >= 32);
137
138 let va = _mm256_loadu_si256(a.as_ptr() as *const __m256i);
141 let vb = _mm256_loadu_si256(b.as_ptr() as *const __m256i);
142
143 let cmp = _mm256_cmpeq_epi8(va, vb);
144 let mask = _mm256_movemask_epi8(cmp);
145
146 mask == -1 }
148
149 #[inline]
151 #[target_feature(enable = "avx2")]
152 pub unsafe fn load_u32x8(ptr: *const u8) -> [u32; 8] {
153 let vec = _mm256_loadu_si256(ptr as *const __m256i);
156 [
157 _mm256_extract_epi32(vec, 0) as u32,
158 _mm256_extract_epi32(vec, 1) as u32,
159 _mm256_extract_epi32(vec, 2) as u32,
160 _mm256_extract_epi32(vec, 3) as u32,
161 _mm256_extract_epi32(vec, 4) as u32,
162 _mm256_extract_epi32(vec, 5) as u32,
163 _mm256_extract_epi32(vec, 6) as u32,
164 _mm256_extract_epi32(vec, 7) as u32,
165 ]
166 }
167}
168
169#[cfg(not(target_arch = "x86_64"))]
171pub mod fallback {
172 use crate::machine::slot::DxMachineSlot;
173
174 impl DxMachineSlot {
175 #[inline]
177 pub fn eq_inline_simd(&self, needle: &str) -> bool {
178 self.eq_inline_str(needle)
179 }
180
181 #[inline]
183 pub fn eq_inline_bytes_simd(&self, needle: &[u8]) -> bool {
184 self.eq_inline_bytes(needle)
185 }
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use crate::machine::slot::DxMachineSlot;
192
193 #[test]
194 #[cfg(target_arch = "x86_64")]
195 fn test_simd_string_comparison() {
196 let slot = DxMachineSlot::inline_from_bytes(b"Hello").unwrap();
197 assert!(slot.eq_inline_str("Hello"));
199 assert!(!slot.eq_inline_str("World"));
200 assert!(!slot.eq_inline_str("Hello!"));
201 }
202
203 #[test]
204 #[cfg(target_arch = "x86_64")]
205 fn test_simd_bytes_comparison() {
206 let slot = DxMachineSlot::inline_from_bytes(b"TestData").unwrap();
207 assert!(slot.eq_inline_bytes(b"TestData"));
209 assert!(!slot.eq_inline_bytes(b"TestFail"));
210 }
211
212 #[test]
213 #[cfg(all(target_arch = "x86_64", target_feature = "sse4.2"))]
214 fn test_load_u32x4() {
215 let data = [1u32, 2, 3, 4];
216 let bytes = unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, 16) };
219
220 unsafe {
223 let loaded = x86_64::load_u32x4(bytes.as_ptr());
224 assert_eq!(loaded, [1, 2, 3, 4]);
225 }
226 }
227
228 #[test]
229 #[cfg(all(target_arch = "x86_64", target_feature = "sse4.2"))]
230 fn test_load_u64x2() {
231 let data = [100u64, 200];
232 let bytes = unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, 16) };
235
236 unsafe {
239 let loaded = x86_64::load_u64x2(bytes.as_ptr());
240 assert_eq!(loaded, [100, 200]);
241 }
242 }
243}