Skip to main content

ab_riscv_interpreter/rv64/zk/zbkx/
rv64_zbkx_helpers.rs

1//! Opaque helpers for Zbkx extension
2
3#[inline]
4#[doc(hidden)]
5#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
6pub fn xperm4(rs1: u64, rs2: 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 = "zbkx") => {
10            unsafe { core::arch::riscv64::xperm4(rs1 as usize, rs2 as usize) as u64 }
11        }
12        _ => {
13            use core::simd::num::SimdUint;
14            use core::simd::{simd_swizzle, u64x16};
15
16            const SHIFT: u64x16 =
17                u64x16::from_array([0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60]);
18            const MASK: u64x16 = u64x16::splat(0xf);
19
20            // Unpack nibbles of rs1 into bytes via SIMD: broadcast, shift per-lane, mask
21            let lut = (u64x16::splat(rs1) >> SHIFT) & MASK;
22            // Unpack nibbles of rs2 into byte indices via SIMD
23            let idx = (u64x16::splat(rs2) >> SHIFT) & MASK;
24            // For each nibble of rs2, look up directly from lut; all indices 0–15 are in-bounds
25            let nibbles = lut.cast().swizzle_dyn(idx.cast());
26            // Pack nibbles back: interleave even/odd lanes and fold into bytes
27            let lo = simd_swizzle!(nibbles, [0, 2, 4, 6, 8, 10, 12, 14]);
28            let hi = simd_swizzle!(nibbles, [1, 3, 5, 7, 9, 11, 13, 15]);
29            u64::from_le_bytes((lo | (hi << 4)).to_array())
30        }
31    }
32}
33
34#[inline]
35#[doc(hidden)]
36#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
37pub fn xperm8(rs1: u64, rs2: 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 = "zbkx") => {
41            unsafe { core::arch::riscv64::xperm8(rs1 as usize, rs2 as usize) as u64 }
42        }
43        _ => {
44            use core::simd::u8x8;
45
46            let lut = u8x8::from_array(rs1.to_le_bytes());
47            let idx = u8x8::from_array(rs2.to_le_bytes());
48
49            let result = lut.swizzle_dyn(idx);
50
51            u64::from_le_bytes(result.to_array())
52        }
53    }
54}