calyx_opt/passes/
default_assigns.rs1use 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
8pub struct DefaultAssigns {
10 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 }
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 let writes = comp
72 .continuous_assignments
73 .iter()
74 .analysis()
75 .writes()
76 .group_by_cell();
77
78 let mut assigns = Vec::new();
79
80 let mt = vec![];
81 let cells = comp.cells.iter().cloned().collect_vec();
82 let mut builder = ir::Builder::new(comp, sigs);
83
84 for cr in &cells {
85 let cell = cr.borrow();
86 let Some(typ) = cell.type_name() else {
87 continue;
88 };
89 let Some(required) = self.data_ports.get(&typ) else {
90 continue;
91 };
92
93 let mut cell_writes: Vec<ir::RRC<ir::Port>> = writes
96 .get(&cell.name())
97 .unwrap_or(&mt)
98 .iter()
99 .map(ir::RRC::clone)
100 .collect();
101
102 if cell.attributes.has(ir::BoolAttr::FSMControl) {
103 cell_writes
104 .extend(cell.ports().into_iter().map(ir::RRC::clone));
105 }
106
107 let cell_writes = cell_writes
108 .into_iter()
109 .map(|p| {
110 let p = p.borrow();
111 p.name
112 })
113 .collect_vec();
114
115 assigns.extend(
116 required.iter().filter(|p| (!cell_writes.contains(p))).map(
117 |name| {
118 let port = cell.get(name);
119 let zero = builder.add_constant(0, port.borrow().width);
120 let assign: ir::Assignment<ir::Nothing> = builder
121 .build_assignment(
122 cell.get(name),
123 zero.borrow().get("out"),
124 ir::Guard::True,
125 );
126 log::info!(
127 "Adding {}",
128 ir::Printer::assignment_to_str(&assign)
129 );
130 assign
131 },
132 ),
133 );
134 }
135
136 comp.continuous_assignments.extend(assigns);
137
138 Ok(Action::Stop)
140 }
141}