calyx_opt/passes/
collapse_control.rs

1use crate::traversal::{Action, Named, VisResult, Visitor};
2use calyx_ir::{self as ir, GetAttributes, 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/// ```
40/// static repeat 0 { ** body ** }
41/// ```
42/// into empty control
43/// and
44/// ```
45/// static repeat 1 {** body **}
46/// ```
47/// into
48/// ```
49/// ** body **
50/// ```
51pub struct CollapseControl {}
52
53impl Named for CollapseControl {
54    fn name() -> &'static str {
55        "collapse-control"
56    }
57
58    fn description() -> &'static str {
59        "Collapse nested seq and par."
60    }
61}
62
63impl Visitor for CollapseControl {
64    /// Collapse seq { seq { A }; B } into seq { A; B }.
65    fn finish_seq(
66        &mut self,
67        s: &mut ir::Seq,
68        _comp: &mut ir::Component,
69        _c: &LibrarySignatures,
70        _comps: &[ir::Component],
71    ) -> VisResult {
72        if s.stmts.is_empty() {
73            return Ok(Action::change(ir::Control::empty()));
74        }
75        if s.stmts.len() == 1 {
76            return Ok(Action::change(s.stmts.pop().unwrap()));
77        }
78        let mut seqs: Vec<ir::Control> = vec![];
79        for con in s.stmts.drain(..) {
80            if con.has_attribute(ir::BoolAttr::NewFSM) {
81                // if con has attribute new_fsm, then we do *not* want to collapse
82                seqs.push(con)
83            } else {
84                match con {
85                    ir::Control::Seq(mut data) => {
86                        seqs.append(&mut data.stmts);
87                    }
88                    _ => seqs.push(con),
89                }
90            }
91        }
92        s.stmts = seqs;
93        Ok(Action::Continue)
94    }
95
96    /// Collapse par { par { A }; B } into par { A; B }.
97    fn finish_par(
98        &mut self,
99        s: &mut ir::Par,
100        _comp: &mut ir::Component,
101        _c: &LibrarySignatures,
102        _comps: &[ir::Component],
103    ) -> VisResult {
104        if s.stmts.is_empty() {
105            return Ok(Action::change(ir::Control::empty()));
106        }
107        if s.stmts.len() == 1 {
108            return Ok(Action::change(s.stmts.pop().unwrap()));
109        }
110        let mut pars: Vec<ir::Control> = vec![];
111        for con in s.stmts.drain(..) {
112            match con {
113                ir::Control::Par(mut data) => {
114                    pars.append(&mut data.stmts);
115                }
116                _ => pars.push(con),
117            }
118        }
119        s.stmts = pars;
120        Ok(Action::Continue)
121    }
122
123    /// Collapse static par {static par {A; B;}} into static par {A; B; }
124    fn finish_static_par(
125        &mut self,
126        s: &mut ir::StaticPar,
127        _comp: &mut ir::Component,
128        _sigs: &LibrarySignatures,
129        _comps: &[ir::Component],
130    ) -> VisResult {
131        if s.stmts.is_empty() {
132            return Ok(Action::static_change(ir::StaticControl::empty()));
133        }
134        if s.stmts.len() == 1 {
135            // Want to preserve @one_hot attribute.
136            let mut replacement_ctrl = s.stmts.pop().unwrap();
137            let attrs = std::mem::take(&mut s.attributes);
138            replacement_ctrl
139                .get_mut_attributes()
140                .copy_from(attrs, vec![ir::BoolAttr::OneHot]);
141
142            return Ok(Action::static_change(replacement_ctrl));
143        }
144        let mut pars: Vec<ir::StaticControl> = vec![];
145        for con in s.stmts.drain(..) {
146            match con {
147                ir::StaticControl::Par(mut data) => {
148                    pars.append(&mut data.stmts);
149                }
150                _ => pars.push(con),
151            }
152        }
153        s.stmts = pars;
154        Ok(Action::Continue)
155    }
156
157    ///Collase static seq {static seq {A; B; }} into static seq {A; B;}
158    fn finish_static_seq(
159        &mut self,
160        s: &mut ir::StaticSeq,
161        _comp: &mut ir::Component,
162        _sigs: &LibrarySignatures,
163        _comps: &[ir::Component],
164    ) -> VisResult {
165        if s.stmts.is_empty() {
166            return Ok(Action::static_change(ir::StaticControl::empty()));
167        }
168        if s.stmts.len() == 1 {
169            // Want to preserve @one_hot attribute.
170            let mut replacement_ctrl = s.stmts.pop().unwrap();
171            let attrs = std::mem::take(&mut s.attributes);
172            replacement_ctrl
173                .get_mut_attributes()
174                .copy_from(attrs, vec![ir::BoolAttr::OneHot]);
175            return Ok(Action::static_change(replacement_ctrl));
176        }
177        let mut seqs: Vec<ir::StaticControl> = vec![];
178        for con in s.stmts.drain(..) {
179            match con {
180                ir::StaticControl::Seq(mut data) => {
181                    seqs.append(&mut data.stmts);
182                }
183                _ => seqs.push(con),
184            }
185        }
186        s.stmts = seqs;
187        Ok(Action::Continue)
188    }
189
190    /// Collapse
191    /// ```
192    /// static repeat 0 { ** body ** }
193    /// ```
194    /// into empty control
195    /// and
196    /// ```
197    /// static repeat 1 {** body **}
198    /// into
199    /// ```
200    /// ** body **
201    /// ```
202    fn finish_static_repeat(
203        &mut self,
204        s: &mut ir::StaticRepeat,
205        _comp: &mut ir::Component,
206        _sigs: &LibrarySignatures,
207        _comps: &[ir::Component],
208    ) -> VisResult {
209        if s.num_repeats == 0 {
210            return Ok(Action::static_change(ir::StaticControl::empty()));
211        }
212        if s.num_repeats == 1 {
213            return Ok(Action::static_change(s.body.take_static_control()));
214        }
215        Ok(Action::Continue)
216    }
217
218    fn finish_repeat(
219        &mut self,
220        s: &mut ir::Repeat,
221        _comp: &mut ir::Component,
222        _sigs: &LibrarySignatures,
223        _comps: &[ir::Component],
224    ) -> VisResult {
225        if s.num_repeats == 0 {
226            return Ok(Action::change(ir::Control::empty()));
227        }
228        if s.num_repeats == 1 {
229            return Ok(Action::change(s.body.take_control()));
230        }
231        Ok(Action::Continue)
232    }
233}