midenc_hir/ir/
cfg.rs

1mod diff;
2mod scc;
3mod visit;
4
5pub use self::{
6    diff::{CfgDiff, CfgUpdate, CfgUpdateKind, GraphDiff},
7    scc::StronglyConnectedComponents,
8    visit::{DefaultGraphVisitor, GraphVisitor, LazyDfsVisitor, PostOrderIter, PreOrderIter},
9};
10
11/// This is an abstraction over graph-like structures used in the IR:
12///
13/// * The CFG of a region, i.e. graph of blocks
14/// * The CFG reachable from a single block, i.e. graph of blocks
15/// * The dominator graph of a region, i.e. graph of dominator nodes
16/// * The call graph of a program
17/// * etc...
18///
19/// It isn't strictly necessary, but it provides some uniformity, and is useful particularly
20/// for implementation of various analyses.
21pub trait Graph {
22    /// The type of node represented in the graph.
23    ///
24    /// Typically this should be a pointer-like reference type, cheap to copy/clone.
25    type Node: Clone;
26    /// Type used to iterate over children of a node in the graph.
27    type ChildIter: ExactSizeIterator<Item = Self::Node>;
28    /// The type used to represent an edge in the graph.
29    ///
30    /// This should be cheap to copy/clone.
31    type Edge;
32    /// Type used to iterate over child edges of a node in the graph.
33    type ChildEdgeIter: ExactSizeIterator<Item = Self::Edge>;
34
35    /// An empty graph has no nodes.
36    #[inline]
37    fn is_empty(&self) -> bool {
38        self.size() == 0
39    }
40    /// Get the number of nodes in this graph
41    fn size(&self) -> usize;
42    /// Get the entry node of the graph.
43    ///
44    /// It is expected that a graph always has an entry. As such, this function will panic if
45    /// called on an "empty" graph. You should check whether the graph is empty _first_, if you
46    /// are working with a possibly-empty graph.
47    fn entry_node(&self) -> Self::Node;
48    /// Get an iterator over the children of `parent`
49    fn children(parent: Self::Node) -> Self::ChildIter;
50    /// Get an iterator over the children edges of `parent`
51    fn children_edges(parent: Self::Node) -> Self::ChildEdgeIter;
52    /// Return the destination node of an edge.
53    fn edge_dest(edge: Self::Edge) -> Self::Node;
54}
55
56impl<G: Graph> Graph for &G {
57    type ChildEdgeIter = <G as Graph>::ChildEdgeIter;
58    type ChildIter = <G as Graph>::ChildIter;
59    type Edge = <G as Graph>::Edge;
60    type Node = <G as Graph>::Node;
61
62    fn is_empty(&self) -> bool {
63        (**self).is_empty()
64    }
65
66    fn size(&self) -> usize {
67        (**self).size()
68    }
69
70    fn entry_node(&self) -> Self::Node {
71        (**self).entry_node()
72    }
73
74    fn children(parent: Self::Node) -> Self::ChildIter {
75        <G as Graph>::children(parent)
76    }
77
78    fn children_edges(parent: Self::Node) -> Self::ChildEdgeIter {
79        <G as Graph>::children_edges(parent)
80    }
81
82    fn edge_dest(edge: Self::Edge) -> Self::Node {
83        <G as Graph>::edge_dest(edge)
84    }
85}
86
87/// An [InvertibleGraph] is a [Graph] which can be "inverted", i.e. edges are reversed.
88///
89/// Technically, any graph is invertible, however we are primarily interested in supporting graphs
90/// for which an inversion of itself has some semantic value. For example, visiting a CFG in
91/// reverse is useful in various contexts, such as constructing dominator trees.
92///
93/// This is primarily consumed via [Inverse].
94pub trait InvertibleGraph: Graph {
95    /// The type of this graph's inversion
96    ///
97    /// This is primarily useful in cases where you inverse the inverse of a graph - by allowing
98    /// the types to differ, you can recover the original graph, rather than having to emulate
99    /// both uninverted graphs using the inverse type.
100    ///
101    /// See [Inverse] for an example of how this is used.
102    type Inverse: Graph;
103    /// The type of iterator used to visit "inverted" children of a node in this graph, i.e.
104    /// the predecessors.
105    type InvertibleChildIter: ExactSizeIterator<Item = Self::Node>;
106    /// The type of iterator used to obtain the set of "inverted" children edges of a node in this
107    /// graph, i.e. the predecessor edges.
108    type InvertibleChildEdgeIter: ExactSizeIterator<Item = Self::Edge>;
109
110    /// Get an iterator over the predecessors of `parent`.
111    ///
112    /// NOTE: `parent` in this case will actually be a child of the nodes in the iterator, but we
113    /// preserve the naming so as to make it apparent we are working with an inversion of the
114    /// original graph.
115    fn inverse_children(parent: Self::Node) -> Self::InvertibleChildIter;
116    /// Get an iterator over the predecessor edges of `parent`.
117    fn inverse_children_edges(parent: Self::Node) -> Self::InvertibleChildEdgeIter;
118    /// Obtain the inversion of this graph
119    fn inverse(self) -> Self::Inverse;
120}
121
122/// This is a wrapper type for [Graph] implementations, used to indicate that iterating a
123/// graph should be iterated in "inverse" order, the semantics of which depend on the graph.
124///
125/// If used with an [InvertibleGraph], it uses the graph impls inverse iterators. If used with a
126/// graph that is _not_ invertible, it uses the graph impls normal iterators. Effectively, this is
127/// a specialization marker type.
128pub struct Inverse<G: Graph> {
129    graph: G,
130}
131
132impl<G: Graph> Inverse<G> {
133    /// Construct an inversion over `graph`
134    #[inline]
135    pub fn new(graph: G) -> Self {
136        Self { graph }
137    }
138}
139
140impl<G: InvertibleGraph> Graph for Inverse<G> {
141    type ChildEdgeIter = InverseChildEdgeIter<<G as InvertibleGraph>::InvertibleChildEdgeIter>;
142    type ChildIter = InverseChildIter<<G as InvertibleGraph>::InvertibleChildIter>;
143    type Edge = <G as Graph>::Edge;
144    type Node = <G as Graph>::Node;
145
146    fn is_empty(&self) -> bool {
147        self.graph.is_empty()
148    }
149
150    fn size(&self) -> usize {
151        self.graph.size()
152    }
153
154    fn entry_node(&self) -> Self::Node {
155        self.graph.entry_node()
156    }
157
158    fn children(parent: Self::Node) -> Self::ChildIter {
159        InverseChildIter::new(<G as InvertibleGraph>::inverse_children(parent))
160    }
161
162    fn children_edges(parent: Self::Node) -> Self::ChildEdgeIter {
163        InverseChildEdgeIter::new(<G as InvertibleGraph>::inverse_children_edges(parent))
164    }
165
166    fn edge_dest(edge: Self::Edge) -> Self::Node {
167        <G as Graph>::edge_dest(edge)
168    }
169}
170
171impl<G: InvertibleGraph> InvertibleGraph for Inverse<G> {
172    type Inverse = G;
173    type InvertibleChildEdgeIter = <G as Graph>::ChildEdgeIter;
174    type InvertibleChildIter = <G as Graph>::ChildIter;
175
176    fn inverse_children(parent: Self::Node) -> Self::InvertibleChildIter {
177        <G as Graph>::children(parent)
178    }
179
180    fn inverse_children_edges(parent: Self::Node) -> Self::InvertibleChildEdgeIter {
181        <G as Graph>::children_edges(parent)
182    }
183
184    fn inverse(self) -> Self::Inverse {
185        self.graph
186    }
187}
188
189/// An iterator returned by `children` that iterates over `inverse_children` of the underlying graph
190#[doc(hidden)]
191pub struct InverseChildIter<I> {
192    iter: I,
193}
194
195impl<I: ExactSizeIterator> InverseChildIter<I> {
196    pub fn new(iter: I) -> Self {
197        Self { iter }
198    }
199}
200impl<I: ExactSizeIterator> ExactSizeIterator for InverseChildIter<I> {
201    #[inline]
202    fn len(&self) -> usize {
203        self.iter.len()
204    }
205
206    #[inline]
207    fn is_empty(&self) -> bool {
208        self.iter.is_empty()
209    }
210}
211impl<I: Iterator> Iterator for InverseChildIter<I> {
212    type Item = <I as Iterator>::Item;
213
214    default fn next(&mut self) -> Option<Self::Item> {
215        self.iter.next()
216    }
217}
218
219/// An iterator returned by `children_edges` that iterates over `inverse_children_edges` of the
220/// underlying graph.
221#[doc(hidden)]
222pub struct InverseChildEdgeIter<I> {
223    iter: I,
224}
225impl<I: ExactSizeIterator> InverseChildEdgeIter<I> {
226    pub fn new(iter: I) -> Self {
227        Self { iter }
228    }
229}
230impl<I: ExactSizeIterator> ExactSizeIterator for InverseChildEdgeIter<I> {
231    #[inline]
232    fn len(&self) -> usize {
233        self.iter.len()
234    }
235
236    #[inline]
237    fn is_empty(&self) -> bool {
238        self.iter.is_empty()
239    }
240}
241impl<I: Iterator> Iterator for InverseChildEdgeIter<I> {
242    type Item = <I as Iterator>::Item;
243
244    default fn next(&mut self) -> Option<Self::Item> {
245        self.iter.next()
246    }
247}