ab_riscv_interpreter/rv64/b/
zbc.rs1#[cfg(test)]
4mod tests;
5
6use crate::rv64::Rv64InterpreterState;
7use crate::{ExecutableInstruction, ExecutionError};
8use ab_riscv_macros::instruction_execution;
9use ab_riscv_primitives::instructions::rv64::b::zbc::Rv64ZbcInstruction;
10use ab_riscv_primitives::registers::general_purpose::Register;
11use core::ops::ControlFlow;
12
13#[instruction_execution]
14impl<Reg, Memory, PC, InstructionHandler, CustomError>
15 ExecutableInstruction<
16 Rv64InterpreterState<Reg, Memory, PC, InstructionHandler, CustomError>,
17 CustomError,
18 > for Rv64ZbcInstruction<Reg>
19where
20 Reg: Register<Type = u64>,
21 [(); Reg::N]:,
22{
23 #[inline(always)]
24 fn execute(
25 self,
26 state: &mut Rv64InterpreterState<Reg, Memory, PC, InstructionHandler, CustomError>,
27 ) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, Self, CustomError>> {
28 match self {
29 Self::Clmul { rd, rs1, rs2 } => {
30 let a = state.regs.read(rs1);
31 let b = state.regs.read(rs2);
32
33 let value = cfg_select! {
35 all(not(miri), target_arch = "riscv64", target_feature = "zbkc") => {
36 core::arch::riscv64::clmul(a as usize, b as usize) as u64
37 }
38 _ => {{
39 let result = clmul_internal(a, b);
40 result as u64
41 }}
42 };
43
44 state.regs.write(rd, value);
45 }
46 Self::Clmulh { rd, rs1, rs2 } => {
47 let a = state.regs.read(rs1);
48 let b = state.regs.read(rs2);
49
50 let value = cfg_select! {
52 all(not(miri), target_arch = "riscv64", target_feature = "zbkc") => {
53 core::arch::riscv64::clmulh(a as usize, b as usize) as u64
54 }
55 _ => {{
56 let result = clmul_internal(a, b);
57 (result >> 64) as u64
58 }}
59 };
60
61 state.regs.write(rd, value);
62 }
63 Self::Clmulr { rd, rs1, rs2 } => {
64 let a = state.regs.read(rs1);
65 let b = state.regs.read(rs2);
66
67 let value = cfg_select! {
69 all(not(miri), target_arch = "riscv64", target_feature = "zbc") => {
70 core::arch::riscv64::clmulr(a as usize, b as usize) as u64
71 }
72 _ => {{
73 let result = clmul_internal(a, b);
74 (result >> 1) as u64
75 }}
76 };
77
78 state.regs.write(rd, value);
79 }
80 }
81
82 Ok(ControlFlow::Continue(()))
83 }
84}
85
86#[cfg(any(miri, not(all(target_arch = "riscv64", target_feature = "zbc"))))]
90#[inline(always)]
91pub fn clmul_internal(a: u64, b: u64) -> u128 {
92 cfg_select! {
93 all(
96 not(miri), target_arch = "aarch64", target_feature = "neon", target_feature = "aes"
97 ) => {{
98 use core::arch::aarch64::vmull_p64;
99
100 unsafe { vmull_p64(a, b) }
102 }}
103 all(target_arch = "x86_64", target_feature = "pclmulqdq") => {{
104 use core::arch::x86_64::{__m128i, _mm_clmulepi64_si128, _mm_cvtsi64_si128};
105 use core::mem::transmute;
106
107 unsafe {
110 transmute::<__m128i, u128>(_mm_clmulepi64_si128(
111 _mm_cvtsi64_si128(a.cast_signed()),
112 _mm_cvtsi64_si128(b.cast_signed()),
113 0,
114 ))
115 }
116 }}
117 _ => {{
118 let mut result = 0u128;
120 let a = a as u128;
121 let mut b = b;
122 for i in 0..u64::BITS {
123 let bit = (b & 1) as u128;
124 result ^= a.wrapping_shl(i) & (0u128.wrapping_sub(bit));
125 b >>= 1;
126 }
127 result
128 }}
129 }
130}