From 5a11c358d7ee24b4cbccdc44a0cc0dfdf74ef1b8 Mon Sep 17 00:00:00 2001 From: Nics Date: Sun, 18 Jan 2026 17:40:49 +0100 Subject: [PATCH] cmov: add riscv32 optimised mask generation --- cmov/README.md | 1 + cmov/src/backends/soft.rs | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/cmov/README.md b/cmov/README.md index 8954d0e0..af770752 100644 --- a/cmov/README.md +++ b/cmov/README.md @@ -36,6 +36,7 @@ on the following CPU architectures: - [x] `x86_64` (`CMOVZ`, `CMOVNZ`) - [x] `arm` (mask generation only) - [x] `aarch64` (`CSEL`) +- [x] `riscv32` (mask generation only) On other target architectures, a "best effort" portable fallback implementation based on bitwise arithmetic is used instead, augmented with tactical usage of diff --git a/cmov/src/backends/soft.rs b/cmov/src/backends/soft.rs index 77a50e19..55b6c4b7 100644 --- a/cmov/src/backends/soft.rs +++ b/cmov/src/backends/soft.rs @@ -122,13 +122,13 @@ fn maskne64(x: u64, y: u64) -> u64 { } /// Return a `u32::MAX` mask if `condition` is non-zero, otherwise return zero for a zero input. -#[cfg(not(target_arch = "arm"))] +#[cfg(not(any(target_arch = "arm", target_arch = "riscv32")))] fn masknz32(condition: u32) -> u32 { masknz!(condition: u32) } /// Return a `u64::MAX` mask if `condition` is non-zero, otherwise return zero for a zero input. -#[cfg(not(target_arch = "arm"))] +#[cfg(not(any(target_arch = "arm", target_arch = "riscv32")))] fn masknz64(condition: u64) -> u64 { masknz!(condition: u64) } @@ -153,8 +153,24 @@ fn masknz32(condition: u32) -> u32 { mask } +/// Optimized mask generation for riscv32 targets. +#[cfg(target_arch = "riscv32")] +fn masknz32(condition: u32) -> u32 { + let mut mask: u32; + unsafe { + core::arch::asm!( + "seqz {0}, {1}", // Set-if-not-zero pseudo-instruction + "addi {0}, {0}, -1", // Subtract 1, to have either full ones or full zeroes mask + lateout(reg) mask, + in(reg) condition, + options(nostack, nomem), + ); + } + mask +} + /// 64-bit wrapper for targets that implement 32-bit mask generation in assembly. -#[cfg(target_arch = "arm")] +#[cfg(any(target_arch = "arm", target_arch = "riscv32"))] fn masknz64(condition: u64) -> u64 { let lo = masknz32((condition & 0xFFFF_FFFF) as u32); let hi = masknz32((condition >> 32) as u32);