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