midenc_compile/stages/
codegen.rs

1use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, vec::Vec};
2
3use miden_assembly::{Library, ast::Module};
4use miden_mast_package::Package;
5use midenc_codegen_masm::{
6    self as masm, MasmComponent, ToMasmComponent,
7    intrinsics::{
8        ADVICE_INTRINSICS_MODULE_NAME, CRYPTO_INTRINSICS_MODULE_NAME, I32_INTRINSICS_MODULE_NAME,
9        I64_INTRINSICS_MODULE_NAME, I128_INTRINSICS_MODULE_NAME, MEM_INTRINSICS_MODULE_NAME,
10    },
11};
12use midenc_hir::{interner::Symbol, pass::AnalysisManager};
13use midenc_session::OutputType;
14
15use super::*;
16
17pub struct CodegenOutput {
18    pub component: Arc<MasmComponent>,
19    pub link_libraries: Vec<Arc<Library>>,
20    pub link_packages: BTreeMap<Symbol, Arc<Package>>,
21    /// The serialized AccountComponentMetadata (name, description, storage layout, etc.)
22    pub account_component_metadata_bytes: Option<Vec<u8>>,
23}
24
25/// Perform code generation on the possibly-linked output of previous stages
26pub struct CodegenStage;
27
28impl Stage for CodegenStage {
29    type Input = LinkOutput;
30    type Output = CodegenOutput;
31
32    fn enabled(&self, context: &Context) -> bool {
33        context.session().should_codegen()
34    }
35
36    fn run(
37        &mut self,
38        linker_output: Self::Input,
39        context: Rc<Context>,
40    ) -> CompilerResult<Self::Output> {
41        let LinkOutput {
42            component,
43            masm: masm_modules,
44            mast: link_libraries,
45            packages: link_packages,
46            ..
47        } = linker_output;
48
49        log::debug!("lowering hir program to masm");
50
51        let analysis_manager = AnalysisManager::new(component.as_operation_ref(), None);
52        let mut masm_component =
53            component.borrow().to_masm_component(analysis_manager).map(Box::new)?;
54
55        let session = context.session();
56        if session.should_emit(OutputType::Masm) {
57            for module in masm_component.modules.iter() {
58                session.emit(OutputMode::Text, module).into_diagnostic()?;
59            }
60        }
61
62        // Ensure intrinsics modules are linked
63        for intrinsics_module in required_intrinsics_modules(session) {
64            log::debug!(
65                "adding required intrinsic module '{}' to masm program",
66                intrinsics_module.path()
67            );
68            masm_component.modules.push(intrinsics_module);
69        }
70
71        // Link in any MASM inputs provided to the compiler
72        for module in masm_modules {
73            log::debug!("adding external masm module '{}' to masm program", module.path());
74            masm_component.modules.push(module);
75        }
76
77        Ok(CodegenOutput {
78            component: Arc::from(masm_component),
79            link_libraries,
80            link_packages,
81            account_component_metadata_bytes: linker_output.account_component_metadata_bytes,
82        })
83    }
84}
85
86fn required_intrinsics_modules(session: &Session) -> impl IntoIterator<Item = Arc<Module>> {
87    [
88        masm::intrinsics::load(MEM_INTRINSICS_MODULE_NAME, &session.source_manager)
89            .map(Arc::from)
90            .expect("undefined intrinsics module"),
91        masm::intrinsics::load(I32_INTRINSICS_MODULE_NAME, &session.source_manager)
92            .map(Arc::from)
93            .expect("undefined intrinsics module"),
94        masm::intrinsics::load(I64_INTRINSICS_MODULE_NAME, &session.source_manager)
95            .map(Arc::from)
96            .expect("undefined intrinsics module"),
97        masm::intrinsics::load(I128_INTRINSICS_MODULE_NAME, &session.source_manager)
98            .map(Arc::from)
99            .expect("undefined intrinsics module"),
100        masm::intrinsics::load(CRYPTO_INTRINSICS_MODULE_NAME, &session.source_manager)
101            .map(Arc::from)
102            .expect("undefined intrinsics module"),
103        masm::intrinsics::load(ADVICE_INTRINSICS_MODULE_NAME, &session.source_manager)
104            .map(Arc::from)
105            .expect("undefined intrinsics module"),
106    ]
107}