use cubecl_core as cubecl;
use cubecl_core::prelude::*;
use cubecl_std::tensor::layout::Coords2d;
use crate::components::batch::partitioned_matmul::hypercube::base::CubeSpan;
#[derive(Default, Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[allow(clippy::enum_variant_names)]
pub enum GlobalOrder {
#[default]
RowMajor,
ColMajor,
SwizzleRowMajor(u32),
SwizzleColMajor(u32),
}
impl GlobalOrder {
pub fn canonicalize(self) -> Self {
match self {
GlobalOrder::SwizzleColMajor(1) => GlobalOrder::ColMajor,
GlobalOrder::SwizzleRowMajor(1) => GlobalOrder::RowMajor,
_ => self,
}
}
}
#[derive(Default)]
#[allow(unused)]
pub enum GlobalOrderSelection {
#[default]
Default,
Fixed(GlobalOrder),
SwizzleRow { m: u32, w: u32 },
SwizzleCol { n: u32, w: u32 },
}
impl GlobalOrderSelection {
pub fn into_order(self, span: &CubeSpan) -> GlobalOrder {
match self {
GlobalOrderSelection::Default => GlobalOrder::default(),
GlobalOrderSelection::Fixed(order) => order,
GlobalOrderSelection::SwizzleRow { m, w } => {
let m_cubes = m.div_ceil(span.m);
if m_cubes % w != 0 {
GlobalOrder::RowMajor
} else {
GlobalOrder::SwizzleRowMajor(w)
}
}
GlobalOrderSelection::SwizzleCol { n, w } => {
let n_cubes = n.div_ceil(span.n);
if n_cubes % w != 0 {
GlobalOrder::RowMajor
} else {
GlobalOrder::SwizzleRowMajor(w)
}
}
}
.canonicalize()
}
}
#[cube]
pub fn swizzle(index: u32, num_steps: u32, #[comptime] step_length: u32) -> Coords2d {
comptime!(assert!(step_length > 0));
let num_elements_per_strip = num_steps * step_length;
let strip_index = index / num_elements_per_strip;
let pos_in_strip = index % num_elements_per_strip;
let strip_offset = step_length * strip_index;
let abs_step_index = pos_in_strip / step_length;
let abs_pos_in_step = pos_in_strip % step_length;
let strip_direction = strip_index % 2;
let step_direction = abs_step_index % 2;
let step_index =
strip_direction * (num_steps - abs_step_index - 1) + (1 - strip_direction) * abs_step_index;
let pos_in_step = if comptime!(step_length & (step_length - 1) == 0) {
abs_pos_in_step ^ (step_direction * (step_length - 1))
} else {
step_direction * (step_length - abs_pos_in_step - 1)
+ (1 - step_direction) * abs_pos_in_step
};
(step_index, pos_in_step + strip_offset)
}