use sva_samples::{Extent, NodeRenderer, Slot};
use super::lowered_node::leaves;
use super::segments::Segments;
use super::value::{Kind, MachineRun, Value};
use super::values::Values;
#[derive(Clone, Debug, Default)]
pub(crate) struct Need {
pub(crate) hold: Segments,
pub(crate) compute: Segments,
pub(crate) restart: bool,
}
pub(crate) type Held<'h> = &'h dyn Fn(usize, &Value) -> (Segments, Option<i64>);
pub(crate) fn as_held(_: usize, value: &Value) -> (Segments, Option<i64>) {
(value.holding(), value.end())
}
pub(crate) fn demand(values: &Values, asked: &[(usize, Extent)]) -> Vec<Need> {
asking(values, asked, false, &as_held)
}
pub(crate) fn planned(values: &Values, asked: &[(usize, Extent)], held: Held) -> Vec<Need> {
asking(values, asked, true, held)
}
fn asking(values: &Values, asked: &[(usize, Extent)], laid: bool, held: Held) -> Vec<Need> {
let mut holds = vec![Segments::default(); values.span()];
for (v, asked_range) in asked {
holds[*v].add(*asked_range);
}
let mut needs = vec![Need::default(); values.span()];
for v in values.ordered().rev() {
let value = &values[v];
let mut hold = holds[v].intersect(value.support());
if let Some(period) = value.period {
hold = hold.folded(period);
}
let (holding, end) = held(v, value);
let (compute, restart) = match &value.kind {
Kind::MachineRun(machine_run) if machine_run.stateful() => {
stateful(machine_run, &hold, (&holding, end))
}
Kind::Frames { .. } | Kind::Istft => whole(value, &hold, &holding),
Kind::Resident(_) if laid => (hold.minus(&holding).minus(&value.covers()), false),
_ => (hold.minus(&holding), false),
};
match &value.kind {
Kind::MachineRun(machine_run) => {
for segment in compute.iter() {
for (slot, image) in images(machine_run, segment).into_iter().enumerate() {
holds[value.reads[slot]].union(&image);
}
}
}
Kind::Resident { .. } => {
for read in &value.reads {
holds[*read].union(&compute);
}
}
Kind::Frames { .. } | Kind::Istft if !compute.is_empty() => {
let source = value.reads[0];
holds[source].add(values[source].support());
}
_ => {}
}
needs[v] = Need {
hold,
compute,
restart,
};
}
needs
}
pub(crate) fn reach(values: &Values, asked: &[(usize, Extent)]) -> Vec<Segments> {
let mut reach = vec![Segments::default(); values.span()];
for (v, asked_range) in asked {
reach[*v].add(*asked_range);
}
for v in values.ordered().rev() {
let value = &values[v];
let held = reach[v].intersect(value.support());
match &value.kind {
Kind::MachineRun(machine_run) => {
for segment in held.iter() {
for (slot, image) in images(machine_run, segment).into_iter().enumerate() {
reach[value.reads[slot]].union(&image);
}
}
}
Kind::Resident { .. } => {
for read in &value.reads {
reach[*read].union(&held);
}
}
_ => {}
}
reach[v] = held;
}
reach
}
fn stateful(
machine_run: &MachineRun,
hold: &Segments,
(holding, end): (&Segments, Option<i64>),
) -> (Segments, bool) {
if hold.is_empty() {
return (Segments::default(), false);
}
let first = hold.hull().start;
let start = machine_run
.start
.expect("a stateful machine run")
.min(first);
let last = hold.hull().end;
let (from, restart) = match end {
None => (start, true),
Some(end) => {
let before = hold.intersect(Extent::new(i64::MIN, end));
match holding.covers(&before) {
true => (end, false),
false => (start, true),
}
}
};
match from < last {
true => (Segments::of(Extent::new(from, last)), restart),
false => (Segments::default(), false),
}
}
fn whole(value: &Value, hold: &Segments, holding: &Segments) -> (Segments, bool) {
debug_assert!(value.support().is_bounded(), "a whole value's support ends");
match hold.is_empty() || !holding.is_empty() {
true => (Segments::default(), false),
false => (Segments::of(value.support()), false),
}
}
pub(crate) fn images(machine_run: &MachineRun, over: Extent) -> Vec<Segments> {
let mut out = vec![Segments::default(); machine_run.layout.read_widths.len()];
for span in machine_run.spanned.spans() {
let met = over.intersect(Extent::new(span.from, span.to));
if met.is_empty() {
continue;
}
leaves(&span.renderer, &mut |leaf| match leaf {
NodeRenderer::Read {
slot: Slot::Read(at),
map,
} => out[at.0 as usize].add(map.image(met)),
NodeRenderer::Indexed {
slot: Slot::Read(at),
reach,
..
} => {
let (least, most) = reach.unwrap_or((i64::MIN, i64::MAX));
let from = met.start.saturating_add(least);
let to = met.end.saturating_add(most).max(from);
out[at.0 as usize].add(Extent::new(from, to));
}
_ => {}
});
}
out
}