Skip to main content

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}