Skip to main content

cranelift_codegen/ir/
progpoint.rs

1//! Program points.
2
3use crate::entity::EntityRef;
4use crate::ir::{Ebb, Inst, ValueDef};
5use core::cmp;
6use core::fmt;
7use core::u32;
8
9/// A `ProgramPoint` represents a position in a function where the live range of an SSA value can
10/// begin or end. It can be either:
11///
12/// 1. An instruction or
13/// 2. An EBB header.
14///
15/// This corresponds more or less to the lines in the textual form of Cranelift IR.
16#[derive(PartialEq, Eq, Clone, Copy)]
17pub struct ProgramPoint(u32);
18
19impl From<Inst> for ProgramPoint {
20    fn from(inst: Inst) -> Self {
21        let idx = inst.index();
22        debug_assert!(idx < (u32::MAX / 2) as usize);
23        Self((idx * 2) as u32)
24    }
25}
26
27impl From<Ebb> for ProgramPoint {
28    fn from(ebb: Ebb) -> Self {
29        let idx = ebb.index();
30        debug_assert!(idx < (u32::MAX / 2) as usize);
31        Self((idx * 2 + 1) as u32)
32    }
33}
34
35impl From<ValueDef> for ProgramPoint {
36    fn from(def: ValueDef) -> Self {
37        match def {
38            ValueDef::Result(inst, _) => inst.into(),
39            ValueDef::Param(ebb, _) => ebb.into(),
40        }
41    }
42}
43
44/// An expanded program point directly exposes the variants, but takes twice the space to
45/// represent.
46#[derive(PartialEq, Eq, Clone, Copy)]
47pub enum ExpandedProgramPoint {
48    /// An instruction in the function.
49    Inst(Inst),
50    /// An EBB header.
51    Ebb(Ebb),
52}
53
54impl ExpandedProgramPoint {
55    /// Get the instruction we know is inside.
56    pub fn unwrap_inst(self) -> Inst {
57        match self {
58            Self::Inst(x) => x,
59            Self::Ebb(x) => panic!("expected inst: {}", x),
60        }
61    }
62}
63
64impl From<Inst> for ExpandedProgramPoint {
65    fn from(inst: Inst) -> Self {
66        Self::Inst(inst)
67    }
68}
69
70impl From<Ebb> for ExpandedProgramPoint {
71    fn from(ebb: Ebb) -> Self {
72        Self::Ebb(ebb)
73    }
74}
75
76impl From<ValueDef> for ExpandedProgramPoint {
77    fn from(def: ValueDef) -> Self {
78        match def {
79            ValueDef::Result(inst, _) => inst.into(),
80            ValueDef::Param(ebb, _) => ebb.into(),
81        }
82    }
83}
84
85impl From<ProgramPoint> for ExpandedProgramPoint {
86    fn from(pp: ProgramPoint) -> Self {
87        if pp.0 & 1 == 0 {
88            Self::Inst(Inst::from_u32(pp.0 / 2))
89        } else {
90            Self::Ebb(Ebb::from_u32(pp.0 / 2))
91        }
92    }
93}
94
95impl fmt::Display for ExpandedProgramPoint {
96    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97        match *self {
98            Self::Inst(x) => write!(f, "{}", x),
99            Self::Ebb(x) => write!(f, "{}", x),
100        }
101    }
102}
103
104impl fmt::Display for ProgramPoint {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        let epp: ExpandedProgramPoint = (*self).into();
107        epp.fmt(f)
108    }
109}
110
111impl fmt::Debug for ExpandedProgramPoint {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        write!(f, "ExpandedProgramPoint({})", self)
114    }
115}
116
117impl fmt::Debug for ProgramPoint {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        write!(f, "ProgramPoint({})", self)
120    }
121}
122
123/// Context for ordering program points.
124///
125/// `ProgramPoint` objects don't carry enough information to be ordered independently, they need a
126/// context providing the program order.
127pub trait ProgramOrder {
128    /// Compare the program points `a` and `b` relative to this program order.
129    ///
130    /// Return `Less` if `a` appears in the program before `b`.
131    ///
132    /// This is declared as a generic such that it can be called with `Inst` and `Ebb` arguments
133    /// directly. Depending on the implementation, there is a good chance performance will be
134    /// improved for those cases where the type of either argument is known statically.
135    fn cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering
136    where
137        A: Into<ExpandedProgramPoint>,
138        B: Into<ExpandedProgramPoint>;
139
140    /// Is the range from `inst` to `ebb` just the gap between consecutive EBBs?
141    ///
142    /// This returns true if `inst` is the terminator in the EBB immediately before `ebb`.
143    fn is_ebb_gap(&self, inst: Inst, ebb: Ebb) -> bool;
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149    use crate::entity::EntityRef;
150    use crate::ir::{Ebb, Inst};
151    use alloc::string::ToString;
152
153    #[test]
154    fn convert() {
155        let i5 = Inst::new(5);
156        let b3 = Ebb::new(3);
157
158        let pp1: ProgramPoint = i5.into();
159        let pp2: ProgramPoint = b3.into();
160
161        assert_eq!(pp1.to_string(), "inst5");
162        assert_eq!(pp2.to_string(), "ebb3");
163    }
164}