calyx_opt/passes/
lower_guards.rs1use crate::traversal::{Action, Named, VisResult, Visitor};
2use calyx_ir::{self as ir, RRC};
3use ir::Nothing;
4
5#[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 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 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 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}