midenc_hir/ir/value/
aliasing.rs

1use core::{fmt, num::NonZeroU8};
2
3use super::*;
4
5/// This is a essentialy a [ValueRef], but with a modified encoding that lets us uniquely identify
6/// aliases of a value on the operand stack during analysis.
7///
8/// Aliases of a value are treated as unique values for purposes of operand stack management, but
9/// are associated with multiple copies of a value on the stack.
10#[derive(Copy, Clone)]
11pub struct ValueOrAlias {
12    /// The SSA value of this operand
13    value: ValueRef,
14    /// To avoid unnecessary borrowing of `value`, we cache the ValueId here
15    value_id: ValueId,
16    /// When an SSA value is used multiple times by an instruction, each use must be accounted for
17    /// on the operand stack as a unique value. The alias identifier is usually generated from a
18    /// counter of the unique instances of the value, but can be any unique integer value.
19    alias_id: u8,
20}
21
22impl ValueOrAlias {
23    /// Create a new [ValueOrAlias] from the given [ValueRef]
24    pub fn new(value: ValueRef) -> Self {
25        let value_id = value.borrow().id();
26        Self {
27            value,
28            value_id,
29            alias_id: 0,
30        }
31    }
32
33    /// Gets the effective size of this type on the Miden operand stack
34    pub fn stack_size(&self) -> usize {
35        self.value.borrow().ty().size_in_felts()
36    }
37
38    /// Create an aliased copy of this value, using `id` to uniquely identify the alias.
39    ///
40    /// NOTE: You must ensure that each alias of the same value gets a unique identifier,
41    /// or you may observe strange behavior due to two aliases that should be distinct,
42    /// being treated as if they have the same identity.
43    pub fn copy(mut self, id: NonZeroU8) -> Self {
44        self.alias_id = id.get();
45        self
46    }
47
48    /// Get an un-aliased copy of this value
49    pub fn unaliased(mut self) -> Self {
50        self.alias_id = 0;
51        self
52    }
53
54    /// Convert this value into an alias, using `id` to uniquely identify the alias.
55    ///
56    /// NOTE: You must ensure that each alias of the same value gets a unique identifier,
57    /// or you may observe strange behavior due to two aliases that should be distinct,
58    /// being treated as if they have the same identity.
59    pub fn set_alias(&mut self, id: NonZeroU8) {
60        self.alias_id = id.get();
61    }
62
63    /// Get the underlying [ValueRef]
64    pub fn value(self) -> ValueRef {
65        self.value
66    }
67
68    /// Borrow the underlying [Value]
69    pub fn borrow_value(&self) -> EntityRef<'_, dyn Value> {
70        self.value.borrow()
71    }
72
73    /// Get the unique alias identifier for this value, if this value is an alias
74    pub fn alias(self) -> Option<NonZeroU8> {
75        NonZeroU8::new(self.alias_id)
76    }
77
78    /// Get the unique alias identifier for this value, if this value is an alias
79    pub fn unwrap_alias(self) -> NonZeroU8 {
80        NonZeroU8::new(self.alias_id).unwrap_or_else(|| panic!("expected {self:?} to be an alias"))
81    }
82
83    /// Returns true if this value is an alias
84    pub fn is_alias(&self) -> bool {
85        self.alias_id != 0
86    }
87}
88
89impl core::borrow::Borrow<ValueRef> for ValueOrAlias {
90    #[inline(always)]
91    fn borrow(&self) -> &ValueRef {
92        &self.value
93    }
94}
95
96impl core::borrow::Borrow<ValueRef> for &ValueOrAlias {
97    #[inline(always)]
98    fn borrow(&self) -> &ValueRef {
99        &self.value
100    }
101}
102
103impl core::borrow::Borrow<ValueRef> for &mut ValueOrAlias {
104    #[inline(always)]
105    fn borrow(&self) -> &ValueRef {
106        &self.value
107    }
108}
109
110impl Eq for ValueOrAlias {}
111
112impl PartialEq for ValueOrAlias {
113    fn eq(&self, other: &Self) -> bool {
114        self.value_id == other.value_id && self.alias_id == other.alias_id
115    }
116}
117
118impl core::hash::Hash for ValueOrAlias {
119    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
120        self.value_id.hash(state);
121        self.alias_id.hash(state);
122    }
123}
124
125impl Ord for ValueOrAlias {
126    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
127        self.value_id.cmp(&other.value_id).then(self.alias_id.cmp(&other.alias_id))
128    }
129}
130
131impl PartialEq<ValueRef> for ValueOrAlias {
132    fn eq(&self, other: &ValueRef) -> bool {
133        &self.value == other
134    }
135}
136
137impl PartialOrd for ValueOrAlias {
138    #[inline]
139    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
140        Some(self.cmp(other))
141    }
142}
143
144impl From<ValueRef> for ValueOrAlias {
145    #[inline]
146    fn from(value: ValueRef) -> Self {
147        Self::new(value)
148    }
149}
150
151impl From<ValueOrAlias> for ValueRef {
152    #[inline]
153    fn from(value: ValueOrAlias) -> Self {
154        value.value
155    }
156}
157
158impl fmt::Display for ValueOrAlias {
159    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160        match self.alias() {
161            None => write!(f, "{}", &self.value_id),
162            Some(alias) => write!(f, "{}.{alias}", &self.value_id),
163        }
164    }
165}
166
167impl fmt::Debug for ValueOrAlias {
168    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169        fmt::Display::fmt(self, f)
170    }
171}