ab_riscv_interpreter/rv32/b/zbc/
rv32_zbc_helpers.rs1#![cfg_attr(
5 all(
6 any(miri, not(all(target_arch = "riscv32", target_feature = "zbc"))),
7 any(
8 all(
9 target_arch = "aarch64",
10 target_feature = "neon",
11 target_feature = "aes"
12 ),
13 all(target_arch = "x86_64", target_feature = "pclmulqdq")
14 ),
15 not(feature = "no-panic")
16 ),
17 expect(
18 clippy::items_after_statements,
19 reason = "https://github.com/rust-lang/rust-clippy/issues/17498"
20 )
21)]
22
23use crate::const_utils::ConstRange;
24use const_fn_specialization::const_fn_specialization;
25
26#[const_fn_specialization]
27#[inline(always)]
28#[doc(hidden)]
29#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
30pub fn clmul(a: u32, b: u32) -> u32 {
31 cfg_select! {
33 all(not(miri), target_arch = "riscv32", target_feature = "zbkc") => {
34 unsafe { core::arch::riscv32::clmul(a as usize, b as usize) as u32 }
36 }
37 _ => clmul_internal(a, b) as u32,
38 }
39}
40
41#[const_fn_specialization]
42#[inline(always)]
43#[doc(hidden)]
44#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
45pub fn clmulh(a: u32, b: u32) -> u32 {
46 cfg_select! {
48 all(not(miri), target_arch = "riscv32", target_feature = "zbkc") => {
49 unsafe { core::arch::riscv32::clmulh(a as usize, b as usize) as u32 }
51 }
52 _ => (clmul_internal(a, b) >> 32) as u32,
53 }
54}
55
56#[const_fn_specialization]
57#[inline(always)]
58#[doc(hidden)]
59#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
60pub fn clmulr(a: u32, b: u32) -> u32 {
61 cfg_select! {
63 all(not(miri), target_arch = "riscv32", target_feature = "zbc") => {
64 unsafe { core::arch::riscv32::clmulr(a as usize, b as usize) as u32 }
66 }
67 _ => (clmul_internal(a, b) >> 31) as u32,
68 }
69}
70
71#[const_fn_specialization]
72#[inline(always)]
73#[doc(hidden)]
74#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
75pub const fn clmul(a: u32, b: u32) -> u32 {
76 clmul_internal_generic(u64::from(a), u64::from(b)) as u32
77}
78
79#[const_fn_specialization]
80#[inline(always)]
81#[doc(hidden)]
82#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
83pub const fn clmulh(a: u32, b: u32) -> u32 {
84 (clmul_internal_generic(u64::from(a), u64::from(b)) >> 32) as u32
85}
86
87#[const_fn_specialization]
88#[inline(always)]
89#[doc(hidden)]
90#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
91pub const fn clmulr(a: u32, b: u32) -> u32 {
92 (clmul_internal_generic(u64::from(a), u64::from(b)) >> 31) as u32
93}
94
95#[cfg(any(miri, not(all(target_arch = "riscv32", target_feature = "zbc"))))]
97#[inline(always)]
98#[doc(hidden)]
99#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
100fn clmul_internal(a: u32, b: u32) -> u64 {
101 let a = u64::from(a);
102 let b = u64::from(b);
103
104 cfg_select! {
105 all(
106 target_arch = "aarch64",
107 target_feature = "neon",
108 target_feature = "aes"
109 ) => {
110 use core::arch::aarch64::vmull_p64;
111
112 unsafe { vmull_p64(a, b) as u64 }
115 }
116 all(target_arch = "x86_64", target_feature = "pclmulqdq") => {
117 use core::arch::x86_64::{__m128i, _mm_clmulepi64_si128, _mm_cvtsi64_si128};
118 use core::mem::transmute;
119
120 unsafe {
122 let result = transmute::<__m128i, u128>(_mm_clmulepi64_si128(
123 _mm_cvtsi64_si128(a.cast_signed()),
124 _mm_cvtsi64_si128(b.cast_signed()),
125 0,
126 ));
127 result as u64
128 }
129 }
130 _ => clmul_internal_generic(a, b),
131 }
132}
133
134#[inline(always)]
136#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
137const fn clmul_internal_generic(a: u64, b: u64) -> u64 {
138 let mut result = 0u64;
139 let mut b = b;
140 for i in ConstRange::new(0, u32::BITS) {
141 let bit = b & 1;
142 result ^= a.wrapping_shl(i) & (0u64.wrapping_sub(bit));
143 b >>= 1;
144 }
145 result
146}