1use crate::analysis::{
2 ControlId, ShareSet,
3 domination_analysis::{
4 node_analysis::{NodeReads, NodeSearch},
5 static_par_domination::StaticParDomination,
6 },
7};
8use calyx_ir as ir;
9use ir::GenericControl;
10use std::collections::{HashMap, HashSet};
11use std::fmt::Debug;
12
13const NODE_ID: ir::Attribute =
14 ir::Attribute::Internal(ir::InternalAttr::NODE_ID);
15const BEGIN_ID: ir::Attribute =
16 ir::Attribute::Internal(ir::InternalAttr::BEGIN_ID);
17const END_ID: ir::Attribute = ir::Attribute::Internal(ir::InternalAttr::END_ID);
18
19#[derive(Default)]
95pub struct DominatorMap {
96 pub map: HashMap<u64, HashSet<u64>>,
98 pub exits_map: HashMap<u64, HashSet<u64>>,
104 pub static_par_domination: StaticParDomination,
108 pub component_name: ir::Id,
109}
110
111impl Debug for DominatorMap {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 writeln!(
115 f,
116 "The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes \nthat are attached to each non-empty control statement when the domination map is built. \nTo see which ID's refer to which control statement, look at the Calyx Program, which should \nbe printed along with the map when it is printed."
117 )?;
118 writeln!(
119 f,
120 "Domination Map for component \"{}\" {{",
121 self.component_name
122 )?;
123 let map = self.map.clone();
124 let mut vec1: Vec<(u64, HashSet<u64>)> = map.into_iter().collect();
125 vec1.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
126 for (k, hs) in vec1.into_iter() {
127 write!(f, "Node: {k:?} --")?;
128 let mut vec = hs.into_iter().collect::<Vec<_>>();
129 vec.sort_unstable();
130 writeln!(f, " Dominators: {vec:?}")?;
131 }
132 write!(f, "}}")
133 }
134}
135
136#[inline]
137fn get_id_static<const BEGIN: bool>(c: &ir::StaticControl) -> u64 {
138 let v = match c {
139 ir::StaticControl::If(_) => {
140 if BEGIN {
141 c.get_attribute(BEGIN_ID)
142 } else {
143 c.get_attribute(END_ID)
144 }
145 }
146 _ => c.get_attribute(NODE_ID),
147 };
148 v.unwrap_or_else(|| unreachable!(
149 "get_id() shouldn't be called on control stmts that don't have id numbering"
150 ))
151}
152
153#[inline]
158fn get_id<const BEGIN: bool>(c: &ir::Control) -> u64 {
159 let v = match c {
160 ir::Control::If(_) | ir::Control::Static(ir::StaticControl::If(_)) => {
161 if BEGIN {
162 c.get_attribute(BEGIN_ID)
163 } else {
164 c.get_attribute(END_ID)
165 }
166 }
167 _ => c.get_attribute(NODE_ID),
168 };
169 v.unwrap_or_else(|| unreachable!(
170 "get_id() shouldn't be called on control stmts that don't have id numbering"
171 ))
172}
173
174fn matches_key_static(sc: &ir::StaticControl, key: u64) -> bool {
175 if get_id_static::<true>(sc) == key {
176 return true;
177 }
178 if let Some(end) = sc.get_attribute(END_ID) {
180 key == end
181 } else {
182 false
183 }
184}
185
186fn matches_key(c: &ir::Control, key: u64) -> bool {
189 if get_id::<true>(c) == key {
190 return true;
191 }
192 if let Some(end) = c.get_attribute(END_ID) {
194 key == end
195 } else {
196 false
197 }
198}
199
200fn get_final_static(sc: &ir::StaticControl) -> HashSet<u64> {
201 let mut hs = HashSet::new();
202 match sc {
203 ir::StaticControl::Empty(_) => (),
204 ir::StaticControl::Enable(_) | ir::StaticControl::Invoke(_) => {
205 hs.insert(ControlId::get_guaranteed_attribute_static(sc, NODE_ID));
206 }
207 ir::StaticControl::Repeat(ir::StaticRepeat {
208 body,
209 num_repeats,
210 ..
211 }) => {
212 if *num_repeats != 0 {
215 return get_final_static(body);
216 }
217 }
218 ir::StaticControl::Seq(ir::StaticSeq { stmts, .. }) => {
219 return get_final_static(stmts[..].last().unwrap_or_else(|| {
220 panic!(
221 "error: empty Static Seq block. TODO: Make Static Seq work on collapse-control pass."
222 )
223 }));
224 }
225 ir::StaticControl::Par(ir::StaticPar { stmts, .. }) => {
226 for stmt in stmts {
227 let stmt_final = get_final_static(stmt);
228 hs = hs.union(&stmt_final).copied().collect()
229 }
230 }
231 ir::StaticControl::If(_) => {
232 hs.insert(ControlId::get_guaranteed_attribute_static(sc, END_ID));
233 }
234 }
235 hs
236}
237
238fn get_final(c: &ir::Control) -> HashSet<u64> {
240 let mut hs = HashSet::new();
241 match c {
242 ir::Control::Empty(_) | ir::Control::FSMEnable(_) => (), ir::Control::Invoke(_)
244 | ir::Control::Enable(_)
245 | ir::Control::While(_) => {
246 hs.insert(ControlId::get_guaranteed_attribute(c, NODE_ID));
247 }
248 ir::Control::Repeat(ir::Repeat {
249 body, num_repeats, ..
250 }) => {
251 if *num_repeats != 0 {
254 return get_final(body);
255 }
256 }
257 ir::Control::If(_) => {
258 hs.insert(ControlId::get_guaranteed_attribute(c, END_ID));
259 }
260 ir::Control::Seq(ir::Seq { stmts, .. }) => {
261 return get_final(stmts[..].last().unwrap_or_else(|| {
262 panic!("error: empty Seq block. Run collapse-control pass.")
263 }));
264 }
265 ir::Control::Par(ir::Par { stmts, .. }) => {
266 for stmt in stmts {
267 let stmt_final = get_final(stmt);
268 hs = hs.union(&stmt_final).copied().collect()
269 }
270 }
271 ir::Control::Static(s) => return get_final_static(s),
272 }
273 hs
274}
275
276impl DominatorMap {
277 pub fn new(control: &mut ir::Control, component_name: ir::Id) -> Self {
279 ControlId::compute_unique_ids(control, 0, true);
280 let mut map = DominatorMap {
281 map: HashMap::new(),
282 exits_map: HashMap::new(),
283 static_par_domination: StaticParDomination::new(
284 control,
285 component_name,
286 ),
287 component_name,
288 };
289 map.build_exit_map(control);
290 map.build_map(control);
291 map
292 }
293
294 fn build_exit_map_static(&mut self, sc: &ir::StaticControl) {
295 match sc {
296 ir::StaticControl::Enable(_) | ir::StaticControl::Invoke(_) => {
297 let id =
298 ControlId::get_guaranteed_attribute_static(sc, NODE_ID);
299 self.exits_map.insert(id, HashSet::from([id]));
300 }
301 ir::StaticControl::Repeat(ir::StaticRepeat { body, .. }) => {
302 let id =
303 ControlId::get_guaranteed_attribute_static(sc, NODE_ID);
304 self.exits_map.insert(id, get_final_static(sc));
305 self.build_exit_map_static(body);
306 }
307 ir::StaticControl::Seq(ir::StaticSeq { stmts, .. })
308 | ir::StaticControl::Par(ir::StaticPar { stmts, .. }) => {
309 for stmt in stmts {
310 self.build_exit_map_static(stmt);
311 }
312 let id =
313 ControlId::get_guaranteed_attribute_static(sc, NODE_ID);
314 self.exits_map.insert(id, get_final_static(sc));
315 }
316 ir::StaticControl::If(ir::StaticIf {
317 tbranch, fbranch, ..
318 }) => {
319 let begin_id =
320 ControlId::get_guaranteed_attribute_static(sc, BEGIN_ID);
321 let end_id =
322 ControlId::get_guaranteed_attribute_static(sc, END_ID);
323 self.exits_map.insert(begin_id, HashSet::from([end_id]));
324 self.exits_map.insert(end_id, HashSet::from([end_id]));
325 self.build_exit_map_static(tbranch);
326 self.build_exit_map_static(fbranch);
327 }
328 ir::StaticControl::Empty(_) => (),
329 }
330 }
331
332 fn build_exit_map(&mut self, c: &ir::Control) {
335 match c {
336 ir::Control::Empty(_) | ir::Control::FSMEnable(_) => (), ir::Control::Invoke(_) | ir::Control::Enable(_) => {
338 let id = ControlId::get_guaranteed_attribute(c, NODE_ID);
339 self.exits_map.insert(id, HashSet::from([id]));
340 }
341 ir::Control::While(ir::While { body, .. }) => {
342 let id = ControlId::get_guaranteed_attribute(c, NODE_ID);
343 self.exits_map.insert(id, HashSet::from([id]));
344 self.build_exit_map(body);
345 }
346 ir::Control::Repeat(ir::Repeat { body, .. }) => {
347 let id = ControlId::get_guaranteed_attribute(c, NODE_ID);
348 self.exits_map.insert(id, get_final(body));
349 self.build_exit_map(body);
350 }
351 ir::Control::If(ir::If {
352 tbranch, fbranch, ..
353 }) => {
354 let begin_id = ControlId::get_guaranteed_attribute(c, BEGIN_ID);
355 let end_id = ControlId::get_guaranteed_attribute(c, END_ID);
356 self.exits_map.insert(begin_id, HashSet::from([end_id]));
357 self.exits_map.insert(end_id, HashSet::from([end_id]));
358 self.build_exit_map(tbranch);
359 self.build_exit_map(fbranch);
360 }
361 ir::Control::Seq(ir::Seq { stmts, .. })
362 | ir::Control::Par(ir::Par { stmts, .. }) => {
363 for stmt in stmts {
364 self.build_exit_map(stmt);
365 }
366 let id = ControlId::get_guaranteed_attribute(c, NODE_ID);
367 self.exits_map.insert(id, get_final(c));
368 }
369 ir::Control::Static(sc) => self.build_exit_map_static(sc),
370 }
371 }
372
373 fn build_map(&mut self, main_c: &mut ir::Control) {
376 let mut og_map = self.map.clone();
377 self.update_map(main_c, 0, &HashSet::new());
378 while og_map != self.map {
379 og_map = self.map.clone();
380 self.update_map(main_c, 0, &HashSet::new());
381 }
382 self.update_static_dominators();
383 }
384
385 fn update_static_dominators(&mut self) {
389 let new_static_domminators =
390 self.static_par_domination.get_static_dominators();
391 for (node_id, node_dominators) in new_static_domminators {
392 let cur_dominators = self.map.entry(node_id).or_default();
393 cur_dominators.extend(node_dominators);
394 }
395 }
396
397 fn update_node(&mut self, pred: &HashSet<u64>, id: u64) {
401 let mut union: HashSet<u64> = HashSet::new();
402 for id in pred.iter() {
403 if let Some(dominators) = self.map.get(id) {
404 union = union.union(dominators).copied().collect();
405 }
406 }
407 union.insert(id);
408 self.map.insert(id, union);
409 }
410
411 fn update_map_static(
412 &mut self,
413 main_sc: &ir::StaticControl,
414 cur_id: u64,
415 pred: &HashSet<u64>,
416 ) {
417 match Self::get_static_control(cur_id, main_sc) {
418 Some(GenericControl::Dynamic(_)) => {
419 unreachable!("should never get dynamic from get_static_control")
420 }
421 None => (),
422 Some(GenericControl::Static(sc)) => match sc {
423 ir::StaticControl::Empty(_) => (),
424 ir::StaticControl::Enable(_) | ir::StaticControl::Invoke(_) => {
425 self.update_node(pred, cur_id);
426 }
427 ir::StaticControl::Repeat(ir::StaticRepeat {
428 body,
429 num_repeats,
430 ..
431 }) => {
432 if *num_repeats != 0 {
433 let body_id = get_id_static::<true>(body);
434 self.update_map_static(main_sc, body_id, pred);
435 }
436 }
437 ir::StaticControl::Seq(ir::StaticSeq { stmts, .. }) => {
438 let mut p = pred;
439 let mut nxt: HashSet<u64>;
440 for stmt in stmts {
441 let id = get_id_static::<true>(stmt);
442 self.update_map_static(main_sc, id, p);
443 nxt = self
445 .exits_map
446 .get(&id)
447 .unwrap_or(
448 pred,
453 )
454 .clone();
455 p = &nxt;
456 }
457 }
458 ir::StaticControl::Par(ir::StaticPar { stmts, .. }) => {
459 for stmt in stmts {
460 let id = get_id_static::<true>(stmt);
461 self.update_map_static(main_sc, id, pred);
462 }
463 }
464 ir::StaticControl::If(ir::StaticIf {
465 tbranch,
466 fbranch,
467 ..
468 }) => {
469 self.update_node(pred, cur_id);
471
472 let if_guard_set = HashSet::from([cur_id]);
474
475 let t_id = get_id_static::<true>(tbranch);
477 self.update_map_static(main_sc, t_id, &if_guard_set);
478
479 if !matches!(**fbranch, ir::StaticControl::Empty(_)) {
481 let f_id = get_id_static::<true>(fbranch);
482 self.update_map_static(main_sc, f_id, &if_guard_set);
483 }
484
485 let end_id =
486 ControlId::get_guaranteed_attribute_static(sc, END_ID);
487 self.update_node(&if_guard_set, end_id)
488 }
489 },
490 }
491 }
492
493 fn update_map(
495 &mut self,
496 main_c: &ir::Control,
497 cur_id: u64,
498 pred: &HashSet<u64>,
499 ) {
500 match Self::get_control(cur_id, main_c) {
501 None => (),
502 Some(GenericControl::Dynamic(c)) => {
503 match c {
504 ir::Control::Empty(_) => {
505 unreachable!(
506 "should not pattern match agaisnt empty in update_map()"
507 )
508 }
509 ir::Control::FSMEnable(_) => {
510 unreachable!("should not encounter fsm nodes")
511 }
512 ir::Control::Invoke(_) | ir::Control::Enable(_) => {
513 self.update_node(pred, cur_id);
514 }
515 ir::Control::Seq(ir::Seq { stmts, .. }) => {
516 let mut p = pred;
517 let mut nxt: HashSet<u64>;
518 for stmt in stmts {
519 let id = get_id::<true>(stmt);
520 self.update_map(main_c, id, p);
521 nxt = self
522 .exits_map
523 .get(&id)
524 .unwrap_or(
525 pred, )
530 .clone();
531 p = &nxt;
532 }
533 }
534 ir::Control::Par(ir::Par { stmts, .. }) => {
535 for stmt in stmts {
536 let id = get_id::<true>(stmt);
537 self.update_map(main_c, id, pred);
538 }
539 }
540 ir::Control::Repeat(ir::Repeat {
541 body,
542 num_repeats,
543 ..
544 }) => {
545 if *num_repeats != 0 {
546 let body_id = get_id::<true>(body);
547 self.update_map(main_c, body_id, pred);
548 }
549 }
550 ir::Control::While(ir::While { body, .. }) => {
557 self.update_node(pred, cur_id);
558 let body_id = get_id::<true>(body);
560 self.update_map(
561 main_c,
562 body_id,
563 &HashSet::from([cur_id]),
564 );
565 }
566 ir::Control::If(ir::If {
567 tbranch, fbranch, ..
568 }) => {
569 self.update_node(pred, cur_id);
571
572 let if_guard_set = HashSet::from([cur_id]);
574
575 let t_id = get_id::<true>(tbranch);
577 self.update_map(main_c, t_id, &if_guard_set);
578
579 if !matches!(**fbranch, ir::Control::Empty(_)) {
581 let f_id = get_id::<true>(fbranch);
582 self.update_map(main_c, f_id, &if_guard_set);
583 }
584
585 let end_id =
586 ControlId::get_guaranteed_attribute(c, END_ID);
587 self.update_node(&if_guard_set, end_id)
588 }
589 ir::Control::Static(_) => panic!(
590 "when matching c in GenericControl::Dynamic(c), c shouldn't be Static Control"
591 ),
592 };
593 }
594 Some(GenericControl::Static(sc)) => {
595 let static_id = get_id_static::<true>(sc);
596 self.update_map_static(sc, static_id, pred);
597 }
598 }
599 }
600
601 pub fn get_static_control(
602 id: u64,
603 sc: &ir::StaticControl,
604 ) -> Option<GenericControl> {
605 if matches!(sc, ir::StaticControl::Empty(_)) {
606 return None;
607 }
608 if matches_key_static(sc, id) {
609 return Some(GenericControl::from(sc));
610 };
611 match sc {
612 ir::StaticControl::Empty(_)
613 | ir::StaticControl::Enable(_)
614 | ir::StaticControl::Invoke(_) => None,
615 ir::StaticControl::Repeat(ir::StaticRepeat { body, .. }) => {
616 Self::get_static_control(id, body)
617 }
618 ir::StaticControl::Seq(ir::StaticSeq { stmts, .. })
619 | ir::StaticControl::Par(ir::StaticPar { stmts, .. }) => {
620 for stmt in stmts {
621 match Self::get_static_control(id, stmt) {
622 None => (),
623 Some(GenericControl::Dynamic(_)) => {
624 unreachable!(
625 "Got a GenericControl::Dynamic when we called get_static_control"
626 )
627 }
628 Some(GenericControl::Static(sc)) => {
629 return Some(GenericControl::from(sc));
630 }
631 }
632 }
633 None
634 }
635 ir::StaticControl::If(ir::StaticIf {
636 tbranch, fbranch, ..
637 }) => {
638 match Self::get_static_control(id, tbranch) {
639 Some(GenericControl::Dynamic(_)) => {
640 unreachable!(
641 "Got a GenericControl::Dynamic when we called get_static_control"
642 )
643 }
644 Some(GenericControl::Static(sc)) => {
645 return Some(GenericControl::from(sc));
646 }
647 None => (),
648 }
649 match Self::get_static_control(id, fbranch) {
650 Some(GenericControl::Dynamic(_)) => {
651 unreachable!(
652 "Got a GenericControl::Dynamic when we called get_static_control"
653 )
654 }
655 Some(GenericControl::Static(sc)) => {
656 return Some(GenericControl::from(sc));
657 }
658 None => (),
659 };
660 None
661 }
662 }
663 }
664
665 pub fn get_control(id: u64, c: &ir::Control) -> Option<GenericControl> {
668 if matches!(c, ir::Control::Empty(_)) {
669 return None;
670 }
671 if matches_key(c, id) {
672 return Some(GenericControl::from(c));
673 }
674 match c {
675 ir::Control::Empty(_)
676 | ir::Control::Invoke(_)
677 | ir::Control::Enable(_)
678 | ir::Control::FSMEnable(_) => None,
679 ir::Control::Seq(ir::Seq { stmts, .. })
680 | ir::Control::Par(ir::Par { stmts, .. }) => {
681 for stmt in stmts {
682 match Self::get_control(id, stmt) {
683 None => (),
684 Some(GenericControl::Dynamic(c)) => {
685 return Some(GenericControl::from(c));
686 }
687 Some(GenericControl::Static(sc)) => {
688 return Some(GenericControl::from(sc));
689 }
690 }
691 }
692 None
693 }
694 ir::Control::Repeat(ir::Repeat { body, .. }) => {
695 Self::get_control(id, body)
696 }
697 ir::Control::If(ir::If {
698 tbranch, fbranch, ..
699 }) => {
700 match Self::get_control(id, tbranch) {
701 Some(GenericControl::Dynamic(c)) => {
702 return Some(GenericControl::from(c));
703 }
704 Some(GenericControl::Static(sc)) => {
705 return Some(GenericControl::from(sc));
706 }
707 None => (),
708 }
709 match Self::get_control(id, fbranch) {
710 Some(GenericControl::Dynamic(c)) => {
711 return Some(GenericControl::from(c));
712 }
713 Some(GenericControl::Static(sc)) => {
714 return Some(GenericControl::from(sc));
715 }
716 None => (),
717 };
718 None
719 }
720 ir::Control::While(ir::While { body, .. }) => {
721 Self::get_control(id, body)
722 }
723 ir::Control::Static(sc) => Self::get_static_control(id, sc),
724 }
725 }
726
727 pub fn get_control_nodes<'a>(
733 nodes: &HashSet<u64>,
734 main_control: &'a ir::Control,
735 ) -> (Vec<&'a ir::Control>, Vec<&'a ir::StaticControl>) {
736 let mut controls: Vec<&ir::Control> = Vec::new();
737 let mut static_controls: Vec<&ir::StaticControl> = Vec::new();
738 for node in nodes {
739 match Self::get_control(*node, main_control) {
740 Some(GenericControl::Static(sc)) => static_controls.push(sc),
741 Some(GenericControl::Dynamic(c)) => controls.push(c),
742 None => {
743 unreachable!("No control statement for ID {}", node)
744 }
745 }
746 }
747 (controls, static_controls)
748 }
749
750 pub fn get_node_reads(
754 node: &u64,
755 comp: &mut ir::Component,
756 shareset: &ShareSet,
757 ) -> HashSet<ir::Id> {
758 NodeReads::get_reads_of_node(node, comp, shareset)
759 }
760
761 pub fn key_written_guaranteed(
765 key: ir::Id,
766 nodes: &HashSet<u64>,
767 comp: &mut ir::Component,
768 ) -> bool {
769 let search_struct = NodeSearch::new(key);
770 search_struct.is_written_guaranteed(nodes, comp)
771 }
772}