calyx_opt/passes_experimental/
hole_inliner.rs1use crate::traversal::{Action, Named, VisResult, Visitor};
2use crate::{analysis::GraphAnalysis, passes::TopDownCompileControl};
3use calyx_ir::{self as ir, LibrarySignatures, RRC, structure};
4use calyx_utils::Error;
5use ir::Nothing;
6use std::{collections::HashMap, rc::Rc};
7
8#[derive(Default)]
9pub struct HoleInliner;
16
17impl Named for HoleInliner {
18 fn name() -> &'static str {
19 "hole-inliner"
20 }
21
22 fn description() -> &'static str {
23 "inlines holes"
24 }
25}
26
27type Store = HashMap<ir::Canonical, (RRC<ir::Port>, ir::Guard<ir::Nothing>)>;
28
29fn fixed_point(graph: &GraphAnalysis, map: &mut Store) {
53 let mut worklist = Vec::new();
55
56 let has_holes = |guard: &ir::Guard<Nothing>| {
58 guard.all_ports().iter().any(|p| p.borrow().is_hole())
59 };
60
61 for (key, (_, guard)) in map.iter() {
63 if !has_holes(guard) {
64 worklist.push(key.clone())
65 }
66 }
67
68 while !worklist.is_empty() {
69 let hole_key = worklist.pop().unwrap_or_else(|| unreachable!());
70 let (hole, new_guard) = map[&hole_key].clone();
71
72 for read in graph
74 .reads_from(&hole.borrow())
75 .filter(|p| p.borrow().is_hole())
76 {
77 let key = read.borrow().canonical();
79 map.entry(read.borrow().canonical())
80 .and_modify(|(_, guard)| {
81 guard.for_each(&mut |port| {
82 if port.borrow().canonical() == hole_key {
83 Some(new_guard.clone())
84 } else {
85 None
86 }
87 })
88 });
89 if !has_holes(&map[&key].1) {
91 worklist.push(key)
92 }
93 }
94 }
95}
96
97impl Visitor for HoleInliner {
98 fn start(
99 &mut self,
100 comp: &mut ir::Component,
101 sigs: &LibrarySignatures,
102 _comps: &[ir::Component],
103 ) -> VisResult {
104 let top_level = match &*comp.control.borrow() {
106 ir::Control::Empty(_) => return Ok(Action::Stop),
107 ir::Control::Enable(en) => Rc::clone(&en.group),
108 _ => {
109 return Err(Error::malformed_control(format!(
110 "{}: Control shoudl be a single enable. Try running `{}` before inlining.",
111 Self::name(),
112 TopDownCompileControl::name()
113 )));
114 }
115 };
116
117 let this_comp = Rc::clone(&comp.signature);
118 let mut builder = ir::Builder::new(comp, sigs);
119
120 let mut asgns = vec![
122 builder.build_assignment(
123 top_level.borrow().get("go"),
124 this_comp.borrow().get_unique_with_attr(ir::NumAttr::Go)?,
125 ir::Guard::True,
126 ),
127 builder.build_assignment(
128 this_comp.borrow().get_unique_with_attr(ir::NumAttr::Done)?,
129 top_level.borrow().get("done"),
130 ir::Guard::True,
131 ),
132 ];
133 builder.component.continuous_assignments.append(&mut asgns);
134
135 let analysis = GraphAnalysis::from(&*builder.component);
137 let subgraph = analysis
138 .edge_induced_subgraph(|src, dst| src.is_hole() || dst.is_hole());
139
140 if subgraph.has_cycles() {
142 return Err(Error::malformed_structure(
144 "Cyclic hole definition.".to_string(),
145 ));
146 }
147
148 let mut map: Store = HashMap::new();
150 let mut assignments = vec![];
151 for group in builder.component.get_groups().iter() {
152 let mut group = group.borrow_mut();
154 assignments.append(&mut group.assignments.drain(..).collect());
155 }
156
157 assert!(
158 builder.component.get_static_groups().is_empty(),
159 "should have removed static groups when inlining holes"
160 );
161
162 assignments.append(
164 &mut builder.component.continuous_assignments.drain(..).collect(),
165 );
166
167 for asgn in &mut assignments {
168 let dst = asgn.dst.borrow();
170 if dst.is_hole() {
171 map.entry(dst.canonical())
172 .and_modify(|(_, val)| {
173 *val = val.clone().or(asgn
175 .guard
176 .clone()
177 .and(ir::Guard::port(Rc::clone(&asgn.src))));
178 })
179 .or_insert((
180 Rc::clone(&asgn.dst),
181 asgn.guard
182 .clone()
183 .and(ir::Guard::port(Rc::clone(&asgn.src))),
184 ));
185 }
186 }
187
188 fixed_point(&subgraph, &mut map);
190
191 assignments.retain(|asgn| !asgn.dst.borrow().is_hole());
193
194 structure!(
197 builder;
198 let signal_on = constant(1, 1);
199 );
200 assignments.iter_mut().for_each(|asgn| {
201 if asgn.src.borrow().is_hole() {
202 let and_guard = ir::Guard::port(Rc::clone(&asgn.src));
203 *asgn.guard &= and_guard;
204 asgn.src = signal_on.borrow().get("out");
205 }
206 });
207
208 for asgn in &mut assignments {
210 asgn.guard.for_each(&mut |port| {
211 if port.borrow().is_hole() {
212 Some(map[&port.borrow().canonical()].1.clone())
213 } else {
214 None
215 }
216 })
217 }
218 comp.continuous_assignments = assignments;
219
220 comp.get_groups_mut().clear();
222 comp.get_static_groups_mut().clear();
223
224 Ok(Action::change(ir::Control::empty()))
226 }
227}