Skip to content

Commit

Permalink
Static interface (#1759)
Browse files Browse the repository at this point in the history
* implemented static interface

* fmt

* clippy

* fmt

* added implementation for one-cycle static interface and avoid promoting main component

* fmt

* clippy

* change order of compile-invoke

* change pass ordering

* restore pass ordering

* changes

* change pass ordering

* clippy

* fmt

* clippy

* add test cases

* restore pass ordering

* fmt

* fix test cases
  • Loading branch information
paili0628 authored Nov 12, 2023
1 parent a43513a commit 4ed26dd
Show file tree
Hide file tree
Showing 43 changed files with 1,252 additions and 158 deletions.
2 changes: 2 additions & 0 deletions calyx-frontend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ pub enum Control {
attributes: Attributes,
/// External cells that may execute with this invoke.
ref_cells: Vec<(Id, Id)>,
/// Combinational group that may execute with this invoke.
comb_group: Option<Id>,
/// (optional) latency. Latency can be inferred if not given.
latency: Option<NonZeroU64>,
},
Expand Down
3 changes: 3 additions & 0 deletions calyx-frontend/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ pub enum BoolAttr {
#[strum(serialize = "inline")]
/// Inline this subcomponent
Inline,
#[strum(serialize = "promoted")]
/// denotes a static component promoted from dynamic
Promoted,
}
impl From<BoolAttr> for Attribute {
fn from(attr: BoolAttr) -> Self {
Expand Down
12 changes: 11 additions & 1 deletion calyx-frontend/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use calyx_utils::{self, CalyxResult, Id};
use calyx_utils::{FileIdx, GPosIdx, GlobalPositionTable};
use pest::pratt_parser::{Assoc, Op, PrattParser};
use pest_consume::{match_nodes, Error, Parser};
use std::convert::TryInto;
use std::fs;
use std::io::Read;
use std::path::Path;
Expand Down Expand Up @@ -865,6 +864,17 @@ impl CalyxParser {
attributes: attrs.add_span(span),
ref_cells: cells,
latency,
comb_group: None,
},
[at_attributes(attrs), static_optional_latency(latency), identifier(comp), invoke_ref_args(cells),invoke_args(inputs), invoke_args(outputs), identifier(group)] =>
ast::Control::StaticInvoke {
comp,
inputs,
outputs,
attributes: attrs.add_span(span),
ref_cells: cells,
latency,
comb_group: Some(group),
},
))
}
Expand Down
2 changes: 1 addition & 1 deletion calyx-frontend/src/syntax.pest
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ invoke_args = { (invoke_arg ~ ("," ~ invoke_arg)*)? }
invoke_ref_arg = {identifier ~ "=" ~ identifier}
invoke_ref_args = {("[" ~ (invoke_ref_arg ~ ("," ~ invoke_ref_arg)*)? ~ "]")?}
invoke = { at_attributes ~ "invoke" ~ identifier ~ invoke_ref_args ~ "(" ~ invoke_args ~ ")" ~ "(" ~ invoke_args ~ ")" ~ ("with" ~ identifier)? ~ ";" }
static_invoke = { at_attributes ~ static_optional_latency ~ "invoke" ~ identifier ~ invoke_ref_args ~ "(" ~ invoke_args ~ ")" ~ "(" ~ invoke_args ~ ")" ~ ";" }
static_invoke = { at_attributes ~ static_optional_latency ~ "invoke" ~ identifier ~ invoke_ref_args ~ "(" ~ invoke_args ~ ")" ~ "(" ~ invoke_args ~ ")" ~ ("with" ~ identifier)? ~ ";" }

