calyx_opt/passes/
collapse_control.rs

1use crate::traversal::{Action, Named, VisResult, Visitor};
2use calyx_ir::{self as ir, LibrarySignatures};
3
4#[derive(Default)]
5/// Collapses and de-nests control constructs.
6///
7/// Running this pass removes unnecessary FSM transitions and compilation
8/// groups during the lowering phase. If a seq is marked with @new_fsm, then
9/// we don't collapse it, since we need that fsm transition to transition
10/// from our old fsm to our new one.
11///
12/// # Example
13/// 1. Collapses nested `seq`:
14/// ```
15/// seq {
16///     seq { A; B }
17///     C;
18/// }
19/// ```
20/// into
21/// ```
22/// seq { A; B C; }
23/// ```
24/// 2. Collapses nested `par`:
25/// ```
26/// par {
27///     par { A; B }
28///     C;
29/// }
30/// ```
31/// into
32/// ```
33/// par { A; B C; }
34/// ```
35///
36/// 3. Collapses nested `static seq` in the same way as 1
37/// 4. Collapses nested `static par` in the same way as 2
38/// 5. Collapses `static repeat`:
39/// Collapse
40/// ```
41/// static repeat 0 { ** body ** }
42/// ```
43/// into empty control
44/// and
45/// ```
46/// static repeat 1 {** body **}
47/// ```
48/// into
49/// ```
50/// ** body **
51/// ```
52pub struct CollapseControl {}
53
54impl Named for CollapseControl {
55    fn name() -> &'static str {
56        "collapse-control"
57    }
58
59    fn description() -> &'static str {
60        "Collapse nested seq and par."
61    }
62}
63
64impl Visitor for CollapseControl {
65    /// Collapse seq { seq { A }; B } into seq { A; B }.
66    fn finish_seq(
67        &mut self,
68        s: &mut ir::Seq,
69        _comp: &mut ir::Component,
70        _c: &LibrarySignatures,
71        _comps: &[ir::Component],
72    ) -> VisResult {
73        if s.stmts.is_empty() {
74            return Ok(Action::change(ir::Control::empty()));
75        }
76        if s.stmts.len() == 1 {
77            return Ok(Action::change(s.stmts.pop().unwrap()));
78        }
79        let mut seqs: Vec<ir::Control> = vec![];
80        for con in s.stmts.drain(..) {
81            if con.has_attribute(ir::BoolAttr::NewFSM) {
82                // if con has attribute new_fsm, then we do *not* want to collapse
83                seqs.push(con)
84            } else {
85                match con {
86                    ir::Control::Seq(mut data) => {
87                        seqs.append(&mut data.stmts);
88                    }
89                    _ => seqs.push(con),
90                }
91            }
92        }
93        s.stmts = seqs;
94        Ok(Action::Continue)
95    }
96
97    /// Collapse par { par { A }; B } into par { A; B }.
98    fn finish_par(
99        &mut self,
100        s: &mut ir::Par,
101        _comp: &mut ir::Component,
102        _c: &LibrarySignatures,
103        _comps: &[ir::Component],
104    ) -> VisResult {
105        if s.stmts.is_empty() {
106            return Ok(Action::change(ir::Control::empty()));
107        }
108        if s.stmts.len() == 1 {
109            return Ok(Action::change(s.stmts.pop().unwrap()));
110        }
111        let mut pars: Vec<ir::Control> = vec![];
112        for con in s.stmts.drain(..) {
113            match con {
114                ir::Control::Par(mut data) => {
115                    pars.append(&mut data.stmts);
116                }
117                _ => pars.push(con),
118            }
119        }
120        s.stmts = pars;
121        Ok(Action::Continue)
122    }
123
124    /// Collapse static par {static par {A; B;}} into static par {A; B; }
125    fn finish_static_par(
126        &mut self,
127        s: &mut ir::StaticPar,
128        _comp: &mut ir::Component,
129        _sigs: &LibrarySignatures,
130        _comps: &[ir::Component],
131    ) -> VisResult {
132        if s.stmts.is_empty() {
133            return Ok(Action::static_change(ir::StaticControl::empty()));
134        }
135        if s.stmts.len() == 1 {
136            return Ok(Action::static_change(s.stmts.pop().unwrap()));
137        }
138        let mut pars: Vec<ir::StaticControl> = vec![];
139        for con in s.stmts.drain(..) {
140            match con {
141                ir::StaticControl::Par(mut data) => {
142                    pars.append(&mut data.stmts);
143                }
144                _ => pars.push(con),
145            }
146        }
147        s.stmts = pars;
148        Ok(Action::Continue)
149    }
150
151    ///Collase static seq {static seq {A; B; }} into static seq {A; B;}
152    fn finish_static_seq(
153        &mut self,
154        s: &mut ir::StaticSeq,
155        _comp: &mut ir::Component,
156        _sigs: &LibrarySignatures,
157        _comps: &[ir::Component],
158    ) -> VisResult {
159        if s.stmts.is_empty() {
160            return Ok(Action::static_change(ir::StaticControl::empty()));
161        }
162        if s.stmts.len() == 1 {
163            return Ok(Action::static_change(s.stmts.pop().unwrap()));
164        }
165        let mut seqs: Vec<ir::StaticControl> = vec![];
166        for con in s.stmts.drain(..) {
167            match con {
168                ir::StaticControl::Seq(mut data) => {
169                    seqs.append(&mut data.stmts);
170                }
171                _ => seqs.push(con),
172            }
173        }
174        s.stmts = seqs;
175        Ok(Action::Continue)
176    }
177
178    /// Collapse
179    /// ```
180    /// static repeat 0 { ** body ** }
181    /// ```
182    /// into empty control
183    /// and
184    /// ```
185    /// static repeat 1 {** body **}
186    /// into
187    /// ```
188    /// ** body **
189    /// ```
190    fn finish_static_repeat(
191        &mut self,
192        s: &mut ir::StaticRepeat,
193        _comp: &mut ir::Component,
194        _sigs: &LibrarySignatures,
195        _comps: &[ir::Component],
196    ) -> VisResult {
197        if s.num_repeats == 0 {
198            return Ok(Action::static_change(ir::StaticControl::empty()));
199        }
200        if s.num_repeats == 1 {
201            return Ok(Action::static_change(s.body.take_static_control()));
202        }
203        Ok(Action::Continue)
204    }
205
206    fn finish_repeat(
207        &mut self,
208        s: &mut ir::Repeat,
209        _comp: &mut ir::Component,
210        _sigs: &LibrarySignatures,
211        _comps: &[ir::Component],
212    ) -> VisResult {
213        if s.num_repeats == 0 {
214            return Ok(Action::change(ir::Control::empty()));
215        }
216        if s.num_repeats == 1 {
217            return Ok(Action::change(s.body.take_control()));
218        }
219        Ok(Action::Continue)
220    }
221}