Skip to content

Commit

Permalink
Test for correctness in correctness tests instead of a separate test,…
Browse files Browse the repository at this point in the history
… use slice16 impl if simd is not available
  • Loading branch information
valaphee committed Mar 23, 2024
1 parent 4b9e109 commit 3df2166
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 366 deletions.
25 changes: 15 additions & 10 deletions src/crc128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ const fn update_slice16(
#[cfg(test)]
mod test {
use crate::{Bytewise, Crc, Implementation, NoTable, Slice16};
use crc_catalog::{Algorithm, CRC_82_DARC};
use crc_catalog::*;

#[test]
fn default_table_size() {
Expand Down Expand Up @@ -267,14 +267,14 @@ mod test {
#[test]
fn correctness() {
let data: &[&str] = &[
"",
"1",
"1234",
"123456789",
"0123456789ABCDE",
"01234567890ABCDEFGHIJK",
"01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK",
];
"",
"1",
"1234",
"123456789",
"0123456789ABCDE",
"01234567890ABCDEFGHIJK",
"01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK",
];

pub const CRC_82_DARC_NONREFLEX: Algorithm<u128> = Algorithm {
width: 82,
Expand All @@ -283,12 +283,17 @@ mod test {
refin: false,
refout: true,
xorout: 0x000000000000000000000,
check: 0x09ea83f625023801fd612,
check: 0x12e0b19fa447c0bf627ac,
residue: 0x000000000000000000000,
};

let algs_to_test = [&CRC_82_DARC, &CRC_82_DARC_NONREFLEX];

// Check if the baseline is as expected.
for alg in algs_to_test {
assert_eq!(Crc::<Bytewise<u128>>::new(alg).checksum("123456789".as_bytes()), alg.check);
}

for alg in algs_to_test {
for data in data {
let crc_slice16 = Crc::<Slice16<u128>>::new(alg);
Expand Down
68 changes: 56 additions & 12 deletions src/crc16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ use crc_catalog::Algorithm;
mod bytewise;
mod default;
mod nolookup;
#[cfg(all(
target_feature = "sse2",
target_feature = "sse4.1",
target_feature = "pclmulqdq"
))]
mod simd;
mod slice16;

Expand Down Expand Up @@ -143,7 +148,7 @@ const fn update_slice16(
#[cfg(test)]
mod test {
use crate::{Bytewise, Crc, Implementation, NoTable, Simd, Slice16};
use crc_catalog::{Algorithm, CRC_16_IBM_SDLC};
use crc_catalog::*;

#[test]
fn default_table_size() {
Expand Down Expand Up @@ -249,18 +254,57 @@ mod test {
"01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK",
];

pub const CRC_16_IBM_SDLC_NONREFLEX: Algorithm<u16> = Algorithm {
width: 16,
poly: 0x1021,
init: 0xffff,
refin: false,
refout: true,
xorout: 0xffff,
check: 0x906e,
residue: 0xf0b8,
};
let algs_to_test = &[
CRC_10_ATM,
CRC_10_CDMA2000,
CRC_10_GSM,
CRC_11_FLEXRAY,
CRC_11_UMTS,
CRC_12_CDMA2000,
CRC_12_DECT,
CRC_12_GSM,
CRC_12_UMTS,
CRC_13_BBC,
CRC_14_DARC,
CRC_14_GSM,
CRC_15_CAN,
CRC_15_MPT1327,
CRC_16_ARC,
CRC_16_CDMA2000,
CRC_16_CMS,
CRC_16_DDS_110,
CRC_16_DECT_R,
CRC_16_DECT_X,
CRC_16_DNP,
CRC_16_EN_13757,
CRC_16_GENIBUS,
CRC_16_GSM,
CRC_16_IBM_3740,
CRC_16_IBM_SDLC,
CRC_16_ISO_IEC_14443_3_A,
CRC_16_KERMIT,
CRC_16_LJ1200,
CRC_16_MAXIM_DOW,
CRC_16_MCRF4XX,
CRC_16_MODBUS,
CRC_16_NRSC_5,
CRC_16_OPENSAFETY_A,
CRC_16_OPENSAFETY_B,
CRC_16_PROFIBUS,
CRC_16_RIELLO,
CRC_16_SPI_FUJITSU,
CRC_16_T10_DIF,
CRC_16_TELEDISK,
CRC_16_TMS37157,
CRC_16_UMTS,
CRC_16_USB,
CRC_16_XMODEM,
];

let algs_to_test = [&CRC_16_IBM_SDLC, &CRC_16_IBM_SDLC_NONREFLEX];
// Check if the baseline is as expected.
for alg in algs_to_test {
assert_eq!(Crc::<Bytewise<u16>>::new(alg).checksum("123456789".as_bytes()), alg.check);
}

for alg in algs_to_test {
for data in data {
Expand Down
16 changes: 9 additions & 7 deletions src/crc16/simd.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::crc32::update_simd;
use crate::simd::{SimdValue, SimdValueOps};
use crate::table::{crc16_table_slice_16, crc32_simd_coefficients};
use crate::simd::{crc32_simd_coefficients, crc32_update_refin, SimdValue};
use crate::table::crc16_table_slice_16;
use crate::{Algorithm, Crc, Digest, Simd};

use super::{finalize, init, update_slice16};
Expand All @@ -12,7 +11,7 @@ impl Crc<Simd<u16>> {
table: (
crc16_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin),
unsafe {
// SAFETY: SimdValue is the same as u64x2 and this only changes the representation of 8*u64 to 4*u64x2.
// SAFETY: Both represent numbers.
core::mem::transmute(crc32_simd_coefficients(
algorithm.width,
algorithm.poly as u32,
Expand All @@ -29,15 +28,18 @@ impl Crc<Simd<u16>> {
}

fn update(&self, mut crc: u16, bytes: &[u8]) -> u16 {
if !SimdValue::is_supported() || !self.algorithm.refin {
if !self.algorithm.refin {
return update_slice16(crc, self.algorithm.refin, &self.table.0, bytes);
}

// SAFETY: Both represent numbers.
let (bytes_before, chunks, bytes_after) = unsafe { bytes.align_to::<[SimdValue; 4]>() };
crc = update_slice16(crc, self.algorithm.refin, &self.table.0, bytes_before);
if let Some(first_chunk) = chunks.first() {
// SAFETY: All required features are supported, by checking SimdValue::is_supported.
crc = unsafe { update_simd(crc as u32, &self.table.1, first_chunk, chunks) } as u16;
// SAFETY: All features are supported as the program has been compiled with all required target features set.
crc =
unsafe { crc32_update_refin(crc as u32, &self.table.1, first_chunk, &chunks[1..]) }
as u16;
}
update_slice16(crc, self.algorithm.refin, &self.table.0, bytes_after)
}
Expand Down
87 changes: 36 additions & 51 deletions src/crc32.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use crate::simd::{SimdValue, SimdValueOps};
use crate::util::crc32;
use crc_catalog::Algorithm;

mod bytewise;
mod default;
mod nolookup;
#[cfg(all(
target_feature = "sse2",
target_feature = "sse4.1",
target_feature = "pclmulqdq"
))]
mod simd;
mod slice16;

Expand Down Expand Up @@ -152,46 +156,10 @@ const fn update_slice16(
crc
}

#[target_feature(enable = "sse2", enable = "sse4.1", enable = "pclmulqdq")]
pub(crate) unsafe fn update_simd(
crc: u32,
coefficients: &[SimdValue; 4],
first_chunk: &[SimdValue; 4],
chunks: &[[SimdValue; 4]],
) -> u32 {
let mut x4 = *first_chunk;

// Apply initial crc value
x4[0] = x4[0].xor(crc as u64);

// Iteratively Fold by 4:
let k1_k2 = coefficients[0];
for chunk in chunks {
for (x, value) in x4.iter_mut().zip(chunk.iter()) {
*x = x.fold_16(k1_k2, *value)
}
}

// Iteratively Fold by 1:
let k3_k4 = coefficients[1];
let mut x = x4[0].fold_16(k3_k4, x4[1]);
x = x.fold_16(k3_k4, x4[2]);
x = x.fold_16(k3_k4, x4[3]);

// Final Reduction of 128-bits
let k5_k6 = coefficients[2];
x = x.fold_8(k3_k4);
x = x.fold_4(k5_k6);

// Barret Reduction
let px_u = coefficients[3];
x.barret_reduction_32(px_u)
}

#[cfg(test)]
mod test {
use crate::{Bytewise, Crc, Implementation, NoTable, Simd, Slice16};
use crc_catalog::{Algorithm, CRC_32_ISCSI};
use crc_catalog::*;

#[test]
fn default_table_size() {
Expand Down Expand Up @@ -292,24 +260,41 @@ mod test {
"1",
"1234",
"123456789",
"0123456789A",
"0123456789ABCDE",
"01234567890ABCDEFGHIJK",
"01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK",
];

pub const CRC_32_ISCSI_NONREFLEX: Algorithm<u32> = Algorithm {
width: 32,
poly: 0x1edc6f41,
init: 0xffffffff,
// This is the only flag that affects the optimized code path
refin: false,
refout: true,
xorout: 0xffffffff,
check: 0xe3069283,
residue: 0xb798b438,
};
let algs_to_test = &[
CRC_17_CAN_FD,
CRC_21_CAN_FD,
CRC_24_BLE,
CRC_24_FLEXRAY_A,
CRC_24_FLEXRAY_B,
CRC_24_INTERLAKEN,
CRC_24_LTE_A,
CRC_24_LTE_B,
CRC_24_OPENPGP,
CRC_24_OS_9,
CRC_30_CDMA,
CRC_31_PHILIPS,
CRC_32_AIXM,
CRC_32_AUTOSAR,
CRC_32_BASE91_D,
CRC_32_BZIP2,
CRC_32_CD_ROM_EDC,
CRC_32_CKSUM,
CRC_32_ISCSI,
CRC_32_ISO_HDLC,
CRC_32_JAMCRC,
CRC_32_MPEG_2,
CRC_32_XFER,
];

let algs_to_test = [&CRC_32_ISCSI, &CRC_32_ISCSI_NONREFLEX];
// Check if the baseline is as expected.
for alg in algs_to_test {
assert_eq!(Crc::<Bytewise<u32>>::new(alg).checksum("123456789".as_bytes()), alg.check);
}

for alg in algs_to_test {
for data in data {
Expand Down
16 changes: 8 additions & 8 deletions src/crc32/simd.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::simd::{SimdValue, SimdValueOps};
use crate::table::{crc32_simd_coefficients, crc32_table_slice_16};
use crate::simd::{crc32_simd_coefficients, crc32_update_refin, SimdValue};
use crate::table::crc32_table_slice_16;
use crate::{Algorithm, Crc, Digest, Simd};

use super::{finalize, init, update_simd, update_slice16};
use super::{finalize, init, update_slice16};

impl Crc<Simd<u32>> {
pub const fn new(algorithm: &'static Algorithm<u32>) -> Self {
Expand All @@ -11,7 +11,7 @@ impl Crc<Simd<u32>> {
table: (
crc32_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin),
unsafe {
// SAFETY: Both represent numbers
// SAFETY: Both represent numbers.
core::mem::transmute(crc32_simd_coefficients(algorithm.width, algorithm.poly))
},
),
Expand All @@ -25,16 +25,16 @@ impl Crc<Simd<u32>> {
}

fn update(&self, mut crc: u32, bytes: &[u8]) -> u32 {
if !SimdValue::is_supported() || !self.algorithm.refin {
if !self.algorithm.refin {
return update_slice16(crc, self.algorithm.refin, &self.table.0, bytes);
}

// SAFETY: Both represent numbers
// SAFETY: Both represent numbers.
let (bytes_before, chunks, bytes_after) = unsafe { bytes.align_to::<[SimdValue; 4]>() };
crc = update_slice16(crc, self.algorithm.refin, &self.table.0, bytes_before);
if let Some(first_chunk) = chunks.first() {
// SAFETY: All required features are supported, by checking SimdValue::is_supported.
crc = unsafe { update_simd(crc, &self.table.1, first_chunk, &chunks[1..]) };
// SAFETY: All features are supported as the program has been compiled with all required target features set.
crc = unsafe { crc32_update_refin(crc, &self.table.1, first_chunk, &chunks[1..]) };
}
update_slice16(crc, self.algorithm.refin, &self.table.0, bytes_after)
}
Expand Down
42 changes: 21 additions & 21 deletions src/crc64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ const fn update_slice16(

#[cfg(test)]
mod test {
use crate::{Bytewise, Crc, Implementation, NoTable, Simd, Slice16};
use crc_catalog::{Algorithm, CRC_64_ECMA_182};
use crate::{Bytewise, Crc, Implementation, NoTable, Slice16};
use crc_catalog::*;

#[test]
fn default_table_size() {
Expand Down Expand Up @@ -252,27 +252,27 @@ mod test {
#[test]
fn correctness() {
let data: &[&str] = &[
"",
"1",
"1234",
"123456789",
"0123456789ABCDE",
"01234567890ABCDEFGHIJK",
"01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK",
];
"",
"1",
"1234",
"123456789",
"0123456789ABCDE",
"01234567890ABCDEFGHIJK",
"01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK",
];

pub const CRC_64_ECMA_182_REFLEX: Algorithm<u64> = Algorithm {
width: 64,
poly: 0x42f0e1eba9ea3693,
init: 0x0000000000000000,
refin: true,
refout: false,
xorout: 0x0000000000000000,
check: 0x6c40df5f0b497347,
residue: 0x0000000000000000,
};
let algs_to_test = &[
CRC_40_GSM,
CRC_64_ECMA_182,
CRC_64_GO_ISO,
CRC_64_WE,
CRC_64_XZ,
];

let algs_to_test = [&CRC_64_ECMA_182, &CRC_64_ECMA_182_REFLEX];
// Check if the baseline is as expected.
for alg in algs_to_test {
assert_eq!(Crc::<Bytewise<u64>>::new(alg).checksum("123456789".as_bytes()), alg.check);
}

for alg in algs_to_test {
for data in data {
Expand Down
Loading

0 comments on commit 3df2166

Please sign in to comment.