-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for AArch64 CRC32 instructions
- Loading branch information
1 parent
1bc367a
commit 188eab0
Showing
5 changed files
with
148 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
//use std::arch::aarch64 as arch; | ||
use stdsimd::arch::aarch64 as arch; | ||
|
||
#[derive(Clone)] | ||
pub struct State { | ||
state: u32, | ||
} | ||
|
||
impl State { | ||
pub fn new() -> Option<Self> { | ||
if is_aarch64_feature_detected!("crc") { | ||
// SAFETY: The conditions above ensure that all | ||
// required instructions are supported by the CPU. | ||
Some(Self { state: 0 }) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
pub fn update(&mut self, buf: &[u8]) { | ||
// SAFETY: The `State::new` constructor ensures that all | ||
// required instructions are supported by the CPU. | ||
self.state = unsafe { calculate(self.state, buf) } | ||
} | ||
|
||
pub fn finalize(self) -> u32 { | ||
self.state | ||
} | ||
|
||
pub fn reset(&mut self) { | ||
self.state = 0; | ||
} | ||
|
||
pub fn combine(&mut self, other: u32, amount: u64) { | ||
self.state = ::combine::combine(self.state, other, amount); | ||
} | ||
} | ||
|
||
#[target_feature(enable = "crc")] | ||
pub unsafe fn calculate(crc: u32, data: &[u8]) -> u32 { | ||
let mut len = data.len(); | ||
let mut c32 = !crc; | ||
let mut ptr = data.as_ptr(); | ||
let mut ptr2; | ||
let mut ptr4; | ||
let mut ptr8; | ||
|
||
if len != 0 && ((ptr as usize) & 1) != 0 { | ||
c32 = arch::crc32b(c32, *ptr as _); | ||
ptr = ptr.offset(1); | ||
len -= 1; | ||
} | ||
|
||
if len > 2 && ((ptr as usize) & 2) != 0 { | ||
ptr2 = ptr as *const u16; | ||
c32 = arch::crc32h(c32, *ptr2 as _); | ||
ptr2 = ptr2.offset(1); | ||
len -= 2; | ||
ptr4 = ptr2 as *const u32; | ||
} else { | ||
ptr4 = ptr as *const u32; | ||
} | ||
|
||
if len > 4 && ((ptr as usize) & 2) != 0 { | ||
c32 = arch::crc32w(c32, *ptr4); | ||
ptr4 = ptr4.offset(1); | ||
len -= 4; | ||
} | ||
|
||
ptr8 = ptr4 as *const u64; | ||
|
||
while len >= 32 { | ||
c32 = arch::crc32x(c32, *ptr8); | ||
ptr8 = ptr8.offset(1); | ||
c32 = arch::crc32x(c32, *ptr8); | ||
ptr8 = ptr8.offset(1); | ||
c32 = arch::crc32x(c32, *ptr8); | ||
ptr8 = ptr8.offset(1); | ||
c32 = arch::crc32x(c32, *ptr8); | ||
ptr8 = ptr8.offset(1); | ||
len -= 32; | ||
} | ||
|
||
while len >= 8 { | ||
c32 = arch::crc32x(c32, *ptr8); | ||
ptr8 = ptr8.offset(1); | ||
len -= 8; | ||
} | ||
|
||
if len >= 4 { | ||
ptr4 = ptr8 as *const u32; | ||
c32 = arch::crc32w(c32, *ptr4); | ||
ptr2 = ptr4.offset(1) as *const u16; | ||
len -= 4; | ||
} else { | ||
ptr2 = ptr8 as *const u16; | ||
} | ||
|
||
if len >= 2 { | ||
c32 = arch::crc32h(c32, *ptr2 as _); | ||
ptr2 = ptr2.offset(1); | ||
len -= 2; | ||
} | ||
|
||
if len != 0 { | ||
ptr = ptr2 as *const u8; | ||
c32 = arch::crc32b(c32, *ptr as _); | ||
} | ||
|
||
!c32 | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
quickcheck! { | ||
fn check_against_baseline(chunks: Vec<(Vec<u8>, usize)>) -> bool { | ||
let mut baseline = super::super::super::baseline::State::new(); | ||
let mut aarch64 = super::State::new().expect("not supported"); | ||
for (chunk, mut offset) in chunks { | ||
// simulate random alignments by offsetting the slice by up to 15 bytes | ||
offset = offset & 0xF; | ||
if chunk.len() <= offset { | ||
baseline.update(&chunk); | ||
aarch64.update(&chunk); | ||
} else { | ||
baseline.update(&chunk[offset..]); | ||
aarch64.update(&chunk[offset..]); | ||
} | ||
} | ||
aarch64.finalize() == baseline.finalize() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters