use alloc::vec::Vec;
use core::fmt;
use super::{
EntityRef, OpOperandStorage, StorableEntity, UnsafeIntrusiveEntityRef, Usable, ValueRange,
};
use crate::{
AttributeRef, AttributeRegistration, BlockOperandRef, BlockRef, OpOperandRange,
OpOperandRangeMut,
};
pub type OpSuccessorStorage = crate::EntityStorage<SuccessorInfo, 0>;
pub type OpSuccessorRange<'a> = crate::EntityRange<'a, SuccessorInfo>;
pub type OpSuccessorRangeMut<'a> = crate::EntityRangeMut<'a, SuccessorInfo, 0>;
pub trait SuccessorOperands {
fn is_empty(&self) -> bool {
self.num_produced() == 0 && self.len() == 0
}
fn len(&self) -> usize;
fn num_produced(&self) -> usize;
#[inline]
fn is_operand_produced(&self, index: usize) -> bool {
index < self.num_produced()
}
fn forwarded(&self) -> OpOperandRange<'_>;
fn get(&self, index: usize) -> Option<SuccessorOperand> {
if self.is_operand_produced(index) {
Some(SuccessorOperand::Produced)
} else {
self.forwarded()
.get(index)
.map(|op_operand| SuccessorOperand::Forwarded(op_operand.borrow().as_value_ref()))
}
}
fn get_unchecked(&self, index: usize) -> SuccessorOperand {
if self.is_operand_produced(index) {
SuccessorOperand::Produced
} else {
SuccessorOperand::Forwarded(self.forwarded()[index].borrow().as_value_ref())
}
}
fn get_operand_index(&self, block_argument_index: usize) -> usize {
assert!(
self.is_operand_produced(block_argument_index),
"cannot map operands produced by the operation"
);
let base_index = self.forwarded()[0].borrow().index as usize;
base_index + (block_argument_index - self.num_produced())
}
}
pub struct SuccessorOperandRange<'a> {
forwarded: OpOperandRange<'a>,
num_produced: usize,
}
impl<'a> SuccessorOperandRange<'a> {
pub fn empty() -> Self {
Self {
forwarded: OpOperandRange::empty(),
num_produced: 0,
}
}
#[inline]
pub const fn forward(forwarded: OpOperandRange<'a>) -> Self {
Self {
forwarded,
num_produced: 0,
}
}
pub fn produced(num_produced: usize) -> Self {
Self {
forwarded: OpOperandRange::empty(),
num_produced,
}
}
#[inline]
pub const fn new(num_produced: usize, forwarded: OpOperandRange<'a>) -> Self {
Self {
forwarded,
num_produced,
}
}
#[inline]
pub fn into_forwarded(self) -> OpOperandRange<'a> {
self.forwarded
}
}
impl SuccessorOperands for SuccessorOperandRange<'_> {
#[inline]
fn len(&self) -> usize {
self.num_produced + self.forwarded.len()
}
#[inline(always)]
fn num_produced(&self) -> usize {
self.num_produced
}
fn forwarded(&self) -> OpOperandRange<'_> {
self.forwarded.clone()
}
}
pub struct SuccessorOperandRangeMut<'a> {
forwarded: OpOperandRangeMut<'a>,
num_produced: usize,
}
impl<'a> SuccessorOperandRangeMut<'a> {
#[inline]
pub const fn forward(forwarded: OpOperandRangeMut<'a>) -> Self {
Self {
forwarded,
num_produced: 0,
}
}
#[inline]
pub const fn new(num_produced: usize, forwarded: OpOperandRangeMut<'a>) -> Self {
Self {
forwarded,
num_produced,
}
}
#[inline(always)]
pub fn forwarded_mut(&mut self) -> &mut OpOperandRangeMut<'a> {
&mut self.forwarded
}
}
impl SuccessorOperands for SuccessorOperandRangeMut<'_> {
#[inline]
fn len(&self) -> usize {
self.num_produced + self.forwarded.len()
}
#[inline(always)]
fn num_produced(&self) -> usize {
self.num_produced
}
#[inline(always)]
fn forwarded(&self) -> OpOperandRange<'_> {
self.forwarded.as_immutable()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SuccessorOperand {
Produced,
Forwarded(crate::ValueRef),
}
impl SuccessorOperand {
pub fn into_value_ref(self) -> Option<crate::ValueRef> {
match self {
Self::Produced => None,
Self::Forwarded(value) => Some(value),
}
}
}
pub trait KeyedSuccessor {
type Key: Sized + Clone + Eq;
type KeyStorage: AttributeRegistration;
type Repr<'a>: 'a;
type ReprMut<'a>: 'a;
fn key(&self) -> Self::Key;
fn into_parts(
self,
) -> (UnsafeIntrusiveEntityRef<Self::KeyStorage>, BlockRef, Vec<super::ValueRef>);
fn into_repr(
key: UnsafeIntrusiveEntityRef<Self::KeyStorage>,
block: BlockOperandRef,
operands: OpOperandRange<'_>,
) -> Self::Repr<'_>;
fn into_repr_mut(
key: UnsafeIntrusiveEntityRef<Self::KeyStorage>,
block: BlockOperandRef,
operands: OpOperandRangeMut<'_>,
) -> Self::ReprMut<'_>;
}
#[derive(Copy, Clone)]
pub struct SuccessorInfo {
pub block: BlockOperandRef,
pub(crate) key: Option<AttributeRef>,
pub(crate) operand_group: u8,
}
impl SuccessorInfo {
pub fn successor(&self) -> BlockRef {
self.block.borrow().successor()
}
pub fn successor_operand_group(&self) -> usize {
self.operand_group as usize
}
pub fn successor_operands(&self) -> ValueRange<'static, 4> {
let owner = self.block.borrow().owner;
ValueRange::from(owner.borrow().operands().group(self.operand_group as usize)).into_owned()
}
}
impl crate::StorableEntity for SuccessorInfo {
#[inline(always)]
fn index(&self) -> usize {
self.block.index()
}
#[inline(always)]
unsafe fn set_index(&mut self, index: usize) {
unsafe {
self.block.set_index(index);
}
}
#[inline(always)]
fn unlink(&mut self) {
if self.block.is_linked() {
self.block.unlink();
}
}
}
impl fmt::Debug for SuccessorInfo {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SuccessorInfo")
.field("block", &self.block.borrow())
.field("key", &self.key)
.field("operand_group", &self.operand_group)
.finish()
}
}
pub struct OpSuccessor<'a> {
pub dest: BlockOperandRef,
pub arguments: OpOperandRange<'a>,
}
impl OpSuccessor<'_> {
pub fn successor(&self) -> BlockRef {
self.dest.borrow().successor()
}
}
impl fmt::Debug for OpSuccessor<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OpSuccessor")
.field("block", &self.dest.borrow().block_id())
.field_with("arguments", |f| {
let mut list = f.debug_list();
for operand in self.arguments.iter() {
list.entry(&operand.borrow());
}
list.finish()
})
.finish()
}
}
pub struct OpSuccessorMut<'a> {
pub dest: BlockOperandRef,
pub arguments: OpOperandRangeMut<'a>,
}
impl OpSuccessorMut<'_> {
pub fn successor(&self) -> BlockRef {
self.dest.borrow().successor()
}
pub fn set(&mut self, mut block: BlockRef) {
{
let mut dest = self.dest.borrow_mut();
if BlockRef::ptr_eq(&block, &dest.successor()) {
return;
}
dest.unlink();
}
let mut block = block.borrow_mut();
let uses = block.uses_mut();
uses.push_back(self.dest);
debug_assert!(self.dest.parent().is_some());
}
}
impl fmt::Debug for OpSuccessorMut<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OpSuccessorMut")
.field("block", &self.dest.borrow().block_id())
.field_with("arguments", |f| {
let mut list = f.debug_list();
for operand in self.arguments.iter() {
list.entry(&operand.borrow());
}
list.finish()
})
.finish()
}
}
pub struct KeyedSuccessorRange<'a, T> {
range: OpSuccessorRange<'a>,
operands: &'a OpOperandStorage,
_marker: core::marker::PhantomData<T>,
}
impl<'a, T> KeyedSuccessorRange<'a, T> {
pub fn new(range: OpSuccessorRange<'a>, operands: &'a OpOperandStorage) -> Self {
Self {
range,
operands,
_marker: core::marker::PhantomData,
}
}
pub fn get(&self, index: usize) -> Option<SuccessorWithKey<'_, T>> {
self.range.get(index).map(|info| {
let operands = self.operands.group(info.operand_group as usize);
SuccessorWithKey {
info,
operands,
_marker: core::marker::PhantomData,
}
})
}
pub fn is_empty(&self) -> bool {
self.range.is_empty()
}
pub fn len(&self) -> usize {
self.range.len()
}
pub fn iter(&self) -> KeyedSuccessorRangeIter<'a, '_, T> {
KeyedSuccessorRangeIter {
range: self,
index: 0,
}
}
}
pub struct KeyedSuccessorRangeMut<'a, T> {
range: OpSuccessorRangeMut<'a>,
operands: &'a mut OpOperandStorage,
_marker: core::marker::PhantomData<T>,
}
impl<'a, T> KeyedSuccessorRangeMut<'a, T> {
pub fn new(range: OpSuccessorRangeMut<'a>, operands: &'a mut OpOperandStorage) -> Self {
Self {
range,
operands,
_marker: core::marker::PhantomData,
}
}
pub fn get(&self, index: usize) -> Option<SuccessorWithKey<'_, T>> {
self.range.get(index).map(|info| {
let operands = self.operands.group(info.operand_group as usize);
SuccessorWithKey {
info,
operands,
_marker: core::marker::PhantomData,
}
})
}
pub fn get_mut(&mut self, index: usize) -> Option<SuccessorWithKeyMut<'_, T>> {
self.range.get_mut(index).map(|info| {
let operands = self.operands.group_mut(info.operand_group as usize);
SuccessorWithKeyMut {
info,
operands,
_marker: core::marker::PhantomData,
}
})
}
pub fn remove(&mut self, index: usize) {
self.range.erase(index);
}
}
pub struct KeyedSuccessorRangeIter<'a, 'b: 'a, T> {
range: &'b KeyedSuccessorRange<'a, T>,
index: usize,
}
impl<'a, 'b: 'a, T> Iterator for KeyedSuccessorRangeIter<'a, 'b, T> {
type Item = SuccessorWithKey<'b, T>;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.range.range.len() {
return None;
}
let idx = self.index;
self.index += 1;
self.range.get(idx)
}
}
pub struct SuccessorWithKey<'a, T> {
info: &'a SuccessorInfo,
operands: OpOperandRange<'a>,
_marker: core::marker::PhantomData<T>,
}
impl<'a, T: KeyedSuccessor> SuccessorWithKey<'a, T>
where
T: KeyedSuccessor,
<T as KeyedSuccessor>::Key: Sized + Clone + Eq,
<T as KeyedSuccessor>::KeyStorage: AttributeRegistration<Value = <T as KeyedSuccessor>::Key>,
{
#[inline]
pub fn info(&self) -> &SuccessorInfo {
self.info
}
pub fn key(&self) -> EntityRef<'_, <T as KeyedSuccessor>::Key> {
let storage = self
.info
.key
.expect("invalid keyed successor: missing key")
.try_downcast_attr::<<T as KeyedSuccessor>::KeyStorage>()
.expect("invalid keyed successor: key is invalid");
EntityRef::map(
storage.borrow(),
<<T as KeyedSuccessor>::KeyStorage as AttributeRegistration>::underlying_value,
)
}
pub fn key_storage(&self) -> UnsafeIntrusiveEntityRef<<T as KeyedSuccessor>::KeyStorage> {
self.info
.key
.expect("invalid keyed successor: missing key")
.try_downcast_attr::<<T as KeyedSuccessor>::KeyStorage>()
.expect("invalid keyed successor: key is invalid")
}
pub fn block(&self) -> BlockRef {
self.info.block.borrow().successor()
}
pub fn block_operand(&self) -> BlockOperandRef {
self.info.block
}
pub fn operand_group(&self) -> usize {
self.info.operand_group as usize
}
#[inline(always)]
pub fn arguments(&self) -> &OpOperandRange<'a> {
&self.operands
}
}
pub struct SuccessorWithKeyMut<'a, T> {
info: &'a SuccessorInfo,
operands: OpOperandRangeMut<'a>,
_marker: core::marker::PhantomData<T>,
}
impl<'a, T: KeyedSuccessor> SuccessorWithKeyMut<'a, T>
where
T: KeyedSuccessor,
<T as KeyedSuccessor>::Key: Sized + Clone + Eq,
<T as KeyedSuccessor>::KeyStorage: AttributeRegistration<Value = <T as KeyedSuccessor>::Key>,
{
pub fn key(&self) -> Option<EntityRef<'_, <T as KeyedSuccessor>::Key>> {
self.info.key.and_then(|storage| {
let storage = storage.try_downcast_attr::<<T as KeyedSuccessor>::KeyStorage>().ok()?;
Some(EntityRef::map(
storage.borrow(),
<<T as KeyedSuccessor>::KeyStorage as AttributeRegistration>::underlying_value,
))
})
}
pub fn block(&self) -> BlockRef {
self.info.block.borrow().successor()
}
pub fn block_operand(&self) -> BlockOperandRef {
self.info.block
}
pub fn operand_group(&self) -> usize {
self.info.operand_group as usize
}
#[inline(always)]
pub fn arguments(&self) -> &OpOperandRangeMut<'a> {
&self.operands
}
#[inline(always)]
pub fn arguments_mut(&mut self) -> &mut OpOperandRangeMut<'a> {
&mut self.operands
}
}