#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct NumLanes(usize);
impl NumLanes {
pub const fn new(val: usize) -> Self {
assert!(val >= 1, "NumLanes must be >= 1");
Self(val)
}
#[inline(always)]
pub const fn as_usize(self) -> usize {
self.0
}
}
pub const fn compute_vec_latency(
vl: usize,
num_lanes: usize,
startup_latency: u64,
is_pipelined: bool,
) -> u64 {
if vl == 0 {
return 1;
}
let groups = vl.div_ceil(num_lanes) as u64;
if is_pipelined { startup_latency + groups - 1 } else { groups * startup_latency }
}
pub fn compute_reduction_latency(
vl: usize,
num_lanes: usize,
startup_latency: u64,
is_ordered: bool,
) -> u64 {
if vl == 0 {
return 1;
}
if is_ordered {
vl as u64 * startup_latency
} else {
let intra = vl.div_ceil(num_lanes) as u64;
let inter = if num_lanes > 1 { (num_lanes as f64).log2().ceil() as u64 } else { 0 };
startup_latency + intra + inter
}
}
#[inline]
pub const fn first_group_ready(issue_cycle: u64, startup_latency: u64) -> u64 {
issue_cycle + startup_latency
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pipelined_basic() {
assert_eq!(compute_vec_latency(4, 4, 1, true), 1);
assert_eq!(compute_vec_latency(8, 4, 1, true), 2);
assert_eq!(compute_vec_latency(16, 4, 4, true), 7);
}
#[test]
fn test_non_pipelined() {
assert_eq!(compute_vec_latency(8, 4, 20, false), 40);
assert_eq!(compute_vec_latency(1, 4, 20, false), 20);
}
#[test]
fn test_vl_zero() {
assert_eq!(compute_vec_latency(0, 4, 5, true), 1);
assert_eq!(compute_vec_latency(0, 4, 5, false), 1);
}
#[test]
fn test_partial_lanes() {
assert_eq!(compute_vec_latency(5, 4, 1, true), 2);
assert_eq!(compute_vec_latency(3, 4, 1, true), 1);
}
#[test]
fn test_reduction_unordered() {
assert_eq!(compute_reduction_latency(16, 4, 1, false), 7);
assert_eq!(compute_reduction_latency(8, 1, 1, false), 9);
}
#[test]
fn test_reduction_ordered() {
assert_eq!(compute_reduction_latency(8, 4, 4, true), 32);
assert_eq!(compute_reduction_latency(1, 4, 4, true), 4);
}
#[test]
fn test_reduction_vl_zero() {
assert_eq!(compute_reduction_latency(0, 4, 4, true), 1);
assert_eq!(compute_reduction_latency(0, 4, 4, false), 1);
}
#[test]
fn test_first_group_ready() {
assert_eq!(first_group_ready(10, 4), 14);
assert_eq!(first_group_ready(0, 1), 1);
}
#[test]
fn test_single_lane() {
assert_eq!(compute_vec_latency(8, 1, 3, true), 10);
}
}