calyx_opt/analysis/
variable_detection.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use super::{GraphAnalysis, read_write_set::AssignmentAnalysis};
use crate::analysis::ShareSet;
use calyx_ir::{self as ir, RRC};

/// Detects if a group is solely being used to update a register.
pub struct VariableDetection;

impl VariableDetection {
    /// A group is variable like if it:
    ///  - among write to state_shareable components, there is only one write
    ///  - has `@go` port equal to `1'd1`
    ///  - has `g[done] = cell.done`
    ///
    /// Returns the name of the cell if such a group is detected,
    /// otherwise returns `None`.
    pub fn variable_like(
        group_ref: &RRC<ir::Group>,
        state_share: &ShareSet,
    ) -> Option<(ir::CellType, ir::Id)> {
        let group = group_ref.borrow();

        let writes = group
            .assignments
            .iter()
            .analysis()
            .cell_writes()
            .filter(|cell| state_share.is_shareable_component(cell))
            .collect::<Vec<_>>();

        if writes.len() != 1 {
            log::debug!(
                "`{}' is not VariableLike: Writes performed to multiple cells",
                group.name()
            );
            // failed writes check
            return None;
        }

        let cell = writes[0].borrow();

        // check if 1 is being written into go port. This also checks
        // if guard is empty, because if it isn't this would show up as
        // a write
        let graph = GraphAnalysis::from(&*group);
        let go_port =
            cell.find_unique_with_attr(ir::NumAttr::Go).ok().flatten()?;
        let activation = graph
            .writes_to(&go_port.borrow())
            .map(|src| src.borrow().is_constant(1, 1))
            .collect::<Vec<_>>();
        if activation.len() != 1 || (!activation.is_empty() && !activation[0]) {
            log::debug!(
                "`{}' is not variableLike: Assignment to cell's go port is not 1'd1",
                group.name()
            );
            // failed write_en check
            return None;
        }

        // check to see if `cell.done` is written into `g[done]`
        let activation = graph
            .writes_to(&group.get("done").borrow())
            // Handle g[done] = g ? 1'd1
            .filter(|src| !src.borrow().is_constant(1, 1))
            .map(|src| src.borrow().get_parent_name() == cell.name())
            .collect::<Vec<_>>();
        if activation.len() != 1 || (!activation.is_empty() && !activation[0]) {
            log::debug!(
                "`{}' is not variableLike: Assignment to group's done port is not cell.done",
                group.name()
            );
            // failed g[done] = reg.done check
            return None;
        }

        Some((cell.prototype.clone(), cell.name()))
    }
}