midenc_hir/ir/
operands.rs

1use core::fmt;
2
3use super::Context;
4use crate::{EntityRef, OperationRef, Type, UnsafeIntrusiveEntityRef, Value, ValueId, ValueRef};
5
6pub type OpOperand = UnsafeIntrusiveEntityRef<OpOperandImpl>;
7pub type OpOperandList = crate::EntityList<OpOperandImpl>;
8#[allow(unused)]
9pub type OpOperandIter<'a> = crate::EntityIter<'a, OpOperandImpl>;
10#[allow(unused)]
11pub type OpOperandCursor<'a> = crate::EntityCursor<'a, OpOperandImpl>;
12#[allow(unused)]
13pub type OpOperandCursorMut<'a> = crate::EntityCursorMut<'a, OpOperandImpl>;
14
15/// An [OpOperand] represents a use of a [Value] by an [Operation]
16pub struct OpOperandImpl {
17    /// The operand value
18    pub value: Option<ValueRef>,
19    /// The owner of this operand, i.e. the operation it is an operand of
20    pub owner: OperationRef,
21    /// The index of this operand in the operand list of an operation
22    pub index: u8,
23}
24impl OpOperandImpl {
25    #[inline]
26    pub fn new(value: ValueRef, owner: OperationRef, index: u8) -> Self {
27        Self {
28            value: Some(value),
29            owner,
30            index,
31        }
32    }
33
34    #[track_caller]
35    pub fn value(&self) -> EntityRef<'_, dyn Value> {
36        self.value.as_ref().expect("operand is unlinked").borrow()
37    }
38
39    #[inline]
40    pub const fn as_value_ref(&self) -> ValueRef {
41        self.value.unwrap()
42    }
43
44    #[inline]
45    pub fn as_operand_ref(&self) -> OpOperand {
46        unsafe { OpOperand::from_raw(self) }
47    }
48
49    pub fn owner(&self) -> EntityRef<'_, crate::Operation> {
50        self.owner.borrow()
51    }
52
53    pub fn ty(&self) -> crate::Type {
54        self.value().ty().clone()
55    }
56
57    pub fn operand_group(&self) -> u8 {
58        let owner = self.owner.borrow();
59        let operands = owner.operands();
60        let operand_index = self.index as usize;
61        let group_index = operands
62            .groups()
63            .position(|group| group.range().contains(&operand_index))
64            .expect("broken operand reference!");
65        group_index as u8
66    }
67
68    /// Set the operand value to `value`, removing the operand from the use list of the previous
69    /// value, and adding it to the use list of `value`.
70    pub fn set(&mut self, mut value: ValueRef) {
71        let this = self.as_operand_ref();
72        if let Some(mut prev) = self.value.take() {
73            unsafe {
74                let mut prev = prev.borrow_mut();
75                prev.uses_mut().cursor_mut_from_ptr(this).remove();
76            }
77        }
78        self.value = Some(value);
79        value.borrow_mut().insert_use(this);
80    }
81}
82impl fmt::Debug for OpOperand {
83    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84        fmt::Debug::fmt(&*self.borrow(), f)
85    }
86}
87impl fmt::Debug for OpOperandImpl {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        #[derive(Debug)]
90        #[allow(unused)]
91        struct ValueInfo<'a> {
92            id: ValueId,
93            ty: &'a Type,
94        }
95
96        let value = self.value.map(|value| value.borrow());
97        let value = value.as_ref().map(|value| ValueInfo {
98            id: value.id(),
99            ty: value.ty(),
100        });
101        f.debug_struct("OpOperand")
102            .field("index", &self.index)
103            .field("value", &value)
104            .finish_non_exhaustive()
105    }
106}
107impl crate::Spanned for OpOperandImpl {
108    fn span(&self) -> crate::SourceSpan {
109        self.value().span()
110    }
111}
112impl crate::Entity for OpOperandImpl {}
113impl crate::EntityListItem for OpOperandImpl {}
114impl crate::StorableEntity for OpOperandImpl {
115    #[inline(always)]
116    fn index(&self) -> usize {
117        self.index as usize
118    }
119
120    unsafe fn set_index(&mut self, index: usize) {
121        self.index = index.try_into().expect("too many operands");
122    }
123
124    fn unlink(&mut self) {
125        if !self.as_operand_ref().is_linked() {
126            return;
127        }
128        if let Some(mut value) = self.value.take() {
129            let ptr = self.as_operand_ref();
130            let mut value = value.borrow_mut();
131            let uses = value.uses_mut();
132            unsafe {
133                let mut cursor = uses.cursor_mut_from_ptr(ptr);
134                cursor.remove();
135            }
136        }
137    }
138}
139
140pub type OpOperandStorage = crate::EntityStorage<OpOperand, 1>;
141pub type OpOperandRange<'a> = crate::EntityRange<'a, OpOperand>;
142pub type OpOperandRangeMut<'a> = crate::EntityRangeMut<'a, OpOperand, 1>;
143
144impl OpOperandRangeMut<'_> {
145    pub fn set_operands<I>(&mut self, operands: I, owner: OperationRef, context: &Context)
146    where
147        I: IntoIterator<Item = ValueRef>,
148    {
149        let mut operands = operands.into_iter().enumerate();
150        let mut num_operands = 0;
151        while let Some((index, value)) = operands.next() {
152            if let Some(operand_ref) = self.get_mut(index) {
153                num_operands += 1;
154                let mut operand = operand_ref.borrow_mut();
155                // If the new operand value and the existing one are the same, no change is required
156                if operand.value.is_some_and(|v| v == value) {
157                    continue;
158                }
159                // Otherwise, set the operand value to the new value
160                operand.set(value);
161            } else {
162                // The operand group is being extended
163                self.extend(core::iter::once((index, value)).chain(operands).map(|(_, value)| {
164                    num_operands += 1;
165                    context.make_operand(value, owner, 0)
166                }));
167                break;
168            }
169        }
170
171        // Remove excess operands
172        if num_operands < self.len() {
173            for _ in 0..(self.len() - num_operands) {
174                let _ = self.pop();
175            }
176        }
177    }
178}