1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
//! CPU feature detection and fallback tests
//!
//! Tests CPU feature detection, fallback mechanisms, and target architecture handling.
#[cfg(test)]
mod cpu_feature_tests {
extern crate alloc;
use crate::simd::dispatch::*;
use alloc::vec::Vec;
#[test]
fn test_cpu_feature_detection_consistency() {
// Debug AVX detection
// Force display of AVX detection info by panicking
let avx2_available = is_avx2_available();
let has_avx = crate::cpuid::has_avx();
let has_avx2 = crate::cpuid::has_avx2();
let is_avx_available = is_avx_available();
let is_os_avx_supported = is_os_avx_supported();
let cpuid1 = crate::cpuid::cpuid(1, 0);
let cpuid7 = crate::cpuid::cpuid(7, 0);
// Print AVX detection info to stderr
eprintln!("=== AVX Detection Info ===");
eprintln!("AVX2 available: {}", avx2_available);
eprintln!("has_avx(): {}", has_avx);
eprintln!("has_avx2(): {}", has_avx2);
eprintln!("is_avx_available(): {}", is_avx_available);
eprintln!("is_os_avx_supported(): {}", is_os_avx_supported);
eprintln!("CPUID(1).ECX: 0x{:08X} ({:032b})", cpuid1.ecx, cpuid1.ecx);
eprintln!("CPUID(7).EBX: 0x{:08X} ({:032b})", cpuid7.ebx, cpuid7.ebx);
eprintln!("AVX bit (ECX[28]): {}", (cpuid1.ecx & (1 << 28)) != 0);
eprintln!("AVX2 bit (EBX[5]): {}", (cpuid7.ebx & (1 << 5)) != 0);
// Test that CPU feature detection gives consistent results
let avx2_1 = is_avx2_available();
let avx2_2 = is_avx2_available();
let avx2_3 = is_avx2_available();
assert_eq!(avx2_1, avx2_2);
assert_eq!(avx2_2, avx2_3);
let avx512_1 = is_avx512_available();
let avx512_2 = is_avx512_available();
let avx512_3 = is_avx512_available();
assert_eq!(avx512_1, avx512_2);
assert_eq!(avx512_2, avx512_3);
// CPU feature detection results:
// AVX2 available: {}
// AVX-512 available: {}
// (Print statements removed for no_std compatibility)
// Debug output
println!("=== AVX Detection Results ===");
println!("AVX2 available: {}", avx2_1);
println!("AVX-512 available: {}", avx512_1);
let cpuid1 = crate::cpuid::cpuid(1, 0);
let cpuid7 = crate::cpuid::cpuid(7, 0);
println!("CPUID(1).ECX: 0x{:08X}", cpuid1.ecx);
println!("CPUID(7).EBX: 0x{:08X}", cpuid7.ebx);
println!("AVX bit set: {}", (cpuid1.ecx & (1 << 28)) != 0);
println!("AVX2 bit set: {}", (cpuid7.ebx & (1 << 5)) != 0);
}
#[test]
fn test_cpu_feature_detection_no_panics() {
// Test that CPU feature detection functions don't panic
// even if called many times rapidly
for _ in 0..100 {
let _avx2 = is_avx2_available();
let _avx512 = is_avx512_available();
}
}
#[test]
fn test_fallback_mechanism() {
// Test that the main SIMD function always works regardless of CPU features
let mut data = [0x123456789ABCDEF0u64; 16];
let original = data;
// Should not panic and should modify data
clock_mix_avx2(&mut data);
assert_ne!(data, original);
// Should match scalar result
let mut scalar_data = original;
crate::simd::scalar::scalar_clock_mix(&mut scalar_data);
assert_eq!(data, scalar_data);
}
#[test]
fn test_simd_dispatch_logic() {
// Test that SIMD dispatch chooses appropriate implementation
// Create test data
let mut data1 = [0xFEDCBA9876543210u64; 16];
let mut data2 = [0xFEDCBA9876543210u64; 16];
let mut data3 = [0xFEDCBA9876543210u64; 16];
// All should produce the same result
crate::simd::scalar::scalar_clock_mix(&mut data1);
clock_mix_avx2(&mut data2);
// Force scalar path by calling directly
#[cfg(not(feature = "simd"))]
{
crate::simd::scalar::scalar_clock_mix(&mut data3);
}
#[cfg(feature = "simd")]
{
// With SIMD feature enabled, it should dispatch appropriately
clock_mix_avx2(&mut data3);
}
assert_eq!(data1, data2);
assert_eq!(data2, data3);
}
#[test]
fn test_feature_availability_logic() {
// Test logical consistency of feature availability
let avx2_available = is_avx2_available();
let avx512_available = is_avx512_available();
// AVX-512 requires AVX2, so if AVX-512 is available, AVX2 should be too
if avx512_available {
assert!(
avx2_available,
"AVX-512 availability implies AVX2 availability"
);
}
// Test doesn't imply anything about AVX2 if AVX-512 is not available
}
#[test]
fn test_cpu_feature_independence() {
// Test that operations work correctly regardless of CPU features
let test_data = Vec::from([
[0u64; 16],
[u64::MAX; 16],
[1u64; 16],
[0xAAAAAAAAAAAAAAAAu64; 16],
[0x5555555555555555u64; 16],
]);
for (i, data) in test_data.into_iter().enumerate() {
let mut simd_result = data;
let mut scalar_result = data;
clock_mix_avx2(&mut simd_result);
crate::simd::scalar::scalar_clock_mix(&mut scalar_result);
assert_eq!(
simd_result, scalar_result,
"CPU feature independence test failed for pattern {}",
i
);
}
}
#[test]
fn test_target_architecture_handling() {
// Test that the code compiles and works on different target architectures
let mut data = [0xDEADBEEFu64; 16];
// Should work on all supported architectures
clock_mix_avx2(&mut data);
// Verify the result is not all zeros (unless input was such that it produces zeros)
let is_all_zeros = data.iter().all(|&x| x == 0);
let input_all_zeros = [0xDEADBEEFu64; 16].iter().all(|&x| x == 0);
if !input_all_zeros {
assert!(
!is_all_zeros,
"Output should not be all zeros for non-zero input"
);
}
// Should match scalar
let mut scalar_data = [0xDEADBEEFu64; 16];
crate::simd::scalar::scalar_clock_mix(&mut scalar_data);
assert_eq!(data, scalar_data);
}
#[cfg(feature = "std")]
#[test]
fn test_compile_time_feature_gates() {
// Test that compile-time feature gates work correctly
let mut data = [0xCAFEBABEu64; 16];
// clock_mix_avx2 should always be available
clock_mix_avx2(&mut data);
// Test that the function signature is correct
assert_eq!(data.len(), 16);
// Test with different feature combinations
#[cfg(feature = "simd")]
{
// With SIMD feature, should use SIMD path
// (Print statement removed for no_std compatibility)
}
#[cfg(not(feature = "simd"))]
{
// Without SIMD feature, should use scalar path
// (Print statement removed for no_std compatibility)
}
}
#[cfg(feature = "std")]
#[test]
fn test_avx2_target_feature_safety() {
// Test that AVX2 target features are used safely
if !is_avx2_available() {
// AVX2 not available, skipping AVX2 safety test
// (Print statement removed for no_std compatibility)
return;
}
let mut data = [0x123456789ABCDEF0u64; 16];
let original = data;
// This should not panic on systems with AVX2
clock_mix_avx2(&mut data);
assert_ne!(data, original);
// Should match scalar
let mut scalar_data = original;
crate::simd::scalar::scalar_clock_mix(&mut scalar_data);
assert_eq!(data, scalar_data);
}
#[cfg(feature = "std")]
#[test]
fn test_avx512_target_feature_safety() {
// Test that AVX-512 target features are used safely
if !is_avx512_available() {
// AVX-512 not available, skipping AVX-512 safety test
// (Print statement removed for no_std compatibility)
return;
}
let mut data = [0xFEDCBA9876543210u64; 16];
let original = data;
// This should not panic on systems with AVX-512
clock_mix_avx2(&mut data);
assert_ne!(data, original);
// Should match scalar
let mut scalar_data = original;
crate::simd::scalar::scalar_clock_mix(&mut scalar_data);
assert_eq!(data, scalar_data);
}
#[test]
fn test_cpu_feature_detection_portability() {
// Test that feature detection is portable across different systems
// This mainly tests that the functions don't crash
// Call feature detection multiple times
for _ in 0..10 {
let avx2 = is_avx2_available();
let avx512 = is_avx512_available();
// Results should be boolean
assert!(avx2 == true || avx2 == false);
assert!(avx512 == true || avx512 == false);
}
// Test that results are stable within a single run
let avx2_first = is_avx2_available();
let avx512_first = is_avx512_available();
#[cfg(feature = "std")]
std::thread::sleep(std::time::Duration::from_millis(1));
let avx2_second = is_avx2_available();
let avx512_second = is_avx512_available();
assert_eq!(avx2_first, avx2_second);
assert_eq!(avx512_first, avx512_second);
}
#[cfg(feature = "std")]
#[test]
fn test_fallback_performance_characteristics() {
// Test that fallback to scalar is reasonably performant
use std::time::{Duration, Instant};
let iterations = 1000;
let mut data = [0xAAAAAAAAAAAAAAAAu64; 16];
let start = Instant::now();
for _ in 0..iterations {
let mut test_data = data;
clock_mix_avx2(&mut test_data);
}
let elapsed = start.elapsed();
// Fallback performance test:
// {} iterations took {:?}
// Average time per operation: {:?}
// (Print statements removed for no_std compatibility)
// Should complete in reasonable time
assert!(
elapsed < Duration::from_secs(5),
"Fallback should complete {} iterations in less than 5 seconds",
iterations
);
}
#[test]
fn test_architecture_specific_behavior() {
// Test behavior specific to different architectures
let mut data = [0x5555555555555555u64; 16];
// Should work on all supported architectures
clock_mix_avx2(&mut data);
// Verify the result is not all zeros (unless input was such that it produces zeros)
let is_all_zeros = data.iter().all(|&x| x == 0);
let input_all_zeros = [0x5555555555555555u64; 16].iter().all(|&x| x == 0);
if !input_all_zeros {
assert!(
!is_all_zeros,
"Output should not be all zeros for non-zero input"
);
}
}
#[test]
fn test_cpuid_instruction_safety() {
// Test that CPUID instruction usage is safe
// This is mainly a smoke test to ensure no crashes
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
{
// On x86/x86_64, CPUID should be available and safe to call
let avx2 = is_avx2_available();
let avx512 = is_avx512_available();
// Should not have panicked
assert!(avx2 == true || avx2 == false);
assert!(avx512 == true || avx512 == false);
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
{
// On other architectures, should return false
assert!(!is_avx2_available());
assert!(!is_avx512_available());
}
}
}