From e72334e0d9d35cf95406787e748c9037fc10dafb Mon Sep 17 00:00:00 2001 From: Aelin Reidel Date: Fri, 22 May 2026 02:10:48 +0200 Subject: [PATCH] crc32: Add implementation for loongarch64 --- zlib-rs/src/crc32.rs | 13 +++- zlib-rs/src/crc32/loongarch.rs | 118 +++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 zlib-rs/src/crc32/loongarch.rs diff --git a/zlib-rs/src/crc32.rs b/zlib-rs/src/crc32.rs index 03a237d8..cf4acfc7 100644 --- a/zlib-rs/src/crc32.rs +++ b/zlib-rs/src/crc32.rs @@ -6,6 +6,8 @@ use crate::CRC32_INITIAL_VALUE; pub(crate) mod acle; mod braid; mod combine; +#[cfg(target_arch = "loongarch64")] +mod loongarch; #[cfg(target_arch = "x86_64")] mod pclmulqdq; #[cfg(target_arch = "x86_64")] @@ -81,8 +83,15 @@ impl Crc32Fold { return; } - // in this case the start value is ignored - self.value = braid::crc32_braid::<5>(self.value, src); + #[cfg(target_arch = "loongarch64")] + { + self.value = self::loongarch::crc32_loongarch64(self.value, src); + } + #[cfg(not(target_arch = "loongarch64"))] + { + // in this case the start value is ignored + self.value = braid::crc32_braid::<5>(self.value, src); + } } pub fn fold_copy(&mut self, dst: &mut [u8], src: &[u8]) { diff --git a/zlib-rs/src/crc32/loongarch.rs b/zlib-rs/src/crc32/loongarch.rs new file mode 100644 index 00000000..4f44be92 --- /dev/null +++ b/zlib-rs/src/crc32/loongarch.rs @@ -0,0 +1,118 @@ +pub fn crc32_loongarch64(crc: u32, buf: &[u8]) -> u32 { + let mut c = !crc as i32; + + // SAFETY: [u8; 8] safely transmutes into i64. + let (before, middle, after) = unsafe { buf.align_to::() }; + + c = remainder(c, before); + + if middle.is_empty() && after.is_empty() { + return !c as u32; + } + + for d in middle { + c = crc_w_d_w(*d, c); + } + + c = remainder(c, after); + + !c as u32 +} + +#[inline] +fn remainder(mut c: i32, mut buf: &[u8]) -> i32 { + if let [b0, b1, b2, b3, rest @ ..] = buf { + c = crc_w_w_w(i32::from_le_bytes([*b0, *b1, *b2, *b3]), c); + buf = rest; + } + + if let [b0, b1, rest @ ..] = buf { + c = crc_w_h_w(i16::from_le_bytes([*b0, *b1]), c); + buf = rest; + } + + if let [b0, rest @ ..] = buf { + c = crc_w_b_w(*b0 as i8, c); + buf = rest; + } + + debug_assert!(buf.is_empty()); + + c +} + +crate::cfg_select! { + miri => { + use core::arch::loongarch64::{crc_w_b_w, crc_w_h_w, crc_w_w_w, crc_w_d_w}; + } + _ => { + use asm::{crc_w_b_w, crc_w_h_w, crc_w_w_w, crc_w_d_w}; + } +} + +// FIXME: there are intrinsics for these in the standard library, but currently +// unstable behind the stdarch_loongarch feature +// +// CRC32 instructions are part of the basic integer operations and therefore +// always available. +mod asm { + /// CRC32 single round checksum for bytes (8 bits). + /// + /// [Loongson's documentation](https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#crc-check-instructions) + pub fn crc_w_b_w(data: i8, mut crc: i32) -> i32 { + unsafe { + core::arch::asm!( + "crc.w.b.w {crc}, {data}, {crc}", + crc = inout(reg) crc, + data = in(reg) data, + options(pure, nomem, nostack, preserves_flags) + ); + } + crc + } + + /// CRC32 single round checksum for half words (16 bits). + /// + /// [Loongson's documentation](https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#crc-check-instructions) + pub fn crc_w_h_w(data: i16, mut crc: i32) -> i32 { + unsafe { + core::arch::asm!( + "crc.w.h.w {crc}, {data}, {crc}", + crc = inout(reg) crc, + data = in(reg) data, + options(pure, nomem, nostack, preserves_flags) + ); + } + crc + } + + /// CRC32 single round checksum for words (32 bits). + /// + /// [Loongson's documentation](https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#crc-check-instructions) + pub fn crc_w_w_w(data: i32, mut crc: i32) -> i32 { + unsafe { + core::arch::asm!( + "crc.w.w.w {crc}, {data}, {crc}", + crc = inout(reg) crc, + data = in(reg) data, + options(pure, nomem, nostack, preserves_flags) + ); + } + crc + } + + /// CRC32 single round checksum for double words (64 bits). + /// + /// [Loongson's documentation](https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#crc-check-instructions) + pub fn crc_w_d_w(data: i64, mut crc: i32) -> i32 { + unsafe { + core::arch::asm!( + "crc.w.d.w {crc}, {data}, {crc}", + crc = inout(reg) crc, + data = in(reg) data, + options(pure, nomem, nostack, preserves_flags) + ); + } + crc + } +}