seq = {
at_attributes ~ "seq" ~ "{"
Expand Down
3 changes: 3 additions & 0 deletions calyx-ir/src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ pub struct StaticInvoke {
pub attributes: Attributes,
/// Mapping from name of external cell in 'comp' to the cell connected to it.
pub ref_cells: CellMap,
/// Optional combinational group that is active when the invoke is active.
pub comb_group: Option<RRC<CombGroup>>,
}
impl GetAttributes for StaticInvoke {
fn get_attributes(&self) -> &Attributes {
Expand Down Expand Up @@ -818,6 +820,7 @@ impl Cloner {
outputs: i.outputs.clone(),
attributes: i.attributes.clone(),
ref_cells: i.ref_cells.clone(),
comb_group: i.comb_group.clone(),
}
}

Expand Down
263 changes: 167 additions & 96 deletions calyx-ir/src/from_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ use super::{
RESERVED_NAMES, RRC,
};
use crate::{Nothing, PortComp, StaticTiming};
use calyx_frontend::{ast, ast::Atom, BoolAttr, Workspace};
use calyx_frontend::{ast, BoolAttr, Workspace};
use calyx_utils::{CalyxResult, Error, GPosIdx, WithPos};
use itertools::Itertools;

use std::collections::{HashMap, HashSet};
use std::num::NonZeroU64;
use std::rc::Rc;

type InvokePortMap = Vec<(Id, Atom)>;

/// Context to store the signature information for all defined primitives and
/// components.
#[derive(Default)]
Expand Down Expand Up @@ -696,82 +694,6 @@ fn build_static_if(
Ok(con)
}

// builds a static invoke from the given information
fn build_static_invoke(
builder: &mut Builder,
component: Id,
(inputs, outputs): (InvokePortMap, InvokePortMap),
attributes: Attributes,
ref_cells: Vec<(Id, Id)>,
given_latency: Option<std::num::NonZeroU64>,
sig_ctx: &SigCtx,
) -> CalyxResult<StaticControl> {
let cell = Rc::clone(&builder.component.find_cell(component).ok_or_else(
|| {
Error::undefined(component, "cell".to_string())
.with_pos(&attributes)
},
)?);
let comp_name = cell
.borrow()
.type_name()
.unwrap_or_else(|| unreachable!("invoked component without a name"));
let latency = get_comp_latency(sig_ctx, Rc::clone(&cell), &attributes)?;
let unwrapped_latency = if let Some(v) = latency {
v
} else {
return Err(Error::malformed_control(format!(
"non-static component {} is statically invoked",
comp_name
))
.with_pos(&attributes));
};
assert_latencies_eq(given_latency, unwrapped_latency.into());

let inputs = inputs
.into_iter()
.map(|(id, port)| {
// checking that comp_name.id exists on comp's signature
check_valid_port(Rc::clone(&cell), &id, &attributes, sig_ctx)?;
atom_to_port(port, builder)
.and_then(|pr| ensure_direction(pr, Direction::Output))
.map(|p| (id, p))
})
.collect::<Result<_, _>>()?;
let outputs = outputs
.into_iter()
.map(|(id, port)| {
// checking that comp_name.id exists on comp's signature
check_valid_port(Rc::clone(&cell), &id, &attributes, sig_ctx)?;
atom_to_port(port, builder)
.and_then(|pr| ensure_direction(pr, Direction::Input))
.map(|p| (id, p))
})
.collect::<Result<_, _>>()?;
let mut inv = StaticInvoke {
comp: cell,
inputs,
outputs,
attributes: Attributes::default(),
ref_cells: Vec::new(),
latency: unwrapped_latency.into(),
};
if !ref_cells.is_empty() {
let mut ext_cell_tuples = Vec::new();
for (outcell, incell) in ref_cells {
let ext_cell_ref = builder
.component
.find_cell(incell)
.ok_or_else(|| Error::undefined(incell, "cell".to_string()))?;
ext_cell_tuples.push((outcell, ext_cell_ref));
}
inv.ref_cells = ext_cell_tuples;
}
let mut con = StaticControl::Invoke(inv);
*con.get_mut_attributes() = attributes;
Ok(con)
}

fn build_static_repeat(
num_repeats: u64,
body: ast::Control,
Expand Down Expand Up @@ -823,16 +745,91 @@ fn build_static_control(
attributes,
ref_cells,
latency,
comb_group,
} => {
return build_static_invoke(
builder,
comp,
(inputs, outputs),
attributes,
ref_cells,
latency,
sig_ctx,
let cell = Rc::clone(
&builder.component.find_cell(comp).ok_or_else(|| {
Error::undefined(comp, "cell".to_string())
.with_pos(&attributes)
})?,
);
let comp_name = cell.borrow().type_name().unwrap_or_else(|| {
unreachable!("invoked component without a name")
});
let c_latency =
get_comp_latency(sig_ctx, Rc::clone(&cell), &attributes)?;
let unwrapped_latency = if let Some(v) = c_latency {
v
} else {
return Err(Error::malformed_control(format!(
"non-static component {} is statically invoked",
comp_name
))
.with_pos(&attributes));
};
assert_latencies_eq(latency, unwrapped_latency.into());

let inputs = inputs
.into_iter()
.map(|(id, port)| {
// checking that comp_name.id exists on comp's signature
check_valid_port(
Rc::clone(&cell),
&id,
&attributes,
sig_ctx,
)?;
atom_to_port(port, builder)
.and_then(|pr| ensure_direction(pr, Direction::Output))
.map(|p| (id, p))
})
.collect::<Result<_, _>>()?;
let outputs = outputs
.into_iter()
.map(|(id, port)| {
// checking that comp_name.id exists on comp's signature
check_valid_port(
Rc::clone(&cell),
&id,
&attributes,
sig_ctx,
)?;
atom_to_port(port, builder)
.and_then(|pr| ensure_direction(pr, Direction::Input))
.map(|p| (id, p))
})
.collect::<Result<_, _>>()?;
let mut inv = StaticInvoke {
comp: cell,
inputs,
outputs,
attributes: Attributes::default(),
ref_cells: Vec::new(),
latency: unwrapped_latency.into(),
comb_group: None,
};
if !ref_cells.is_empty() {
let mut ext_cell_tuples = Vec::new();
for (outcell, incell) in ref_cells {
let ext_cell_ref =
builder.component.find_cell(incell).ok_or_else(
|| Error::undefined(incell, "cell".to_string()),
)?;
ext_cell_tuples.push((outcell, ext_cell_ref));
}
inv.ref_cells = ext_cell_tuples;
}
if let Some(cg) = comb_group {
let cg_ref =
builder.component.find_comb_group(cg).ok_or_else(|| {
Error::undefined(cg, "combinational group".to_string())
.with_pos(&inv.attributes)
})?;
inv.comb_group = Some(cg_ref);
}
let mut con = StaticControl::Invoke(inv);
*con.get_mut_attributes() = attributes;
return Ok(con);
}
ast::Control::StaticSeq {
stmts,
Expand Down Expand Up @@ -933,17 +930,91 @@ fn build_control(
attributes,
ref_cells,
latency,
comb_group,
} => {
let i = build_static_invoke(
builder,
comp,
(inputs, outputs),
attributes,
ref_cells,
latency,
sig_ctx,
let cell = Rc::clone(
&builder.component.find_cell(comp).ok_or_else(|| {
Error::undefined(comp, "cell".to_string())
.with_pos(&attributes)
})?,
);
Control::Static(i?)
let comp_name = cell.borrow().type_name().unwrap_or_else(|| {
unreachable!("invoked component without a name")
});
let c_latency =
get_comp_latency(sig_ctx, Rc::clone(&cell), &attributes)?;
let unwrapped_latency = if let Some(v) = c_latency {
v
} else {
return Err(Error::malformed_control(format!(
"non-static component {} is statically invoked",
comp_name
))
.with_pos(&attributes));
};
assert_latencies_eq(latency, unwrapped_latency.into());

let inputs = inputs
.into_iter()
.map(|(id, port)| {
// checking that comp_name.id exists on comp's signature
check_valid_port(
Rc::clone(&cell),
&id,
&attributes,
sig_ctx,
)?;
atom_to_port(port, builder)
.and_then(|pr| ensure_direction(pr, Direction::Output))
.map(|p| (id, p))
})
.collect::<Result<_, _>>()?;
let outputs = outputs
.into_iter()
.map(|(id, port)| {
// checking that comp_name.id exists on comp's signature
check_valid_port(
Rc::clone(&cell),
&id,
&attributes,
sig_ctx,
)?;
atom_to_port(port, builder)
.and_then(|pr| ensure_direction(pr, Direction::Input))
.map(|p| (id, p))
})
.collect::<Result<_, _>>()?;
let mut inv = StaticInvoke {
comp: cell,
inputs,
outputs,
attributes: Attributes::default(),
ref_cells: Vec::new(),
latency: unwrapped_latency.into(),
comb_group: None,
};
if !ref_cells.is_empty() {
let mut ext_cell_tuples = Vec::new();
for (outcell, incell) in ref_cells {
let ext_cell_ref =
builder.component.find_cell(incell).ok_or_else(
|| Error::undefined(incell, "cell".to_string()),
)?;
ext_cell_tuples.push((outcell, ext_cell_ref));
}
inv.ref_cells = ext_cell_tuples;
}
if let Some(cg) = comb_group {
let cg_ref =
builder.component.find_comb_group(cg).ok_or_else(|| {
Error::undefined(cg, "combinational group".to_string())
.with_pos(&inv.attributes)
})?;
inv.comb_group = Some(cg_ref);
}
let mut con = StaticControl::Invoke(inv);
*con.get_mut_attributes() = attributes;
Control::Static(con)
}
ast::Control::Invoke {
comp: component,
Expand Down
4 changes: 4 additions & 0 deletions calyx-ir/src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ impl Printer {
outputs,
attributes,
ref_cells,
comb_group,
}) => {
write!(f, "{}", Self::format_at_attributes(attributes))?;
write!(
Expand Down Expand Up @@ -552,6 +553,9 @@ impl Printer {
}
if outputs.is_empty() {
write!(f, ")")?;
}
if let Some(group) = comb_group {
writeln!(f, " with {};", group.borrow().name)?;
} else {
write!(f, "\n{})", " ".repeat(indent_level))?;
}
Expand Down
Loading

0 comments on commit 4ed26dd

Please sign in to comment.