1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use crate::traversal::{Action, Named, VisResult, Visitor};
use calyx_ir::{self as ir, Component, Control, LibrarySignatures};
use calyx_ir::{build_assignments, structure};
use std::rc::Rc;

#[derive(Default)]
/// Compiles away all [`ir::Empty`](calyx_ir::Empty) statements into an
/// [`ir::Enable`](calyx_ir::Enable).
///
/// The generated program enables the following group:
/// ```calyx
/// cells {
///     @generated empty_reg = std_reg(1);
/// }
///
/// group _empty {
///     empty_reg.write_en = 1'd1;
///     empty_reg.in = 1'd1;
///     _empty["done"] = empty_reg.done;
/// }
/// ```
pub struct CompileEmpty {
    // Name of the empty group if it has been created.
    group_name: Option<ir::Id>,
}

impl Named for CompileEmpty {
    fn name() -> &'static str {
        "compile-empty"
    }

    fn description() -> &'static str {
        "Rewrites empty control to invocation to empty group"
    }
}

impl Visitor for CompileEmpty {
    fn empty(
        &mut self,
        _s: &mut ir::Empty,
        comp: &mut Component,
        sigs: &LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        let group_ref = match self.group_name {
            Some(g) => comp.find_group(g).unwrap(),
            None => {
                let mut builder = ir::Builder::new(comp, sigs);

                // Build the new group
                let empty_group = builder.add_group("_empty");
                empty_group
                    .borrow_mut()
                    .attributes
                    .insert(ir::NumAttr::Static, 1);

                // Add this signal empty_group[done] = 1'd1;
                structure!(builder;
                    let signal_on = constant(1, 1);
                    let empty_reg = prim std_reg(1);
                );
                let assigns = build_assignments!(builder;
                    empty_reg["write_en"] = ? signal_on["out"];
                    empty_reg["in"] = ? signal_on["out"];
                    empty_group["done"] = ? empty_reg["done"];
                );
                empty_group.borrow_mut().assignments.extend(assigns);

                // Register the name of the group to the pass
                self.group_name = Some(empty_group.borrow().name());

                empty_group
            }
        };

        Ok(Action::change(Control::enable(Rc::clone(&group_ref))))
    }

    fn finish(
        &mut self,
        _comp: &mut Component,
        _sigs: &LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        // The empty group, if created, is only defined for this component.
        // Deregister it before walking over another group.
        self.group_name = None;
        Ok(Action::Continue)
    }
}