calyx_opt/analysis/
variable_detection.rs

1use super::{GraphAnalysis, read_write_set::AssignmentAnalysis};
2use crate::analysis::ShareSet;
3use calyx_ir::{self as ir, RRC};
4
5/// Detects if a group is solely being used to update a register.
6pub struct VariableDetection;
7
8impl VariableDetection {
9    /// A group is variable like if it:
10    ///  - among write to state_shareable components, there is only one write
11    ///  - has `@go` port equal to `1'd1`
12    ///  - has `g[done] = cell.done`
13    ///
14    /// Returns the name of the cell if such a group is detected,
15    /// otherwise returns `None`.
16    pub fn variable_like(
17        group_ref: &RRC<ir::Group>,
18        state_share: &ShareSet,
19    ) -> Option<(ir::CellType, ir::Id)> {
20        let group = group_ref.borrow();
21
22        let writes = group
23            .assignments
24            .iter()
25            .analysis()
26            .cell_writes()
27            .filter(|cell| state_share.is_shareable_component(cell))
28            .collect::<Vec<_>>();
29
30        if writes.len() != 1 {
31            log::debug!(
32                "`{}' is not VariableLike: Writes performed to multiple cells",
33                group.name()
34            );
35            // failed writes check
36            return None;
37        }
38
39        let cell = writes[0].borrow();
40
41        // check if 1 is being written into go port. This also checks
42        // if guard is empty, because if it isn't this would show up as
43        // a write
44        let graph = GraphAnalysis::from(&*group);
45        let go_port =
46            cell.find_unique_with_attr(ir::NumAttr::Go).ok().flatten()?;
47        let activation = graph
48            .writes_to(&go_port.borrow())
49            .map(|src| src.borrow().is_constant(1, 1))
50            .collect::<Vec<_>>();
51        if activation.len() != 1 || (!activation.is_empty() && !activation[0]) {
52            log::debug!(
53                "`{}' is not variableLike: Assignment to cell's go port is not 1'd1",
54                group.name()
55            );
56            // failed write_en check
57            return None;
58        }
59
60        // check to see if `cell.done` is written into `g[done]`
61        let activation = graph
62            .writes_to(&group.get("done").borrow())
63            // Handle g[done] = g ? 1'd1
64            .filter(|src| !src.borrow().is_constant(1, 1))
65            .map(|src| src.borrow().get_parent_name() == cell.name())
66            .collect::<Vec<_>>();
67        if activation.len() != 1 || (!activation.is_empty() && !activation[0]) {
68            log::debug!(
69                "`{}' is not variableLike: Assignment to group's done port is not cell.done",
70                group.name()
71            );
72            // failed g[done] = reg.done check
73            return None;
74        }
75
76        Some((cell.prototype.clone(), cell.name()))
77    }
78}