From 43f7f89494dd7c5e18ae2b698e8f6dc52eede4ec Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 27 Aug 2021 20:35:34 +0530 Subject: [PATCH 01/50] simplify parsing names with attributes attached --- calyx/src/frontend/parser.rs | 56 +++++++++------------------------- calyx/src/frontend/syntax.pest | 9 ++++-- 2 files changed, 20 insertions(+), 45 deletions(-) diff --git a/calyx/src/frontend/parser.rs b/calyx/src/frontend/parser.rs index 880a01d2ef..c3920b4a96 100644 --- a/calyx/src/frontend/parser.rs +++ b/calyx/src/frontend/parser.rs @@ -209,13 +209,21 @@ impl CalyxParser { [string_lit(key), bitwidth(num)] => (key, num) )) } - fn attributes(input: Node) -> ParseResult { Ok(match_nodes!( input.into_children(); [attribute(kvs)..] => kvs.collect::>().into() )) } + fn name_with_attribute( + input: Node, + ) -> ParseResult<(ir::Id, ir::Attributes)> { + Ok(match_nodes!( + input.into_children(); + [identifier(name), attributes(attrs)] => (name, attrs), + [identifier(name)] => (name, vec![].into()), + )) + } fn attr_val(input: Node) -> ParseResult { Ok(match_nodes!( @@ -307,30 +315,18 @@ impl CalyxParser { fn primitive(input: Node) -> ParseResult { Ok(match_nodes!( input.into_children(); - [identifier(name), attributes(attrs), params(p), signature(s)] => ir::Primitive { + [name_with_attribute((name, attrs)), params(p), signature(s)] => ir::Primitive { name, params: p, signature: s, attributes: attrs, }, - [identifier(name), attributes(attrs), signature(s)] => ir::Primitive { + [name_with_attribute((name, attrs)), signature(s)] => ir::Primitive { name, params: Vec::with_capacity(0), signature: s, attributes: attrs, }, - [identifier(name), params(p), signature(s)] => ir::Primitive { - name, - params: p, - signature: s, - attributes: ir::Attributes::default() - }, - [identifier(name), signature(s)] => ir::Primitive { - name, - params: Vec::with_capacity(0), - signature: s, - attributes: ir::Attributes::default() - } )) } @@ -488,15 +484,10 @@ impl CalyxParser { fn group(input: Node) -> ParseResult { Ok(match_nodes!( input.into_children(); - [identifier(name), attributes(attrs), wire(wire)..] => ast::Group { + [name_with_attribute((name, attrs)), wire(wire)..] => ast::Group { name, attributes: attrs, wires: wire.collect() - }, - [identifier(name), wire(wire)..] => ast::Group { - name, - attributes: ir::Attributes::default(), - wires: wire.collect() } )) } @@ -658,26 +649,7 @@ impl CalyxParser { Ok(match_nodes!( input.into_children(); [ - identifier(id), - signature(sig), - cells(cells), - connections(connections), - control(control) - ] => { - let (continuous_assignments, groups) = connections; - ast::ComponentDef { - name: id, - signature: sig, - cells, - groups, - continuous_assignments, - control, - attributes: ir::Attributes::default() - } - }, - [ - identifier(id), - attributes(attributes), + name_with_attribute((name, attributes)), signature(sig), cells(cells), connections(connections), @@ -685,7 +657,7 @@ impl CalyxParser { ] => { let (continuous_assignments, groups) = connections; ast::ComponentDef { - name: id, + name, signature: sig, cells, groups, diff --git a/calyx/src/frontend/syntax.pest b/calyx/src/frontend/syntax.pest index 2f2149e098..2db09c29d1 100644 --- a/calyx/src/frontend/syntax.pest +++ b/calyx/src/frontend/syntax.pest @@ -50,7 +50,7 @@ extern_or_component = { } component = { - "component" ~ identifier ~ attributes? ~ signature + "component" ~ name_with_attribute ~ signature ~ "{" ~ cells ~ connections @@ -92,7 +92,7 @@ params = { } primitive = { - "primitive" ~ identifier ~ attributes? ~ params? ~ signature ~ ";" + "primitive" ~ name_with_attribute ~ params? ~ signature ~ ";" } ext = { @@ -188,6 +188,9 @@ attribute = { attributes = { "<" ~ (attribute ~ ("," ~ attribute)*) ~ ">" } +name_with_attribute = { + identifier ~ attributes? +} // @static(1) style annotation attr_val = { @@ -201,7 +204,7 @@ at_attributes = { } group = { - "group" ~ identifier ~ attributes? ~ "{" + "group" ~ name_with_attribute ~ "{" ~ wire* ~ "}" } From 74d8c7fe7cdce5fd4af40f727d7ef67a4e90cf15 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 27 Aug 2021 21:03:43 +0530 Subject: [PATCH 02/50] initial implementation of comb groups --- calyx/src/frontend/ast.rs | 1 + calyx/src/frontend/parser.rs | 13 ++++++++++++- calyx/src/frontend/syntax.pest | 3 ++- calyx/src/ir/builder.rs | 23 +++++++++++++++++++++++ calyx/src/ir/from_ast.rs | 22 ++++++++++++++-------- calyx/src/ir/printer.rs | 3 +++ calyx/src/ir/structure.rs | 13 +++++++++++++ 7 files changed, 68 insertions(+), 10 deletions(-) diff --git a/calyx/src/frontend/ast.rs b/calyx/src/frontend/ast.rs index 1644eb457d..407f857491 100644 --- a/calyx/src/frontend/ast.rs +++ b/calyx/src/frontend/ast.rs @@ -251,6 +251,7 @@ pub struct Group { pub name: ir::Id, pub wires: Vec, pub attributes: ir::Attributes, + pub is_comb: bool, } /// Data for the `->` structure statement. diff --git a/calyx/src/frontend/parser.rs b/calyx/src/frontend/parser.rs index c3920b4a96..5533c9a43d 100644 --- a/calyx/src/frontend/parser.rs +++ b/calyx/src/frontend/parser.rs @@ -91,6 +91,10 @@ impl CalyxParser { Ok(()) } + fn comb(_input: Node) -> ParseResult<()> { + Ok(()) + } + // ================ Literals ===================== fn identifier(input: Node) -> ParseResult { Ok(ir::Id::new( @@ -487,7 +491,14 @@ impl CalyxParser { [name_with_attribute((name, attrs)), wire(wire)..] => ast::Group { name, attributes: attrs, - wires: wire.collect() + wires: wire.collect(), + is_comb: false, + }, + [comb(_), name_with_attribute((name, attrs)), wire(wire)..] => ast::Group { + name, + attributes: attrs, + wires: wire.collect(), + is_comb: true, } )) } diff --git a/calyx/src/frontend/syntax.pest b/calyx/src/frontend/syntax.pest index 2db09c29d1..b5aed8893d 100644 --- a/calyx/src/frontend/syntax.pest +++ b/calyx/src/frontend/syntax.pest @@ -203,8 +203,9 @@ at_attributes = { at_attribute* } +comb = { "comb" } group = { - "group" ~ name_with_attribute ~ "{" + comb? ~ "group" ~ name_with_attribute ~ "{" ~ wire* ~ "}" } diff --git a/calyx/src/ir/builder.rs b/calyx/src/ir/builder.rs index 650f83536a..465d210af7 100644 --- a/calyx/src/ir/builder.rs +++ b/calyx/src/ir/builder.rs @@ -66,6 +66,7 @@ impl<'a> Builder<'a> { attributes: ir::Attributes::default(), holes: smallvec![], assignments: vec![], + is_comb: false, })); // Add default holes to the group. @@ -86,6 +87,28 @@ impl<'a> Builder<'a> { group } + /// Construct a combinational group + pub fn add_comb_group(&mut self, prefix: S) -> RRC + where + S: Into + ToString + Clone, + { + let name = self.component.generate_name(prefix); + + // Check if there is a group with the same name. + let group = Rc::new(RefCell::new(ir::Group { + name, + attributes: ir::Attributes::default(), + assignments: vec![], + holes: smallvec![], + is_comb: true, + })); + + // Add the group to the component. + self.component.groups.add(Rc::clone(&group)); + + group + } + /// Return reference for a constant cell associated with the (val, width) /// pair, building and adding it to the component if needed.. /// If the constant does not exist, it is added to the Context. diff --git a/calyx/src/ir/from_ast.rs b/calyx/src/ir/from_ast.rs index b4006dd2c1..9a22591bee 100644 --- a/calyx/src/ir/from_ast.rs +++ b/calyx/src/ir/from_ast.rs @@ -276,16 +276,22 @@ fn add_cell(cell: ast::Cell, sig_ctx: &SigCtx, builder: &mut Builder) { ///////////////// Group Construction ///////////////////////// -/// Build an IR group using the AST Group. +/// Build an [ir::Group] from an [ast::Group] and attach it to the [ir::Compoennt] +/// associated with the [ir::Builder] fn add_group(group: ast::Group, builder: &mut Builder) -> CalyxResult<()> { - let ir_group = builder.add_group(group.name); - ir_group.borrow_mut().attributes = group.attributes; + let assigns = group + .wires + .into_iter() + .map(|assign| build_assignment(assign, builder)) + .collect::>>()?; - // Add assignemnts to the group - for wire in group.wires { - let assign = build_assignment(wire, builder)?; - ir_group.borrow_mut().assignments.push(assign) - } + let ir_group = if group.is_comb { + builder.add_comb_group(group.name) + } else { + builder.add_group(group.name) + }; + ir_group.borrow_mut().attributes = group.attributes; + ir_group.borrow_mut().assignments = assigns; Ok(()) } diff --git a/calyx/src/ir/printer.rs b/calyx/src/ir/printer.rs index 5707b6e85c..d611e60358 100644 --- a/calyx/src/ir/printer.rs +++ b/calyx/src/ir/printer.rs @@ -189,6 +189,9 @@ impl IRPrinter { f: &mut F, ) -> io::Result<()> { write!(f, "{}", " ".repeat(indent_level))?; + if group.is_comb() { + write!(f, "comb")?; + } write!(f, "group {}", group.name().id)?; if !group.attributes.is_empty() { write!(f, "{}", Self::format_attributes(&group.attributes))?; diff --git a/calyx/src/ir/structure.rs b/calyx/src/ir/structure.rs index c74b5199e8..a3ea9021e4 100644 --- a/calyx/src/ir/structure.rs +++ b/calyx/src/ir/structure.rs @@ -319,6 +319,11 @@ pub struct Group { /// Attributes for this group. pub attributes: Attributes, + + /// True if this is a combinational group. A combinational group does + /// not have any holes and should only contain assignments that should be + /// combinationally active + pub(super) is_comb: bool, } impl Group { /// Get a reference to the named hole if it exists. @@ -346,6 +351,14 @@ impl Group { }) } + /// Returns true if this group is combinational. + #[inline] + pub fn is_comb(&self) -> bool { + debug_assert!(self.holes.is_empty()); + self.is_comb + } + + /// The name of this group. pub fn name(&self) -> &Id { &self.name } From bbc3e541eac89c165c9552a35d63c414f91c3dd0 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 28 Aug 2021 19:06:07 +0530 Subject: [PATCH 03/50] top-down-cc requires cond ports to be @stable --- calyx/src/analysis/control_ports.rs | 10 +- calyx/src/analysis/live_range_analysis.rs | 5 +- calyx/src/analysis/reaching_defns.rs | 10 +- calyx/src/analysis/schedule_conflicts.rs | 6 +- calyx/src/ir/control.rs | 6 +- calyx/src/ir/from_ast.rs | 36 ++++-- calyx/src/ir/printer.rs | 11 +- calyx/src/ir/structure.rs | 2 +- calyx/src/passes/compile_control.rs | 11 +- calyx/src/passes/component_interface.rs | 8 +- calyx/src/passes/infer_static_timing.rs | 6 +- calyx/src/passes/inliner.rs | 3 +- calyx/src/passes/remove_comb_groups.rs | 9 +- calyx/src/passes/static_timing.rs | 26 ++-- calyx/src/passes/top_down_compile_control.rs | 119 ++++++------------- calyx/src/passes/well_formed.rs | 18 ++- tools/vim/futil/syntax/futil.vim | 5 +- 17 files changed, 149 insertions(+), 142 deletions(-) diff --git a/calyx/src/analysis/control_ports.rs b/calyx/src/analysis/control_ports.rs index 4c12d947c5..06b1e48443 100644 --- a/calyx/src/analysis/control_ports.rs +++ b/calyx/src/analysis/control_ports.rs @@ -36,10 +36,12 @@ fn construct( fbranch, .. }) => { - used_ports - .entry(cond.borrow().name().clone()) - .or_default() - .push(Rc::clone(port)); + if let Some(c) = cond { + used_ports + .entry(c.borrow().name().clone()) + .or_default() + .push(Rc::clone(port)); + } construct(tbranch, used_ports); construct(fbranch, used_ports); diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 355eb9b9bc..00d57084fe 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -429,7 +429,10 @@ fn build_live_ranges( // feed to condition to compute build_live_ranges( - &ir::Control::enable(cond.clone()), + &cond + .as_ref() + .map(|c| ir::Control::enable(Rc::clone(c))) + .unwrap_or_else(ir::Control::empty), alive, gens, kills, diff --git a/calyx/src/analysis/reaching_defns.rs b/calyx/src/analysis/reaching_defns.rs index 80baa9f14e..15a5b4e2c0 100644 --- a/calyx/src/analysis/reaching_defns.rs +++ b/calyx/src/analysis/reaching_defns.rs @@ -331,12 +331,12 @@ fn build_reaching_def( cond, .. }) => { - let fake_enable = ir::Control::Enable(ir::Enable { - attributes: ir::Attributes::default(), - group: Rc::clone(cond), - }); + let cond = &cond + .as_ref() + .map(|c| ir::Control::enable(Rc::clone(c))) + .unwrap_or_else(ir::Control::empty); let (post_cond_def, post_cond_killed) = - build_reaching_def(&fake_enable, reach, killed, rd, counter); + build_reaching_def(cond, reach, killed, rd, counter); let (t_case_def, t_case_killed) = build_reaching_def( tbranch, post_cond_def.clone(), diff --git a/calyx/src/analysis/schedule_conflicts.rs b/calyx/src/analysis/schedule_conflicts.rs index 226c30322e..70ebf73ce8 100644 --- a/calyx/src/analysis/schedule_conflicts.rs +++ b/calyx/src/analysis/schedule_conflicts.rs @@ -121,8 +121,10 @@ fn build_conflict_graph( fbranch, .. }) => { - all_enables.push(cond.clone_name()); - confs.add_node(cond.borrow().name()); + if let Some(c) = cond { + all_enables.push(c.clone_name()); + confs.add_node(c.borrow().name()); + } build_conflict_graph(tbranch, confs, all_enables); build_conflict_graph(fbranch, confs, all_enables); } diff --git a/calyx/src/ir/control.rs b/calyx/src/ir/control.rs index e9fda0b570..dad1789f22 100644 --- a/calyx/src/ir/control.rs +++ b/calyx/src/ir/control.rs @@ -24,8 +24,8 @@ pub struct If { /// Port that connects the conditional check. pub port: RRC, - /// Group that makes the signal on the conditional port valid. - pub cond: RRC, + /// Optional combinational group attached using `with`. + pub cond: Option>, /// Control for the true branch. pub tbranch: Box, @@ -169,7 +169,7 @@ impl Control { /// Convience constructor for if pub fn if_( port: RRC, - cond: RRC, + cond: Option>, tbranch: Box, fbranch: Box, ) -> Self { diff --git a/calyx/src/ir/from_ast.rs b/calyx/src/ir/from_ast.rs index 9a22591bee..58178c3dc4 100644 --- a/calyx/src/ir/from_ast.rs +++ b/calyx/src/ir/from_ast.rs @@ -279,17 +279,17 @@ fn add_cell(cell: ast::Cell, sig_ctx: &SigCtx, builder: &mut Builder) { /// Build an [ir::Group] from an [ast::Group] and attach it to the [ir::Compoennt] /// associated with the [ir::Builder] fn add_group(group: ast::Group, builder: &mut Builder) -> CalyxResult<()> { + let ir_group = if group.is_comb { + builder.add_comb_group(group.name) + } else { + builder.add_group(group.name) + }; let assigns = group .wires .into_iter() .map(|assign| build_assignment(assign, builder)) .collect::>>()?; - let ir_group = if group.is_comb { - builder.add_comb_group(group.name) - } else { - builder.add_group(group.name) - }; ir_group.borrow_mut().attributes = group.attributes; ir_group.borrow_mut().assignments = assigns; @@ -448,11 +448,18 @@ fn build_control( fbranch, attributes, } => { + let group = + builder.component.find_group(&cond).ok_or_else(|| { + Error::Undefined(cond.clone(), "group".to_string()) + })?; + /* if !group.borrow().is_comb() { + return Err(Error::MalformedControl( + cond.fmt_err("This should be a combinational group."), + )); + } */ let mut con = Control::if_( get_port_ref(port, builder.component)?, - Rc::clone(&builder.component.find_group(&cond).ok_or_else( - || Error::Undefined(cond.clone(), "group".to_string()), - )?), + Some(group), Box::new(build_control(*tbranch, builder)?), Box::new(build_control(*fbranch, builder)?), ); @@ -465,11 +472,18 @@ fn build_control( body, attributes, } => { + let group = + builder.component.find_group(&cond).ok_or_else(|| { + Error::Undefined(cond.clone(), "group".to_string()) + })?; + /* if !group.borrow().is_comb() { + return Err(Error::MalformedControl( + cond.fmt_err("This should be a combinational group."), + )); + } */ let mut con = Control::while_( get_port_ref(port, builder.component)?, - Rc::clone(&builder.component.find_group(&cond).ok_or_else( - || Error::Undefined(cond.clone(), "group".to_string()), - )?), + group, Box::new(build_control(*body, builder)?), ); *(con.get_mut_attributes().unwrap()) = attributes; diff --git a/calyx/src/ir/printer.rs b/calyx/src/ir/printer.rs index d611e60358..d455e2ec20 100644 --- a/calyx/src/ir/printer.rs +++ b/calyx/src/ir/printer.rs @@ -290,12 +290,11 @@ impl IRPrinter { if !attributes.is_empty() { write!(f, "{} ", Self::format_at_attributes(attributes))? } - writeln!( - f, - "if {} with {} {{", - Self::get_port_access(&port.borrow()), - cond.borrow().name().id - )?; + writeln!(f, "if {} ", Self::get_port_access(&port.borrow()),)?; + if let Some(c) = cond { + write!(f, "with {} ", c.borrow().name.id)?; + } + writeln!(f, "{{")?; Self::write_control(tbranch, indent_level + 2, f)?; write!(f, "{}}}", " ".repeat(indent_level))?; if let ir::Control::Empty(_) = **fbranch { diff --git a/calyx/src/ir/structure.rs b/calyx/src/ir/structure.rs index a3ea9021e4..7e1d98266b 100644 --- a/calyx/src/ir/structure.rs +++ b/calyx/src/ir/structure.rs @@ -354,7 +354,7 @@ impl Group { /// Returns true if this group is combinational. #[inline] pub fn is_comb(&self) -> bool { - debug_assert!(self.holes.is_empty()); + debug_assert!(!self.is_comb || self.holes.is_empty()); self.is_comb } diff --git a/calyx/src/passes/compile_control.rs b/calyx/src/passes/compile_control.rs index 0c557d260a..6340fac991 100644 --- a/calyx/src/passes/compile_control.rs +++ b/calyx/src/passes/compile_control.rs @@ -5,6 +5,7 @@ use crate::ir::{ traversal::{Action, Named, VisResult, Visitor}, LibrarySignatures, }; +use crate::passes::TopDownCompileControl; use crate::{build_assignments, guard, structure}; use std::convert::TryInto; use std::rc::Rc; @@ -78,7 +79,15 @@ impl Visitor for CompileControl { // create a new group for if related structure let if_group = builder.add_group("if"); - let cond_group = Rc::clone(&cif.cond); + if cif.cond.is_some() { + return Err(Error::MalformedStructure(format!( + "{}: if without `with` is not supported. Use `{}` instead", + Self::name(), + TopDownCompileControl::name() + ))); + } + + let cond_group = Rc::clone(cif.cond.as_ref().unwrap()); let cond = Rc::clone(&cif.port); // extract group names from control statement diff --git a/calyx/src/passes/component_interface.rs b/calyx/src/passes/component_interface.rs index 6b89417fa1..cd834d04a2 100644 --- a/calyx/src/passes/component_interface.rs +++ b/calyx/src/passes/component_interface.rs @@ -70,10 +70,10 @@ impl Visitor for ComponentInterface { } else if let ir::Control::Empty(..) = &*control { Ok(Action::Stop) } else { - Err(Error::MalformedControl( - "ComponentInterface: Structure has more than one group" - .to_string(), - )) + Err(Error::MalformedControl(format!( + "{}: Structure has more than one group", + Self::name() + ))) } } } diff --git a/calyx/src/passes/infer_static_timing.rs b/calyx/src/passes/infer_static_timing.rs index fdf917f3f4..f80544c80d 100644 --- a/calyx/src/passes/infer_static_timing.rs +++ b/calyx/src/passes/infer_static_timing.rs @@ -424,8 +424,7 @@ impl Visitor for InferStaticTiming { _comp: &mut ir::Component, _sigs: &LibrarySignatures, ) -> VisResult { - if let (Some(ctime), Some(ttime), Some(ftime)) = ( - s.cond.borrow().attributes.get("static"), + if let (Some(ttime), Some(ftime)) = ( s.tbranch .get_attributes() .and_then(|attr| attr.get("static")), @@ -433,8 +432,7 @@ impl Visitor for InferStaticTiming { .get_attributes() .and_then(|attr| attr.get("static")), ) { - s.attributes - .insert("static", ctime + 1 + cmp::max(ttime, ftime)); + s.attributes.insert("static", 1 + cmp::max(ttime, ftime)); } Ok(Action::Continue) diff --git a/calyx/src/passes/inliner.rs b/calyx/src/passes/inliner.rs index 6be75941ac..bdf600dc03 100644 --- a/calyx/src/passes/inliner.rs +++ b/calyx/src/passes/inliner.rs @@ -113,7 +113,8 @@ impl Visitor for Inliner { ir::Control::Empty(_) => return Ok(Action::Stop), ir::Control::Enable(en) => Rc::clone(&en.group), _ => return Err(Error::MalformedControl(format!( - "The hole inliner requires control to be a single enable. Try running `{}` before inlining.", + "{}: Control shoudl be a single enable. Try running `{}` before inlining.", + Self::name(), TopDownCompileControl::name())) ) }; diff --git a/calyx/src/passes/remove_comb_groups.rs b/calyx/src/passes/remove_comb_groups.rs index 206020e17f..f0ef847f4e 100644 --- a/calyx/src/passes/remove_comb_groups.rs +++ b/calyx/src/passes/remove_comb_groups.rs @@ -202,9 +202,12 @@ impl Visitor for RemoveCombGroups { _comp: &mut ir::Component, _sigs: &LibrarySignatures, ) -> VisResult { - let key = (s.cond.borrow().name().clone(), s.port.borrow().canonical()); - if let Some(new_port) = self.port_rewrite.get(&key) { - s.port = Rc::clone(new_port); + if let Some(cond) = &s.cond { + let key = + (cond.borrow().name().clone(), s.port.borrow().canonical()); + if let Some(new_port) = self.port_rewrite.get(&key) { + s.port = Rc::clone(new_port); + } } Ok(Action::Continue) } diff --git a/calyx/src/passes/static_timing.rs b/calyx/src/passes/static_timing.rs index b602d0e0d7..9df8c6e845 100644 --- a/calyx/src/passes/static_timing.rs +++ b/calyx/src/passes/static_timing.rs @@ -194,24 +194,26 @@ impl Visitor for StaticTiming { if let (ir::Control::Enable(tdata), ir::Control::Enable(fdata)) = (&*s.tbranch, &*s.fbranch) { - let cond = &s.cond; let tru = &tdata.group; let fal = &fdata.group; - if let (Some(ctime), Some(ttime), Some(ftime)) = ( - check_not_comb(cond)?, - check_not_comb(tru)?, - check_not_comb(fal)?, - ) { - let mut builder = ir::Builder::new(comp, ctx); + if s.cond.is_some() { + return Err(Error::MalformedStructure(format!("{}: condition group should be removed from if. Run `{}` before this pass.", Self::name(), RemoveCombGroups::name()))); + } + + if let (Some(ttime), Some(ftime)) = + (check_not_comb(tru)?, check_not_comb(fal)?) + { + todo!() + /* let mut builder = ir::Builder::new(comp, ctx); let if_group = builder.add_group("static_if"); if_group .borrow_mut() .attributes - .insert("static", ctime + 1 + cmp::max(ttime, ftime)); + .insert("static", 1 + cmp::max(ttime, ftime)); - let end_true_time = ttime + ctime + 1; - let end_false_time = ftime + ctime + 1; + let end_true_time = ttime + 1; + let end_false_time = ftime + 1; // `0` state + (ctime + max(ttime, ftime) + 1) states. let fsm_size = get_bit_width_from( 1 + cmp::max(end_true_time, end_false_time), @@ -223,9 +225,6 @@ impl Visitor for StaticTiming { let cond_stored = prim std_reg(1); let reset_val = constant(0, fsm_size); - let cond_time_const = constant(ctime, fsm_size); - let cond_done_time_const = constant(ctime, fsm_size); - let true_end_const = constant(end_true_time, fsm_size); let false_end_const = constant(end_false_time, fsm_size); @@ -302,6 +301,7 @@ impl Visitor for StaticTiming { comp.continuous_assignments.append(&mut clean_assigns); return Ok(Action::Change(ir::Control::enable(if_group))); + */ } } diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index 44d39e98c7..572df6abef 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -1,10 +1,14 @@ use super::math_utilities::get_bit_width_from; -use crate::ir::{ - self, - traversal::{Action, Named, VisResult, Visitor}, - LibrarySignatures, RRC, -}; +use crate::errors::CalyxResult; use crate::{build_assignments, guard, structure}; +use crate::{ + errors::Error, + ir::{ + self, + traversal::{Action, Named, VisResult, Visitor}, + LibrarySignatures, RRC, + }, +}; use ir::IRPrinter; use itertools::Itertools; use petgraph::{algo::connected_components, graph::DiGraph}; @@ -84,7 +88,7 @@ fn calculate_states( schedule: &mut Schedule, // Component builder builder: &mut ir::Builder, -) -> u64 { +) -> CalyxResult { match con { // Compiled to: // ``` @@ -106,23 +110,23 @@ fn calculate_states( .append(&mut en_go); schedule.transitions.push((cur_state, nxt_state, done_cond)); - nxt_state + Ok(nxt_state) } // Give children the states `cur`, `cur + 1`, `cur + 2`, ... ir::Control::Seq(ir::Seq { stmts, .. }) => { let mut cur = cur_state; for stmt in stmts { - cur = calculate_states(stmt, cur, pre_guard, schedule, builder); + cur = + calculate_states(stmt, cur, pre_guard, schedule, builder)?; } - cur + Ok(cur) } // Generate the following transitions: - // 1. cur -> cur + 1: Compute the condition and store the generated value. - // 2. (cur + 1 -> cur + t): Compute the true branch when stored condition + // 1. (cur -> cur + t): Compute the true branch when stored condition // is true. - // 3. (cur + 1 -> cur + f): Compute the true branch when stored condition + // 2. (cur -> cur + f): Compute the true branch when stored condition // is false. - // 4. (cur + t -> cur + max(t, f) + 1) + // 3. (cur + t -> cur + max(t, f) + 1) // (cur + f -> cur + max(t, f) + 1): Transition to a "join" stage // after running the branch. ir::Control::If(ir::If { @@ -132,81 +136,34 @@ fn calculate_states( fbranch, .. }) => { - structure!(builder; - let signal_on = constant(1, 1); - let signal_off = constant(0, 1); - let cs_if = prim std_reg(1); - ); - - // Compute the condition and save its value in cs_if - let mut cond_save_assigns = vec![ - builder.build_assignment( - cs_if.borrow().get("in"), - Rc::clone(port), - pre_guard.clone(), - ), - builder.build_assignment( - cs_if.borrow().get("write_en"), - signal_on.borrow().get("out"), - pre_guard.clone(), - ), - builder.build_assignment( - cond.borrow().get("go"), - signal_on.borrow().get("out"), - pre_guard.clone(), - ), - ]; - - // Schedule the condition computation first and transition to next - // state. - let after_cond_compute = cur_state + 1; - schedule - .enables - .entry(cur_state) - .or_default() - .append(&mut cond_save_assigns); - schedule.transitions.push(( - cur_state, - after_cond_compute, - guard!(cond["done"]), - )); + // The port must be marked as stable before compilation can proceed + if !matches!(port.borrow().attributes.get("stable"), Some(1)) { + let (cell, port) = port.borrow().canonical(); + return Err(Error::MalformedStructure(format!("{}: `{}.{}` is not marked with @stable. It cannot be used for computing `if` condition.", TopDownCompileControl::name(), cell, port))); + } + // There shouldn't be a group in `with` position. + if cond.is_some() { + return Err(Error::MalformedStructure(format!("{}: Found group `{}` in with position of if. This should have compiled away.", TopDownCompileControl::name(), cond.as_ref().unwrap().borrow().name()))); + } + let port_guard = ir::Guard::port(Rc::clone(port)); // Computation for true branch - let true_go = guard!(cs_if["out"]) & pre_guard.clone(); + let true_go = port_guard.clone() & pre_guard.clone(); let after_true = calculate_states( - tbranch, - after_cond_compute, - &true_go, - schedule, - builder, - ); + tbranch, cur_state, &true_go, schedule, builder, + )?; // Computation for false branch - let false_go = !guard!(cs_if["out"]) & pre_guard.clone(); + let false_go = !port_guard & pre_guard.clone(); let after_false = calculate_states( - fbranch, - after_cond_compute, - &false_go, - schedule, - builder, - ); + fbranch, cur_state, &false_go, schedule, builder, + )?; // Transition to a join stage let next = std::cmp::max(after_true, after_false) + 1; schedule.transitions.push((after_true, next, true_go)); schedule.transitions.push((after_false, next, false_go)); - // Cleanup: Reset cs_if in the join stage. - let mut cleanup = build_assignments!(builder; - cs_if["in"] = pre_guard ? signal_off["out"]; - cs_if["write_en"] = pre_guard ? signal_on["out"]; - ); - schedule - .enables - .entry(next) - .or_default() - .append(&mut cleanup); - - next + Ok(next) } // Compile in three stage: // 1. cur -> cur + 1: Compute the condition and store the generated value. @@ -263,7 +220,7 @@ fn calculate_states( &body_go, schedule, builder, - ); + )?; // Back edge jump when condition was true schedule.transitions.push((nxt, cur_state, body_go)); @@ -286,7 +243,7 @@ fn calculate_states( .or_default() .append(&mut cleanup); - exit + Ok(exit) } // `par` sub-programs should already be compiled ir::Control::Par(..) => { @@ -469,7 +426,7 @@ impl Visitor for TopDownCompileControl { &ir::Guard::True, &mut schedule, &mut builder, - ); + )?; realize_schedule(schedule, &mut builder) } }; @@ -546,7 +503,7 @@ impl Visitor for TopDownCompileControl { &ir::Guard::True, &mut schedule, &mut builder, - ); + )?; let comp_group = realize_schedule(schedule, &mut builder); Ok(Action::Change(ir::Control::enable(comp_group))) diff --git a/calyx/src/passes/well_formed.rs b/calyx/src/passes/well_formed.rs index 691d492a45..877e9a62d0 100644 --- a/calyx/src/passes/well_formed.rs +++ b/calyx/src/passes/well_formed.rs @@ -169,8 +169,17 @@ impl Visitor for WellFormed { _comp: &mut Component, _ctx: &LibrarySignatures, ) -> VisResult { + /* let cond = s.cond.borrow(); + if !cond.is_comb() { + return Err(Error::MalformedControl( + cond.name() + .fmt_err(&format!("Group `{}` was used with `with` syntax. It should be a combinational group.", cond.name())), + )); + } */ // Add cond group as a used port. - self.used_groups.insert(s.cond.clone_name()); + if let Some(cond) = &s.cond { + self.used_groups.insert(cond.clone_name()); + } Ok(Action::Continue) } @@ -180,6 +189,13 @@ impl Visitor for WellFormed { _comp: &mut Component, _ctx: &LibrarySignatures, ) -> VisResult { + /* let cond = s.cond.borrow(); + if !cond.is_comb() { + return Err(Error::MalformedControl( + cond.name() + .fmt_err(&format!("Group `{}` was used with `with` syntax. It should be a combinational group.", cond.name())), + )); + } */ // Add cond group as a used port. self.used_groups.insert(s.cond.clone_name()); Ok(Action::Continue) diff --git a/tools/vim/futil/syntax/futil.vim b/tools/vim/futil/syntax/futil.vim index 4151e03dcc..2a65c1929a 100644 --- a/tools/vim/futil/syntax/futil.vim +++ b/tools/vim/futil/syntax/futil.vim @@ -3,7 +3,7 @@ if exists("b:current_syntax") endif " Numbers -syn match futilConstant "\v<[0-9]+('d[0-9]+)?>" +syn match futilConstant "\v<[0-9]+('(d|b|x|o)[0-9]+)?>" hi link futilConstant Constant " String literals for attributes @@ -44,6 +44,9 @@ hi link futilPortParam Type syn match futilArrow '->' nextgroup=futilPorts skipwhite skipnl hi link futilArrow futilOperator +" Modifiers for components, groups, primitives +syn keyword futilModifier comb +hi link futilModifier Operator " Highlight holes syn keyword futilHole go done From 10512334d54980294f13f11badb03a80324aaf76 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 30 Aug 2021 18:20:51 +0530 Subject: [PATCH 04/50] remove-comb-groups updates control now --- calyx/src/analysis/live_range_analysis.rs | 11 +- calyx/src/analysis/reaching_defns.rs | 18 +- calyx/src/ir/builder.rs | 9 +- calyx/src/ir/component.rs | 20 +- calyx/src/ir/control.rs | 6 +- calyx/src/ir/from_ast.rs | 42 ++-- calyx/src/ir/mod.rs | 4 +- calyx/src/ir/printer.rs | 29 ++- calyx/src/ir/structure.rs | 36 ++- calyx/src/passes/compile_control.rs | 6 +- calyx/src/passes/remove_comb_groups.rs | 217 ++++++++++--------- calyx/src/passes/top_down_compile_control.rs | 1 + calyx/src/passes/well_formed.rs | 18 +- 13 files changed, 244 insertions(+), 173 deletions(-) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 00d57084fe..63dbb6ef4f 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -428,16 +428,7 @@ fn build_live_ranges( let kills = &t_kills | &f_kills; // feed to condition to compute - build_live_ranges( - &cond - .as_ref() - .map(|c| ir::Control::enable(Rc::clone(c))) - .unwrap_or_else(ir::Control::empty), - alive, - gens, - kills, - lr, - ) + build_live_ranges(&ir::Control::empty(), alive, gens, kills, lr) } ir::Control::Par(ir::Par { stmts, .. }) => { let (alive, gens, kills) = stmts diff --git a/calyx/src/analysis/reaching_defns.rs b/calyx/src/analysis/reaching_defns.rs index 15a5b4e2c0..760d3da708 100644 --- a/calyx/src/analysis/reaching_defns.rs +++ b/calyx/src/analysis/reaching_defns.rs @@ -326,17 +326,15 @@ fn build_reaching_def( (par_exit_defs, &global_killed | &killed) } ir::Control::If(ir::If { - tbranch, - fbranch, - cond, - .. + tbranch, fbranch, .. }) => { - let cond = &cond - .as_ref() - .map(|c| ir::Control::enable(Rc::clone(c))) - .unwrap_or_else(ir::Control::empty); - let (post_cond_def, post_cond_killed) = - build_reaching_def(cond, reach, killed, rd, counter); + let (post_cond_def, post_cond_killed) = build_reaching_def( + &ir::Control::empty(), + reach, + killed, + rd, + counter, + ); let (t_case_def, t_case_killed) = build_reaching_def( tbranch, post_cond_def.clone(), diff --git a/calyx/src/ir/builder.rs b/calyx/src/ir/builder.rs index 465d210af7..e8976bd2ba 100644 --- a/calyx/src/ir/builder.rs +++ b/calyx/src/ir/builder.rs @@ -66,7 +66,6 @@ impl<'a> Builder<'a> { attributes: ir::Attributes::default(), holes: smallvec![], assignments: vec![], - is_comb: false, })); // Add default holes to the group. @@ -88,23 +87,21 @@ impl<'a> Builder<'a> { } /// Construct a combinational group - pub fn add_comb_group(&mut self, prefix: S) -> RRC + pub fn add_comb_group(&mut self, prefix: S) -> RRC where S: Into + ToString + Clone, { let name = self.component.generate_name(prefix); // Check if there is a group with the same name. - let group = Rc::new(RefCell::new(ir::Group { + let group = Rc::new(RefCell::new(ir::CombGroup { name, attributes: ir::Attributes::default(), assignments: vec![], - holes: smallvec![], - is_comb: true, })); // Add the group to the component. - self.component.groups.add(Rc::clone(&group)); + self.component.comb_groups.add(Rc::clone(&group)); group } diff --git a/calyx/src/ir/component.rs b/calyx/src/ir/component.rs index f17e2367e7..9e8b75ec1a 100644 --- a/calyx/src/ir/component.rs +++ b/calyx/src/ir/component.rs @@ -1,6 +1,6 @@ use super::{ - Assignment, Attributes, Builder, Cell, CellType, CloneName, Control, - Direction, GetName, Group, Id, RRC, + Assignment, Attributes, Builder, Cell, CellType, CloneName, CombGroup, + Control, Direction, GetName, Group, Id, RRC, }; use crate::utils; use linked_hash_map::LinkedHashMap; @@ -24,6 +24,8 @@ pub struct Component { pub cells: IdList, /// Groups of assignment wires. pub groups: IdList, + /// Groups of assignment wires. + pub comb_groups: IdList, /// The set of "continuous assignments", i.e., assignments that are always /// active. pub continuous_assignments: Vec, @@ -74,6 +76,7 @@ impl Component { signature: this_sig, cells: IdList::default(), groups: IdList::default(), + comb_groups: IdList::default(), continuous_assignments: vec![], control: Rc::new(RefCell::new(Control::empty())), namegen: utils::NameGenerator::with_prev_defined_names(port_names), @@ -89,6 +92,14 @@ impl Component { self.groups.find(name) } + /// Return a refernece to a combination group with `name` if present. + pub fn find_comb_group(&self, name: &S) -> Option> + where + S: Clone + AsRef, + { + self.comb_groups.find(name) + } + /// Return a reference to the cell with `name` if present. pub fn find_cell(&self, name: &S) -> Option> where @@ -132,6 +143,11 @@ impl IdList { self.0.clear(); } + /// Returns true if there are no elements in the list. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + /// Keep only the elements in the collection which satisfy the given /// predicate pub fn retain(&mut self, mut f: F) diff --git a/calyx/src/ir/control.rs b/calyx/src/ir/control.rs index dad1789f22..07bb92be69 100644 --- a/calyx/src/ir/control.rs +++ b/calyx/src/ir/control.rs @@ -1,4 +1,4 @@ -use super::{Attributes, Cell, GetAttributes, Group, Id, Port, RRC}; +use super::{Attributes, Cell, CombGroup, GetAttributes, Group, Id, Port, RRC}; /// Data for the `seq` control statement. #[derive(Debug)] @@ -25,7 +25,7 @@ pub struct If { pub port: RRC, /// Optional combinational group attached using `with`. - pub cond: Option>, + pub cond: Option>, /// Control for the true branch. pub tbranch: Box, @@ -169,7 +169,7 @@ impl Control { /// Convience constructor for if pub fn if_( port: RRC, - cond: Option>, + cond: Option>, tbranch: Box, fbranch: Box, ) -> Self { diff --git a/calyx/src/ir/from_ast.rs b/calyx/src/ir/from_ast.rs index 58178c3dc4..63d27a3416 100644 --- a/calyx/src/ir/from_ast.rs +++ b/calyx/src/ir/from_ast.rs @@ -279,19 +279,27 @@ fn add_cell(cell: ast::Cell, sig_ctx: &SigCtx, builder: &mut Builder) { /// Build an [ir::Group] from an [ast::Group] and attach it to the [ir::Compoennt] /// associated with the [ir::Builder] fn add_group(group: ast::Group, builder: &mut Builder) -> CalyxResult<()> { - let ir_group = if group.is_comb { - builder.add_comb_group(group.name) + if group.is_comb { + let ir_group = builder.add_comb_group(group.name); + let assigns = group + .wires + .into_iter() + .map(|assign| build_assignment(assign, builder)) + .collect::>>()?; + + ir_group.borrow_mut().attributes = group.attributes; + ir_group.borrow_mut().assignments = assigns; } else { - builder.add_group(group.name) - }; - let assigns = group - .wires - .into_iter() - .map(|assign| build_assignment(assign, builder)) - .collect::>>()?; + let ir_group = builder.add_group(group.name); + let assigns = group + .wires + .into_iter() + .map(|assign| build_assignment(assign, builder)) + .collect::>>()?; - ir_group.borrow_mut().attributes = group.attributes; - ir_group.borrow_mut().assignments = assigns; + ir_group.borrow_mut().attributes = group.attributes; + ir_group.borrow_mut().assignments = assigns; + }; Ok(()) } @@ -449,14 +457,12 @@ fn build_control( attributes, } => { let group = - builder.component.find_group(&cond).ok_or_else(|| { - Error::Undefined(cond.clone(), "group".to_string()) + builder.component.find_comb_group(&cond).ok_or_else(|| { + Error::Undefined( + cond.clone(), + "combinational group".to_string(), + ) })?; - /* if !group.borrow().is_comb() { - return Err(Error::MalformedControl( - cond.fmt_err("This should be a combinational group."), - )); - } */ let mut con = Control::if_( get_port_ref(port, builder.component)?, Some(group), diff --git a/calyx/src/ir/mod.rs b/calyx/src/ir/mod.rs index 874267ef83..74f128ba0d 100644 --- a/calyx/src/ir/mod.rs +++ b/calyx/src/ir/mod.rs @@ -31,8 +31,8 @@ pub use id::Id; pub use primitives::{PortDef, Primitive, Width}; pub use printer::IRPrinter; pub use structure::{ - Assignment, Binding, Cell, CellIterator, CellType, CloneName, Direction, - GetName, Group, Port, PortIterator, PortParent, + Assignment, Binding, Cell, CellIterator, CellType, CloneName, CombGroup, + Direction, GetName, Group, Port, PortIterator, PortParent, }; /// Visitor to traverse a control program. diff --git a/calyx/src/ir/printer.rs b/calyx/src/ir/printer.rs index d455e2ec20..4ade5f82dd 100644 --- a/calyx/src/ir/printer.rs +++ b/calyx/src/ir/printer.rs @@ -101,6 +101,10 @@ impl IRPrinter { Self::write_group(&group.borrow(), 4, f)?; writeln!(f)?; } + for comb_group in comp.comb_groups.iter() { + Self::write_comb_group(&comb_group.borrow(), 4, f)?; + writeln!(f)?; + } // Write the continuous assignments for assign in &comp.continuous_assignments { Self::write_assignment(assign, 4, f)?; @@ -182,6 +186,26 @@ impl IRPrinter { write!(f, "{};", Self::get_port_access(&assign.src.borrow())) } + /// Format and write a combinational group. + pub fn write_comb_group( + group: &ir::CombGroup, + indent_level: usize, + f: &mut F, + ) -> io::Result<()> { + write!(f, "{}", " ".repeat(indent_level))?; + write!(f, "comb group {}", group.name().id)?; + if !group.attributes.is_empty() { + write!(f, "{}", Self::format_attributes(&group.attributes))?; + } + writeln!(f, " {{")?; + + for assign in &group.assignments { + Self::write_assignment(assign, indent_level + 2, f)?; + writeln!(f)?; + } + write!(f, "{}}}", " ".repeat(indent_level)) + } + /// Format and write a group. pub fn write_group( group: &ir::Group, @@ -189,9 +213,6 @@ impl IRPrinter { f: &mut F, ) -> io::Result<()> { write!(f, "{}", " ".repeat(indent_level))?; - if group.is_comb() { - write!(f, "comb")?; - } write!(f, "group {}", group.name().id)?; if !group.attributes.is_empty() { write!(f, "{}", Self::format_attributes(&group.attributes))?; @@ -290,7 +311,7 @@ impl IRPrinter { if !attributes.is_empty() { write!(f, "{} ", Self::format_at_attributes(attributes))? } - writeln!(f, "if {} ", Self::get_port_access(&port.borrow()),)?; + write!(f, "if {} ", Self::get_port_access(&port.borrow()),)?; if let Some(c) = cond { write!(f, "with {} ", c.borrow().name.id)?; } diff --git a/calyx/src/ir/structure.rs b/calyx/src/ir/structure.rs index 7e1d98266b..9ffabf741c 100644 --- a/calyx/src/ir/structure.rs +++ b/calyx/src/ir/structure.rs @@ -319,11 +319,6 @@ pub struct Group { /// Attributes for this group. pub attributes: Attributes, - - /// True if this is a combinational group. A combinational group does - /// not have any holes and should only contain assignments that should be - /// combinationally active - pub(super) is_comb: bool, } impl Group { /// Get a reference to the named hole if it exists. @@ -351,14 +346,29 @@ impl Group { }) } - /// Returns true if this group is combinational. + /// The name of this group. #[inline] - pub fn is_comb(&self) -> bool { - debug_assert!(!self.is_comb || self.holes.is_empty()); - self.is_comb + pub fn name(&self) -> &Id { + &self.name } +} - /// The name of this group. +/// A combinational group. +/// A combinational group does not have any holes and should only contain assignments that should +/// will be combinationally active +#[derive(Debug)] +pub struct CombGroup { + /// Name of this group + pub(super) name: Id, + + /// The assignments used in this group + pub assignments: Vec, + + /// Attributes for this group. + pub attributes: Attributes, +} +impl CombGroup { + #[inline] pub fn name(&self) -> &Id { &self.name } @@ -382,6 +392,12 @@ impl GetName for Group { } } +impl GetName for CombGroup { + fn name(&self) -> &Id { + &self.name() + } +} + /// A utility trait representing the ability to clone the name of an object. /// Automatically definied for anything that implements GetName pub trait CloneName { diff --git a/calyx/src/passes/compile_control.rs b/calyx/src/passes/compile_control.rs index 6340fac991..68a371b6ae 100644 --- a/calyx/src/passes/compile_control.rs +++ b/calyx/src/passes/compile_control.rs @@ -74,7 +74,9 @@ impl Visitor for CompileControl { comp: &mut ir::Component, ctx: &LibrarySignatures, ) -> VisResult { - let mut builder = ir::Builder::new(comp, ctx); + todo!("compile-control support for if-with") + + /* let mut builder = ir::Builder::new(comp, ctx); // create a new group for if related structure let if_group = builder.add_group("if"); @@ -170,7 +172,7 @@ impl Visitor for CompileControl { ); comp.continuous_assignments.append(&mut cleanup_assigns); - Ok(Action::Change(ir::Control::enable(if_group))) + Ok(Action::Change(ir::Control::enable(if_group))) */ } /// XXX(rachit): The explanation is not consistent with the code. diff --git a/calyx/src/passes/remove_comb_groups.rs b/calyx/src/passes/remove_comb_groups.rs index f0ef847f4e..3c71a5d6e6 100644 --- a/calyx/src/passes/remove_comb_groups.rs +++ b/calyx/src/passes/remove_comb_groups.rs @@ -1,9 +1,7 @@ use std::collections::HashMap; use std::rc::Rc; -use itertools::Itertools; - -use crate::errors::Error; +use crate::errors::{CalyxResult, Error}; use crate::ir::{ self, traversal::{Action, Named, VisResult, Visitor}, @@ -16,6 +14,9 @@ use crate::{analysis, guard, structure}; /// into proper groups by registering the values read from the ports of cells /// used within the combinational group. /// +/// It also transforms if-with and while-with into simple `if` and `while` operators that first +/// execute the respective cond group and then execute the control operator. +/// /// # Example /// ``` /// group comb_cond<"static"=0> { @@ -48,17 +49,25 @@ use crate::{analysis, guard, structure}; /// comb_cond[done] = lt_reg.done & eq_reg.done ? 1'd1; /// } /// control { -/// if lt_reg.out with comb_cond { -/// ... +/// seq { +/// comb_cond; +/// if lt_reg.out { +/// ... +/// } /// } -/// while eq_reg.out with comb_cond { -/// ... +/// seq { +/// comb_cond; +/// while eq_reg.out { +/// ... +/// comb_cond; +/// } /// } /// } /// ``` pub struct RemoveCombGroups { - // Mapping from (group_name, (cell_name, port_name)) -> port. - port_rewrite: HashMap<(ir::Id, (ir::Id, ir::Id)), RRC>, + // Mapping from (group_name, (cell_name, port_name)) -> (port, group). + port_rewrite: + HashMap<(ir::Id, (ir::Id, ir::Id)), (RRC, RRC)>, // The pass updated combinational groups for this component. updated: bool, } @@ -84,101 +93,99 @@ impl Visitor for RemoveCombGroups { let mut used_ports = analysis::ControlPorts::from(&*comp.control.borrow()); - // Detach groups from the component - let groups = comp.groups.drain().collect_vec(); - let mut builder = ir::Builder::new(comp, sigs); - for group_ref in &groups { - let group = group_ref.borrow(); - - // Is this group combinational - let done_assign = group - .assignments - .iter() - .find(|assign| { - let dst = assign.dst.borrow(); - dst.is_hole() && *group.name() == dst.get_parent_name() - }) - .map(|asgn| { - asgn.guard.is_true() && asgn.src.borrow().is_constant(1, 1) - }); - let is_comb = group - .attributes - .get("static") - .map(|v| *v == 0) - .unwrap_or(false) - || done_assign.unwrap_or(false); - - if !is_comb { - continue; - } - - // If any groups were updated, tell the pass that updates - // were made. + // If any groups were updated, tell the pass that updates + // were made. + if !comp.comb_groups.is_empty() { self.updated = true; + } else { + return Ok(Action::Continue); + } - // Register the ports read by the combinational group's usages. - let used_ports = - used_ports.remove(group.name()).ok_or_else(|| { + let mut builder = ir::Builder::new(comp, sigs); + + // Groups generated by transforming combinational groups + let groups = builder + .component + .comb_groups + .drain() + .map(|cg_ref| { + let name = cg_ref.borrow().name().clone(); + // Register the ports read by the combinational group's usages. + let used_ports = used_ports.remove(&name).ok_or_else(|| { Error::MalformedStructure(format!( "Values from combinational group {} never used", - group.name() + name )) })?; - let mut save_regs = Vec::with_capacity(used_ports.len()); + // Group generated to replace this comb group. + let group_ref = builder.add_group(name.as_ref()); + let mut group = group_ref.borrow_mut(); + // Attach assignmens from comb group + group.assignments = + cg_ref.borrow_mut().assignments.drain(..).collect(); + + // Registers to save value for the group + let mut save_regs = Vec::with_capacity(used_ports.len()); + for port in used_ports { + // Register to save port value + structure!(builder; + let comb_reg = prim std_reg(port.borrow().width); + let signal_on = constant(1, 1); + ); + let write = builder.build_assignment( + comb_reg.borrow().get("in"), + Rc::clone(&port), + ir::Guard::True, + ); + let en = builder.build_assignment( + comb_reg.borrow().get("write_en"), + signal_on.borrow().get("out"), + ir::Guard::True, + ); + group.assignments.push(write); + group.assignments.push(en); + + // Define mapping from this port to the register's output + // value. + self.port_rewrite.insert( + (name.clone(), port.borrow().canonical().clone()), + ( + Rc::clone(&comb_reg.borrow().get("out")), + Rc::clone(&group_ref), + ), + ); - // Explicitly drop group to avoid Borrow Error. - drop(group); - let mut group = group_ref.borrow_mut(); + save_regs.push(comb_reg); + } - for port in used_ports { - // Register to save port value structure!(builder; - let comb_reg = prim std_reg(port.borrow().width); let signal_on = constant(1, 1); ); - let write = builder.build_assignment( - comb_reg.borrow().get("in"), - Rc::clone(&port), - ir::Guard::True, - ); - let en = builder.build_assignment( - comb_reg.borrow().get("write_en"), + + // Create a done condition + let done_guard = save_regs + .drain(..) + .map(|reg| guard!(reg["done"])) + .fold(ir::Guard::True, ir::Guard::and); + let done_assign = builder.build_assignment( + group.get("done"), signal_on.borrow().get("out"), - ir::Guard::True, - ); - group.assignments.push(write); - group.assignments.push(en); - - // Define mapping from this port to the register's output - // value. - self.port_rewrite.insert( - (group.name().clone(), port.borrow().canonical().clone()), - Rc::clone(&comb_reg.borrow().get("out")), + done_guard, ); + group.assignments.push(done_assign); - save_regs.push(comb_reg); - } - - // Update the done condition - for mut assign in group.assignments.iter_mut() { - let dst = assign.dst.borrow(); - if dst.is_hole() && dst.name == "done" { - // The source should be the constant 1 since this is a combinational group. - debug_assert!(assign.src.borrow().is_constant(1, 1)); - assign.guard = Box::new( - save_regs - .drain(..) - .map(|reg| guard!(reg["done"])) - .fold(ir::Guard::True, ir::Guard::and), - ); - } - } + // Add a "static" attribute + group.attributes.insert("static", 1); + drop(group); - // Update the "static" attribute - group.attributes.insert("static", 1); + Ok(group_ref) + }) + .collect::>>()?; + + for group in groups { + comp.groups.add(group) } - comp.groups = groups.into(); Ok(Action::Continue) } @@ -189,27 +196,43 @@ impl Visitor for RemoveCombGroups { _comp: &mut ir::Component, _sigs: &LibrarySignatures, ) -> VisResult { - let key = (s.cond.borrow().name().clone(), s.port.borrow().canonical()); + /* let key = (s.cond.borrow().name().clone(), s.port.borrow().canonical()); if let Some(new_port) = self.port_rewrite.get(&key) { s.port = Rc::clone(new_port); - } + } */ Ok(Action::Continue) } + /// Transforms a `if-with` into a `seq-if` which first runs the cond group + /// and then the branch. fn start_if( &mut self, s: &mut ir::If, - _comp: &mut ir::Component, + comp: &mut ir::Component, _sigs: &LibrarySignatures, ) -> VisResult { - if let Some(cond) = &s.cond { - let key = - (cond.borrow().name().clone(), s.port.borrow().canonical()); - if let Some(new_port) = self.port_rewrite.get(&key) { - s.port = Rc::clone(new_port); - } + if s.cond.is_some() { + // Construct a new `if` statement + let key = ( + s.cond.as_ref().unwrap().borrow().name().clone(), + s.port.borrow().canonical(), + ); + let (port_ref, cond_ref) = self.port_rewrite.get(&key).unwrap(); + let tbranch = + std::mem::replace(s.tbranch.as_mut(), ir::Control::empty()); + let fbranch = + std::mem::replace(s.tbranch.as_mut(), ir::Control::empty()); + let if_ = ir::Control::if_( + Rc::clone(port_ref), + None, + Box::new(tbranch), + Box::new(fbranch), + ); + let cond = ir::Control::enable(Rc::clone(cond_ref)); + Ok(Action::Change(ir::Control::seq(vec![cond, if_]))) + } else { + Ok(Action::Continue) } - Ok(Action::Continue) } fn finish( diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index 572df6abef..ec4658043c 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -504,6 +504,7 @@ impl Visitor for TopDownCompileControl { &mut schedule, &mut builder, )?; + schedule.display(); let comp_group = realize_schedule(schedule, &mut builder); Ok(Action::Change(ir::Control::enable(comp_group))) diff --git a/calyx/src/passes/well_formed.rs b/calyx/src/passes/well_formed.rs index 877e9a62d0..54a10c07ef 100644 --- a/calyx/src/passes/well_formed.rs +++ b/calyx/src/passes/well_formed.rs @@ -57,10 +57,10 @@ impl Visitor for WellFormed { } } - // For each group, check if there is at least one write to the done + // For each non-combinational group, check if there is at least one write to the done // signal of that group. // Names of the groups whose `done` hole has been written to. - for group_ref in comp.groups.iter() { + comp.groups.iter().try_for_each(|group_ref| { let group = group_ref.borrow(); let gname = group.name(); // Find an assignment writing to this group's done condition. @@ -71,14 +71,14 @@ impl Visitor for WellFormed { && dst.get_parent_name() == gname }); if done.is_none() { - return Err(Error::MalformedStructure(gname.fmt_err( - &format!( - "No writes to the `done' hole for group `{}'", - gname.to_string() - ), - ))); + Err(Error::MalformedStructure(gname.fmt_err(&format!( + "No writes to the `done' hole for group `{}'", + gname.to_string() + )))) + } else { + Ok(()) } - } + })?; // Check if any groups refer to another group's done signal. for group_ref in comp.groups.iter() { From 3473eaaad83bd8654f5e3d12297aa6bc54a63b07 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 31 Aug 2021 21:42:56 +0530 Subject: [PATCH 05/50] make `with` option in `if` and `while` --- calyx/src/analysis/control_ports.rs | 17 ++++- calyx/src/analysis/live_range_analysis.rs | 5 +- calyx/src/analysis/reaching_defns.rs | 11 +-- calyx/src/analysis/schedule_conflicts.rs | 10 ++- calyx/src/default_passes.rs | 9 ++- calyx/src/frontend/ast.rs | 4 +- calyx/src/frontend/parser.rs | 16 +++- calyx/src/frontend/syntax.pest | 7 +- calyx/src/ir/control.rs | 4 +- calyx/src/ir/from_ast.rs | 42 +++++----- calyx/src/ir/printer.rs | 9 ++- calyx/src/ir/structure.rs | 2 +- calyx/src/passes/compile_control.rs | 5 +- calyx/src/passes/infer_static_timing.rs | 5 +- calyx/src/passes/remove_comb_groups.rs | 44 ++++++++--- calyx/src/passes/static_timing.rs | 6 +- calyx/src/passes/top_down_compile_control.rs | 76 ++++--------------- calyx/src/passes/well_formed.rs | 20 +---- primitives/math.futil | 3 +- .../if-static-different-latencies.futil | 3 +- tests/correctness/if.futil | 3 +- tests/correctness/invoke-memory.futil | 3 +- tests/correctness/invoke.futil | 6 +- tests/correctness/pipelined-mac.futil | 15 ++-- tests/correctness/unsigned-dot-product.futil | 3 +- tests/correctness/while.futil | 16 ++-- tests/passes/compile-control/compile-if.futil | 3 +- .../compile-control/compile-while.futil | 8 +- 28 files changed, 172 insertions(+), 183 deletions(-) diff --git a/calyx/src/analysis/control_ports.rs b/calyx/src/analysis/control_ports.rs index 06b1e48443..719c8fd29f 100644 --- a/calyx/src/analysis/control_ports.rs +++ b/calyx/src/analysis/control_ports.rs @@ -1,9 +1,12 @@ use std::{collections::HashMap, rc::Rc}; +use itertools::Itertools; + use crate::ir::{self, RRC}; /// Contains a mapping from name of groups to the ports read by the control /// program. +/// The vector of ports is guaranteed to only contain unique ports. pub struct ControlPorts { used_ports: HashMap>>, } @@ -49,10 +52,12 @@ fn construct( ir::Control::While(ir::While { cond, port, body, .. }) => { - used_ports - .entry(cond.borrow().name().clone()) - .or_default() - .push(Rc::clone(port)); + if let Some(c) = cond { + used_ports + .entry(c.borrow().name().clone()) + .or_default() + .push(Rc::clone(port)); + } construct(body, used_ports); } ir::Control::Seq(ir::Seq { stmts, .. }) @@ -66,6 +71,10 @@ impl From<&ir::Control> for ControlPorts { fn from(con: &ir::Control) -> Self { let mut used_ports = HashMap::default(); construct(con, &mut used_ports); + // Deduplicate all vectors + used_ports.values_mut().for_each(|v| { + *v = v.drain(..).unique_by(|p| p.borrow().name.clone()).collect() + }); ControlPorts { used_ports } } } diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 63dbb6ef4f..898b8ec0ea 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -406,7 +406,6 @@ fn build_live_ranges( }, ), ir::Control::If(ir::If { - cond, tbranch, fbranch, .. @@ -457,11 +456,11 @@ fn build_live_ranges( let alive = alive.transfer(&gens, &kills); (alive, gens, kills) } - ir::Control::While(ir::While { body, cond, .. }) => { + ir::Control::While(ir::While { body, .. }) => { let (alive, gens, kills) = build_live_ranges(body, alive, gens, kills, lr); let (alive, gens, kills) = build_live_ranges( - &ir::Control::enable(cond.clone()), + &ir::Control::empty(), alive, gens, kills, diff --git a/calyx/src/analysis/reaching_defns.rs b/calyx/src/analysis/reaching_defns.rs index 760d3da708..01464a798e 100644 --- a/calyx/src/analysis/reaching_defns.rs +++ b/calyx/src/analysis/reaching_defns.rs @@ -6,7 +6,6 @@ use std::cmp::{Ord, PartialOrd}; use std::{ collections::{BTreeMap, BTreeSet, HashMap}, ops::BitOr, - rc::Rc, }; const INVOKE_PREFIX: &str = "__invoke_"; @@ -351,13 +350,9 @@ fn build_reaching_def( ); (&t_case_def | &f_case_def, &t_case_killed | &f_case_killed) } - ir::Control::While(ir::While { cond, body, .. }) => { - let fake_enable = ir::Control::Enable(ir::Enable { - attributes: ir::Attributes::default(), - group: Rc::clone(cond), - }); + ir::Control::While(ir::While { body, .. }) => { let (post_cond_def, post_cond_killed) = build_reaching_def( - &fake_enable, + &ir::Control::empty(), reach.clone(), killed, rd, @@ -375,7 +370,7 @@ fn build_reaching_def( remove_entries_defined_by(&mut round_1_killed, &reach); let (post_cond2_def, post_cond2_killed) = build_reaching_def( - &fake_enable, + &ir::Control::empty(), &round_1_def | &reach, round_1_killed, rd, diff --git a/calyx/src/analysis/schedule_conflicts.rs b/calyx/src/analysis/schedule_conflicts.rs index 70ebf73ce8..d0b8da7220 100644 --- a/calyx/src/analysis/schedule_conflicts.rs +++ b/calyx/src/analysis/schedule_conflicts.rs @@ -121,6 +121,8 @@ fn build_conflict_graph( fbranch, .. }) => { + // XXX (rachit): This might be incorrect since cond is a combinational + // group if let Some(c) = cond { all_enables.push(c.clone_name()); confs.add_node(c.borrow().name()); @@ -129,8 +131,12 @@ fn build_conflict_graph( build_conflict_graph(fbranch, confs, all_enables); } ir::Control::While(ir::While { cond, body, .. }) => { - all_enables.push(cond.clone_name()); - confs.add_node(cond.borrow().name()); + // XXX (rachit): This might be incorrect since cond is a combinational + // group + if let Some(c) = cond { + all_enables.push(c.clone_name()); + confs.add_node(c.borrow().name()); + } build_conflict_graph(body, confs, all_enables); } ir::Control::Par(ir::Par { stmts, .. }) => { diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index 7c8ca8bb5f..cffbd48667 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -54,13 +54,17 @@ impl PassManager { CollapseControl, ResourceSharing, MinimizeRegs, - CompileInvoke, ] ); register_alias!( pm, "compile", - [CompileEmpty, StaticTiming, TopDownCompileControl] + [ + CompileInvoke, + CompileEmpty, + StaticTiming, + TopDownCompileControl + ] ); register_alias!(pm, "post-opt", [DeadCellRemoval]); register_alias!( @@ -88,6 +92,7 @@ impl PassManager { "external", [ "validate", + SynthesisPapercut, "pre-opt", "compile", "post-opt", diff --git a/calyx/src/frontend/ast.rs b/calyx/src/frontend/ast.rs index 407f857491..eb7f79d8a2 100644 --- a/calyx/src/frontend/ast.rs +++ b/calyx/src/frontend/ast.rs @@ -287,7 +287,7 @@ pub enum Control { port: Port, /// Modules that need to be enabled to send signal on `port`. - cond: ir::Id, + cond: Option, /// Control for the true branch. tbranch: Box, @@ -304,7 +304,7 @@ pub enum Control { port: Port, /// Modules that need to be enabled to send signal on `port`. - cond: ir::Id, + cond: Option, /// Control for the loop body. body: Box, diff --git a/calyx/src/frontend/parser.rs b/calyx/src/frontend/parser.rs index 5533c9a43d..3354e2007e 100644 --- a/calyx/src/frontend/parser.rs +++ b/calyx/src/frontend/parser.rs @@ -578,17 +578,25 @@ impl CalyxParser { )) } + fn port_with(input: Node) -> ParseResult<(ast::Port, Option)> { + Ok(match_nodes!( + input.into_children(); + [port(port), identifier(cond)] => (port, Some(cond)), + [port(port)] => (port, None), + )) + } + fn if_stmt(input: Node) -> ParseResult { Ok(match_nodes!( input.into_children(); - [at_attributes(attrs), port(port), identifier(cond), block(stmt)] => ast::Control::If { + [at_attributes(attrs), port_with((port, cond)), block(stmt)] => ast::Control::If { port, cond, tbranch: Box::new(stmt), fbranch: Box::new(ast::Control::Empty{}), attributes: attrs, }, - [at_attributes(attrs), port(port), identifier(cond), block(tbranch), block(fbranch)] => + [at_attributes(attrs), port_with((port, cond)), block(tbranch), block(fbranch)] => ast::Control::If { port, cond, @@ -596,7 +604,7 @@ impl CalyxParser { fbranch: Box::new(fbranch), attributes: attrs, }, - [at_attributes(attrs), port(port), identifier(cond), block(tbranch), if_stmt(fbranch)] => + [at_attributes(attrs), port_with((port, cond)), block(tbranch), if_stmt(fbranch)] => ast::Control::If { port, cond, @@ -611,7 +619,7 @@ impl CalyxParser { fn while_stmt(input: Node) -> ParseResult { Ok(match_nodes!( input.into_children(); - [at_attributes(attrs), port(port), identifier(cond), block(stmt)] => ast::Control::While { + [at_attributes(attrs), port_with((port, cond)), block(stmt)] => ast::Control::While { port, cond, body: Box::new(stmt), diff --git a/calyx/src/frontend/syntax.pest b/calyx/src/frontend/syntax.pest index b5aed8893d..1b60daff0f 100644 --- a/calyx/src/frontend/syntax.pest +++ b/calyx/src/frontend/syntax.pest @@ -247,12 +247,15 @@ block = { | stmts_without_block } +port_with = { + port ~ ("with" ~ identifier)? +} if_stmt = { - at_attributes ~ "if" ~ port ~ "with" ~ identifier ~ block ~ ("else" ~ (if_stmt | block))? + at_attributes ~ "if" ~ port_with ~ block ~ ("else" ~ (if_stmt | block))? } while_stmt = { - at_attributes ~ "while" ~ port ~ "with" ~ identifier ~ block + at_attributes ~ "while" ~ port_with ~ block } stmt = { diff --git a/calyx/src/ir/control.rs b/calyx/src/ir/control.rs index 07bb92be69..bb11756704 100644 --- a/calyx/src/ir/control.rs +++ b/calyx/src/ir/control.rs @@ -44,7 +44,7 @@ pub struct While { pub port: RRC, /// Group that makes the signal on the conditional port valid. - pub cond: RRC, + pub cond: Option>, /// Control for the loop body. pub body: Box, @@ -185,7 +185,7 @@ impl Control { /// Convience constructor for while pub fn while_( port: RRC, - cond: RRC, + cond: Option>, body: Box, ) -> Self { Control::While(While { diff --git a/calyx/src/ir/from_ast.rs b/calyx/src/ir/from_ast.rs index 63d27a3416..6d54bb1f0f 100644 --- a/calyx/src/ir/from_ast.rs +++ b/calyx/src/ir/from_ast.rs @@ -451,21 +451,24 @@ fn build_control( } ast::Control::If { port, - cond, + cond: maybe_cond, tbranch, fbranch, attributes, } => { - let group = - builder.component.find_comb_group(&cond).ok_or_else(|| { - Error::Undefined( - cond.clone(), - "combinational group".to_string(), - ) - })?; + let group = maybe_cond + .map(|cond| { + builder.component.find_comb_group(&cond).ok_or_else(|| { + Error::Undefined( + cond.clone(), + "combinational group".to_string(), + ) + }) + }) + .transpose()?; let mut con = Control::if_( get_port_ref(port, builder.component)?, - Some(group), + group, Box::new(build_control(*tbranch, builder)?), Box::new(build_control(*fbranch, builder)?), ); @@ -474,19 +477,20 @@ fn build_control( } ast::Control::While { port, - cond, + cond: maybe_cond, body, attributes, } => { - let group = - builder.component.find_group(&cond).ok_or_else(|| { - Error::Undefined(cond.clone(), "group".to_string()) - })?; - /* if !group.borrow().is_comb() { - return Err(Error::MalformedControl( - cond.fmt_err("This should be a combinational group."), - )); - } */ + let group = maybe_cond + .map(|cond| { + builder.component.find_comb_group(&cond).ok_or_else(|| { + Error::Undefined( + cond.clone(), + "combinational group".to_string(), + ) + }) + }) + .transpose()?; let mut con = Control::while_( get_port_ref(port, builder.component)?, group, diff --git a/calyx/src/ir/printer.rs b/calyx/src/ir/printer.rs index 4ade5f82dd..402fd788d6 100644 --- a/calyx/src/ir/printer.rs +++ b/calyx/src/ir/printer.rs @@ -335,12 +335,15 @@ impl IRPrinter { if !attributes.is_empty() { write!(f, "{} ", Self::format_at_attributes(attributes))? } - writeln!( + write!( f, - "while {} with {} {{", + "while {} ", Self::get_port_access(&port.borrow()), - cond.borrow().name().id )?; + if let Some(c) = cond { + write!(f, "with {} ", c.borrow().name.id)?; + } + writeln!(f, "{{")?; Self::write_control(body, indent_level + 2, f)?; writeln!(f, "{}}}", " ".repeat(indent_level)) } diff --git a/calyx/src/ir/structure.rs b/calyx/src/ir/structure.rs index 9ffabf741c..dc29d1fa2b 100644 --- a/calyx/src/ir/structure.rs +++ b/calyx/src/ir/structure.rs @@ -394,7 +394,7 @@ impl GetName for Group { impl GetName for CombGroup { fn name(&self) -> &Id { - &self.name() + self.name() } } diff --git a/calyx/src/passes/compile_control.rs b/calyx/src/passes/compile_control.rs index 68a371b6ae..049219aad7 100644 --- a/calyx/src/passes/compile_control.rs +++ b/calyx/src/passes/compile_control.rs @@ -184,7 +184,8 @@ impl Visitor for CompileControl { comp: &mut ir::Component, ctx: &LibrarySignatures, ) -> VisResult { - let mut builder = ir::Builder::new(comp, ctx); + todo!() + /* let mut builder = ir::Builder::new(comp, ctx); // create group let while_group = builder.add_group("while"); @@ -264,7 +265,7 @@ impl Visitor for CompileControl { ); comp.continuous_assignments.append(&mut clean_assigns); - Ok(Action::Change(ir::Control::enable(while_group))) + Ok(Action::Change(ir::Control::enable(while_group))) */ } fn finish_seq( diff --git a/calyx/src/passes/infer_static_timing.rs b/calyx/src/passes/infer_static_timing.rs index f80544c80d..3485228e1f 100644 --- a/calyx/src/passes/infer_static_timing.rs +++ b/calyx/src/passes/infer_static_timing.rs @@ -407,13 +407,12 @@ impl Visitor for InferStaticTiming { _comp: &mut ir::Component, _sigs: &LibrarySignatures, ) -> VisResult { - if let (Some(bound), Some(cond_time), Some(body_time)) = ( + if let (Some(bound), Some(body_time)) = ( s.attributes.get("bound").cloned(), - s.cond.borrow().attributes.get("static"), s.body.get_attributes().and_then(|attr| attr.get("static")), ) { s.attributes - .insert("static", bound * body_time + (bound + 1) * cond_time); + .insert("static", bound * body_time); } Ok(Action::Continue) } diff --git a/calyx/src/passes/remove_comb_groups.rs b/calyx/src/passes/remove_comb_groups.rs index 3c71a5d6e6..dd73cdb729 100644 --- a/calyx/src/passes/remove_comb_groups.rs +++ b/calyx/src/passes/remove_comb_groups.rs @@ -66,12 +66,14 @@ use crate::{analysis, guard, structure}; /// ``` pub struct RemoveCombGroups { // Mapping from (group_name, (cell_name, port_name)) -> (port, group). - port_rewrite: - HashMap<(ir::Id, (ir::Id, ir::Id)), (RRC, RRC)>, + port_rewrite: HashMap, RRC)>, // The pass updated combinational groups for this component. updated: bool, } +/// Represents (group_name, (cell_name, port_name)) +type PortInGroup = (ir::Id, (ir::Id, ir::Id)); + impl Named for RemoveCombGroups { fn name() -> &'static str { "remove-comb-groups" @@ -196,11 +198,32 @@ impl Visitor for RemoveCombGroups { _comp: &mut ir::Component, _sigs: &LibrarySignatures, ) -> VisResult { - /* let key = (s.cond.borrow().name().clone(), s.port.borrow().canonical()); - if let Some(new_port) = self.port_rewrite.get(&key) { - s.port = Rc::clone(new_port); - } */ - Ok(Action::Continue) + if s.cond.is_some() { + // Construct a new `while` statement + let key = ( + s.cond.as_ref().unwrap().borrow().name().clone(), + s.port.borrow().canonical(), + ); + let (port_ref, cond_ref) = self.port_rewrite.get(&key).unwrap(); + let port = Rc::clone(port_ref); + // Add @stable annotation to port + port.borrow_mut().attributes.insert("stable", 1); + let cond_in_body = ir::Control::enable(Rc::clone(cond_ref)); + let body = std::mem::replace(s.body.as_mut(), ir::Control::empty()); + let new_body = ir::Control::seq(vec![body, cond_in_body]); + let while_ = ir::Control::while_( + Rc::clone(port_ref), + None, + Box::new(new_body), + ); + let cond_before_body = ir::Control::enable(Rc::clone(cond_ref)); + Ok(Action::Change(ir::Control::seq(vec![ + cond_before_body, + while_, + ]))) + } else { + Ok(Action::Continue) + } } /// Transforms a `if-with` into a `seq-if` which first runs the cond group @@ -208,7 +231,7 @@ impl Visitor for RemoveCombGroups { fn start_if( &mut self, s: &mut ir::If, - comp: &mut ir::Component, + _comp: &mut ir::Component, _sigs: &LibrarySignatures, ) -> VisResult { if s.cond.is_some() { @@ -218,10 +241,13 @@ impl Visitor for RemoveCombGroups { s.port.borrow().canonical(), ); let (port_ref, cond_ref) = self.port_rewrite.get(&key).unwrap(); + let port = Rc::clone(port_ref); + // Add @stable annotation to port + port.borrow_mut().attributes.insert("stable", 1); let tbranch = std::mem::replace(s.tbranch.as_mut(), ir::Control::empty()); let fbranch = - std::mem::replace(s.tbranch.as_mut(), ir::Control::empty()); + std::mem::replace(s.fbranch.as_mut(), ir::Control::empty()); let if_ = ir::Control::if_( Rc::clone(port_ref), None, diff --git a/calyx/src/passes/static_timing.rs b/calyx/src/passes/static_timing.rs index 9df8c6e845..cf96869f4d 100644 --- a/calyx/src/passes/static_timing.rs +++ b/calyx/src/passes/static_timing.rs @@ -65,9 +65,8 @@ impl Visitor for StaticTiming { comp: &mut ir::Component, ctx: &LibrarySignatures, ) -> VisResult { - // let st = &mut comp.structure; - - if let ir::Control::Enable(data) = &*wh.body { + todo!() + /* if let ir::Control::Enable(data) = &*wh.body { let cond = &wh.cond; let port = &wh.port; let body = &data.group; @@ -183,6 +182,7 @@ impl Visitor for StaticTiming { } Ok(Action::Continue) + */ } fn finish_if( diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index ec4658043c..d9b45267eb 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -102,6 +102,7 @@ fn calculate_states( let mut en_go = build_assignments!(builder; group["go"] = not_done ? signal_on["out"]; ); + // Transition to the next state. let nxt_state = cur_state + 1; schedule .enables @@ -122,7 +123,7 @@ fn calculate_states( Ok(cur) } // Generate the following transitions: - // 1. (cur -> cur + t): Compute the true branch when stored condition + // 1. (cur -> cur + t): Run the true branch // is true. // 2. (cur -> cur + f): Compute the true branch when stored condition // is false. @@ -136,11 +137,6 @@ fn calculate_states( fbranch, .. }) => { - // The port must be marked as stable before compilation can proceed - if !matches!(port.borrow().attributes.get("stable"), Some(1)) { - let (cell, port) = port.borrow().canonical(); - return Err(Error::MalformedStructure(format!("{}: `{}.{}` is not marked with @stable. It cannot be used for computing `if` condition.", TopDownCompileControl::name(), cell, port))); - } // There shouldn't be a group in `with` position. if cond.is_some() { return Err(Error::MalformedStructure(format!("{}: Found group `{}` in with position of if. This should have compiled away.", TopDownCompileControl::name(), cond.as_ref().unwrap().borrow().name()))); @@ -150,7 +146,7 @@ fn calculate_states( // Computation for true branch let true_go = port_guard.clone() & pre_guard.clone(); let after_true = calculate_states( - tbranch, cur_state, &true_go, schedule, builder, + tbranch, dbg!(cur_state), &true_go, schedule, builder, )?; // Computation for false branch let false_go = !port_guard & pre_guard.clone(); @@ -166,57 +162,24 @@ fn calculate_states( Ok(next) } // Compile in three stage: - // 1. cur -> cur + 1: Compute the condition and store the generated value. - // 2. cur + 1 -> cur + b: Compute the body when the stored condition + // 2. cur -> cur + b: Compute the body when the stored condition // is true. // 3. cur + b -> cur: Jump to the start state when stored condition was true. - // 4. cur + 1 -> cur + b + 1: Exit stage + // 4. cur -> cur + b + 1: Exit stage ir::Control::While(ir::While { cond, port, body, .. }) => { - structure!(builder; - let signal_on = constant(1, 1); - let signal_off = constant(0, 1); - let cs_wh = prim std_reg(1); - ); - - // Compute the condition first and save its value. - let mut cond_save_assigns = vec![ - builder.build_assignment( - cs_wh.borrow().get("in"), - Rc::clone(port), - pre_guard.clone(), - ), - builder.build_assignment( - cs_wh.borrow().get("write_en"), - signal_on.borrow().get("out"), - pre_guard.clone(), - ), - builder.build_assignment( - cond.borrow().get("go"), - signal_on.borrow().get("out"), - pre_guard.clone(), - ), - ]; - - // Compute the condition first - let after_cond_compute = cur_state + 1; - schedule - .enables - .entry(cur_state) - .or_default() - .append(&mut cond_save_assigns); - schedule.transitions.push(( - cur_state, - after_cond_compute, - guard!(cond["done"]), - )); + // There shouldn't be a group in `with` position. + if cond.is_some() { + return Err(Error::MalformedStructure(format!("{}: Found group `{}` in with position of if. This should have compiled away.", TopDownCompileControl::name(), cond.as_ref().unwrap().borrow().name()))); + } // Build the FSM for the body - let body_go = guard!(cs_wh["out"]) & pre_guard.clone(); + let port_guard = ir::Guard::port(Rc::clone(port)); + let body_go = pre_guard.clone(); let nxt = calculate_states( body, - after_cond_compute, + cur_state, &body_go, schedule, builder, @@ -226,22 +189,11 @@ fn calculate_states( schedule.transitions.push((nxt, cur_state, body_go)); // Exit state: Jump to this when the condition is false. - let wh_done = !guard!(cs_wh["out"]) & pre_guard.clone(); + let wh_done = !port_guard & pre_guard.clone(); let exit = nxt + 1; schedule .transitions - .push((after_cond_compute, exit, wh_done)); - - // Cleanup state registers in exit stage - let mut cleanup = build_assignments!(builder; - cs_wh["in"] = pre_guard ? signal_off["out"]; - cs_wh["write_en"] = pre_guard ? signal_on["out"]; - ); - schedule - .enables - .entry(exit) - .or_default() - .append(&mut cleanup); + .push((cur_state, exit, wh_done)); Ok(exit) } diff --git a/calyx/src/passes/well_formed.rs b/calyx/src/passes/well_formed.rs index 54a10c07ef..67cda20805 100644 --- a/calyx/src/passes/well_formed.rs +++ b/calyx/src/passes/well_formed.rs @@ -130,7 +130,7 @@ impl Visitor for WellFormed { .unwrap_or(false) || done_assign.unwrap_or(false) { - return Err(Error::MalformedStructure(group.name().fmt_err("Group with constant done condition not allowed inside normal control operators"))); + return Err(Error::MalformedStructure(group.name().fmt_err("Group with constant done condition are invalid. Use `comb group` instead to define a combinational group."))); } Ok(Action::Continue) @@ -169,13 +169,6 @@ impl Visitor for WellFormed { _comp: &mut Component, _ctx: &LibrarySignatures, ) -> VisResult { - /* let cond = s.cond.borrow(); - if !cond.is_comb() { - return Err(Error::MalformedControl( - cond.name() - .fmt_err(&format!("Group `{}` was used with `with` syntax. It should be a combinational group.", cond.name())), - )); - } */ // Add cond group as a used port. if let Some(cond) = &s.cond { self.used_groups.insert(cond.clone_name()); @@ -189,15 +182,10 @@ impl Visitor for WellFormed { _comp: &mut Component, _ctx: &LibrarySignatures, ) -> VisResult { - /* let cond = s.cond.borrow(); - if !cond.is_comb() { - return Err(Error::MalformedControl( - cond.name() - .fmt_err(&format!("Group `{}` was used with `with` syntax. It should be a combinational group.", cond.name())), - )); - } */ // Add cond group as a used port. - self.used_groups.insert(s.cond.clone_name()); + if let Some(cond) = &s.cond { + self.used_groups.insert(cond.clone_name()); + } Ok(Action::Continue) } diff --git a/primitives/math.futil b/primitives/math.futil index 2cb46210c8..915d524788 100644 --- a/primitives/math.futil +++ b/primitives/math.futil @@ -57,10 +57,9 @@ component pow(base: 32, exp: 32) -> (out: 32) { count.write_en = 1'd1; incr_count[done] = count.done; } - group cond<"static"=0> { + comb group cond { lt.right = exp; lt.left = count.out; - cond[done] = 1'd1; } out = t.out; } diff --git a/tests/correctness/if-static-different-latencies.futil b/tests/correctness/if-static-different-latencies.futil index 67ca831e0b..a47141b3fe 100644 --- a/tests/correctness/if-static-different-latencies.futil +++ b/tests/correctness/if-static-different-latencies.futil @@ -16,10 +16,9 @@ component main() -> () { add = std_add(32); } wires { - group cond { + comb group cond { eq.left = 1'd0; eq.right = 1'd1; - cond[done] = 1'd1; } group true { diff --git a/tests/correctness/if.futil b/tests/correctness/if.futil index 6b73ebade6..7bf5565bf1 100644 --- a/tests/correctness/if.futil +++ b/tests/correctness/if.futil @@ -7,10 +7,9 @@ component main() -> () { } wires { - group cond<"static"=0> { + comb group cond { lt.left = 32'd5; lt.right = 32'd9; - cond[done] = 1'd1; } group true<"static"=1> { diff --git a/tests/correctness/invoke-memory.futil b/tests/correctness/invoke-memory.futil index 7cf380735d..23ce8666f9 100644 --- a/tests/correctness/invoke-memory.futil +++ b/tests/correctness/invoke-memory.futil @@ -7,10 +7,9 @@ component copy(dest_done: 1, src_read_data: 32, length: 3) -> add = std_add(3); } wires { - group cond<"static"=0> { + comb group cond { lt.left = N.out; lt.right = length; - cond[done] = 1'd1; } group upd_index<"static"=1> { add.left = N.out; diff --git a/tests/correctness/invoke.futil b/tests/correctness/invoke.futil index b3bbe90133..01022bae01 100644 --- a/tests/correctness/invoke.futil +++ b/tests/correctness/invoke.futil @@ -33,10 +33,9 @@ component exponent(base: 32, exp: 4) -> (out: 32) { count.write_en = 1'd1; incr_count[done] = count.done; } - group cond<"static"=0> { + comb group cond { lt.right = exp; lt.left = count.out; - cond[done] = 1'd1; } out = pow.out; @@ -66,8 +65,7 @@ component main() -> () { tmp_0 = std_reg(32); } wires { - group cond0 { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const1.out; } diff --git a/tests/correctness/pipelined-mac.futil b/tests/correctness/pipelined-mac.futil index 1dadb7915b..d18cdb6ce3 100644 --- a/tests/correctness/pipelined-mac.futil +++ b/tests/correctness/pipelined-mac.futil @@ -60,10 +60,6 @@ component pipelined_mac( unset_out_valid[done] = out_valid.done; } - group no_op { - no_op[done] = 1'd1; - } - output_valid = out_valid.out; out = pipe2.out; } @@ -71,17 +67,17 @@ component pipelined_mac( seq { // Execute all stages in parallel par { - if data_valid with no_op { stage1; } - if stage2_valid.out with no_op { stage2; } + if data_valid { stage1; } + if stage2_valid.out { stage2; } } // Configure valid signals for next invoke par { - if data_valid with no_op { + if data_valid { set_stage2_valid; } else { unset_stage2_valid; } - if stage2_valid.out with no_op { + if stage2_valid.out { set_out_valid; } else { unset_out_valid; @@ -143,10 +139,9 @@ component main() -> () { out.write_data = mac.out; save_out[done] = out.done; } - group in_range { + comb group in_range { lt0.left = idx0.out; lt0.right = 4'd10; - in_range[done] = 1'd1; } } control { diff --git a/tests/correctness/unsigned-dot-product.futil b/tests/correctness/unsigned-dot-product.futil index c26272319b..a16ca5b293 100644 --- a/tests/correctness/unsigned-dot-product.futil +++ b/tests/correctness/unsigned-dot-product.futil @@ -17,8 +17,7 @@ component main() -> () { mult = std_mult_pipe(32); } wires { - group is_less_than<"static"=0> { - is_less_than[done] = 1'd1; + comb group is_less_than<"static"=0> { lt0.left = counter.out; lt0.right = const1.out; } // Control segment for `counter` < `4`. diff --git a/tests/correctness/while.futil b/tests/correctness/while.futil index d496c73d6f..392c217a5d 100644 --- a/tests/correctness/while.futil +++ b/tests/correctness/while.futil @@ -8,28 +8,30 @@ component main() -> () { } wires { - group cond<"static"=0> { + comb group cond<"static"=0> { i.addr0 = 1'd0; lt.left = i.read_data; lt.right = 32'd8; - cond[done] = 1'b1; } group incr<"static"=1> { + add.right = i.read_data; + add.left = 32'd1; + i.write_data = add.out; i.addr0 = 1'd0; i.write_en = 1'b1; - add.right = i.read_data; - add.left = 32'd1; - incr[done] = i.done; } } control { while lt.out with cond { - incr; + seq { + incr; + incr; + } } -} + } } diff --git a/tests/passes/compile-control/compile-if.futil b/tests/passes/compile-control/compile-if.futil index 400976b400..450fe032ba 100644 --- a/tests/passes/compile-control/compile-if.futil +++ b/tests/passes/compile-control/compile-if.futil @@ -22,10 +22,9 @@ component main() -> () { false[done] = f.done; } - group cond { + comb group cond { lt.left = 1'b1; lt.right = 1'b0; - cond[done] = 1'b1; } } diff --git a/tests/passes/compile-control/compile-while.futil b/tests/passes/compile-control/compile-while.futil index 9513ef905c..544eeeae48 100644 --- a/tests/passes/compile-control/compile-while.futil +++ b/tests/passes/compile-control/compile-while.futil @@ -6,19 +6,21 @@ component main() -> () { cells { add = std_add(32); lt = std_lt(32); + r = std_reg(32); } wires { group do_add { add.right = 32'd4; add.left = 32'd4; - do_add[done] = 1'b1; + r.in = add.out; + r.write_en = 1'd1; + do_add[done] = r.done; } - group cond { + comb group cond { lt.right = 32'd5; lt.left = 32'd1; - cond[done] = 1'b1; } } From 15c58b32ba9d9802bfc78cece8e7cc599589f730 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 1 Sep 2021 22:58:50 +0530 Subject: [PATCH 06/50] fix top down compilation and disable static-timing pass --- calyx/src/analysis/live_range_analysis.rs | 4 +- calyx/src/default_passes.rs | 12 +- calyx/src/ir/printer.rs | 6 +- calyx/src/passes/infer_static_timing.rs | 3 +- calyx/src/passes/mod.rs | 8 +- calyx/src/passes/remove_comb_groups.rs | 13 +- calyx/src/passes/top_down_compile_control.rs | 299 +++++++++++++------ src/backend/circt.rs | 12 +- 8 files changed, 230 insertions(+), 127 deletions(-) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 898b8ec0ea..9fee8eb601 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -406,9 +406,7 @@ fn build_live_ranges( }, ), ir::Control::If(ir::If { - tbranch, - fbranch, - .. + tbranch, fbranch, .. }) => { // compute each branch let (t_alive, t_gens, t_kills) = build_live_ranges( diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index cffbd48667..9761baa598 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -1,11 +1,11 @@ //! Defines the default passes available to [PassManager]. use crate::passes::{ - ClkInsertion, CollapseControl, CompileControl, CompileEmpty, CompileInvoke, + ClkInsertion, CollapseControl, CompileEmpty, CompileInvoke, ComponentInterface, DeadCellRemoval, Externalize, GoInsertion, GuardCanonical, InferStaticTiming, Inliner, MergeAssign, MinimizeRegs, Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, ResetInsertion, - ResourceSharing, SimplifyGuards, StaticTiming, SynthesisPapercut, - TopDownCompileControl, WellFormed, + ResourceSharing, SimplifyGuards, SynthesisPapercut, TopDownCompileControl, + WellFormed, }; use crate::{ errors::CalyxResult, ir::traversal::Named, pass_manager::PassManager, @@ -19,8 +19,8 @@ impl PassManager { // Register passes. pm.register_pass::()?; - pm.register_pass::()?; - pm.register_pass::()?; + // pm.register_pass::()?; + // pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -62,7 +62,7 @@ impl PassManager { [ CompileInvoke, CompileEmpty, - StaticTiming, + // StaticTiming, TopDownCompileControl ] ); diff --git a/calyx/src/ir/printer.rs b/calyx/src/ir/printer.rs index 402fd788d6..0e8f99505e 100644 --- a/calyx/src/ir/printer.rs +++ b/calyx/src/ir/printer.rs @@ -335,11 +335,7 @@ impl IRPrinter { if !attributes.is_empty() { write!(f, "{} ", Self::format_at_attributes(attributes))? } - write!( - f, - "while {} ", - Self::get_port_access(&port.borrow()), - )?; + write!(f, "while {} ", Self::get_port_access(&port.borrow()),)?; if let Some(c) = cond { write!(f, "with {} ", c.borrow().name.id)?; } diff --git a/calyx/src/passes/infer_static_timing.rs b/calyx/src/passes/infer_static_timing.rs index 3485228e1f..458c9cdc35 100644 --- a/calyx/src/passes/infer_static_timing.rs +++ b/calyx/src/passes/infer_static_timing.rs @@ -411,8 +411,7 @@ impl Visitor for InferStaticTiming { s.attributes.get("bound").cloned(), s.body.get_attributes().and_then(|attr| attr.get("static")), ) { - s.attributes - .insert("static", bound * body_time); + s.attributes.insert("static", bound * body_time); } Ok(Action::Continue) } diff --git a/calyx/src/passes/mod.rs b/calyx/src/passes/mod.rs index 26e18101d4..3e3f0a37c6 100644 --- a/calyx/src/passes/mod.rs +++ b/calyx/src/passes/mod.rs @@ -1,7 +1,7 @@ //! Passes for the Calyx compiler. mod clk_insertion; mod collapse_control; -mod compile_control; +// mod compile_control; mod compile_empty; mod compile_invoke; mod component_interface; @@ -22,14 +22,14 @@ mod reset_insertion; mod resource_sharing; mod sharing_components; mod simplify_guards; -mod static_timing; +// mod static_timing; mod synthesis_papercut; mod top_down_compile_control; mod well_formed; pub use clk_insertion::ClkInsertion; pub use collapse_control::CollapseControl; -pub use compile_control::CompileControl; +// pub use compile_control::CompileControl; pub use compile_empty::CompileEmpty; pub use compile_invoke::CompileInvoke; pub use component_interface::ComponentInterface; @@ -48,7 +48,7 @@ pub use remove_comb_groups::RemoveCombGroups; pub use reset_insertion::ResetInsertion; pub use resource_sharing::ResourceSharing; pub use simplify_guards::SimplifyGuards; -pub use static_timing::StaticTiming; +// pub use static_timing::StaticTiming; pub use synthesis_papercut::SynthesisPapercut; pub use top_down_compile_control::TopDownCompileControl; pub use well_formed::WellFormed; diff --git a/calyx/src/passes/remove_comb_groups.rs b/calyx/src/passes/remove_comb_groups.rs index dd73cdb729..6e09065e06 100644 --- a/calyx/src/passes/remove_comb_groups.rs +++ b/calyx/src/passes/remove_comb_groups.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::rc::Rc; use crate::errors::{CalyxResult, Error}; +use crate::ir::GetAttributes; use crate::ir::{ self, traversal::{Action, Named, VisResult, Visitor}, @@ -192,7 +193,7 @@ impl Visitor for RemoveCombGroups { Ok(Action::Continue) } - fn start_while( + fn finish_while( &mut self, s: &mut ir::While, _comp: &mut ir::Component, @@ -205,17 +206,17 @@ impl Visitor for RemoveCombGroups { s.port.borrow().canonical(), ); let (port_ref, cond_ref) = self.port_rewrite.get(&key).unwrap(); - let port = Rc::clone(port_ref); - // Add @stable annotation to port - port.borrow_mut().attributes.insert("stable", 1); let cond_in_body = ir::Control::enable(Rc::clone(cond_ref)); let body = std::mem::replace(s.body.as_mut(), ir::Control::empty()); let new_body = ir::Control::seq(vec![body, cond_in_body]); - let while_ = ir::Control::while_( + let mut while_ = ir::Control::while_( Rc::clone(port_ref), None, Box::new(new_body), ); + if let Some(attrs) = while_.get_mut_attributes() { + *attrs = std::mem::take(&mut s.attributes); + } let cond_before_body = ir::Control::enable(Rc::clone(cond_ref)); Ok(Action::Change(ir::Control::seq(vec![ cond_before_body, @@ -228,7 +229,7 @@ impl Visitor for RemoveCombGroups { /// Transforms a `if-with` into a `seq-if` which first runs the cond group /// and then the branch. - fn start_if( + fn finish_if( &mut self, s: &mut ir::If, _comp: &mut ir::Component, diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index d9b45267eb..19b12f912b 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -1,6 +1,6 @@ use super::math_utilities::get_bit_width_from; use crate::errors::CalyxResult; -use crate::{build_assignments, guard, structure}; +use crate::{build_assignments, guard, passes, structure}; use crate::{ errors::Error, ir::{ @@ -77,59 +77,140 @@ impl Schedule { } } -/// Recursively calcuate the states for each child in a control sub-program. -fn calculate_states( +/// Computes the entry and exit points of a given [ir::Control] program. +/// +/// ## Example +/// In the following Calyx program: +/// ``` +/// while comb_reg.out { +/// seq { +/// incr; +/// cond0; +/// } +/// } +/// ``` +/// The entry point is `incr` and the exit point is `cond0`. +/// +/// Multiple entry and exit points are created when conditions are used: +/// ``` +/// while comb_reg.out { +/// incr; +/// if comb_reg2.out { +/// true; +/// } else { +/// false; +/// } +/// } +/// ``` +/// The entry set is `incr` while exit set is `[true, false]`. +fn entries_and_exits( + con: &ir::Control, + cur_state: u64, + is_entry: bool, + is_exit: bool, + entries: &mut Vec, + exits: &mut Vec, +) -> u64 { + match con { + ir::Control::Enable(_) => { + if is_entry { + entries.push(cur_state) + } else if is_exit { + exits.push(cur_state) + } + cur_state + 1 + } + ir::Control::Seq(ir::Seq { stmts, .. }) => { + let len = stmts.len(); + let mut cur = cur_state; + for (idx, stmt) in stmts.iter().enumerate() { + let entry = idx == 0 && is_entry; + let exit = idx == len - 1 && is_exit; + cur = entries_and_exits(stmt, cur, entry, exit, entries, exits); + } + cur + } + ir::Control::If(ir::If { + tbranch, fbranch, .. + }) => { + let tru_nxt = entries_and_exits( + tbranch, cur_state, is_entry, is_exit, entries, exits, + ); + entries_and_exits( + fbranch, tru_nxt, is_entry, is_exit, entries, exits, + ) + } + ir::Control::While(ir::While { body, .. }) => entries_and_exits( + body, cur_state, is_entry, is_exit, entries, exits, + ), + ir::Control::Invoke(_) => todo!(), + ir::Control::Empty(_) => todo!(), + ir::Control::Par(_) => todo!(), + } +} + +/// Calculate [ir::Assignment] to enable in each FSM state and [ir::Guard] required to transition +/// between FSM states. Each step of the calculation computes the previous states that still need +/// to transition. +fn calculate_states_recur( con: &ir::Control, // The current state cur_state: u64, - // Additional guard for this condition. - pre_guard: &ir::Guard, + // The set of previous states that want to transition into cur_state + prev_states: Vec<(u64, ir::Guard)>, + // Guard that needs to be true to reach this state + with_guard: &ir::Guard, // Current schedule. schedule: &mut Schedule, // Component builder builder: &mut ir::Builder, -) -> CalyxResult { +) -> CalyxResult<(Vec<(u64, ir::Guard)>, u64)> { match con { - // Compiled to: - // ``` - // group[go] = (fsm.out == cur_state) & !group[done] & pre_guard ? 1'd1; - // fsm.in = (fsm.out == cur_state) & group[done] & pre_guard ? nxt_state; - // ``` + // Enable the group in `cur_state` and construct all transitions from + // previous states to this enable. ir::Control::Enable(ir::Enable { group, .. }) => { - let done_cond = guard!(group["done"]) & pre_guard.clone(); - let not_done = !guard!(group["done"]) & pre_guard.clone(); + let not_done = !guard!(group["done"]); let signal_on = builder.add_constant(1, 1); let mut en_go = build_assignments!(builder; group["go"] = not_done ? signal_on["out"]; ); - // Transition to the next state. - let nxt_state = cur_state + 1; schedule .enables .entry(cur_state) .or_default() .append(&mut en_go); - schedule.transitions.push((cur_state, nxt_state, done_cond)); - Ok(nxt_state) + let transitions = prev_states + .into_iter() + .map(|(st, guard)| (st, cur_state, guard & with_guard.clone())); + schedule.transitions.extend(transitions); + + let done_cond = guard!(group["done"]); + let nxt = cur_state + 1; + Ok((vec![(cur_state, done_cond)], nxt)) } - // Give children the states `cur`, `cur + 1`, `cur + 2`, ... ir::Control::Seq(ir::Seq { stmts, .. }) => { + let mut prev = prev_states; let mut cur = cur_state; - for stmt in stmts { - cur = - calculate_states(stmt, cur, pre_guard, schedule, builder)?; + for (idx, stmt) in stmts.iter().enumerate() { + let res = calculate_states_recur( + stmt, + cur, + prev, + // Only the first group gets the with_guard for the previous state. + if idx == 0 { + with_guard + } else { + &ir::Guard::True + }, + schedule, + builder, + )?; + prev = res.0; + cur = res.1; } - Ok(cur) + Ok((prev, cur)) } - // Generate the following transitions: - // 1. (cur -> cur + t): Run the true branch - // is true. - // 2. (cur -> cur + f): Compute the true branch when stored condition - // is false. - // 3. (cur + t -> cur + max(t, f) + 1) - // (cur + f -> cur + max(t, f) + 1): Transition to a "join" stage - // after running the branch. ir::Control::If(ir::If { port, cond, @@ -137,80 +218,113 @@ fn calculate_states( fbranch, .. }) => { - // There shouldn't be a group in `with` position. if cond.is_some() { return Err(Error::MalformedStructure(format!("{}: Found group `{}` in with position of if. This should have compiled away.", TopDownCompileControl::name(), cond.as_ref().unwrap().borrow().name()))); } let port_guard = ir::Guard::port(Rc::clone(port)); - - // Computation for true branch - let true_go = port_guard.clone() & pre_guard.clone(); - let after_true = calculate_states( - tbranch, dbg!(cur_state), &true_go, schedule, builder, + // Add transitions for the true branch + let (tru_prev, tru_nxt) = calculate_states_recur( + tbranch, + cur_state, + prev_states.clone(), + &port_guard, + schedule, + builder, )?; - // Computation for false branch - let false_go = !port_guard & pre_guard.clone(); - let after_false = calculate_states( - fbranch, cur_state, &false_go, schedule, builder, + let (fal_prev, fal_nxt) = calculate_states_recur( + fbranch, + tru_nxt, + prev_states, + &!port_guard, + schedule, + builder, )?; - - // Transition to a join stage - let next = std::cmp::max(after_true, after_false) + 1; - schedule.transitions.push((after_true, next, true_go)); - schedule.transitions.push((after_false, next, false_go)); - - Ok(next) + let prevs = + tru_prev.into_iter().chain(fal_prev.into_iter()).collect(); + Ok((prevs, fal_nxt)) } - // Compile in three stage: - // 2. cur -> cur + b: Compute the body when the stored condition - // is true. - // 3. cur + b -> cur: Jump to the start state when stored condition was true. - // 4. cur -> cur + b + 1: Exit stage ir::Control::While(ir::While { cond, port, body, .. }) => { - // There shouldn't be a group in `with` position. if cond.is_some() { return Err(Error::MalformedStructure(format!("{}: Found group `{}` in with position of if. This should have compiled away.", TopDownCompileControl::name(), cond.as_ref().unwrap().borrow().name()))); } - // Build the FSM for the body + // Step 1: Generate the forward edges normally. let port_guard = ir::Guard::port(Rc::clone(port)); - let body_go = pre_guard.clone(); - let nxt = calculate_states( + let (prevs, nxt) = calculate_states_recur( body, cur_state, - &body_go, + prev_states.clone(), + &port_guard, schedule, builder, )?; - // Back edge jump when condition was true - schedule.transitions.push((nxt, cur_state, body_go)); - - // Exit state: Jump to this when the condition is false. - let wh_done = !port_guard & pre_guard.clone(); - let exit = nxt + 1; - schedule - .transitions - .push((cur_state, exit, wh_done)); - - Ok(exit) - } - // `par` sub-programs should already be compiled - ir::Control::Par(..) => { - unreachable!("par should be compiled away!") - } - ir::Control::Empty(..) => { - unreachable!("empty control should have been compiled away!") - } - ir::Control::Invoke(..) => { - unreachable!("invoke should have been compiled away!") + // Step 2: Generate the backward edges + // First compute the entry and exit points. + let mut entries = vec![]; + let mut exits = vec![]; + entries_and_exits( + body, + cur_state, + true, + true, + &mut entries, + &mut exits, + ); + // For each exit point, generate a map to the guards used. + let guard_map = + prevs.clone().into_iter().collect::>(); + // Generate exit to entry transitions which occur when the condition + // is true at the end of the while body. + let exit_to_entry_transitions = exits + .into_iter() + .cartesian_product(entries) + .map(|(old, new)| { + (old, new, guard_map[&old].clone() & port_guard.clone()) + }); + schedule.transitions.extend(exit_to_entry_transitions); + + // Step 3: The final out edges from the while come from: + // - Before the body when the condition is false + // - Inside the body when the condition is false + let not_port_guard = !port_guard; + let all_prevs = prev_states + .into_iter() + .chain(prevs.into_iter()) + .map(|(st, guard)| (st, guard & not_port_guard.clone())) + .collect(); + + Ok((all_prevs, nxt)) } + ir::Control::Invoke(_) => unreachable!("`invoke` statements should have been compiled away. Run `{}` before this pass.", passes::CompileInvoke::name()), + ir::Control::Empty(_) => unreachable!("`invoke` statements should have been compiled away. Run `{}` before this pass.", passes::CompileEmpty::name()), + ir::Control::Par(_) => unreachable!(), } } -/// Implement a given [Schedule] and return the name of the [`ir::Group`](crate::ir::Group) that +fn calculate_states( + con: &ir::Control, + // The current state + schedule: &mut Schedule, + // Component builder + builder: &mut ir::Builder, +) -> CalyxResult<()> { + let (prev, nxt) = calculate_states_recur( + con, + 0, + vec![], + &ir::Guard::True, + schedule, + builder, + )?; + let transitions = prev.into_iter().map(|(st, guard)| (st, nxt, guard)); + schedule.transitions.extend(transitions); + Ok(()) +} + +/// Implement a given [Schedule] and return the name of the [ir::Group] that /// implements it. fn realize_schedule( schedule: Schedule, @@ -300,15 +414,15 @@ fn realize_schedule( /// code using an finite-state machine (FSM). /// /// Lowering operates in two steps: -/// 1. Compile all [`ir::Par`](crate::ir::Par) control sub-programs into a -/// single [`ir::Enable`][enable] of a group that runs all children +/// 1. Compile all [ir::Par] control sub-programs into a +/// single [ir::Enable] of a group that runs all children /// to completion. -/// 2. Compile the top-level control program into a single [`ir::Enable`][enable]. +/// 2. Compile the top-level control program into a single [ir::Enable]. /// /// ## Compiling non-`par` programs /// Assuming all `par` statements have already been compiled in a control /// sub-program, we can build a schedule for executing it. We calculate a -/// schedule by assigning an FSM state to each leaf node (an [`ir::Enable`][enable]) +/// schedule by assigning an FSM state to each leaf node (an [ir::Enable]) /// as a guard condition. Each control program node also defines a transition /// function over the states calculated for its children. /// @@ -326,8 +440,6 @@ fn realize_schedule( /// ## Compilation guarantee /// At the end of this pass, the control program will have no more than one /// group enable in it. -/// -/// [enable]: crate::ir::Enable #[derive(Default)] pub struct TopDownCompileControl; @@ -372,13 +484,7 @@ impl Visitor for TopDownCompileControl { // Compile complex schedule and return the group. _ => { let mut schedule = Schedule::default(); - calculate_states( - con, - 0, - &ir::Guard::True, - &mut schedule, - &mut builder, - )?; + calculate_states(con, &mut schedule, &mut builder)?; realize_schedule(schedule, &mut builder) } }; @@ -449,13 +555,8 @@ impl Visitor for TopDownCompileControl { let control = Rc::clone(&comp.control); let mut builder = ir::Builder::new(comp, sigs); let mut schedule = Schedule::default(); - calculate_states( - &control.borrow(), - 0, - &ir::Guard::True, - &mut schedule, - &mut builder, - )?; + // Add assignments for the final states + calculate_states(&control.borrow(), &mut schedule, &mut builder)?; schedule.display(); let comp_group = realize_schedule(schedule, &mut builder); diff --git a/src/backend/circt.rs b/src/backend/circt.rs index 3aa2deba3e..b0540a818c 100644 --- a/src/backend/circt.rs +++ b/src/backend/circt.rs @@ -333,11 +333,15 @@ impl CirctBackend { fbranch, .. }) => { + assert!( + cond.is_some(), + "`if` without `with` not support in CIRCT backend" + ); writeln!( f, "calyx.if {} with @{} {{", Self::get_port_access(&port.borrow()), - cond.borrow().name().id + cond.as_ref().unwrap().borrow().name().id )?; Self::write_control(tbranch, indent_level + 2, f)?; write!(f, "{}}}", " ".repeat(indent_level))?; @@ -352,11 +356,15 @@ impl CirctBackend { ir::Control::While(ir::While { port, cond, body, .. }) => { + assert!( + cond.is_some(), + "`while` without `with` not support in CIRCT backend" + ); writeln!( f, "while {} with @{} {{", Self::get_port_access(&port.borrow()), - cond.borrow().name().id + cond.as_ref().unwrap().borrow().name().id )?; Self::write_control(body, indent_level + 2, f)?; writeln!(f, "{}}}", " ".repeat(indent_level)) From e807d7933b6c6efa5bab63f286c1eb75480797db Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 1 Sep 2021 23:03:36 +0530 Subject: [PATCH 07/50] compiler workflow should not build interpreter --- .github/workflows/rust.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 22b1a6100c..ee5e10cdfd 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -196,7 +196,7 @@ jobs: cd ./dahlia && sbt assembly shell: bash - - name: Cache Futil dependencies + - name: Cache Calyx dependencies uses: actions/cache@v2 with: path: | @@ -228,7 +228,6 @@ jobs: uses: actions-rs/cargo@v1 with: command: build - args: --all - name: Test run: | From 37693b293ccd8095658d3d054a8d5666b51c166f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 2 Sep 2021 10:33:47 +0530 Subject: [PATCH 08/50] fix some doc comments --- calyx/src/ir/structure.rs | 4 ++-- interp/src/primitives/stateful.rs | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/calyx/src/ir/structure.rs b/calyx/src/ir/structure.rs index dc29d1fa2b..6f8ad3c559 100644 --- a/calyx/src/ir/structure.rs +++ b/calyx/src/ir/structure.rs @@ -273,13 +273,13 @@ impl Cell { &self.name } - /// Returns a reference to all [ir::Port] attached to this cells. + /// Returns a reference to all [super::Port] attached to this cells. pub fn ports(&self) -> &SmallVec<[RRC; 10]> { &self.ports } } -/// Generic wrapper for iterators that return [RRC] of [ir::Cell]. +/// Generic wrapper for iterators that return [RRC] of [super::Cell]. pub struct CellIterator<'a> { pub port_iter: Box> + 'a>, } diff --git a/interp/src/primitives/stateful.rs b/interp/src/primitives/stateful.rs index 42d98fba83..8b13404c5e 100644 --- a/interp/src/primitives/stateful.rs +++ b/interp/src/primitives/stateful.rs @@ -18,15 +18,14 @@ where }) } -///Pipelined Multiplication (3 cycles) -///Still bounded by u64. -///How to use: -///[execute] with the desired bindings. To capture these bindings -///into the internal (out) queue, [do_tick()]. -///The product associated with a given input will -///be output on the third [do_tick()]. -///Note: Calling [execute] multiple times before [do_tick()] has no effect; only -///the last set of inputs prior to the [do_tick()] will be saved. +/// Pipelined Multiplication (3 cycles) +/// Still bounded by u64. +/// How to use: +/// [Primitive::execute] with the desired bindings. +/// To capture these bindings into the internal (out) queue, [Primitive::do_tick]. +/// The product associated with a given input will be output on the third [do_tick()]. +/// Note: Calling [Primitive::execute] multiple times before [Primitive::do_tick] has no effect; only the last +/// set of inputs prior to the [Primitve::do_tick] will be saved. #[derive(Default)] pub struct StdMultPipe { pub width: u64, From 3d683941e0e1beb4ca9962fb2e8054b6870e29ff Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 2 Sep 2021 11:06:28 +0530 Subject: [PATCH 09/50] add comb primitive syntax --- calyx/src/frontend/parser.rs | 21 ++++++++++++++++----- calyx/src/frontend/syntax.pest | 7 +++++-- calyx/src/ir/builder.rs | 1 + calyx/src/ir/primitives.rs | 4 +++- calyx/src/ir/structure.rs | 2 ++ src/backend/circt.rs | 1 + 6 files changed, 28 insertions(+), 8 deletions(-) diff --git a/calyx/src/frontend/parser.rs b/calyx/src/frontend/parser.rs index 3354e2007e..f9c1cf32b9 100644 --- a/calyx/src/frontend/parser.rs +++ b/calyx/src/frontend/parser.rs @@ -304,7 +304,7 @@ impl CalyxParser { fn signature(input: Node) -> ParseResult> { Ok(match_nodes!( input.into_children(); - // XXX(rachit): We expect the signature to be extended to have `go`, + // NOTE(rachit): We expect the signature to be extended to have `go`, // `done`, and `clk`. [] => Vec::with_capacity(3), [inputs(ins)] => ins , @@ -315,21 +315,32 @@ impl CalyxParser { )) } - // ==============PortDeftives ===================== + // ==============Primitives===================== + fn sig_with_params( + input: Node, + ) -> ParseResult<(Vec, Vec)> { + Ok(match_nodes!( + input.into_children(); + [params(p), signature(s)] => (p, s), + [signature(s)] => (vec![], s), + )) + } fn primitive(input: Node) -> ParseResult { Ok(match_nodes!( input.into_children(); - [name_with_attribute((name, attrs)), params(p), signature(s)] => ir::Primitive { + [name_with_attribute((name, attrs)), sig_with_params((p, s))] => ir::Primitive { name, params: p, signature: s, attributes: attrs, + is_comb: false, }, - [name_with_attribute((name, attrs)), signature(s)] => ir::Primitive { + [comb(_), name_with_attribute((name, attrs)), sig_with_params((p, s))] => ir::Primitive { name, - params: Vec::with_capacity(0), + params: p, signature: s, attributes: attrs, + is_comb: true, }, )) } diff --git a/calyx/src/frontend/syntax.pest b/calyx/src/frontend/syntax.pest index 1b60daff0f..616c078856 100644 --- a/calyx/src/frontend/syntax.pest +++ b/calyx/src/frontend/syntax.pest @@ -37,6 +37,7 @@ bad_num = @{ ASCII_DIGIT ~ ('a'..'z' | 'A'..'Z' | '0'..'9' | "'")* } // ====== toplevel ====== +comb = { "comb" } file = { SOI @@ -91,8 +92,11 @@ params = { "[" ~ (identifier ~ ("," ~ identifier)*)? ~ "]" } +sig_with_params = { + params? ~ signature +} primitive = { - "primitive" ~ name_with_attribute ~ params? ~ signature ~ ";" + comb? ~ "primitive" ~ name_with_attribute ~ sig_with_params ~ ";" } ext = { @@ -203,7 +207,6 @@ at_attributes = { at_attribute* } -comb = { "comb" } group = { comb? ~ "group" ~ name_with_attribute ~ "{" ~ wire* diff --git a/calyx/src/ir/builder.rs b/calyx/src/ir/builder.rs index e8976bd2ba..c65df414bd 100644 --- a/calyx/src/ir/builder.rs +++ b/calyx/src/ir/builder.rs @@ -172,6 +172,7 @@ impl<'a> Builder<'a> { ir::CellType::Primitive { name: prim_id, param_binding, + is_comb: prim.is_comb, }, ports, ); diff --git a/calyx/src/ir/primitives.rs b/calyx/src/ir/primitives.rs index 15021159d9..9bb353ce49 100644 --- a/calyx/src/ir/primitives.rs +++ b/calyx/src/ir/primitives.rs @@ -14,7 +14,7 @@ use smallvec::SmallVec; /// ); /// ``` /// -/// The signature of a port is represented using [`PortDef`] which also specify +/// The signature of a port is represented using [PortDef] which also specify /// the direction of the port. #[derive(Clone, Debug)] pub struct Primitive { @@ -26,6 +26,8 @@ pub struct Primitive { pub signature: Vec, /// Key-value attributes for this primitive. pub attributes: Attributes, + /// True iff this is a combinational primitive + pub is_comb: bool, } impl Primitive { diff --git a/calyx/src/ir/structure.rs b/calyx/src/ir/structure.rs index 6f8ad3c559..bd56af6673 100644 --- a/calyx/src/ir/structure.rs +++ b/calyx/src/ir/structure.rs @@ -126,6 +126,8 @@ pub enum CellType { name: Id, /// Bindings for the parameters. Uses Vec to retain the input order. param_binding: Binding, + /// True iff this is a combinational primitive + is_comb: bool, }, /// Cell constructed using a Calyx component Component { diff --git a/src/backend/circt.rs b/src/backend/circt.rs index b0540a818c..a5149a6ea0 100644 --- a/src/backend/circt.rs +++ b/src/backend/circt.rs @@ -159,6 +159,7 @@ impl CirctBackend { ir::CellType::Primitive { name, param_binding, + .. } => { let bind: HashMap<&str, u64> = param_binding .iter() From e316293c6764bdb5f04cc6edb390bd3e58dfc681 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 2 Sep 2021 11:07:03 +0530 Subject: [PATCH 10/50] make combinational primitives with `comb` --- primitives/binary_operators.futil | 38 +++++++++++++++---------------- primitives/core.futil | 36 ++++++++++++++--------------- primitives/unsynthesizable.futil | 12 +++++----- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/primitives/binary_operators.futil b/primitives/binary_operators.futil index bf4818077c..fc0290c4e5 100644 --- a/primitives/binary_operators.futil +++ b/primitives/binary_operators.futil @@ -1,10 +1,10 @@ extern "binary_operators.sv" { /// =================== Unsigned, Fixed Point ========================= - primitive std_fp_add<"share"=1>[ + comb primitive std_fp_add<"share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) ->(out: WIDTH); - primitive std_fp_sub<"share"=1>[ + comb primitive std_fp_sub<"share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH)->(out: WIDTH); @@ -33,11 +33,11 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_fp_gt<"share"=1>[ + comb primitive std_fp_gt<"share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_fp_add_dwidth<"share"=1>[ + comb primitive std_fp_add_dwidth<"share"=1>[ WIDTH1, WIDTH2, INT_WIDTH1, @@ -48,11 +48,11 @@ extern "binary_operators.sv" { ](left: WIDTH1, right: WIDTH2) -> (out: OUT_WIDTH); /// =================== Signed, Fixed Point ========================= - primitive std_fp_sadd<"share"=1>[ + comb primitive std_fp_sadd<"share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_fp_ssub<"share"=1>[ + comb primitive std_fp_ssub<"share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) -> (out: WIDTH); @@ -81,15 +81,15 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_fp_sgt<"share"=1>[ + comb primitive std_fp_sgt<"share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_fp_slt<"share"=1>[ + comb primitive std_fp_slt<"share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_fp_sadd_dwidth<"share"=1>[ + comb primitive std_fp_sadd_dwidth<"share"=1>[ WIDTH1, WIDTH2 , INT_WIDTH1, @@ -125,8 +125,8 @@ extern "binary_operators.sv" { ); /// =================== Signed, Bitnum ========================= - primitive std_sadd<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_ssub<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_sadd<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_ssub<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); primitive std_smult_pipe[WIDTH]( @write_together(1) left: WIDTH, @@ -148,13 +148,13 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_sgt<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_slt<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_seq<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_sneq<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_sge<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_sle<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_slsh<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_srsh<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_sgt<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_slt<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_seq<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_sneq<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_sge<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_sle<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_slsh<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_srsh<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); } diff --git a/primitives/core.futil b/primitives/core.futil index af79efd097..65f1318c07 100644 --- a/primitives/core.futil +++ b/primitives/core.futil @@ -1,27 +1,27 @@ extern "core.sv" { /// Primitives - primitive std_const<"share"=1>[WIDTH, VALUE]() -> (out: WIDTH); - primitive std_slice<"share"=1>[IN_WIDTH, OUT_WIDTH](in: IN_WIDTH) -> (out: OUT_WIDTH); - primitive std_pad<"share"=1>[IN_WIDTH, OUT_WIDTH](in: IN_WIDTH) -> (out: OUT_WIDTH); + comb primitive std_const<"share"=1>[WIDTH, VALUE]() -> (out: WIDTH); + comb primitive std_slice<"share"=1>[IN_WIDTH, OUT_WIDTH](in: IN_WIDTH) -> (out: OUT_WIDTH); + comb primitive std_pad<"share"=1>[IN_WIDTH, OUT_WIDTH](in: IN_WIDTH) -> (out: OUT_WIDTH); /// Logical operators - primitive std_not<"share"=1>[WIDTH](in: WIDTH) -> (out: WIDTH); - primitive std_and<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_or<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_xor<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_not<"share"=1>[WIDTH](in: WIDTH) -> (out: WIDTH); + comb primitive std_and<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_or<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_xor<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); /// Numerical Operators - primitive std_add<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_sub<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_gt<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_lt<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_eq<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_neq<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_ge<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_le<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); - primitive std_lsh<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_rsh<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_mux<"share"=1>[WIDTH](cond: 1, tru: WIDTH, fal: WIDTH) -> (out: WIDTH); + comb primitive std_add<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_sub<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_gt<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_lt<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_eq<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_neq<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_ge<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_le<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: 1); + comb primitive std_lsh<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_rsh<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_mux<"share"=1>[WIDTH](cond: 1, tru: WIDTH, fal: WIDTH) -> (out: WIDTH); /// Memories primitive std_reg<"static"=1>[WIDTH]( diff --git a/primitives/unsynthesizable.futil b/primitives/unsynthesizable.futil index e3d32fad66..2cc79a0d98 100644 --- a/primitives/unsynthesizable.futil +++ b/primitives/unsynthesizable.futil @@ -1,12 +1,12 @@ extern "unsynthesizable.sv" { // Designs that use these primitives cannot be synthesized. - primitive std_unsyn_mult<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_unsyn_div<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_unsyn_mod<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_unsyn_mult<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_unsyn_div<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_unsyn_mod<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_unsyn_smult<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_unsyn_sdiv<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_unsyn_smod<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_unsyn_smult<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_unsyn_sdiv<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); + comb primitive std_unsyn_smod<"share"=1>[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH); } From 12d39b28e502143d82735c46d4c3170575a53047 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 2 Sep 2021 12:32:58 +0530 Subject: [PATCH 11/50] Implement `Schedule::realize_schedule` --- calyx/src/passes/top_down_compile_control.rs | 191 +++++++++---------- 1 file changed, 92 insertions(+), 99 deletions(-) diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index 19b12f912b..70113fe2ba 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -11,7 +11,7 @@ use crate::{ }; use ir::IRPrinter; use itertools::Itertools; -use petgraph::{algo::connected_components, graph::DiGraph}; +use petgraph::graph::DiGraph; use std::collections::HashMap; use std::rc::Rc; @@ -36,7 +36,7 @@ impl Schedule { ); debug_assert!( - connected_components(&graph) == 1, + petgraph::algo::connected_components(&graph) == 1, "State transition graph has unreachable states (graph has more than one connected component)."); } @@ -75,6 +75,88 @@ impl Schedule { eprintln!("({}, {}): {}", i, f, IRPrinter::guard_str(g)); }) } + + /// Implement a given [Schedule] and return the name of the [ir::Group] that + /// implements it. + fn realize_schedule(self, builder: &mut ir::Builder) -> RRC { + self.validate(); + let final_state = self.last_state(); + let fsm_size = get_bit_width_from( + final_state + 1, /* represent 0..final_state */ + ); + structure!(builder; + let fsm = prim std_reg(fsm_size); + let signal_on = constant(1, 1); + let last_state = constant(final_state, fsm_size); + let first_state = constant(0, fsm_size); + ); + + // The compilation group + let group = builder.add_group("tdcc"); + + // Enable assignments + group.borrow_mut().assignments.extend( + self.enables + .into_iter() + .sorted_by(|(k1, _), (k2, _)| k1.cmp(k2)) + .flat_map(|(state, mut assigns)| { + let state_const = builder.add_constant(state, fsm_size); + let state_guard = + guard!(fsm["out"]).eq(guard!(state_const["out"])); + assigns.iter_mut().for_each(|asgn| { + asgn.guard.update(|g| g.and(state_guard.clone())) + }); + assigns + }), + ); + + // Transition assignments + group.borrow_mut().assignments.extend( + self.transitions.into_iter().flat_map(|(s, e, guard)| { + structure!(builder; + let end_const = constant(e, fsm_size); + let start_const = constant(s, fsm_size); + ); + let ec_borrow = end_const.borrow(); + let trans_guard = + guard!(fsm["out"]).eq(guard!(start_const["out"])) & guard; + + vec![ + builder.build_assignment( + fsm.borrow().get("in"), + ec_borrow.get("out"), + trans_guard.clone(), + ), + builder.build_assignment( + fsm.borrow().get("write_en"), + signal_on.borrow().get("out"), + trans_guard, + ), + ] + }), + ); + + // Done condition for group + let last_guard = guard!(fsm["out"]).eq(guard!(last_state["out"])); + let done_assign = builder.build_assignment( + group.borrow().get("done"), + signal_on.borrow().get("out"), + last_guard.clone(), + ); + group.borrow_mut().assignments.push(done_assign); + + // Cleanup: Add a transition from last state to the first state. + let mut reset_fsm = build_assignments!(builder; + fsm["in"] = last_guard ? first_state["out"]; + fsm["write_en"] = last_guard ? signal_on["out"]; + ); + builder + .component + .continuous_assignments + .append(&mut reset_fsm); + + group + } } /// Computes the entry and exit points of a given [ir::Control] program. @@ -306,107 +388,20 @@ fn calculate_states_recur( fn calculate_states( con: &ir::Control, - // The current state - schedule: &mut Schedule, - // Component builder builder: &mut ir::Builder, -) -> CalyxResult<()> { +) -> CalyxResult { + let mut schedule = Schedule::default(); let (prev, nxt) = calculate_states_recur( con, 0, vec![], &ir::Guard::True, - schedule, + &mut schedule, builder, )?; let transitions = prev.into_iter().map(|(st, guard)| (st, nxt, guard)); schedule.transitions.extend(transitions); - Ok(()) -} - -/// Implement a given [Schedule] and return the name of the [ir::Group] that -/// implements it. -fn realize_schedule( - schedule: Schedule, - builder: &mut ir::Builder, -) -> RRC { - schedule.validate(); - let final_state = schedule.last_state(); - let fsm_size = - get_bit_width_from(final_state + 1 /* represent 0..final_state */); - structure!(builder; - let fsm = prim std_reg(fsm_size); - let signal_on = constant(1, 1); - let last_state = constant(final_state, fsm_size); - let first_state = constant(0, fsm_size); - ); - - // The compilation group - let group = builder.add_group("tdcc"); - - // Enable assignments - group.borrow_mut().assignments.extend( - schedule - .enables - .into_iter() - .sorted_by(|(k1, _), (k2, _)| k1.cmp(k2)) - .flat_map(|(state, mut assigns)| { - let state_const = builder.add_constant(state, fsm_size); - let state_guard = - guard!(fsm["out"]).eq(guard!(state_const["out"])); - assigns.iter_mut().for_each(|asgn| { - asgn.guard.update(|g| g.and(state_guard.clone())) - }); - assigns - }), - ); - - // Transition assignments - group.borrow_mut().assignments.extend( - schedule.transitions.into_iter().flat_map(|(s, e, guard)| { - structure!(builder; - let end_const = constant(e, fsm_size); - let start_const = constant(s, fsm_size); - ); - let ec_borrow = end_const.borrow(); - let trans_guard = - guard!(fsm["out"]).eq(guard!(start_const["out"])) & guard; - - vec![ - builder.build_assignment( - fsm.borrow().get("in"), - ec_borrow.get("out"), - trans_guard.clone(), - ), - builder.build_assignment( - fsm.borrow().get("write_en"), - signal_on.borrow().get("out"), - trans_guard, - ), - ] - }), - ); - - // Done condition for group - let last_guard = guard!(fsm["out"]).eq(guard!(last_state["out"])); - let done_assign = builder.build_assignment( - group.borrow().get("done"), - signal_on.borrow().get("out"), - last_guard.clone(), - ); - group.borrow_mut().assignments.push(done_assign); - - // Cleanup: Add a transition from last state to the first state. - let mut reset_fsm = build_assignments!(builder; - fsm["in"] = last_guard ? first_state["out"]; - fsm["write_en"] = last_guard ? signal_on["out"]; - ); - builder - .component - .continuous_assignments - .append(&mut reset_fsm); - - group + Ok(schedule) } /// **Core lowering pass.** @@ -483,9 +478,8 @@ impl Visitor for TopDownCompileControl { } // Compile complex schedule and return the group. _ => { - let mut schedule = Schedule::default(); - calculate_states(con, &mut schedule, &mut builder)?; - realize_schedule(schedule, &mut builder) + let schedule = calculate_states(con, &mut builder)?; + schedule.realize_schedule(&mut builder) } }; @@ -554,11 +548,10 @@ impl Visitor for TopDownCompileControl { let control = Rc::clone(&comp.control); let mut builder = ir::Builder::new(comp, sigs); - let mut schedule = Schedule::default(); // Add assignments for the final states - calculate_states(&control.borrow(), &mut schedule, &mut builder)?; + let schedule = calculate_states(&control.borrow(), &mut builder)?; schedule.display(); - let comp_group = realize_schedule(schedule, &mut builder); + let comp_group = schedule.realize_schedule(&mut builder); Ok(Action::Change(ir::Control::enable(comp_group))) } From b165912bec2a5b0e155f21f4692cb67b84fb03dd Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 2 Sep 2021 13:10:32 +0530 Subject: [PATCH 12/50] some cleanup and register top-down-st --- calyx/src/default_passes.rs | 3 ++- calyx/src/passes/mod.rs | 2 ++ calyx/src/passes/top_down_compile_control.rs | 6 +++--- calyx/src/passes/top_down_static_timing.rs | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index 9761baa598..d97437700a 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -5,7 +5,7 @@ use crate::passes::{ GuardCanonical, InferStaticTiming, Inliner, MergeAssign, MinimizeRegs, Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, ResetInsertion, ResourceSharing, SimplifyGuards, SynthesisPapercut, TopDownCompileControl, - WellFormed, + TopDownStaticTiming, WellFormed, }; use crate::{ errors::CalyxResult, ir::traversal::Named, pass_manager::PassManager, @@ -38,6 +38,7 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; + pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; diff --git a/calyx/src/passes/mod.rs b/calyx/src/passes/mod.rs index 3e3f0a37c6..effc5a90af 100644 --- a/calyx/src/passes/mod.rs +++ b/calyx/src/passes/mod.rs @@ -25,6 +25,7 @@ mod simplify_guards; // mod static_timing; mod synthesis_papercut; mod top_down_compile_control; +mod top_down_static_timing; mod well_formed; pub use clk_insertion::ClkInsertion; @@ -51,4 +52,5 @@ pub use simplify_guards::SimplifyGuards; // pub use static_timing::StaticTiming; pub use synthesis_papercut::SynthesisPapercut; pub use top_down_compile_control::TopDownCompileControl; +pub use top_down_static_timing::TopDownStaticTiming; pub use well_formed::WellFormed; diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index 70113fe2ba..7816933a9e 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -15,7 +15,7 @@ use petgraph::graph::DiGraph; use std::collections::HashMap; use std::rc::Rc; -/// Represents the execution schedule of a control program. +/// Represents the dyanmic execution schedule of a control program. #[derive(Default)] struct Schedule { /// Assigments that should be enabled in a given state. @@ -303,7 +303,7 @@ fn calculate_states_recur( if cond.is_some() { return Err(Error::MalformedStructure(format!("{}: Found group `{}` in with position of if. This should have compiled away.", TopDownCompileControl::name(), cond.as_ref().unwrap().borrow().name()))); } - let port_guard = ir::Guard::port(Rc::clone(port)); + let port_guard = Rc::clone(port).into(); // Add transitions for the true branch let (tru_prev, tru_nxt) = calculate_states_recur( tbranch, @@ -333,7 +333,7 @@ fn calculate_states_recur( } // Step 1: Generate the forward edges normally. - let port_guard = ir::Guard::port(Rc::clone(port)); + let port_guard = Rc::clone(port).into(); let (prevs, nxt) = calculate_states_recur( body, cur_state, diff --git a/calyx/src/passes/top_down_static_timing.rs b/calyx/src/passes/top_down_static_timing.rs index 206146f678..ab32a10ae0 100644 --- a/calyx/src/passes/top_down_static_timing.rs +++ b/calyx/src/passes/top_down_static_timing.rs @@ -3,7 +3,7 @@ use crate::ir::{ traversal::{Action, Named, VisResult, Visitor}, IRPrinter, LibrarySignatures, }; -use crate::{build_assignments, guard, structure}; +use crate::{build_assignments, structure}; use itertools::Itertools; use std::collections::HashMap; From 89a682912db66f435530cc493664a64999c5154d Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 2 Sep 2021 14:29:08 +0530 Subject: [PATCH 13/50] remove with_guard from calculate_states_recur --- calyx/src/passes/top_down_compile_control.rs | 45 ++++++++------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index 7816933a9e..bdd86578fe 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -240,8 +240,6 @@ fn calculate_states_recur( cur_state: u64, // The set of previous states that want to transition into cur_state prev_states: Vec<(u64, ir::Guard)>, - // Guard that needs to be true to reach this state - with_guard: &ir::Guard, // Current schedule. schedule: &mut Schedule, // Component builder @@ -264,7 +262,7 @@ fn calculate_states_recur( let transitions = prev_states .into_iter() - .map(|(st, guard)| (st, cur_state, guard & with_guard.clone())); + .map(|(st, guard)| (st, cur_state, guard)); schedule.transitions.extend(transitions); let done_cond = guard!(group["done"]); @@ -274,17 +272,11 @@ fn calculate_states_recur( ir::Control::Seq(ir::Seq { stmts, .. }) => { let mut prev = prev_states; let mut cur = cur_state; - for (idx, stmt) in stmts.iter().enumerate() { + for stmt in stmts { let res = calculate_states_recur( stmt, cur, prev, - // Only the first group gets the with_guard for the previous state. - if idx == 0 { - with_guard - } else { - &ir::Guard::True - }, schedule, builder, )?; @@ -303,21 +295,24 @@ fn calculate_states_recur( if cond.is_some() { return Err(Error::MalformedStructure(format!("{}: Found group `{}` in with position of if. This should have compiled away.", TopDownCompileControl::name(), cond.as_ref().unwrap().borrow().name()))); } - let port_guard = Rc::clone(port).into(); - // Add transitions for the true branch + let port_guard: ir::Guard = Rc::clone(port).into(); + // Previous states transitioning into true branch need the conditional + // to be true. + let tru_transitions = prev_states.clone().into_iter().map(|(s, g)| (s, g & port_guard.clone())).collect(); let (tru_prev, tru_nxt) = calculate_states_recur( tbranch, cur_state, - prev_states.clone(), - &port_guard, + tru_transitions, schedule, builder, )?; + // Previous states transitioning into false branch need the conditional + // to be false. + let fal_transitions = prev_states.into_iter().map(|(s, g)| (s, g & !port_guard.clone())).collect(); let (fal_prev, fal_nxt) = calculate_states_recur( fbranch, tru_nxt, - prev_states, - &!port_guard, + fal_transitions, schedule, builder, )?; @@ -333,12 +328,14 @@ fn calculate_states_recur( } // Step 1: Generate the forward edges normally. - let port_guard = Rc::clone(port).into(); + let port_guard: ir::Guard = Rc::clone(port).into(); + // Previous transitions into the body require the condition to be + // true. + let transitions = prev_states.clone().into_iter().map(|(s, g)| (s, g & port_guard.clone())).collect(); let (prevs, nxt) = calculate_states_recur( body, cur_state, - prev_states.clone(), - &port_guard, + transitions, schedule, builder, )?; @@ -391,14 +388,8 @@ fn calculate_states( builder: &mut ir::Builder, ) -> CalyxResult { let mut schedule = Schedule::default(); - let (prev, nxt) = calculate_states_recur( - con, - 0, - vec![], - &ir::Guard::True, - &mut schedule, - builder, - )?; + let (prev, nxt) = + calculate_states_recur(con, 0, vec![], &mut schedule, builder)?; let transitions = prev.into_iter().map(|(st, guard)| (st, nxt, guard)); schedule.transitions.extend(transitions); Ok(schedule) From 7bed491b1aec4fc5a0a8640699f5e3fb8a12632f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 3 Sep 2021 09:26:54 +0530 Subject: [PATCH 14/50] fix bug in back edge generation of top-down-cc while FSM --- calyx/src/passes/top_down_compile_control.rs | 50 +++++++++----------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index bdd86578fe..737f44cc01 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -191,14 +191,15 @@ fn entries_and_exits( is_entry: bool, is_exit: bool, entries: &mut Vec, - exits: &mut Vec, + exits: &mut Vec<(u64, RRC)>, ) -> u64 { match con { - ir::Control::Enable(_) => { + ir::Control::Enable(ir::Enable { group, .. }) => { if is_entry { entries.push(cur_state) - } else if is_exit { - exits.push(cur_state) + } + if is_exit { + exits.push((cur_state, Rc::clone(group))) } cur_state + 1 } @@ -327,20 +328,9 @@ fn calculate_states_recur( return Err(Error::MalformedStructure(format!("{}: Found group `{}` in with position of if. This should have compiled away.", TopDownCompileControl::name(), cond.as_ref().unwrap().borrow().name()))); } - // Step 1: Generate the forward edges normally. let port_guard: ir::Guard = Rc::clone(port).into(); - // Previous transitions into the body require the condition to be - // true. - let transitions = prev_states.clone().into_iter().map(|(s, g)| (s, g & port_guard.clone())).collect(); - let (prevs, nxt) = calculate_states_recur( - body, - cur_state, - transitions, - schedule, - builder, - )?; - // Step 2: Generate the backward edges + // Step 1: Generate the backward edges // First compute the entry and exit points. let mut entries = vec![]; let mut exits = vec![]; @@ -352,18 +342,24 @@ fn calculate_states_recur( &mut entries, &mut exits, ); - // For each exit point, generate a map to the guards used. - let guard_map = - prevs.clone().into_iter().collect::>(); - // Generate exit to entry transitions which occur when the condition - // is true at the end of the while body. - let exit_to_entry_transitions = exits + let back_edge_prevs = exits.into_iter().map(|(st, group)| (st, group.borrow().get("done").into())); + + // Step 2: Generate the forward edges normally. + // Previous transitions into the body require the condition to be + // true. + let transitions: Vec<(u64, ir::Guard)> = prev_states + .clone() .into_iter() - .cartesian_product(entries) - .map(|(old, new)| { - (old, new, guard_map[&old].clone() & port_guard.clone()) - }); - schedule.transitions.extend(exit_to_entry_transitions); + .chain(back_edge_prevs) + .map(|(s, g)| (s, g & port_guard.clone())) + .collect(); + let (prevs, nxt) = calculate_states_recur( + body, + cur_state, + transitions, + schedule, + builder, + )?; // Step 3: The final out edges from the while come from: // - Before the body when the condition is false From 86d87974d5e6bd89991baa6481533b5d8c479424 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 09:06:42 +0530 Subject: [PATCH 15/50] Fix bug in tdcc FSM generation, implement dead-group-removal pass, and fix misc bugs in passes --- calyx/src/analysis/control_ports.rs | 2 +- calyx/src/analysis/live_range_analysis.rs | 57 ++++++++------- calyx/src/default_passes.rs | 13 ++-- calyx/src/ir/structure.rs | 2 +- calyx/src/passes/dead_cell_removal.rs | 13 +++- calyx/src/passes/dead_group_removal.rs | 73 ++++++++++++++++++++ calyx/src/passes/mod.rs | 6 +- calyx/src/passes/remove_comb_groups.rs | 11 ++- calyx/src/passes/top_down_compile_control.rs | 28 +++++++- 9 files changed, 165 insertions(+), 40 deletions(-) create mode 100644 calyx/src/passes/dead_group_removal.rs diff --git a/calyx/src/analysis/control_ports.rs b/calyx/src/analysis/control_ports.rs index 719c8fd29f..1a0fe3cc1a 100644 --- a/calyx/src/analysis/control_ports.rs +++ b/calyx/src/analysis/control_ports.rs @@ -73,7 +73,7 @@ impl From<&ir::Control> for ControlPorts { construct(con, &mut used_ports); // Deduplicate all vectors used_ports.values_mut().for_each(|v| { - *v = v.drain(..).unique_by(|p| p.borrow().name.clone()).collect() + *v = v.drain(..).unique_by(|p| p.borrow().canonical()).collect() }); ControlPorts { used_ports } } diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 9fee8eb601..6992e77596 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -60,6 +60,11 @@ impl Prop { fn transfer(self, gen: &Prop, kill: &Prop) -> Self { &(&self - kill) | gen } + + /// Add an element to Prop. + fn insert(&mut self, id: ir::Id) { + self.set.insert(id); + } } /// This analysis implements a parallel version of a classic liveness analysis. @@ -340,29 +345,29 @@ impl LiveRangeAnalysis { } } - fn find_gen_kill_invoke(invoke: &ir::Invoke) -> (Prop, Prop) { - let register_filter = |port: &RRC| { - if let ir::PortParent::Cell(cell_wref) = &port.borrow().parent { - cell_wref.upgrade().borrow().type_name() - == Some(&"std_reg".into()) - } else { - false + fn port_to_cell_name(port: &RRC) -> Option { + if let ir::PortParent::Cell(cell_wref) = &port.borrow().parent { + let cell = cell_wref.upgrade(); + if cell.borrow().type_name() == Some(&"std_reg".into()) { + return Some(cell.borrow().clone_name()); } - }; + } + None + } + /// Returns (reads, writes) that occur in the [ir::Invoke] statement. + fn find_gen_kill_invoke(invoke: &ir::Invoke) -> (Prop, Prop) { let reads: Prop = invoke .inputs .iter() - .filter(|(_, src)| register_filter(src)) - .map(|(_, src)| src.borrow().get_parent_name()) + .filter_map(|(_, src)| Self::port_to_cell_name(src)) .collect::>() .into(); let writes: Prop = invoke .outputs .iter() - .filter(|(_, src)| register_filter(src)) - .map(|(_, dest)| dest.borrow().get_parent_name()) + .filter_map(|(_, src)| Self::port_to_cell_name(src)) .collect::>() .into(); @@ -406,7 +411,10 @@ fn build_live_ranges( }, ), ir::Control::If(ir::If { - tbranch, fbranch, .. + tbranch, + fbranch, + port, + .. }) => { // compute each branch let (t_alive, t_gens, t_kills) = build_live_ranges( @@ -421,11 +429,14 @@ fn build_live_ranges( // take union let alive = &t_alive | &f_alive; - let gens = &t_gens | &f_gens; + let mut gens = &t_gens | &f_gens; let kills = &t_kills | &f_kills; // feed to condition to compute - build_live_ranges(&ir::Control::empty(), alive, gens, kills, lr) + if let Some(cell) = LiveRangeAnalysis::port_to_cell_name(port) { + gens.insert(cell) + } + (alive, gens, kills) } ir::Control::Par(ir::Par { stmts, .. }) => { let (alive, gens, kills) = stmts @@ -454,17 +465,13 @@ fn build_live_ranges( let alive = alive.transfer(&gens, &kills); (alive, gens, kills) } - ir::Control::While(ir::While { body, .. }) => { - let (alive, gens, kills) = + ir::Control::While(ir::While { body, port, .. }) => { + let (alive, mut gens, kills) = build_live_ranges(body, alive, gens, kills, lr); - let (alive, gens, kills) = build_live_ranges( - &ir::Control::empty(), - alive, - gens, - kills, - lr, - ); - build_live_ranges(body, alive, gens, kills, lr) + if let Some(cell) = LiveRangeAnalysis::port_to_cell_name(port) { + gens.insert(cell) + } + build_live_ranges(body, alive, dbg!(gens), kills, lr) } } } diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index d97437700a..40f7fd272d 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -1,11 +1,11 @@ //! Defines the default passes available to [PassManager]. use crate::passes::{ ClkInsertion, CollapseControl, CompileEmpty, CompileInvoke, - ComponentInterface, DeadCellRemoval, Externalize, GoInsertion, - GuardCanonical, InferStaticTiming, Inliner, MergeAssign, MinimizeRegs, - Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, ResetInsertion, - ResourceSharing, SimplifyGuards, SynthesisPapercut, TopDownCompileControl, - TopDownStaticTiming, WellFormed, + ComponentInterface, DeadCellRemoval, DeadGroupRemoval, Externalize, + GoInsertion, GuardCanonical, InferStaticTiming, Inliner, MergeAssign, + MinimizeRegs, Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, + ResetInsertion, ResourceSharing, SimplifyGuards, SynthesisPapercut, + TopDownCompileControl, WellFormed, }; use crate::{ errors::CalyxResult, ir::traversal::Named, pass_manager::PassManager, @@ -33,12 +33,13 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; + pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; - pm.register_pass::()?; + // pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; diff --git a/calyx/src/ir/structure.rs b/calyx/src/ir/structure.rs index bd56af6673..03ba84662b 100644 --- a/calyx/src/ir/structure.rs +++ b/calyx/src/ir/structure.rs @@ -155,7 +155,7 @@ pub struct Cell { /// Underlying type for this cell pub prototype: CellType, /// Attributes for this group. - pub(super) attributes: Attributes, + pub attributes: Attributes, } impl GetAttributes for Cell { diff --git a/calyx/src/passes/dead_cell_removal.rs b/calyx/src/passes/dead_cell_removal.rs index 236414b758..847cf02b27 100644 --- a/calyx/src/passes/dead_cell_removal.rs +++ b/calyx/src/passes/dead_cell_removal.rs @@ -58,6 +58,12 @@ impl Visitor for DeadCellRemoval { .map(|c| c.clone_name()), ) } + for cg in comp.comb_groups.iter() { + self.used_cells.extend( + &mut analysis::ReadWriteSet::uses(&cg.borrow().assignments) + .map(|c| c.clone_name()), + ) + } // All cells used in continuous assignments. self.used_cells.extend( @@ -66,8 +72,11 @@ impl Visitor for DeadCellRemoval { ); // Remove cells that are not used. - comp.cells - .retain(|c| self.used_cells.contains(c.borrow().name())); + comp.cells.retain(|c| { + let cell = c.borrow(); + cell.attributes.has("external") + || self.used_cells.contains(cell.name()) + }); Ok(Action::Stop) } diff --git a/calyx/src/passes/dead_group_removal.rs b/calyx/src/passes/dead_group_removal.rs new file mode 100644 index 0000000000..f23422280c --- /dev/null +++ b/calyx/src/passes/dead_group_removal.rs @@ -0,0 +1,73 @@ +use crate::ir::{ + self, + traversal::{Action, Named, VisResult, Visitor}, + CloneName, LibrarySignatures, +}; +use std::collections::HashSet; + +/// Removes unused cells from components. +#[derive(Default)] +pub struct DeadGroupRemoval { + used_groups: HashSet, + used_comb_groups: HashSet, +} + +impl Named for DeadGroupRemoval { + fn name() -> &'static str { + "dead-group-removal" + } + + fn description() -> &'static str { + "removes unsed groups from components" + } +} + +impl Visitor for DeadGroupRemoval { + fn enable( + &mut self, + s: &mut ir::Enable, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + ) -> VisResult { + self.used_groups.insert(s.group.borrow().clone_name()); + Ok(Action::Continue) + } + + fn finish_if( + &mut self, + s: &mut ir::If, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + ) -> VisResult { + if let Some(cg) = &s.cond { + self.used_comb_groups.insert(cg.borrow().clone_name()); + } + Ok(Action::Continue) + } + + fn finish_while( + &mut self, + s: &mut ir::While, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + ) -> VisResult { + if let Some(cg) = &s.cond { + self.used_comb_groups.insert(cg.borrow().clone_name()); + } + Ok(Action::Continue) + } + + fn finish( + &mut self, + comp: &mut ir::Component, + _sigs: &LibrarySignatures, + ) -> VisResult { + // Remove Groups that are not used + comp.groups + .retain(|g| self.used_groups.contains(g.borrow().name())); + comp.comb_groups + .retain(|cg| self.used_comb_groups.contains(cg.borrow().name())); + + Ok(Action::Stop) + } +} diff --git a/calyx/src/passes/mod.rs b/calyx/src/passes/mod.rs index effc5a90af..f2892fbeaa 100644 --- a/calyx/src/passes/mod.rs +++ b/calyx/src/passes/mod.rs @@ -6,6 +6,7 @@ mod compile_empty; mod compile_invoke; mod component_interface; mod dead_cell_removal; +mod dead_group_removal; mod externalize; mod go_insertion; mod guard_canonical; @@ -25,7 +26,7 @@ mod simplify_guards; // mod static_timing; mod synthesis_papercut; mod top_down_compile_control; -mod top_down_static_timing; +// mod top_down_static_timing; mod well_formed; pub use clk_insertion::ClkInsertion; @@ -35,6 +36,7 @@ pub use compile_empty::CompileEmpty; pub use compile_invoke::CompileInvoke; pub use component_interface::ComponentInterface; pub use dead_cell_removal::DeadCellRemoval; +pub use dead_group_removal::DeadGroupRemoval; pub use externalize::Externalize; pub use go_insertion::GoInsertion; pub use guard_canonical::GuardCanonical; @@ -52,5 +54,5 @@ pub use simplify_guards::SimplifyGuards; // pub use static_timing::StaticTiming; pub use synthesis_papercut::SynthesisPapercut; pub use top_down_compile_control::TopDownCompileControl; -pub use top_down_static_timing::TopDownStaticTiming; +// pub use top_down_static_timing::TopDownStaticTiming; pub use well_formed::WellFormed; diff --git a/calyx/src/passes/remove_comb_groups.rs b/calyx/src/passes/remove_comb_groups.rs index 6e09065e06..2df372418f 100644 --- a/calyx/src/passes/remove_comb_groups.rs +++ b/calyx/src/passes/remove_comb_groups.rs @@ -241,7 +241,16 @@ impl Visitor for RemoveCombGroups { s.cond.as_ref().unwrap().borrow().name().clone(), s.port.borrow().canonical(), ); - let (port_ref, cond_ref) = self.port_rewrite.get(&key).unwrap(); + let (port_ref, cond_ref) = + self.port_rewrite.get(&key).unwrap_or_else(|| { + panic!( + "{}: Port `{}.{}` in group `{}` doesn't have a rewrite", + Self::name(), + key.1 .0, + key.1 .1, + key.0 + ) + }); let port = Rc::clone(port_ref); // Add @stable annotation to port port.borrow_mut().attributes.insert("stable", 1); diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index 737f44cc01..d9af3ae760 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -22,6 +22,8 @@ struct Schedule { pub enables: HashMap>, /// Transition from one state to another when the guard is true. pub transitions: Vec<(u64, u64, ir::Guard)>, + /// Assignments that are always active + pub always_active: Vec, } impl Schedule { @@ -73,7 +75,13 @@ impl Schedule { .sorted_by(|(k1, _, _), (k2, _, _)| k1.cmp(k2)) .for_each(|(i, f, g)| { eprintln!("({}, {}): {}", i, f, IRPrinter::guard_str(g)); - }) + }); + eprintln!("-----Always Active-----"); + self.always_active.iter().for_each(|assign| { + IRPrinter::write_assignment(assign, 0, &mut std::io::stderr()) + .expect("Printing failed!"); + eprintln!(); + }) } /// Implement a given [Schedule] and return the name of the [ir::Group] that @@ -136,6 +144,12 @@ impl Schedule { }), ); + // Always active assignments + group + .borrow_mut() + .assignments + .extend(self.always_active.into_iter()); + // Done condition for group let last_guard = guard!(fsm["out"]).eq(guard!(last_state["out"])); let done_assign = builder.build_assignment( @@ -252,6 +266,8 @@ fn calculate_states_recur( ir::Control::Enable(ir::Enable { group, .. }) => { let not_done = !guard!(group["done"]); let signal_on = builder.add_constant(1, 1); + + // Activate this group in the current state let mut en_go = build_assignments!(builder; group["go"] = not_done ? signal_on["out"]; ); @@ -261,6 +277,14 @@ fn calculate_states_recur( .or_default() .append(&mut en_go); + // Activate group when each previous states are done. + for (st, g) in &prev_states { + let mut early_go = build_assignments!(builder; + group["go"] = g ? signal_on["out"]; + ); + schedule.enables.entry(*st).or_default().append(&mut early_go); + } + let transitions = prev_states .into_iter() .map(|(st, guard)| (st, cur_state, guard)); @@ -427,7 +451,7 @@ pub struct TopDownCompileControl; impl Named for TopDownCompileControl { fn name() -> &'static str { - "top-down-cc" + "tdcc" } fn description() -> &'static str { From ac961dca3a7006b2cccc59486a8d427c0ce718be Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 09:07:59 +0530 Subject: [PATCH 16/50] add CombGroup to calyx-py and fix frontends to generate comb groups --- calyx-py/calyx/gen_exp.py | 103 ++++++++++++++------- calyx-py/calyx/py_ast.py | 16 +++- frontends/ntt-pipeline/gen-ntt-pipeline.py | 57 +++++++----- 3 files changed, 116 insertions(+), 60 deletions(-) diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index 6e9cbbab39..2f1dbf8078 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -1,11 +1,17 @@ -from calyx.py_ast import * +from calyx.py_ast import ( + Connect, CompVar, Cell, Group, ConstantPort, CompPort, Stdlib, + Component, ThisPort, And, HolePort, Atom, Not, PortDef, SeqComp, + Enable, While, ParComp, Structure, CompInst, Invoke, Program, Control, + If, Import, CombGroup +) from calyx.utils import float_to_fixed_point from math import factorial, log2 from typing import List from fud.stages.verilator import numeric_types -def generate_fp_pow_component(width: int, int_width: int, is_signed: bool) -> Component: +def generate_fp_pow_component( + width: int, int_width: int, is_signed: bool) -> Component: """Generates a fixed point `pow` component, which computes the value x**y, where y must be an integer. """ @@ -87,12 +93,12 @@ def generate_fp_pow_component(width: int, int_width: int, is_signed: bool) -> Co ), ], ), - Group( + CombGroup( id=CompVar("cond"), connections=[ Connect(CompPort(count, "out"), CompPort(lt, "left")), - Connect(ThisPort(CompVar("integer_exp")), CompPort(lt, "right")), - Connect(ConstantPort(1, 1), HolePort(CompVar("cond"), "done")), + Connect(ThisPort(CompVar("integer_exp")), + CompPort(lt, "right")), ], ), Connect(CompPort(CompVar("pow"), "out"), ThisPort(CompVar("out"))), @@ -117,6 +123,7 @@ def generate_fp_pow_component(width: int, int_width: int, is_signed: bool) -> Co ), ) + def generate_cells( degree: int, width: int, int_width: int, is_signed: bool ) -> List[Cell]: @@ -137,7 +144,10 @@ def generate_cells( ) pow_registers = [ - Cell(CompVar(f"p{i}"), stdlib.register(width)) for i in range(2, degree + 1) + Cell( + CompVar(f"p{i}"), + stdlib.register(width) + ) for i in range(2, degree + 1) ] product_registers = [ Cell(CompVar(f"product{i}"), stdlib.register(width)) @@ -167,20 +177,26 @@ def generate_cells( ] # One extra `fp_pow` instance to compute e^{int_value}. pows = [ - Cell(CompVar(f"pow{i}"), CompInst("fp_pow", [])) for i in range(1, degree + 1) + Cell( + CompVar(f"pow{i}"), CompInst("fp_pow", []) + ) for i in range(1, degree + 1) ] reciprocal_factorials = [] for i in range(2, degree + 1): - fixed_point_value = float_to_fixed_point(1.0 / factorial(i), frac_width) + fixed_point_value = float_to_fixed_point( + 1.0 / factorial(i), frac_width) value = numeric_types.FixedPoint( str(fixed_point_value), width, int_width, is_signed=is_signed ).unsigned_integer() reciprocal_factorials.append( - Cell(CompVar(f"reciprocal_factorial{i}"), stdlib.constant(width, value)) + Cell(CompVar(f"reciprocal_factorial{i}"), stdlib.constant( + width, value)) ) # Constant values for the exponent to the fixed point `pow` function. constants = [ - Cell(CompVar(f"c{i}"), stdlib.constant(width, i)) for i in range(2, degree + 1) + Cell( + CompVar(f"c{i}"), stdlib.constant(width, i) + ) for i in range(2, degree + 1) ] + [ Cell( CompVar("one"), @@ -218,7 +234,7 @@ def generate_cells( ) pipes.append( Cell( - CompVar(f"div_pipe"), + CompVar("div_pipe"), stdlib.fixed_point_op( "div_pipe", width, int_width, frac_width, signed=is_signed ), @@ -277,7 +293,8 @@ def divide_and_conquer_sums(degree: int) -> List[Structure]: reg_rhs = CompVar(f"{register_name}{rhs}") sum = CompVar(f"sum{i + 1}") - # In the first round and first group, we add the 1st degree, the value `x` itself. + # In the first round and first group, we add the 1st degree, the + # value `x` itself. lhs = ( CompPort(CompVar("frac_x"), "out") if round == 1 and i == 0 @@ -296,7 +313,7 @@ def divide_and_conquer_sums(degree: int) -> List[Structure]: # Sums the 0th degree value, 1, and the final # sum of the divide-and-conquer. - group_name = CompVar(f"add_degree_zero") + group_name = CompVar("add_degree_zero") adder = CompVar("add1") reg = CompVar("sum1") groups.append( @@ -329,7 +346,8 @@ def generate_groups( connections=[ Connect(ConstantPort(1, 1), CompPort(input, "write_en")), Connect(ThisPort(CompVar("x")), CompPort(input, "in")), - Connect(CompPort(input, "done"), HolePort(CompVar("init"), "done")), + Connect(CompPort(input, "done"), + HolePort(CompVar("init"), "done")), ], static_delay=1, ) @@ -349,13 +367,16 @@ def generate_groups( CompPort(mult_pipe, "go"), Not(Atom(CompPort(mult_pipe, "done"))), ), - Connect(CompPort(mult_pipe, "done"), CompPort(input, "write_en")), + Connect(CompPort(mult_pipe, "done"), + CompPort(input, "write_en")), Connect(CompPort(mult_pipe, "out"), CompPort(input, "in")), - Connect(CompPort(input, "done"), HolePort(CompVar("negate"), "done")), + Connect(CompPort(input, "done"), HolePort( + CompVar("negate"), "done")), ], ) - # Initialization: split up the value `x` into its integer and fractional values. + # Initialization: split up the value `x` into its integer and fractional + # values. split_bits = Group( id=CompVar("split_bits"), connections=[ @@ -440,7 +461,8 @@ def multiply_by_reciprocal_factorial(i: int) -> Group: CompPort(mult_pipe, "go"), Not(Atom(CompPort(mult_pipe, "done"))), ), - Connect(CompPort(mult_pipe, "done"), CompPort(product, "write_en")), + Connect(CompPort(mult_pipe, "done"), + CompPort(product, "write_en")), Connect(CompPort(mult_pipe, "out"), CompPort(product, "in")), Connect(CompPort(product, "done"), HolePort(group_name, "done")), ] @@ -469,9 +491,11 @@ def final_multiply(register_id: CompVar) -> List[Group]: CompPort(mult_pipe, "go"), Not(Atom(CompPort(mult_pipe, "done"))), ), - Connect(CompPort(mult_pipe, "done"), CompPort(reg, "write_en")), + Connect(CompPort(mult_pipe, "done"), + CompPort(reg, "write_en")), Connect(CompPort(mult_pipe, "out"), CompPort(reg, "in")), - Connect(CompPort(reg, "done"), HolePort(group_name, "done")), + Connect(CompPort(reg, "done"), + HolePort(group_name, "done")), ], ) ] @@ -483,28 +507,32 @@ def final_multiply(register_id: CompVar) -> List[Group]: reciprocal = Group( id=CompVar("reciprocal"), connections=[ - Connect(CompPort(CompVar("one"), "out"), CompPort(div_pipe, "left")), + Connect(CompPort(CompVar("one"), "out"), + CompPort(div_pipe, "left")), Connect(CompPort(input, "out"), CompPort(div_pipe, "right")), Connect( ConstantPort(1, 1), CompPort(div_pipe, "go"), Not(Atom(CompPort(div_pipe, "done"))), ), - Connect(CompPort(div_pipe, "done"), CompPort(input, "write_en")), - Connect(CompPort(div_pipe, "out_quotient"), CompPort(input, "in")), + Connect(CompPort(div_pipe, "done"), + CompPort(input, "write_en")), + Connect(CompPort(div_pipe, "out_quotient"), + CompPort(input, "in")), Connect( - CompPort(input, "done"), HolePort(CompVar("reciprocal"), "done") + CompPort(input, "done"), HolePort( + CompVar("reciprocal"), "done") ), ], ) - is_negative = Group( + is_negative = CombGroup( id=CompVar("is_negative"), connections=[ - Connect(ThisPort(CompVar("x")), CompPort(CompVar("lt"), "left")), - Connect(ConstantPort(width, 0), CompPort(CompVar("lt"), "right")), - Connect(ConstantPort(1, 1), HolePort(CompVar("is_negative"), "done")), - ], - static_delay=0, + Connect(ThisPort(CompVar("x")), + CompPort(CompVar("lt"), "left")), + Connect(ConstantPort(width, 0), + CompPort(CompVar("lt"), "right")), + ] ) # Connect final value to the `out` signal of the component. @@ -547,10 +575,12 @@ def generate_control(degree: int, is_signed: bool) -> Control: ] ) ] - consume_pow = [ParComp([Enable(f"consume_pow{i}") for i in range(2, degree + 1)])] + consume_pow = [ + ParComp([Enable(f"consume_pow{i}") for i in range(2, degree + 1)])] mult_by_reciprocal = [ ParComp( - [Enable(f"mult_by_reciprocal_factorial{i}") for i in range(2, degree + 1)] + [Enable(f"mult_by_reciprocal_factorial{i}") + for i in range(2, degree + 1)] ) ] @@ -558,7 +588,8 @@ def generate_control(degree: int, is_signed: bool) -> Control: Enable_count = degree >> 1 for r in range(1, int(log2(degree) + 1)): divide_and_conquer.append( - ParComp([Enable(f"sum_round{r}_{i}") for i in range(1, Enable_count + 1)]) + ParComp([Enable(f"sum_round{r}_{i}") + for i in range(1, Enable_count + 1)]) ) Enable_count >>= 1 @@ -631,7 +662,8 @@ def generate_exp_taylor_series_approximation( if __name__ == "__main__": - import argparse, json + import argparse + import json parser = argparse.ArgumentParser( description="`exp` using a Taylor Series approximation" @@ -677,7 +709,8 @@ def generate_exp_taylor_series_approximation( outputs=[], structs=[ Cell(CompVar("t"), Stdlib().register(width)), - Cell(CompVar("x"), Stdlib().mem_d1(width, 1, 1), is_external=True), + Cell(CompVar("x"), Stdlib().mem_d1( + width, 1, 1), is_external=True), Cell( CompVar("ret"), Stdlib().mem_d1(width, 1, 1), diff --git a/calyx-py/calyx/py_ast.py b/calyx-py/calyx/py_ast.py index 244fb6968a..09f997495e 100644 --- a/calyx-py/calyx/py_ast.py +++ b/calyx-py/calyx/py_ast.py @@ -166,7 +166,7 @@ class Connect(Structure): def doc(self) -> str: source = ( self.src.doc() - if self.guard == None + if self.guard is None else f"{self.guard.doc()} ? {self.src.doc()}" ) return f"{self.dest.doc()} = {source};" @@ -180,7 +180,7 @@ class Group(Structure): def doc(self) -> str: static_delay_attr = ( - "" if self.static_delay == None else f'<"static"={self.static_delay}>' + "" if self.static_delay is None else f'<"static"={self.static_delay}>' ) return block( f"group {self.id.doc()}{static_delay_attr}", @@ -188,6 +188,18 @@ def doc(self) -> str: ) +@dataclass +class CombGroup(Structure): + id: CompVar + connections: list[Connect] + + def doc(self) -> str: + return block( + f"comb group {self.id.doc()}", + [c.doc() for c in self.connections], + ) + + @dataclass class CompInst(Emittable): id: str diff --git a/frontends/ntt-pipeline/gen-ntt-pipeline.py b/frontends/ntt-pipeline/gen-ntt-pipeline.py index 4f17ad5082..94801c14f9 100644 --- a/frontends/ntt-pipeline/gen-ntt-pipeline.py +++ b/frontends/ntt-pipeline/gen-ntt-pipeline.py @@ -1,6 +1,9 @@ from prettytable import PrettyTable import numpy as np -from calyx.py_ast import * +from calyx.py_ast import ( + ParComp, SeqComp, Enable, CompVar, Connect, Atom, Not, Group, HolePort, + Component, Program, CompPort, Cell, ConstantPort, And, Import, Stdlib +) from calyx.utils import bits_needed @@ -133,7 +136,8 @@ def generate_ntt_pipeline(input_bitwidth: int, n: int, q: int): Reference: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/05/RLWE-1.pdf """ - assert n > 0 and (not (n & (n - 1))), f"Input length: {n} must be a power of 2." + assert n > 0 and ( + not (n & (n - 1))), f"Input length: {n} must be a power of 2." bitwidth = bits_needed(n) num_stages = bitwidth - 1 @@ -198,7 +202,8 @@ def op_mod_group(stage, row, operations_tuple): Connect(CompPort(reg, "out"), CompPort(op, "left")), Connect(CompPort(mul, "out"), CompPort(op, "right")), Connect(CompPort(op, "out"), CompPort(mod_pipe, "left")), - Connect(ConstantPort(input_bitwidth, q), CompPort(mod_pipe, "right")), + Connect(ConstantPort(input_bitwidth, q), + CompPort(mod_pipe, "right")), Connect( ConstantPort(1, 1), CompPort(mod_pipe, "go"), @@ -255,12 +260,12 @@ def cells(): stdlib = Stdlib() memories = [ - Cell(input, stdlib.mem_d1(input_bitwidth, n, bitwidth), is_external=True), - Cell(phis, stdlib.mem_d1(input_bitwidth, n, bitwidth), is_external=True), + Cell(input, stdlib.mem_d1(input_bitwidth, + n, bitwidth), is_external=True), + Cell(phis, stdlib.mem_d1(input_bitwidth, + n, bitwidth), is_external=True), ] r_regs = [ - Cell(CompVar(f"r{r}"), stdlib.register(input_bitwidth)) for r in range(n) - ] A_regs = [ Cell(CompVar(f"A{r}"), stdlib.register(input_bitwidth)) for r in range(n) ] @@ -286,11 +291,13 @@ def cells(): for i in range(n // 2) ] adds = [ - Cell(CompVar(f"add{i}"), stdlib.op("add", input_bitwidth, signed=True)) + Cell(CompVar(f"add{i}"), stdlib.op( + "add", input_bitwidth, signed=True)) for i in range(n // 2) ] subs = [ - Cell(CompVar(f"sub{i}"), stdlib.op("sub", input_bitwidth, signed=True)) + Cell(CompVar(f"sub{i}"), stdlib.op( + "sub", input_bitwidth, signed=True)) for i in range(n // 2) ] @@ -330,11 +337,14 @@ def control(): for s in range(num_stages): if s != 0: # Only append precursors if this is not the first stage. - ntt_stages.append(ParComp([Enable(f"precursor_{r}") for r in range(n)])) + ntt_stages.append( + ParComp([Enable(f"precursor_{r}") for r in range(n)])) # Multiply - ntt_stages.append(ParComp([Enable(f"s{s}_mul{i}") for i in range(n // 2)])) + ntt_stages.append( + ParComp([Enable(f"s{s}_mul{i}") for i in range(n // 2)])) # Addition or subtraction mod `q` - ntt_stages.append(ParComp([Enable(f"s{s}_r{r}_op_mod") for r in range(n)])) + ntt_stages.append( + ParComp([Enable(f"s{s}_r{r}_op_mod") for r in range(n)])) return SeqComp(preambles + ntt_stages + epilogues) pp_table(operations, multiplies, n, num_stages) @@ -353,7 +363,8 @@ def control(): if __name__ == "__main__": - import argparse, json + import argparse + import json parser = argparse.ArgumentParser(description="NTT") parser.add_argument("file", nargs="?", type=str) @@ -367,23 +378,23 @@ def control(): input_bitwidth, input_size, modulus = None, None, None required_fields = [args.input_bitwidth, args.input_size, args.modulus] if all(map(lambda x: x is not None, required_fields)): - input_bitwidth = args.input_bitwidth - input_size = args.input_size - modulus = args.modulus - parallel_reduction = args.parallel_reduction + input_bitwidth=args.input_bitwidth + input_size=args.input_size + modulus=args.modulus + parallel_reduction=args.parallel_reduction elif args.file is not None: with open(args.file, "r") as f: - spec = json.load(f) - input_bitwidth = spec["input_bitwidth"] - input_size = spec["input_size"] - modulus = spec["modulus"] - parallel_reduction = spec.get("parallel_reduction") + spec=json.load(f) + input_bitwidth=spec["input_bitwidth"] + input_size=spec["input_size"] + modulus=spec["modulus"] + parallel_reduction=spec.get("parallel_reduction") else: parser.error( "Need to pass either `-f FILE` or all of `-b INPUT_BITWIDTH -n INPUT_SIZE -q MODULUS`" ) - program = generate_ntt_pipeline(input_bitwidth, input_size, modulus) + program=generate_ntt_pipeline(input_bitwidth, input_size, modulus) if parallel_reduction is not None: for c in program.components: From e66c77e58fba935000392c1ff07477e66753b73a Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 09:09:36 +0530 Subject: [PATCH 17/50] remove generated calyx files for exp frontend --- .gitignore | 2 + .../correctness/exp/degree-4-signed.txt.futil | 274 ------------ .../exp/degree-4-unsigned.txt.futil | 244 ----------- .../correctness/exp/degree-8-signed.txt.futil | 400 ------------------ .../exp/degree-8-unsigned.txt.futil | 370 ---------------- .../ntt-pipeline/ntt-16-reduced-4.txt.futil | 0 .../correctness/ntt-pipeline/ntt-16.txt.futil | 0 .../correctness/ntt-pipeline/ntt-8.txt.futil | 0 8 files changed, 2 insertions(+), 1288 deletions(-) delete mode 100644 tests/correctness/exp/degree-4-signed.txt.futil delete mode 100644 tests/correctness/exp/degree-4-unsigned.txt.futil delete mode 100644 tests/correctness/exp/degree-8-signed.txt.futil delete mode 100644 tests/correctness/exp/degree-8-unsigned.txt.futil delete mode 100644 tests/correctness/ntt-pipeline/ntt-16-reduced-4.txt.futil delete mode 100644 tests/correctness/ntt-pipeline/ntt-16.txt.futil delete mode 100644 tests/correctness/ntt-pipeline/ntt-8.txt.futil diff --git a/.gitignore b/.gitignore index 46e0753dc2..318bdd65c6 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ __pycache__ !.vscode/settings.json !.vscode/launch.json !.vscode/tasks.json + +./tests/correctness/exp/*.futil diff --git a/tests/correctness/exp/degree-4-signed.txt.futil b/tests/correctness/exp/degree-4-signed.txt.futil deleted file mode 100644 index 27748a283c..0000000000 --- a/tests/correctness/exp/degree-4-signed.txt.futil +++ /dev/null @@ -1,274 +0,0 @@ -import "primitives/std.lib"; -component exp(x: 32) -> (out: 32) { - cells { - exponent_value = std_reg(32); - int_x = std_reg(32); - frac_x = std_reg(32); - m = std_reg(32); - and0 = std_and(32); - and1 = std_and(32); - rsh = std_rsh(32); - lt = std_slt(32); - c2 = std_const(32, 2); - c3 = std_const(32, 3); - c4 = std_const(32, 4); - one = std_const(32, 65536); - e = std_const(32, 178145); - negative_one = std_const(32, 4294901760); - product2 = std_reg(32); - product3 = std_reg(32); - product4 = std_reg(32); - p2 = std_reg(32); - p3 = std_reg(32); - p4 = std_reg(32); - sum1 = std_reg(32); - sum2 = std_reg(32); - add1 = std_fp_sadd(32, 16, 16); - add2 = std_fp_sadd(32, 16, 16); - mult_pipe1 = std_fp_smult_pipe(32, 16, 16); - mult_pipe2 = std_fp_smult_pipe(32, 16, 16); - mult_pipe3 = std_fp_smult_pipe(32, 16, 16); - mult_pipe4 = std_fp_smult_pipe(32, 16, 16); - div_pipe = std_fp_sdiv_pipe(32, 16, 16); - reciprocal_factorial2 = std_const(32, 32768); - reciprocal_factorial3 = std_const(32, 10923); - reciprocal_factorial4 = std_const(32, 2731); - pow1 = fp_pow(); - pow2 = fp_pow(); - pow3 = fp_pow(); - pow4 = fp_pow(); - } - wires { - group init<"static"=1> { - exponent_value.write_en = 1'd1; - exponent_value.in = x; - init[done] = exponent_value.done; - } - group split_bits { - and0.left = exponent_value.out; - and0.right = 32'd4294901760; - rsh.left = and0.out; - rsh.right = 32'd16; - and1.left = exponent_value.out; - and1.right = 32'd65535; - int_x.write_en = 1'd1; - frac_x.write_en = 1'd1; - int_x.in = rsh.out; - frac_x.in = and1.out; - split_bits[done] = int_x.done & frac_x.done ? 1'd1; - } - group negate { - mult_pipe1.left = exponent_value.out; - mult_pipe1.right = negative_one.out; - mult_pipe1.go = !mult_pipe1.done ? 1'd1; - exponent_value.write_en = mult_pipe1.done; - exponent_value.in = mult_pipe1.out; - negate[done] = exponent_value.done; - } - group is_negative<"static"=0> { - lt.left = x; - lt.right = 32'd0; - is_negative[done] = 1'd1; - } - group reciprocal { - div_pipe.left = one.out; - div_pipe.right = m.out; - div_pipe.go = !div_pipe.done ? 1'd1; - m.write_en = div_pipe.done; - m.in = div_pipe.out_quotient; - reciprocal[done] = m.done; - } - group consume_pow2<"static"=1> { - p2.write_en = 1'd1; - p2.in = pow2.out; - consume_pow2[done] = p2.done ? 1'd1; - } - group consume_pow3<"static"=1> { - p3.write_en = 1'd1; - p3.in = pow3.out; - consume_pow3[done] = p3.done ? 1'd1; - } - group consume_pow4<"static"=1> { - p4.write_en = 1'd1; - p4.in = pow4.out; - consume_pow4[done] = p4.done ? 1'd1; - } - group mult_by_reciprocal_factorial2 { - mult_pipe2.left = p2.out; - mult_pipe2.right = reciprocal_factorial2.out; - mult_pipe2.go = !mult_pipe2.done ? 1'd1; - product2.write_en = mult_pipe2.done; - product2.in = mult_pipe2.out; - mult_by_reciprocal_factorial2[done] = product2.done; - } - group mult_by_reciprocal_factorial3 { - mult_pipe3.left = p3.out; - mult_pipe3.right = reciprocal_factorial3.out; - mult_pipe3.go = !mult_pipe3.done ? 1'd1; - product3.write_en = mult_pipe3.done; - product3.in = mult_pipe3.out; - mult_by_reciprocal_factorial3[done] = product3.done; - } - group mult_by_reciprocal_factorial4 { - mult_pipe4.left = p4.out; - mult_pipe4.right = reciprocal_factorial4.out; - mult_pipe4.go = !mult_pipe4.done ? 1'd1; - product4.write_en = mult_pipe4.done; - product4.in = mult_pipe4.out; - mult_by_reciprocal_factorial4[done] = product4.done; - } - group sum_round1_1<"static"=1> { - add1.left = frac_x.out; - add1.right = product2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round1_1[done] = sum1.done; - } - group sum_round1_2<"static"=1> { - add2.left = product3.out; - add2.right = product4.out; - sum2.write_en = 1'd1; - sum2.in = add2.out; - sum_round1_2[done] = sum2.done; - } - group sum_round2_1<"static"=1> { - add1.left = sum1.out; - add1.right = sum2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round2_1[done] = sum1.done; - } - group add_degree_zero<"static"=1> { - add1.left = sum1.out; - add1.right = one.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - add_degree_zero[done] = sum1.done; - } - group final_multiply { - mult_pipe1.left = pow1.out; - mult_pipe1.right = sum1.out; - mult_pipe1.go = !mult_pipe1.done ? 1'd1; - m.write_en = mult_pipe1.done; - m.in = mult_pipe1.out; - final_multiply[done] = m.done; - } - out = m.out; - } - control { - seq { - init; - if lt.out with is_negative { - negate; - } - split_bits; - par { - invoke pow1(base=e.out, integer_exp=int_x.out)(); - invoke pow2(base=frac_x.out, integer_exp=c2.out)(); - invoke pow3(base=frac_x.out, integer_exp=c3.out)(); - invoke pow4(base=frac_x.out, integer_exp=c4.out)(); - } - par { - consume_pow2; - consume_pow3; - consume_pow4; - } - par { - mult_by_reciprocal_factorial2; - mult_by_reciprocal_factorial3; - mult_by_reciprocal_factorial4; - } - par { - sum_round1_1; - sum_round1_2; - } - par { - sum_round2_1; - } - add_degree_zero; - final_multiply; - if lt.out with is_negative { - reciprocal; - } - } - } -} -component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { - cells { - pow = std_reg(32); - count = std_reg(32); - mul = std_fp_smult_pipe(32, 16, 16); - lt = std_slt(32); - incr = std_sadd(32); - } - wires { - group init { - pow.in = 32'd65536; - pow.write_en = 1'd1; - count.in = 32'd0; - count.write_en = 1'd1; - init[done] = pow.done & count.done ? 1'd1; - } - group execute_mul { - mul.left = base; - mul.right = pow.out; - mul.go = !mul.done ? 1'd1; - pow.write_en = mul.done; - pow.in = mul.out; - execute_mul[done] = pow.done; - } - group incr_count { - incr.left = 32'd1; - incr.right = count.out; - count.in = incr.out; - count.write_en = 1'd1; - incr_count[done] = count.done; - } - group cond { - lt.left = count.out; - lt.right = integer_exp; - cond[done] = 1'd1; - } - out = pow.out; - } - control { - seq { - init; - while lt.out with cond { - par { - execute_mul; - incr_count; - } - } - } - } -} -component main() -> () { - cells { - t = std_reg(32); - @external(1) x = std_mem_d1(32, 1, 1); - @external(1) ret = std_mem_d1(32, 1, 1); - e = exp(); - } - wires { - group init { - x.addr0 = 1'd0; - t.in = x.read_data; - t.write_en = 1'd1; - init[done] = t.done; - } - group write_to_memory { - ret.addr0 = 1'd0; - ret.write_en = 1'd1; - ret.write_data = e.out; - write_to_memory[done] = ret.done; - } - } - control { - seq { - init; - invoke e(x=t.out)(); - write_to_memory; - } - } -} diff --git a/tests/correctness/exp/degree-4-unsigned.txt.futil b/tests/correctness/exp/degree-4-unsigned.txt.futil deleted file mode 100644 index 92147e8c38..0000000000 --- a/tests/correctness/exp/degree-4-unsigned.txt.futil +++ /dev/null @@ -1,244 +0,0 @@ -import "primitives/std.lib"; -component exp(x: 32) -> (out: 32) { - cells { - exponent_value = std_reg(32); - int_x = std_reg(32); - frac_x = std_reg(32); - m = std_reg(32); - and0 = std_and(32); - and1 = std_and(32); - rsh = std_rsh(32); - c2 = std_const(32, 2); - c3 = std_const(32, 3); - c4 = std_const(32, 4); - one = std_const(32, 65536); - e = std_const(32, 178145); - product2 = std_reg(32); - product3 = std_reg(32); - product4 = std_reg(32); - p2 = std_reg(32); - p3 = std_reg(32); - p4 = std_reg(32); - sum1 = std_reg(32); - sum2 = std_reg(32); - add1 = std_fp_add(32, 16, 16); - add2 = std_fp_add(32, 16, 16); - mult_pipe1 = std_fp_mult_pipe(32, 16, 16); - mult_pipe2 = std_fp_mult_pipe(32, 16, 16); - mult_pipe3 = std_fp_mult_pipe(32, 16, 16); - mult_pipe4 = std_fp_mult_pipe(32, 16, 16); - reciprocal_factorial2 = std_const(32, 32768); - reciprocal_factorial3 = std_const(32, 10923); - reciprocal_factorial4 = std_const(32, 2731); - pow1 = fp_pow(); - pow2 = fp_pow(); - pow3 = fp_pow(); - pow4 = fp_pow(); - } - wires { - group init<"static"=1> { - exponent_value.write_en = 1'd1; - exponent_value.in = x; - init[done] = exponent_value.done; - } - group split_bits { - and0.left = exponent_value.out; - and0.right = 32'd4294901760; - rsh.left = and0.out; - rsh.right = 32'd16; - and1.left = exponent_value.out; - and1.right = 32'd65535; - int_x.write_en = 1'd1; - frac_x.write_en = 1'd1; - int_x.in = rsh.out; - frac_x.in = and1.out; - split_bits[done] = int_x.done & frac_x.done ? 1'd1; - } - group consume_pow2<"static"=1> { - p2.write_en = 1'd1; - p2.in = pow2.out; - consume_pow2[done] = p2.done ? 1'd1; - } - group consume_pow3<"static"=1> { - p3.write_en = 1'd1; - p3.in = pow3.out; - consume_pow3[done] = p3.done ? 1'd1; - } - group consume_pow4<"static"=1> { - p4.write_en = 1'd1; - p4.in = pow4.out; - consume_pow4[done] = p4.done ? 1'd1; - } - group mult_by_reciprocal_factorial2 { - mult_pipe2.left = p2.out; - mult_pipe2.right = reciprocal_factorial2.out; - mult_pipe2.go = !mult_pipe2.done ? 1'd1; - product2.write_en = mult_pipe2.done; - product2.in = mult_pipe2.out; - mult_by_reciprocal_factorial2[done] = product2.done; - } - group mult_by_reciprocal_factorial3 { - mult_pipe3.left = p3.out; - mult_pipe3.right = reciprocal_factorial3.out; - mult_pipe3.go = !mult_pipe3.done ? 1'd1; - product3.write_en = mult_pipe3.done; - product3.in = mult_pipe3.out; - mult_by_reciprocal_factorial3[done] = product3.done; - } - group mult_by_reciprocal_factorial4 { - mult_pipe4.left = p4.out; - mult_pipe4.right = reciprocal_factorial4.out; - mult_pipe4.go = !mult_pipe4.done ? 1'd1; - product4.write_en = mult_pipe4.done; - product4.in = mult_pipe4.out; - mult_by_reciprocal_factorial4[done] = product4.done; - } - group sum_round1_1<"static"=1> { - add1.left = frac_x.out; - add1.right = product2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round1_1[done] = sum1.done; - } - group sum_round1_2<"static"=1> { - add2.left = product3.out; - add2.right = product4.out; - sum2.write_en = 1'd1; - sum2.in = add2.out; - sum_round1_2[done] = sum2.done; - } - group sum_round2_1<"static"=1> { - add1.left = sum1.out; - add1.right = sum2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round2_1[done] = sum1.done; - } - group add_degree_zero<"static"=1> { - add1.left = sum1.out; - add1.right = one.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - add_degree_zero[done] = sum1.done; - } - group final_multiply { - mult_pipe1.left = pow1.out; - mult_pipe1.right = sum1.out; - mult_pipe1.go = !mult_pipe1.done ? 1'd1; - m.write_en = mult_pipe1.done; - m.in = mult_pipe1.out; - final_multiply[done] = m.done; - } - out = m.out; - } - control { - seq { - init; - split_bits; - par { - invoke pow1(base=e.out, integer_exp=int_x.out)(); - invoke pow2(base=frac_x.out, integer_exp=c2.out)(); - invoke pow3(base=frac_x.out, integer_exp=c3.out)(); - invoke pow4(base=frac_x.out, integer_exp=c4.out)(); - } - par { - consume_pow2; - consume_pow3; - consume_pow4; - } - par { - mult_by_reciprocal_factorial2; - mult_by_reciprocal_factorial3; - mult_by_reciprocal_factorial4; - } - par { - sum_round1_1; - sum_round1_2; - } - par { - sum_round2_1; - } - add_degree_zero; - final_multiply; - } - } -} -component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { - cells { - pow = std_reg(32); - count = std_reg(32); - mul = std_fp_mult_pipe(32, 16, 16); - lt = std_lt(32); - incr = std_add(32); - } - wires { - group init { - pow.in = 32'd65536; - pow.write_en = 1'd1; - count.in = 32'd0; - count.write_en = 1'd1; - init[done] = pow.done & count.done ? 1'd1; - } - group execute_mul { - mul.left = base; - mul.right = pow.out; - mul.go = !mul.done ? 1'd1; - pow.write_en = mul.done; - pow.in = mul.out; - execute_mul[done] = pow.done; - } - group incr_count { - incr.left = 32'd1; - incr.right = count.out; - count.in = incr.out; - count.write_en = 1'd1; - incr_count[done] = count.done; - } - group cond { - lt.left = count.out; - lt.right = integer_exp; - cond[done] = 1'd1; - } - out = pow.out; - } - control { - seq { - init; - while lt.out with cond { - par { - execute_mul; - incr_count; - } - } - } - } -} -component main() -> () { - cells { - t = std_reg(32); - @external(1) x = std_mem_d1(32, 1, 1); - @external(1) ret = std_mem_d1(32, 1, 1); - e = exp(); - } - wires { - group init { - x.addr0 = 1'd0; - t.in = x.read_data; - t.write_en = 1'd1; - init[done] = t.done; - } - group write_to_memory { - ret.addr0 = 1'd0; - ret.write_en = 1'd1; - ret.write_data = e.out; - write_to_memory[done] = ret.done; - } - } - control { - seq { - init; - invoke e(x=t.out)(); - write_to_memory; - } - } -} diff --git a/tests/correctness/exp/degree-8-signed.txt.futil b/tests/correctness/exp/degree-8-signed.txt.futil deleted file mode 100644 index 9fc485d2e2..0000000000 --- a/tests/correctness/exp/degree-8-signed.txt.futil +++ /dev/null @@ -1,400 +0,0 @@ -import "primitives/std.lib"; -component exp(x: 32) -> (out: 32) { - cells { - exponent_value = std_reg(32); - int_x = std_reg(32); - frac_x = std_reg(32); - m = std_reg(32); - and0 = std_and(32); - and1 = std_and(32); - rsh = std_rsh(32); - lt = std_slt(32); - c2 = std_const(32, 2); - c3 = std_const(32, 3); - c4 = std_const(32, 4); - c5 = std_const(32, 5); - c6 = std_const(32, 6); - c7 = std_const(32, 7); - c8 = std_const(32, 8); - one = std_const(32, 65536); - e = std_const(32, 178145); - negative_one = std_const(32, 4294901760); - product2 = std_reg(32); - product3 = std_reg(32); - product4 = std_reg(32); - product5 = std_reg(32); - product6 = std_reg(32); - product7 = std_reg(32); - product8 = std_reg(32); - p2 = std_reg(32); - p3 = std_reg(32); - p4 = std_reg(32); - p5 = std_reg(32); - p6 = std_reg(32); - p7 = std_reg(32); - p8 = std_reg(32); - sum1 = std_reg(32); - sum2 = std_reg(32); - sum3 = std_reg(32); - sum4 = std_reg(32); - add1 = std_fp_sadd(32, 16, 16); - add2 = std_fp_sadd(32, 16, 16); - add3 = std_fp_sadd(32, 16, 16); - add4 = std_fp_sadd(32, 16, 16); - mult_pipe1 = std_fp_smult_pipe(32, 16, 16); - mult_pipe2 = std_fp_smult_pipe(32, 16, 16); - mult_pipe3 = std_fp_smult_pipe(32, 16, 16); - mult_pipe4 = std_fp_smult_pipe(32, 16, 16); - mult_pipe5 = std_fp_smult_pipe(32, 16, 16); - mult_pipe6 = std_fp_smult_pipe(32, 16, 16); - mult_pipe7 = std_fp_smult_pipe(32, 16, 16); - mult_pipe8 = std_fp_smult_pipe(32, 16, 16); - div_pipe = std_fp_sdiv_pipe(32, 16, 16); - reciprocal_factorial2 = std_const(32, 32768); - reciprocal_factorial3 = std_const(32, 10923); - reciprocal_factorial4 = std_const(32, 2731); - reciprocal_factorial5 = std_const(32, 546); - reciprocal_factorial6 = std_const(32, 91); - reciprocal_factorial7 = std_const(32, 13); - reciprocal_factorial8 = std_const(32, 2); - pow1 = fp_pow(); - pow2 = fp_pow(); - pow3 = fp_pow(); - pow4 = fp_pow(); - pow5 = fp_pow(); - pow6 = fp_pow(); - pow7 = fp_pow(); - pow8 = fp_pow(); - } - wires { - group init<"static"=1> { - exponent_value.write_en = 1'd1; - exponent_value.in = x; - init[done] = exponent_value.done; - } - group split_bits { - and0.left = exponent_value.out; - and0.right = 32'd4294901760; - rsh.left = and0.out; - rsh.right = 32'd16; - and1.left = exponent_value.out; - and1.right = 32'd65535; - int_x.write_en = 1'd1; - frac_x.write_en = 1'd1; - int_x.in = rsh.out; - frac_x.in = and1.out; - split_bits[done] = int_x.done & frac_x.done ? 1'd1; - } - group negate { - mult_pipe1.left = exponent_value.out; - mult_pipe1.right = negative_one.out; - mult_pipe1.go = !mult_pipe1.done ? 1'd1; - exponent_value.write_en = mult_pipe1.done; - exponent_value.in = mult_pipe1.out; - negate[done] = exponent_value.done; - } - group is_negative<"static"=0> { - lt.left = x; - lt.right = 32'd0; - is_negative[done] = 1'd1; - } - group reciprocal { - div_pipe.left = one.out; - div_pipe.right = m.out; - div_pipe.go = !div_pipe.done ? 1'd1; - m.write_en = div_pipe.done; - m.in = div_pipe.out_quotient; - reciprocal[done] = m.done; - } - group consume_pow2<"static"=1> { - p2.write_en = 1'd1; - p2.in = pow2.out; - consume_pow2[done] = p2.done ? 1'd1; - } - group consume_pow3<"static"=1> { - p3.write_en = 1'd1; - p3.in = pow3.out; - consume_pow3[done] = p3.done ? 1'd1; - } - group consume_pow4<"static"=1> { - p4.write_en = 1'd1; - p4.in = pow4.out; - consume_pow4[done] = p4.done ? 1'd1; - } - group consume_pow5<"static"=1> { - p5.write_en = 1'd1; - p5.in = pow5.out; - consume_pow5[done] = p5.done ? 1'd1; - } - group consume_pow6<"static"=1> { - p6.write_en = 1'd1; - p6.in = pow6.out; - consume_pow6[done] = p6.done ? 1'd1; - } - group consume_pow7<"static"=1> { - p7.write_en = 1'd1; - p7.in = pow7.out; - consume_pow7[done] = p7.done ? 1'd1; - } - group consume_pow8<"static"=1> { - p8.write_en = 1'd1; - p8.in = pow8.out; - consume_pow8[done] = p8.done ? 1'd1; - } - group mult_by_reciprocal_factorial2 { - mult_pipe2.left = p2.out; - mult_pipe2.right = reciprocal_factorial2.out; - mult_pipe2.go = !mult_pipe2.done ? 1'd1; - product2.write_en = mult_pipe2.done; - product2.in = mult_pipe2.out; - mult_by_reciprocal_factorial2[done] = product2.done; - } - group mult_by_reciprocal_factorial3 { - mult_pipe3.left = p3.out; - mult_pipe3.right = reciprocal_factorial3.out; - mult_pipe3.go = !mult_pipe3.done ? 1'd1; - product3.write_en = mult_pipe3.done; - product3.in = mult_pipe3.out; - mult_by_reciprocal_factorial3[done] = product3.done; - } - group mult_by_reciprocal_factorial4 { - mult_pipe4.left = p4.out; - mult_pipe4.right = reciprocal_factorial4.out; - mult_pipe4.go = !mult_pipe4.done ? 1'd1; - product4.write_en = mult_pipe4.done; - product4.in = mult_pipe4.out; - mult_by_reciprocal_factorial4[done] = product4.done; - } - group mult_by_reciprocal_factorial5 { - mult_pipe5.left = p5.out; - mult_pipe5.right = reciprocal_factorial5.out; - mult_pipe5.go = !mult_pipe5.done ? 1'd1; - product5.write_en = mult_pipe5.done; - product5.in = mult_pipe5.out; - mult_by_reciprocal_factorial5[done] = product5.done; - } - group mult_by_reciprocal_factorial6 { - mult_pipe6.left = p6.out; - mult_pipe6.right = reciprocal_factorial6.out; - mult_pipe6.go = !mult_pipe6.done ? 1'd1; - product6.write_en = mult_pipe6.done; - product6.in = mult_pipe6.out; - mult_by_reciprocal_factorial6[done] = product6.done; - } - group mult_by_reciprocal_factorial7 { - mult_pipe7.left = p7.out; - mult_pipe7.right = reciprocal_factorial7.out; - mult_pipe7.go = !mult_pipe7.done ? 1'd1; - product7.write_en = mult_pipe7.done; - product7.in = mult_pipe7.out; - mult_by_reciprocal_factorial7[done] = product7.done; - } - group mult_by_reciprocal_factorial8 { - mult_pipe8.left = p8.out; - mult_pipe8.right = reciprocal_factorial8.out; - mult_pipe8.go = !mult_pipe8.done ? 1'd1; - product8.write_en = mult_pipe8.done; - product8.in = mult_pipe8.out; - mult_by_reciprocal_factorial8[done] = product8.done; - } - group sum_round1_1<"static"=1> { - add1.left = frac_x.out; - add1.right = product2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round1_1[done] = sum1.done; - } - group sum_round1_2<"static"=1> { - add2.left = product3.out; - add2.right = product4.out; - sum2.write_en = 1'd1; - sum2.in = add2.out; - sum_round1_2[done] = sum2.done; - } - group sum_round1_3<"static"=1> { - add3.left = product5.out; - add3.right = product6.out; - sum3.write_en = 1'd1; - sum3.in = add3.out; - sum_round1_3[done] = sum3.done; - } - group sum_round1_4<"static"=1> { - add4.left = product7.out; - add4.right = product8.out; - sum4.write_en = 1'd1; - sum4.in = add4.out; - sum_round1_4[done] = sum4.done; - } - group sum_round2_1<"static"=1> { - add1.left = sum1.out; - add1.right = sum2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round2_1[done] = sum1.done; - } - group sum_round2_2<"static"=1> { - add2.left = sum3.out; - add2.right = sum4.out; - sum2.write_en = 1'd1; - sum2.in = add2.out; - sum_round2_2[done] = sum2.done; - } - group sum_round3_1<"static"=1> { - add1.left = sum1.out; - add1.right = sum2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round3_1[done] = sum1.done; - } - group add_degree_zero<"static"=1> { - add1.left = sum1.out; - add1.right = one.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - add_degree_zero[done] = sum1.done; - } - group final_multiply { - mult_pipe1.left = pow1.out; - mult_pipe1.right = sum1.out; - mult_pipe1.go = !mult_pipe1.done ? 1'd1; - m.write_en = mult_pipe1.done; - m.in = mult_pipe1.out; - final_multiply[done] = m.done; - } - out = m.out; - } - control { - seq { - init; - if lt.out with is_negative { - negate; - } - split_bits; - par { - invoke pow1(base=e.out, integer_exp=int_x.out)(); - invoke pow2(base=frac_x.out, integer_exp=c2.out)(); - invoke pow3(base=frac_x.out, integer_exp=c3.out)(); - invoke pow4(base=frac_x.out, integer_exp=c4.out)(); - invoke pow5(base=frac_x.out, integer_exp=c5.out)(); - invoke pow6(base=frac_x.out, integer_exp=c6.out)(); - invoke pow7(base=frac_x.out, integer_exp=c7.out)(); - invoke pow8(base=frac_x.out, integer_exp=c8.out)(); - } - par { - consume_pow2; - consume_pow3; - consume_pow4; - consume_pow5; - consume_pow6; - consume_pow7; - consume_pow8; - } - par { - mult_by_reciprocal_factorial2; - mult_by_reciprocal_factorial3; - mult_by_reciprocal_factorial4; - mult_by_reciprocal_factorial5; - mult_by_reciprocal_factorial6; - mult_by_reciprocal_factorial7; - mult_by_reciprocal_factorial8; - } - par { - sum_round1_1; - sum_round1_2; - sum_round1_3; - sum_round1_4; - } - par { - sum_round2_1; - sum_round2_2; - } - par { - sum_round3_1; - } - add_degree_zero; - final_multiply; - if lt.out with is_negative { - reciprocal; - } - } - } -} -component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { - cells { - pow = std_reg(32); - count = std_reg(32); - mul = std_fp_smult_pipe(32, 16, 16); - lt = std_slt(32); - incr = std_sadd(32); - } - wires { - group init { - pow.in = 32'd65536; - pow.write_en = 1'd1; - count.in = 32'd0; - count.write_en = 1'd1; - init[done] = pow.done & count.done ? 1'd1; - } - group execute_mul { - mul.left = base; - mul.right = pow.out; - mul.go = !mul.done ? 1'd1; - pow.write_en = mul.done; - pow.in = mul.out; - execute_mul[done] = pow.done; - } - group incr_count { - incr.left = 32'd1; - incr.right = count.out; - count.in = incr.out; - count.write_en = 1'd1; - incr_count[done] = count.done; - } - group cond { - lt.left = count.out; - lt.right = integer_exp; - cond[done] = 1'd1; - } - out = pow.out; - } - control { - seq { - init; - while lt.out with cond { - par { - execute_mul; - incr_count; - } - } - } - } -} -component main() -> () { - cells { - t = std_reg(32); - @external(1) x = std_mem_d1(32, 1, 1); - @external(1) ret = std_mem_d1(32, 1, 1); - e = exp(); - } - wires { - group init { - x.addr0 = 1'd0; - t.in = x.read_data; - t.write_en = 1'd1; - init[done] = t.done; - } - group write_to_memory { - ret.addr0 = 1'd0; - ret.write_en = 1'd1; - ret.write_data = e.out; - write_to_memory[done] = ret.done; - } - } - control { - seq { - init; - invoke e(x=t.out)(); - write_to_memory; - } - } -} diff --git a/tests/correctness/exp/degree-8-unsigned.txt.futil b/tests/correctness/exp/degree-8-unsigned.txt.futil deleted file mode 100644 index 128b1a5fa0..0000000000 --- a/tests/correctness/exp/degree-8-unsigned.txt.futil +++ /dev/null @@ -1,370 +0,0 @@ -import "primitives/std.lib"; -component exp(x: 32) -> (out: 32) { - cells { - exponent_value = std_reg(32); - int_x = std_reg(32); - frac_x = std_reg(32); - m = std_reg(32); - and0 = std_and(32); - and1 = std_and(32); - rsh = std_rsh(32); - c2 = std_const(32, 2); - c3 = std_const(32, 3); - c4 = std_const(32, 4); - c5 = std_const(32, 5); - c6 = std_const(32, 6); - c7 = std_const(32, 7); - c8 = std_const(32, 8); - one = std_const(32, 65536); - e = std_const(32, 178145); - product2 = std_reg(32); - product3 = std_reg(32); - product4 = std_reg(32); - product5 = std_reg(32); - product6 = std_reg(32); - product7 = std_reg(32); - product8 = std_reg(32); - p2 = std_reg(32); - p3 = std_reg(32); - p4 = std_reg(32); - p5 = std_reg(32); - p6 = std_reg(32); - p7 = std_reg(32); - p8 = std_reg(32); - sum1 = std_reg(32); - sum2 = std_reg(32); - sum3 = std_reg(32); - sum4 = std_reg(32); - add1 = std_fp_add(32, 16, 16); - add2 = std_fp_add(32, 16, 16); - add3 = std_fp_add(32, 16, 16); - add4 = std_fp_add(32, 16, 16); - mult_pipe1 = std_fp_mult_pipe(32, 16, 16); - mult_pipe2 = std_fp_mult_pipe(32, 16, 16); - mult_pipe3 = std_fp_mult_pipe(32, 16, 16); - mult_pipe4 = std_fp_mult_pipe(32, 16, 16); - mult_pipe5 = std_fp_mult_pipe(32, 16, 16); - mult_pipe6 = std_fp_mult_pipe(32, 16, 16); - mult_pipe7 = std_fp_mult_pipe(32, 16, 16); - mult_pipe8 = std_fp_mult_pipe(32, 16, 16); - reciprocal_factorial2 = std_const(32, 32768); - reciprocal_factorial3 = std_const(32, 10923); - reciprocal_factorial4 = std_const(32, 2731); - reciprocal_factorial5 = std_const(32, 546); - reciprocal_factorial6 = std_const(32, 91); - reciprocal_factorial7 = std_const(32, 13); - reciprocal_factorial8 = std_const(32, 2); - pow1 = fp_pow(); - pow2 = fp_pow(); - pow3 = fp_pow(); - pow4 = fp_pow(); - pow5 = fp_pow(); - pow6 = fp_pow(); - pow7 = fp_pow(); - pow8 = fp_pow(); - } - wires { - group init<"static"=1> { - exponent_value.write_en = 1'd1; - exponent_value.in = x; - init[done] = exponent_value.done; - } - group split_bits { - and0.left = exponent_value.out; - and0.right = 32'd4294901760; - rsh.left = and0.out; - rsh.right = 32'd16; - and1.left = exponent_value.out; - and1.right = 32'd65535; - int_x.write_en = 1'd1; - frac_x.write_en = 1'd1; - int_x.in = rsh.out; - frac_x.in = and1.out; - split_bits[done] = int_x.done & frac_x.done ? 1'd1; - } - group consume_pow2<"static"=1> { - p2.write_en = 1'd1; - p2.in = pow2.out; - consume_pow2[done] = p2.done ? 1'd1; - } - group consume_pow3<"static"=1> { - p3.write_en = 1'd1; - p3.in = pow3.out; - consume_pow3[done] = p3.done ? 1'd1; - } - group consume_pow4<"static"=1> { - p4.write_en = 1'd1; - p4.in = pow4.out; - consume_pow4[done] = p4.done ? 1'd1; - } - group consume_pow5<"static"=1> { - p5.write_en = 1'd1; - p5.in = pow5.out; - consume_pow5[done] = p5.done ? 1'd1; - } - group consume_pow6<"static"=1> { - p6.write_en = 1'd1; - p6.in = pow6.out; - consume_pow6[done] = p6.done ? 1'd1; - } - group consume_pow7<"static"=1> { - p7.write_en = 1'd1; - p7.in = pow7.out; - consume_pow7[done] = p7.done ? 1'd1; - } - group consume_pow8<"static"=1> { - p8.write_en = 1'd1; - p8.in = pow8.out; - consume_pow8[done] = p8.done ? 1'd1; - } - group mult_by_reciprocal_factorial2 { - mult_pipe2.left = p2.out; - mult_pipe2.right = reciprocal_factorial2.out; - mult_pipe2.go = !mult_pipe2.done ? 1'd1; - product2.write_en = mult_pipe2.done; - product2.in = mult_pipe2.out; - mult_by_reciprocal_factorial2[done] = product2.done; - } - group mult_by_reciprocal_factorial3 { - mult_pipe3.left = p3.out; - mult_pipe3.right = reciprocal_factorial3.out; - mult_pipe3.go = !mult_pipe3.done ? 1'd1; - product3.write_en = mult_pipe3.done; - product3.in = mult_pipe3.out; - mult_by_reciprocal_factorial3[done] = product3.done; - } - group mult_by_reciprocal_factorial4 { - mult_pipe4.left = p4.out; - mult_pipe4.right = reciprocal_factorial4.out; - mult_pipe4.go = !mult_pipe4.done ? 1'd1; - product4.write_en = mult_pipe4.done; - product4.in = mult_pipe4.out; - mult_by_reciprocal_factorial4[done] = product4.done; - } - group mult_by_reciprocal_factorial5 { - mult_pipe5.left = p5.out; - mult_pipe5.right = reciprocal_factorial5.out; - mult_pipe5.go = !mult_pipe5.done ? 1'd1; - product5.write_en = mult_pipe5.done; - product5.in = mult_pipe5.out; - mult_by_reciprocal_factorial5[done] = product5.done; - } - group mult_by_reciprocal_factorial6 { - mult_pipe6.left = p6.out; - mult_pipe6.right = reciprocal_factorial6.out; - mult_pipe6.go = !mult_pipe6.done ? 1'd1; - product6.write_en = mult_pipe6.done; - product6.in = mult_pipe6.out; - mult_by_reciprocal_factorial6[done] = product6.done; - } - group mult_by_reciprocal_factorial7 { - mult_pipe7.left = p7.out; - mult_pipe7.right = reciprocal_factorial7.out; - mult_pipe7.go = !mult_pipe7.done ? 1'd1; - product7.write_en = mult_pipe7.done; - product7.in = mult_pipe7.out; - mult_by_reciprocal_factorial7[done] = product7.done; - } - group mult_by_reciprocal_factorial8 { - mult_pipe8.left = p8.out; - mult_pipe8.right = reciprocal_factorial8.out; - mult_pipe8.go = !mult_pipe8.done ? 1'd1; - product8.write_en = mult_pipe8.done; - product8.in = mult_pipe8.out; - mult_by_reciprocal_factorial8[done] = product8.done; - } - group sum_round1_1<"static"=1> { - add1.left = frac_x.out; - add1.right = product2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round1_1[done] = sum1.done; - } - group sum_round1_2<"static"=1> { - add2.left = product3.out; - add2.right = product4.out; - sum2.write_en = 1'd1; - sum2.in = add2.out; - sum_round1_2[done] = sum2.done; - } - group sum_round1_3<"static"=1> { - add3.left = product5.out; - add3.right = product6.out; - sum3.write_en = 1'd1; - sum3.in = add3.out; - sum_round1_3[done] = sum3.done; - } - group sum_round1_4<"static"=1> { - add4.left = product7.out; - add4.right = product8.out; - sum4.write_en = 1'd1; - sum4.in = add4.out; - sum_round1_4[done] = sum4.done; - } - group sum_round2_1<"static"=1> { - add1.left = sum1.out; - add1.right = sum2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round2_1[done] = sum1.done; - } - group sum_round2_2<"static"=1> { - add2.left = sum3.out; - add2.right = sum4.out; - sum2.write_en = 1'd1; - sum2.in = add2.out; - sum_round2_2[done] = sum2.done; - } - group sum_round3_1<"static"=1> { - add1.left = sum1.out; - add1.right = sum2.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - sum_round3_1[done] = sum1.done; - } - group add_degree_zero<"static"=1> { - add1.left = sum1.out; - add1.right = one.out; - sum1.write_en = 1'd1; - sum1.in = add1.out; - add_degree_zero[done] = sum1.done; - } - group final_multiply { - mult_pipe1.left = pow1.out; - mult_pipe1.right = sum1.out; - mult_pipe1.go = !mult_pipe1.done ? 1'd1; - m.write_en = mult_pipe1.done; - m.in = mult_pipe1.out; - final_multiply[done] = m.done; - } - out = m.out; - } - control { - seq { - init; - split_bits; - par { - invoke pow1(base=e.out, integer_exp=int_x.out)(); - invoke pow2(base=frac_x.out, integer_exp=c2.out)(); - invoke pow3(base=frac_x.out, integer_exp=c3.out)(); - invoke pow4(base=frac_x.out, integer_exp=c4.out)(); - invoke pow5(base=frac_x.out, integer_exp=c5.out)(); - invoke pow6(base=frac_x.out, integer_exp=c6.out)(); - invoke pow7(base=frac_x.out, integer_exp=c7.out)(); - invoke pow8(base=frac_x.out, integer_exp=c8.out)(); - } - par { - consume_pow2; - consume_pow3; - consume_pow4; - consume_pow5; - consume_pow6; - consume_pow7; - consume_pow8; - } - par { - mult_by_reciprocal_factorial2; - mult_by_reciprocal_factorial3; - mult_by_reciprocal_factorial4; - mult_by_reciprocal_factorial5; - mult_by_reciprocal_factorial6; - mult_by_reciprocal_factorial7; - mult_by_reciprocal_factorial8; - } - par { - sum_round1_1; - sum_round1_2; - sum_round1_3; - sum_round1_4; - } - par { - sum_round2_1; - sum_round2_2; - } - par { - sum_round3_1; - } - add_degree_zero; - final_multiply; - } - } -} -component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { - cells { - pow = std_reg(32); - count = std_reg(32); - mul = std_fp_mult_pipe(32, 16, 16); - lt = std_lt(32); - incr = std_add(32); - } - wires { - group init { - pow.in = 32'd65536; - pow.write_en = 1'd1; - count.in = 32'd0; - count.write_en = 1'd1; - init[done] = pow.done & count.done ? 1'd1; - } - group execute_mul { - mul.left = base; - mul.right = pow.out; - mul.go = !mul.done ? 1'd1; - pow.write_en = mul.done; - pow.in = mul.out; - execute_mul[done] = pow.done; - } - group incr_count { - incr.left = 32'd1; - incr.right = count.out; - count.in = incr.out; - count.write_en = 1'd1; - incr_count[done] = count.done; - } - group cond { - lt.left = count.out; - lt.right = integer_exp; - cond[done] = 1'd1; - } - out = pow.out; - } - control { - seq { - init; - while lt.out with cond { - par { - execute_mul; - incr_count; - } - } - } - } -} -component main() -> () { - cells { - t = std_reg(32); - @external(1) x = std_mem_d1(32, 1, 1); - @external(1) ret = std_mem_d1(32, 1, 1); - e = exp(); - } - wires { - group init { - x.addr0 = 1'd0; - t.in = x.read_data; - t.write_en = 1'd1; - init[done] = t.done; - } - group write_to_memory { - ret.addr0 = 1'd0; - ret.write_en = 1'd1; - ret.write_data = e.out; - write_to_memory[done] = ret.done; - } - } - control { - seq { - init; - invoke e(x=t.out)(); - write_to_memory; - } - } -} diff --git a/tests/correctness/ntt-pipeline/ntt-16-reduced-4.txt.futil b/tests/correctness/ntt-pipeline/ntt-16-reduced-4.txt.futil deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/correctness/ntt-pipeline/ntt-16.txt.futil b/tests/correctness/ntt-pipeline/ntt-16.txt.futil deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/correctness/ntt-pipeline/ntt-8.txt.futil b/tests/correctness/ntt-pipeline/ntt-8.txt.futil deleted file mode 100644 index e69de29bb2..0000000000 From 30f0255b1d2c74b229931c0b71abd16f2f39ba96 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 09:10:15 +0530 Subject: [PATCH 18/50] flag-compare runs dead-group-removal before runnning the compiler --- tools/flag-compare.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/flag-compare.sh b/tools/flag-compare.sh index 3daee0a891..ee0abdc90b 100755 --- a/tools/flag-compare.sh +++ b/tools/flag-compare.sh @@ -3,10 +3,10 @@ # Usage: # ./flag-compare.sh -set -euf -o pipefail +set -uf -o pipefail -flag1='-p all -d static-timing' -flag2='-p all' +flag1='-p dead-group-removal -p all' +flag2='-p dead-group-removal -p all' file=$1 data=$2 From 473d972cc0e0b3e8647758c771149200d4101d0b Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 09:29:18 +0530 Subject: [PATCH 19/50] doc comment for dead-cell-removal --- calyx/src/passes/dead_group_removal.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/calyx/src/passes/dead_group_removal.rs b/calyx/src/passes/dead_group_removal.rs index f23422280c..18288a4148 100644 --- a/calyx/src/passes/dead_group_removal.rs +++ b/calyx/src/passes/dead_group_removal.rs @@ -5,7 +5,10 @@ use crate::ir::{ }; use std::collections::HashSet; -/// Removes unused cells from components. +/// Removes unused groups and combinational groups from components. +/// A group is considered in use when it shows up in an [ir::Enable]. +/// A combinational group is considered in use when it is a part of an +/// [ir::If] or [ir::While]. #[derive(Default)] pub struct DeadGroupRemoval { used_groups: HashSet, From dfcd10dc77de480a05b60cbfd7015220741192b6 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 12:14:12 +0530 Subject: [PATCH 20/50] extensive comments for tdcc --- calyx/src/passes/top_down_compile_control.rs | 186 ++++++++++++------- 1 file changed, 116 insertions(+), 70 deletions(-) diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index d9af3ae760..e4b96940fe 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -173,7 +173,7 @@ impl Schedule { } } -/// Computes the entry and exit points of a given [ir::Control] program. +/// Computes the exit points of a given [ir::Control] program. /// /// ## Example /// In the following Calyx program: @@ -185,9 +185,9 @@ impl Schedule { /// } /// } /// ``` -/// The entry point is `incr` and the exit point is `cond0`. +/// The exit point is `cond0`. /// -/// Multiple entry and exit points are created when conditions are used: +/// Multiple exit points are created when conditions are used: /// ``` /// while comb_reg.out { /// incr; @@ -198,57 +198,46 @@ impl Schedule { /// } /// } /// ``` -/// The entry set is `incr` while exit set is `[true, false]`. -fn entries_and_exits( - con: &ir::Control, - cur_state: u64, - is_entry: bool, - is_exit: bool, - entries: &mut Vec, - exits: &mut Vec<(u64, RRC)>, -) -> u64 { +/// The exit set is `[true, false]`. +fn control_exits(con: &ir::Control, exits: &mut Vec<(u64, RRC)>) { match con { - ir::Control::Enable(ir::Enable { group, .. }) => { - if is_entry { - entries.push(cur_state) - } - if is_exit { - exits.push((cur_state, Rc::clone(group))) - } - cur_state + 1 + ir::Control::Enable(ir::Enable { attributes, group, .. }) => { + let cur_state = attributes + .get("node_id") + .expect("Group does not have node_id"); + exits.push((*cur_state, Rc::clone(group))) } ir::Control::Seq(ir::Seq { stmts, .. }) => { - let len = stmts.len(); - let mut cur = cur_state; - for (idx, stmt) in stmts.iter().enumerate() { - let entry = idx == 0 && is_entry; - let exit = idx == len - 1 && is_exit; - cur = entries_and_exits(stmt, cur, entry, exit, entries, exits); + if let Some(con) = stmts.iter().last() { + control_exits(con, exits); } - cur } ir::Control::If(ir::If { tbranch, fbranch, .. }) => { - let tru_nxt = entries_and_exits( - tbranch, cur_state, is_entry, is_exit, entries, exits, - ); - entries_and_exits( - fbranch, tru_nxt, is_entry, is_exit, entries, exits, - ) + control_exits(tbranch, exits); + control_exits(fbranch, exits) + } + ir::Control::While(ir::While { body, .. }) => { + control_exits(body, exits) } - ir::Control::While(ir::While { body, .. }) => entries_and_exits( - body, cur_state, is_entry, is_exit, entries, exits, - ), - ir::Control::Invoke(_) => todo!(), - ir::Control::Empty(_) => todo!(), - ir::Control::Par(_) => todo!(), + ir::Control::Empty(..) + | ir::Control::Par(..) + | ir::Control::Invoke(..) => unreachable!() } } -/// Calculate [ir::Assignment] to enable in each FSM state and [ir::Guard] required to transition -/// between FSM states. Each step of the calculation computes the previous states that still need -/// to transition. +/// Represents an edge from a predeccesor to the current control node. +/// The `u64` represents the FSM state of the predeccesor and the guard needs +/// to be true for the predeccesor to transition to the current state. +type PredEdge = (u64, ir::Guard); + +/// Recursively build an dynamic finite state machine represented by a [Schedule]. +/// Does the following, given an [ir::Control]: +/// 1. If needed, add transitions from predeccesors to the current state. +/// 2. Enable the groups in the current state +/// 3. Calculate [PredEdge] implied by this state +/// 4. Return [PredEdge] and the next state. fn calculate_states_recur( con: &ir::Control, // The current state @@ -259,10 +248,9 @@ fn calculate_states_recur( schedule: &mut Schedule, // Component builder builder: &mut ir::Builder, -) -> CalyxResult<(Vec<(u64, ir::Guard)>, u64)> { +) -> CalyxResult<(Vec, u64)> { match con { - // Enable the group in `cur_state` and construct all transitions from - // previous states to this enable. + // See explanation of FSM states generated in [ir::TopDownCompileControl]. ir::Control::Enable(ir::Enable { group, .. }) => { let not_done = !guard!(group["done"]); let signal_on = builder.add_constant(1, 1); @@ -277,7 +265,10 @@ fn calculate_states_recur( .or_default() .append(&mut en_go); - // Activate group when each previous states are done. + // Activate group in the cycle when previous state signals done. + // NOTE: We explicilty do not add `not_done` to the guard. + // See explanation in [ir::TopDownCompileControl] to understand + // why. for (st, g) in &prev_states { let mut early_go = build_assignments!(builder; group["go"] = g ? signal_on["out"]; @@ -356,14 +347,9 @@ fn calculate_states_recur( // Step 1: Generate the backward edges // First compute the entry and exit points. - let mut entries = vec![]; let mut exits = vec![]; - entries_and_exits( + control_exits( body, - cur_state, - true, - true, - &mut entries, &mut exits, ); let back_edge_prevs = exits.into_iter().map(|(st, group)| (st, group.borrow().get("done").into())); @@ -416,32 +402,92 @@ fn calculate_states( } /// **Core lowering pass.** -/// Compiles away the control programs in components into purely structural -/// code using an finite-state machine (FSM). +/// Compiles away the control programs in components into purely structural code using an +/// finite-state machine (FSM). /// /// Lowering operates in two steps: -/// 1. Compile all [ir::Par] control sub-programs into a -/// single [ir::Enable] of a group that runs all children -/// to completion. +/// 1. Compile all [ir::Par] control sub-programs into a single [ir::Enable] of a group that runs +/// all children to completion. /// 2. Compile the top-level control program into a single [ir::Enable]. /// /// ## Compiling non-`par` programs -/// Assuming all `par` statements have already been compiled in a control -/// sub-program, we can build a schedule for executing it. We calculate a -/// schedule by assigning an FSM state to each leaf node (an [ir::Enable]) -/// as a guard condition. Each control program node also defines a transition -/// function over the states calculated for its children. +/// At very high-level, the pass assigns an FSM state to each [ir::Enable] in the program and +/// generates transitions to the state to activate the groups contained within the [ir::Enable]. +/// +/// The compilation process calculates all predeccesors of the [ir::Enable] while walking over the +/// control program. A predeccesor is any enable statement that can directly "jump" to the current +/// [ir::Enable]. The compilation process computes all such predeccesors and the guards that need +/// to be true for the predeccesor to jump into this enable statement. +/// +/// ``` +/// cond0; +/// while lt.out { +/// if gt.out { true } else { false } +/// } +/// next; +/// ``` +/// The predeccesor sets are: +/// ``` +/// cond0 -> [] +/// true -> [(cond0, lt.out & gt.out); (true; lt.out & gt.out); (false, lt.out & !gt.out)] +/// false -> [(cond0, lt.out & !gt.out); (true; lt.out & gt.out); (false, lt.out & !gt.out)] +/// next -> [(cond0, !lt.out); (true, !lt.out); (false, !lt.out)] +/// ``` +/// +/// ### Compiling [ir::Enable] +/// The process first takes all edges from predeccesors and transitions to the state for this +/// enable and enables the group in this state: +/// ```text +/// let cur_state; // state of this enable +/// for (state, guard) in predeccesors: +/// transitions.insert(state, cur_state, guard) +/// enables.insert(cur_state, group) +/// ``` +/// +/// While this process will generate a functioning FSM, the FSM takes unnecessary cycles for FSM +/// transitions. +/// +/// For example: +/// ``` +/// seq { one; two; } +/// ``` +/// The FSM generated will look like this (where `f` is the FSM register): +/// ``` +/// f.in = one[done] ? 1; +/// f.in = two[done] ? 2; +/// one[go] = !one[done] & f.out == 0; +/// two[go] = !two[done] & f.out == 1; +/// ``` +/// +/// The cycle-level timing for this FSM will look like: +/// - cycle 0: (f.out == 0), enable one +/// - cycle t: (f.out == 0), (one[done] == 1), disable one +/// - cycle t+1: (f.out == 1), enable two +/// - cycle t+l: (f.out == 1), (two[done] == 1), disable two +/// - cycle t+l+1: finish +/// +/// The transition t -> t+1 represents one where group one is done but group two hasn't started +/// executing. +/// +/// To address this specific problem, there is an additional enable added to run all groups within +/// an enable *while the FSM is transitioning*. +/// The final transition will look like this: +/// ``` +/// f.in = one[done] ? 1; +/// f.in = two[done] ? 2; +/// one[go] = !one[done] & f.out == 0; +/// two[go] = (!two[done] & f.out == 1) || (one[done] & f.out == 0); +/// ``` /// -/// At the end of schedule generation, each FSM state has a set of groups to -/// enable as well as a transition function. -/// This FSM is realized into an implementation using a new group that implements -/// the group enables and the transitions. +/// Note that `!two[done]` isn't present in the second disjunct because all groups are guaranteed +/// to run for at least one cycle and the second disjunct will only be true for one cycle before +/// the first disjunct becomes true. /// /// ## Compiling `par` programs -/// We have to generate new FSM-based controller for each child of a `par` node -/// so that each child can indepdendently make progress. -/// If we tie the children to one top-level FSM, their transitions would become -/// interdependent and reduce available concurrency. +/// We have to generate new FSM-based controller for each child of a `par` node so that each child +/// can indepdendently make progress. +/// If we tie the children to one top-level FSM, their transitions would become interdependent and +/// reduce available concurrency. /// /// ## Compilation guarantee /// At the end of this pass, the control program will have no more than one From 35f5eeb721c57510d5f85e6bd108b68404e9ff45 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 12:16:27 +0530 Subject: [PATCH 21/50] disable broken passes and disable static-timing testing --- calyx/src/passes/mod.rs | 6 ------ runt.toml | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/calyx/src/passes/mod.rs b/calyx/src/passes/mod.rs index f2892fbeaa..7dc9aa9f21 100644 --- a/calyx/src/passes/mod.rs +++ b/calyx/src/passes/mod.rs @@ -1,7 +1,6 @@ //! Passes for the Calyx compiler. mod clk_insertion; mod collapse_control; -// mod compile_control; mod compile_empty; mod compile_invoke; mod component_interface; @@ -23,15 +22,12 @@ mod reset_insertion; mod resource_sharing; mod sharing_components; mod simplify_guards; -// mod static_timing; mod synthesis_papercut; mod top_down_compile_control; -// mod top_down_static_timing; mod well_formed; pub use clk_insertion::ClkInsertion; pub use collapse_control::CollapseControl; -// pub use compile_control::CompileControl; pub use compile_empty::CompileEmpty; pub use compile_invoke::CompileInvoke; pub use component_interface::ComponentInterface; @@ -51,8 +47,6 @@ pub use remove_comb_groups::RemoveCombGroups; pub use reset_insertion::ResetInsertion; pub use resource_sharing::ResourceSharing; pub use simplify_guards::SimplifyGuards; -// pub use static_timing::StaticTiming; pub use synthesis_papercut::SynthesisPapercut; pub use top_down_compile_control::TopDownCompileControl; -// pub use top_down_static_timing::TopDownStaticTiming; pub use well_formed::WellFormed; diff --git a/runt.toml b/runt.toml index ee4ea54fd8..8c6cb77e2d 100644 --- a/runt.toml +++ b/runt.toml @@ -57,7 +57,6 @@ paths = [ ] cmd = """ fud exec -s verilog.data {}.data \ - -s futil.flags '-d static-timing' \ -s futil.exec './target/debug/futil' \ -s verilog.cycle_limit 500 \ {} --to dat \ @@ -87,18 +86,19 @@ fud exec -s verilog.data {}.data \ {} --to dat -q | jq .memories """ -## Same as correctness dynamic but runs with static-timing. -[[tests]] -name = "correctness static timing" -paths = [ "tests/correctness/*.futil" ] -cmd = """ -fud exec -s verilog.cycle_limit 500 \ - -s verilog.data {}.data \ - -s futil.exec './target/debug/futil' \ - {} --to dat \ - -q \ - | jq .memories -""" +## XXX: Same as correctness dynamic but runs with static-timing. +## Currently disabled. +# [[tests]] +# name = "correctness static timing" +# paths = [ "tests/correctness/*.futil" ] +# cmd = """ +# fud exec -s verilog.cycle_limit 500 \ + # -s verilog.data {}.data \ + # -s futil.exec './target/debug/futil' \ + # {} --to dat \ + # -q \ + # | jq .memories +# """ [[tests]] name = "[frontend] systolic array correctness" From 1cf99144e7d90daa12d8a57ef1254e6d533e668b Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 12:19:47 +0530 Subject: [PATCH 22/50] disable compile-control tests --- .../compile-control/compile-if-static.expect | 49 ----------------- .../passes/compile-control/compile-if.expect | 50 ----------------- .../compile-control/compile-par-static.expect | 55 ------------------- .../passes/compile-control/compile-par.expect | 55 ------------------- .../compile-control/compile-seq-static.expect | 44 --------------- .../passes/compile-control/compile-seq.expect | 44 --------------- .../compile-while-static.expect | 47 ---------------- .../compile-control/compile-while.expect | 43 --------------- 8 files changed, 387 deletions(-) delete mode 100644 tests/passes/compile-control/compile-if-static.expect delete mode 100644 tests/passes/compile-control/compile-if.expect delete mode 100644 tests/passes/compile-control/compile-par-static.expect delete mode 100644 tests/passes/compile-control/compile-par.expect delete mode 100644 tests/passes/compile-control/compile-seq-static.expect delete mode 100644 tests/passes/compile-control/compile-seq.expect delete mode 100644 tests/passes/compile-control/compile-while-static.expect delete mode 100644 tests/passes/compile-control/compile-while.expect diff --git a/tests/passes/compile-control/compile-if-static.expect b/tests/passes/compile-control/compile-if-static.expect deleted file mode 100644 index e9ecb780f6..0000000000 --- a/tests/passes/compile-control/compile-if-static.expect +++ /dev/null @@ -1,49 +0,0 @@ -import "primitives/std.lib"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - t = std_reg(1); - f = std_reg(1); - lt = std_lt(1); - @generated comb_reg = std_reg(1); - @generated fsm = std_reg(2); - @generated cond_stored = std_reg(1); - @generated incr = std_add(2); - } - wires { - group true<"static"=1> { - t.in = 1'd1; - t.write_en = 1'd1; - true[done] = t.done; - } - group false<"static"=1> { - f.in = 1'd1; - f.write_en = 1'd1; - false[done] = f.done; - } - group cond<"static"=1> { - lt.left = 1'd1; - lt.right = 1'd0; - cond[done] = comb_reg.done ? 1'd1; - comb_reg.in = lt.out; - comb_reg.write_en = 1'd1; - } - group static_if<"static"=3> { - incr.left = fsm.out; - incr.right = 2'd1; - fsm.in = fsm.out != 2'd3 ? incr.out; - fsm.write_en = fsm.out != 2'd3 ? 1'd1; - cond[go] = fsm.out < 2'd1 ? 1'd1; - cond_stored.write_en = fsm.out == 2'd1 ? 1'd1; - true[go] = fsm.out > 2'd1 & fsm.out < 2'd3 & cond_stored.out ? 1'd1; - false[go] = fsm.out > 2'd1 & fsm.out < 2'd3 & !cond_stored.out ? 1'd1; - static_if[done] = fsm.out == 2'd3 ? 1'd1; - cond_stored.in = fsm.out == 2'd1 ? comb_reg.out; - } - fsm.in = fsm.out == 2'd3 ? 2'd0; - fsm.write_en = fsm.out == 2'd3 ? 1'd1; - } - - control { - static_if; - } -} diff --git a/tests/passes/compile-control/compile-if.expect b/tests/passes/compile-control/compile-if.expect deleted file mode 100644 index ef7f1b721e..0000000000 --- a/tests/passes/compile-control/compile-if.expect +++ /dev/null @@ -1,50 +0,0 @@ -import "primitives/std.lib"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - t = std_reg(1); - f = std_reg(1); - lt = std_lt(1); - @generated cond_computed = std_reg(1); - @generated cond_stored = std_reg(1); - @generated done_reg = std_reg(1); - } - wires { - group true { - t.in = 1'd1; - t.write_en = 1'd1; - true[done] = t.done; - } - group false { - f.in = 1'd1; - f.write_en = 1'd1; - false[done] = f.done; - } - group cond { - lt.left = 1'd1; - lt.right = 1'd0; - cond[done] = 1'd1; - } - group if { - cond_stored.in = cond[go] & cond[done] ? lt.out; - cond_stored.write_en = cond[go] & cond[done] ? lt.out; - cond[go] = !cond_computed.out ? 1'd1; - cond_computed.in = cond[go] & cond[done] ? 1'd1; - cond_computed.write_en = cond[go] & cond[done] ? 1'd1; - true[go] = !true[done] & cond_computed.out & cond_stored.out ? 1'd1; - false[go] = !false[done] & cond_computed.out & !cond_stored.out ? 1'd1; - done_reg.in = cond_computed.out & cond_stored.out & true[done] | cond_computed.out & !cond_stored.out & false[done] ? 1'd1; - done_reg.write_en = cond_computed.out & cond_stored.out & true[done] | cond_computed.out & !cond_stored.out & false[done] ? 1'd1; - if[done] = done_reg.out ? 1'd1; - } - done_reg.in = done_reg.out ? 1'd0; - done_reg.write_en = done_reg.out ? 1'd1; - cond_computed.in = done_reg.out ? 1'd0; - cond_computed.write_en = done_reg.out ? 1'd1; - cond_stored.in = done_reg.out ? 1'd0; - cond_stored.write_en = done_reg.out ? 1'd1; - } - - control { - if; - } -} diff --git a/tests/passes/compile-control/compile-par-static.expect b/tests/passes/compile-control/compile-par-static.expect deleted file mode 100644 index fd89014174..0000000000 --- a/tests/passes/compile-control/compile-par-static.expect +++ /dev/null @@ -1,55 +0,0 @@ -import "primitives/std.lib"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - a = std_reg(2); - b = std_reg(2); - c = std_reg(2); - @generated par_reset = std_reg(1); - @generated par_done_reg = std_reg(1); - @generated par_done_reg0 = std_reg(1); - @generated par_done_reg1 = std_reg(1); - } - wires { - group A<"static"=1> { - a.in = 2'd0; - a.write_en = 1'd1; - A[done] = a.done; - } - group B<"static"=1> { - b.in = 2'd1; - b.write_en = 1'd1; - B[done] = b.done; - } - group C<"static"=1> { - c.in = 2'd2; - c.write_en = 1'd1; - C[done] = c.done; - } - group par { - A[go] = !(par_done_reg.out | A[done]) ? 1'd1; - par_done_reg.in = A[done] ? 1'd1; - par_done_reg.write_en = A[done] ? 1'd1; - B[go] = !(par_done_reg0.out | B[done]) ? 1'd1; - par_done_reg0.in = B[done] ? 1'd1; - par_done_reg0.write_en = B[done] ? 1'd1; - C[go] = !(par_done_reg1.out | C[done]) ? 1'd1; - par_done_reg1.in = C[done] ? 1'd1; - par_done_reg1.write_en = C[done] ? 1'd1; - par_reset.in = par_done_reg.out & par_done_reg0.out & par_done_reg1.out ? 1'd1; - par_reset.write_en = par_done_reg.out & par_done_reg0.out & par_done_reg1.out ? 1'd1; - par[done] = par_reset.out ? 1'd1; - } - par_reset.in = par_reset.out ? 1'd0; - par_reset.write_en = par_reset.out ? 1'd1; - par_done_reg.in = par_reset.out ? 1'd0; - par_done_reg.write_en = par_reset.out ? 1'd1; - par_done_reg0.in = par_reset.out ? 1'd0; - par_done_reg0.write_en = par_reset.out ? 1'd1; - par_done_reg1.in = par_reset.out ? 1'd0; - par_done_reg1.write_en = par_reset.out ? 1'd1; - } - - control { - par; - } -} diff --git a/tests/passes/compile-control/compile-par.expect b/tests/passes/compile-control/compile-par.expect deleted file mode 100644 index 52ad07125f..0000000000 --- a/tests/passes/compile-control/compile-par.expect +++ /dev/null @@ -1,55 +0,0 @@ -import "primitives/std.lib"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - a = std_reg(2); - b = std_reg(2); - c = std_reg(2); - @generated par_reset = std_reg(1); - @generated par_done_reg = std_reg(1); - @generated par_done_reg0 = std_reg(1); - @generated par_done_reg1 = std_reg(1); - } - wires { - group A { - a.in = 2'd0; - a.write_en = 1'd1; - A[done] = a.done; - } - group B { - b.in = 2'd1; - b.write_en = 1'd1; - B[done] = b.done; - } - group C { - c.in = 2'd2; - c.write_en = 1'd1; - C[done] = c.done; - } - group par { - A[go] = !(par_done_reg.out | A[done]) ? 1'd1; - par_done_reg.in = A[done] ? 1'd1; - par_done_reg.write_en = A[done] ? 1'd1; - B[go] = !(par_done_reg0.out | B[done]) ? 1'd1; - par_done_reg0.in = B[done] ? 1'd1; - par_done_reg0.write_en = B[done] ? 1'd1; - C[go] = !(par_done_reg1.out | C[done]) ? 1'd1; - par_done_reg1.in = C[done] ? 1'd1; - par_done_reg1.write_en = C[done] ? 1'd1; - par_reset.in = par_done_reg.out & par_done_reg0.out & par_done_reg1.out ? 1'd1; - par_reset.write_en = par_done_reg.out & par_done_reg0.out & par_done_reg1.out ? 1'd1; - par[done] = par_reset.out ? 1'd1; - } - par_reset.in = par_reset.out ? 1'd0; - par_reset.write_en = par_reset.out ? 1'd1; - par_done_reg.in = par_reset.out ? 1'd0; - par_done_reg.write_en = par_reset.out ? 1'd1; - par_done_reg0.in = par_reset.out ? 1'd0; - par_done_reg0.write_en = par_reset.out ? 1'd1; - par_done_reg1.in = par_reset.out ? 1'd0; - par_done_reg1.write_en = par_reset.out ? 1'd1; - } - - control { - par; - } -} diff --git a/tests/passes/compile-control/compile-seq-static.expect b/tests/passes/compile-control/compile-seq-static.expect deleted file mode 100644 index 053050da82..0000000000 --- a/tests/passes/compile-control/compile-seq-static.expect +++ /dev/null @@ -1,44 +0,0 @@ -import "primitives/std.lib"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - a = std_reg(2); - b = std_reg(2); - c = std_reg(2); - @generated fsm = std_reg(2); - } - wires { - group A<"static"=1> { - a.in = 2'd0; - a.write_en = 1'd1; - A[done] = a.done; - } - group B<"static"=1> { - b.in = 2'd1; - b.write_en = 1'd1; - B[done] = b.done; - } - group C<"static"=1> { - c.in = 2'd2; - c.write_en = 1'd1; - C[done] = c.done; - } - group seq { - A[go] = fsm.out == 2'd0 & !A[done] ? 1'd1; - fsm.in = fsm.out == 2'd0 & A[done] ? 2'd1; - fsm.write_en = fsm.out == 2'd0 & A[done] ? 1'd1; - B[go] = fsm.out == 2'd1 & !B[done] ? 1'd1; - fsm.in = fsm.out == 2'd1 & B[done] ? 2'd2; - fsm.write_en = fsm.out == 2'd1 & B[done] ? 1'd1; - C[go] = fsm.out == 2'd2 & !C[done] ? 1'd1; - fsm.in = fsm.out == 2'd2 & C[done] ? 2'd3; - fsm.write_en = fsm.out == 2'd2 & C[done] ? 1'd1; - seq[done] = fsm.out == 2'd3 ? 1'd1; - } - fsm.in = fsm.out == 2'd3 ? 2'd0; - fsm.write_en = fsm.out == 2'd3 ? 1'd1; - } - - control { - seq; - } -} diff --git a/tests/passes/compile-control/compile-seq.expect b/tests/passes/compile-control/compile-seq.expect deleted file mode 100644 index ccd77db5ba..0000000000 --- a/tests/passes/compile-control/compile-seq.expect +++ /dev/null @@ -1,44 +0,0 @@ -import "primitives/std.lib"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - a = std_reg(2); - b = std_reg(2); - c = std_reg(2); - @generated fsm = std_reg(2); - } - wires { - group A { - a.in = 2'd0; - a.write_en = 1'd1; - A[done] = a.done; - } - group B { - b.in = 2'd1; - b.write_en = 1'd1; - B[done] = b.done; - } - group C { - c.in = 2'd2; - c.write_en = 1'd1; - C[done] = c.done; - } - group seq { - A[go] = fsm.out == 2'd0 & !A[done] ? 1'd1; - fsm.in = fsm.out == 2'd0 & A[done] ? 2'd1; - fsm.write_en = fsm.out == 2'd0 & A[done] ? 1'd1; - B[go] = fsm.out == 2'd1 & !B[done] ? 1'd1; - fsm.in = fsm.out == 2'd1 & B[done] ? 2'd2; - fsm.write_en = fsm.out == 2'd1 & B[done] ? 1'd1; - C[go] = fsm.out == 2'd2 & !C[done] ? 1'd1; - fsm.in = fsm.out == 2'd2 & C[done] ? 2'd3; - fsm.write_en = fsm.out == 2'd2 & C[done] ? 1'd1; - seq[done] = fsm.out == 2'd3 ? 1'd1; - } - fsm.in = fsm.out == 2'd3 ? 2'd0; - fsm.write_en = fsm.out == 2'd3 ? 1'd1; - } - - control { - seq; - } -} diff --git a/tests/passes/compile-control/compile-while-static.expect b/tests/passes/compile-control/compile-while-static.expect deleted file mode 100644 index c03ae25311..0000000000 --- a/tests/passes/compile-control/compile-while-static.expect +++ /dev/null @@ -1,47 +0,0 @@ -import "primitives/std.lib"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add = std_add(32); - add_r = std_reg(32); - lt = std_lt(32); - lt_r = std_reg(1); - @generated fsm = std_reg(2); - @generated cond_stored = std_reg(1); - @generated incr = std_add(2); - } - wires { - group do_add<"static"=1> { - add.right = 32'd4; - add.left = 32'd4; - add_r.in = add.out; - add_r.write_en = 1'd1; - do_add[done] = add_r.done; - } - group cond<"static"=1> { - lt.right = 32'd5; - lt.left = 32'd1; - lt_r.in = lt.out; - lt_r.write_en = 1'd1; - cond[done] = lt_r.out; - } - group static_while { - incr.left = fsm.out; - incr.right = 2'd1; - fsm.in = fsm.out < 2'd2 | fsm.out >= 2'd2 & fsm.out < 2'd3 & cond_stored.out ? incr.out; - fsm.write_en = fsm.out < 2'd2 | fsm.out >= 2'd2 & fsm.out < 2'd3 & cond_stored.out ? 1'd1; - cond[go] = fsm.out < 2'd1 ? 1'd1; - cond_stored.write_en = fsm.out == 2'd1 ? 1'd1; - do_add[go] = cond_stored.out & fsm.out >= 2'd2 & fsm.out < 2'd3 ? 1'd1; - fsm.in = fsm.out == 2'd3 ? 2'd0; - fsm.write_en = fsm.out == 2'd3 ? 1'd1; - static_while[done] = fsm.out == 2'd2 & !cond_stored.out ? 1'd1; - cond_stored.in = fsm.out == 2'd1 ? lt_r.out; - } - fsm.in = fsm.out == 2'd2 & !cond_stored.out ? 2'd0; - fsm.write_en = fsm.out == 2'd2 & !cond_stored.out ? 1'd1; - } - - control { - static_while; - } -} diff --git a/tests/passes/compile-control/compile-while.expect b/tests/passes/compile-control/compile-while.expect deleted file mode 100644 index fd00cb5963..0000000000 --- a/tests/passes/compile-control/compile-while.expect +++ /dev/null @@ -1,43 +0,0 @@ -import "primitives/std.lib"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add = std_add(32); - lt = std_lt(32); - @generated cond_computed = std_reg(1); - @generated cond_stored = std_reg(1); - @generated done_reg = std_reg(1); - } - wires { - group do_add { - add.right = 32'd4; - add.left = 32'd4; - do_add[done] = 1'd1; - } - group cond { - lt.right = 32'd5; - lt.left = 32'd1; - cond[done] = 1'd1; - } - group while { - cond_stored.in = cond[go] & cond[done] ? lt.out; - cond[go] = !cond_computed.out ? 1'd1; - cond_computed.in = cond[go] & cond[done] ? 1'd1; - cond_computed.write_en = cond[go] & cond[done] ? 1'd1; - cond_stored.write_en = cond[go] & cond[done] ? 1'd1; - do_add[go] = cond_stored.out & cond_computed.out & !do_add[done] ? 1'd1; - cond_computed.in = cond_stored.out & cond_computed.out & do_add[done] ? 1'd0; - cond_computed.write_en = cond_stored.out & cond_computed.out & do_add[done] ? 1'd1; - done_reg.in = cond_computed.out & !cond_stored.out ? 1'd1; - done_reg.write_en = cond_computed.out & !cond_stored.out ? 1'd1; - while[done] = done_reg.out ? 1'd1; - cond_computed.in = cond_computed.out & !cond_stored.out ? 1'd0; - cond_computed.write_en = cond_computed.out & !cond_stored.out ? 1'd1; - } - done_reg.in = done_reg.out ? 1'd0; - done_reg.write_en = done_reg.out ? 1'd1; - } - - control { - while; - } -} From f3582320c8e0dc964b75ac078c3639e8a551069c Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 13:36:24 +0530 Subject: [PATCH 23/50] update some tests --- docs/tutorial/language-tut.md | 5 +- examples/futil/dot-product.futil | 3 +- examples/futil/vectorized-add.futil | 3 +- .../tutorial/language-tutorial-iterate.futil | 3 +- frontends/ntt-pipeline/gen-ntt-pipeline.py | 22 ++++---- tests/errors/comb-group-in-control.expect | 2 +- tests/errors/mismatch-widths.expect | 2 +- tests/frontend/dahlia/combine.expect | 3 +- tests/frontend/dahlia/for.expect | 3 +- tests/frontend/dahlia/if.expect | 3 +- tests/frontend/dahlia/invoke-memory.expect | 3 +- .../frontend/dahlia/matadd-fixed-point.expect | 6 +-- .../frontend/dahlia/signed_dotproduct.expect | 3 +- tests/frontend/dahlia/unroll.expect | 3 +- tests/frontend/exp/degree-2-unsigned.expect | 3 +- tests/frontend/exp/degree-4-signed.expect | 6 +-- tests/frontend/exp/degree-4-unsigned.expect | 3 +- .../batch_flatten-same-dimensions.expect | 6 +-- tests/frontend/relay/batch_flatten.expect | 9 ++-- tests/frontend/relay/batch_matmul.expect | 21 +++----- tests/frontend/relay/bias_add.expect | 12 ++--- tests/frontend/relay/broadcast.expect | 6 +-- tests/frontend/relay/constant-multiply.expect | 3 +- tests/frontend/relay/conv2d.expect | 21 +++----- tests/frontend/relay/dense.expect | 15 ++---- .../relay/duplicate-relay-call.expect | 12 ++--- tests/frontend/relay/max_pool2d.expect | 21 +++----- tests/frontend/relay/negative.expect | 3 +- tests/frontend/relay/relu.expect | 15 ++---- tests/frontend/relay/reshape.expect | 12 ++--- tests/frontend/relay/softmax.expect | 24 +++------ tests/frontend/relay/sqrt.expect | 6 +-- tests/frontend/relay/tensor_add.expect | 6 +-- tests/parsing/attributes.expect | 8 +-- tests/passes/compile-empty.expect | 4 +- tests/passes/compile-empty.futil | 3 +- tests/passes/infer-static/bounded-loop.expect | 9 ++-- tests/passes/infer-static/bounded-loop.futil | 3 +- .../minimize-regs/condition-register.futil | 6 ++- .../regressions/group-multi-drive.futil | 2 +- .../remove-comb-groups/comb-with-static.futil | 3 +- .../remove-comb-groups/multi-use.expect | 51 +++++++++++++------ .../passes/remove-comb-groups/multi-use.futil | 5 +- .../passes/resource-sharing/cond-port.expect | 20 +++++--- tests/passes/resource-sharing/cond-port.futil | 5 +- 45 files changed, 170 insertions(+), 217 deletions(-) diff --git a/docs/tutorial/language-tut.md b/docs/tutorial/language-tut.md index cc4b1af22f..f02946f5ff 100644 --- a/docs/tutorial/language-tut.md +++ b/docs/tutorial/language-tut.md @@ -247,8 +247,9 @@ Next, the `incr` group adds one to the value in `counter` using `add2`: {{#include ../../examples/tutorial/language-tutorial-iterate.futil:incr}} ``` -And finally, `cond` uses our comparator `lt` to compute the signal we need for our `while` loop: - +And finally, `cond` uses our comparator `lt` to compute the signal we need for +our `while` loop. We use a `comb group` to denote that the assignments inside +the condition can be run combinationally: ``` {{#include ../../examples/tutorial/language-tutorial-iterate.futil:cond}} ``` diff --git a/examples/futil/dot-product.futil b/examples/futil/dot-product.futil index 5cd9ab0c63..8a79ff7988 100644 --- a/examples/futil/dot-product.futil +++ b/examples/futil/dot-product.futil @@ -20,8 +20,7 @@ component main() -> () { @external(1) v0 = std_mem_d1(32,1,1); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const1.out; } diff --git a/examples/futil/vectorized-add.futil b/examples/futil/vectorized-add.futil index 81f6e53013..51804c6270 100644 --- a/examples/futil/vectorized-add.futil +++ b/examples/futil/vectorized-add.futil @@ -15,8 +15,7 @@ component main() -> () { le0 = std_le(4); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const1.out; } diff --git a/examples/tutorial/language-tutorial-iterate.futil b/examples/tutorial/language-tutorial-iterate.futil index aa06563ada..bbd04fb783 100644 --- a/examples/tutorial/language-tutorial-iterate.futil +++ b/examples/tutorial/language-tutorial-iterate.futil @@ -55,10 +55,9 @@ component main() -> () { // ANCHOR_END: incr // ANCHOR: cond - group cond { + comb group cond { lt.left = counter.out; lt.right = 32'd8; - cond[done] = 1'b1; } // ANCHOR_END: cond } diff --git a/frontends/ntt-pipeline/gen-ntt-pipeline.py b/frontends/ntt-pipeline/gen-ntt-pipeline.py index 94801c14f9..e558d7c944 100644 --- a/frontends/ntt-pipeline/gen-ntt-pipeline.py +++ b/frontends/ntt-pipeline/gen-ntt-pipeline.py @@ -266,6 +266,8 @@ def cells(): n, bitwidth), is_external=True), ] r_regs = [ + Cell(CompVar(f"r{r}"), stdlib.register(input_bitwidth)) for r in range(n) + ] A_regs = [ Cell(CompVar(f"A{r}"), stdlib.register(input_bitwidth)) for r in range(n) ] @@ -378,23 +380,23 @@ def control(): input_bitwidth, input_size, modulus = None, None, None required_fields = [args.input_bitwidth, args.input_size, args.modulus] if all(map(lambda x: x is not None, required_fields)): - input_bitwidth=args.input_bitwidth - input_size=args.input_size - modulus=args.modulus - parallel_reduction=args.parallel_reduction + input_bitwidth = args.input_bitwidth + input_size = args.input_size + modulus = args.modulus + parallel_reduction = args.parallel_reduction elif args.file is not None: with open(args.file, "r") as f: - spec=json.load(f) - input_bitwidth=spec["input_bitwidth"] - input_size=spec["input_size"] - modulus=spec["modulus"] - parallel_reduction=spec.get("parallel_reduction") + spec = json.load(f) + input_bitwidth = spec["input_bitwidth"] + input_size = spec["input_size"] + modulus = spec["modulus"] + parallel_reduction = spec.get("parallel_reduction") else: parser.error( "Need to pass either `-f FILE` or all of `-b INPUT_BITWIDTH -n INPUT_SIZE -q MODULUS`" ) - program=generate_ntt_pipeline(input_bitwidth, input_size, modulus) + program = generate_ntt_pipeline(input_bitwidth, input_size, modulus) if parallel_reduction is not None: for c in program.components: diff --git a/tests/errors/comb-group-in-control.expect b/tests/errors/comb-group-in-control.expect index d73e4d4f53..f8de0fe0eb 100644 --- a/tests/errors/comb-group-in-control.expect +++ b/tests/errors/comb-group-in-control.expect @@ -3,4 +3,4 @@ ---STDERR--- Error: Malformed Structure: 7 | group a { - | ^ Group with constant done condition not allowed inside normal control operators + | ^ Group with constant done condition are invalid. Use `comb group` instead to define a combinational group. diff --git a/tests/errors/mismatch-widths.expect b/tests/errors/mismatch-widths.expect index 8a1264fa7c..e26c56d67c 100644 --- a/tests/errors/mismatch-widths.expect +++ b/tests/errors/mismatch-widths.expect @@ -1,5 +1,5 @@ ---CODE--- 101 ---STDERR--- -thread 'main' panicked at 'Invalid assignment. `x.out' and `add.left' have different widths', calyx/src/ir/builder.rs:182:9 +thread 'main' panicked at 'Invalid assignment. `x.out' and `add.left' have different widths', calyx/src/ir/builder.rs:203:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/frontend/dahlia/combine.expect b/tests/frontend/dahlia/combine.expect index ad2ab9067a..48ded1ebee 100644 --- a/tests/frontend/dahlia/combine.expect +++ b/tests/frontend/dahlia/combine.expect @@ -13,8 +13,7 @@ component main() -> () { res_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const1.out; } diff --git a/tests/frontend/dahlia/for.expect b/tests/frontend/dahlia/for.expect index e13cbf42fe..6eeb36dd4c 100644 --- a/tests/frontend/dahlia/for.expect +++ b/tests/frontend/dahlia/for.expect @@ -9,8 +9,7 @@ component main() -> () { le0 = std_le(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const1.out; } diff --git a/tests/frontend/dahlia/if.expect b/tests/frontend/dahlia/if.expect index 206acffba3..dcbef038f2 100644 --- a/tests/frontend/dahlia/if.expect +++ b/tests/frontend/dahlia/if.expect @@ -10,8 +10,7 @@ component main() -> () { y_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { lt0.left = const0.out; lt0.right = const1.out; } diff --git a/tests/frontend/dahlia/invoke-memory.expect b/tests/frontend/dahlia/invoke-memory.expect index 6b2ef0829b..911bd79ee6 100644 --- a/tests/frontend/dahlia/invoke-memory.expect +++ b/tests/frontend/dahlia/invoke-memory.expect @@ -7,8 +7,7 @@ component mem_copy(dest0_read_data: 32, dest0_done: 1, src0_read_data: 32, src0_ src_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { lt0.left = i_0.out; lt0.right = length; } diff --git a/tests/frontend/dahlia/matadd-fixed-point.expect b/tests/frontend/dahlia/matadd-fixed-point.expect index 9311cbd315..e428b73c26 100644 --- a/tests/frontend/dahlia/matadd-fixed-point.expect +++ b/tests/frontend/dahlia/matadd-fixed-point.expect @@ -21,13 +21,11 @@ component main() -> () { @external(1) result0_00_0 = std_mem_d2(16,2,2,2,2); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = j0.out; le1.right = const3.out; } diff --git a/tests/frontend/dahlia/signed_dotproduct.expect b/tests/frontend/dahlia/signed_dotproduct.expect index 50e753c41b..f98641e74b 100644 --- a/tests/frontend/dahlia/signed_dotproduct.expect +++ b/tests/frontend/dahlia/signed_dotproduct.expect @@ -22,8 +22,7 @@ component main() -> () { v_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const2.out; } diff --git a/tests/frontend/dahlia/unroll.expect b/tests/frontend/dahlia/unroll.expect index b467f517e2..7b0405d58c 100644 --- a/tests/frontend/dahlia/unroll.expect +++ b/tests/frontend/dahlia/unroll.expect @@ -26,8 +26,7 @@ component main() -> () { slice3 = std_slice(4,2); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const1.out; } diff --git a/tests/frontend/exp/degree-2-unsigned.expect b/tests/frontend/exp/degree-2-unsigned.expect index 8f54b34e2f..360dd67764 100644 --- a/tests/frontend/exp/degree-2-unsigned.expect +++ b/tests/frontend/exp/degree-2-unsigned.expect @@ -130,10 +130,9 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { count.write_en = 1'd1; incr_count[done] = count.done; } - group cond { + comb group cond { lt.left = count.out; lt.right = integer_exp; - cond[done] = 1'd1; } out = pow.out; } diff --git a/tests/frontend/exp/degree-4-signed.expect b/tests/frontend/exp/degree-4-signed.expect index 90812614e4..c6fc641fca 100644 --- a/tests/frontend/exp/degree-4-signed.expect +++ b/tests/frontend/exp/degree-4-signed.expect @@ -65,10 +65,9 @@ component exp(x: 16) -> (out: 16) { exponent_value.in = mult_pipe1.out; negate[done] = exponent_value.done; } - group is_negative<"static"=0> { + comb group is_negative { lt.left = x; lt.right = 16'd0; - is_negative[done] = 1'd1; } group reciprocal { div_pipe.left = one.out; @@ -224,10 +223,9 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { count.write_en = 1'd1; incr_count[done] = count.done; } - group cond { + comb group cond { lt.left = count.out; lt.right = integer_exp; - cond[done] = 1'd1; } out = pow.out; } diff --git a/tests/frontend/exp/degree-4-unsigned.expect b/tests/frontend/exp/degree-4-unsigned.expect index 9538eaf2fe..123e43338a 100644 --- a/tests/frontend/exp/degree-4-unsigned.expect +++ b/tests/frontend/exp/degree-4-unsigned.expect @@ -194,10 +194,9 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { count.write_en = 1'd1; incr_count[done] = count.done; } - group cond { + comb group cond { lt.left = count.out; lt.right = integer_exp; - cond[done] = 1'd1; } out = pow.out; } diff --git a/tests/frontend/relay/batch_flatten-same-dimensions.expect b/tests/frontend/relay/batch_flatten-same-dimensions.expect index 287e607036..68db933dad 100644 --- a/tests/frontend/relay/batch_flatten-same-dimensions.expect +++ b/tests/frontend/relay/batch_flatten-same-dimensions.expect @@ -36,13 +36,11 @@ component batch_flatten_2x4096(x0_0_read_data: 32, x0_0_done: 1, x10_0_read_data x_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const2.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const4.out; } diff --git a/tests/frontend/relay/batch_flatten.expect b/tests/frontend/relay/batch_flatten.expect index 27c3f8401a..487dcf8f5d 100644 --- a/tests/frontend/relay/batch_flatten.expect +++ b/tests/frontend/relay/batch_flatten.expect @@ -42,18 +42,15 @@ component batch_flatten_1x4(x0_0_0_read_data: 32, x0_0_0_done: 1, x10_0_read_dat x_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const2.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const4.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __k0.out; le2.right = const6.out; } diff --git a/tests/frontend/relay/batch_matmul.expect b/tests/frontend/relay/batch_matmul.expect index 19ac9a61f6..7d62a21d54 100644 --- a/tests/frontend/relay/batch_matmul.expect +++ b/tests/frontend/relay/batch_matmul.expect @@ -71,38 +71,31 @@ component batch_matmul_4x7x7(a0_0_0_read_data: 32, a0_0_0_done: 1, b0_0_0_read_d red_read00 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __batch0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __i0.out; le1.right = const3.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __j0.out; le2.right = const5.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le3.left = __batch1.out; le3.right = const10.out; } - group cond4<"static"=0> { - cond4[done] = 1'd1; + comb group cond4 { le4.left = __i1.out; le4.right = const12.out; } - group cond5<"static"=0> { - cond5[done] = 1'd1; + comb group cond5 { le5.left = __j1.out; le5.right = const14.out; } - group cond6<"static"=0> { - cond6[done] = 1'd1; + comb group cond6 { le6.left = __k0.out; le6.right = const16.out; } diff --git a/tests/frontend/relay/bias_add.expect b/tests/frontend/relay/bias_add.expect index 17701a735e..2e8439d902 100644 --- a/tests/frontend/relay/bias_add.expect +++ b/tests/frontend/relay/bias_add.expect @@ -47,23 +47,19 @@ component bias_add_1x64x512x256(x0_0_0_0_read_data: 32, x0_0_0_0_done: 1, bias0_ x_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const3.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __k0.out; le2.right = const5.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le3.left = __l0.out; le3.right = const7.out; } diff --git a/tests/frontend/relay/broadcast.expect b/tests/frontend/relay/broadcast.expect index 955ba10b9c..a516aba980 100644 --- a/tests/frontend/relay/broadcast.expect +++ b/tests/frontend/relay/broadcast.expect @@ -36,13 +36,11 @@ component add_2x4(x0_0_read_data: 32, x0_0_done: 1, y0_0_read_data: 32, y0_0_don y_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const3.out; } diff --git a/tests/frontend/relay/constant-multiply.expect b/tests/frontend/relay/constant-multiply.expect index 6a0a86d6d0..034cd7af3d 100644 --- a/tests/frontend/relay/constant-multiply.expect +++ b/tests/frontend/relay/constant-multiply.expect @@ -29,8 +29,7 @@ component multiply_1(x0_read_data: 32, x0_done: 1, x1: 32, x20_read_data: 32, x2 x_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } diff --git a/tests/frontend/relay/conv2d.expect b/tests/frontend/relay/conv2d.expect index 62cfa85181..f0f997b452 100644 --- a/tests/frontend/relay/conv2d.expect +++ b/tests/frontend/relay/conv2d.expect @@ -91,38 +91,31 @@ component conv2d_5x512x14x14(data0_0_0_0_read_data: 32, data0_0_0_0_done: 1, wei weight_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __b0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __c0.out; le1.right = const3.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __y0.out; le2.right = const5.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le3.left = __x0.out; le3.right = const7.out; } - group cond4<"static"=0> { - cond4[done] = 1'd1; + comb group cond4 { le4.left = __k0.out; le4.right = const10.out; } - group cond5<"static"=0> { - cond5[done] = 1'd1; + comb group cond5 { le5.left = __dy0.out; le5.right = const12.out; } - group cond6<"static"=0> { - cond6[done] = 1'd1; + comb group cond6 { le6.left = __dx0.out; le6.right = const14.out; } diff --git a/tests/frontend/relay/dense.expect b/tests/frontend/relay/dense.expect index 098c8f5554..6ee5c44b5e 100644 --- a/tests/frontend/relay/dense.expect +++ b/tests/frontend/relay/dense.expect @@ -59,28 +59,23 @@ component dense_1x10(x0_0_read_data: 32, x0_0_done: 1, y0_0_read_data: 32, y0_0_ y_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const3.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __i1.out; le2.right = const7.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le3.left = __j1.out; le3.right = const9.out; } - group cond4<"static"=0> { - cond4[done] = 1'd1; + comb group cond4 { le4.left = __k0.out; le4.right = const11.out; } diff --git a/tests/frontend/relay/duplicate-relay-call.expect b/tests/frontend/relay/duplicate-relay-call.expect index 13838c7205..ad9c8c27cd 100644 --- a/tests/frontend/relay/duplicate-relay-call.expect +++ b/tests/frontend/relay/duplicate-relay-call.expect @@ -37,13 +37,11 @@ component negative_2x2_1(x10_0_read_data: 32, x10_0_done: 1, x20_0_read_data: 32 x1_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const3.out; } @@ -126,13 +124,11 @@ component negative_2x2(x0_0_read_data: 32, x0_0_done: 1, x10_0_read_data: 32, x1 x_read0_0 = std_reg(32); } wires { - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __i1.out; le2.right = const8.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le3.left = __j1.out; le3.right = const10.out; } diff --git a/tests/frontend/relay/max_pool2d.expect b/tests/frontend/relay/max_pool2d.expect index 3afd65778d..a101a6c2a5 100644 --- a/tests/frontend/relay/max_pool2d.expect +++ b/tests/frontend/relay/max_pool2d.expect @@ -82,38 +82,31 @@ component max_pool2d_2x2x2x2(data0_0_0_0_read_data: 32, data0_0_0_0_done: 1, res slice9 = std_slice(32,2); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __b0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __c0.out; le1.right = const3.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __y0.out; le2.right = const5.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le3.left = __x0.out; le3.right = const7.out; } - group cond4<"static"=0> { - cond4[done] = 1'd1; + comb group cond4 { le4.left = __m0.out; le4.right = const11.out; } - group cond5<"static"=0> { - cond5[done] = 1'd1; + comb group cond5 { le5.left = __n0.out; le5.right = const13.out; } - group cond6<"static"=0> { - cond6[done] = 1'd1; + comb group cond6 { gt0.left = __current_0.out; gt0.right = __max_0.out; } diff --git a/tests/frontend/relay/negative.expect b/tests/frontend/relay/negative.expect index 7db547beef..0409f66ce5 100644 --- a/tests/frontend/relay/negative.expect +++ b/tests/frontend/relay/negative.expect @@ -28,8 +28,7 @@ component negative_4(x0_read_data: 32, x0_done: 1, x10_read_data: 32, x10_done: x_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } diff --git a/tests/frontend/relay/relu.expect b/tests/frontend/relay/relu.expect index 0a48081edb..27d174d776 100644 --- a/tests/frontend/relay/relu.expect +++ b/tests/frontend/relay/relu.expect @@ -48,28 +48,23 @@ component relu_2x4x8x32(x0_0_0_0_read_data: 32, x0_0_0_0_done: 1, x10_0_0_0_read x_read1_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const3.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __k0.out; le2.right = const5.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le3.left = __l0.out; le3.right = const7.out; } - group cond4<"static"=0> { - cond4[done] = 1'd1; + comb group cond4 { gt0.left = x_read0_0.out; gt0.right = fp_const0.out; } diff --git a/tests/frontend/relay/reshape.expect b/tests/frontend/relay/reshape.expect index 15bad9b473..4f068f1a3b 100644 --- a/tests/frontend/relay/reshape.expect +++ b/tests/frontend/relay/reshape.expect @@ -49,23 +49,19 @@ component reshape_1x8(x0_0_0_0_read_data: 32, x0_0_0_0_done: 1, x10_0_read_data: x_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const2.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const4.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = __k0.out; le2.right = const6.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le3.left = __l0.out; le3.right = const8.out; } diff --git a/tests/frontend/relay/softmax.expect b/tests/frontend/relay/softmax.expect index 746e21cbd8..dccaa0d9e5 100644 --- a/tests/frontend/relay/softmax.expect +++ b/tests/frontend/relay/softmax.expect @@ -70,33 +70,27 @@ component softmax_1x10(x0_0_read_data: 32, x0_0_done: 1, x10_0_read_data: 32, x1 x_read3_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const3.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const5.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { gt0.left = x_read0_0.out; gt0.right = __max_0.out; } - group cond3<"static"=0> { - cond3[done] = 1'd1; + comb group cond3 { le2.left = __i1.out; le2.right = const9.out; } - group cond4<"static"=0> { - cond4[done] = 1'd1; + comb group cond4 { le3.left = __j1.out; le3.right = const11.out; } - group cond5<"static"=0> { - cond5[done] = 1'd1; + comb group cond5 { le4.left = __k0.out; le4.right = const14.out; } @@ -405,10 +399,9 @@ component exp(x: 32) -> (out: 32) { exponent_value.in = mult_pipe1.out; negate[done] = exponent_value.done; } - group is_negative<"static"=0> { + comb group is_negative { lt.left = x; lt.right = 32'd0; - is_negative[done] = 1'd1; } group reciprocal { div_pipe.left = one.out; @@ -662,10 +655,9 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { count.write_en = 1'd1; incr_count[done] = count.done; } - group cond { + comb group cond { lt.left = count.out; lt.right = integer_exp; - cond[done] = 1'd1; } out = pow.out; } diff --git a/tests/frontend/relay/sqrt.expect b/tests/frontend/relay/sqrt.expect index 8fcf605bf0..ecb613a968 100644 --- a/tests/frontend/relay/sqrt.expect +++ b/tests/frontend/relay/sqrt.expect @@ -34,13 +34,11 @@ component sqrt_1x4(x0_0_read_data: 32, x0_0_done: 1, x10_0_read_data: 32, x10_0_ x_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const3.out; } diff --git a/tests/frontend/relay/tensor_add.expect b/tests/frontend/relay/tensor_add.expect index 8a8e7bdeeb..f3bcb122b1 100644 --- a/tests/frontend/relay/tensor_add.expect +++ b/tests/frontend/relay/tensor_add.expect @@ -35,13 +35,11 @@ component add_2x4(x0_0_read_data: 32, x0_0_done: 1, y0_0_read_data: 32, y0_0_don y_read0_0 = std_reg(32); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = __i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = __j0.out; le1.right = const3.out; } diff --git a/tests/parsing/attributes.expect b/tests/parsing/attributes.expect index 07f06d2446..e3100ab8f7 100644 --- a/tests/parsing/attributes.expect +++ b/tests/parsing/attributes.expect @@ -6,14 +6,16 @@ component main<"static"=1>(@stable(32) @go_port in: 32, go: 1, clk: 1, @go go0: @external(32) le = std_le(32); } wires { - group cond<"stable"=1> { - cond[done] = 1'd1; + group upd<"stable"=1> { + upd[done] = r.done; + } + comb group cond<"stable"=0> { } } control { @bound(32) while le.out with cond { - cond; + upd; } } } diff --git a/tests/passes/compile-empty.expect b/tests/passes/compile-empty.expect index 255adb1e09..50a12bc2be 100644 --- a/tests/passes/compile-empty.expect +++ b/tests/passes/compile-empty.expect @@ -15,10 +15,12 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { empty_reg.in = 1'd1; _empty[done] = empty_reg.done; } + comb group cond { + } } control { - if r.out with do_incr { + if r.out with cond { do_incr; } else { _empty; diff --git a/tests/passes/compile-empty.futil b/tests/passes/compile-empty.futil index 458d399a9d..7867f05656 100644 --- a/tests/passes/compile-empty.futil +++ b/tests/passes/compile-empty.futil @@ -6,6 +6,7 @@ component main() -> () { r = std_reg(1); } wires { + comb group cond {} group do_incr { r.in = 1'd1; r.write_en = 1'd1; @@ -13,7 +14,7 @@ component main() -> () { } } control { - if r.out with do_incr { + if r.out with cond { do_incr; } } diff --git a/tests/passes/infer-static/bounded-loop.expect b/tests/passes/infer-static/bounded-loop.expect index ac025c8291..835a8a9091 100644 --- a/tests/passes/infer-static/bounded-loop.expect +++ b/tests/passes/infer-static/bounded-loop.expect @@ -7,11 +7,6 @@ component main<"static"=10>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done d add = std_add(32); } wires { - group cond<"static"=0> { - lt.left = i.read_data; - lt.right = 32'd5; - cond[done] = 1'd1; - } group incr_i<"static"=1> { i.write_data = add.out; i.addr0 = 1'd0; @@ -28,6 +23,10 @@ component main<"static"=10>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done d add.left = 32'd1; incr_j[done] = j.done; } + comb group cond { + lt.left = i.read_data; + lt.right = 32'd5; + } } control { diff --git a/tests/passes/infer-static/bounded-loop.futil b/tests/passes/infer-static/bounded-loop.futil index a66d1577b7..bf5a1105e4 100644 --- a/tests/passes/infer-static/bounded-loop.futil +++ b/tests/passes/infer-static/bounded-loop.futil @@ -11,10 +11,9 @@ component main() -> () { } wires { - group cond<"static"=0> { + comb group cond { lt.left = i.read_data; lt.right = 32'd5; - cond[done] = 1'b1; } group incr_i<"static"=1> { diff --git a/tests/passes/minimize-regs/condition-register.futil b/tests/passes/minimize-regs/condition-register.futil index 0b41781573..e7c6e71207 100644 --- a/tests/passes/minimize-regs/condition-register.futil +++ b/tests/passes/minimize-regs/condition-register.futil @@ -48,11 +48,13 @@ component main() -> () { control { seq { wr_x; - if y.out with cond { + cond; + if y.out { some_math; } wr_z; - while z.out with cond1 { + cond1; + while z.out { some_math1; } } diff --git a/tests/passes/regressions/group-multi-drive.futil b/tests/passes/regressions/group-multi-drive.futil index 372c214fab..f0f1554881 100644 --- a/tests/passes/regressions/group-multi-drive.futil +++ b/tests/passes/regressions/group-multi-drive.futil @@ -1,4 +1,4 @@ -// -p all -d infer-static-timing -d static-timing -d well-formed -d papercut -d resource-sharing -p simplify-guards +// -p all -d infer-static-timing -d well-formed -d papercut -d resource-sharing -p simplify-guards import "primitives/std.lib"; component main() -> () { diff --git a/tests/passes/remove-comb-groups/comb-with-static.futil b/tests/passes/remove-comb-groups/comb-with-static.futil index db65adde1d..948b2e65eb 100644 --- a/tests/passes/remove-comb-groups/comb-with-static.futil +++ b/tests/passes/remove-comb-groups/comb-with-static.futil @@ -6,10 +6,9 @@ component main<"static"=1>(in: 32) -> () { r = std_reg(32); } wires { - group find_index { + comb group find_index { e0.left = in; e0.right = 32'd1; - find_index[done] = 1'd1; } group write { diff --git a/tests/passes/remove-comb-groups/multi-use.expect b/tests/passes/remove-comb-groups/multi-use.expect index 31840aabd9..4423f630e2 100644 --- a/tests/passes/remove-comb-groups/multi-use.expect +++ b/tests/passes/remove-comb-groups/multi-use.expect @@ -12,7 +12,12 @@ component main(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: @generated comb_reg2 = std_reg(1); } wires { - group find_index<"static"=1> { + group write { + r.write_en = 1'd1; + r.in = 32'd1; + write[done] = r.done; + } + group find_index0<"static"=1> { e0.left = in; e0.right = 32'd1; e1.left = in; @@ -21,7 +26,6 @@ component main(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: e2.right = 32'd2; e3.left = in; e3.right = 32'd3; - find_index[done] = comb_reg.done & comb_reg0.done & comb_reg1.done & comb_reg2.done ? 1'd1; comb_reg.in = e0.out; comb_reg.write_en = 1'd1; comb_reg0.in = e1.out; @@ -30,27 +34,44 @@ component main(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: comb_reg1.write_en = 1'd1; comb_reg2.in = e3.out; comb_reg2.write_en = 1'd1; - } - group write { - r.write_en = 1'd1; - r.in = 32'd1; - write[done] = r.done; + find_index0[done] = comb_reg.done & comb_reg0.done & comb_reg1.done & comb_reg2.done ? 1'd1; } } control { par { - if comb_reg.out with find_index { - write; + seq { + find_index0; + if comb_reg.out { + write; + } + } + seq { + find_index0; + if comb_reg0.out { + write; + } } - if comb_reg0.out with find_index { - write; + seq { + find_index0; + if comb_reg1.out { + write; + } } - if comb_reg1.out with find_index { - write; + seq { + find_index0; + if comb_reg2.out { + write; + } } - if comb_reg2.out with find_index { - write; + seq { + find_index0; + while comb_reg.out { + seq { + write; + find_index0; + } + } } } } diff --git a/tests/passes/remove-comb-groups/multi-use.futil b/tests/passes/remove-comb-groups/multi-use.futil index 347b549a4b..82995b7a67 100644 --- a/tests/passes/remove-comb-groups/multi-use.futil +++ b/tests/passes/remove-comb-groups/multi-use.futil @@ -9,7 +9,7 @@ component main(in: 32) -> () { r = std_reg(32); } wires { - group find_index { + comb group find_index { e0.left = in; e0.right = 32'd1; @@ -21,8 +21,6 @@ component main(in: 32) -> () { e3.left = in; e3.right = 32'd3; - - find_index[done] = 1'd1; } group write { @@ -37,6 +35,7 @@ component main(in: 32) -> () { if e1.out with find_index { write; } if e2.out with find_index { write; } if e3.out with find_index { write; } + while e0.out with find_index { write; } } } } diff --git a/tests/passes/resource-sharing/cond-port.expect b/tests/passes/resource-sharing/cond-port.expect index 3e0d5993c3..91dea43fcc 100644 --- a/tests/passes/resource-sharing/cond-port.expect +++ b/tests/passes/resource-sharing/cond-port.expect @@ -5,13 +5,9 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { gt1 = std_gt(32); x_0 = std_reg(32); y_0 = std_reg(1); + @generated comb_reg = std_reg(1); } wires { - group cond0 { - cond0[done] = 1'd1; - gt0.left = x_0.out; - gt0.right = 32'd2; - } group let0 { x_0.in = 32'd1; x_0.write_en = 1'd1; @@ -29,14 +25,24 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { x_0.in = 32'd10; upd0[done] = x_0.done ? 1'd1; } + group cond00<"static"=1> { + gt0.left = x_0.out; + gt0.right = 32'd2; + comb_reg.in = gt0.out; + comb_reg.write_en = 1'd1; + cond00[done] = comb_reg.done ? 1'd1; + } } control { seq { let0; let1; - if gt0.out with cond0 { - upd0; + seq { + cond00; + if comb_reg.out { + upd0; + } } } } diff --git a/tests/passes/resource-sharing/cond-port.futil b/tests/passes/resource-sharing/cond-port.futil index 68ae2764a4..397c52ec1e 100644 --- a/tests/passes/resource-sharing/cond-port.futil +++ b/tests/passes/resource-sharing/cond-port.futil @@ -1,4 +1,4 @@ -// -p resource-sharing +// -p remove-comb-groups -p resource-sharing import "primitives/std.lib"; component main() -> () { cells { @@ -8,8 +8,7 @@ component main() -> () { y_0 = std_reg(1); } wires { - group cond0 { - cond0[done] = 1'd1; + comb group cond0 { gt1.left = x_0.out; gt1.right = 32'd2; } From 1ad00a3c3ee715e5d9bcf4ebb3797fee45fc21b0 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 13:52:52 +0530 Subject: [PATCH 24/50] fix bug introduced in tdcc --- calyx/src/passes/top_down_compile_control.rs | 64 ++++++++++---------- runt.toml | 13 ++-- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index e4b96940fe..b76b2e0843 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -22,8 +22,6 @@ struct Schedule { pub enables: HashMap>, /// Transition from one state to another when the guard is true. pub transitions: Vec<(u64, u64, ir::Guard)>, - /// Assignments that are always active - pub always_active: Vec, } impl Schedule { @@ -76,12 +74,6 @@ impl Schedule { .for_each(|(i, f, g)| { eprintln!("({}, {}): {}", i, f, IRPrinter::guard_str(g)); }); - eprintln!("-----Always Active-----"); - self.always_active.iter().for_each(|assign| { - IRPrinter::write_assignment(assign, 0, &mut std::io::stderr()) - .expect("Printing failed!"); - eprintln!(); - }) } /// Implement a given [Schedule] and return the name of the [ir::Group] that @@ -144,12 +136,6 @@ impl Schedule { }), ); - // Always active assignments - group - .borrow_mut() - .assignments - .extend(self.always_active.into_iter()); - // Done condition for group let last_guard = guard!(fsm["out"]).eq(guard!(last_state["out"])); let done_assign = builder.build_assignment( @@ -173,7 +159,7 @@ impl Schedule { } } -/// Computes the exit points of a given [ir::Control] program. +/// Computes the entry and exit points of a given [ir::Control] program. /// /// ## Example /// In the following Calyx program: @@ -199,31 +185,44 @@ impl Schedule { /// } /// ``` /// The exit set is `[true, false]`. -fn control_exits(con: &ir::Control, exits: &mut Vec<(u64, RRC)>) { +fn control_exits( + con: &ir::Control, + cur_state: u64, + is_exit: bool, + exits: &mut Vec<(u64, RRC)>, +) -> u64 { match con { - ir::Control::Enable(ir::Enable { attributes, group, .. }) => { - let cur_state = attributes - .get("node_id") - .expect("Group does not have node_id"); - exits.push((*cur_state, Rc::clone(group))) + ir::Control::Enable(ir::Enable { group, .. }) => { + if is_exit { + exits.push((cur_state, Rc::clone(group))) + } + cur_state + 1 } ir::Control::Seq(ir::Seq { stmts, .. }) => { - if let Some(con) = stmts.iter().last() { - control_exits(con, exits); + let len = stmts.len(); + let mut cur = cur_state; + for (idx, stmt) in stmts.iter().enumerate() { + let exit = idx == len - 1 && is_exit; + cur = control_exits(stmt, cur, exit, exits); } + cur } ir::Control::If(ir::If { tbranch, fbranch, .. }) => { - control_exits(tbranch, exits); - control_exits(fbranch, exits) - } - ir::Control::While(ir::While { body, .. }) => { - control_exits(body, exits) + let tru_nxt = control_exits( + tbranch, cur_state, is_exit, exits, + ); + control_exits( + fbranch, tru_nxt, is_exit, exits, + ) } - ir::Control::Empty(..) - | ir::Control::Par(..) - | ir::Control::Invoke(..) => unreachable!() + ir::Control::While(ir::While { body, .. }) => control_exits( + body, cur_state, is_exit, exits, + ), + ir::Control::Invoke(_) => unreachable!("`invoke` statements should have been compiled away. Run `{}` before this pass.", passes::CompileInvoke::name()), + ir::Control::Empty(_) => unreachable!("`invoke` statements should have been compiled away. Run `{}` before this pass.", passes::CompileEmpty::name()), + ir::Control::Par(_) => unreachable!(), } } @@ -350,6 +349,8 @@ fn calculate_states_recur( let mut exits = vec![]; control_exits( body, + cur_state, + true, &mut exits, ); let back_edge_prevs = exits.into_iter().map(|(st, group)| (st, group.borrow().get("done").into())); @@ -607,7 +608,6 @@ impl Visitor for TopDownCompileControl { let mut builder = ir::Builder::new(comp, sigs); // Add assignments for the final states let schedule = calculate_states(&control.borrow(), &mut builder)?; - schedule.display(); let comp_group = schedule.realize_schedule(&mut builder); Ok(Action::Change(ir::Control::enable(comp_group))) diff --git a/runt.toml b/runt.toml index 8c6cb77e2d..bb00452506 100644 --- a/runt.toml +++ b/runt.toml @@ -5,7 +5,6 @@ ver = "0.3.2" [[tests]] name = "[core] passes" paths = [ - "tests/passes/*.futil", "tests/passes/**/*.futil", ] # gets the pass flags a comment on the first line of the test file @@ -203,21 +202,27 @@ python3 {} name = "language tutorial" paths = ["examples/tutorial/*.futil"] cmd = """ -fud e {} --to dat -s verilog.data examples/tutorial/data.json -q +fud e {} -s verilog.cycle_limit 500 \ + -s verilog.data examples/tutorial/data.json \ + --to dat -q """ [[tests]] name = "memory by reference tutorial" paths = ["examples/futil/memory-by-reference/*.futil"] cmd = """ -fud e {} --to dat -s verilog.data {}.data -q +fud e {} -s verilog.cycle_limit 500 \ + -s verilog.data examples/tutorial/data.json \ + --to dat -q """ [[tests]] name = "dahlia examples" paths = ["examples/dahlia/*.fuse"] cmd = """ -fud e {} --to dat -s verilog.data {}.data -q +fud e {} -s verilog.cycle_limit 500 \ + -s verilog.data examples/tutorial/data.json \ + --to dat -q """ [[tests]] From 5e283f59850f5ca645479c5f788aceb17b399292 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 15:19:11 +0530 Subject: [PATCH 25/50] mechanism to pass cli option to passes --- calyx/src/ir/context.rs | 3 + calyx/src/ir/from_ast.rs | 1 + calyx/src/passes/top_down_compile_control.rs | 74 ++++++++++++++------ src/cmdline.rs | 4 ++ src/main.rs | 9 +-- 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/calyx/src/ir/context.rs b/calyx/src/ir/context.rs index 1da1200546..1972ac6a97 100644 --- a/calyx/src/ir/context.rs +++ b/calyx/src/ir/context.rs @@ -57,4 +57,7 @@ pub struct Context { pub enable_verification: bool, /// Original import statements. pub imports: Vec, + /// Extra options provided to the command line. Interperted by individual + /// passes + pub extra_opts: Vec, } diff --git a/calyx/src/ir/from_ast.rs b/calyx/src/ir/from_ast.rs index 6d54bb1f0f..e89a196c49 100644 --- a/calyx/src/ir/from_ast.rs +++ b/calyx/src/ir/from_ast.rs @@ -142,6 +142,7 @@ pub fn ast_to_ir( imports: namespace.imports, enable_verification, synthesis_mode, + extra_opts: vec![], }) } diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index b76b2e0843..ac5df6ab71 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -1,5 +1,6 @@ use super::math_utilities::get_bit_width_from; use crate::errors::CalyxResult; +use crate::ir::traversal::ConstructVisitor; use crate::{build_assignments, guard, passes, structure}; use crate::{ errors::Error, @@ -13,6 +14,7 @@ use ir::IRPrinter; use itertools::Itertools; use petgraph::graph::DiGraph; use std::collections::HashMap; +use std::io::Write; use std::rc::Rc; /// Represents the dyanmic execution schedule of a control program. @@ -50,35 +52,36 @@ impl Schedule { } /// Print out the current schedule - #[allow(dead_code)] - fn display(&self) { + fn display(&self, group: String) { + let out = &mut std::io::stdout(); + writeln!(out, "======== {} =========", group).unwrap(); self.enables .iter() .sorted_by(|(k1, _), (k2, _)| k1.cmp(k2)) .for_each(|(state, assigns)| { - eprintln!("======== {} =========", state); + writeln!(out, "{}:", state).unwrap(); assigns.iter().for_each(|assign| { - IRPrinter::write_assignment( - assign, - 0, - &mut std::io::stderr(), - ) - .expect("Printing failed!"); - eprintln!(); + IRPrinter::write_assignment(assign, 2, out).unwrap(); + writeln!(out).unwrap(); }) }); - eprintln!("------------"); + writeln!(out, "transitions:").unwrap(); self.transitions .iter() .sorted_by(|(k1, _, _), (k2, _, _)| k1.cmp(k2)) .for_each(|(i, f, g)| { - eprintln!("({}, {}): {}", i, f, IRPrinter::guard_str(g)); + writeln!(out, " ({}, {}): {}", i, f, IRPrinter::guard_str(g)) + .unwrap(); }); } /// Implement a given [Schedule] and return the name of the [ir::Group] that /// implements it. - fn realize_schedule(self, builder: &mut ir::Builder) -> RRC { + fn realize_schedule( + self, + group: RRC, + builder: &mut ir::Builder, + ) -> RRC { self.validate(); let final_state = self.last_state(); let fsm_size = get_bit_width_from( @@ -91,9 +94,6 @@ impl Schedule { let first_state = constant(0, fsm_size); ); - // The compilation group - let group = builder.add_group("tdcc"); - // Enable assignments group.borrow_mut().assignments.extend( self.enables @@ -493,8 +493,26 @@ fn calculate_states( /// ## Compilation guarantee /// At the end of this pass, the control program will have no more than one /// group enable in it. -#[derive(Default)] -pub struct TopDownCompileControl; +pub struct TopDownCompileControl { + dump_fsm: bool, +} + +impl ConstructVisitor for TopDownCompileControl { + fn from(ctx: &ir::Context) -> CalyxResult + where + Self: Sized + Named, + { + let dump_fsm = ctx + .extra_opts + .iter() + .any(|opt| opt == &format!("{}:{}", Self::name(), "dump-fsm")); + Ok(TopDownCompileControl { dump_fsm }) + } + + fn clear_data(&mut self) { + /* All data can be transferred between components */ + } +} impl Named for TopDownCompileControl { fn name() -> &'static str { @@ -537,7 +555,15 @@ impl Visitor for TopDownCompileControl { // Compile complex schedule and return the group. _ => { let schedule = calculate_states(con, &mut builder)?; - schedule.realize_schedule(&mut builder) + let group = builder.add_group("tdcc"); + if self.dump_fsm { + schedule.display(format!( + "{}:{}", + builder.component.name, + group.borrow().name() + )); + } + schedule.realize_schedule(group, &mut builder) } }; @@ -608,7 +634,15 @@ impl Visitor for TopDownCompileControl { let mut builder = ir::Builder::new(comp, sigs); // Add assignments for the final states let schedule = calculate_states(&control.borrow(), &mut builder)?; - let comp_group = schedule.realize_schedule(&mut builder); + let group = builder.add_group("tdcc"); + if self.dump_fsm { + schedule.display(format!( + "{}:{}", + builder.component.name, + group.borrow().name() + )); + } + let comp_group = schedule.realize_schedule(group, &mut builder); Ok(Action::Change(ir::Control::enable(comp_group))) } diff --git a/src/cmdline.rs b/src/cmdline.rs index b66e7fc62b..69b283f64b 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -49,6 +49,10 @@ pub struct Opts { #[argh(option, short = 'd', long = "disable-pass")] pub disable_pass: Vec, + /// extra options passed to the context + #[argh(option, short = 'x', long = "extra-opt")] + pub extra_opts: Vec, + /// list all avaliable pass options #[argh(switch, long = "list-passes")] pub list_passes: bool, diff --git a/src/main.rs b/src/main.rs index 741246b57a..082dff0763 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ fn main() -> CalyxResult<()> { let pm = PassManager::default_passes()?; // parse the command line arguments into Opts struct - let opts = Opts::get_opts(); + let mut opts = Opts::get_opts(); // list all the avaliable pass options when flag --list-passes is enabled if opts.list_passes { @@ -20,15 +20,16 @@ fn main() -> CalyxResult<()> { let namespace = frontend::NamespaceDef::new(&opts.file, &opts.lib_path)?; // Build the IR representation - let mut rep = ir::from_ast::ast_to_ir( + let mut ctx = ir::from_ast::ast_to_ir( namespace, opts.enable_synthesis, !opts.disable_verify, )?; + ctx.extra_opts = opts.extra_opts.drain(..).collect(); // Run all passes specified by the command line - pm.execute_plan(&mut rep, &opts.pass, &opts.disable_pass)?; + pm.execute_plan(&mut ctx, &opts.pass, &opts.disable_pass)?; - opts.run_backend(&rep)?; + opts.run_backend(&ctx)?; Ok(()) } From cccdf95ca9414ec04ca1124a676e47190b3b385c Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 15:19:28 +0530 Subject: [PATCH 26/50] tests for tdcc dump FSMs --- .../compile-if-static.futil | 0 .../compile-par-static.futil | 0 .../compile-seq-static.futil | 0 .../compile-while-static.futil | 0 tests/passes/tdcc/compile-if.expect | 14 ++++++++++ .../compile-if.futil | 2 +- tests/passes/tdcc/compile-par.expect | 13 +++++++++ .../compile-par.futil | 8 ++++-- tests/passes/tdcc/compile-seq.expect | 13 +++++++++ .../compile-seq.futil | 2 +- tests/passes/tdcc/compile-while.expect | 16 +++++++++++ .../compile-while.futil | 2 +- tests/passes/tdcc/seq-with-same-done.expect | 9 +++++++ tests/passes/tdcc/seq-with-same-done.futil | 27 +++++++++++++++++++ 14 files changed, 101 insertions(+), 5 deletions(-) rename tests/passes/{compile-control => static-timing}/compile-if-static.futil (100%) rename tests/passes/{compile-control => static-timing}/compile-par-static.futil (100%) rename tests/passes/{compile-control => static-timing}/compile-seq-static.futil (100%) rename tests/passes/{compile-control => static-timing}/compile-while-static.futil (100%) create mode 100644 tests/passes/tdcc/compile-if.expect rename tests/passes/{compile-control => tdcc}/compile-if.futil (91%) create mode 100644 tests/passes/tdcc/compile-par.expect rename tests/passes/{compile-control => tdcc}/compile-par.futil (80%) create mode 100644 tests/passes/tdcc/compile-seq.expect rename tests/passes/{compile-control => tdcc}/compile-seq.futil (90%) create mode 100644 tests/passes/tdcc/compile-while.expect rename tests/passes/{compile-control => tdcc}/compile-while.futil (90%) create mode 100644 tests/passes/tdcc/seq-with-same-done.expect create mode 100644 tests/passes/tdcc/seq-with-same-done.futil diff --git a/tests/passes/compile-control/compile-if-static.futil b/tests/passes/static-timing/compile-if-static.futil similarity index 100% rename from tests/passes/compile-control/compile-if-static.futil rename to tests/passes/static-timing/compile-if-static.futil diff --git a/tests/passes/compile-control/compile-par-static.futil b/tests/passes/static-timing/compile-par-static.futil similarity index 100% rename from tests/passes/compile-control/compile-par-static.futil rename to tests/passes/static-timing/compile-par-static.futil diff --git a/tests/passes/compile-control/compile-seq-static.futil b/tests/passes/static-timing/compile-seq-static.futil similarity index 100% rename from tests/passes/compile-control/compile-seq-static.futil rename to tests/passes/static-timing/compile-seq-static.futil diff --git a/tests/passes/compile-control/compile-while-static.futil b/tests/passes/static-timing/compile-while-static.futil similarity index 100% rename from tests/passes/compile-control/compile-while-static.futil rename to tests/passes/static-timing/compile-while-static.futil diff --git a/tests/passes/tdcc/compile-if.expect b/tests/passes/tdcc/compile-if.expect new file mode 100644 index 0000000000..74785210bc --- /dev/null +++ b/tests/passes/tdcc/compile-if.expect @@ -0,0 +1,14 @@ +======== main:tdcc ========= +0: + cond0[go] = !cond0[done] ? 1'd1; + true[go] = cond0[done] & t.out ? 1'd1; + false[go] = cond0[done] & !t.out ? 1'd1; +1: + true[go] = !true[done] ? 1'd1; +2: + false[go] = !false[done] ? 1'd1; +transitions: + (0, 1): cond0[done] & t.out + (0, 2): cond0[done] & !t.out + (1, 3): true[done] + (2, 3): false[done] diff --git a/tests/passes/compile-control/compile-if.futil b/tests/passes/tdcc/compile-if.futil similarity index 91% rename from tests/passes/compile-control/compile-if.futil rename to tests/passes/tdcc/compile-if.futil index 450fe032ba..339fe72b6a 100644 --- a/tests/passes/compile-control/compile-if.futil +++ b/tests/passes/tdcc/compile-if.futil @@ -1,4 +1,4 @@ -// -p compile-control +// -x tdcc:dump-fsm -d post-opt -d lower -b none import "primitives/std.lib"; diff --git a/tests/passes/tdcc/compile-par.expect b/tests/passes/tdcc/compile-par.expect new file mode 100644 index 0000000000..86674c9f85 --- /dev/null +++ b/tests/passes/tdcc/compile-par.expect @@ -0,0 +1,13 @@ +======== main:tdcc ========= +0: + A[go] = !A[done] ? 1'd1; + par[go] = A[done] ? 1'd1; +1: + par[go] = !par[done] ? 1'd1; + B[go] = par[done] ? 1'd1; +2: + B[go] = !B[done] ? 1'd1; +transitions: + (0, 1): A[done] + (1, 2): par[done] + (2, 3): B[done] diff --git a/tests/passes/compile-control/compile-par.futil b/tests/passes/tdcc/compile-par.futil similarity index 80% rename from tests/passes/compile-control/compile-par.futil rename to tests/passes/tdcc/compile-par.futil index 986003aad9..1c0a3c3c1b 100644 --- a/tests/passes/compile-control/compile-par.futil +++ b/tests/passes/tdcc/compile-par.futil @@ -1,4 +1,4 @@ -// -p compile-control +// -x tdcc:dump-fsm -d post-opt -d lower -b none import "primitives/std.lib"; @@ -30,6 +30,10 @@ component main() -> () { } control { - par { A; B; C; } + seq { + A; + par { A; B; C; } + B; + } } } diff --git a/tests/passes/tdcc/compile-seq.expect b/tests/passes/tdcc/compile-seq.expect new file mode 100644 index 0000000000..dafe87e434 --- /dev/null +++ b/tests/passes/tdcc/compile-seq.expect @@ -0,0 +1,13 @@ +======== main:tdcc ========= +0: + A[go] = !A[done] ? 1'd1; + B[go] = A[done] ? 1'd1; +1: + B[go] = !B[done] ? 1'd1; + C[go] = B[done] ? 1'd1; +2: + C[go] = !C[done] ? 1'd1; +transitions: + (0, 1): A[done] + (1, 2): B[done] + (2, 3): C[done] diff --git a/tests/passes/compile-control/compile-seq.futil b/tests/passes/tdcc/compile-seq.futil similarity index 90% rename from tests/passes/compile-control/compile-seq.futil rename to tests/passes/tdcc/compile-seq.futil index 224cd543d9..cdf968f07f 100644 --- a/tests/passes/compile-control/compile-seq.futil +++ b/tests/passes/tdcc/compile-seq.futil @@ -1,4 +1,4 @@ -// -p compile-control +// -x tdcc:dump-fsm -d post-opt -d lower -b none import "primitives/std.lib"; diff --git a/tests/passes/tdcc/compile-while.expect b/tests/passes/tdcc/compile-while.expect new file mode 100644 index 0000000000..59166d7d08 --- /dev/null +++ b/tests/passes/tdcc/compile-while.expect @@ -0,0 +1,16 @@ +======== main:tdcc ========= +0: + cond0[go] = !cond0[done] ? 1'd1; + do_add[go] = cond0[done] & comb_reg.out ? 1'd1; +1: + do_add[go] = !do_add[done] ? 1'd1; + cond0[go] = do_add[done] ? 1'd1; +2: + do_add[go] = cond0[done] & comb_reg.out ? 1'd1; + cond0[go] = !cond0[done] ? 1'd1; +transitions: + (0, 1): cond0[done] & comb_reg.out + (0, 3): cond0[done] & !comb_reg.out + (1, 2): do_add[done] + (2, 1): cond0[done] & comb_reg.out + (2, 3): cond0[done] & !comb_reg.out diff --git a/tests/passes/compile-control/compile-while.futil b/tests/passes/tdcc/compile-while.futil similarity index 90% rename from tests/passes/compile-control/compile-while.futil rename to tests/passes/tdcc/compile-while.futil index 544eeeae48..f7917c8bc2 100644 --- a/tests/passes/compile-control/compile-while.futil +++ b/tests/passes/tdcc/compile-while.futil @@ -1,4 +1,4 @@ -// -p compile-control +// -x tdcc:dump-fsm -d post-opt -d lower -b none import "primitives/std.lib"; diff --git a/tests/passes/tdcc/seq-with-same-done.expect b/tests/passes/tdcc/seq-with-same-done.expect new file mode 100644 index 0000000000..ec06cc7dd9 --- /dev/null +++ b/tests/passes/tdcc/seq-with-same-done.expect @@ -0,0 +1,9 @@ +======== main:tdcc ========= +0: + one[go] = !one[done] ? 1'd1; + two[go] = one[done] ? 1'd1; +1: + two[go] = !two[done] ? 1'd1; +transitions: + (0, 1): one[done] + (1, 2): two[done] diff --git a/tests/passes/tdcc/seq-with-same-done.futil b/tests/passes/tdcc/seq-with-same-done.futil new file mode 100644 index 0000000000..6c3d1b8fa1 --- /dev/null +++ b/tests/passes/tdcc/seq-with-same-done.futil @@ -0,0 +1,27 @@ +// -x tdcc:dump-fsm -d post-opt -d lower -b none + +import "primitives/std.lib"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r = std_reg(1); + } + wires { + group one { + r.in = 1'd0; + r.write_en = 1'd1; + one[done] = r.done ? 1'd1; + } + group two { + r.in = 1'd1; + r.write_en = 1'd1; + two[done] = r.done ? 1'd1; + } + } + + control { + seq { + one; + two; + } + } +} From b5dece05d038ca3e2005cc85156a6fa66da59132 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 15:37:13 +0530 Subject: [PATCH 27/50] fix more tests --- calyx/src/analysis/live_range_analysis.rs | 2 +- .../minimize-regs/condition-register.expect | 8 +- .../minimize-regs/condition-register.futil | 4 +- .../minimize-regs/continuous-assignment.futil | 2 +- .../minimize-regs/escape-boundary.futil | 2 +- tests/passes/minimize-regs/invoke.expect | 2 +- tests/passes/minimize-regs/invoke.futil | 4 +- .../live-register-analysis.expect | 63 +++++--- .../live-register-analysis.futil | 8 +- tests/passes/minimize-regs/nested-par.expect | 8 +- tests/passes/minimize-regs/nested-par.futil | 10 +- .../minimize-regs/par-while-liveness.expect | 86 ++++++---- .../minimize-regs/par-while-liveness.futil | 11 +- tests/passes/minimize-regs/par-write.futil | 2 +- .../minimize-regs/simple-liveness.expect | 2 +- .../minimize-regs/simple-liveness.futil | 4 +- .../passes/minimize-regs/thread-local.expect | 4 +- tests/passes/minimize-regs/thread-local.futil | 6 +- .../regressions/group-multi-drive.expect | 8 +- tests/passes/unsharing/continuous.expect | 3 +- tests/passes/unsharing/continuous.futil | 147 +++++++++--------- tests/passes/unsharing/unsharing.expect | 3 +- tests/passes/unsharing/unsharing.futil | 135 ++++++++-------- tests/passes/unsharing/while.expect | 3 +- tests/passes/unsharing/while.futil | 113 +++++++------- 25 files changed, 343 insertions(+), 297 deletions(-) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 6992e77596..0ec9e1092f 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -471,7 +471,7 @@ fn build_live_ranges( if let Some(cell) = LiveRangeAnalysis::port_to_cell_name(port) { gens.insert(cell) } - build_live_ranges(body, alive, dbg!(gens), kills, lr) + build_live_ranges(body, alive, gens, kills, lr) } } } diff --git a/tests/passes/minimize-regs/condition-register.expect b/tests/passes/minimize-regs/condition-register.expect index f38d7d3385..8e207d40b7 100644 --- a/tests/passes/minimize-regs/condition-register.expect +++ b/tests/passes/minimize-regs/condition-register.expect @@ -32,18 +32,20 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { group some_math1 { x.in = 1'd0; x.write_en = 1'd1; - some_math[done] = x.done; + some_math1[done] = x.done; } } control { seq { wr_x; - if x.out with cond { + cond; + if x.out { some_math; } wr_z; - while x.out with cond1 { + cond1; + while x.out { some_math1; } } diff --git a/tests/passes/minimize-regs/condition-register.futil b/tests/passes/minimize-regs/condition-register.futil index e7c6e71207..43db427b44 100644 --- a/tests/passes/minimize-regs/condition-register.futil +++ b/tests/passes/minimize-regs/condition-register.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component main() -> () { cells { @@ -41,7 +41,7 @@ component main() -> () { group some_math1 { z.in = 1'd0; z.write_en = 1'd1; - some_math[done] = z.done; + some_math1[done] = z.done; } } diff --git a/tests/passes/minimize-regs/continuous-assignment.futil b/tests/passes/minimize-regs/continuous-assignment.futil index 4824b5ff6a..a7beb16576 100644 --- a/tests/passes/minimize-regs/continuous-assignment.futil +++ b/tests/passes/minimize-regs/continuous-assignment.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component main() -> (x_out: 32) { cells { diff --git a/tests/passes/minimize-regs/escape-boundary.futil b/tests/passes/minimize-regs/escape-boundary.futil index 1a6e5b0a24..da0fa1cdb3 100644 --- a/tests/passes/minimize-regs/escape-boundary.futil +++ b/tests/passes/minimize-regs/escape-boundary.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component main() -> (x_out: 32) { cells { diff --git a/tests/passes/minimize-regs/invoke.expect b/tests/passes/minimize-regs/invoke.expect index 381a877ff9..865d93e684 100644 --- a/tests/passes/minimize-regs/invoke.expect +++ b/tests/passes/minimize-regs/invoke.expect @@ -35,7 +35,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { group rd_x { add_x.left = x.out; add_x.right = x.out; - rd_x[done] = 1'd1; + rd_x[done] = x.done; } group wr_y { x.in = 32'd10; diff --git a/tests/passes/minimize-regs/invoke.futil b/tests/passes/minimize-regs/invoke.futil index db41a5c5ed..dead6d9d82 100644 --- a/tests/passes/minimize-regs/invoke.futil +++ b/tests/passes/minimize-regs/invoke.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component add(left: 32, right: 32) -> (out: 32) { @@ -39,7 +39,7 @@ component main() -> () { group rd_x { add_x.left = x.out; add_x.right = x.out; - rd_x[done] = 1'd1; + rd_x[done] = x.done; // XXX: This is wrong functionally } group wr_y { y.in = 32'd10; diff --git a/tests/passes/minimize-regs/live-register-analysis.expect b/tests/passes/minimize-regs/live-register-analysis.expect index 6478142e4a..77a565e322 100644 --- a/tests/passes/minimize-regs/live-register-analysis.expect +++ b/tests/passes/minimize-regs/live-register-analysis.expect @@ -11,18 +11,9 @@ component kernel(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { i0 = std_reg(6); le0 = std_le(6); le1 = std_le(6); + @generated comb_reg = std_reg(1); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; - le0.left = i0.out; - le0.right = 6'd31; - } - group cond1<"static"=0> { - cond1[done] = 1'd1; - le1.left = i0.out; - le1.right = 6'd31; - } group let0<"static"=1> { i0.in = 6'd0; i0.write_en = 1'd1; @@ -83,28 +74,54 @@ component kernel(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { i0.in = add1.out; upd7[done] = i0.done; } + group cond00<"static"=1> { + le0.left = i0.out; + le0.right = 6'd31; + comb_reg.in = le0.out; + comb_reg.write_en = 1'd1; + cond00[done] = comb_reg.done ? 1'd1; + } + group cond10<"static"=1> { + le1.left = i0.out; + le1.right = 6'd31; + comb_reg.in = le1.out; + comb_reg.write_en = 1'd1; + cond10[done] = comb_reg.done ? 1'd1; + } } control { seq { let0; - while le0.out with cond0 { - seq { - upd0; - par { - upd1; - upd2; + seq { + cond00; + while comb_reg.out { + seq { + seq { + upd0; + par { + upd1; + upd2; + } + upd3; + upd4; + } + cond00; } - upd3; - upd4; } } let1; - while le1.out with cond1 { - seq { - upd5; - upd6; - upd7; + seq { + cond10; + while comb_reg.out { + seq { + seq { + upd5; + upd6; + upd7; + } + cond10; + } } } } diff --git a/tests/passes/minimize-regs/live-register-analysis.futil b/tests/passes/minimize-regs/live-register-analysis.futil index 1cf30966fc..d1187372f8 100644 --- a/tests/passes/minimize-regs/live-register-analysis.futil +++ b/tests/passes/minimize-regs/live-register-analysis.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component kernel() -> () { cells { @@ -16,13 +16,11 @@ component kernel() -> () { le1 = std_le(6); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = 6'd31; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = i1.out; le1.right = 6'd31; } diff --git a/tests/passes/minimize-regs/nested-par.expect b/tests/passes/minimize-regs/nested-par.expect index cea1707fa7..5068bf7a6a 100644 --- a/tests/passes/minimize-regs/nested-par.expect +++ b/tests/passes/minimize-regs/nested-par.expect @@ -24,10 +24,10 @@ component kernel(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { b0.write_en = 1'd1; wr_b0[done] = b0.done; } - group rd_x0<"static"=0> { + group rd_x0 { read_x0.right = before0.out; read_x0.left = before0.out; - rd_x0[done] = 1'd1; + rd_x0[done] = before0.done; } group wr_before1<"static"=1> { before1.in = 4'd1; @@ -44,10 +44,10 @@ component kernel(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { b1.write_en = 1'd1; wr_b1[done] = b1.done; } - group rd_x1<"static"=0> { + group rd_x1 { read_x1.right = before1.out; read_x1.left = before1.out; - rd_x1[done] = 1'd1; + rd_x1[done] = before1.done; } } diff --git a/tests/passes/minimize-regs/nested-par.futil b/tests/passes/minimize-regs/nested-par.futil index d3172a83dd..682d9f003f 100644 --- a/tests/passes/minimize-regs/nested-par.futil +++ b/tests/passes/minimize-regs/nested-par.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component kernel() -> () { cells { @@ -28,10 +28,10 @@ component kernel() -> () { b0.write_en = 1'd1; wr_b0[done] = b0.done; } - group rd_x0<"static"=0> { + group rd_x0 { read_x0.right = x0.out; read_x0.left = x0.out; - rd_x0[done] = 1'd1; + rd_x0[done] = x0.done; // XXX: This is functionally wrong } group wr_before1<"static"=1> { @@ -49,10 +49,10 @@ component kernel() -> () { b1.write_en = 1'd1; wr_b1[done] = b1.done; } - group rd_x1<"static"=0> { + group rd_x1 { read_x1.right = x1.out; read_x1.left = x1.out; - rd_x1[done] = 1'd1; + rd_x1[done] = x1.done; // XXX: This is functionally wrong } } control { diff --git a/tests/passes/minimize-regs/par-while-liveness.expect b/tests/passes/minimize-regs/par-while-liveness.expect index c5e6ad8373..7d73ca6195 100644 --- a/tests/passes/minimize-regs/par-while-liveness.expect +++ b/tests/passes/minimize-regs/par-while-liveness.expect @@ -26,23 +26,10 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { le0 = std_le(4); le1 = std_le(4); le2 = std_le(4); + @generated comb_reg = std_reg(1); + @generated comb_reg0 = std_reg(1); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; - le0.left = i0.out; - le0.right = const1.out; - } - group cond1<"static"=0> { - cond1[done] = 1'd1; - le1.left = i1.out; - le1.right = const4.out; - } - group cond2<"static"=0> { - cond2[done] = 1'd1; - le2.left = i0.out; - le2.right = const7.out; - } group let0<"static"=1> { i0.in = const0.out; i0.write_en = 1'd1; @@ -115,6 +102,27 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { i0.in = add2.out; upd8[done] = i0.done ? 1'd1; } + group cond00<"static"=1> { + le0.left = i0.out; + le0.right = const1.out; + comb_reg.in = le0.out; + comb_reg.write_en = 1'd1; + cond00[done] = comb_reg.done ? 1'd1; + } + group cond10<"static"=1> { + le1.left = i1.out; + le1.right = const4.out; + comb_reg0.in = le1.out; + comb_reg0.write_en = 1'd1; + cond10[done] = comb_reg0.done ? 1'd1; + } + group cond20<"static"=1> { + le2.left = i0.out; + le2.right = const7.out; + comb_reg.in = le2.out; + comb_reg.write_en = 1'd1; + cond20[done] = comb_reg.done ? 1'd1; + } } control { @@ -122,31 +130,49 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { par { seq { let0; - while le0.out with cond0 { - seq { - upd0; - upd1; - upd2; + seq { + cond00; + while comb_reg.out { + seq { + seq { + upd0; + upd1; + upd2; + } + cond00; + } } } } seq { let1; - while le1.out with cond1 { - seq { - upd3; - upd4; - upd5; + seq { + cond10; + while comb_reg0.out { + seq { + seq { + upd3; + upd4; + upd5; + } + cond10; + } } } } } let2; - while le2.out with cond2 { - seq { - upd6; - upd7; - upd8; + seq { + cond20; + while comb_reg.out { + seq { + seq { + upd6; + upd7; + upd8; + } + cond20; + } } } } diff --git a/tests/passes/minimize-regs/par-while-liveness.futil b/tests/passes/minimize-regs/par-while-liveness.futil index 8e533c6182..82194e3ece 100644 --- a/tests/passes/minimize-regs/par-while-liveness.futil +++ b/tests/passes/minimize-regs/par-while-liveness.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component main() -> () { cells { @@ -31,18 +31,15 @@ component main() -> () { le2 = std_le(4); } wires { - group cond0<"static"=0> { - cond0[done] = 1'd1; + comb group cond0 { le0.left = i0.out; le0.right = const1.out; } - group cond1<"static"=0> { - cond1[done] = 1'd1; + comb group cond1 { le1.left = i1.out; le1.right = const4.out; } - group cond2<"static"=0> { - cond2[done] = 1'd1; + comb group cond2 { le2.left = i2.out; le2.right = const7.out; } diff --git a/tests/passes/minimize-regs/par-write.futil b/tests/passes/minimize-regs/par-write.futil index 735a0e1357..69ab94eff6 100644 --- a/tests/passes/minimize-regs/par-write.futil +++ b/tests/passes/minimize-regs/par-write.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component main() -> () { diff --git a/tests/passes/minimize-regs/simple-liveness.expect b/tests/passes/minimize-regs/simple-liveness.expect index 43e77b4b2a..918dc1b927 100644 --- a/tests/passes/minimize-regs/simple-liveness.expect +++ b/tests/passes/minimize-regs/simple-liveness.expect @@ -24,7 +24,7 @@ component kernel(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { group rd_x<"static"=1> { read_x.right = before.out; read_x.left = before.out; - rd_x[done] = 1'd1; + rd_x[done] = before.done; } } diff --git a/tests/passes/minimize-regs/simple-liveness.futil b/tests/passes/minimize-regs/simple-liveness.futil index 92ce71eafd..21089f95c4 100644 --- a/tests/passes/minimize-regs/simple-liveness.futil +++ b/tests/passes/minimize-regs/simple-liveness.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component kernel() -> () { cells { @@ -26,7 +26,7 @@ component kernel() -> () { group rd_x<"static"=1> { read_x.right = x.out; read_x.left = x.out; - rd_x[done] = 1'b1; + rd_x[done] = x.done; // XXX: This is functionally incorrect } } control { diff --git a/tests/passes/minimize-regs/thread-local.expect b/tests/passes/minimize-regs/thread-local.expect index 8f2aaad3d3..0ecb838190 100644 --- a/tests/passes/minimize-regs/thread-local.expect +++ b/tests/passes/minimize-regs/thread-local.expect @@ -15,7 +15,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { group rd_x { add_x.left = x.out; add_x.right = x.out; - rd_x[done] = 1'd1; + rd_x[done] = x.done; } group wr_y { y.in = 32'd4; @@ -25,7 +25,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { group rd_y { add_y.left = y.out; add_y.right = y.out; - rd_y[done] = 1'd1; + rd_y[done] = y.done; } } diff --git a/tests/passes/minimize-regs/thread-local.futil b/tests/passes/minimize-regs/thread-local.futil index 60a0f7b282..fffb7e846a 100644 --- a/tests/passes/minimize-regs/thread-local.futil +++ b/tests/passes/minimize-regs/thread-local.futil @@ -1,4 +1,4 @@ -// -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal import "primitives/std.lib"; component main() -> () { @@ -19,7 +19,7 @@ component main() -> () { group rd_x { add_x.left = x.out; add_x.right = x.out; - rd_x[done] = 1'b1; + rd_x[done] = x.done; // XXX: This is functionally wrong } group wr_y { @@ -31,7 +31,7 @@ component main() -> () { group rd_y { add_y.left = y.out; add_y.right = y.out; - rd_y[done] = 1'b1; + rd_y[done] = y.done; // XXX: This is functionally wrong } } diff --git a/tests/passes/regressions/group-multi-drive.expect b/tests/passes/regressions/group-multi-drive.expect index 42572f8f20..644d5306ef 100644 --- a/tests/passes/regressions/group-multi-drive.expect +++ b/tests/passes/regressions/group-multi-drive.expect @@ -7,8 +7,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { done = fsm.out == 2'd2 ? 1'd1; - add.left = !r.done & go & (fsm.out == 2'd1 | fsm.out == 2'd0) ? 32'd1; - add.right = !r.done & go & (fsm.out == 2'd1 | fsm.out == 2'd0) ? r.out; + add.left = go & (!r.done & fsm.out == 2'd1 | fsm.out == 2'd0) ? 32'd1; + add.right = go & (!r.done & fsm.out == 2'd1 | fsm.out == 2'd0) ? r.out; fsm.clk = clk; fsm.in = fsm.out == 2'd2 ? 2'd0; fsm.in = fsm.out == 2'd0 & r.done & go ? 2'd1; @@ -16,8 +16,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { fsm.reset = reset; fsm.write_en = fsm.out == 2'd2 | r.done & go & fsm.out == 2'd1 | fsm.out == 2'd0 & r.done & go ? 1'd1; r.clk = clk; - r.in = !r.done & go & (fsm.out == 2'd1 | fsm.out == 2'd0) ? add.out; - r.write_en = !r.done & go & (fsm.out == 2'd1 | fsm.out == 2'd0) ? 1'd1; + r.in = go & (!r.done & fsm.out == 2'd1 | fsm.out == 2'd0) ? add.out; + r.write_en = go & (!r.done & fsm.out == 2'd1 | fsm.out == 2'd0) ? 1'd1; } control {} diff --git a/tests/passes/unsharing/continuous.expect b/tests/passes/unsharing/continuous.expect index 8bf36f33d2..b40d3f1e8c 100644 --- a/tests/passes/unsharing/continuous.expect +++ b/tests/passes/unsharing/continuous.expect @@ -68,7 +68,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { seq { set_flag; zero; - if flag.out with cond { + cond; + if flag.out { seq { one; } diff --git a/tests/passes/unsharing/continuous.futil b/tests/passes/unsharing/continuous.futil index fcd54131e8..5fbde95c29 100644 --- a/tests/passes/unsharing/continuous.futil +++ b/tests/passes/unsharing/continuous.futil @@ -2,89 +2,90 @@ import "primitives/core.futil"; component main() -> () { - cells { - r = std_reg(32); - x = std_reg(32); - y = std_reg(32); - add2 = std_add(32); - flag = std_reg(1); - other = std_reg(32); - } - - wires { - group zero { - r.in = 32'd0; - r.write_en = 1'd1; - x.write_en = 1'd1; - x.in = 32'd0; - y.write_en = 1'd1; - y.in = 32'd0; - zero[done] = r.done; - } + cells { + r = std_reg(32); + x = std_reg(32); + y = std_reg(32); + add2 = std_add(32); + flag = std_reg(1); + other = std_reg(32); + } - group one { - r.in = 32'd1; - r.write_en = 1'd1; - x.write_en = 1'd1; - x.in = 32'd1; - y.write_en = 1'd1; - y.in = 32'd1; - one[done] = r.done; - } + wires { + group zero { + r.in = 32'd0; + r.write_en = 1'd1; + x.write_en = 1'd1; + x.in = 32'd0; + y.write_en = 1'd1; + y.in = 32'd0; + zero[done] = r.done; + } - group cond { - flag.in = flag.out ? 1'd0; - flag.in = !flag.out ? 1'd1; - flag.write_en = 1'd1; - cond[done] = flag.done; - } + group one { + r.in = 32'd1; + r.write_en = 1'd1; + x.write_en = 1'd1; + x.in = 32'd1; + y.write_en = 1'd1; + y.in = 32'd1; + one[done] = r.done; + } - group final { - add2.left = 32'd154; - add2.right = r.out; - other.in = add2.out; - other.write_en = 1'd1; - final[done] = other.done; - } + group cond { + flag.in = flag.out ? 1'd0; + flag.in = !flag.out ? 1'd1; + flag.write_en = 1'd1; + cond[done] = flag.done; + } - group alt { - r.in = 32'd99; - r.write_en = 1'd1; - alt[done] = r.done; - } + group final { + add2.left = 32'd154; + add2.right = r.out; + other.in = add2.out; + other.write_en = 1'd1; + final[done] = other.done; + } - group five { - r.in = 32'd5; - r.write_en = 1'd1; - y.write_en = 1'd1; - y.in = 32'd5; - x.write_en = 1'd1; - x.in = 32'd5; - five[done] = r.done; - } + group alt { + r.in = 32'd99; + r.write_en = 1'd1; + alt[done] = r.done; + } - group set_flag { - flag.in = 1'd1; - flag.write_en = 1'd1; - set_flag[done] = flag.done; - } + group five { + r.in = 32'd5; + r.write_en = 1'd1; + y.write_en = 1'd1; + y.in = 32'd5; + x.write_en = 1'd1; + x.in = 32'd5; + five[done] = r.done; + } - r.in = 1'd0 ? 32'd1; + group set_flag { + flag.in = 1'd1; + flag.write_en = 1'd1; + set_flag[done] = flag.done; } - control { - seq{ - set_flag; - zero; - if flag.out with cond { - seq {one;} - } else { - seq {five;} - } + r.in = 1'd0 ? 32'd1; + } + + control { + seq{ + set_flag; + zero; + cond; + if flag.out { + seq {one;} + } else { + seq {five;} + } - final; - alt; + final; + alt; - } } + } } diff --git a/tests/passes/unsharing/unsharing.expect b/tests/passes/unsharing/unsharing.expect index 1a0b4b630f..84b95cc1fb 100644 --- a/tests/passes/unsharing/unsharing.expect +++ b/tests/passes/unsharing/unsharing.expect @@ -63,7 +63,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { seq { set_flag; zero; - if flag.out with cond { + cond; + if flag.out { seq { one; } diff --git a/tests/passes/unsharing/unsharing.futil b/tests/passes/unsharing/unsharing.futil index fda020399d..411e4b9b9a 100644 --- a/tests/passes/unsharing/unsharing.futil +++ b/tests/passes/unsharing/unsharing.futil @@ -2,83 +2,84 @@ import "primitives/core.futil"; component main() -> () { - cells { - r = std_reg(32); - x = std_reg(32); - y = std_reg(32); - add2 = std_add(32); - flag = std_reg(1); - other = std_reg(32); - } + cells { + r = std_reg(32); + x = std_reg(32); + y = std_reg(32); + add2 = std_add(32); + flag = std_reg(1); + other = std_reg(32); + } - wires { - group zero { - r.in = 32'd0; - r.write_en = 1'd1; - x.write_en = 1'd1; - x.in = 32'd0; - y.write_en = 1'd1; - y.in = 32'd0; - zero[done] = r.done; - } + wires { + group zero { + r.in = 32'd0; + r.write_en = 1'd1; + x.write_en = 1'd1; + x.in = 32'd0; + y.write_en = 1'd1; + y.in = 32'd0; + zero[done] = r.done; + } - group one { - r.in = 32'd1; - r.write_en = 1'd1; - x.write_en = 1'd1; - x.in = 32'd1; - one[done] = r.done; - } + group one { + r.in = 32'd1; + r.write_en = 1'd1; + x.write_en = 1'd1; + x.in = 32'd1; + one[done] = r.done; + } - group cond { - flag.in = flag.out ? 1'd0; - flag.in = !flag.out ? 1'd1; - flag.write_en = 1'd1; - cond[done] = flag.done; - } + group cond { + flag.in = flag.out ? 1'd0; + flag.in = !flag.out ? 1'd1; + flag.write_en = 1'd1; + cond[done] = flag.done; + } - group final { - add2.left = 32'd154; - add2.right = r.out; - other.in = add2.out; - other.write_en = 1'd1; - final[done] = other.done; - } + group final { + add2.left = 32'd154; + add2.right = r.out; + other.in = add2.out; + other.write_en = 1'd1; + final[done] = other.done; + } - group alt { - r.in = 32'd99; - r.write_en = 1'd1; - alt[done] = r.done; - } + group alt { + r.in = 32'd99; + r.write_en = 1'd1; + alt[done] = r.done; + } - group five { - r.in = 32'd5; - r.write_en = 1'd1; - y.write_en = 1'd1; - y.in = 32'd5; - five[done] = r.done; - } + group five { + r.in = 32'd5; + r.write_en = 1'd1; + y.write_en = 1'd1; + y.in = 32'd5; + five[done] = r.done; + } - group set_flag { - flag.in = 1'd1; - flag.write_en = 1'd1; - set_flag[done] = flag.done; - } + group set_flag { + flag.in = 1'd1; + flag.write_en = 1'd1; + set_flag[done] = flag.done; } + } - control { - seq{ - set_flag; - zero; - if flag.out with cond { - seq {one;} - } else { - seq {five;} - } + control { + seq{ + set_flag; + zero; + cond; + if flag.out { + seq {one;} + } else { + seq {five;} + } - final; - alt; + final; + alt; - } } + } } diff --git a/tests/passes/unsharing/while.expect b/tests/passes/unsharing/while.expect index c0b99a3bfd..baa8706f54 100644 --- a/tests/passes/unsharing/while.expect +++ b/tests/passes/unsharing/while.expect @@ -53,7 +53,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { seq { set_flag; zero; - while flag.out with cond { + cond; + while flag.out { seq { one; } diff --git a/tests/passes/unsharing/while.futil b/tests/passes/unsharing/while.futil index 2503eff50c..e864f205af 100644 --- a/tests/passes/unsharing/while.futil +++ b/tests/passes/unsharing/while.futil @@ -2,71 +2,72 @@ import "primitives/core.futil"; component main() -> () { - cells { - r = std_reg(32); - add2 = std_add(32); - flag = std_reg(1); - other = std_reg(32); - } + cells { + r = std_reg(32); + add2 = std_add(32); + flag = std_reg(1); + other = std_reg(32); + } - wires { - group zero { - r.in = 32'd0; - r.write_en = 1'd1; - zero[done] = r.done; - } + wires { + group zero { + r.in = 32'd0; + r.write_en = 1'd1; + zero[done] = r.done; + } - group one { - r.in = 32'd1; - r.write_en = 1'd1; - one[done] = r.done; - } + group one { + r.in = 32'd1; + r.write_en = 1'd1; + one[done] = r.done; + } - group cond { - flag.in = flag.out ? 1'd0; - flag.in = !flag.out ? 1'd1; - flag.write_en = 1'd1; - cond[done] = flag.done; - } + group cond { + flag.in = flag.out ? 1'd0; + flag.in = !flag.out ? 1'd1; + flag.write_en = 1'd1; + cond[done] = flag.done; + } - group final { - add2.left = 32'd154; - add2.right = r.out; - other.in = add2.out; - other.write_en = 1'd1; - final[done] = other.done; - } + group final { + add2.left = 32'd154; + add2.right = r.out; + other.in = add2.out; + other.write_en = 1'd1; + final[done] = other.done; + } - group alt { - r.in = 32'd99; - r.write_en = 1'd1; - alt[done] = r.done; - } + group alt { + r.in = 32'd99; + r.write_en = 1'd1; + alt[done] = r.done; + } - group five { - r.in = 32'd5; - r.write_en = 1'd1; - five[done] = r.done; - } + group five { + r.in = 32'd5; + r.write_en = 1'd1; + five[done] = r.done; + } - group set_flag { - flag.in = 1'd1; - flag.write_en = 1'd1; - set_flag[done] = flag.done; - } + group set_flag { + flag.in = 1'd1; + flag.write_en = 1'd1; + set_flag[done] = flag.done; } + } - control { - seq{ - set_flag; - zero; - while flag.out with cond { - seq {one;} - } - final; - five; - alt; + control { + seq{ + set_flag; + zero; + cond; + while flag.out { + seq {one;} + } + final; + five; + alt; - } } + } } From 18d3e80be61cdfc4ba162c25d5a124e7b89c2abe Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 15:44:29 +0530 Subject: [PATCH 28/50] update more tests --- examples/dahlia/dot-product.expect | 2 +- examples/dahlia/vectorized-add.expect | 2 +- examples/futil/dot-product.expect | 116 ++++++++---------- .../memory-by-reference.expect | 2 +- examples/futil/multi-component.expect | 4 +- examples/futil/pass-in-register.expect | 10 +- examples/futil/simple.expect | 10 +- examples/futil/vectorized-add.expect | 100 +++++++-------- .../tutorial/language-tutorial-compute.expect | 2 +- .../tutorial/language-tutorial-iterate.expect | 2 +- runt.toml | 4 +- 11 files changed, 112 insertions(+), 142 deletions(-) diff --git a/examples/dahlia/dot-product.expect b/examples/dahlia/dot-product.expect index f6100fc202..5bc1d4f672 100644 --- a/examples/dahlia/dot-product.expect +++ b/examples/dahlia/dot-product.expect @@ -1,5 +1,5 @@ { - "cycles": 108, + "cycles": 98, "memories": { "A0": [ 27, diff --git a/examples/dahlia/vectorized-add.expect b/examples/dahlia/vectorized-add.expect index 6b55ee7372..9d7d382e6d 100644 --- a/examples/dahlia/vectorized-add.expect +++ b/examples/dahlia/vectorized-add.expect @@ -1,5 +1,5 @@ { - "cycles": 60, + "cycles": 50, "memories": { "A0": [ 1, diff --git a/examples/futil/dot-product.expect b/examples/futil/dot-product.expect index 955fdaeeab..288544db51 100644 --- a/examples/futil/dot-product.expect +++ b/examples/futil/dot-product.expect @@ -18,85 +18,71 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { mult_pipe0 = std_mult_pipe(32); @external v0 = std_mem_d1(32, 1, 1); @generated comb_reg = std_reg(1); - @generated fsm = std_reg(1); - @generated incr = std_add(1); - @generated fsm0 = std_reg(4); - @generated incr0 = std_add(4); - @generated fsm1 = std_reg(4); - @generated cond_stored = std_reg(1); - @generated incr1 = std_add(4); - @generated fsm2 = std_reg(2); + @generated pd = std_reg(1); + @generated pd0 = std_reg(1); + @generated fsm = std_reg(4); } wires { - A0.addr0 = fsm.out < 1'd1 & fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; + A0.addr0 = !(pd.out | A_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) ? i0.out; A0.clk = clk; A_read0_0.clk = clk; - A_read0_0.in = fsm.out < 1'd1 & fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? A0.read_data; - A_read0_0.in = fsm0.out == 4'd5 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? bin_read0_0.out; - A_read0_0.write_en = fsm0.out == 4'd5 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm.out < 1'd1 & fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - B0.addr0 = fsm.out < 1'd1 & fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; + A_read0_0.in = !(pd.out | A_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) ? A0.read_data; + A_read0_0.in = bin_read0_0.done & fsm.out == 4'd3 & go | !A_read0_0.done & fsm.out == 4'd4 & go ? bin_read0_0.out; + A_read0_0.write_en = bin_read0_0.done & fsm.out == 4'd3 & go | !A_read0_0.done & fsm.out == 4'd4 & go | !(pd.out | A_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) ? 1'd1; + B0.addr0 = !(pd0.out | B_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) ? i0.out; B0.clk = clk; B_read0_0.clk = clk; - B_read0_0.in = fsm.out < 1'd1 & fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? B0.read_data; - B_read0_0.write_en = fsm.out < 1'd1 & fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - done = fsm2.out == 2'd2 ? 1'd1; - add0.left = fsm0.out == 4'd6 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? v0.read_data; - add0.right = fsm0.out == 4'd6 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? A_read0_0.out; - add1.left = fsm0.out == 4'd7 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; - add1.right = fsm0.out == 4'd7 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? const4.out; + B_read0_0.in = !(pd0.out | B_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) ? B0.read_data; + B_read0_0.write_en = !(pd0.out | B_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) ? 1'd1; + done = fsm.out == 4'd8 ? 1'd1; + add0.left = A_read0_0.done & fsm.out == 4'd4 & go | !v0.done & fsm.out == 4'd5 & go ? v0.read_data; + add0.right = A_read0_0.done & fsm.out == 4'd4 & go | !v0.done & fsm.out == 4'd5 & go ? A_read0_0.out; + add1.left = v0.done & fsm.out == 4'd5 & go | !i0.done & fsm.out == 4'd6 & go ? i0.out; + add1.right = v0.done & fsm.out == 4'd5 & go | !i0.done & fsm.out == 4'd6 & go ? const4.out; bin_read0_0.clk = clk; - bin_read0_0.in = fsm0.out >= 4'd1 & fsm0.out < 4'd5 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? mult_pipe0.out; - bin_read0_0.write_en = fsm0.out >= 4'd1 & fsm0.out < 4'd5 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? mult_pipe0.done; + bin_read0_0.in = pd.out & pd0.out & fsm.out == 4'd2 & go | !bin_read0_0.done & fsm.out == 4'd3 & go ? mult_pipe0.out; + bin_read0_0.write_en = pd.out & pd0.out & fsm.out == 4'd2 & go | !bin_read0_0.done & fsm.out == 4'd3 & go ? mult_pipe0.done; comb_reg.clk = clk; - comb_reg.in = fsm1.out < 4'd1 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? le0.out; + comb_reg.in = i0.done & fsm.out == 4'd0 & go | !comb_reg.done & fsm.out == 4'd1 & go | i0.done & fsm.out == 4'd6 & go | !comb_reg.done & fsm.out == 4'd7 & go ? le0.out; comb_reg.reset = reset; - comb_reg.write_en = fsm1.out < 4'd1 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - cond_stored.clk = clk; - cond_stored.in = fsm1.out == 4'd1 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? comb_reg.out; - cond_stored.reset = reset; - cond_stored.write_en = fsm1.out == 4'd1 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; + comb_reg.write_en = i0.done & fsm.out == 4'd0 & go | !comb_reg.done & fsm.out == 4'd1 & go | i0.done & fsm.out == 4'd6 & go | !comb_reg.done & fsm.out == 4'd7 & go ? 1'd1; fsm.clk = clk; - fsm.in = fsm.out == 1'd1 ? 1'd0; - fsm.in = fsm.out != 1'd1 & fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? incr.out; + fsm.in = fsm.out == 4'd8 ? 4'd0; + fsm.in = fsm.out == 4'd0 & i0.done & go ? 4'd1; + fsm.in = fsm.out == 4'd1 & comb_reg.done & comb_reg.out & go | fsm.out == 4'd7 & comb_reg.done & comb_reg.out & go ? 4'd2; + fsm.in = fsm.out == 4'd2 & pd.out & pd0.out & go ? 4'd3; + fsm.in = fsm.out == 4'd3 & bin_read0_0.done & go ? 4'd4; + fsm.in = fsm.out == 4'd4 & A_read0_0.done & go ? 4'd5; + fsm.in = fsm.out == 4'd5 & v0.done & go ? 4'd6; + fsm.in = fsm.out == 4'd6 & i0.done & go ? 4'd7; + fsm.in = fsm.out == 4'd1 & comb_reg.done & !comb_reg.out & go | fsm.out == 4'd7 & comb_reg.done & !comb_reg.out & go ? 4'd8; fsm.reset = reset; - fsm.write_en = fsm.out != 1'd1 & fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm.out == 1'd1 ? 1'd1; - fsm0.clk = clk; - fsm0.in = fsm0.out == 4'd8 ? 4'd0; - fsm0.in = fsm0.out != 4'd8 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? incr0.out; - fsm0.reset = reset; - fsm0.write_en = fsm0.out != 4'd8 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm0.out == 4'd8 ? 1'd1; - fsm1.clk = clk; - fsm1.in = fsm1.out == 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm1.out == 4'd2 & !cond_stored.out ? 4'd0; - fsm1.in = (fsm1.out < 4'd2 | fsm1.out >= 4'd2 & fsm1.out < 4'd10 & cond_stored.out) & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? incr1.out; - fsm1.reset = reset; - fsm1.write_en = (fsm1.out < 4'd2 | fsm1.out >= 4'd2 & fsm1.out < 4'd10 & cond_stored.out) & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm1.out == 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm1.out == 4'd2 & !cond_stored.out ? 1'd1; - fsm2.clk = clk; - fsm2.in = fsm2.out == 2'd2 ? 2'd0; - fsm2.in = fsm2.out == 2'd0 & i0.done & go ? 2'd1; - fsm2.in = fsm2.out == 2'd1 & fsm1.out == 4'd2 & !cond_stored.out & go ? 2'd2; - fsm2.reset = reset; - fsm2.write_en = fsm2.out == 2'd0 & i0.done & go | fsm2.out == 2'd1 & fsm1.out == 4'd2 & !cond_stored.out & go | fsm2.out == 2'd2 ? 1'd1; + fsm.write_en = fsm.out == 4'd0 & i0.done & go | fsm.out == 4'd1 & comb_reg.done & comb_reg.out & go | fsm.out == 4'd7 & comb_reg.done & comb_reg.out & go | fsm.out == 4'd2 & pd.out & pd0.out & go | fsm.out == 4'd3 & bin_read0_0.done & go | fsm.out == 4'd4 & A_read0_0.done & go | fsm.out == 4'd5 & v0.done & go | fsm.out == 4'd6 & i0.done & go | fsm.out == 4'd1 & comb_reg.done & !comb_reg.out & go | fsm.out == 4'd7 & comb_reg.done & !comb_reg.out & go | fsm.out == 4'd8 ? 1'd1; i0.clk = clk; - i0.in = fsm0.out == 4'd7 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? add1.out; - i0.in = !i0.done & fsm2.out == 2'd0 & go ? const0.out; - i0.write_en = !i0.done & fsm2.out == 2'd0 & go | fsm0.out == 4'd7 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - incr.left = fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - incr.right = fsm0.out == 4'd0 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? fsm.out; - incr0.left = cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 4'd1; - incr0.right = cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? fsm0.out; - incr1.left = !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? fsm1.out; - incr1.right = !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 4'd1; - le0.left = fsm1.out < 4'd1 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; - le0.right = fsm1.out < 4'd1 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? const1.out; + i0.in = v0.done & fsm.out == 4'd5 & go | !i0.done & fsm.out == 4'd6 & go ? add1.out; + i0.in = !i0.done & fsm.out == 4'd0 & go ? const0.out; + i0.write_en = !i0.done & fsm.out == 4'd0 & go | v0.done & fsm.out == 4'd5 & go | !i0.done & fsm.out == 4'd6 & go ? 1'd1; + le0.left = i0.done & fsm.out == 4'd0 & go | !comb_reg.done & fsm.out == 4'd1 & go | i0.done & fsm.out == 4'd6 & go | !comb_reg.done & fsm.out == 4'd7 & go ? i0.out; + le0.right = i0.done & fsm.out == 4'd0 & go | !comb_reg.done & fsm.out == 4'd1 & go | i0.done & fsm.out == 4'd6 & go | !comb_reg.done & fsm.out == 4'd7 & go ? const1.out; mult_pipe0.clk = clk; - mult_pipe0.go = !mult_pipe0.done & fsm0.out >= 4'd1 & fsm0.out < 4'd5 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - mult_pipe0.left = fsm0.out >= 4'd1 & fsm0.out < 4'd5 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? A_read0_0.out; - mult_pipe0.right = fsm0.out >= 4'd1 & fsm0.out < 4'd5 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? B_read0_0.out; - v0.addr0 = fsm0.out == 4'd6 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? const2.out; - v0.addr0 = fsm0.out == 4'd6 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? const3.out; + mult_pipe0.go = !mult_pipe0.done & (pd.out & pd0.out & fsm.out == 4'd2 & go | !bin_read0_0.done & fsm.out == 4'd3 & go) ? 1'd1; + mult_pipe0.left = pd.out & pd0.out & fsm.out == 4'd2 & go | !bin_read0_0.done & fsm.out == 4'd3 & go ? A_read0_0.out; + mult_pipe0.right = pd.out & pd0.out & fsm.out == 4'd2 & go | !bin_read0_0.done & fsm.out == 4'd3 & go ? B_read0_0.out; + pd.clk = clk; + pd.in = pd.out & pd0.out ? 1'd0; + pd.in = A_read0_0.done & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) ? 1'd1; + pd.reset = reset; + pd.write_en = A_read0_0.done & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) | pd.out & pd0.out ? 1'd1; + pd0.clk = clk; + pd0.in = pd.out & pd0.out ? 1'd0; + pd0.in = B_read0_0.done & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) ? 1'd1; + pd0.reset = reset; + pd0.write_en = B_read0_0.done & (comb_reg.done & comb_reg.out & fsm.out == 4'd1 & go | !(pd.out & pd0.out) & fsm.out == 4'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 4'd7 & go) | pd.out & pd0.out ? 1'd1; + v0.addr0 = A_read0_0.done & fsm.out == 4'd4 & go | !v0.done & fsm.out == 4'd5 & go ? const2.out; + v0.addr0 = A_read0_0.done & fsm.out == 4'd4 & go | !v0.done & fsm.out == 4'd5 & go ? const3.out; v0.clk = clk; - v0.write_data = fsm0.out == 4'd6 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? add0.out; - v0.write_en = fsm0.out == 4'd6 & cond_stored.out & fsm1.out >= 4'd2 & fsm1.out < 4'd10 & !(fsm1.out == 4'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; + v0.write_data = A_read0_0.done & fsm.out == 4'd4 & go | !v0.done & fsm.out == 4'd5 & go ? add0.out; + v0.write_en = A_read0_0.done & fsm.out == 4'd4 & go | !v0.done & fsm.out == 4'd5 & go ? 1'd1; } control {} diff --git a/examples/futil/memory-by-reference/memory-by-reference.expect b/examples/futil/memory-by-reference/memory-by-reference.expect index e34fd15047..b768481a0f 100644 --- a/examples/futil/memory-by-reference/memory-by-reference.expect +++ b/examples/futil/memory-by-reference/memory-by-reference.expect @@ -1,5 +1,5 @@ { - "cycles": 11, + "cycles": 10, "memories": { "x": [ 1 diff --git a/examples/futil/multi-component.expect b/examples/futil/multi-component.expect index 1f939831d3..85a8530ca1 100644 --- a/examples/futil/multi-component.expect +++ b/examples/futil/multi-component.expect @@ -22,8 +22,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { wires { done = fsm.out == 2'd2 ? 1'd1; current_value.clk = clk; - current_value.in = !current_value.done & fsm.out == 2'd1 & go ? id.out; - current_value.write_en = !current_value.done & fsm.out == 2'd1 & go ? 1'd1; + current_value.in = id.done & fsm.out == 2'd0 & go | !current_value.done & fsm.out == 2'd1 & go ? id.out; + current_value.write_en = id.done & fsm.out == 2'd0 & go | !current_value.done & fsm.out == 2'd1 & go ? 1'd1; fsm.clk = clk; fsm.in = fsm.out == 2'd2 ? 2'd0; fsm.in = fsm.out == 2'd0 & id.done & go ? 2'd1; diff --git a/examples/futil/pass-in-register.expect b/examples/futil/pass-in-register.expect index e082c07b1f..66b3b7c11c 100644 --- a/examples/futil/pass-in-register.expect +++ b/examples/futil/pass-in-register.expect @@ -32,14 +32,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { fsm.reset = reset; fsm.write_en = fsm.out == 2'd0 & r.done & go | fsm.out == 2'd1 & op.done & go | fsm.out == 2'd2 ? 1'd1; op.clk = clk; - op.go = !op.done & fsm.out == 2'd1 & go ? 1'd1; - op.reg_done = !op.done & fsm.out == 2'd1 & go ? r.done; - op.reg_out = !op.done & fsm.out == 2'd1 & go ? r.out; + op.go = r.done & fsm.out == 2'd0 & go | !op.done & fsm.out == 2'd1 & go ? 1'd1; + op.reg_done = r.done & fsm.out == 2'd0 & go | !op.done & fsm.out == 2'd1 & go ? r.done; + op.reg_out = r.done & fsm.out == 2'd0 & go | !op.done & fsm.out == 2'd1 & go ? r.out; r.clk = clk; r.in = !r.done & fsm.out == 2'd0 & go ? 32'd15; - r.in = !op.done & fsm.out == 2'd1 & go ? op.reg_in; + r.in = r.done & fsm.out == 2'd0 & go | !op.done & fsm.out == 2'd1 & go ? op.reg_in; r.write_en = !r.done & fsm.out == 2'd0 & go ? 1'd1; - r.write_en = !op.done & fsm.out == 2'd1 & go ? op.reg_write_en; + r.write_en = r.done & fsm.out == 2'd0 & go | !op.done & fsm.out == 2'd1 & go ? op.reg_write_en; } control {} diff --git a/examples/futil/simple.expect b/examples/futil/simple.expect index 4ad41d24e5..8bf5d7c42e 100644 --- a/examples/futil/simple.expect +++ b/examples/futil/simple.expect @@ -20,15 +20,15 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { fsm.reset = reset; fsm.write_en = fsm.out == 2'd0 & reg0.done & go | fsm.out == 2'd1 & reg1.done & go | fsm.out == 2'd2 ? 1'd1; mult.clk = clk; - mult.go = !mult.done & !reg1.done & fsm.out == 2'd1 & go ? 1'd1; - mult.left = !reg1.done & fsm.out == 2'd1 & go ? const0.out; - mult.right = !reg1.done & fsm.out == 2'd1 & go ? const1.out; + mult.go = !mult.done & (reg0.done & fsm.out == 2'd0 & go | !reg1.done & fsm.out == 2'd1 & go) ? 1'd1; + mult.left = reg0.done & fsm.out == 2'd0 & go | !reg1.done & fsm.out == 2'd1 & go ? const0.out; + mult.right = reg0.done & fsm.out == 2'd0 & go | !reg1.done & fsm.out == 2'd1 & go ? const1.out; reg0.clk = clk; reg0.in = !reg0.done & fsm.out == 2'd0 & go ? add.out; reg0.write_en = !reg0.done & fsm.out == 2'd0 & go ? 1'd1; reg1.clk = clk; - reg1.in = !reg1.done & fsm.out == 2'd1 & go ? mult.out; - reg1.write_en = !reg1.done & fsm.out == 2'd1 & go ? mult.done; + reg1.in = reg0.done & fsm.out == 2'd0 & go | !reg1.done & fsm.out == 2'd1 & go ? mult.out; + reg1.write_en = reg0.done & fsm.out == 2'd0 & go | !reg1.done & fsm.out == 2'd1 & go ? mult.done; } control {} diff --git a/examples/futil/vectorized-add.expect b/examples/futil/vectorized-add.expect index cd65c651b6..bcbb28441b 100644 --- a/examples/futil/vectorized-add.expect +++ b/examples/futil/vectorized-add.expect @@ -14,76 +14,60 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { i0 = std_reg(4); le0 = std_le(4); @generated comb_reg = std_reg(1); - @generated fsm = std_reg(1); - @generated incr = std_add(1); - @generated fsm0 = std_reg(2); - @generated incr0 = std_add(2); - @generated fsm1 = std_reg(3); - @generated cond_stored = std_reg(1); - @generated incr1 = std_add(3); - @generated fsm2 = std_reg(2); + @generated pd = std_reg(1); + @generated pd0 = std_reg(1); + @generated fsm = std_reg(3); } wires { - A0.addr0 = fsm.out < 1'd1 & fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; + A0.addr0 = !(pd.out | A_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) ? i0.out; A0.clk = clk; A_read0_0.clk = clk; - A_read0_0.in = fsm.out < 1'd1 & fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? A0.read_data; - A_read0_0.write_en = fsm.out < 1'd1 & fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - B0.addr0 = fsm.out < 1'd1 & fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; + A_read0_0.in = !(pd.out | A_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) ? A0.read_data; + A_read0_0.write_en = !(pd.out | A_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) ? 1'd1; + B0.addr0 = !(pd0.out | B_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) ? i0.out; B0.clk = clk; B_read0_0.clk = clk; - B_read0_0.in = fsm.out < 1'd1 & fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? B0.read_data; - B_read0_0.write_en = fsm.out < 1'd1 & fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - Sum0.addr0 = fsm0.out == 2'd1 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; + B_read0_0.in = !(pd0.out | B_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) ? B0.read_data; + B_read0_0.write_en = !(pd0.out | B_read0_0.done) & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) ? 1'd1; + Sum0.addr0 = pd.out & pd0.out & fsm.out == 3'd2 & go | !Sum0.done & fsm.out == 3'd3 & go ? i0.out; Sum0.clk = clk; - Sum0.write_data = fsm0.out == 2'd1 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? add0.out; - Sum0.write_en = fsm0.out == 2'd1 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - done = fsm2.out == 2'd2 ? 1'd1; - add0.left = fsm0.out == 2'd1 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? A_read0_0.out; - add0.right = fsm0.out == 2'd1 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? B_read0_0.out; - add1.left = fsm0.out == 2'd2 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; - add1.right = fsm0.out == 2'd2 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? const2.out; + Sum0.write_data = pd.out & pd0.out & fsm.out == 3'd2 & go | !Sum0.done & fsm.out == 3'd3 & go ? add0.out; + Sum0.write_en = pd.out & pd0.out & fsm.out == 3'd2 & go | !Sum0.done & fsm.out == 3'd3 & go ? 1'd1; + done = fsm.out == 3'd6 ? 1'd1; + add0.left = pd.out & pd0.out & fsm.out == 3'd2 & go | !Sum0.done & fsm.out == 3'd3 & go ? A_read0_0.out; + add0.right = pd.out & pd0.out & fsm.out == 3'd2 & go | !Sum0.done & fsm.out == 3'd3 & go ? B_read0_0.out; + add1.left = Sum0.done & fsm.out == 3'd3 & go | !i0.done & fsm.out == 3'd4 & go ? i0.out; + add1.right = Sum0.done & fsm.out == 3'd3 & go | !i0.done & fsm.out == 3'd4 & go ? const2.out; comb_reg.clk = clk; - comb_reg.in = fsm1.out < 3'd1 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? le0.out; + comb_reg.in = i0.done & fsm.out == 3'd0 & go | !comb_reg.done & fsm.out == 3'd1 & go | i0.done & fsm.out == 3'd4 & go | !comb_reg.done & fsm.out == 3'd5 & go ? le0.out; comb_reg.reset = reset; - comb_reg.write_en = fsm1.out < 3'd1 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - cond_stored.clk = clk; - cond_stored.in = fsm1.out == 3'd1 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? comb_reg.out; - cond_stored.reset = reset; - cond_stored.write_en = fsm1.out == 3'd1 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; + comb_reg.write_en = i0.done & fsm.out == 3'd0 & go | !comb_reg.done & fsm.out == 3'd1 & go | i0.done & fsm.out == 3'd4 & go | !comb_reg.done & fsm.out == 3'd5 & go ? 1'd1; fsm.clk = clk; - fsm.in = fsm.out == 1'd1 ? 1'd0; - fsm.in = fsm.out != 1'd1 & fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? incr.out; + fsm.in = fsm.out == 3'd6 ? 3'd0; + fsm.in = fsm.out == 3'd0 & i0.done & go ? 3'd1; + fsm.in = fsm.out == 3'd1 & comb_reg.done & comb_reg.out & go | fsm.out == 3'd5 & comb_reg.done & comb_reg.out & go ? 3'd2; + fsm.in = fsm.out == 3'd2 & pd.out & pd0.out & go ? 3'd3; + fsm.in = fsm.out == 3'd3 & Sum0.done & go ? 3'd4; + fsm.in = fsm.out == 3'd4 & i0.done & go ? 3'd5; + fsm.in = fsm.out == 3'd1 & comb_reg.done & !comb_reg.out & go | fsm.out == 3'd5 & comb_reg.done & !comb_reg.out & go ? 3'd6; fsm.reset = reset; - fsm.write_en = fsm.out != 1'd1 & fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm.out == 1'd1 ? 1'd1; - fsm0.clk = clk; - fsm0.in = fsm0.out == 2'd3 ? 2'd0; - fsm0.in = fsm0.out != 2'd3 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? incr0.out; - fsm0.reset = reset; - fsm0.write_en = fsm0.out != 2'd3 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm0.out == 2'd3 ? 1'd1; - fsm1.clk = clk; - fsm1.in = fsm1.out == 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm1.out == 3'd2 & !cond_stored.out ? 3'd0; - fsm1.in = (fsm1.out < 3'd2 | fsm1.out >= 3'd2 & fsm1.out < 3'd5 & cond_stored.out) & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? incr1.out; - fsm1.reset = reset; - fsm1.write_en = (fsm1.out < 3'd2 | fsm1.out >= 3'd2 & fsm1.out < 3'd5 & cond_stored.out) & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm1.out == 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go | fsm1.out == 3'd2 & !cond_stored.out ? 1'd1; - fsm2.clk = clk; - fsm2.in = fsm2.out == 2'd2 ? 2'd0; - fsm2.in = fsm2.out == 2'd0 & i0.done & go ? 2'd1; - fsm2.in = fsm2.out == 2'd1 & fsm1.out == 3'd2 & !cond_stored.out & go ? 2'd2; - fsm2.reset = reset; - fsm2.write_en = fsm2.out == 2'd0 & i0.done & go | fsm2.out == 2'd1 & fsm1.out == 3'd2 & !cond_stored.out & go | fsm2.out == 2'd2 ? 1'd1; + fsm.write_en = fsm.out == 3'd0 & i0.done & go | fsm.out == 3'd1 & comb_reg.done & comb_reg.out & go | fsm.out == 3'd5 & comb_reg.done & comb_reg.out & go | fsm.out == 3'd2 & pd.out & pd0.out & go | fsm.out == 3'd3 & Sum0.done & go | fsm.out == 3'd4 & i0.done & go | fsm.out == 3'd1 & comb_reg.done & !comb_reg.out & go | fsm.out == 3'd5 & comb_reg.done & !comb_reg.out & go | fsm.out == 3'd6 ? 1'd1; i0.clk = clk; - i0.in = fsm0.out == 2'd2 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? add1.out; - i0.in = !i0.done & fsm2.out == 2'd0 & go ? const0.out; - i0.write_en = !i0.done & fsm2.out == 2'd0 & go | fsm0.out == 2'd2 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - incr.left = fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 1'd1; - incr.right = fsm0.out == 2'd0 & cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? fsm.out; - incr0.left = cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 2'd1; - incr0.right = cond_stored.out & fsm1.out >= 3'd2 & fsm1.out < 3'd5 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? fsm0.out; - incr1.left = !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? fsm1.out; - incr1.right = !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? 3'd1; - le0.left = fsm1.out < 3'd1 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? i0.out; - le0.right = fsm1.out < 3'd1 & !(fsm1.out == 3'd2 & !cond_stored.out) & fsm2.out == 2'd1 & go ? const1.out; + i0.in = Sum0.done & fsm.out == 3'd3 & go | !i0.done & fsm.out == 3'd4 & go ? add1.out; + i0.in = !i0.done & fsm.out == 3'd0 & go ? const0.out; + i0.write_en = !i0.done & fsm.out == 3'd0 & go | Sum0.done & fsm.out == 3'd3 & go | !i0.done & fsm.out == 3'd4 & go ? 1'd1; + le0.left = i0.done & fsm.out == 3'd0 & go | !comb_reg.done & fsm.out == 3'd1 & go | i0.done & fsm.out == 3'd4 & go | !comb_reg.done & fsm.out == 3'd5 & go ? i0.out; + le0.right = i0.done & fsm.out == 3'd0 & go | !comb_reg.done & fsm.out == 3'd1 & go | i0.done & fsm.out == 3'd4 & go | !comb_reg.done & fsm.out == 3'd5 & go ? const1.out; + pd.clk = clk; + pd.in = pd.out & pd0.out ? 1'd0; + pd.in = A_read0_0.done & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) ? 1'd1; + pd.reset = reset; + pd.write_en = A_read0_0.done & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) | pd.out & pd0.out ? 1'd1; + pd0.clk = clk; + pd0.in = pd.out & pd0.out ? 1'd0; + pd0.in = B_read0_0.done & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) ? 1'd1; + pd0.reset = reset; + pd0.write_en = B_read0_0.done & (comb_reg.done & comb_reg.out & fsm.out == 3'd1 & go | !(pd.out & pd0.out) & fsm.out == 3'd2 & go | comb_reg.done & comb_reg.out & fsm.out == 3'd5 & go) | pd.out & pd0.out ? 1'd1; } control {} diff --git a/examples/tutorial/language-tutorial-compute.expect b/examples/tutorial/language-tutorial-compute.expect index e4da1ded0f..7ad777d7f0 100644 --- a/examples/tutorial/language-tutorial-compute.expect +++ b/examples/tutorial/language-tutorial-compute.expect @@ -1,5 +1,5 @@ { - "cycles": 10, + "cycles": 11, "memories": { "mem": [ 14 diff --git a/examples/tutorial/language-tutorial-iterate.expect b/examples/tutorial/language-tutorial-iterate.expect index d6f0b01714..bcfbbc2b40 100644 --- a/examples/tutorial/language-tutorial-iterate.expect +++ b/examples/tutorial/language-tutorial-iterate.expect @@ -1,5 +1,5 @@ { - "cycles": 60, + "cycles": 58, "memories": { "mem": [ 42 diff --git a/runt.toml b/runt.toml index bb00452506..eeac22bf6d 100644 --- a/runt.toml +++ b/runt.toml @@ -212,7 +212,7 @@ name = "memory by reference tutorial" paths = ["examples/futil/memory-by-reference/*.futil"] cmd = """ fud e {} -s verilog.cycle_limit 500 \ - -s verilog.data examples/tutorial/data.json \ + -s verilog.data {}.data \ --to dat -q """ @@ -221,7 +221,7 @@ name = "dahlia examples" paths = ["examples/dahlia/*.fuse"] cmd = """ fud e {} -s verilog.cycle_limit 500 \ - -s verilog.data examples/tutorial/data.json \ + -s verilog.data {}.data \ --to dat -q """ From cffd5f69e88fa3a2e825288592b43d2a40eb262d Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 15:49:37 +0530 Subject: [PATCH 29/50] update correctness tests --- tests/correctness/exp/degree-4-signed.expect | 2 +- tests/correctness/exp/degree-4-unsigned.expect | 2 +- tests/correctness/exp/degree-8-signed.expect | 2 +- tests/correctness/exp/degree-8-unsigned.expect | 2 +- tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect | 2 +- tests/correctness/ntt-pipeline/ntt-16.expect | 2 +- tests/correctness/ntt-pipeline/ntt-8.expect | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/correctness/exp/degree-4-signed.expect b/tests/correctness/exp/degree-4-signed.expect index 356232b8f5..cad81378ce 100644 --- a/tests/correctness/exp/degree-4-signed.expect +++ b/tests/correctness/exp/degree-4-signed.expect @@ -1,5 +1,5 @@ { - "cycles": 88, + "cycles": 60, "memories": { "ret": [ "2.7182769775390625" diff --git a/tests/correctness/exp/degree-4-unsigned.expect b/tests/correctness/exp/degree-4-unsigned.expect index 8f6c7f474e..b09674cdcc 100644 --- a/tests/correctness/exp/degree-4-unsigned.expect +++ b/tests/correctness/exp/degree-4-unsigned.expect @@ -1,5 +1,5 @@ { - "cycles": 78, + "cycles": 56, "memories": { "ret": [ "2.7182769775390625" diff --git a/tests/correctness/exp/degree-8-signed.expect b/tests/correctness/exp/degree-8-signed.expect index ef9a2abbb2..344e8943f6 100644 --- a/tests/correctness/exp/degree-8-signed.expect +++ b/tests/correctness/exp/degree-8-signed.expect @@ -1,5 +1,5 @@ { - "cycles": 187, + "cycles": 144, "memories": { "ret": [ "0.0001068115234375" diff --git a/tests/correctness/exp/degree-8-unsigned.expect b/tests/correctness/exp/degree-8-unsigned.expect index 5035bd8fa9..47164cff1b 100644 --- a/tests/correctness/exp/degree-8-unsigned.expect +++ b/tests/correctness/exp/degree-8-unsigned.expect @@ -1,5 +1,5 @@ { - "cycles": 125, + "cycles": 88, "memories": { "ret": [ "9181.710357666015625" diff --git a/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect b/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect index 5eac7dfc52..e0dc74d1e6 100644 --- a/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect +++ b/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect @@ -1,5 +1,5 @@ { - "cycles": 735, + "cycles": 680, "memories": { "a": [ 7371, diff --git a/tests/correctness/ntt-pipeline/ntt-16.expect b/tests/correctness/ntt-pipeline/ntt-16.expect index 549de0ed09..c2973c3d39 100644 --- a/tests/correctness/ntt-pipeline/ntt-16.expect +++ b/tests/correctness/ntt-pipeline/ntt-16.expect @@ -1,5 +1,5 @@ { - "cycles": 249, + "cycles": 210, "memories": { "a": [ 7371, diff --git a/tests/correctness/ntt-pipeline/ntt-8.expect b/tests/correctness/ntt-pipeline/ntt-8.expect index 096985ca4d..e7db564f35 100644 --- a/tests/correctness/ntt-pipeline/ntt-8.expect +++ b/tests/correctness/ntt-pipeline/ntt-8.expect @@ -1,5 +1,5 @@ { - "cycles": 172, + "cycles": 151, "memories": { "a": [ 5390, From 8a0fff1e0f58b1fc0c8cd4b34c8ab09388eb3023 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 19:38:02 +0530 Subject: [PATCH 30/50] systolic tests update --- tests/correctness/systolic/array-1.expect | 2 +- tests/correctness/systolic/array-2.expect | 2 +- tests/correctness/systolic/array-3.expect | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/correctness/systolic/array-1.expect b/tests/correctness/systolic/array-1.expect index 014866d39a..a16f11720c 100644 --- a/tests/correctness/systolic/array-1.expect +++ b/tests/correctness/systolic/array-1.expect @@ -1,5 +1,5 @@ { - "cycles": 24, + "cycles": 35, "out_00": 760, "pe_00": [ 0, diff --git a/tests/correctness/systolic/array-2.expect b/tests/correctness/systolic/array-2.expect index 6823531188..7201d01fd9 100644 --- a/tests/correctness/systolic/array-2.expect +++ b/tests/correctness/systolic/array-2.expect @@ -1,5 +1,5 @@ { - "cycles": 39, + "cycles": 56, "out_00": 760, "out_01": 400, "out_10": 1120, diff --git a/tests/correctness/systolic/array-3.expect b/tests/correctness/systolic/array-3.expect index 1414cc7f98..9e844ea4e3 100644 --- a/tests/correctness/systolic/array-3.expect +++ b/tests/correctness/systolic/array-3.expect @@ -1,5 +1,5 @@ { - "cycles": 56, + "cycles": 79, "out_00": 760, "out_01": 400, "out_02": 1120, From 4d40a103bc702e909e549e9050c91ac1f017a0fe Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 4 Sep 2021 22:34:52 +0530 Subject: [PATCH 31/50] another tdcc FSM gen test --- tests/passes/tdcc/while-if.expect | 29 ++++++++++++++++++++ tests/passes/tdcc/while-if.futil | 44 +++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/passes/tdcc/while-if.expect create mode 100644 tests/passes/tdcc/while-if.futil diff --git a/tests/passes/tdcc/while-if.expect b/tests/passes/tdcc/while-if.expect new file mode 100644 index 0000000000..a6bf88077c --- /dev/null +++ b/tests/passes/tdcc/while-if.expect @@ -0,0 +1,29 @@ +======== main:tdcc ========= +0: + one[go] = !one[done] ? 1'd1; + two[go] = one[done] & is_not_zero.out & is_even.out ? 1'd1; + three[go] = one[done] & is_not_zero.out & !is_even.out ? 1'd1; + four[go] = one[done] & !is_not_zero.out ? 1'd1; +1: + two[go] = !two[done] ? 1'd1; + two[go] = two[done] & is_not_zero.out & is_even.out ? 1'd1; + three[go] = two[done] & is_not_zero.out & !is_even.out ? 1'd1; + four[go] = two[done] & !is_not_zero.out ? 1'd1; +2: + two[go] = three[done] & is_not_zero.out & is_even.out ? 1'd1; + three[go] = !three[done] ? 1'd1; + three[go] = three[done] & is_not_zero.out & !is_even.out ? 1'd1; + four[go] = three[done] & !is_not_zero.out ? 1'd1; +3: + four[go] = !four[done] ? 1'd1; +transitions: + (0, 1): one[done] & is_not_zero.out & is_even.out + (0, 2): one[done] & is_not_zero.out & !is_even.out + (0, 3): one[done] & !is_not_zero.out + (1, 1): two[done] & is_not_zero.out & is_even.out + (1, 2): two[done] & is_not_zero.out & !is_even.out + (1, 3): two[done] & !is_not_zero.out + (2, 1): three[done] & is_not_zero.out & is_even.out + (2, 2): three[done] & is_not_zero.out & !is_even.out + (2, 3): three[done] & !is_not_zero.out + (3, 4): four[done] diff --git a/tests/passes/tdcc/while-if.futil b/tests/passes/tdcc/while-if.futil new file mode 100644 index 0000000000..c6c369e48b --- /dev/null +++ b/tests/passes/tdcc/while-if.futil @@ -0,0 +1,44 @@ +// -x tdcc:dump-fsm -d post-opt -d lower -b none +import "primitives/core.futil"; +component main() -> () { + cells { + is_even = std_reg(1); + is_not_zero = std_reg(1); + r = std_reg(32); + } + wires { + group one { + is_not_zero.in = 1'd0; + is_not_zero.write_en = 1'd0; + one[done] = is_not_zero.done; + } + group two { + r.in = 32'd0; + r.write_en = 1'd0; + two[done] = r.done; + } + group three { + r.in = 32'd0; + r.write_en = 1'd0; + three[done] = r.done; + } + group four { + is_even.in = 1'd0; + is_even.write_en = 1'd0; + four[done] = is_even.done; + } + } + control { + seq { + one; + while is_not_zero.out { + if is_even.out { + two; + } else { + three; + } + } + four; + } + } +} From 620dfa25d250f1a4c93bd20808ce6d7f77266cc3 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 09:58:36 +0530 Subject: [PATCH 32/50] tdcc: handle branch at start --- calyx/src/passes/top_down_compile_control.rs | 23 ++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index ac5df6ab71..fa40ed9ada 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -65,6 +65,7 @@ impl Schedule { writeln!(out).unwrap(); }) }); + // writeln!(out, "{}:\n ", self.last_state()).unwrap(); writeln!(out, "transitions:").unwrap(); self.transitions .iter() @@ -251,6 +252,14 @@ fn calculate_states_recur( match con { // See explanation of FSM states generated in [ir::TopDownCompileControl]. ir::Control::Enable(ir::Enable { group, .. }) => { + // If there is exactly one previous transition state with a `true` + // guard, then merge this state into previous state. + let (cur_state, prev_states) = if prev_states.len() == 1 && prev_states[0].1.is_true() { + (prev_states[0].0, vec![]) + } else { + (cur_state, prev_states) + }; + let not_done = !guard!(group["done"]); let signal_on = builder.add_constant(1, 1); @@ -395,8 +404,18 @@ fn calculate_states( builder: &mut ir::Builder, ) -> CalyxResult { let mut schedule = Schedule::default(); - let (prev, nxt) = - calculate_states_recur(con, 0, vec![], &mut schedule, builder)?; + let first_state = (0, ir::Guard::True); + // We create an empty first state in case the control program starts with + // a branch (if, while). + // If the program doesn't branch, then the initial state is merged into + // the first group. + let (prev, nxt) = calculate_states_recur( + con, + 1, + vec![first_state], + &mut schedule, + builder, + )?; let transitions = prev.into_iter().map(|(st, guard)| (st, nxt, guard)); schedule.transitions.extend(transitions); Ok(schedule) From 7e4a9301fecd37dfd3d544b66ac1a559285eb26d Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 09:59:38 +0530 Subject: [PATCH 33/50] tdcc: visualize final state --- calyx/src/passes/top_down_compile_control.rs | 20 ++++++------- tests/passes/tdcc/branch-at-start.expect | 24 ++++++++++++++++ tests/passes/tdcc/branch-at-start.futil | 30 ++++++++++++++++++++ tests/passes/tdcc/compile-if.expect | 2 ++ tests/passes/tdcc/compile-par.expect | 2 ++ tests/passes/tdcc/compile-seq.expect | 2 ++ tests/passes/tdcc/compile-while.expect | 2 ++ tests/passes/tdcc/seq-with-same-done.expect | 2 ++ tests/passes/tdcc/while-if.expect | 2 ++ 9 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 tests/passes/tdcc/branch-at-start.expect create mode 100644 tests/passes/tdcc/branch-at-start.futil diff --git a/calyx/src/passes/top_down_compile_control.rs b/calyx/src/passes/top_down_compile_control.rs index fa40ed9ada..8b13df3fb6 100644 --- a/calyx/src/passes/top_down_compile_control.rs +++ b/calyx/src/passes/top_down_compile_control.rs @@ -65,7 +65,7 @@ impl Schedule { writeln!(out).unwrap(); }) }); - // writeln!(out, "{}:\n ", self.last_state()).unwrap(); + writeln!(out, "{}:\n ", self.last_state()).unwrap(); writeln!(out, "transitions:").unwrap(); self.transitions .iter() @@ -243,7 +243,7 @@ fn calculate_states_recur( // The current state cur_state: u64, // The set of previous states that want to transition into cur_state - prev_states: Vec<(u64, ir::Guard)>, + preds: Vec<(u64, ir::Guard)>, // Current schedule. schedule: &mut Schedule, // Component builder @@ -254,10 +254,10 @@ fn calculate_states_recur( ir::Control::Enable(ir::Enable { group, .. }) => { // If there is exactly one previous transition state with a `true` // guard, then merge this state into previous state. - let (cur_state, prev_states) = if prev_states.len() == 1 && prev_states[0].1.is_true() { - (prev_states[0].0, vec![]) + let (cur_state, prev_states) = if preds.len() == 1 && preds[0].1.is_true() { + (preds[0].0, vec![]) } else { - (cur_state, prev_states) + (cur_state, preds) }; let not_done = !guard!(group["done"]); @@ -294,7 +294,7 @@ fn calculate_states_recur( Ok((vec![(cur_state, done_cond)], nxt)) } ir::Control::Seq(ir::Seq { stmts, .. }) => { - let mut prev = prev_states; + let mut prev = preds; let mut cur = cur_state; for stmt in stmts { let res = calculate_states_recur( @@ -322,7 +322,7 @@ fn calculate_states_recur( let port_guard: ir::Guard = Rc::clone(port).into(); // Previous states transitioning into true branch need the conditional // to be true. - let tru_transitions = prev_states.clone().into_iter().map(|(s, g)| (s, g & port_guard.clone())).collect(); + let tru_transitions = preds.clone().into_iter().map(|(s, g)| (s, g & port_guard.clone())).collect(); let (tru_prev, tru_nxt) = calculate_states_recur( tbranch, cur_state, @@ -332,7 +332,7 @@ fn calculate_states_recur( )?; // Previous states transitioning into false branch need the conditional // to be false. - let fal_transitions = prev_states.into_iter().map(|(s, g)| (s, g & !port_guard.clone())).collect(); + let fal_transitions = preds.into_iter().map(|(s, g)| (s, g & !port_guard.clone())).collect(); let (fal_prev, fal_nxt) = calculate_states_recur( fbranch, tru_nxt, @@ -367,7 +367,7 @@ fn calculate_states_recur( // Step 2: Generate the forward edges normally. // Previous transitions into the body require the condition to be // true. - let transitions: Vec<(u64, ir::Guard)> = prev_states + let transitions: Vec<(u64, ir::Guard)> = preds .clone() .into_iter() .chain(back_edge_prevs) @@ -385,7 +385,7 @@ fn calculate_states_recur( // - Before the body when the condition is false // - Inside the body when the condition is false let not_port_guard = !port_guard; - let all_prevs = prev_states + let all_prevs = preds .into_iter() .chain(prevs.into_iter()) .map(|(st, guard)| (st, guard & not_port_guard.clone())) diff --git a/tests/passes/tdcc/branch-at-start.expect b/tests/passes/tdcc/branch-at-start.expect new file mode 100644 index 0000000000..edbf0f76a4 --- /dev/null +++ b/tests/passes/tdcc/branch-at-start.expect @@ -0,0 +1,24 @@ +======== main:tdcc ========= +0: + one[go] = is_valid & is_even.out ? 1'd1; + two[go] = is_valid & !is_even.out ? 1'd1; +1: + one[go] = !one[done] ? 1'd1; + one[go] = one[done] & is_valid & is_even.out ? 1'd1; + two[go] = one[done] & is_valid & !is_even.out ? 1'd1; +2: + one[go] = two[done] & is_valid & is_even.out ? 1'd1; + two[go] = !two[done] ? 1'd1; + two[go] = two[done] & is_valid & !is_even.out ? 1'd1; +3: + +transitions: + (0, 1): is_valid & is_even.out + (0, 2): is_valid & !is_even.out + (0, 3): !is_valid + (1, 1): one[done] & is_valid & is_even.out + (1, 2): one[done] & is_valid & !is_even.out + (1, 3): one[done] & !is_valid + (2, 1): two[done] & is_valid & is_even.out + (2, 2): two[done] & is_valid & !is_even.out + (2, 3): two[done] & !is_valid diff --git a/tests/passes/tdcc/branch-at-start.futil b/tests/passes/tdcc/branch-at-start.futil new file mode 100644 index 0000000000..78714f0b4c --- /dev/null +++ b/tests/passes/tdcc/branch-at-start.futil @@ -0,0 +1,30 @@ +// -x tdcc:dump-fsm -d post-opt -d lower -b none +import "primitives/core.futil"; +component main(is_valid: 1) -> () { + cells { + is_even = std_reg(1); + is_not_zero = std_reg(1); + r = std_reg(32); + } + wires { + group one { + is_not_zero.in = 1'd0; + is_not_zero.write_en = 1'd0; + one[done] = is_not_zero.done; + } + group two { + r.in = 32'd0; + r.write_en = 1'd0; + two[done] = r.done; + } + } + control { + while is_valid { + if is_even.out { + one; + } else { + two; + } + } + } +} diff --git a/tests/passes/tdcc/compile-if.expect b/tests/passes/tdcc/compile-if.expect index 74785210bc..c6dbc150ee 100644 --- a/tests/passes/tdcc/compile-if.expect +++ b/tests/passes/tdcc/compile-if.expect @@ -7,6 +7,8 @@ true[go] = !true[done] ? 1'd1; 2: false[go] = !false[done] ? 1'd1; +3: + transitions: (0, 1): cond0[done] & t.out (0, 2): cond0[done] & !t.out diff --git a/tests/passes/tdcc/compile-par.expect b/tests/passes/tdcc/compile-par.expect index 86674c9f85..6415054391 100644 --- a/tests/passes/tdcc/compile-par.expect +++ b/tests/passes/tdcc/compile-par.expect @@ -7,6 +7,8 @@ B[go] = par[done] ? 1'd1; 2: B[go] = !B[done] ? 1'd1; +3: + transitions: (0, 1): A[done] (1, 2): par[done] diff --git a/tests/passes/tdcc/compile-seq.expect b/tests/passes/tdcc/compile-seq.expect index dafe87e434..a4cda039ac 100644 --- a/tests/passes/tdcc/compile-seq.expect +++ b/tests/passes/tdcc/compile-seq.expect @@ -7,6 +7,8 @@ C[go] = B[done] ? 1'd1; 2: C[go] = !C[done] ? 1'd1; +3: + transitions: (0, 1): A[done] (1, 2): B[done] diff --git a/tests/passes/tdcc/compile-while.expect b/tests/passes/tdcc/compile-while.expect index 59166d7d08..974471ed13 100644 --- a/tests/passes/tdcc/compile-while.expect +++ b/tests/passes/tdcc/compile-while.expect @@ -8,6 +8,8 @@ 2: do_add[go] = cond0[done] & comb_reg.out ? 1'd1; cond0[go] = !cond0[done] ? 1'd1; +3: + transitions: (0, 1): cond0[done] & comb_reg.out (0, 3): cond0[done] & !comb_reg.out diff --git a/tests/passes/tdcc/seq-with-same-done.expect b/tests/passes/tdcc/seq-with-same-done.expect index ec06cc7dd9..bafd386558 100644 --- a/tests/passes/tdcc/seq-with-same-done.expect +++ b/tests/passes/tdcc/seq-with-same-done.expect @@ -4,6 +4,8 @@ two[go] = one[done] ? 1'd1; 1: two[go] = !two[done] ? 1'd1; +2: + transitions: (0, 1): one[done] (1, 2): two[done] diff --git a/tests/passes/tdcc/while-if.expect b/tests/passes/tdcc/while-if.expect index a6bf88077c..657f3b5206 100644 --- a/tests/passes/tdcc/while-if.expect +++ b/tests/passes/tdcc/while-if.expect @@ -16,6 +16,8 @@ four[go] = three[done] & !is_not_zero.out ? 1'd1; 3: four[go] = !four[done] ? 1'd1; +4: + transitions: (0, 1): one[done] & is_not_zero.out & is_even.out (0, 2): one[done] & is_not_zero.out & !is_even.out From 68e8a47b2546a530837839c19680158f20ec70d3 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 10:26:54 +0530 Subject: [PATCH 34/50] dead-group-removal: tests --- tests/passes/dead-group-removal/group.expect | 32 ++++++++++++++ tests/passes/dead-group-removal/group.futil | 46 ++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tests/passes/dead-group-removal/group.expect create mode 100644 tests/passes/dead-group-removal/group.futil diff --git a/tests/passes/dead-group-removal/group.expect b/tests/passes/dead-group-removal/group.expect new file mode 100644 index 0000000000..c1d7548067 --- /dev/null +++ b/tests/passes/dead-group-removal/group.expect @@ -0,0 +1,32 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r = std_reg(32); + lt = std_lt(32); + } + wires { + group one { + r.in = 32'd1; + r.write_en = 1'd1; + one[done] = r.done; + } + group two { + r.in = 32'd1; + r.write_en = 1'd1; + two[done] = r.done; + } + comb group cond { + lt.left = 32'd0; + lt.right = r.out; + } + } + + control { + seq { + one; + if r.out with cond { + two; + } + } + } +} diff --git a/tests/passes/dead-group-removal/group.futil b/tests/passes/dead-group-removal/group.futil new file mode 100644 index 0000000000..56cb2dd44b --- /dev/null +++ b/tests/passes/dead-group-removal/group.futil @@ -0,0 +1,46 @@ +// -p dead-group-removal +import "primitives/core.futil"; +component main() -> () { + cells { + r = std_reg(32); + lt = std_lt(32); + } + wires { + comb group dead_comb { + lt.left = 32'd0; + lt.right = r.out; + } + comb group cond { + lt.left = 32'd0; + lt.right = r.out; + } + group one { + r.in = 32'd1; + r.write_en = 1'd1; + one[done] = r.done; + } + group two { + r.in = 32'd1; + r.write_en = 1'd1; + two[done] = r.done; + } + group dead_one { + r.in = 32'd1; + r.write_en = 1'd1; + dead_one[done] = r.done; + } + group dead_two { + r.in = 32'd1; + r.write_en = 1'd1; + dead_two[done] = r.done; + } + } + control { + seq { + one; + if r.out with cond { + two; + } + } + } +} From 8b73c2374816e04c15089647ebc313502f9e600f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 11:01:38 +0530 Subject: [PATCH 35/50] papercut: check if cond port is combinational --- calyx/src/passes/papercut.rs | 46 ++++++++++++++++++- runt.toml | 1 + .../cell-and-group-conflict.expect} | 0 .../cell-and-group-conflict.futil} | 0 .../cell-as-group.expect} | 0 .../cell-as-group.futil} | 0 .../papercut/comb-port-in-condition.expect | 6 +++ .../papercut/comb-port-in-condition.futil | 10 ++++ .../no-control-no-done.expect} | 0 .../no-control-no-done.futil} | 0 .../no-done.expect} | 0 .../no-done.futil} | 0 .../read-missing-write.expect} | 0 .../read-missing-write.futil} | 0 14 files changed, 62 insertions(+), 1 deletion(-) rename tests/errors/{papercut-cell-and-group-conflict.expect => papercut/cell-and-group-conflict.expect} (100%) rename tests/errors/{papercut-cell-and-group-conflict.futil => papercut/cell-and-group-conflict.futil} (100%) rename tests/errors/{papercut-cell-as-group.expect => papercut/cell-as-group.expect} (100%) rename tests/errors/{papercut-cell-as-group.futil => papercut/cell-as-group.futil} (100%) create mode 100644 tests/errors/papercut/comb-port-in-condition.expect create mode 100644 tests/errors/papercut/comb-port-in-condition.futil rename tests/errors/{papercut-no-control-no-done.expect => papercut/no-control-no-done.expect} (100%) rename tests/errors/{papercut-no-control-no-done.futil => papercut/no-control-no-done.futil} (100%) rename tests/errors/{papercut-no-done.expect => papercut/no-done.expect} (100%) rename tests/errors/{papercut-no-done.futil => papercut/no-done.futil} (100%) rename tests/errors/{papercut-read-missing-write.expect => papercut/read-missing-write.expect} (100%) rename tests/errors/{papercut-read-missing-write.futil => papercut/read-missing-write.futil} (100%) diff --git a/calyx/src/passes/papercut.rs b/calyx/src/passes/papercut.rs index a41fa352c6..4c561b18bc 100644 --- a/calyx/src/passes/papercut.rs +++ b/calyx/src/passes/papercut.rs @@ -246,6 +246,50 @@ impl Visitor for Papercut { } } - Ok(Action::Stop) + Ok(Action::Continue) + } + + fn start_while( + &mut self, + s: &mut ir::While, + _comp: &mut ir::Component, + _ctx: &LibrarySignatures, + ) -> VisResult { + if s.cond.is_none() { + let port = s.port.borrow(); + if let ir::PortParent::Cell(cell_wref) = &port.parent { + let cell_ref = cell_wref.upgrade(); + let cell = cell_ref.borrow(); + if let ir::CellType::Primitive { is_comb, name: prim_name, .. } = &cell.prototype { + if *is_comb { + let msg = format!("Port `{}.{}` is an output port on combinational primitive `{}` and will always output 0. Add a `with` statement to the `while` statement to ensure it has a valid value during execution.", cell.name(), port.name, prim_name); + return Err(Error::Papercut(msg, cell.name().clone())); + } + } + } + } + Ok(Action::Continue) + } + + fn start_if( + &mut self, + s: &mut ir::If, + _comp: &mut ir::Component, + _ctx: &LibrarySignatures, + ) -> VisResult { + if s.cond.is_none() { + let port = s.port.borrow(); + if let ir::PortParent::Cell(cell_wref) = &port.parent { + let cell_ref = cell_wref.upgrade(); + let cell = cell_ref.borrow(); + if let ir::CellType::Primitive { is_comb, name: prim_name, .. } = &cell.prototype { + if *is_comb { + let msg = format!("Port `{}.{}` is an output port on combinational primitive `{}` and will always output 0. Add a `with` statement to the `if` statement to ensure it has a valid value during execution.", cell.name(), port.name, prim_name); + return Err(Error::Papercut(msg, cell.name().clone())); + } + } + } + } + Ok(Action::Continue) } } diff --git a/runt.toml b/runt.toml index eeac22bf6d..e562549bc3 100644 --- a/runt.toml +++ b/runt.toml @@ -27,6 +27,7 @@ cmd = """ name = "[core] errors" paths = [ "tests/errors/*.futil", + "tests/errors/papercut/*.futil", "tests/errors/parser/*.futil" ] cmd = """ diff --git a/tests/errors/papercut-cell-and-group-conflict.expect b/tests/errors/papercut/cell-and-group-conflict.expect similarity index 100% rename from tests/errors/papercut-cell-and-group-conflict.expect rename to tests/errors/papercut/cell-and-group-conflict.expect diff --git a/tests/errors/papercut-cell-and-group-conflict.futil b/tests/errors/papercut/cell-and-group-conflict.futil similarity index 100% rename from tests/errors/papercut-cell-and-group-conflict.futil rename to tests/errors/papercut/cell-and-group-conflict.futil diff --git a/tests/errors/papercut-cell-as-group.expect b/tests/errors/papercut/cell-as-group.expect similarity index 100% rename from tests/errors/papercut-cell-as-group.expect rename to tests/errors/papercut/cell-as-group.expect diff --git a/tests/errors/papercut-cell-as-group.futil b/tests/errors/papercut/cell-as-group.futil similarity index 100% rename from tests/errors/papercut-cell-as-group.futil rename to tests/errors/papercut/cell-as-group.futil diff --git a/tests/errors/papercut/comb-port-in-condition.expect b/tests/errors/papercut/comb-port-in-condition.expect new file mode 100644 index 0000000000..9bf2c33f93 --- /dev/null +++ b/tests/errors/papercut/comb-port-in-condition.expect @@ -0,0 +1,6 @@ +---CODE--- +1 +---STDERR--- +Error: +4 | le = std_le(32); + | ^^ [Papercut] Port `le.out` is an output port on combinational primitive `std_le` and will always output 0. Add a `with` statement to enable a combinational group to run the primitive. diff --git a/tests/errors/papercut/comb-port-in-condition.futil b/tests/errors/papercut/comb-port-in-condition.futil new file mode 100644 index 0000000000..23fdec6878 --- /dev/null +++ b/tests/errors/papercut/comb-port-in-condition.futil @@ -0,0 +1,10 @@ +import "primitives/core.futil"; +component main() -> () { + cells { + le = std_le(32); + } + wires { } + control { + if le.out { seq {} } + } +} diff --git a/tests/errors/papercut-no-control-no-done.expect b/tests/errors/papercut/no-control-no-done.expect similarity index 100% rename from tests/errors/papercut-no-control-no-done.expect rename to tests/errors/papercut/no-control-no-done.expect diff --git a/tests/errors/papercut-no-control-no-done.futil b/tests/errors/papercut/no-control-no-done.futil similarity index 100% rename from tests/errors/papercut-no-control-no-done.futil rename to tests/errors/papercut/no-control-no-done.futil diff --git a/tests/errors/papercut-no-done.expect b/tests/errors/papercut/no-done.expect similarity index 100% rename from tests/errors/papercut-no-done.expect rename to tests/errors/papercut/no-done.expect diff --git a/tests/errors/papercut-no-done.futil b/tests/errors/papercut/no-done.futil similarity index 100% rename from tests/errors/papercut-no-done.futil rename to tests/errors/papercut/no-done.futil diff --git a/tests/errors/papercut-read-missing-write.expect b/tests/errors/papercut/read-missing-write.expect similarity index 100% rename from tests/errors/papercut-read-missing-write.expect rename to tests/errors/papercut/read-missing-write.expect diff --git a/tests/errors/papercut-read-missing-write.futil b/tests/errors/papercut/read-missing-write.futil similarity index 100% rename from tests/errors/papercut-read-missing-write.futil rename to tests/errors/papercut/read-missing-write.futil From 2522bdf258f78a918a111f0e09dc0a335576bb20 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 11:05:19 +0530 Subject: [PATCH 36/50] fix tcam implementation --- primitives/tcam.futil | 199 ++++++++++++++++++++++++++++++------------ 1 file changed, 142 insertions(+), 57 deletions(-) diff --git a/primitives/tcam.futil b/primitives/tcam.futil index 5ac07ac740..3a8c40c972 100644 --- a/primitives/tcam.futil +++ b/primitives/tcam.futil @@ -73,7 +73,7 @@ component comparator_element(lenA: 5, lenB: 5, addrA: 5, addrB: 5, mlA: 1, mlB: ml = std_reg(1); } wires { - group select<"static"=0> { + comb group select { gt0.left = lenA; gt0.right = lenB; not0.in = mlB; @@ -81,7 +81,6 @@ component comparator_element(lenA: 5, lenB: 5, addrA: 5, addrB: 5, mlA: 1, mlB: or0.right = gt0.out; and0.left = mlA; and0.right = or0.out; - select[done] = 1'd1; } group A<"static"=1> { len.write_en = 1'd1; @@ -312,23 +311,46 @@ component TCAM_IPv4(write_en: 1, search_en: 1, in: 32, prefix_len: 6, write_inde ce31 = comparator_element(); ce40 = comparator_element(); + + comb_reg0 = std_reg(1); + comb_reg1 = std_reg(1); + comb_reg2 = std_reg(1); + comb_reg3 = std_reg(1); + comb_reg4 = std_reg(1); + comb_reg5 = std_reg(1); + comb_reg6 = std_reg(1); + comb_reg7 = std_reg(1); + comb_reg8 = std_reg(1); + comb_reg9 = std_reg(1); + comb_reg10 = std_reg(1); + comb_reg11 = std_reg(1); + comb_reg12 = std_reg(1); + comb_reg13 = std_reg(1); + comb_reg14 = std_reg(1); + comb_reg15 = std_reg(1); + comb_reg16 = std_reg(1); + comb_reg17 = std_reg(1); + comb_reg18 = std_reg(1); + comb_reg19 = std_reg(1); + comb_reg20 = std_reg(1); + comb_reg21 = std_reg(1); + comb_reg22 = std_reg(1); + comb_reg23 = std_reg(1); + comb_reg24 = std_reg(1); + comb_reg25 = std_reg(1); + comb_reg26 = std_reg(1); + comb_reg27 = std_reg(1); + comb_reg28 = std_reg(1); + comb_reg29 = std_reg(1); + comb_reg30 = std_reg(1); + comb_reg31 = std_reg(1); + out = std_reg(5); } wires { - group is_write_enabled<"static"=0> { - w_eq.left = write_en; - w_eq.right = 1'd1; - is_write_enabled[done] = 1'd1; - } - group is_length_zero<"static"=0> { + comb group is_length_zero { z_eq.left = 6'd0; z_eq.right = prefix_len; - is_length_zero[done] = 1'd1; - } - group is_search_enabled<"static"=0> { - s_eq.left = search_en; - s_eq.right = 1'd1; - is_search_enabled[done] = 1'd1; } group write_zero<"static"=1> { zero_index.write_en = 1'd1; @@ -655,7 +677,7 @@ component TCAM_IPv4(write_en: 1, search_en: 1, in: 32, prefix_len: 6, write_inde p31.in = in; write31[done] = p31.done & l31.done ? 1'd1; } - group find_write_index<"static"=0> { + group find_write_index { is_index0.left = 5'd0; is_index1.left = 5'd1; is_index2.left = 5'd2; @@ -722,12 +744,71 @@ component TCAM_IPv4(write_en: 1, search_en: 1, in: 32, prefix_len: 6, write_inde is_index29.right = write_index; is_index30.right = write_index; is_index31.right = write_index; - find_write_index[done] = 1'd1; - } - group validity<"static"=0> { - is_invalid.left = ce40.mlX; - is_invalid.right = 1'd0; - validity[done] = 1'd1; + comb_reg0.in = is_index0.out; + comb_reg0.write_en = 1'd1; + comb_reg1.in = is_index1.out; + comb_reg1.write_en = 1'd1; + comb_reg2.in = is_index2.out; + comb_reg2.write_en = 1'd1; + comb_reg3.in = is_index3.out; + comb_reg3.write_en = 1'd1; + comb_reg4.in = is_index4.out; + comb_reg4.write_en = 1'd1; + comb_reg5.in = is_index5.out; + comb_reg5.write_en = 1'd1; + comb_reg6.in = is_index6.out; + comb_reg6.write_en = 1'd1; + comb_reg7.in = is_index7.out; + comb_reg7.write_en = 1'd1; + comb_reg8.in = is_index8.out; + comb_reg8.write_en = 1'd1; + comb_reg9.in = is_index9.out; + comb_reg9.write_en = 1'd1; + comb_reg10.in = is_index10.out; + comb_reg10.write_en = 1'd1; + comb_reg11.in = is_index11.out; + comb_reg11.write_en = 1'd1; + comb_reg12.in = is_index12.out; + comb_reg12.write_en = 1'd1; + comb_reg13.in = is_index13.out; + comb_reg13.write_en = 1'd1; + comb_reg14.in = is_index14.out; + comb_reg14.write_en = 1'd1; + comb_reg15.in = is_index15.out; + comb_reg15.write_en = 1'd1; + comb_reg16.in = is_index16.out; + comb_reg16.write_en = 1'd1; + comb_reg17.in = is_index17.out; + comb_reg17.write_en = 1'd1; + comb_reg18.in = is_index18.out; + comb_reg18.write_en = 1'd1; + comb_reg19.in = is_index19.out; + comb_reg19.write_en = 1'd1; + comb_reg20.in = is_index20.out; + comb_reg20.write_en = 1'd1; + comb_reg21.in = is_index21.out; + comb_reg21.write_en = 1'd1; + comb_reg22.in = is_index22.out; + comb_reg22.write_en = 1'd1; + comb_reg23.in = is_index23.out; + comb_reg23.write_en = 1'd1; + comb_reg24.in = is_index24.out; + comb_reg24.write_en = 1'd1; + comb_reg25.in = is_index25.out; + comb_reg25.write_en = 1'd1; + comb_reg26.in = is_index26.out; + comb_reg26.write_en = 1'd1; + comb_reg27.in = is_index27.out; + comb_reg27.write_en = 1'd1; + comb_reg28.in = is_index28.out; + comb_reg28.write_en = 1'd1; + comb_reg29.in = is_index29.out; + comb_reg29.write_en = 1'd1; + comb_reg30.in = is_index30.out; + comb_reg30.write_en = 1'd1; + comb_reg31.in = is_index31.out; + comb_reg31.write_en = 1'd1; + find_write_index[done] = comb_reg0.done; } group default_to_zero_length_index<"static"=1> { out.write_en = 1'd1; @@ -745,47 +826,50 @@ component TCAM_IPv4(write_en: 1, search_en: 1, in: 32, prefix_len: 6, write_inde control { par { - if w_eq.out with is_write_enabled { + if write_en { if z_eq.out with is_length_zero { write_zero; } else { - par { - if is_index0.out with find_write_index { write0; } - if is_index1.out with find_write_index { write1; } - if is_index2.out with find_write_index { write2; } - if is_index3.out with find_write_index { write3; } - if is_index4.out with find_write_index { write4; } - if is_index5.out with find_write_index { write5; } - if is_index6.out with find_write_index { write6; } - if is_index7.out with find_write_index { write7; } - if is_index8.out with find_write_index { write8; } - if is_index9.out with find_write_index { write9; } - if is_index10.out with find_write_index { write10; } - if is_index11.out with find_write_index { write11; } - if is_index12.out with find_write_index { write12; } - if is_index13.out with find_write_index { write13; } - if is_index14.out with find_write_index { write14; } - if is_index15.out with find_write_index { write15; } - if is_index16.out with find_write_index { write16; } - if is_index17.out with find_write_index { write17; } - if is_index18.out with find_write_index { write18; } - if is_index19.out with find_write_index { write19; } - if is_index20.out with find_write_index { write20; } - if is_index21.out with find_write_index { write21; } - if is_index22.out with find_write_index { write22; } - if is_index23.out with find_write_index { write23; } - if is_index24.out with find_write_index { write24; } - if is_index25.out with find_write_index { write25; } - if is_index26.out with find_write_index { write26; } - if is_index27.out with find_write_index { write27; } - if is_index28.out with find_write_index { write28; } - if is_index29.out with find_write_index { write29; } - if is_index30.out with find_write_index { write30; } - if is_index31.out with find_write_index { write31; } + seq { + find_write_index; + par { + if comb_reg0.out { write0; } + if comb_reg1.out { write1; } + if comb_reg2.out { write2; } + if comb_reg3.out { write3; } + if comb_reg4.out { write4; } + if comb_reg5.out { write5; } + if comb_reg6.out { write6; } + if comb_reg7.out { write7; } + if comb_reg8.out { write8; } + if comb_reg9.out { write9; } + if comb_reg10.out { write10; } + if comb_reg11.out { write11; } + if comb_reg12.out { write12; } + if comb_reg13.out { write13; } + if comb_reg14.out { write14; } + if comb_reg15.out { write15; } + if comb_reg16.out { write16; } + if comb_reg17.out { write17; } + if comb_reg18.out { write18; } + if comb_reg19.out { write19; } + if comb_reg20.out { write20; } + if comb_reg21.out { write21; } + if comb_reg22.out { write22; } + if comb_reg23.out { write23; } + if comb_reg24.out { write24; } + if comb_reg25.out { write25; } + if comb_reg26.out { write26; } + if comb_reg27.out { write27; } + if comb_reg28.out { write28; } + if comb_reg29.out { write29; } + if comb_reg30.out { write30; } + if comb_reg31.out { write31; } + } } } } - if s_eq.out with is_search_enabled { + if search_en { seq { par { invoke me0(in=in, prefix=p0.out, length=l0.out)(); @@ -860,7 +944,8 @@ component TCAM_IPv4(write_en: 1, search_en: 1, in: 32, prefix_len: 6, write_inde invoke ce31(lenA=ce22.lenX, lenB=ce23.lenX, addrA=ce22.addrX, addrB=ce23.addrX, mlA=ce22.mlX, mlB=ce23.mlX)(); } invoke ce40(lenA=ce30.lenX, lenB=ce31.lenX, addrA=ce30.addrX, addrB=ce31.addrX, mlA=ce30.mlX, mlB=ce31.mlX)(); - if is_invalid.out with validity { default_to_zero_length_index; } else { save_index; } + // If the final comparator has a valid value then save it. + if ce40.mlX { save_index; } else { default_to_zero_length_index; } } } } From ae2796ca695711c29f7c3c2e656482520143d337 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 11:12:14 +0530 Subject: [PATCH 37/50] fix mrxl --- frontends/mrxl/mrxl/gen_futil.py | 33 +++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/frontends/mrxl/mrxl/gen_futil.py b/frontends/mrxl/mrxl/gen_futil.py index 2e009a9541..f179d7798b 100644 --- a/frontends/mrxl/mrxl/gen_futil.py +++ b/frontends/mrxl/mrxl/gen_futil.py @@ -1,5 +1,7 @@ from . import ast -from calyx.py_ast import * +from calyx.py_ast import ( + Connect, Group, CompVar, Stdlib, Cell, Program, Component, Import, SeqComp, + ConstantPort, HolePort, CompPort, Enable, While, ParComp, CombGroup) def emit_mem_decl(name, size, par): @@ -33,12 +35,11 @@ def emit_cond_group(suffix, arr_size, b=None): group_id = CompVar(f"cond{bank_suffix}{suffix}") le = CompVar(f"le{bank_suffix}{suffix}") idx = CompVar(f"idx{bank_suffix}{suffix}") - return Group( + return CombGroup( id=group_id, connections=[ Connect(CompPort(idx, "out"), CompPort(le, "left")), Connect(ConstantPort(32, arr_size), CompPort(le, "right")), - Connect(ConstantPort(1, 1), HolePort(group_id, "done")), ], ) @@ -103,12 +104,14 @@ def emit_eval_body_group(s_idx, stmt, b=None): src = CompVar(f"{bi.src}{bank_suffix}") dest = CompVar(f"idx{bank_suffix}_{s_idx}") - mem_offsets.append(Connect(CompPort(dest, "out"), CompPort(src, "addr0"))) + mem_offsets.append( + Connect(CompPort(dest, "out"), CompPort(src, "addr0"))) if isinstance(stmt.op, ast.Map): src = CompVar(f"{stmt.dest}{bank_suffix}") dest = CompVar(f"idx{bank_suffix}_{s_idx}") - mem_offsets.append(Connect(CompPort(dest, "out"), CompPort(src, "addr0"))) + mem_offsets.append( + Connect(CompPort(dest, "out"), CompPort(src, "addr0"))) compute_left_op = emit_compute_op( stmt.op.body.lhs, stmt.op, stmt.dest, name2arr, s_idx, bank_suffix @@ -153,14 +156,14 @@ def gen_reduce_impl(stmt, arr_size, s_idx): of the `reduce` statement instead of an implementation of a `map` statement. """ - result = dict() stdlib = Stdlib() op_name = "mult" if stmt.op.body.op == "mul" else "add" cells = [ Cell(CompVar(f"le{s_idx}"), stdlib.op("lt", 32, signed=False)), Cell(CompVar(f"idx{s_idx}"), stdlib.register(32)), Cell(CompVar(f"adder_idx{s_idx}"), stdlib.op("add", 32, signed=False)), - Cell(CompVar(f"adder_op{s_idx}"), stdlib.op(f"{op_name}", 32, signed=False)), + Cell(CompVar(f"adder_op{s_idx}"), stdlib.op( + f"{op_name}", 32, signed=False)), ] wires = [ emit_cond_group(s_idx, arr_size), @@ -170,7 +173,8 @@ def gen_reduce_impl(stmt, arr_size, s_idx): control = While( port=CompPort(CompVar(f"le{s_idx}"), "out"), cond=CompVar(f"cond{s_idx}"), - body=SeqComp([Enable(f"eval_body{s_idx}"), Enable(f"incr_idx{s_idx}")]), + body=SeqComp( + [Enable(f"eval_body{s_idx}"), Enable(f"incr_idx{s_idx}")]), ) return {"cells": cells, "wires": wires, "control": control} @@ -188,14 +192,14 @@ def gen_map_impl(stmt, arr_size, bank_factor, s_idx): - a group that implements the loop condition, checking if the index has reached the end of the input array """ - result = dict() stdlib = Stdlib() cells = [] for b in range(bank_factor): cells.extend( [ - Cell(CompVar(f"le_b{b}_{s_idx}"), stdlib.op("lt", 32, signed=False)), + Cell(CompVar(f"le_b{b}_{s_idx}"), + stdlib.op("lt", 32, signed=False)), Cell(CompVar(f"idx_b{b}_{s_idx}"), stdlib.register(32)), Cell( CompVar(f"adder_idx_b{b}_{s_idx}"), @@ -294,7 +298,8 @@ def emit(prog): used_names.append(decl.name) if decl.type.size: # A memory arr_size = decl.type.size - cells.extend(emit_mem_decl(decl.name, decl.type.size, name2par[decl.name])) + cells.extend(emit_mem_decl( + decl.name, decl.type.size, name2par[decl.name])) else: # A register cells.append(Cell(CompVar(decl.name), stdlib.register(32))) @@ -302,9 +307,11 @@ def emit(prog): for stmt in prog.stmts: if stmt.dest not in used_names: if isinstance(stmt.op, ast.Map): - cells.extend(emit_mem_decl(stmt.dest, arr_size, name2par[stmt.dest])) + cells.extend(emit_mem_decl( + stmt.dest, arr_size, name2par[stmt.dest])) else: - cells.append(emit_reg_decl(stmt.dest, 32)) + raise NotImplementedError("Generating register declarations") + # cells.append(emit_reg_decl(stmt.dest, 32)) used_names.append(stmt.dest) # Generate Calyx. From c06ac16c27a49cdcd7e234546c1882df4c0a55bb Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 11:44:07 +0530 Subject: [PATCH 38/50] update test for live_range_analysis --- calyx/src/analysis/live_range_analysis.rs | 10 ++--- .../minimize-regs/condition-register.expect | 39 ++++-------------- .../minimize-regs/condition-register.futil | 41 ++++--------------- 3 files changed, 22 insertions(+), 68 deletions(-) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 0ec9e1092f..a12b1038cc 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -428,13 +428,13 @@ fn build_live_ranges( build_live_ranges(fbranch, alive, gens, kills, lr); // take union - let alive = &t_alive | &f_alive; - let mut gens = &t_gens | &f_gens; + let mut alive = &t_alive | &f_alive; + let gens = &t_gens | &f_gens; let kills = &t_kills | &f_kills; // feed to condition to compute if let Some(cell) = LiveRangeAnalysis::port_to_cell_name(port) { - gens.insert(cell) + alive.insert(cell) } (alive, gens, kills) } @@ -466,10 +466,10 @@ fn build_live_ranges( (alive, gens, kills) } ir::Control::While(ir::While { body, port, .. }) => { - let (alive, mut gens, kills) = + let (mut alive, gens, kills) = build_live_ranges(body, alive, gens, kills, lr); if let Some(cell) = LiveRangeAnalysis::port_to_cell_name(port) { - gens.insert(cell) + alive.insert(cell) } build_live_ranges(body, alive, gens, kills, lr) } diff --git a/tests/passes/minimize-regs/condition-register.expect b/tests/passes/minimize-regs/condition-register.expect index 8e207d40b7..a40f0cc5cb 100644 --- a/tests/passes/minimize-regs/condition-register.expect +++ b/tests/passes/minimize-regs/condition-register.expect @@ -2,6 +2,7 @@ import "primitives/std.lib"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { x = std_reg(1); + y = std_reg(1); } wires { group wr_x { @@ -9,44 +10,22 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { x.write_en = 1'd1; wr_x[done] = x.done; } - group cond { - x.in = 1'd1; - x.write_en = 1'd1; - cond[done] = x.done; - } - group some_math { - x.in = 1'd0; - x.write_en = 1'd1; - some_math[done] = x.done; - } - group wr_z { - x.in = 1'd1; - x.write_en = 1'd1; - wr_z[done] = x.done; - } - group cond1 { - x.in = 1'd1; - x.write_en = 1'd1; - cond1[done] = x.done; + group wr_y { + y.in = 1'd1; + y.write_en = 1'd1; + wr_y[done] = y.done; } - group some_math1 { - x.in = 1'd0; - x.write_en = 1'd1; - some_math1[done] = x.done; + group rd_y { + rd_y[done] = y.out; } } control { seq { wr_x; - cond; + wr_y; if x.out { - some_math; - } - wr_z; - cond1; - while x.out { - some_math1; + rd_y; } } } diff --git a/tests/passes/minimize-regs/condition-register.futil b/tests/passes/minimize-regs/condition-register.futil index 43db427b44..18edc2da1d 100644 --- a/tests/passes/minimize-regs/condition-register.futil +++ b/tests/passes/minimize-regs/condition-register.futil @@ -4,7 +4,6 @@ component main() -> () { cells { x = std_reg(1); y = std_reg(1); - z = std_reg(1); } wires { @@ -14,48 +13,24 @@ component main() -> () { wr_x[done] = x.done; } - group cond { + group wr_y { y.in = 1'd1; y.write_en = 1'd1; - cond[done] = y.done; + wr_y[done] = y.done; } - group some_math { - y.in = 1'd0; - y.write_en = 1'd1; - some_math[done] = y.done; - } - - group wr_z { - z.in = 1'd1; - z.write_en = 1'd1; - wr_z[done] = z.done; + group rd_y { + rd_y[done] = y.out; } - group cond1 { - z.in = 1'd1; - z.write_en = 1'd1; - cond1[done] = z.done; - } - - group some_math1 { - z.in = 1'd0; - z.write_en = 1'd1; - some_math1[done] = z.done; - } } control { seq { - wr_x; - cond; - if y.out { - some_math; - } - wr_z; - cond1; - while z.out { - some_math1; + wr_x; // writes to x + wr_y; // writes to y + if x.out { // reads x + rd_y; // reads y } } } From da7bf507841fd99afeef79f13a68aae6571971f0 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 11:46:24 +0530 Subject: [PATCH 39/50] emit comb groups in circt backend --- src/backend/circt.rs | 21 +++++++++++++++++++++ tests/backend/circt/no-guards.expect | 10 +++++++--- tests/backend/circt/no-guards.futil | 10 +++++++--- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/backend/circt.rs b/src/backend/circt.rs index a5149a6ea0..51dc51a77f 100644 --- a/src/backend/circt.rs +++ b/src/backend/circt.rs @@ -131,6 +131,10 @@ impl CirctBackend { Self::write_group(&group.borrow(), 4, f)?; writeln!(f)?; } + for comb_group in comp.comb_groups.iter() { + Self::write_comb_group(&comb_group.borrow(), 4, f)?; + writeln!(f)?; + } // Write the continuous assignments for assign in &comp.continuous_assignments { Self::write_assignment(assign, 4, f)?; @@ -299,6 +303,23 @@ impl CirctBackend { write!(f, "{}}}", " ".repeat(indent_level)) } + /// Format and write combinational groups + pub fn write_comb_group( + group: &ir::CombGroup, + indent_level: usize, + f: &mut F, + ) -> io::Result<()> { + write!(f, "{}", " ".repeat(indent_level))?; + write!(f, "calyx.group @{}", group.name().id)?; + writeln!(f, " {{")?; + + for assign in &group.assignments { + Self::write_assignment(assign, indent_level + 2, f)?; + writeln!(f)?; + } + write!(f, "{}}}", " ".repeat(indent_level)) + } + /// Format and write a control program pub fn write_control( control: &ir::Control, diff --git a/tests/backend/circt/no-guards.expect b/tests/backend/circt/no-guards.expect index dd803cae1c..f772be223f 100644 --- a/tests/backend/circt/no-guards.expect +++ b/tests/backend/circt/no-guards.expect @@ -34,17 +34,21 @@ calyx.component @main(%go: i1, %clk: i1, %reset: i1, %go0: i1, %clk0: i1, %reset calyx.assign %r.write_en = %_1_1 : 1 calyx.group_done %r.done : 1 } + calyx.group @CombGroup { + calyx.assign %add.left = %r.out : 8 + calyx.assign %add.right = %_1_8 : 8 + } calyx.assign %c0.go = %_0_1 : 1 } calyx.control { calyx.seq { - calyx.enable @Group1; - while %c1.out with @Group2 { + calyx.enable @Group2; + while %c1.out with @CombGroup { calyx.seq { calyx.enable @Group1; calyx.enable @Group1; - calyx.if %c1.out with @Group2 { + calyx.if %c1.out with @CombGroup { calyx.enable @Group2; } } diff --git a/tests/backend/circt/no-guards.futil b/tests/backend/circt/no-guards.futil index b00e2a7132..7579c5e547 100644 --- a/tests/backend/circt/no-guards.futil +++ b/tests/backend/circt/no-guards.futil @@ -39,16 +39,20 @@ component main(go: 1, clk: 1, reset: 1) -> (done: 1) { r.write_en = 1'd1; Group2[done] = r.done; } + comb group CombGroup { + add.left = r.out; + add.right = 8'd1; + } c0.go = 1'd0; } control { seq { - Group1; - while c1.out with Group2 { + Group2; + while c1.out with CombGroup { seq { Group1; Group1; - if c1.out with Group2 { + if c1.out with CombGroup { Group2; } } From 2388ffd88448676677ff1b0dd60f6988c9062fa7 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 11:46:54 +0530 Subject: [PATCH 40/50] update test --- tests/errors/papercut/comb-port-in-condition.expect | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/errors/papercut/comb-port-in-condition.expect b/tests/errors/papercut/comb-port-in-condition.expect index 9bf2c33f93..125c1a7f09 100644 --- a/tests/errors/papercut/comb-port-in-condition.expect +++ b/tests/errors/papercut/comb-port-in-condition.expect @@ -3,4 +3,4 @@ ---STDERR--- Error: 4 | le = std_le(32); - | ^^ [Papercut] Port `le.out` is an output port on combinational primitive `std_le` and will always output 0. Add a `with` statement to enable a combinational group to run the primitive. + | ^^ [Papercut] Port `le.out` is an output port on combinational primitive `std_le` and will always output 0. Add a `with` statement to the `if` statement to ensure it has a valid value during execution. From d28e6e558494f28e34265767930b3642cc531d93 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 13:36:41 +0530 Subject: [PATCH 41/50] build dahlia with getHeaders --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ee5e10cdfd..077c06342f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -193,7 +193,7 @@ jobs: - name: Build Dahlia if: steps.dahlia-cache.outputs.cache-hit != 'true' run: | - cd ./dahlia && sbt assembly + cd ./dahlia && sbt "; getHeaders; assembly" shell: bash - name: Cache Calyx dependencies From 4c4180a81269c98f5394831cc2b4a34944dbc54d Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 5 Sep 2021 13:51:33 +0530 Subject: [PATCH 42/50] fmt --- calyx/src/passes/papercut.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/calyx/src/passes/papercut.rs b/calyx/src/passes/papercut.rs index 4c561b18bc..a500e2f3a4 100644 --- a/calyx/src/passes/papercut.rs +++ b/calyx/src/passes/papercut.rs @@ -260,7 +260,12 @@ impl Visitor for Papercut { if let ir::PortParent::Cell(cell_wref) = &port.parent { let cell_ref = cell_wref.upgrade(); let cell = cell_ref.borrow(); - if let ir::CellType::Primitive { is_comb, name: prim_name, .. } = &cell.prototype { + if let ir::CellType::Primitive { + is_comb, + name: prim_name, + .. + } = &cell.prototype + { if *is_comb { let msg = format!("Port `{}.{}` is an output port on combinational primitive `{}` and will always output 0. Add a `with` statement to the `while` statement to ensure it has a valid value during execution.", cell.name(), port.name, prim_name); return Err(Error::Papercut(msg, cell.name().clone())); @@ -282,7 +287,12 @@ impl Visitor for Papercut { if let ir::PortParent::Cell(cell_wref) = &port.parent { let cell_ref = cell_wref.upgrade(); let cell = cell_ref.borrow(); - if let ir::CellType::Primitive { is_comb, name: prim_name, .. } = &cell.prototype { + if let ir::CellType::Primitive { + is_comb, + name: prim_name, + .. + } = &cell.prototype + { if *is_comb { let msg = format!("Port `{}.{}` is an output port on combinational primitive `{}` and will always output 0. Add a `with` statement to the `if` statement to ensure it has a valid value during execution.", cell.name(), port.name, prim_name); return Err(Error::Papercut(msg, cell.name().clone())); From 7ce2b9b00006413168eccf8f72e9d8fbcd6928b3 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Sun, 5 Sep 2021 14:19:06 -0400 Subject: [PATCH 43/50] update interpreter to work (maybe) with comb groups --- interp/src/environment.rs | 1 + interp/src/interpreter/interpret_control.rs | 42 ++-- interp/src/interpreter/interpret_group.rs | 46 +++- .../steppers/control_interpreter.rs | 205 +++++++++++++----- .../interpreter/steppers/group_interpreter.rs | 11 +- 5 files changed, 229 insertions(+), 76 deletions(-) diff --git a/interp/src/environment.rs b/interp/src/environment.rs index 3bb0fa4bdd..d30b89b630 100644 --- a/interp/src/environment.rs +++ b/interp/src/environment.rs @@ -156,6 +156,7 @@ impl InterpreterState { if let ir::CellType::Primitive { name, param_binding, + is_comb, } = cl.prototype.clone() { let cell_name = match name.as_ref() { diff --git a/interp/src/interpreter/interpret_control.rs b/interp/src/interpreter/interpret_control.rs index be0652a40f..ad34c65f5b 100644 --- a/interp/src/interpreter/interpret_control.rs +++ b/interp/src/interpreter/interpret_control.rs @@ -1,7 +1,8 @@ //! Inteprets a control in a component. use super::interpret_group::{ - finish_group_interpretation, interp_cont, interpret_group, + finish_comb_group_interpretation, finish_group_interpretation, interp_cont, + interpret_comb_group, interpret_group, }; use crate::environment::InterpreterState; use crate::errors::InterpreterResult; @@ -97,13 +98,19 @@ fn eval_if( mut env: InterpreterState, comp: &ir::Component, ) -> InterpreterResult { - env = interpret_group(&i.cond.borrow(), continuous_assignments, env)?; + if let Some(comb) = &i.cond { + env = + interpret_comb_group(&comb.borrow(), continuous_assignments, env)?; + } + let cond_flag = env.get_from_port(&i.port.borrow()).as_u64(); - env = finish_group_interpretation( - &i.cond.borrow(), - continuous_assignments, - env, - )?; + if let Some(comb) = &i.cond { + env = finish_comb_group_interpretation( + &comb.borrow(), + continuous_assignments, + env, + )?; + } let target = if cond_flag == 0 { &i.fbranch @@ -126,14 +133,23 @@ fn eval_while( comp: &ir::Component, ) -> InterpreterResult { loop { - env = interpret_group(&w.cond.borrow(), continuous_assignments, env)?; + if let Some(comb) = &w.cond { + env = interpret_comb_group( + &comb.borrow(), + continuous_assignments, + env, + )?; + } let cond_val = env.get_from_port(&w.port.borrow()).as_u64(); - env = finish_group_interpretation( - &w.cond.borrow(), - continuous_assignments, - env, - )?; + + if let Some(comb) = &w.cond { + env = finish_comb_group_interpretation( + &comb.borrow(), + continuous_assignments, + env, + )?; + } if cond_val == 0 { break; diff --git a/interp/src/interpreter/interpret_group.rs b/interp/src/interpreter/interpret_group.rs index 445993e177..dbd69c4b89 100644 --- a/interp/src/interpreter/interpret_group.rs +++ b/interp/src/interpreter/interpret_group.rs @@ -58,7 +58,7 @@ pub fn interp_cont( let mut assign_interp = AssignmentInterpreter::new( env, - done_prt_ref, + Some(done_prt_ref), (std::iter::empty(), continuous_assignments.iter()), ); assign_interp.run()?; @@ -73,7 +73,7 @@ pub fn interp_cont( // required because of lifetime shennanigans let final_env = finish_interpretation( res, - &done_port.borrow() as &ir::Port as ConstPort, + Some(&done_port.borrow() as &ir::Port as ConstPort), continuous_assignments.iter(), ); final_env @@ -91,7 +91,23 @@ pub fn interpret_group( let interp = AssignmentInterpreter::new( env, - grp_done_ref, + Some(grp_done_ref), + (group.assignments.iter(), continuous_assignments.iter()), + ); + + interp.run_and_deconstruct() +} + +/// Evaluates a group, given an environment. +pub fn interpret_comb_group( + group: &ir::CombGroup, + // TODO (griffin): Use these during interpretation + continuous_assignments: &[ir::Assignment], + env: InterpreterState, +) -> InterpreterResult { + let interp = AssignmentInterpreter::new( + env, + None, (group.assignments.iter(), continuous_assignments.iter()), ); @@ -108,7 +124,22 @@ pub fn finish_group_interpretation( finish_interpretation( env, - grp_done_ref, + Some(grp_done_ref), + group + .assignments + .iter() + .chain(continuous_assignments.iter()), + ) +} + +pub fn finish_comb_group_interpretation( + group: &ir::CombGroup, + continuous_assignments: &[ir::Assignment], + env: InterpreterState, +) -> InterpreterResult { + finish_interpretation::<_, ConstPort>( + env, + None, group .assignments .iter() @@ -198,7 +229,7 @@ pub(crate) fn finish_interpretation< P: AsRaw, >( mut env: InterpreterState, - done_signal: P, + done_signal: Option

, assigns: I, ) -> InterpreterResult { // replace port values for all the assignments @@ -213,7 +244,10 @@ pub(crate) fn finish_interpretation< let cells = get_dest_cells(assigns.iter().copied()); - env.insert(done_signal.as_raw(), Value::bit_low()); + if let Some(done_signal) = done_signal { + env.insert(done_signal.as_raw(), Value::bit_low()); + } + eval_prims(&mut env, cells.iter(), true); Ok(env) diff --git a/interp/src/interpreter/steppers/control_interpreter.rs b/interp/src/interpreter/steppers/control_interpreter.rs index c28b52a40e..4124971cc3 100644 --- a/interp/src/interpreter/steppers/control_interpreter.rs +++ b/interp/src/interpreter/steppers/control_interpreter.rs @@ -8,9 +8,10 @@ use crate::{ interpreter::utils::{is_signal_high, ConstPort, ReferenceHolder}, values::Value, }; -use calyx::ir::{self, Assignment, Component, Control}; +use calyx::ir::{self, Assignment, Component, Control, RRC}; use itertools::{peek_nth, Itertools, PeekNth}; use std::cell::Ref; +use std::rc::Rc; // this almost certainly doesn't need to exist but it can't be a trait fn with a // default impl because it consumes self @@ -76,11 +77,60 @@ impl Interpreter for EmptyInterpreter { } } -type EnableHolder<'a> = ReferenceHolder<'a, ir::Group>; +pub enum EnableHolder<'a> { + RefGroup(Ref<'a, ir::Group>), + RefCombGroup(Ref<'a, ir::CombGroup>), + BorrowGrp(&'a ir::Group), + BorrowCombGroup(&'a ir::CombGroup), +} + +impl<'a> From<&'a ir::Group> for EnableHolder<'a> { + fn from(grp: &'a ir::Group) -> Self { + Self::BorrowGrp(grp) + } +} + +impl<'a> From<&'a ir::CombGroup> for EnableHolder<'a> { + fn from(comb_grp: &'a ir::CombGroup) -> Self { + Self::BorrowCombGroup(comb_grp) + } +} + +impl<'a> From> for EnableHolder<'a> { + fn from(grp: Ref<'a, ir::Group>) -> Self { + Self::RefGroup(grp) + } +} + +impl<'a> From> for EnableHolder<'a> { + fn from(comb_grp: Ref<'a, ir::CombGroup>) -> Self { + Self::RefCombGroup(comb_grp) + } +} + +impl<'a> From<&'a ir::Enable> for EnableHolder<'a> { + fn from(en: &'a ir::Enable) -> Self { + Self::RefGroup(en.group.borrow()) + } +} -impl<'a> From<&'a ir::Enable> for ReferenceHolder<'a, ir::Group> { - fn from(e: &'a ir::Enable) -> Self { - e.group.borrow().into() +impl<'a> EnableHolder<'a> { + fn assignments(&self) -> &[ir::Assignment] { + match self { + EnableHolder::RefGroup(x) => &x.assignments, + EnableHolder::RefCombGroup(x) => &x.assignments, + EnableHolder::BorrowGrp(x) => &x.assignments, + EnableHolder::BorrowCombGroup(x) => &x.assignments, + } + } + + fn done_port(&self) -> Option { + match self { + EnableHolder::RefGroup(x) => Some(get_done_port(x).as_raw()), + EnableHolder::BorrowGrp(x) => Some(get_done_port(x).as_raw()), + EnableHolder::BorrowCombGroup(_) + | EnableHolder::RefCombGroup(_) => None, + } } } @@ -102,15 +152,11 @@ impl<'a> EnableInterpreter<'a> { { let enable: EnableHolder = enable.into(); let assigns = ( - enable.assignments.iter().cloned().collect_vec(), + enable.assignments().iter().cloned().collect_vec(), continuous.iter().cloned().collect_vec(), ); - let done = get_done_port(&enable); - let interp = AssignmentInterpreter::new_owned( - env, - &done.borrow() as &ir::Port as *const ir::Port, - assigns, - ); + let done = enable.done_port(); + let interp = AssignmentInterpreter::new_owned(env, done, assigns); Self { enable, group_name, @@ -121,7 +167,7 @@ impl<'a> EnableInterpreter<'a> { impl<'a> EnableInterpreter<'a> { fn reset(self) -> InterpreterState { - self.interp.reset(self.enable.assignments.iter()) + self.interp.reset(self.enable.assignments().iter()) } fn get>(&self, port: P) -> &Value { self.interp.get(port) @@ -299,7 +345,7 @@ impl<'a> Interpreter for ParInterpreter<'a> { } } pub struct IfInterpreter<'a> { - port: ConstPort, + cond_port: ConstPort, cond: Option>, tbranch: &'a Control, fbranch: &'a Control, @@ -313,19 +359,36 @@ impl<'a> IfInterpreter<'a> { env: InterpreterState, continuous_assigns: &'a [Assignment], ) -> Self { - let port: ConstPort = ctrl_if.port.as_ptr(); - let cond = EnableInterpreter::new( - ctrl_if.cond.borrow(), - Some(ctrl_if.cond.borrow().name().clone()), - env, - continuous_assigns, - ); + let cond_port: ConstPort = ctrl_if.port.as_ptr(); + + let (cond, branch_interp) = if let Some(cond) = &ctrl_if.cond { + ( + Some(EnableInterpreter::new( + cond.borrow(), + Some(cond.borrow().name().clone()), + env, + continuous_assigns, + )), + None, + ) + } else { + let grp = if is_signal_high(env.get_from_port(cond_port)) { + &ctrl_if.tbranch + } else { + &ctrl_if.fbranch + }; + ( + None, + Some(ControlInterpreter::new(grp, env, continuous_assigns)), + ) + }; + Self { - port, - cond: Some(cond), + cond_port, + cond, tbranch: &ctrl_if.tbranch, fbranch: &ctrl_if.fbranch, - branch_interp: None, + branch_interp, continuous_assignments: continuous_assigns, } } @@ -338,7 +401,7 @@ impl<'a> Interpreter for IfInterpreter<'a> { let i = self.cond.take().unwrap(); let branch; #[allow(clippy::branches_sharing_code)] - if is_signal_high(i.get(self.port)) { + if is_signal_high(i.get(self.cond_port)) { let env = i.deconstruct(); branch = ControlInterpreter::new( self.tbranch, @@ -396,11 +459,12 @@ impl<'a> Interpreter for IfInterpreter<'a> { } pub struct WhileInterpreter<'a> { port: ConstPort, - cond: Ref<'a, ir::Group>, + cond: Option>, body: &'a Control, continuous_assignments: &'a [ir::Assignment], cond_interp: Option>, body_interp: Option>, + terminal_env: Option, } impl<'a> WhileInterpreter<'a> { @@ -410,20 +474,41 @@ impl<'a> WhileInterpreter<'a> { continuous_assignments: &'a [Assignment], ) -> Self { let port: ConstPort = ctrl_while.port.as_ptr(); - let cond = ctrl_while.cond.borrow(); - let cond_interp = EnableInterpreter::new( - Ref::clone(&cond), - Some(cond.name().clone()), - env, - continuous_assignments, - ); + let cond_interp; + let body_interp; + let terminal_env; + + if let Some(cond) = &ctrl_while.cond { + cond_interp = Some(EnableInterpreter::new( + cond.borrow(), + Some(cond.borrow().name().clone()), + env, + continuous_assignments, + )); + terminal_env = None; + body_interp = None; + } else if is_signal_high(env.get_from_port(port)) { + body_interp = Some(ControlInterpreter::new( + &ctrl_while.body, + env, + continuous_assignments, + )); + terminal_env = None; + cond_interp = None; + } else { + terminal_env = Some(env); + body_interp = None; + cond_interp = None; + } + Self { port, - cond, + cond: ctrl_while.cond.as_ref().map(|x| x.borrow()), body: &ctrl_while.body, continuous_assignments, - cond_interp: Some(cond_interp), - body_interp: None, + cond_interp, + body_interp, + terminal_env, } } } @@ -451,14 +536,27 @@ impl<'a> Interpreter for WhileInterpreter<'a> { bi.step()? } else { let bi = self.body_interp.take().unwrap(); - let cond_interp = EnableInterpreter::new( - Ref::clone(&self.cond), - Some(self.cond.name().clone()), - bi.deconstruct(), - self.continuous_assignments, - ); - self.cond_interp = Some(cond_interp) + let env = bi.deconstruct(); + + if let Some(cond) = &self.cond { + let cond_interp = EnableInterpreter::new( + Ref::clone(cond), + Some(cond.name().clone()), + env, + self.continuous_assignments, + ); + self.cond_interp = Some(cond_interp) + } else if is_signal_high(env.get_from_port(self.port)) { + self.body_interp = Some(ControlInterpreter::new( + self.body, + env, + self.continuous_assignments, + )); + } else { + self.terminal_env = Some(env); + } } + } else if self.terminal_env.is_some() { } else { panic!("While Interpreter is in an invalid state") } @@ -466,16 +564,11 @@ impl<'a> Interpreter for WhileInterpreter<'a> { } fn deconstruct(self) -> InterpreterState { - self.cond_interp.unwrap().deconstruct() + self.terminal_env.unwrap() } fn is_done(&self) -> bool { - self.body_interp.is_none() - && self.cond_interp.is_some() - && self.cond_interp.as_ref().unwrap().is_done() - && !is_signal_high( - self.cond_interp.as_ref().unwrap().get(self.port), - ) + self.terminal_env.is_some() } fn get_env(&self) -> Vec<&InterpreterState> { @@ -483,6 +576,8 @@ impl<'a> Interpreter for WhileInterpreter<'a> { cond.get_env() } else if let Some(body) = &self.body_interp { body.get_env() + } else if let Some(env) = &self.terminal_env { + vec![&env] } else { unreachable!("Invalid internal state for WhileInterpreter") } @@ -652,7 +747,7 @@ impl<'a> StructuralInterpreter<'a> { let interp = AssignmentInterpreter::new( env, - done_port, + Some(done_port), (std::iter::empty(), continuous_assignments.iter()), ); @@ -673,8 +768,12 @@ impl<'a> Interpreter for StructuralInterpreter<'a> { fn deconstruct(self) -> InterpreterState { let mut final_env = self.interp.deconstruct(); final_env.insert(self.go_port, Value::bit_low()); - finish_interpretation(final_env, self.done_port, self.continuous.iter()) - .unwrap() + finish_interpretation( + final_env, + Some(self.done_port), + self.continuous.iter(), + ) + .unwrap() } fn run(&mut self) -> InterpreterResult<()> { diff --git a/interp/src/interpreter/steppers/group_interpreter.rs b/interp/src/interpreter/steppers/group_interpreter.rs index 7f25e968c7..6530090370 100644 --- a/interp/src/interpreter/steppers/group_interpreter.rs +++ b/interp/src/interpreter/steppers/group_interpreter.rs @@ -66,7 +66,7 @@ where /// group of assignments pub struct AssignmentInterpreter<'a> { state: InterpreterState, - done_port: ConstPort, + done_port: Option, assigns: AssignmentOwner<'a>, cells: Vec>, val_changed: Option, @@ -77,7 +77,7 @@ impl<'a> AssignmentInterpreter<'a> { /// assignments from an outside context pub fn new( state: InterpreterState, - done_signal: ConstPort, + done_signal: Option, assigns: (I1, I2), ) -> Self where @@ -101,7 +101,7 @@ impl<'a> AssignmentInterpreter<'a> { /// interpretes pub fn new_owned( state: InterpreterState, - done_signal: ConstPort, + done_signal: Option, vecs: (Vec, Vec), ) -> Self { let done_port = done_signal; @@ -268,7 +268,10 @@ impl<'a> AssignmentInterpreter<'a> { #[inline] fn is_done(&self) -> bool { - utils::is_signal_high(self.state.get_from_port(self.done_port)) + self.done_port.is_none() + || utils::is_signal_high( + self.state.get_from_port(self.done_port.unwrap()), + ) } pub fn deconstruct(self) -> InterpreterState { From 96583094d555668953f508380c1bbe6723c510ad Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Sun, 5 Sep 2021 14:40:42 -0400 Subject: [PATCH 44/50] fix while bug --- interp/src/interpreter/steppers/control_interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interp/src/interpreter/steppers/control_interpreter.rs b/interp/src/interpreter/steppers/control_interpreter.rs index 4124971cc3..2cffbd2456 100644 --- a/interp/src/interpreter/steppers/control_interpreter.rs +++ b/interp/src/interpreter/steppers/control_interpreter.rs @@ -526,7 +526,7 @@ impl<'a> Interpreter for WhileInterpreter<'a> { ); self.body_interp = Some(body_interp) } else { - self.cond_interp = Some(ci) + self.terminal_env = Some(ci.deconstruct()) } } else { ci.step()? From a24f4eef8cb380730a981ad483ea1fb8d6391e26 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Sun, 5 Sep 2021 14:40:55 -0400 Subject: [PATCH 45/50] update tests and add timeout --- interp/runt.toml | 17 ++++++++++++++--- interp/tests/complex/unsigned-dot-product.futil | 3 +-- interp/tests/control/if.futil | 3 +-- interp/tests/control/if_reg.futil | 6 +++++- interp/tests/control/iteration/iter_mult.futil | 6 ++---- interp/tests/control/iteration/while.futil | 3 +-- interp/tests/control/static/while_static.futil | 3 +-- interp/tests/errors/multiple_drivers_comb.futil | 3 +-- 8 files changed, 26 insertions(+), 18 deletions(-) diff --git a/interp/runt.toml b/interp/runt.toml index ea69914fe8..fa9a363453 100644 --- a/interp/runt.toml +++ b/interp/runt.toml @@ -9,6 +9,7 @@ paths = [ cmd = """ ../target/debug/interp {} | jq .memories """ +timeout = 3 [[tests]] name = "errors" @@ -19,6 +20,7 @@ paths = [ cmd = """ ../target/debug/interp {} """ +timeout = 3 [[tests]] name = "complex" @@ -29,6 +31,7 @@ paths = [ cmd = """ ../target/debug/interp {} """ +timeout = 3 [[tests]] name = "primitives" @@ -38,6 +41,7 @@ paths = [ cmd = """ ../target/debug/interp {} | jq .memories """ +timeout = 3 [[tests]] name = "par to seq" @@ -48,6 +52,7 @@ paths = [ cmd = """ ../target/debug/futil {} -p par-to-seq -l ../ | ../target/debug/interp | jq .memories """ +timeout = 3 [[tests]] name = "control" @@ -59,6 +64,7 @@ paths = [ cmd = """ ../target/debug/interp {} | jq .memories """ +timeout = 3 [[tests]] name = "fully structural" @@ -68,10 +74,10 @@ paths = [ # "tests/control/iteration/*.futil" ] cmd = """ -../target/debug/futil {} -d static-timing -d pre-opt -d post-opt -l ../ | ../target/debug/interp | jq .memories +../target/debug/futil {} -d pre-opt -d post-opt -l ../ | ../target/debug/interp | jq .memories """ expect_dir = "tests/lowered/" - +timeout = 3 [[tests]] @@ -82,6 +88,7 @@ paths = [ cmd = """ ../target/debug/interp {} debug -p | jq .memories """ +timeout = 3 [[tests]] name = "primitives (CIDR)" @@ -91,6 +98,7 @@ paths = [ cmd = """ ../target/debug/interp {} debug -p | jq .memories """ +timeout = 3 [[tests]] name = "control (CIDR)" @@ -101,6 +109,7 @@ paths = [ cmd = """ ../target/debug/interp {} debug -p | jq .memories """ +timeout = 3 [[tests]] name = "fully structural (CIDR)" @@ -110,8 +119,9 @@ paths = [ # "tests/control/iteration/*.futil" ] cmd = """ -../target/debug/futil {} -d static-timing -d pre-opt -d post-opt -l ../ | ../target/debug/interp debug -p | jq .memories +../target/debug/futil {} -d pre-opt -d post-opt -l ../ | ../target/debug/interp debug -p | jq .memories """ +timeout = 3 [[tests]] name = "fully structural static" @@ -122,3 +132,4 @@ cmd = """ ../target/debug/futil {} -d pre-opt -d post-opt -l ../ | ../target/debug/interp | jq .memories """ expect_dir = "tests/lowered/" +timeout = 3 diff --git a/interp/tests/complex/unsigned-dot-product.futil b/interp/tests/complex/unsigned-dot-product.futil index 0de0f02358..be581681ad 100644 --- a/interp/tests/complex/unsigned-dot-product.futil +++ b/interp/tests/complex/unsigned-dot-product.futil @@ -16,8 +16,7 @@ component main() -> () { @external mult = std_mult_pipe(32); } wires { - group is_less_than<"static"=0> { - is_less_than[done] = 1'd1; + comb group is_less_than<"static"=0> { lt0.left = counter.out; lt0.right = 3'd4; } // Control segment for `counter` < `4`. diff --git a/interp/tests/control/if.futil b/interp/tests/control/if.futil index d5548255d3..69ff5ed80b 100644 --- a/interp/tests/control/if.futil +++ b/interp/tests/control/if.futil @@ -7,12 +7,11 @@ component main() -> () { } wires { - group cond<"static"=0> { + comb group cond<"static"=0> { //b/c lt is used in this distinctly not-last group, //by end of execution all its ports are 0/X/not asserted. lt.left = 32'd9; lt.right = 32'd16; - cond[done] = 1'd1; } group true<"static"=1> { diff --git a/interp/tests/control/if_reg.futil b/interp/tests/control/if_reg.futil index 7a536e67dc..69fde2ae28 100644 --- a/interp/tests/control/if_reg.futil +++ b/interp/tests/control/if_reg.futil @@ -36,10 +36,14 @@ component main() -> () { //b/c this isn't just 1 group prog, //reg1 should have [done] low //at the end of execution (tho prog. ends when reg1.done is high) - if lt0.out with cond { + seq { + cond; + if reg0.out { true; } else { false; } + } + } } diff --git a/interp/tests/control/iteration/iter_mult.futil b/interp/tests/control/iteration/iter_mult.futil index 1753ec79b1..5627769dd0 100644 --- a/interp/tests/control/iteration/iter_mult.futil +++ b/interp/tests/control/iteration/iter_mult.futil @@ -131,11 +131,10 @@ component main() -> () { shift_c[done] = c.done; } - group cond_while { + comb group cond_while { //lt compares i and 4 lt.left = i.out; lt.right = 3'd4; - cond_while[done] = 1'b1; } group incr_while { @@ -147,10 +146,9 @@ component main() -> () { incr_while[done] = i.done; } - group cond_if { + comb group cond_if { //get LSB of Q slicer.in = q.out; - cond_if[done] = 1'b1; } } diff --git a/interp/tests/control/iteration/while.futil b/interp/tests/control/iteration/while.futil index f82d2012e5..4e2b6b1ff6 100644 --- a/interp/tests/control/iteration/while.futil +++ b/interp/tests/control/iteration/while.futil @@ -8,11 +8,10 @@ component main() -> () { } wires { - group cond<"static"=0> { //how can something take 0 cycles? + comb group cond<"static"=0> { //how can something take 0 cycles? i.addr0 = 1'd0; lt.left = i.read_data; lt.right = 32'd8; - cond[done] = 1'b1; } group incr<"static"=1> { diff --git a/interp/tests/control/static/while_static.futil b/interp/tests/control/static/while_static.futil index 00c32f3848..5dae8dfc4e 100644 --- a/interp/tests/control/static/while_static.futil +++ b/interp/tests/control/static/while_static.futil @@ -6,8 +6,7 @@ component main() -> () { } wires { - group cond_while { - cond_while[done] = 1'b1; + comb group cond_while { } } diff --git a/interp/tests/errors/multiple_drivers_comb.futil b/interp/tests/errors/multiple_drivers_comb.futil index 5f88b21e3a..24edc54fd6 100644 --- a/interp/tests/errors/multiple_drivers_comb.futil +++ b/interp/tests/errors/multiple_drivers_comb.futil @@ -8,11 +8,10 @@ component main() -> () { } wires { - group op { + comb group op { add0.left = const0.out; add0.left = const1.out; add0.right = const1.out; - op[done] = 1'b1; } } From 28ebac282c5c94837fcae85a8de595ef57f0bea6 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Sun, 5 Sep 2021 14:43:38 -0400 Subject: [PATCH 46/50] make tdcc happy --- interp/runt.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interp/runt.toml b/interp/runt.toml index fa9a363453..b4417b927b 100644 --- a/interp/runt.toml +++ b/interp/runt.toml @@ -74,7 +74,7 @@ paths = [ # "tests/control/iteration/*.futil" ] cmd = """ -../target/debug/futil {} -d pre-opt -d post-opt -l ../ | ../target/debug/interp | jq .memories +../target/debug/futil {} -d pre-opt -d post-opt -p remove-comb-groups -l ../ | ../target/debug/interp | jq .memories """ expect_dir = "tests/lowered/" timeout = 3 @@ -119,7 +119,7 @@ paths = [ # "tests/control/iteration/*.futil" ] cmd = """ -../target/debug/futil {} -d pre-opt -d post-opt -l ../ | ../target/debug/interp debug -p | jq .memories +../target/debug/futil {} -d pre-opt -d post-opt -p remove-comb-groups -l ../ | ../target/debug/interp debug -p | jq .memories """ timeout = 3 @@ -129,7 +129,7 @@ paths = [ "tests/control/static*.futil" ] cmd = """ -../target/debug/futil {} -d pre-opt -d post-opt -l ../ | ../target/debug/interp | jq .memories +../target/debug/futil {} -d pre-opt -d post-opt -l ../ | ../target/debug/interp | jq .memories """ expect_dir = "tests/lowered/" timeout = 3 From 63c2567de25a242e46d28595346d1ad9d821ef34 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Sun, 5 Sep 2021 14:44:45 -0400 Subject: [PATCH 47/50] clean up warnings --- interp/src/environment.rs | 2 +- interp/src/interpreter/steppers/control_interpreter.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/interp/src/environment.rs b/interp/src/environment.rs index d30b89b630..af8e441d0a 100644 --- a/interp/src/environment.rs +++ b/interp/src/environment.rs @@ -156,7 +156,7 @@ impl InterpreterState { if let ir::CellType::Primitive { name, param_binding, - is_comb, + is_comb: _, } = cl.prototype.clone() { let cell_name = match name.as_ref() { diff --git a/interp/src/interpreter/steppers/control_interpreter.rs b/interp/src/interpreter/steppers/control_interpreter.rs index 2cffbd2456..08fe1034ad 100644 --- a/interp/src/interpreter/steppers/control_interpreter.rs +++ b/interp/src/interpreter/steppers/control_interpreter.rs @@ -5,13 +5,12 @@ use crate::utils::AsRaw; use crate::{ environment::InterpreterState, errors::InterpreterResult, - interpreter::utils::{is_signal_high, ConstPort, ReferenceHolder}, + interpreter::utils::{is_signal_high, ConstPort}, values::Value, }; -use calyx::ir::{self, Assignment, Component, Control, RRC}; +use calyx::ir::{self, Assignment, Component, Control}; use itertools::{peek_nth, Itertools, PeekNth}; use std::cell::Ref; -use std::rc::Rc; // this almost certainly doesn't need to exist but it can't be a trait fn with a // default impl because it consumes self From 8bd143056b733d75994a4e9975eb68e6e38e604c Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Sun, 5 Sep 2021 14:57:18 -0400 Subject: [PATCH 48/50] clippy --- interp/src/interpreter/steppers/control_interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interp/src/interpreter/steppers/control_interpreter.rs b/interp/src/interpreter/steppers/control_interpreter.rs index 08fe1034ad..5a84f54a50 100644 --- a/interp/src/interpreter/steppers/control_interpreter.rs +++ b/interp/src/interpreter/steppers/control_interpreter.rs @@ -576,7 +576,7 @@ impl<'a> Interpreter for WhileInterpreter<'a> { } else if let Some(body) = &self.body_interp { body.get_env() } else if let Some(env) = &self.terminal_env { - vec![&env] + vec![env] } else { unreachable!("Invalid internal state for WhileInterpreter") } From 67e1eae1958d3217c970222269a77ad1acbe70c7 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 6 Sep 2021 08:43:26 +0530 Subject: [PATCH 49/50] reserved cells test is not longer relevant --- calyx/src/passes/well_formed.rs | 59 +++++++++++--------------- tests/errors/reserved-cell-name.expect | 6 --- tests/errors/reserved-cell-name.futil | 10 ----- 3 files changed, 24 insertions(+), 51 deletions(-) delete mode 100644 tests/errors/reserved-cell-name.expect delete mode 100644 tests/errors/reserved-cell-name.futil diff --git a/calyx/src/passes/well_formed.rs b/calyx/src/passes/well_formed.rs index 6635b4f2f9..6a71701e6b 100644 --- a/calyx/src/passes/well_formed.rs +++ b/calyx/src/passes/well_formed.rs @@ -1,33 +1,20 @@ use crate::errors::Error; use crate::ir::traversal::{Action, Named, VisResult, Visitor}; -use crate::ir::{ - self, CloneName, Component, LibrarySignatures, RESERVED_NAMES, -}; +use crate::ir::{self, CloneName, Component, LibrarySignatures}; use std::collections::HashSet; /// Pass to check if the program is well-formed. /// /// Catches the following errors: -/// 1. Programs that use reserved SystemVerilog keywords as identifiers. -/// 2. Programs that don't use a defined group. +/// 1. Programs that don't use a defined group or combinational group. +/// 2. Groups that don't write to their done signal. +/// 3. Groups that write to another group's done signal. +#[derive(Default)] pub struct WellFormed { - /// Set of names that components and cells are not allowed to have. - reserved_names: HashSet, - /// Names of the groups that have been used in the control. used_groups: HashSet, -} - -impl Default for WellFormed { - fn default() -> Self { - let reserved_names = - RESERVED_NAMES.iter().map(|s| s.to_string()).collect(); - - WellFormed { - reserved_names, - used_groups: HashSet::new(), - } - } + /// Names of combinational groups used in the control. + used_comb_groups: HashSet, } impl Named for WellFormed { @@ -46,14 +33,6 @@ impl Visitor for WellFormed { comp: &mut Component, _ctx: &LibrarySignatures, ) -> VisResult { - // Check if any of the cells use a reserved name. - for cell_ref in comp.cells.iter() { - let cell = cell_ref.borrow(); - if self.reserved_names.contains(&cell.name().id) { - return Err(Error::ReservedName(cell.clone_name())); - } - } - // For each non-combinational group, check if there is at least one write to the done // signal of that group. // Names of the groups whose `done` hole has been written to. @@ -168,7 +147,7 @@ impl Visitor for WellFormed { ) -> VisResult { // Add cond group as a used port. if let Some(cond) = &s.cond { - self.used_groups.insert(cond.clone_name()); + self.used_comb_groups.insert(cond.clone_name()); } Ok(Action::Continue) } @@ -181,7 +160,7 @@ impl Visitor for WellFormed { ) -> VisResult { // Add cond group as a used port. if let Some(cond) = &s.cond { - self.used_groups.insert(cond.clone_name()); + self.used_comb_groups.insert(cond.clone_name()); } Ok(Action::Continue) } @@ -193,11 +172,21 @@ impl Visitor for WellFormed { ) -> VisResult { let all_groups: HashSet = comp.groups.iter().map(|g| g.clone_name()).collect(); - let unused_group = - all_groups.difference(&self.used_groups).into_iter().next(); - match unused_group { - Some(group) => Err(Error::UnusedGroup(group.clone())), - None => Ok(Action::Continue), + if let Some(group) = + all_groups.difference(&self.used_groups).into_iter().next() + { + return Err(Error::UnusedGroup(group.clone())); + }; + + let all_comb_groups: HashSet = + comp.comb_groups.iter().map(|g| g.clone_name()).collect(); + if let Some(group) = all_comb_groups + .difference(&self.used_comb_groups) + .into_iter() + .next() + { + return Err(Error::UnusedGroup(group.clone())); } + Ok(Action::Continue) } } diff --git a/tests/errors/reserved-cell-name.expect b/tests/errors/reserved-cell-name.expect deleted file mode 100644 index 60cb7d0ef0..0000000000 --- a/tests/errors/reserved-cell-name.expect +++ /dev/null @@ -1,6 +0,0 @@ ----CODE--- -1 ----STDERR--- -Error: -4 | reg = std_reg(32); - | ^^^ Use of reserved keyword: reg diff --git a/tests/errors/reserved-cell-name.futil b/tests/errors/reserved-cell-name.futil deleted file mode 100644 index 27b501b9dc..0000000000 --- a/tests/errors/reserved-cell-name.futil +++ /dev/null @@ -1,10 +0,0 @@ -import "primitives/std.lib"; -component main() -> () { - cells { - reg = std_reg(32); - } - wires { - } - control { - } -} From a5320099782fd829f1384eba2e78f87a3ce48bb5 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 6 Sep 2021 09:25:51 +0530 Subject: [PATCH 50/50] fmt --- calyx/src/ir/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calyx/src/ir/context.rs b/calyx/src/ir/context.rs index 2f9086d4ef..4e0dc3c0e4 100644 --- a/calyx/src/ir/context.rs +++ b/calyx/src/ir/context.rs @@ -28,7 +28,7 @@ impl LibrarySignatures { where S: AsRef, { - &self.sigs.get(&name.as_ref().into()).unwrap_or_else(|| { + self.sigs.get(&name.as_ref().into()).unwrap_or_else(|| { panic!( "Primitive `{}` is not defined in the context.", name.as_ref()