use furiosa_mapping::M;
use crate::scalar::Scalar;
pub(crate) use furiosa_opt_lower::{
BITS_PER_BYTE, FETCH_VALID_CLUSTER_SIZES as CLUSTER_SIZES, FETCH_VALID_SLICE_SIZES as SLICE_SIZES, FLIT_BYTES,
VRF_BYTES,
};
pub(crate) const PACKET_ALIGN_BYTES: usize = 8;
pub(crate) fn assert_cluster_size<Cluster: M>() {
const {
let mut i = 0;
let mut ok = false;
while i < CLUSTER_SIZES.len() {
ok |= CLUSTER_SIZES[i] == Cluster::SIZE;
i += 1;
}
assert!(ok, "Cluster::SIZE must be 1 or 2");
};
}
pub(crate) fn assert_slice_size<Slice: M>() {
const {
let mut i = 0;
let mut ok = false;
while i < SLICE_SIZES.len() {
ok |= SLICE_SIZES[i] == Slice::SIZE;
i += 1;
}
assert!(ok, "Slice::SIZE must be 64, 128, or 256");
};
}
pub(crate) fn assert_packet_aligned_by_access_width<D: Scalar, Packet: M>() {
const {
assert!(
size_in_bytes(D::BITS, Packet::SIZE).is_multiple_of(PACKET_ALIGN_BYTES),
"Packet size must be 8-byte aligned"
);
};
}
pub(crate) fn assert_packet_aligned_by_access_width_max_flit<D: Scalar, Packet: M>() {
const {
let bytes = size_in_bytes(D::BITS, Packet::SIZE);
assert!(
bytes != 0 && bytes.is_multiple_of(PACKET_ALIGN_BYTES) && bytes <= FLIT_BYTES,
"Packet size must be 8, 16, 24, or 32 bytes"
);
};
}
pub(crate) fn assert_packet_one_flit<D: Scalar, Packet: M>() {
const {
assert!(
size_in_bytes(D::BITS, Packet::SIZE) == FLIT_BYTES,
"Packet size must be exactly one flit (32 bytes)"
);
};
}
pub(crate) fn assert_packet_one_or_two_flit<D: Scalar, Packet: M>() {
const {
let bytes = size_in_bytes(D::BITS, Packet::SIZE);
assert!(
bytes == FLIT_BYTES || bytes == 2 * FLIT_BYTES,
"Packet size must be one or two flits (32 or 64 bytes)"
);
};
}
pub(crate) fn assert_vrf_capacity<D: Scalar, Element: M>() {
const {
assert!(
size_in_bytes(D::BITS, Element::SIZE) <= VRF_BYTES,
"VRF data must fit the vector register file (8192 bytes per slice)"
);
};
}
pub(crate) fn assert_dm_to_dm_dimension_preserved<Chip: M, Chip2: M, Cluster: M, Cluster2: M, Slice: M, Slice2: M>() {
assert_chip_preserved::<Chip, Chip2>();
assert_cluster_preserved::<Cluster, Cluster2>();
assert_slice_preserved::<Slice, Slice2>();
}
pub(crate) fn assert_reshape_dimension_preserved<
Chip: M,
Chip2: M,
Cluster: M,
Cluster2: M,
Slice: M,
Slice2: M,
Element: M,
Element2: M,
>() {
assert_chip_preserved::<Chip, Chip2>();
assert_cluster_preserved::<Cluster, Cluster2>();
assert_slice_preserved::<Slice, Slice2>();
assert_element_preserved::<Element, Element2>();
}
pub(crate) fn assert_hbm_reshape_dimension_preserved<Chip: M, Chip2: M, Element: M, Element2: M>() {
assert_chip_preserved::<Chip, Chip2>();
assert_element_preserved::<Element, Element2>();
}
pub(crate) fn assert_lift_factor<Placement: M, Time: M, OutTime: M>() {
const {
assert!(OutTime::SIZE != 0, "a lift's output `Time` must not be empty");
};
const {
if OutTime::SIZE != 0 {
assert!(
Time::SIZE.is_multiple_of(OutTime::SIZE),
"a lift's output `Time` must divide its input `Time`"
);
}
};
const {
if OutTime::SIZE != 0 && Time::SIZE.is_multiple_of(OutTime::SIZE) {
let lifted = Time::SIZE / OutTime::SIZE;
assert!(
lifted == 1 || lifted.is_power_of_two(),
"a lift fills broadcasts of the dimension, so the axes it takes out of `Time` must multiply \
to a power of two"
);
}
};
const {
if OutTime::SIZE != 0 && Time::SIZE.is_multiple_of(OutTime::SIZE) {
let lifted = Time::SIZE / OutTime::SIZE;
assert!(
Placement::SIZE.is_multiple_of(lifted),
"a lift fills broadcasts of the dimension, so the axes it takes out of `Time` must divide \
the dimension's size"
);
}
};
}
pub(crate) fn assert_chip_preserved<Chip: M, Chip2: M>() {
const { assert!(Chip::SIZE == Chip2::SIZE, "Chip size must be preserved") };
}
pub(crate) fn assert_cluster_preserved<Cluster: M, Cluster2: M>() {
const { assert!(Cluster::SIZE == Cluster2::SIZE, "Cluster size must be preserved") };
}
pub(crate) fn assert_slice_preserved<Slice: M, Slice2: M>() {
const { assert!(Slice::SIZE == Slice2::SIZE, "Slice size must be preserved") };
}
fn assert_element_preserved<Element: M, Element2: M>() {
const { assert!(Element::SIZE == Element2::SIZE, "Element size must be preserved") };
}
pub(crate) const fn size_in_bytes(bits: usize, length: usize) -> usize {
assert!(
(length * bits).is_multiple_of(BITS_PER_BYTE),
"total bits must be byte-aligned"
);
(length * bits) / BITS_PER_BYTE
}