calyx_opt/passes/
dump_ports.rs

1use calyx_ir::{self as ir, RRC, WRC};
2use ir::rewriter;
3use itertools::Itertools;
4use std::rc::Rc;
5
6#[derive(Default)]
7/// Results generated from the process of dumping out ports.
8pub struct DumpResults {
9    /// The cells that were removed from the component.
10    pub cells: Vec<RRC<ir::Cell>>,
11    /// Rewrites from (cell, port) to the new port.
12    /// Usually consumed by an [`ir::rewriter::Rewriter`].
13    pub rewrites: rewriter::PortRewriteMap,
14}
15
16/// Formats name of a port given the id of the cell and the port
17pub(super) fn format_port_name(canon: &ir::Canonical) -> ir::Id {
18    format!("{}_{}", canon.cell, canon.port).into()
19}
20
21/// Remove all the cells matching the given criterion (f evaluates to true) from
22/// the component and inline all the ports of the removed cells to the component
23/// signature.
24///
25/// If `remove_clk_and_reset` is true, does not inline ports marked with @clk and @reset.
26pub(super) fn dump_ports_to_signature<F>(
27    component: &mut ir::Component,
28    cell_filter: F,
29    remove_clk_and_reset: bool,
30) -> DumpResults
31where
32    F: Fn(&RRC<ir::Cell>) -> bool,
33{
34    let mut removed = rewriter::PortRewriteMap::default();
35
36    let (ext_cells, cells): (Vec<_>, Vec<_>) =
37        component.cells.drain().partition(cell_filter);
38    component.cells.append(cells.into_iter());
39
40    for cell_ref in &ext_cells {
41        let cell = cell_ref.borrow();
42        log::debug!("cell `{}' removed", cell.name());
43        // We need this information because we might want to attach the `@data`
44        // attribute to some of the ports.
45        let is_data_cell = cell.attributes.has(ir::BoolAttr::Data);
46
47        // If we do not eliminate the @clk and @reset ports, we may
48        // get signals conflicting the original @clk and @reset signals of
49        // the component, see https://github.com/calyxir/calyx/issues/1034
50        let ports_inline = cell
51            .ports
52            .iter()
53            .filter(|pr| {
54                if remove_clk_and_reset {
55                    let p = pr.borrow();
56                    !p.attributes.has(ir::BoolAttr::Clk)
57                        && !p.attributes.has(ir::BoolAttr::Reset)
58                } else {
59                    true
60                }
61            })
62            .map(Rc::clone)
63            .collect_vec();
64
65        for port_ref in ports_inline {
66            let canon = port_ref.borrow().canonical();
67            let port = port_ref.borrow();
68            // We might want to insert the @data attribute for optimization purposes.
69            // But to do this, we have to make sure that the cell is marked @data
70            // as well.
71            let new_port_attrs =
72                if is_data_cell & port.attributes.has(ir::BoolAttr::Data) {
73                    let mut attrs = ir::Attributes::default();
74                    attrs.insert(ir::BoolAttr::Data, 1);
75                    attrs
76                } else {
77                    ir::Attributes::default()
78                };
79
80            let new_port = ir::rrc(ir::Port {
81                name: component.generate_name(format_port_name(&canon)),
82                width: port.width,
83                direction: port.direction.clone(),
84                parent: ir::PortParent::Cell(WRC::from(&component.signature)),
85                attributes: new_port_attrs,
86            });
87            component
88                .signature
89                .borrow_mut()
90                .ports
91                .push(Rc::clone(&new_port));
92
93            // Record the port as removed
94            removed.insert(canon.clone(), Rc::clone(&new_port));
95        }
96    }
97    DumpResults {
98        cells: ext_cells,
99        rewrites: removed,
100    }
101}