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::instruction::rv64::b::zbc::Rv64ZbcInstruction;
10use ab_riscv_primitives::registers::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 #[cfg(all(not(miri), target_arch = "riscv64", target_feature = "zbkc"))]
34 let value = core::arch::riscv64::clmul(a as usize, b as usize) as u64;
35
36 #[cfg(not(all(not(miri), target_arch = "riscv64", target_feature = "zbkc")))]
37 let value = {
38 let result = clmul_internal(a, b);
39 result as u64
40 };
41
42 state.regs.write(rd, value);
43 }
44 Self::Clmulh { rd, rs1, rs2 } => {
45 let a = state.regs.read(rs1);
46 let b = state.regs.read(rs2);
47
48 #[cfg(all(not(miri), target_arch = "riscv64", target_feature = "zbkc"))]
49 let value = core::arch::riscv64::clmulh(a as usize, b as usize) as u64;
50
51 #[cfg(not(all(not(miri), target_arch = "riscv64", target_feature = "zbkc")))]
52 let value = {
53 let result = clmul_internal(a, b);
54 (result >> 64) as u64
55 };
56
57 state.regs.write(rd, value);
58 }
59 Self::Clmulr { rd, rs1, rs2 } => {
60 let a = state.regs.read(rs1);
61 let b = state.regs.read(rs2);
62
63 #[cfg(all(not(miri), target_arch = "riscv64", target_feature = "zbc"))]
64 let value = core::arch::riscv64::clmulr(a as usize, b as usize) as u64;
65
66 #[cfg(not(all(not(miri), target_arch = "riscv64", target_feature = "zbc")))]
67 let value = {
68 let result = clmul_internal(a, b);
69 (result >> 1) as u64
70 };
71
72 state.regs.write(rd, value);
73 }
74 }
75
76 Ok(ControlFlow::Continue(()))
77 }
78}
79
80#[cfg(any(miri, not(all(target_arch = "riscv64", target_feature = "zbc"))))]
84#[inline(always)]
85pub fn clmul_internal(a: u64, b: u64) -> u128 {
86 #[cfg(all(
89 not(miri),
90 target_arch = "aarch64",
91 target_feature = "neon",
92 target_feature = "aes"
93 ))]
94 {
95 use core::arch::aarch64::vmull_p64;
96
97 unsafe { vmull_p64(a, b) }
99 }
100
101 #[cfg(all(target_arch = "x86_64", target_feature = "pclmulqdq"))]
102 {
103 use core::arch::x86_64::{__m128i, _mm_clmulepi64_si128, _mm_cvtsi64_si128};
104 use core::mem::transmute;
105
106 unsafe {
109 transmute::<__m128i, u128>(_mm_clmulepi64_si128(
110 _mm_cvtsi64_si128(a.cast_signed()),
111 _mm_cvtsi64_si128(b.cast_signed()),
112 0,
113 ))
114 }
115 }
116
117 #[cfg(not(any(
118 all(
119 not(miri),
120 target_arch = "aarch64",
121 target_feature = "neon",
122 target_feature = "aes"
123 ),
124 all(target_arch = "x86_64", target_feature = "pclmulqdq")
125 )))]
126 {
127 let mut result = 0u128;
129 let a = a as u128;
130 let mut b = b;
131 for i in 0..u64::BITS {
132 let bit = (b & 1) as u128;
133 result ^= a.wrapping_shl(i) & (0u128.wrapping_sub(bit));
134 b >>= 1;
135 }
136 result
137 }
138}