ir_lang/entity.rs
1//! Stable handles into a module and its functions.
2//!
3//! Every entity is named by a small `Copy` handle wrapping a dense `u32` index, so a
4//! pass can keep a side table as a plain `Vec` indexed by `handle.index()`. Handles are
5//! scoped to the module (functions, globals, signatures, aggregates) or the function
6//! (values, blocks, instructions, stack slots) that minted them. They are never reused:
7//! removing an instruction or a block leaves a tombstone, so a handle never silently
8//! starts naming a different entity. [`Builder::compact`](crate::Builder::compact)
9//! is the one operation that renumbers, and it returns an explicit [`Remap`](crate::Remap).
10
11use core::fmt;
12
13macro_rules! handle {
14 ($(#[$doc:meta])* $name:ident, $prefix:literal, $example:literal) => {
15 $(#[$doc])*
16 ///
17 /// # Examples
18 ///
19 /// ```
20 #[doc = concat!("use ir_lang::", stringify!($name), ";")]
21 ///
22 #[doc = concat!("let h = ", stringify!($name), "::from_u32(3);")]
23 /// assert_eq!(h.index(), 3);
24 #[doc = concat!("assert_eq!(h.to_string(), \"", $example, "\");")]
25 /// ```
26 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
27 pub struct $name(u32);
28
29 impl $name {
30 /// Makes a handle from a raw index.
31 ///
32 /// Handles normally come from the module or function that owns the
33 /// entity. This constructor exists for side tables and tests; a handle
34 /// made up this way is checked like any other (an out-of-range handle is
35 /// a validation error, never a panic).
36 ///
37 /// # Examples
38 ///
39 /// ```
40 #[doc = concat!("use ir_lang::", stringify!($name), ";")]
41 ///
42 #[doc = concat!("assert_eq!(", stringify!($name), "::from_u32(0).index(), 0);")]
43 /// ```
44 #[inline]
45 #[must_use]
46 pub const fn from_u32(index: u32) -> Self {
47 Self(index)
48 }
49
50 /// Returns the dense zero-based index of this handle.
51 ///
52 /// # Examples
53 ///
54 /// ```
55 #[doc = concat!("use ir_lang::", stringify!($name), ";")]
56 ///
57 #[doc = concat!("assert_eq!(", stringify!($name), "::from_u32(7).index(), 7);")]
58 /// ```
59 #[inline]
60 #[must_use]
61 pub const fn index(self) -> usize {
62 self.0 as usize
63 }
64
65 /// Returns the raw `u32` index.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 #[doc = concat!("use ir_lang::", stringify!($name), ";")]
71 ///
72 #[doc = concat!("assert_eq!(", stringify!($name), "::from_u32(9).as_u32(), 9);")]
73 /// ```
74 #[inline]
75 #[must_use]
76 pub const fn as_u32(self) -> u32 {
77 self.0
78 }
79 }
80
81 impl fmt::Display for $name {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 write!(f, concat!($prefix, "{}"), self.0)
84 }
85 }
86 };
87}
88
89handle!(
90 /// An SSA value in a function: a block parameter or an instruction result.
91 ///
92 /// Every value has one type and exactly one definition. It prints as `v<n>`.
93 Value,
94 "v",
95 "v3"
96);
97
98handle!(
99 /// A basic block in a function. It prints as `b<n>`.
100 Block,
101 "b",
102 "b3"
103);
104
105handle!(
106 /// An instruction in a function. Instruction handles are not printed in the
107 /// textual form (an instruction is named by its results); in messages it prints
108 /// as `inst<n>`.
109 Inst,
110 "inst",
111 "inst3"
112);
113
114handle!(
115 /// A stack slot of a function: frame memory addressed with
116 /// [`InstData::StackAddr`](crate::InstData::StackAddr). It prints as `ss<n>`.
117 StackSlot,
118 "ss",
119 "ss3"
120);
121
122handle!(
123 /// A function declaration in a module (defined or imported). In messages it
124 /// prints as `f<n>`; the textual form names functions by symbol (`@name`).
125 FuncId,
126 "f",
127 "f3"
128);
129
130handle!(
131 /// A global (data) declaration in a module. In messages it prints as `g<n>`;
132 /// the textual form names globals by symbol (`@name`).
133 GlobalId,
134 "g",
135 "g3"
136);
137
138handle!(
139 /// An interned function signature in a module. It prints as `s<n>`.
140 SigId,
141 "s",
142 "s3"
143);
144
145handle!(
146 /// An aggregate (struct or array) memory type in a module. It prints as `t<n>`.
147 AggId,
148 "t",
149 "t3"
150);
151
152handle!(
153 /// A mutable local variable of the builder's SSA construction
154 /// ([`Builder::declare_var`](crate::Builder::declare_var)): a name for "the
155 /// current value of `x`" that the builder turns into SSA values and block
156 /// parameters. Scoped to one builder. In messages it prints as `var<n>`.
157 Variable,
158 "var",
159 "var3"
160);
161
162/// The results of one instruction: a run of consecutive values.
163///
164/// An instruction defines zero or more values, always with consecutive handles, so
165/// the run is stored as a start and a length rather than a list.
166///
167/// # Examples
168///
169/// ```
170/// use ir_lang::{Module, Signature, Type, Linkage, MemOrder};
171///
172/// let mut m = Module::new("demo");
173/// let f = m.declare_function("f", &Signature::new(&[Type::Ptr], &[]), Linkage::Export)?;
174/// let mut b = m.build(f)?;
175/// let p = b.param(0)?;
176/// let old = b.iconst(Type::I64, 1)?;
177/// let new = b.iconst(Type::I64, 2)?;
178/// let inst = b.cmpxchg(p, old, new, MemOrder::SeqCst, MemOrder::SeqCst)?;
179/// let results = b.results(inst);
180/// assert_eq!(results.len(), 2);
181/// assert_eq!(results.get(1), Some(results.first().unwrap().next()));
182/// # Ok::<(), Box<dyn std::error::Error>>(())
183/// ```
184#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
185pub struct ValueRange {
186 pub(crate) start: u32,
187 pub(crate) len: u32,
188}
189
190impl ValueRange {
191 /// The number of values in the run.
192 ///
193 /// # Examples
194 ///
195 /// ```
196 /// use ir_lang::ValueRange;
197 ///
198 /// assert_eq!(ValueRange::default().len(), 0);
199 /// ```
200 #[inline]
201 #[must_use]
202 pub const fn len(self) -> usize {
203 self.len as usize
204 }
205
206 /// Whether the run is empty (the instruction defines nothing).
207 ///
208 /// # Examples
209 ///
210 /// ```
211 /// use ir_lang::ValueRange;
212 ///
213 /// assert!(ValueRange::default().is_empty());
214 /// ```
215 #[inline]
216 #[must_use]
217 pub const fn is_empty(self) -> bool {
218 self.len == 0
219 }
220
221 /// The `i`-th value of the run, if there is one.
222 ///
223 /// # Examples
224 ///
225 /// ```
226 /// use ir_lang::ValueRange;
227 ///
228 /// assert_eq!(ValueRange::default().get(0), None);
229 /// ```
230 #[inline]
231 #[must_use]
232 pub const fn get(self, i: usize) -> Option<Value> {
233 if i < self.len as usize {
234 match self.start.checked_add(i as u32) {
235 Some(v) => Some(Value(v)),
236 None => None,
237 }
238 } else {
239 None
240 }
241 }
242
243 /// The first value of the run, if there is one.
244 ///
245 /// # Examples
246 ///
247 /// ```
248 /// use ir_lang::ValueRange;
249 ///
250 /// assert_eq!(ValueRange::default().first(), None);
251 /// ```
252 #[inline]
253 #[must_use]
254 pub const fn first(self) -> Option<Value> {
255 self.get(0)
256 }
257
258 /// Whether `value` is one of the run's values.
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use ir_lang::{Value, ValueRange};
264 ///
265 /// assert!(!ValueRange::default().contains(Value::from_u32(0)));
266 /// ```
267 #[inline]
268 #[must_use]
269 pub const fn contains(self, value: Value) -> bool {
270 value.0 >= self.start && value.0 - self.start < self.len
271 }
272
273 /// Iterates over the run's values in order.
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// use ir_lang::ValueRange;
279 ///
280 /// assert_eq!(ValueRange::default().iter().count(), 0);
281 /// ```
282 #[inline]
283 pub fn iter(self) -> impl ExactSizeIterator<Item = Value> + DoubleEndedIterator {
284 (self.start..self.start.saturating_add(self.len)).map(Value)
285 }
286}
287
288impl IntoIterator for ValueRange {
289 type Item = Value;
290 type IntoIter = core::iter::Map<core::ops::Range<u32>, fn(u32) -> Value>;
291
292 fn into_iter(self) -> Self::IntoIter {
293 (self.start..self.start.saturating_add(self.len)).map(Value as fn(u32) -> Value)
294 }
295}
296
297impl Value {
298 /// The value with the next index. Results of one instruction are consecutive,
299 /// so `first.next()` is the second result.
300 ///
301 /// # Examples
302 ///
303 /// ```
304 /// use ir_lang::Value;
305 ///
306 /// assert_eq!(Value::from_u32(4).next(), Value::from_u32(5));
307 /// ```
308 #[inline]
309 #[must_use]
310 pub const fn next(self) -> Value {
311 Value(self.0.saturating_add(1))
312 }
313}
314
315/// The sentinel used for "no entity" in the internal linked lists.
316pub(crate) const NONE: u32 = u32::MAX;
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321 use alloc::string::ToString;
322
323 #[test]
324 fn test_handles_display_with_their_prefixes() {
325 assert_eq!(Value::from_u32(1).to_string(), "v1");
326 assert_eq!(Block::from_u32(2).to_string(), "b2");
327 assert_eq!(StackSlot::from_u32(0).to_string(), "ss0");
328 assert_eq!(AggId::from_u32(5).to_string(), "t5");
329 assert_eq!(SigId::from_u32(5).to_string(), "s5");
330 }
331
332 #[test]
333 fn test_value_range_contains_and_iterates() {
334 let r = ValueRange { start: 4, len: 2 };
335 assert!(r.contains(Value::from_u32(4)));
336 assert!(r.contains(Value::from_u32(5)));
337 assert!(!r.contains(Value::from_u32(6)));
338 assert!(!r.contains(Value::from_u32(3)));
339 assert_eq!(r.iter().collect::<alloc::vec::Vec<_>>().len(), 2);
340 assert_eq!(r.into_iter().next_back(), Some(Value::from_u32(5)));
341 }
342}