diff --git a/calyx-opt/src/analysis/control_ports.rs b/calyx-opt/src/analysis/control_ports.rs index 2ca1c46d7c..2fb9238b4f 100644 --- a/calyx-opt/src/analysis/control_ports.rs +++ b/calyx-opt/src/analysis/control_ports.rs @@ -1,3 +1,4 @@ +use super::AssignmentAnalysis; use calyx_ir::{self as ir, RRC}; use itertools::Itertools; use std::{ @@ -66,10 +67,15 @@ impl ControlPorts { comb_group: &Option>, ) { if let Some(c) = comb_group { - let cells = - super::ReadWriteSet::uses(c.borrow().assignments.iter()) - .map(|cell| cell.borrow().name()) - .collect::>(); + let cells = c + .borrow() + .assignments + .iter() + .analysis() + .cell_uses() + .map(|cell| cell.borrow().name()) + .collect::>(); + // Only add ports that come from cells used in this comb group. let ports = inputs diff --git a/calyx-opt/src/analysis/dataflow_order.rs b/calyx-opt/src/analysis/dataflow_order.rs index 1e0f604ac7..952acbabe1 100644 --- a/calyx-opt/src/analysis/dataflow_order.rs +++ b/calyx-opt/src/analysis/dataflow_order.rs @@ -118,11 +118,7 @@ impl DataflowOrder { .collect_vec(); let ws = { let dst = assign.dst.borrow(); - let dst_parent = matches!( - dst.cell_parent().borrow().prototype, - ir::CellType::Primitive { .. } - ); - if dst_parent { + if dst.cell_parent().borrow().is_primitive::<&str>(None) { Some(dst.canonical()) } else { None diff --git a/calyx-opt/src/analysis/domination_analysis/node_analysis.rs b/calyx-opt/src/analysis/domination_analysis/node_analysis.rs index 48e8164681..32dc61d6b7 100644 --- a/calyx-opt/src/analysis/domination_analysis/node_analysis.rs +++ b/calyx-opt/src/analysis/domination_analysis/node_analysis.rs @@ -1,4 +1,6 @@ -use crate::analysis::{DominatorMap, ReadWriteSet, ShareSet}; +use crate::analysis::{ + AssignmentAnalysis, DominatorMap, ReadWriteSet, ShareSet, +}; use calyx_ir as ir; use std::collections::HashSet; @@ -77,11 +79,11 @@ fn add_assignment_reads( share: &ShareSet, assignments: &[ir::Assignment], ) { - for cell in ReadWriteSet::read_set( - assignments - .iter() - .filter(|assign| !reads_only_dones(assign)), - ) { + let assigns = assignments + .iter() + .filter(|assign| !reads_only_dones(assign)); + + for cell in assigns.analysis().cell_reads() { if share.is_shareable_component(&cell) && !cell.borrow().is_reference() { reads.insert(cell.borrow().name()); diff --git a/calyx-opt/src/analysis/inference_analysis.rs b/calyx-opt/src/analysis/inference_analysis.rs index 0b425649ae..48ae55fa33 100644 --- a/calyx-opt/src/analysis/inference_analysis.rs +++ b/calyx-opt/src/analysis/inference_analysis.rs @@ -1,6 +1,5 @@ -use crate::analysis::{ - compute_static::WithStatic, GraphAnalysis, ReadWriteSet, -}; +use super::AssignmentAnalysis; +use crate::analysis::{compute_static::WithStatic, GraphAnalysis}; use calyx_ir::{self as ir, GetAttributes, RRC}; use ir::CellType; use itertools::Itertools; @@ -281,7 +280,7 @@ impl InferenceAnalysis { &self, group: &ir::Group, ) -> Vec<(RRC, RRC)> { - let rw_set = ReadWriteSet::uses(group.assignments.iter()); + let rw_set = group.assignments.iter().analysis().cell_uses(); let mut go_done_edges: Vec<(RRC, RRC)> = Vec::new(); for cell_ref in rw_set { @@ -518,7 +517,12 @@ impl InferenceAnalysis { // This checks any group that writes to the component: // We can probably switch this to any group that writes to the component's // `go` port to be more precise analysis. - if ReadWriteSet::write_set(group.borrow_mut().assignments.iter()) + if group + .borrow_mut() + .assignments + .iter() + .analysis() + .cell_writes() .any(|cell| match cell.borrow().prototype { CellType::Component { name } => { self.updated_components.contains(&name) diff --git a/calyx-opt/src/analysis/live_range_analysis.rs b/calyx-opt/src/analysis/live_range_analysis.rs index 76b4f2c952..c2416ba990 100644 --- a/calyx-opt/src/analysis/live_range_analysis.rs +++ b/calyx-opt/src/analysis/live_range_analysis.rs @@ -1,4 +1,6 @@ -use crate::analysis::{ControlId, ReadWriteSet, ShareSet, VariableDetection}; +use crate::analysis::{ + AssignmentAnalysis, ControlId, ReadWriteSet, ShareSet, VariableDetection, +}; use calyx_ir::{self as ir, Id, RRC}; use itertools::Itertools; use std::{ @@ -40,11 +42,12 @@ pub fn meaningful_port_read_set<'a, T: 'a>( assigns: impl Iterator> + Clone + 'a, ) -> impl Iterator> + 'a { // go_writes = all cells which are guaranteed to have their go port written to in assigns - let go_writes: Vec> = - ReadWriteSet::port_write_set(assigns.clone().filter(|asgn| { + let go_writes: Vec> = assigns + .clone() + .filter(|asgn| { // to be included in go_writes, one of the following must hold: // a) guard is true - // b) cell.go = !cell.done ? 1'd1 + // b cell.go = !cell.done ? 1'd1 if asgn.guard.is_true() { return true; } @@ -55,7 +58,9 @@ pub fn meaningful_port_read_set<'a, T: 'a>( &asgn.dst.borrow().cell_parent().borrow().name(), ) && asgn.src.borrow().is_constant(1, 1) - })) + }) + .analysis() + .writes() .filter(|port| port.borrow().attributes.has(ir::NumAttr::Go)) .map(|port| Rc::clone(&port.borrow().cell_parent())) .collect(); @@ -736,7 +741,9 @@ impl LiveRangeAnalysis { }); // calculate reads, but ignore `variable`. we've already dealt with that - let reads: HashSet<_> = ReadWriteSet::read_set(assignments) + let reads: HashSet<_> = assignments + .analysis() + .cell_reads() .filter(|c| sc_clone.is_shareable_component(c)) .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) .collect(); @@ -760,11 +767,13 @@ impl LiveRangeAnalysis { .cloned() .collect::>(); - let writes: HashSet<_> = - ReadWriteSet::write_set(assignments.iter()) - .filter(|c| sc_clone.is_shareable_component(c)) - .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) - .collect(); + let writes: HashSet<_> = assignments + .iter() + .analysis() + .cell_writes() + .filter(|c| sc_clone.is_shareable_component(c)) + .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) + .collect(); (reads, writes) } @@ -792,7 +801,10 @@ impl LiveRangeAnalysis { .cloned() .collect::>(); - let writes: HashSet<_> = ReadWriteSet::write_set(assignments.iter()) + let writes: HashSet<_> = assignments + .iter() + .analysis() + .cell_writes() .filter(|c| sc_clone.is_shareable_component(c)) .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) .collect(); @@ -804,7 +816,10 @@ impl LiveRangeAnalysis { assigns: &[ir::Assignment], shareable_components: &ShareSet, ) -> TypeNameSet { - ReadWriteSet::uses(assigns.iter()) + assigns + .iter() + .analysis() + .cell_uses() .filter(|cell| shareable_components.is_shareable_component(cell)) .map(|cell| (cell.borrow().prototype.clone(), cell.borrow().name())) .collect::>() @@ -818,11 +833,20 @@ impl LiveRangeAnalysis { state_shareable: &ShareSet, ) -> (TypeNameSet, TypeNameSet) { let group = group_ref.borrow(); - let share_uses = ReadWriteSet::uses(group.assignments.iter()) + let share_uses = group + .assignments + .iter() + .analysis() + .cell_uses() .filter(|cell| shareable.is_shareable_component(cell)) .map(|cell| (cell.borrow().prototype.clone(), cell.borrow().name())) .collect::>(); - let state_reads = ReadWriteSet::read_set(group.assignments.iter()) + let state_reads = group + .assignments + .iter() + .analysis() + .reads() + .cells() .filter(|cell| state_shareable.is_shareable_component(cell)) .map(|cell| (cell.borrow().prototype.clone(), cell.borrow().name())) .collect::>(); @@ -887,7 +911,13 @@ impl LiveRangeAnalysis { if let Some(comb_group) = comb_group_info { read_set.extend( - ReadWriteSet::read_set(comb_group.borrow().assignments.iter()) + comb_group + .borrow() + .assignments + .iter() + .analysis() + .reads() + .cells() .filter(|cell| { shareable_components.is_shareable_component(cell) }) @@ -920,7 +950,12 @@ impl LiveRangeAnalysis { // uses of shareable components in the comb group (if it exists) if let Some(comb_group) = &comb_group_info { uses.extend( - ReadWriteSet::uses(comb_group.borrow().assignments.iter()) + comb_group + .borrow() + .assignments + .iter() + .analysis() + .cell_uses() .filter(|cell| { shareable_components.is_shareable_component(cell) }) diff --git a/calyx-opt/src/analysis/mod.rs b/calyx-opt/src/analysis/mod.rs index 6be29f0d27..cb00684f85 100644 --- a/calyx-opt/src/analysis/mod.rs +++ b/calyx-opt/src/analysis/mod.rs @@ -36,7 +36,7 @@ pub use inference_analysis::InferenceAnalysis; pub use live_range_analysis::LiveRangeAnalysis; pub use port_interface::PortInterface; pub use promotion_analysis::PromotionAnalysis; -pub use read_write_set::ReadWriteSet; +pub use read_write_set::{AssignmentAnalysis, ReadWriteSet}; pub use schedule_conflicts::ScheduleConflicts; pub use share_set::ShareSet; pub use static_par_timing::StaticParTiming; diff --git a/calyx-opt/src/analysis/reaching_defns.rs b/calyx-opt/src/analysis/reaching_defns.rs index 384cfda858..342dda05b2 100644 --- a/calyx-opt/src/analysis/reaching_defns.rs +++ b/calyx-opt/src/analysis/reaching_defns.rs @@ -1,6 +1,6 @@ //! Calculate the reaching definitions in a control program. -use crate::analysis::ReadWriteSet; use calyx_ir as ir; +use itertools::Itertools; use std::cmp::Ordering; use std::cmp::{Ord, PartialOrd}; use std::{ @@ -8,6 +8,8 @@ use std::{ ops::BitOr, }; +use super::read_write_set::AssignmentAnalysis; + const INVOKE_PREFIX: &str = "__invoke_"; type GroupName = ir::Id; @@ -219,18 +221,19 @@ impl ReachingDefinitionAnalysis { where I: Iterator> + Clone + 'a, { - let continuous_regs: Vec = - ReadWriteSet::uses(continuous_assignments) - .filter_map(|cell| { - let cell_ref = cell.borrow(); - if let Some(name) = cell_ref.type_name() { - if name == "std_reg" { - return Some(cell_ref.name()); - } + let continuous_regs: Vec = continuous_assignments + .analysis() + .cell_uses() + .filter_map(|cell| { + let cell_ref = cell.borrow(); + if let Some(name) = cell_ref.type_name() { + if name == "std_reg" { + return Some(cell_ref.name()); } - None - }) - .collect(); + } + None + }) + .collect(); let mut overlap_map: BTreeMap< ir::Id, @@ -301,6 +304,34 @@ fn remove_entries_defined_by(set: &mut KilledSet, defs: &DefSet) { .collect(); } +/// Returns the register cells whose out port is read anywhere in the given +/// assignments +fn register_reads(assigns: &[ir::Assignment]) -> BTreeSet { + assigns + .iter() + .analysis() + .reads() + .filter_map(|p| { + let port = p.borrow(); + let ir::PortParent::Cell(cell_wref) = &port.parent else { + unreachable!("Port not part of a cell"); + }; + // Skip this if the port is not an output + if &port.name != "out" { + return None; + }; + let cr = cell_wref.upgrade(); + let cell = cr.borrow(); + if cell.is_primitive(Some("std_reg")) { + Some(cr.borrow().name()) + } else { + None + } + }) + .unique() + .collect() +} + // handles `build_reaching_defns` for the enable/static_enables case. // asgns are the assignments in the group (either static or dynamic) fn handle_reaching_def_enables( @@ -309,7 +340,7 @@ fn handle_reaching_def_enables( rd: &mut ReachingDefinitionAnalysis, group_name: ir::Id, ) -> (DefSet, KilledSet) { - let writes = ReadWriteSet::must_write_set(asgns.iter()); + let writes = asgns.iter().analysis().must_writes().cells(); // for each write: // Killing all other reaching defns for that var // generating a new defn (Id, GROUP) @@ -321,9 +352,8 @@ fn handle_reaching_def_enables( .map(|x| x.borrow().name()) .collect::>(); - let read_set = ReadWriteSet::register_reads(asgns.iter()) - .map(|x| x.borrow().name()) - .collect::>(); + let read_set = register_reads(asgns); + // only kill a def if the value is not read. let (mut cur_reach, killed) = reach.kill_from_writeread(&write_set, &read_set); diff --git a/calyx-opt/src/analysis/read_write_set.rs b/calyx-opt/src/analysis/read_write_set.rs index 43d14927b8..2754de1bfa 100644 --- a/calyx-opt/src/analysis/read_write_set.rs +++ b/calyx-opt/src/analysis/read_write_set.rs @@ -1,122 +1,188 @@ use calyx_ir::{self as ir, RRC}; use itertools::Itertools; -use std::{iter, rc::Rc}; +use std::{collections::HashMap, iter, rc::Rc}; -/// Calcuate the reads-from and writes-to set for a given set of assignments. -pub struct ReadWriteSet; +#[derive(Clone)] +pub struct AssignmentIterator<'a, T: 'a, I> +where + I: Iterator>, +{ + iter: I, +} -impl ReadWriteSet { - /// Returns [ir::Port] that are read from in the given Assignment. - pub fn port_reads( - assign: &ir::Assignment, - ) -> impl Iterator> + '_ { - assign - .guard - .all_ports() - .into_iter() - .chain(iter::once(Rc::clone(&assign.src))) - .filter(|port| !port.borrow().is_hole()) +impl<'a, T: 'a, I> Iterator for AssignmentIterator<'a, T, I> +where + I: Iterator>, +{ + type Item = &'a ir::Assignment; + + fn next(&mut self) -> Option { + self.iter.next() } +} +impl<'a, T: 'a, I: 'a> AssignmentIterator<'a, T, I> +where + I: Iterator>, +{ /// Returns [ir::Port] which are read from in the assignments. - pub fn port_read_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - assigns.flat_map(Self::port_reads) + pub fn reads( + self, + ) -> PortIterator> + 'a> { + PortIterator::new(self.flat_map(ReadWriteSet::port_reads)) } /// Returns [ir::Port] which are written to in the assignments. - pub fn port_write_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - assigns - .map(|assign| Rc::clone(&assign.dst)) - .filter(|port| !port.borrow().is_hole()) - } - - /// Returns [ir::Cell] which are read from in the assignments. - /// **Ignores** reads from group holes. - pub fn read_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - Self::port_read_set(assigns) - .map(|port| Rc::clone(&port.borrow().cell_parent())) - .unique_by(|cell| cell.borrow().name()) + pub fn writes( + self, + ) -> PortIterator> + 'a> { + PortIterator::new( + self.map(|assign| Rc::clone(&assign.dst)) + .filter(|port| !port.borrow().is_hole()), + ) } - /// Returns [ir::Cell] which are written to by the assignments. - /// **Ignores** reads from group holes. - pub fn write_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - Self::port_write_set(assigns) - .map(|port| Rc::clone(&port.borrow().cell_parent())) - .unique_by(|cell| cell.borrow().name()) + /// Return the name of the cells that these assignments write to for writes + /// that are guarded by true. + /// **Ignores** writes to group holes. + pub fn must_writes( + self, + ) -> PortIterator> + 'a> { + PortIterator::new(self.filter_map(|assignment| { + if assignment.guard.is_true() && !assignment.dst.borrow().is_hole() + { + Some(Rc::clone(&assignment.dst)) + } else { + None + } + })) } - /// Returns the register cells whose out port is read anywhere in the given - /// assignments - pub fn register_reads<'a, T: 'a>( - assigns: impl Iterator> + Clone + 'a, - ) -> impl Iterator> + 'a { - fn is_register_out(port_ref: RRC) -> Option> { - let port = port_ref.borrow(); - if let ir::PortParent::Cell(cell_wref) = &port.parent { - if &port.name == "out" { - return Some(Rc::clone(&cell_wref.upgrade())); - } - } - None - } - let guard_ports = assigns.clone().flat_map(|assign| { + /// Returns the ports mentioned in this set of assignments. + pub fn uses( + self, + ) -> PortIterator> + 'a> { + PortIterator::new(self.flat_map(|assign| { assign .guard .all_ports() .into_iter() - .filter_map(is_register_out) - }); - assigns - .filter_map(|assign| is_register_out(Rc::clone(&assign.src))) - .chain(guard_ports) - .filter(|x| { - if let Some(name) = x.borrow().type_name() { - name == "std_reg" - } else { - false - } - }) - .unique_by(|cell| cell.borrow().name()) + .chain(iter::once(Rc::clone(&assign.dst))) + .chain(iter::once(Rc::clone(&assign.src))) + .filter(|port| !port.borrow().is_hole()) + })) } - /// Return the name of the cells that these assignments write to for writes - /// that are guarded by true. - /// **Ignores** writes to group holes. - pub fn must_write_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - assigns - .filter_map(|assignment| { - if let ir::Guard::True = *assignment.guard { - let dst_ref = assignment.dst.borrow(); - if let ir::PortParent::Cell(cell_wref) = &dst_ref.parent { - return Some(Rc::clone(&cell_wref.upgrade())); - } - } - None - }) - .unique_by(|cell| cell.borrow().name()) + // Convinience Methods + + /// Returns the cells read from in this set of assignments + pub fn cell_reads(self) -> impl Iterator> + 'a { + self.reads().cells() } - /// Returns all uses of cells in this group. Uses constitute both reads and - /// writes to cells. - pub fn uses<'a, T: 'a>( - assigns: impl Iterator> + Clone + 'a, - ) -> impl Iterator> + 'a { - let reads = Self::read_set(assigns.clone()); - reads - .chain(Self::write_set(assigns)) + /// Returns the cells written to in this set of assignments + pub fn cell_writes(self) -> impl Iterator> + 'a { + self.writes().cells() + } + + /// Returns the cells used in this set of assignments + pub fn cell_uses(self) -> impl Iterator> + 'a { + self.uses().cells() + } +} + +impl<'a, T: 'a, I: 'a> AssignmentIterator<'a, T, I> +where + I: Iterator>, + I: Clone, + T: Clone, +{ + /// Separately returns the read and write sets for the given assignments. + pub fn reads_and_writes( + self, + ) -> ( + PortIterator> + 'a>, + PortIterator> + 'a>, + ) { + (self.clone().reads(), self.writes()) + } +} + +/// Analyzes that can be performed on a set of assignments. +pub trait AssignmentAnalysis<'a, T: 'a>: + Iterator> +where + Self: Sized, +{ + fn analysis(self) -> AssignmentIterator<'a, T, Self> { + AssignmentIterator { iter: self } + } +} + +impl<'a, T: 'a, I: 'a> AssignmentAnalysis<'a, T> for I where + I: Iterator> +{ +} + +/// An iterator over ports +pub struct PortIterator +where + I: Iterator>, +{ + iter: I, +} + +impl Iterator for PortIterator +where + I: Iterator>, +{ + type Item = RRC; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl PortIterator +where + I: Iterator>, +{ + pub const fn new(iter: I) -> Self { + Self { iter } + } + + /// Return the unique cells that the ports are a part of + pub fn cells(self) -> impl Iterator> { + self.iter + .map(|port| Rc::clone(&port.borrow().cell_parent())) .unique_by(|cell| cell.borrow().name()) } + + /// Group the ports by cells that they are a part of + pub fn group_by_cell(self) -> HashMap>> { + self.iter.into_group_map_by(|port| { + port.borrow().cell_parent().borrow().name() + }) + } +} + +/// Calcuate the reads-from and writes-to set for a given set of assignments. +pub struct ReadWriteSet; + +impl ReadWriteSet { + /// Returns [ir::Port] that are read from in the given Assignment. + pub fn port_reads( + assign: &ir::Assignment, + ) -> PortIterator>> { + PortIterator::new( + assign + .guard + .all_ports() + .into_iter() + .chain(iter::once(Rc::clone(&assign.src))) + .filter(|port| !port.borrow().is_hole()), + ) + } } impl ReadWriteSet { @@ -127,12 +193,11 @@ impl ReadWriteSet { ) -> (Vec>, Vec>) { match scon { ir::StaticControl::Empty(_) => (vec![], vec![]), - ir::StaticControl::Enable(ir::StaticEnable { group, .. }) => ( - Self::port_read_set(group.borrow().assignments.iter()) - .collect(), - Self::port_write_set(group.borrow().assignments.iter()) - .collect(), - ), + ir::StaticControl::Enable(ir::StaticEnable { group, .. }) => { + let g = group.borrow(); + let (r, w) = g.assignments.iter().analysis().reads_and_writes(); + (r.collect(), w.collect()) + } ir::StaticControl::Repeat(ir::StaticRepeat { body, .. }) => { Self::control_port_read_write_set_static(body) } @@ -236,20 +301,23 @@ impl ReadWriteSet { ) -> (Vec>, Vec>) { match con { ir::Control::Empty(_) => (vec![], vec![]), - ir::Control::Enable(ir::Enable { group, .. }) => ( - Self::port_read_set(group.borrow().assignments.iter().filter( - |assign| { - INCLUDE_HOLE_ASSIGNS || !assign.dst.borrow().is_hole() - }, - )) - .collect(), - Self::port_write_set(group.borrow().assignments.iter().filter( - |assign| { - INCLUDE_HOLE_ASSIGNS || !assign.dst.borrow().is_hole() - }, - )) - .collect(), - ), + ir::Control::Enable(ir::Enable { group, .. }) => { + let group = group.borrow(); + let (reads, writes) = + group.assignments.iter().analysis().reads_and_writes(); + ( + reads + .filter(|p| { + INCLUDE_HOLE_ASSIGNS || !p.borrow().is_hole() + }) + .collect(), + writes + .filter(|p| { + INCLUDE_HOLE_ASSIGNS || !p.borrow().is_hole() + }) + .collect(), + ) + } ir::Control::Invoke(ir::Invoke { inputs, outputs, @@ -295,10 +363,12 @@ impl ReadWriteSet { 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(r).collect(), writes.chain(w).collect()) + let (reads, writes) = + cg.assignments.iter().analysis().reads_and_writes(); + ( + reads.into_iter().chain(r).collect(), + writes.into_iter().chain(w).collect(), + ) } None => (r, w), } @@ -330,12 +400,11 @@ impl ReadWriteSet { twrites.append(&mut fwrites); if let Some(cg) = cond { - treads.extend(Self::port_read_set( - cg.borrow().assignments.iter(), - )); - twrites.extend(Self::port_write_set( - cg.borrow().assignments.iter(), - )); + let cg = cg.borrow(); + let (reads, writes) = + cg.assignments.iter().analysis().reads_and_writes(); + treads.extend(reads); + twrites.extend(writes); } (treads, twrites) } @@ -347,12 +416,11 @@ impl ReadWriteSet { reads.push(Rc::clone(port)); if let Some(cg) = cond { - reads.extend(Self::port_read_set( - cg.borrow().assignments.iter(), - )); - writes.extend(Self::port_write_set( - cg.borrow().assignments.iter(), - )); + let cg = cg.borrow(); + let (r, w) = + cg.assignments.iter().analysis().reads_and_writes(); + reads.extend(r); + writes.extend(w); } (reads, writes) } @@ -386,26 +454,4 @@ impl ReadWriteSet { .collect(), ) } - - /// Returns the ports that are read and written, respectively, - /// in the continuous assignments of the given component. - pub fn cont_ports_read_write_set( - comp: &mut calyx_ir::Component, - ) -> (Vec>, Vec>) { - ( - Self::port_read_set(comp.continuous_assignments.iter()).collect(), - Self::port_write_set(comp.continuous_assignments.iter()).collect(), - ) - } - - /// Returns the cells that are read and written, respectively, - /// in the continuous assignments of the given component. - pub fn cont_read_write_set( - comp: &mut calyx_ir::Component, - ) -> (Vec>, Vec>) { - ( - Self::read_set(comp.continuous_assignments.iter()).collect(), - Self::write_set(comp.continuous_assignments.iter()).collect(), - ) - } } diff --git a/calyx-opt/src/analysis/variable_detection.rs b/calyx-opt/src/analysis/variable_detection.rs index 46535f5a33..3cc112b6fa 100644 --- a/calyx-opt/src/analysis/variable_detection.rs +++ b/calyx-opt/src/analysis/variable_detection.rs @@ -1,4 +1,4 @@ -use super::{GraphAnalysis, ReadWriteSet}; +use super::{read_write_set::AssignmentAnalysis, GraphAnalysis}; use crate::analysis::ShareSet; use calyx_ir::{self as ir, RRC}; @@ -18,7 +18,11 @@ impl VariableDetection { ) -> Option<(ir::CellType, ir::Id)> { let group = group_ref.borrow(); - let writes = ReadWriteSet::write_set(group.assignments.iter()) + let writes = group + .assignments + .iter() + .analysis() + .cell_writes() .filter(|cell| state_share.is_shareable_component(cell)) .collect::>(); diff --git a/calyx-opt/src/passes/cell_share.rs b/calyx-opt/src/passes/cell_share.rs index 9ec5f5c5a0..860abd2de8 100644 --- a/calyx-opt/src/passes/cell_share.rs +++ b/calyx-opt/src/passes/cell_share.rs @@ -1,5 +1,6 @@ use crate::analysis::{ - GraphColoring, LiveRangeAnalysis, ReadWriteSet, ShareSet, StaticParTiming, + AssignmentAnalysis, GraphColoring, LiveRangeAnalysis, ShareSet, + StaticParTiming, }; use crate::traversal::{ Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor, @@ -191,10 +192,13 @@ impl CellShare { _sigs: &ir::LibrarySignatures, ) { //add cont cells - self.cont_ref_cells = - ReadWriteSet::uses(comp.continuous_assignments.iter()) - .map(|cr| cr.borrow().name()) - .collect(); + self.cont_ref_cells = comp + .continuous_assignments + .iter() + .analysis() + .cell_uses() + .map(|cr| cr.borrow().name()) + .collect(); //add ref cells self.cont_ref_cells.extend( comp.cells diff --git a/calyx-opt/src/passes/group_to_invoke.rs b/calyx-opt/src/passes/group_to_invoke.rs index 3764ad0abc..4acdb50020 100644 --- a/calyx-opt/src/passes/group_to_invoke.rs +++ b/calyx-opt/src/passes/group_to_invoke.rs @@ -1,4 +1,4 @@ -use crate::analysis::ReadWriteSet; +use crate::analysis::AssignmentAnalysis; use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; use calyx_ir::{self as ir}; use calyx_ir::{GetAttributes, RRC}; @@ -237,7 +237,10 @@ impl GroupToInvoke { assigns: &[ir::Assignment], group_done_port: &ir::RRC, ) { - let mut writes = ReadWriteSet::write_set(assigns.iter()) + let mut writes = assigns + .iter() + .analysis() + .cell_writes() .filter(|cell| match cell.borrow().prototype { ir::CellType::Primitive { is_comb, .. } => !is_comb, _ => true, diff --git a/calyx-opt/src/passes/group_to_seq.rs b/calyx-opt/src/passes/group_to_seq.rs index e58983f489..4b39c960dd 100644 --- a/calyx-opt/src/passes/group_to_seq.rs +++ b/calyx-opt/src/passes/group_to_seq.rs @@ -1,4 +1,4 @@ -use crate::analysis::ReadWriteSet; +use crate::analysis::{AssignmentAnalysis, ReadWriteSet}; use crate::traversal::{Action, Named, VisResult, Visitor}; use calyx_ir as ir; use ir::Nothing; @@ -150,7 +150,7 @@ fn comp_or_non_comb(cell: &ir::RRC) -> bool { //If asmt is a write to a cell named name returns Some(name). //If asmt is a write to a group port, returns None. fn writes_to_cell(asmt: &ir::Assignment) -> Option> { - ReadWriteSet::write_set(std::iter::once(asmt)).next() + std::iter::once(asmt).analysis().cell_writes().next() } ///Primarily used to help determine the order cells are executed within @@ -306,16 +306,18 @@ where pub fn possible_split( asmts: &[ir::Assignment], ) -> Option<(ir::Id, ir::Id)> { - let stateful_writes: Vec = - ReadWriteSet::write_set(asmts.iter()) - .filter_map(|cell| { - if cell.borrow().is_comb_cell() { - None - } else { - Some(cell.borrow().name()) - } - }) - .collect(); + let stateful_writes: Vec = asmts + .iter() + .analysis() + .cell_writes() + .filter_map(|cell| { + if cell.borrow().is_comb_cell() { + None + } else { + Some(cell.borrow().name()) + } + }) + .collect(); if stateful_writes.len() == 2 { let (maybe_first, maybe_last, last) = diff --git a/calyx-opt/src/passes/papercut.rs b/calyx-opt/src/passes/papercut.rs index 895e0faee3..aa98626ed5 100644 --- a/calyx-opt/src/passes/papercut.rs +++ b/calyx-opt/src/passes/papercut.rs @@ -1,4 +1,4 @@ -use crate::analysis; +use crate::analysis::{self, AssignmentAnalysis}; use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; use calyx_ir::{self as ir, LibrarySignatures}; use calyx_utils::{CalyxResult, Error}; @@ -124,11 +124,13 @@ impl Visitor for Papercut { } // Compute all cells that are driven in by the continuous assignments0 - self.cont_cells = analysis::ReadWriteSet::write_set( - comp.continuous_assignments.iter(), - ) - .map(|cr| cr.borrow().name()) - .collect(); + self.cont_cells = comp + .continuous_assignments + .iter() + .analysis() + .cell_writes() + .map(|cr| cr.borrow().name()) + .collect(); Ok(Action::Continue) } @@ -200,11 +202,17 @@ impl Visitor for Papercut { impl Papercut { fn check_specs(&mut self, assigns: &[ir::Assignment]) -> VisResult { - let all_writes = analysis::ReadWriteSet::port_write_set(assigns.iter()) + let all_writes = assigns + .iter() + .analysis() + .writes() .filter_map(port_information) .into_grouping_map() .collect::>(); - let all_reads = analysis::ReadWriteSet::port_read_set(assigns.iter()) + let all_reads = assigns + .iter() + .analysis() + .reads() .filter_map(port_information) .into_grouping_map() .collect::>(); diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs index 69f051bea5..23f8683131 100644 --- a/calyx-opt/src/passes/schedule_compaction.rs +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -1,4 +1,6 @@ -use crate::analysis::{InferenceAnalysis, PromotionAnalysis, ReadWriteSet}; +use crate::analysis::{ + AssignmentAnalysis, InferenceAnalysis, PromotionAnalysis, +}; use crate::traversal::{Action, ConstructVisitor}; use crate::{ analysis, @@ -261,7 +263,13 @@ impl Visitor for ScheduleCompaction { sigs: &calyx_ir::LibrarySignatures, _comps: &[calyx_ir::Component], ) -> crate::traversal::VisResult { - let (cont_reads, cont_writes) = ReadWriteSet::cont_read_write_set(comp); + let (cont_reads, cont_writes) = comp + .continuous_assignments + .iter() + .analysis() + .reads_and_writes(); + let (cont_reads, cont_writes) = + (cont_reads.cells().collect(), cont_writes.cells().collect()); InferenceAnalysis::remove_promotable_from_seq(s); self.inference_analysis.fixup_seq(s);