use super::{PassDesc, Preserved};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FusionGroup {
pub start: usize,
pub len: usize,
pub preserved: Preserved,
pub is_barrier: bool,
}
impl FusionGroup {
#[inline]
#[must_use]
pub const fn end(&self) -> usize {
self.start + self.len
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Pipeline {
pub stage: &'static str,
pub passes: &'static [PassDesc],
}
impl Pipeline {
#[inline]
#[must_use]
pub const fn new(stage: &'static str, passes: &'static [PassDesc]) -> Self {
Self { stage, passes }
}
#[must_use]
pub const fn group_count(&self) -> usize {
let mut groups = 0;
let mut rest = self.passes;
let mut previous_was_barrier = true;
while let [pass, tail @ ..] = rest {
let barrier = !pass.fusability.is_fusable();
if barrier || previous_was_barrier {
groups += 1;
}
previous_was_barrier = barrier;
rest = tail;
}
groups
}
#[must_use]
pub const fn group(&self, index: usize) -> Option<FusionGroup> {
let mut seen = 0;
let mut start = 0;
while let Some((_, [first, ..])) = self.passes.split_at_checked(start) {
let len = self.group_len_at(start);
if seen == index {
return Some(FusionGroup {
start,
len,
preserved: self.preserved_from(start, len),
is_barrier: !first.fusability.is_fusable(),
});
}
seen += 1;
start += len;
}
None
}
const fn group_len_at(&self, start: usize) -> usize {
let Some((_, [first, rest @ ..])) = self.passes.split_at_checked(start) else {
return 1;
};
if !first.fusability.is_fusable() {
return 1;
}
let mut len = 1;
let mut tail = rest;
while let [pass, more @ ..] = tail {
if !pass.fusability.is_fusable() {
break;
}
len += 1;
tail = more;
}
len
}
const fn preserved_from(&self, start: usize, len: usize) -> Preserved {
let Some((_, from)) = self.passes.split_at_checked(start) else {
return Preserved::NONE;
};
let group = match from.split_at_checked(len) {
Some((group, _)) => group,
None => from,
};
let [first, rest @ ..] = group else {
return Preserved::NONE;
};
let mut preserved = first.preserved;
let mut tail = rest;
while let [pass, more @ ..] = tail {
preserved = preserved.intersect(pass.preserved);
tail = more;
}
preserved
}
#[must_use]
pub const fn group_of_pass(&self, index: usize) -> Option<usize> {
if index >= self.passes.len() {
return None;
}
let mut group = 0;
let mut start = 0;
while start < self.passes.len() {
let len = self.group_len_at(start);
if index < start + len {
return Some(group);
}
group += 1;
start += len;
}
None
}
#[must_use]
pub const fn is_fully_serialized(&self) -> bool {
self.group_count() == self.passes.len()
}
}
impl Pipeline {
pub fn groups(&self) -> impl Iterator<Item = FusionGroup> + '_ {
let count = self.group_count();
(0..count).filter_map(move |index| self.group(index))
}
#[must_use]
pub fn passes_of(&self, group: FusionGroup) -> &'static [PassDesc] {
self.passes
.get(group.start..group.end())
.unwrap_or_default()
}
}