calyx_opt/passes/
data_path_infer.rs1use crate::traversal::{Action, Named, VisResult, Visitor};
2use calyx_ir as ir;
3use ir::RRC;
4use std::{collections::HashSet, rc::Rc};
5
6#[derive(Default)]
7pub struct DataPathInfer {
21 control_cells: HashSet<ir::Id>,
23}
24
25impl Named for DataPathInfer {
26 fn name() -> &'static str {
27 "infer-data-path"
28 }
29
30 fn description() -> &'static str {
31 "Infers @data annotations for cells"
32 }
33}
34
35impl DataPathInfer {
36 #[inline]
37 fn mark_port_control(&mut self, port: &ir::Port) {
39 if Self::always_safe_src(port) || port.is_hole() {
40 log::debug!("`{}': safe port", port.canonical());
41 return;
42 }
43 log::debug!("`{}': control port", port.canonical());
44 self.control_cells.insert(port.get_parent_name());
45 }
46
47 #[inline]
48 fn always_safe_src(port: &ir::Port) -> bool {
52 port.attributes.has(ir::BoolAttr::Stable)
53 || port.attributes.has(ir::NumAttr::Done)
54 }
55
56 fn port_and_cg(
58 &mut self,
59 port: RRC<ir::Port>,
60 mb_cg: &Option<RRC<ir::CombGroup>>,
61 ) {
62 let cond_port = port.borrow();
63 assert!(!cond_port.is_hole());
64 self.mark_port_control(&cond_port);
65
66 if let Some(cgr) = mb_cg {
69 let cg = cgr.borrow();
70 for assign in &cg.assignments {
71 self.mark_port_control(&assign.src.borrow());
72 }
73 }
74 }
75
76 fn handle_assign<T: Clone>(&mut self, assign: &ir::Assignment<T>) {
78 let dst = assign.dst.borrow();
81 if dst.is_hole() || !dst.attributes.has(ir::BoolAttr::Data) {
82 let src = assign.src.borrow();
83 self.mark_port_control(&src);
84 }
85 assign.guard.all_ports().into_iter().for_each(|p| {
87 let port = p.borrow();
88 self.mark_port_control(&port);
89 });
90 }
91
92 fn iterate_assign<T: Clone>(&mut self, assign: &ir::Assignment<T>) {
93 let dst = assign.dst.borrow();
96 let src = assign.src.borrow();
97 if !dst.is_hole() {
98 let dst_cell = dst.get_parent_name();
99 if self.control_cells.contains(&dst_cell) {
100 self.mark_port_control(&src);
101 }
102 }
103 }
104}
105
106impl Visitor for DataPathInfer {
107 fn finish_if(
108 &mut self,
109 s: &mut ir::If,
110 _comp: &mut ir::Component,
111 _sigs: &ir::LibrarySignatures,
112 _comps: &[ir::Component],
113 ) -> VisResult {
114 self.port_and_cg(Rc::clone(&s.port), &s.cond);
115 Ok(Action::Continue)
116 }
117
118 fn finish_while(
119 &mut self,
120 s: &mut ir::While,
121 _comp: &mut ir::Component,
122 _sigs: &ir::LibrarySignatures,
123 _comps: &[ir::Component],
124 ) -> VisResult {
125 self.port_and_cg(Rc::clone(&s.port), &s.cond);
126 Ok(Action::Continue)
127 }
128
129 fn finish(
130 &mut self,
131 comp: &mut ir::Component,
132 _sigs: &ir::LibrarySignatures,
133 _comps: &[ir::Component],
134 ) -> VisResult {
135 self.control_cells.extend(comp.cells.iter().filter_map(|c| {
138 let cell = c.borrow();
139 if cell.attributes.has(ir::BoolAttr::Control) {
140 Some(cell.name())
141 } else {
142 None
143 }
144 }));
145
146 comp.for_each_assignment(|assign| self.handle_assign(assign));
148 comp.for_each_static_assignment(|assign| self.handle_assign(assign));
149
150 let mut old_len = 0;
153 let mut iter_count = 0;
154 while old_len != self.control_cells.len() {
155 old_len = self.control_cells.len();
156
157 comp.for_each_assignment(|assign| self.iterate_assign(assign));
158 comp.for_each_static_assignment(|assign| {
159 self.iterate_assign(assign)
160 });
161
162 iter_count += 1;
164 if iter_count > 5 {
165 log::warn!(
166 "Data path infer did not converge after 5 iterations"
167 );
168 }
169 }
170
171 for c in comp.cells.iter() {
173 let mut cell = c.borrow_mut();
174 if self.control_cells.contains(&cell.name()) {
175 cell.attributes.insert(ir::BoolAttr::Control, 1);
176 } else {
177 cell.attributes.insert(ir::BoolAttr::Data, 1);
178 }
179 }
180
181 Ok(Action::Stop)
182 }
183}