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
use core::ptr::copy_nonoverlapping;
use core::mem;
#[allow(non_camel_case_types)]
#[repr(simd)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) struct u64x2(pub u64, pub u64);
const BSWAP_EPI_64: u64x2 = u64x2(0x0001020304050607, 0x08090a0b0c0d0e0f);
impl u64x2 {
/// Reads u64x2 from array pointer (potentially unaligned)
#[inline(always)]
pub fn read(src: &[u8; 16]) -> Self {
unsafe {
let mut tmp: Self = mem::uninitialized();
copy_nonoverlapping(
src.as_ptr(),
&mut tmp as *mut Self as *mut u8,
16,
);
tmp
}
}
/// Write u64x2 content into array pointer (potentially unaligned)
#[inline(always)]
pub fn write(self, dst: &mut [u8; 16]) {
unsafe {
copy_nonoverlapping(
&self as *const Self as *const u8,
dst.as_mut_ptr(),
16,
);
}
}
/// Read [u64x2; 8] from array pointer (potentially unaligned)
#[inline(always)]
pub fn read8(src: &[u8; 16*8]) -> [Self; 8] {
unsafe {
let mut tmp: [Self; 8] = mem::uninitialized();
copy_nonoverlapping(
src.as_ptr(),
&mut tmp as *mut [Self; 8] as *mut u8,
16*8,
);
tmp
}
}
/// Write [u64x2; 8] content into array pointer (potentially unaligned)
#[inline(always)]
pub fn write8(src: [u64x2; 8], dst: &mut [u8; 16*8]) {
unsafe {
copy_nonoverlapping(
&src as *const [Self; 8] as *const u8,
dst.as_mut_ptr(),
16*8,
);
}
}
#[inline(always)]
/// increments last u64 without carry using paddq instruction, so
/// it can be done without moving from XMM register
pub fn inc_be(&mut self) {
unsafe{
asm!("paddq $0, $1"
:"+x"(*self)
:"x"(u64x2(0, 1))
:
:"intel", "alignstack"
);
}
}
#[inline(always)]
/// Convert to big-endiann representation
pub fn swap_bytes(&self) -> u64x2 {
let mut val = *self;
unsafe{
asm!("pshufb $0, $1"
:"+x"(val)
:"x"(BSWAP_EPI_64)
:
:"intel", "alignstack"
);
}
val
}
}