calyx_opt/passes_experimental/sync/
compile_sync_without_sync_reg.rs1use crate::traversal::{Action, Named, VisResult, Visitor};
2use calyx_ir::Guard;
3use calyx_ir::Nothing;
4use calyx_ir::{self as ir, GetAttributes, RRC};
5use calyx_ir::{build_assignments, guard, structure};
6use calyx_utils::{CalyxResult, Error};
7use std::collections::HashMap;
8
9#[derive(Default)]
10pub struct CompileSyncWithoutSyncReg;
28
29impl Named for CompileSyncWithoutSyncReg {
30 fn name() -> &'static str {
31 "compile-sync-without-sync-reg"
32 }
33
34 fn description() -> &'static str {
35 "Implement barriers for statements marked with @sync attribute without std_sync_reg"
36 }
37}
38
39#[derive(Default)]
42struct BarrierMap(HashMap<u64, (RRC<ir::Cell>, Box<ir::Guard<ir::Nothing>>)>);
43
44impl BarrierMap {
45 fn get_mut(
46 &mut self,
47 idx: &u64,
48 ) -> Option<&mut (RRC<calyx_ir::Cell>, Box<Guard<Nothing>>)> {
49 self.0.get_mut(idx)
50 }
51
52 fn new() -> Self {
53 BarrierMap(HashMap::new())
54 }
55
56 fn get_reg(&mut self, idx: &u64) -> &mut RRC<ir::Cell> {
57 let (cell, _) = self.get_mut(idx).unwrap();
58 cell
59 }
60
61 fn get_guard(&mut self, idx: &u64) -> &mut Box<ir::Guard<ir::Nothing>> {
62 let (_, gd) = self.get_mut(idx).unwrap();
63 gd
64 }
65
66 fn insert_shared_wire(&mut self, builder: &mut ir::Builder, idx: &u64) {
67 if !self.0.contains_key(idx) {
68 structure!(builder;
69 let s = prim std_wire(1);
70 );
71 let gd = ir::Guard::True;
72 self.0.insert(*idx, (s, Box::new(gd)));
73 }
74 }
75}
76
77fn build_barrier_group(
80 builder: &mut ir::Builder,
81 barrier_idx: &u64,
82 barrier_reg: &mut BarrierMap,
83) -> ir::Control {
84 let group = builder.add_group("barrier");
85 structure!(
86 builder;
87 let bar = prim std_reg(1);
88 let z = constant(0, 1);
89 let constant = constant(1, 1);
90 );
91
92 barrier_reg
93 .get_guard(barrier_idx)
94 .update(|g| g.and(guard!(bar["out"])));
95
96 let s = barrier_reg.get_reg(barrier_idx);
97
98 let assigns = build_assignments!(builder;
99 bar["in"] = ? constant["out"];
100 bar["write_en"] = ? constant["out"];
101 group["done"] = ? s["out"];
102 );
103 group.borrow_mut().assignments.extend(assigns);
104
105 let clear = builder.add_group("clear");
106 let clear_assigns = build_assignments!(builder;
107 bar["in"] = ? z["out"];
108 bar["write_en"] = ? constant["out"];
109 clear["done"] = ? bar["done"];);
110 clear.borrow_mut().assignments.extend(clear_assigns);
111
112 let stmts = vec![ir::Control::enable(group), ir::Control::enable(clear)];
113
114 ir::Control::seq(stmts)
115}
116
117fn produce_err(con: &ir::Control) -> CalyxResult<()> {
119 match con {
120 ir::Control::Enable(e) => {
121 if con.get_attributes().get(ir::NumAttr::Sync).is_some() {
122 return Err(Error::malformed_control(
123 "Enable or Invoke controls cannot be marked with @sync"
124 .to_string(),
125 )
126 .with_pos(e.get_attributes()));
127 }
128 Ok(())
129 }
130 ir::Control::Invoke(i) => {
131 if con.get_attributes().get(ir::NumAttr::Sync).is_some() {
132 return Err(Error::malformed_control(
133 "Enable or Invoke controls cannot be marked with @sync"
134 .to_string(),
135 )
136 .with_pos(&i.attributes));
137 }
138 Ok(())
139 }
140 _ => Ok(()),
141 }
142}
143
144fn insert_barrier(
147 builder: &mut ir::Builder,
148 con: &mut ir::Control,
149 barrier_reg: &mut BarrierMap,
150 barrier_con: &mut HashMap<u64, ir::Control>,
151) -> CalyxResult<()> {
152 match con {
153 ir::Control::Empty(_) => {
154 if let Some(ref n) = con.get_attributes().get(ir::NumAttr::Sync) {
155 barrier_reg.insert_shared_wire(builder, n);
156 let con_ref = barrier_con.entry(*n).or_insert_with(|| {
157 build_barrier_group(builder, n, barrier_reg)
158 });
159 *con = ir::Cloner::control(con_ref);
160 }
161 Ok(())
162 }
163 ir::Control::Seq(seq) => {
164 for s in seq.stmts.iter_mut() {
165 insert_barrier(builder, s, barrier_reg, barrier_con)?;
166 }
167 Ok(())
168 }
169 ir::Control::If(i) => {
170 insert_barrier(builder, &mut i.tbranch, barrier_reg, barrier_con)?;
171 insert_barrier(builder, &mut i.fbranch, barrier_reg, barrier_con)?;
172 Ok(())
173 }
174 ir::Control::While(w) => {
175 insert_barrier(builder, &mut w.body, barrier_reg, barrier_con)?;
176 Ok(())
177 }
178 ir::Control::Enable(_) | ir::Control::Invoke(_) => {
179 produce_err(con)?;
180 Ok(())
181 }
182 _ => Ok(()),
183 }
184}
185impl Visitor for CompileSyncWithoutSyncReg {
186 fn finish_par(
187 &mut self,
188 s: &mut ir::Par,
189 comp: &mut ir::Component,
190 sigs: &ir::LibrarySignatures,
191 _comps: &[ir::Component],
192 ) -> VisResult {
193 let mut builder = ir::Builder::new(comp, sigs);
194 let mut barrier_reg: BarrierMap = BarrierMap::new();
195 for stmt in s.stmts.iter_mut() {
196 let mut barrier_con: HashMap<u64, ir::Control> = HashMap::new();
197 insert_barrier(
198 &mut builder,
199 stmt,
200 &mut barrier_reg,
201 &mut barrier_con,
202 )?;
203 }
204
205 for (_, (wire, g_box)) in barrier_reg.0 {
207 structure!( builder;
208 let constant = constant(1,1);
209 );
210 let g = *g_box;
211 let cont_assigns = build_assignments!(builder;
212 wire["in"] = g ? constant["out"];
213 );
214 builder
215 .component
216 .continuous_assignments
217 .extend(cont_assigns);
218 }
219 Ok(Action::Continue)
220 }
221}