use crate::{
assembly::Assembly,
code_gen::{optimize_module, symbols, CodeGenContext, CodeGenerationError},
ir::{file::gen_file_ir, file_group::gen_file_group_ir},
value::{IrTypeContext, IrValueContext},
ModuleGroupId, ModulePartition,
};
use inkwell::module::{Linkage, Module};
use rustc_hash::FxHashSet;
pub struct AssemblyBuilder<'db, 'ink, 'ctx, 't> {
code_gen: &'ctx CodeGenContext<'db, 'ink>,
module_group_partition: &'t ModulePartition,
module_group_id: ModuleGroupId,
assembly_module: Module<'ink>,
}
impl<'db, 'ink, 'ctx, 't> AssemblyBuilder<'db, 'ink, 'ctx, 't> {
pub(crate) fn new(
code_gen: &'ctx CodeGenContext<'db, 'ink>,
module_group_partition: &'t ModulePartition,
module_group_id: ModuleGroupId,
) -> Self {
let module_group = &module_group_partition[module_group_id];
let assembly_module = code_gen.create_module(&module_group.name);
Self {
code_gen,
module_group_partition,
module_group_id,
assembly_module,
}
}
pub fn build(self) -> Result<Assembly<'db, 'ink, 'ctx>, anyhow::Error> {
let module_group = &self.module_group_partition[self.module_group_id];
let group_ir = gen_file_group_ir(self.code_gen, module_group);
let file = gen_file_ir(self.code_gen, &group_ir, module_group);
self.assembly_module
.link_in_module(group_ir.llvm_module.clone())
.map_err(|e| CodeGenerationError::ModuleLinkerError(e.to_string()))?;
self.assembly_module
.link_in_module(file.llvm_module.clone())
.map_err(|e| CodeGenerationError::ModuleLinkerError(e.to_string()))?;
if self.code_gen.db.target().options.is_like_windows {
let fltused =
self.assembly_module
.add_global(self.code_gen.context.i32_type(), None, "_fltused");
fltused.set_initializer(&self.code_gen.context.i32_type().const_int(1, false));
fltused.set_linkage(Linkage::External);
}
let target_data = self.code_gen.target_machine.get_target_data();
let type_context = IrTypeContext {
context: self.code_gen.context,
target_data: &target_data,
struct_types: &self.code_gen.rust_types,
};
let value_context = IrValueContext {
type_context: &type_context,
context: type_context.context,
module: &self.assembly_module,
};
let direct_children = module_group
.iter()
.flat_map(|module| module.children(self.code_gen.db))
.collect();
let dependencies = group_ir
.referenced_modules
.union(&direct_children)
.filter_map(|&module| self.module_group_partition.group_for_module(module))
.collect::<FxHashSet<_>>()
.into_iter()
.map(|group_id| {
self.module_group_partition[group_id]
.relative_file_path()
.to_string()
})
.collect();
symbols::gen_reflection_ir(
self.code_gen.db,
&value_context,
&file.function_definitions,
&file.type_definitions,
&group_ir.dispatch_table,
&group_ir.type_table,
&self.code_gen.hir_types,
self.code_gen.optimization_level,
dependencies,
);
optimize_module(&self.assembly_module, self.code_gen.optimization_level);
Ok(Assembly::new(self.code_gen, self.assembly_module))
}
}