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 ir::Control::Enable(ir::Enable { group, .. }) => {
305 let group = group.borrow();
306 let (reads, writes) =
307 group.assignments.iter().analysis().reads_and_writes();
308 (
309 reads
310 .filter(|p| {
311 INCLUDE_HOLE_ASSIGNS || !p.borrow().is_hole()
312 })
313 .collect(),
314 writes
315 .filter(|p| {
316 INCLUDE_HOLE_ASSIGNS || !p.borrow().is_hole()
317 })
318 .collect(),
319 )
320 }
321 ir::Control::Invoke(ir::Invoke {
322 inputs,
323 outputs,
324 comb_group,
325 ref_cells,
326 comp,
327 ..
328 }) => {
329 let inps = inputs.iter().map(|(_, p)| p).cloned();
331 let outs = outputs.iter().map(|(_, p)| p).cloned();
332 let mut r: Vec<RRC<ir::Port>> = inps.collect();
333 let mut w: Vec<RRC<ir::Port>> = outs.collect();
334 w.push(
336 comp.borrow()
337 .find_all_with_attr(ir::NumAttr::Go)
338 .next()
339 .unwrap_or_else(|| {
340 unreachable!(
341 "No @go port for component {}",
342 comp.borrow().name()
343 )
344 }),
345 );
346
347 for (_, cell) in ref_cells {
348 for port in cell.borrow().ports.iter() {
349 match port.borrow().direction {
350 ir::Direction::Input => {
351 w.push(Rc::clone(port));
352 }
353 ir::Direction::Output => {
354 r.push(Rc::clone(port));
355 }
356 _ => {
357 w.push(Rc::clone(port));
358 r.push(Rc::clone(port));
359 }
360 }
361 }
362 }
363 match comb_group {
364 Some(cgr) => {
365 let cg = cgr.borrow();
366 let (reads, writes) =
367 cg.assignments.iter().analysis().reads_and_writes();
368 (
369 reads.into_iter().chain(r).collect(),
370 writes.into_iter().chain(w).collect(),
371 )
372 }
373 None => (r, w),
374 }
375 }
376 ir::Control::Seq(ir::Seq { stmts, .. })
377 | ir::Control::Par(ir::Par { stmts, .. }) => {
378 let (mut reads, mut writes) = (vec![], vec![]);
379 for stmt in stmts {
380 let (mut read, mut write) =
381 Self::control_port_read_write_set::<true>(stmt);
382 reads.append(&mut read);
383 writes.append(&mut write);
384 }
385 (reads, writes)
386 }
387 ir::Control::If(ir::If {
388 port,
389 cond,
390 tbranch,
391 fbranch,
392 ..
393 }) => {
394 let (mut treads, mut twrites) =
395 Self::control_port_read_write_set::<true>(tbranch);
396 let (mut freads, mut fwrites) =
397 Self::control_port_read_write_set::<true>(fbranch);
398 treads.append(&mut freads);
399 treads.push(Rc::clone(port));
400 twrites.append(&mut fwrites);
401
402 if let Some(cg) = cond {
403 let cg = cg.borrow();
404 let (reads, writes) =
405 cg.assignments.iter().analysis().reads_and_writes();
406 treads.extend(reads);
407 twrites.extend(writes);
408 }
409 (treads, twrites)
410 }
411 ir::Control::While(ir::While {
412 port, cond, body, ..
413 }) => {
414 let (mut reads, mut writes) =
415 Self::control_port_read_write_set::<true>(body);
416 reads.push(Rc::clone(port));
417
418 if let Some(cg) = cond {
419 let cg = cg.borrow();
420 let (r, w) =
421 cg.assignments.iter().analysis().reads_and_writes();
422 reads.extend(r);
423 writes.extend(w);
424 }
425 (reads, writes)
426 }
427 ir::Control::Repeat(ir::Repeat { body, .. }) => {
428 Self::control_port_read_write_set::<true>(body)
429 }
430 ir::Control::Static(sc) => {
431 Self::control_port_read_write_set_static(sc)
432 }
433 }
434 }
435
436 pub fn control_read_write_set<const INCLUDE_HOLE_ASSIGNS: bool>(
442 con: &ir::Control,
443 ) -> (Vec<RRC<ir::Cell>>, Vec<RRC<ir::Cell>>) {
444 let (port_reads, port_writes) =
445 Self::control_port_read_write_set::<INCLUDE_HOLE_ASSIGNS>(con);
446 (
447 port_reads
448 .into_iter()
449 .map(|p| p.borrow().cell_parent())
450 .collect(),
451 port_writes
452 .into_iter()
453 .map(|p| p.borrow().cell_parent())
454 .collect(),
455 )
456 }
457}