ir_lang/entity.rs
1//! Stable handles into a function: [`Value`] and [`Block`].
2
3use core::fmt;
4
5/// A handle to an SSA value inside a [`Function`](crate::Function).
6///
7/// A value is the result of one instruction or one block parameter. It is named by
8/// this small, copyable handle rather than by an expression position, which is what
9/// lets a later pass refer to a result without holding a borrow of the function and
10/// lets the IR stay flat. A handle is stable for the life of the function that
11/// minted it and is dense (the handles of a function are `0..n`), so it doubles as
12/// an index into a side table a pass keeps alongside the IR.
13///
14/// Handles are scoped to the function they come from: a `Value` minted by one
15/// function's [`Builder`](crate::Builder) is meaningless in another. The validator
16/// catches a value used where its definition does not reach, but it cannot tell two
17/// functions' identically-numbered handles apart, so do not mix them.
18///
19/// # Examples
20///
21/// ```
22/// use ir_lang::{Builder, Type};
23///
24/// let mut b = Builder::new("id", &[Type::Int], Type::Int);
25/// let entry = b.entry();
26/// // The entry block's parameters are the function's parameters, as values.
27/// let x = b.block_params(entry)[0];
28/// b.ret(Some(x));
29///
30/// // A value handle is `Copy` and prints as `v<n>`.
31/// assert_eq!(x.to_string(), "v0");
32/// assert_eq!(x.index(), 0);
33/// ```
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub struct Value(u32);
37
38impl Value {
39 pub(crate) const fn from_raw(raw: u32) -> Self {
40 Self(raw)
41 }
42
43 /// Returns the zero-based index of this value, for use as a key into a side
44 /// table a pass keeps alongside the function.
45 ///
46 /// The values of a function are numbered densely from zero in the order they
47 /// are created, so a `Vec` sized to the value count can be indexed directly by
48 /// `value.index()`.
49 ///
50 /// # Examples
51 ///
52 /// ```
53 /// use ir_lang::{Builder, Type};
54 ///
55 /// let mut b = Builder::new("k", &[], Type::Int);
56 /// let a = b.iconst(1);
57 /// let c = b.iconst(2);
58 /// assert_eq!(a.index(), 0);
59 /// assert_eq!(c.index(), 1);
60 /// ```
61 #[must_use]
62 pub const fn index(self) -> usize {
63 self.0 as usize
64 }
65}
66
67impl fmt::Display for Value {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 write!(f, "v{}", self.0)
70 }
71}
72
73/// A handle to a basic block inside a [`Function`](crate::Function).
74///
75/// A block is a straight-line run of instructions with one entry and one
76/// terminator. This handle names a block so a terminator can branch to it and so a
77/// pass can walk the control-flow graph. Like [`Value`], it is `Copy`, stable for
78/// the life of its function, and dense from zero.
79///
80/// # Examples
81///
82/// ```
83/// use ir_lang::{Builder, Type};
84///
85/// let mut b = Builder::new("f", &[], Type::Unit);
86/// let entry = b.entry();
87/// let exit = b.create_block(&[]);
88///
89/// assert_eq!(entry.to_string(), "b0");
90/// assert_eq!(exit.to_string(), "b1");
91/// assert_eq!(exit.index(), 1);
92/// ```
93#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
94#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
95pub struct Block(u32);
96
97impl Block {
98 pub(crate) const fn from_raw(raw: u32) -> Self {
99 Self(raw)
100 }
101
102 /// Returns the zero-based index of this block, for use as a key into a side
103 /// table a pass keeps alongside the function.
104 ///
105 /// Blocks are numbered densely from zero in creation order; the entry block is
106 /// always block zero.
107 ///
108 /// # Examples
109 ///
110 /// ```
111 /// use ir_lang::{Builder, Type};
112 ///
113 /// let b = Builder::new("f", &[], Type::Unit);
114 /// assert_eq!(b.entry().index(), 0);
115 /// ```
116 #[must_use]
117 pub const fn index(self) -> usize {
118 self.0 as usize
119 }
120}
121
122impl fmt::Display for Block {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 write!(f, "b{}", self.0)
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn test_value_display_and_index_agree() {
134 let v = Value::from_raw(7);
135 assert_eq!(v.to_string(), "v7");
136 assert_eq!(v.index(), 7);
137 }
138
139 #[test]
140 fn test_block_display_and_index_agree() {
141 let b = Block::from_raw(3);
142 assert_eq!(b.to_string(), "b3");
143 assert_eq!(b.index(), 3);
144 }
145
146 #[test]
147 fn test_handles_order_by_raw_index() {
148 assert!(Value::from_raw(0) < Value::from_raw(1));
149 assert!(Block::from_raw(2) > Block::from_raw(1));
150 }
151}