calyx_opt/passes/
externalize.rs

1use super::dump_ports;
2use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor};
3use calyx_ir::{self as ir, LibrarySignatures, RRC};
4use calyx_utils::CalyxResult;
5
6/// Externalize input/output ports for cells marked with the `@external(1)` attribute.
7/// The ports of these cells are exposed through the ports of the parent
8/// component.
9///
10/// For example:
11/// ```
12/// component main() -> () {
13///     cells {
14///         // Inputs: addr0, write_data, write_en
15///         // Outputs: read_data, done
16///         @external(1) m1 = prim comb_mem_d1(32, 10, 4);
17///     }
18///     wires {
19///         m1.addr0 = 1'd1;
20///         x.in = m1.read_data;
21///     }
22/// }
23/// ```
24/// is transformed into:
25/// ```
26/// component main(
27///     m1_read_data: 32,
28///     m1_done: 1
29/// ) -> (m1_add0: 4, m1_write_data: 32, m1_write_en: 1) {
30///     cells {
31///         // m1 removed.
32///     }
33///     wires {
34///         m1_add0 = 1'd1;
35///         x.in = m1_read_data;
36///     }
37/// }
38/// ```
39pub struct Externalize;
40
41impl ConstructVisitor for Externalize {
42    fn from(_ctx: &ir::Context) -> CalyxResult<Self>
43    where
44        Self: Sized,
45    {
46        let externalize = Externalize;
47        Ok(externalize)
48    }
49
50    fn clear_data(&mut self) {
51        //data is shared between components
52    }
53}
54
55impl Named for Externalize {
56    fn name() -> &'static str {
57        "externalize"
58    }
59
60    fn description() -> &'static str {
61        "Externalize the interfaces of cells marked with `@external(1)`"
62    }
63}
64
65fn has_external_attribute(cr: &RRC<ir::Cell>) -> bool {
66    let cell = cr.borrow();
67    cell.get_attribute(ir::BoolAttr::External).is_some()
68}
69
70impl Visitor for Externalize {
71    fn start(
72        &mut self,
73        comp: &mut ir::Component,
74        _ctx: &LibrarySignatures,
75        _comps: &[ir::Component],
76    ) -> VisResult {
77        let dump_ports::DumpResults { cells, rewrites } =
78            dump_ports::dump_ports_to_signature(
79                comp,
80                has_external_attribute,
81                false,
82            );
83
84        let rw = ir::Rewriter {
85            port_map: rewrites,
86            ..Default::default()
87        };
88        comp.for_each_assignment(|assign| {
89            rw.rewrite_assign(assign);
90        });
91        comp.for_each_static_assignment(|assign| {
92            rw.rewrite_assign(assign);
93        });
94        rw.rewrite_control(&mut comp.control.borrow_mut());
95        // Don't allow cells to be dropped before this because otherwise rewriting will fail
96        drop(cells);
97
98        Ok(Action::Stop)
99    }
100}