calyx_opt/analysis/
variable_detection.rs

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