Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement invoke #300

Merged
merged 20 commits into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions calyx/src/analysis/live_range_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ fn build_live_ranges(
) {
match c {
ir::Control::Empty(_) => (),
ir::Control::Invoke(_) => unimplemented!(),
ir::Control::Enable(ir::Enable { group }) => {
// XXX(sam) no reason to compute this every time
let (reads, writes) = LiveRangeAnalysis::find_gen_kill(&group);
Expand Down
1 change: 1 addition & 0 deletions calyx/src/analysis/schedule_conflicts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ fn build_conflict_graph(
) {
match c {
ir::Control::Empty(_) => (),
ir::Control::Invoke(_) => unimplemented!(),
ir::Control::Enable(ir::Enable { group }) => {
confs.add_node(group);
all_enables.push(Rc::clone(group));
Expand Down
9 changes: 9 additions & 0 deletions calyx/src/frontend/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,15 @@ pub enum Control {
/// Group to be enabled
comp: ir::Id,
},
/// Invoke component with input/output assignments.
Invoke {
/// Name of the component to be invoked.
comp: ir::Id,
/// Input assignments
inputs: Vec<(ir::Id, Port)>,
/// Output assignments
outputs: Vec<(ir::Id, Port)>,
},
/// Control statement that does nothing.
Empty {},
}
10 changes: 6 additions & 4 deletions calyx/src/frontend/futil_syntax.pest
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ connections = {

enable = { identifier ~ ";" }

invoke_arg = { identifier ~ "=" ~ port }
invoke_args = { (invoke_arg ~ ("," ~ invoke_arg)*)? }
invoke = { "invoke" ~ identifier ~ "(" ~ invoke_args ~ ")" ~ "(" ~ invoke_args ~ ")" ~ ";" }

seq = {
"seq" ~ "{"
~ stmt*
Expand Down Expand Up @@ -202,15 +206,13 @@ while_stmt = {

stmt = {
enable
| invoke
| (seq ~ ";"?)
| (par ~ ";"?)
| (if_stmt ~ ";"?)
| (while_stmt ~ ";"?)
}

control = {
"control"
~ "{"
~ stmt?
~ "}"
"control" ~ (("{" ~ "}") | block)
}
25 changes: 24 additions & 1 deletion calyx/src/frontend/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,28 @@ impl FutilParser {
Ok((wires, groups))
}

fn invoke_arg(input: Node) -> ParseResult<(ir::Id, ast::Port)> {
Ok(match_nodes!(
input.into_children();
[identifier(name), port(p)] => (name, p)
))
}

fn invoke_args(input: Node) -> ParseResult<Vec<(ir::Id, ast::Port)>> {
Ok(match_nodes!(
input.into_children();
[invoke_arg(args)..] => args.collect()
))
}

fn invoke(input: Node) -> ParseResult<ast::Control> {
Ok(match_nodes!(
input.into_children();
[identifier(comp), invoke_args(inputs), invoke_args(outputs)] =>
ast::Control::Invoke { comp, inputs, outputs }
))
}

fn enable(input: Node) -> ParseResult<ast::Control> {
Ok(match_nodes!(
input.into_children();
Expand Down Expand Up @@ -457,6 +479,7 @@ impl FutilParser {
Ok(match_nodes!(
input.into_children();
[enable(data)] => data,
[invoke(data)] => data,
[seq(data)] => data,
[par(data)] => data,
[if_stmt(data)] => data,
Expand All @@ -483,7 +506,7 @@ impl FutilParser {
fn control(input: Node) -> ParseResult<ast::Control> {
Ok(match_nodes!(
input.into_children();
[stmt(stmt)] => stmt,
[block(stmt)] => stmt,
[] => ast::Control::Empty{}
))
}
Expand Down
35 changes: 26 additions & 9 deletions calyx/src/ir/control.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
use super::{Group, Port, RRC};
use super::{Cell, Group, Id, Port, RRC};

/// Data for the `seq` control statement.
//#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[derive(Debug)]
pub struct Seq {
/// List of `Control` statements to run in sequence.
pub stmts: Vec<Control>,
}

/// Data for the `par` control statement.
//#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[derive(Debug)]
pub struct Par {
/// List of `Control` statements to run in parallel.
pub stmts: Vec<Control>,
}

/// Data for the `if` control statement.
//#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[derive(Debug)]
pub struct If {
/// Port that connects the conditional check.
Expand All @@ -34,7 +31,6 @@ pub struct If {
}

/// Data for the `if` control statement.
//#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[derive(Debug)]
pub struct While {
/// Port that connects the conditional check.
Expand All @@ -48,26 +44,36 @@ pub struct While {
}

/// Data for the `enable` control statement.
//#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[derive(Debug)]
pub struct Enable {
/// List of components to run.
pub group: RRC<Group>,
}

type PortMap = Vec<(Id, RRC<Port>)>;

/// Data for an `invoke` control statement.
#[derive(Debug)]
pub struct Invoke {
/// Cell that is being invoked.
pub comp: RRC<Cell>,
/// Mapping from name of input ports in `comp` to the port connected to it.
pub inputs: PortMap,
/// Mapping from name of output ports in `comp` to the port connected to it.
pub outputs: PortMap,
}

impl From<RRC<Group>> for Enable {
fn from(group: RRC<Group>) -> Self {
Enable { group }
}
}

/// Data for the `empty` control statement.
//#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[derive(Debug)]
pub struct Empty {}

/// Control AST nodes.
//#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[derive(Debug)]
pub enum Control {
/// Represents sequential composition of control statements.
Expand All @@ -78,6 +84,8 @@ pub enum Control {
If(If),
/// Standard imperative while statement
While(While),
/// Invoke a sub-component with the given port assignments
Invoke(Invoke),
/// Runs the control for a list of subcomponents.
Enable(Enable),
/// Control statement that does nothing.
Expand All @@ -100,11 +108,20 @@ impl Control {
Control::Par(Par { stmts })
}

/// Convience constructor for par.
/// Convience constructor for enable.
pub fn enable(group: RRC<Group>) -> Self {
Control::Enable(Enable { group })
}

/// Convience constructor for invoke.
pub fn invoke(comp: RRC<Cell>, inputs: PortMap, outputs: PortMap) -> Self {
Control::Invoke(Invoke {
comp,
inputs,
outputs,
})
}

/// Convience constructor for if
pub fn if_(
port: RRC<Port>,
Expand Down
19 changes: 19 additions & 0 deletions calyx/src/ir/from_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,25 @@ fn build_control(
Error::Undefined(component.clone(), "group".to_string())
})?,
)),
ast::Control::Invoke {
comp: component,
inputs,
outputs,
} => {
let cell =
Rc::clone(&comp.find_cell(&component).ok_or_else(|| {
Error::Undefined(component.clone(), "cell".to_string())
})?);
let inps = inputs
.into_iter()
.map(|(id, port)| get_port_ref(port, comp).map(|p| (id, p)))
.collect::<Result<_, _>>()?;
let outs = outputs
.into_iter()
.map(|(id, port)| get_port_ref(port, comp).map(|p| (id, p)))
.collect::<Result<_, _>>()?;
Control::invoke(cell, inps, outs)
}
ast::Control::Seq { stmts } => Control::seq(
stmts
.into_iter()
Expand Down
2 changes: 1 addition & 1 deletion calyx/src/ir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub use builder::Builder;
pub use common::{RRC, WRC};
pub use component::Component;
pub use context::Context;
pub use control::{Control, Empty, Enable, If, Par, Seq, While};
pub use control::{Control, Empty, Enable, If, Invoke, Par, Seq, While};
pub use guard::Guard;
pub use id::Id;
pub use printer::IRPrinter;
Expand Down
39 changes: 36 additions & 3 deletions calyx/src/ir/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ impl IRPrinter {
for cell in &comp.cells {
Self::write_cell(&cell.borrow(), 4, f)?;
}
// TODO(rachit): Trailing spaces added for test faithfulness
writeln!(f, " }}")?;

// Add the wires
Expand All @@ -62,7 +61,6 @@ impl IRPrinter {
Self::write_assignment(assign, 4, f)?;
writeln!(f)?;
}
// TODO(rachit): Trailing spaces added for test faithfulness
writeln!(f, " }}\n")?;

// Add the control program
Expand Down Expand Up @@ -105,7 +103,7 @@ impl IRPrinter {
ir::CellType::Constant { .. } => Ok(()),
ir::CellType::Component { name } => {
write!(f, "{}", " ".repeat(indent_level))?;
write!(f, "{} = {}", cell.name.id, name)
writeln!(f, "{} = {};", cell.name.id, name)
}
_ => unimplemented!(),
}
Expand Down Expand Up @@ -169,6 +167,41 @@ impl IRPrinter {
ir::Control::Enable(ir::Enable { group }) => {
writeln!(f, "{};", group.borrow().name.id)
}
ir::Control::Invoke(ir::Invoke {
comp,
inputs,
outputs,
}) => {
write!(f, "invoke {}(", comp.borrow().name)?;
for (arg, port) in inputs {
write!(
f,
"\n{}{} = {},",
" ".repeat(indent_level + 2),
arg,
Self::get_port_access(&port.borrow())
)?;
}
if inputs.is_empty() {
write!(f, ")(")?;
} else {
write!(f, "\n{})(", " ".repeat(indent_level))?;
}
for (arg, port) in outputs {
write!(
f,
"\n{}{} = {},",
" ".repeat(indent_level + 2),
arg,
Self::get_port_access(&port.borrow())
)?;
}
if outputs.is_empty() {
writeln!(f, ");")
} else {
writeln!(f, "\n{});", " ".repeat(indent_level))
}
}
ir::Control::Seq(ir::Seq { stmts }) => {
writeln!(f, "seq {{")?;
for stmt in stmts {
Expand Down
35 changes: 10 additions & 25 deletions calyx/src/ir/traversal/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ pub trait Visitor {
Ok(Action::Continue)
}

/// Excecuted before visiting the children of a `ir::Enable` node.
fn start_enable(
/// Excecuted at an `ir::Enable` node. This is leaf node with no children.
fn enable(
&mut self,
_s: &mut ir::Enable,
_comp: &mut Component,
Expand All @@ -185,28 +185,18 @@ pub trait Visitor {
Ok(Action::Continue)
}

/// Excecuted after visiting the children of a `ir::Enable` node.
fn finish_enable(
/// Excecuted at an `ir::Invoke` node. This is leaf node with no children.
fn invoke(
&mut self,
_s: &mut ir::Enable,
_s: &mut ir::Invoke,
_comp: &mut Component,
_sigs: &LibrarySignatures,
) -> VisResult {
Ok(Action::Continue)
}

/// Excecuted before visiting the children of a `ir::Empty` node.
fn start_empty(
&mut self,
_s: &mut ir::Empty,
_comp: &mut Component,
_sigs: &LibrarySignatures,
) -> VisResult {
Ok(Action::Continue)
}

/// Excecuted after visiting the children of a `ir::Empty` node.
fn finish_empty(
/// Excecuted at an `ir::Empty` node. This is leaf node with no children.
fn empty(
&mut self,
_s: &mut ir::Empty,
_comp: &mut Component,
Expand Down Expand Up @@ -263,14 +253,9 @@ impl Visitable for Control {
.and_then(|| ctrl.body.visit(visitor, component, sigs))?
.pop()
.and_then(|| visitor.finish_while(ctrl, component, sigs))?,
Control::Enable(ctrl) => visitor
.start_enable(ctrl, component, sigs)?
.pop()
.and_then(|| visitor.finish_enable(ctrl, component, sigs))?,
Control::Empty(ctrl) => visitor
.start_empty(ctrl, component, sigs)?
.pop()
.and_then(|| visitor.finish_empty(ctrl, component, sigs))?,
Control::Enable(ctrl) => visitor.enable(ctrl, component, sigs)?,
Control::Empty(ctrl) => visitor.empty(ctrl, component, sigs)?,
Control::Invoke(data) => visitor.invoke(data, component, sigs)?,
}
.apply_change(self)
}
Expand Down
2 changes: 1 addition & 1 deletion calyx/src/passes/compile_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl Named for CompileEmpty {
}

impl Visitor for CompileEmpty {
fn finish_empty(
fn empty(
&mut self,
_s: &mut ir::Empty,
comp: &mut Component,
Expand Down
Loading