midenc_hir/ir/
value.rs

1mod aliasing;
2mod range;
3mod stack;
4
5use core::{any::Any, fmt};
6
7pub use self::{
8    aliasing::ValueOrAlias,
9    range::{AsValueRange, ValueRange},
10    stack::StackOperand,
11};
12use super::*;
13use crate::{DynHash, DynPartialEq};
14
15/// A unique identifier for a [Value] in the IR
16#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[repr(transparent)]
18pub struct ValueId(u32);
19impl ValueId {
20    pub const fn from_u32(id: u32) -> Self {
21        Self(id)
22    }
23
24    pub const fn as_u32(&self) -> u32 {
25        self.0
26    }
27}
28impl EntityId for ValueId {
29    #[inline(always)]
30    fn as_usize(&self) -> usize {
31        self.0 as usize
32    }
33}
34impl fmt::Debug for ValueId {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        write!(f, "v{}", &self.0)
37    }
38}
39impl fmt::Display for ValueId {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        write!(f, "v{}", &self.0)
42    }
43}
44
45/// Represents an SSA value in the IR.
46///
47/// The data underlying a [Value] represents a _definition_, and thus implements [Usable]. The users
48/// of a [Value] are operands (see [OpOperandImpl]). Operands are associated with an operation. Thus
49/// the graph formed of the edges between values and operations via operands forms the data-flow
50/// graph of the program.
51pub trait Value:
52    Any
53    + EntityWithId<Id = ValueId>
54    + Spanned
55    + Usable<Use = OpOperandImpl>
56    + fmt::Debug
57    + fmt::Display
58    + DynPartialEq
59    + DynHash
60{
61    /// Set the source location of this value
62    fn set_span(&mut self, span: SourceSpan);
63    /// Get the type of this value
64    fn ty(&self) -> &Type;
65    /// Set the type of this value
66    fn set_type(&mut self, ty: Type);
67    /// Get the defining operation for this value, _if_ defined by an operation.
68    ///
69    /// Returns `None` if this value is defined by other means than an operation result.
70    fn get_defining_op(&self) -> Option<OperationRef>;
71    /// Get the region which contains the definition of this value
72    fn parent_region(&self) -> Option<RegionRef> {
73        self.parent_block().and_then(|block| block.parent())
74    }
75    /// Get the block which contains the definition of this value
76    fn parent_block(&self) -> Option<BlockRef>;
77    /// Returns true if this value is used outside of the given block
78    fn is_used_outside_of_block(&self, block: &BlockRef) -> bool {
79        self.iter_uses()
80            .any(|user| user.owner.parent().is_some_and(|blk| !BlockRef::ptr_eq(&blk, block)))
81    }
82    /// Replace all uses of `self` with `replacement`
83    fn replace_all_uses_with(&mut self, mut replacement: ValueRef) {
84        let mut cursor = self.uses_mut().front_mut();
85        while let Some(mut user) = cursor.as_pointer() {
86            // Rewrite use of `self` with `replacement`
87            {
88                let mut user = user.borrow_mut();
89                user.value = Some(replacement);
90            }
91            // Remove `user` from the use list of `self`
92            cursor.remove();
93            // Add `user` to the use list of `replacement`
94            replacement.borrow_mut().insert_use(user);
95        }
96    }
97    /// Replace all uses of `self` with `replacement` unless the user is in `exceptions`
98    fn replace_all_uses_except(&mut self, mut replacement: ValueRef, exceptions: &[OperationRef]) {
99        let mut cursor = self.uses_mut().front_mut();
100        while let Some(mut user) = cursor.as_pointer() {
101            // Rewrite use of `self` with `replacement` if user not in `exceptions`
102            {
103                let mut user = user.borrow_mut();
104                if exceptions.contains(&user.owner) {
105                    cursor.move_next();
106                    continue;
107                }
108                user.value = Some(replacement);
109            }
110            // Remove `user` from the use list of `self`
111            cursor.remove();
112            // Add `user` to the use list of `replacement`
113            replacement.borrow_mut().insert_use(user);
114        }
115    }
116}
117
118impl dyn Value {
119    #[inline]
120    pub fn is<T: Value>(&self) -> bool {
121        (self as &dyn Any).is::<T>()
122    }
123
124    #[inline]
125    pub fn downcast_ref<T: Value>(&self) -> Option<&T> {
126        (self as &dyn Any).downcast_ref::<T>()
127    }
128
129    #[inline]
130    pub fn downcast_mut<T: Value>(&mut self) -> Option<&mut T> {
131        (self as &mut dyn Any).downcast_mut::<T>()
132    }
133
134    /// Replace all uses of `self` with `replacement` if `should_replace` returns true
135    pub fn replace_uses_with_if<F>(&mut self, mut replacement: ValueRef, should_replace: F)
136    where
137        F: Fn(&OpOperandImpl) -> bool,
138    {
139        let mut cursor = self.uses_mut().front_mut();
140        while let Some(mut user) = cursor.as_pointer() {
141            // Rewrite use of `self` with `replacement` if `should_replace` returns true
142            {
143                let mut user = user.borrow_mut();
144                if !should_replace(&user) {
145                    cursor.move_next();
146                    continue;
147                }
148                user.value = Some(replacement);
149            }
150            // Remove `user` from the use list of `self`
151            cursor.remove();
152            // Add `user` to the use list of `replacement`
153            replacement.borrow_mut().insert_use(user);
154        }
155    }
156}
157
158/// Generates the boilerplate for a concrete [Value] type.
159macro_rules! value_impl {
160    (
161        $(#[$outer:meta])*
162        $vis:vis struct $ValueKind:ident {
163            $(#[doc $($owner_doc_args:tt)*])*
164            owner: $OwnerTy:ty,
165            $(#[doc $($index_doc_args:tt)*])*
166            index: u8,
167            $(
168                $(#[$inner:ident $($args:tt)*])*
169                $Field:ident: $FieldTy:ty,
170            )*
171        }
172
173        fn get_defining_op(&$GetDefiningOpSelf:ident) -> Option<OperationRef> $GetDefiningOp:block
174
175        fn parent_block(&$ParentBlockSelf:ident) -> Option<BlockRef> $ParentBlock:block
176
177        $($t:tt)*
178    ) => {
179        $(#[$outer])*
180        #[derive(Spanned)]
181        $vis struct $ValueKind {
182            id: ValueId,
183            #[span]
184            span: SourceSpan,
185            ty: Type,
186            uses: OpOperandList,
187            owner: $OwnerTy,
188            index: u8,
189            $(
190                $(#[$inner $($args)*])*
191                $Field: $FieldTy
192            ),*
193        }
194
195
196        impl $ValueKind {
197            pub fn new(
198                span: SourceSpan,
199                id: ValueId,
200                ty: Type,
201                owner: $OwnerTy,
202                index: u8,
203                $(
204                    $Field: $FieldTy
205                ),*
206            ) -> Self {
207                Self {
208                    id,
209                    ty,
210                    span,
211                    uses: Default::default(),
212                    owner,
213                    index,
214                    $(
215                        $Field
216                    ),*
217                }
218            }
219
220            $(#[doc $($owner_doc_args)*])*
221            pub fn owner(&self) -> $OwnerTy {
222                self.owner.clone()
223            }
224
225            $(#[doc $($index_doc_args)*])*
226            pub fn index(&self) -> usize {
227                self.index as usize
228            }
229        }
230
231        impl Value for $ValueKind {
232            fn ty(&self) -> &Type {
233                &self.ty
234            }
235
236            fn set_span(&mut self, span: SourceSpan) {
237                self.span = span;
238            }
239
240            fn set_type(&mut self, ty: Type) {
241                self.ty = ty;
242            }
243
244            fn get_defining_op(&$GetDefiningOpSelf) -> Option<OperationRef> $GetDefiningOp
245
246            fn parent_block(&$ParentBlockSelf) -> Option<BlockRef> $ParentBlock
247        }
248
249        impl Entity for $ValueKind {}
250        impl EntityWithId for $ValueKind {
251            type Id = ValueId;
252
253            #[inline(always)]
254            fn id(&self) -> Self::Id {
255                self.id
256            }
257        }
258
259        impl EntityParent<OpOperandImpl> for $ValueKind {
260            fn offset() -> usize {
261                core::mem::offset_of!($ValueKind, uses)
262            }
263        }
264
265        impl Usable for $ValueKind {
266            type Use = OpOperandImpl;
267
268            #[inline(always)]
269            fn uses(&self) -> &OpOperandList {
270                &self.uses
271            }
272
273            #[inline(always)]
274            fn uses_mut(&mut self) -> &mut OpOperandList {
275                &mut self.uses
276            }
277        }
278
279
280        impl Eq for $ValueKind {}
281
282        impl PartialEq for $ValueKind {
283            fn eq(&self, other: &Self) -> bool {
284                self.id == other.id
285            }
286        }
287
288        impl Ord for $ValueKind {
289            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
290                self.id.cmp(&other.id)
291            }
292        }
293
294        impl PartialOrd for $ValueKind {
295            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
296                Some(self.cmp(other))
297            }
298        }
299
300        impl core::hash::Hash for $ValueKind {
301            fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
302                self.id.hash(state);
303            }
304        }
305
306        impl fmt::Display for $ValueKind {
307            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308                use crate::formatter::PrettyPrint;
309
310                self.pretty_print(f)
311            }
312        }
313
314        impl fmt::Debug for $ValueKind {
315            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
316                let mut builder = f.debug_struct(stringify!($ValueKind));
317                builder
318                    .field("id", &self.id)
319                    .field("ty", &self.ty)
320                    .field("index", &self.index)
321                    .field("is_used", &(!self.uses.is_empty()));
322
323                $(
324                    builder.field(stringify!($Field), &self.$Field);
325                )*
326
327                builder.finish_non_exhaustive()
328            }
329        }
330
331        $($t)*
332    }
333}
334
335/// A pointer to a [Value]
336pub type ValueRef = UnsafeEntityRef<dyn Value>;
337/// A pointer to a [BlockArgument]
338pub type BlockArgumentRef = UnsafeEntityRef<BlockArgument>;
339/// A pointer to a [OpResult]
340pub type OpResultRef = UnsafeEntityRef<OpResult>;
341
342value_impl!(
343    /// A [BlockArgument] represents the definition of a [Value] by a block parameter
344    pub struct BlockArgument {
345        /// Get the [Block] to which this [BlockArgument] belongs
346        owner: BlockRef,
347        /// Get the index of this argument in the argument list of the owning [Block]
348        index: u8,
349    }
350
351    fn get_defining_op(&self) -> Option<OperationRef> {
352        None
353    }
354
355    fn parent_block(&self) -> Option<BlockRef> {
356        Some(self.owner)
357    }
358);
359
360impl BlockArgument {
361    #[inline]
362    pub fn as_value_ref(&self) -> ValueRef {
363        self.as_block_argument_ref() as ValueRef
364    }
365
366    #[inline]
367    pub fn as_block_argument_ref(&self) -> BlockArgumentRef {
368        unsafe { BlockArgumentRef::from_raw(self) }
369    }
370}
371
372impl crate::formatter::PrettyPrint for BlockArgument {
373    fn render(&self) -> crate::formatter::Document {
374        use crate::formatter::*;
375
376        display(self.id) + const_text(": ") + self.ty.render()
377    }
378}
379
380impl StorableEntity for BlockArgument {
381    #[inline(always)]
382    fn index(&self) -> usize {
383        self.index as usize
384    }
385
386    unsafe fn set_index(&mut self, index: usize) {
387        self.index = index.try_into().expect("too many block arguments");
388    }
389}
390
391pub type BlockArgumentRange<'a> = crate::EntityRange<'a, BlockArgumentRef>;
392pub type BlockArgumentRangeMut<'a> = crate::EntityRangeMut<'a, BlockArgumentRef, 1>;
393
394value_impl!(
395    /// An [OpResult] represents the definition of a [Value] by the result of an [Operation]
396    pub struct OpResult {
397        /// Get the [Operation] to which this [OpResult] belongs
398        owner: OperationRef,
399        /// Get the index of this result in the result list of the owning [Operation]
400        index: u8,
401    }
402
403    fn get_defining_op(&self) -> Option<OperationRef> {
404        Some(self.owner)
405    }
406
407    fn parent_block(&self) -> Option<BlockRef> {
408        self.owner.parent()
409    }
410);
411
412impl OpResult {
413    #[inline]
414    pub fn as_value_ref(&self) -> ValueRef {
415        unsafe { ValueRef::from_raw(self as &dyn Value) }
416    }
417
418    #[inline]
419    pub fn as_op_result_ref(&self) -> OpResultRef {
420        unsafe { OpResultRef::from_raw(self) }
421    }
422}
423
424impl crate::formatter::PrettyPrint for OpResult {
425    #[inline]
426    fn render(&self) -> crate::formatter::Document {
427        use crate::formatter::*;
428
429        display(self.id)
430    }
431}
432
433impl StorableEntity for OpResult {
434    #[inline(always)]
435    fn index(&self) -> usize {
436        self.index as usize
437    }
438
439    unsafe fn set_index(&mut self, index: usize) {
440        self.index = index.try_into().expect("too many op results");
441    }
442
443    /// Unlink all users of this result
444    ///
445    /// The users will still refer to this result, but the use list of this value will be empty
446    fn unlink(&mut self) {
447        let uses = self.uses_mut();
448        uses.clear();
449    }
450}
451
452pub type OpResultStorage = crate::EntityStorage<OpResultRef, 1>;
453pub type OpResultRange<'a> = crate::EntityRange<'a, OpResultRef>;
454pub type OpResultRangeMut<'a> = crate::EntityRangeMut<'a, OpResultRef, 1>;