midenc_codegen_masm/
convert.rs1use miden_assembly::LibraryPath;
2use midenc_hir::{
3 self as hir,
4 pass::{AnalysisManager, ConversionPass, ConversionResult},
5 ConversionPassRegistration, PassInfo,
6};
7use midenc_hir_analysis as analysis;
8use midenc_session::Session;
9
10use crate::{
11 codegen::{FunctionEmitter, OperandStack, Scheduler, TypedValue},
12 masm, MasmArtifact,
13};
14
15type ProgramGlobalVariableAnalysis = analysis::GlobalVariableAnalysis<hir::Program>;
16type ModuleGlobalVariableAnalysis = analysis::GlobalVariableAnalysis<hir::Module>;
17
18#[derive(ConversionPassRegistration)]
35pub struct ConvertHirToMasm<T>(core::marker::PhantomData<T>);
36impl<T> Default for ConvertHirToMasm<T> {
37 fn default() -> Self {
38 Self(core::marker::PhantomData)
39 }
40}
41impl<T> PassInfo for ConvertHirToMasm<T> {
42 const DESCRIPTION: &'static str = "Convert an HIR module or program to Miden Assembly\n\nSee \
43 the module documentation for ConvertHirToMasm for more \
44 details";
45 const FLAG: &'static str = "convert-hir-to-masm";
46 const SUMMARY: &'static str = "Convert an HIR module or program to Miden Assembly";
47}
48
49impl ConversionPass for ConvertHirToMasm<hir::Program> {
50 type From = Box<hir::Program>;
51 type To = MasmArtifact;
52
53 fn convert(
54 &mut self,
55 mut program: Self::From,
56 analyses: &mut AnalysisManager,
57 session: &Session,
58 ) -> ConversionResult<Self::To> {
59 let globals =
61 analyses.get_or_compute::<ProgramGlobalVariableAnalysis>(&program, session)?;
62
63 let mut artifact = if program.has_entrypoint() {
64 masm::Program::from_hir(&program, &globals)
65 .map(Box::new)
66 .map(MasmArtifact::Executable)?
67 } else {
68 MasmArtifact::Library(Box::new(masm::Library::from_hir(&program, &globals)))
69 };
70
71 let libraries = core::mem::take(program.libraries_mut());
73 for lib in libraries.into_values() {
74 artifact.link_library(lib);
75 }
76
77 let modules = program.modules_mut().take();
79
80 for module in modules.into_iter() {
81 let mut convert_to_masm = ConvertHirToMasm::<hir::Module>::default();
83 let masm_module = convert_to_masm.convert(module, analyses, session)?;
84
85 artifact.insert(masm_module);
87 }
88
89 Ok(artifact)
90 }
91}
92
93impl ConversionPass for ConvertHirToMasm<hir::Module> {
94 type From = Box<hir::Module>;
95 type To = Box<masm::Module>;
96
97 fn convert(
98 &mut self,
99 mut module: Self::From,
100 analyses: &mut AnalysisManager,
101 session: &Session,
102 ) -> ConversionResult<Self::To> {
103 use miden_assembly::ast::ModuleKind;
104 use midenc_hir::ProgramAnalysisKey;
105
106 let kind = if module.is_kernel() {
107 ModuleKind::Kernel
108 } else {
109 ModuleKind::Library
110 };
111 let name = LibraryPath::new(&module.name).unwrap_or_else(|err| {
112 panic!("invalid module name '{}': {}", module.name.as_str(), err)
113 });
114 let mut masm_module = Box::new(masm::Module::new(name, kind));
115
116 masm_module.imports = module.imports();
118
119 if !analyses.is_available::<ProgramGlobalVariableAnalysis>(&ProgramAnalysisKey) {
122 analyses.get_or_compute::<ModuleGlobalVariableAnalysis>(&module, session)?;
123 }
124
125 while let Some(function) = module.pop_front() {
130 let mut convert_to_masm = ConvertHirToMasm::<&hir::Function>::default();
131 let masm_function = convert_to_masm.convert(&function, analyses, session)?;
132 masm_module.push_back(Box::new(masm_function));
133 }
134
135 Ok(masm_module)
136 }
137}
138
139impl<'a> ConversionPass for ConvertHirToMasm<&'a hir::Function> {
140 type From = &'a hir::Function;
141 type To = masm::Function;
142
143 fn convert(
144 &mut self,
145 f: Self::From,
146 analyses: &mut AnalysisManager,
147 session: &Session,
148 ) -> ConversionResult<Self::To> {
149 use midenc_hir::ProgramAnalysisKey;
150
151 let mut f_prime = masm::Function::new(f.id, f.signature.clone());
152
153 {
155 let entry = f.dfg.entry_block();
156
157 let globals = analyses
158 .get::<ProgramGlobalVariableAnalysis>(&ProgramAnalysisKey)
159 .map(|result| result.layout().clone())
160 .unwrap_or_else(|| {
161 let result = analyses.expect::<ModuleGlobalVariableAnalysis>(
162 &f.id.module,
163 "expected global variable analysis to be available",
164 );
165 result.layout().clone()
166 });
167
168 let domtree = analyses.get_or_compute::<analysis::DominatorTree>(f, session)?;
169 let loops = analyses.get_or_compute::<analysis::LoopAnalysis>(f, session)?;
170 let liveness = analyses.get_or_compute::<analysis::LivenessAnalysis>(f, session)?;
171
172 let mut stack = OperandStack::default();
173 for arg in f.dfg.block_args(entry).iter().rev().copied() {
174 let ty = f.dfg.value_type(arg).clone();
175 stack.push(TypedValue { value: arg, ty });
176 }
177
178 let scheduler = Scheduler::new(f, &mut f_prime, &domtree, &loops, &liveness);
179 let schedule = scheduler.build();
180
181 let emitter =
187 FunctionEmitter::new(f, &mut f_prime, &domtree, &loops, &liveness, &globals);
188 emitter.emit(schedule, stack);
189 }
190
191 Ok(f_prime)
192 }
193}