use furiosa_mapping::*;
use furiosa_opt_macro::primitive;
use std::marker::PhantomData;
use crate::backend::Backend;
use crate::constraints;
use crate::context::*;
use crate::engine::vector::scalar::VeScalar;
use crate::engine::{CanApplyCollect, CanApplyToTrf, CanApplyToVrf};
use crate::runtime::CurrentBackend;
use crate::scalar::*;
use crate::tensor::Tensor;
use crate::tensor::memory::{Address, TrfAddress, TrfTensor, VrfTensor};
use crate::tensor::tu::{Position, TuTensor};
#[derive(Debug)]
pub struct PositionCollect;
impl Position for PositionCollect {}
pub type CollectTensor<'l, const T: Tu, D, Chip, Cluster, Slice, Time, Packet, B = CurrentBackend> =
TuTensor<'l, { T }, PositionCollect, D, Chip, Cluster, Slice, Time, Packet, B>;
impl<'l, const T: Tu, D: Scalar, Chip: M, Cluster: M, Slice: M, Time: M, Packet: M, B: Backend>
CollectTensor<'l, T, D, Chip, Cluster, Slice, Time, Packet, B>
{
fn check_constraints() {
constraints::assert_cluster_size::<Cluster>();
constraints::assert_slice_size::<Slice>();
constraints::assert_packet_one_flit::<D, Packet>();
}
#[doc(hidden)]
pub fn new(ctx: &'l mut TuContext<{ T }>, inner: Tensor<D, Self::Mapping, B>) -> Self {
Self::check_constraints();
Self {
ctx,
inner,
_position: PhantomData,
}
}
}
impl<'l, const T: Tu, P: CanApplyCollect, D: Scalar, Chip: M, Cluster: M, Slice: M, Time: M, Packet: M, B: Backend>
TuTensor<'l, T, P, D, Chip, Cluster, Slice, Time, Packet, B>
{
#[primitive(TuTensor::collect)]
pub fn collect<Time2: M, Packet2: M>(self) -> CollectTensor<'l, T, D, Chip, Cluster, Slice, Time2, Packet2, B> {
verify_collect::<D, Time, Packet, Time2, Packet2>();
CollectTensor::new(self.ctx, self.inner.transpose(false))
}
}
impl<'l, const T: Tu, P: CanApplyToTrf, D: Scalar, Chip: M, Cluster: M, Slice: M, Time: M, Packet: M, B: Backend>
TuTensor<'l, T, P, D, Chip, Cluster, Slice, Time, Packet, B>
{
#[primitive(TuTensor::to_trf)]
pub fn to_trf<Lane: M, Element: M>(self) -> TrfTensor<D, Chip, Cluster, Slice, Lane, Element, B> {
verify_to_trf::<D, Lane, Time, Packet, Element>(&TrfAddress::Full);
TrfTensor::new(self.inner.transpose(false), None)
}
#[primitive(TuTensor::to_trf_at)]
pub fn to_trf_at<Lane: M, Element: M>(
self,
address: TrfAddress,
) -> TrfTensor<D, Chip, Cluster, Slice, Lane, Element, B> {
verify_to_trf::<D, Lane, Time, Packet, Element>(&address);
TrfTensor::new(self.inner.transpose(false), Some(address))
}
}
impl<'l, const T: Tu, P: CanApplyToVrf, D: VeScalar, Chip: M, Cluster: M, Slice: M, Time: M, Packet: M, B: Backend>
TuTensor<'l, T, P, D, Chip, Cluster, Slice, Time, Packet, B>
{
#[primitive(TuTensor::to_vrf)]
pub fn to_vrf<Element: M>(self) -> VrfTensor<D, Chip, Cluster, Slice, Element, B> {
VrfTensor::new(self.inner.transpose(false), None)
}
#[primitive(TuTensor::to_vrf_at)]
pub fn to_vrf_at<Element: M>(self, address: Address) -> VrfTensor<D, Chip, Cluster, Slice, Element, B> {
VrfTensor::new(self.inner.transpose(false), Some(address))
}
}
pub(crate) fn verify_collect<D: Scalar, Time: M, Packet: M, Time2: M, Packet2: M>() {
furiosa_opt_lower::config_collect(
&Time::to_value(),
&Packet::to_value(),
&Time2::to_value(),
&Packet2::to_value(),
D::BITS,
)
.unwrap_or_else(|message| panic!("{message}"));
}
pub(crate) fn verify_to_trf<D: Scalar, Lane: M, Time: M, Packet: M, Element: M>(address: &TrfAddress) {
use furiosa_opt_lower::ToTrfError;
furiosa_opt_lower::config_to_trf(
&Lane::to_value(),
&Time::to_value(),
&Packet::to_value(),
&Element::to_value(),
address.capacity(),
D::BITS,
)
.unwrap_or_else(|error| match error {
ToTrfError::ExceedsCapacity {
total_bytes,
lanes,
per_lane_bytes,
capacity,
} => panic!(
"TRF data ({total_bytes} bytes = {lanes} lanes x {per_lane_bytes} bytes) \
exceeds register file capacity ({capacity} bytes for {address})"
),
other => panic!("{other}"),
});
}