midenc_compile/stages/
codegen.rs

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