#[cfg(target_arch = "spirv")]
use core::arch::asm;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum MatrixUse {
MatrixA = 0,
MatrixB = 1,
MatrixAccumulator = 2,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum MatrixLayout {
RowMajor = 0,
ColumnMajor = 1,
}
pub const MATRIX_A: u32 = MatrixUse::MatrixA as u32;
pub const MATRIX_B: u32 = MatrixUse::MatrixB as u32;
pub const MATRIX_ACCUMULATOR: u32 = MatrixUse::MatrixAccumulator as u32;
pub const ROW_MAJOR: MatrixLayout = MatrixLayout::RowMajor;
pub const COLUMN_MAJOR: MatrixLayout = MatrixLayout::ColumnMajor;
#[spirv(cooperative_matrix)]
#[derive(Copy, Clone)]
#[repr(C)]
pub struct CooperativeMatrix<T, const USE: u32, const ROWS: u32, const COLS: u32> {
_anti_zst_padding: MaybeUninit<u32>,
_phantom: PhantomData<T>,
}
impl<T, const USE: u32, const ROWS: u32, const COLS: u32> CooperativeMatrix<T, USE, ROWS, COLS> {
#[spirv_std_macros::gpu_only]
#[doc(alias = "OpCooperativeMatrixLoadKHR")]
#[inline]
pub unsafe fn load(slice: &[T], layout: MatrixLayout, stride: u32) -> Self {
unsafe {
let mut result = MaybeUninit::<Self>::uninit();
let layout_u32 = layout as u32;
let ptr = slice.as_ptr();
asm!(
"%u32 = OpTypeInt 32 0",
"%layout = OpLoad %u32 {layout}",
"%stride = OpLoad %u32 {stride}",
"%result = OpCooperativeMatrixLoadKHR typeof* {out} {ptr} %layout %stride",
"OpStore {out} %result",
ptr = in(reg) ptr,
layout = in(reg) &layout_u32,
stride = in(reg) &stride,
out = in(reg) result.as_mut_ptr(),
);
result.assume_init()
}
}
#[spirv_std_macros::gpu_only]
#[doc(alias = "OpCooperativeMatrixStoreKHR")]
#[inline]
pub unsafe fn store(self, slice: &mut [T], layout: MatrixLayout, stride: u32) {
unsafe {
let layout_u32 = layout as u32;
let ptr = slice.as_mut_ptr();
asm!(
"%u32 = OpTypeInt 32 0",
"%layout = OpLoad %u32 {layout}",
"%stride = OpLoad %u32 {stride}",
"%matrix = OpLoad _ {matrix}",
"OpCooperativeMatrixStoreKHR {ptr} %matrix %layout %stride",
ptr = in(reg) ptr,
matrix = in(reg) &self,
layout = in(reg) &layout_u32,
stride = in(reg) &stride,
);
}
}
#[spirv_std_macros::gpu_only]
#[doc(alias = "OpCooperativeMatrixLengthKHR")]
#[inline]
pub fn length(&self) -> u32 {
unsafe {
let mut result: u32 = 0;
asm!(
"%u32 = OpTypeInt 32 0",
"%coop_ty = typeof* {self_ptr}",
"%result = OpCooperativeMatrixLengthKHR %u32 %coop_ty",
"OpStore {out} %result",
self_ptr = in(reg) self,
out = in(reg) &mut result,
);
result
}
}
}
#[spirv_std_macros::gpu_only]
#[doc(alias = "OpCooperativeMatrixMulAddKHR")]
#[inline]
pub fn mul_add<TA, TB, TC, const M: u32, const N: u32, const K: u32>(
a: CooperativeMatrix<TA, { MatrixUse::MatrixA as u32 }, M, K>,
b: CooperativeMatrix<TB, { MatrixUse::MatrixB as u32 }, K, N>,
c: CooperativeMatrix<TC, { MatrixUse::MatrixAccumulator as u32 }, M, N>,
) -> CooperativeMatrix<TC, { MatrixUse::MatrixAccumulator as u32 }, M, N> {
unsafe {
let mut result = MaybeUninit::<
CooperativeMatrix<TC, { MatrixUse::MatrixAccumulator as u32 }, M, N>,
>::uninit();
asm!(
"%a = OpLoad _ {a}",
"%b = OpLoad _ {b}",
"%c = OpLoad _ {c}",
"%result = OpCooperativeMatrixMulAddKHR _ %a %b %c",
"OpStore {out} %result",
a = in(reg) &a,
b = in(reg) &b,
c = in(reg) &c,
out = in(reg) result.as_mut_ptr(),
);
result.assume_init()
}
}