use core::{any::Any, fmt, hash::Hash, ptr::NonNull};
use midenc_hir::{
Block, BlockArgument, BlockArgumentRef, BlockRef, DynHash, DynPartialEq, FxHashMap, FxHasher,
OpResult, OpResultRef, Operation, OperationRef, ProgramPoint, RawEntityRef, SourceSpan,
Spanned, Value, ValueRef,
};
#[derive(Copy, Clone)]
pub struct LatticeAnchorRef(NonNull<dyn LatticeAnchor>);
impl LatticeAnchorRef {
#[inline]
fn new(raw: NonNull<dyn LatticeAnchor>) -> Self {
Self(raw)
}
fn compute_hash<A>(anchor: &A) -> u64
where
A: ?Sized + LatticeAnchor,
{
use core::hash::Hasher;
let mut hasher = FxHasher::default();
anchor.dyn_hash(&mut hasher);
hasher.finish()
}
pub fn intern<A>(
anchor: &A,
alloc: &blink_alloc::Blink,
interned: &mut FxHashMap<u64, LatticeAnchorRef>,
) -> LatticeAnchorRef
where
A: LatticeAnchorExt,
{
let hash = anchor.anchor_id();
*interned
.entry(hash)
.or_insert_with(|| <A as LatticeAnchorExt>::alloc(anchor, alloc))
}
}
impl core::ops::Deref for LatticeAnchorRef {
type Target = dyn LatticeAnchor;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl core::convert::AsRef<dyn LatticeAnchor> for LatticeAnchorRef {
#[inline(always)]
fn as_ref(&self) -> &dyn LatticeAnchor {
unsafe { self.0.as_ref() }
}
}
impl Eq for LatticeAnchorRef {}
impl PartialEq for LatticeAnchorRef {
fn eq(&self, other: &Self) -> bool {
unsafe { self.0.as_ref().dyn_eq(other.0.as_ref()) }
}
}
impl Hash for LatticeAnchorRef {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
unsafe {
self.0.as_ref().dyn_hash(state);
}
}
}
impl Spanned for LatticeAnchorRef {
fn span(&self) -> SourceSpan {
unsafe { self.0.as_ref().span() }
}
}
impl fmt::Debug for LatticeAnchorRef {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
fmt::Debug::fmt(unsafe { self.0.as_ref() }, f)
}
}
impl fmt::Display for LatticeAnchorRef {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
fmt::Display::fmt(unsafe { self.0.as_ref() }, f)
}
}
pub trait LatticeAnchor:
Any + Spanned + fmt::Debug + fmt::Display + DynPartialEq + DynHash
{
fn is_value(&self) -> bool {
false
}
fn as_value(&self) -> Option<ValueRef> {
None
}
fn is_valid_program_point(&self) -> bool {
false
}
fn as_program_point(&self) -> Option<ProgramPoint> {
None
}
}
impl LatticeAnchor for LatticeAnchorRef {
#[inline]
fn is_value(&self) -> bool {
self.as_ref().is_value()
}
#[inline]
fn as_value(&self) -> Option<ValueRef> {
self.as_ref().as_value()
}
#[inline]
fn is_valid_program_point(&self) -> bool {
self.as_ref().is_valid_program_point()
}
#[inline]
fn as_program_point(&self) -> Option<ProgramPoint> {
self.as_ref().as_program_point()
}
}
impl LatticeAnchor for ProgramPoint {
fn is_valid_program_point(&self) -> bool {
true
}
fn as_program_point(&self) -> Option<ProgramPoint> {
Some(*self)
}
}
impl LatticeAnchor for Operation {
fn is_valid_program_point(&self) -> bool {
true
}
fn as_program_point(&self) -> Option<ProgramPoint> {
Some(ProgramPoint::before(self))
}
}
impl LatticeAnchor for Block {
fn is_valid_program_point(&self) -> bool {
true
}
fn as_program_point(&self) -> Option<ProgramPoint> {
Some(ProgramPoint::at_start_of(self))
}
}
impl LatticeAnchor for BlockArgument {
fn is_value(&self) -> bool {
true
}
fn as_value(&self) -> Option<ValueRef> {
Some(self.as_value_ref())
}
}
impl LatticeAnchor for OpResult {
fn is_value(&self) -> bool {
true
}
fn as_value(&self) -> Option<ValueRef> {
Some(self.as_value_ref())
}
}
impl LatticeAnchor for dyn Value {
fn is_value(&self) -> bool {
true
}
fn as_value(&self) -> Option<ValueRef> {
Some(unsafe { ValueRef::from_raw(self) })
}
}
impl<A: ?Sized + LatticeAnchor, Metadata: 'static> LatticeAnchor for RawEntityRef<A, Metadata> {
default fn is_value(&self) -> bool {
false
}
default fn as_value(&self) -> Option<ValueRef> {
None
}
default fn is_valid_program_point(&self) -> bool {
false
}
default fn as_program_point(&self) -> Option<ProgramPoint> {
None
}
}
impl LatticeAnchor for ValueRef {
fn is_value(&self) -> bool {
true
}
fn as_value(&self) -> Option<ValueRef> {
Some(*self)
}
}
impl LatticeAnchor for BlockArgumentRef {
fn is_value(&self) -> bool {
true
}
fn as_value(&self) -> Option<ValueRef> {
Some(*self)
}
}
impl LatticeAnchor for OpResultRef {
fn is_value(&self) -> bool {
true
}
fn as_value(&self) -> Option<ValueRef> {
Some(*self)
}
}
impl LatticeAnchor for OperationRef {
fn is_valid_program_point(&self) -> bool {
true
}
fn as_program_point(&self) -> Option<ProgramPoint> {
Some(ProgramPoint::before(*self))
}
}
impl LatticeAnchor for BlockRef {
fn is_valid_program_point(&self) -> bool {
true
}
fn as_program_point(&self) -> Option<ProgramPoint> {
Some(ProgramPoint::at_start_of(*self))
}
}
#[doc(hidden)]
pub trait LatticeAnchorExt: sealed::IsLatticeAnchor {
fn anchor_id(&self) -> u64;
fn alloc(&self, alloc: &blink_alloc::Blink) -> LatticeAnchorRef;
}
mod sealed {
use super::LatticeAnchor;
pub trait IsLatticeAnchor: LatticeAnchor {}
impl<A: LatticeAnchor> IsLatticeAnchor for A {}
}
impl<A: LatticeAnchor + Clone> LatticeAnchorExt for A {
default fn anchor_id(&self) -> u64 {
LatticeAnchorRef::compute_hash(self)
}
default fn alloc(&self, alloc: &blink_alloc::Blink) -> LatticeAnchorRef {
let ptr = alloc.put(self.clone());
LatticeAnchorRef::new(unsafe { NonNull::new_unchecked(ptr) })
}
}
impl LatticeAnchorExt for LatticeAnchorRef {
fn anchor_id(&self) -> u64 {
LatticeAnchorRef::compute_hash(self.as_ref())
}
#[inline(always)]
fn alloc(&self, _alloc: &blink_alloc::Blink) -> LatticeAnchorRef {
*self
}
}
impl LatticeAnchorExt for ValueRef {
fn anchor_id(&self) -> u64 {
LatticeAnchorRef::compute_hash(&*self.borrow())
}
fn alloc(&self, _alloc: &blink_alloc::Blink) -> LatticeAnchorRef {
let value = self.borrow();
let ptr = if let Some(result) = value.downcast_ref::<OpResult>() {
result as &dyn LatticeAnchor as *const dyn LatticeAnchor
} else {
let arg = value.downcast_ref::<BlockArgument>().unwrap();
arg as &dyn LatticeAnchor as *const dyn LatticeAnchor
};
LatticeAnchorRef::new(unsafe { NonNull::new_unchecked(ptr.cast_mut()) })
}
}
impl LatticeAnchorExt for BlockArgumentRef {
fn anchor_id(&self) -> u64 {
LatticeAnchorRef::compute_hash(&*self.borrow())
}
fn alloc(&self, _alloc: &blink_alloc::Blink) -> LatticeAnchorRef {
let ptr = &*self.borrow() as &dyn LatticeAnchor as *const dyn LatticeAnchor;
LatticeAnchorRef::new(unsafe { NonNull::new_unchecked(ptr.cast_mut()) })
}
}
impl LatticeAnchorExt for OpResultRef {
fn anchor_id(&self) -> u64 {
LatticeAnchorRef::compute_hash(&*self.borrow())
}
fn alloc(&self, _alloc: &blink_alloc::Blink) -> LatticeAnchorRef {
let ptr = &*self.borrow() as &dyn LatticeAnchor as *const dyn LatticeAnchor;
LatticeAnchorRef::new(unsafe { NonNull::new_unchecked(ptr.cast_mut()) })
}
}
impl LatticeAnchorExt for BlockRef {
fn anchor_id(&self) -> u64 {
LatticeAnchorRef::compute_hash(&*self.borrow())
}
fn alloc(&self, _alloc: &blink_alloc::Blink) -> LatticeAnchorRef {
let ptr = &*self.borrow() as &dyn LatticeAnchor as *const dyn LatticeAnchor;
LatticeAnchorRef::new(unsafe { NonNull::new_unchecked(ptr.cast_mut()) })
}
}
impl LatticeAnchorExt for OperationRef {
fn anchor_id(&self) -> u64 {
LatticeAnchorRef::compute_hash(&*self.borrow())
}
fn alloc(&self, _alloc: &blink_alloc::Blink) -> LatticeAnchorRef {
let ptr = &*self.borrow() as &dyn LatticeAnchor as *const dyn LatticeAnchor;
LatticeAnchorRef::new(unsafe { NonNull::new_unchecked(ptr.cast_mut()) })
}
}
impl LatticeAnchorExt for ProgramPoint {
fn anchor_id(&self) -> u64 {
LatticeAnchorRef::compute_hash(self)
}
fn alloc(&self, alloc: &blink_alloc::Blink) -> LatticeAnchorRef {
let ptr = alloc.put(*self);
LatticeAnchorRef::new(unsafe { NonNull::new_unchecked(ptr) })
}
}