use std::collections::HashMap;
use crate::tensor::backend::Backend;
use crate::tensor::graph::NodeKind;
use crate::tensor::ops::def_op::OpKind;
use crate::tensor::planner::get_id;
#[derive(Copy, Clone, PartialEq)]
pub(crate) enum Tag {
Anything,
AsContiguousCache,
AsContiguous,
}
pub(crate) enum AliasKind<'a, T, B: Backend> {
Alias(&'a NodeKind<T, B>, Tag),
Takeover(&'a NodeKind<T, B>, Tag),
NoAlias,
}
pub(crate) struct AliasMap<'a, T, B: Backend> {
map: HashMap<usize, (&'a NodeKind<T, B>, Tag)>,
}
impl<'a, T, B: Backend> AliasMap<'a, T, B> {
pub fn new() -> Self {
Self {
map: HashMap::with_capacity(32),
}
}
#[inline]
pub fn resolve(&self, node: &'a NodeKind<T, B>) -> &'a NodeKind<T, B> {
let id = get_id(node);
self.map.get(&id).map_or(node, |(node, _)| *node)
}
#[inline]
pub fn insert(&mut self, id: usize, node: &'a NodeKind<T, B>, tag: Tag) {
self.map.insert(id, (node, tag));
}
#[inline]
pub fn takeover(
&mut self,
old_owner: &NodeKind<T, B>,
new_owner: &'a NodeKind<T, B>,
tag: Tag,
) {
let old_owner_id = get_id(old_owner);
for (_, value) in self.map.iter_mut() {
if get_id(value.0) == old_owner_id {
*value = (new_owner, tag);
}
}
let id = get_id(old_owner);
self.map.insert(id, (new_owner, tag));
}
#[inline]
fn get_alias(&self, id: usize) -> Option<(&'a NodeKind<T, B>, Tag)> {
self.map.get(&id).map(|(node, tag)| (*node, *tag))
}
}
#[inline]
fn is_node_op<T: PartialEq, B: Backend>(node: &NodeKind<T, B>, op: &OpKind<T>) -> bool {
match node {
NodeKind::Edge(_) | NodeKind::Slot(_) | NodeKind::Baked(_) => false,
NodeKind::Node(n) => n.op == *op,
NodeKind::Cache(c) => c.get_node().op == *op,
}
}
#[inline]
pub(crate) fn classify<'a, T: PartialEq, B: Backend>(
op: &OpKind<T>,
inputs: &'a [NodeKind<T, B>],
alias_map: &AliasMap<'a, T, B>,
) -> AliasKind<'a, T, B> {
match op {
OpKind::AsContiguous => {
if let NodeKind::Cache(_) = &inputs[0] {
return AliasKind::Alias(&inputs[0], Tag::AsContiguous);
}
let id = get_id(&inputs[0]);
if let Some((_, tag)) = alias_map.get_alias(id) {
if tag == Tag::AsContiguous || tag == Tag::AsContiguousCache {
AliasKind::Alias(alias_map.resolve(&inputs[0]), Tag::AsContiguous)
} else {
AliasKind::Takeover(alias_map.resolve(&inputs[0]), Tag::AsContiguous)
}
}
else if is_node_op(&inputs[0], op) {
AliasKind::Alias(&inputs[0], Tag::AsContiguous)
} else {
AliasKind::Takeover(&inputs[0], Tag::AsContiguous)
}
}
OpKind::NoOp => AliasKind::Alias(alias_map.resolve(&inputs[0]), Tag::Anything),
_ => AliasKind::NoAlias,
}
}
#[inline]
pub(crate) fn classify_cache<'a, T: PartialEq, B: Backend>(
inputs: &'a [NodeKind<T, B>],
alias_map: &AliasMap<'a, T, B>,
) -> AliasKind<'a, T, B> {
let id = get_id(&inputs[0]);
if let Some((owner, tag)) = alias_map.get_alias(id) {
if tag == Tag::AsContiguousCache {
AliasKind::Alias(owner, Tag::AsContiguousCache)
} else {
AliasKind::Takeover(owner, Tag::AsContiguousCache)
}
} else {
AliasKind::Takeover(&inputs[0], Tag::AsContiguousCache)
}
}