Skip to main content

ab_riscv_interpreter/rv64/b/zbc/
rv64_zbc_helpers.rs

1//! Opaque helpers for Zbc extension
2
3#[inline(always)]
4#[doc(hidden)]
5#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
6pub fn clmul(a: u64, b: u64) -> u64 {
7    // TODO: Miri is excluded because corresponding intrinsic is not implemented there
8    cfg_select! {
9        all(not(miri), target_arch = "riscv64", target_feature = "zbkc") => {
10            // SAFETY: Compile-time checked for supported feature
11            unsafe { core::arch::riscv64::clmul(a as usize, b as usize) as u64 }
12        }
13        _ => {{
14            let result = clmul_internal(a, b);
15            result as u64
16        }}
17    }
18}
19
20#[inline(always)]
21#[doc(hidden)]
22#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
23pub fn clmulh(a: u64, b: u64) -> u64 {
24    // TODO: Miri is excluded because corresponding intrinsic is not implemented there
25    cfg_select! {
26        all(not(miri), target_arch = "riscv64", target_feature = "zbkc") => {
27            // SAFETY: Compile-time checked for supported feature
28            unsafe { core::arch::riscv64::clmulh(a as usize, b as usize) as u64 }
29        }
30        _ => {{
31            let result = clmul_internal(a, b);
32            (result >> 64) as u64
33        }}
34    }
35}
36
37#[inline(always)]
38#[doc(hidden)]
39#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
40pub fn clmulr(a: u64, b: u64) -> u64 {
41    // TODO: Miri is excluded because corresponding intrinsic is not implemented there
42    cfg_select! {
43        all(not(miri), target_arch = "riscv64", target_feature = "zbc") => {
44            // SAFETY: Compile-time checked for supported feature
45            unsafe { core::arch::riscv64::clmulr(a as usize, b as usize) as u64 }
46        }
47        _ => {{
48            let result = clmul_internal(a, b);
49            (result >> 63) as u64
50        }}
51    }
52}
53
54/// Carryless multiplication helper
55#[cfg(any(miri, not(all(target_arch = "riscv64", target_feature = "zbc"))))]
56#[inline(always)]
57#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
58fn clmul_internal(a: u64, b: u64) -> u128 {
59    cfg_select! {
60        // TODO: `llvm.aarch64.neon.pmull64` is not supported in Miri yet:
61        //  https://github.com/rust-lang/miri/issues/3172#issuecomment-3730602707
62        all(
63            not(miri), target_arch = "aarch64", target_feature = "neon", target_feature = "aes"
64        ) => {{
65            use core::arch::aarch64::vmull_p64;
66
67            // SAFETY: Compile-time checked for supported feature
68            unsafe { vmull_p64(a, b) }
69        }}
70        all(target_arch = "x86_64", target_feature = "pclmulqdq") => {{
71            use core::arch::x86_64::{__m128i, _mm_clmulepi64_si128, _mm_cvtsi64_si128};
72            use core::mem::transmute;
73
74            // SAFETY: Necessary target features enabled, `__m128i` and `u128` have the same memory
75            // layout
76            unsafe {
77                transmute::<__m128i, u128>(_mm_clmulepi64_si128(
78                    _mm_cvtsi64_si128(a.cast_signed()),
79                    _mm_cvtsi64_si128(b.cast_signed()),
80                    0,
81                ))
82            }
83        }}
84        _ => {{
85            // Generic implementation
86            let mut result = 0u128;
87            let a = u128::from(a);
88            let mut b = b;
89            for i in 0..u64::BITS {
90                let bit = u128::from(b & 1);
91                result ^= a.wrapping_shl(i) & (0u128.wrapping_sub(bit));
92                b >>= 1u8;
93            }
94            result
95        }}
96    }
97}