calyx_opt/passes/
dump_ports.rs

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
91
92
93
94
95
96
97
98
99
100
101
use calyx_ir::{self as ir, RRC, WRC};
use ir::rewriter;
use itertools::Itertools;
use std::rc::Rc;

#[derive(Default)]
/// Results generated from the process of dumping out ports.
pub struct DumpResults {
    /// The cells that were removed from the component.
    pub cells: Vec<RRC<ir::Cell>>,
    /// Rewrites from (cell, port) to the new port.
    /// Usually consumed by an [`ir::rewriter::Rewriter`].
    pub rewrites: rewriter::PortRewriteMap,
}

/// Formats name of a port given the id of the cell and the port
pub(super) fn format_port_name(canon: &ir::Canonical) -> ir::Id {
    format!("{}_{}", canon.cell, canon.port).into()
}

/// Remove all the cells matching the given criterion (f evaluates to true) from
/// the component and inline all the ports of the removed cells to the component
/// signature.
///
/// If `remove_clk_and_reset` is true, does not inline ports marked with @clk and @reset.
pub(super) fn dump_ports_to_signature<F>(
    component: &mut ir::Component,
    cell_filter: F,
    remove_clk_and_reset: bool,
) -> DumpResults
where
    F: Fn(&RRC<ir::Cell>) -> bool,
{
    let mut removed = rewriter::PortRewriteMap::default();

    let (ext_cells, cells): (Vec<_>, Vec<_>) =
        component.cells.drain().partition(cell_filter);
    component.cells.append(cells.into_iter());

    for cell_ref in &ext_cells {
        let cell = cell_ref.borrow();
        log::debug!("cell `{}' removed", cell.name());
        // We need this information because we might want to attach the `@data`
        // attribute to some of the ports.
        let is_data_cell = cell.attributes.has(ir::BoolAttr::Data);

        // If we do not eliminate the @clk and @reset ports, we may
        // get signals conflicting the original @clk and @reset signals of
        // the component, see https://github.com/calyxir/calyx/issues/1034
        let ports_inline = cell
            .ports
            .iter()
            .filter(|pr| {
                if remove_clk_and_reset {
                    let p = pr.borrow();
                    !p.attributes.has(ir::BoolAttr::Clk)
                        && !p.attributes.has(ir::BoolAttr::Reset)
                } else {
                    true
                }
            })
            .map(Rc::clone)
            .collect_vec();

        for port_ref in ports_inline {
            let canon = port_ref.borrow().canonical();
            let port = port_ref.borrow();
            // We might want to insert the @data attribute for optimization purposes.
            // But to do this, we have to make sure that the cell is marked @data
            // as well.
            let new_port_attrs =
                if is_data_cell & port.attributes.has(ir::BoolAttr::Data) {
                    let mut attrs = ir::Attributes::default();
                    attrs.insert(ir::BoolAttr::Data, 1);
                    attrs
                } else {
                    ir::Attributes::default()
                };

            let new_port = ir::rrc(ir::Port {
                name: component.generate_name(format_port_name(&canon)),
                width: port.width,
                direction: port.direction.clone(),
                parent: ir::PortParent::Cell(WRC::from(&component.signature)),
                attributes: new_port_attrs,
            });
            component
                .signature
                .borrow_mut()
                .ports
                .push(Rc::clone(&new_port));

            // Record the port as removed
            removed.insert(canon.clone(), Rc::clone(&new_port));
        }
    }
    DumpResults {
        cells: ext_cells,
        rewrites: removed,
    }
}