diff --git a/calyx-frontend/src/attribute.rs b/calyx-frontend/src/attribute.rs index 834e5895bf..76cdb57e50 100644 --- a/calyx-frontend/src/attribute.rs +++ b/calyx-frontend/src/attribute.rs @@ -103,6 +103,9 @@ pub enum NumAttr { #[strum(serialize = "promote_static")] /// Promote the group or control to static with the annotated latency PromoteStatic, + #[strum(serialize = "compactable")] + /// suggest that the current static seq block is compactable + Compactable, } impl From for Attribute { fn from(attr: NumAttr) -> Self { diff --git a/calyx-opt/src/analysis/control_order.rs b/calyx-opt/src/analysis/control_order.rs index f62d5c45c8..27102ebfe1 100644 --- a/calyx-opt/src/analysis/control_order.rs +++ b/calyx-opt/src/analysis/control_order.rs @@ -34,8 +34,28 @@ impl ControlOrder { let cell = cr.borrow(); match cell.prototype { // Ignore constants and _this - ir::CellType::Constant { .. } - | ir::CellType::ThisComponent => None, + ir::CellType::Constant { .. } => None, + ir::CellType::ThisComponent => None, + _ => Some(cell.name()), + } + }) + .unique() + } + + fn get_cells_static_seq( + ports: Vec>, + ) -> impl Iterator { + ports + .into_iter() + .filter_map(|p| { + let cr = p.borrow().cell_parent(); + let cell = cr.borrow(); + match cell.prototype { + // Ignore constants and _this + ir::CellType::Constant { .. } => None, + ir::CellType::ThisComponent => { + Some(ir::Id::new("this_comp")) + } _ => Some(cell.name()), } }) @@ -123,4 +143,68 @@ impl ControlOrder { Err(Error::misc(format!("No possible sequential ordering. Control programs exhibit data race:\n{}", msg))) } } + + // returns a graph of dependency for input programs + // input control programs are considered to have data dependency if: + // 1. subsequent program writes to cells that previous program reads from + // 2. subsequent program writes to cells that previous program writes to + // 3. subsequent program reads from cells that previous program writes to + pub fn get_dependency_graph_static_seq( + stmts: impl Iterator, + dependency: &mut HashMap>, + latency_map: &mut HashMap, + ) -> DiGraph, ()> { + // Directed graph where edges means that a control program must be run before. + let mut gr: DiGraph, ()> = DiGraph::new(); + + // Mapping name of cell to all the indices that read or write to it. + let mut reads: HashMap> = HashMap::default(); + let mut writes: HashMap> = HashMap::default(); + + for c in stmts { + let (port_reads, port_writes) = + ReadWriteSet::control_port_read_write_set_static(&c); + let r_cells = Self::get_cells_static_seq(port_reads); + let w_cells = Self::get_cells_static_seq(port_writes); + let latency = c.get_latency(); + let idx = gr.add_node(Some(c)); + dependency.insert(idx, Vec::new()); + latency_map.insert(idx, latency); + + for cell in r_cells { + if let Some(wr_idxs) = writes.get(&cell) { + for wr_idx in wr_idxs { + if !wr_idx.eq(&idx) { + gr.add_edge(*wr_idx, idx, ()); + dependency.entry(idx).or_default().push(*wr_idx); + } + } + } + reads.entry(cell).or_default().push(idx); + } + + for cell in w_cells { + if let Some(wr_idxs) = writes.get(&cell) { + for wr_idx in wr_idxs { + if !wr_idx.eq(&idx) { + gr.add_edge(*wr_idx, idx, ()); + dependency.entry(idx).or_default().push(*wr_idx); + } + } + } + + if let Some(r_idxs) = reads.get(&cell) { + for r_idx in r_idxs { + if !r_idx.eq(&idx) { + gr.add_edge(*r_idx, idx, ()); + dependency.entry(idx).or_default().push(*r_idx); + } + } + } + + writes.entry(cell).or_default().push(idx); + } + } + gr + } } diff --git a/calyx-opt/src/analysis/read_write_set.rs b/calyx-opt/src/analysis/read_write_set.rs index e1cb8baade..de1103e7b8 100644 --- a/calyx-opt/src/analysis/read_write_set.rs +++ b/calyx-opt/src/analysis/read_write_set.rs @@ -165,11 +165,30 @@ impl ReadWriteSet { ir::StaticControl::Invoke(ir::StaticInvoke { inputs, outputs, + ref_cells, .. }) => { - let inps = inputs.iter().map(|(_, p)| p).cloned(); - let outs = outputs.iter().map(|(_, p)| p).cloned(); - (inps.collect(), outs.collect()) + let mut inps: Vec> = + inputs.iter().map(|(_, p)| p).cloned().collect(); + let mut outs: Vec> = + outputs.iter().map(|(_, p)| p).cloned().collect(); + for (_, cell) in ref_cells.iter() { + for port in cell.borrow().ports.iter() { + match port.borrow().direction { + ir::Direction::Input => { + outs.push(Rc::clone(port)); + } + ir::Direction::Output => { + inps.push(Rc::clone(port)); + } + _ => { + outs.push(Rc::clone(port)); + inps.push(Rc::clone(port)); + } + } + } + } + (inps, outs) } } } @@ -190,22 +209,39 @@ impl ReadWriteSet { inputs, outputs, comb_group, + ref_cells, .. }) => { let inps = inputs.iter().map(|(_, p)| p).cloned(); let outs = outputs.iter().map(|(_, p)| p).cloned(); + let mut r: Vec> = inps.collect(); + let mut w: Vec> = outs.collect(); + + for (_, cell) in ref_cells { + for port in cell.borrow().ports.iter() { + match port.borrow().direction { + ir::Direction::Input => { + w.push(Rc::clone(port)); + } + ir::Direction::Output => { + r.push(Rc::clone(port)); + } + _ => { + w.push(Rc::clone(port)); + r.push(Rc::clone(port)); + } + } + } + } match comb_group { Some(cgr) => { let cg = cgr.borrow(); let assigns = cg.assignments.iter(); let reads = Self::port_read_set(assigns.clone()); let writes = Self::port_write_set(assigns); - ( - reads.chain(inps).collect(), - writes.chain(outs).collect(), - ) + (reads.chain(r).collect(), writes.chain(w).collect()) } - None => (inps.collect(), outs.collect()), + None => (r, w), } } ir::Control::Seq(ir::Seq { stmts, .. }) diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 517fca3660..72f1062d84 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -6,10 +6,10 @@ use crate::passes::{ DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, DiscoverExternal, Externalize, GoInsertion, GroupToInvoke, GroupToSeq, HoleInliner, InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, - RegisterUnsharing, RemoveIds, ResetInsertion, SimplifyStaticGuards, - SimplifyWithControl, StaticInliner, StaticPromotion, SynthesisPapercut, - TopDownCompileControl, TopDownStaticTiming, UnrollBounded, WellFormed, - WireInliner, WrapMain, + RegisterUnsharing, RemoveIds, ResetInsertion, ScheduleCompaction, + SimplifyStaticGuards, SimplifyWithControl, StaticInliner, StaticPromotion, + SynthesisPapercut, TopDownCompileControl, TopDownStaticTiming, + UnrollBounded, WellFormed, WireInliner, WrapMain, }; use crate::traversal::Named; use crate::{pass_manager::PassManager, register_alias}; @@ -36,6 +36,7 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; + pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -93,6 +94,7 @@ impl PassManager { CompileInvoke, // creates dead comb groups AttributePromotion, StaticPromotion, + ScheduleCompaction, CompileRepeat, DeadGroupRemoval, // Since previous passes potentially create dead groups CollapseControl, diff --git a/calyx-opt/src/passes/compile_invoke.rs b/calyx-opt/src/passes/compile_invoke.rs index 3458ce3440..92b26a45c4 100644 --- a/calyx-opt/src/passes/compile_invoke.rs +++ b/calyx-opt/src/passes/compile_invoke.rs @@ -128,11 +128,11 @@ impl CompileInvoke { /// /// Since this pass eliminates all ref cells in post order, we expect that /// invoked component already had all of its ref cells removed. - fn ref_cells_to_ports( + fn ref_cells_to_ports( &mut self, inv_cell: RRC, ref_cells: impl Iterator)>, - ) -> Vec> { + ) -> Vec> { let inv_comp = inv_cell.borrow().type_name().unwrap(); let mut assigns = Vec::new(); for (ref_cell_name, cell) in ref_cells { @@ -361,6 +361,10 @@ impl Visitor for CompileInvoke { let invoke_group = builder.add_static_group("static_invoke", s.latency); + invoke_group.borrow_mut().assignments.extend( + self.ref_cells_to_ports(Rc::clone(&s.comp), s.ref_cells.drain(..)), + ); + // comp.go = 1'd1; structure!(builder; let one = constant(1, 1); diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index a12982c387..cf9d261a37 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -28,6 +28,7 @@ mod par_to_seq; mod register_unsharing; mod remove_ids; mod reset_insertion; +mod schedule_compaction; mod simplify_static_guards; mod static_inliner; mod static_promotion; @@ -73,6 +74,7 @@ pub use par_to_seq::ParToSeq; pub use register_unsharing::RegisterUnsharing; pub use remove_ids::RemoveIds; pub use reset_insertion::ResetInsertion; +pub use schedule_compaction::ScheduleCompaction; pub use simplify_static_guards::SimplifyStaticGuards; pub use simplify_with_control::SimplifyWithControl; pub use static_inliner::StaticInliner; diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs new file mode 100644 index 0000000000..9b873eee46 --- /dev/null +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -0,0 +1,180 @@ +use crate::traversal::Action; +use crate::{ + analysis, + traversal::{Named, Visitor}, +}; +use calyx_ir as ir; +use petgraph::{algo, graph::NodeIndex}; +use std::collections::HashMap; + +#[derive(Default)] +/// for static seqs that are statically promoted by the compiler, +/// aggressively compacts the execution schedule so that the execution +/// order of control operators still respects data dependency +/// Example: see tests/passes/schedule-compaction/schedule-compaction.rs +pub struct ScheduleCompaction; + +impl Named for ScheduleCompaction { + fn name() -> &'static str { + "schedule-compaction" + } + + fn description() -> &'static str { + "Aggressively compact schedule for static seqs which were promoted from generic seqs" + } +} + +impl Visitor for ScheduleCompaction { + fn iteration_order() -> crate::traversal::Order + where + Self: Sized, + { + crate::traversal::Order::Post + } + + fn finish_static_seq( + &mut self, + s: &mut calyx_ir::StaticSeq, + comp: &mut calyx_ir::Component, + sigs: &calyx_ir::LibrarySignatures, + _comps: &[calyx_ir::Component], + ) -> crate::traversal::VisResult { + // records the corresponding node indices that each control program + // has data dependency on + let mut dependency: HashMap> = HashMap::new(); + // records the latency of corresponding control operator for each node index + let mut latency_map: HashMap = HashMap::new(); + // records the scheduled start time of corresponding control operator for each node index + let mut schedule: HashMap = HashMap::new(); + + let mut builder = ir::Builder::new(comp, sigs); + + let mut total_order = + analysis::ControlOrder::::get_dependency_graph_static_seq( + s.stmts.drain(..), + &mut dependency, + &mut latency_map, + ); + + if let Ok(order) = algo::toposort(&total_order, None) { + let mut total_time: u64 = 0; + let mut stmts: Vec = Vec::new(); + + for i in order { + let mut start: u64 = 0; + for node in dependency.get(&i).unwrap() { + let allow_start = schedule[node] + latency_map[node]; + if allow_start > start { + start = allow_start; + } + } + schedule.insert(i, start); + + let control = total_order[i].take().unwrap(); + let mut st_seq_stmts: Vec = Vec::new(); + if start > 0 { + let no_op = builder.add_static_group("no-op", start); + + st_seq_stmts.push(ir::StaticControl::Enable( + ir::StaticEnable { + group: no_op, + attributes: ir::Attributes::default(), + }, + )); + } + if start + latency_map[&i] > total_time { + total_time = start + latency_map[&i]; + } + + st_seq_stmts.push(control); + stmts.push(ir::StaticControl::Seq(ir::StaticSeq { + stmts: st_seq_stmts, + attributes: ir::Attributes::default(), + latency: start + latency_map[&i], + })); + } + + let s_par = ir::StaticControl::Par(ir::StaticPar { + stmts, + attributes: ir::Attributes::default(), + latency: total_time, + }); + return Ok(Action::static_change(s_par)); + } else { + println!( + "Error when producing topo sort. Dependency graph has a cycle." + ); + } + Ok(Action::Continue) + } + + fn finish_static_repeat( + &mut self, + s: &mut ir::StaticRepeat, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> crate::traversal::VisResult { + s.latency = s.body.get_latency() * s.num_repeats; + Ok(Action::Continue) + } + + fn finish_static_par( + &mut self, + s: &mut ir::StaticPar, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> crate::traversal::VisResult { + let mut latency: u64 = 0; + for stmt in s.stmts.iter() { + latency = std::cmp::max(latency, stmt.get_latency()); + } + s.latency = latency; + Ok(Action::Continue) + } + + fn finish_static_if( + &mut self, + s: &mut ir::StaticIf, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> crate::traversal::VisResult { + s.latency = + std::cmp::max(s.tbranch.get_latency(), s.fbranch.get_latency()); + Ok(Action::Continue) + } + + fn finish( + &mut self, + comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> crate::traversal::VisResult { + if comp.is_static() { + comp.latency = Some( + std::num::NonZeroU64::new( + comp.control.borrow().get_latency().unwrap(), + ) + .unwrap(), + ); + } + Ok(Action::Continue) + } + + fn static_invoke( + &mut self, + s: &mut ir::StaticInvoke, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + comps: &[ir::Component], + ) -> crate::traversal::VisResult { + for comp in comps { + if comp.name.eq(&s.comp.borrow().type_name().unwrap()) { + s.latency = u64::from(comp.latency.unwrap()); + } + } + Ok(Action::Continue) + } +} diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index a4fd888faa..f71a4934d9 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -476,9 +476,11 @@ impl StaticPromotion { _ => unreachable!("We do not insert non-static controls other than group enables with `promote_static` attribute") } } + let mut attributes = ir::Attributes::default(); + attributes.insert(ir::NumAttr::Compactable, 1); ir::Control::Static(StaticControl::Seq(ir::StaticSeq { stmts: static_seq_st, - attributes: ir::Attributes::default(), + attributes, latency, })) } diff --git a/examples/dahlia/dot-product.expect b/examples/dahlia/dot-product.expect index 1241bd92e7..3e1a2e9141 100644 --- a/examples/dahlia/dot-product.expect +++ b/examples/dahlia/dot-product.expect @@ -1,5 +1,5 @@ { - "cycles": 98, + "cycles": 90, "memories": { "A": [ 27, diff --git a/examples/futil/dot-product.expect b/examples/futil/dot-product.expect index b90294a1e5..0bbfdc0606 100644 --- a/examples/futil/dot-product.expect +++ b/examples/futil/dot-product.expect @@ -28,92 +28,92 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated invoke0_done = std_wire(1); @generated early_reset_cond00_go = std_wire(1); @generated early_reset_cond00_done = std_wire(1); - @generated early_reset_static_seq_go = std_wire(1); - @generated early_reset_static_seq_done = std_wire(1); + @generated early_reset_static_par_go = std_wire(1); + @generated early_reset_static_par_done = std_wire(1); @generated wrapper_early_reset_cond00_go = std_wire(1); @generated wrapper_early_reset_cond00_done = std_wire(1); - @generated while_wrapper_early_reset_static_seq_go = std_wire(1); - @generated while_wrapper_early_reset_static_seq_done = std_wire(1); + @generated while_wrapper_early_reset_static_par_go = std_wire(1); + @generated while_wrapper_early_reset_static_par_done = std_wire(1); @generated tdcc_go = std_wire(1); @generated tdcc_done = std_wire(1); } wires { - i0.write_en = invoke0_go.out | fsm.out == 4'd7 & early_reset_static_seq_go.out ? 1'd1; + i0.write_en = invoke0_go.out | fsm.out == 4'd1 & early_reset_static_par_go.out ? 1'd1; i0.clk = clk; i0.reset = reset; - i0.in = fsm.out == 4'd7 & early_reset_static_seq_go.out ? add1.out; + i0.in = fsm.out == 4'd1 & early_reset_static_par_go.out ? add1.out; i0.in = invoke0_go.out ? const0.out; early_reset_cond00_go.in = wrapper_early_reset_cond00_go.out ? 1'd1; - add1.left = fsm.out == 4'd7 & early_reset_static_seq_go.out ? i0.out; - add1.right = fsm.out == 4'd7 & early_reset_static_seq_go.out ? const3.out; + add1.left = fsm.out == 4'd1 & early_reset_static_par_go.out ? i0.out; + add1.right = fsm.out == 4'd1 & early_reset_static_par_go.out ? const3.out; done = tdcc_done.out ? 1'd1; - fsm.write_en = early_reset_cond00_go.out | early_reset_static_seq_go.out ? 1'd1; + fsm.write_en = early_reset_cond00_go.out | early_reset_static_par_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; fsm.in = fsm.out != 4'd0 & early_reset_cond00_go.out ? adder.out; - fsm.in = fsm.out == 4'd0 & early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? 4'd0; - fsm.in = fsm.out != 4'd8 & early_reset_static_seq_go.out ? adder0.out; + fsm.in = fsm.out == 4'd0 & early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? 4'd0; + fsm.in = fsm.out != 4'd7 & early_reset_static_par_go.out ? adder0.out; adder.left = early_reset_cond00_go.out ? fsm.out; adder.right = early_reset_cond00_go.out ? 4'd1; - add0.left = fsm.out == 4'd6 & early_reset_static_seq_go.out ? v0.read_data; - add0.right = fsm.out == 4'd6 & early_reset_static_seq_go.out ? B_read0_0.out; - v0.write_en = fsm.out == 4'd6 & early_reset_static_seq_go.out ? 1'd1; + add0.left = fsm.out == 4'd6 & early_reset_static_par_go.out ? v0.read_data; + add0.right = fsm.out == 4'd6 & early_reset_static_par_go.out ? B_read0_0.out; + v0.write_en = fsm.out == 4'd6 & early_reset_static_par_go.out ? 1'd1; v0.clk = clk; - v0.addr0 = fsm.out == 4'd6 & early_reset_static_seq_go.out ? const2.out; + v0.addr0 = fsm.out == 4'd6 & early_reset_static_par_go.out ? const2.out; v0.reset = reset; - v0.write_data = fsm.out == 4'd6 & early_reset_static_seq_go.out ? add0.out; - comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? 1'd1; + v0.write_data = fsm.out == 4'd6 & early_reset_static_par_go.out ? add0.out; + comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? 1'd1; comb_reg.clk = clk; comb_reg.reset = reset; - comb_reg.in = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? le0.out; + comb_reg.in = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? le0.out; early_reset_cond00_done.in = ud.out; - while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_par_go.in = !while_wrapper_early_reset_static_par_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; invoke0_go.in = !invoke0_done.out & fsm0.out == 2'd0 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_par_done.in = !comb_reg.out & fsm.out == 4'd0 ? 1'd1; tdcc_go.in = go; A0.clk = clk; - A0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; + A0.addr0 = fsm.out == 4'd0 & early_reset_static_par_go.out ? i0.out; A0.reset = reset; - fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; + fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 1'd1; fsm0.clk = clk; fsm0.reset = reset; fsm0.in = fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; fsm0.in = fsm0.out == 2'd3 ? 2'd0; - fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; + fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 2'd3; fsm0.in = fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; mult_pipe0.clk = clk; - mult_pipe0.left = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? A_read0_0.out; - mult_pipe0.go = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? 1'd1; + mult_pipe0.left = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? A_read0_0.out; + mult_pipe0.go = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? 1'd1; mult_pipe0.reset = reset; - mult_pipe0.right = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? B_read0_0.out; - adder0.left = early_reset_static_seq_go.out ? fsm.out; - adder0.right = early_reset_static_seq_go.out ? 4'd1; + mult_pipe0.right = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? B_read0_0.out; + adder0.left = early_reset_static_par_go.out ? fsm.out; + adder0.right = early_reset_static_par_go.out ? 4'd1; invoke0_done.in = i0.done; - early_reset_static_seq_go.in = while_wrapper_early_reset_static_seq_go.out ? 1'd1; - le0.left = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? i0.out; - le0.right = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? const1.out; + early_reset_static_par_done.in = ud0.out; + le0.left = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? i0.out; + le0.right = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? const1.out; signal_reg.write_en = fsm.out == 4'd0 & signal_reg.out | fsm.out == 4'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; signal_reg.in = fsm.out == 4'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.in = fsm.out == 4'd0 & signal_reg.out ? 1'd0; B0.clk = clk; - B0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; + B0.addr0 = fsm.out == 4'd0 & early_reset_static_par_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd5) & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd5 & fsm.out < 4'd6) & early_reset_static_par_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; - B_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? B0.read_data; - B_read0_0.in = fsm.out == 4'd5 & early_reset_static_seq_go.out ? A_read0_0.out; + B_read0_0.in = fsm.out == 4'd0 & early_reset_static_par_go.out ? B0.read_data; + B_read0_0.in = fsm.out == 4'd5 & early_reset_static_par_go.out ? A_read0_0.out; wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm0.out == 2'd1 & tdcc_go.out ? 1'd1; wrapper_early_reset_cond00_done.in = fsm.out == 4'd0 & signal_reg.out ? 1'd1; - early_reset_static_seq_done.in = ud0.out; tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; - while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 4'd0 ? 1'd1; - A_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd4) & early_reset_static_seq_go.out ? 1'd1; + early_reset_static_par_go.in = while_wrapper_early_reset_static_par_go.out ? 1'd1; + A_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd4 & fsm.out >= 4'd1 & fsm.out < 4'd5 & fsm.out < 4'd5) & early_reset_static_par_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; - A_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? A0.read_data; - A_read0_0.in = fsm.out == 4'd4 & early_reset_static_seq_go.out ? mult_pipe0.out; + A_read0_0.in = fsm.out == 4'd0 & early_reset_static_par_go.out ? A0.read_data; + A_read0_0.in = fsm.out == 4'd4 & early_reset_static_par_go.out ? mult_pipe0.out; } control {} } diff --git a/examples/futil/simple.expect b/examples/futil/simple.expect index 4f61bc431b..16a037543a 100644 --- a/examples/futil/simple.expect +++ b/examples/futil/simple.expect @@ -6,29 +6,29 @@ static<5> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done @generated ud = undef(1); @generated adder = std_add(3); @generated signal_reg = std_reg(1); - @generated early_reset_static_seq_go = std_wire(1); - @generated early_reset_static_seq_done = std_wire(1); - @generated wrapper_early_reset_static_seq_go = std_wire(1); - @generated wrapper_early_reset_static_seq_done = std_wire(1); + @generated early_reset_static_par_go = std_wire(1); + @generated early_reset_static_par_done = std_wire(1); + @generated wrapper_early_reset_static_par_go = std_wire(1); + @generated wrapper_early_reset_static_par_done = std_wire(1); } wires { - done = wrapper_early_reset_static_seq_done.out ? 1'd1; - fsm.write_en = early_reset_static_seq_go.out ? 1'd1; + done = wrapper_early_reset_static_par_done.out ? 1'd1; + fsm.write_en = early_reset_static_par_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; - fsm.in = fsm.out != 3'd4 & early_reset_static_seq_go.out ? adder.out; - fsm.in = fsm.out == 3'd4 & early_reset_static_seq_go.out ? 3'd0; - adder.left = early_reset_static_seq_go.out ? fsm.out; - adder.right = early_reset_static_seq_go.out ? 3'd1; - wrapper_early_reset_static_seq_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; - early_reset_static_seq_go.in = wrapper_early_reset_static_seq_go.out ? 1'd1; - signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; + fsm.in = fsm.out != 3'd4 & early_reset_static_par_go.out ? adder.out; + fsm.in = fsm.out == 3'd4 & early_reset_static_par_go.out ? 3'd0; + adder.left = early_reset_static_par_go.out ? fsm.out; + adder.right = early_reset_static_par_go.out ? 3'd1; + wrapper_early_reset_static_par_go.in = go; + wrapper_early_reset_static_par_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; + early_reset_static_par_done.in = ud.out; + signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_par_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; - signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; + signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_par_go.out ? 1'd1; signal_reg.in = fsm.out == 3'd0 & signal_reg.out ? 1'd0; - early_reset_static_seq_done.in = ud.out; - wrapper_early_reset_static_seq_go.in = go; + early_reset_static_par_go.in = wrapper_early_reset_static_par_go.out ? 1'd1; } control {} } diff --git a/examples/futil/vectorized-add.expect b/examples/futil/vectorized-add.expect index 005c8bc0f2..5072243436 100644 --- a/examples/futil/vectorized-add.expect +++ b/examples/futil/vectorized-add.expect @@ -25,85 +25,85 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated invoke0_done = std_wire(1); @generated early_reset_cond00_go = std_wire(1); @generated early_reset_cond00_done = std_wire(1); - @generated early_reset_static_seq_go = std_wire(1); - @generated early_reset_static_seq_done = std_wire(1); + @generated early_reset_static_par_go = std_wire(1); + @generated early_reset_static_par_done = std_wire(1); @generated wrapper_early_reset_cond00_go = std_wire(1); @generated wrapper_early_reset_cond00_done = std_wire(1); - @generated while_wrapper_early_reset_static_seq_go = std_wire(1); - @generated while_wrapper_early_reset_static_seq_done = std_wire(1); + @generated while_wrapper_early_reset_static_par_go = std_wire(1); + @generated while_wrapper_early_reset_static_par_done = std_wire(1); @generated tdcc_go = std_wire(1); @generated tdcc_done = std_wire(1); } wires { - i0.write_en = invoke0_go.out | fsm.out == 3'd2 & early_reset_static_seq_go.out ? 1'd1; + i0.write_en = invoke0_go.out | fsm.out == 3'd2 & early_reset_static_par_go.out ? 1'd1; i0.clk = clk; i0.reset = reset; - i0.in = fsm.out == 3'd2 & early_reset_static_seq_go.out ? add1.out; + i0.in = fsm.out == 3'd2 & early_reset_static_par_go.out ? add1.out; i0.in = invoke0_go.out ? const0.out; early_reset_cond00_go.in = wrapper_early_reset_cond00_go.out ? 1'd1; - add1.left = fsm.out == 3'd2 & early_reset_static_seq_go.out ? i0.out; - add1.right = fsm.out == 3'd2 & early_reset_static_seq_go.out ? const2.out; + add1.left = fsm.out == 3'd2 & early_reset_static_par_go.out ? i0.out; + add1.right = fsm.out == 3'd2 & early_reset_static_par_go.out ? const2.out; done = tdcc_done.out ? 1'd1; - fsm.write_en = early_reset_cond00_go.out | early_reset_static_seq_go.out ? 1'd1; + fsm.write_en = early_reset_cond00_go.out | early_reset_static_par_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; fsm.in = fsm.out != 3'd0 & early_reset_cond00_go.out ? adder.out; - fsm.in = fsm.out != 3'd3 & early_reset_static_seq_go.out ? adder0.out; - fsm.in = fsm.out == 3'd0 & early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? 3'd0; + fsm.in = fsm.out != 3'd3 & early_reset_static_par_go.out ? adder0.out; + fsm.in = fsm.out == 3'd0 & early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? 3'd0; adder.left = early_reset_cond00_go.out ? fsm.out; adder.right = early_reset_cond00_go.out ? 3'd1; - add0.left = fsm.out == 3'd1 & early_reset_static_seq_go.out ? A_read0_0.out; - add0.right = fsm.out == 3'd1 & early_reset_static_seq_go.out ? B_read0_0.out; - comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? 1'd1; + add0.left = fsm.out == 3'd1 & early_reset_static_par_go.out ? A_read0_0.out; + add0.right = fsm.out == 3'd1 & early_reset_static_par_go.out ? B_read0_0.out; + comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? 1'd1; comb_reg.clk = clk; comb_reg.reset = reset; - comb_reg.in = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? le0.out; + comb_reg.in = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? le0.out; early_reset_cond00_done.in = ud.out; - while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_par_go.in = !while_wrapper_early_reset_static_par_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; invoke0_go.in = !invoke0_done.out & fsm0.out == 2'd0 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_par_done.in = !comb_reg.out & fsm.out == 3'd0 ? 1'd1; tdcc_go.in = go; A0.clk = clk; - A0.addr0 = fsm.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; + A0.addr0 = fsm.out == 3'd0 & early_reset_static_par_go.out ? i0.out; A0.reset = reset; - Sum0.write_en = fsm.out == 3'd1 & early_reset_static_seq_go.out ? 1'd1; + Sum0.write_en = fsm.out == 3'd1 & early_reset_static_par_go.out ? 1'd1; Sum0.clk = clk; - Sum0.addr0 = fsm.out == 3'd1 & early_reset_static_seq_go.out ? i0.out; + Sum0.addr0 = fsm.out == 3'd1 & early_reset_static_par_go.out ? i0.out; Sum0.reset = reset; - Sum0.write_data = fsm.out == 3'd1 & early_reset_static_seq_go.out ? add0.out; - fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; + Sum0.write_data = fsm.out == 3'd1 & early_reset_static_par_go.out ? add0.out; + fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 1'd1; fsm0.clk = clk; fsm0.reset = reset; fsm0.in = fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; fsm0.in = fsm0.out == 2'd3 ? 2'd0; - fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; + fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 2'd3; fsm0.in = fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; - adder0.left = early_reset_static_seq_go.out ? fsm.out; - adder0.right = early_reset_static_seq_go.out ? 3'd1; + adder0.left = early_reset_static_par_go.out ? fsm.out; + adder0.right = early_reset_static_par_go.out ? 3'd1; invoke0_done.in = i0.done; - early_reset_static_seq_go.in = while_wrapper_early_reset_static_seq_go.out ? 1'd1; - le0.left = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? i0.out; - le0.right = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? const1.out; + early_reset_static_par_done.in = ud0.out; + le0.left = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? i0.out; + le0.right = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? const1.out; signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.in = fsm.out == 3'd0 & signal_reg.out ? 1'd0; B0.clk = clk; - B0.addr0 = fsm.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; + B0.addr0 = fsm.out == 3'd0 & early_reset_static_par_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_par_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; - B_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? B0.read_data; + B_read0_0.in = fsm.out == 3'd0 & early_reset_static_par_go.out ? B0.read_data; wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm0.out == 2'd1 & tdcc_go.out ? 1'd1; wrapper_early_reset_cond00_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; - early_reset_static_seq_done.in = ud0.out; tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; - while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 3'd0 ? 1'd1; - A_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; + early_reset_static_par_go.in = while_wrapper_early_reset_static_par_go.out ? 1'd1; + A_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_par_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; - A_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? A0.read_data; + A_read0_0.in = fsm.out == 3'd0 & early_reset_static_par_go.out ? A0.read_data; } control {} } diff --git a/tests/correctness/exp/any-base-1.expect b/tests/correctness/exp/any-base-1.expect index 8517668be4..04633a5641 100644 --- a/tests/correctness/exp/any-base-1.expect +++ b/tests/correctness/exp/any-base-1.expect @@ -1,5 +1,5 @@ { - "cycles": 220, + "cycles": 213, "memories": { "b": [ "4.5" diff --git a/tests/correctness/exp/any-base-2.expect b/tests/correctness/exp/any-base-2.expect index 1c1ad7e19b..d415bab291 100644 --- a/tests/correctness/exp/any-base-2.expect +++ b/tests/correctness/exp/any-base-2.expect @@ -1,5 +1,5 @@ { - "cycles": 215, + "cycles": 208, "memories": { "b": [ "7.5" diff --git a/tests/correctness/exp/any-base-3.expect b/tests/correctness/exp/any-base-3.expect index 71f36e7fe6..721f012ced 100644 --- a/tests/correctness/exp/any-base-3.expect +++ b/tests/correctness/exp/any-base-3.expect @@ -1,5 +1,5 @@ { - "cycles": 307, + "cycles": 304, "memories": { "b": [ "0.75" diff --git a/tests/correctness/exp/neg-base.expect b/tests/correctness/exp/neg-base.expect index 8f9d466104..2ff0c5df11 100644 --- a/tests/correctness/exp/neg-base.expect +++ b/tests/correctness/exp/neg-base.expect @@ -1,5 +1,5 @@ { - "cycles": 228, + "cycles": 223, "memories": { "b": [ "-2.600006103515625" diff --git a/tests/correctness/invoke-memory.futil b/tests/correctness/invoke-memory.futil index 48a2fc0549..4b672f2ed4 100644 --- a/tests/correctness/invoke-memory.futil +++ b/tests/correctness/invoke-memory.futil @@ -51,4 +51,4 @@ component main() -> () { (dest_write_data=d.write_data, dest_write_en=d.write_en, dest_addr0=d.addr0, src_addr0=s.addr0); } } -} +} \ No newline at end of file diff --git a/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect b/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect index 4000a995f8..fecc29a73d 100644 --- a/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect +++ b/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect @@ -1,5 +1,5 @@ { - "cycles": 681, + "cycles": 663, "memories": { "a": [ 7371, diff --git a/tests/correctness/seq.futil b/tests/correctness/seq.futil index 66a2c2e3cc..2d9b72e328 100644 --- a/tests/correctness/seq.futil +++ b/tests/correctness/seq.futil @@ -37,4 +37,4 @@ component main() -> () { commit; } } -} +} \ No newline at end of file diff --git a/tests/passes/compile-invoke/static-ref.expect b/tests/passes/compile-invoke/static-ref.expect index a21e4a6bfc..e81780ca09 100644 --- a/tests/passes/compile-invoke/static-ref.expect +++ b/tests/passes/compile-invoke/static-ref.expect @@ -47,6 +47,11 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { reg_to_mem[done] = mem.done; } static<2> group static_invoke { + mem.addr0 = adder.out_addr0; + mem.write_data = adder.out_write_data; + mem.write_en = adder.out_write_en; + adder.out_read_data = mem.read_data; + adder.out_done = mem.done; adder.go = 1'd1; } } diff --git a/tests/passes/schedule-compaction/schedule-compaction.expect b/tests/passes/schedule-compaction/schedule-compaction.expect new file mode 100644 index 0000000000..bf7291c5cb --- /dev/null +++ b/tests/passes/schedule-compaction/schedule-compaction.expect @@ -0,0 +1,52 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a_reg = std_reg(32); + b_reg = std_reg(32); + c_reg = std_reg(32); + d_reg = std_reg(32); + a = std_add(32); + } + wires { + static<1> group A { + a_reg.write_en = 1'd1; + a_reg.in = 32'd5; + } + static<10> group C { + c_reg.write_en = %0 ? 1'd1; + c_reg.in = 32'd10; + } + static<1> group B { + b_reg.write_en = 1'd1; + a.right = c_reg.out; + a.left = a_reg.out; + b_reg.in = a.out; + } + static<10> group D { + d_reg.write_en = %0 ? 1'd1; + d_reg.in = a_reg.out; + } + static<1> group no-op { + } + static<10> group no-op0 { + } + } + control { + static<11> par { + static<10> seq { + C; + } + static<1> seq { + A; + } + static<11> seq { + no-op; + D; + } + static<11> seq { + no-op0; + B; + } + } + } +} diff --git a/tests/passes/schedule-compaction/schedule-compaction.futil b/tests/passes/schedule-compaction/schedule-compaction.futil new file mode 100644 index 0000000000..048f335c7c --- /dev/null +++ b/tests/passes/schedule-compaction/schedule-compaction.futil @@ -0,0 +1,59 @@ +// -p validate -p schedule-compaction +// for control operators under static seq, +// we consider the subsequent control operator B to have data dependency on +// prior operator A in the following three cases: +// 1. B writes to a cell A reads from +// 2. B reads from a cell A writes to +// 3. B writes to a cell A writes to +// As such, we can draw the following dependency graph for the control program: +// A C +// | \ / +// | \ / +// | \ / +// | \ +// | / \ +// | / \ +// | / \ +// B D +// So we can compact the execution schedule to respect this data dependency +import "primitives/core.futil"; + +component main () -> () { + cells { + a_reg = std_reg(32); + b_reg = std_reg(32); + c_reg = std_reg(32); + d_reg = std_reg(32); + a = std_add(32); + } + + wires { + static<1> group A { + a_reg.in = 32'd5; + a_reg.write_en = 1'd1; + } + + static<10> group C { + c_reg.in = 32'd10; + c_reg.write_en = %0 ? 1'd1; + } + + static<1> group B { + a.left = a_reg.out; + a.right = c_reg.out; + b_reg.in = a.out; + b_reg.write_en = 1'd1; + } + + static<10> group D { + d_reg.in = a_reg.out; + d_reg.write_en = %0 ? 1'd1; + } + } + + control { + @compactable static seq { + A; C; B; D; + } + } +} \ No newline at end of file diff --git a/tests/passes/static-promotion/component.expect b/tests/passes/static-promotion/component.expect index e4992bc5e1..5515c1b23a 100644 --- a/tests/passes/static-promotion/component.expect +++ b/tests/passes/static-promotion/component.expect @@ -20,7 +20,7 @@ static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done } } control { - static<3> seq { + @compactable static<3> seq { A0; B0; C0; diff --git a/tests/passes/static-promotion/groups.expect b/tests/passes/static-promotion/groups.expect index c584404019..c46b3770e1 100644 --- a/tests/passes/static-promotion/groups.expect +++ b/tests/passes/static-promotion/groups.expect @@ -34,7 +34,7 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don } control { seq { - static<4> seq { + @compactable static<4> seq { one_cycle0; two_cycles0; mem_wrt_to_done0; diff --git a/tests/passes/static-promotion/invoke.expect b/tests/passes/static-promotion/invoke.expect index 17cec75440..cb0f4671bc 100644 --- a/tests/passes/static-promotion/invoke.expect +++ b/tests/passes/static-promotion/invoke.expect @@ -11,7 +11,7 @@ static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done } } control { - static<3> seq { + @compactable static<3> seq { upd00; static<2> invoke exp0( base = r.out, @@ -36,7 +36,7 @@ static<2> component exponent(base: 32, exp: 32, @go go: 1, @clk clk: 1, @reset r } } control { - static<2> seq { + @compactable static<2> seq { upd10; upd20; } diff --git a/tests/passes/static-promotion/multi-static.expect b/tests/passes/static-promotion/multi-static.expect index 75306c664d..5413970bff 100644 --- a/tests/passes/static-promotion/multi-static.expect +++ b/tests/passes/static-promotion/multi-static.expect @@ -11,7 +11,7 @@ static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done } } control { - static<3> seq { + @compactable static<3> seq { upd00; static<2> invoke exp0( base = r.out, @@ -36,7 +36,7 @@ static<2> component exponent(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset re } } control { - static<2> seq { + @compactable static<2> seq { upd10; upd20; } diff --git a/tests/passes/static-promotion/upgrade-bound.expect b/tests/passes/static-promotion/upgrade-bound.expect index 78554d15a8..fa3f416a13 100644 --- a/tests/passes/static-promotion/upgrade-bound.expect +++ b/tests/passes/static-promotion/upgrade-bound.expect @@ -22,7 +22,7 @@ static<15> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done don } control { @bound(5) static repeat 5 { - static<3> seq { + @compactable static<3> seq { A0; B0; C0;