use super::*;
use crate::engine::vector::layer::{FpToFxp, FxpToFp};
use crate::prelude::VeScalar;
impl LogicBinaryOpI32 {
pub fn op_fn(&self) -> fn(i32, i32) -> i32 {
match self {
Self::BitAnd => |a, b| a & b,
Self::BitOr => |a, b| a | b,
Self::BitXor => |a, b| a ^ b,
Self::LeftShift => |a, b| a << (b as u32),
Self::LogicRightShift => |a, b| ((a as u32) >> (b as u32)) as i32,
Self::ArithRightShift => |a, b| a >> (b as u32),
}
}
}
impl LogicBinaryOpF32 {
pub(crate) fn op_fn(&self) -> fn(f32, f32) -> f32 {
match self {
Self::BitAnd => |a, b| f32::from_bits(a.to_bits() & b.to_bits()),
Self::BitOr => |a, b| f32::from_bits(a.to_bits() | b.to_bits()),
Self::BitXor => |a, b| f32::from_bits(a.to_bits() ^ b.to_bits()),
}
}
}
impl FxpBinaryOp {
pub fn op_fn(&self) -> fn(i32, i32) -> i32 {
match self {
Self::AddFxp => |a, b| a.wrapping_add(b),
Self::AddFxpSat => |a, b| a.saturating_add(b),
Self::SubFxp => |a, b| a.wrapping_sub(b),
Self::SubFxpSat => |a, b| a.saturating_sub(b),
Self::LeftShift => |a, b| a << (b as u32),
Self::LeftShiftSat => |a, b| a.saturating_mul(1 << (b as u32)),
Self::MulFxp => |a, b| {
if a == i32::MIN && b == i32::MIN {
i32::MAX
} else {
let product = i64::from(a) * i64::from(b);
(((product >> 30) + 1) >> 1) as i32
}
},
Self::MulInt => |a, b| a.wrapping_mul(b),
Self::LogicRightShift => |a, b| ((a as u32) >> (b as u32)) as i32,
Self::ArithRightShift => |a, b| a >> (b as u32),
Self::ArithRightShiftRound => todo!("ArithRightShiftRound not implemented"),
}
}
}
impl FpUnaryOp {
pub fn op_fn(&self) -> fn(f32) -> f32 {
match self {
Self::Exp => |x| x.exp(),
Self::NegExp => |x| (-x).exp(),
Self::Sqrt => |x| x.sqrt(),
Self::Tanh => |x| x.tanh(),
Self::Sigmoid => |x| 1.0 / (1.0 + (-x).exp()),
Self::Erf => |_x| todo!("Erf not implemented"),
Self::Log => |x| x.ln(),
Self::Sin => |x| x.sin(),
Self::Cos => |x| x.cos(),
}
}
}
impl FpBinaryOp {
pub fn op_fn(&self) -> fn(f32, f32) -> f32 {
match self {
Self::AddF => |a, b| a + b,
Self::SubF => |a, b| a - b,
Self::MulF(_) => |a, b| a * b,
Self::DivF => |a, b| a / b,
}
}
}
impl FpTernaryOp {
pub fn op_fn(&self) -> fn(f32, f32, f32) -> f32 {
match self {
Self::FmaF => |a, b, c| a.mul_add(b, c),
}
}
}
impl ClipBinaryOpI32 {
pub fn op_fn(&self) -> fn(i32, i32) -> i32 {
match self {
Self::AddFxp => |a, b| a.wrapping_add(b),
Self::AddFxpSat => |a, b| a.saturating_add(b),
Self::Min => |a, b| a.min(b),
Self::Max => |a, b| a.max(b),
Self::AbsMin => |a, b| if a.abs() < b.abs() { a } else { b },
Self::AbsMax => |a, b| if a.abs() > b.abs() { a } else { b },
}
}
}
impl ClipBinaryOpF32 {
pub fn op_fn(&self) -> fn(f32, f32) -> f32 {
match self {
Self::Add => |a, b| a + b,
Self::Min => |a, b| a.min(b),
Self::Max => |a, b| a.max(b),
Self::AbsMin => |a, b| if a.abs() < b.abs() { a } else { b },
Self::AbsMax => |a, b| if a.abs() > b.abs() { a } else { b },
}
}
}
impl FxpToFp {
pub(crate) fn op_fn(&self) -> impl Fn(i32) -> f32 + Sync {
let int_width = self.int_width();
move |x| crate::float::fixedpoint_to_float(x, int_width)
}
}
impl FpToFxp {
pub(crate) fn op_fn(&self) -> impl Fn(f32) -> i32 + Sync {
let int_width = self.int_width();
move |x| crate::float::float_to_fixedpoint(x, int_width)
}
}
pub trait HasConversionOp<D: VeScalar, D2: VeScalar>: Clone + Copy {
fn conversion_op_fn(&self) -> impl Fn(D) -> D2 + Sync;
}
impl HasConversionOp<i32, f32> for FxpToFp {
fn conversion_op_fn(&self) -> impl Fn(i32) -> f32 + Sync {
self.op_fn()
}
}
impl HasConversionOp<f32, i32> for FpToFxp {
fn conversion_op_fn(&self) -> impl Fn(f32) -> i32 + Sync {
self.op_fn()
}
}
impl IntraSliceReduceOpI32 {
pub(crate) fn reduce_fn(&self) -> fn(i32, i32) -> i32 {
match self {
Self::AddSat => |a, b| a.saturating_add(b),
Self::Max => |a, b| a.max(b),
Self::Min => |a, b| a.min(b),
}
}
pub(crate) fn identity(&self) -> i32 {
match self {
Self::AddSat => 0,
Self::Max => i32::MIN,
Self::Min => i32::MAX,
}
}
}
impl IntraSliceReduceOpF32 {
pub(crate) fn reduce_fn(&self) -> fn(f32, f32) -> f32 {
match self {
Self::Add => |a, b| a + b,
Self::Max => |a, b| a.max(b),
Self::Min => |a, b| a.min(b),
}
}
pub(crate) fn identity(&self) -> f32 {
match self {
Self::Add => 0.0,
Self::Max => f32::NEG_INFINITY,
Self::Min => f32::INFINITY,
}
}
}
impl InterSliceReduceOpI32 {
pub(crate) fn reduce_fn(&self) -> fn(i32, i32) -> i32 {
match self {
Self::Add => |a, b| a.wrapping_add(b),
Self::AddSat => |a, b| a.saturating_add(b),
Self::Max => |a, b| a.max(b),
Self::Min => |a, b| a.min(b),
}
}
pub(crate) fn identity(&self) -> i32 {
match self {
Self::Add | Self::AddSat => 0,
Self::Max => i32::MIN,
Self::Min => i32::MAX,
}
}
}
impl InterSliceReduceOpF32 {
pub(crate) fn reduce_fn(&self) -> fn(f32, f32) -> f32 {
match self {
Self::Add => |a, b| a + b,
Self::Max => |a, b| a.max(b),
Self::Min => |a, b| a.min(b),
Self::Mul => |a, b| a * b,
}
}
pub(crate) fn identity(&self) -> f32 {
match self {
Self::Add => 0.0,
Self::Max => f32::NEG_INFINITY,
Self::Min => f32::INFINITY,
Self::Mul => 1.0,
}
}
}
impl FpDivBinaryOp {
pub fn op_fn(&self) -> fn(f32, f32) -> f32 {
match self {
Self::DivF => |a, b| a / b,
}
}
}
pub trait HasUnaryOp<D>: Clone + Copy {
fn unary_op_fn(self) -> impl Fn(D) -> D + Sync;
}
pub trait HasBinaryOp<D>: Clone + Copy {
fn binary_op_fn(self, mode: Option<BinaryArgMode>) -> impl Fn(D, D) -> D + Sync;
}
pub trait HasTernaryOp<D>: Clone + Copy {
fn ternary_op_fn(self, mode: Option<TernaryArgMode>) -> impl Fn(D, D, D) -> D + Sync;
}
impl HasBinaryOp<i32> for LogicBinaryOpI32 {
fn binary_op_fn(self, mode: Option<BinaryArgMode>) -> impl Fn(i32, i32) -> i32 + Sync {
mode.unwrap_or(BinaryArgMode::Mode01).apply(self.op_fn())
}
}
impl HasBinaryOp<f32> for LogicBinaryOpF32 {
fn binary_op_fn(self, mode: Option<BinaryArgMode>) -> impl Fn(f32, f32) -> f32 + Sync {
mode.unwrap_or(BinaryArgMode::Mode01).apply(self.op_fn())
}
}
impl HasBinaryOp<i32> for FxpBinaryOp {
fn binary_op_fn(self, mode: Option<BinaryArgMode>) -> impl Fn(i32, i32) -> i32 + Sync {
mode.unwrap_or(BinaryArgMode::Mode01).apply(self.op_fn())
}
}
impl HasUnaryOp<f32> for FpUnaryOp {
fn unary_op_fn(self) -> impl Fn(f32) -> f32 + Sync {
self.op_fn()
}
}
impl HasBinaryOp<f32> for FpBinaryOp {
fn binary_op_fn(self, mode: Option<BinaryArgMode>) -> impl Fn(f32, f32) -> f32 + Sync {
mode.unwrap_or(BinaryArgMode::Mode01).apply(self.op_fn())
}
}
impl HasTernaryOp<f32> for FpTernaryOp {
fn ternary_op_fn(self, mode: Option<TernaryArgMode>) -> impl Fn(f32, f32, f32) -> f32 + Sync {
mode.unwrap_or(TernaryArgMode::Mode012).apply(self.op_fn())
}
}
impl HasBinaryOp<f32> for FpDivBinaryOp {
fn binary_op_fn(self, mode: Option<BinaryArgMode>) -> impl Fn(f32, f32) -> f32 + Sync {
mode.unwrap_or(BinaryArgMode::Mode01).apply(self.op_fn())
}
}
impl HasBinaryOp<i32> for ClipBinaryOpI32 {
fn binary_op_fn(self, mode: Option<BinaryArgMode>) -> impl Fn(i32, i32) -> i32 + Sync {
mode.unwrap_or(BinaryArgMode::Mode01).apply(self.op_fn())
}
}
impl HasBinaryOp<f32> for ClipBinaryOpF32 {
fn binary_op_fn(self, mode: Option<BinaryArgMode>) -> impl Fn(f32, f32) -> f32 + Sync {
mode.unwrap_or(BinaryArgMode::Mode01).apply(self.op_fn())
}
}