calyx_opt/passes/
dead_group_removal.rs

1use crate::traversal::{Action, Named, VisResult, Visitor};
2use calyx_ir::{self as ir, LibrarySignatures};
3use std::collections::HashSet;
4
5/// Removes unused groups and combinational groups from components.
6/// A group is considered in use when it shows up in an [ir::Enable].
7/// A combinational group is considered in use when it is a part of an
8/// [ir::If] or [ir::While] or [ir::Invoke].
9#[derive(Default)]
10pub struct DeadGroupRemoval {
11    used_groups: HashSet<ir::Id>,
12    used_comb_groups: HashSet<ir::Id>,
13}
14
15impl DeadGroupRemoval {
16    /// A function that in-place updates a Vec with the name of the parent
17    /// of a port, if that port parent is a Group
18    fn push_group_names(
19        group_names: &mut Vec<ir::Id>,
20        port: &ir::RRC<ir::Port>,
21    ) {
22        if let ir::PortParent::Group(group_wref) = &port.borrow().parent {
23            group_names.push(group_wref.upgrade().borrow().name());
24        }
25    }
26}
27
28impl Named for DeadGroupRemoval {
29    fn name() -> &'static str {
30        "dead-group-removal"
31    }
32
33    fn description() -> &'static str {
34        "removes unsed groups from components"
35    }
36}
37
38impl Visitor for DeadGroupRemoval {
39    fn enable(
40        &mut self,
41        s: &mut ir::Enable,
42        _comp: &mut ir::Component,
43        _sigs: &ir::LibrarySignatures,
44        _comps: &[ir::Component],
45    ) -> VisResult {
46        self.used_groups.insert(s.group.borrow().name());
47        Ok(Action::Continue)
48    }
49
50    fn fsm_enable(
51        &mut self,
52        s: &mut calyx_ir::FSMEnable,
53        _comp: &mut calyx_ir::Component,
54        _sigs: &LibrarySignatures,
55        _comps: &[calyx_ir::Component],
56    ) -> VisResult {
57        // add all groups that are assigned to / read from, by the parent FSM
58        self.used_groups.extend(
59            s.fsm
60                .borrow()
61                .get_called_port_parents(DeadGroupRemoval::push_group_names),
62        );
63        Ok(Action::Continue)
64    }
65
66    fn static_enable(
67        &mut self,
68        s: &mut ir::StaticEnable,
69        _comp: &mut ir::Component,
70        _sigs: &ir::LibrarySignatures,
71        _comps: &[ir::Component],
72    ) -> VisResult {
73        self.used_groups.insert(s.group.borrow().name());
74        Ok(Action::Continue)
75    }
76
77    fn finish_if(
78        &mut self,
79        s: &mut ir::If,
80        _comp: &mut ir::Component,
81        _sigs: &ir::LibrarySignatures,
82        _comps: &[ir::Component],
83    ) -> VisResult {
84        if let Some(cg) = &s.cond {
85            self.used_comb_groups.insert(cg.borrow().name());
86        }
87        Ok(Action::Continue)
88    }
89
90    fn invoke(
91        &mut self,
92        s: &mut ir::Invoke,
93        _comp: &mut ir::Component,
94        _sigs: &ir::LibrarySignatures,
95        _comps: &[ir::Component],
96    ) -> VisResult {
97        if let Some(cg) = &s.comb_group {
98            self.used_comb_groups.insert(cg.borrow().name());
99        }
100        Ok(Action::Continue)
101    }
102
103    fn finish_while(
104        &mut self,
105        s: &mut ir::While,
106        _comp: &mut ir::Component,
107        _sigs: &ir::LibrarySignatures,
108        _comps: &[ir::Component],
109    ) -> VisResult {
110        if let Some(cg) = &s.cond {
111            self.used_comb_groups.insert(cg.borrow().name());
112        }
113        Ok(Action::Continue)
114    }
115
116    fn finish(
117        &mut self,
118        comp: &mut ir::Component,
119        _sigs: &LibrarySignatures,
120        _comps: &[ir::Component],
121    ) -> VisResult {
122        // Groups that are driven by their `go` signals should not be
123        // removed.
124        for group in comp.get_groups().iter() {
125            for assign in &group.borrow().assignments {
126                let dst = assign.dst.borrow();
127                if dst.is_hole() && dst.name == "go" {
128                    self.used_groups.insert(dst.get_parent_name());
129                }
130            }
131        }
132
133        for assign in &comp.continuous_assignments {
134            let dst = assign.dst.borrow();
135            if dst.is_hole() && dst.name == "go" {
136                self.used_groups.insert(dst.get_parent_name());
137            }
138        }
139
140        for group in comp.get_static_groups().iter() {
141            for assign in &group.borrow().assignments {
142                let dst = assign.dst.borrow();
143                if dst.is_hole() && dst.name == "go" {
144                    self.used_groups.insert(dst.get_parent_name());
145                }
146            }
147        }
148
149        // add all groups invoked by each fsm
150        for fsm in comp.get_fsms().iter() {
151            self.used_groups.extend(
152                fsm.borrow().get_called_port_parents(
153                    DeadGroupRemoval::push_group_names,
154                ),
155            );
156        }
157
158        // Remove Groups that are not used
159        comp.get_groups_mut()
160            .retain(|g| self.used_groups.contains(&g.borrow().name()));
161        comp.get_static_groups_mut()
162            .retain(|g| self.used_groups.contains(&g.borrow().name()));
163        comp.comb_groups
164            .retain(|cg| self.used_comb_groups.contains(&cg.borrow().name()));
165
166        Ok(Action::Stop)
167    }
168}