use strided_kernel::ExecContext;
use strided_view::ElementOp;
pub trait Backend<T: crate::ScalarBase> {
const MATERIALIZES_CONJ: bool;
const REQUIRES_UNIT_STRIDE: bool;
fn bgemm_contiguous_into(
c: &mut crate::contiguous::ContiguousOperandMut<T>,
a: &crate::contiguous::ContiguousOperand<T>,
b: &crate::contiguous::ContiguousOperand<T>,
batch_dims: &[usize],
m: usize,
n: usize,
k: usize,
alpha: T,
beta: T,
) -> strided_view::Result<()>;
}
#[allow(dead_code)]
pub(crate) trait OverwriteBackend<T: crate::ScalarBase> {
fn bgemm_contiguous_overwrite(
c: &mut crate::contiguous::UninitContiguousOperand<'_, '_, T>,
a: &crate::contiguous::ContiguousOperand<T>,
b: &crate::contiguous::ContiguousOperand<T>,
batch_dims: &[usize],
m: usize,
n: usize,
k: usize,
alpha: T,
ctx: &ExecContext,
) -> strided_view::Result<()>;
}
#[cfg(feature = "faer")]
pub struct FaerBackend;
#[cfg(any(feature = "blas", feature = "blas-inject"))]
pub struct BlasBackend;
#[allow(dead_code)]
pub struct NaiveBackend;
impl<T> Backend<T> for NaiveBackend
where
T: crate::ScalarBase + strided_view::ElementOpApply,
{
const MATERIALIZES_CONJ: bool = false;
const REQUIRES_UNIT_STRIDE: bool = false;
fn bgemm_contiguous_into(
c: &mut crate::contiguous::ContiguousOperandMut<T>,
a: &crate::contiguous::ContiguousOperand<T>,
b: &crate::contiguous::ContiguousOperand<T>,
batch_dims: &[usize],
m: usize,
n: usize,
k: usize,
alpha: T,
beta: T,
) -> strided_view::Result<()> {
let a_ptr = a.ptr();
let b_ptr = b.ptr();
let c_ptr = c.ptr();
let a_rs = a.row_stride();
let a_cs = a.col_stride();
let b_rs = b.row_stride();
let b_cs = b.col_stride();
let c_rs = c.row_stride();
let c_cs = c.col_stride();
let mut batch_iter = crate::util::MultiIndex::new(batch_dims);
while batch_iter.next().is_some() {
let a_base = batch_iter.offset(a.batch_strides());
let b_base = batch_iter.offset(b.batch_strides());
let c_base = batch_iter.offset(c.batch_strides());
for i in 0..m {
for j in 0..n {
let mut acc = T::zero();
for l in 0..k {
let mut a_val = unsafe {
*a_ptr.offset(a_base + i as isize * a_rs + l as isize * a_cs)
};
let mut b_val = unsafe {
*b_ptr.offset(b_base + l as isize * b_rs + j as isize * b_cs)
};
if a.conj() {
a_val = strided_view::Conj::apply(a_val);
}
if b.conj() {
b_val = strided_view::Conj::apply(b_val);
}
acc = acc + a_val * b_val;
}
unsafe {
let c_elem = c_ptr.offset(c_base + i as isize * c_rs + j as isize * c_cs);
if beta == T::zero() {
*c_elem = alpha * acc;
} else {
*c_elem = alpha * acc + beta * (*c_elem);
}
}
}
}
}
Ok(())
}
}
#[cfg(not(any(feature = "blas", feature = "blas-inject")))]
impl<T> OverwriteBackend<T> for NaiveBackend
where
T: crate::ScalarBase + strided_view::ElementOpApply,
{
fn bgemm_contiguous_overwrite(
c: &mut crate::contiguous::UninitContiguousOperand<'_, '_, T>,
a: &crate::contiguous::ContiguousOperand<T>,
b: &crate::contiguous::ContiguousOperand<T>,
batch_dims: &[usize],
m: usize,
n: usize,
k: usize,
alpha: T,
ctx: &ExecContext,
) -> strided_view::Result<()> {
crate::uninit::bgemm_contiguous_naive(c, a, b, batch_dims, m, n, k, alpha, ctx)
}
}
#[cfg(any(
all(feature = "blas", not(feature = "blas-inject")),
all(feature = "blas-inject", not(feature = "blas"))
))]
pub type ActiveBackend = BlasBackend;
#[cfg(all(feature = "faer", not(any(feature = "blas", feature = "blas-inject"))))]
pub type ActiveBackend = FaerBackend;
#[cfg(not(any(feature = "faer", feature = "blas", feature = "blas-inject")))]
pub type ActiveBackend = NaiveBackend;
#[cfg(all(feature = "blas", feature = "blas-inject"))]
pub type ActiveBackend = NaiveBackend;