diff --git a/calyx-backend/src/backend_opt.rs b/calyx-backend/src/backend_opt.rs index 166189fb1a..f11c73374f 100644 --- a/calyx-backend/src/backend_opt.rs +++ b/calyx-backend/src/backend_opt.rs @@ -14,6 +14,7 @@ pub enum BackendOpt { Sexp, Yxi, Firrtl, + PrimitiveUses, None, } @@ -30,6 +31,7 @@ fn backends() -> Vec<(&'static str, BackendOpt)> { ("sexp", BackendOpt::Sexp), ("yxi", BackendOpt::Yxi), ("firrtl", BackendOpt::Firrtl), + ("primitive-uses", BackendOpt::PrimitiveUses), ("none", BackendOpt::None), ] } @@ -74,6 +76,7 @@ impl ToString for BackendOpt { Self::Yxi => "yxi", Self::Calyx => "calyx", Self::Firrtl => "firrtl", + Self::PrimitiveUses => "primitive-uses", Self::None => "none", } .to_string() diff --git a/calyx-backend/src/lib.rs b/calyx-backend/src/lib.rs index 2701920dbd..e2b9bf2f51 100644 --- a/calyx-backend/src/lib.rs +++ b/calyx-backend/src/lib.rs @@ -1,12 +1,14 @@ //! Backends for the Calyx compiler. mod backend_opt; mod firrtl; +mod primitive_uses; mod traits; mod verilog; mod yxi; pub use backend_opt::BackendOpt; pub use firrtl::FirrtlBackend; +pub use primitive_uses::PrimitiveUsesBackend; pub use traits::Backend; pub use verilog::VerilogBackend; pub use yxi::YxiBackend; diff --git a/calyx-backend/src/primitive_uses.rs b/calyx-backend/src/primitive_uses.rs new file mode 100644 index 0000000000..8867e2f0d9 --- /dev/null +++ b/calyx-backend/src/primitive_uses.rs @@ -0,0 +1,110 @@ +//! Primitive instantiations backend for the Calyx compiler. +//! +//! Transforms an [`ir::Context`](crate::ir::Context) into a JSON file that +//! records the unique primitive instantiations in a program. +//! Usage: -b primitive-inst [-o ] +//! Adapted from resources.rs. + +use std::{collections::HashSet, io}; + +use crate::traits::Backend; +use calyx_ir as ir; +use calyx_utils::{CalyxResult, OutputFile}; +use serde::{Deserialize, Serialize}; + +#[derive(Default)] +pub struct PrimitiveUsesBackend; + +impl Backend for PrimitiveUsesBackend { + fn name(&self) -> &'static str { + "primitive_uses" + } + + /// OK to run this analysis on any Calyx program + fn validate(_ctx: &ir::Context) -> CalyxResult<()> { + Ok(()) + } + + /// Don't need to take care of this for this pass + fn link_externs( + _ctx: &ir::Context, + _file: &mut OutputFile, + ) -> CalyxResult<()> { + Ok(()) + } + + fn emit(ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> { + let main_comp = ctx.entrypoint(); + + let mut primitive_set: HashSet = HashSet::new(); + + gen_primitive_set(ctx, main_comp, &mut primitive_set); + + write_json(primitive_set.clone(), file)?; + + Ok(()) + } +} + +#[derive(PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] +struct PrimitiveUse { + name: String, + params: Vec, +} + +#[derive(PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] +struct PrimitiveParam { + param_name: String, + param_value: u64, +} + +/// Accumulates a set with each primitive with a given set of parameters +/// in the program with entrypoint `main_comp`. +fn gen_primitive_set( + ctx: &ir::Context, + main_comp: &ir::Component, + primitive_set: &mut HashSet, +) { + for cell in main_comp.cells.iter() { + let cell_ref = cell.borrow(); + match &cell_ref.prototype { + ir::CellType::Primitive { + name, + param_binding, + .. + } => { + let curr_params = param_binding + .iter() + .map(|(param_name, param_size)| PrimitiveParam { + param_name: param_name.to_string(), + param_value: *param_size, + }) + .collect(); + let curr_primitive = PrimitiveUse { + name: name.to_string(), + params: curr_params, + }; + (*primitive_set).insert(curr_primitive); + } + ir::CellType::Component { name } => { + let component = ctx + .components + .iter() + .find(|comp| comp.name == name) + .unwrap(); + gen_primitive_set(ctx, component, primitive_set); + } + _ => (), + } + } +} + +/// Write the collected set of primitive instantiations to a JSON file. +fn write_json( + primitive_set: HashSet, + file: &mut OutputFile, +) -> Result<(), io::Error> { + let created_vec: Vec = primitive_set.into_iter().collect(); + serde_json::to_writer_pretty(file.get_write(), &created_vec)?; + Ok(()) +} diff --git a/src/cmdline.rs b/src/cmdline.rs index 61cb1fb4fd..93d9f5b012 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -4,8 +4,8 @@ use argh::FromArgs; use calyx_backend::SexpBackend; use calyx_backend::{ xilinx::{XilinxInterfaceBackend, XilinxXmlBackend}, - Backend, BackendOpt, FirrtlBackend, MlirBackend, ResourcesBackend, - VerilogBackend, YxiBackend, + Backend, BackendOpt, FirrtlBackend, MlirBackend, PrimitiveUsesBackend, + ResourcesBackend, VerilogBackend, YxiBackend, }; use calyx_ir as ir; use calyx_utils::{CalyxResult, Error, OutputFile}; @@ -170,6 +170,10 @@ impl Opts { let backend = FirrtlBackend; backend.run(context, self.output) } + BackendOpt::PrimitiveUses => { + let backend = PrimitiveUsesBackend; + backend.run(context, self.output) + } BackendOpt::Calyx => { ir::Printer::write_context( &context,