Skip to content

Commit

Permalink
Turn dynamic to static (#1419)
Browse files Browse the repository at this point in the history
* added dynamic_to_static pass, and added functions to turn dynamic guards and assignments
into static ones

* added dynamic-to-static pass

* separate new infer-static-timing pass from old one

* fmt

* fixed bug and changed pass name to group-static-promotion

* fmt

* addressed comments

* fmt

* clippy

* fixed error message

* got rid of infer-static-timing pass

* modify group-static-promotion pass

* merge conflict

* temp

* err

* modified static-group-promotion, fixed test cases

* fmt and rename

* added group promotion tests

* clippY

* deleted @static attributes tests

* rename tests

* deleted all infer-static test cases

* make changes

* fixed non-frontend tests

* changed frontend tests

* redid dahlia test cases

* implemented From<> without &

* simplify-with-control uses static groups

* fixed bug

* improved test cases

* removed debugging stmts

* rewrite compiler test cases, add go-done port to static-promotion

* attribute promotion, some small static promotion fixes

* overwrite tests .expect files

* code cleaning

* further code cleaning

* clippy

* changed test cases

* skip sync-dot-product-opt.futil

---------

Co-authored-by: Caleb <[email protected]>
Co-authored-by: calebmkim <[email protected]>
  • Loading branch information
3 people authored May 17, 2023
1 parent 8464a6a commit 86c6762
Show file tree
Hide file tree
Showing 116 changed files with 1,231 additions and 1,164 deletions.
10 changes: 2 additions & 8 deletions calyx-ir/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use super::{
};
use crate::guard::StaticTiming;
use crate::Nothing;
use calyx_frontend::NumAttr;
use calyx_utils::NameGenerator;
use itertools::Itertools;
use linked_hash_map::LinkedHashMap;
Expand Down Expand Up @@ -174,14 +173,9 @@ impl Component {
}

/// Check whether this is a static component.
/// A static component is a component that has at least one static go-done path.
/// A static component is a component which has a latency field.
pub fn is_static(&self) -> bool {
let sig = self.signature.borrow();
let mut go_ports = sig.find_all_with_attr(NumAttr::Go);
go_ports.any(|p| {
let port = p.borrow();
port.attributes.has(NumAttr::Static)
})
self.latency.is_some()
}

/// Apply function to all assignments within static groups.
Expand Down
21 changes: 21 additions & 0 deletions calyx-ir/src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,19 @@ pub enum StaticControl {
Invoke(StaticInvoke),
}

impl Control {
pub fn is_static(&self) -> bool {
matches!(self, Control::Static(_))
}

pub fn get_latency(&self) -> Option<StaticLatency> {
match self {
Control::Static(sc) => Some(sc.get_latency()),
_ => None,
}
}
}

impl From<Invoke> for Control {
fn from(inv: Invoke) -> Self {
Control::Invoke(inv)
Expand Down Expand Up @@ -457,6 +470,14 @@ impl Control {
})
}

/// Convience constructor for enable.
pub fn static_enable(group: RRC<StaticGroup>) -> Self {
Control::Static(StaticControl::Enable(StaticEnable {
group,
attributes: Attributes::default(),
}))
}

/// Convience constructor for invoke.
pub fn invoke(comp: RRC<Cell>, inputs: PortMap, outputs: PortMap) -> Self {
Control::Invoke(Invoke {
Expand Down
32 changes: 32 additions & 0 deletions calyx-ir/src/guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,38 @@ where
}
}

impl From<Guard<Nothing>> for Guard<StaticTiming> {
/// Turns a normal guard into a static guard
fn from(g: Guard<Nothing>) -> Self {
match g {
Guard::Or(left, right) => {
let l = Self::from(*left);
let r = Self::from(*right);
Guard::Or(Box::new(l), Box::new(r))
}
Guard::And(left, right) => {
let l = Self::from(*left);
let r = Self::from(*right);
Guard::And(Box::new(l), Box::new(r))
}
Guard::Not(c) => {
let inside = Self::from(*c);
Guard::Not(Box::new(inside))
}
Guard::True => Guard::True,
Guard::CompOp(pc, left, right) => Guard::CompOp(pc, left, right),
Guard::Port(p) => Guard::Port(p),
Guard::Info(_) => {
unreachable!(
"{:?}: Guard<Nothing> should not be of the
info variant type",
g
)
}
}
}
}

impl<T> Guard<T> {
/// Returns true definitely `Guard::True`.
/// Returning false does not mean that the guard is not true.
Expand Down
12 changes: 12 additions & 0 deletions calyx-ir/src/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,18 @@ impl<T> Assignment<T> {
}
}

impl From<Assignment<Nothing>> for Assignment<StaticTiming> {
/// Turns a normal assignment into a static assignment
fn from(assgn: Assignment<Nothing>) -> Assignment<StaticTiming> {
Assignment {
dst: Rc::clone(&assgn.dst),
src: Rc::clone(&assgn.src),
guard: Box::new(Guard::from(*assgn.guard)),
attributes: assgn.attributes,
}
}
}

impl<StaticTiming> Assignment<StaticTiming> {
/// Apply function `f` to each port contained within the assignment and
/// replace the port with the generated value if not None.
Expand Down
81 changes: 81 additions & 0 deletions calyx-opt/src/analysis/compute_static.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use calyx_ir::{self as ir, GetAttributes};
use std::collections::HashMap;
use std::rc::Rc;

/// Trait to propagate and extra "static" attributes through [ir::Control].
/// Calling the update function ensures that the current program, as well as all
Expand Down Expand Up @@ -133,3 +134,83 @@ impl WithStatic for ir::While {
Some(bound * b_time)
}
}

pub trait IntoStatic {
type StaticCon;
fn make_static(&mut self) -> Option<Self::StaticCon>;
}

impl IntoStatic for ir::Seq {
type StaticCon = ir::StaticSeq;
fn make_static(&mut self) -> Option<Self::StaticCon> {
let mut static_stmts: Vec<ir::StaticControl> = Vec::new();
let mut latency = 0;
for stmt in self.stmts.iter() {
if !matches!(stmt, ir::Control::Static(_)) {
log::debug!("Cannot build `static seq`. Control statement inside `seq` is not static");
return None;
}
}

for stmt in self.stmts.drain(..) {
let ir::Control::Static(sc) = stmt else {unreachable!("We have already checked that all control statements are static")};
latency += sc.get_latency();
static_stmts.push(sc);
}
Some(ir::StaticSeq {
stmts: static_stmts,
attributes: self.attributes.clone(),
latency,
})
}
}

impl IntoStatic for ir::Par {
type StaticCon = ir::StaticPar;
fn make_static(&mut self) -> Option<Self::StaticCon> {
let mut static_stmts: Vec<ir::StaticControl> = Vec::new();
let mut latency = 0;
for stmt in self.stmts.iter() {
if !matches!(stmt, ir::Control::Static(_)) {
log::debug!("Cannot build `static seq`. Control statement inside `seq` is not static");
return None;
}
}

for stmt in self.stmts.drain(..) {
let ir::Control::Static(sc) = stmt else {unreachable!("We have already checked that all control statements are static")};
latency = std::cmp::max(latency, sc.get_latency());
static_stmts.push(sc);
}
Some(ir::StaticPar {
stmts: static_stmts,
attributes: self.attributes.clone(),
latency,
})
}
}

impl IntoStatic for ir::If {
type StaticCon = ir::StaticIf;
fn make_static(&mut self) -> Option<Self::StaticCon> {
if !(self.tbranch.is_static() && self.fbranch.is_static()) {
return None;
};
let tb = std::mem::replace(&mut *self.tbranch, ir::Control::empty());
let fb = std::mem::replace(&mut *self.fbranch, ir::Control::empty());
let ir::Control::Static(sc_t) = tb else {
unreachable!("we have already checked tbranch to be static")
};
let ir::Control::Static(sc_f) = fb else {
unreachable!("we have already checker fbranch to be static")
};
let latency = std::cmp::max(sc_t.get_latency(), sc_f.get_latency());
Some(ir::StaticIf {
tbranch: Box::new(sc_t),
fbranch: Box::new(sc_f),
attributes: ir::Attributes::default(),
port: Rc::clone(&self.port),
latency,
})
}
}
1 change: 1 addition & 0 deletions calyx-opt/src/analysis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod share_set;
mod static_par_timing;
mod variable_detection;

pub use compute_static::IntoStatic;
pub use compute_static::WithStatic;
pub use control_id::ControlId;
pub use control_order::ControlOrder;
Expand Down
24 changes: 12 additions & 12 deletions calyx-opt/src/default_passes.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! Defines the default passes available to [PassManager].
use crate::passes::{
Canonicalize, CellShare, ClkInsertion, CollapseControl, CombProp,
CompileEmpty, CompileInvoke, CompileRef, CompileStatic, CompileSync,
CompileSyncWithoutSyncReg, ComponentInliner, DataPathInfer,
AttributePromotion, Canonicalize, CellShare, ClkInsertion, CollapseControl,
CombProp, CompileEmpty, CompileInvoke, CompileRef, CompileStatic,
CompileSync, CompileSyncWithoutSyncReg, ComponentInliner, DataPathInfer,
DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, Externalize,
GoInsertion, GroupToInvoke, GroupToSeq, HoleInliner, InferShare,
InferStaticTiming, LowerGuards, MergeAssign, MergeStaticPar, Papercut,
ParToSeq, RegisterUnsharing, RemoveIds, ResetInsertion,
SimplifyStaticGuards, SimplifyWithControl, StaticInliner, StaticParConv,
LowerGuards, MergeAssign, MergeStaticPar, Papercut, ParToSeq,
RegisterUnsharing, RemoveIds, ResetInsertion, SimplifyStaticGuards,
SimplifyWithControl, StaticInliner, StaticParConv, StaticPromotion,
SynthesisPapercut, TopDownCompileControl, TopDownStaticTiming,
UnrollBounded, WellFormed, WireInliner,
};
Expand Down Expand Up @@ -36,9 +36,10 @@ impl PassManager {
pm.register_pass::<GroupToSeq>()?;
pm.register_pass::<InferShare>()?;
pm.register_pass::<CellShare>()?;
pm.register_pass::<InferStaticTiming>()?;
pm.register_pass::<MergeStaticPar>()?;
pm.register_pass::<StaticPromotion>()?;
pm.register_pass::<AttributePromotion>()?;
pm.register_pass::<SimplifyStaticGuards>()?;
pm.register_pass::<MergeStaticPar>()?;
pm.register_pass::<StaticParConv>()?;
pm.register_pass::<DataPathInfer>()?;

Expand Down Expand Up @@ -90,10 +91,9 @@ impl PassManager {
CombProp,
CellShare, // LiveRangeAnalaysis should handle comb groups
SimplifyWithControl, // Must run before infer-static-timing
InferStaticTiming,
CompileInvoke, // creates dead comb groups
StaticParConv, // Must be before collapse-control and merge-static-par
MergeStaticPar, // creates dead groups potentially
CompileInvoke, // creates dead comb groups
AttributePromotion,
StaticPromotion,
DeadGroupRemoval, // Since previous passes potentially create dead groups
CollapseControl,
]
Expand Down
87 changes: 87 additions & 0 deletions calyx-opt/src/passes/attribute_promotion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use crate::traversal::{Action, Named, VisResult, Visitor};
use calyx_ir::{self as ir, LibrarySignatures};
use std::collections::HashMap;

#[derive(Default)]
/// Removes NODE_ID, BEGIN_ID, and END_ID from each control statement
pub struct AttributePromotion {
/// maps dynamic group names its corresponding upgraded static group
/// Then we use this to replace regular groups
upgraded_groups: HashMap<ir::Id, ir::RRC<ir::StaticGroup>>,
}

impl Named for AttributePromotion {
fn name() -> &'static str {
"attr-promotion"
}

fn description() -> &'static str {
"upgrades @static and @bound annotations to appropriate static control"
}
}

impl Visitor for AttributePromotion {
fn start(
&mut self,
comp: &mut ir::Component,
sigs: &LibrarySignatures,
_comps: &[ir::Component],
) -> VisResult {
// drain groups
let comp_groups: Vec<ir::RRC<ir::Group>> =
comp.get_groups_mut().drain().collect();
let mut builder = ir::Builder::new(comp, sigs);
let mut non_upgraded_groups = Vec::new();

for group in comp_groups {
let group_rc_clone = std::rc::Rc::clone(&group);
let mut gr = group.borrow_mut();
// if group has static annotation, then create corresponding static group, and add to self.upgraded_groups
// otherwise just add back to component.groups
if let Some(lat) = gr.attributes.get(ir::NumAttr::Static) {
let sg = builder.add_static_group(gr.name(), lat);
for assignment in gr.assignments.drain(..) {
// don't add done signal to static group
if !(assignment.dst.borrow().is_hole()
&& assignment.dst.borrow().name == "done")
{
let static_s = ir::Assignment::from(assignment);
sg.borrow_mut().assignments.push(static_s);
}
}
self.upgraded_groups.insert(gr.name(), sg);
} else {
non_upgraded_groups.push(group_rc_clone);
}
}

builder
.component
.get_groups_mut()
.append(non_upgraded_groups.into_iter());

Ok(Action::Continue)
}

fn enable(
&mut self,
s: &mut ir::Enable,
_comp: &mut ir::Component,
_sigs: &LibrarySignatures,
_comps: &[ir::Component],
) -> VisResult {
// check if this groups is indeed an "upgraded_group". If so, then change
// to static enable. Otherwise continue.
if let Some(static_group) =
self.upgraded_groups.get(&s.group.borrow().name())
{
let static_enable = ir::StaticControl::Enable(ir::StaticEnable {
group: std::rc::Rc::clone(static_group),
attributes: s.attributes.clone(),
});
Ok(Action::change(ir::Control::Static(static_enable)))
} else {
Ok(Action::Continue)
}
}
}
6 changes: 4 additions & 2 deletions calyx-opt/src/passes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Passes for the Calyx compiler.
mod attribute_promotion;
mod canonical;
mod cell_share;
mod clk_insertion;
Expand All @@ -19,7 +20,6 @@ mod group_to_invoke;
mod group_to_seq;
mod hole_inliner;
mod infer_share;
mod infer_static_timing;
mod lower_guards;
mod math_utilities;
mod merge_assign;
Expand All @@ -31,6 +31,7 @@ mod remove_ids;
mod reset_insertion;
mod simplify_static_guards;
mod static_inliner;
mod static_promotion;
mod sync;
// mod simplify_guards;
mod data_path_infer;
Expand All @@ -43,6 +44,7 @@ mod unroll_bound;
mod well_formed;
mod wire_inliner;

pub use attribute_promotion::AttributePromotion;
pub use canonical::Canonicalize;
pub use cell_share::CellShare;
pub use clk_insertion::ClkInsertion;
Expand All @@ -62,7 +64,6 @@ pub use group_to_invoke::GroupToInvoke;
pub use group_to_seq::GroupToSeq;
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;
Expand All @@ -74,6 +75,7 @@ pub use reset_insertion::ResetInsertion;
pub use simplify_static_guards::SimplifyStaticGuards;
pub use simplify_with_control::SimplifyWithControl;
pub use static_inliner::StaticInliner;
pub use static_promotion::StaticPromotion;
pub use sync::CompileSync;
pub use sync::CompileSyncWithoutSyncReg;
// pub use simplify_guards::SimplifyGuards;
Expand Down
Loading

0 comments on commit 86c6762

Please sign in to comment.