From dec5a29b994308ddb8ba55fc8773cc78705567d9 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 8 Jun 2022 13:57:46 -0400 Subject: [PATCH 01/32] first version of parseq-to-seqpar pass --- calyx/src/default_passes.rs | 8 +- calyx/src/passes/mod.rs | 2 + calyx/src/passes/parseq_to_seqpar.rs | 116 ++++++++++++++++++ .../compile-par-partial-static.futil | 16 +-- tests/passes/parseq-to-seqpar.expect | 75 +++++++++++ tests/passes/parseq-to-seqpar.futil | 47 +++++++ 6 files changed, 246 insertions(+), 18 deletions(-) create mode 100644 calyx/src/passes/parseq_to_seqpar.rs create mode 100644 tests/passes/parseq-to-seqpar.expect create mode 100644 tests/passes/parseq-to-seqpar.futil diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index d8cb467aa1..7c646e866c 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -4,9 +4,10 @@ use crate::passes::{ CompileInvoke, ComponentInliner, ComponentInterface, DeadCellRemoval, DeadGroupRemoval, Externalize, GoInsertion, GroupToInvoke, HoleInliner, InferStaticTiming, LowerGuards, MergeAssign, MergeStaticPar, MinimizeRegs, - Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, ResetInsertion, - ResourceSharing, SimplifyGuards, SynthesisPapercut, TopDownCompileControl, - TopDownStaticTiming, UnrollBounded, WellFormed, WireInliner, + Papercut, ParSeqToSeqPar, ParToSeq, RegisterUnsharing, RemoveCombGroups, + ResetInsertion, ResourceSharing, SimplifyGuards, SynthesisPapercut, + TopDownCompileControl, TopDownStaticTiming, UnrollBounded, WellFormed, + WireInliner, }; use crate::{ errors::CalyxResult, ir::traversal::Named, pass_manager::PassManager, @@ -34,6 +35,7 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; + pm.register_pass::()?; // Compilation passes pm.register_pass::()?; diff --git a/calyx/src/passes/mod.rs b/calyx/src/passes/mod.rs index 02e6d875c6..24eaf22f47 100644 --- a/calyx/src/passes/mod.rs +++ b/calyx/src/passes/mod.rs @@ -21,6 +21,7 @@ mod merge_static_par; mod minimize_regs; mod papercut; mod par_to_seq; +mod parseq_to_seqpar; mod register_unsharing; mod remove_comb_groups; mod reset_insertion; @@ -55,6 +56,7 @@ pub use merge_static_par::MergeStaticPar; pub use minimize_regs::MinimizeRegs; pub use papercut::Papercut; pub use par_to_seq::ParToSeq; +pub use parseq_to_seqpar::ParSeqToSeqPar; pub use register_unsharing::RegisterUnsharing; pub use remove_comb_groups::RemoveCombGroups; pub use reset_insertion::ResetInsertion; diff --git a/calyx/src/passes/parseq_to_seqpar.rs b/calyx/src/passes/parseq_to_seqpar.rs new file mode 100644 index 0000000000..1c26dacf7c --- /dev/null +++ b/calyx/src/passes/parseq_to_seqpar.rs @@ -0,0 +1,116 @@ +use crate::ir; +use crate::ir::traversal::{Action, Named, VisResult, Visitor}; +use crate::ir::GetAttributes; + +#[derive(Default)] +/// Transforms a par of seq blocks into a seq of par blocks. For the +/// transformation to occur, each seq block must have the same number of statements, +/// and the nth statement of each seq block in the par block +/// must all have the same number of clock cycles. +/// +/// #Example +/// par { +/// seq { @static(M) A0; @static(N) B0; @static(P) C0; } +/// seq { @static(M) A1; @static(N) B1; @static(P) C1; } +/// seq { @static(M) A2; @static(N) B2; @static(P) C2; } +///} +/// +/// into +/// +/// seq { +/// par{ @static(M) A0; @static(M) A1; @static(M) A2;} +/// par{ @static(N) B0; @static(N) B1; @static(N) B2;} +/// par{ @static(P) C0; @static(P) C1; @static(P) C2;} +/// } +/// +pub struct ParSeqToSeqPar; + +impl Named for ParSeqToSeqPar { + fn name() -> &'static str { + "parseq-to-seqpar" + } + + fn description() -> &'static str { + "Transform `par` of `seq` to `seq` of `par` under correct conditions" + } +} + +impl Visitor for ParSeqToSeqPar { + fn finish_par( + &mut self, + s: &mut ir::Par, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + let mut new_seq = ir::Seq { + stmts: Vec::new(), + attributes: ir::Attributes::default(), + }; + + let mut transformation_ok = true; + let mut all_seqs_iterated = false; + let mut n = 0; + + while !all_seqs_iterated && transformation_ok { + let mut new_par = ir::Par { + stmts: Vec::new(), + attributes: ir::Attributes::default(), + }; + + let mut each_seq_has_nth_stmt = true; + let mut set_num_cycles = false; + let mut num_cycles = 0; + + all_seqs_iterated = true; + (*s.stmts).into_iter().for_each(|x| match x { + ir::Control::Seq(seq) => { + match seq.stmts.get(n) { + Some(stmt) => { + all_seqs_iterated = false; + if let Some(&num_cycles_cur) = stmt + .get_attributes() + .and_then(|atts| atts.get("static")) + { + if !set_num_cycles { + num_cycles = num_cycles_cur; + set_num_cycles = true; + } + if num_cycles_cur == num_cycles { + new_par + .stmts + .push(ir::Control::clone(stmt)); + } else { + //don't have same number of cycles + transformation_ok = false; + } + } else { + //no static attribute for nth statement in seq + transformation_ok = false; + } + } + None => { + each_seq_has_nth_stmt = false; + } + } + } + //not all statements in the par are seqs + _ => transformation_ok = false, + }); + if !each_seq_has_nth_stmt && !all_seqs_iterated { + //seqs are not all same length + transformation_ok = false; + } + if !all_seqs_iterated && transformation_ok { + new_seq.stmts.push(ir::Control::Par(new_par)); + } + n += 1; + } + + if transformation_ok { + return Ok(Action::Change(Box::new(ir::Control::Seq(new_seq)))); + } else { + return Ok(Action::Continue); + } + } +} diff --git a/tests/passes/merge-static-par/compile-par-partial-static.futil b/tests/passes/merge-static-par/compile-par-partial-static.futil index 419d59e0bc..b620e23a3b 100644 --- a/tests/passes/merge-static-par/compile-par-partial-static.futil +++ b/tests/passes/merge-static-par/compile-par-partial-static.futil @@ -5,8 +5,6 @@ import "primitives/core.futil"; component main() -> () { cells { a = std_reg(2); - b = std_reg(2); - c = std_reg(2); } wires { @@ -15,21 +13,9 @@ component main() -> () { a.write_en = 1'b1; A[done] = a.done; } - - group B<"static"=1> { - b.in = 2'd1; - b.write_en = 1'b1; - B[done] = b.done; - } - - group C { - c.in = 2'd2; - c.write_en = 1'b1; - C[done] = c.done; - } } control { - par { A; B; C; } + par { A} } } \ No newline at end of file diff --git a/tests/passes/parseq-to-seqpar.expect b/tests/passes/parseq-to-seqpar.expect new file mode 100644 index 0000000000..9ea094bebc --- /dev/null +++ b/tests/passes/parseq-to-seqpar.expect @@ -0,0 +1,75 @@ +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + } + wires { + group A0 { + } + group A1 { + } + group A2 { + } + group B0 { + } + group B1 { + } + group B2 { + } + group C { + } + } + + control { + par { + seq { + par { + @static(2) A0; + @static(2) B0; + } + par { + @static(3) A1; + @static(3) B1; + } + par { + @static A2; + @static B2; + } + } + par { + seq { + @static(2) A0; + @static(3) A1; + } + seq { + @static(2) B0; + @static(3) B1; + @static B2; + } + } + par { + seq { + @static(2) A0; + @static(3) A1; + @static A2; + } + seq { + @static(2) B0; + @static(4) B1; + @static B2; + } + } + par { + seq { + @static(2) A0; + @static(3) A1; + @static A2; + } + seq { + @static(2) B0; + @static(4) B1; + @static B2; + } + @static(6) C; + } + } + } +} diff --git a/tests/passes/parseq-to-seqpar.futil b/tests/passes/parseq-to-seqpar.futil new file mode 100644 index 0000000000..6178e146b3 --- /dev/null +++ b/tests/passes/parseq-to-seqpar.futil @@ -0,0 +1,47 @@ +// -p parseq-to-seqpar + +component main() -> () { + cells { + } + + wires { + group A0{ + } + group A1{ + } + group A2{ + } + group B0{ + } + group B1 { + } + group B2 { + } + group C{ + } + } + + control { + par{ + par { + seq{@static(2)A0; @static(3)A1; @static(1)A2;} + seq{@static(2)B0; @static(3)B1; @static(1)B2;} + } + + par { + seq{@static(2)A0; @static(3)A1; } + seq{@static(2)B0; @static(3)B1; @static(1)B2;} + } + + par { + seq{@static(2)A0; @static(3)A1; @static(1)A2; } + seq{@static(2)B0; @static(4)B1; @static(1)B2;} + } + par { + seq{@static(2)A0; @static(3)A1; @static(1)A2; } + seq{@static(2)B0; @static(4)B1; @static(1)B2;} + @static(6)C; + } + } + } +} \ No newline at end of file From cb4682a58259f70c24e758e0a8da7889fd395d1c Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 8 Jun 2022 14:02:45 -0400 Subject: [PATCH 02/32] undid changes I accidentally made to another test --- .../compile-par-partial-static.futil | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/passes/merge-static-par/compile-par-partial-static.futil b/tests/passes/merge-static-par/compile-par-partial-static.futil index b620e23a3b..419d59e0bc 100644 --- a/tests/passes/merge-static-par/compile-par-partial-static.futil +++ b/tests/passes/merge-static-par/compile-par-partial-static.futil @@ -5,6 +5,8 @@ import "primitives/core.futil"; component main() -> () { cells { a = std_reg(2); + b = std_reg(2); + c = std_reg(2); } wires { @@ -13,9 +15,21 @@ component main() -> () { a.write_en = 1'b1; A[done] = a.done; } + + group B<"static"=1> { + b.in = 2'd1; + b.write_en = 1'b1; + B[done] = b.done; + } + + group C { + c.in = 2'd2; + c.write_en = 1'b1; + C[done] = c.done; + } } control { - par { A} + par { A; B; C; } } } \ No newline at end of file From de77c08f77d8a244cb384e8bbca67695fdbc3887 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 8 Jun 2022 14:20:53 -0400 Subject: [PATCH 03/32] fixed clippy's formatting complaints --- calyx/src/passes/parseq_to_seqpar.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/calyx/src/passes/parseq_to_seqpar.rs b/calyx/src/passes/parseq_to_seqpar.rs index 1c26dacf7c..54191d2856 100644 --- a/calyx/src/passes/parseq_to_seqpar.rs +++ b/calyx/src/passes/parseq_to_seqpar.rs @@ -63,7 +63,7 @@ impl Visitor for ParSeqToSeqPar { let mut num_cycles = 0; all_seqs_iterated = true; - (*s.stmts).into_iter().for_each(|x| match x { + (*s.stmts).iter().for_each(|x| match x { ir::Control::Seq(seq) => { match seq.stmts.get(n) { Some(stmt) => { @@ -108,9 +108,9 @@ impl Visitor for ParSeqToSeqPar { } if transformation_ok { - return Ok(Action::Change(Box::new(ir::Control::Seq(new_seq)))); + Ok(Action::Change(Box::new(ir::Control::Seq(new_seq)))) } else { - return Ok(Action::Continue); + Ok(Action::Continue) } } } From 91ebb43df3e061ccbcdeb578474bdb89745655c9 Mon Sep 17 00:00:00 2001 From: Caleb Date: Thu, 9 Jun 2022 13:46:29 -0400 Subject: [PATCH 04/32] renamed the pass and restructured code --- calyx/src/default_passes.rs | 6 +- calyx/src/passes/mod.rs | 4 +- calyx/src/passes/parseq_to_seqpar.rs | 116 -------------- calyx/src/passes/static_par_conv.rs | 145 ++++++++++++++++++ ...o-seqpar.expect => static-par-conv.expect} | 0 ...-to-seqpar.futil => static-par-conv.futil} | 2 +- 6 files changed, 151 insertions(+), 122 deletions(-) delete mode 100644 calyx/src/passes/parseq_to_seqpar.rs create mode 100644 calyx/src/passes/static_par_conv.rs rename tests/passes/{parseq-to-seqpar.expect => static-par-conv.expect} (100%) rename tests/passes/{parseq-to-seqpar.futil => static-par-conv.futil} (97%) diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index 7c646e866c..4019b6d255 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -4,8 +4,8 @@ use crate::passes::{ CompileInvoke, ComponentInliner, ComponentInterface, DeadCellRemoval, DeadGroupRemoval, Externalize, GoInsertion, GroupToInvoke, HoleInliner, InferStaticTiming, LowerGuards, MergeAssign, MergeStaticPar, MinimizeRegs, - Papercut, ParSeqToSeqPar, ParToSeq, RegisterUnsharing, RemoveCombGroups, - ResetInsertion, ResourceSharing, SimplifyGuards, SynthesisPapercut, + Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, ResetInsertion, + ResourceSharing, SimplifyGuards, StaticParConv, SynthesisPapercut, TopDownCompileControl, TopDownStaticTiming, UnrollBounded, WellFormed, WireInliner, }; @@ -35,7 +35,7 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; - pm.register_pass::()?; + pm.register_pass::()?; // Compilation passes pm.register_pass::()?; diff --git a/calyx/src/passes/mod.rs b/calyx/src/passes/mod.rs index 24eaf22f47..ea6e4b45f9 100644 --- a/calyx/src/passes/mod.rs +++ b/calyx/src/passes/mod.rs @@ -21,13 +21,13 @@ mod merge_static_par; mod minimize_regs; mod papercut; mod par_to_seq; -mod parseq_to_seqpar; mod register_unsharing; mod remove_comb_groups; mod reset_insertion; mod resource_sharing; mod sharing_components; mod simplify_guards; +mod static_par_conv; mod synthesis_papercut; mod top_down_compile_control; mod top_down_static_timing; @@ -56,13 +56,13 @@ pub use merge_static_par::MergeStaticPar; pub use minimize_regs::MinimizeRegs; pub use papercut::Papercut; pub use par_to_seq::ParToSeq; -pub use parseq_to_seqpar::ParSeqToSeqPar; pub use register_unsharing::RegisterUnsharing; pub use remove_comb_groups::RemoveCombGroups; pub use reset_insertion::ResetInsertion; pub use resource_sharing::ResourceSharing; pub use sharing_components::ShareComponents; pub use simplify_guards::SimplifyGuards; +pub use static_par_conv::StaticParConv; pub use synthesis_papercut::SynthesisPapercut; pub use top_down_compile_control::TopDownCompileControl; pub use top_down_static_timing::TopDownStaticTiming; diff --git a/calyx/src/passes/parseq_to_seqpar.rs b/calyx/src/passes/parseq_to_seqpar.rs deleted file mode 100644 index 54191d2856..0000000000 --- a/calyx/src/passes/parseq_to_seqpar.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::ir; -use crate::ir::traversal::{Action, Named, VisResult, Visitor}; -use crate::ir::GetAttributes; - -#[derive(Default)] -/// Transforms a par of seq blocks into a seq of par blocks. For the -/// transformation to occur, each seq block must have the same number of statements, -/// and the nth statement of each seq block in the par block -/// must all have the same number of clock cycles. -/// -/// #Example -/// par { -/// seq { @static(M) A0; @static(N) B0; @static(P) C0; } -/// seq { @static(M) A1; @static(N) B1; @static(P) C1; } -/// seq { @static(M) A2; @static(N) B2; @static(P) C2; } -///} -/// -/// into -/// -/// seq { -/// par{ @static(M) A0; @static(M) A1; @static(M) A2;} -/// par{ @static(N) B0; @static(N) B1; @static(N) B2;} -/// par{ @static(P) C0; @static(P) C1; @static(P) C2;} -/// } -/// -pub struct ParSeqToSeqPar; - -impl Named for ParSeqToSeqPar { - fn name() -> &'static str { - "parseq-to-seqpar" - } - - fn description() -> &'static str { - "Transform `par` of `seq` to `seq` of `par` under correct conditions" - } -} - -impl Visitor for ParSeqToSeqPar { - fn finish_par( - &mut self, - s: &mut ir::Par, - _comp: &mut ir::Component, - _sigs: &ir::LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - let mut new_seq = ir::Seq { - stmts: Vec::new(), - attributes: ir::Attributes::default(), - }; - - let mut transformation_ok = true; - let mut all_seqs_iterated = false; - let mut n = 0; - - while !all_seqs_iterated && transformation_ok { - let mut new_par = ir::Par { - stmts: Vec::new(), - attributes: ir::Attributes::default(), - }; - - let mut each_seq_has_nth_stmt = true; - let mut set_num_cycles = false; - let mut num_cycles = 0; - - all_seqs_iterated = true; - (*s.stmts).iter().for_each(|x| match x { - ir::Control::Seq(seq) => { - match seq.stmts.get(n) { - Some(stmt) => { - all_seqs_iterated = false; - if let Some(&num_cycles_cur) = stmt - .get_attributes() - .and_then(|atts| atts.get("static")) - { - if !set_num_cycles { - num_cycles = num_cycles_cur; - set_num_cycles = true; - } - if num_cycles_cur == num_cycles { - new_par - .stmts - .push(ir::Control::clone(stmt)); - } else { - //don't have same number of cycles - transformation_ok = false; - } - } else { - //no static attribute for nth statement in seq - transformation_ok = false; - } - } - None => { - each_seq_has_nth_stmt = false; - } - } - } - //not all statements in the par are seqs - _ => transformation_ok = false, - }); - if !each_seq_has_nth_stmt && !all_seqs_iterated { - //seqs are not all same length - transformation_ok = false; - } - if !all_seqs_iterated && transformation_ok { - new_seq.stmts.push(ir::Control::Par(new_par)); - } - n += 1; - } - - if transformation_ok { - Ok(Action::Change(Box::new(ir::Control::Seq(new_seq)))) - } else { - Ok(Action::Continue) - } - } -} diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs new file mode 100644 index 0000000000..6a612c9ad8 --- /dev/null +++ b/calyx/src/passes/static_par_conv.rs @@ -0,0 +1,145 @@ +use crate::ir; +use crate::ir::traversal::{Action, Named, VisResult, Visitor}; +use crate::ir::GetAttributes; + +#[derive(Default)] +/// Transforms a par of seq blocks into a seq of par blocks. For the +/// transformation to occur, each seq block must have the same number of statements, +/// and the nth statement of each seq block in the par block +/// must all have the same number of clock cycles. +/// +/// #Example +/// par { +/// seq { @static(M) A0; @static(N) B0; @static(P) C0; } +/// seq { @static(M) A1; @static(N) B1; @static(P) C1; } +/// seq { @static(M) A2; @static(N) B2; @static(P) C2; } +///} +/// +/// into +/// +/// seq { +/// par{ @static(M) A0; @static(M) A1; @static(M) A2;} +/// par{ @static(N) B0; @static(N) B1; @static(N) B2;} +/// par{ @static(P) C0; @static(P) C1; @static(P) C2;} +/// } +/// +pub struct StaticParConv; + +impl Named for StaticParConv { + fn name() -> &'static str { + "static-par-conv" + } + + fn description() -> &'static str { + "Transform `par` of `seq` to `seq` of `par` under correct conditions" + } +} + +// Given a Control statement, returns the length of stmts if the Control statement +// is a Seq. Panics if Control statement is not a Seq. +fn len_if_seq(stmt: &ir::Control) -> usize { + match stmt { + ir::Control::Seq(seq) => seq.stmts.len(), + _ => panic!("Not a sequence"), + } +} + +// Given a Control statement and an index n. +// If the Control statement is not a Seq, then panics. +// Othrwise, returns Some(cycles), where cycles is the value of the "static" +// attribute of the nth stmt in the Seq. Returns None if no such value is available. +fn cycles_if_seq(s: &ir::Control, index: usize) -> Option<&u64> { + match s { + ir::Control::Seq(seq) => seq.stmts.get(index).and_then(|stmt| { + stmt.get_attributes().and_then(|atts| atts.get("static")) + }), + _ => panic!("Not a sequence"), + } +} + +impl Visitor for StaticParConv { + fn finish_par( + &mut self, + s: &mut ir::Par, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + //if the par block is empty we can stop + if (*s).stmts.is_empty() { + return Ok(Action::Continue); + } + + //make sure only have seq stmts + if !(*s).stmts.iter().all(|x| match x { + ir::Control::Seq(_seq) => true, + _ => false, + }) { + return Ok(Action::Continue); + } + + //make sure each seq has the same number of stmts + let lens_vec = + (*s).stmts.iter().map(len_if_seq).collect::>(); + let min_seq_len = *lens_vec + .iter() + .min() + .unwrap_or_else(|| panic!("empty par block")); + let max_seq_len = *lens_vec + .iter() + .max() + .unwrap_or_else(|| panic!("empty par block")); + if min_seq_len != max_seq_len { + return Ok(Action::Continue); + } + let seq_len = min_seq_len; + + //make sure nth statement in each seq takes same number of cycle + for n in 0..seq_len { + let cycles_vec = (*s) + .stmts + .iter() + .map(|stmt| cycles_if_seq(stmt, n)) + .collect::>>(); + if cycles_vec.is_empty() { + panic!("empty par block"); + } + let fst = cycles_vec[0]; + if fst == None { + return Ok(Action::Continue); + } + if !cycles_vec.into_iter().all(|xth| xth == fst) { + return Ok(Action::Continue); + } + } + + //It complains when I try to use the vec![] syntax. It says: + //the trait `Clone` is not implemented for `ir::control::Control` + //note: required by a bound in `from_elem` + //So I am doing it this way instead. + let mut new_seq_stmts = Vec::new(); + for _n in 0..seq_len { + new_seq_stmts.push(Vec::new()); + } + + for con in s.stmts.drain(..) { + match con { + ir::Control::Seq(mut seq) => { + let mut counter = 0; + for stmt in seq.stmts.drain(..) { + new_seq_stmts[counter].push(stmt); + counter += 1; + } + } + _ => panic!("Encountered non sequences"), + } + } + + let par_vec = new_seq_stmts + .into_iter() + .map(|vec| ir::Control::par(vec)) + .collect(); + + Ok(Action::Change(Box::new(ir::Control::seq(par_vec)))) + } +} diff --git a/tests/passes/parseq-to-seqpar.expect b/tests/passes/static-par-conv.expect similarity index 100% rename from tests/passes/parseq-to-seqpar.expect rename to tests/passes/static-par-conv.expect diff --git a/tests/passes/parseq-to-seqpar.futil b/tests/passes/static-par-conv.futil similarity index 97% rename from tests/passes/parseq-to-seqpar.futil rename to tests/passes/static-par-conv.futil index 6178e146b3..8295dc37e6 100644 --- a/tests/passes/parseq-to-seqpar.futil +++ b/tests/passes/static-par-conv.futil @@ -1,4 +1,4 @@ -// -p parseq-to-seqpar +// -p static-par-conv component main() -> () { cells { From ff037428746d925da57f3468e717b5879446358e Mon Sep 17 00:00:00 2001 From: Caleb Date: Thu, 9 Jun 2022 14:01:28 -0400 Subject: [PATCH 05/32] fixed clippy complaints --- calyx/src/passes/static_par_conv.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index 6a612c9ad8..f92e307e36 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -71,10 +71,11 @@ impl Visitor for StaticParConv { } //make sure only have seq stmts - if !(*s).stmts.iter().all(|x| match x { - ir::Control::Seq(_seq) => true, - _ => false, - }) { + if !(*s) + .stmts + .iter() + .all(|x| matches!(x, ir::Control::Seq(_seq))) + { return Ok(Action::Continue); } @@ -125,20 +126,15 @@ impl Visitor for StaticParConv { for con in s.stmts.drain(..) { match con { ir::Control::Seq(mut seq) => { - let mut counter = 0; - for stmt in seq.stmts.drain(..) { + for (counter, stmt) in seq.stmts.drain(..).enumerate() { new_seq_stmts[counter].push(stmt); - counter += 1; } } _ => panic!("Encountered non sequences"), } } - let par_vec = new_seq_stmts - .into_iter() - .map(|vec| ir::Control::par(vec)) - .collect(); + let par_vec = new_seq_stmts.into_iter().map(ir::Control::par).collect(); Ok(Action::Change(Box::new(ir::Control::seq(par_vec)))) } From d7e44b2e246fbc134612495bc2bd7b63a3bc1fae Mon Sep 17 00:00:00 2001 From: Caleb Date: Sat, 11 Jun 2022 12:54:08 -0400 Subject: [PATCH 06/32] transforms uneven length seqs and adds static attribute --- calyx/src/default_passes.rs | 1 + calyx/src/passes/static_par_conv.rs | 168 +++++++++++------- tests/passes/static-par-conv.expect | 75 -------- tests/passes/static-par-conv.futil | 47 ----- .../static-par-conv/diff-num-cycles.expect | 33 ++++ .../static-par-conv/diff-num-cycles.futil | 29 +++ tests/passes/static-par-conv/nested.expect | 65 +++++++ tests/passes/static-par-conv/nested.futil | 46 +++++ .../subset-can-transform.expect | 36 ++++ .../subset-can-transform.futil | 32 ++++ .../static-par-conv/transform-diff-len.expect | 36 ++++ .../static-par-conv/transform-diff-len.futil | 30 ++++ .../static-par-conv/transform-same-len.expect | 35 ++++ .../static-par-conv/transform-same-len.futil | 29 +++ 14 files changed, 475 insertions(+), 187 deletions(-) delete mode 100644 tests/passes/static-par-conv.expect delete mode 100644 tests/passes/static-par-conv.futil create mode 100644 tests/passes/static-par-conv/diff-num-cycles.expect create mode 100644 tests/passes/static-par-conv/diff-num-cycles.futil create mode 100644 tests/passes/static-par-conv/nested.expect create mode 100644 tests/passes/static-par-conv/nested.futil create mode 100644 tests/passes/static-par-conv/subset-can-transform.expect create mode 100644 tests/passes/static-par-conv/subset-can-transform.futil create mode 100644 tests/passes/static-par-conv/transform-diff-len.expect create mode 100644 tests/passes/static-par-conv/transform-diff-len.futil create mode 100644 tests/passes/static-par-conv/transform-same-len.expect create mode 100644 tests/passes/static-par-conv/transform-same-len.futil diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index 4019b6d255..8c53533db3 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -75,6 +75,7 @@ impl PassManager { InferStaticTiming, MergeStaticPar, DeadGroupRemoval, + StaticParConv, // Must be before `collapse-control` CollapseControl, ResourceSharing, MinimizeRegs, diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index f92e307e36..dd73cdeed9 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -6,7 +6,7 @@ use crate::ir::GetAttributes; /// Transforms a par of seq blocks into a seq of par blocks. For the /// transformation to occur, each seq block must have the same number of statements, /// and the nth statement of each seq block in the par block -/// must all have the same number of clock cycles. +/// must all have the same number of clock cycles. (Subject to change) /// /// #Example /// par { @@ -17,14 +17,20 @@ use crate::ir::GetAttributes; /// /// into /// -/// seq { -/// par{ @static(M) A0; @static(M) A1; @static(M) A2;} -/// par{ @static(N) B0; @static(N) B1; @static(N) B2;} -/// par{ @static(P) C0; @static(P) C1; @static(P) C2;} +/// @static(M + N + P) seq { +/// @static(M) par{ @static(M) A0; @static(M) A1; @static(M) A2;} +/// @static(N) par{ @static(N) B0; @static(N) B1; @static(N) B2;} +/// @static(P) par{ @static(P) C0; @static(P) C1; @static(P) C2;} /// } -/// + pub struct StaticParConv; +enum StaticAttr { + NoAttr, + NoStmt, + StaticVal(u64), +} + impl Named for StaticParConv { fn name() -> &'static str { "static-par-conv" @@ -35,28 +41,47 @@ impl Named for StaticParConv { } } -// Given a Control statement, returns the length of stmts if the Control statement -// is a Seq. Panics if Control statement is not a Seq. -fn len_if_seq(stmt: &ir::Control) -> usize { +// Given a Control statement, returns the Some(length), where length +// is the length of stmts if the Control statement +// is a Seq. None if Control statement is not a Seq. +fn len_if_seq(stmt: &ir::Control) -> Option { match stmt { - ir::Control::Seq(seq) => seq.stmts.len(), - _ => panic!("Not a sequence"), + ir::Control::Seq(seq) => Some(seq.stmts.len()), + _ => None, } } // Given a Control statement and an index n. -// If the Control statement is not a Seq, then panics. -// Othrwise, returns Some(cycles), where cycles is the value of the "static" -// attribute of the nth stmt in the Seq. Returns None if no such value is available. -fn cycles_if_seq(s: &ir::Control, index: usize) -> Option<&u64> { +// If the Control statement is not a Seq, then unreachable! +// Otherwise, returns a StaticAttr. It returns NoStmt if there +// exists no nth statement in the Seq. It returns NoAttr if +// the nth statement exists, but does not have a "static" attribute. +// It returns StaticVal(static_val), where static_val is the +// value of the "static" attribute of the nth statement. +fn cycles_if_seq(s: &ir::Control, index: usize) -> StaticAttr { match s { - ir::Control::Seq(seq) => seq.stmts.get(index).and_then(|stmt| { - stmt.get_attributes().and_then(|atts| atts.get("static")) - }), - _ => panic!("Not a sequence"), + ir::Control::Seq(seq) => { + if let Some(stmt) = seq.stmts.get(index) { + match stmt.get_attributes().and_then(|atts| atts.get("static")) + { + None => StaticAttr::NoAttr, + Some(&static_val) => StaticAttr::StaticVal(static_val), + } + } else { + StaticAttr::NoStmt + } + } + _ => unreachable!("Not a sequence"), } } +// returns a default Attribute with "static" set to v +fn attribute_with_static(v: u64) -> ir::Attributes { + let mut atts = ir::Attributes::default(); + atts.insert("static", v); + atts +} + impl Visitor for StaticParConv { fn finish_par( &mut self, @@ -66,76 +91,89 @@ impl Visitor for StaticParConv { _comps: &[ir::Component], ) -> VisResult { //if the par block is empty we can stop - if (*s).stmts.is_empty() { + if s.stmts.is_empty() { return Ok(Action::Continue); } - //make sure only have seq stmts - if !(*s) + //make sure there are only seqs, and if so, get the length of the longest seq + let lens_vec = s .stmts .iter() - .all(|x| matches!(x, ir::Control::Seq(_seq))) - { + .map(len_if_seq) + .collect::>>(); + let max_seq_len = if let Some(lens) = lens_vec { + lens.into_iter() + .max() + .unwrap_or_else(|| unreachable!("empty par block")) + } else { return Ok(Action::Continue); - } + }; - //make sure each seq has the same number of stmts - let lens_vec = - (*s).stmts.iter().map(len_if_seq).collect::>(); - let min_seq_len = *lens_vec - .iter() - .min() - .unwrap_or_else(|| panic!("empty par block")); - let max_seq_len = *lens_vec - .iter() - .max() - .unwrap_or_else(|| panic!("empty par block")); - if min_seq_len != max_seq_len { - return Ok(Action::Continue); - } - let seq_len = min_seq_len; + //vec to hold the @static vals for each par block in the seq we will create + let mut new_pars_static = Vec::new(); - //make sure nth statement in each seq takes same number of cycle - for n in 0..seq_len { - let cycles_vec = (*s) + //make sure nth statement in each seq (if it exists) takes same number of cycles + for n in 0..max_seq_len { + let cycles_vec = s .stmts .iter() .map(|stmt| cycles_if_seq(stmt, n)) - .collect::>>(); - if cycles_vec.is_empty() { - panic!("empty par block"); - } - let fst = cycles_vec[0]; - if fst == None { - return Ok(Action::Continue); - } - if !cycles_vec.into_iter().all(|xth| xth == fst) { - return Ok(Action::Continue); - } + .collect::>(); + // There is an uglier way to do this doing just 1 iteration + let cycles_val = cycles_vec + .iter() + .find(|x| matches!(x, StaticAttr::StaticVal(_v))); + match cycles_val { + Some(&StaticAttr::StaticVal(v)) => { + if cycles_vec.into_iter().all(|static_attr| { + match static_attr { + StaticAttr::StaticVal(x) => x == v, + StaticAttr::NoStmt => true, + StaticAttr::NoAttr => false, + } + }) { + new_pars_static.push(v); + } else { + return Ok(Action::Continue); + } + } + _ => return Ok(Action::Continue), + }; } - //It complains when I try to use the vec![] syntax. It says: - //the trait `Clone` is not implemented for `ir::control::Control` - //note: required by a bound in `from_elem` - //So I am doing it this way instead. - let mut new_seq_stmts = Vec::new(); - for _n in 0..seq_len { - new_seq_stmts.push(Vec::new()); + let mut new_pars_stmts = Vec::new(); + for _n in 0..max_seq_len { + new_pars_stmts.push(Vec::new()); } for con in s.stmts.drain(..) { match con { ir::Control::Seq(mut seq) => { for (counter, stmt) in seq.stmts.drain(..).enumerate() { - new_seq_stmts[counter].push(stmt); + new_pars_stmts[counter].push(stmt); } } - _ => panic!("Encountered non sequences"), + _ => unreachable!("encountered non sequence"), } } - let par_vec = new_seq_stmts.into_iter().map(ir::Control::par).collect(); + //the @static attribute for the entire seq block I will create + let new_seq_static: u64 = new_pars_static.iter().sum(); + + let pars_vec = new_pars_stmts + .into_iter() + .zip(new_pars_static.into_iter()) + .map(|(s, v)| { + ir::Control::Par(ir::Par { + stmts: s, + attributes: attribute_with_static(v), + }) + }) + .collect(); - Ok(Action::Change(Box::new(ir::Control::seq(par_vec)))) + Ok(Action::Change(Box::new(ir::Control::Seq(ir::Seq { + stmts: pars_vec, + attributes: attribute_with_static(new_seq_static), + })))) } } diff --git a/tests/passes/static-par-conv.expect b/tests/passes/static-par-conv.expect deleted file mode 100644 index 9ea094bebc..0000000000 --- a/tests/passes/static-par-conv.expect +++ /dev/null @@ -1,75 +0,0 @@ -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - } - wires { - group A0 { - } - group A1 { - } - group A2 { - } - group B0 { - } - group B1 { - } - group B2 { - } - group C { - } - } - - control { - par { - seq { - par { - @static(2) A0; - @static(2) B0; - } - par { - @static(3) A1; - @static(3) B1; - } - par { - @static A2; - @static B2; - } - } - par { - seq { - @static(2) A0; - @static(3) A1; - } - seq { - @static(2) B0; - @static(3) B1; - @static B2; - } - } - par { - seq { - @static(2) A0; - @static(3) A1; - @static A2; - } - seq { - @static(2) B0; - @static(4) B1; - @static B2; - } - } - par { - seq { - @static(2) A0; - @static(3) A1; - @static A2; - } - seq { - @static(2) B0; - @static(4) B1; - @static B2; - } - @static(6) C; - } - } - } -} diff --git a/tests/passes/static-par-conv.futil b/tests/passes/static-par-conv.futil deleted file mode 100644 index 8295dc37e6..0000000000 --- a/tests/passes/static-par-conv.futil +++ /dev/null @@ -1,47 +0,0 @@ -// -p static-par-conv - -component main() -> () { - cells { - } - - wires { - group A0{ - } - group A1{ - } - group A2{ - } - group B0{ - } - group B1 { - } - group B2 { - } - group C{ - } - } - - control { - par{ - par { - seq{@static(2)A0; @static(3)A1; @static(1)A2;} - seq{@static(2)B0; @static(3)B1; @static(1)B2;} - } - - par { - seq{@static(2)A0; @static(3)A1; } - seq{@static(2)B0; @static(3)B1; @static(1)B2;} - } - - par { - seq{@static(2)A0; @static(3)A1; @static(1)A2; } - seq{@static(2)B0; @static(4)B1; @static(1)B2;} - } - par { - seq{@static(2)A0; @static(3)A1; @static(1)A2; } - seq{@static(2)B0; @static(4)B1; @static(1)B2;} - @static(6)C; - } - } - } -} \ No newline at end of file diff --git a/tests/passes/static-par-conv/diff-num-cycles.expect b/tests/passes/static-par-conv/diff-num-cycles.expect new file mode 100644 index 0000000000..9b806af420 --- /dev/null +++ b/tests/passes/static-par-conv/diff-num-cycles.expect @@ -0,0 +1,33 @@ +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + } + wires { + group A0 { + } + group A1 { + } + group A2 { + } + group B0 { + } + group B1 { + } + group B2 { + } + } + + control { + par { + seq { + @static(2) A0; + @static(3) A1; + @static A2; + } + seq { + @static(2) B0; + @static(4) B1; + @static B2; + } + } + } +} diff --git a/tests/passes/static-par-conv/diff-num-cycles.futil b/tests/passes/static-par-conv/diff-num-cycles.futil new file mode 100644 index 0000000000..14af176c42 --- /dev/null +++ b/tests/passes/static-par-conv/diff-num-cycles.futil @@ -0,0 +1,29 @@ +// -p static-par-conv + +component main() -> () { + cells { + } + + wires { + group A0{ + } + group A1{ + } + group A2{ + } + group B0{ + } + group B1 { + } + group B2 { + } + } + + control { + par { + seq{@static(2)A0; @static(3)A1; @static(1)A2;} + seq{@static(2)B0; @static(4)B1; @static(1)B2;} + } + } + +} \ No newline at end of file diff --git a/tests/passes/static-par-conv/nested.expect b/tests/passes/static-par-conv/nested.expect new file mode 100644 index 0000000000..f0037df7e5 --- /dev/null +++ b/tests/passes/static-par-conv/nested.expect @@ -0,0 +1,65 @@ +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + } + wires { + group A0 { + } + group A1 { + } + group A2 { + } + group B0 { + } + group B1 { + } + group B2 { + } + group C0 { + } + group C1 { + } + group C2 { + } + group D0 { + } + group D1 { + } + group D2 { + } + } + + control { + @static(6) seq { + @static par { + @static par { + @static A0; + @static B0; + } + @static par { + @static C0; + @static D0; + } + } + @static(2) par { + @static(2) par { + @static(2) A1; + @static(2) B1; + } + @static(2) par { + @static(2) C1; + @static(2) D1; + } + } + @static(3) par { + @static(3) par { + @static(3) A2; + @static(3) B2; + } + @static(3) par { + @static(3) C2; + @static(3) D2; + } + } + } + } +} diff --git a/tests/passes/static-par-conv/nested.futil b/tests/passes/static-par-conv/nested.futil new file mode 100644 index 0000000000..726ef63bc1 --- /dev/null +++ b/tests/passes/static-par-conv/nested.futil @@ -0,0 +1,46 @@ +// -p static-par-conv + +component main() -> () { + cells { + } + + wires { + group A0{ + } + group A1{ + } + group A2{ + } + group B0{ + } + group B1 { + } + group B2 { + } + group C0{ + } + group C1{ + } + group C2{ + } + group D0{ + } + group D1 { + } + group D2 { + } + } + + control { + par{ + par { + seq{@static(1)A0; @static(2)A1; @static(3)A2;} + seq{@static(1)B0; @static(2)B1; @static(3)B2;} + } + par { + seq{@static(1)C0; @static(2)C1; @static(3)C2;} + seq{@static(1)D0; @static(2)D1; @static(3)D2;} + } + } + } +} \ No newline at end of file diff --git a/tests/passes/static-par-conv/subset-can-transform.expect b/tests/passes/static-par-conv/subset-can-transform.expect new file mode 100644 index 0000000000..b89820dd1c --- /dev/null +++ b/tests/passes/static-par-conv/subset-can-transform.expect @@ -0,0 +1,36 @@ +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + } + wires { + group A0 { + } + group A1 { + } + group A2 { + } + group B0 { + } + group B1 { + } + group B2 { + } + group C { + } + } + + control { + par { + seq { + @static(2) A0; + @static(3) A1; + @static A2; + } + seq { + @static(2) B0; + @static(3) B1; + @static B2; + } + @static(6) C; + } + } +} diff --git a/tests/passes/static-par-conv/subset-can-transform.futil b/tests/passes/static-par-conv/subset-can-transform.futil new file mode 100644 index 0000000000..fdfacaa5c8 --- /dev/null +++ b/tests/passes/static-par-conv/subset-can-transform.futil @@ -0,0 +1,32 @@ +// -p static-par-conv + +component main() -> () { + cells { + } + + wires { + group A0{ + } + group A1{ + } + group A2{ + } + group B0{ + } + group B1 { + } + group B2 { + } + group C{ + } + } + + control { + par { + seq{@static(2)A0; @static(3)A1; @static(1)A2;} + seq{@static(2)B0; @static(3)B1; @static(1)B2;} + @static(6) C; + } + } + +} \ No newline at end of file diff --git a/tests/passes/static-par-conv/transform-diff-len.expect b/tests/passes/static-par-conv/transform-diff-len.expect new file mode 100644 index 0000000000..c6b7b779cc --- /dev/null +++ b/tests/passes/static-par-conv/transform-diff-len.expect @@ -0,0 +1,36 @@ +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + } + wires { + group A0 { + } + group A1 { + } + group A2 { + } + group B0 { + } + group B1 { + } + group B2 { + } + group C { + } + } + + control { + @static(6) seq { + @static(2) par { + @static(2) A0; + @static(2) B0; + } + @static(3) par { + @static(3) A1; + @static(3) B1; + } + @static par { + @static B2; + } + } + } +} diff --git a/tests/passes/static-par-conv/transform-diff-len.futil b/tests/passes/static-par-conv/transform-diff-len.futil new file mode 100644 index 0000000000..553ca65a62 --- /dev/null +++ b/tests/passes/static-par-conv/transform-diff-len.futil @@ -0,0 +1,30 @@ +// -p static-par-conv + +component main() -> () { + cells { + } + + wires { + group A0{ + } + group A1{ + } + group A2{ + } + group B0{ + } + group B1 { + } + group B2 { + } + group C{ + } + } + + control { + par { + seq{@static(2)A0; @static(3)A1; } + seq{@static(2)B0; @static(3)B1; @static(1)B2;} + } + } +} \ No newline at end of file diff --git a/tests/passes/static-par-conv/transform-same-len.expect b/tests/passes/static-par-conv/transform-same-len.expect new file mode 100644 index 0000000000..67212537a5 --- /dev/null +++ b/tests/passes/static-par-conv/transform-same-len.expect @@ -0,0 +1,35 @@ +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + } + wires { + group A0 { + } + group A1 { + } + group A2 { + } + group B0 { + } + group B1 { + } + group B2 { + } + } + + control { + @static(6) seq { + @static(2) par { + @static(2) A0; + @static(2) B0; + } + @static(3) par { + @static(3) A1; + @static(3) B1; + } + @static par { + @static A2; + @static B2; + } + } + } +} diff --git a/tests/passes/static-par-conv/transform-same-len.futil b/tests/passes/static-par-conv/transform-same-len.futil new file mode 100644 index 0000000000..91ea4edeea --- /dev/null +++ b/tests/passes/static-par-conv/transform-same-len.futil @@ -0,0 +1,29 @@ +// -p static-par-conv + +component main() -> () { + cells { + } + + wires { + group A0{ + } + group A1{ + } + group A2{ + } + group B0{ + } + group B1 { + } + group B2 { + } + } + + control { + par { + seq{@static(2)A0; @static(3)A1; @static(1)A2;} + seq{@static(2)B0; @static(3)B1; @static(1)B2;} + } + } + +} \ No newline at end of file From 92b1eddeb81a646f7c4ee9009c71be89e915856d Mon Sep 17 00:00:00 2001 From: Caleb Date: Sat, 11 Jun 2022 19:18:26 -0400 Subject: [PATCH 07/32] small code change --- calyx/src/passes/static_par_conv.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index dd73cdeed9..7208086099 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -123,22 +123,19 @@ impl Visitor for StaticParConv { let cycles_val = cycles_vec .iter() .find(|x| matches!(x, StaticAttr::StaticVal(_v))); - match cycles_val { - Some(&StaticAttr::StaticVal(v)) => { - if cycles_vec.into_iter().all(|static_attr| { - match static_attr { - StaticAttr::StaticVal(x) => x == v, - StaticAttr::NoStmt => true, - StaticAttr::NoAttr => false, - } - }) { - new_pars_static.push(v); - } else { - return Ok(Action::Continue); - } + if let Some(&StaticAttr::StaticVal(v)) = cycles_val { + if cycles_vec.into_iter().all(|static_attr| match static_attr { + StaticAttr::StaticVal(x) => x == v, + StaticAttr::NoStmt => true, + StaticAttr::NoAttr => false, + }) { + new_pars_static.push(v); + } else { + return Ok(Action::Continue); } - _ => return Ok(Action::Continue), - }; + } else { + return Ok(Action::Continue); + } } let mut new_pars_stmts = Vec::new(); From 2c334efd9ffafb366b440bab95706a2a79a09f4c Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 14 Jun 2022 10:17:04 -0400 Subject: [PATCH 08/32] does transformation using interweaving and when only a subset of stmts can be transformed --- calyx/src/passes/static_par_conv.rs | 223 +++++++++++------- .../static-par-conv/diff-num-cycles.expect | 10 +- ...iff-len.expect => empty-seq-blocks.expect} | 14 +- ...-diff-len.futil => empty-seq-blocks.futil} | 6 +- .../passes/static-par-conv/interweave.expect | 54 +++++ tests/passes/static-par-conv/interweave.futil | 42 ++++ tests/passes/static-par-conv/nested.expect | 24 +- .../subset-can-transform.expect | 24 +- .../static-par-conv/transform-same-len.expect | 6 +- 9 files changed, 269 insertions(+), 134 deletions(-) rename tests/passes/static-par-conv/{transform-diff-len.expect => empty-seq-blocks.expect} (56%) rename tests/passes/static-par-conv/{transform-diff-len.futil => empty-seq-blocks.futil} (72%) create mode 100644 tests/passes/static-par-conv/interweave.expect create mode 100644 tests/passes/static-par-conv/interweave.futil diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index 7208086099..f2f1979eda 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -3,10 +3,10 @@ use crate::ir::traversal::{Action, Named, VisResult, Visitor}; use crate::ir::GetAttributes; #[derive(Default)] -/// Transforms a par of seq blocks into a seq of par blocks. For the -/// transformation to occur, each seq block must have the same number of statements, -/// and the nth statement of each seq block in the par block -/// must all have the same number of clock cycles. (Subject to change) +/// Transforms a par of seq blocks into a seq of par blocks. It will sometimes only +/// apply this transformation to a subset of seq blocks in the par block. +/// This transformation should never increase the number of cycles the par +/// block takes to execute. /// /// #Example /// par { @@ -25,12 +25,6 @@ use crate::ir::GetAttributes; pub struct StaticParConv; -enum StaticAttr { - NoAttr, - NoStmt, - StaticVal(u64), -} - impl Named for StaticParConv { fn name() -> &'static str { "static-par-conv" @@ -41,37 +35,49 @@ impl Named for StaticParConv { } } -// Given a Control statement, returns the Some(length), where length -// is the length of stmts if the Control statement -// is a Seq. None if Control statement is not a Seq. -fn len_if_seq(stmt: &ir::Control) -> Option { - match stmt { - ir::Control::Seq(seq) => Some(seq.stmts.len()), - _ => None, - } -} - -// Given a Control statement and an index n. -// If the Control statement is not a Seq, then unreachable! -// Otherwise, returns a StaticAttr. It returns NoStmt if there -// exists no nth statement in the Seq. It returns NoAttr if -// the nth statement exists, but does not have a "static" attribute. -// It returns StaticVal(static_val), where static_val is the -// value of the "static" attribute of the nth statement. -fn cycles_if_seq(s: &ir::Control, index: usize) -> StaticAttr { - match s { - ir::Control::Seq(seq) => { - if let Some(stmt) = seq.stmts.get(index) { - match stmt.get_attributes().and_then(|atts| atts.get("static")) - { - None => StaticAttr::NoAttr, - Some(&static_val) => StaticAttr::StaticVal(static_val), +// Takes in two seqs, longer and shorter. longer should be at least as long as +// shorter. Returns Some(vec) if there exists arrangement of shorter and longer +// such that each statement in shorter can be paired with a statement in longer, +// such that executing these pairs in as a seq of pars will respect dependencies and +// the number of cycles it takes will remaine the same (i.e., the same as longer)/ +// The vec it returns the indices that each element of shorter should be paired +// with longer. So, if we represent the vecs by the static attribute of their +// statements, if longer = [4,1,5] and shorter [4,5] then vec would be +// [0,2], since the 4 in shorter lines up with the 4 in longer (@ index 0) +// and the 5 in shorter lines up with 5 in longer (@ index 2). A consequence of this is +// that vec should always be the same length as shorter. +fn is_compatible(longer: &ir::Seq, shorter: &ir::Seq) -> Option> { + let mut long_iter = (*longer).stmts.iter(); + let mut short_iter = (*shorter).stmts.iter(); + + let mut long_val = long_iter.next(); + let mut short_val = short_iter.next(); + + let mut index_counter = Vec::new(); + let mut counter = 0; + + while let (Some(c1), Some(c2)) = (long_val, short_val) { + match ( + c1.get_attributes().and_then(|atts| atts.get("static")), + c2.get_attributes().and_then(|atts| atts.get("static")), + ) { + (Some(x1), Some(x2)) => { + if x2 <= x1 { + long_val = long_iter.next(); + short_val = short_iter.next(); + index_counter.push(counter); + } else { + long_val = long_iter.next(); } - } else { - StaticAttr::NoStmt } + _ => return None, } - _ => unreachable!("Not a sequence"), + counter += 1; + } + + match short_val { + None => Some(index_counter), + Some(_) => None, } } @@ -95,82 +101,117 @@ impl Visitor for StaticParConv { return Ok(Action::Continue); } - //make sure there are only seqs, and if so, get the length of the longest seq - let lens_vec = s - .stmts + // non_compatible holds everything that will NOT be turned into a + // seq of pars + let (mut seqs, mut non_compatible) = (Vec::new(), Vec::new()); + for con in s.stmts.drain(..) { + match con { + ir::Control::Seq(seq) => seqs.push(seq), + x => non_compatible.push(x), + } + } + + if seqs.is_empty() { + return Ok(Action::Change(Box::new(ir::Control::par( + non_compatible, + )))); + } + + //is there a more idiomatic way to take ownership of just the longest seq + //but not the others? + let max_seq_len = seqs .iter() - .map(len_if_seq) - .collect::>>(); - let max_seq_len = if let Some(lens) = lens_vec { - lens.into_iter() - .max() - .unwrap_or_else(|| unreachable!("empty par block")) + .map(|seq| seq.stmts.len()) + .max() + .unwrap_or_else(|| unreachable!("no seqs")); + let longest_seq; + if let Some(p) = + seqs.iter().position(|seq| seq.stmts.len() == max_seq_len) + { + longest_seq = seqs.swap_remove(p); } else { - return Ok(Action::Continue); - }; + unreachable!("no seq that has length max_seq_len") + } - //vec to hold the @static vals for each par block in the seq we will create - let mut new_pars_static = Vec::new(); - - //make sure nth statement in each seq (if it exists) takes same number of cycles - for n in 0..max_seq_len { - let cycles_vec = s - .stmts - .iter() - .map(|stmt| cycles_if_seq(stmt, n)) - .collect::>(); - // There is an uglier way to do this doing just 1 iteration - let cycles_val = cycles_vec - .iter() - .find(|x| matches!(x, StaticAttr::StaticVal(_v))); - if let Some(&StaticAttr::StaticVal(v)) = cycles_val { - if cycles_vec.into_iter().all(|static_attr| match static_attr { - StaticAttr::StaticVal(x) => x == v, - StaticAttr::NoStmt => true, - StaticAttr::NoAttr => false, - }) { - new_pars_static.push(v); - } else { - return Ok(Action::Continue); - } + let mut indexed_seqs = vec![]; + + //organizing seqs into those that are compatible w/ longest_seq + //and those that are not + for seq in seqs.drain(..) { + if let Some(index_vec) = is_compatible(&longest_seq, &seq) { + indexed_seqs.push((seq, index_vec)); } else { - return Ok(Action::Continue); + non_compatible.push(ir::Control::Seq(seq)); } } + if indexed_seqs.is_empty() { + non_compatible.push(ir::Control::Seq(longest_seq)); + return Ok(Action::Change(Box::new(ir::Control::par( + non_compatible, + )))); + } + + indexed_seqs.push((longest_seq, (0..max_seq_len).collect())); + let mut new_pars_stmts = Vec::new(); for _n in 0..max_seq_len { new_pars_stmts.push(Vec::new()); } - for con in s.stmts.drain(..) { - match con { - ir::Control::Seq(mut seq) => { - for (counter, stmt) in seq.stmts.drain(..).enumerate() { - new_pars_stmts[counter].push(stmt); - } - } - _ => unreachable!("encountered non sequence"), + for (seq, indices) in indexed_seqs.drain(..) { + let mut labeled_stmts: Vec<(ir::Control, usize)> = + seq.stmts.into_iter().zip(indices.into_iter()).collect(); + for (stmt, index) in labeled_stmts.drain(..) { + new_pars_stmts[index].push(stmt); } } - //the @static attribute for the entire seq block I will create - let new_seq_static: u64 = new_pars_static.iter().sum(); + let new_pars_static = match new_pars_stmts + .iter() + .map(|vec| { + vec + .iter() + .map(|stmt| { + match stmt + .get_attributes() + .and_then(|atts| atts.get("static")) + { + Some(&x1) => x1, + None => unreachable!("every statement in the new par blocks should have a static attribute"), + } + }) + .max() + }) + .collect::>>() + { + Some(vec) => vec, + None => unreachable!("none of the par blocks should be empty"), + }; + + let new_seq_static = new_pars_static.iter().sum(); - let pars_vec = new_pars_stmts + let new_pars: Vec = new_pars_stmts .into_iter() .zip(new_pars_static.into_iter()) - .map(|(s, v)| { + .map(|(stmts_vec, static_attr)| { ir::Control::Par(ir::Par { - stmts: s, - attributes: attribute_with_static(v), + stmts: stmts_vec, + attributes: attribute_with_static(static_attr), }) }) .collect(); - Ok(Action::Change(Box::new(ir::Control::Seq(ir::Seq { - stmts: pars_vec, + let new_seq = ir::Control::Seq(ir::Seq { + stmts: new_pars, attributes: attribute_with_static(new_seq_static), - })))) + }); + + if non_compatible.is_empty() { + return Ok(Action::Change(Box::new(new_seq))); + } + + non_compatible.push(new_seq); + Ok(Action::Change(Box::new(ir::Control::par(non_compatible)))) } } diff --git a/tests/passes/static-par-conv/diff-num-cycles.expect b/tests/passes/static-par-conv/diff-num-cycles.expect index 9b806af420..3fb794849c 100644 --- a/tests/passes/static-par-conv/diff-num-cycles.expect +++ b/tests/passes/static-par-conv/diff-num-cycles.expect @@ -18,16 +18,16 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { control { par { - seq { - @static(2) A0; - @static(3) A1; - @static A2; - } seq { @static(2) B0; @static(4) B1; @static B2; } + seq { + @static(2) A0; + @static(3) A1; + @static A2; + } } } } diff --git a/tests/passes/static-par-conv/transform-diff-len.expect b/tests/passes/static-par-conv/empty-seq-blocks.expect similarity index 56% rename from tests/passes/static-par-conv/transform-diff-len.expect rename to tests/passes/static-par-conv/empty-seq-blocks.expect index c6b7b779cc..803d454240 100644 --- a/tests/passes/static-par-conv/transform-diff-len.expect +++ b/tests/passes/static-par-conv/empty-seq-blocks.expect @@ -19,17 +19,9 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { - @static(6) seq { - @static(2) par { - @static(2) A0; - @static(2) B0; - } - @static(3) par { - @static(3) A1; - @static(3) B1; - } - @static par { - @static B2; + par { + A0; + @static(0) seq { } } } diff --git a/tests/passes/static-par-conv/transform-diff-len.futil b/tests/passes/static-par-conv/empty-seq-blocks.futil similarity index 72% rename from tests/passes/static-par-conv/transform-diff-len.futil rename to tests/passes/static-par-conv/empty-seq-blocks.futil index 553ca65a62..27b64a1279 100644 --- a/tests/passes/static-par-conv/transform-diff-len.futil +++ b/tests/passes/static-par-conv/empty-seq-blocks.futil @@ -23,8 +23,10 @@ component main() -> () { control { par { - seq{@static(2)A0; @static(3)A1; } - seq{@static(2)B0; @static(3)B1; @static(1)B2;} + seq{} + seq{} + seq{} + A0; } } } \ No newline at end of file diff --git a/tests/passes/static-par-conv/interweave.expect b/tests/passes/static-par-conv/interweave.expect new file mode 100644 index 0000000000..959f6bdd5f --- /dev/null +++ b/tests/passes/static-par-conv/interweave.expect @@ -0,0 +1,54 @@ +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + } + wires { + group A0 { + } + group A1 { + } + group A2 { + } + group B0 { + } + group B1 { + } + group C0 { + } + group C1 { + } + group D0 { + } + group D1 { + } + group E0 { + } + group E1 { + } + } + + control { + par { + seq { + @static(2) D0; + @static(5) D1; + } + @static(9) seq { + @static(2) par { + @static E0; + @static(2) C0; + @static(2) A0; + } + @static(3) par { + @static(2) E1; + @static(3) B0; + @static(3) A1; + } + @static(4) par { + @static(4) B1; + @static(4) C1; + @static(4) A2; + } + } + } + } +} diff --git a/tests/passes/static-par-conv/interweave.futil b/tests/passes/static-par-conv/interweave.futil new file mode 100644 index 0000000000..b4f31bc0bc --- /dev/null +++ b/tests/passes/static-par-conv/interweave.futil @@ -0,0 +1,42 @@ +// -p static-par-conv + +component main() -> () { + cells { + } + + wires { + group A0{ + } + group A1{ + } + group A2{ + } + group B0{ + } + group B1 { + } + group C0{ + } + group C1 { + } + group D0{ + } + group D1{ + } + group E0{ + } + group E1{ + } + } + + control { + par { + seq{@static(2)A0; @static(3)A1; @static(4)A2;} + seq{@static(1)E0; @static(2)E1;} + seq{@static(3)B0; @static(4)B1;} + seq{@static(2)C0; @static(4)C1;} + seq{@static(2)D0; @static(5)D1;} + } + } + +} \ No newline at end of file diff --git a/tests/passes/static-par-conv/nested.expect b/tests/passes/static-par-conv/nested.expect index f0037df7e5..afcf1423ca 100644 --- a/tests/passes/static-par-conv/nested.expect +++ b/tests/passes/static-par-conv/nested.expect @@ -32,32 +32,32 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @static(6) seq { @static par { @static par { - @static A0; - @static B0; + @static D0; + @static C0; } @static par { - @static C0; - @static D0; + @static B0; + @static A0; } } @static(2) par { @static(2) par { - @static(2) A1; - @static(2) B1; + @static(2) D1; + @static(2) C1; } @static(2) par { - @static(2) C1; - @static(2) D1; + @static(2) B1; + @static(2) A1; } } @static(3) par { @static(3) par { - @static(3) A2; - @static(3) B2; + @static(3) D2; + @static(3) C2; } @static(3) par { - @static(3) C2; - @static(3) D2; + @static(3) B2; + @static(3) A2; } } } diff --git a/tests/passes/static-par-conv/subset-can-transform.expect b/tests/passes/static-par-conv/subset-can-transform.expect index b89820dd1c..4676178c14 100644 --- a/tests/passes/static-par-conv/subset-can-transform.expect +++ b/tests/passes/static-par-conv/subset-can-transform.expect @@ -20,17 +20,21 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { control { par { - seq { - @static(2) A0; - @static(3) A1; - @static A2; - } - seq { - @static(2) B0; - @static(3) B1; - @static B2; - } @static(6) C; + @static(6) seq { + @static(2) par { + @static(2) B0; + @static(2) A0; + } + @static(3) par { + @static(3) B1; + @static(3) A1; + } + @static par { + @static B2; + @static A2; + } + } } } } diff --git a/tests/passes/static-par-conv/transform-same-len.expect b/tests/passes/static-par-conv/transform-same-len.expect index 67212537a5..5fba034172 100644 --- a/tests/passes/static-par-conv/transform-same-len.expect +++ b/tests/passes/static-par-conv/transform-same-len.expect @@ -19,16 +19,16 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { control { @static(6) seq { @static(2) par { - @static(2) A0; @static(2) B0; + @static(2) A0; } @static(3) par { - @static(3) A1; @static(3) B1; + @static(3) A1; } @static par { - @static A2; @static B2; + @static A2; } } } From 9304734d98b370bde1f9c9d78ad5880d4f6cbaa5 Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 14 Jun 2022 14:01:04 -0400 Subject: [PATCH 09/32] added partitioning --- calyx/src/passes/static_par_conv.rs | 214 ++++++++++-------- .../static-par-conv/diff-num-cycles.expect | 14 +- .../passes/static-par-conv/interweave.expect | 12 +- ...-can-transform.expect => partition.expect} | 27 ++- ...et-can-transform.futil => partition.futil} | 16 +- 5 files changed, 170 insertions(+), 113 deletions(-) rename tests/passes/static-par-conv/{subset-can-transform.expect => partition.expect} (58%) rename tests/passes/static-par-conv/{subset-can-transform.futil => partition.futil} (60%) diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index f2f1979eda..65e7a83250 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -1,6 +1,7 @@ use crate::ir; use crate::ir::traversal::{Action, Named, VisResult, Visitor}; use crate::ir::GetAttributes; +use std::cmp::Ordering; #[derive(Default)] /// Transforms a par of seq blocks into a seq of par blocks. It will sometimes only @@ -35,6 +36,12 @@ impl Named for StaticParConv { } } +// given a stmt, returns Some(&val) where val is the values of the "static" +// attribute of stmt. Returns None if no "static" attribute exists. +fn get_static_attr(stmt: &ir::Control) -> Option<&u64> { + stmt.get_attributes().and_then(|atts| atts.get("static")) +} + // Takes in two seqs, longer and shorter. longer should be at least as long as // shorter. Returns Some(vec) if there exists arrangement of shorter and longer // such that each statement in shorter can be paired with a statement in longer, @@ -57,10 +64,7 @@ fn is_compatible(longer: &ir::Seq, shorter: &ir::Seq) -> Option> { let mut counter = 0; while let (Some(c1), Some(c2)) = (long_val, short_val) { - match ( - c1.get_attributes().and_then(|atts| atts.get("static")), - c2.get_attributes().and_then(|atts| atts.get("static")), - ) { + match (get_static_attr(c1), get_static_attr(c2)) { (Some(x1), Some(x2)) => { if x2 <= x1 { long_val = long_iter.next(); @@ -88,6 +92,18 @@ fn attribute_with_static(v: u64) -> ir::Attributes { atts } +//returns the Some(sum), where sum is the sum of the static attribute for each +//stmt in seq. None if there is at least one statement that does not have a +// static attribute +fn get_static_sum(seq: &ir::Seq) -> Option { + let static_vals = seq + .stmts + .iter() + .map(get_static_attr) + .collect::>>(); + static_vals.map(|v| v.into_iter().sum()) +} + impl Visitor for StaticParConv { fn finish_par( &mut self, @@ -101,117 +117,121 @@ impl Visitor for StaticParConv { return Ok(Action::Continue); } - // non_compatible holds everything that will NOT be turned into a - // seq of pars - let (mut seqs, mut non_compatible) = (Vec::new(), Vec::new()); + let (mut to_be_partitioned, mut has_been_partitioned) = + (Vec::new(), Vec::new()); for con in s.stmts.drain(..) { match con { - ir::Control::Seq(seq) => seqs.push(seq), - x => non_compatible.push(x), + ir::Control::Seq(seq) => to_be_partitioned.push(seq), + x => has_been_partitioned.push(x), } } - if seqs.is_empty() { - return Ok(Action::Change(Box::new(ir::Control::par( - non_compatible, - )))); - } - - //is there a more idiomatic way to take ownership of just the longest seq - //but not the others? - let max_seq_len = seqs - .iter() - .map(|seq| seq.stmts.len()) - .max() - .unwrap_or_else(|| unreachable!("no seqs")); - let longest_seq; - if let Some(p) = - seqs.iter().position(|seq| seq.stmts.len() == max_seq_len) - { - longest_seq = seqs.swap_remove(p); - } else { - unreachable!("no seq that has length max_seq_len") - } - - let mut indexed_seqs = vec![]; + //sort from longest seq to shortes + to_be_partitioned.sort_by(|s1, s2| { + let len1 = s1.stmts.len(); + let static1 = get_static_sum(s1); + let len2 = s2.stmts.len(); + let static2 = get_static_sum(s2); + match len2.cmp(&len1) { + Ordering::Equal => static2.cmp(&static1), + x => x, + } + }); - //organizing seqs into those that are compatible w/ longest_seq - //and those that are not - for seq in seqs.drain(..) { - if let Some(index_vec) = is_compatible(&longest_seq, &seq) { - indexed_seqs.push((seq, index_vec)); - } else { - non_compatible.push(ir::Control::Seq(seq)); + while !to_be_partitioned.is_empty() { + let longest_seq = to_be_partitioned.remove(0); + let max_seq_len = longest_seq.stmts.len(); + + //group to hold seqs compatible w/ longest_seq as well as + //the respective indices in which each stmt should be inserted + let mut partition_group: Vec<(ir::Seq, Vec)> = vec![]; + + //organizing seqs into those that are compatible w/ longest_seq + //and those that are not + let mut i = 0; + while i != to_be_partitioned.len() { + if let Some(index_vec) = + is_compatible(&longest_seq, &to_be_partitioned[i]) + { + let seq = to_be_partitioned.remove(i); + partition_group.push((seq, index_vec)); + } else { + i += 1; + } } - } - if indexed_seqs.is_empty() { - non_compatible.push(ir::Control::Seq(longest_seq)); - return Ok(Action::Change(Box::new(ir::Control::par( - non_compatible, - )))); - } + if partition_group.is_empty() { + has_been_partitioned.push(ir::Control::Seq(longest_seq)); + continue; + }; - indexed_seqs.push((longest_seq, (0..max_seq_len).collect())); + partition_group.push((longest_seq, (0..max_seq_len).collect())); - let mut new_pars_stmts = Vec::new(); - for _n in 0..max_seq_len { - new_pars_stmts.push(Vec::new()); - } + let mut new_pars_stmts = Vec::new(); + for _n in 0..max_seq_len { + new_pars_stmts.push(Vec::new()); + } - for (seq, indices) in indexed_seqs.drain(..) { - let mut labeled_stmts: Vec<(ir::Control, usize)> = - seq.stmts.into_iter().zip(indices.into_iter()).collect(); - for (stmt, index) in labeled_stmts.drain(..) { - new_pars_stmts[index].push(stmt); + for (seq, indices) in partition_group.drain(..) { + if seq.stmts.len() != indices.len() { + panic!("seq should be same len as indices") + } + let mut labeled_stmts: Vec<(ir::Control, usize)> = + seq.stmts.into_iter().zip(indices.into_iter()).collect(); + for (stmt, index) in labeled_stmts.drain(..) { + new_pars_stmts[index].push(stmt); + } } - } - let new_pars_static = match new_pars_stmts - .iter() - .map(|vec| { - vec - .iter() - .map(|stmt| { - match stmt - .get_attributes() - .and_then(|atts| atts.get("static")) - { - Some(&x1) => x1, - None => unreachable!("every statement in the new par blocks should have a static attribute"), - } + let new_pars_static = match new_pars_stmts + .iter() + .map(|vec| { + vec + .iter() + .map(|stmt| { + match get_static_attr(stmt) + { + Some(&x1) => x1, + None => unreachable!("every statement in the new par blocks should have a static attribute"), + } + }) + .max() + }) + .collect::>>() + { + Some(vec) => vec, + None => unreachable!("none of the par blocks should be empty"), + }; + + let new_seq_static = new_pars_static.iter().sum(); + + let new_pars: Vec = new_pars_stmts + .into_iter() + .zip(new_pars_static.into_iter()) + .map(|(stmts_vec, static_attr)| { + ir::Control::Par(ir::Par { + stmts: stmts_vec, + attributes: attribute_with_static(static_attr), }) - .max() - }) - .collect::>>() - { - Some(vec) => vec, - None => unreachable!("none of the par blocks should be empty"), - }; - - let new_seq_static = new_pars_static.iter().sum(); - - let new_pars: Vec = new_pars_stmts - .into_iter() - .zip(new_pars_static.into_iter()) - .map(|(stmts_vec, static_attr)| { - ir::Control::Par(ir::Par { - stmts: stmts_vec, - attributes: attribute_with_static(static_attr), }) - }) - .collect(); + .collect(); - let new_seq = ir::Control::Seq(ir::Seq { - stmts: new_pars, - attributes: attribute_with_static(new_seq_static), - }); + let new_seq = ir::Control::Seq(ir::Seq { + stmts: new_pars, + attributes: attribute_with_static(new_seq_static), + }); - if non_compatible.is_empty() { - return Ok(Action::Change(Box::new(new_seq))); + has_been_partitioned.push(new_seq); + } + + if has_been_partitioned.len() == 1 { + if let ir::Control::Seq(seq) = has_been_partitioned.remove(0) { + return Ok(Action::Change(Box::new(ir::Control::Seq(seq)))); + } } - non_compatible.push(new_seq); - Ok(Action::Change(Box::new(ir::Control::par(non_compatible)))) + Ok(Action::Change(Box::new(ir::Control::par( + has_been_partitioned, + )))) } } diff --git a/tests/passes/static-par-conv/diff-num-cycles.expect b/tests/passes/static-par-conv/diff-num-cycles.expect index 3fb794849c..3a909822af 100644 --- a/tests/passes/static-par-conv/diff-num-cycles.expect +++ b/tests/passes/static-par-conv/diff-num-cycles.expect @@ -17,16 +17,18 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { - par { - seq { + @static(7) seq { + @static(2) par { + @static(2) A0; @static(2) B0; - @static(4) B1; - @static B2; } - seq { - @static(2) A0; + @static(4) par { @static(3) A1; + @static(4) B1; + } + @static par { @static A2; + @static B2; } } } diff --git a/tests/passes/static-par-conv/interweave.expect b/tests/passes/static-par-conv/interweave.expect index 959f6bdd5f..3c1a22c5b9 100644 --- a/tests/passes/static-par-conv/interweave.expect +++ b/tests/passes/static-par-conv/interweave.expect @@ -28,19 +28,15 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { control { par { - seq { - @static(2) D0; - @static(5) D1; - } @static(9) seq { @static(2) par { - @static E0; @static(2) C0; + @static E0; @static(2) A0; } @static(3) par { - @static(2) E1; @static(3) B0; + @static(2) E1; @static(3) A1; } @static(4) par { @@ -49,6 +45,10 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @static(4) A2; } } + seq { + @static(2) D0; + @static(5) D1; + } } } } diff --git a/tests/passes/static-par-conv/subset-can-transform.expect b/tests/passes/static-par-conv/partition.expect similarity index 58% rename from tests/passes/static-par-conv/subset-can-transform.expect rename to tests/passes/static-par-conv/partition.expect index 4676178c14..26925fd37f 100644 --- a/tests/passes/static-par-conv/subset-can-transform.expect +++ b/tests/passes/static-par-conv/partition.expect @@ -14,13 +14,36 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } group B2 { } - group C { + group E { + } + group C0 { + } + group C1 { + } + group C2 { + } + group D0 { + } + group D1 { } } control { par { - @static(6) C; + @static(6) E; + @static(13) seq { + @static par { + @static D0; + @static C0; + } + @static(5) par { + @static(5) C1; + } + @static(7) par { + @static(6) D1; + @static(7) C2; + } + } @static(6) seq { @static(2) par { @static(2) B0; diff --git a/tests/passes/static-par-conv/subset-can-transform.futil b/tests/passes/static-par-conv/partition.futil similarity index 60% rename from tests/passes/static-par-conv/subset-can-transform.futil rename to tests/passes/static-par-conv/partition.futil index fdfacaa5c8..b1d6c6a34a 100644 --- a/tests/passes/static-par-conv/subset-can-transform.futil +++ b/tests/passes/static-par-conv/partition.futil @@ -17,7 +17,17 @@ component main() -> () { } group B2 { } - group C{ + group E{ + } + group C0{ + } + group C1{ + } + group C2{ + } + group D0{ + } + group D1 { } } @@ -25,7 +35,9 @@ component main() -> () { par { seq{@static(2)A0; @static(3)A1; @static(1)A2;} seq{@static(2)B0; @static(3)B1; @static(1)B2;} - @static(6) C; + seq{@static(1)C0; @static(5)C1; @static(7)C2;} + seq{@static(1)D0; @static(6)D1;} + @static(6) E; } } From a90e909f85ef101f4b7c4d51b982235c2f1c70bb Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 14 Jun 2022 15:16:26 -0400 Subject: [PATCH 10/32] fixed small bug --- calyx/src/passes/static_par_conv.rs | 11 +++++++++-- tests/passes/static-par-conv/empty-seq-blocks.expect | 2 -- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index 65e7a83250..cd012b60f8 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -142,6 +142,10 @@ impl Visitor for StaticParConv { let longest_seq = to_be_partitioned.remove(0); let max_seq_len = longest_seq.stmts.len(); + if max_seq_len == 0 { + break; + } + //group to hold seqs compatible w/ longest_seq as well as //the respective indices in which each stmt should be inserted let mut partition_group: Vec<(ir::Seq, Vec)> = vec![]; @@ -225,8 +229,11 @@ impl Visitor for StaticParConv { } if has_been_partitioned.len() == 1 { - if let ir::Control::Seq(seq) = has_been_partitioned.remove(0) { - return Ok(Action::Change(Box::new(ir::Control::Seq(seq)))); + match has_been_partitioned.remove(0) { + ir::Control::Seq(seq) => { + return Ok(Action::Change(Box::new(ir::Control::Seq(seq)))) + } + x => has_been_partitioned.push(x), } } diff --git a/tests/passes/static-par-conv/empty-seq-blocks.expect b/tests/passes/static-par-conv/empty-seq-blocks.expect index 803d454240..1971dc614c 100644 --- a/tests/passes/static-par-conv/empty-seq-blocks.expect +++ b/tests/passes/static-par-conv/empty-seq-blocks.expect @@ -21,8 +21,6 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { control { par { A0; - @static(0) seq { - } } } } From fc681fa5a66eb832ba72f09ff231afc89d4092cb Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 14 Jun 2022 21:22:01 -0400 Subject: [PATCH 11/32] added comments --- calyx/src/passes/static_par_conv.rs | 73 ++++++++++++++++++----------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index cd012b60f8..4e7668e5d6 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -36,23 +36,24 @@ impl Named for StaticParConv { } } -// given a stmt, returns Some(&val) where val is the values of the "static" +// given a stmt, returns Some(&val) where val is the value of the "static" // attribute of stmt. Returns None if no "static" attribute exists. fn get_static_attr(stmt: &ir::Control) -> Option<&u64> { stmt.get_attributes().and_then(|atts| atts.get("static")) } -// Takes in two seqs, longer and shorter. longer should be at least as long as +// Takes two seqs, longer and shorter. longer should be at least as long as // shorter. Returns Some(vec) if there exists arrangement of shorter and longer // such that each statement in shorter can be paired with a statement in longer, // such that executing these pairs in as a seq of pars will respect dependencies and -// the number of cycles it takes will remaine the same (i.e., the same as longer)/ -// The vec it returns the indices that each element of shorter should be paired -// with longer. So, if we represent the vecs by the static attribute of their -// statements, if longer = [4,1,5] and shorter [4,5] then vec would be -// [0,2], since the 4 in shorter lines up with the 4 in longer (@ index 0) -// and the 5 in shorter lines up with 5 in longer (@ index 2). A consequence of this is -// that vec should always be the same length as shorter. +// the number of cycles it takes will remain the same (i.e., the same as longer) +// The vec it returns contains which indices of longer each element in shorter +// should be paired with. So, if we represent the vecs by the static attribute of their +// statements, and longer = [4,1,5] and shorter [4,5] then vec would be +// [0,2], since the 4 in shorter can be paired with the 4 in longer (@ index 0) +// and the 5 in shorter can be paired with the 5 in longer (@ index 2). +// A consequence of this is that vec should always be the same length as shorter. +// If no such vec exists, returns None. fn is_compatible(longer: &ir::Seq, shorter: &ir::Seq) -> Option> { let mut long_iter = (*longer).stmts.iter(); let mut short_iter = (*shorter).stmts.iter(); @@ -85,16 +86,16 @@ fn is_compatible(longer: &ir::Seq, shorter: &ir::Seq) -> Option> { } } -// returns a default Attribute with "static" set to v +// Returns a default Attribute with "static" set to v fn attribute_with_static(v: u64) -> ir::Attributes { let mut atts = ir::Attributes::default(); atts.insert("static", v); atts } -//returns the Some(sum), where sum is the sum of the static attribute for each -//stmt in seq. None if there is at least one statement that does not have a -// static attribute +// Returns the Some(sum), where sum is the sum of the static attribute for each +// stmt in seq. Returns None if there is at least one statement in seq +// that does not have astatic attribute fn get_static_sum(seq: &ir::Seq) -> Option { let static_vals = seq .stmts @@ -126,7 +127,7 @@ impl Visitor for StaticParConv { } } - //sort from longest seq to shortes + //sort from longest seq to shortest to_be_partitioned.sort_by(|s1, s2| { let len1 = s1.stmts.len(); let static1 = get_static_sum(s1); @@ -142,51 +143,67 @@ impl Visitor for StaticParConv { let longest_seq = to_be_partitioned.remove(0); let max_seq_len = longest_seq.stmts.len(); + //if we just have a bunch of empty seqs if max_seq_len == 0 { break; } - //group to hold seqs compatible w/ longest_seq as well as - //the respective indices in which each stmt should be inserted - let mut partition_group: Vec<(ir::Seq, Vec)> = vec![]; + //the stmts in this vec of vecs will eventually be transformed into a + //seq of pars. The usize is used to determine which par block + //its respective statement will eventually be put in. + let mut partition_group: Vec> = vec![]; - //organizing seqs into those that are compatible w/ longest_seq - //and those that are not + //looking for seqs that are compatible with longest_seq let mut i = 0; while i != to_be_partitioned.len() { if let Some(index_vec) = is_compatible(&longest_seq, &to_be_partitioned[i]) { let seq = to_be_partitioned.remove(i); - partition_group.push((seq, index_vec)); + if seq.stmts.len() != index_vec.len() { + unreachable!("seq should be same len as indices") + } + let indexed_stmts: Vec<(ir::Control, usize)> = seq + .stmts + .into_iter() + .zip(index_vec.into_iter()) + .collect(); + partition_group.push(indexed_stmts); } else { i += 1; } } + //if there are no seqs compatible w/ longest_seq, then + //there is no point in making a seq of pars since we just + //have a single seq (namely longest_seq) if partition_group.is_empty() { has_been_partitioned.push(ir::Control::Seq(longest_seq)); continue; }; - partition_group.push((longest_seq, (0..max_seq_len).collect())); + //adding longest_seq to partition_group + let longest_len_vec: Vec = (0..max_seq_len).collect(); + let longest_seq_indexed = longest_seq + .stmts + .into_iter() + .zip(longest_len_vec.into_iter()) + .collect(); + partition_group.push(longest_seq_indexed); + //now we start the process of creating a seq of pars let mut new_pars_stmts = Vec::new(); for _n in 0..max_seq_len { new_pars_stmts.push(Vec::new()); } - for (seq, indices) in partition_group.drain(..) { - if seq.stmts.len() != indices.len() { - panic!("seq should be same len as indices") - } - let mut labeled_stmts: Vec<(ir::Control, usize)> = - seq.stmts.into_iter().zip(indices.into_iter()).collect(); - for (stmt, index) in labeled_stmts.drain(..) { + for mut v in partition_group.drain(..) { + for (stmt, index) in v.drain(..) { new_pars_stmts[index].push(stmt); } } + //getting the static attribute for each of the par blocks we will build let new_pars_static = match new_pars_stmts .iter() .map(|vec| { From 56573f55348b9b74a025029f19799e21ac15c867 Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 14 Jun 2022 21:27:28 -0400 Subject: [PATCH 12/32] fixed clippy complaints --- calyx/src/passes/static_par_conv.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index 4e7668e5d6..7d2899d836 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -183,12 +183,8 @@ impl Visitor for StaticParConv { }; //adding longest_seq to partition_group - let longest_len_vec: Vec = (0..max_seq_len).collect(); - let longest_seq_indexed = longest_seq - .stmts - .into_iter() - .zip(longest_len_vec.into_iter()) - .collect(); + let longest_seq_indexed = + longest_seq.stmts.into_iter().zip(0..max_seq_len).collect(); partition_group.push(longest_seq_indexed); //now we start the process of creating a seq of pars From 649bb91c56c5eede74566f2f749da74e9df5abd6 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Jun 2022 12:18:06 -0400 Subject: [PATCH 13/32] removes par block if par block would only have one statement --- calyx/src/passes/static_par_conv.rs | 31 ++++++++----------- .../static-par-conv/empty-seq-blocks.expect | 4 +-- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/calyx/src/passes/static_par_conv.rs b/calyx/src/passes/static_par_conv.rs index 7d2899d836..b3af69db6a 100644 --- a/calyx/src/passes/static_par_conv.rs +++ b/calyx/src/passes/static_par_conv.rs @@ -6,7 +6,7 @@ use std::cmp::Ordering; #[derive(Default)] /// Transforms a par of seq blocks into a seq of par blocks. It will sometimes only /// apply this transformation to a subset of seq blocks in the par block. -/// This transformation should never increase the number of cycles the par +/// Regardless, this transformation should never increase the number of cycles the par /// block takes to execute. /// /// #Example @@ -45,15 +45,14 @@ fn get_static_attr(stmt: &ir::Control) -> Option<&u64> { // Takes two seqs, longer and shorter. longer should be at least as long as // shorter. Returns Some(vec) if there exists arrangement of shorter and longer // such that each statement in shorter can be paired with a statement in longer, -// such that executing these pairs in as a seq of pars will respect dependencies and -// the number of cycles it takes will remain the same (i.e., the same as longer) +// such that executing these pairs as a seq of pars will respect dependencies and +// the number of cycles it takes will remain the same. If no such vec exists, returns None. // The vec it returns contains which indices of longer each element in shorter // should be paired with. So, if we represent the vecs by the static attribute of their -// statements, and longer = [4,1,5] and shorter [4,5] then vec would be +// statements, and longer = [4,1,5] and shorter = [4,5] then vec would be // [0,2], since the 4 in shorter can be paired with the 4 in longer (@ index 0) // and the 5 in shorter can be paired with the 5 in longer (@ index 2). // A consequence of this is that vec should always be the same length as shorter. -// If no such vec exists, returns None. fn is_compatible(longer: &ir::Seq, shorter: &ir::Seq) -> Option> { let mut long_iter = (*longer).stmts.iter(); let mut short_iter = (*shorter).stmts.iter(); @@ -68,12 +67,10 @@ fn is_compatible(longer: &ir::Seq, shorter: &ir::Seq) -> Option> { match (get_static_attr(c1), get_static_attr(c2)) { (Some(x1), Some(x2)) => { if x2 <= x1 { - long_val = long_iter.next(); short_val = short_iter.next(); index_counter.push(counter); - } else { - long_val = long_iter.next(); } + long_val = long_iter.next(); } _ => return None, } @@ -95,7 +92,7 @@ fn attribute_with_static(v: u64) -> ir::Attributes { // Returns the Some(sum), where sum is the sum of the static attribute for each // stmt in seq. Returns None if there is at least one statement in seq -// that does not have astatic attribute +// that does not have a static attribute fn get_static_sum(seq: &ir::Seq) -> Option { let static_vals = seq .stmts @@ -150,7 +147,7 @@ impl Visitor for StaticParConv { //the stmts in this vec of vecs will eventually be transformed into a //seq of pars. The usize is used to determine which par block - //its respective statement will eventually be put in. + //the respective statement will eventually be put in. let mut partition_group: Vec> = vec![]; //looking for seqs that are compatible with longest_seq @@ -202,8 +199,8 @@ impl Visitor for StaticParConv { //getting the static attribute for each of the par blocks we will build let new_pars_static = match new_pars_stmts .iter() - .map(|vec| { - vec + .map(|stmts| { + stmts .iter() .map(|stmt| { match get_static_attr(stmt) @@ -241,13 +238,11 @@ impl Visitor for StaticParConv { has_been_partitioned.push(new_seq); } + //no need for a par block if the par block will only contain one control statement if has_been_partitioned.len() == 1 { - match has_been_partitioned.remove(0) { - ir::Control::Seq(seq) => { - return Ok(Action::Change(Box::new(ir::Control::Seq(seq)))) - } - x => has_been_partitioned.push(x), - } + return Ok(Action::Change(Box::new( + has_been_partitioned.remove(0), + ))); } Ok(Action::Change(Box::new(ir::Control::par( diff --git a/tests/passes/static-par-conv/empty-seq-blocks.expect b/tests/passes/static-par-conv/empty-seq-blocks.expect index 1971dc614c..de398d1292 100644 --- a/tests/passes/static-par-conv/empty-seq-blocks.expect +++ b/tests/passes/static-par-conv/empty-seq-blocks.expect @@ -19,8 +19,6 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { - par { - A0; - } + A0; } } From eeaad2823318398eceb640323ca1efe89600d248 Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 17 Jun 2022 10:49:20 -0400 Subject: [PATCH 14/32] combined, but some bugs --- calyx/src/analysis/live_range_analysis.rs | 50 +++++----- calyx/src/passes/minimize_regs.rs | 99 ++++++++++++++++--- .../was-resource-sharing/cond-port.expect | 49 +++++++++ .../was-resource-sharing/cond-port.futil | 43 ++++++++ .../continuous-assign.expect | 17 ++++ .../continuous-assign.futil | 18 ++++ .../multiple-cells.expect | 37 +++++++ .../was-resource-sharing/multiple-cells.futil | 37 +++++++ .../share-component.expect | 43 ++++++++ .../share-component.futil | 44 +++++++++ .../passes/was-resource-sharing/share.expect | 31 ++++++ tests/passes/was-resource-sharing/share.futil | 32 ++++++ 12 files changed, 461 insertions(+), 39 deletions(-) create mode 100644 tests/passes/was-resource-sharing/cond-port.expect create mode 100644 tests/passes/was-resource-sharing/cond-port.futil create mode 100644 tests/passes/was-resource-sharing/continuous-assign.expect create mode 100644 tests/passes/was-resource-sharing/continuous-assign.futil create mode 100644 tests/passes/was-resource-sharing/multiple-cells.expect create mode 100644 tests/passes/was-resource-sharing/multiple-cells.futil create mode 100644 tests/passes/was-resource-sharing/share-component.expect create mode 100644 tests/passes/was-resource-sharing/share-component.futil create mode 100644 tests/passes/was-resource-sharing/share.expect create mode 100644 tests/passes/was-resource-sharing/share.futil diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 0ff4cebf61..407d894bf0 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -222,8 +222,8 @@ pub struct LiveRangeAnalysis { /// Groups that have been identified as variable-like. /// Mapping from group name to the name of the register. variable_like: HashMap>, - /// Set of shareable components (as type names) - shareable_components: HashSet, + /// Set of state shareable components (as type names) + state_share: HashSet, } impl Debug for LiveRangeAnalysis { @@ -236,14 +236,14 @@ impl Debug for LiveRangeAnalysis { } } -//given a set of shareable_components and a cell, determines whether cell's +//given a set of state_shareable and a cell, determines whether cell's //type is shareable or not fn is_shareable_component( - shareable_components: &HashSet, + shareable: &HashSet, cell: &RRC, ) -> bool { if let Some(type_name) = cell.borrow().type_name() { - shareable_components.contains(type_name) + shareable.contains(type_name) } else { false } @@ -254,11 +254,12 @@ impl LiveRangeAnalysis { pub fn new( comp: &ir::Component, control: &ir::Control, - shareable_components: HashSet, + state_share: HashSet, + shareable: HashSet, ) -> Self { let mut ranges = LiveRangeAnalysis::default(); - ranges.shareable_components = shareable_components; + ranges.state_share = state_share; build_live_ranges( control, @@ -272,7 +273,8 @@ impl LiveRangeAnalysis { let global_reads: Prop = ReadWriteSet::read_set(comp.continuous_assignments.iter()) .filter(|c| { - is_shareable_component(&ranges.shareable_components, &c) + is_shareable_component(&ranges.state_share, &c) + || is_shareable_component(&shareable, &c) }) .map(|c| c.clone_name()) .collect::>() @@ -327,7 +329,7 @@ impl LiveRangeAnalysis { &mut self, group_ref: &RRC, ) -> (Prop, Prop) { - let sc_clone = self.shareable_components.clone(); + let sc_clone = self.state_share.clone(); let group = group_ref.borrow(); // if the group contains what looks like a variable write, @@ -387,11 +389,11 @@ impl LiveRangeAnalysis { fn port_to_cell_name( port: &RRC, - shareable_components: &HashSet, + state_share: &HashSet, ) -> Option { if let ir::PortParent::Cell(cell_wref) = &port.borrow().parent { let cell = cell_wref.upgrade(); - if is_shareable_component(shareable_components, &cell) { + if is_shareable_component(state_share, &cell) { return Some(cell.borrow().clone_name()); } } @@ -401,23 +403,19 @@ impl LiveRangeAnalysis { /// Returns (reads, writes) that occur in the [ir::Invoke] statement. fn find_gen_kill_invoke( invoke: &ir::Invoke, - shareable_components: &HashSet, + state_share: &HashSet, ) -> (Prop, Prop) { let reads: Prop = invoke .inputs .iter() - .filter_map(|(_, src)| { - Self::port_to_cell_name(src, shareable_components) - }) + .filter_map(|(_, src)| Self::port_to_cell_name(src, state_share)) .collect::>() .into(); let writes: Prop = invoke .outputs .iter() - .filter_map(|(_, src)| { - Self::port_to_cell_name(src, shareable_components) - }) + .filter_map(|(_, src)| Self::port_to_cell_name(src, state_share)) .collect::>() .into(); @@ -439,7 +437,7 @@ fn build_live_ranges( ir::Control::Invoke(invoke) => { let (reads, writes) = LiveRangeAnalysis::find_gen_kill_invoke( invoke, - &lr.shareable_components, + &lr.state_share, ); let alive = alive.transfer(&reads, &writes); (alive, &gens | &reads, &kills | &writes) @@ -485,10 +483,9 @@ fn build_live_ranges( let kills = &t_kills | &f_kills; // feed to condition to compute - if let Some(cell) = LiveRangeAnalysis::port_to_cell_name( - port, - &lr.shareable_components, - ) { + if let Some(cell) = + LiveRangeAnalysis::port_to_cell_name(port, &lr.state_share) + { alive.insert(cell) } (alive, gens, kills) @@ -523,10 +520,9 @@ fn build_live_ranges( ir::Control::While(ir::While { body, port, .. }) => { let (mut alive, gens, kills) = build_live_ranges(body, alive, gens, kills, lr); - if let Some(cell) = LiveRangeAnalysis::port_to_cell_name( - port, - &lr.shareable_components, - ) { + if let Some(cell) = + LiveRangeAnalysis::port_to_cell_name(port, &lr.state_share) + { alive.insert(cell) } build_live_ranges(body, alive, gens, kills, lr) diff --git a/calyx/src/passes/minimize_regs.rs b/calyx/src/passes/minimize_regs.rs index ebfc58fefb..5801ea7c76 100644 --- a/calyx/src/passes/minimize_regs.rs +++ b/calyx/src/passes/minimize_regs.rs @@ -1,8 +1,8 @@ use super::sharing_components::ShareComponents; use crate::errors::CalyxResult; use crate::{ - analysis::LiveRangeAnalysis, - ir::{self, traversal::ConstructVisitor, traversal::Named}, + analysis::{LiveRangeAnalysis, ReadWriteSet}, + ir::{self, traversal::ConstructVisitor, traversal::Named, CloneName}, }; use std::collections::{HashMap, HashSet}; @@ -22,8 +22,14 @@ use std::collections::{HashMap, HashSet}; pub struct MinimizeRegs { live: LiveRangeAnalysis, rewrites: HashMap>, - /// Set of shareable components (as type names) - shareable_components: HashSet, + /// Set of state shareable components (as type names) + state_shareable: HashSet, + + /// Mapping from the name of a group to the cells that it uses. + used_cells_map: HashMap>, + + /// Set of shareable components. + shareable: HashSet, } impl Named for MinimizeRegs { @@ -37,24 +43,48 @@ impl Named for MinimizeRegs { impl ConstructVisitor for MinimizeRegs { fn from(ctx: &ir::Context) -> CalyxResult { - let mut shareable_components = HashSet::new(); - // add state_share=1 primitives to the shareable_components set + let mut state_shareable = HashSet::new(); + let mut shareable = HashSet::new(); + // add state_share=1 primitives to the state_shareable set for prim in ctx.lib.signatures() { - if let Some(&1) = prim.attributes.get("state_share") { - shareable_components.insert(prim.name.clone()); + if let Some(&1) = prim.attributes.get("share") { + shareable.insert(prim.name.clone()); + } else if let Some(&1) = prim.attributes.get("state_share") { + state_shareable.insert(prim.name.clone()); + } + } + + // add share=1 user defined components to the shareable_components set + for comp in &ctx.components { + if let Some(&1) = comp.attributes.get("share") { + shareable.insert(comp.name.clone()); } } Ok(MinimizeRegs { live: LiveRangeAnalysis::default(), rewrites: HashMap::new(), - shareable_components, + state_shareable, + used_cells_map: HashMap::new(), + shareable, }) } fn clear_data(&mut self) { self.rewrites = HashMap::new(); self.live = LiveRangeAnalysis::default(); + self.used_cells_map = HashMap::new(); + } +} + +//Given cell, cont_cell, and shareable_components, returns true if +//cell is shareable (as determined by shareable_components) and is not +//a continuous cell +fn share_filter(cell: &ir::Cell, shareable: &HashSet) -> bool { + if let Some(type_name) = cell.type_name() { + shareable.contains(type_name) + } else { + false } } @@ -67,17 +97,57 @@ impl ShareComponents for MinimizeRegs { self.live = LiveRangeAnalysis::new( comp, &*comp.control.borrow(), - self.shareable_components.clone(), + self.state_shareable.clone(), + self.shareable.clone(), ); + + //Following code is from resource_sharing pass + let group_uses = comp.groups.iter().map(|group| { + ( + group.clone_name(), + ReadWriteSet::uses(group.borrow().assignments.iter()) + .filter(|cell| { + share_filter(&cell.borrow(), &self.shareable) + }) + .map(|cell| cell.clone_name()) + .collect::>(), + ) + }); + let cg_uses = comp.comb_groups.iter().map(|cg| { + ( + cg.clone_name(), + ReadWriteSet::uses(cg.borrow().assignments.iter()) + .filter(|cell| { + share_filter(&cell.borrow(), &self.shareable) + }) + .map(|cell| cell.clone_name()) + .collect::>(), + ) + }); + self.used_cells_map = group_uses.chain(cg_uses).collect(); } fn lookup_group_conflicts(&self, group_name: &ir::Id) -> Vec { - self.live.get(group_name).iter().cloned().collect() + let mut state_shareable: Vec = + self.live.get(group_name).iter().cloned().collect(); + + //resource-sharing code + let shareable = self + .used_cells_map + .get(group_name) + .unwrap_or_else(|| { + panic!("Missing used cells for group: {}", group_name) + }) + .clone(); + + state_shareable.extend(shareable); + + state_shareable } fn cell_filter(&self, cell: &ir::Cell) -> bool { if let Some(name) = cell.type_name() { - self.shareable_components.contains(name) + self.state_shareable.contains(name) || self.shareable.contains(name) } else { false } @@ -91,6 +161,11 @@ impl ShareComponents for MinimizeRegs { let conflicts = self.live.get(group.borrow().name()); add_conflicts(conflicts.iter().cloned().collect()); } + + //resource-sharing code + for used in self.used_cells_map.values() { + add_conflicts(used.clone()) + } } fn set_rewrites(&mut self, rewrites: HashMap>) { diff --git a/tests/passes/was-resource-sharing/cond-port.expect b/tests/passes/was-resource-sharing/cond-port.expect new file mode 100644 index 0000000000..84243bf12a --- /dev/null +++ b/tests/passes/was-resource-sharing/cond-port.expect @@ -0,0 +1,49 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + gt0 = std_gt(32); + gt1 = std_gt(32); + x_0 = std_reg(32); + y_0 = std_reg(1); + @generated comb_reg = std_reg(1); + } + wires { + group let0 { + x_0.in = 32'd1; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1 { + y_0.in = gt0.out; + y_0.write_en = 1'd1; + let1[done] = y_0.done; + gt0.left = x_0.out; + gt0.right = 32'd1; + } + group upd0 { + x_0.write_en = 1'd1; + 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; + seq { + cond00; + if comb_reg.out { + upd0; + } + } + } + } +} diff --git a/tests/passes/was-resource-sharing/cond-port.futil b/tests/passes/was-resource-sharing/cond-port.futil new file mode 100644 index 0000000000..1c6b454df6 --- /dev/null +++ b/tests/passes/was-resource-sharing/cond-port.futil @@ -0,0 +1,43 @@ +// -p remove-comb-groups -p minimize-regs +import "primitives/core.futil"; +component main() -> () { + cells { + gt0 = std_gt(32); + gt1 = std_gt(32); + x_0 = std_reg(32); + y_0 = std_reg(1); + } + wires { + comb group cond0 { + gt1.left = x_0.out; + gt1.right = 32'd2; + } + group let0 { + x_0.in = 32'd1; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1 { + y_0.in = gt0.out; + y_0.write_en = 1'd1; + let1[done] = y_0.done; + gt0.left = x_0.out; + gt0.right = 32'd1; + } + group upd0 { + x_0.write_en = 1'd1; + x_0.in = 1'd1 ? 32'd10; + upd0[done] = x_0.done ? 1'd1; + } + } + control { + seq { + let0; + let1; + if gt1.out with cond0 { + upd0; + } + } + } +} + diff --git a/tests/passes/was-resource-sharing/continuous-assign.expect b/tests/passes/was-resource-sharing/continuous-assign.expect new file mode 100644 index 0000000000..5853bba2a7 --- /dev/null +++ b/tests/passes/was-resource-sharing/continuous-assign.expect @@ -0,0 +1,17 @@ +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r0 = std_reg(32); + r1 = std_reg(32); + add0 = std_add(32); + add1 = std_add(32); + } + wires { + done = r0.done; + add1.left = r0.out; + add0.left = r1.out; + } + + control {} +} diff --git a/tests/passes/was-resource-sharing/continuous-assign.futil b/tests/passes/was-resource-sharing/continuous-assign.futil new file mode 100644 index 0000000000..518ed3fe81 --- /dev/null +++ b/tests/passes/was-resource-sharing/continuous-assign.futil @@ -0,0 +1,18 @@ +// -p validate -p minimize-regs +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r0 = std_reg(32); + r1 = std_reg(32); + add0 = std_add(32); + add1 = std_add(32); + } + wires { + add0.left = r1.out; + add1.left = r0.out; + done = r0.done; + } + + control { } +} diff --git a/tests/passes/was-resource-sharing/multiple-cells.expect b/tests/passes/was-resource-sharing/multiple-cells.expect new file mode 100644 index 0000000000..f2f0e89cc4 --- /dev/null +++ b/tests/passes/was-resource-sharing/multiple-cells.expect @@ -0,0 +1,37 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add0 = std_add(32); + add1 = std_add(32); + add2 = std_add(32); + add3 = std_add(32); + x_0 = std_reg(32); + } + wires { + group let0<"static"=1> { + add0.left = 32'd1; + add0.right = 32'd2; + add1.right = 32'd3; + add1.left = add0.out; + x_0.in = add1.out; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1<"static"=1> { + add0.left = 32'd1; + add0.right = 32'd2; + add1.right = 32'd3; + add1.left = add0.out; + x_0.in = add1.out; + x_0.write_en = 1'd1; + let1[done] = x_0.done; + } + } + + control { + seq { + let0; + let1; + } + } +} diff --git a/tests/passes/was-resource-sharing/multiple-cells.futil b/tests/passes/was-resource-sharing/multiple-cells.futil new file mode 100644 index 0000000000..8373d0d8b6 --- /dev/null +++ b/tests/passes/was-resource-sharing/multiple-cells.futil @@ -0,0 +1,37 @@ +// -p minimize-regs +import "primitives/core.futil"; +component main() -> () { + cells { + add0 = std_add(32); + add1 = std_add(32); + add2 = std_add(32); + add3 = std_add(32); + x_0 = std_reg(32); + } + wires { + group let0<"static"=1> { + add0.left = 32'd1; + add0.right = 32'd2; + add1.right = 32'd3; + add1.left = add0.out; + x_0.in = add1.out; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1<"static"=1> { + add2.left = 32'd1; + add2.right = 32'd2; + add3.right = 32'd3; + add3.left = add2.out; + x_0.in = add3.out; + x_0.write_en = 1'd1; + let1[done] = x_0.done; + } + } + control { + seq { + let0; + let1; + } + } +} diff --git a/tests/passes/was-resource-sharing/share-component.expect b/tests/passes/was-resource-sharing/share-component.expect new file mode 100644 index 0000000000..8c271b756f --- /dev/null +++ b/tests/passes/was-resource-sharing/share-component.expect @@ -0,0 +1,43 @@ +import "primitives/core.futil"; +component my_add<"share"=1>(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + add = std_add(32); + } + wires { + add.left = left; + add.right = right; + out = add.out; + } + + control {} +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add0 = my_add(); + add1 = my_add(); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd0[done] = x_0.done ? 1'd1; + } + group upd1 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd1[done] = x_0.done ? 1'd1; + } + } + + control { + seq { + upd0; + upd1; + } + } +} diff --git a/tests/passes/was-resource-sharing/share-component.futil b/tests/passes/was-resource-sharing/share-component.futil new file mode 100644 index 0000000000..28cb37a8fd --- /dev/null +++ b/tests/passes/was-resource-sharing/share-component.futil @@ -0,0 +1,44 @@ +// -p minimize-regs + +import "primitives/core.futil"; +component my_add<"share"=1>(left: 32, right: 32) -> (out: 32) { + cells { + add = std_add(32); + } + wires { + add.left = left; + add.right = right; + out = add.out; + } + control {} +} + +component main() -> () { + cells { + add0 = my_add(); + add1 = my_add(); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd0[done] = x_0.done ? 1'd1; + } + group upd1 { + add1.left = x_0.out; + add1.right = 32'd1; + x_0.in = add1.out; + x_0.write_en = 1'd1; + upd1[done] = x_0.done ? 1'd1; + } + } + control { + seq { + upd0; + upd1; + } + } +} diff --git a/tests/passes/was-resource-sharing/share.expect b/tests/passes/was-resource-sharing/share.expect new file mode 100644 index 0000000000..16215666e0 --- /dev/null +++ b/tests/passes/was-resource-sharing/share.expect @@ -0,0 +1,31 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add0 = std_add(32); + add1 = std_add(32); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd0[done] = x_0.done ? 1'd1; + } + group upd1 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd1[done] = x_0.done ? 1'd1; + } + } + + control { + seq { + upd0; + upd1; + } + } +} diff --git a/tests/passes/was-resource-sharing/share.futil b/tests/passes/was-resource-sharing/share.futil new file mode 100644 index 0000000000..4146b3c2d2 --- /dev/null +++ b/tests/passes/was-resource-sharing/share.futil @@ -0,0 +1,32 @@ +// -p minimize-regs + +import "primitives/core.futil"; +component main() -> () { + cells { + add0 = std_add(32); + add1 = std_add(32); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd0[done] = x_0.done ? 1'd1; + } + group upd1 { + add1.left = x_0.out; + add1.right = 32'd1; + x_0.in = add1.out; + x_0.write_en = 1'd1; + upd1[done] = x_0.done ? 1'd1; + } + } + control { + seq { + upd0; + upd1; + } + } +} From 51a9cb1959a91d054bc2b09f29bb521d9dc34fa1 Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 17 Jun 2022 13:51:17 -0400 Subject: [PATCH 15/32] combined lra --- calyx/src/analysis/live_range_analysis.rs | 42 ++++- calyx/src/passes/minimize_regs.rs | 66 +------ .../condition-register.expect | 32 ++++ .../condition-register.futil | 37 ++++ .../continuous-assignment.expect | 27 +++ .../continuous-assignment.futil | 27 +++ .../was_minimize_regs/escape-boundary.expect | 26 +++ .../was_minimize_regs/escape-boundary.futil | 26 +++ .../was_minimize_regs/invoke.expect | 58 ++++++ .../was_minimize_regs/invoke.futil | 58 ++++++ .../live-register-analysis.expect | 127 +++++++++++++ .../live-register-analysis.fuse | 14 ++ .../live-register-analysis.futil | 112 +++++++++++ .../was_minimize_regs/nested-par.expect | 74 ++++++++ .../was_minimize_regs/nested-par.futil | 78 ++++++++ .../par-while-liveness.expect | 175 ++++++++++++++++++ .../par-while-liveness.futil | 153 +++++++++++++++ .../was_minimize_regs/par-write.expect | 26 +++ .../was_minimize_regs/par-write.futil | 27 +++ .../was_minimize_regs/simple-liveness.expect | 41 ++++ .../was_minimize_regs/simple-liveness.futil | 42 +++++ .../was_minimize_regs/thread-local.expect | 46 +++++ .../was_minimize_regs/thread-local.futil | 48 +++++ .../was_resource_share/cond-port.expect | 49 +++++ .../was_resource_share/cond-port.futil | 43 +++++ .../continuous-assign.expect | 17 ++ .../continuous-assign.futil | 18 ++ .../was_resource_share/multiple-cells.expect | 37 ++++ .../was_resource_share/multiple-cells.futil | 37 ++++ .../was_resource_share/share-component.expect | 43 +++++ .../was_resource_share/share-component.futil | 44 +++++ .../was_resource_share/share.expect | 31 ++++ .../was_resource_share/share.futil | 32 ++++ 33 files changed, 1645 insertions(+), 68 deletions(-) create mode 100644 tests/passes/general_share/was_minimize_regs/condition-register.expect create mode 100644 tests/passes/general_share/was_minimize_regs/condition-register.futil create mode 100644 tests/passes/general_share/was_minimize_regs/continuous-assignment.expect create mode 100644 tests/passes/general_share/was_minimize_regs/continuous-assignment.futil create mode 100644 tests/passes/general_share/was_minimize_regs/escape-boundary.expect create mode 100644 tests/passes/general_share/was_minimize_regs/escape-boundary.futil create mode 100644 tests/passes/general_share/was_minimize_regs/invoke.expect create mode 100644 tests/passes/general_share/was_minimize_regs/invoke.futil create mode 100644 tests/passes/general_share/was_minimize_regs/live-register-analysis.expect create mode 100644 tests/passes/general_share/was_minimize_regs/live-register-analysis.fuse create mode 100644 tests/passes/general_share/was_minimize_regs/live-register-analysis.futil create mode 100644 tests/passes/general_share/was_minimize_regs/nested-par.expect create mode 100644 tests/passes/general_share/was_minimize_regs/nested-par.futil create mode 100644 tests/passes/general_share/was_minimize_regs/par-while-liveness.expect create mode 100644 tests/passes/general_share/was_minimize_regs/par-while-liveness.futil create mode 100644 tests/passes/general_share/was_minimize_regs/par-write.expect create mode 100644 tests/passes/general_share/was_minimize_regs/par-write.futil create mode 100644 tests/passes/general_share/was_minimize_regs/simple-liveness.expect create mode 100644 tests/passes/general_share/was_minimize_regs/simple-liveness.futil create mode 100644 tests/passes/general_share/was_minimize_regs/thread-local.expect create mode 100644 tests/passes/general_share/was_minimize_regs/thread-local.futil create mode 100644 tests/passes/general_share/was_resource_share/cond-port.expect create mode 100644 tests/passes/general_share/was_resource_share/cond-port.futil create mode 100644 tests/passes/general_share/was_resource_share/continuous-assign.expect create mode 100644 tests/passes/general_share/was_resource_share/continuous-assign.futil create mode 100644 tests/passes/general_share/was_resource_share/multiple-cells.expect create mode 100644 tests/passes/general_share/was_resource_share/multiple-cells.futil create mode 100644 tests/passes/general_share/was_resource_share/share-component.expect create mode 100644 tests/passes/general_share/was_resource_share/share-component.futil create mode 100644 tests/passes/general_share/was_resource_share/share.expect create mode 100644 tests/passes/general_share/was_resource_share/share.futil diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 407d894bf0..d5c5e37e4b 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -236,7 +236,7 @@ impl Debug for LiveRangeAnalysis { } } -//given a set of state_shareable and a cell, determines whether cell's +//given a set of shareable and a cell, determines whether cell's //type is shareable or not fn is_shareable_component( shareable: &HashSet, @@ -269,13 +269,45 @@ impl LiveRangeAnalysis { &mut ranges, ); + comp.groups.iter().for_each(|group| { + let group_uses: Prop = + ReadWriteSet::uses(group.borrow().assignments.iter()) + .filter(|cell| is_shareable_component(&shareable, &cell)) + .map(|cell| cell.clone_name()) + .collect::>() + .into(); + match ranges.live.get_mut(group.borrow().name()) { + None => { + unreachable!( + "don't have live range for {}", + group.borrow().name() + ) + } + Some(prop) => *prop = &*prop | &group_uses, + } + }); + comp.comb_groups.iter().for_each(|group| { + let group_uses: Prop = + ReadWriteSet::uses(group.borrow().assignments.iter()) + .filter(|cell| is_shareable_component(&shareable, &cell)) + .map(|cell| cell.clone_name()) + .collect::>() + .into(); + match ranges.live.get_mut(group.borrow().name()) { + None => { + unreachable!( + "don't have live range for {}", + group.borrow().name() + ) + } + Some(prop) => *prop = &*prop | &group_uses, + } + }); + // add global reads to every point let global_reads: Prop = ReadWriteSet::read_set(comp.continuous_assignments.iter()) - .filter(|c| { - is_shareable_component(&ranges.state_share, &c) - || is_shareable_component(&shareable, &c) - }) + .filter(|c| is_shareable_component(&ranges.state_share, &c)) .map(|c| c.clone_name()) .collect::>() .into(); diff --git a/calyx/src/passes/minimize_regs.rs b/calyx/src/passes/minimize_regs.rs index 5801ea7c76..e4630815f0 100644 --- a/calyx/src/passes/minimize_regs.rs +++ b/calyx/src/passes/minimize_regs.rs @@ -1,8 +1,8 @@ use super::sharing_components::ShareComponents; use crate::errors::CalyxResult; use crate::{ - analysis::{LiveRangeAnalysis, ReadWriteSet}, - ir::{self, traversal::ConstructVisitor, traversal::Named, CloneName}, + analysis::LiveRangeAnalysis, + ir::{self, traversal::ConstructVisitor, traversal::Named}, }; use std::collections::{HashMap, HashSet}; @@ -25,9 +25,6 @@ pub struct MinimizeRegs { /// Set of state shareable components (as type names) state_shareable: HashSet, - /// Mapping from the name of a group to the cells that it uses. - used_cells_map: HashMap>, - /// Set of shareable components. shareable: HashSet, } @@ -65,7 +62,6 @@ impl ConstructVisitor for MinimizeRegs { live: LiveRangeAnalysis::default(), rewrites: HashMap::new(), state_shareable, - used_cells_map: HashMap::new(), shareable, }) } @@ -73,18 +69,6 @@ impl ConstructVisitor for MinimizeRegs { fn clear_data(&mut self) { self.rewrites = HashMap::new(); self.live = LiveRangeAnalysis::default(); - self.used_cells_map = HashMap::new(); - } -} - -//Given cell, cont_cell, and shareable_components, returns true if -//cell is shareable (as determined by shareable_components) and is not -//a continuous cell -fn share_filter(cell: &ir::Cell, shareable: &HashSet) -> bool { - if let Some(type_name) = cell.type_name() { - shareable.contains(type_name) - } else { - false } } @@ -100,49 +84,10 @@ impl ShareComponents for MinimizeRegs { self.state_shareable.clone(), self.shareable.clone(), ); - - //Following code is from resource_sharing pass - let group_uses = comp.groups.iter().map(|group| { - ( - group.clone_name(), - ReadWriteSet::uses(group.borrow().assignments.iter()) - .filter(|cell| { - share_filter(&cell.borrow(), &self.shareable) - }) - .map(|cell| cell.clone_name()) - .collect::>(), - ) - }); - let cg_uses = comp.comb_groups.iter().map(|cg| { - ( - cg.clone_name(), - ReadWriteSet::uses(cg.borrow().assignments.iter()) - .filter(|cell| { - share_filter(&cell.borrow(), &self.shareable) - }) - .map(|cell| cell.clone_name()) - .collect::>(), - ) - }); - self.used_cells_map = group_uses.chain(cg_uses).collect(); } fn lookup_group_conflicts(&self, group_name: &ir::Id) -> Vec { - let mut state_shareable: Vec = - self.live.get(group_name).iter().cloned().collect(); - - //resource-sharing code - let shareable = self - .used_cells_map - .get(group_name) - .unwrap_or_else(|| { - panic!("Missing used cells for group: {}", group_name) - }) - .clone(); - - state_shareable.extend(shareable); - - state_shareable + self.live.get(group_name).iter().cloned().collect() } fn cell_filter(&self, cell: &ir::Cell) -> bool { @@ -161,11 +106,6 @@ impl ShareComponents for MinimizeRegs { let conflicts = self.live.get(group.borrow().name()); add_conflicts(conflicts.iter().cloned().collect()); } - - //resource-sharing code - for used in self.used_cells_map.values() { - add_conflicts(used.clone()) - } } fn set_rewrites(&mut self, rewrites: HashMap>) { diff --git a/tests/passes/general_share/was_minimize_regs/condition-register.expect b/tests/passes/general_share/was_minimize_regs/condition-register.expect new file mode 100644 index 0000000000..e9202b6184 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/condition-register.expect @@ -0,0 +1,32 @@ +import "primitives/core.futil"; +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 { + x.in = 1'd1; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + group wr_y { + y.in = 1'd1; + y.write_en = 1'd1; + wr_y[done] = y.done; + } + group rd_y { + rd_y[done] = y.out; + } + } + + control { + seq { + wr_x; + wr_y; + if x.out { + rd_y; + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/condition-register.futil b/tests/passes/general_share/was_minimize_regs/condition-register.futil new file mode 100644 index 0000000000..c519cdb3e3 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/condition-register.futil @@ -0,0 +1,37 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; +component main() -> () { + cells { + x = std_reg(1); + y = std_reg(1); + } + + wires { + group wr_x { + x.in = 1'd1; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + + group wr_y { + y.in = 1'd1; + y.write_en = 1'd1; + wr_y[done] = y.done; + } + + group rd_y { + rd_y[done] = y.out; + } + + } + + control { + seq { + wr_x; // writes to x + wr_y; // writes to y + if x.out { // reads x + rd_y; // reads y + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/continuous-assignment.expect b/tests/passes/general_share/was_minimize_regs/continuous-assignment.expect new file mode 100644 index 0000000000..3bae36d4f3 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/continuous-assignment.expect @@ -0,0 +1,27 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (x_out: 32, @done done: 1) { + cells { + x_0 = std_reg(32); + y_0 = std_reg(32); + } + wires { + group let0<"static"=1> { + x_0.in = 32'd1; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1<"static"=1> { + y_0.in = 32'd2; + y_0.write_en = 1'd1; + let1[done] = y_0.done; + } + x_out = x_0.out; + } + + control { + seq { + let0; + let1; + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/continuous-assignment.futil b/tests/passes/general_share/was_minimize_regs/continuous-assignment.futil new file mode 100644 index 0000000000..edfa115196 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/continuous-assignment.futil @@ -0,0 +1,27 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; +component main() -> (x_out: 32) { + cells { + x_0 = std_reg(32); + y_0 = std_reg(32); + } + wires { + group let0<"static"=1> { + x_0.in = 32'd1; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1<"static"=1> { + y_0.in = 32'd2; + y_0.write_en = 1'd1; + let1[done] = y_0.done; + } + x_out = x_0.out; + } + control { + seq { + let0; + let1; + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/escape-boundary.expect b/tests/passes/general_share/was_minimize_regs/escape-boundary.expect new file mode 100644 index 0000000000..bdd1ff06a0 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/escape-boundary.expect @@ -0,0 +1,26 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (x_out: 32, @done done: 1) { + cells { + x_0 = std_reg(32); + y_0 = std_reg(32); + } + wires { + group let0<"static"=1> { + x_0.in = 32'd1; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1<"static"=1> { + y_0.in = 32'd2; + y_0.write_en = 1'd1; + let1[done] = y_0.done; + } + } + + control { + par { + let0; + let1; + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/escape-boundary.futil b/tests/passes/general_share/was_minimize_regs/escape-boundary.futil new file mode 100644 index 0000000000..99f842abf3 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/escape-boundary.futil @@ -0,0 +1,26 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; +component main() -> (x_out: 32) { + cells { + x_0 = std_reg(32); + y_0 = std_reg(32); + } + wires { + group let0<"static"=1> { + x_0.in = 32'd1; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1<"static"=1> { + y_0.in = 32'd2; + y_0.write_en = 1'd1; + let1[done] = y_0.done; + } + } + control { + par { + let0; + let1; + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/invoke.expect b/tests/passes/general_share/was_minimize_regs/invoke.expect new file mode 100644 index 0000000000..599d2e5956 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/invoke.expect @@ -0,0 +1,58 @@ +import "primitives/core.futil"; +component add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + adder = std_add(32); + outpt = std_reg(32); + } + wires { + group do_add { + adder.left = left; + adder.right = right; + outpt.in = adder.out; + outpt.write_en = 1'd1; + do_add[done] = outpt.done; + } + } + + control { + seq { + do_add; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + x = std_reg(32); + @external add_x = std_add(32); + my_add = add(); + } + wires { + group wr_x { + x.in = 32'd1; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + group rd_x { + add_x.left = x.out; + add_x.right = x.out; + rd_x[done] = x.done; + } + group wr_y { + x.in = 32'd10; + x.write_en = 1'd1; + wr_y[done] = x.done; + } + } + + control { + seq { + wr_x; + rd_x; + wr_y; + invoke my_add( + left = x.out, + right = x.out + )(); + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/invoke.futil b/tests/passes/general_share/was_minimize_regs/invoke.futil new file mode 100644 index 0000000000..db04cc8718 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/invoke.futil @@ -0,0 +1,58 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; + +component add(left: 32, right: 32) -> (out: 32) { + cells { + adder = std_add(32); + outpt = std_reg(32); + } + wires { + group do_add { + adder.left = left; + adder.right = right; + outpt.in = adder.out; + outpt.write_en = 1'd1; + do_add[done] = outpt.done; + } + } + control { + seq { + do_add; + } + } +} + +component main() -> () { + cells { + x = std_reg(32); + @external add_x = std_add(32); + + my_add = add(); + y = std_reg(32); + } + wires { + group wr_x { + x.in = 32'd1; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + group rd_x { + add_x.left = x.out; + add_x.right = x.out; + rd_x[done] = x.done; // XXX: This is wrong functionally + } + group wr_y { + y.in = 32'd10; + y.write_en = 1'd1; + wr_y[done] = y.done; + } + } + control { + seq { + wr_x; + rd_x; + wr_y; + invoke my_add(left = y.out, right = y.out)(); + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/live-register-analysis.expect b/tests/passes/general_share/was_minimize_regs/live-register-analysis.expect new file mode 100644 index 0000000000..341235da02 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/live-register-analysis.expect @@ -0,0 +1,127 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + @external A0 = std_mem_d1(32, 32, 6); + A_read0_0 = std_reg(32); + @external B0 = std_mem_d1(32, 32, 6); + B_read0_0 = std_reg(32); + @external C0 = std_mem_d1(32, 32, 6); + add0 = std_add(6); + i0 = std_reg(6); + le0 = std_le(6); + @generated comb_reg = std_reg(1); + } + wires { + group let0<"static"=1> { + i0.in = 6'd0; + i0.write_en = 1'd1; + let0[done] = i0.done; + } + group let1<"static"=1> { + i0.in = 6'd0; + i0.write_en = 1'd1; + let1[done] = i0.done; + } + group upd0<"static"=1> { + A_read0_0.write_en = 1'd1; + A0.addr0 = i0.out; + A_read0_0.in = A0.read_data; + upd0[done] = A_read0_0.done; + } + group upd1<"static"=1> { + C0.addr0 = i0.out; + C0.write_en = 1'd1; + C0.write_data = A_read0_0.out; + upd1[done] = C0.done; + } + group upd2<"static"=1> { + B_read0_0.write_en = 1'd1; + B0.addr0 = i0.out; + B_read0_0.in = B0.read_data; + upd2[done] = B_read0_0.done; + } + group upd3<"static"=1> { + A0.addr0 = i0.out; + A0.write_en = 1'd1; + A0.write_data = B_read0_0.out; + upd3[done] = A0.done; + } + group upd4<"static"=1> { + i0.write_en = 1'd1; + add0.left = i0.out; + add0.right = 6'd1; + i0.in = add0.out; + upd4[done] = i0.done; + } + group upd5<"static"=1> { + A_read0_0.write_en = 1'd1; + C0.addr0 = i0.out; + A_read0_0.in = C0.read_data; + upd5[done] = A_read0_0.done; + } + group upd6<"static"=1> { + B0.addr0 = i0.out; + B0.write_en = 1'd1; + B0.write_data = A_read0_0.out; + upd6[done] = B0.done; + } + group upd7<"static"=1> { + i0.write_en = 1'd1; + add0.left = i0.out; + add0.right = 6'd1; + i0.in = add0.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> { + le0.left = i0.out; + le0.right = 6'd31; + comb_reg.in = le0.out; + comb_reg.write_en = 1'd1; + cond10[done] = comb_reg.done ? 1'd1; + } + } + + control { + seq { + let0; + seq { + cond00; + while comb_reg.out { + seq { + seq { + upd0; + par { + upd1; + upd2; + } + upd3; + upd4; + } + cond00; + } + } + } + let1; + seq { + cond10; + while comb_reg.out { + seq { + seq { + upd5; + upd6; + upd7; + } + cond10; + } + } + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/live-register-analysis.fuse b/tests/passes/general_share/was_minimize_regs/live-register-analysis.fuse new file mode 100644 index 0000000000..1a3349420a --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/live-register-analysis.fuse @@ -0,0 +1,14 @@ +// swap the contents of A and B + +decl A: ubit<32>[32]; +decl B: ubit<32>[32]; +decl C: ubit<32>[32]; + +for (let i: ubit<6> = 0..32) { + C[i] := A[i]; + A[i] := B[i]; +} + +for (let i: ubit<6> = 0..32) { + B[i] := C[i]; +} diff --git a/tests/passes/general_share/was_minimize_regs/live-register-analysis.futil b/tests/passes/general_share/was_minimize_regs/live-register-analysis.futil new file mode 100644 index 0000000000..d1dab7c962 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/live-register-analysis.futil @@ -0,0 +1,112 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; +component main() -> () { + cells { + @external(1) A0 = std_mem_d1(32,32,6); + A_read0_0 = std_reg(32); + @external(1) B0 = std_mem_d1(32,32,6); + B_read0_0 = std_reg(32); + @external(1) C0 = std_mem_d1(32,32,6); + C_read0_0 = std_reg(32); + add0 = std_add(6); + add1 = std_add(6); + i0 = std_reg(6); + i1 = std_reg(6); + le0 = std_le(6); + le1 = std_le(6); + } + wires { + comb group cond0 { + le0.left = i0.out; + le0.right = 6'd31; + } + comb group cond1 { + le1.left = i1.out; + le1.right = 6'd31; + } + group let0<"static"=1> { + i0.in = 6'd0; + i0.write_en = 1'd1; + let0[done] = i0.done; + } + group let1<"static"=1> { + i1.in = 6'd0; + i1.write_en = 1'd1; + let1[done] = i1.done; + } + group upd0<"static"=1> { + A_read0_0.write_en = 1'd1; + A0.addr0 = i0.out; + A_read0_0.in = A0.read_data; + upd0[done] = A_read0_0.done; + } + group upd1<"static"=1> { + C0.addr0 = i0.out; + C0.write_en = 1'd1; + C0.write_data = A_read0_0.out; + upd1[done] = C0.done; + } + group upd2<"static"=1> { + B_read0_0.write_en = 1'd1; + B0.addr0 = i0.out; + B_read0_0.in = B0.read_data; + upd2[done] = B_read0_0.done; + } + group upd3<"static"=1> { + A0.addr0 = i0.out; + A0.write_en = 1'd1; + A0.write_data = B_read0_0.out; + upd3[done] = A0.done; + } + group upd4<"static"=1> { + i0.write_en = 1'd1; + add0.left = i0.out; + add0.right = 6'd1; + i0.in = add0.out; + upd4[done] = i0.done; + } + group upd5<"static"=1> { + C_read0_0.write_en = 1'd1; + C0.addr0 = i1.out; + C_read0_0.in = C0.read_data; + upd5[done] = C_read0_0.done; + } + group upd6<"static"=1> { + B0.addr0 = i1.out; + B0.write_en = 1'd1; + B0.write_data = C_read0_0.out; + upd6[done] = B0.done; + } + group upd7<"static"=1> { + i1.write_en = 1'd1; + add1.left = i1.out; + add1.right = 6'd1; + i1.in = add1.out; + upd7[done] = i1.done; + } + } + control { + seq { + let0; + while le0.out with cond0 { + seq { + upd0; + par { + upd1; + upd2; + } + upd3; + upd4; + } + } + let1; + while le1.out with cond1 { + seq { + upd5; + upd6; + upd7; + } + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/nested-par.expect b/tests/passes/general_share/was_minimize_regs/nested-par.expect new file mode 100644 index 0000000000..01e242bf89 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/nested-par.expect @@ -0,0 +1,74 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + b0 = std_reg(32); + before0 = std_reg(4); + @external read_x0 = std_add(4); + b1 = std_reg(32); + before1 = std_reg(4); + @external read_x1 = std_add(4); + } + wires { + group wr_before0<"static"=1> { + before0.in = 4'd1; + before0.write_en = 1'd1; + wr_before0[done] = before0.done; + } + group wr_x0<"static"=1> { + before0.in = 4'd1; + before0.write_en = 1'd1; + wr_x0[done] = before0.done; + } + group wr_b0<"static"=1> { + b0.in = 32'd1; + b0.write_en = 1'd1; + wr_b0[done] = b0.done; + } + group rd_x0 { + read_x0.right = before0.out; + read_x0.left = before0.out; + rd_x0[done] = before0.done; + } + group wr_before1<"static"=1> { + before1.in = 4'd1; + before1.write_en = 1'd1; + wr_before1[done] = before1.done; + } + group wr_x1<"static"=1> { + before1.in = 4'd1; + before1.write_en = 1'd1; + wr_x1[done] = before1.done; + } + group wr_b1<"static"=1> { + b1.in = 32'd1; + b1.write_en = 1'd1; + wr_b1[done] = b1.done; + } + group rd_x1 { + read_x1.right = before1.out; + read_x1.left = before1.out; + rd_x1[done] = before1.done; + } + } + + control { + par { + seq { + wr_before0; + par { + wr_x0; + wr_b0; + } + rd_x0; + } + seq { + wr_before1; + par { + wr_x1; + wr_b1; + } + rd_x1; + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/nested-par.futil b/tests/passes/general_share/was_minimize_regs/nested-par.futil new file mode 100644 index 0000000000..a9a3dc9978 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/nested-par.futil @@ -0,0 +1,78 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; +component main() -> () { + cells { + b0 = std_reg(32); + before0 = std_reg(4); + x0 = std_reg(4); + @external read_x0 = std_add(4); + + b1 = std_reg(32); + before1 = std_reg(4); + x1 = std_reg(4); + @external read_x1 = std_add(4); + } + wires { + group wr_before0<"static"=1> { + before0.in = 4'd1; + before0.write_en = 1'd1; + wr_before0[done] = before0.done; + } + group wr_x0<"static"=1> { + x0.in = 4'd1; + x0.write_en = 1'd1; + wr_x0[done] = x0.done; + } + group wr_b0<"static"=1> { + b0.in = 32'd1; + b0.write_en = 1'd1; + wr_b0[done] = b0.done; + } + group rd_x0 { + read_x0.right = x0.out; + read_x0.left = x0.out; + rd_x0[done] = x0.done; // XXX: This is functionally wrong + } + + group wr_before1<"static"=1> { + before1.in = 4'd1; + before1.write_en = 1'd1; + wr_before1[done] = before1.done; + } + group wr_x1<"static"=1> { + x1.in = 4'd1; + x1.write_en = 1'd1; + wr_x1[done] = x1.done; + } + group wr_b1<"static"=1> { + b1.in = 32'd1; + b1.write_en = 1'd1; + wr_b1[done] = b1.done; + } + group rd_x1 { + read_x1.right = x1.out; + read_x1.left = x1.out; + rd_x1[done] = x1.done; // XXX: This is functionally wrong + } + } + control { + par { + seq { + wr_before0; + par { + wr_x0; + wr_b0; + } + rd_x0; + } + seq { + wr_before1; + par { + wr_x1; + wr_b1; + } + rd_x1; + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/par-while-liveness.expect b/tests/passes/general_share/was_minimize_regs/par-while-liveness.expect new file mode 100644 index 0000000000..940f37dfd0 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/par-while-liveness.expect @@ -0,0 +1,175 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + @external a_src0 = std_mem_d1(32, 8, 4); + a_src_read0_0 = std_reg(32); + @external a_tar0 = std_mem_d1(32, 8, 4); + add0 = std_add(4); + add1 = std_add(4); + @external b_src0 = std_mem_d1(32, 8, 4); + b_src_read0_0 = std_reg(32); + @external b_tar0 = std_mem_d1(32, 8, 4); + @external c_src0 = std_mem_d1(32, 8, 4); + @external c_tar0 = std_mem_d1(32, 8, 4); + const0 = std_const(4, 0); + const1 = std_const(4, 7); + const2 = std_const(4, 1); + const3 = std_const(4, 0); + const4 = std_const(4, 7); + const5 = std_const(4, 1); + i0 = std_reg(4); + i1 = std_reg(4); + le0 = std_le(4); + le1 = std_le(4); + @generated comb_reg = std_reg(1); + @generated comb_reg0 = std_reg(1); + } + wires { + group let0<"static"=1> { + i0.in = const0.out; + i0.write_en = 1'd1; + let0[done] = i0.done; + } + group let1<"static"=1> { + i1.in = const3.out; + i1.write_en = 1'd1; + let1[done] = i1.done; + } + group let2<"static"=1> { + i0.in = const0.out; + i0.write_en = 1'd1; + let2[done] = i0.done; + } + group upd0<"static"=1> { + a_src_read0_0.write_en = 1'd1; + a_src0.addr0 = i0.out; + a_src_read0_0.in = a_src0.read_data; + upd0[done] = a_src_read0_0.done ? 1'd1; + } + group upd1<"static"=1> { + a_tar0.addr0 = i0.out; + a_tar0.write_en = 1'd1; + a_tar0.write_data = a_src_read0_0.out; + upd1[done] = a_tar0.done ? 1'd1; + } + group upd2<"static"=1> { + i0.write_en = 1'd1; + add0.left = i0.out; + add0.right = const2.out; + i0.in = add0.out; + upd2[done] = i0.done ? 1'd1; + } + group upd3<"static"=1> { + b_src_read0_0.write_en = 1'd1; + b_src0.addr0 = i1.out; + b_src_read0_0.in = b_src0.read_data; + upd3[done] = b_src_read0_0.done ? 1'd1; + } + group upd4<"static"=1> { + b_tar0.addr0 = i1.out; + b_tar0.write_en = 1'd1; + b_tar0.write_data = b_src_read0_0.out; + upd4[done] = b_tar0.done ? 1'd1; + } + group upd5<"static"=1> { + i1.write_en = 1'd1; + add1.left = i1.out; + add1.right = const5.out; + i1.in = add1.out; + upd5[done] = i1.done ? 1'd1; + } + group upd6<"static"=1> { + a_src_read0_0.write_en = 1'd1; + c_tar0.addr0 = i0.out; + a_src_read0_0.in = c_tar0.read_data; + upd6[done] = a_src_read0_0.done ? 1'd1; + } + group upd7<"static"=1> { + c_src0.addr0 = i0.out; + c_src0.write_en = 1'd1; + c_src0.write_data = a_src_read0_0.out; + upd7[done] = c_src0.done ? 1'd1; + } + group upd8<"static"=1> { + i0.write_en = 1'd1; + add0.left = i0.out; + add0.right = const2.out; + i0.in = add0.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> { + le0.left = i0.out; + le0.right = const1.out; + comb_reg.in = le0.out; + comb_reg.write_en = 1'd1; + cond20[done] = comb_reg.done ? 1'd1; + } + } + + control { + seq { + par { + seq { + let0; + seq { + cond00; + while comb_reg.out { + seq { + seq { + upd0; + upd1; + upd2; + } + cond00; + } + } + } + } + seq { + let1; + seq { + cond10; + while comb_reg0.out { + seq { + seq { + upd3; + upd4; + upd5; + } + cond10; + } + } + } + } + } + let2; + seq { + cond20; + while comb_reg.out { + seq { + seq { + upd6; + upd7; + upd8; + } + cond20; + } + } + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/par-while-liveness.futil b/tests/passes/general_share/was_minimize_regs/par-while-liveness.futil new file mode 100644 index 0000000000..f3c21200ea --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/par-while-liveness.futil @@ -0,0 +1,153 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; +component main() -> () { + cells { + @external(1) a_src0 = std_mem_d1(32,8,4); + a_src_read0_0 = std_reg(32); + @external(1) a_tar0 = std_mem_d1(32,8,4); + add0 = std_add(4); + add1 = std_add(4); + add2 = std_add(4); + @external(1) b_src0 = std_mem_d1(32,8,4); + b_src_read0_0 = std_reg(32); + @external(1) b_tar0 = std_mem_d1(32,8,4); + @external(1) c_src0 = std_mem_d1(32,8,4); + @external(1) c_tar0 = std_mem_d1(32,8,4); + c_tar_read0_0 = std_reg(32); + const0 = std_const(4,0); + const1 = std_const(4,7); + const2 = std_const(4,1); + const3 = std_const(4,0); + const4 = std_const(4,7); + const5 = std_const(4,1); + const6 = std_const(4,0); + const7 = std_const(4,7); + const8 = std_const(4,1); + i0 = std_reg(4); + i1 = std_reg(4); + i2 = std_reg(4); + le0 = std_le(4); + le1 = std_le(4); + le2 = std_le(4); + } + wires { + comb group cond0 { + le0.left = i0.out; + le0.right = const1.out; + } + comb group cond1 { + le1.left = i1.out; + le1.right = const4.out; + } + comb group cond2 { + le2.left = i2.out; + le2.right = const7.out; + } + group let0<"static"=1> { + i0.in = const0.out; + i0.write_en = 1'd1; + let0[done] = i0.done; + } + group let1<"static"=1> { + i1.in = const3.out; + i1.write_en = 1'd1; + let1[done] = i1.done; + } + group let2<"static"=1> { + i2.in = const6.out; + i2.write_en = 1'd1; + let2[done] = i2.done; + } + group upd0<"static"=1> { + a_src_read0_0.write_en = 1'd1; + a_src0.addr0 = i0.out; + a_src_read0_0.in = 1'd1 ? a_src0.read_data; + upd0[done] = a_src_read0_0.done ? 1'd1; + } + group upd1<"static"=1> { + a_tar0.addr0 = i0.out; + a_tar0.write_en = 1'd1; + a_tar0.write_data = 1'd1 ? a_src_read0_0.out; + upd1[done] = a_tar0.done ? 1'd1; + } + group upd2<"static"=1> { + i0.write_en = 1'd1; + add0.left = i0.out; + add0.right = const2.out; + i0.in = 1'd1 ? add0.out; + upd2[done] = i0.done ? 1'd1; + } + group upd3<"static"=1> { + b_src_read0_0.write_en = 1'd1; + b_src0.addr0 = i1.out; + b_src_read0_0.in = 1'd1 ? b_src0.read_data; + upd3[done] = b_src_read0_0.done ? 1'd1; + } + group upd4<"static"=1> { + b_tar0.addr0 = i1.out; + b_tar0.write_en = 1'd1; + b_tar0.write_data = 1'd1 ? b_src_read0_0.out; + upd4[done] = b_tar0.done ? 1'd1; + } + group upd5<"static"=1> { + i1.write_en = 1'd1; + add1.left = i1.out; + add1.right = const5.out; + i1.in = 1'd1 ? add1.out; + upd5[done] = i1.done ? 1'd1; + } + group upd6<"static"=1> { + c_tar_read0_0.write_en = 1'd1; + c_tar0.addr0 = i2.out; + c_tar_read0_0.in = 1'd1 ? c_tar0.read_data; + upd6[done] = c_tar_read0_0.done ? 1'd1; + } + group upd7<"static"=1> { + c_src0.addr0 = i2.out; + c_src0.write_en = 1'd1; + c_src0.write_data = 1'd1 ? c_tar_read0_0.out; + upd7[done] = c_src0.done ? 1'd1; + } + group upd8<"static"=1> { + i2.write_en = 1'd1; + add2.left = i2.out; + add2.right = const8.out; + i2.in = 1'd1 ? add2.out; + upd8[done] = i2.done ? 1'd1; + } + } + control { + seq { + par { + seq { + let0; + while le0.out with cond0 { + seq { + upd0; + upd1; + upd2; + } + } + } + seq { + let1; + while le1.out with cond1 { + seq { + upd3; + upd4; + upd5; + } + } + } + } + let2; + while le2.out with cond2 { + seq { + upd6; + upd7; + upd8; + } + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/par-write.expect b/tests/passes/general_share/was_minimize_regs/par-write.expect new file mode 100644 index 0000000000..f3a4a26ad6 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/par-write.expect @@ -0,0 +1,26 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + x = std_reg(32); + y = std_reg(32); + } + wires { + group wr_x { + x.in = 32'd1; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + group wr_y { + y.in = 32'd2; + y.write_en = 1'd1; + wr_y[done] = y.done; + } + } + + control { + par { + wr_x; + wr_y; + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/par-write.futil b/tests/passes/general_share/was_minimize_regs/par-write.futil new file mode 100644 index 0000000000..b99210fdcb --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/par-write.futil @@ -0,0 +1,27 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; + +component main() -> () { + cells { + x = std_reg(32); + y = std_reg(32); + } + wires { + group wr_x { + x.in = 32'd1; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + group wr_y { + y.in = 32'd2; + y.write_en = 1'd1; + wr_y[done] = y.done; + } + } + control { + par { + wr_x; + wr_y; + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/simple-liveness.expect b/tests/passes/general_share/was_minimize_regs/simple-liveness.expect new file mode 100644 index 0000000000..f2e4c208da --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/simple-liveness.expect @@ -0,0 +1,41 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + b = std_reg(32); + before = std_reg(4); + @external read_x = std_add(4); + } + wires { + group wr_before<"static"=1> { + before.in = 4'd1; + before.write_en = 1'd1; + wr_before[done] = before.done; + } + group wr_x<"static"=1> { + before.in = 4'd1; + before.write_en = 1'd1; + wr_x[done] = before.done; + } + group wr_b<"static"=1> { + b.in = 32'd1; + b.write_en = 1'd1; + wr_b[done] = b.done; + } + group rd_x<"static"=1> { + read_x.right = before.out; + read_x.left = before.out; + rd_x[done] = before.done; + } + } + + control { + seq { + wr_before; + par { + wr_x; + wr_b; + } + rd_x; + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/simple-liveness.futil b/tests/passes/general_share/was_minimize_regs/simple-liveness.futil new file mode 100644 index 0000000000..17215282a6 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/simple-liveness.futil @@ -0,0 +1,42 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; +component main() -> () { + cells { + b = std_reg(32); + before = std_reg(4); + x = std_reg(4); + @external read_x = std_add(4); + } + wires { + group wr_before<"static"=1> { + before.in = 4'd1; + before.write_en = 1'd1; + wr_before[done] = before.done; + } + group wr_x<"static"=1> { + x.in = 4'd1; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + group wr_b<"static"=1> { + b.in = 32'd1; + b.write_en = 1'd1; + wr_b[done] = b.done; + } + group rd_x<"static"=1> { + read_x.right = x.out; + read_x.left = x.out; + rd_x[done] = x.done; // XXX: This is functionally incorrect + } + } + control { + seq { + wr_before; + par { + wr_x; + wr_b; + } + rd_x; + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/thread-local.expect b/tests/passes/general_share/was_minimize_regs/thread-local.expect new file mode 100644 index 0000000000..7b7fb9504b --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/thread-local.expect @@ -0,0 +1,46 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + x = std_reg(32); + y = std_reg(32); + @external add_x = std_add(32); + @external add_y = std_add(32); + } + wires { + group wr_x { + x.in = 32'd2; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + group rd_x { + add_x.left = x.out; + add_x.right = x.out; + rd_x[done] = x.done; + } + group wr_y { + y.in = 32'd4; + y.write_en = 1'd1; + wr_y[done] = y.done; + } + group rd_y { + add_y.left = y.out; + add_y.right = y.out; + rd_y[done] = y.done; + } + } + + control { + seq { + par { + seq { + wr_x; + rd_x; + } + seq { + wr_y; + rd_y; + } + } + } + } +} diff --git a/tests/passes/general_share/was_minimize_regs/thread-local.futil b/tests/passes/general_share/was_minimize_regs/thread-local.futil new file mode 100644 index 0000000000..1e5db45804 --- /dev/null +++ b/tests/passes/general_share/was_minimize_regs/thread-local.futil @@ -0,0 +1,48 @@ +// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +import "primitives/core.futil"; + +component main() -> () { + cells { + x = std_reg(32); + y = std_reg(32); + @external add_x = std_add(32); + @external add_y = std_add(32); + } + + wires { + group wr_x { + x.in = 32'd2; + x.write_en = 1'd1; + wr_x[done] = x.done; + } + + group rd_x { + add_x.left = x.out; + add_x.right = x.out; + rd_x[done] = x.done; // XXX: This is functionally wrong + } + + group wr_y { + y.in = 32'd4; + y.write_en = 1'd1; + wr_y[done] = y.done; + } + + group rd_y { + add_y.left = y.out; + add_y.right = y.out; + rd_y[done] = y.done; // XXX: This is functionally wrong + } + } + + control { + seq { + par { + // thread local use of x + seq { wr_x; rd_x; } + // this should stay y + seq { wr_y; rd_y; } + } + } + } +} diff --git a/tests/passes/general_share/was_resource_share/cond-port.expect b/tests/passes/general_share/was_resource_share/cond-port.expect new file mode 100644 index 0000000000..5cedbb0a11 --- /dev/null +++ b/tests/passes/general_share/was_resource_share/cond-port.expect @@ -0,0 +1,49 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + gt0 = std_gt(32); + gt1 = std_gt(32); + x_0 = std_reg(32); + y_0 = std_reg(1); + @generated comb_reg = std_reg(1); + } + wires { + group let0 { + x_0.in = 32'd1; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1 { + y_0.in = gt0.out; + y_0.write_en = 1'd1; + let1[done] = y_0.done; + gt0.left = x_0.out; + gt0.right = 32'd1; + } + group upd0 { + x_0.write_en = 1'd1; + 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; + y_0.in = gt0.out; + y_0.write_en = 1'd1; + cond00[done] = y_0.done ? 1'd1; + } + } + + control { + seq { + let0; + let1; + seq { + cond00; + if y_0.out { + upd0; + } + } + } + } +} diff --git a/tests/passes/general_share/was_resource_share/cond-port.futil b/tests/passes/general_share/was_resource_share/cond-port.futil new file mode 100644 index 0000000000..1c6b454df6 --- /dev/null +++ b/tests/passes/general_share/was_resource_share/cond-port.futil @@ -0,0 +1,43 @@ +// -p remove-comb-groups -p minimize-regs +import "primitives/core.futil"; +component main() -> () { + cells { + gt0 = std_gt(32); + gt1 = std_gt(32); + x_0 = std_reg(32); + y_0 = std_reg(1); + } + wires { + comb group cond0 { + gt1.left = x_0.out; + gt1.right = 32'd2; + } + group let0 { + x_0.in = 32'd1; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1 { + y_0.in = gt0.out; + y_0.write_en = 1'd1; + let1[done] = y_0.done; + gt0.left = x_0.out; + gt0.right = 32'd1; + } + group upd0 { + x_0.write_en = 1'd1; + x_0.in = 1'd1 ? 32'd10; + upd0[done] = x_0.done ? 1'd1; + } + } + control { + seq { + let0; + let1; + if gt1.out with cond0 { + upd0; + } + } + } +} + diff --git a/tests/passes/general_share/was_resource_share/continuous-assign.expect b/tests/passes/general_share/was_resource_share/continuous-assign.expect new file mode 100644 index 0000000000..6a5bb4d6da --- /dev/null +++ b/tests/passes/general_share/was_resource_share/continuous-assign.expect @@ -0,0 +1,17 @@ +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r0 = std_reg(32); + r1 = std_reg(32); + add0 = std_add(32); + add1 = std_add(32); + } + wires { + done = r0.done; + add1.left = r0.out; + add0.left = r0.out; + } + + control {} +} diff --git a/tests/passes/general_share/was_resource_share/continuous-assign.futil b/tests/passes/general_share/was_resource_share/continuous-assign.futil new file mode 100644 index 0000000000..ba758bb7ca --- /dev/null +++ b/tests/passes/general_share/was_resource_share/continuous-assign.futil @@ -0,0 +1,18 @@ +// -p validate -p minimize-regs +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r0 = std_reg(32); + r1 = std_reg(32); + add0 = std_add(32); + add1 = std_add(32); + } + wires { + add0.left = r1.out; + add1.left = r0.out; + done = r0.done; + } + + control { } +} diff --git a/tests/passes/general_share/was_resource_share/multiple-cells.expect b/tests/passes/general_share/was_resource_share/multiple-cells.expect new file mode 100644 index 0000000000..f2f0e89cc4 --- /dev/null +++ b/tests/passes/general_share/was_resource_share/multiple-cells.expect @@ -0,0 +1,37 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add0 = std_add(32); + add1 = std_add(32); + add2 = std_add(32); + add3 = std_add(32); + x_0 = std_reg(32); + } + wires { + group let0<"static"=1> { + add0.left = 32'd1; + add0.right = 32'd2; + add1.right = 32'd3; + add1.left = add0.out; + x_0.in = add1.out; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1<"static"=1> { + add0.left = 32'd1; + add0.right = 32'd2; + add1.right = 32'd3; + add1.left = add0.out; + x_0.in = add1.out; + x_0.write_en = 1'd1; + let1[done] = x_0.done; + } + } + + control { + seq { + let0; + let1; + } + } +} diff --git a/tests/passes/general_share/was_resource_share/multiple-cells.futil b/tests/passes/general_share/was_resource_share/multiple-cells.futil new file mode 100644 index 0000000000..8373d0d8b6 --- /dev/null +++ b/tests/passes/general_share/was_resource_share/multiple-cells.futil @@ -0,0 +1,37 @@ +// -p minimize-regs +import "primitives/core.futil"; +component main() -> () { + cells { + add0 = std_add(32); + add1 = std_add(32); + add2 = std_add(32); + add3 = std_add(32); + x_0 = std_reg(32); + } + wires { + group let0<"static"=1> { + add0.left = 32'd1; + add0.right = 32'd2; + add1.right = 32'd3; + add1.left = add0.out; + x_0.in = add1.out; + x_0.write_en = 1'd1; + let0[done] = x_0.done; + } + group let1<"static"=1> { + add2.left = 32'd1; + add2.right = 32'd2; + add3.right = 32'd3; + add3.left = add2.out; + x_0.in = add3.out; + x_0.write_en = 1'd1; + let1[done] = x_0.done; + } + } + control { + seq { + let0; + let1; + } + } +} diff --git a/tests/passes/general_share/was_resource_share/share-component.expect b/tests/passes/general_share/was_resource_share/share-component.expect new file mode 100644 index 0000000000..8c271b756f --- /dev/null +++ b/tests/passes/general_share/was_resource_share/share-component.expect @@ -0,0 +1,43 @@ +import "primitives/core.futil"; +component my_add<"share"=1>(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + add = std_add(32); + } + wires { + add.left = left; + add.right = right; + out = add.out; + } + + control {} +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add0 = my_add(); + add1 = my_add(); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd0[done] = x_0.done ? 1'd1; + } + group upd1 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd1[done] = x_0.done ? 1'd1; + } + } + + control { + seq { + upd0; + upd1; + } + } +} diff --git a/tests/passes/general_share/was_resource_share/share-component.futil b/tests/passes/general_share/was_resource_share/share-component.futil new file mode 100644 index 0000000000..28cb37a8fd --- /dev/null +++ b/tests/passes/general_share/was_resource_share/share-component.futil @@ -0,0 +1,44 @@ +// -p minimize-regs + +import "primitives/core.futil"; +component my_add<"share"=1>(left: 32, right: 32) -> (out: 32) { + cells { + add = std_add(32); + } + wires { + add.left = left; + add.right = right; + out = add.out; + } + control {} +} + +component main() -> () { + cells { + add0 = my_add(); + add1 = my_add(); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd0[done] = x_0.done ? 1'd1; + } + group upd1 { + add1.left = x_0.out; + add1.right = 32'd1; + x_0.in = add1.out; + x_0.write_en = 1'd1; + upd1[done] = x_0.done ? 1'd1; + } + } + control { + seq { + upd0; + upd1; + } + } +} diff --git a/tests/passes/general_share/was_resource_share/share.expect b/tests/passes/general_share/was_resource_share/share.expect new file mode 100644 index 0000000000..16215666e0 --- /dev/null +++ b/tests/passes/general_share/was_resource_share/share.expect @@ -0,0 +1,31 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add0 = std_add(32); + add1 = std_add(32); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd0[done] = x_0.done ? 1'd1; + } + group upd1 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd1[done] = x_0.done ? 1'd1; + } + } + + control { + seq { + upd0; + upd1; + } + } +} diff --git a/tests/passes/general_share/was_resource_share/share.futil b/tests/passes/general_share/was_resource_share/share.futil new file mode 100644 index 0000000000..4146b3c2d2 --- /dev/null +++ b/tests/passes/general_share/was_resource_share/share.futil @@ -0,0 +1,32 @@ +// -p minimize-regs + +import "primitives/core.futil"; +component main() -> () { + cells { + add0 = std_add(32); + add1 = std_add(32); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.left = x_0.out; + add0.right = 32'd1; + x_0.in = add0.out; + x_0.write_en = 1'd1; + upd0[done] = x_0.done ? 1'd1; + } + group upd1 { + add1.left = x_0.out; + add1.right = 32'd1; + x_0.in = add1.out; + x_0.write_en = 1'd1; + upd1[done] = x_0.done ? 1'd1; + } + } + control { + seq { + upd0; + upd1; + } + } +} From b1975031872d74d4b55082d6259efb4f543c689b Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 17 Jun 2022 15:08:52 -0400 Subject: [PATCH 16/32] combined resource_sharing and minimize_regs --- calyx/src/analysis/live_range_analysis.rs | 25 +-- calyx/src/passes/minimize_regs.rs | 35 +++- .../continuous-assign.expect | 2 +- .../minimize-regs/condition-register.expect | 32 ---- .../minimize-regs/condition-register.futil | 37 ---- .../continuous-assignment.expect | 27 --- .../minimize-regs/continuous-assignment.futil | 27 --- .../minimize-regs/escape-boundary.expect | 26 --- .../minimize-regs/escape-boundary.futil | 26 --- tests/passes/minimize-regs/invoke.expect | 58 ------ tests/passes/minimize-regs/invoke.futil | 58 ------ .../live-register-analysis.expect | 129 ------------- .../minimize-regs/live-register-analysis.fuse | 14 -- .../live-register-analysis.futil | 112 ----------- tests/passes/minimize-regs/nested-par.expect | 74 ------- tests/passes/minimize-regs/nested-par.futil | 78 -------- .../minimize-regs/par-while-liveness.expect | 180 ------------------ .../minimize-regs/par-while-liveness.futil | 153 --------------- tests/passes/minimize-regs/par-write.expect | 26 --- tests/passes/minimize-regs/par-write.futil | 27 --- .../minimize-regs/simple-liveness.expect | 41 ---- .../minimize-regs/simple-liveness.futil | 42 ---- .../passes/minimize-regs/thread-local.expect | 46 ----- tests/passes/minimize-regs/thread-local.futil | 48 ----- .../passes/resource-sharing/cond-port.expect | 49 ----- tests/passes/resource-sharing/cond-port.futil | 43 ----- .../resource-sharing/continuous-assign.expect | 17 -- .../resource-sharing/continuous-assign.futil | 18 -- .../resource-sharing/multiple-cells.expect | 37 ---- .../resource-sharing/multiple-cells.futil | 37 ---- .../resource-sharing/share-component.expect | 43 ----- .../resource-sharing/share-component.futil | 44 ----- tests/passes/resource-sharing/share.expect | 31 --- tests/passes/resource-sharing/share.futil | 32 ---- .../was-resource-sharing/cond-port.expect | 49 ----- .../was-resource-sharing/cond-port.futil | 43 ----- .../continuous-assign.expect | 17 -- .../continuous-assign.futil | 18 -- .../multiple-cells.expect | 37 ---- .../was-resource-sharing/multiple-cells.futil | 37 ---- .../share-component.expect | 43 ----- .../share-component.futil | 44 ----- .../passes/was-resource-sharing/share.expect | 31 --- tests/passes/was-resource-sharing/share.futil | 32 ---- 44 files changed, 41 insertions(+), 1984 deletions(-) delete mode 100644 tests/passes/minimize-regs/condition-register.expect delete mode 100644 tests/passes/minimize-regs/condition-register.futil delete mode 100644 tests/passes/minimize-regs/continuous-assignment.expect delete mode 100644 tests/passes/minimize-regs/continuous-assignment.futil delete mode 100644 tests/passes/minimize-regs/escape-boundary.expect delete mode 100644 tests/passes/minimize-regs/escape-boundary.futil delete mode 100644 tests/passes/minimize-regs/invoke.expect delete mode 100644 tests/passes/minimize-regs/invoke.futil delete mode 100644 tests/passes/minimize-regs/live-register-analysis.expect delete mode 100644 tests/passes/minimize-regs/live-register-analysis.fuse delete mode 100644 tests/passes/minimize-regs/live-register-analysis.futil delete mode 100644 tests/passes/minimize-regs/nested-par.expect delete mode 100644 tests/passes/minimize-regs/nested-par.futil delete mode 100644 tests/passes/minimize-regs/par-while-liveness.expect delete mode 100644 tests/passes/minimize-regs/par-while-liveness.futil delete mode 100644 tests/passes/minimize-regs/par-write.expect delete mode 100644 tests/passes/minimize-regs/par-write.futil delete mode 100644 tests/passes/minimize-regs/simple-liveness.expect delete mode 100644 tests/passes/minimize-regs/simple-liveness.futil delete mode 100644 tests/passes/minimize-regs/thread-local.expect delete mode 100644 tests/passes/minimize-regs/thread-local.futil delete mode 100644 tests/passes/resource-sharing/cond-port.expect delete mode 100644 tests/passes/resource-sharing/cond-port.futil delete mode 100644 tests/passes/resource-sharing/continuous-assign.expect delete mode 100644 tests/passes/resource-sharing/continuous-assign.futil delete mode 100644 tests/passes/resource-sharing/multiple-cells.expect delete mode 100644 tests/passes/resource-sharing/multiple-cells.futil delete mode 100644 tests/passes/resource-sharing/share-component.expect delete mode 100644 tests/passes/resource-sharing/share-component.futil delete mode 100644 tests/passes/resource-sharing/share.expect delete mode 100644 tests/passes/resource-sharing/share.futil delete mode 100644 tests/passes/was-resource-sharing/cond-port.expect delete mode 100644 tests/passes/was-resource-sharing/cond-port.futil delete mode 100644 tests/passes/was-resource-sharing/continuous-assign.expect delete mode 100644 tests/passes/was-resource-sharing/continuous-assign.futil delete mode 100644 tests/passes/was-resource-sharing/multiple-cells.expect delete mode 100644 tests/passes/was-resource-sharing/multiple-cells.futil delete mode 100644 tests/passes/was-resource-sharing/share-component.expect delete mode 100644 tests/passes/was-resource-sharing/share-component.futil delete mode 100644 tests/passes/was-resource-sharing/share.expect delete mode 100644 tests/passes/was-resource-sharing/share.futil diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index d5c5e37e4b..afce12b81c 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -269,6 +269,7 @@ impl LiveRangeAnalysis { &mut ranges, ); + //adds (non-state) shareable cells as live in the group they're contained in comp.groups.iter().for_each(|group| { let group_uses: Prop = ReadWriteSet::uses(group.borrow().assignments.iter()) @@ -304,16 +305,6 @@ impl LiveRangeAnalysis { } }); - // add global reads to every point - let global_reads: Prop = - ReadWriteSet::read_set(comp.continuous_assignments.iter()) - .filter(|c| is_shareable_component(&ranges.state_share, &c)) - .map(|c| c.clone_name()) - .collect::>() - .into(); - for (_, prop) in ranges.live.iter_mut() { - *prop = &*prop | &global_reads; - } ranges } /// Look up the set of things live at a group definition. @@ -421,11 +412,11 @@ impl LiveRangeAnalysis { fn port_to_cell_name( port: &RRC, - state_share: &HashSet, + shareable_components: &HashSet, ) -> Option { if let ir::PortParent::Cell(cell_wref) = &port.borrow().parent { let cell = cell_wref.upgrade(); - if is_shareable_component(state_share, &cell) { + if is_shareable_component(shareable_components, &cell) { return Some(cell.borrow().clone_name()); } } @@ -435,19 +426,23 @@ impl LiveRangeAnalysis { /// Returns (reads, writes) that occur in the [ir::Invoke] statement. fn find_gen_kill_invoke( invoke: &ir::Invoke, - state_share: &HashSet, + shareable_components: &HashSet, ) -> (Prop, Prop) { let reads: Prop = invoke .inputs .iter() - .filter_map(|(_, src)| Self::port_to_cell_name(src, state_share)) + .filter_map(|(_, src)| { + Self::port_to_cell_name(src, shareable_components) + }) .collect::>() .into(); let writes: Prop = invoke .outputs .iter() - .filter_map(|(_, src)| Self::port_to_cell_name(src, state_share)) + .filter_map(|(_, src)| { + Self::port_to_cell_name(src, shareable_components) + }) .collect::>() .into(); diff --git a/calyx/src/passes/minimize_regs.rs b/calyx/src/passes/minimize_regs.rs index e4630815f0..aed138df70 100644 --- a/calyx/src/passes/minimize_regs.rs +++ b/calyx/src/passes/minimize_regs.rs @@ -1,8 +1,8 @@ use super::sharing_components::ShareComponents; use crate::errors::CalyxResult; use crate::{ - analysis::LiveRangeAnalysis, - ir::{self, traversal::ConstructVisitor, traversal::Named}, + analysis::{LiveRangeAnalysis, ReadWriteSet}, + ir::{self, traversal::ConstructVisitor, traversal::Named, CloneName}, }; use std::collections::{HashMap, HashSet}; @@ -25,8 +25,11 @@ pub struct MinimizeRegs { /// Set of state shareable components (as type names) state_shareable: HashSet, - /// Set of shareable components. + /// Set of shareable components (as type names) shareable: HashSet, + + /// Cell active in continuous assignments + cont_cells: HashSet, } impl Named for MinimizeRegs { @@ -61,6 +64,7 @@ impl ConstructVisitor for MinimizeRegs { Ok(MinimizeRegs { live: LiveRangeAnalysis::default(), rewrites: HashMap::new(), + cont_cells: HashSet::new(), state_shareable, shareable, }) @@ -69,6 +73,7 @@ impl ConstructVisitor for MinimizeRegs { fn clear_data(&mut self) { self.rewrites = HashMap::new(); self.live = LiveRangeAnalysis::default(); + self.cont_cells = HashSet::new(); } } @@ -78,6 +83,11 @@ impl ShareComponents for MinimizeRegs { comp: &ir::Component, _sigs: &ir::LibrarySignatures, ) { + self.cont_cells = + ReadWriteSet::uses(comp.continuous_assignments.iter()) + .map(|cr| cr.borrow().clone_name()) + .collect(); + self.live = LiveRangeAnalysis::new( comp, &*comp.control.borrow(), @@ -87,10 +97,19 @@ impl ShareComponents for MinimizeRegs { } fn lookup_group_conflicts(&self, group_name: &ir::Id) -> Vec { - self.live.get(group_name).iter().cloned().collect() + self.live + .get(group_name) + .iter() + .filter(|cell_name| !self.cont_cells.contains(cell_name)) + .cloned() + .collect() } fn cell_filter(&self, cell: &ir::Cell) -> bool { + // Cells used in continuous assignments cannot be shared. + if self.cont_cells.contains(cell.name()) { + return false; + } if let Some(name) = cell.type_name() { self.state_shareable.contains(name) || self.shareable.contains(name) } else { @@ -104,7 +123,13 @@ impl ShareComponents for MinimizeRegs { { for group in comp.groups.iter() { let conflicts = self.live.get(group.borrow().name()); - add_conflicts(conflicts.iter().cloned().collect()); + add_conflicts( + conflicts + .iter() + .filter(|cell_name| !self.cont_cells.contains(cell_name)) + .cloned() + .collect(), + ); } } diff --git a/tests/passes/general_share/was_resource_share/continuous-assign.expect b/tests/passes/general_share/was_resource_share/continuous-assign.expect index 6a5bb4d6da..5853bba2a7 100644 --- a/tests/passes/general_share/was_resource_share/continuous-assign.expect +++ b/tests/passes/general_share/was_resource_share/continuous-assign.expect @@ -10,7 +10,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { wires { done = r0.done; add1.left = r0.out; - add0.left = r0.out; + add0.left = r1.out; } control {} diff --git a/tests/passes/minimize-regs/condition-register.expect b/tests/passes/minimize-regs/condition-register.expect deleted file mode 100644 index e9202b6184..0000000000 --- a/tests/passes/minimize-regs/condition-register.expect +++ /dev/null @@ -1,32 +0,0 @@ -import "primitives/core.futil"; -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 { - x.in = 1'd1; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - group wr_y { - y.in = 1'd1; - y.write_en = 1'd1; - wr_y[done] = y.done; - } - group rd_y { - rd_y[done] = y.out; - } - } - - control { - seq { - wr_x; - wr_y; - if x.out { - rd_y; - } - } - } -} diff --git a/tests/passes/minimize-regs/condition-register.futil b/tests/passes/minimize-regs/condition-register.futil deleted file mode 100644 index c519cdb3e3..0000000000 --- a/tests/passes/minimize-regs/condition-register.futil +++ /dev/null @@ -1,37 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; -component main() -> () { - cells { - x = std_reg(1); - y = std_reg(1); - } - - wires { - group wr_x { - x.in = 1'd1; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - - group wr_y { - y.in = 1'd1; - y.write_en = 1'd1; - wr_y[done] = y.done; - } - - group rd_y { - rd_y[done] = y.out; - } - - } - - control { - seq { - wr_x; // writes to x - wr_y; // writes to y - if x.out { // reads x - rd_y; // reads y - } - } - } -} diff --git a/tests/passes/minimize-regs/continuous-assignment.expect b/tests/passes/minimize-regs/continuous-assignment.expect deleted file mode 100644 index 3bae36d4f3..0000000000 --- a/tests/passes/minimize-regs/continuous-assignment.expect +++ /dev/null @@ -1,27 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (x_out: 32, @done done: 1) { - cells { - x_0 = std_reg(32); - y_0 = std_reg(32); - } - wires { - group let0<"static"=1> { - x_0.in = 32'd1; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1<"static"=1> { - y_0.in = 32'd2; - y_0.write_en = 1'd1; - let1[done] = y_0.done; - } - x_out = x_0.out; - } - - control { - seq { - let0; - let1; - } - } -} diff --git a/tests/passes/minimize-regs/continuous-assignment.futil b/tests/passes/minimize-regs/continuous-assignment.futil deleted file mode 100644 index edfa115196..0000000000 --- a/tests/passes/minimize-regs/continuous-assignment.futil +++ /dev/null @@ -1,27 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; -component main() -> (x_out: 32) { - cells { - x_0 = std_reg(32); - y_0 = std_reg(32); - } - wires { - group let0<"static"=1> { - x_0.in = 32'd1; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1<"static"=1> { - y_0.in = 32'd2; - y_0.write_en = 1'd1; - let1[done] = y_0.done; - } - x_out = x_0.out; - } - control { - seq { - let0; - let1; - } - } -} diff --git a/tests/passes/minimize-regs/escape-boundary.expect b/tests/passes/minimize-regs/escape-boundary.expect deleted file mode 100644 index bdd1ff06a0..0000000000 --- a/tests/passes/minimize-regs/escape-boundary.expect +++ /dev/null @@ -1,26 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (x_out: 32, @done done: 1) { - cells { - x_0 = std_reg(32); - y_0 = std_reg(32); - } - wires { - group let0<"static"=1> { - x_0.in = 32'd1; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1<"static"=1> { - y_0.in = 32'd2; - y_0.write_en = 1'd1; - let1[done] = y_0.done; - } - } - - control { - par { - let0; - let1; - } - } -} diff --git a/tests/passes/minimize-regs/escape-boundary.futil b/tests/passes/minimize-regs/escape-boundary.futil deleted file mode 100644 index 99f842abf3..0000000000 --- a/tests/passes/minimize-regs/escape-boundary.futil +++ /dev/null @@ -1,26 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; -component main() -> (x_out: 32) { - cells { - x_0 = std_reg(32); - y_0 = std_reg(32); - } - wires { - group let0<"static"=1> { - x_0.in = 32'd1; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1<"static"=1> { - y_0.in = 32'd2; - y_0.write_en = 1'd1; - let1[done] = y_0.done; - } - } - control { - par { - let0; - let1; - } - } -} diff --git a/tests/passes/minimize-regs/invoke.expect b/tests/passes/minimize-regs/invoke.expect deleted file mode 100644 index 599d2e5956..0000000000 --- a/tests/passes/minimize-regs/invoke.expect +++ /dev/null @@ -1,58 +0,0 @@ -import "primitives/core.futil"; -component add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { - cells { - adder = std_add(32); - outpt = std_reg(32); - } - wires { - group do_add { - adder.left = left; - adder.right = right; - outpt.in = adder.out; - outpt.write_en = 1'd1; - do_add[done] = outpt.done; - } - } - - control { - seq { - do_add; - } - } -} -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - x = std_reg(32); - @external add_x = std_add(32); - my_add = add(); - } - wires { - group wr_x { - x.in = 32'd1; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - group rd_x { - add_x.left = x.out; - add_x.right = x.out; - rd_x[done] = x.done; - } - group wr_y { - x.in = 32'd10; - x.write_en = 1'd1; - wr_y[done] = x.done; - } - } - - control { - seq { - wr_x; - rd_x; - wr_y; - invoke my_add( - left = x.out, - right = x.out - )(); - } - } -} diff --git a/tests/passes/minimize-regs/invoke.futil b/tests/passes/minimize-regs/invoke.futil deleted file mode 100644 index db04cc8718..0000000000 --- a/tests/passes/minimize-regs/invoke.futil +++ /dev/null @@ -1,58 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; - -component add(left: 32, right: 32) -> (out: 32) { - cells { - adder = std_add(32); - outpt = std_reg(32); - } - wires { - group do_add { - adder.left = left; - adder.right = right; - outpt.in = adder.out; - outpt.write_en = 1'd1; - do_add[done] = outpt.done; - } - } - control { - seq { - do_add; - } - } -} - -component main() -> () { - cells { - x = std_reg(32); - @external add_x = std_add(32); - - my_add = add(); - y = std_reg(32); - } - wires { - group wr_x { - x.in = 32'd1; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - group rd_x { - add_x.left = x.out; - add_x.right = x.out; - rd_x[done] = x.done; // XXX: This is wrong functionally - } - group wr_y { - y.in = 32'd10; - y.write_en = 1'd1; - wr_y[done] = y.done; - } - } - control { - seq { - wr_x; - rd_x; - wr_y; - invoke my_add(left = y.out, right = y.out)(); - } - } -} diff --git a/tests/passes/minimize-regs/live-register-analysis.expect b/tests/passes/minimize-regs/live-register-analysis.expect deleted file mode 100644 index 42de11de68..0000000000 --- a/tests/passes/minimize-regs/live-register-analysis.expect +++ /dev/null @@ -1,129 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - @external A0 = std_mem_d1(32, 32, 6); - A_read0_0 = std_reg(32); - @external B0 = std_mem_d1(32, 32, 6); - B_read0_0 = std_reg(32); - @external C0 = std_mem_d1(32, 32, 6); - add0 = std_add(6); - add1 = std_add(6); - i0 = std_reg(6); - le0 = std_le(6); - le1 = std_le(6); - @generated comb_reg = std_reg(1); - } - wires { - group let0<"static"=1> { - i0.in = 6'd0; - i0.write_en = 1'd1; - let0[done] = i0.done; - } - group let1<"static"=1> { - i0.in = 6'd0; - i0.write_en = 1'd1; - let1[done] = i0.done; - } - group upd0<"static"=1> { - A_read0_0.write_en = 1'd1; - A0.addr0 = i0.out; - A_read0_0.in = A0.read_data; - upd0[done] = A_read0_0.done; - } - group upd1<"static"=1> { - C0.addr0 = i0.out; - C0.write_en = 1'd1; - C0.write_data = A_read0_0.out; - upd1[done] = C0.done; - } - group upd2<"static"=1> { - B_read0_0.write_en = 1'd1; - B0.addr0 = i0.out; - B_read0_0.in = B0.read_data; - upd2[done] = B_read0_0.done; - } - group upd3<"static"=1> { - A0.addr0 = i0.out; - A0.write_en = 1'd1; - A0.write_data = B_read0_0.out; - upd3[done] = A0.done; - } - group upd4<"static"=1> { - i0.write_en = 1'd1; - add0.left = i0.out; - add0.right = 6'd1; - i0.in = add0.out; - upd4[done] = i0.done; - } - group upd5<"static"=1> { - A_read0_0.write_en = 1'd1; - C0.addr0 = i0.out; - A_read0_0.in = C0.read_data; - upd5[done] = A_read0_0.done; - } - group upd6<"static"=1> { - B0.addr0 = i0.out; - B0.write_en = 1'd1; - B0.write_data = A_read0_0.out; - upd6[done] = B0.done; - } - group upd7<"static"=1> { - i0.write_en = 1'd1; - add1.left = i0.out; - add1.right = 6'd1; - 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; - seq { - cond00; - while comb_reg.out { - seq { - seq { - upd0; - par { - upd1; - upd2; - } - upd3; - upd4; - } - cond00; - } - } - } - let1; - seq { - cond10; - while comb_reg.out { - seq { - seq { - upd5; - upd6; - upd7; - } - cond10; - } - } - } - } - } -} diff --git a/tests/passes/minimize-regs/live-register-analysis.fuse b/tests/passes/minimize-regs/live-register-analysis.fuse deleted file mode 100644 index 1a3349420a..0000000000 --- a/tests/passes/minimize-regs/live-register-analysis.fuse +++ /dev/null @@ -1,14 +0,0 @@ -// swap the contents of A and B - -decl A: ubit<32>[32]; -decl B: ubit<32>[32]; -decl C: ubit<32>[32]; - -for (let i: ubit<6> = 0..32) { - C[i] := A[i]; - A[i] := B[i]; -} - -for (let i: ubit<6> = 0..32) { - B[i] := C[i]; -} diff --git a/tests/passes/minimize-regs/live-register-analysis.futil b/tests/passes/minimize-regs/live-register-analysis.futil deleted file mode 100644 index d1dab7c962..0000000000 --- a/tests/passes/minimize-regs/live-register-analysis.futil +++ /dev/null @@ -1,112 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; -component main() -> () { - cells { - @external(1) A0 = std_mem_d1(32,32,6); - A_read0_0 = std_reg(32); - @external(1) B0 = std_mem_d1(32,32,6); - B_read0_0 = std_reg(32); - @external(1) C0 = std_mem_d1(32,32,6); - C_read0_0 = std_reg(32); - add0 = std_add(6); - add1 = std_add(6); - i0 = std_reg(6); - i1 = std_reg(6); - le0 = std_le(6); - le1 = std_le(6); - } - wires { - comb group cond0 { - le0.left = i0.out; - le0.right = 6'd31; - } - comb group cond1 { - le1.left = i1.out; - le1.right = 6'd31; - } - group let0<"static"=1> { - i0.in = 6'd0; - i0.write_en = 1'd1; - let0[done] = i0.done; - } - group let1<"static"=1> { - i1.in = 6'd0; - i1.write_en = 1'd1; - let1[done] = i1.done; - } - group upd0<"static"=1> { - A_read0_0.write_en = 1'd1; - A0.addr0 = i0.out; - A_read0_0.in = A0.read_data; - upd0[done] = A_read0_0.done; - } - group upd1<"static"=1> { - C0.addr0 = i0.out; - C0.write_en = 1'd1; - C0.write_data = A_read0_0.out; - upd1[done] = C0.done; - } - group upd2<"static"=1> { - B_read0_0.write_en = 1'd1; - B0.addr0 = i0.out; - B_read0_0.in = B0.read_data; - upd2[done] = B_read0_0.done; - } - group upd3<"static"=1> { - A0.addr0 = i0.out; - A0.write_en = 1'd1; - A0.write_data = B_read0_0.out; - upd3[done] = A0.done; - } - group upd4<"static"=1> { - i0.write_en = 1'd1; - add0.left = i0.out; - add0.right = 6'd1; - i0.in = add0.out; - upd4[done] = i0.done; - } - group upd5<"static"=1> { - C_read0_0.write_en = 1'd1; - C0.addr0 = i1.out; - C_read0_0.in = C0.read_data; - upd5[done] = C_read0_0.done; - } - group upd6<"static"=1> { - B0.addr0 = i1.out; - B0.write_en = 1'd1; - B0.write_data = C_read0_0.out; - upd6[done] = B0.done; - } - group upd7<"static"=1> { - i1.write_en = 1'd1; - add1.left = i1.out; - add1.right = 6'd1; - i1.in = add1.out; - upd7[done] = i1.done; - } - } - control { - seq { - let0; - while le0.out with cond0 { - seq { - upd0; - par { - upd1; - upd2; - } - upd3; - upd4; - } - } - let1; - while le1.out with cond1 { - seq { - upd5; - upd6; - upd7; - } - } - } - } -} diff --git a/tests/passes/minimize-regs/nested-par.expect b/tests/passes/minimize-regs/nested-par.expect deleted file mode 100644 index 01e242bf89..0000000000 --- a/tests/passes/minimize-regs/nested-par.expect +++ /dev/null @@ -1,74 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - b0 = std_reg(32); - before0 = std_reg(4); - @external read_x0 = std_add(4); - b1 = std_reg(32); - before1 = std_reg(4); - @external read_x1 = std_add(4); - } - wires { - group wr_before0<"static"=1> { - before0.in = 4'd1; - before0.write_en = 1'd1; - wr_before0[done] = before0.done; - } - group wr_x0<"static"=1> { - before0.in = 4'd1; - before0.write_en = 1'd1; - wr_x0[done] = before0.done; - } - group wr_b0<"static"=1> { - b0.in = 32'd1; - b0.write_en = 1'd1; - wr_b0[done] = b0.done; - } - group rd_x0 { - read_x0.right = before0.out; - read_x0.left = before0.out; - rd_x0[done] = before0.done; - } - group wr_before1<"static"=1> { - before1.in = 4'd1; - before1.write_en = 1'd1; - wr_before1[done] = before1.done; - } - group wr_x1<"static"=1> { - before1.in = 4'd1; - before1.write_en = 1'd1; - wr_x1[done] = before1.done; - } - group wr_b1<"static"=1> { - b1.in = 32'd1; - b1.write_en = 1'd1; - wr_b1[done] = b1.done; - } - group rd_x1 { - read_x1.right = before1.out; - read_x1.left = before1.out; - rd_x1[done] = before1.done; - } - } - - control { - par { - seq { - wr_before0; - par { - wr_x0; - wr_b0; - } - rd_x0; - } - seq { - wr_before1; - par { - wr_x1; - wr_b1; - } - rd_x1; - } - } - } -} diff --git a/tests/passes/minimize-regs/nested-par.futil b/tests/passes/minimize-regs/nested-par.futil deleted file mode 100644 index a9a3dc9978..0000000000 --- a/tests/passes/minimize-regs/nested-par.futil +++ /dev/null @@ -1,78 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; -component main() -> () { - cells { - b0 = std_reg(32); - before0 = std_reg(4); - x0 = std_reg(4); - @external read_x0 = std_add(4); - - b1 = std_reg(32); - before1 = std_reg(4); - x1 = std_reg(4); - @external read_x1 = std_add(4); - } - wires { - group wr_before0<"static"=1> { - before0.in = 4'd1; - before0.write_en = 1'd1; - wr_before0[done] = before0.done; - } - group wr_x0<"static"=1> { - x0.in = 4'd1; - x0.write_en = 1'd1; - wr_x0[done] = x0.done; - } - group wr_b0<"static"=1> { - b0.in = 32'd1; - b0.write_en = 1'd1; - wr_b0[done] = b0.done; - } - group rd_x0 { - read_x0.right = x0.out; - read_x0.left = x0.out; - rd_x0[done] = x0.done; // XXX: This is functionally wrong - } - - group wr_before1<"static"=1> { - before1.in = 4'd1; - before1.write_en = 1'd1; - wr_before1[done] = before1.done; - } - group wr_x1<"static"=1> { - x1.in = 4'd1; - x1.write_en = 1'd1; - wr_x1[done] = x1.done; - } - group wr_b1<"static"=1> { - b1.in = 32'd1; - b1.write_en = 1'd1; - wr_b1[done] = b1.done; - } - group rd_x1 { - read_x1.right = x1.out; - read_x1.left = x1.out; - rd_x1[done] = x1.done; // XXX: This is functionally wrong - } - } - control { - par { - seq { - wr_before0; - par { - wr_x0; - wr_b0; - } - rd_x0; - } - seq { - wr_before1; - par { - wr_x1; - wr_b1; - } - rd_x1; - } - } - } -} diff --git a/tests/passes/minimize-regs/par-while-liveness.expect b/tests/passes/minimize-regs/par-while-liveness.expect deleted file mode 100644 index 6bfa8628c2..0000000000 --- a/tests/passes/minimize-regs/par-while-liveness.expect +++ /dev/null @@ -1,180 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - @external a_src0 = std_mem_d1(32, 8, 4); - a_src_read0_0 = std_reg(32); - @external a_tar0 = std_mem_d1(32, 8, 4); - add0 = std_add(4); - add1 = std_add(4); - add2 = std_add(4); - @external b_src0 = std_mem_d1(32, 8, 4); - b_src_read0_0 = std_reg(32); - @external b_tar0 = std_mem_d1(32, 8, 4); - @external c_src0 = std_mem_d1(32, 8, 4); - @external c_tar0 = std_mem_d1(32, 8, 4); - const0 = std_const(4, 0); - const1 = std_const(4, 7); - const2 = std_const(4, 1); - const3 = std_const(4, 0); - const4 = std_const(4, 7); - const5 = std_const(4, 1); - const6 = std_const(4, 0); - const7 = std_const(4, 7); - const8 = std_const(4, 1); - i0 = std_reg(4); - i1 = std_reg(4); - 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 let0<"static"=1> { - i0.in = const0.out; - i0.write_en = 1'd1; - let0[done] = i0.done; - } - group let1<"static"=1> { - i1.in = const3.out; - i1.write_en = 1'd1; - let1[done] = i1.done; - } - group let2<"static"=1> { - i0.in = const6.out; - i0.write_en = 1'd1; - let2[done] = i0.done; - } - group upd0<"static"=1> { - a_src_read0_0.write_en = 1'd1; - a_src0.addr0 = i0.out; - a_src_read0_0.in = a_src0.read_data; - upd0[done] = a_src_read0_0.done ? 1'd1; - } - group upd1<"static"=1> { - a_tar0.addr0 = i0.out; - a_tar0.write_en = 1'd1; - a_tar0.write_data = a_src_read0_0.out; - upd1[done] = a_tar0.done ? 1'd1; - } - group upd2<"static"=1> { - i0.write_en = 1'd1; - add0.left = i0.out; - add0.right = const2.out; - i0.in = add0.out; - upd2[done] = i0.done ? 1'd1; - } - group upd3<"static"=1> { - b_src_read0_0.write_en = 1'd1; - b_src0.addr0 = i1.out; - b_src_read0_0.in = b_src0.read_data; - upd3[done] = b_src_read0_0.done ? 1'd1; - } - group upd4<"static"=1> { - b_tar0.addr0 = i1.out; - b_tar0.write_en = 1'd1; - b_tar0.write_data = b_src_read0_0.out; - upd4[done] = b_tar0.done ? 1'd1; - } - group upd5<"static"=1> { - i1.write_en = 1'd1; - add1.left = i1.out; - add1.right = const5.out; - i1.in = add1.out; - upd5[done] = i1.done ? 1'd1; - } - group upd6<"static"=1> { - a_src_read0_0.write_en = 1'd1; - c_tar0.addr0 = i0.out; - a_src_read0_0.in = c_tar0.read_data; - upd6[done] = a_src_read0_0.done ? 1'd1; - } - group upd7<"static"=1> { - c_src0.addr0 = i0.out; - c_src0.write_en = 1'd1; - c_src0.write_data = a_src_read0_0.out; - upd7[done] = c_src0.done ? 1'd1; - } - group upd8<"static"=1> { - i0.write_en = 1'd1; - add2.left = i0.out; - add2.right = const8.out; - 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 { - seq { - par { - seq { - let0; - seq { - cond00; - while comb_reg.out { - seq { - seq { - upd0; - upd1; - upd2; - } - cond00; - } - } - } - } - seq { - let1; - seq { - cond10; - while comb_reg0.out { - seq { - seq { - upd3; - upd4; - upd5; - } - cond10; - } - } - } - } - } - let2; - 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 deleted file mode 100644 index f3c21200ea..0000000000 --- a/tests/passes/minimize-regs/par-while-liveness.futil +++ /dev/null @@ -1,153 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; -component main() -> () { - cells { - @external(1) a_src0 = std_mem_d1(32,8,4); - a_src_read0_0 = std_reg(32); - @external(1) a_tar0 = std_mem_d1(32,8,4); - add0 = std_add(4); - add1 = std_add(4); - add2 = std_add(4); - @external(1) b_src0 = std_mem_d1(32,8,4); - b_src_read0_0 = std_reg(32); - @external(1) b_tar0 = std_mem_d1(32,8,4); - @external(1) c_src0 = std_mem_d1(32,8,4); - @external(1) c_tar0 = std_mem_d1(32,8,4); - c_tar_read0_0 = std_reg(32); - const0 = std_const(4,0); - const1 = std_const(4,7); - const2 = std_const(4,1); - const3 = std_const(4,0); - const4 = std_const(4,7); - const5 = std_const(4,1); - const6 = std_const(4,0); - const7 = std_const(4,7); - const8 = std_const(4,1); - i0 = std_reg(4); - i1 = std_reg(4); - i2 = std_reg(4); - le0 = std_le(4); - le1 = std_le(4); - le2 = std_le(4); - } - wires { - comb group cond0 { - le0.left = i0.out; - le0.right = const1.out; - } - comb group cond1 { - le1.left = i1.out; - le1.right = const4.out; - } - comb group cond2 { - le2.left = i2.out; - le2.right = const7.out; - } - group let0<"static"=1> { - i0.in = const0.out; - i0.write_en = 1'd1; - let0[done] = i0.done; - } - group let1<"static"=1> { - i1.in = const3.out; - i1.write_en = 1'd1; - let1[done] = i1.done; - } - group let2<"static"=1> { - i2.in = const6.out; - i2.write_en = 1'd1; - let2[done] = i2.done; - } - group upd0<"static"=1> { - a_src_read0_0.write_en = 1'd1; - a_src0.addr0 = i0.out; - a_src_read0_0.in = 1'd1 ? a_src0.read_data; - upd0[done] = a_src_read0_0.done ? 1'd1; - } - group upd1<"static"=1> { - a_tar0.addr0 = i0.out; - a_tar0.write_en = 1'd1; - a_tar0.write_data = 1'd1 ? a_src_read0_0.out; - upd1[done] = a_tar0.done ? 1'd1; - } - group upd2<"static"=1> { - i0.write_en = 1'd1; - add0.left = i0.out; - add0.right = const2.out; - i0.in = 1'd1 ? add0.out; - upd2[done] = i0.done ? 1'd1; - } - group upd3<"static"=1> { - b_src_read0_0.write_en = 1'd1; - b_src0.addr0 = i1.out; - b_src_read0_0.in = 1'd1 ? b_src0.read_data; - upd3[done] = b_src_read0_0.done ? 1'd1; - } - group upd4<"static"=1> { - b_tar0.addr0 = i1.out; - b_tar0.write_en = 1'd1; - b_tar0.write_data = 1'd1 ? b_src_read0_0.out; - upd4[done] = b_tar0.done ? 1'd1; - } - group upd5<"static"=1> { - i1.write_en = 1'd1; - add1.left = i1.out; - add1.right = const5.out; - i1.in = 1'd1 ? add1.out; - upd5[done] = i1.done ? 1'd1; - } - group upd6<"static"=1> { - c_tar_read0_0.write_en = 1'd1; - c_tar0.addr0 = i2.out; - c_tar_read0_0.in = 1'd1 ? c_tar0.read_data; - upd6[done] = c_tar_read0_0.done ? 1'd1; - } - group upd7<"static"=1> { - c_src0.addr0 = i2.out; - c_src0.write_en = 1'd1; - c_src0.write_data = 1'd1 ? c_tar_read0_0.out; - upd7[done] = c_src0.done ? 1'd1; - } - group upd8<"static"=1> { - i2.write_en = 1'd1; - add2.left = i2.out; - add2.right = const8.out; - i2.in = 1'd1 ? add2.out; - upd8[done] = i2.done ? 1'd1; - } - } - control { - seq { - par { - seq { - let0; - while le0.out with cond0 { - seq { - upd0; - upd1; - upd2; - } - } - } - seq { - let1; - while le1.out with cond1 { - seq { - upd3; - upd4; - upd5; - } - } - } - } - let2; - while le2.out with cond2 { - seq { - upd6; - upd7; - upd8; - } - } - } - } -} diff --git a/tests/passes/minimize-regs/par-write.expect b/tests/passes/minimize-regs/par-write.expect deleted file mode 100644 index f3a4a26ad6..0000000000 --- a/tests/passes/minimize-regs/par-write.expect +++ /dev/null @@ -1,26 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - x = std_reg(32); - y = std_reg(32); - } - wires { - group wr_x { - x.in = 32'd1; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - group wr_y { - y.in = 32'd2; - y.write_en = 1'd1; - wr_y[done] = y.done; - } - } - - control { - par { - wr_x; - wr_y; - } - } -} diff --git a/tests/passes/minimize-regs/par-write.futil b/tests/passes/minimize-regs/par-write.futil deleted file mode 100644 index b99210fdcb..0000000000 --- a/tests/passes/minimize-regs/par-write.futil +++ /dev/null @@ -1,27 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; - -component main() -> () { - cells { - x = std_reg(32); - y = std_reg(32); - } - wires { - group wr_x { - x.in = 32'd1; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - group wr_y { - y.in = 32'd2; - y.write_en = 1'd1; - wr_y[done] = y.done; - } - } - control { - par { - wr_x; - wr_y; - } - } -} diff --git a/tests/passes/minimize-regs/simple-liveness.expect b/tests/passes/minimize-regs/simple-liveness.expect deleted file mode 100644 index f2e4c208da..0000000000 --- a/tests/passes/minimize-regs/simple-liveness.expect +++ /dev/null @@ -1,41 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - b = std_reg(32); - before = std_reg(4); - @external read_x = std_add(4); - } - wires { - group wr_before<"static"=1> { - before.in = 4'd1; - before.write_en = 1'd1; - wr_before[done] = before.done; - } - group wr_x<"static"=1> { - before.in = 4'd1; - before.write_en = 1'd1; - wr_x[done] = before.done; - } - group wr_b<"static"=1> { - b.in = 32'd1; - b.write_en = 1'd1; - wr_b[done] = b.done; - } - group rd_x<"static"=1> { - read_x.right = before.out; - read_x.left = before.out; - rd_x[done] = before.done; - } - } - - control { - seq { - wr_before; - par { - wr_x; - wr_b; - } - rd_x; - } - } -} diff --git a/tests/passes/minimize-regs/simple-liveness.futil b/tests/passes/minimize-regs/simple-liveness.futil deleted file mode 100644 index 17215282a6..0000000000 --- a/tests/passes/minimize-regs/simple-liveness.futil +++ /dev/null @@ -1,42 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; -component main() -> () { - cells { - b = std_reg(32); - before = std_reg(4); - x = std_reg(4); - @external read_x = std_add(4); - } - wires { - group wr_before<"static"=1> { - before.in = 4'd1; - before.write_en = 1'd1; - wr_before[done] = before.done; - } - group wr_x<"static"=1> { - x.in = 4'd1; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - group wr_b<"static"=1> { - b.in = 32'd1; - b.write_en = 1'd1; - wr_b[done] = b.done; - } - group rd_x<"static"=1> { - read_x.right = x.out; - read_x.left = x.out; - rd_x[done] = x.done; // XXX: This is functionally incorrect - } - } - control { - seq { - wr_before; - par { - wr_x; - wr_b; - } - rd_x; - } - } -} diff --git a/tests/passes/minimize-regs/thread-local.expect b/tests/passes/minimize-regs/thread-local.expect deleted file mode 100644 index 7b7fb9504b..0000000000 --- a/tests/passes/minimize-regs/thread-local.expect +++ /dev/null @@ -1,46 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - x = std_reg(32); - y = std_reg(32); - @external add_x = std_add(32); - @external add_y = std_add(32); - } - wires { - group wr_x { - x.in = 32'd2; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - group rd_x { - add_x.left = x.out; - add_x.right = x.out; - rd_x[done] = x.done; - } - group wr_y { - y.in = 32'd4; - y.write_en = 1'd1; - wr_y[done] = y.done; - } - group rd_y { - add_y.left = y.out; - add_y.right = y.out; - rd_y[done] = y.done; - } - } - - control { - seq { - par { - seq { - wr_x; - rd_x; - } - seq { - wr_y; - rd_y; - } - } - } - } -} diff --git a/tests/passes/minimize-regs/thread-local.futil b/tests/passes/minimize-regs/thread-local.futil deleted file mode 100644 index 1e5db45804..0000000000 --- a/tests/passes/minimize-regs/thread-local.futil +++ /dev/null @@ -1,48 +0,0 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal -import "primitives/core.futil"; - -component main() -> () { - cells { - x = std_reg(32); - y = std_reg(32); - @external add_x = std_add(32); - @external add_y = std_add(32); - } - - wires { - group wr_x { - x.in = 32'd2; - x.write_en = 1'd1; - wr_x[done] = x.done; - } - - group rd_x { - add_x.left = x.out; - add_x.right = x.out; - rd_x[done] = x.done; // XXX: This is functionally wrong - } - - group wr_y { - y.in = 32'd4; - y.write_en = 1'd1; - wr_y[done] = y.done; - } - - group rd_y { - add_y.left = y.out; - add_y.right = y.out; - rd_y[done] = y.done; // XXX: This is functionally wrong - } - } - - control { - seq { - par { - // thread local use of x - seq { wr_x; rd_x; } - // this should stay y - seq { wr_y; rd_y; } - } - } - } -} diff --git a/tests/passes/resource-sharing/cond-port.expect b/tests/passes/resource-sharing/cond-port.expect deleted file mode 100644 index 84243bf12a..0000000000 --- a/tests/passes/resource-sharing/cond-port.expect +++ /dev/null @@ -1,49 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - gt0 = std_gt(32); - gt1 = std_gt(32); - x_0 = std_reg(32); - y_0 = std_reg(1); - @generated comb_reg = std_reg(1); - } - wires { - group let0 { - x_0.in = 32'd1; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1 { - y_0.in = gt0.out; - y_0.write_en = 1'd1; - let1[done] = y_0.done; - gt0.left = x_0.out; - gt0.right = 32'd1; - } - group upd0 { - x_0.write_en = 1'd1; - 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; - 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 deleted file mode 100644 index 60c5d1b724..0000000000 --- a/tests/passes/resource-sharing/cond-port.futil +++ /dev/null @@ -1,43 +0,0 @@ -// -p remove-comb-groups -p resource-sharing -import "primitives/core.futil"; -component main() -> () { - cells { - gt0 = std_gt(32); - gt1 = std_gt(32); - x_0 = std_reg(32); - y_0 = std_reg(1); - } - wires { - comb group cond0 { - gt1.left = x_0.out; - gt1.right = 32'd2; - } - group let0 { - x_0.in = 32'd1; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1 { - y_0.in = gt0.out; - y_0.write_en = 1'd1; - let1[done] = y_0.done; - gt0.left = x_0.out; - gt0.right = 32'd1; - } - group upd0 { - x_0.write_en = 1'd1; - x_0.in = 1'd1 ? 32'd10; - upd0[done] = x_0.done ? 1'd1; - } - } - control { - seq { - let0; - let1; - if gt1.out with cond0 { - upd0; - } - } - } -} - diff --git a/tests/passes/resource-sharing/continuous-assign.expect b/tests/passes/resource-sharing/continuous-assign.expect deleted file mode 100644 index 5853bba2a7..0000000000 --- a/tests/passes/resource-sharing/continuous-assign.expect +++ /dev/null @@ -1,17 +0,0 @@ -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - r0 = std_reg(32); - r1 = std_reg(32); - add0 = std_add(32); - add1 = std_add(32); - } - wires { - done = r0.done; - add1.left = r0.out; - add0.left = r1.out; - } - - control {} -} diff --git a/tests/passes/resource-sharing/continuous-assign.futil b/tests/passes/resource-sharing/continuous-assign.futil deleted file mode 100644 index fec6d43f5b..0000000000 --- a/tests/passes/resource-sharing/continuous-assign.futil +++ /dev/null @@ -1,18 +0,0 @@ -// -p validate -p resource-sharing -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - r0 = std_reg(32); - r1 = std_reg(32); - add0 = std_add(32); - add1 = std_add(32); - } - wires { - add0.left = r1.out; - add1.left = r0.out; - done = r0.done; - } - - control { } -} diff --git a/tests/passes/resource-sharing/multiple-cells.expect b/tests/passes/resource-sharing/multiple-cells.expect deleted file mode 100644 index f2f0e89cc4..0000000000 --- a/tests/passes/resource-sharing/multiple-cells.expect +++ /dev/null @@ -1,37 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add0 = std_add(32); - add1 = std_add(32); - add2 = std_add(32); - add3 = std_add(32); - x_0 = std_reg(32); - } - wires { - group let0<"static"=1> { - add0.left = 32'd1; - add0.right = 32'd2; - add1.right = 32'd3; - add1.left = add0.out; - x_0.in = add1.out; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1<"static"=1> { - add0.left = 32'd1; - add0.right = 32'd2; - add1.right = 32'd3; - add1.left = add0.out; - x_0.in = add1.out; - x_0.write_en = 1'd1; - let1[done] = x_0.done; - } - } - - control { - seq { - let0; - let1; - } - } -} diff --git a/tests/passes/resource-sharing/multiple-cells.futil b/tests/passes/resource-sharing/multiple-cells.futil deleted file mode 100644 index 701f76fde7..0000000000 --- a/tests/passes/resource-sharing/multiple-cells.futil +++ /dev/null @@ -1,37 +0,0 @@ -// -p resource-sharing -import "primitives/core.futil"; -component main() -> () { - cells { - add0 = std_add(32); - add1 = std_add(32); - add2 = std_add(32); - add3 = std_add(32); - x_0 = std_reg(32); - } - wires { - group let0<"static"=1> { - add0.left = 32'd1; - add0.right = 32'd2; - add1.right = 32'd3; - add1.left = add0.out; - x_0.in = add1.out; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1<"static"=1> { - add2.left = 32'd1; - add2.right = 32'd2; - add3.right = 32'd3; - add3.left = add2.out; - x_0.in = add3.out; - x_0.write_en = 1'd1; - let1[done] = x_0.done; - } - } - control { - seq { - let0; - let1; - } - } -} diff --git a/tests/passes/resource-sharing/share-component.expect b/tests/passes/resource-sharing/share-component.expect deleted file mode 100644 index 8c271b756f..0000000000 --- a/tests/passes/resource-sharing/share-component.expect +++ /dev/null @@ -1,43 +0,0 @@ -import "primitives/core.futil"; -component my_add<"share"=1>(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { - cells { - add = std_add(32); - } - wires { - add.left = left; - add.right = right; - out = add.out; - } - - control {} -} -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add0 = my_add(); - add1 = my_add(); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - - control { - seq { - upd0; - upd1; - } - } -} diff --git a/tests/passes/resource-sharing/share-component.futil b/tests/passes/resource-sharing/share-component.futil deleted file mode 100644 index f973b947c1..0000000000 --- a/tests/passes/resource-sharing/share-component.futil +++ /dev/null @@ -1,44 +0,0 @@ -// -p resource-sharing - -import "primitives/core.futil"; -component my_add<"share"=1>(left: 32, right: 32) -> (out: 32) { - cells { - add = std_add(32); - } - wires { - add.left = left; - add.right = right; - out = add.out; - } - control {} -} - -component main() -> () { - cells { - add0 = my_add(); - add1 = my_add(); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add1.left = x_0.out; - add1.right = 32'd1; - x_0.in = add1.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - control { - seq { - upd0; - upd1; - } - } -} diff --git a/tests/passes/resource-sharing/share.expect b/tests/passes/resource-sharing/share.expect deleted file mode 100644 index 16215666e0..0000000000 --- a/tests/passes/resource-sharing/share.expect +++ /dev/null @@ -1,31 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add0 = std_add(32); - add1 = std_add(32); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - - control { - seq { - upd0; - upd1; - } - } -} diff --git a/tests/passes/resource-sharing/share.futil b/tests/passes/resource-sharing/share.futil deleted file mode 100644 index 71ce401e0e..0000000000 --- a/tests/passes/resource-sharing/share.futil +++ /dev/null @@ -1,32 +0,0 @@ -// -p resource-sharing - -import "primitives/core.futil"; -component main() -> () { - cells { - add0 = std_add(32); - add1 = std_add(32); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add1.left = x_0.out; - add1.right = 32'd1; - x_0.in = add1.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - control { - seq { - upd0; - upd1; - } - } -} diff --git a/tests/passes/was-resource-sharing/cond-port.expect b/tests/passes/was-resource-sharing/cond-port.expect deleted file mode 100644 index 84243bf12a..0000000000 --- a/tests/passes/was-resource-sharing/cond-port.expect +++ /dev/null @@ -1,49 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - gt0 = std_gt(32); - gt1 = std_gt(32); - x_0 = std_reg(32); - y_0 = std_reg(1); - @generated comb_reg = std_reg(1); - } - wires { - group let0 { - x_0.in = 32'd1; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1 { - y_0.in = gt0.out; - y_0.write_en = 1'd1; - let1[done] = y_0.done; - gt0.left = x_0.out; - gt0.right = 32'd1; - } - group upd0 { - x_0.write_en = 1'd1; - 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; - seq { - cond00; - if comb_reg.out { - upd0; - } - } - } - } -} diff --git a/tests/passes/was-resource-sharing/cond-port.futil b/tests/passes/was-resource-sharing/cond-port.futil deleted file mode 100644 index 1c6b454df6..0000000000 --- a/tests/passes/was-resource-sharing/cond-port.futil +++ /dev/null @@ -1,43 +0,0 @@ -// -p remove-comb-groups -p minimize-regs -import "primitives/core.futil"; -component main() -> () { - cells { - gt0 = std_gt(32); - gt1 = std_gt(32); - x_0 = std_reg(32); - y_0 = std_reg(1); - } - wires { - comb group cond0 { - gt1.left = x_0.out; - gt1.right = 32'd2; - } - group let0 { - x_0.in = 32'd1; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1 { - y_0.in = gt0.out; - y_0.write_en = 1'd1; - let1[done] = y_0.done; - gt0.left = x_0.out; - gt0.right = 32'd1; - } - group upd0 { - x_0.write_en = 1'd1; - x_0.in = 1'd1 ? 32'd10; - upd0[done] = x_0.done ? 1'd1; - } - } - control { - seq { - let0; - let1; - if gt1.out with cond0 { - upd0; - } - } - } -} - diff --git a/tests/passes/was-resource-sharing/continuous-assign.expect b/tests/passes/was-resource-sharing/continuous-assign.expect deleted file mode 100644 index 5853bba2a7..0000000000 --- a/tests/passes/was-resource-sharing/continuous-assign.expect +++ /dev/null @@ -1,17 +0,0 @@ -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - r0 = std_reg(32); - r1 = std_reg(32); - add0 = std_add(32); - add1 = std_add(32); - } - wires { - done = r0.done; - add1.left = r0.out; - add0.left = r1.out; - } - - control {} -} diff --git a/tests/passes/was-resource-sharing/continuous-assign.futil b/tests/passes/was-resource-sharing/continuous-assign.futil deleted file mode 100644 index 518ed3fe81..0000000000 --- a/tests/passes/was-resource-sharing/continuous-assign.futil +++ /dev/null @@ -1,18 +0,0 @@ -// -p validate -p minimize-regs -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - r0 = std_reg(32); - r1 = std_reg(32); - add0 = std_add(32); - add1 = std_add(32); - } - wires { - add0.left = r1.out; - add1.left = r0.out; - done = r0.done; - } - - control { } -} diff --git a/tests/passes/was-resource-sharing/multiple-cells.expect b/tests/passes/was-resource-sharing/multiple-cells.expect deleted file mode 100644 index f2f0e89cc4..0000000000 --- a/tests/passes/was-resource-sharing/multiple-cells.expect +++ /dev/null @@ -1,37 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add0 = std_add(32); - add1 = std_add(32); - add2 = std_add(32); - add3 = std_add(32); - x_0 = std_reg(32); - } - wires { - group let0<"static"=1> { - add0.left = 32'd1; - add0.right = 32'd2; - add1.right = 32'd3; - add1.left = add0.out; - x_0.in = add1.out; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1<"static"=1> { - add0.left = 32'd1; - add0.right = 32'd2; - add1.right = 32'd3; - add1.left = add0.out; - x_0.in = add1.out; - x_0.write_en = 1'd1; - let1[done] = x_0.done; - } - } - - control { - seq { - let0; - let1; - } - } -} diff --git a/tests/passes/was-resource-sharing/multiple-cells.futil b/tests/passes/was-resource-sharing/multiple-cells.futil deleted file mode 100644 index 8373d0d8b6..0000000000 --- a/tests/passes/was-resource-sharing/multiple-cells.futil +++ /dev/null @@ -1,37 +0,0 @@ -// -p minimize-regs -import "primitives/core.futil"; -component main() -> () { - cells { - add0 = std_add(32); - add1 = std_add(32); - add2 = std_add(32); - add3 = std_add(32); - x_0 = std_reg(32); - } - wires { - group let0<"static"=1> { - add0.left = 32'd1; - add0.right = 32'd2; - add1.right = 32'd3; - add1.left = add0.out; - x_0.in = add1.out; - x_0.write_en = 1'd1; - let0[done] = x_0.done; - } - group let1<"static"=1> { - add2.left = 32'd1; - add2.right = 32'd2; - add3.right = 32'd3; - add3.left = add2.out; - x_0.in = add3.out; - x_0.write_en = 1'd1; - let1[done] = x_0.done; - } - } - control { - seq { - let0; - let1; - } - } -} diff --git a/tests/passes/was-resource-sharing/share-component.expect b/tests/passes/was-resource-sharing/share-component.expect deleted file mode 100644 index 8c271b756f..0000000000 --- a/tests/passes/was-resource-sharing/share-component.expect +++ /dev/null @@ -1,43 +0,0 @@ -import "primitives/core.futil"; -component my_add<"share"=1>(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { - cells { - add = std_add(32); - } - wires { - add.left = left; - add.right = right; - out = add.out; - } - - control {} -} -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add0 = my_add(); - add1 = my_add(); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - - control { - seq { - upd0; - upd1; - } - } -} diff --git a/tests/passes/was-resource-sharing/share-component.futil b/tests/passes/was-resource-sharing/share-component.futil deleted file mode 100644 index 28cb37a8fd..0000000000 --- a/tests/passes/was-resource-sharing/share-component.futil +++ /dev/null @@ -1,44 +0,0 @@ -// -p minimize-regs - -import "primitives/core.futil"; -component my_add<"share"=1>(left: 32, right: 32) -> (out: 32) { - cells { - add = std_add(32); - } - wires { - add.left = left; - add.right = right; - out = add.out; - } - control {} -} - -component main() -> () { - cells { - add0 = my_add(); - add1 = my_add(); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add1.left = x_0.out; - add1.right = 32'd1; - x_0.in = add1.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - control { - seq { - upd0; - upd1; - } - } -} diff --git a/tests/passes/was-resource-sharing/share.expect b/tests/passes/was-resource-sharing/share.expect deleted file mode 100644 index 16215666e0..0000000000 --- a/tests/passes/was-resource-sharing/share.expect +++ /dev/null @@ -1,31 +0,0 @@ -import "primitives/core.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add0 = std_add(32); - add1 = std_add(32); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - - control { - seq { - upd0; - upd1; - } - } -} diff --git a/tests/passes/was-resource-sharing/share.futil b/tests/passes/was-resource-sharing/share.futil deleted file mode 100644 index 4146b3c2d2..0000000000 --- a/tests/passes/was-resource-sharing/share.futil +++ /dev/null @@ -1,32 +0,0 @@ -// -p minimize-regs - -import "primitives/core.futil"; -component main() -> () { - cells { - add0 = std_add(32); - add1 = std_add(32); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add1.left = x_0.out; - add1.right = 32'd1; - x_0.in = add1.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - control { - seq { - upd0; - upd1; - } - } -} From 926f3e130b3f772cae2b605055e9dfb7465d6efd Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 17 Jun 2022 15:30:32 -0400 Subject: [PATCH 17/32] fixed clippy complaints/cleaned code --- calyx/src/analysis/live_range_analysis.rs | 76 ++++++++++++----------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index afce12b81c..b0447a9f02 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -249,6 +249,27 @@ fn is_shareable_component( } } +//Given assignments, looks for each use of a shareable cell. Then, add them as live +//in ranges, in the group indicated by name. +fn add_shareable_ranges( + assignments: &[ir::Assignment], + shareable: &HashSet, + name: &ir::Id, + ranges: &mut LiveRangeAnalysis, +) { + let group_uses: Prop = ReadWriteSet::uses(assignments.iter()) + .filter(|cell| is_shareable_component(shareable, cell)) + .map(|cell| cell.clone_name()) + .collect::>() + .into(); + match ranges.live.get_mut(name) { + None => { + unreachable!("don't have live range for {}", name) + } + Some(prop) => *prop = &*prop | &group_uses, + } +} + impl LiveRangeAnalysis { /// Construct a live range analysis. pub fn new( @@ -257,9 +278,10 @@ impl LiveRangeAnalysis { state_share: HashSet, shareable: HashSet, ) -> Self { - let mut ranges = LiveRangeAnalysis::default(); - - ranges.state_share = state_share; + let mut ranges = LiveRangeAnalysis { + state_share, + ..Default::default() + }; build_live_ranges( control, @@ -271,38 +293,20 @@ impl LiveRangeAnalysis { //adds (non-state) shareable cells as live in the group they're contained in comp.groups.iter().for_each(|group| { - let group_uses: Prop = - ReadWriteSet::uses(group.borrow().assignments.iter()) - .filter(|cell| is_shareable_component(&shareable, &cell)) - .map(|cell| cell.clone_name()) - .collect::>() - .into(); - match ranges.live.get_mut(group.borrow().name()) { - None => { - unreachable!( - "don't have live range for {}", - group.borrow().name() - ) - } - Some(prop) => *prop = &*prop | &group_uses, - } + add_shareable_ranges( + &group.borrow().assignments, + &shareable, + group.borrow().name(), + &mut ranges, + ) }); comp.comb_groups.iter().for_each(|group| { - let group_uses: Prop = - ReadWriteSet::uses(group.borrow().assignments.iter()) - .filter(|cell| is_shareable_component(&shareable, &cell)) - .map(|cell| cell.clone_name()) - .collect::>() - .into(); - match ranges.live.get_mut(group.borrow().name()) { - None => { - unreachable!( - "don't have live range for {}", - group.borrow().name() - ) - } - Some(prop) => *prop = &*prop | &group_uses, - } + add_shareable_ranges( + &group.borrow().assignments, + &shareable, + group.borrow().name(), + &mut ranges, + ) }); ranges @@ -377,7 +381,7 @@ impl LiveRangeAnalysis { // calculate reads, but ignore `variable`. we've already dealt with that let reads: HashSet<_> = ReadWriteSet::read_set(assignments) - .filter(|c| is_shareable_component(&sc_clone, &c)) + .filter(|c| is_shareable_component(&sc_clone, c)) .map(|c| c.clone_name()) .collect(); @@ -388,7 +392,7 @@ impl LiveRangeAnalysis { } else { let reads: HashSet<_> = ReadWriteSet::read_set(group.assignments.iter()) - .filter(|c| is_shareable_component(&sc_clone, &c)) + .filter(|c| is_shareable_component(&sc_clone, c)) .map(|c| c.clone_name()) .collect(); @@ -402,7 +406,7 @@ impl LiveRangeAnalysis { let writes: HashSet<_> = ReadWriteSet::write_set(assignments.iter()) - .filter(|c| is_shareable_component(&sc_clone, &c)) + .filter(|c| is_shareable_component(&sc_clone, c)) .map(|c| c.clone_name()) .collect(); From 93b1f5e1d4ef966f52e10004df476840e8e0b192 Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 17 Jun 2022 15:46:52 -0400 Subject: [PATCH 18/32] changed a.expect to have state_share attribute --- tests/import/a.expect | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/import/a.expect b/tests/import/a.expect index 2ba1464a6b..0b684716af 100644 --- a/tests/import/a.expect +++ b/tests/import/a.expect @@ -24,7 +24,7 @@ extern "/calyx/primitives/core.sv" { 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); - primitive std_reg<"static"=1>[WIDTH](@write_together in: WIDTH, @write_together @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@stable out: WIDTH, @done done: 1); + primitive std_reg<"state_share"=1,"static"=1>[WIDTH](@write_together in: WIDTH, @write_together @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@stable out: WIDTH, @done done: 1); primitive std_mem_d1<"static"=1>[WIDTH, SIZE, IDX_SIZE](@read_together addr0: IDX_SIZE, @write_together write_data: WIDTH, @write_together @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); primitive std_mem_d2<"static"=1>[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @write_together write_data: WIDTH, @write_together @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); primitive std_mem_d3<"static"=1>[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @write_together write_data: WIDTH, @write_together @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); From 185fdbcee005fa96e1862d21966dbe406b4790bc Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 17 Jun 2022 16:01:45 -0400 Subject: [PATCH 19/32] added a space --- tests/import/a.expect | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/import/a.expect b/tests/import/a.expect index 0b684716af..225c850418 100644 --- a/tests/import/a.expect +++ b/tests/import/a.expect @@ -24,7 +24,7 @@ extern "/calyx/primitives/core.sv" { 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); - primitive std_reg<"state_share"=1,"static"=1>[WIDTH](@write_together in: WIDTH, @write_together @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@stable out: WIDTH, @done done: 1); + primitive std_reg<"state_share"=1, "static"=1>[WIDTH](@write_together in: WIDTH, @write_together @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@stable out: WIDTH, @done done: 1); primitive std_mem_d1<"static"=1>[WIDTH, SIZE, IDX_SIZE](@read_together addr0: IDX_SIZE, @write_together write_data: WIDTH, @write_together @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); primitive std_mem_d2<"static"=1>[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @write_together write_data: WIDTH, @write_together @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); primitive std_mem_d3<"static"=1>[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @write_together write_data: WIDTH, @write_together @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); From 7dfb1fe5ce4926126bb0aeb517fb25500c97a257 Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 24 Jun 2022 15:10:51 -0400 Subject: [PATCH 20/32] renamed to cell_share --- calyx/src/analysis/live_range_analysis.rs | 91 ++++++------ calyx/src/analysis/mod.rs | 2 + calyx/src/default_passes.rs | 54 +++---- calyx/src/ir/control.rs | 4 +- .../{minimize_regs.rs => cell_share.rs} | 36 ++--- calyx/src/passes/mod.rs | 8 +- calyx/src/passes/resource_sharing.rs | 134 ------------------ primitives/binary_operators.futil | 14 +- .../cond-port.expect | 0 .../cond-port.futil | 2 +- .../condition-register.expect | 0 .../condition-register.futil | 2 +- .../continuous-assign-no-groups.expect} | 0 .../continuous-assign-no-groups.futil} | 2 +- .../continuous-assignment.expect | 0 .../continuous-assignment.futil | 2 +- .../escape-boundary.expect | 0 .../escape-boundary.futil | 2 +- .../invoke.expect | 0 .../invoke.futil | 2 +- .../live-register-analysis.expect | 0 .../live-register-analysis.fuse | 0 .../live-register-analysis.futil | 2 +- .../multiple-adders.expect} | 0 .../multiple-adders.futil} | 2 +- .../nested-par.expect | 0 .../nested-par.futil | 2 +- .../par-while-liveness.expect | 0 .../par-while-liveness.futil | 2 +- .../par-write.expect | 0 .../par-write.futil | 2 +- .../share-adders.expect} | 0 .../share-adders.futil} | 2 +- .../share-component.expect | 0 .../share-component.futil | 2 +- .../simple-liveness.expect | 0 .../simple-liveness.futil | 2 +- .../thread-local.expect | 0 .../thread-local.futil | 2 +- .../regressions/group-multi-drive.futil | 2 +- 40 files changed, 127 insertions(+), 248 deletions(-) rename calyx/src/passes/{minimize_regs.rs => cell_share.rs} (81%) delete mode 100644 calyx/src/passes/resource_sharing.rs rename tests/passes/{general_share/was_resource_share => cell-share}/cond-port.expect (100%) rename tests/passes/{general_share/was_resource_share => cell-share}/cond-port.futil (94%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/condition-register.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/condition-register.futil (87%) rename tests/passes/{general_share/was_resource_share/continuous-assign.expect => cell-share/continuous-assign-no-groups.expect} (100%) rename tests/passes/{general_share/was_resource_share/continuous-assign.futil => cell-share/continuous-assign-no-groups.futil} (91%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/continuous-assignment.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/continuous-assignment.futil (85%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/escape-boundary.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/escape-boundary.futil (84%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/invoke.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/invoke.futil (92%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/live-register-analysis.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/live-register-analysis.fuse (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/live-register-analysis.futil (96%) rename tests/passes/{general_share/was_resource_share/multiple-cells.expect => cell-share/multiple-adders.expect} (100%) rename tests/passes/{general_share/was_resource_share/multiple-cells.futil => cell-share/multiple-adders.futil} (97%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/nested-par.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/nested-par.futil (95%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/par-while-liveness.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/par-while-liveness.futil (97%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/par-write.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/par-write.futil (82%) rename tests/passes/{general_share/was_resource_share/share.expect => cell-share/share-adders.expect} (100%) rename tests/passes/{general_share/was_resource_share/share.futil => cell-share/share-adders.futil} (96%) rename tests/passes/{general_share/was_resource_share => cell-share}/share-component.expect (100%) rename tests/passes/{general_share/was_resource_share => cell-share}/share-component.futil (97%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/simple-liveness.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/simple-liveness.futil (91%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/thread-local.expect (100%) rename tests/passes/{general_share/was_minimize_regs => cell-share}/thread-local.futil (91%) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index b0447a9f02..da16706974 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -223,7 +223,7 @@ pub struct LiveRangeAnalysis { /// Mapping from group name to the name of the register. variable_like: HashMap>, /// Set of state shareable components (as type names) - state_share: HashSet, + state_share: ShareSet, } impl Debug for LiveRangeAnalysis { @@ -236,37 +236,23 @@ impl Debug for LiveRangeAnalysis { } } -//given a set of shareable and a cell, determines whether cell's -//type is shareable or not -fn is_shareable_component( - shareable: &HashSet, - cell: &RRC, -) -> bool { - if let Some(type_name) = cell.borrow().type_name() { - shareable.contains(type_name) - } else { - false - } +#[derive(Default, Clone)] +struct ShareSet { + shareable: HashSet, } -//Given assignments, looks for each use of a shareable cell. Then, add them as live -//in ranges, in the group indicated by name. -fn add_shareable_ranges( - assignments: &[ir::Assignment], - shareable: &HashSet, - name: &ir::Id, - ranges: &mut LiveRangeAnalysis, -) { - let group_uses: Prop = ReadWriteSet::uses(assignments.iter()) - .filter(|cell| is_shareable_component(shareable, cell)) - .map(|cell| cell.clone_name()) - .collect::>() - .into(); - match ranges.live.get_mut(name) { - None => { - unreachable!("don't have live range for {}", name) +impl ShareSet { + fn new(set: HashSet) -> ShareSet { + ShareSet { shareable: set } + } + //given a set of shareable and a cell, determines whether cell's + //type is shareable or not + fn is_shareable_component(&self, cell: &RRC) -> bool { + if let Some(type_name) = cell.borrow().type_name() { + self.shareable.contains(type_name) + } else { + false } - Some(prop) => *prop = &*prop | &group_uses, } } @@ -279,7 +265,7 @@ impl LiveRangeAnalysis { shareable: HashSet, ) -> Self { let mut ranges = LiveRangeAnalysis { - state_share, + state_share: ShareSet::new(state_share), ..Default::default() }; @@ -291,26 +277,47 @@ impl LiveRangeAnalysis { &mut ranges, ); + let share_set = ShareSet::new(shareable); + //adds (non-state) shareable cells as live in the group they're contained in comp.groups.iter().for_each(|group| { - add_shareable_ranges( + ranges.add_shareable_ranges( &group.borrow().assignments, - &shareable, + &share_set, group.borrow().name(), - &mut ranges, ) }); comp.comb_groups.iter().for_each(|group| { - add_shareable_ranges( + ranges.add_shareable_ranges( &group.borrow().assignments, - &shareable, + &share_set, group.borrow().name(), - &mut ranges, ) }); ranges } + + //For each cell used in assignments, adds it as part of the group_name's live range + fn add_shareable_ranges( + &mut self, + assignments: &[ir::Assignment], + shareable: &ShareSet, + group_name: &ir::Id, + ) { + let group_uses: Prop = ReadWriteSet::uses(assignments.iter()) + .filter(|cell| shareable.is_shareable_component(cell)) + .map(|cell| cell.clone_name()) + .collect::>() + .into(); + match self.live.get_mut(group_name) { + None => { + unreachable!("don't have live range for {}", group_name) + } + Some(prop) => *prop = &*prop | &group_uses, + } + } + /// Look up the set of things live at a group definition. pub fn get(&self, group: &ir::Id) -> &HashSet { &self @@ -381,7 +388,7 @@ impl LiveRangeAnalysis { // calculate reads, but ignore `variable`. we've already dealt with that let reads: HashSet<_> = ReadWriteSet::read_set(assignments) - .filter(|c| is_shareable_component(&sc_clone, c)) + .filter(|c| sc_clone.is_shareable_component(c)) .map(|c| c.clone_name()) .collect(); @@ -392,7 +399,7 @@ impl LiveRangeAnalysis { } else { let reads: HashSet<_> = ReadWriteSet::read_set(group.assignments.iter()) - .filter(|c| is_shareable_component(&sc_clone, c)) + .filter(|c| sc_clone.is_shareable_component(c)) .map(|c| c.clone_name()) .collect(); @@ -406,7 +413,7 @@ impl LiveRangeAnalysis { let writes: HashSet<_> = ReadWriteSet::write_set(assignments.iter()) - .filter(|c| is_shareable_component(&sc_clone, c)) + .filter(|c| sc_clone.is_shareable_component(c)) .map(|c| c.clone_name()) .collect(); @@ -416,11 +423,11 @@ impl LiveRangeAnalysis { fn port_to_cell_name( port: &RRC, - shareable_components: &HashSet, + shareable_components: &ShareSet, ) -> Option { if let ir::PortParent::Cell(cell_wref) = &port.borrow().parent { let cell = cell_wref.upgrade(); - if is_shareable_component(shareable_components, &cell) { + if shareable_components.is_shareable_component(&cell) { return Some(cell.borrow().clone_name()); } } @@ -430,7 +437,7 @@ impl LiveRangeAnalysis { /// Returns (reads, writes) that occur in the [ir::Invoke] statement. fn find_gen_kill_invoke( invoke: &ir::Invoke, - shareable_components: &HashSet, + shareable_components: &ShareSet, ) -> (Prop, Prop) { let reads: Prop = invoke .inputs diff --git a/calyx/src/analysis/mod.rs b/calyx/src/analysis/mod.rs index eb695e8eb4..756ec9e142 100644 --- a/calyx/src/analysis/mod.rs +++ b/calyx/src/analysis/mod.rs @@ -6,6 +6,7 @@ mod control_order; mod control_ports; mod dataflow_order; +mod dominator_map; mod graph; mod graph_coloring; mod live_range_analysis; @@ -18,6 +19,7 @@ mod variable_detection; pub use control_order::ControlOrder; pub use control_ports::ControlPorts; pub use dataflow_order::DataflowOrder; +pub use dominator_map::DominatorMap; pub use graph::GraphAnalysis; pub use graph_coloring::GraphColoring; pub use live_range_analysis::LiveRangeAnalysis; diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index 11a19b8579..0b62aa4767 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -1,13 +1,13 @@ //! Defines the default passes available to [PassManager]. use crate::passes::{ - Canonicalize, ClkInsertion, CollapseControl, CombProp, CompileEmpty, - CompileInvoke, CompileRef, ComponentInliner, ComponentInterface, + Canonicalize, CellShare, ClkInsertion, CollapseControl, CombProp, + CompileEmpty, CompileInvoke, ComponentInliner, ComponentInterface, DeadCellRemoval, DeadGroupRemoval, Externalize, GoInsertion, GroupToInvoke, - HoleInliner, InferStaticTiming, LowerGuards, MergeAssign, MergeStaticPar, - MinimizeRegs, Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, - ResetInsertion, ResourceSharing, SimplifyGuards, StaticParConv, - SynthesisPapercut, TopDownCompileControl, TopDownStaticTiming, - UnrollBounded, WellFormed, WireInliner, + HoleInliner, InferShare, InferStaticTiming, LowerGuards, MergeAssign, + MergeStaticPar, Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, + ResetInsertion, SimplifyGuards, StaticParConv, SynthesisPapercut, + TopDownCompileControl, TopDownStaticTiming, UnrollBounded, WellFormed, + WireInliner, }; use crate::{ errors::CalyxResult, ir::traversal::Named, pass_manager::PassManager, @@ -29,10 +29,10 @@ 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::()?; @@ -67,22 +67,26 @@ impl PassManager { register_alias!(pm, "validate", [WellFormed, Papercut, Canonicalize]); register_alias!( - pm, - "pre-opt", - [ - ComponentInliner, - CombProp, - RemoveCombGroups, // Must run before `infer-static-timing`. - InferStaticTiming, - MergeStaticPar, - DeadGroupRemoval, - StaticParConv, // Must be before `collapse-control` - CollapseControl, - CompileRef, //Must run before 'resource-sharing'. - ResourceSharing, - MinimizeRegs, - ] - ); + pm, + "pre-opt", + [ + ComponentInliner, + CombProp, + RemoveCombGroups, // Must run before `infer-static-timing`. + InferStaticTiming, + MergeStaticPar, + DeadGroupRemoval, + StaticParConv, // Must be before `collapse-control` + CollapseControl, + <<<<<<< Updated upstream + CompileRef, //Must run before 'resource-sharing'. + ResourceSharing, + MinimizeRegs, + ======= + CellShare, + >>>>>>> Stashed changes + ] + ); register_alias!(pm, "compile", [CompileInvoke, TopDownCompileControl]); register_alias!( pm, diff --git a/calyx/src/ir/control.rs b/calyx/src/ir/control.rs index c249f91e67..7c6cfa786b 100644 --- a/calyx/src/ir/control.rs +++ b/calyx/src/ir/control.rs @@ -32,7 +32,7 @@ pub struct If { /// Control for the true branch. pub tbranch: Box, - /// Control for the true branch. + /// Control for the false branch. pub fbranch: Box, /// Attributes attached to this control statement. @@ -87,8 +87,8 @@ pub struct Invoke { #[derive(Debug)] pub struct Empty {} -/// Control AST nodes. #[derive(Debug)] +/// Control AST nodes. pub enum Control { /// Represents sequential composition of control statements. Seq(Seq), diff --git a/calyx/src/passes/minimize_regs.rs b/calyx/src/passes/cell_share.rs similarity index 81% rename from calyx/src/passes/minimize_regs.rs rename to calyx/src/passes/cell_share.rs index aed138df70..ed84c2b33d 100644 --- a/calyx/src/passes/minimize_regs.rs +++ b/calyx/src/passes/cell_share.rs @@ -6,20 +6,20 @@ use crate::{ }; use std::collections::{HashMap, HashSet}; -/// Given a [LiveRangeAnalysis] that specifies the registers alive at each -/// group, minimize the registers used for each component. +/// Given a [LiveRangeAnalysis] that specifies the "share" and "state_share" cells +/// alive at each group, minimizes the cells used for each component. /// -/// This works by constructing an interference graph for each alive register. -/// If two registers are ever alive at the same time, then there is an edge -/// between them in the interference graph. Additionally, if two registers -/// are different sizes, then there is an edge between them. +/// This works by constructing an interference graph for each alive "state_share" cell. +/// If two cells are ever alive at the same time, then there is an edge +/// between them in the interference graph. Additionally, if two cells +/// are different prototypes, then there is an edge between them. /// /// A greedy graph coloring algorithm on the interference graph -/// is used to assign each register a name. +/// is used to assign each cell a name. /// -/// This pass only renames uses of registers. [crate::passes::DeadCellRemoval] should be run after this -/// to actually remove the register definitions. -pub struct MinimizeRegs { +/// This pass only renames uses of cells. [crate::passes::DeadCellRemoval] should be run after this +/// to actually remove the definitions. +pub struct CellShare { live: LiveRangeAnalysis, rewrites: HashMap>, /// Set of state shareable components (as type names) @@ -32,24 +32,24 @@ pub struct MinimizeRegs { cont_cells: HashSet, } -impl Named for MinimizeRegs { +impl Named for CellShare { fn name() -> &'static str { - "minimize-regs" + "cell-share" } fn description() -> &'static str { - "use the fewest possible registers" + "use the fewest possible cells" } } -impl ConstructVisitor for MinimizeRegs { +impl ConstructVisitor for CellShare { fn from(ctx: &ir::Context) -> CalyxResult { let mut state_shareable = HashSet::new(); let mut shareable = HashSet::new(); // add state_share=1 primitives to the state_shareable set for prim in ctx.lib.signatures() { - if let Some(&1) = prim.attributes.get("share") { + if prim.attributes.has("share") { shareable.insert(prim.name.clone()); - } else if let Some(&1) = prim.attributes.get("state_share") { + } else if prim.attributes.has("state_share") { state_shareable.insert(prim.name.clone()); } } @@ -61,7 +61,7 @@ impl ConstructVisitor for MinimizeRegs { } } - Ok(MinimizeRegs { + Ok(CellShare { live: LiveRangeAnalysis::default(), rewrites: HashMap::new(), cont_cells: HashSet::new(), @@ -77,7 +77,7 @@ impl ConstructVisitor for MinimizeRegs { } } -impl ShareComponents for MinimizeRegs { +impl ShareComponents for CellShare { fn initialize( &mut self, comp: &ir::Component, diff --git a/calyx/src/passes/mod.rs b/calyx/src/passes/mod.rs index 89264f4178..b1be94c271 100644 --- a/calyx/src/passes/mod.rs +++ b/calyx/src/passes/mod.rs @@ -1,5 +1,6 @@ //! Passes for the Calyx compiler. mod canonical; +mod cell_share; mod clk_insertion; mod collapse_control; mod comb_prop; @@ -15,18 +16,17 @@ mod externalize; mod go_insertion; mod group_to_invoke; mod hole_inliner; +mod infer_share; mod infer_static_timing; mod lower_guards; mod math_utilities; mod merge_assign; mod merge_static_par; -mod minimize_regs; mod papercut; mod par_to_seq; mod register_unsharing; mod remove_comb_groups; mod reset_insertion; -mod resource_sharing; mod sharing_components; mod simplify_guards; mod static_par_conv; @@ -38,6 +38,7 @@ mod well_formed; mod wire_inliner; pub use canonical::Canonicalize; +pub use cell_share::CellShare; pub use clk_insertion::ClkInsertion; pub use collapse_control::CollapseControl; pub use comb_prop::CombProp; @@ -52,17 +53,16 @@ pub use externalize::Externalize; pub use go_insertion::GoInsertion; pub use group_to_invoke::GroupToInvoke; pub use hole_inliner::HoleInliner; +pub use infer_share::InferShare; pub use infer_static_timing::InferStaticTiming; pub use lower_guards::LowerGuards; pub use merge_assign::MergeAssign; pub use merge_static_par::MergeStaticPar; -pub use minimize_regs::MinimizeRegs; pub use papercut::Papercut; pub use par_to_seq::ParToSeq; pub use register_unsharing::RegisterUnsharing; pub use remove_comb_groups::RemoveCombGroups; pub use reset_insertion::ResetInsertion; -pub use resource_sharing::ResourceSharing; pub use sharing_components::ShareComponents; pub use simplify_guards::SimplifyGuards; pub use static_par_conv::StaticParConv; diff --git a/calyx/src/passes/resource_sharing.rs b/calyx/src/passes/resource_sharing.rs deleted file mode 100644 index cb0f036fa4..0000000000 --- a/calyx/src/passes/resource_sharing.rs +++ /dev/null @@ -1,134 +0,0 @@ -use super::sharing_components::ShareComponents; -use crate::analysis; -use crate::errors::CalyxResult; -use crate::ir::{self, traversal::Named, CloneName, RRC}; -use ir::traversal::ConstructVisitor; -use std::collections::{HashMap, HashSet}; - -/// Rewrites groups to share cells marked with the "share" attribute -/// when the groups are guaranteed to never run in parallel. -pub struct ResourceSharing { - /// Mapping from the name of a group to the cells that it uses. - used_cells_map: HashMap>, - - /// This is used to rewrite all uses of `old_cell` with `new_cell` in the group. - rewrites: HashMap>, - - /// Set of shareable components. - shareable_components: HashSet, - - /// Cell active in continuous assignments - cont_cells: HashSet, -} - -impl Named for ResourceSharing { - fn name() -> &'static str { - "resource-sharing" - } - - fn description() -> &'static str { - "shares resources between groups that don't execute in parallel" - } -} - -impl ConstructVisitor for ResourceSharing { - fn from(ctx: &ir::Context) -> CalyxResult { - let mut shareable_components = HashSet::new(); - // add share=1 primitives to the shareable_components set - for prim in ctx.lib.signatures() { - if let Some(&1) = prim.attributes.get("share") { - shareable_components.insert(prim.name.clone()); - } - } - // add share=1 user defined components to the shareable_components set - for comp in &ctx.components { - if let Some(&1) = comp.attributes.get("share") { - shareable_components.insert(comp.name.clone()); - } - } - Ok(ResourceSharing { - used_cells_map: HashMap::new(), - rewrites: HashMap::new(), - shareable_components, - cont_cells: HashSet::new(), - }) - } - - fn clear_data(&mut self) { - self.used_cells_map = HashMap::new(); - self.rewrites = HashMap::new(); - self.cont_cells = HashSet::new(); - } -} - -impl ShareComponents for ResourceSharing { - fn initialize( - &mut self, - component: &ir::Component, - _sigs: &ir::LibrarySignatures, - ) { - // Cell used in continuous assignments cannot be shared. - self.cont_cells = analysis::ReadWriteSet::uses( - component.continuous_assignments.iter(), - ) - .map(|cr| cr.borrow().clone_name()) - .collect(); - let group_uses = component.groups.iter().map(|group| { - ( - group.clone_name(), - analysis::ReadWriteSet::uses(group.borrow().assignments.iter()) - .filter(|cell| self.cell_filter(&cell.borrow())) - .map(|cell| cell.clone_name()) - .collect::>(), - ) - }); - let cg_uses = component.comb_groups.iter().map(|cg| { - ( - cg.clone_name(), - analysis::ReadWriteSet::uses(cg.borrow().assignments.iter()) - .filter(|cell| self.cell_filter(&cell.borrow())) - .map(|cell| cell.clone_name()) - .collect::>(), - ) - }); - self.used_cells_map = group_uses.chain(cg_uses).collect(); - } - - fn lookup_group_conflicts(&self, group_name: &ir::Id) -> Vec { - self.used_cells_map - .get(group_name) - .unwrap_or_else(|| { - panic!("Missing used cells for group: {}", group_name) - }) - .clone() - } - - fn cell_filter(&self, cell: &ir::Cell) -> bool { - // Cells used in continuous assignments cannot be shared. - if self.cont_cells.contains(cell.name()) { - return false; - } - if let Some(type_name) = cell.type_name() { - self.shareable_components.contains(type_name) - } else { - false - } - } - - fn custom_conflicts(&self, _comp: &ir::Component, mut add_conflicts: F) - where - F: FnMut(Vec), - { - for used in self.used_cells_map.values() { - add_conflicts(used.clone()) - } - } - - fn set_rewrites(&mut self, rewrites: HashMap>) { - self.rewrites = rewrites; - } - - fn get_rewrites(&self) -> &HashMap> { - &self.rewrites - } -} diff --git a/primitives/binary_operators.futil b/primitives/binary_operators.futil index 78baf79b11..3e24b0fc2d 100644 --- a/primitives/binary_operators.futil +++ b/primitives/binary_operators.futil @@ -8,7 +8,7 @@ extern "binary_operators.sv" { WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH)->(out: WIDTH); - primitive std_fp_mult_pipe<"static"=3>[ + primitive std_fp_mult_pipe<"static"=3, "state_share" = 1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -21,7 +21,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_fp_div_pipe[ + primitive std_fp_div_pipe<"state_share" = 1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -48,7 +48,7 @@ extern "binary_operators.sv" { WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_fp_smult_pipe<"static"=3>[ + primitive std_fp_smult_pipe<"static"=3, "state_share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -61,7 +61,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_fp_sdiv_pipe[ + primitive std_fp_sdiv_pipe<"state_share" = 1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -87,7 +87,7 @@ extern "binary_operators.sv" { /// Other unsigned bitnum primitives are found in the core library, /// since they're required for FSM encoding. - primitive std_mult_pipe<"static"=3>[WIDTH]( + primitive std_mult_pipe<"static"=3, "state_share"=1>[WIDTH]( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, @@ -98,7 +98,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_div_pipe[WIDTH]( + primitive std_div_pipe[WIDTH]<"state_share" = 1>( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, @@ -114,7 +114,7 @@ extern "binary_operators.sv" { 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<"static"=3>[WIDTH]( + primitive std_smult_pipe<"static"=3, "state_share"=1>[WIDTH]( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, diff --git a/tests/passes/general_share/was_resource_share/cond-port.expect b/tests/passes/cell-share/cond-port.expect similarity index 100% rename from tests/passes/general_share/was_resource_share/cond-port.expect rename to tests/passes/cell-share/cond-port.expect diff --git a/tests/passes/general_share/was_resource_share/cond-port.futil b/tests/passes/cell-share/cond-port.futil similarity index 94% rename from tests/passes/general_share/was_resource_share/cond-port.futil rename to tests/passes/cell-share/cond-port.futil index 1c6b454df6..9dd4c72d3c 100644 --- a/tests/passes/general_share/was_resource_share/cond-port.futil +++ b/tests/passes/cell-share/cond-port.futil @@ -1,4 +1,4 @@ -// -p remove-comb-groups -p minimize-regs +// -p remove-comb-groups -p cell-share import "primitives/core.futil"; component main() -> () { cells { diff --git a/tests/passes/general_share/was_minimize_regs/condition-register.expect b/tests/passes/cell-share/condition-register.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/condition-register.expect rename to tests/passes/cell-share/condition-register.expect diff --git a/tests/passes/general_share/was_minimize_regs/condition-register.futil b/tests/passes/cell-share/condition-register.futil similarity index 87% rename from tests/passes/general_share/was_minimize_regs/condition-register.futil rename to tests/passes/cell-share/condition-register.futil index c519cdb3e3..12ea3f7f0c 100644 --- a/tests/passes/general_share/was_minimize_regs/condition-register.futil +++ b/tests/passes/cell-share/condition-register.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> () { cells { diff --git a/tests/passes/general_share/was_resource_share/continuous-assign.expect b/tests/passes/cell-share/continuous-assign-no-groups.expect similarity index 100% rename from tests/passes/general_share/was_resource_share/continuous-assign.expect rename to tests/passes/cell-share/continuous-assign-no-groups.expect diff --git a/tests/passes/general_share/was_resource_share/continuous-assign.futil b/tests/passes/cell-share/continuous-assign-no-groups.futil similarity index 91% rename from tests/passes/general_share/was_resource_share/continuous-assign.futil rename to tests/passes/cell-share/continuous-assign-no-groups.futil index ba758bb7ca..11817d462c 100644 --- a/tests/passes/general_share/was_resource_share/continuous-assign.futil +++ b/tests/passes/cell-share/continuous-assign-no-groups.futil @@ -1,4 +1,4 @@ -// -p validate -p minimize-regs +// -p validate -p cell-share import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { diff --git a/tests/passes/general_share/was_minimize_regs/continuous-assignment.expect b/tests/passes/cell-share/continuous-assignment.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/continuous-assignment.expect rename to tests/passes/cell-share/continuous-assignment.expect diff --git a/tests/passes/general_share/was_minimize_regs/continuous-assignment.futil b/tests/passes/cell-share/continuous-assignment.futil similarity index 85% rename from tests/passes/general_share/was_minimize_regs/continuous-assignment.futil rename to tests/passes/cell-share/continuous-assignment.futil index edfa115196..84f0d26af8 100644 --- a/tests/passes/general_share/was_minimize_regs/continuous-assignment.futil +++ b/tests/passes/cell-share/continuous-assignment.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> (x_out: 32) { cells { diff --git a/tests/passes/general_share/was_minimize_regs/escape-boundary.expect b/tests/passes/cell-share/escape-boundary.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/escape-boundary.expect rename to tests/passes/cell-share/escape-boundary.expect diff --git a/tests/passes/general_share/was_minimize_regs/escape-boundary.futil b/tests/passes/cell-share/escape-boundary.futil similarity index 84% rename from tests/passes/general_share/was_minimize_regs/escape-boundary.futil rename to tests/passes/cell-share/escape-boundary.futil index 99f842abf3..b9fcf279b2 100644 --- a/tests/passes/general_share/was_minimize_regs/escape-boundary.futil +++ b/tests/passes/cell-share/escape-boundary.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> (x_out: 32) { cells { diff --git a/tests/passes/general_share/was_minimize_regs/invoke.expect b/tests/passes/cell-share/invoke.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/invoke.expect rename to tests/passes/cell-share/invoke.expect diff --git a/tests/passes/general_share/was_minimize_regs/invoke.futil b/tests/passes/cell-share/invoke.futil similarity index 92% rename from tests/passes/general_share/was_minimize_regs/invoke.futil rename to tests/passes/cell-share/invoke.futil index db04cc8718..656507745a 100644 --- a/tests/passes/general_share/was_minimize_regs/invoke.futil +++ b/tests/passes/cell-share/invoke.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component add(left: 32, right: 32) -> (out: 32) { diff --git a/tests/passes/general_share/was_minimize_regs/live-register-analysis.expect b/tests/passes/cell-share/live-register-analysis.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/live-register-analysis.expect rename to tests/passes/cell-share/live-register-analysis.expect diff --git a/tests/passes/general_share/was_minimize_regs/live-register-analysis.fuse b/tests/passes/cell-share/live-register-analysis.fuse similarity index 100% rename from tests/passes/general_share/was_minimize_regs/live-register-analysis.fuse rename to tests/passes/cell-share/live-register-analysis.fuse diff --git a/tests/passes/general_share/was_minimize_regs/live-register-analysis.futil b/tests/passes/cell-share/live-register-analysis.futil similarity index 96% rename from tests/passes/general_share/was_minimize_regs/live-register-analysis.futil rename to tests/passes/cell-share/live-register-analysis.futil index d1dab7c962..784fa9f714 100644 --- a/tests/passes/general_share/was_minimize_regs/live-register-analysis.futil +++ b/tests/passes/cell-share/live-register-analysis.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> () { cells { diff --git a/tests/passes/general_share/was_resource_share/multiple-cells.expect b/tests/passes/cell-share/multiple-adders.expect similarity index 100% rename from tests/passes/general_share/was_resource_share/multiple-cells.expect rename to tests/passes/cell-share/multiple-adders.expect diff --git a/tests/passes/general_share/was_resource_share/multiple-cells.futil b/tests/passes/cell-share/multiple-adders.futil similarity index 97% rename from tests/passes/general_share/was_resource_share/multiple-cells.futil rename to tests/passes/cell-share/multiple-adders.futil index 8373d0d8b6..0527e4b0d5 100644 --- a/tests/passes/general_share/was_resource_share/multiple-cells.futil +++ b/tests/passes/cell-share/multiple-adders.futil @@ -1,4 +1,4 @@ -// -p minimize-regs +// -p cell-share import "primitives/core.futil"; component main() -> () { cells { diff --git a/tests/passes/general_share/was_minimize_regs/nested-par.expect b/tests/passes/cell-share/nested-par.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/nested-par.expect rename to tests/passes/cell-share/nested-par.expect diff --git a/tests/passes/general_share/was_minimize_regs/nested-par.futil b/tests/passes/cell-share/nested-par.futil similarity index 95% rename from tests/passes/general_share/was_minimize_regs/nested-par.futil rename to tests/passes/cell-share/nested-par.futil index a9a3dc9978..49da20ec88 100644 --- a/tests/passes/general_share/was_minimize_regs/nested-par.futil +++ b/tests/passes/cell-share/nested-par.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> () { cells { diff --git a/tests/passes/general_share/was_minimize_regs/par-while-liveness.expect b/tests/passes/cell-share/par-while-liveness.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/par-while-liveness.expect rename to tests/passes/cell-share/par-while-liveness.expect diff --git a/tests/passes/general_share/was_minimize_regs/par-while-liveness.futil b/tests/passes/cell-share/par-while-liveness.futil similarity index 97% rename from tests/passes/general_share/was_minimize_regs/par-while-liveness.futil rename to tests/passes/cell-share/par-while-liveness.futil index f3c21200ea..ad8f4970b6 100644 --- a/tests/passes/general_share/was_minimize_regs/par-while-liveness.futil +++ b/tests/passes/cell-share/par-while-liveness.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> () { cells { diff --git a/tests/passes/general_share/was_minimize_regs/par-write.expect b/tests/passes/cell-share/par-write.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/par-write.expect rename to tests/passes/cell-share/par-write.expect diff --git a/tests/passes/general_share/was_minimize_regs/par-write.futil b/tests/passes/cell-share/par-write.futil similarity index 82% rename from tests/passes/general_share/was_minimize_regs/par-write.futil rename to tests/passes/cell-share/par-write.futil index b99210fdcb..0a75985e91 100644 --- a/tests/passes/general_share/was_minimize_regs/par-write.futil +++ b/tests/passes/cell-share/par-write.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> () { diff --git a/tests/passes/general_share/was_resource_share/share.expect b/tests/passes/cell-share/share-adders.expect similarity index 100% rename from tests/passes/general_share/was_resource_share/share.expect rename to tests/passes/cell-share/share-adders.expect diff --git a/tests/passes/general_share/was_resource_share/share.futil b/tests/passes/cell-share/share-adders.futil similarity index 96% rename from tests/passes/general_share/was_resource_share/share.futil rename to tests/passes/cell-share/share-adders.futil index 4146b3c2d2..c5d226a063 100644 --- a/tests/passes/general_share/was_resource_share/share.futil +++ b/tests/passes/cell-share/share-adders.futil @@ -1,4 +1,4 @@ -// -p minimize-regs +// -p cell-share import "primitives/core.futil"; component main() -> () { diff --git a/tests/passes/general_share/was_resource_share/share-component.expect b/tests/passes/cell-share/share-component.expect similarity index 100% rename from tests/passes/general_share/was_resource_share/share-component.expect rename to tests/passes/cell-share/share-component.expect diff --git a/tests/passes/general_share/was_resource_share/share-component.futil b/tests/passes/cell-share/share-component.futil similarity index 97% rename from tests/passes/general_share/was_resource_share/share-component.futil rename to tests/passes/cell-share/share-component.futil index 28cb37a8fd..974b735735 100644 --- a/tests/passes/general_share/was_resource_share/share-component.futil +++ b/tests/passes/cell-share/share-component.futil @@ -1,4 +1,4 @@ -// -p minimize-regs +// -p cell-share import "primitives/core.futil"; component my_add<"share"=1>(left: 32, right: 32) -> (out: 32) { diff --git a/tests/passes/general_share/was_minimize_regs/simple-liveness.expect b/tests/passes/cell-share/simple-liveness.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/simple-liveness.expect rename to tests/passes/cell-share/simple-liveness.expect diff --git a/tests/passes/general_share/was_minimize_regs/simple-liveness.futil b/tests/passes/cell-share/simple-liveness.futil similarity index 91% rename from tests/passes/general_share/was_minimize_regs/simple-liveness.futil rename to tests/passes/cell-share/simple-liveness.futil index 17215282a6..235ba9f4e4 100644 --- a/tests/passes/general_share/was_minimize_regs/simple-liveness.futil +++ b/tests/passes/cell-share/simple-liveness.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> () { cells { diff --git a/tests/passes/general_share/was_minimize_regs/thread-local.expect b/tests/passes/cell-share/thread-local.expect similarity index 100% rename from tests/passes/general_share/was_minimize_regs/thread-local.expect rename to tests/passes/cell-share/thread-local.expect diff --git a/tests/passes/general_share/was_minimize_regs/thread-local.futil b/tests/passes/cell-share/thread-local.futil similarity index 91% rename from tests/passes/general_share/was_minimize_regs/thread-local.futil rename to tests/passes/cell-share/thread-local.futil index 1e5db45804..ea4d802bb9 100644 --- a/tests/passes/general_share/was_minimize_regs/thread-local.futil +++ b/tests/passes/cell-share/thread-local.futil @@ -1,4 +1,4 @@ -// -p well-formed -p remove-comb-groups -p minimize-regs -p dead-cell-removal +// -p well-formed -p remove-comb-groups -p cell-share -p dead-cell-removal import "primitives/core.futil"; component main() -> () { diff --git a/tests/passes/regressions/group-multi-drive.futil b/tests/passes/regressions/group-multi-drive.futil index 8fded95f1e..765d85e0b8 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 well-formed -d papercut -d resource-sharing -p simplify-guards +// -p all -d infer-static-timing -d well-formed -d papercut -d cell-share -p simplify-guards import "primitives/core.futil"; component main() -> () { From 5c6202ea48c30266b169855c3067d3949f1b1689 Mon Sep 17 00:00:00 2001 From: Caleb Date: Sun, 26 Jun 2022 17:07:59 -0400 Subject: [PATCH 21/32] removed dominators stuff --- calyx/src/analysis/mod.rs | 2 - calyx/src/default_passes.rs | 50 ++++++++----------- calyx/src/passes/cell_share.rs | 28 +++++++++-- calyx/src/passes/mod.rs | 2 - primitives/binary_operators.futil | 14 +++--- .../passes/cell-share/share-component.expect | 43 ---------------- tests/passes/cell-share/share-component.futil | 44 ---------------- 7 files changed, 52 insertions(+), 131 deletions(-) delete mode 100644 tests/passes/cell-share/share-component.expect delete mode 100644 tests/passes/cell-share/share-component.futil diff --git a/calyx/src/analysis/mod.rs b/calyx/src/analysis/mod.rs index 756ec9e142..eb695e8eb4 100644 --- a/calyx/src/analysis/mod.rs +++ b/calyx/src/analysis/mod.rs @@ -6,7 +6,6 @@ mod control_order; mod control_ports; mod dataflow_order; -mod dominator_map; mod graph; mod graph_coloring; mod live_range_analysis; @@ -19,7 +18,6 @@ mod variable_detection; pub use control_order::ControlOrder; pub use control_ports::ControlPorts; pub use dataflow_order::DataflowOrder; -pub use dominator_map::DominatorMap; pub use graph::GraphAnalysis; pub use graph_coloring::GraphColoring; pub use live_range_analysis::LiveRangeAnalysis; diff --git a/calyx/src/default_passes.rs b/calyx/src/default_passes.rs index 0b62aa4767..e147b12c39 100644 --- a/calyx/src/default_passes.rs +++ b/calyx/src/default_passes.rs @@ -1,13 +1,13 @@ //! Defines the default passes available to [PassManager]. use crate::passes::{ Canonicalize, CellShare, ClkInsertion, CollapseControl, CombProp, - CompileEmpty, CompileInvoke, ComponentInliner, ComponentInterface, - DeadCellRemoval, DeadGroupRemoval, Externalize, GoInsertion, GroupToInvoke, - HoleInliner, InferShare, InferStaticTiming, LowerGuards, MergeAssign, - MergeStaticPar, Papercut, ParToSeq, RegisterUnsharing, RemoveCombGroups, - ResetInsertion, SimplifyGuards, StaticParConv, SynthesisPapercut, - TopDownCompileControl, TopDownStaticTiming, UnrollBounded, WellFormed, - WireInliner, + CompileEmpty, CompileInvoke, CompileRef, ComponentInliner, + ComponentInterface, DeadCellRemoval, DeadGroupRemoval, Externalize, + GoInsertion, GroupToInvoke, HoleInliner, InferStaticTiming, LowerGuards, + MergeAssign, MergeStaticPar, Papercut, ParToSeq, RegisterUnsharing, + RemoveCombGroups, ResetInsertion, SimplifyGuards, StaticParConv, + SynthesisPapercut, TopDownCompileControl, TopDownStaticTiming, + UnrollBounded, WellFormed, WireInliner, }; use crate::{ errors::CalyxResult, ir::traversal::Named, pass_manager::PassManager, @@ -31,7 +31,6 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; - pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -67,26 +66,21 @@ impl PassManager { register_alias!(pm, "validate", [WellFormed, Papercut, Canonicalize]); register_alias!( - pm, - "pre-opt", - [ - ComponentInliner, - CombProp, - RemoveCombGroups, // Must run before `infer-static-timing`. - InferStaticTiming, - MergeStaticPar, - DeadGroupRemoval, - StaticParConv, // Must be before `collapse-control` - CollapseControl, - <<<<<<< Updated upstream - CompileRef, //Must run before 'resource-sharing'. - ResourceSharing, - MinimizeRegs, - ======= - CellShare, - >>>>>>> Stashed changes - ] - ); + pm, + "pre-opt", + [ + ComponentInliner, + CombProp, + RemoveCombGroups, // Must run before `infer-static-timing`. + InferStaticTiming, + MergeStaticPar, + DeadGroupRemoval, + StaticParConv, // Must be before `collapse-control` + CollapseControl, + CompileRef, //Must run before 'resource-sharing'. + CellShare, + ] + ); register_alias!(pm, "compile", [CompileInvoke, TopDownCompileControl]); register_alias!( pm, diff --git a/calyx/src/passes/cell_share.rs b/calyx/src/passes/cell_share.rs index ed84c2b33d..a57ebb0322 100644 --- a/calyx/src/passes/cell_share.rs +++ b/calyx/src/passes/cell_share.rs @@ -30,6 +30,8 @@ pub struct CellShare { /// Cell active in continuous assignments cont_cells: HashSet, + //Ref cells + ref_cells: HashSet, } impl Named for CellShare { @@ -56,8 +58,8 @@ impl ConstructVisitor for CellShare { // add share=1 user defined components to the shareable_components set for comp in &ctx.components { - if let Some(&1) = comp.attributes.get("share") { - shareable.insert(comp.name.clone()); + if let Some(&1) = comp.attributes.get("state_share") { + state_shareable.insert(comp.name.clone()); } } @@ -65,6 +67,7 @@ impl ConstructVisitor for CellShare { live: LiveRangeAnalysis::default(), rewrites: HashMap::new(), cont_cells: HashSet::new(), + ref_cells: HashSet::new(), state_shareable, shareable, }) @@ -74,6 +77,7 @@ impl ConstructVisitor for CellShare { self.rewrites = HashMap::new(); self.live = LiveRangeAnalysis::default(); self.cont_cells = HashSet::new(); + self.ref_cells = HashSet::new(); } } @@ -87,6 +91,12 @@ impl ShareComponents for CellShare { ReadWriteSet::uses(comp.continuous_assignments.iter()) .map(|cr| cr.borrow().clone_name()) .collect(); + self.ref_cells = comp + .cells + .iter() + .filter(|cell| cell.borrow().is_reference()) + .map(|cell| cell.borrow().clone_name()) + .collect(); self.live = LiveRangeAnalysis::new( comp, @@ -100,14 +110,19 @@ impl ShareComponents for CellShare { self.live .get(group_name) .iter() - .filter(|cell_name| !self.cont_cells.contains(cell_name)) + .filter(|cell_name| { + !(self.cont_cells.contains(cell_name) + || self.ref_cells.contains(cell_name)) + }) .cloned() .collect() } fn cell_filter(&self, cell: &ir::Cell) -> bool { // Cells used in continuous assignments cannot be shared. - if self.cont_cells.contains(cell.name()) { + if self.cont_cells.contains(cell.name()) + || self.ref_cells.contains(cell.name()) + { return false; } if let Some(name) = cell.type_name() { @@ -126,7 +141,10 @@ impl ShareComponents for CellShare { add_conflicts( conflicts .iter() - .filter(|cell_name| !self.cont_cells.contains(cell_name)) + .filter(|cell_name| { + !(self.cont_cells.contains(cell_name) + || self.ref_cells.contains(cell_name)) + }) .cloned() .collect(), ); diff --git a/calyx/src/passes/mod.rs b/calyx/src/passes/mod.rs index b1be94c271..472f42e656 100644 --- a/calyx/src/passes/mod.rs +++ b/calyx/src/passes/mod.rs @@ -16,7 +16,6 @@ mod externalize; mod go_insertion; mod group_to_invoke; mod hole_inliner; -mod infer_share; mod infer_static_timing; mod lower_guards; mod math_utilities; @@ -53,7 +52,6 @@ pub use externalize::Externalize; pub use go_insertion::GoInsertion; pub use group_to_invoke::GroupToInvoke; pub use hole_inliner::HoleInliner; -pub use infer_share::InferShare; pub use infer_static_timing::InferStaticTiming; pub use lower_guards::LowerGuards; pub use merge_assign::MergeAssign; diff --git a/primitives/binary_operators.futil b/primitives/binary_operators.futil index 3e24b0fc2d..78baf79b11 100644 --- a/primitives/binary_operators.futil +++ b/primitives/binary_operators.futil @@ -8,7 +8,7 @@ extern "binary_operators.sv" { WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH)->(out: WIDTH); - primitive std_fp_mult_pipe<"static"=3, "state_share" = 1>[ + primitive std_fp_mult_pipe<"static"=3>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -21,7 +21,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_fp_div_pipe<"state_share" = 1>[ + primitive std_fp_div_pipe[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -48,7 +48,7 @@ extern "binary_operators.sv" { WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_fp_smult_pipe<"static"=3, "state_share"=1>[ + primitive std_fp_smult_pipe<"static"=3>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -61,7 +61,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_fp_sdiv_pipe<"state_share" = 1>[ + primitive std_fp_sdiv_pipe[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -87,7 +87,7 @@ extern "binary_operators.sv" { /// Other unsigned bitnum primitives are found in the core library, /// since they're required for FSM encoding. - primitive std_mult_pipe<"static"=3, "state_share"=1>[WIDTH]( + primitive std_mult_pipe<"static"=3>[WIDTH]( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, @@ -98,7 +98,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_div_pipe[WIDTH]<"state_share" = 1>( + primitive std_div_pipe[WIDTH]( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, @@ -114,7 +114,7 @@ extern "binary_operators.sv" { 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<"static"=3, "state_share"=1>[WIDTH]( + primitive std_smult_pipe<"static"=3>[WIDTH]( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, diff --git a/tests/passes/cell-share/share-component.expect b/tests/passes/cell-share/share-component.expect deleted file mode 100644 index 8c271b756f..0000000000 --- a/tests/passes/cell-share/share-component.expect +++ /dev/null @@ -1,43 +0,0 @@ -import "primitives/core.futil"; -component my_add<"share"=1>(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { - cells { - add = std_add(32); - } - wires { - add.left = left; - add.right = right; - out = add.out; - } - - control {} -} -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - add0 = my_add(); - add1 = my_add(); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - - control { - seq { - upd0; - upd1; - } - } -} diff --git a/tests/passes/cell-share/share-component.futil b/tests/passes/cell-share/share-component.futil deleted file mode 100644 index 974b735735..0000000000 --- a/tests/passes/cell-share/share-component.futil +++ /dev/null @@ -1,44 +0,0 @@ -// -p cell-share - -import "primitives/core.futil"; -component my_add<"share"=1>(left: 32, right: 32) -> (out: 32) { - cells { - add = std_add(32); - } - wires { - add.left = left; - add.right = right; - out = add.out; - } - control {} -} - -component main() -> () { - cells { - add0 = my_add(); - add1 = my_add(); - x_0 = std_reg(32); - } - wires { - group upd0 { - add0.left = x_0.out; - add0.right = 32'd1; - x_0.in = add0.out; - x_0.write_en = 1'd1; - upd0[done] = x_0.done ? 1'd1; - } - group upd1 { - add1.left = x_0.out; - add1.right = 32'd1; - x_0.in = add1.out; - x_0.write_en = 1'd1; - upd1[done] = x_0.done ? 1'd1; - } - } - control { - seq { - upd0; - upd1; - } - } -} From 4f2ce56e3d8bb57358b2bbfe3b10737d6bc0ad1d Mon Sep 17 00:00:00 2001 From: Caleb Date: Sun, 26 Jun 2022 17:24:06 -0400 Subject: [PATCH 22/32] minor changes to cell_share.rs --- calyx/src/passes/cell_share.rs | 45 ++++++++++++++-------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/calyx/src/passes/cell_share.rs b/calyx/src/passes/cell_share.rs index a57ebb0322..06f756f894 100644 --- a/calyx/src/passes/cell_share.rs +++ b/calyx/src/passes/cell_share.rs @@ -28,10 +28,8 @@ pub struct CellShare { /// Set of shareable components (as type names) shareable: HashSet, - /// Cell active in continuous assignments - cont_cells: HashSet, - //Ref cells - ref_cells: HashSet, + /// Cell active in continuous assignments, or ref cells (we want to ignore both) + cont_ref_cells: HashSet, } impl Named for CellShare { @@ -56,18 +54,18 @@ impl ConstructVisitor for CellShare { } } - // add share=1 user defined components to the shareable_components set + // add state_share=1 user defined components to the state_shareable set for comp in &ctx.components { - if let Some(&1) = comp.attributes.get("state_share") { + if comp.attributes.has("state_share") { state_shareable.insert(comp.name.clone()); } + //it seems like we never want to have a "share" user-defined components } Ok(CellShare { live: LiveRangeAnalysis::default(), rewrites: HashMap::new(), - cont_cells: HashSet::new(), - ref_cells: HashSet::new(), + cont_ref_cells: HashSet::new(), state_shareable, shareable, }) @@ -76,8 +74,7 @@ impl ConstructVisitor for CellShare { fn clear_data(&mut self) { self.rewrites = HashMap::new(); self.live = LiveRangeAnalysis::default(); - self.cont_cells = HashSet::new(); - self.ref_cells = HashSet::new(); + self.cont_ref_cells = HashSet::new(); } } @@ -87,16 +84,18 @@ impl ShareComponents for CellShare { comp: &ir::Component, _sigs: &ir::LibrarySignatures, ) { - self.cont_cells = + //add cont cells + self.cont_ref_cells = ReadWriteSet::uses(comp.continuous_assignments.iter()) .map(|cr| cr.borrow().clone_name()) .collect(); - self.ref_cells = comp - .cells - .iter() - .filter(|cell| cell.borrow().is_reference()) - .map(|cell| cell.borrow().clone_name()) - .collect(); + //add ref cells + self.cont_ref_cells.extend( + comp.cells + .iter() + .filter(|cell| cell.borrow().is_reference()) + .map(|cell| cell.borrow().clone_name()), + ); self.live = LiveRangeAnalysis::new( comp, @@ -110,19 +109,14 @@ impl ShareComponents for CellShare { self.live .get(group_name) .iter() - .filter(|cell_name| { - !(self.cont_cells.contains(cell_name) - || self.ref_cells.contains(cell_name)) - }) + .filter(|cell_name| !self.cont_ref_cells.contains(cell_name)) .cloned() .collect() } fn cell_filter(&self, cell: &ir::Cell) -> bool { // Cells used in continuous assignments cannot be shared. - if self.cont_cells.contains(cell.name()) - || self.ref_cells.contains(cell.name()) - { + if self.cont_ref_cells.contains(cell.name()) { return false; } if let Some(name) = cell.type_name() { @@ -142,8 +136,7 @@ impl ShareComponents for CellShare { conflicts .iter() .filter(|cell_name| { - !(self.cont_cells.contains(cell_name) - || self.ref_cells.contains(cell_name)) + !self.cont_ref_cells.contains(cell_name) }) .cloned() .collect(), From 82b40722583ae8dd308174354b38e329cd357228 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 27 Jun 2022 11:56:49 -0400 Subject: [PATCH 23/32] can share state_share components --- calyx/src/analysis/live_range_analysis.rs | 6 +- calyx/src/analysis/variable_detection.rs | 26 ++++-- calyx/src/passes/cell_share.rs | 2 + primitives/binary_operators.futil | 14 +-- tests/passes/cell-share/share-comp.expect | 47 ++++++++++ tests/passes/cell-share/share-comp.futil | 48 ++++++++++ tests/passes/cell-share/share-mult.expect | 99 +++++++++++++++++++++ tests/passes/cell-share/share-mult.futil | 101 ++++++++++++++++++++++ 8 files changed, 326 insertions(+), 17 deletions(-) create mode 100644 tests/passes/cell-share/share-comp.expect create mode 100644 tests/passes/cell-share/share-comp.futil create mode 100644 tests/passes/cell-share/share-mult.expect create mode 100644 tests/passes/cell-share/share-mult.futil diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index da16706974..42f92e3c3e 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -237,7 +237,7 @@ impl Debug for LiveRangeAnalysis { } #[derive(Default, Clone)] -struct ShareSet { +pub struct ShareSet { shareable: HashSet, } @@ -247,7 +247,7 @@ impl ShareSet { } //given a set of shareable and a cell, determines whether cell's //type is shareable or not - fn is_shareable_component(&self, cell: &RRC) -> bool { + pub fn is_shareable_component(&self, cell: &RRC) -> bool { if let Some(type_name) = cell.borrow().type_name() { self.shareable.contains(type_name) } else { @@ -340,7 +340,7 @@ impl LiveRangeAnalysis { let group = grp.borrow(); let name = group.name(); if !self.variable_like.contains_key(name) { - let res = VariableDetection::variable_like(grp); + let res = VariableDetection::variable_like(grp, &self.state_share); self.variable_like.insert(grp.clone_name(), res); } &self.variable_like[name] diff --git a/calyx/src/analysis/variable_detection.rs b/calyx/src/analysis/variable_detection.rs index 65cd06700a..4fc5c79f69 100644 --- a/calyx/src/analysis/variable_detection.rs +++ b/calyx/src/analysis/variable_detection.rs @@ -1,4 +1,5 @@ use super::{GraphAnalysis, ReadWriteSet}; +use crate::analysis::live_range_analysis::ShareSet; use crate::ir; use ir::{CloneName, RRC}; @@ -7,16 +8,19 @@ pub struct VariableDetection; impl VariableDetection { /// A group is variable like if it: - /// - only uses single register - /// - has `write_en = 1'd1` - /// - has `g[done] = reg.done` + /// - only writes to a single cell that has type state_share + /// - has `@go` port equal to `1'd1` + /// - has `g[done] = cell.done` /// Returns the name of the register if such a group is detected, /// otherwise returns `None`. - pub fn variable_like(group_ref: &RRC) -> Option { + pub fn variable_like( + group_ref: &RRC, + state_share: &ShareSet, + ) -> Option { let group = group_ref.borrow(); let writes = ReadWriteSet::write_set(group.assignments.iter()) - .filter(|cell| cell.borrow().type_name() == Some(&"std_reg".into())) + .filter(|cell| state_share.is_shareable_component(cell)) .collect::>(); if writes.len() != 1 { @@ -25,12 +29,20 @@ impl VariableDetection { } let cell = writes[0].borrow(); - // check if 1 is being written into write_en. This also checks + + // check if 1 is being written into go port. This also checks // if guard is empty, because if it isn't this would show up as // a write let graph = GraphAnalysis::from(&*group); let activation = graph - .writes_to(&cell.get("write_en").borrow()) + .writes_to( + &cell + .ports + .iter() + .find(|port| port.borrow().attributes.has("go")) + .unwrap_or_else(|| unreachable!("no go port on cell")) + .borrow(), + ) .map(|src| src.borrow().is_constant(1, 1)) .collect::>(); if activation.len() != 1 || (!activation.is_empty() && !activation[0]) { diff --git a/calyx/src/passes/cell_share.rs b/calyx/src/passes/cell_share.rs index 06f756f894..d2b06fa617 100644 --- a/calyx/src/passes/cell_share.rs +++ b/calyx/src/passes/cell_share.rs @@ -131,11 +131,13 @@ impl ShareComponents for CellShare { F: FnMut(Vec), { for group in comp.groups.iter() { + //println!("group name: {}: ", group.borrow().name().id.clone()); let conflicts = self.live.get(group.borrow().name()); add_conflicts( conflicts .iter() .filter(|cell_name| { + //println!("{}", cell_name); !self.cont_ref_cells.contains(cell_name) }) .cloned() diff --git a/primitives/binary_operators.futil b/primitives/binary_operators.futil index 78baf79b11..377ab2b0ce 100644 --- a/primitives/binary_operators.futil +++ b/primitives/binary_operators.futil @@ -8,7 +8,7 @@ extern "binary_operators.sv" { WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH)->(out: WIDTH); - primitive std_fp_mult_pipe<"static"=3>[ + primitive std_fp_mult_pipe<"static"=3,"state_share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -21,7 +21,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_fp_div_pipe[ + primitive std_fp_div_pipe<"state_share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -48,7 +48,7 @@ extern "binary_operators.sv" { WIDTH, INT_WIDTH, FRAC_WIDTH ](left: WIDTH, right: WIDTH) -> (out: WIDTH); - primitive std_fp_smult_pipe<"static"=3>[ + primitive std_fp_smult_pipe<"static"=3, "state_share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -61,7 +61,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_fp_sdiv_pipe[ + primitive std_fp_sdiv_pipe<"state_share"=1>[ WIDTH, INT_WIDTH, FRAC_WIDTH ]( @clk clk: 1, @@ -87,7 +87,7 @@ extern "binary_operators.sv" { /// Other unsigned bitnum primitives are found in the core library, /// since they're required for FSM encoding. - primitive std_mult_pipe<"static"=3>[WIDTH]( + primitive std_mult_pipe<"static"=3, "state_share"=1>[WIDTH]( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, @@ -98,7 +98,7 @@ extern "binary_operators.sv" { @done done: 1 ); - primitive std_div_pipe[WIDTH]( + primitive std_div_pipe<"state_share"=1>[WIDTH]( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, @@ -114,7 +114,7 @@ extern "binary_operators.sv" { 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<"static"=3>[WIDTH]( + primitive std_smult_pipe<"static"=3, "state_share"=1>[WIDTH]( @clk clk: 1, @reset reset: 1, @write_together(1) @go go: 1, diff --git a/tests/passes/cell-share/share-comp.expect b/tests/passes/cell-share/share-comp.expect new file mode 100644 index 0000000000..9d57190cf6 --- /dev/null +++ b/tests/passes/cell-share/share-comp.expect @@ -0,0 +1,47 @@ +import "primitives/core.futil"; +component add_5<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + group add_group { + add.left = 32'd5; + add.right = in; + r.write_en = 1'd1; + r.in = add.out; + add_group[done] = r.done; + } + out = r.out; + } + + control { + add_group; + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add0 = add_5(); + add1 = add_5(); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.go = 1'd1; + add0.in = 32'd5; + upd0[done] = add0.done; + } + group upd1 { + add0.go = 1'd1; + add0.in = 32'd8; + upd1[done] = add0.done; + } + } + + control { + seq { + upd0; + upd1; + } + } +} diff --git a/tests/passes/cell-share/share-comp.futil b/tests/passes/cell-share/share-comp.futil new file mode 100644 index 0000000000..d64d36cda7 --- /dev/null +++ b/tests/passes/cell-share/share-comp.futil @@ -0,0 +1,48 @@ +// -p cell-share + +import "primitives/core.futil"; +component add_5<"state_share"=1>(in:32) -> (out: 32) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + group add_group{ + add.left = 32'd5; + add.right = in; + r.write_en = 1'd1; + r.in = add.out; + add_group[done] = r.done; + } + out = r.out; + } + control { + add_group; + } +} + +component main() -> () { + cells { + add0 = add_5(); + add1 = add_5(); + x_0 = std_reg(32); + } + wires { + group upd0 { + add0.go = 1'd1; + add0.in = 32'd5; + upd0[done] = add0.done; + } + group upd1 { + add1.go = 1'd1; + add1.in = 32'd8; + upd1[done] = add1.done; + } + } + control { + seq { + upd0; + upd1; + } + } +} \ No newline at end of file diff --git a/tests/passes/cell-share/share-mult.expect b/tests/passes/cell-share/share-mult.expect new file mode 100644 index 0000000000..a0096f2996 --- /dev/null +++ b/tests/passes/cell-share/share-mult.expect @@ -0,0 +1,99 @@ +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + @external A0 = std_mem_d1(32, 2, 2); + A_read0_0 = std_reg(32); + A_read1_0 = std_reg(32); + @external B0 = std_mem_d1(32, 2, 2); + B_read0_0 = std_reg(32); + B_read1_0 = std_reg(32); + bin_read0_0 = std_reg(32); + bin_read1_0 = std_reg(32); + const0 = std_const(2, 0); + const1 = std_const(2, 0); + const2 = std_const(2, 0); + const3 = std_const(2, 0); + mult_pipe0 = std_mult_pipe(32); + mult_pipe1 = std_mult_pipe(32); + x_0 = std_reg(32); + y_0 = std_reg(32); + } + wires { + group prelet0 { + mult_pipe0.left = A_read0_0.out; + mult_pipe0.right = B_read0_0.out; + mult_pipe0.go = 1'd1; + prelet0[done] = mult_pipe0.done; + } + group let0 { + A_read0_0.in = mult_pipe0.out; + A_read0_0.write_en = 1'd1; + let0[done] = A_read0_0.done; + } + group let1<"static"=1> { + B_read0_0.in = A_read0_0.out; + B_read0_0.write_en = 1'd1; + let1[done] = B_read0_0.done; + } + group prelet2 { + mult_pipe0.left = A_read0_0.out; + mult_pipe0.right = B_read0_0.out; + mult_pipe0.go = 1'd1; + prelet2[done] = mult_pipe0.done; + } + group let2 { + A_read0_0.in = mult_pipe0.out; + A_read0_0.write_en = 1'd1; + let2[done] = A_read0_0.done; + } + group let3<"static"=1> { + B_read0_0.in = A_read0_0.out; + B_read0_0.write_en = 1'd1; + let3[done] = B_read0_0.done; + } + group upd0<"static"=1> { + A_read0_0.write_en = 1'd1; + A0.addr0 = const0.out; + A_read0_0.in = A0.read_data; + upd0[done] = A_read0_0.done; + } + group upd1<"static"=1> { + B_read0_0.write_en = 1'd1; + B0.addr0 = const1.out; + B_read0_0.in = B0.read_data; + upd1[done] = B_read0_0.done; + } + group upd2<"static"=1> { + A_read0_0.write_en = 1'd1; + A0.addr0 = const0.out; + A_read0_0.in = A0.read_data; + upd2[done] = A_read0_0.done; + } + group upd3<"static"=1> { + B_read0_0.write_en = 1'd1; + B0.addr0 = const1.out; + B_read0_0.in = B0.read_data; + upd3[done] = B_read0_0.done; + } + } + + control { + seq { + par { + upd0; + upd1; + } + prelet0; + let0; + let1; + par { + upd2; + upd3; + } + prelet2; + let2; + let3; + } + } +} diff --git a/tests/passes/cell-share/share-mult.futil b/tests/passes/cell-share/share-mult.futil new file mode 100644 index 0000000000..c18ed8a303 --- /dev/null +++ b/tests/passes/cell-share/share-mult.futil @@ -0,0 +1,101 @@ +//-p cell-share + +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; + +component main() -> () { + cells { + @external(1) A0 = std_mem_d1(32,2,2); + A_read0_0 = std_reg(32); + A_read1_0 = std_reg(32); + @external(1) B0 = std_mem_d1(32,2,2); + B_read0_0 = std_reg(32); + B_read1_0 = std_reg(32); + bin_read0_0 = std_reg(32); + bin_read1_0 = std_reg(32); + const0 = std_const(2,0); + const1 = std_const(2,0); + const2 = std_const(2,0); + const3 = std_const(2,0); + mult_pipe0 = std_mult_pipe(32); + mult_pipe1 = std_mult_pipe(32); + x_0 = std_reg(32); + y_0 = std_reg(32); + } + wires { + group prelet0{ + mult_pipe0.left = A_read0_0.out; + mult_pipe0.right = B_read0_0.out; + mult_pipe0.go = 1'd1; + prelet0[done] = mult_pipe0.done; + } + group let0{ + bin_read0_0.in = mult_pipe0.out; + bin_read0_0.write_en = 1'd1; + let0[done] = bin_read0_0.done; + } + group let1<"static"=1> { + x_0.in = bin_read0_0.out; + x_0.write_en = 1'd1; + let1[done] = x_0.done; + } + group prelet2{ + mult_pipe1.left = A_read1_0.out; + mult_pipe1.right = B_read1_0.out; + mult_pipe1.go = 1'd1; + prelet2[done] = mult_pipe1.done; + } + group let2{ + bin_read1_0.in = mult_pipe1.out; + bin_read1_0.write_en = 1'd1; + let2[done] = bin_read1_0.done; + } + group let3<"static"=1> { + y_0.in = bin_read1_0.out; + y_0.write_en = 1'd1; + let3[done] = y_0.done; + } + group upd0<"static"=1> { + A_read0_0.write_en = 1'd1; + A0.addr0 = const0.out; + A_read0_0.in = A0.read_data; + upd0[done] = A_read0_0.done; + } + group upd1<"static"=1> { + B_read0_0.write_en = 1'd1; + B0.addr0 = const1.out; + B_read0_0.in = B0.read_data; + upd1[done] = B_read0_0.done; + } + group upd2<"static"=1> { + A_read1_0.write_en = 1'd1; + A0.addr0 = const2.out; + A_read1_0.in = A0.read_data; + upd2[done] = A_read1_0.done; + } + group upd3<"static"=1> { + B_read1_0.write_en = 1'd1; + B0.addr0 = const3.out; + B_read1_0.in = B0.read_data; + upd3[done] = B_read1_0.done; + } + } + control { + seq { + par { + upd0; + upd1; + } + prelet0; + let0; + let1; + par { + upd2; + upd3; + } + prelet2; + let2; + let3; + } + } +} From cf33cda06f60cc1ebaa75369f51e8e971a49a9dc Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 27 Jun 2022 12:52:59 -0400 Subject: [PATCH 24/32] modified benches/component-sharing.rs --- benches/component-sharing.rs | 11 +++++------ calyx/src/passes/cell_share.rs | 2 -- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/benches/component-sharing.rs b/benches/component-sharing.rs index 3609dc65bb..5d8b6149ea 100644 --- a/benches/component-sharing.rs +++ b/benches/component-sharing.rs @@ -6,7 +6,7 @@ use calyx::{frontend, ir, passes}; use ir::traversal::Visitor; use std::path::Path; -fn resource_sharing_bench(c: &mut Criterion) { +fn cell_share_bench(c: &mut Criterion) { let mut gemm_group = c.benchmark_group("gemm"); for name in &["gemm2", "gemm3", "gemm4", "gemm6", "gemm8"] { gemm_group.bench_with_input( @@ -33,8 +33,7 @@ fn resource_sharing_bench(c: &mut Criterion) { rep }, |mut rep: ir::Context| { - passes::ResourceSharing::do_pass_default(&mut rep) - .unwrap(); + passes::CellShare::do_pass_default(&mut rep).unwrap(); }, BatchSize::SmallInput, ) @@ -45,8 +44,8 @@ fn resource_sharing_bench(c: &mut Criterion) { } criterion_group! { - name = resource_sharing; + name = cell_share; config = Criterion::default().sample_size(20); - targets = resource_sharing_bench + targets = cell_share_bench } -criterion_main!(resource_sharing); +criterion_main!(CellShare); diff --git a/calyx/src/passes/cell_share.rs b/calyx/src/passes/cell_share.rs index d2b06fa617..06f756f894 100644 --- a/calyx/src/passes/cell_share.rs +++ b/calyx/src/passes/cell_share.rs @@ -131,13 +131,11 @@ impl ShareComponents for CellShare { F: FnMut(Vec), { for group in comp.groups.iter() { - //println!("group name: {}: ", group.borrow().name().id.clone()); let conflicts = self.live.get(group.borrow().name()); add_conflicts( conflicts .iter() .filter(|cell_name| { - //println!("{}", cell_name); !self.cont_ref_cells.contains(cell_name) }) .cloned() From ca9932f9597b8271553e1ecf9610ce698599dd45 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 27 Jun 2022 17:29:17 -0400 Subject: [PATCH 25/32] small change --- benches/component-sharing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/component-sharing.rs b/benches/component-sharing.rs index 5d8b6149ea..0218a1b8e2 100644 --- a/benches/component-sharing.rs +++ b/benches/component-sharing.rs @@ -48,4 +48,4 @@ criterion_group! { config = Criterion::default().sample_size(20); targets = cell_share_bench } -criterion_main!(CellShare); +criterion_main!(cell_share); From a0ae50d1574af73cef002f155b44b2af7c776b44 Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 28 Jun 2022 07:52:59 -0400 Subject: [PATCH 26/32] small change to control.rs --- calyx/src/ir/control.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calyx/src/ir/control.rs b/calyx/src/ir/control.rs index 7c6cfa786b..d34680d88a 100644 --- a/calyx/src/ir/control.rs +++ b/calyx/src/ir/control.rs @@ -87,8 +87,8 @@ pub struct Invoke { #[derive(Debug)] pub struct Empty {} -#[derive(Debug)] /// Control AST nodes. +#[derive(Debug)] pub enum Control { /// Represents sequential composition of control statements. Seq(Seq), From f7ec498b175aace41f0e74dde673319404e9b2e7 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 28 Jun 2022 11:46:50 -0400 Subject: [PATCH 27/32] Dont clone ShareSet --- calyx/src/analysis/live_range_analysis.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 42f92e3c3e..7451220cf6 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -236,7 +236,7 @@ impl Debug for LiveRangeAnalysis { } } -#[derive(Default, Clone)] +#[derive(Default)] pub struct ShareSet { shareable: HashSet, } @@ -363,12 +363,12 @@ impl LiveRangeAnalysis { &mut self, group_ref: &RRC, ) -> (Prop, Prop) { - let sc_clone = self.state_share.clone(); - let group = group_ref.borrow(); + let maybe_var = self.variable_like(group_ref).clone(); + let sc_clone = &self.state_share; // if the group contains what looks like a variable write, // then just add variable to write set - if let Some(variable) = self.variable_like(group_ref) { + if let Some(variable) = maybe_var { // we don't want to read the control signal of `variable` let assignments = group .assignments From 4954b4bc4ba39842101462e8898cb8bc3f05e278 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 28 Jun 2022 11:47:36 -0400 Subject: [PATCH 28/32] doc comment for shareSet --- calyx/src/analysis/live_range_analysis.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 7451220cf6..4ede4fe988 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -236,6 +236,7 @@ impl Debug for LiveRangeAnalysis { } } +/// The type names of all components and primitives marked with "state_share". #[derive(Default)] pub struct ShareSet { shareable: HashSet, From f4ca7b32a8d221b5903f9859626e4046bb81bd6d Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 28 Jun 2022 11:49:43 -0400 Subject: [PATCH 29/32] better error --- calyx/src/analysis/live_range_analysis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calyx/src/analysis/live_range_analysis.rs b/calyx/src/analysis/live_range_analysis.rs index 4ede4fe988..aa4d48eb2d 100644 --- a/calyx/src/analysis/live_range_analysis.rs +++ b/calyx/src/analysis/live_range_analysis.rs @@ -313,7 +313,7 @@ impl LiveRangeAnalysis { .into(); match self.live.get_mut(group_name) { None => { - unreachable!("don't have live range for {}", group_name) + unreachable!("Missing live range for {}. This might happen if a group is not used int the control program", group_name) } Some(prop) => *prop = &*prop | &group_uses, } From e34181c0b6fbfdc8bea4e94b24cfb920675f59e9 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 28 Jun 2022 11:57:58 -0400 Subject: [PATCH 30/32] early bail out for variable detection --- calyx/src/analysis/variable_detection.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/calyx/src/analysis/variable_detection.rs b/calyx/src/analysis/variable_detection.rs index 4fc5c79f69..932342b4f2 100644 --- a/calyx/src/analysis/variable_detection.rs +++ b/calyx/src/analysis/variable_detection.rs @@ -34,15 +34,9 @@ impl VariableDetection { // if guard is empty, because if it isn't this would show up as // a write let graph = GraphAnalysis::from(&*group); + let go_port = cell.find_with_attr("go")?; let activation = graph - .writes_to( - &cell - .ports - .iter() - .find(|port| port.borrow().attributes.has("go")) - .unwrap_or_else(|| unreachable!("no go port on cell")) - .borrow(), - ) + .writes_to(&go_port.borrow()) .map(|src| src.borrow().is_constant(1, 1)) .collect::>(); if activation.len() != 1 || (!activation.is_empty() && !activation[0]) { @@ -50,10 +44,9 @@ impl VariableDetection { return None; } - // check to see if `reg.done` is written into `g[done]` + // check to see if `cell.done` is written into `g[done]` let activation = graph .writes_to(&group.get("done").borrow()) - .filter(|src| !src.borrow().is_constant(1, 1)) .map(|src| src.borrow().get_parent_name() == cell.name()) .collect::>(); if activation.len() != 1 || (!activation.is_empty() && !activation[0]) { From 363e73f74635b689e11c6f3579b18aaab14799d0 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 28 Jun 2022 12:19:27 -0400 Subject: [PATCH 31/32] comments for the future --- calyx/src/passes/cell_share.rs | 7 +++++-- calyx/src/passes/sharing_components.rs | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/calyx/src/passes/cell_share.rs b/calyx/src/passes/cell_share.rs index 06f756f894..e35de41777 100644 --- a/calyx/src/passes/cell_share.rs +++ b/calyx/src/passes/cell_share.rs @@ -97,6 +97,8 @@ impl ShareComponents for CellShare { .map(|cell| cell.borrow().clone_name()), ); + // TODO(rachit): Pass cont_ref_cells to LiveRangeAnalysis so that it ignores unneccessary + // cells. self.live = LiveRangeAnalysis::new( comp, &*comp.control.borrow(), @@ -105,12 +107,13 @@ impl ShareComponents for CellShare { ); } - fn lookup_group_conflicts(&self, group_name: &ir::Id) -> Vec { + fn lookup_group_conflicts(&self, group_name: &ir::Id) -> Vec<&ir::Id> { self.live .get(group_name) .iter() + // TODO(rachit): Once we make the above change and LiveRangeAnalysis ignores + // cont_ref_cells during construction, we do not need this filter call. .filter(|cell_name| !self.cont_ref_cells.contains(cell_name)) - .cloned() .collect() } diff --git a/calyx/src/passes/sharing_components.rs b/calyx/src/passes/sharing_components.rs index 28597b9214..60e0fff26c 100644 --- a/calyx/src/passes/sharing_components.rs +++ b/calyx/src/passes/sharing_components.rs @@ -46,7 +46,7 @@ pub trait ShareComponents { /// Return a vector of conflicting cell names for a the group `group_name`. /// These are the names of the cells that conflict if their groups are /// run in parallel. - fn lookup_group_conflicts(&self, group_name: &ir::Id) -> Vec; + fn lookup_group_conflicts(&self, group_name: &ir::Id) -> Vec<&ir::Id>; /// Given a cell and the library signatures, this function decides if /// this cell is relevant to the current sharing pass or not. This @@ -121,7 +121,7 @@ impl Visitor for T { for conflict in self.lookup_group_conflicts(&conflicted_group) { - acc.entry(id_to_type[&conflict].clone()) + acc.entry(id_to_type[conflict].clone()) .or_default() .push(conflict.clone()) } @@ -133,11 +133,11 @@ impl Visitor for T { .into_iter() .for_each(|(group, conflict_group_b)| { for a in self.lookup_group_conflicts(&group) { - let g = graphs_by_type.get_mut(&id_to_type[&a]).unwrap(); - if let Some(confs) = conflict_group_b.get(&id_to_type[&a]) { + let g = graphs_by_type.get_mut(&id_to_type[a]).unwrap(); + if let Some(confs) = conflict_group_b.get(&id_to_type[a]) { for b in confs { if a != b { - g.insert_conflict(&a, b); + g.insert_conflict(a, b); } } } From 2a520607cf30d032df1f04fffbba9cc9db2c260e Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 28 Jun 2022 12:38:11 -0400 Subject: [PATCH 32/32] comment --- calyx/src/analysis/variable_detection.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/calyx/src/analysis/variable_detection.rs b/calyx/src/analysis/variable_detection.rs index 932342b4f2..ede4927a1c 100644 --- a/calyx/src/analysis/variable_detection.rs +++ b/calyx/src/analysis/variable_detection.rs @@ -47,6 +47,8 @@ impl VariableDetection { // check to see if `cell.done` is written into `g[done]` let activation = graph .writes_to(&group.get("done").borrow()) + // Handle g[done] = g ? 1'd1 + .filter(|src| !src.borrow().is_constant(1, 1)) .map(|src| src.borrow().get_parent_name() == cell.name()) .collect::>(); if activation.len() != 1 || (!activation.is_empty() && !activation[0]) {