use std::{
any::TypeId,
fmt,
hash::Hash,
marker::{PhantomData, PhantomPinned},
ops::{Deref, Index},
};
use crate::compiler::compiled_code::Symbol;
use super::{op::Const, ty::*, Graph, OpCode};
#[derive(Clone, Copy, Hash, Debug)]
pub struct NodeId<T: AnyTy = Top> {
pub(super) index: usize,
pub(super) _p: PhantomData<T>,
}
impl<T: AnyTy> From<usize> for NodeId<T> {
fn from(value: usize) -> Self {
Self {
index: value,
_p: PhantomData,
}
}
}
impl<T: AnyTy> NodeId<T> {
pub fn index(&self) -> usize {
self.index
}
}
impl<T: AnyTy> NodeId<T> {
pub fn cast<U: AnyTy>(&self) -> NodeId<U> {
debug_assert!(T::TYPE == U::TYPE || T::TYPE == Top::TYPE || U::TYPE == Top::TYPE);
if U::TYPE != Top::TYPE {
}
NodeId {
index: self.index,
_p: PhantomData,
}
}
}
impl<T: AnyTy> PartialEq for NodeId<T> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl<T: AnyTy> Eq for NodeId<T> {}
unsafe impl<T: AnyTy> Send for NodeId<T> {}
unsafe impl<T: AnyTy> Sync for NodeId<T> {}
pub struct NodeData {
pub node: NodeId,
pub cfg_id: usize,
pub ty: Type,
op: usize,
pub(super) op_name: &'static str,
op_type: TypeId,
pub inputs: Vec<NodeId>,
pub controls: Vec<NodeId<()>>,
pub effects: Vec<NodeId>,
pub literal: Option<Literal>,
pub uses: Vec<Use>,
pub control_uses: Vec<Use>,
pub effect_uses: Vec<Use>,
pub mark: usize,
pub dead: bool,
pub(crate) block: Option<usize>,
pub(crate) fixed_reg: Option<usize>,
pub(crate) stack_arg_index: Option<usize>,
pub(crate) interval: usize,
pub(crate) temp_reg: Option<u8>,
pub(crate) move_node_before: Option<NodeId>,
pub(crate) move_node_after: Option<NodeId>,
pub(crate) never_binded: bool,
pub(crate) has_call_indirect_ctx: bool,
_pin: PhantomPinned,
}
impl NodeData {
pub(super) fn new<Op: OpCode>(id: NodeId, ty: Type, op: Op) -> Self {
Self {
node: id,
cfg_id: id.index(),
ty,
op: op.into(),
op_name: op.name(),
op_type: std::any::TypeId::of::<Op>(),
inputs: Default::default(),
controls: Default::default(),
effects: Default::default(),
uses: vec![],
control_uses: vec![],
effect_uses: vec![],
literal: None,
mark: 0,
dead: false,
block: None,
fixed_reg: None,
stack_arg_index: None,
interval: usize::MAX,
temp_reg: None,
move_node_after: None,
move_node_before: None,
never_binded: true,
has_call_indirect_ctx: false,
_pin: PhantomPinned,
}
}
#[inline(always)]
pub fn op<Op: OpCode>(&self) -> Op {
debug_assert_eq!(self.op_type, std::any::TypeId::of::<Op>());
Op::from(self.op)
}
#[inline(always)]
pub fn has_output<Op: OpCode>(&self) -> bool {
debug_assert_eq!(self.op_type, std::any::TypeId::of::<Op>());
self.op::<Op>().has_output()
}
}
#[derive(Debug, Clone)]
pub enum Literal {
Value(Const),
Func(Symbol),
ParamIndex(usize),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum InputKind {
Data,
Control,
Effect,
}
pub struct Inputs<T: AnyTy = Top> {
owner: NodeId,
nodes: Vec<NodeId<T>>,
#[allow(unused)]
kind: InputKind,
}
impl<T: AnyTy> Inputs<T> {
pub fn set(&mut self, g: &mut Graph, index: usize, node: NodeId<T>, remove_stale_uses: bool) {
let use_edge = Use {
user: self.owner,
input: index,
};
if remove_stale_uses {
let remove_user = |uses: &mut Vec<Use>| {
uses.retain(|u| u != &use_edge);
};
match self.kind {
InputKind::Data => remove_user(&mut g[self.nodes[index]].uses),
InputKind::Control => remove_user(&mut g[self.nodes[index]].control_uses),
InputKind::Effect => remove_user(&mut g[self.nodes[index]].effect_uses),
}
}
self.nodes[index] = node;
let add_user = |uses: &mut Vec<Use>| {
uses.push(use_edge);
};
match self.kind {
InputKind::Data => add_user(&mut g[node].uses),
InputKind::Control => add_user(&mut g[node].control_uses),
InputKind::Effect => add_user(&mut g[node].effect_uses),
}
}
pub fn push(&mut self, g: &mut Graph, node: NodeId<T>) {
let input = self.nodes.len();
self.nodes.push(node);
let user = self.owner;
match self.kind {
InputKind::Data => g[node].uses.push(Use { user, input }),
InputKind::Control => g[node].control_uses.push(Use { user, input }),
InputKind::Effect => g[node].effect_uses.push(Use { user, input }),
}
}
}
impl<T: AnyTy> Index<usize> for Inputs<T> {
type Output = NodeId<T>;
fn index(&self, index: usize) -> &Self::Output {
&self.nodes[index]
}
}
impl<T: AnyTy> Deref for Inputs<T> {
type Target = [NodeId<T>];
fn deref(&self) -> &Self::Target {
&self.nodes
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Use {
pub(crate) user: NodeId,
pub(crate) input: usize,
}
impl Use {
pub fn user(&self) -> NodeId {
self.user
}
pub fn input(&self) -> usize {
self.input
}
}
impl fmt::Debug for NodeData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[%{}] {} {:?}", self.node.index, self.op_name, self.ty)?;
if let Some(literal) = self.literal.as_ref() {
write!(f, " <{:?}>", literal)?;
}
let n = self.controls.len();
if n != 0 {
write!(f, " ctrl=[")?;
for i in 0..n {
if i != 0 {
write!(f, ", ")?
}
write!(f, "%{}", self.controls[i].index)?;
}
write!(f, "]")?;
}
let n = self.inputs.len();
if n != 0 {
write!(f, " inputs=[")?;
for i in 0..n {
if i != 0 {
write!(f, ", ")?
}
write!(f, "%{}", self.inputs[i].index)?;
}
write!(f, "]")?;
}
let n = self.effects.len();
if n != 0 {
write!(f, " effect=[")?;
for i in 0..n {
if i != 0 {
write!(f, ", ")?
}
write!(f, "%{}", self.effects[i].index)?;
}
write!(f, "]")?;
}
const OUTPUT_USERS: bool = true;
if OUTPUT_USERS && self.uses.len() != 0 {
write!(f, " uses=[")?;
for i in 0..self.uses.len() {
if i != 0 {
write!(f, ", ")?
}
write!(f, "%{}:{}", self.uses[i].user.index, self.uses[i].input)?;
}
write!(f, "]")?;
}
write!(f, "")
}
}