Skip to main content

ab_riscv_interpreter/rv64/b/zbc/
zbc_helpers.rs

1//! Opaque helpers for Zbc extension
2
3/// Carryless multiplication helper
4#[cfg(any(miri, not(all(target_arch = "riscv64", target_feature = "zbc"))))]
5#[inline(always)]
6#[doc(hidden)]
7pub fn clmul_internal(a: u64, b: u64) -> u128 {
8    cfg_select! {
9        // TODO: `llvm.aarch64.neon.pmull64` is not supported in Miri yet:
10        //  https://github.com/rust-lang/miri/issues/3172#issuecomment-3730602707
11        all(
12            not(miri), target_arch = "aarch64", target_feature = "neon", target_feature = "aes"
13        ) => {{
14            use core::arch::aarch64::vmull_p64;
15
16            // SAFETY: Necessary target features enabled
17            unsafe { vmull_p64(a, b) }
18        }}
19        all(target_arch = "x86_64", target_feature = "pclmulqdq") => {{
20            use core::arch::x86_64::{__m128i, _mm_clmulepi64_si128, _mm_cvtsi64_si128};
21            use core::mem::transmute;
22
23            // SAFETY: Necessary target features enabled, `__m128i` and `u128` have the same memory
24            // layout
25            unsafe {
26                transmute::<__m128i, u128>(_mm_clmulepi64_si128(
27                    _mm_cvtsi64_si128(a.cast_signed()),
28                    _mm_cvtsi64_si128(b.cast_signed()),
29                    0,
30                ))
31            }
32        }}
33        _ => {{
34            // Generic implementation
35            let mut result = 0u128;
36            let a = a as u128;
37            let mut b = b;
38            for i in 0..u64::BITS {
39                let bit = (b & 1) as u128;
40                result ^= a.wrapping_shl(i) & (0u128.wrapping_sub(bit));
41                b >>= 1;
42            }
43            result
44        }}
45    }
46}
47
48/// Only here to prevent compiler warnings about unused `zbc_helpers` module
49#[doc(hidden)]
50pub const PLACEHOLDER: () = ();