From 3df2166844515a4151403f5be394fa0ba41a7cab Mon Sep 17 00:00:00 2001 From: valaphee <32491319+valaphee@users.noreply.github.com> Date: Sat, 23 Mar 2024 01:49:12 +0100 Subject: [PATCH] Test for correctness in correctness tests instead of a separate test, use slice16 impl if simd is not available --- src/crc128.rs | 25 ++++--- src/crc16.rs | 68 ++++++++++++++--- src/crc16/simd.rs | 16 ++-- src/crc32.rs | 87 +++++++++------------- src/crc32/simd.rs | 16 ++-- src/crc64.rs | 42 +++++------ src/crc8.rs | 58 ++++++++++++--- src/crc8/simd.rs | 16 ++-- src/lib.rs | 26 +++++++ src/simd.rs | 88 +++++++++++++++++++++- src/simd/x86.rs | 6 -- src/table.rs | 48 ------------ tests/crc.rs | 181 ---------------------------------------------- 13 files changed, 311 insertions(+), 366 deletions(-) delete mode 100644 tests/crc.rs diff --git a/src/crc128.rs b/src/crc128.rs index a380a0e..1312214 100644 --- a/src/crc128.rs +++ b/src/crc128.rs @@ -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() { @@ -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 = Algorithm { width: 82, @@ -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::>::new(alg).checksum("123456789".as_bytes()), alg.check); + } + for alg in algs_to_test { for data in data { let crc_slice16 = Crc::>::new(alg); diff --git a/src/crc16.rs b/src/crc16.rs index 427906c..cea8ad1 100644 --- a/src/crc16.rs +++ b/src/crc16.rs @@ -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; @@ -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() { @@ -249,18 +254,57 @@ mod test { "01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK", ]; - pub const CRC_16_IBM_SDLC_NONREFLEX: Algorithm = 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::>::new(alg).checksum("123456789".as_bytes()), alg.check); + } for alg in algs_to_test { for data in data { diff --git a/src/crc16/simd.rs b/src/crc16/simd.rs index 1387714..0101927 100644 --- a/src/crc16/simd.rs +++ b/src/crc16/simd.rs @@ -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}; @@ -12,7 +11,7 @@ impl Crc> { 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, @@ -29,15 +28,18 @@ impl Crc> { } 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) } diff --git a/src/crc32.rs b/src/crc32.rs index fd4ec28..e00422b 100644 --- a/src/crc32.rs +++ b/src/crc32.rs @@ -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; @@ -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() { @@ -292,24 +260,41 @@ mod test { "1", "1234", "123456789", - "0123456789A", + "0123456789ABCDE", "01234567890ABCDEFGHIJK", "01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK", ]; - pub const CRC_32_ISCSI_NONREFLEX: Algorithm = 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::>::new(alg).checksum("123456789".as_bytes()), alg.check); + } for alg in algs_to_test { for data in data { diff --git a/src/crc32/simd.rs b/src/crc32/simd.rs index 21f18b1..1ae223c 100644 --- a/src/crc32/simd.rs +++ b/src/crc32/simd.rs @@ -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> { pub const fn new(algorithm: &'static Algorithm) -> Self { @@ -11,7 +11,7 @@ impl Crc> { 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)) }, ), @@ -25,16 +25,16 @@ impl Crc> { } 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) } diff --git a/src/crc64.rs b/src/crc64.rs index 186531e..38bda46 100644 --- a/src/crc64.rs +++ b/src/crc64.rs @@ -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() { @@ -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 = 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::>::new(alg).checksum("123456789".as_bytes()), alg.check); + } for alg in algs_to_test { for data in data { diff --git a/src/crc8.rs b/src/crc8.rs index 73aaea8..785f4d9 100644 --- a/src/crc8.rs +++ b/src/crc8.rs @@ -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; @@ -90,7 +95,7 @@ const fn update_slice16(mut crc: u8, table: &[[u8; 256]; 16], bytes: &[u8]) -> u #[cfg(test)] mod test { use crate::{Bytewise, Crc, Implementation, NoTable, Simd, Slice16}; - use crc_catalog::{Algorithm, CRC_8_BLUETOOTH}; + use crc_catalog::*; #[test] fn default_table_size() { @@ -196,18 +201,47 @@ mod test { "01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK", ]; - pub const CRC_8_BLUETOOTH_NONREFLEX: Algorithm = Algorithm { - width: 8, - poly: 0xa7, - init: 0x00, - refin: false, - refout: true, - xorout: 0x00, - check: 0x26, - residue: 0x00, - }; + let algs_to_test = &[ + CRC_3_GSM, + CRC_3_ROHC, + CRC_4_G_704, + CRC_4_INTERLAKEN, + CRC_5_EPC_C1G2, + CRC_5_G_704, + CRC_5_USB, + CRC_6_CDMA2000_A, + CRC_6_CDMA2000_B, + CRC_6_DARC, + CRC_6_G_704, + CRC_6_GSM, + CRC_7_MMC, + CRC_7_ROHC, + CRC_7_UMTS, + CRC_8_AUTOSAR, + CRC_8_BLUETOOTH, + CRC_8_CDMA2000, + CRC_8_DARC, + CRC_8_DVB_S2, + CRC_8_GSM_A, + CRC_8_GSM_B, + CRC_8_I_432_1, + CRC_8_I_CODE, + CRC_8_LTE, + CRC_8_MAXIM_DOW, + CRC_8_MIFARE_MAD, + CRC_8_NRSC_5, + CRC_8_OPENSAFETY, + CRC_8_ROHC, + CRC_8_SAE_J1850, + CRC_8_SMBUS, + CRC_8_TECH_3250, + CRC_8_WCDMA, + ]; - let algs_to_test = [&CRC_8_BLUETOOTH, &CRC_8_BLUETOOTH_NONREFLEX]; + // Check if the baseline is as expected. + for alg in algs_to_test { + assert_eq!(Crc::>::new(alg).checksum("123456789".as_bytes()), alg.check); + } for alg in algs_to_test { for data in data { diff --git a/src/crc8/simd.rs b/src/crc8/simd.rs index cda6dc0..01a75f3 100644 --- a/src/crc8/simd.rs +++ b/src/crc8/simd.rs @@ -1,6 +1,5 @@ -use crate::crc32::update_simd; -use crate::simd::{SimdValue, SimdValueOps}; -use crate::table::{crc32_simd_coefficients, crc8_table_slice_16}; +use crate::simd::{crc32_simd_coefficients, crc32_update_refin, SimdValue}; +use crate::table::crc8_table_slice_16; use crate::{Algorithm, Crc, Digest, Simd}; use super::{finalize, init, update_slice16}; @@ -12,7 +11,7 @@ impl Crc> { table: ( crc8_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, @@ -29,15 +28,18 @@ impl Crc> { } fn update(&self, mut crc: u8, bytes: &[u8]) -> u8 { - if !SimdValue::is_supported() { + if !self.algorithm.refin { return update_slice16(crc, &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.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 u8; + // 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 u8; } update_slice16(crc, &self.table.0, bytes_after) } diff --git a/src/lib.rs b/src/lib.rs index 5e11f4f..5f25924 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,11 @@ mod crc16; mod crc32; mod crc64; mod crc8; +#[cfg(all( + target_feature = "sse2", + target_feature = "sse4.1", + target_feature = "pclmulqdq" +))] mod simd; mod table; mod util; @@ -50,11 +55,27 @@ pub struct Bytewise(core::marker::PhantomData); pub struct NoTable(core::marker::PhantomData); /// Implementation using platform-specific simd instructions. Use it with `Crc>` +#[cfg(all( + target_feature = "sse2", + target_feature = "sse4.1", + target_feature = "pclmulqdq" +))] pub struct Simd(core::marker::PhantomData); +#[cfg(not(all( + target_feature = "sse2", + target_feature = "sse4.1", + target_feature = "pclmulqdq" +)))] +pub type Simd = Slice16; impl crate::private::Sealed for Slice16 {} impl crate::private::Sealed for Bytewise {} impl crate::private::Sealed for NoTable {} +#[cfg(all( + target_feature = "sse2", + target_feature = "sse4.1", + target_feature = "pclmulqdq" +))] impl crate::private::Sealed for Simd {} impl crate::Implementation for Slice16 { @@ -72,6 +93,11 @@ impl crate::Implementation for NoTable { type Table = (); } +#[cfg(all( + target_feature = "sse2", + target_feature = "sse4.1", + target_feature = "pclmulqdq" +))] impl crate::Implementation for Simd { type Width = W; type Table = ([[W; 256]; 16], [simd::SimdValue; 4]); diff --git a/src/simd.rs b/src/simd.rs index 5b8b3d0..94f49f7 100644 --- a/src/simd.rs +++ b/src/simd.rs @@ -1,8 +1,6 @@ mod x86; -pub(crate) trait SimdValueOps { - fn is_supported() -> bool; - +trait SimdValueOps { unsafe fn xor(self, value: u64) -> Self; unsafe fn fold_16(self, x_mod_p: Self, value: Self) -> Self; @@ -15,3 +13,87 @@ pub(crate) trait SimdValueOps { } pub(crate) use x86::SimdValue; + +pub(crate) const fn crc32_simd_coefficients(width: u8, poly: u32) -> [u64; 8] { + const fn xt_mod_px(mut t: u32, px: u64) -> u64 { + if t < 32 { + return 0; + } + t -= 31; + + let mut n = 0x80000000; + let mut i = 0; + while i < t { + n <<= 1; + if n & 0x100000000 != 0 { + n ^= px; + } + i += 1; + } + n << 32 + } + + const fn u(px: u64) -> u64 { + let mut q = 0; + let mut n = 0x100000000; + let mut i = 0; + while i < 33 { + q <<= 1; + if n & 0x100000000 != 0 { + q |= 1; + n ^= px; + } + n <<= 1; + i += 1; + } + q + } + + let px = (poly as u64) << (u32::BITS as u8 - width); + [ + xt_mod_px(4 * 128 + 32, px).reverse_bits() << 1, + xt_mod_px(4 * 128 - 32, px).reverse_bits() << 1, + xt_mod_px(128 + 32, px).reverse_bits() << 1, + xt_mod_px(128 - 32, px).reverse_bits() << 1, + xt_mod_px(64, px).reverse_bits() << 1, + xt_mod_px(32, px).reverse_bits() << 1, + px.reverse_bits() >> 31, + u(px).reverse_bits() >> 31, + ] +} + +#[target_feature(enable = "sse2", enable = "sse4.1", enable = "pclmulqdq")] +pub(crate) unsafe fn crc32_update_refin( + 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) +} diff --git a/src/simd/x86.rs b/src/simd/x86.rs index 590ea67..742c866 100644 --- a/src/simd/x86.rs +++ b/src/simd/x86.rs @@ -10,12 +10,6 @@ use core::mem; pub struct SimdValue(arch::__m128i); impl SimdValueOps for SimdValue { - fn is_supported() -> bool { - cfg!(target_feature = "pclmulqdq") - && cfg!(target_feature = "sse2") - && cfg!(target_feature = "sse4.1") - } - #[inline] #[target_feature(enable = "sse2")] unsafe fn xor(self, value: u64) -> Self { diff --git a/src/table.rs b/src/table.rs index 2fc1d01..fcf8353 100644 --- a/src/table.rs +++ b/src/table.rs @@ -144,54 +144,6 @@ pub(crate) const fn crc32_table_slice_16(width: u8, poly: u32, reflect: bool) -> table } -pub(crate) const fn crc32_simd_coefficients(width: u8, poly: u32) -> [u64; 8] { - const fn xt_mod_px(mut t: u32, px: u64) -> u64 { - if t < 32 { - return 0; - } - t -= 31; - - let mut n = 0x80000000; - let mut i = 0; - while i < t { - n <<= 1; - if n & 0x100000000 != 0 { - n ^= px; - } - i += 1; - } - n << 32 - } - - const fn u(px: u64) -> u64 { - let mut q = 0; - let mut n = 0x100000000; - let mut i = 0; - while i < 33 { - q <<= 1; - if n & 0x100000000 != 0 { - q |= 1; - n ^= px; - } - n <<= 1; - i += 1; - } - q - } - - let px = (poly as u64) << (u32::BITS as u8 - width); - [ - xt_mod_px(4 * 128 + 32, px).reverse_bits() << 1, - xt_mod_px(4 * 128 - 32, px).reverse_bits() << 1, - xt_mod_px(128 + 32, px).reverse_bits() << 1, - xt_mod_px(128 - 32, px).reverse_bits() << 1, - xt_mod_px(64, px).reverse_bits() << 1, - xt_mod_px(32, px).reverse_bits() << 1, - px.reverse_bits() >> 31, - u(px).reverse_bits() >> 31, - ] -} - pub(crate) const fn crc64_table(width: u8, poly: u64, reflect: bool) -> [u64; 256] { let poly = if reflect { let poly = poly.reverse_bits(); diff --git a/tests/crc.rs b/tests/crc.rs deleted file mode 100644 index 43ceba3..0000000 --- a/tests/crc.rs +++ /dev/null @@ -1,181 +0,0 @@ -use crc::*; - -const INIT: &[u8] = b"123456789"; - -const INIT_PART1: &[u8] = b"1234"; -const INIT_PART2: &[u8] = b"56789"; - -#[test] -fn crc_8() { - let algs = &[ - CRC_3_GSM, - CRC_3_ROHC, - CRC_4_G_704, - CRC_4_INTERLAKEN, - CRC_5_EPC_C1G2, - CRC_5_G_704, - CRC_5_USB, - CRC_6_CDMA2000_A, - CRC_6_CDMA2000_B, - CRC_6_DARC, - CRC_6_G_704, - CRC_6_GSM, - CRC_7_MMC, - CRC_7_ROHC, - CRC_7_UMTS, - CRC_8_AUTOSAR, - CRC_8_BLUETOOTH, - CRC_8_CDMA2000, - CRC_8_DARC, - CRC_8_DVB_S2, - CRC_8_GSM_A, - CRC_8_GSM_B, - CRC_8_I_432_1, - CRC_8_I_CODE, - CRC_8_LTE, - CRC_8_MAXIM_DOW, - CRC_8_MIFARE_MAD, - CRC_8_NRSC_5, - CRC_8_OPENSAFETY, - CRC_8_ROHC, - CRC_8_SAE_J1850, - CRC_8_SMBUS, - CRC_8_TECH_3250, - CRC_8_WCDMA, - ]; - for alg in algs.iter() { - let crc = Crc::::new(alg); - assert_eq!(alg.check, crc.checksum(INIT)); - let mut digest = crc.digest(); - digest.update(INIT_PART1); - digest.update(INIT_PART2); - assert_eq!(alg.check, digest.finalize()); - } -} - -#[test] -fn crc_16() { - let algs = &[ - 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, - ]; - for alg in algs.iter() { - let crc = Crc::::new(alg); - assert_eq!(alg.check, crc.checksum(INIT)); - let mut digest = crc.digest(); - digest.update(INIT_PART1); - digest.update(INIT_PART2); - assert_eq!(alg.check, digest.finalize()); - } -} - -#[test] -fn crc_32() { - let algs = &[ - 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, - ]; - for alg in algs { - let crc = Crc::::new(alg); - assert_eq!(alg.check, crc.checksum(INIT)); - let mut digest = crc.digest(); - digest.update(INIT_PART1); - digest.update(INIT_PART2); - assert_eq!(alg.check, digest.finalize()); - } -} - -#[test] -fn crc_64() { - let algs = &[ - CRC_40_GSM, - CRC_64_ECMA_182, - CRC_64_GO_ISO, - CRC_64_WE, - CRC_64_XZ, - ]; - for alg in algs { - let crc = Crc::::new(alg); - assert_eq!(alg.check, crc.checksum(INIT)); - let mut digest = crc.digest(); - digest.update(INIT_PART1); - digest.update(INIT_PART2); - assert_eq!(alg.check, digest.finalize()); - } -} - -#[test] -fn crc_128() { - let algs = &[CRC_82_DARC]; - for alg in algs { - let crc = Crc::::new(alg); - assert_eq!(alg.check, crc.checksum(INIT)); - let mut digest = crc.digest(); - digest.update(INIT_PART1); - digest.update(INIT_PART2); - assert_eq!(alg.check, digest.finalize()); - } -}