1use calyx_ir::{self as ir, RRC};
2use itertools::Itertools;
3use std::{collections::HashMap, iter, rc::Rc};
4
5#[derive(Clone)]
6pub struct AssignmentIterator<'a, T: 'a, I>
7where
8 I: Iterator<Item = &'a ir::Assignment<T>>,
9{
10 iter: I,
11}
12
13impl<'a, T: 'a, I> Iterator for AssignmentIterator<'a, T, I>
14where
15 I: Iterator<Item = &'a ir::Assignment<T>>,
16{
17 type Item = &'a ir::Assignment<T>;
18
19 fn next(&mut self) -> Option<Self::Item> {
20 self.iter.next()
21 }
22}
23
24impl<'a, T: 'a, I: 'a> AssignmentIterator<'a, T, I>
25where
26 I: Iterator<Item = &'a ir::Assignment<T>>,
27{
28 pub fn reads(
30 self,
31 ) -> PortIterator<impl Iterator<Item = RRC<ir::Port>> + 'a> {
32 PortIterator::new(self.flat_map(ReadWriteSet::port_reads))
33 }
34
35 pub fn writes(
37 self,
38 ) -> PortIterator<impl Iterator<Item = RRC<ir::Port>> + 'a> {
39 PortIterator::new(
40 self.map(|assign| Rc::clone(&assign.dst))
41 .filter(|port| !port.borrow().is_hole()),
42 )
43 }
44
45 pub fn must_writes(
49 self,
50 ) -> PortIterator<impl Iterator<Item = RRC<ir::Port>> + 'a> {
51 PortIterator::new(self.filter_map(|assignment| {
52 if assignment.guard.is_true() && !assignment.dst.borrow().is_hole()
53 {
54 Some(Rc::clone(&assignment.dst))
55 } else {
56 None
57 }
58 }))
59 }
60
61 pub fn uses(
63 self,
64 ) -> PortIterator<impl Iterator<Item = RRC<ir::Port>> + 'a> {
65 PortIterator::new(self.flat_map(|assign| {
66 assign
67 .guard
68 .all_ports()
69 .into_iter()
70 .chain(iter::once(Rc::clone(&assign.dst)))
71 .chain(iter::once(Rc::clone(&assign.src)))
72 .filter(|port| !port.borrow().is_hole())
73 }))
74 }
75
76 pub fn cell_reads(self) -> impl Iterator<Item = RRC<ir::Cell>> + 'a {
80 self.reads().cells()
81 }
82
83 pub fn cell_writes(self) -> impl Iterator<Item = RRC<ir::Cell>> + 'a {
85 self.writes().cells()
86 }
87
88 pub fn cell_uses(self) -> impl Iterator<Item = RRC<ir::Cell>> + 'a {
90 self.uses().cells()
91 }
92}
93
94impl<'a, T: 'a, I: 'a> AssignmentIterator<'a, T, I>
95where
96 I: Iterator<Item = &'a ir::Assignment<T>>,
97 I: Clone,
98 T: Clone,
99{
100 pub fn reads_and_writes(
102 self,
103 ) -> (
104 PortIterator<impl Iterator<Item = RRC<ir::Port>> + 'a>,
105 PortIterator<impl Iterator<Item = RRC<ir::Port>> + 'a>,
106 ) {
107 (self.clone().reads(), self.writes())
108 }
109}
110
111pub trait AssignmentAnalysis<'a, T: 'a>:
113 Iterator<Item = &'a ir::Assignment<T>>
114where
115 Self: Sized,
116{
117 fn analysis(self) -> AssignmentIterator<'a, T, Self> {
118 AssignmentIterator { iter: self }
119 }
120}
121
122impl<'a, T: 'a, I: 'a> AssignmentAnalysis<'a, T> for I where
123 I: Iterator<Item = &'a ir::Assignment<T>>
124{
125}
126
127pub struct PortIterator<I>
129where
130 I: Iterator<Item = RRC<ir::Port>>,
131{
132 iter: I,
133}
134
135impl<I> Iterator for PortIterator<I>
136where
137 I: Iterator<Item = RRC<ir::Port>>,
138{
139 type Item = RRC<ir::Port>;
140
141 fn next(&mut self) -> Option<Self::Item> {
142 self.iter.next()
143 }
144}
145
146impl<I> PortIterator<I>
147where
148 I: Iterator<Item = RRC<ir::Port>>,
149{
150 pub const fn new(iter: I) -> Self {
151 Self { iter }
152 }
153
154 pub fn cells(self) -> impl Iterator<Item = RRC<ir::Cell>> {
156 self.iter
157 .map(|port| Rc::clone(&port.borrow().cell_parent()))
158 .unique_by(|cell| cell.borrow().name())
159 }
160
161 pub fn group_by_cell(self) -> HashMap<ir::Id, Vec<RRC<ir::Port>>> {
163 self.iter.into_group_map_by(|port| {
164 port.borrow().cell_parent().borrow().name()
165 })
166 }
167}
168
169pub struct ReadWriteSet;
171
172impl ReadWriteSet {
173 pub fn port_reads<T>(
175 assign: &ir::Assignment<T>,
176 ) -> PortIterator<impl Iterator<Item = RRC<ir::Port>>> {
177 PortIterator::new(
178 assign
179 .guard
180 .all_ports()
181 .into_iter()
182 .chain(iter::once(Rc::clone(&assign.src)))
183 .filter(|port| !port.borrow().is_hole()),
184 )
185 }
186}
187
188impl ReadWriteSet {
189 pub fn control_port_read_write_set_static(
192 scon: &ir::StaticControl,
193 ) -> (Vec<RRC<ir::Port>>, Vec<RRC<ir::Port>>) {
194 match scon {
195 ir::StaticControl::Empty(_) => (vec![], vec![]),
196 ir::StaticControl::Enable(ir::StaticEnable { group, .. }) => {
197 let g = group.borrow();
198 let (r, w) = g.assignments.iter().analysis().reads_and_writes();
199 (r.collect(), w.collect())
200 }
201 ir::StaticControl::Repeat(ir::StaticRepeat { body, .. }) => {
202 Self::control_port_read_write_set_static(body)
203 }
204 ir::StaticControl::Seq(ir::StaticSeq { stmts, .. })
205 | ir::StaticControl::Par(ir::StaticPar { stmts, .. }) => {
206 let (mut reads, mut writes) = (vec![], vec![]);
207 for stmt in stmts {
208 let (mut read, mut write) =
209 Self::control_port_read_write_set_static(stmt);
210 reads.append(&mut read);
211 writes.append(&mut write);
212 }
213 (reads, writes)
214 }
215 ir::StaticControl::If(ir::StaticIf {
216 port,
217 tbranch,
218 fbranch,
219 ..
220 }) => {
221 let (mut treads, mut twrites) =
222 Self::control_port_read_write_set_static(tbranch);
223 let (mut freads, mut fwrites) =
224 Self::control_port_read_write_set_static(fbranch);
225 treads.append(&mut freads);
226 treads.push(Rc::clone(port));
227 twrites.append(&mut fwrites);
228
229 (treads, twrites)
230 }
231 ir::StaticControl::Invoke(ir::StaticInvoke {
232 inputs,
233 outputs,
234 ref_cells,
235 comp,
236 ..
237 }) => {
238 let mut inps: Vec<RRC<ir::Port>> =
239 inputs.iter().map(|(_, p)| p).cloned().collect();
240 let mut outs: Vec<RRC<ir::Port>> =
241 outputs.iter().map(|(_, p)| p).cloned().collect();
242 inps.push(
244 comp.borrow()
245 .find_all_with_attr(ir::NumAttr::Go)
246 .next()
247 .unwrap_or_else(|| {
248 unreachable!(
249 "No @go port for component {}",
250 comp.borrow().name()
251 )
252 }),
253 );
254 for (_, cell) in ref_cells.iter() {
255 for port in cell.borrow().ports.iter() {
256 match port.borrow().direction {
257 ir::Direction::Input => {
258 outs.push(Rc::clone(port));
259 }
260 ir::Direction::Output => {
261 inps.push(Rc::clone(port));
262 }
263 _ => {
264 outs.push(Rc::clone(port));
265 inps.push(Rc::clone(port));
266 }
267 }
268 }
269 }
270 (inps, outs)
271 }
272 }
273 }
274
275 pub fn control_read_write_set_static(
278 scon: &ir::StaticControl,
279 ) -> (Vec<RRC<ir::Cell>>, Vec<RRC<ir::Cell>>) {
280 let (port_reads, port_writes) =
281 Self::control_port_read_write_set_static(scon);
282 (
283 port_reads
284 .into_iter()
285 .map(|p| p.borrow().cell_parent())
286 .collect(),
287 port_writes
288 .into_iter()
289 .map(|p| p.borrow().cell_parent())
290 .collect(),
291 )
292 }
293
294 pub fn control_port_read_write_set<const INCLUDE_HOLE_ASSIGNS: bool>(
300 con: &ir::Control,
301 ) -> (Vec<RRC<ir::Port>>, Vec<RRC<ir::Port>>) {
302 match con {
303 ir::Control::Empty(_) => (vec![], vec![]),
304
305 ir::Control::Enable(ir::Enable { group, .. }) => {
306 let group = group.borrow();
307 let (reads, writes) =
308 group.assignments.iter().analysis().reads_and_writes();
309 (
310 reads
311 .filter(|p| {
312 INCLUDE_HOLE_ASSIGNS || !p.borrow().is_hole()
313 })
314 .collect(),
315 writes
316 .filter(|p| {
317 INCLUDE_HOLE_ASSIGNS || !p.borrow().is_hole()
318 })
319 .collect(),
320 )
321 }
322 ir::Control::Invoke(ir::Invoke {
323 inputs,
324 outputs,
325 comb_group,
326 ref_cells,
327 comp,
328 ..
329 }) => {
330 let inps = inputs.iter().map(|(_, p)| p).cloned();
332 let outs = outputs.iter().map(|(_, p)| p).cloned();
333 let mut r: Vec<RRC<ir::Port>> = inps.collect();
334 let mut w: Vec<RRC<ir::Port>> = outs.collect();
335 w.push(
337 comp.borrow()
338 .find_all_with_attr(ir::NumAttr::Go)
339 .next()
340 .unwrap_or_else(|| {
341 unreachable!(
342 "No @go port for component {}",
343 comp.borrow().name()
344 )
345 }),
346 );
347
348 for (_, cell) in ref_cells {
349 for port in cell.borrow().ports.iter() {
350 match port.borrow().direction {
351 ir::Direction::Input => {
352 w.push(Rc::clone(port));
353 }
354 ir::Direction::Output => {
355 r.push(Rc::clone(port));
356 }
357 _ => {
358 w.push(Rc::clone(port));
359 r.push(Rc::clone(port));
360 }
361 }
362 }
363 }
364 match comb_group {
365 Some(cgr) => {
366 let cg = cgr.borrow();
367 let (reads, writes) =
368 cg.assignments.iter().analysis().reads_and_writes();
369 (
370 reads.into_iter().chain(r).collect(),
371 writes.into_iter().chain(w).collect(),
372 )
373 }
374 None => (r, w),
375 }
376 }
377 ir::Control::Seq(ir::Seq { stmts, .. })
378 | ir::Control::Par(ir::Par { stmts, .. }) => {
379 let (mut reads, mut writes) = (vec![], vec![]);
380 for stmt in stmts {
381 let (mut read, mut write) =
382 Self::control_port_read_write_set::<true>(stmt);
383 reads.append(&mut read);
384 writes.append(&mut write);
385 }
386 (reads, writes)
387 }
388 ir::Control::If(ir::If {
389 port,
390 cond,
391 tbranch,
392 fbranch,
393 ..
394 }) => {
395 let (mut treads, mut twrites) =
396 Self::control_port_read_write_set::<true>(tbranch);
397 let (mut freads, mut fwrites) =
398 Self::control_port_read_write_set::<true>(fbranch);
399 treads.append(&mut freads);
400 treads.push(Rc::clone(port));
401 twrites.append(&mut fwrites);
402
403 if let Some(cg) = cond {
404 let cg = cg.borrow();
405 let (reads, writes) =
406 cg.assignments.iter().analysis().reads_and_writes();
407 treads.extend(reads);
408 twrites.extend(writes);
409 }
410 (treads, twrites)
411 }
412 ir::Control::While(ir::While {
413 port, cond, body, ..
414 }) => {
415 let (mut reads, mut writes) =
416 Self::control_port_read_write_set::<true>(body);
417 reads.push(Rc::clone(port));
418
419 if let Some(cg) = cond {
420 let cg = cg.borrow();
421 let (r, w) =
422 cg.assignments.iter().analysis().reads_and_writes();
423 reads.extend(r);
424 writes.extend(w);
425 }
426 (reads, writes)
427 }
428 ir::Control::Repeat(ir::Repeat { body, .. }) => {
429 Self::control_port_read_write_set::<true>(body)
430 }
431 ir::Control::Static(sc) => {
432 Self::control_port_read_write_set_static(sc)
433 }
434 ir::Control::FSMEnable(_) => {
435 todo!("should not encounter fsm nodes")
436 }
437 }
438 }
439
440 pub fn control_read_write_set<const INCLUDE_HOLE_ASSIGNS: bool>(
446 con: &ir::Control,
447 ) -> (Vec<RRC<ir::Cell>>, Vec<RRC<ir::Cell>>) {
448 let (port_reads, port_writes) =
449 Self::control_port_read_write_set::<INCLUDE_HOLE_ASSIGNS>(con);
450 (
451 port_reads
452 .into_iter()
453 .map(|p| p.borrow().cell_parent())
454 .collect(),
455 port_writes
456 .into_iter()
457 .map(|p| p.borrow().cell_parent())
458 .collect(),
459 )
460 }
461}