pulsar_backend/calyx/
builder.rs

1// Copyright (C) 2024 Ethan Uppal. All rights reserved.
2
3use calyx_ir::RRC;
4use pulsar_utils::environment::Environment;
5use std::{
6    collections::HashMap, fmt::Display, marker::PhantomData, path::PathBuf
7};
8
9pub mod macros;
10
11/// Describes the semantics of a cell.
12#[derive(Clone, PartialEq, Eq)]
13pub enum CalyxCellKind {
14    /// `Register { size }` is a `"std_reg"` of bit-width `size`.
15    Register { size: usize },
16
17    /// `CombMemoryD1 { size, length, address_bits }` is a `"comb_mem_d1"` with
18    /// cell bit-width `size`, cell count `length`, and address bit-width
19    /// `address_bits`.
20    CombMemoryD1 {
21        size: usize,
22        length: usize,
23        address_bits: usize
24    },
25
26    /// A calyx primitive other than a register, memory, or constant.
27    Primitive { name: String, params: Vec<u64> },
28
29    /// `GoDoneComponent { component }` is a cell for a
30    /// component named `component`.
31    GoDoneComponent { component: String },
32
33    /// `Constant { width }` is a `"std_const"` with bit-width `width`.
34    Constant { width: usize }
35}
36
37impl CalyxCellKind {
38    /// Whether the cell represents a primitive, in which case
39    /// [`CalyxCellKind::to_string`] retrieves the name of the primitive in the
40    /// standard library.
41    pub fn is_primitive(&self) -> bool {
42        matches!(
43            self,
44            Self::Register { size: _ }
45                | Self::CombMemoryD1 {
46                    size: _,
47                    length: _,
48                    address_bits: _
49                }
50                | Self::Primitive { name: _, params: _ }
51        )
52    }
53
54    /// Whether the cell is a memory.
55    pub fn is_memory(&self) -> bool {
56        matches!(
57            self,
58            Self::CombMemoryD1 {
59                size: _,
60                length: _,
61                address_bits: _
62            }
63        )
64    }
65
66    /// The parameters associated with the primitive.
67    ///
68    /// Requires: `self.is_primitive()`.
69    pub(crate) fn primitive_params(&self) -> Vec<u64> {
70        match &self {
71            CalyxCellKind::Register { size } => vec![*size as u64],
72            CalyxCellKind::CombMemoryD1 {
73                size,
74                length,
75                address_bits
76            } => vec![*size as u64, *length as u64, *address_bits as u64],
77            CalyxCellKind::Primitive { name: _, params } => params.clone(),
78            CalyxCellKind::GoDoneComponent { component: _ } => {
79                panic!("Cell not a primitive")
80            }
81            CalyxCellKind::Constant { width } => vec![*width as u64]
82        }
83    }
84}
85
86impl Display for CalyxCellKind {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        match &self {
89            Self::Register { size: _ } => "std_reg",
90            Self::CombMemoryD1 {
91                size: _,
92                length: _,
93                address_bits: _
94            } => "comb_mem_d1",
95            Self::Primitive { name, params: _ } => name,
96            Self::GoDoneComponent { component } => component,
97            Self::Constant { width: _ } => "std_const"
98        }
99        .fmt(f)
100    }
101}
102
103// might remove these later
104pub type CalyxPort = RRC<calyx_ir::Port>;
105
106/// A wrapper around [`calyx_ir::Cell`]s containing additional semantic
107/// information (see [`CalyxCellKind`]).
108#[derive(Clone)]
109pub struct CalyxCell {
110    pub kind: CalyxCellKind,
111    pub value: RRC<calyx_ir::Cell>
112}
113
114impl CalyxCell {
115    /// See [`calyx_ir::Cell::get`].
116    pub fn get(&self, port: &str) -> CalyxPort {
117        self.value.borrow().get(port)
118    }
119}
120
121/// An abstraction over a calyx group for adding assignments.
122pub trait CalyxAssignmentContainer {
123    type AssignmentType;
124
125    /// Inserts a single assignment.
126    fn add(&self, assignment: calyx_ir::Assignment<Self::AssignmentType>);
127
128    /// Inserts a set of assignment.
129    fn extend<
130        I: IntoIterator<Item = calyx_ir::Assignment<Self::AssignmentType>>
131    >(
132        &self, assignments: I
133    ) {
134        assignments.into_iter().for_each(|a| self.add(a));
135    }
136}
137
138/// See [`calyx_ir::Group`].
139pub struct CalyxGroup {
140    pub value: RRC<calyx_ir::Group>
141}
142
143impl CalyxAssignmentContainer for CalyxGroup {
144    type AssignmentType = calyx_ir::Nothing;
145
146    fn add(&self, assignment: calyx_ir::Assignment<Self::AssignmentType>) {
147        self.value.borrow_mut().assignments.push(assignment);
148    }
149}
150
151/// See [`calyx_ir::CombGroup`].
152pub struct CalyxCombGroup {
153    pub value: RRC<calyx_ir::CombGroup>
154}
155
156impl CalyxAssignmentContainer for CalyxCombGroup {
157    type AssignmentType = calyx_ir::Nothing;
158
159    fn add(&self, assignment: calyx_ir::Assignment<Self::AssignmentType>) {
160        self.value.borrow_mut().assignments.push(assignment);
161    }
162}
163
164/// A flag for [`CalyxControl`].
165pub trait CalyxControlType {}
166
167/// Represents sequential [`CalyxControl`].
168pub struct Sequential;
169impl CalyxControlType for Sequential {}
170
171/// Represents parallel [`CalyxControl`].
172pub struct Parallel;
173impl CalyxControlType for Parallel {}
174
175/// A wrapper around [`calyx_ir::Control`] for scoped building.
176pub struct CalyxControl<T: CalyxControlType> {
177    children: Vec<calyx_ir::Control>,
178    phantom: PhantomData<T>
179}
180
181impl<T: CalyxControlType> CalyxControl<T> {
182    /// Opens a `seq` context where `f` is called. For instance,
183    /// ```
184    /// fn add_seq(control: &mut CalyxControl, my_group: &CalyxGroup) {
185    ///     control.seq(|s| {
186    ///         s.enable(my_group);
187    ///     });
188    /// }
189    /// ```
190    /// produces the following calyx:
191    /// ```
192    /// ...
193    /// seq {
194    ///     my_group;
195    /// }
196    /// ...
197    /// ```
198    pub fn seq<F>(&mut self, f: F)
199    where
200        F: FnOnce(&mut CalyxControl<Sequential>) {
201        let mut child = CalyxControl::<Sequential>::default();
202        f(&mut child);
203        self.children.push(calyx_ir::Control::seq(child.children));
204    }
205
206    /// Opens a `par` context. See [`CalyxControl::seq`] for details.
207    pub fn par<F>(&mut self, f: F)
208    where
209        F: FnOnce(&mut CalyxControl<Parallel>) {
210        let mut child = CalyxControl::<Parallel>::default();
211        f(&mut child);
212        self.children.push(calyx_ir::Control::par(child.children));
213    }
214
215    /// Opens an `if` context. See [`CalyxControl::seq`] for details.
216    pub fn if_<F>(
217        &mut self, port: CalyxPort, cond: Option<CalyxCombGroup>, true_f: F,
218        false_f: F
219    ) where
220        F: FnOnce(&mut CalyxControl<Sequential>) {
221        let mut true_branch = CalyxControl::<Sequential>::default();
222        let mut false_branch = CalyxControl::<Sequential>::default();
223        true_f(&mut true_branch);
224        false_f(&mut false_branch);
225        self.children.push(calyx_ir::Control::if_(
226            port,
227            cond.map(|cond| cond.value),
228            Box::new(true_branch.to_control()),
229            Box::new(false_branch.to_control())
230        ));
231    }
232
233    /// Opens a `while` context. See [`CalyxControl::seq`] for details.
234    pub fn while_<F>(
235        &mut self, port: CalyxPort, cond: Option<CalyxCombGroup>, f: F
236    ) where
237        F: FnOnce(&mut CalyxControl<Sequential>) {
238        let mut body = CalyxControl::<Sequential>::default();
239        f(&mut body);
240        self.children.push(calyx_ir::Control::while_(
241            port,
242            cond.map(|cond| cond.value),
243            Box::new(body.to_control())
244        ));
245    }
246
247    // TODO: more control
248}
249
250impl<T: CalyxControlType> Default for CalyxControl<T> {
251    fn default() -> Self {
252        Self {
253            children: vec![],
254            phantom: PhantomData
255        }
256    }
257}
258
259impl CalyxControl<Sequential> {
260    /// Enables `group` to run in sequence.
261    pub fn enable_next(&mut self, group: &CalyxGroup) {
262        self.children
263            .push(calyx_ir::Control::enable(group.value.clone()));
264    }
265
266    /// Unwraps the control builder.
267    pub fn to_control(self) -> calyx_ir::Control {
268        if self.children.is_empty() {
269            calyx_ir::Control::empty()
270        } else {
271            calyx_ir::Control::seq(self.children)
272        }
273    }
274}
275
276impl CalyxControl<Parallel> {
277    /// Enables `group` to run in parallel.
278    pub fn enable(&mut self, group: &CalyxGroup) {
279        self.children
280            .push(calyx_ir::Control::enable(group.value.clone()));
281    }
282
283    /// Unwraps the control builder.
284    pub fn to_control(self) -> calyx_ir::Control {
285        if self.children.is_empty() {
286            calyx_ir::Control::empty()
287        } else {
288            calyx_ir::Control::par(self.children)
289        }
290    }
291}
292
293/// A wrapper for a calyx component that can only be created through
294/// [`CalyxBuilder::build_component`], where it must live no longer than the
295/// builder that created it.
296///
297/// The wrapper maintains cell and control manipulation. Cells can be created
298/// through methods such as [`CalyxComponent::named_reg`] or
299/// [`CalyxComponent::component_cell`]. It also contains unique per-component
300/// data initialized via `ComponentData::default` which can be accessed through
301/// appropriate getters.
302pub struct CalyxComponent<'a, ComponentData: Default> {
303    ext_sigs: &'a HashMap<String, Vec<calyx_ir::PortDef<u64>>>,
304    lib_sig: &'a calyx_ir::LibrarySignatures,
305    env: Environment<String, CalyxCell>,
306    component: calyx_ir::Component,
307    cell_name_prefix: String,
308    unique_counter: usize,
309    user_data: ComponentData,
310    control_builder: CalyxControl<Sequential>
311}
312
313impl<'a, ComponentData: Default> CalyxComponent<'a, ComponentData> {
314    fn new(
315        component: calyx_ir::Component, cell_name_prefix: String,
316        ext_sigs: &'a HashMap<String, Vec<calyx_ir::PortDef<u64>>>,
317        lib_sig: &'a calyx_ir::LibrarySignatures
318    ) -> Self {
319        Self {
320            ext_sigs,
321            lib_sig,
322            env: Environment::new(),
323            component,
324            cell_name_prefix,
325            unique_counter: 0,
326            user_data: ComponentData::default(),
327            control_builder: CalyxControl::default()
328        }
329    }
330
331    /// The user data associated with the component.
332    pub fn user_data_ref(&self) -> &ComponentData {
333        &self.user_data
334    }
335
336    /// See [`CalyxComponent::user_data_ref`].
337    pub fn user_data_mut(&mut self) -> &mut ComponentData {
338        &mut self.user_data
339    }
340
341    /// The input/output signature of this component as a cell.
342    pub fn signature(&mut self) -> CalyxCell {
343        CalyxCell {
344            kind: CalyxCellKind::GoDoneComponent {
345                component: self.component.name.to_string()
346            },
347            value: self.component.signature.clone()
348        }
349    }
350
351    /// The control of this component.
352    pub fn control(&mut self) -> &mut CalyxControl<Sequential> {
353        &mut self.control_builder
354    }
355
356    /// Enables direct access to a [`calyx_ir::Builder`] for this component.
357    pub fn with_calyx_builder<F, T>(&mut self, f: F) -> T
358    where
359        F: FnOnce(&mut calyx_ir::Builder) -> T {
360        // Creating a calyx_ir::Builder is very cheap (for now). If I can figure
361        // out a better way, e.g., storing the builder in the struct, I will
362        // switch to that, but I tried doing that for many hours to no avail.
363        let mut ir_builder =
364            calyx_ir::Builder::new(&mut self.component, self.lib_sig)
365                .not_generated();
366        f(&mut ir_builder)
367    }
368
369    /// A register cell bound to `name`.
370    ///
371    /// Requires: `name` has not been bound.
372    pub fn new_reg(&mut self, name: String, width: usize) -> CalyxCell {
373        let mut bind_name = self.cell_name_prefix.clone();
374        bind_name.push_str(&name);
375        self.create_cell(bind_name, CalyxCellKind::Register { size: width })
376    }
377
378    /// A memory cell bound to `name`.
379    ///
380    /// Requires: `name` has not been bound.
381    pub fn named_mem(
382        &mut self, name: String, cell_size: usize, length: usize,
383        address_bits: usize
384    ) -> CalyxCell {
385        let mut bind_name = self.cell_name_prefix.clone();
386        bind_name.push_str(&name);
387        self.create_cell(
388            bind_name,
389            CalyxCellKind::CombMemoryD1 {
390                size: cell_size,
391                length,
392                address_bits
393            }
394        )
395    }
396
397    /// Creates a cell named `name` for a primitive `prim` with parameters
398    /// `params`. Before using this function, see if
399    /// [`CalyxComponent::named_reg`] or [`CalyxComponent::named_mem`] are more
400    /// appropriate.
401    ///
402    /// Requires: `name` has not been bound.
403    pub fn new_prim(
404        &mut self, name: &str, prim: &str, params: Vec<u64>
405    ) -> CalyxCell {
406        self.create_cell(
407            name.into(),
408            CalyxCellKind::Primitive {
409                name: prim.into(),
410                params
411            }
412        )
413    }
414
415    /// A cell for a component `component` whose name is guaranteed to begin
416    /// with `prefix`. If `instantiate_new`, then a unique cell will be created.
417    /// Both the cell and the actual cell name are returned.
418    pub fn component_cell(
419        &mut self, prefix: String, component: String, instantiate_new: bool
420    ) -> (String, CalyxCell) {
421        let cell_name = if instantiate_new {
422            format!("{}{}", prefix, self.get_unique_number())
423        } else {
424            prefix
425        };
426        let cell = CalyxCell {
427            kind: CalyxCellKind::GoDoneComponent {
428                component: component.clone()
429            },
430            value: self._create_component_cell(cell_name.clone(), component)
431        };
432        (cell_name, cell)
433    }
434
435    /// An unnamed cell of a given `kind`.
436    pub fn new_unnamed_cell(&mut self, kind: CalyxCellKind) -> CalyxCell {
437        let cell_name = format!("t{}", self.get_unique_number());
438        self.create_cell(cell_name, kind)
439    }
440
441    /// A constant cell, that is, a primitive `"std_const"`.
442    pub fn constant(&mut self, value: i64, width: usize) -> CalyxCell {
443        CalyxCell {
444            kind: CalyxCellKind::Constant { width },
445            value: self.with_calyx_builder(|b| {
446                b.add_constant(value as u64, width as u64)
447            })
448        }
449    }
450
451    /// Equivlane to `constant(1, 1)`.
452    pub fn signal_out(&mut self) -> CalyxCell {
453        self.constant(1, 1)
454    }
455
456    /// Adds `name` as a named alias to refer to `cell`.
457    ///
458    /// Requires: `name` has not been previously bound.
459    pub fn alias_cell(&mut self, name: String, cell: CalyxCell) {
460        assert!(self
461            .env
462            .bind(format!("{}{}", self.cell_name_prefix, name), cell)
463            .is_none());
464    }
465
466    /// Looks up a named cell previously bound to `name`.
467    ///
468    /// Requires: `name` has been bound.
469    pub fn find(&mut self, name: String) -> CalyxCell {
470        self.env
471            .find(format!("{}{}", self.cell_name_prefix, name))
472            .expect("Did not find cell in component environment")
473            .clone()
474    }
475
476    /// See [`Environment::push`].
477    pub fn begin_scope(&mut self) {
478        self.env.push();
479    }
480
481    /// See [`Environment::pop`].
482    pub fn end_scope(&mut self) -> bool {
483        self.env.pop()
484    }
485
486    /// Creates a new group guaranteed to start with `prefix`.
487    pub fn add_group(&mut self, prefix: &str) -> CalyxGroup {
488        CalyxGroup {
489            value: self.with_calyx_builder(|b| b.add_group(prefix))
490        }
491    }
492
493    /// Creates a new combinational group guaranteed to start with `prefix`.
494    pub fn add_comb_group(&mut self, prefix: &str) -> CalyxCombGroup {
495        CalyxCombGroup {
496            value: self.with_calyx_builder(|b| b.add_comb_group(prefix))
497        }
498    }
499
500    /// Yields a [`calyx_ir::Component`].
501    pub fn finalize(self) -> calyx_ir::Component {
502        *self.component.control.borrow_mut() =
503            self.control_builder.to_control();
504        self.component
505    }
506
507    /// Creates a cell of type `kind` bound to `key`.
508    ///
509    /// Requires: `key` has not been bound.
510    fn create_cell(&mut self, key: String, kind: CalyxCellKind) -> CalyxCell {
511        let calyx_cell = if kind.is_primitive() {
512            self._create_primitive(
513                key.clone(),
514                kind.to_string(),
515                kind.primitive_params()
516            )
517        } else if let CalyxCellKind::GoDoneComponent { component } = &kind {
518            self._create_component_cell(key.clone(), component.clone())
519        } else {
520            panic!("unknown cell kind")
521        };
522        let cell = CalyxCell {
523            kind,
524            value: calyx_cell
525        };
526        self.env.bind(key, cell.clone());
527        cell
528    }
529
530    /// A number guaranteed to be unique across all calls to this function for a
531    /// specific component builder such as `self`.
532    fn get_unique_number(&mut self) -> usize {
533        let result = self.unique_counter;
534        self.unique_counter += 1;
535        result
536    }
537
538    /// Creates a [`calyx_ir::Cell`] for a `primitive`.
539    fn _create_primitive(
540        &mut self, name: String, primitive: String, params: Vec<u64>
541    ) -> RRC<calyx_ir::Cell> {
542        self.with_calyx_builder(|b| b.add_primitive(name, primitive, &params))
543    }
544
545    /// Creates a [`calyx_ir::Cell`] for a `component`.
546    fn _create_component_cell(
547        &mut self, name: String, component: String
548    ) -> RRC<calyx_ir::Cell> {
549        let mut port_defs = self.ext_sigs.get(&component).unwrap().clone();
550
551        let mut go_attr = calyx_ir::Attributes::default();
552        go_attr.insert(calyx_ir::Attribute::Num(calyx_ir::NumAttr::Go), 1);
553        port_defs.push(calyx_ir::PortDef::new(
554            "go",
555            1,
556            calyx_ir::Direction::Input,
557            go_attr
558        ));
559
560        let mut done_attr = calyx_ir::Attributes::default();
561        done_attr.insert(calyx_ir::Attribute::Num(calyx_ir::NumAttr::Done), 1);
562        port_defs.push(calyx_ir::PortDef::new(
563            "done",
564            1,
565            calyx_ir::Direction::Output,
566            done_attr
567        ));
568
569        let mut clk_attr = calyx_ir::Attributes::default();
570        clk_attr.insert(calyx_ir::Attribute::Bool(calyx_ir::BoolAttr::Clk), 1);
571        port_defs.push(calyx_ir::PortDef::new(
572            "clk",
573            1,
574            calyx_ir::Direction::Input,
575            clk_attr
576        ));
577
578        let mut reset_attr = calyx_ir::Attributes::default();
579        reset_attr
580            .insert(calyx_ir::Attribute::Bool(calyx_ir::BoolAttr::Reset), 1);
581        port_defs.push(calyx_ir::PortDef::new(
582            "reset",
583            1,
584            calyx_ir::Direction::Input,
585            reset_attr
586        ));
587
588        let cell = self._cell_from_signature(
589            name.clone().into(),
590            calyx_ir::CellType::Component {
591                name: component.clone().into()
592            },
593            port_defs
594        );
595        self.component.cells.add(cell.clone());
596        cell
597    }
598
599    /// For some reason, this is private: https://github.com/calyxir/calyx/blob/main/calyx-ir/src/builder.rs#L361
600    fn _cell_from_signature(
601        &self, name: calyx_ir::Id, typ: calyx_ir::CellType,
602        ports: Vec<calyx_ir::PortDef<u64>>
603    ) -> RRC<calyx_ir::Cell> {
604        let cell = calyx_ir::rrc(calyx_ir::Cell::new(name, typ));
605        ports.into_iter().for_each(|pd| {
606            let port = calyx_ir::rrc(calyx_ir::Port {
607                name: pd.name(),
608                width: pd.width,
609                direction: pd.direction,
610                parent: calyx_ir::PortParent::Cell(calyx_ir::WRC::from(&cell)),
611                attributes: pd.attributes
612            });
613            cell.borrow_mut().ports.push(port);
614        });
615        cell
616    }
617}
618
619/// A builder for calyx IR optimized for generation from a higher-level AST or
620/// IR.
621pub struct CalyxBuilder {
622    /// The calyx program being built.
623    ctx: calyx_ir::Context,
624
625    /// Component signatures.
626    sigs: HashMap<String, Vec<calyx_ir::PortDef<u64>>>,
627
628    /// Prefix for named cells to avoid collision with unnamed cells.
629    cell_name_prefix: String
630}
631
632impl CalyxBuilder {
633    /// Constructs a new calyx builder. See the documentation at
634    /// [`CalyxBuilder`] for general usage information.
635    ///
636    /// - `prelude` is an optional calyx file that will be parsed and inlined in
637    ///   additional to the standard library, which is useful for additional
638    ///   component definitions or imports.
639    ///
640    /// - `lib_path` should be the root of the calyx installation location,
641    ///   e.g., the folder generated from cloning the repository from GitHub.
642    ///
643    /// - `entrypoint` is the name of the entry component in the program. If
644    ///   `None` is passed, it will default to `"main"`. You can use
645    ///   [`CalyxBuilder::set_entrypoint`] to update it.
646    ///
647    /// - `cell_name_prefix` is the non-empty prefix applied to all named cells
648    ///   (e.g., those requested via [`CalyxComponent::named_reg`]) to guarantee
649    ///   no collisions with unnamed cells (e.g., those requested via
650    ///   [`CalyxComponent::unnamed_cell`]). It must be non-empty.
651    pub fn new(
652        prelude: Option<PathBuf>, lib_path: PathBuf,
653        entrypoint: Option<String>, cell_name_prefix: String
654    ) -> Self {
655        assert!(!cell_name_prefix.is_empty());
656
657        // A workspace is created for the sole purpose of obtaining standard
658        // library definitions -- it is immediately turned into a context.
659        let ws =
660            calyx_frontend::Workspace::construct(&prelude, &lib_path).unwrap();
661        let ctx = calyx_ir::Context {
662            components: vec![],
663            lib: ws.lib,
664            entrypoint: entrypoint.unwrap_or("main".into()).into(),
665            bc: calyx_ir::BackendConf::default(),
666            extra_opts: vec![],
667            metadata: None
668        };
669
670        Self {
671            ctx,
672            sigs: HashMap::new(),
673            cell_name_prefix
674        }
675    }
676
677    /// <div class="warning">This builder cannot be used.</div>
678    pub fn dummy() -> Self {
679        Self {
680            ctx: calyx_ir::Context {
681                components: vec![],
682                lib: calyx_ir::LibrarySignatures::default(),
683                entrypoint: "".into(),
684                bc: calyx_ir::BackendConf::default(),
685                extra_opts: vec![],
686                metadata: None
687            },
688            sigs: HashMap::new(),
689            cell_name_prefix: "".into()
690        }
691    }
692
693    /// Binds a component (named `name`)'s signature to a list of `ports` so it
694    /// can be constructed or instantiated by another component.
695    pub fn register_component(
696        &mut self, name: String, ports: Vec<calyx_ir::PortDef<u64>>
697    ) {
698        self.sigs.insert(name, ports);
699    }
700
701    /// Returns a component wrapper for a registered component. Once you are
702    /// finished with the component builder, call [`finish_component!`].
703    ///
704    /// Requires: [`CalyxBuilder::register_component`] has been issued for
705    /// `name`.
706    pub fn start_component<ComponentData: Default>(
707        &self, name: String
708    ) -> CalyxComponent<ComponentData> {
709        CalyxComponent::new(
710            calyx_ir::Component::new(
711                name.clone(),
712                self.sigs
713                    .get(&name)
714                    .expect("Use `register_component` first")
715                    .clone(),
716                true,
717                false,
718                None
719            ),
720            self.cell_name_prefix.clone(),
721            &self.sigs,
722            &self.ctx.lib
723        )
724    }
725
726    /// Please use [`finish_component!`] instead.
727    pub fn _finish_component(&mut self, component: calyx_ir::Component) {
728        self.ctx.components.push(component);
729    }
730
731    /// Updates the name of the program entrypoint.
732    ///
733    /// Requires: [`CalyxBuilder::register_component`] has been issued for
734    /// `entrypoint`.
735    pub fn set_entrypoint(&mut self, entrypoint: String) {
736        assert!(self.sigs.contains_key(&entrypoint));
737        self.ctx.entrypoint = entrypoint.into();
738    }
739
740    /// Yields a [`calyx_ir::Context`].
741    ///
742    /// Requires: the entrypoint provided at [`CalyxBuilder::new`] is the name
743    /// of a component added.
744    pub fn finalize(self) -> calyx_ir::Context {
745        self.ctx
746    }
747}
748
749/// `finish_component!(builder, component)` marks a `component` as finalized in
750/// `builder`.
751#[macro_export]
752macro_rules! finish_component {
753    ($builder:expr, $component:expr) => {
754        $builder._finish_component($component.finalize())
755    };
756}