calyx_opt/passes/
default_assigns.rs

1use crate::analysis::AssignmentAnalysis;
2use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor};
3use calyx_ir::{self as ir, LibrarySignatures};
4use calyx_utils::{CalyxResult, Error};
5use itertools::Itertools;
6use std::collections::HashMap;
7
8/// Adds default assignments to all non-`@data` ports of an instance.
9pub struct DefaultAssigns {
10    /// Mapping from component to data ports
11    data_ports: HashMap<ir::Id, Vec<ir::Id>>,
12}
13
14impl Named for DefaultAssigns {
15    fn name() -> &'static str {
16        "default-assigns"
17    }
18
19    fn description() -> &'static str {
20        "adds default assignments to all non-`@data` ports of an instance."
21    }
22}
23
24impl ConstructVisitor for DefaultAssigns {
25    fn from(ctx: &ir::Context) -> CalyxResult<Self>
26    where
27        Self: Sized,
28    {
29        let data_ports = ctx
30            .lib
31            .signatures()
32            .map(|sig| {
33                let ports = sig.signature.iter().filter_map(|p| {
34                    if p.direction == ir::Direction::Input
35                        && !p.attributes.has(ir::BoolAttr::Data)
36                        && !p.attributes.has(ir::BoolAttr::Clk)
37                        && !p.attributes.has(ir::BoolAttr::Reset)
38                    {
39                        Some(p.name())
40                    } else {
41                        None
42                    }
43                });
44                (sig.name, ports.collect())
45            })
46            .collect();
47        Ok(Self { data_ports })
48    }
49
50    fn clear_data(&mut self) {
51        /* shared across components */
52    }
53}
54
55impl Visitor for DefaultAssigns {
56    fn start(
57        &mut self,
58        comp: &mut ir::Component,
59        sigs: &LibrarySignatures,
60        _comps: &[ir::Component],
61    ) -> VisResult {
62        if !comp.is_structural() {
63            return Err(Error::pass_assumption(
64                Self::name(),
65                format!("component {} is not purely structural", comp.name),
66            ));
67        }
68
69        // We only need to consider write set of the continuous assignments
70        let writes = comp
71            .continuous_assignments
72            .iter()
73            .analysis()
74            .writes()
75            .group_by_cell();
76
77        let mut assigns = Vec::new();
78
79        let mt = vec![];
80        let cells = comp.cells.iter().cloned().collect_vec();
81        let mut builder = ir::Builder::new(comp, sigs);
82
83        for cr in &cells {
84            let cell = cr.borrow();
85            let Some(typ) = cell.type_name() else {
86                continue;
87            };
88            let Some(required) = self.data_ports.get(&typ) else {
89                continue;
90            };
91
92            // For all the assignments not in the write set, add a default assignment
93            let cell_writes = writes
94                .get(&cell.name())
95                .unwrap_or(&mt)
96                .iter()
97                .map(|p| {
98                    let p = p.borrow();
99                    p.name
100                })
101                .collect_vec();
102
103            assigns.extend(
104                required.iter().filter(|p| !cell_writes.contains(p)).map(
105                    |name| {
106                        let port = cell.get(name);
107                        let zero = builder.add_constant(0, port.borrow().width);
108                        let assign: ir::Assignment<ir::Nothing> = builder
109                            .build_assignment(
110                                cell.get(name),
111                                zero.borrow().get("out"),
112                                ir::Guard::True,
113                            );
114                        log::info!(
115                            "Adding {}",
116                            ir::Printer::assignment_to_str(&assign)
117                        );
118                        assign
119                    },
120                ),
121            );
122        }
123
124        comp.continuous_assignments.extend(assigns);
125
126        // Purely structural pass
127        Ok(Action::Stop)
128    }
129}