calyx_opt/passes_experimental/sync/
compile_sync_without_sync_reg.rsuse crate::traversal::{Action, Named, VisResult, Visitor};
use calyx_ir::Guard;
use calyx_ir::Nothing;
use calyx_ir::{self as ir, GetAttributes, RRC};
use calyx_ir::{build_assignments, guard, structure};
use calyx_utils::{CalyxResult, Error};
use std::collections::HashMap;
#[derive(Default)]
pub struct CompileSyncWithoutSyncReg;
impl Named for CompileSyncWithoutSyncReg {
fn name() -> &'static str {
"compile-sync-without-sync-reg"
}
fn description() -> &'static str {
"Implement barriers for statements marked with @sync attribute without std_sync_reg"
}
}
#[derive(Default)]
struct BarrierMap(HashMap<u64, (RRC<ir::Cell>, Box<ir::Guard<ir::Nothing>>)>);
impl BarrierMap {
fn get_mut(
&mut self,
idx: &u64,
) -> Option<&mut (RRC<calyx_ir::Cell>, Box<Guard<Nothing>>)> {
self.0.get_mut(idx)
}
fn new() -> Self {
BarrierMap(HashMap::new())
}
fn get_reg(&mut self, idx: &u64) -> &mut RRC<ir::Cell> {
let (cell, _) = self.get_mut(idx).unwrap();
cell
}
fn get_guard(&mut self, idx: &u64) -> &mut Box<ir::Guard<ir::Nothing>> {
let (_, gd) = self.get_mut(idx).unwrap();
gd
}
fn insert_shared_wire(&mut self, builder: &mut ir::Builder, idx: &u64) {
if !self.0.contains_key(idx) {
structure!(builder;
let s = prim std_wire(1);
);
let gd = ir::Guard::True;
self.0.insert(*idx, (s, Box::new(gd)));
}
}
}
fn build_barrier_group(
builder: &mut ir::Builder,
barrier_idx: &u64,
barrier_reg: &mut BarrierMap,
) -> ir::Control {
let group = builder.add_group("barrier");
structure!(
builder;
let bar = prim std_reg(1);
let z = constant(0, 1);
let constant = constant(1, 1);
);
barrier_reg
.get_guard(barrier_idx)
.update(|g| g.and(guard!(bar["out"])));
let s = barrier_reg.get_reg(barrier_idx);
let assigns = build_assignments!(builder;
bar["in"] = ? constant["out"];
bar["write_en"] = ? constant["out"];
group["done"] = ? s["out"];
);
group.borrow_mut().assignments.extend(assigns);
let clear = builder.add_group("clear");
let clear_assigns = build_assignments!(builder;
bar["in"] = ? z["out"];
bar["write_en"] = ? constant["out"];
clear["done"] = ? bar["done"];);
clear.borrow_mut().assignments.extend(clear_assigns);
let stmts = vec![ir::Control::enable(group), ir::Control::enable(clear)];
ir::Control::seq(stmts)
}
fn produce_err(con: &ir::Control) -> CalyxResult<()> {
match con {
ir::Control::Enable(e) => {
if con.get_attributes().get(ir::NumAttr::Sync).is_some() {
return Err(Error::malformed_control(
"Enable or Invoke controls cannot be marked with @sync"
.to_string(),
)
.with_pos(e.get_attributes()));
}
Ok(())
}
ir::Control::Invoke(i) => {
if con.get_attributes().get(ir::NumAttr::Sync).is_some() {
return Err(Error::malformed_control(
"Enable or Invoke controls cannot be marked with @sync"
.to_string(),
)
.with_pos(&i.attributes));
}
Ok(())
}
_ => Ok(()),
}
}
fn insert_barrier(
builder: &mut ir::Builder,
con: &mut ir::Control,
barrier_reg: &mut BarrierMap,
barrier_con: &mut HashMap<u64, ir::Control>,
) -> CalyxResult<()> {
match con {
ir::Control::Empty(_) => {
if let Some(ref n) = con.get_attributes().get(ir::NumAttr::Sync) {
barrier_reg.insert_shared_wire(builder, n);
let con_ref = barrier_con.entry(*n).or_insert_with(|| {
build_barrier_group(builder, n, barrier_reg)
});
std::mem::swap(con, &mut ir::Cloner::control(con_ref));
}
Ok(())
}
ir::Control::Seq(seq) => {
for s in seq.stmts.iter_mut() {
insert_barrier(builder, s, barrier_reg, barrier_con)?;
}
Ok(())
}
ir::Control::If(i) => {
insert_barrier(builder, &mut i.tbranch, barrier_reg, barrier_con)?;
insert_barrier(builder, &mut i.fbranch, barrier_reg, barrier_con)?;
Ok(())
}
ir::Control::While(w) => {
insert_barrier(builder, &mut w.body, barrier_reg, barrier_con)?;
Ok(())
}
ir::Control::Enable(_) | ir::Control::Invoke(_) => {
produce_err(con)?;
Ok(())
}
_ => Ok(()),
}
}
impl Visitor for CompileSyncWithoutSyncReg {
fn finish_par(
&mut self,
s: &mut ir::Par,
comp: &mut ir::Component,
sigs: &ir::LibrarySignatures,
_comps: &[ir::Component],
) -> VisResult {
let mut builder = ir::Builder::new(comp, sigs);
let mut barrier_reg: BarrierMap = BarrierMap::new();
for stmt in s.stmts.iter_mut() {
let mut barrier_con: HashMap<u64, ir::Control> = HashMap::new();
insert_barrier(
&mut builder,
stmt,
&mut barrier_reg,
&mut barrier_con,
)?;
}
for (_, (wire, g_box)) in barrier_reg.0 {
structure!( builder;
let constant = constant(1,1);
);
let g = *g_box;
let cont_assigns = build_assignments!(builder;
wire["in"] = g ? constant["out"];
);
builder
.component
.continuous_assignments
.extend(cont_assigns);
}
Ok(Action::Continue)
}
}