calyx_backend/
primitive_uses.rs

1//! Primitive instantiations backend for the Calyx compiler.
2//!
3//! Transforms an [`ir::Context`](crate::ir::Context) into a JSON file that
4//! records the unique primitive instantiations in a program.
5//! Usage: -b primitive-inst [-o <OUTPUT_FILE>]
6//! Adapted from resources.rs.
7
8use std::{collections::HashSet, io};
9
10use crate::traits::Backend;
11use calyx_ir as ir;
12use calyx_utils::{CalyxResult, OutputFile};
13use serde::{Deserialize, Serialize};
14
15#[derive(Default)]
16pub struct PrimitiveUsesBackend;
17
18impl Backend for PrimitiveUsesBackend {
19    fn name(&self) -> &'static str {
20        "primitive_uses"
21    }
22
23    /// OK to run this analysis on any Calyx program
24    fn validate(_ctx: &ir::Context) -> CalyxResult<()> {
25        Ok(())
26    }
27
28    /// Don't need to take care of this for this pass
29    fn link_externs(
30        _ctx: &ir::Context,
31        _file: &mut OutputFile,
32    ) -> CalyxResult<()> {
33        Ok(())
34    }
35
36    fn emit(ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> {
37        let main_comp = ctx.entrypoint();
38
39        let mut primitive_set: HashSet<PrimitiveUse> = HashSet::new();
40
41        gen_primitive_set(ctx, main_comp, &mut primitive_set);
42
43        write_json(primitive_set.clone(), file)?;
44
45        Ok(())
46    }
47}
48
49#[derive(PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
50struct PrimitiveUse {
51    name: String,
52    params: Vec<PrimitiveParam>,
53}
54
55#[derive(PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
56struct PrimitiveParam {
57    param_name: String,
58    param_value: u64,
59}
60
61/// Accumulates a set with each primitive with a given set of parameters
62/// in the program with entrypoint `main_comp`.
63fn gen_primitive_set(
64    ctx: &ir::Context,
65    main_comp: &ir::Component,
66    primitive_set: &mut HashSet<PrimitiveUse>,
67) {
68    for cell in main_comp.cells.iter() {
69        let cell_ref = cell.borrow();
70        match &cell_ref.prototype {
71            ir::CellType::Primitive {
72                name,
73                param_binding,
74                ..
75            } => {
76                let curr_params = param_binding
77                    .iter()
78                    .map(|(param_name, param_size)| PrimitiveParam {
79                        param_name: param_name.to_string(),
80                        param_value: *param_size,
81                    })
82                    .collect();
83                let curr_primitive = PrimitiveUse {
84                    name: name.to_string(),
85                    params: curr_params,
86                };
87                (*primitive_set).insert(curr_primitive);
88            }
89            ir::CellType::Component { name } => {
90                let component = ctx
91                    .components
92                    .iter()
93                    .find(|comp| comp.name == name)
94                    .unwrap();
95                gen_primitive_set(ctx, component, primitive_set);
96            }
97            _ => (),
98        }
99    }
100}
101
102/// Write the collected set of primitive instantiations to a JSON file.
103fn write_json(
104    primitive_set: HashSet<PrimitiveUse>,
105    file: &mut OutputFile,
106) -> Result<(), io::Error> {
107    let created_vec: Vec<PrimitiveUse> = primitive_set.into_iter().collect();
108    serde_json::to_writer_pretty(file.get_write(), &created_vec)?;
109    Ok(())
110}