1use core::panic;
2use std::{
3 collections::{BTreeMap, HashMap, HashSet},
4 ops::Add,
5};
6
7use crate::traversal::{
8 Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor,
9};
10use calyx_ir::{self as ir, BoolAttr, Guard, Id, Nothing, NumAttr};
11use calyx_utils::{CalyxResult, OutputFile};
12use serde::Serialize;
13
14#[derive(PartialEq, Eq, Hash, Clone, Serialize)]
15struct StatsEntry {
16 group_probe: u32,
17 structural_enable_probe: u32,
18 cell_probe: u32,
19 primitive_probe: u32,
20}
21
22impl Add for StatsEntry {
23 type Output = Self;
24
25 fn add(self, other: Self) -> Self {
26 Self {
27 group_probe: self.group_probe + other.group_probe,
28 structural_enable_probe: self.structural_enable_probe
29 + other.structural_enable_probe,
30 cell_probe: self.cell_probe + other.cell_probe,
31 primitive_probe: self.primitive_probe + other.primitive_probe,
32 }
33 }
34}
35
36pub struct ProfilerInstrumentation {
39 probe_stats: BTreeMap<String, StatsEntry>,
40 emit_probe_stats: Option<OutputFile>,
41 invoke_comb_groups_to_stats: HashMap<Id, Option<StatsEntry>>,
42}
43
44type CallsFromGroupMap<T> = HashMap<Id, Vec<(Id, ir::Guard<T>)>>;
47
48impl Named for ProfilerInstrumentation {
49 fn name() -> &'static str {
50 "profiler-instrumentation"
51 }
52
53 fn description() -> &'static str {
54 "Add instrumentation for profiling"
55 }
56
57 fn opts() -> Vec<crate::traversal::PassOpt> {
58 vec![PassOpt::new(
59 "emit-probe-stats",
60 "emit json file of shared cells",
61 ParseVal::OutStream(OutputFile::Null),
62 PassOpt::parse_outstream,
63 )]
64 }
65}
66
67impl ConstructVisitor for ProfilerInstrumentation {
68 fn from(ctx: &ir::Context) -> CalyxResult<Self>
69 where
70 Self: Sized + Named,
71 {
72 let opts = Self::get_opts(ctx);
73
74 Ok(ProfilerInstrumentation {
75 probe_stats: BTreeMap::new(),
76 emit_probe_stats: opts["emit-probe-stats"].not_null_outstream(),
77 invoke_comb_groups_to_stats: HashMap::new(),
78 })
79 }
80
81 fn clear_data(&mut self) {}
82}
83
84fn count_helper<T>(map_opt: Option<CallsFromGroupMap<T>>) -> u32 {
85 match map_opt {
86 Some(map) => map
87 .values()
88 .fold(0, |acc, vec_ref| acc + vec_ref.len() as u32),
89 None => 0,
90 }
91}
92
93fn count<T>(
94 num_groups: u32,
95 structural_enable_map_opt: Option<CallsFromGroupMap<T>>,
96 cell_invoke_map_opt: Option<CallsFromGroupMap<T>>,
97 primitive_map_opt: Option<CallsFromGroupMap<T>>,
98) -> StatsEntry {
99 let num_structural_enables = count_helper(structural_enable_map_opt);
100 let num_cell_invokes = count_helper(cell_invoke_map_opt);
101 let num_primitive_invokes = count_helper(primitive_map_opt);
102
103 StatsEntry {
104 group_probe: num_groups,
105 structural_enable_probe: num_structural_enables,
106 cell_probe: num_cell_invokes,
107 primitive_probe: num_primitive_invokes,
108 }
109}
110
111fn group(
113 comp: &mut ir::Component,
114 sigs: &ir::LibrarySignatures,
115 collect_stats: bool,
116) -> Option<StatsEntry> {
117 let mut structural_enable_map: CallsFromGroupMap<Nothing> = HashMap::new();
119 let mut cell_invoke_map: CallsFromGroupMap<Nothing> = HashMap::new();
121 let mut primitive_invoke_map: CallsFromGroupMap<Nothing> = HashMap::new();
123 let group_names = comp
124 .groups
125 .iter()
126 .map(|group| group.borrow().name())
127 .collect::<Vec<_>>();
128
129 for group_ref in comp.groups.iter() {
131 let group = &group_ref.borrow();
132 let mut comb_primitives_covered = HashSet::new();
134 let mut primitive_vec: Vec<(Id, ir::Guard<Nothing>)> = Vec::new();
135 for assignment_ref in group.assignments.iter() {
136 let dst_borrow = assignment_ref.dst.borrow();
137 if let ir::PortParent::Group(parent_group_ref) = &dst_borrow.parent
138 && dst_borrow.name == "go"
139 {
140 let invoked_group_name =
142 parent_group_ref.upgrade().borrow().name();
143 let guard = *(assignment_ref.guard.clone());
144 match structural_enable_map.get_mut(&invoked_group_name) {
145 Some(vec_ref) => vec_ref.push((group.name(), guard)),
146 None => {
147 structural_enable_map.insert(
148 invoked_group_name,
149 vec![(group.name(), guard)],
150 );
151 }
152 }
153 }
154 if let ir::PortParent::Cell(cell_ref) = &dst_borrow.parent {
155 match cell_ref.upgrade().borrow().prototype.clone() {
156 calyx_ir::CellType::Primitive {
157 name: _,
158 param_binding: _,
159 is_comb,
160 latency: _,
161 } => {
162 let cell_name = cell_ref.upgrade().borrow().name();
163 if is_comb {
164 if comb_primitives_covered.insert(cell_name) {
166 primitive_vec.push((cell_name, Guard::True));
167 }
168 } else if dst_borrow.has_attribute(NumAttr::Go) {
169 let guard = Guard::and(
171 *(assignment_ref.guard.clone()),
172 Guard::port(ir::rrc(
173 assignment_ref.src.borrow().clone(),
174 )),
175 );
176 primitive_vec.push((cell_name, guard));
177 }
178 }
179 calyx_ir::CellType::Component { name: _ } => {
180 if dst_borrow.has_attribute(NumAttr::Go) {
181 let cell_name = cell_ref.upgrade().borrow().name();
182 let guard = *(assignment_ref.guard.clone());
183 match cell_invoke_map.get_mut(&group.name()) {
184 Some(vec_ref) => {
185 vec_ref.push((cell_name, guard));
186 }
187 None => {
188 cell_invoke_map.insert(
189 group.name(),
190 vec![(cell_name, guard)],
191 );
192 }
193 }
194 }
195 }
196 _ => (),
197 }
198 }
199 }
200 primitive_invoke_map.insert(group_ref.borrow().name(), primitive_vec);
201 }
202
203 let group_name_assign_and_cell = create_probes_and_assignments(
205 comp,
206 sigs,
207 &group_names,
208 Some(&structural_enable_map),
209 Some(&cell_invoke_map),
210 Some(&primitive_invoke_map),
211 );
212
213 for group in comp.groups.iter() {
215 for (group_name, asgn, cell) in group_name_assign_and_cell.iter() {
216 if group.borrow().name() == group_name {
217 group.borrow_mut().assignments.push(asgn.clone());
218 comp.cells.add(cell.to_owned());
219 }
220 }
221 }
222
223 if collect_stats {
224 Some(count(
225 group_names.len() as u32,
226 Some(structural_enable_map),
227 Some(cell_invoke_map),
228 Some(primitive_invoke_map),
229 ))
230 } else {
231 None
232 }
233}
234
235fn combinational_group(
240 comp: &mut ir::Component,
241 sigs: &ir::LibrarySignatures,
242 collect_stats: bool,
243 covered: &HashSet<Id>,
244) -> Option<StatsEntry> {
245 let mut cell_invoke_map: CallsFromGroupMap<Nothing> = HashMap::new();
249 let mut primitive_invoke_map: CallsFromGroupMap<Nothing> = HashMap::new();
251
252 let group_names = comp
253 .comb_groups
254 .iter()
255 .filter(|group| !covered.contains(&group.borrow().name()))
257 .map(|group| group.borrow().name())
258 .collect::<Vec<_>>();
259
260 for group_ref in comp
261 .comb_groups
262 .iter()
263 .filter(|group| !covered.contains(&group.borrow().name()))
264 {
265 let group = &group_ref.borrow();
266 let mut comb_primitives_covered = HashSet::new();
267 let mut comb_cells_covered = HashSet::new();
268
269 for assignment_ref in group.assignments.iter() {
270 let dst_borrow = assignment_ref.dst.borrow();
271 if let ir::PortParent::Cell(cell_ref) = &dst_borrow.parent {
272 match cell_ref.upgrade().borrow().prototype.clone() {
273 calyx_ir::CellType::Primitive {
274 name: _,
275 param_binding: _,
276 is_comb,
277 latency: _,
278 } => {
279 let cell_name = cell_ref.upgrade().borrow().name();
280 if is_comb {
281 if comb_primitives_covered.insert(cell_name) {
283 match primitive_invoke_map
284 .get_mut(&group.name())
285 {
286 Some(vec_ref) => {
287 vec_ref.push((cell_name, Guard::True));
288 }
289 None => {
290 primitive_invoke_map.insert(
291 group.name(),
292 vec![(cell_name, Guard::True)],
293 );
294 }
295 }
296 }
297 } else if dst_borrow.has_attribute(NumAttr::Go) {
298 panic!(
299 "Non-combinational primitive {} invoked inside of combinational group {}!",
300 dst_borrow.canonical(),
301 group.name()
302 )
303 }
304 }
305 calyx_ir::CellType::Component { name: _ } => {
306 let cell_name = cell_ref.upgrade().borrow().name();
307 if dst_borrow.name == "go" {
308 panic!(
309 "Non-combinational cell {} invoked inside of combinational group {}!",
310 cell_name,
311 group.name()
312 );
313 } else if comb_cells_covered.insert(cell_name) {
314 let guard = *(assignment_ref.guard.clone());
315 match cell_invoke_map.get_mut(&group.name()) {
316 Some(vec_ref) => {
317 vec_ref.push((cell_name, guard));
318 }
319 None => {
320 cell_invoke_map.insert(
321 group.name(),
322 vec![(cell_name, guard)],
323 );
324 }
325 }
326 }
327 }
328 _ => (),
329 }
330 }
331 }
332 }
333
334 let group_name_asgn_and_cell = create_probes_and_assignments(
335 comp,
336 sigs,
337 &group_names,
338 None, Some(&cell_invoke_map),
340 Some(&primitive_invoke_map),
341 );
342
343 for comb_group in comp.comb_groups.iter() {
345 for (comb_group_name, asgn, cell) in group_name_asgn_and_cell.iter() {
346 if comb_group.borrow().name() == comb_group_name {
347 comb_group.borrow_mut().assignments.push(asgn.clone());
348 comp.cells.add(cell.to_owned());
349 }
350 }
351 }
352
353 if collect_stats {
354 Some(count(
355 group_names.len() as u32,
356 None,
357 Some(cell_invoke_map),
358 Some(primitive_invoke_map),
359 ))
360 } else {
361 None
362 }
363}
364
365fn static_group(
367 comp: &mut ir::Component,
368 sigs: &ir::LibrarySignatures,
369 collect_stats: bool,
370) -> Option<StatsEntry> {
371 let group_names = comp
372 .static_groups
373 .iter()
374 .map(|group| group.borrow().name())
375 .collect::<Vec<_>>();
376
377 let mut structural_enable_map: CallsFromGroupMap<ir::StaticTiming> =
379 HashMap::new();
380 let mut cell_invoke_map: CallsFromGroupMap<ir::StaticTiming> =
382 HashMap::new();
383 let mut primitive_invoke_map: CallsFromGroupMap<ir::StaticTiming> =
385 HashMap::new();
386
387 for group_ref in comp.static_groups.iter() {
388 let group = &group_ref.borrow();
389 let mut comb_primitives_covered = HashSet::new();
391 let mut primitive_vec: Vec<(Id, ir::Guard<ir::StaticTiming>)> =
392 Vec::new();
393 for assignment_ref in group.assignments.iter() {
394 let dst_borrow = assignment_ref.dst.borrow();
395 if let ir::PortParent::Group(parent_group_ref) = &dst_borrow.parent
396 && dst_borrow.name == "go"
397 {
398 let invoked_group_name =
400 parent_group_ref.upgrade().borrow().name();
401 let guard = *(assignment_ref.guard).clone();
402 structural_enable_map
403 .entry(invoked_group_name)
404 .or_default()
405 .push((group.name(), guard));
406 }
407 if let ir::PortParent::Cell(cell_ref) = &dst_borrow.parent {
408 match cell_ref.upgrade().borrow().prototype.clone() {
409 calyx_ir::CellType::Primitive { is_comb, .. } => {
410 let cell_name = cell_ref.upgrade().borrow().name();
411 if is_comb {
412 if comb_primitives_covered.insert(cell_name) {
414 primitive_vec.push((cell_name, Guard::True));
415 }
416 } else if dst_borrow.has_attribute(NumAttr::Go) {
417 let guard = Guard::and(
419 *(assignment_ref.guard).clone(),
420 Guard::port(ir::rrc(
421 assignment_ref.src.borrow().clone(),
422 )),
423 );
424 primitive_vec.push((cell_name, guard));
425 }
426 }
427 calyx_ir::CellType::Component { name: _ } => {
428 if dst_borrow.has_attribute(NumAttr::Go) {
429 let cell_name = cell_ref.upgrade().borrow().name();
430 let guard = *(assignment_ref.guard.clone());
431 cell_invoke_map
432 .entry(group.name())
433 .or_default()
434 .push((cell_name, guard));
435 }
436 }
437 _ => (),
438 }
439 }
440 }
441 primitive_invoke_map.insert(group_ref.borrow().name(), primitive_vec);
442 }
443
444 let group_name_assign_and_cell = create_probes_and_assignments(
445 comp,
446 sigs,
447 &group_names,
448 Some(&structural_enable_map),
449 Some(&cell_invoke_map),
450 Some(&primitive_invoke_map),
451 );
452
453 for static_group in comp.static_groups.iter() {
455 for (static_group_name, asgn, cell) in group_name_assign_and_cell.iter()
456 {
457 if static_group.borrow().name() == static_group_name {
458 static_group.borrow_mut().assignments.push(asgn.clone());
459 comp.cells.add(cell.to_owned());
460 }
461 }
462 }
463
464 if collect_stats {
465 Some(count(
466 group_names.len() as u32,
467 Some(structural_enable_map),
468 Some(cell_invoke_map),
469 Some(primitive_invoke_map),
470 ))
471 } else {
472 None
473 }
474}
475
476fn create_probes_and_assignments<T: Clone>(
482 comp: &mut ir::Component,
483 sigs: &ir::LibrarySignatures,
484 group_names: &[Id],
485 structural_enable_map_opt: Option<&CallsFromGroupMap<T>>,
486 cell_invoke_map_opt: Option<&CallsFromGroupMap<T>>,
487 primitive_invoke_map_opt: Option<&CallsFromGroupMap<T>>,
488) -> Vec<(
489 Id,
490 calyx_ir::Assignment<T>,
491 std::rc::Rc<std::cell::RefCell<calyx_ir::Cell>>,
492)> {
493 let delimiter = "___";
494 let comp_name = comp.name;
495 let mut builder = ir::Builder::new(comp, sigs);
497 let one = builder.add_constant(1, 1);
498
499 let mut group_name_assign_and_cell = Vec::new();
502
503 for group_name in group_names.iter() {
505 let name = format!("{group_name}{delimiter}{comp_name}_group_probe");
507 let probe_cell = builder.add_primitive(name, "std_wire", &[1]);
508 let probe_asgn: ir::Assignment<T> = builder.build_assignment(
509 probe_cell.borrow().get("in"),
510 one.borrow().get("out"),
511 Guard::True,
512 );
513 probe_cell.borrow_mut().add_attribute(BoolAttr::Control, 1);
515 probe_cell
516 .borrow_mut()
517 .add_attribute(BoolAttr::Protected, 1);
518 group_name_assign_and_cell.push((*group_name, probe_asgn, probe_cell));
519 }
520
521 if let Some(sem) = structural_enable_map_opt {
522 for (invoked_group_name, parent_groups) in sem.iter() {
524 for (parent_group, guard) in parent_groups.iter() {
525 let probe_cell_name = format!(
526 "{invoked_group_name}{delimiter}{parent_group}{delimiter}{comp_name}_se_probe"
527 );
528 let probe_cell =
529 builder.add_primitive(probe_cell_name, "std_wire", &[1]);
530 probe_cell.borrow_mut().add_attribute(BoolAttr::Control, 1);
531 probe_cell
532 .borrow_mut()
533 .add_attribute(BoolAttr::Protected, 1);
534 let probe_asgn: ir::Assignment<T> = builder.build_assignment(
535 probe_cell.borrow().get("in"),
536 one.borrow().get("out"),
537 guard.clone(),
538 );
539 group_name_assign_and_cell.push((
540 *parent_group,
541 probe_asgn,
542 probe_cell,
543 ));
544 }
545 }
546 }
547
548 if let Some(cell_invoke_map) = cell_invoke_map_opt {
549 for (invoker_group, invoked_cells) in cell_invoke_map.iter() {
551 for (invoked_cell, guard) in invoked_cells {
552 let probe_cell_name = format!(
553 "{invoked_cell}{delimiter}{invoker_group}{delimiter}{comp_name}_cell_probe"
554 );
555 let probe_cell =
556 builder.add_primitive(probe_cell_name, "std_wire", &[1]);
557 probe_cell.borrow_mut().add_attribute(BoolAttr::Control, 1);
558 probe_cell
559 .borrow_mut()
560 .add_attribute(BoolAttr::Protected, 1);
561 let probe_asgn: ir::Assignment<T> = builder.build_assignment(
563 probe_cell.borrow().get("in"),
564 one.borrow().get("out"),
565 guard.clone(),
566 );
567 group_name_assign_and_cell.push((
568 *invoker_group,
569 probe_asgn,
570 probe_cell,
571 ));
572 }
573 }
574 }
575
576 if let Some(primitive_invoke_map) = primitive_invoke_map_opt {
577 for (group, primitive_invs) in primitive_invoke_map.iter() {
579 for (primitive_cell_name, guard) in primitive_invs.iter() {
580 let probe_cell_name = format!(
581 "{primitive_cell_name}{delimiter}{group}{delimiter}{comp_name}_primitive_probe"
582 );
583 let probe_cell =
584 builder.add_primitive(probe_cell_name, "std_wire", &[1]);
585 probe_cell.borrow_mut().add_attribute(BoolAttr::Control, 1);
586 probe_cell
587 .borrow_mut()
588 .add_attribute(BoolAttr::Protected, 1);
589 let probe_asgn: ir::Assignment<T> = builder.build_assignment(
590 probe_cell.borrow().get("in"),
591 one.borrow().get("out"),
592 guard.clone(),
593 );
594 group_name_assign_and_cell
595 .push((*group, probe_asgn, probe_cell));
596 }
597 }
598 }
599
600 group_name_assign_and_cell
601}
602
603fn continuous_assignments(
607 comp: &mut ir::Component,
608 sigs: &ir::LibrarySignatures,
609 collect_stats: bool,
610) -> Option<StatsEntry> {
611 let mut cell_invoke_vec: Vec<(Id, ir::Guard<Nothing>)> = Vec::new();
613 let mut primitive_invoke_vec: Vec<(Id, ir::Guard<Nothing>)> = Vec::new();
615
616 let mut comb_primitives_covered = HashSet::new();
618 let mut comb_cells_covered = HashSet::new();
619 for assignment_ref in comp.continuous_assignments.iter() {
620 let dst_borrow = assignment_ref.dst.borrow();
621 let guard = *(assignment_ref.guard).clone();
622 if let ir::PortParent::Cell(cell_ref) = &dst_borrow.parent {
623 match cell_ref.upgrade().borrow().prototype.clone() {
624 calyx_ir::CellType::Primitive { .. } => {
625 let cell_name = cell_ref.upgrade().borrow().name();
626 if comb_primitives_covered.insert(cell_name) {
628 primitive_invoke_vec.push((cell_name, guard));
629 }
630 }
631 calyx_ir::CellType::Component { .. } => {
632 let cell_name = cell_ref.upgrade().borrow().name();
633 if comb_cells_covered.insert(cell_name) {
634 cell_invoke_vec.push((cell_name, guard));
635 }
636 }
637 _ => (),
638 }
639 }
640 }
641
642 let delimiter = "___";
644 let comp_name = comp.name;
645 let mut builder = ir::Builder::new(comp, sigs);
646 let one = builder.add_constant(1, 1);
647 let mut assign_and_cell = Vec::new();
648 for (primitive_cell_name, guard) in primitive_invoke_vec.iter() {
649 let probe_cell_name = format!(
650 "{primitive_cell_name}{delimiter}{comp_name}_contprimitive_probe"
651 );
652 let probe_cell =
653 builder.add_primitive(probe_cell_name, "std_wire", &[1]);
654 probe_cell.borrow_mut().add_attribute(BoolAttr::Control, 1);
655 probe_cell
656 .borrow_mut()
657 .add_attribute(BoolAttr::Protected, 1);
658 let probe_asgn: ir::Assignment<Nothing> = builder.build_assignment(
659 probe_cell.borrow().get("in"),
660 one.borrow().get("out"),
661 guard.clone(),
662 );
663 assign_and_cell.push((probe_asgn, probe_cell));
664 }
665 for (cell_name, guard) in cell_invoke_vec.iter() {
667 let probe_cell_name =
668 format!("{cell_name}{delimiter}{comp_name}_contcell_probe");
669 let probe_cell =
670 builder.add_primitive(probe_cell_name, "std_wire", &[1]);
671 probe_cell.borrow_mut().add_attribute(BoolAttr::Control, 1);
672 probe_cell
673 .borrow_mut()
674 .add_attribute(BoolAttr::Protected, 1);
675 let probe_asgn: ir::Assignment<Nothing> = builder.build_assignment(
676 probe_cell.borrow().get("in"),
677 one.borrow().get("out"),
678 guard.clone(),
679 );
680 assign_and_cell.push((probe_asgn, probe_cell));
681 }
682
683 for (asgn, cell) in assign_and_cell.iter() {
685 comp.continuous_assignments.push(asgn.clone());
686 comp.cells.add(cell.to_owned());
687 }
688
689 if collect_stats {
690 Some(StatsEntry {
691 group_probe: 0,
692 structural_enable_probe: 0,
693 cell_probe: cell_invoke_vec.len() as u32,
694 primitive_probe: primitive_invoke_vec.len() as u32,
695 })
696 } else {
697 None
698 }
699}
700
701fn populate_stats(
702 component_name: Id,
703 stats_map: &mut BTreeMap<String, StatsEntry>,
704 stats_list: Vec<Option<StatsEntry>>,
705) {
706 let this_comp_stats_list = stats_list.iter().fold(
707 StatsEntry {
708 group_probe: 0,
709 structural_enable_probe: 0,
710 cell_probe: 0,
711 primitive_probe: 0,
712 },
713 |s, g_s_opt| match g_s_opt {
714 Some(g_s) => s + g_s.clone(),
715 None => s,
716 },
717 );
718 stats_map.insert(component_name.to_string(), this_comp_stats_list);
719}
720
721impl Visitor for ProfilerInstrumentation {
722 fn invoke(
723 &mut self,
724 s: &mut calyx_ir::Invoke,
725 comp: &mut calyx_ir::Component,
726 sigs: &calyx_ir::LibrarySignatures,
727 _comps: &[calyx_ir::Component],
728 ) -> VisResult {
729 let cell_name = s.comp.borrow().name();
730 let mut comb_group = match &s.comb_group {
732 Some(s) => s.borrow_mut(),
733 None => {
734 panic!(
735 "Invokes should come with a comb group. Please run `uniquefy_enables` before running this pass!"
736 )
737 }
738 };
739 let comb_group_name = comb_group.name();
740
741 let mut cell_invoke_map: CallsFromGroupMap<Nothing> = HashMap::new();
744 cell_invoke_map.insert(comb_group_name, vec![(cell_name, Guard::True)]);
745
746 let mut primitive_name_set = HashSet::new();
748 let mut primitives_invoked_vec = vec![];
749 for assignment_ref in comb_group.assignments.iter() {
750 let dst_borrow = assignment_ref.dst.borrow();
751 if let ir::PortParent::Cell(cell_ref) = &dst_borrow.parent
752 && let calyx_ir::CellType::Primitive { .. } =
753 cell_ref.upgrade().borrow().prototype.clone()
754 {
755 let primitive_cell_name = cell_ref.upgrade().borrow().name();
756 if primitive_name_set.insert(primitive_cell_name) {
757 primitives_invoked_vec.push((
758 primitive_cell_name,
759 *(assignment_ref.guard.clone()),
760 ));
761 }
762 }
763 }
764 let mut primitive_invoke_map: CallsFromGroupMap<Nothing> =
765 HashMap::new();
766 primitive_invoke_map.insert(comb_group_name, primitives_invoked_vec);
767
768 let group_name_asgn_and_cell = create_probes_and_assignments(
769 comp,
770 sigs,
771 &[comb_group_name],
772 None,
773 Some(&cell_invoke_map),
774 Some(&primitive_invoke_map),
775 );
776
777 for (_comb_group_name, asgn, cell) in group_name_asgn_and_cell {
779 comb_group.assignments.push(asgn.clone());
780 comp.cells.add(cell.to_owned());
781 }
782
783 let stats = if self.emit_probe_stats.is_some() {
785 Some(count(
786 1,
787 None,
788 Some(cell_invoke_map),
789 Some(primitive_invoke_map),
790 ))
791 } else {
792 None
793 };
794 self.invoke_comb_groups_to_stats
795 .insert(comb_group_name, stats);
796
797 Ok(Action::Continue)
798 }
799
800 fn static_invoke(
801 &mut self,
802 s: &mut calyx_ir::StaticInvoke,
803 comp: &mut calyx_ir::Component,
804 sigs: &calyx_ir::LibrarySignatures,
805 _comps: &[calyx_ir::Component],
806 ) -> VisResult {
807 let cell_name = s.comp.borrow().name();
808 let mut comb_group = match &s.comb_group {
810 Some(s) => s.borrow_mut(),
811 None => {
812 panic!(
813 "Invokes should come with a comb group. Please run `uniquefy_enables` before running this pass!"
814 )
815 }
816 };
817 let comb_group_name = comb_group.name();
818
819 let mut cell_invoke_map: CallsFromGroupMap<Nothing> = HashMap::new();
822 cell_invoke_map.insert(comb_group_name, vec![(cell_name, Guard::True)]);
823
824 let mut primitive_name_set = HashSet::new();
826 let mut primitives_invoked_vec = vec![];
827 for assignment_ref in comb_group.assignments.iter() {
828 let dst_borrow = assignment_ref.dst.borrow();
829 if let ir::PortParent::Cell(cell_ref) = &dst_borrow.parent
830 && let calyx_ir::CellType::Primitive { name, .. } =
831 cell_ref.upgrade().borrow().prototype.clone()
832 && primitive_name_set.insert(name)
833 {
834 primitives_invoked_vec
835 .push((name, *(assignment_ref.guard.clone())));
836 }
837 }
838 let mut primitive_invoke_map: CallsFromGroupMap<Nothing> =
839 HashMap::new();
840 primitive_invoke_map.insert(comb_group_name, primitives_invoked_vec);
841
842 let group_name_asgn_and_cell = create_probes_and_assignments(
843 comp,
844 sigs,
845 &[comb_group_name],
846 None,
847 Some(&cell_invoke_map),
848 Some(&primitive_invoke_map),
849 );
850
851 for (_comb_group_name, asgn, cell) in group_name_asgn_and_cell {
853 comb_group.assignments.push(asgn.clone());
854 comp.cells.add(cell.to_owned());
855 }
856
857 let stats = if self.emit_probe_stats.is_some() {
859 Some(count(
860 1,
861 None,
862 Some(cell_invoke_map),
863 Some(primitive_invoke_map),
864 ))
865 } else {
866 None
867 };
868 self.invoke_comb_groups_to_stats
869 .insert(comb_group_name, stats);
870
871 Ok(Action::Continue)
872 }
873
874 fn finish(
875 &mut self,
876 comp: &mut calyx_ir::Component,
877 sigs: &calyx_ir::LibrarySignatures,
878 _comps: &[calyx_ir::Component],
879 ) -> VisResult {
880 let count = self.emit_probe_stats.is_some();
881 let group_stats_opt = group(comp, sigs, count);
882 let comb_group_stats_opt = combinational_group(
883 comp,
884 sigs,
885 count,
886 &self.invoke_comb_groups_to_stats.keys().cloned().collect(),
887 );
888 let static_group_stats_opt = static_group(comp, sigs, count);
889 let continuous_assignments_opt =
890 continuous_assignments(comp, sigs, count);
891
892 if count {
893 populate_stats(
894 comp.name,
895 &mut self.probe_stats,
896 vec![
897 group_stats_opt,
898 comb_group_stats_opt,
899 static_group_stats_opt,
900 continuous_assignments_opt,
901 ],
902 )
903 }
904 Ok(Action::Continue)
905 }
906
907 fn finish_context(&mut self, _ctx: &mut calyx_ir::Context) -> VisResult {
908 if let Some(json_out_file) = &mut self.emit_probe_stats {
909 let _ = serde_json::to_writer_pretty(
910 json_out_file.get_write(),
911 &self.probe_stats,
912 );
913 }
914 Ok(Action::Stop)
915 }
916}