calyx_opt/passes/
lower_guards.rs

1use crate::traversal::{Action, Named, VisResult, Visitor};
2use calyx_ir::{self as ir, RRC};
3use ir::Nothing;
4
5/// Lowers guards into a purely structural representation. After this pass,
6/// all guards are guaranteed to be either [ir::Guard::True] or [ir::Guard::Port].
7#[derive(Default)]
8pub struct LowerGuards;
9
10impl Named for LowerGuards {
11    fn name() -> &'static str {
12        "lower-guards"
13    }
14
15    fn description() -> &'static str {
16        "lower guards to a purely structural representation"
17    }
18}
19
20fn guard_to_prim(guard: &ir::Guard<ir::Nothing>) -> Option<String> {
21    let var_name = match guard {
22        ir::Guard::Or(..) => "or",
23        ir::Guard::And(..) => "and",
24        ir::Guard::CompOp(op, _, _) => match op {
25            ir::PortComp::Eq => "eq",
26            ir::PortComp::Neq => "neq",
27            ir::PortComp::Gt => "gt",
28            ir::PortComp::Lt => "lt",
29            ir::PortComp::Geq => "ge",
30            ir::PortComp::Leq => "le",
31        },
32        ir::Guard::True | ir::Guard::Not(_) | ir::Guard::Port(_) => {
33            return None;
34        }
35        ir::Guard::Info(_) => {
36            panic!("Guards Shouldn't Take Info at this Point")
37        }
38    };
39    Some(var_name.to_string())
40}
41
42fn lower_guard(
43    guard: ir::Guard<Nothing>,
44    assigns: &mut Vec<ir::Assignment<Nothing>>,
45    builder: &mut ir::Builder,
46) -> RRC<ir::Port> {
47    let maybe_prim = guard_to_prim(&guard);
48    match guard {
49        ir::Guard::And(l, r) | ir::Guard::Or(l, r) => {
50            let l_low = lower_guard(*l, assigns, builder);
51            let r_low = lower_guard(*r, assigns, builder);
52
53            let prim = maybe_prim.unwrap();
54            let prim_name = format!("std_{prim}");
55            let prim_cell =
56                builder.add_primitive(prim, prim_name, &[l_low.borrow().width]);
57            let prim = prim_cell.borrow();
58
59            assigns.push(builder.build_assignment(
60                prim.get("left"),
61                l_low,
62                ir::Guard::True,
63            ));
64            assigns.push(builder.build_assignment(
65                prim.get("right"),
66                r_low,
67                ir::Guard::True,
68            ));
69            prim.get("out")
70        }
71
72        ir::Guard::CompOp(_, l, r) => {
73            let prim = maybe_prim.unwrap();
74            let prim_name = format!("std_{prim}");
75            let prim_cell =
76                builder.add_primitive(prim, prim_name, &[l.borrow().width]);
77            let prim = prim_cell.borrow();
78
79            assigns.push(builder.build_assignment(
80                prim.get("left"),
81                l,
82                ir::Guard::True,
83            ));
84            assigns.push(builder.build_assignment(
85                prim.get("right"),
86                r,
87                ir::Guard::True,
88            ));
89            prim.get("out")
90        }
91        ir::Guard::Not(g) => {
92            let g_low = lower_guard(*g, assigns, builder);
93            let not_prim = builder.add_primitive(
94                "not",
95                "std_not",
96                &[g_low.borrow().width],
97            );
98            let not = not_prim.borrow();
99            assigns.push(builder.build_assignment(
100                not.get("in"),
101                g_low,
102                ir::Guard::True,
103            ));
104            not.get("out")
105        }
106        ir::Guard::True => builder.add_constant(1, 1).borrow().get("out"),
107        ir::Guard::Port(p) => p,
108        ir::Guard::Info(_) => panic!("shouldn't have info ports at this point"),
109    }
110}
111
112fn lower_assigns(
113    assigns: Vec<ir::Assignment<Nothing>>,
114    builder: &mut ir::Builder,
115) -> Vec<ir::Assignment<Nothing>> {
116    let mut new_assigns = Vec::with_capacity(assigns.len() * 2);
117    for mut assign in assigns {
118        let g = std::mem::take(&mut assign.guard);
119        let mut assigns = vec![];
120        let port = lower_guard(*g, &mut assigns, builder);
121        assign.guard = Box::new(port.into());
122        new_assigns.extend(assigns);
123        new_assigns.push(assign);
124    }
125    new_assigns
126}
127
128impl Visitor for LowerGuards {
129    fn start(
130        &mut self,
131        comp: &mut ir::Component,
132        sigs: &ir::LibrarySignatures,
133        _comps: &[ir::Component],
134    ) -> VisResult {
135        let mut builder = ir::Builder::new(comp, sigs);
136
137        // Transform continuous assignments
138        let conts: Vec<_> =
139            builder.component.continuous_assignments.drain(..).collect();
140        let new_conts = lower_assigns(conts, &mut builder);
141        builder.component.continuous_assignments = new_conts;
142
143        // Transform group assignments
144        let groups = builder
145            .component
146            .get_groups_mut()
147            .drain()
148            .inspect(|group| {
149                let assigns =
150                    group.borrow_mut().assignments.drain(..).collect();
151                let new_assigns = lower_assigns(assigns, &mut builder);
152                group.borrow_mut().assignments = new_assigns;
153            })
154            .into();
155        builder.component.set_groups(groups);
156
157        /*let static_groups = builder
158            .component
159            .get_static_groups_mut()
160            .drain()
161            .map(|group| {
162                let assigns =
163                    group.borrow_mut().assignments.drain(..).collect();
164                let new_assigns = lower_assigns(assigns, &mut builder);
165                group.borrow_mut().assignments = new_assigns;
166                group
167            })
168            .into();
169        builder.component.set_static_groups(static_groups);*/
170
171        // Transform comb group assignments
172        let comb_groups = builder
173            .component
174            .comb_groups
175            .drain()
176            .inspect(|group| {
177                let assigns =
178                    group.borrow_mut().assignments.drain(..).collect();
179                let new_assigns = lower_assigns(assigns, &mut builder);
180                group.borrow_mut().assignments = new_assigns;
181            })
182            .into();
183        builder.component.comb_groups = comb_groups;
184
185        Ok(Action::Stop)
186    }
187}